From 9b02432b9f8ef3c093f6888a3e4c2c2d6631780a Mon Sep 17 00:00:00 2001 From: HyungKyu Song Date: Thu, 14 Feb 2013 22:08:02 +0900 Subject: [PATCH] Tizen 2.0 Release --- CODING_STYLE | 4 + Changelog | 8 +- HACKING | 11 +- MAINTAINERS | 93 +- Makefile | 222 +- Makefile.hw | 5 +- Makefile.objs | 188 +- Makefile.target | 246 +- Makefile.user | 4 +- QMP/qmp-shell | 0 QMP/qmp.py | 54 +- VERSION | 2 +- a.out.h | 2 +- acl.c | 19 +- aio.c | 6 +- alpha-dis.c | 4 - arch_init.c | 45 +- arch_init.h | 19 +- arm-semi.c | 119 +- arm.ld | 12 +- async.c | 126 +- audio/alsaaudio.c | 10 +- audio/audio.c | 70 +- audio/audio_pt_int.c | 2 - audio/audio_template.h | 20 +- audio/coreaudio.c | 8 +- audio/esdaudio.c | 8 +- audio/fmodaudio.c | 6 +- audio/mixeng.c | 2 +- audio/mixeng_template.h | 4 +- audio/noaudio.c | 4 +- audio/ossaudio.c | 4 +- audio/paaudio.c | 8 +- audio/sdlaudio.c | 21 +- audio/spiceaudio.c | 4 +- audio/wavaudio.c | 52 +- audio/wavcapture.c | 87 +- audio/winwaveaudio.c | 16 +- balloon.c | 128 +- balloon.h | 15 +- bitmap.c | 256 + bitmap.h | 222 + bitops.c | 142 + bitops.h | 272 + block-migration.c | 104 +- block.c | 1428 ++-- block.h | 161 +- block/blkdebug.c | 10 +- block/blkverify.c | 9 - block/bochs.c | 19 +- block/cloop.c | 136 +- block/cow.c | 50 +- block/curl.c | 124 +- block/dmg.c | 29 +- block/iscsi.c | 591 ++ block/nbd.c | 188 +- block/parallels.c | 23 +- block/qcow.c | 485 +- block/qcow2-cache.c | 20 +- block/qcow2-cluster.c | 81 +- block/qcow2-refcount.c | 105 +- block/qcow2-snapshot.c | 71 +- block/qcow2.c | 636 +- block/qcow2.h | 14 +- block/qed-check.c | 9 +- block/qed-cluster.c | 35 +- block/qed-gencb.c | 4 +- block/qed-l2-cache.c | 6 +- block/qed-table.c | 20 +- block/qed.c | 189 +- block/qed.h | 35 + block/raw-posix.c | 478 +- block/raw-win32.c | 105 +- block/raw.c | 75 +- block/rbd.c | 999 +-- block/sheepdog.c | 394 +- block/vdi.c | 114 +- block/vmdk.c | 1572 +++- block/vpc.c | 84 +- block/vvfat.c | 306 +- block_int.h | 102 +- blockdev.c | 99 +- blockdev.h | 1 + bsd-user/main.c | 57 +- bsd-user/mmap.c | 16 +- bsd-user/qemu.h | 2 +- bsd-user/syscall.c | 5 +- bswap.h | 473 ++ bt-host.c | 3 +- bt-vhci.c | 3 +- buffered_file.c | 59 +- check-qdict.c | 9 +- check-qfloat.c | 2 +- check-qint.c | 2 +- check-qjson.c | 3 +- check-qlist.c | 8 +- check-qstring.c | 4 +- cmd.c | 176 +- compatfd.c | 61 +- compatfd.h | 1 + compiler.h | 51 + config.h | 2 +- configure | 1382 +++- console.c | 134 +- console.h | 44 +- coroutine-gthread.c | 131 + coroutine-ucontext.c | 232 + coroutine-win32.c | 92 + cpu-all.h | 543 +- cpu-common.h | 66 +- cpu-defs.h | 20 +- cpu-exec.c | 921 +-- cpus.c | 1141 +-- cpus.h | 13 +- cris-dis.c | 12 +- cursor.c | 4 +- cutils.c | 110 +- darwin-user/commpage.c | 2 +- darwin-user/machload.c | 4 +- darwin-user/main.c | 55 +- darwin-user/signal.c | 4 - darwin-user/syscall.c | 2 +- default-configs/alpha-softmmu.mak | 12 + default-configs/i386-softmmu.mak | 4 + default-configs/lm32-softmmu.mak | 6 + default-configs/microblaze-softmmu.mak | 1 + default-configs/microblazeel-linux-user.mak | 1 + default-configs/microblazeel-softmmu.mak | 5 + default-configs/mips-softmmu.mak | 2 + default-configs/mips64-softmmu.mak | 2 + default-configs/mips64el-softmmu.mak | 2 + default-configs/mipsel-softmmu.mak | 2 + default-configs/pci.mak | 1 + default-configs/ppc-softmmu.mak | 1 + default-configs/ppc64-softmmu.mak | 1 + default-configs/ppcemb-softmmu.mak | 1 + default-configs/s390x-linux-user.mak | 1 + default-configs/unicore32-linux-user.mak | 1 + default-configs/x86_64-softmmu.mak | 4 + default-configs/xtensa-softmmu.mak | 5 + default-configs/xtensaeb-softmmu.mak | 5 + device_tree.c | 98 +- device_tree.h | 4 +- dis-asm.h | 4 + disas.c | 17 +- dma-helpers.c | 86 +- dma.h | 38 +- docs/ccid.txt | 135 + docs/ich9-ehci-uhci.cfg | 37 + docs/libcacard.txt | 483 ++ docs/memory.txt | 172 + docs/qapi-code-gen.txt | 316 + docs/qdev-device-use.txt | 182 +- docs/specs/qcow2.txt | 260 + docs/specs/qed_spec.txt | 8 + docs/tracing.txt | 147 +- docs/usb2.txt | 146 + dyngen-exec.h | 34 +- elf.h | 24 + error.c | 146 + error.h | 70 + error_int.h | 29 + event_notifier.c | 61 + event_notifier.h | 16 + exec-all.h | 82 +- exec-memory.h | 44 + exec.c | 858 +- fpu/softfloat-macros.h | 216 +- fpu/softfloat-specialize.h | 495 +- fpu/softfloat.c | 1725 ++-- fpu/softfloat.h | 291 +- fsdev/file-op-9p.h | 133 + fsdev/qemu-fsdev-dummy.c | 28 + fsdev/qemu-fsdev.c | 84 +- fsdev/qemu-fsdev.h | 24 +- gdbstub.c | 337 +- gen-icount.h | 2 +- hax.h | 48 + hmp-commands.hx | 71 +- hmp.c | 523 ++ hmp.h | 41 + host-utils.h | 2 +- hppa-dis.c | 8 +- hppa.ld | 18 +- hw/9pfs/codir.c | 168 + hw/9pfs/cofile.c | 261 + hw/9pfs/cofs.c | 344 + hw/9pfs/coxattr.c | 107 + hw/9pfs/virtio-9p-coth.c | 98 + hw/9pfs/virtio-9p-coth.h | 107 + hw/9pfs/virtio-9p-device.c | 189 + hw/9pfs/virtio-9p-handle.c | 679 ++ hw/9pfs/virtio-9p-local.c | 794 ++ hw/9pfs/virtio-9p-posix-acl.c | 159 + hw/9pfs/virtio-9p-synth.c | 572 ++ hw/9pfs/virtio-9p-synth.h | 50 + hw/9pfs/virtio-9p-xattr-user.c | 112 + hw/9pfs/virtio-9p-xattr.c | 160 + hw/9pfs/virtio-9p-xattr.h | 105 + hw/9pfs/virtio-9p.c | 3309 ++++++++ hw/9pfs/virtio-9p.h | 472 ++ hw/a9mpcore.c | 2 +- hw/ac97.c | 127 +- hw/acpi.c | 491 +- hw/acpi.h | 68 + hw/acpi_piix4.c | 263 +- hw/adb.c | 89 +- hw/adb.h | 67 + hw/adlib.c | 11 +- hw/ads7846.c | 41 +- hw/alpha_dp264.c | 177 + hw/alpha_pci.c | 134 + hw/alpha_sys.h | 24 + hw/alpha_typhoon.c | 820 ++ hw/an5206.c | 25 +- hw/apb_pci.c | 109 +- hw/apic.c | 59 +- hw/apic.h | 6 +- hw/applesmc.c | 2 +- hw/arm-misc.h | 9 +- hw/arm11mpcore.c | 10 +- hw/arm_boot.c | 33 +- hw/arm_gic.c | 79 +- hw/arm_pic.c | 15 +- hw/arm_sysctl.c | 210 +- hw/arm_timer.c | 127 +- hw/armv7m.c | 51 +- hw/armv7m_nvic.c | 52 +- hw/audiodev.h | 2 +- hw/axis_dev88.c | 46 +- hw/baum.c | 56 +- hw/baum.h | 2 +- hw/bitbang_i2c.c | 9 +- hw/blizzard.c | 9 +- hw/boards.h | 1 + hw/bonito.c | 38 +- hw/bt-hci-csr.c | 7 +- hw/bt-hci.c | 32 +- hw/bt-hid.c | 66 +- hw/bt-l2cap.c | 18 +- hw/bt-sdp.c | 20 +- hw/bt.c | 6 +- hw/bt.h | 332 +- hw/cbus.c | 6 +- hw/ccid-card-emulated.c | 595 ++ hw/ccid-card-passthru.c | 340 + hw/ccid.h | 58 + hw/cirrus_vga.c | 485 +- hw/collie.c | 68 + hw/cris-boot.c | 1 - hw/cris_pic_cpu.c | 7 +- hw/cs4231a.c | 38 +- hw/cuda.c | 173 +- hw/debugcon.c | 2 +- hw/dec_pci.c | 39 +- hw/devices.h | 16 +- hw/dma.c | 10 + hw/dp8393x.c | 12 +- hw/ds1225y.c | 172 +- hw/ds1338.c | 2 +- hw/dummy_m68k.c | 10 +- hw/e1000.c | 249 +- hw/e1000_hw.h | 17 + hw/eepro100.c | 592 +- hw/eeprom93xx.c | 14 +- hw/elf_ops.h | 26 +- hw/empty_slot.c | 21 +- hw/es1370.c | 73 +- hw/escc.c | 115 +- hw/escc.h | 2 +- hw/esp.c | 204 +- hw/etraxfs.h | 20 +- hw/etraxfs_dma.c | 59 +- hw/etraxfs_eth.c | 108 +- hw/etraxfs_pic.c | 30 +- hw/etraxfs_ser.c | 67 +- hw/etraxfs_timer.c | 33 +- hw/fdc.c | 267 +- hw/fdc.h | 34 +- hw/flash.h | 33 +- hw/fmopl.c | 8 +- hw/framebuffer.c | 3 + hw/fw_cfg.c | 140 +- hw/g364fb.c | 383 +- hw/grackle_pci.c | 58 +- hw/grlib_apbuart.c | 4 +- hw/grlib_gptimer.c | 31 +- hw/grlib_irqmp.c | 6 +- hw/gt64xxx.c | 90 +- hw/gumstix.c | 14 +- hw/gus.c | 43 +- hw/hda-audio.c | 26 +- hw/heathrow_pic.c | 93 +- hw/hid.c | 467 ++ hw/hid.h | 59 + hw/hpet.c | 30 +- hw/hpet_emul.h | 4 +- hw/hw.h | 156 +- hw/i2c.c | 4 +- hw/i2c.h | 7 +- hw/i8254.c | 85 +- hw/i8259.c | 440 +- hw/ide.h | 6 +- hw/ide/ahci.c | 152 +- hw/ide/ahci.h | 22 +- hw/ide/atapi.c | 1117 +++ hw/ide/cmd646.c | 215 +- hw/ide/core.c | 1512 ++-- hw/ide/ich.c | 55 +- hw/ide/internal.h | 294 +- hw/ide/isa.c | 6 +- hw/ide/macio.c | 95 +- hw/ide/microdrive.c | 6 +- hw/ide/mmio.c | 4 +- hw/ide/pci.c | 140 +- hw/ide/pci.h | 23 +- hw/ide/piix.c | 129 +- hw/ide/qdev.c | 93 +- hw/ide/via.c | 80 +- hw/integratorcp.c | 47 +- hw/intel-hda.c | 115 +- hw/intel-hda.h | 2 +- hw/ioapic.c | 12 +- hw/ioapic.h | 7 + hw/ioh3420.c | 7 +- hw/irq.c | 37 +- hw/irq.h | 10 +- hw/isa-bus.c | 60 +- hw/isa.h | 43 +- hw/isa_mmio.c | 29 +- hw/ivshmem.c | 192 +- hw/jazz_led.c | 2 +- hw/kvmclock.c | 118 + hw/kvmclock.h | 24 + hw/lan9118.c | 50 +- hw/lance.c | 32 +- hw/leon3.c | 17 +- hw/lm32.h | 25 + hw/lm32_boards.c | 303 + hw/lm32_hwsetup.h | 178 + hw/lm32_juart.c | 150 + hw/lm32_juart.h | 11 + hw/lm32_pic.c | 190 + hw/lm32_pic.h | 14 + hw/lm32_sys.c | 161 + hw/lm32_timer.c | 222 + hw/lm32_uart.c | 288 + hw/lm4549.c | 336 + hw/lm4549.h | 43 + hw/lm832x.c | 10 +- hw/loader.c | 61 +- hw/loader.h | 4 +- hw/lsi53c895a.c | 558 +- hw/m48t59.c | 72 +- hw/mac_dbdma.c | 118 +- hw/mac_dbdma.h | 5 +- hw/mac_nvram.c | 73 +- hw/macio.c | 73 +- hw/mainstone.c | 64 +- hw/marvell_88w8618_audio.c | 2 +- hw/max111x.c | 51 +- hw/max7310.c | 26 +- hw/mc146818rtc.c | 51 +- hw/mcf5206.c | 6 +- hw/mcf5208.c | 76 +- hw/mcf_fec.c | 8 +- hw/mcf_intc.c | 4 +- hw/mcf_uart.c | 6 +- hw/microblaze_pic_cpu.c | 8 +- hw/microblaze_pic_cpu.h | 8 + hw/milkymist-ac97.c | 335 + hw/milkymist-hpdmc.c | 161 + hw/milkymist-hw.h | 223 + hw/milkymist-memcard.c | 294 + hw/milkymist-minimac2.c | 538 ++ hw/milkymist-pfpu.c | 535 ++ hw/milkymist-softusb.c | 326 + hw/milkymist-sysctl.c | 318 + hw/milkymist-tmu2.c | 481 ++ hw/milkymist-uart.c | 234 + hw/milkymist-vgafb.c | 320 + hw/milkymist-vgafb_template.h | 74 + hw/milkymist.c | 215 + hw/mips.h | 12 - hw/mips_fulong2e.c | 53 +- hw/mips_jazz.c | 147 +- hw/mips_malta.c | 255 +- hw/mips_mipssim.c | 39 +- hw/mips_r4k.c | 74 +- hw/mips_timer.c | 10 +- hw/mipsnet.c | 155 +- hw/mpc8544_guts.c | 135 + hw/mpcore.c | 45 +- hw/msi.c | 18 +- hw/msix.c | 162 +- hw/msix.h | 6 +- hw/msmouse.c | 11 +- hw/msmouse.h | 2 +- hw/mst_fpga.c | 159 +- hw/multiboot.c | 46 +- hw/musicpal.c | 275 +- hw/nand.c | 424 +- hw/ne2000-isa.c | 29 +- hw/ne2000.c | 90 +- hw/ne2000.h | 8 +- hw/nseries.c | 114 +- hw/omap.h | 84 +- hw/omap1.c | 1033 +-- hw/omap2.c | 148 +- hw/omap_clk.c | 8 +- hw/omap_dma.c | 4 +- hw/omap_dss.c | 13 +- hw/omap_gpio.c | 260 +- hw/omap_gpmc.c | 753 +- hw/omap_gptimer.c | 16 +- hw/omap_i2c.c | 4 +- hw/omap_intc.c | 181 +- hw/omap_l4.c | 24 +- hw/omap_lcdc.c | 9 +- hw/omap_mmc.c | 4 +- hw/omap_sdrc.c | 2 +- hw/omap_spi.c | 2 +- hw/omap_sx1.c | 13 +- hw/omap_synctimer.c | 4 +- hw/omap_uart.c | 29 +- hw/onenand.c | 372 +- hw/opencores_eth.c | 747 ++ hw/openpic.c | 579 +- hw/openpic.h | 6 +- hw/palm.c | 83 +- hw/parallel.c | 102 +- hw/pc.c | 248 +- hw/pc.h | 195 +- hw/pc_piix.c | 351 +- hw/pci-hotplug.c | 8 +- hw/pci-stub.c | 17 +- hw/pci.c | 687 +- hw/pci.h | 129 +- hw/pci_bridge.c | 85 +- hw/pci_host.c | 112 +- hw/pci_host.h | 23 +- hw/pci_ids.h | 21 +- hw/pci_internals.h | 25 +- hw/pci_regs.h | 63 +- hw/pcie.c | 17 +- hw/pcie.h | 2 +- hw/pcie_aer.c | 36 +- hw/pcie_host.c | 131 +- hw/pcie_host.h | 12 +- hw/pcie_port.c | 2 +- hw/pckbd.c | 61 +- hw/pcnet-pci.c | 135 +- hw/pcnet.c | 104 +- hw/pcnet.h | 26 +- hw/pcspk.c | 6 +- hw/petalogix_ml605_mmu.c | 267 + hw/petalogix_s3adsp1800_mmu.c | 40 +- hw/pflash_cfi01.c | 85 +- hw/pflash_cfi02.c | 122 +- hw/piix4.c | 52 +- hw/piix_pci.c | 338 +- hw/pl011.c | 80 +- hw/pl022.c | 86 +- hw/pl031.c | 10 +- hw/pl041.c | 636 ++ hw/pl041.h | 135 + hw/pl041.hx | 81 + hw/pl050.c | 2 +- hw/pl061.c | 206 +- hw/pl080.c | 10 +- hw/pl110.c | 117 +- hw/pl110_template.h | 104 +- hw/pl181.c | 8 +- hw/pl190.c | 2 +- hw/ppc-viosrp.h | 216 + hw/ppc.c | 249 +- hw/ppc.h | 38 +- hw/ppc405.h | 23 +- hw/ppc405_boards.c | 150 +- hw/ppc405_uc.c | 239 +- hw/ppc440.c | 32 +- hw/ppc440.h | 6 +- hw/ppc440_bamboo.c | 28 +- hw/ppc4xx.h | 2 + hw/ppc4xx_devs.c | 59 +- hw/ppc4xx_pci.c | 100 +- hw/ppc_booke.c | 254 + hw/ppc_mac.h | 75 +- hw/ppc_newworld.c | 112 +- hw/ppc_oldworld.c | 80 +- hw/ppc_prep.c | 138 +- hw/ppce500_mpc8544ds.c | 302 +- hw/ppce500_pci.c | 288 +- hw/ppce500_spin.c | 216 + hw/prep_pci.c | 25 +- hw/prep_pci.h | 5 +- hw/primecell.h | 4 + hw/ps2.c | 94 +- hw/ptimer.c | 77 +- hw/pxa.h | 68 +- hw/pxa2xx.c | 827 +- hw/pxa2xx_dma.c | 219 +- hw/pxa2xx_gpio.c | 11 +- hw/pxa2xx_keypad.c | 163 +- hw/pxa2xx_lcd.c | 251 +- hw/pxa2xx_mmci.c | 18 +- hw/pxa2xx_pcmcia.c | 2 +- hw/pxa2xx_pic.c | 91 +- hw/pxa2xx_timer.c | 296 +- hw/qdev-properties.c | 54 +- hw/qdev.c | 94 +- hw/qdev.h | 8 +- hw/qxl-logger.c | 4 +- hw/qxl-render.c | 69 +- hw/qxl.c | 773 +- hw/qxl.h | 46 +- hw/r2d.c | 48 +- hw/rc4030.c | 16 +- hw/realview.c | 126 +- hw/realview_gic.c | 40 +- hw/rtl8139.c | 877 +- hw/s390-virtio-bus.c | 47 +- hw/s390-virtio-bus.h | 7 +- hw/s390-virtio.c | 112 +- hw/sb16.c | 36 +- hw/scsi-bus.c | 1154 ++- hw/scsi-defs.h | 170 +- hw/scsi-disk.c | 1506 ++-- hw/scsi-generic.c | 471 +- hw/scsi.h | 175 +- hw/sd.c | 52 +- hw/serial.c | 210 +- hw/sga.c | 56 + hw/sh7750.c | 3 +- hw/sh7750_regs.h | 6 +- hw/sh_intc.c | 13 +- hw/sh_pci.c | 73 +- hw/sh_serial.c | 4 +- hw/sh_timer.c | 6 +- hw/shix.c | 11 - hw/slavio_intctl.c | 8 +- hw/slavio_misc.c | 2 +- hw/slavio_timer.c | 8 +- hw/sm501.c | 160 +- hw/sm501_template.h | 2 +- hw/smbios.c | 14 +- hw/smbios.h | 22 +- hw/smbus.c | 2 +- hw/smbus.h | 3 + hw/smbus_eeprom.c | 22 +- hw/smc91c111.c | 40 +- hw/soc_dma.c | 12 +- hw/soc_dma.h | 8 +- hw/spapr.c | 615 ++ hw/spapr.h | 310 + hw/spapr_hcall.c | 707 ++ hw/spapr_llan.c | 508 ++ hw/spapr_pci.c | 508 ++ hw/spapr_pci.h | 61 + hw/spapr_rtas.c | 301 + hw/spapr_vio.c | 843 ++ hw/spapr_vio.h | 117 + hw/spapr_vscsi.c | 969 +++ hw/spapr_vty.c | 215 + hw/spitz.c | 74 +- hw/srp.h | 240 + hw/ssd0303.c | 4 +- hw/ssd0323.c | 2 +- hw/ssi-sd.c | 2 +- hw/ssi.c | 8 +- hw/stellaris.c | 413 +- hw/stellaris_enet.c | 33 +- hw/stellaris_input.c | 56 +- hw/strongarm.c | 1561 ++++ hw/strongarm.h | 68 + hw/sun4m.c | 85 +- hw/sun4m.h | 4 + hw/sun4m_iommu.c | 4 +- hw/sun4u.c | 147 +- hw/syborg.c | 9 +- hw/syborg_fb.c | 15 +- hw/syborg_interrupt.c | 2 +- hw/syborg_keyboard.c | 59 +- hw/syborg_pointer.c | 75 +- hw/syborg_rtc.c | 36 +- hw/syborg_serial.c | 68 +- hw/syborg_timer.c | 46 +- hw/syborg_virtio.c | 9 +- hw/sysbus.c | 109 +- hw/sysbus.h | 26 +- hw/tc58128.c | 7 +- hw/tc6393xb.c | 83 +- hw/tcx.c | 156 +- hw/tosa.c | 21 +- hw/tsc2005.c | 6 +- hw/tsc210x.c | 24 +- hw/tusb6010.c | 130 +- hw/twl92230.c | 9 +- hw/unin_pci.c | 172 +- hw/usb-bt.c | 70 +- hw/usb-bus.c | 184 +- hw/usb-ccid.c | 1321 +++ hw/usb-desc.c | 76 +- hw/usb-desc.h | 26 +- hw/usb-ehci.c | 1993 +++-- hw/usb-hid.c | 551 +- hw/usb-hub.c | 156 +- hw/usb-libhw.c | 63 + hw/usb-msd.c | 366 +- hw/usb-musb.c | 146 +- hw/usb-net.c | 83 +- hw/usb-ohci.c | 276 +- hw/usb-serial.c | 58 +- hw/usb-uhci.c | 398 +- hw/usb-wacom.c | 102 +- hw/usb.c | 233 +- hw/usb.h | 109 +- hw/versatile_pci.c | 100 +- hw/versatilepb.c | 37 +- hw/vexpress.c | 229 + hw/vga-isa-mm.c | 57 +- hw/vga-isa.c | 49 +- hw/vga-pci.c | 108 +- hw/vga.c | 441 +- hw/vga_int.h | 31 +- hw/vhost.c | 155 +- hw/vhost.h | 2 + hw/vhost_net.c | 30 +- hw/virtex_ml507.c | 31 +- hw/virtio-balloon.c | 133 +- hw/virtio-balloon.h | 2 +- hw/virtio-blk.c | 101 +- hw/virtio-blk.h | 4 +- hw/virtio-console.c | 93 +- hw/virtio-net.c | 21 +- hw/virtio-net.h | 2 +- hw/virtio-pci.c | 1297 ++- hw/virtio-pci.h | 53 + hw/virtio-serial-bus.c | 215 +- hw/virtio-serial.h | 27 +- hw/virtio.c | 171 +- hw/virtio.h | 30 +- hw/vmmouse.c | 64 +- hw/vmport.c | 61 +- hw/vmware_vga.c | 377 +- hw/vmware_vga.h | 12 +- hw/vt82c686.c | 159 +- hw/watchdog.c | 2 +- hw/wdt_i6300esb.c | 66 +- hw/wdt_ib700.c | 4 +- hw/wm8750.c | 2 +- hw/xen.h | 33 + hw/xen_backend.c | 461 +- hw/xen_backend.h | 9 +- hw/xen_common.h | 132 +- hw/xen_console.c | 36 +- hw/xen_devconfig.c | 10 +- hw/xen_disk.c | 562 +- hw/xen_domainbuild.c | 10 +- hw/xen_machine_pv.c | 2 +- hw/xen_nic.c | 274 +- hw/xen_platform.c | 396 + hw/xenfb.c | 55 +- hw/xics.c | 493 ++ hw/xics.h | 38 + hw/xilinx.h | 44 +- hw/xilinx_axidma.c | 509 ++ hw/xilinx_axidma.h | 39 + hw/xilinx_axienet.c | 898 ++ hw/xilinx_ethlite.c | 44 +- hw/xilinx_intc.c | 29 +- hw/xilinx_timer.c | 34 +- hw/xilinx_uartlite.c | 34 +- hw/xio3130_downstream.c | 6 +- hw/xio3130_upstream.c | 6 +- hw/xtensa_bootparam.h | 25 + hw/xtensa_lx60.c | 312 + hw/xtensa_pic.c | 161 + hw/xtensa_sim.c | 116 + hw/z2.c | 360 + hw/zaurus.c | 22 +- i386.ld | 8 +- ia64-dis.c | 3 + input.c | 131 +- int128.h | 116 + iohandler.c | 194 + ioport.c | 137 +- ioport.h | 23 +- iov.c | 103 +- iov.h | 14 +- json-lexer.c | 53 +- json-lexer.h | 1 + json-parser.c | 83 +- json-parser.h | 2 + json-streamer.c | 42 +- json-streamer.h | 1 + kvm-all.c | 2017 ++--- kvm-stub.c | 36 +- kvm.h | 37 +- libcacard/Makefile | 66 + libcacard/cac.c | 404 + libcacard/cac.h | 23 + libcacard/card_7816.c | 763 ++ libcacard/card_7816.h | 62 + libcacard/card_7816t.h | 165 + libcacard/event.c | 106 + libcacard/eventt.h | 29 + libcacard/libcacard.pc.in | 13 + libcacard/link_test.c | 22 + libcacard/vcard.c | 339 + libcacard/vcard.h | 86 + libcacard/vcard_emul.h | 65 + libcacard/vcard_emul_nss.c | 1264 +++ libcacard/vcard_emul_type.c | 57 + libcacard/vcard_emul_type.h | 32 + libcacard/vcardt.h | 64 + libcacard/vevent.h | 27 + libcacard/vreader.c | 513 ++ libcacard/vreader.h | 55 + libcacard/vreadert.h | 24 + libcacard/vscard_common.h | 178 + libcacard/vscclient.c | 657 ++ libfdt_env.h | 8 +- linux-aio.c | 74 +- linux-headers/COPYING | 356 + linux-headers/README | 2 + linux-headers/asm-powerpc/kvm.h | 332 + linux-headers/asm-powerpc/kvm_para.h | 53 + linux-headers/asm-s390/kvm.h | 44 + linux-headers/asm-s390/kvm_para.h | 17 + linux-headers/asm-x86/hyperv.h | 193 + linux-headers/asm-x86/kvm.h | 324 + linux-headers/asm-x86/kvm_para.h | 93 + linux-headers/linux/kvm.h | 863 ++ linux-headers/linux/kvm_para.h | 29 + linux-headers/linux/vhost.h | 130 + linux-headers/linux/virtio_config.h | 54 + linux-headers/linux/virtio_ring.h | 163 + linux-user/alpha/syscall_nr.h | 30 +- linux-user/arm/nwfpe/fpa11.c | 2 +- linux-user/arm/nwfpe/fpa11.h | 2 +- linux-user/arm/nwfpe/fpa11_cpdt.c | 10 +- linux-user/arm/nwfpe/fpa11_cprt.c | 2 +- linux-user/arm/nwfpe/fpopcode.c | 32 +- linux-user/arm/syscall_nr.h | 13 + linux-user/cris/syscall_nr.h | 2 + linux-user/elfload.c | 476 +- linux-user/flatload.c | 46 +- linux-user/i386/syscall_nr.h | 12 + linux-user/ioctls.h | 17 +- linux-user/linuxload.c | 27 +- linux-user/m68k/syscall_nr.h | 16 + linux-user/main.c | 1003 ++- linux-user/microblaze/syscall_nr.h | 14 +- linux-user/mips/syscall_nr.h | 13 + linux-user/mips64/syscall_nr.h | 13 + linux-user/mipsn32/syscall_nr.h | 14 + linux-user/mmap.c | 6 +- linux-user/ppc/syscall_nr.h | 30 + linux-user/qemu-types.h | 12 + linux-user/qemu.h | 23 +- linux-user/s390x/syscall.h | 23 + linux-user/s390x/syscall_nr.h | 358 + linux-user/s390x/target_signal.h | 26 + linux-user/s390x/termbits.h | 283 + linux-user/sh4/syscall_nr.h | 34 +- linux-user/signal.c | 435 +- linux-user/sparc/syscall_nr.h | 15 + linux-user/sparc64/syscall_nr.h | 12 + linux-user/strace.c | 274 +- linux-user/strace.list | 15 +- linux-user/syscall.c | 1137 ++- linux-user/syscall_defs.h | 167 +- linux-user/syscall_types.h | 20 + linux-user/target_flat.h | 10 + linux-user/unicore32/syscall.h | 55 + linux-user/unicore32/syscall_nr.h | 371 + linux-user/unicore32/target_signal.h | 26 + linux-user/unicore32/termbits.h | 2 + linux-user/vm86.c | 4 +- linux-user/x86_64/syscall_nr.h | 12 + m68k-semi.c | 9 +- main-loop.c | 482 ++ main-loop.h | 351 + memory.c | 1437 ++++ memory.h | 509 ++ migration-exec.c | 40 +- migration-fd.c | 66 +- migration-tcp.c | 81 +- migration-unix.c | 116 +- migration.c | 560 +- migration.h | 105 +- mips-dis.c | 2 +- mips.ld | 18 +- module.c | 2 +- module.h | 2 + monitor.c | 1050 +-- monitor.h | 2 + nbd.c | 1045 ++- nbd.h | 31 +- net.c | 234 +- net.h | 16 +- net/dump.c | 4 +- net/queue.c | 14 +- net/slirp.c | 66 +- net/socket.c | 28 +- net/tap-bsd.c | 26 +- net/tap-linux.c | 6 +- net/tap-win32.c | 4 +- net/tap.c | 1 - net/vde.c | 1 - new_emulator_project | 0 notify.c | 4 +- notify.h | 4 +- os-posix.c | 41 +- os-win32.c | 150 +- osdep.c | 1 - osdep.h | 40 +- oslib-posix.c | 61 +- oslib-win32.c | 13 +- package/build.linux | 8 +- package/build.windows | 54 +- package/pkginfo.manifest | 9 +- path.c | 28 +- pc-bios/README | 34 +- pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/linuxboot.bin | Bin 1024 -> 1024 bytes pc-bios/mpc8544ds.dtb | Bin 12288 -> 2028 bytes pc-bios/mpc8544ds.dts | 21 +- pc-bios/multiboot.bin | Bin 1024 -> 1024 bytes pc-bios/openbios-ppc | Bin 729876 -> 729876 bytes pc-bios/openbios-sparc32 | Bin 377388 -> 381484 bytes pc-bios/openbios-sparc64 | Bin 1598328 -> 1598328 bytes pc-bios/optionrom/multiboot.S | 2 + pc-bios/optionrom/optionrom.h | 40 +- pc-bios/palcode-clipper | Bin 0 -> 185703 bytes pc-bios/petalogix-ml605.dtb | Bin 0 -> 9982 bytes pc-bios/pxe-e1000.rom | Bin 0 -> 67072 bytes pc-bios/pxe-eepro100.rom | Bin 0 -> 61440 bytes pc-bios/pxe-ne2k_pci.rom | Bin 0 -> 61440 bytes pc-bios/pxe-pcnet.rom | Bin 0 -> 61440 bytes pc-bios/pxe-rtl8139.rom | Bin 0 -> 61440 bytes pc-bios/pxe-virtio.rom | Bin 0 -> 60416 bytes pc-bios/s390-zipl.rom | Bin 3336 -> 3304 bytes pc-bios/sgabios.bin | Bin 0 -> 4096 bytes pc-bios/slof.bin | Bin 0 -> 738744 bytes pc-bios/spapr-rtas.bin | Bin 0 -> 20 bytes pc-bios/spapr-rtas/Makefile | 24 + pc-bios/spapr-rtas/spapr-rtas.S | 37 + pc-bios/vgabios-maruvga.bin | Bin 0 -> 38912 bytes pflib.c | 10 +- poison.h | 23 +- posix-aio-compat.c | 125 +- ppc.ld | 34 +- ppc64.ld | 26 +- qapi-schema-guest.json | 217 + qapi-schema-test.json | 22 + qapi-schema.json | 889 ++ qapi/qapi-dealloc-visitor.c | 171 + qapi/qapi-dealloc-visitor.h | 26 + qapi/qapi-types-core.h | 23 + qapi/qapi-visit-core.c | 118 + qapi/qapi-visit-core.h | 76 + qapi/qmp-core.h | 41 + qapi/qmp-dispatch.c | 124 + qapi/qmp-input-visitor.c | 301 + qapi/qmp-input-visitor.h | 27 + qapi/qmp-output-visitor.c | 251 + qapi/qmp-output-visitor.h | 28 + qapi/qmp-registry.c | 40 + qbool.c | 4 +- qdict.c | 12 +- qemu-barrier.h | 34 +- qemu-char.c | 716 +- qemu-char.h | 176 +- qemu-common.h | 136 +- qemu-config.c | 96 +- qemu-coroutine-int.h | 49 + qemu-coroutine-lock.c | 162 + qemu-coroutine.c | 75 + qemu-coroutine.h | 191 + qemu-doc.texi | 129 +- qemu-error.c | 3 +- qemu-ga.c | 637 ++ qemu-img-cmds.hx | 12 +- qemu-img.c | 336 +- qemu-img.texi | 23 +- qemu-io.c | 2679 +++--- qemu-lock.h | 210 +- qemu-nbd.c | 315 +- qemu-option.c | 67 +- qemu-option.h | 3 +- qemu-options.hx | 476 +- qemu-os-posix.h | 7 +- qemu-os-win32.h | 19 +- qemu-progress.c | 150 + qemu-queue.h | 13 + qemu-sockets.c | 33 +- qemu-tech.texi | 42 +- qemu-thread-posix.c | 149 + qemu-thread-posix.h | 17 + qemu-thread-win32.c | 281 + qemu-thread-win32.h | 21 + qemu-thread.h | 36 +- qemu-timer.c | 854 +- qemu-timer.h | 69 +- qemu-tls.h | 52 + qemu-tool.c | 52 +- qemu-xattr.h | 30 + qemu_socket.h | 6 +- qerror.c | 138 +- qerror.h | 36 + qfloat.c | 4 +- qga/guest-agent-command-state.c | 73 + qga/guest-agent-commands.c | 561 ++ qga/guest-agent-core.h | 31 + qint.c | 4 +- qlist.c | 10 +- qlist.h | 11 + qmp-commands.hx | 341 +- qmp.c | 119 + qstring.c | 10 +- readline.c | 10 +- rules.mak | 16 +- savevm.c | 433 +- scripts/analyse-9p-simpletrace.py | 142 + scripts/checkpatch.pl | 17 +- scripts/create_config | 0 scripts/get_maintainer.pl | 2149 +++++ scripts/kvm/kvm_stat | 480 ++ scripts/kvm/vmxcap | 224 + scripts/ordereddict.py | 127 + scripts/qapi-commands.py | 445 + scripts/qapi-types.py | 278 + scripts/qapi-visit.py | 246 + scripts/qapi.py | 206 + scripts/qemu-binfmt-conf.sh | 4 +- scripts/refresh-pxe-roms.sh | 99 + scripts/signrom.sh | 0 scripts/simpletrace.py | 126 +- scripts/texi2pod.pl | 0 scripts/tracetool | 158 +- scripts/update-linux-headers.sh | 55 + slirp/arp_table.c | 95 + slirp/bootp.c | 23 +- slirp/if.c | 22 +- slirp/ip.h | 24 +- slirp/ip_icmp.c | 163 +- slirp/ip_icmp.h | 3 + slirp/ip_input.c | 34 +- slirp/ip_output.c | 4 +- slirp/libslirp.h | 13 +- slirp/main.h | 2 +- slirp/mbuf.c | 2 + slirp/mbuf.h | 6 +- slirp/misc.c | 23 +- slirp/slirp.c | 193 +- slirp/slirp.h | 52 +- slirp/socket.c | 8 +- slirp/tcp.h | 4 +- slirp/tcp_input.c | 41 +- slirp/tcp_subr.c | 4 +- slirp/tftp.c | 20 +- slirp/tftp.h | 2 +- slirp/udp.c | 23 +- softmmu-semi.h | 2 +- softmmu_defs.h | 8 + softmmu_exec.h | 12 +- softmmu_header.h | 9 + softmmu_template.h | 216 +- sparc.ld | 12 +- spice-qemu-char.c | 80 +- sysemu.h | 76 +- target-alpha/cpu.h | 406 +- target-alpha/helper.c | 592 +- target-alpha/helper.h | 37 +- target-alpha/machine.c | 87 + target-alpha/op_helper.c | 320 +- target-alpha/translate.c | 875 +- target-arm/cpu.h | 48 +- target-arm/helper.c | 891 +- target-arm/helper.h | 475 ++ target-arm/iwmmxt_helper.c | 2 +- target-arm/machine.c | 16 +- target-arm/neon_helper.c | 676 +- target-arm/op_addsub.h | 2 +- target-arm/op_helper.c | 28 +- target-arm/translate.c | 2930 ++++--- target-cris/cpu.h | 20 +- target-cris/helper.c | 13 +- target-cris/mmu.c | 1 - target-cris/op_helper.c | 19 +- target-cris/opcode-cris.h | 12 +- target-cris/translate.c | 8 +- target-cris/translate_v10.c | 77 +- target-i386/cpu.h | 133 +- target-i386/cpuid.c | 123 +- target-i386/hax-all.c | 1157 +++ target-i386/hax-i386.h | 82 + target-i386/hax-interface.h | 335 + target-i386/hax-windows.c | 490 ++ target-i386/hax-windows.h | 53 + target-i386/helper.c | 225 +- target-i386/helper.h | 3 - target-i386/kvm.c | 928 +-- target-i386/machine.c | 209 +- target-i386/ops_sse.h | 96 +- target-i386/svm.h | 8 +- target-i386/translate.c | 327 +- target-lm32/README | 46 + target-lm32/TODO | 3 + target-lm32/cpu.h | 257 + target-lm32/helper.c | 255 + target-lm32/helper.h | 14 + target-lm32/machine.c | 33 + target-lm32/op_helper.c | 106 + target-lm32/translate.c | 1239 +++ target-m68k/cpu.h | 17 +- target-m68k/helper.c | 11 +- target-m68k/op_helper.c | 51 +- target-m68k/translate.c | 49 +- target-microblaze/cpu.h | 39 +- target-microblaze/helper.c | 7 +- target-microblaze/helper.h | 3 + target-microblaze/microblaze-decode.h | 3 + target-microblaze/mmu.c | 1 - target-microblaze/op_helper.c | 73 +- target-microblaze/translate.c | 67 +- target-mips/cpu.h | 89 +- target-mips/helper.c | 27 +- target-mips/helper.h | 10 + target-mips/machine.c | 2 +- target-mips/op_helper.c | 945 ++- target-mips/translate.c | 120 +- target-mips/translate_init.c | 12 +- target-ppc/STATUS | 2 +- target-ppc/cpu.h | 540 +- target-ppc/helper.c | 1018 ++- target-ppc/helper.h | 15 +- target-ppc/kvm.c | 599 +- target-ppc/kvm_ppc.c | 73 +- target-ppc/kvm_ppc.h | 96 +- target-ppc/machine.c | 22 +- target-ppc/op_helper.c | 377 +- target-ppc/translate.c | 1070 ++- target-ppc/translate_init.c | 644 +- target-s390x/cpu.h | 812 +- target-s390x/helper.c | 594 +- target-s390x/helpers.h | 152 + target-s390x/kvm.c | 105 +- target-s390x/op_helper.c | 2971 ++++++- target-s390x/translate.c | 5206 +++++++++++- target-sh4/cpu.h | 17 +- target-sh4/helper.c | 9 +- target-sh4/helper.h | 48 +- target-sh4/op_helper.c | 228 +- target-sh4/translate.c | 22 +- target-sparc/cc_helper.c | 485 ++ target-sparc/cpu.h | 157 +- target-sparc/cpu_init.c | 848 ++ target-sparc/fop_helper.c | 480 ++ target-sparc/helper.c | 1543 +--- target-sparc/helper.h | 246 +- target-sparc/int32_helper.c | 169 + target-sparc/int64_helper.c | 201 + target-sparc/ldst_helper.c | 2371 ++++++ target-sparc/machine.c | 48 +- target-sparc/mmu_helper.c | 853 ++ target-sparc/op_helper.c | 4479 +--------- target-sparc/translate.c | 1639 ++-- target-sparc/vis_helper.c | 489 ++ target-sparc/win_helper.c | 393 + target-unicore32/cpu.h | 188 + target-unicore32/helper.c | 486 ++ target-unicore32/helper.h | 70 + target-unicore32/op_helper.c | 249 + target-unicore32/translate.c | 2103 +++++ target-xtensa/core-dc232b.c | 28 + target-xtensa/core-dc232b/core-isa.h | 423 + target-xtensa/core-dc232b/gdb-config.c | 261 + target-xtensa/core-fsf.c | 22 + target-xtensa/core-fsf/core-isa.h | 361 + target-xtensa/cpu.h | 442 + target-xtensa/helper.c | 542 ++ target-xtensa/helpers.h | 32 + target-xtensa/machine.c | 38 + target-xtensa/op_helper.c | 664 ++ target-xtensa/overlay_tool.h | 540 ++ target-xtensa/translate.c | 2552 ++++++ tcg/README | 10 +- tcg/arm/tcg-target.c | 82 +- tcg/arm/tcg-target.h | 35 +- tcg/hppa/tcg-target.c | 79 +- tcg/hppa/tcg-target.h | 36 +- tcg/i386/tcg-target.c | 175 +- tcg/i386/tcg-target.h | 77 +- tcg/ia64/tcg-target.c | 43 +- tcg/ia64/tcg-target.h | 72 +- tcg/mips/tcg-target.c | 23 +- tcg/mips/tcg-target.h | 40 +- tcg/optimize.c | 806 +- tcg/ppc/tcg-target.c | 56 +- tcg/ppc/tcg-target.h | 40 +- tcg/ppc64/tcg-target.c | 53 +- tcg/ppc64/tcg-target.h | 73 +- tcg/s390/tcg-target.c | 16 +- tcg/s390/tcg-target.h | 74 +- tcg/sparc/tcg-target.c | 32 +- tcg/sparc/tcg-target.h | 78 +- tcg/tcg-op.h | 1076 ++- tcg/tcg-opc.h | 248 +- tcg/tcg.c | 278 +- tcg/tcg.h | 224 +- tcg/tci/README | 130 + tcg/tci/tcg-target.c | 902 ++ tcg/tci/tcg-target.h | 164 + tci-dis.c | 59 + tci.c | 1208 +++ test-coroutine.c | 192 + test-qmp-commands.c | 142 + test-visitor.c | 338 + tests/Makefile | 4 + tests/cris/.gdbinit | 11 + tests/cris/check_openpf1.c | 2 +- tests/cris/check_openpf2.c | 2 +- tests/cris/check_stat3.c | 2 +- tests/cris/check_stat4.c | 2 +- tests/linux-test.c | 2 + tests/lm32/Makefile | 102 + tests/lm32/crt.S | 84 + tests/lm32/linker.ld | 55 + tests/lm32/macros.inc | 79 + tests/lm32/test_add.S | 75 + tests/lm32/test_addi.S | 56 + tests/lm32/test_and.S | 45 + tests/lm32/test_andhi.S | 35 + tests/lm32/test_andi.S | 35 + tests/lm32/test_b.S | 13 + tests/lm32/test_be.S | 48 + tests/lm32/test_bg.S | 78 + tests/lm32/test_bge.S | 78 + tests/lm32/test_bgeu.S | 78 + tests/lm32/test_bgu.S | 78 + tests/lm32/test_bi.S | 23 + tests/lm32/test_bne.S | 48 + tests/lm32/test_break.S | 20 + tests/lm32/test_bret.S | 38 + tests/lm32/test_call.S | 16 + tests/lm32/test_calli.S | 15 + tests/lm32/test_cmpe.S | 40 + tests/lm32/test_cmpei.S | 35 + tests/lm32/test_cmpg.S | 64 + tests/lm32/test_cmpge.S | 64 + tests/lm32/test_cmpgei.S | 55 + tests/lm32/test_cmpgeu.S | 64 + tests/lm32/test_cmpgeui.S | 55 + tests/lm32/test_cmpgi.S | 55 + tests/lm32/test_cmpgu.S | 64 + tests/lm32/test_cmpgui.S | 55 + tests/lm32/test_cmpne.S | 40 + tests/lm32/test_cmpnei.S | 35 + tests/lm32/test_divu.S | 29 + tests/lm32/test_eret.S | 38 + tests/lm32/test_lb.S | 45 + tests/lm32/test_lbu.S | 45 + tests/lm32/test_lh.S | 45 + tests/lm32/test_lhu.S | 45 + tests/lm32/test_lw.S | 30 + tests/lm32/test_modu.S | 35 + tests/lm32/test_mul.S | 70 + tests/lm32/test_muli.S | 45 + tests/lm32/test_nor.S | 51 + tests/lm32/test_nori.S | 35 + tests/lm32/test_or.S | 51 + tests/lm32/test_orhi.S | 35 + tests/lm32/test_ori.S | 35 + tests/lm32/test_ret.S | 14 + tests/lm32/test_sb.S | 30 + tests/lm32/test_scall.S | 20 + tests/lm32/test_sextb.S | 20 + tests/lm32/test_sexth.S | 20 + tests/lm32/test_sh.S | 30 + tests/lm32/test_sl.S | 45 + tests/lm32/test_sli.S | 30 + tests/lm32/test_sr.S | 57 + tests/lm32/test_sri.S | 40 + tests/lm32/test_sru.S | 57 + tests/lm32/test_srui.S | 40 + tests/lm32/test_sub.S | 75 + tests/lm32/test_sw.S | 35 + tests/lm32/test_xnor.S | 51 + tests/lm32/test_xnori.S | 35 + tests/lm32/test_xor.S | 51 + tests/lm32/test_xori.S | 35 + tests/qruncom.c | 8 +- tests/test-i386.c | 14 +- tests/test-mmap.c | 6 +- tests/test_path.c | 2 +- tests/xtensa/Makefile | 75 + tests/xtensa/crt.S | 24 + tests/xtensa/linker.ld | 112 + tests/xtensa/macros.inc | 68 + tests/xtensa/test_b.S | 221 + tests/xtensa/test_bi.S | 103 + tests/xtensa/test_boolean.S | 23 + tests/xtensa/test_bz.S | 57 + tests/xtensa/test_clamps.S | 42 + tests/xtensa/test_fail.S | 9 + tests/xtensa/test_interrupt.S | 194 + tests/xtensa/test_loop.S | 77 + tests/xtensa/test_mac16.S | 243 + tests/xtensa/test_max.S | 81 + tests/xtensa/test_min.S | 81 + tests/xtensa/test_mmu.S | 318 + tests/xtensa/test_mul16.S | 83 + tests/xtensa/test_mul32.S | 20 + tests/xtensa/test_nsa.S | 59 + tests/xtensa/test_pipeline.S | 157 + tests/xtensa/test_quo.S | 147 + tests/xtensa/test_rem.S | 147 + tests/xtensa/test_rst0.S | 148 + tests/xtensa/test_sar.S | 111 + tests/xtensa/test_sext.S | 69 + tests/xtensa/test_shift.S | 206 + tests/xtensa/test_timer.S | 178 + tests/xtensa/test_windowed.S | 302 + tests/xtensa/vectors.S | 39 + tizen/Makefile | 14 + tizen/build.sh | 9 +- tizen/distrib/ffmpeg/bin/avcodec-52.72.2.dll | Bin 0 -> 1850894 bytes tizen/distrib/ffmpeg/bin/avcodec-52.dll | Bin 0 -> 1850894 bytes tizen/distrib/ffmpeg/bin/avcodec-52.lib | Bin 0 -> 149036 bytes tizen/distrib/ffmpeg/bin/avcodec.dll | Bin 0 -> 1850894 bytes tizen/distrib/ffmpeg/bin/avcodec.lib | Bin 0 -> 149036 bytes tizen/distrib/ffmpeg/bin/avdevice-52.2.0.dll | Bin 0 -> 9742 bytes tizen/distrib/ffmpeg/bin/avdevice-52.dll | Bin 0 -> 9742 bytes tizen/distrib/ffmpeg/bin/avdevice-52.lib | Bin 0 -> 2484 bytes tizen/distrib/ffmpeg/bin/avdevice.dll | Bin 0 -> 9742 bytes tizen/distrib/ffmpeg/bin/avdevice.lib | Bin 0 -> 2484 bytes tizen/distrib/ffmpeg/bin/avformat-52.64.2.dll | Bin 0 -> 114702 bytes tizen/distrib/ffmpeg/bin/avformat-52.dll | Bin 0 -> 114702 bytes tizen/distrib/ffmpeg/bin/avformat-52.lib | Bin 0 -> 37272 bytes tizen/distrib/ffmpeg/bin/avformat.dll | Bin 0 -> 114702 bytes tizen/distrib/ffmpeg/bin/avformat.lib | Bin 0 -> 37272 bytes tizen/distrib/ffmpeg/bin/avutil-50.15.1.dll | Bin 0 -> 82958 bytes tizen/distrib/ffmpeg/bin/avutil-50.dll | Bin 0 -> 82958 bytes tizen/distrib/ffmpeg/bin/avutil-50.lib | Bin 0 -> 20238 bytes tizen/distrib/ffmpeg/bin/avutil.dll | Bin 0 -> 82958 bytes tizen/distrib/ffmpeg/bin/avutil.lib | Bin 0 -> 20238 bytes .../distrib/ffmpeg/include/libavutil/pixfmt.h | 3 + tizen/distrib/ffmpeg/lib/libavcodec.a | Bin 9931482 -> 11092452 bytes tizen/distrib/ffmpeg/lib/libavcodec.dll.a | Bin 415906 -> 450490 bytes tizen/distrib/ffmpeg/lib/libavdevice.a | Bin 46974 -> 46978 bytes tizen/distrib/ffmpeg/lib/libavdevice.dll.a | Bin 3464 -> 3464 bytes tizen/distrib/ffmpeg/lib/libavformat.a | Bin 557054 -> 557218 bytes tizen/distrib/ffmpeg/lib/libavformat.dll.a | Bin 109306 -> 109306 bytes tizen/distrib/ffmpeg/lib/libavutil.a | Bin 276800 -> 276996 bytes tizen/distrib/ffmpeg/lib/libavutil.dll.a | Bin 61512 -> 61512 bytes tizen/distrib/ffmpeg/libavutil/pixfmt.h | 3 + tizen/distrib/ffmpeg/tizen_configure | 6 +- tizen/qemu_configure.sh | 42 + tizen/src/Makefile | 68 + tizen/src/Makefile.tizen | 102 + tizen/src/VERSION | 2 +- tizen/src/check_hax.c | 196 + tizen/src/debug_ch.c | 88 +- tizen/src/debug_ch.h | 7 +- tizen/src/emul_state.c | 217 + tizen/src/emul_state.h | 121 + tizen/src/emulator.c | 1404 +--- tizen/src/emulator.h | 92 +- tizen/src/guest_server.c | 201 + tizen/src/guest_server.h | 40 + tizen/src/hw/beginend_funcs.sh | 41 + tizen/src/hw/gl_func_perso.h | 119 + tizen/src/hw/gloffscreen.h | 126 + tizen/src/hw/gloffscreen_common.c | 456 ++ tizen/src/hw/gloffscreen_glx.c | 448 + tizen/src/hw/gloffscreen_test.c | 163 + tizen/src/hw/gloffscreen_wgl.c | 833 ++ tizen/src/hw/gloffscreen_xcomposite.c | 514 ++ tizen/src/hw/helper_opengl.c | 275 + tizen/src/hw/maru_board.c | 337 + tizen/src/hw/maru_brightness.c | 152 + tizen/src/hw/maru_brightness.h | 45 + tizen/src/hw/maru_camera_common.h | 108 + tizen/src/hw/maru_camera_common_pci.c | 249 + tizen/src/hw/maru_camera_linux_pci.c | 667 ++ tizen/src/hw/maru_camera_win32_interface.h | 932 +++ tizen/src/hw/maru_camera_win32_pci.c | 1971 +++++ tizen/src/hw/maru_codec.c | 912 ++- tizen/src/hw/maru_codec.h | 101 +- tizen/src/hw/maru_overlay.c | 197 + tizen/src/hw/maru_overlay.h | 59 + tizen/src/hw/maru_pci_ids.h | 49 + tizen/src/hw/maru_pm.c | 331 +- tizen/src/hw/maru_pm.h | 2 +- tizen/src/hw/maru_touchscreen.c | 181 +- tizen/src/hw/maru_touchscreen.h | 142 + tizen/src/hw/maru_vga.c | 1599 ++++ tizen/src/hw/maru_vga_int.h | 49 + tizen/src/hw/maru_vga_template.h | 531 ++ tizen/src/hw/mesa_gl.h | 2251 +++++ tizen/src/hw/mesa_glext.h | 7279 +++++++++++++++++ tizen/src/hw/mesa_glu.h | 354 + tizen/src/hw/mesa_mipmap.c | 825 ++ tizen/src/hw/mesa_mipmap.h | 24 + tizen/src/hw/op_helper.c | 5881 +++++++++++++ tizen/src/hw/opengl_exec.c | 3353 ++++++++ tizen/src/hw/opengl_exec.h | 34 + tizen/src/hw/opengl_func.h | 600 ++ tizen/src/hw/opengl_process.h | 33 + tizen/src/hw/parse_gl_h.c | 1506 ++++ tizen/src/hw/range_alloc.h | 211 + tizen/src/hw/virtio-gl.c | 226 + tizen/src/maru_common.h | 44 + tizen/src/maru_finger.c | 373 + tizen/src/maru_finger.h | 71 + tizen/src/maru_sdl.c | 365 + tizen/src/maru_sdl.h | 55 + tizen/src/mloop_event.c | 357 + tizen/src/mloop_event.h | 53 + tizen/src/option.c | 938 +-- tizen/src/option.h | 35 +- tizen/src/sdb.c | 369 + tizen/src/sdb.h | 113 + tizen/src/sdl_rotate.c | 1610 ++++ tizen/src/sdl_rotate.h | 99 + tizen/src/sdl_zoom.c | 96 + tizen/src/sdl_zoom.h | 25 + tizen/src/sdl_zoom_template.h | 225 + tizen/src/skin/client/.classpath | 9 + tizen/src/skin/client/.project | 17 + .../org.eclipse.core.resources.prefs | 2 + tizen/src/skin/client/build.xml | 120 + tizen/src/skin/client/dev/.skin.properties | 6 + .../skin/client/dev/.skinconfig.properties | 11 + tizen/src/skin/client/dev/dbi-sample.xml | 180 + .../tizen/emulator/skin/dbi/ColorsType.java | 67 + .../tizen/emulator/skin/dbi/EmulatorUI.java | 97 + .../emulator/skin/dbi/EventInfoType.java | 87 + .../emulator/skin/dbi/ImageListType.java | 95 + .../emulator/skin/dbi/KeyMapListType.java | 74 + .../tizen/emulator/skin/dbi/KeyMapType.java | 123 + .../org/tizen/emulator/skin/dbi/LcdType.java | 89 + .../emulator/skin/dbi/ObjectFactory.java | 127 + .../tizen/emulator/skin/dbi/RegionType.java | 146 + .../org/tizen/emulator/skin/dbi/RgbType.java | 123 + .../emulator/skin/dbi/RotationNameType.java | 64 + .../tizen/emulator/skin/dbi/RotationType.java | 153 + .../emulator/skin/dbi/RotationsType.java | 76 + .../tizen/emulator/skin/dbi/package-info.java | 9 + .../skin/client/lib/swt/cocoa-macosx/src.zip | Bin 0 -> 1831294 bytes .../client/lib/swt/cocoa-macosx/swt-debug.jar | Bin 0 -> 2278960 bytes .../skin/client/lib/swt/cocoa-macosx/swt.jar | Bin 0 -> 1694512 bytes .../src/skin/client/lib/swt/gtk-linux/src.zip | Bin 0 -> 1958746 bytes .../client/lib/swt/gtk-linux/swt-debug.jar | Bin 0 -> 2153399 bytes .../src/skin/client/lib/swt/gtk-linux/swt.jar | Bin 0 -> 1542398 bytes .../skin/client/lib/swt/win32-win32/src.zip | Bin 0 -> 2346270 bytes .../client/lib/swt/win32-win32/swt-debug.jar | Bin 0 -> 2588469 bytes .../skin/client/lib/swt/win32-win32/swt.jar | Bin 0 -> 1891572 bytes .../skin/client/resource/icons/Emulator.ico | Bin 0 -> 4286 bytes .../client/resource/icons/Emulator_20x20.png | Bin 0 -> 3633 bytes .../src/skin/client/resource/icons/about.png | Bin 0 -> 3600 bytes .../skin/client/resource/icons/advanced.png | Bin 0 -> 3527 bytes .../src/skin/client/resource/icons/close.png | Bin 0 -> 3604 bytes .../resource/icons/copy_screenshot_dialog.png | Bin 0 -> 3267 bytes .../client/resource/icons/detail_info.png | Bin 0 -> 3426 bytes .../icons/refresh_screenshot_dialog.png | Bin 0 -> 3917 bytes .../src/skin/client/resource/icons/rotate.png | Bin 0 -> 3581 bytes .../resource/icons/save_screenshot_dialog.png | Bin 0 -> 3272 bytes .../src/skin/client/resource/icons/scale.png | Bin 0 -> 3581 bytes .../skin/client/resource/icons/screenshot.png | Bin 0 -> 3434 bytes .../src/skin/client/resource/icons/shell.png | Bin 0 -> 3501 bytes .../client/resource/icons/usb_keyboard.png | Bin 0 -> 3436 bytes .../client/skins/emul_320x480/default.dbi | 180 + .../client/skins/emul_320x480/default_0.png | Bin 0 -> 31843 bytes .../client/skins/emul_320x480/default_0_p.png | Bin 0 -> 33038 bytes .../client/skins/emul_320x480/default_180.png | Bin 0 -> 31522 bytes .../skins/emul_320x480/default_180_p.png | Bin 0 -> 33097 bytes .../client/skins/emul_320x480/default_L90.png | Bin 0 -> 28944 bytes .../skins/emul_320x480/default_L90_p.png | Bin 0 -> 30381 bytes .../client/skins/emul_320x480/default_R90.png | Bin 0 -> 28181 bytes .../skins/emul_320x480/default_R90_p.png | Bin 0 -> 30057 bytes .../skins/emul_3keys_320x480/default.dbi | 244 + .../skins/emul_3keys_320x480/default_0.png | Bin 0 -> 32138 bytes .../skins/emul_3keys_320x480/default_0_p.png | Bin 0 -> 34903 bytes .../skins/emul_3keys_320x480/default_180.png | Bin 0 -> 32171 bytes .../emul_3keys_320x480/default_180_p.png | Bin 0 -> 35737 bytes .../skins/emul_3keys_320x480/default_L90.png | Bin 0 -> 29494 bytes .../emul_3keys_320x480/default_L90_p.png | Bin 0 -> 33242 bytes .../skins/emul_3keys_320x480/default_R90.png | Bin 0 -> 28735 bytes .../emul_3keys_320x480/default_R90_p.png | Bin 0 -> 32847 bytes .../skins/emul_3keys_480x800/default.dbi | 244 + .../skins/emul_3keys_480x800/default_0.png | Bin 0 -> 52823 bytes .../skins/emul_3keys_480x800/default_0_p.png | Bin 0 -> 56938 bytes .../skins/emul_3keys_480x800/default_180.png | Bin 0 -> 52622 bytes .../emul_3keys_480x800/default_180_p.png | Bin 0 -> 58106 bytes .../skins/emul_3keys_480x800/default_L90.png | Bin 0 -> 48670 bytes .../emul_3keys_480x800/default_L90_p.png | Bin 0 -> 54051 bytes .../skins/emul_3keys_480x800/default_R90.png | Bin 0 -> 47478 bytes .../emul_3keys_480x800/default_R90_p.png | Bin 0 -> 53533 bytes .../skins/emul_3keys_600x1024/default.dbi | 244 + .../skins/emul_3keys_600x1024/default_0.png | Bin 0 -> 68771 bytes .../skins/emul_3keys_600x1024/default_0_p.png | Bin 0 -> 73990 bytes .../skins/emul_3keys_600x1024/default_180.png | Bin 0 -> 68427 bytes .../emul_3keys_600x1024/default_180_p.png | Bin 0 -> 75535 bytes .../skins/emul_3keys_600x1024/default_L90.png | Bin 0 -> 65387 bytes .../emul_3keys_600x1024/default_L90_p.png | Bin 0 -> 72788 bytes .../skins/emul_3keys_600x1024/default_R90.png | Bin 0 -> 64770 bytes .../emul_3keys_600x1024/default_R90_p.png | Bin 0 -> 73135 bytes .../skins/emul_3keys_720x1280/default.dbi | 244 + .../skins/emul_3keys_720x1280/default_0.png | Bin 0 -> 83969 bytes .../skins/emul_3keys_720x1280/default_0_p.png | Bin 0 -> 90796 bytes .../skins/emul_3keys_720x1280/default_180.png | Bin 0 -> 84060 bytes .../emul_3keys_720x1280/default_180_p.png | Bin 0 -> 93522 bytes .../skins/emul_3keys_720x1280/default_L90.png | Bin 0 -> 80087 bytes .../emul_3keys_720x1280/default_L90_p.png | Bin 0 -> 89604 bytes .../skins/emul_3keys_720x1280/default_R90.png | Bin 0 -> 79535 bytes .../emul_3keys_720x1280/default_R90_p.png | Bin 0 -> 89976 bytes .../client/skins/emul_480x800/default.dbi | 180 + .../client/skins/emul_480x800/default_0.png | Bin 0 -> 52469 bytes .../client/skins/emul_480x800/default_0_p.png | Bin 0 -> 54897 bytes .../client/skins/emul_480x800/default_180.png | Bin 0 -> 52169 bytes .../skins/emul_480x800/default_180_p.png | Bin 0 -> 55315 bytes .../client/skins/emul_480x800/default_L90.png | Bin 0 -> 47991 bytes .../skins/emul_480x800/default_L90_p.png | Bin 0 -> 50686 bytes .../client/skins/emul_480x800/default_R90.png | Bin 0 -> 46793 bytes .../skins/emul_480x800/default_R90_p.png | Bin 0 -> 50292 bytes .../client/skins/emul_600x1024/default.dbi | 180 + .../client/skins/emul_600x1024/default_0.png | Bin 0 -> 68407 bytes .../skins/emul_600x1024/default_0_p.png | Bin 0 -> 71074 bytes .../skins/emul_600x1024/default_180.png | Bin 0 -> 67941 bytes .../skins/emul_600x1024/default_180_p.png | Bin 0 -> 71523 bytes .../skins/emul_600x1024/default_L90.png | Bin 0 -> 64865 bytes .../skins/emul_600x1024/default_L90_p.png | Bin 0 -> 67889 bytes .../skins/emul_600x1024/default_R90.png | Bin 0 -> 64040 bytes .../skins/emul_600x1024/default_R90_p.png | Bin 0 -> 68103 bytes .../client/skins/emul_720x1280/default.dbi | 180 + .../client/skins/emul_720x1280/default_0.png | Bin 0 -> 83440 bytes .../skins/emul_720x1280/default_0_p.png | Bin 0 -> 86865 bytes .../skins/emul_720x1280/default_180.png | Bin 0 -> 83287 bytes .../skins/emul_720x1280/default_180_p.png | Bin 0 -> 88195 bytes .../skins/emul_720x1280/default_L90.png | Bin 0 -> 79088 bytes .../skins/emul_720x1280/default_L90_p.png | Bin 0 -> 82776 bytes .../skins/emul_720x1280/default_R90.png | Bin 0 -> 78391 bytes .../skins/emul_720x1280/default_R90_p.png | Bin 0 -> 83262 bytes .../emulator/skin/EmulatorShutdownhook.java | 56 + .../org/tizen/emulator/skin/EmulatorSkin.java | 1626 ++++ .../tizen/emulator/skin/EmulatorSkinMain.java | 359 + .../emulator/skin/comm/ICommunicator.java | 244 + .../skin/comm/sock/SocketCommunicator.java | 602 ++ .../skin/comm/sock/data/AbstractSendData.java | 78 + .../skin/comm/sock/data/BooleanData.java | 71 + .../skin/comm/sock/data/ISendData.java | 42 + .../skin/comm/sock/data/KeyEventData.java | 70 + .../skin/comm/sock/data/LcdStateData.java | 65 + .../skin/comm/sock/data/MouseEventData.java | 75 + .../skin/comm/sock/data/StartData.java | 77 + .../emulator/skin/config/EmulatorConfig.java | 417 + .../emulator/skin/dialog/AboutDialog.java | 194 + .../skin/dialog/DetailInfoDialog.java | 339 + .../emulator/skin/dialog/LicenseDialog.java | 138 + .../emulator/skin/dialog/SkinDialog.java | 177 + .../skin/exception/ConfigException.java | 56 + .../skin/exception/EmulatorException.java | 56 + .../skin/exception/JaxbException.java | 56 + .../skin/exception/ScreenShotException.java | 56 + .../emulator/skin/image/ImageRegistry.java | 311 + .../tizen/emulator/skin/log/SkinLogger.java | 257 + .../skin/screenshot/ScreenShotDialog.java | 551 ++ .../org/tizen/emulator/skin/util/IOUtil.java | 80 + .../tizen/emulator/skin/util/JaxbUtil.java | 112 + .../tizen/emulator/skin/util/SkinRegion.java | 49 + .../emulator/skin/util/SkinRotation.java | 93 + .../tizen/emulator/skin/util/SkinUtil.java | 357 + .../tizen/emulator/skin/util/StringUtil.java | 48 + tizen/src/skin/client/xsd/dbi.xsd | 92 + tizen/src/skin/maruskin_client.c | 215 + tizen/src/skin/maruskin_client.h | 35 + tizen/src/skin/maruskin_keymap.c | 273 + tizen/src/skin/maruskin_keymap.h | 235 + tizen/src/skin/maruskin_operation.c | 438 + tizen/src/skin/maruskin_operation.h | 77 + tizen/src/skin/maruskin_server.c | 1104 +++ tizen/src/skin/maruskin_server.h | 39 + trace-events | 723 +- trace/control.c | 42 + trace/control.h | 41 + trace/default.c | 41 + trace/simple.c | 395 + trace/simple.h | 38 + trace/stderr.c | 52 + trace/stderr.h | 11 + translate-all.c | 8 +- ui/cocoa.m | 33 +- ui/curses.c | 3 +- ui/keymaps.c | 16 +- ui/qemu-spice.h | 28 +- ui/sdl.c | 708 +- ui/sdl_keysym.h | 4 - ui/spice-core.c | 316 +- ui/spice-display.c | 171 +- ui/spice-display.h | 56 +- ui/spice-input.c | 8 +- ui/vnc-auth-sasl.c | 44 +- ui/vnc-auth-vencrypt.c | 18 +- ui/vnc-enc-hextile.c | 8 +- ui/vnc-enc-tight.c | 101 +- ui/vnc-enc-zlib.c | 4 +- ui/vnc-enc-zrle-template.c | 263 + ui/vnc-enc-zrle.c | 366 + ui/vnc-enc-zrle.h | 40 + ui/vnc-enc-zywrle-template.c | 170 + ui/vnc-enc-zywrle.h | 659 ++ ui/vnc-jobs-async.c | 22 +- ui/vnc-palette.c | 62 +- ui/vnc-palette.h | 7 +- ui/vnc-tls.c | 90 +- ui/vnc.c | 554 +- ui/vnc.h | 64 +- ui/vnc_keysym.h | 18 + usb-bsd.c | 22 +- usb-linux.c | 1374 ++-- usb-redir.c | 1252 +++ user-exec.c | 631 ++ vl.c | 1337 ++- x86_64.ld | 14 +- xen-all.c | 981 +++ xen-mapcache.c | 387 + xen-mapcache.h | 51 + xen-stub.c | 45 + xtensa-semi.c | 224 + 1533 files changed, 221385 insertions(+), 54172 deletions(-) mode change 100644 => 100755 Makefile.target mode change 100644 => 100755 QMP/qmp-shell create mode 100644 bitmap.c create mode 100644 bitmap.h create mode 100644 bitops.c create mode 100644 bitops.h create mode 100644 block/iscsi.c create mode 100644 compiler.h create mode 100644 coroutine-gthread.c create mode 100644 coroutine-ucontext.c create mode 100644 coroutine-win32.c create mode 100644 default-configs/alpha-softmmu.mak create mode 100644 default-configs/lm32-softmmu.mak create mode 100644 default-configs/microblazeel-linux-user.mak create mode 100644 default-configs/microblazeel-softmmu.mak create mode 100644 default-configs/s390x-linux-user.mak create mode 100644 default-configs/unicore32-linux-user.mak create mode 100644 default-configs/xtensa-softmmu.mak create mode 100644 default-configs/xtensaeb-softmmu.mak create mode 100644 docs/ccid.txt create mode 100644 docs/ich9-ehci-uhci.cfg create mode 100644 docs/libcacard.txt create mode 100644 docs/memory.txt create mode 100644 docs/qapi-code-gen.txt create mode 100644 docs/specs/qcow2.txt create mode 100644 docs/usb2.txt create mode 100644 error.c create mode 100644 error.h create mode 100644 error_int.h create mode 100644 event_notifier.c create mode 100644 event_notifier.h create mode 100644 exec-memory.h create mode 100644 fsdev/file-op-9p.h create mode 100644 fsdev/qemu-fsdev-dummy.c create mode 100644 hax.h create mode 100644 hmp.c create mode 100644 hmp.h create mode 100644 hw/9pfs/codir.c create mode 100644 hw/9pfs/cofile.c create mode 100644 hw/9pfs/cofs.c create mode 100644 hw/9pfs/coxattr.c create mode 100644 hw/9pfs/virtio-9p-coth.c create mode 100644 hw/9pfs/virtio-9p-coth.h create mode 100644 hw/9pfs/virtio-9p-device.c create mode 100644 hw/9pfs/virtio-9p-handle.c create mode 100644 hw/9pfs/virtio-9p-local.c create mode 100644 hw/9pfs/virtio-9p-posix-acl.c create mode 100644 hw/9pfs/virtio-9p-synth.c create mode 100644 hw/9pfs/virtio-9p-synth.h create mode 100644 hw/9pfs/virtio-9p-xattr-user.c create mode 100644 hw/9pfs/virtio-9p-xattr.c create mode 100644 hw/9pfs/virtio-9p-xattr.h create mode 100644 hw/9pfs/virtio-9p.c create mode 100644 hw/9pfs/virtio-9p.h create mode 100644 hw/adb.h create mode 100644 hw/alpha_dp264.c create mode 100644 hw/alpha_pci.c create mode 100644 hw/alpha_sys.h create mode 100644 hw/alpha_typhoon.c create mode 100644 hw/ccid-card-emulated.c create mode 100644 hw/ccid-card-passthru.c create mode 100644 hw/ccid.h create mode 100644 hw/collie.c create mode 100644 hw/hid.c create mode 100644 hw/hid.h create mode 100644 hw/ide/atapi.c create mode 100644 hw/kvmclock.c create mode 100644 hw/kvmclock.h create mode 100644 hw/lm32.h create mode 100644 hw/lm32_boards.c create mode 100644 hw/lm32_hwsetup.h create mode 100644 hw/lm32_juart.c create mode 100644 hw/lm32_juart.h create mode 100644 hw/lm32_pic.c create mode 100644 hw/lm32_pic.h create mode 100644 hw/lm32_sys.c create mode 100644 hw/lm32_timer.c create mode 100644 hw/lm32_uart.c create mode 100644 hw/lm4549.c create mode 100644 hw/lm4549.h create mode 100644 hw/microblaze_pic_cpu.h create mode 100644 hw/milkymist-ac97.c create mode 100644 hw/milkymist-hpdmc.c create mode 100644 hw/milkymist-hw.h create mode 100644 hw/milkymist-memcard.c create mode 100644 hw/milkymist-minimac2.c create mode 100644 hw/milkymist-pfpu.c create mode 100644 hw/milkymist-softusb.c create mode 100644 hw/milkymist-sysctl.c create mode 100644 hw/milkymist-tmu2.c create mode 100644 hw/milkymist-uart.c create mode 100644 hw/milkymist-vgafb.c create mode 100644 hw/milkymist-vgafb_template.h create mode 100644 hw/milkymist.c create mode 100644 hw/mpc8544_guts.c create mode 100644 hw/opencores_eth.c mode change 100755 => 100644 hw/pc.h create mode 100644 hw/petalogix_ml605_mmu.c create mode 100644 hw/pl041.c create mode 100644 hw/pl041.h create mode 100644 hw/pl041.hx create mode 100644 hw/ppc-viosrp.h create mode 100644 hw/ppc_booke.c create mode 100644 hw/ppce500_spin.c create mode 100644 hw/sga.c create mode 100644 hw/spapr.c create mode 100644 hw/spapr.h create mode 100644 hw/spapr_hcall.c create mode 100644 hw/spapr_llan.c create mode 100644 hw/spapr_pci.c create mode 100644 hw/spapr_pci.h create mode 100644 hw/spapr_rtas.c create mode 100644 hw/spapr_vio.c create mode 100644 hw/spapr_vio.h create mode 100644 hw/spapr_vscsi.c create mode 100644 hw/spapr_vty.c create mode 100644 hw/srp.h create mode 100644 hw/strongarm.c create mode 100644 hw/strongarm.h create mode 100644 hw/usb-ccid.c create mode 100644 hw/usb-libhw.c create mode 100644 hw/vexpress.c mode change 100755 => 100644 hw/vga.c create mode 100644 hw/virtio-pci.h create mode 100644 hw/xen_platform.c create mode 100644 hw/xics.c create mode 100644 hw/xics.h create mode 100644 hw/xilinx_axidma.c create mode 100644 hw/xilinx_axidma.h create mode 100644 hw/xilinx_axienet.c create mode 100644 hw/xtensa_bootparam.h create mode 100644 hw/xtensa_lx60.c create mode 100644 hw/xtensa_pic.c create mode 100644 hw/xtensa_sim.c create mode 100644 hw/z2.c create mode 100644 int128.h create mode 100644 iohandler.c create mode 100644 libcacard/Makefile create mode 100644 libcacard/cac.c create mode 100644 libcacard/cac.h create mode 100644 libcacard/card_7816.c create mode 100644 libcacard/card_7816.h create mode 100644 libcacard/card_7816t.h create mode 100644 libcacard/event.c create mode 100644 libcacard/eventt.h create mode 100644 libcacard/libcacard.pc.in create mode 100644 libcacard/link_test.c create mode 100644 libcacard/vcard.c create mode 100644 libcacard/vcard.h create mode 100644 libcacard/vcard_emul.h create mode 100644 libcacard/vcard_emul_nss.c create mode 100644 libcacard/vcard_emul_type.c create mode 100644 libcacard/vcard_emul_type.h create mode 100644 libcacard/vcardt.h create mode 100644 libcacard/vevent.h create mode 100644 libcacard/vreader.c create mode 100644 libcacard/vreader.h create mode 100644 libcacard/vreadert.h create mode 100644 libcacard/vscard_common.h create mode 100644 libcacard/vscclient.c create mode 100644 linux-headers/COPYING create mode 100644 linux-headers/README create mode 100644 linux-headers/asm-powerpc/kvm.h create mode 100644 linux-headers/asm-powerpc/kvm_para.h create mode 100644 linux-headers/asm-s390/kvm.h create mode 100644 linux-headers/asm-s390/kvm_para.h create mode 100644 linux-headers/asm-x86/hyperv.h create mode 100644 linux-headers/asm-x86/kvm.h create mode 100644 linux-headers/asm-x86/kvm_para.h create mode 100644 linux-headers/linux/kvm.h create mode 100644 linux-headers/linux/kvm_para.h create mode 100644 linux-headers/linux/vhost.h create mode 100644 linux-headers/linux/virtio_config.h create mode 100644 linux-headers/linux/virtio_ring.h create mode 100644 linux-user/s390x/syscall.h create mode 100644 linux-user/s390x/syscall_nr.h create mode 100644 linux-user/s390x/target_signal.h create mode 100644 linux-user/s390x/termbits.h create mode 100644 linux-user/target_flat.h create mode 100644 linux-user/unicore32/syscall.h create mode 100644 linux-user/unicore32/syscall_nr.h create mode 100644 linux-user/unicore32/target_signal.h create mode 100644 linux-user/unicore32/termbits.h create mode 100644 main-loop.c create mode 100644 main-loop.h create mode 100644 memory.c create mode 100644 memory.h create mode 100644 new_emulator_project mode change 100755 => 100644 pc-bios/linuxboot.bin create mode 100755 pc-bios/palcode-clipper create mode 100644 pc-bios/petalogix-ml605.dtb create mode 100644 pc-bios/pxe-e1000.rom create mode 100644 pc-bios/pxe-eepro100.rom create mode 100644 pc-bios/pxe-ne2k_pci.rom create mode 100644 pc-bios/pxe-pcnet.rom create mode 100644 pc-bios/pxe-rtl8139.rom create mode 100644 pc-bios/pxe-virtio.rom create mode 100755 pc-bios/sgabios.bin create mode 100644 pc-bios/slof.bin create mode 100644 pc-bios/spapr-rtas.bin create mode 100644 pc-bios/spapr-rtas/Makefile create mode 100644 pc-bios/spapr-rtas/spapr-rtas.S create mode 100644 pc-bios/vgabios-maruvga.bin create mode 100644 qapi-schema-guest.json create mode 100644 qapi-schema-test.json create mode 100644 qapi-schema.json create mode 100644 qapi/qapi-dealloc-visitor.c create mode 100644 qapi/qapi-dealloc-visitor.h create mode 100644 qapi/qapi-types-core.h create mode 100644 qapi/qapi-visit-core.c create mode 100644 qapi/qapi-visit-core.h create mode 100644 qapi/qmp-core.h create mode 100644 qapi/qmp-dispatch.c create mode 100644 qapi/qmp-input-visitor.c create mode 100644 qapi/qmp-input-visitor.h create mode 100644 qapi/qmp-output-visitor.c create mode 100644 qapi/qmp-output-visitor.h create mode 100644 qapi/qmp-registry.c create mode 100644 qemu-coroutine-int.h create mode 100644 qemu-coroutine-lock.c create mode 100644 qemu-coroutine.c create mode 100644 qemu-coroutine.h create mode 100644 qemu-ga.c create mode 100644 qemu-progress.c create mode 100644 qemu-thread-posix.c create mode 100644 qemu-thread-posix.h create mode 100644 qemu-thread-win32.c create mode 100644 qemu-thread-win32.h create mode 100644 qemu-tls.h create mode 100644 qemu-xattr.h create mode 100644 qga/guest-agent-command-state.c create mode 100644 qga/guest-agent-commands.c create mode 100644 qga/guest-agent-core.h create mode 100644 qmp.c create mode 100755 scripts/analyse-9p-simpletrace.py mode change 100644 => 100755 scripts/checkpatch.pl mode change 100644 => 100755 scripts/create_config create mode 100755 scripts/get_maintainer.pl create mode 100755 scripts/kvm/kvm_stat create mode 100755 scripts/kvm/vmxcap create mode 100644 scripts/ordereddict.py create mode 100644 scripts/qapi-commands.py create mode 100644 scripts/qapi-types.py create mode 100644 scripts/qapi-visit.py create mode 100644 scripts/qapi.py create mode 100755 scripts/refresh-pxe-roms.sh mode change 100644 => 100755 scripts/signrom.sh mode change 100644 => 100755 scripts/simpletrace.py mode change 100644 => 100755 scripts/texi2pod.pl mode change 100644 => 100755 scripts/tracetool create mode 100755 scripts/update-linux-headers.sh create mode 100644 slirp/arp_table.c create mode 100644 target-alpha/machine.c create mode 100644 target-arm/helper.h create mode 100644 target-i386/hax-all.c create mode 100644 target-i386/hax-i386.h create mode 100644 target-i386/hax-interface.h create mode 100644 target-i386/hax-windows.c create mode 100644 target-i386/hax-windows.h create mode 100644 target-lm32/README create mode 100644 target-lm32/TODO create mode 100644 target-lm32/cpu.h create mode 100644 target-lm32/helper.c create mode 100644 target-lm32/helper.h create mode 100644 target-lm32/machine.c create mode 100644 target-lm32/op_helper.c create mode 100644 target-lm32/translate.c create mode 100644 target-s390x/helpers.h create mode 100644 target-sparc/cc_helper.c create mode 100644 target-sparc/cpu_init.c create mode 100644 target-sparc/fop_helper.c create mode 100644 target-sparc/int32_helper.c create mode 100644 target-sparc/int64_helper.c create mode 100644 target-sparc/ldst_helper.c create mode 100644 target-sparc/mmu_helper.c create mode 100644 target-sparc/vis_helper.c create mode 100644 target-sparc/win_helper.c create mode 100644 target-unicore32/cpu.h create mode 100644 target-unicore32/helper.c create mode 100644 target-unicore32/helper.h create mode 100644 target-unicore32/op_helper.c create mode 100644 target-unicore32/translate.c create mode 100644 target-xtensa/core-dc232b.c create mode 100644 target-xtensa/core-dc232b/core-isa.h create mode 100644 target-xtensa/core-dc232b/gdb-config.c create mode 100644 target-xtensa/core-fsf.c create mode 100644 target-xtensa/core-fsf/core-isa.h create mode 100644 target-xtensa/cpu.h create mode 100644 target-xtensa/helper.c create mode 100644 target-xtensa/helpers.h create mode 100644 target-xtensa/machine.c create mode 100644 target-xtensa/op_helper.c create mode 100644 target-xtensa/overlay_tool.h create mode 100644 target-xtensa/translate.c create mode 100644 tcg/tci/README create mode 100644 tcg/tci/tcg-target.c create mode 100644 tcg/tci/tcg-target.h create mode 100644 tci-dis.c create mode 100644 tci.c create mode 100644 test-coroutine.c create mode 100644 test-qmp-commands.c create mode 100644 test-visitor.c create mode 100644 tests/cris/.gdbinit create mode 100644 tests/lm32/Makefile create mode 100644 tests/lm32/crt.S create mode 100644 tests/lm32/linker.ld create mode 100644 tests/lm32/macros.inc create mode 100644 tests/lm32/test_add.S create mode 100644 tests/lm32/test_addi.S create mode 100644 tests/lm32/test_and.S create mode 100644 tests/lm32/test_andhi.S create mode 100644 tests/lm32/test_andi.S create mode 100644 tests/lm32/test_b.S create mode 100644 tests/lm32/test_be.S create mode 100644 tests/lm32/test_bg.S create mode 100644 tests/lm32/test_bge.S create mode 100644 tests/lm32/test_bgeu.S create mode 100644 tests/lm32/test_bgu.S create mode 100644 tests/lm32/test_bi.S create mode 100644 tests/lm32/test_bne.S create mode 100644 tests/lm32/test_break.S create mode 100644 tests/lm32/test_bret.S create mode 100644 tests/lm32/test_call.S create mode 100644 tests/lm32/test_calli.S create mode 100644 tests/lm32/test_cmpe.S create mode 100644 tests/lm32/test_cmpei.S create mode 100644 tests/lm32/test_cmpg.S create mode 100644 tests/lm32/test_cmpge.S create mode 100644 tests/lm32/test_cmpgei.S create mode 100644 tests/lm32/test_cmpgeu.S create mode 100644 tests/lm32/test_cmpgeui.S create mode 100644 tests/lm32/test_cmpgi.S create mode 100644 tests/lm32/test_cmpgu.S create mode 100644 tests/lm32/test_cmpgui.S create mode 100644 tests/lm32/test_cmpne.S create mode 100644 tests/lm32/test_cmpnei.S create mode 100644 tests/lm32/test_divu.S create mode 100644 tests/lm32/test_eret.S create mode 100644 tests/lm32/test_lb.S create mode 100644 tests/lm32/test_lbu.S create mode 100644 tests/lm32/test_lh.S create mode 100644 tests/lm32/test_lhu.S create mode 100644 tests/lm32/test_lw.S create mode 100644 tests/lm32/test_modu.S create mode 100644 tests/lm32/test_mul.S create mode 100644 tests/lm32/test_muli.S create mode 100644 tests/lm32/test_nor.S create mode 100644 tests/lm32/test_nori.S create mode 100644 tests/lm32/test_or.S create mode 100644 tests/lm32/test_orhi.S create mode 100644 tests/lm32/test_ori.S create mode 100644 tests/lm32/test_ret.S create mode 100644 tests/lm32/test_sb.S create mode 100644 tests/lm32/test_scall.S create mode 100644 tests/lm32/test_sextb.S create mode 100644 tests/lm32/test_sexth.S create mode 100644 tests/lm32/test_sh.S create mode 100644 tests/lm32/test_sl.S create mode 100644 tests/lm32/test_sli.S create mode 100644 tests/lm32/test_sr.S create mode 100644 tests/lm32/test_sri.S create mode 100644 tests/lm32/test_sru.S create mode 100644 tests/lm32/test_srui.S create mode 100644 tests/lm32/test_sub.S create mode 100644 tests/lm32/test_sw.S create mode 100644 tests/lm32/test_xnor.S create mode 100644 tests/lm32/test_xnori.S create mode 100644 tests/lm32/test_xor.S create mode 100644 tests/lm32/test_xori.S create mode 100644 tests/xtensa/Makefile create mode 100644 tests/xtensa/crt.S create mode 100644 tests/xtensa/linker.ld create mode 100644 tests/xtensa/macros.inc create mode 100644 tests/xtensa/test_b.S create mode 100644 tests/xtensa/test_bi.S create mode 100644 tests/xtensa/test_boolean.S create mode 100644 tests/xtensa/test_bz.S create mode 100644 tests/xtensa/test_clamps.S create mode 100644 tests/xtensa/test_fail.S create mode 100644 tests/xtensa/test_interrupt.S create mode 100644 tests/xtensa/test_loop.S create mode 100644 tests/xtensa/test_mac16.S create mode 100644 tests/xtensa/test_max.S create mode 100644 tests/xtensa/test_min.S create mode 100644 tests/xtensa/test_mmu.S create mode 100644 tests/xtensa/test_mul16.S create mode 100644 tests/xtensa/test_mul32.S create mode 100644 tests/xtensa/test_nsa.S create mode 100644 tests/xtensa/test_pipeline.S create mode 100644 tests/xtensa/test_quo.S create mode 100644 tests/xtensa/test_rem.S create mode 100644 tests/xtensa/test_rst0.S create mode 100644 tests/xtensa/test_sar.S create mode 100644 tests/xtensa/test_sext.S create mode 100644 tests/xtensa/test_shift.S create mode 100644 tests/xtensa/test_timer.S create mode 100644 tests/xtensa/test_windowed.S create mode 100644 tests/xtensa/vectors.S create mode 100644 tizen/Makefile create mode 100755 tizen/distrib/ffmpeg/bin/avcodec-52.72.2.dll create mode 100755 tizen/distrib/ffmpeg/bin/avcodec-52.dll create mode 100644 tizen/distrib/ffmpeg/bin/avcodec-52.lib create mode 100755 tizen/distrib/ffmpeg/bin/avcodec.dll create mode 100644 tizen/distrib/ffmpeg/bin/avcodec.lib create mode 100755 tizen/distrib/ffmpeg/bin/avdevice-52.2.0.dll create mode 100755 tizen/distrib/ffmpeg/bin/avdevice-52.dll create mode 100644 tizen/distrib/ffmpeg/bin/avdevice-52.lib create mode 100755 tizen/distrib/ffmpeg/bin/avdevice.dll create mode 100644 tizen/distrib/ffmpeg/bin/avdevice.lib create mode 100755 tizen/distrib/ffmpeg/bin/avformat-52.64.2.dll create mode 100755 tizen/distrib/ffmpeg/bin/avformat-52.dll create mode 100644 tizen/distrib/ffmpeg/bin/avformat-52.lib create mode 100755 tizen/distrib/ffmpeg/bin/avformat.dll create mode 100644 tizen/distrib/ffmpeg/bin/avformat.lib create mode 100755 tizen/distrib/ffmpeg/bin/avutil-50.15.1.dll create mode 100755 tizen/distrib/ffmpeg/bin/avutil-50.dll create mode 100644 tizen/distrib/ffmpeg/bin/avutil-50.lib create mode 100755 tizen/distrib/ffmpeg/bin/avutil.dll create mode 100644 tizen/distrib/ffmpeg/bin/avutil.lib create mode 100755 tizen/qemu_configure.sh create mode 100755 tizen/src/Makefile create mode 100755 tizen/src/Makefile.tizen create mode 100644 tizen/src/check_hax.c create mode 100644 tizen/src/emul_state.c create mode 100644 tizen/src/emul_state.h create mode 100644 tizen/src/guest_server.c create mode 100644 tizen/src/guest_server.h create mode 100755 tizen/src/hw/beginend_funcs.sh create mode 100755 tizen/src/hw/gl_func_perso.h create mode 100755 tizen/src/hw/gloffscreen.h create mode 100755 tizen/src/hw/gloffscreen_common.c create mode 100755 tizen/src/hw/gloffscreen_glx.c create mode 100755 tizen/src/hw/gloffscreen_test.c create mode 100755 tizen/src/hw/gloffscreen_wgl.c create mode 100755 tizen/src/hw/gloffscreen_xcomposite.c create mode 100755 tizen/src/hw/helper_opengl.c create mode 100644 tizen/src/hw/maru_board.c create mode 100644 tizen/src/hw/maru_brightness.c create mode 100644 tizen/src/hw/maru_brightness.h create mode 100644 tizen/src/hw/maru_camera_common.h create mode 100644 tizen/src/hw/maru_camera_common_pci.c create mode 100644 tizen/src/hw/maru_camera_linux_pci.c create mode 100644 tizen/src/hw/maru_camera_win32_interface.h create mode 100644 tizen/src/hw/maru_camera_win32_pci.c create mode 100644 tizen/src/hw/maru_overlay.c create mode 100644 tizen/src/hw/maru_overlay.h create mode 100644 tizen/src/hw/maru_pci_ids.h create mode 100644 tizen/src/hw/maru_touchscreen.h create mode 100644 tizen/src/hw/maru_vga.c create mode 100644 tizen/src/hw/maru_vga_int.h create mode 100644 tizen/src/hw/maru_vga_template.h create mode 100755 tizen/src/hw/mesa_gl.h create mode 100755 tizen/src/hw/mesa_glext.h create mode 100755 tizen/src/hw/mesa_glu.h create mode 100755 tizen/src/hw/mesa_mipmap.c create mode 100755 tizen/src/hw/mesa_mipmap.h create mode 100755 tizen/src/hw/op_helper.c create mode 100755 tizen/src/hw/opengl_exec.c create mode 100755 tizen/src/hw/opengl_exec.h create mode 100755 tizen/src/hw/opengl_func.h create mode 100755 tizen/src/hw/opengl_process.h create mode 100755 tizen/src/hw/parse_gl_h.c create mode 100755 tizen/src/hw/range_alloc.h create mode 100755 tizen/src/hw/virtio-gl.c create mode 100644 tizen/src/maru_common.h create mode 100644 tizen/src/maru_finger.c create mode 100644 tizen/src/maru_finger.h create mode 100644 tizen/src/maru_sdl.c create mode 100644 tizen/src/maru_sdl.h create mode 100644 tizen/src/mloop_event.c create mode 100644 tizen/src/mloop_event.h create mode 100644 tizen/src/sdb.c create mode 100644 tizen/src/sdb.h create mode 100644 tizen/src/sdl_rotate.c create mode 100644 tizen/src/sdl_rotate.h create mode 100644 tizen/src/sdl_zoom.c create mode 100644 tizen/src/sdl_zoom.h create mode 100644 tizen/src/sdl_zoom_template.h create mode 100644 tizen/src/skin/client/.classpath create mode 100644 tizen/src/skin/client/.project create mode 100644 tizen/src/skin/client/.settings/org.eclipse.core.resources.prefs create mode 100644 tizen/src/skin/client/build.xml create mode 100644 tizen/src/skin/client/dev/.skin.properties create mode 100644 tizen/src/skin/client/dev/.skinconfig.properties create mode 100644 tizen/src/skin/client/dev/dbi-sample.xml create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ColorsType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/EmulatorUI.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/EventInfoType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ImageListType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/KeyMapListType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/KeyMapType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/LcdType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/ObjectFactory.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RegionType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RgbType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationNameType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/RotationsType.java create mode 100644 tizen/src/skin/client/jaxb_src/org/tizen/emulator/skin/dbi/package-info.java create mode 100644 tizen/src/skin/client/lib/swt/cocoa-macosx/src.zip create mode 100644 tizen/src/skin/client/lib/swt/cocoa-macosx/swt-debug.jar create mode 100644 tizen/src/skin/client/lib/swt/cocoa-macosx/swt.jar create mode 100644 tizen/src/skin/client/lib/swt/gtk-linux/src.zip create mode 100644 tizen/src/skin/client/lib/swt/gtk-linux/swt-debug.jar create mode 100644 tizen/src/skin/client/lib/swt/gtk-linux/swt.jar create mode 100644 tizen/src/skin/client/lib/swt/win32-win32/src.zip create mode 100644 tizen/src/skin/client/lib/swt/win32-win32/swt-debug.jar create mode 100644 tizen/src/skin/client/lib/swt/win32-win32/swt.jar create mode 100644 tizen/src/skin/client/resource/icons/Emulator.ico create mode 100644 tizen/src/skin/client/resource/icons/Emulator_20x20.png create mode 100644 tizen/src/skin/client/resource/icons/about.png create mode 100644 tizen/src/skin/client/resource/icons/advanced.png create mode 100644 tizen/src/skin/client/resource/icons/close.png create mode 100644 tizen/src/skin/client/resource/icons/copy_screenshot_dialog.png create mode 100644 tizen/src/skin/client/resource/icons/detail_info.png create mode 100644 tizen/src/skin/client/resource/icons/refresh_screenshot_dialog.png create mode 100644 tizen/src/skin/client/resource/icons/rotate.png create mode 100644 tizen/src/skin/client/resource/icons/save_screenshot_dialog.png create mode 100644 tizen/src/skin/client/resource/icons/scale.png create mode 100644 tizen/src/skin/client/resource/icons/screenshot.png create mode 100644 tizen/src/skin/client/resource/icons/shell.png create mode 100644 tizen/src/skin/client/resource/icons/usb_keyboard.png create mode 100644 tizen/src/skin/client/skins/emul_320x480/default.dbi create mode 100644 tizen/src/skin/client/skins/emul_320x480/default_0.png create mode 100644 tizen/src/skin/client/skins/emul_320x480/default_0_p.png create mode 100644 tizen/src/skin/client/skins/emul_320x480/default_180.png create mode 100644 tizen/src/skin/client/skins/emul_320x480/default_180_p.png create mode 100644 tizen/src/skin/client/skins/emul_320x480/default_L90.png create mode 100644 tizen/src/skin/client/skins/emul_320x480/default_L90_p.png create mode 100644 tizen/src/skin/client/skins/emul_320x480/default_R90.png create mode 100644 tizen/src/skin/client/skins/emul_320x480/default_R90_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default.dbi create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default_0.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default_0_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default_180.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default_180_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default_L90.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default_L90_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default_R90.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_320x480/default_R90_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default.dbi create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default_0.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default_0_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default_180.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default_180_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default_L90.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default_L90_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default_R90.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_480x800/default_R90_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default.dbi create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default_0.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default_0_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default_180.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default_180_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default_L90_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_600x1024/default_R90_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default.dbi create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default_0.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default_0_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default_180.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default_180_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default_L90_p.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90.png create mode 100644 tizen/src/skin/client/skins/emul_3keys_720x1280/default_R90_p.png create mode 100644 tizen/src/skin/client/skins/emul_480x800/default.dbi create mode 100644 tizen/src/skin/client/skins/emul_480x800/default_0.png create mode 100644 tizen/src/skin/client/skins/emul_480x800/default_0_p.png create mode 100644 tizen/src/skin/client/skins/emul_480x800/default_180.png create mode 100644 tizen/src/skin/client/skins/emul_480x800/default_180_p.png create mode 100644 tizen/src/skin/client/skins/emul_480x800/default_L90.png create mode 100644 tizen/src/skin/client/skins/emul_480x800/default_L90_p.png create mode 100644 tizen/src/skin/client/skins/emul_480x800/default_R90.png create mode 100644 tizen/src/skin/client/skins/emul_480x800/default_R90_p.png create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default.dbi create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default_0.png create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default_0_p.png create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default_180.png create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default_180_p.png create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default_L90.png create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default_L90_p.png create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default_R90.png create mode 100644 tizen/src/skin/client/skins/emul_600x1024/default_R90_p.png create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default.dbi create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default_0.png create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default_0_p.png create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default_180.png create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default_180_p.png create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default_L90.png create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default_L90_p.png create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default_R90.png create mode 100644 tizen/src/skin/client/skins/emul_720x1280/default_R90_p.png create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorShutdownhook.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkin.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkinMain.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/ICommunicator.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/SocketCommunicator.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/AbstractSendData.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/BooleanData.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/ISendData.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/KeyEventData.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/LcdStateData.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/MouseEventData.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/comm/sock/data/StartData.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/config/EmulatorConfig.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/AboutDialog.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/DetailInfoDialog.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/LicenseDialog.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/dialog/SkinDialog.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/exception/ConfigException.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/exception/EmulatorException.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/exception/JaxbException.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/exception/ScreenShotException.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/image/ImageRegistry.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/log/SkinLogger.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/screenshot/ScreenShotDialog.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/util/IOUtil.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/util/JaxbUtil.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinRegion.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinRotation.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/util/SkinUtil.java create mode 100644 tizen/src/skin/client/src/org/tizen/emulator/skin/util/StringUtil.java create mode 100644 tizen/src/skin/client/xsd/dbi.xsd create mode 100644 tizen/src/skin/maruskin_client.c create mode 100644 tizen/src/skin/maruskin_client.h create mode 100644 tizen/src/skin/maruskin_keymap.c create mode 100644 tizen/src/skin/maruskin_keymap.h create mode 100644 tizen/src/skin/maruskin_operation.c create mode 100644 tizen/src/skin/maruskin_operation.h create mode 100644 tizen/src/skin/maruskin_server.c create mode 100644 tizen/src/skin/maruskin_server.h create mode 100644 trace/control.c create mode 100644 trace/control.h create mode 100644 trace/default.c create mode 100644 trace/simple.c create mode 100644 trace/simple.h create mode 100644 trace/stderr.c create mode 100644 trace/stderr.h create mode 100644 ui/vnc-enc-zrle-template.c create mode 100644 ui/vnc-enc-zrle.c create mode 100644 ui/vnc-enc-zrle.h create mode 100644 ui/vnc-enc-zywrle-template.c create mode 100644 ui/vnc-enc-zywrle.h create mode 100644 usb-redir.c create mode 100644 user-exec.c create mode 100644 xen-all.c create mode 100644 xen-mapcache.c create mode 100644 xen-mapcache.h create mode 100644 xen-stub.c create mode 100644 xtensa-semi.c diff --git a/CODING_STYLE b/CODING_STYLE index 5ecfa22161..6e61c49089 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -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: diff --git a/Changelog b/Changelog index 152feaacb5..28a69afa0b 100644 --- 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 6ba9d7e740..733eab2dac 100644 --- 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. diff --git a/MAINTAINERS b/MAINTAINERS index ab48380058..06df70ca89 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -56,12 +56,13 @@ M: Paul Brook Guest CPU cores (TCG): ---------------------- Alpha -M: qemu-devel@nongnu.org -S: Orphan +M: Richard Henderson +S: Maintained F: target-alpha/ ARM M: Paul Brook +M: Peter Maydell S: Maintained F: target-arm/ @@ -70,6 +71,11 @@ M: Edgar E. Iglesias S: Maintained F: target-cris/ +LM32 +M: Michael Walle +S: Maintained +F: target-lm32/ + M68K M: Paul Brook S: Maintained @@ -110,6 +116,12 @@ M: qemu-devel@nongnu.org S: Odd Fixes F: target-i386/ +Xtensa +M: Max Filippov +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 +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 +M: Peter Maydell S: Maintained F: hw/integratorcp.c @@ -172,6 +195,7 @@ F: hw/palm.c Real View M: Paul Brook +M: Peter Maydell S: Maintained F: hw/realview* @@ -182,11 +206,13 @@ F: hw/spitz.c Stellaris M: Paul Brook +M: Peter Maydell S: Maintained F: hw/stellaris.c Versatile PB M: Paul Brook +M: Peter Maydell S: Maintained F: hw/versatilepb.c @@ -202,6 +228,18 @@ M: Edgar E. Iglesias S: Maintained F: hw/etraxfs.c +LM32 Machines +------------- +EVR32 and uclinux BSP +M: Michael Walle +S: Maintained +F: hw/lm32_boards.c + +milkymist +M: Michael Walle +S: Maintained +F: hw/milkymist.c + M68K Machines ------------- an5206 @@ -265,9 +303,9 @@ M: Alexander Graf S: Maintained F: hw/ppc_oldworld.c -Prep -M: qemu-devel@nongnu.org -S: Orphan +PReP +M: Andreas Färber +S: Odd Fixes F: hw/ppc_prep.c SH4 Machines @@ -308,6 +346,18 @@ M: Anthony Liguori S: Supported F: hw/pc.[ch] hw/pc_piix.c +Xtensa Machines +--------------- +sim +M: Max Filippov +S: Maintained +F: hw/xtensa_sim.c + +Avnet LX60 +M: Max Filippov +S: Maintained +F: hw/xtensa_lx60.c + Devices ------- IDE @@ -315,6 +365,11 @@ M: Kevin Wolf S: Odd Fixes F: hw/ide/ +OMAP +M: Peter Maydell +S: Maintained +F: hw/omap* + PCI M: Michael S. Tsirkin S: Supported @@ -396,6 +451,11 @@ M: Anthony Liguori S: Maintained F: ui/ +Cocoa graphics +M: Andreas Färber +S: Odd Fixes +F: ui/cocoa.m + Main loop M: Anthony Liguori S: Supported @@ -414,9 +474,21 @@ S: Maintained F: net/ SLIRP -M: qemu-devel@nongnu.org -S: Orphan +M: Jan Kiszka +S: Maintained F: slirp/ +T: git://git.kiszka.org/qemu.git queues/slirp + +Tracing +M: Stefan Hajnoczi +S: Maintained +F: trace/ +T: git://repo.or.cz/qemu/stefanha.git tracing + +Checkpatch +M: Blue Swirl +S: Odd Fixes +F: scripts/checkpatch.pl Usermode Emulation ------------------ @@ -463,7 +535,7 @@ S: Maintained F: tcg/ia64/ MIPS target -M: Aurelien Jarno +M: Aurelien Jarno S: Maintained F: tcg/mips/ @@ -487,3 +559,8 @@ SPARC target M: Blue Swirl S: Maintained F: tcg/sparc/ + +TCI target +M: Stefan Weil +S: Maintained +F: tcg/tci diff --git a/Makefile b/Makefile index 37f22ea948..301c75e7e5 100644 --- 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) diff --git a/Makefile.hw b/Makefile.hw index f2e63b42ed..63eb7e40be 100644 --- a/Makefile.hw +++ b/Makefile.hw @@ -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 diff --git a/Makefile.objs b/Makefile.objs index 3b52e3363d..3a699ee7d8 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -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) + diff --git a/Makefile.target b/Makefile.target old mode 100644 new mode 100755 index 9791d4cb11..b19e96effd --- a/Makefile.target +++ b/Makefile.target @@ -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 diff --git a/Makefile.user b/Makefile.user index 024b7736b9..2b1e4d154e 100644 --- a/Makefile.user +++ b/Makefile.user @@ -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) diff --git a/QMP/qmp-shell b/QMP/qmp-shell old mode 100644 new mode 100755 diff --git a/QMP/qmp.py b/QMP/qmp.py index 14ce8b0d05..c7dbea076d 100644 --- a/QMP/qmp.py +++ b/QMP/qmp.py @@ -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 930e3000bd..7dea76edb3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.14.1 +1.0.1 diff --git a/a.out.h b/a.out.h index dfc104e606..33ca7f77ea 100644 --- 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 311dade4e2..e840b9b633 100644 --- 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 2f086557b6..1239ca7bd2 100644 --- 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); } } diff --git a/alpha-dis.c b/alpha-dis.c index 8a2411e4d5..ae331b35b8 100644 --- a/alpha-dis.c +++ b/alpha-dis.c @@ -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 diff --git a/arch_init.c b/arch_init.c index ba59a61379..7995c27de6 100644 --- a/arch_init.c +++ b/arch_init.c @@ -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 +} diff --git a/arch_init.h b/arch_init.h index 17c9164d39..f538758514 100644 --- a/arch_init.h +++ b/arch_init.h @@ -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 diff --git a/arm-semi.c b/arm-semi.c index 1d5179b601..873518a20e 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -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 12b3edb5bb..7f13da9ebb 100644 --- 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 57ac3a8180..332d511ed5 100644 --- a/async.c +++ b/async.c @@ -24,93 +24,10 @@ #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 diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 4d720146df..cb45b49c2a 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -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; } } diff --git a/audio/audio.c b/audio/audio.c index 1729c0be2c..cf1a30e074 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -39,6 +39,11 @@ #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; } diff --git a/audio/audio_pt_int.c b/audio/audio_pt_int.c index 908c569a92..9a9c306a9c 100644 --- a/audio/audio_pt_int.c +++ b/audio/audio_pt_int.c @@ -6,8 +6,6 @@ #include "audio_int.h" #include "audio_pt_int.h" -#include - static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err, const char *fmt, ...) { diff --git a/audio/audio_template.h b/audio/audio_template.h index fd4469e638..e62a71345e 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -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) diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 0a26413d75..5964c62eaf 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -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; } diff --git a/audio/esdaudio.c b/audio/esdaudio.c index ff97b397d2..bd6e1cc19b 100644 --- a/audio/esdaudio.c +++ b/audio/esdaudio.c @@ -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; } diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index c34cf53567..fabf84dd3b 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -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; } diff --git a/audio/mixeng.c b/audio/mixeng.c index 4a9e8ebe2a..5446be674f 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -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) diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h index a2d0ef84fd..e644c231ad 100644 --- a/audio/mixeng_template.h +++ b/audio/mixeng_template.h @@ -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 diff --git a/audio/noaudio.c b/audio/noaudio.c index 0304094a6e..54958f8623 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -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 ()); diff --git a/audio/ossaudio.c b/audio/ossaudio.c index b49e102747..df51b7cc58 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -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; } } diff --git a/audio/paaudio.c b/audio/paaudio.c index fb4510e426..d1f3912cee 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -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; } diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index b74dcfa734..d24daa5ead 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -32,7 +32,6 @@ #elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) #include #endif -#include #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; diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index a5c0d6bc66..f972110e05 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -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; diff --git a/audio/wavaudio.c b/audio/wavaudio.c index c522be4531..a449b5127e 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -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; } diff --git a/audio/wavcapture.c b/audio/wavcapture.c index 1f49cd1fec..4f785f5f49 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -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 : "", wav->bytes); + monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n", + wav->freq, wav->bits, wav->nchannels, + path ? path : "", 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; } diff --git a/audio/winwaveaudio.c b/audio/winwaveaudio.c index e5ad3c6604..87e7493270 100644 --- a/audio/winwaveaudio.c +++ b/audio/winwaveaudio.c @@ -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; } diff --git a/balloon.c b/balloon.c index 0021fef4b8..e1cd5fac4c 100644 --- 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 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,106 +24,80 @@ * 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; diff --git a/balloon.h b/balloon.h index d478e28475..b36abeadf0 100644 --- a/balloon.h +++ b/balloon.h @@ -15,18 +15,15 @@ #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 index 0000000000..a62c8ba681 --- /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 index 0000000000..08755eba11 --- /dev/null +++ b/bitmap.h @@ -0,0 +1,222 @@ +/* + * Bitmap Module + * + * Copyright (C) 2010 Corentin Chary + * + * 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 index 0000000000..d9de71f7e8 --- /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 + * (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 index 0000000000..07d1a0638f --- /dev/null +++ b/bitops.h @@ -0,0 +1,272 @@ +/* + * Bitops Module + * + * Copyright (C) 2010 Corentin Chary + * + * 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 diff --git a/block-migration.c b/block-migration.c index 8218bac09c..5f10486416 100644 --- a/block-migration.c +++ b/block-migration.c @@ -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 b203875be6..d0158877d6 100644 --- 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 @@ -43,20 +45,33 @@ #include #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 097b78975d..a826059897 100644 --- 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 + diff --git a/block/blkdebug.c b/block/blkdebug.c index cd9eb8006a..9b885359e4 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -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, diff --git a/block/blkverify.c b/block/blkverify.c index c7522b4093..483f3b3cfe 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -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, diff --git a/block/bochs.c b/block/bochs.c index 5fe2fa3580..ab7944dc43 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -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, }; diff --git a/block/cloop.c b/block/cloop.c index fe015c4255..7570eb8e74 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -27,9 +27,10 @@ #include typedef struct BDRVCloopState { + CoMutex lock; uint32_t block_size; uint32_t n_blocks; - uint64_t* offsets; + 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;in_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;isectors_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) diff --git a/block/cow.c b/block/cow.c index 4cf543c832..089d395c40 100644 --- a/block/cow.c +++ b/block/cow.c @@ -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, }; diff --git a/block/curl.c b/block/curl.c index 407f0955a3..4209ac88ce 100644 --- a/block/curl.c +++ b/block/curl.c @@ -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; } } diff --git a/block/dmg.c b/block/dmg.c index a3c815b862..37902a4347 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -28,6 +28,7 @@ #include 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;in_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 index 0000000000..938c568071 --- /dev/null +++ b/block/iscsi.c @@ -0,0 +1,591 @@ +/* + * QEMU Block driver for iSCSI images + * + * Copyright (c) 2010-2011 Ronnie Sahlberg + * + * 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 +#include "qemu-common.h" +#include "qemu-error.h" +#include "block_int.h" +#include "trace.h" + +#include +#include + + +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://[%@][:]// + */ +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); diff --git a/block/nbd.c b/block/nbd.c index c8dc763c6b..882b2dc84a 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -28,97 +28,156 @@ #include "qemu-common.h" #include "nbd.h" +#include "block_int.h" #include "module.h" +#include "qemu_socket.h" #include #include #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 :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", diff --git a/block/parallels.c b/block/parallels.c index 35a14aa422..d30f0ecf77 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -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, }; diff --git a/block/qcow.c b/block/qcow.c index f67d3d39f2..4814ed0ced 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -26,6 +26,7 @@ #include "module.h" #include #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, }; diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 382473933c..340a6f2b26 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -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; +} diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 750abe37d4..f4e049fa90 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -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; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 915d85acbf..9605367777 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -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; } diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 74823a5ebf..bdc33ba94c 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -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) { diff --git a/block/qcow2.c b/block/qcow2.c index 75b8becc0a..d7805ce943 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -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, }; diff --git a/block/qcow2.h b/block/qcow2.h index a019831838..4e44eea5ef 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -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); diff --git a/block/qed-check.c b/block/qed-check.c index 474c847d18..e4a49ce72c 100644 --- a/block/qed-check.c +++ b/block/qed-check.c @@ -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; } diff --git a/block/qed-cluster.c b/block/qed-cluster.c index 0ec864b14c..f64b2af8f7 100644 --- a/block/qed-cluster.c +++ b/block/qed-cluster.c @@ -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; diff --git a/block/qed-gencb.c b/block/qed-gencb.c index 1513dc6f79..7d7ac1ffc8 100644 --- a/block/qed-gencb.c +++ b/block/qed-gencb.c @@ -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); } diff --git a/block/qed-l2-cache.c b/block/qed-l2-cache.c index 57518a4e7f..02b81a2e33 100644 --- a/block/qed-l2-cache.c +++ b/block/qed-l2-cache.c @@ -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); } } diff --git a/block/qed-table.c b/block/qed-table.c index d38c673547..f31f9ff069 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -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; } diff --git a/block/qed.c b/block/qed.c index 75ae2440ee..7e22e77b9d 100644 --- a/block/qed.c +++ b/block/qed.c @@ -12,9 +12,11 @@ * */ +#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, diff --git a/block/qed.h b/block/qed.h index 9f72ad5499..62cbd3b899 100644 --- a/block/qed.h +++ b/block/qed.h @@ -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 */ diff --git a/block/raw-posix.c b/block/raw-posix.c index 6b72470599..a3de373586 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -43,17 +43,17 @@ #ifdef __sun__ #define _POSIX_PTHREAD_SEMANTICS 1 -#include #include #endif #ifdef __linux__ +#include +#include #include #include #include #include #endif #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) -#include #include #include #endif @@ -64,6 +64,13 @@ #include #endif +#ifdef __NetBSD__ +#include +#include +#include +#include +#endif + #ifdef __DragonFly__ #include #include @@ -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__ */ diff --git a/block/raw-win32.c b/block/raw-win32.c index c204a80d79..566ec27fb9 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -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) diff --git a/block/raw.c b/block/raw.c index b0f72d6a62..6098070d65 100644 --- a/block/raw.c +++ b/block/raw.c @@ -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, diff --git a/block/rbd.c b/block/rbd.c index 249a590c98..54a6961737 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1,45 +1,56 @@ /* * QEMU Block driver for RADOS (Ceph) * - * Copyright (C) 2010 Christian Brunner + * Copyright (C) 2010-2011 Christian Brunner , + * Josh Durgin * * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. * */ +#include + #include "qemu-common.h" #include "qemu-error.h" - -#include "rbd_types.h" #include "block_int.h" -#include - - +#include /* * 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) diff --git a/block/sheepdog.c b/block/sheepdog.c index a54e0dee31..62f1f3a0cf 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -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, diff --git a/block/vdi.c b/block/vdi.c index 116b25bc9b..02da6b44d0 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -52,6 +52,7 @@ #include "qemu-common.h" #include "block_int.h" #include "module.h" +#include "migration.h" #if defined(CONFIG_UUID) #include @@ -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, diff --git a/block/vmdk.c b/block/vmdk.c index 8fc9d67208..f5441591d7 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -26,9 +26,15 @@ #include "qemu-common.h" #include "block_int.h" #include "module.h" +#include "migration.h" +#include #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, §ors, 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, }; diff --git a/block/vpc.c b/block/vpc.c index 7b025be01d..89a5ee2668 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -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, }; diff --git a/block/vvfat.c b/block/vvfat.c index fe568fe2c7..a310ce8c3e 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -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_tod_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= 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_numfaked_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 diff --git a/block_int.h b/block_int.h index 545ad11ff3..77c0187c3d 100644 --- a/block_int.h +++ b/block_int.h @@ -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 */ diff --git a/blockdev.c b/blockdev.c index 8c96754503..222818690d 100644 --- a/blockdev.c +++ b/blockdev.c @@ -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)); diff --git a/blockdev.h b/blockdev.h index 2c9e7804c9..3587786a64 100644 --- a/blockdev.h +++ b/blockdev.h @@ -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; diff --git a/bsd-user/main.c b/bsd-user/main.c index 6b12f8bba1..cc7d4a37ad 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -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 = ®s1; 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); diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index 207c774fb0..5d6cffc458 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -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; } diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index e343894ab1..1ba2d083d1 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -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. */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index eb1cdf21ca..18b43f1a2a 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #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 82a79517db..cc7f84d30f 100644 --- a/bswap.h +++ b/bswap.h @@ -4,6 +4,7 @@ #include "config-host.h" #include +#include "softfloat.h" #ifdef CONFIG_MACHINE_BSWAP_H #include @@ -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 */ diff --git a/bt-host.c b/bt-host.c index 6931e7cc62..df5b7cdace 100644 --- 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; diff --git a/bt-vhci.c b/bt-vhci.c index 679c5e05d7..bbc1029854 100644 --- 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; diff --git a/buffered_file.c b/buffered_file.c index 8435a31946..fed9a227bb 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -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; } diff --git a/check-qdict.c b/check-qdict.c index 6afce5a5ca..5515773b89 100644 --- a/check-qdict.c +++ b/check-qdict.c @@ -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); } diff --git a/check-qfloat.c b/check-qfloat.c index b71d9834f0..3344057b3b 100644 --- a/check-qfloat.c +++ b/check-qfloat.c @@ -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 diff --git a/check-qint.c b/check-qint.c index f3b031698c..3af51f20c8 100644 --- a/check-qint.c +++ b/check-qint.c @@ -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 diff --git a/check-qjson.c b/check-qjson.c index 64fcdcb4ad..36d4ac26b4 100644 --- a/check-qjson.c +++ b/check-qjson.c @@ -33,7 +33,8 @@ START_TEST(escaped_string) { "\"\\n\"", "\n" }, { "\"\\r\"", "\r" }, { "\"\\t\"", "\t" }, - { "\"\\/\"", "\\/" }, + { "\"/\"", "/" }, + { "\"\\/\"", "/", .skip = 1 }, { "\"\\\\\"", "\\" }, { "\"\\\"\"", "\"" }, { "\"hello world \\\"embedded string\\\"\"", diff --git a/check-qlist.c b/check-qlist.c index 58984cbfcc..ee2454a27f 100644 --- a/check-qlist.c +++ b/check-qlist.c @@ -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 diff --git a/check-qstring.c b/check-qstring.c index c9bafc26b3..93bd4757b7 100644 --- a/check-qstring.c +++ b/check-qstring.c @@ -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 db2c9c4c5e..0806e18ce0 100644 --- 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)); } } diff --git a/compatfd.c b/compatfd.c index a7cebc4867..02306a4f71 100644 --- a/compatfd.c +++ b/compatfd.c @@ -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 +} diff --git a/compatfd.h b/compatfd.h index fc3791520f..6b04877b97 100644 --- a/compatfd.h +++ b/compatfd.h @@ -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 index 0000000000..a1c0794947 --- /dev/null +++ b/compiler.h @@ -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 */ diff --git a/config.h b/config.h index e20f78696a..82c0ab265c 100644 --- a/config.h +++ b/config.h @@ -1,2 +1,2 @@ #include "config-host.h" -#include "config-target.h" +#include "i386-softmmu/config-target.h" diff --git a/configure b/configure index ab540e1ef5..494bcb5069 100755 --- 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-" 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 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 ########################################## @@ -1176,28 +1343,123 @@ fi if test "$xen" != "no" ; then xen_libs="-lxenstore -lxenctrl -lxenguest" + + # Xen unstable cat > $TMPC < #include -int main(void) { xs_daemon_open(); xc_interface_open(); return 0; } +#include +#include +#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 < +#include +#include +#include +#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 < +#include +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 < +#include +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 < 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 < #include @@ -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 < #include @@ -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 < #include @@ -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 < -#include -#include - -#include -#include - -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 < -#include -#include - -#include -#include - -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 -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 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 < -#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 <> $TMPC </dev/null` - fi - if compile_prog "$kvm_cflags" "" ; then - kvm=yes - cat > $TMPC < -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 < - 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 < -#include -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 < -#include -#ifndef CEPH_OSD_TMAP_SET -#error missing CEPH_OSD_TMAP_SET -#endif +#include 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 < #include +#ifdef CONFIG_LIBATTR #include +#else +#include +#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 , 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 +#include +#include +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 + +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 + +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 + +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 +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 < $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 -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 +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 +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 +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-" 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 diff --git a/console.c b/console.c index 57d6eb506c..ed6a653fdf 100644 --- 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) diff --git a/console.h b/console.h index ed88432a0b..3f490f55de 100644 --- 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 +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 index 0000000000..fdea27a106 --- /dev/null +++ b/coroutine-gthread.c @@ -0,0 +1,131 @@ +/* + * GThread coroutine initialization code + * + * Copyright (C) 2006 Anthony Liguori + * Copyright (C) 2011 Aneesh Kumar K.V + * + * 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 . + */ + +#include +#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 index 0000000000..3d01075b06 --- /dev/null +++ b/coroutine-ucontext.c @@ -0,0 +1,232 @@ +/* + * ucontext coroutine initialization code + * + * Copyright (C) 2006 Anthony Liguori + * Copyright (C) 2011 Kevin Wolf + * + * 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 . + */ + +/* XXX Is there a nicer way to disable glibc's stack check for longjmp? */ +#ifdef _FORTIFY_SOURCE +#undef _FORTIFY_SOURCE +#endif +#include +#include +#include +#include +#include +#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 index 0000000000..4179609eec --- /dev/null +++ b/coroutine-win32.c @@ -0,0 +1,92 @@ +/* + * Win32 coroutine initialization code + * + * Copyright (c) 2011 Kevin Wolf + * + * 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; +} diff --git a/cpu-all.h b/cpu-all.h index ffbd6a4df8..5f47ab8df9 100644 --- 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 */ diff --git a/cpu-common.h b/cpu-common.h index 6d4a898ad1..3f45428699 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -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) diff --git a/cpu-defs.h b/cpu-defs.h index 8d4bf86c53..5e22d836e4 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -37,16 +37,22 @@ #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 diff --git a/cpu-exec.c b/cpu-exec.c index 8c9fb8b1a2..989f28e9b4 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -17,45 +17,22 @@ * License along with this library; if not, see . */ #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 -#ifdef __linux__ -#include -#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 - -# 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 - -# 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 - -# 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 - -#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 -# 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 -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 ... */ -# 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 4c9928e2ce..6d0ad8275a 100644 --- a/cpus.c +++ b/cpus.c @@ -30,26 +30,312 @@ #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 + +#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 bf4d9bb87a..4ea2fe2c22 100644 --- 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 diff --git a/cris-dis.c b/cris-dis.c index 5fa67d9f29..5b8e90b2cd 100644 --- a/cris-dis.c +++ b/cris-dis.c @@ -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])); } diff --git a/cursor.c b/cursor.c index dfb9eefaad..efc5917029 100644 --- 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) diff --git a/cutils.c b/cutils.c index f9a7e3689e..24b3fe355b 100644 --- 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; +} diff --git a/darwin-user/commpage.c b/darwin-user/commpage.c index f6aa71e058..cc29bddd95 100644 --- a/darwin-user/commpage.c +++ b/darwin-user/commpage.c @@ -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); diff --git a/darwin-user/machload.c b/darwin-user/machload.c index 3bc3b65559..0aa828298b 100644 --- a/darwin-user/machload.c +++ b/darwin-user/machload.c @@ -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 */ diff --git a/darwin-user/main.c b/darwin-user/main.c index 175e12f968..c0f14f8260 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -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 = ®s1; 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); diff --git a/darwin-user/signal.c b/darwin-user/signal.c index 48620184ee..c530227f1c 100644 --- a/darwin-user/signal.c +++ b/darwin-user/signal.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -32,8 +31,6 @@ #undef uc_link #endif -#include - #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)); diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c index 060acc889d..f3cc1f83a6 100644 --- a/darwin-user/syscall.c +++ b/darwin-user/syscall.c @@ -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 index 0000000000..bd1dd95a2a --- /dev/null +++ b/default-configs/alpha-softmmu.mak @@ -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 diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 323fafbf7f..e67ebb360e 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -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 index 0000000000..0d19974b40 --- /dev/null +++ b/default-configs/lm32-softmmu.mak @@ -0,0 +1,6 @@ +# Default configuration for lm32-softmmu + +CONFIG_PTIMER=y +CONFIG_PFLASH_CFI01=y +CONFIG_PFLASH_CFI02=y +CONFIG_SD=y diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak index 4399b8b361..613edab742 100644 --- a/default-configs/microblaze-softmmu.mak +++ b/default-configs/microblaze-softmmu.mak @@ -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 index 0000000000..378c6ddcb0 --- /dev/null +++ b/default-configs/microblazeel-linux-user.mak @@ -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 index 0000000000..4b40fb21a5 --- /dev/null +++ b/default-configs/microblazeel-softmmu.mak @@ -0,0 +1,5 @@ +# Default configuration for microblazeel-softmmu + +CONFIG_PTIMER=y +CONFIG_PFLASH_CFI01=y +CONFIG_SERIAL=y diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak index f524971598..94a34862dc 100644 --- a/default-configs/mips-softmmu.mak +++ b/default-configs/mips-softmmu.mak @@ -26,3 +26,5 @@ CONFIG_DP8393X=y CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y +CONFIG_G364FB=y +CONFIG_I8259=y diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak index aeab6b2c28..b5d310816f 100644 --- a/default-configs/mips64-softmmu.mak +++ b/default-configs/mips64-softmmu.mak @@ -26,3 +26,5 @@ CONFIG_DP8393X=y CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y +CONFIG_G364FB=y +CONFIG_I8259=y diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index 8e6511cbeb..2831f44f2a 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -28,3 +28,5 @@ CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y CONFIG_FULONG=y +CONFIG_G364FB=y +CONFIG_I8259=y diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak index a05ac25393..14c949df13 100644 --- a/default-configs/mipsel-softmmu.mak +++ b/default-configs/mipsel-softmmu.mak @@ -26,3 +26,5 @@ CONFIG_DP8393X=y CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y +CONFIG_G364FB=y +CONFIG_I8259=y diff --git a/default-configs/pci.mak b/default-configs/pci.mak index 0471efbcd8..22bd3502d4 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -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 diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 45637429ed..c85cdceb15 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -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/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index d5073b3e09..8874115d81 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -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/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 9f0730c7a5..5db7205267 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -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 index 0000000000..a243c99874 --- /dev/null +++ b/default-configs/s390x-linux-user.mak @@ -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 index 0000000000..6aafd21494 --- /dev/null +++ b/default-configs/unicore32-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for unicore32-linux-user diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index eff26d2a24..b75757ee5f 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -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 index 0000000000..9d8899cde7 --- /dev/null +++ b/default-configs/xtensa-softmmu.mak @@ -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 index 0000000000..9d8899cde7 --- /dev/null +++ b/default-configs/xtensaeb-softmmu.mak @@ -0,0 +1,5 @@ +# Default configuration for Xtensa + +CONFIG_SERIAL=y +CONFIG_OPENCORES_ETH=y +CONFIG_PFLASH_CFI01=y diff --git a/device_tree.c b/device_tree.c index 426a63155c..86a694c955 100644 --- a/device_tree.c +++ b/device_tree.c @@ -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; } diff --git a/device_tree.h b/device_tree.h index f05c4e7311..4378685b7a 100644 --- a/device_tree.h +++ b/device_tree.h @@ -17,10 +17,12 @@ 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__ */ diff --git a/dis-asm.h b/dis-asm.h index 296537ad3a..4f15fad4fa 100644 --- 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 c76f36f590..3b1fd977a8 100644 --- a/disas.c +++ b/disas.c @@ -5,7 +5,6 @@ #include #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); diff --git a/dma-helpers.c b/dma-helpers.c index 712ed897f3..bdcd38cd27 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -12,18 +12,17 @@ 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 f3bb275159..a13209d7eb 100644 --- a/dma.h +++ b/dma.h @@ -15,23 +15,43 @@ #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 index 0000000000..b8e504a3cc --- /dev/null +++ b/docs/ccid.txt @@ -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 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)" 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 index 0000000000..a0e9b96f4d --- /dev/null +++ b/docs/ich9-ehci-uhci.cfg @@ -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 index 0000000000..f7d7519f3a --- /dev/null +++ b/docs/libcacard.txt @@ -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 index 0000000000..3fc1683d88 --- /dev/null +++ b/docs/memory.txt @@ -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 index 0000000000..5831e371ea --- /dev/null +++ b/docs/qapi-code-gen.txt @@ -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$ diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt index 4bb2be8850..136d271120 100644 --- a/docs/qdev-device-use.txt +++ b/docs/qdev-device-use.txt @@ -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 becomes -chardev serial,path= +* COM becomes -chardev serial,path=COM * 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 index 0000000000..e792953c8f --- /dev/null +++ b/docs/specs/qcow2.txt @@ -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) diff --git a/docs/specs/qed_spec.txt b/docs/specs/qed_spec.txt index 1d5fa87e01..7982e058b2 100644 --- a/docs/specs/qed_spec.txt +++ b/docs/specs/qed_spec.txt @@ -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: diff --git a/docs/tracing.txt b/docs/tracing.txt index 21183f9a68..ea29f2c222 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -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=" command line argument can be used to enable the +events listed in 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 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 \ + qemu.stp diff --git a/docs/usb2.txt b/docs/usb2.txt new file mode 100644 index 0000000000..228aa33ceb --- /dev/null +++ b/docs/usb2.txt @@ -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= -- Specifies the bus number the device must be attached + to. + + hostaddr= -- Specifies the device address the device got + assigned by the guest os. + + hostport= -- Specifies the physical port the device is attached + to. + + vendorid= -- Specifies the vendor ID of the device. + productid= -- 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 diff --git a/dyngen-exec.h b/dyngen-exec.h index db00fbae04..3544372a65 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -19,16 +19,12 @@ #if !defined(__DYNGEN_EXEC_H__) #define __DYNGEN_EXEC_H__ -#include "qemu-common.h" - -#ifdef __OpenBSD__ -#include -#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 7067c90fb0..2e05d34620 100644 --- 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 index 0000000000..990050f792 --- /dev/null +++ b/error.c @@ -0,0 +1,146 @@ +/* + * QEMU Error Objects + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..6361f407fd --- /dev/null +++ b/error.h @@ -0,0 +1,70 @@ +/* + * QEMU Error Objects + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 + +/** + * 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 index 0000000000..5e3942405a --- /dev/null +++ b/error_int.h @@ -0,0 +1,29 @@ +/* + * QEMU Error Objects + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..2c735556a1 --- /dev/null +++ b/event_notifier.c @@ -0,0 +1,61 @@ +/* + * event notifier support + * + * Copyright Red Hat, Inc. 2010 + * + * Authors: + * Michael S. Tsirkin + * + * 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 +#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 index 0000000000..24117ea97b --- /dev/null +++ b/event_notifier.h @@ -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 diff --git a/exec-all.h b/exec-all.h index 8871d9a164..3819bef12a 100644 --- a/exec-all.h +++ b/exec-all.h @@ -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 index 0000000000..334219fe23 --- /dev/null +++ b/exec-memory.h @@ -0,0 +1,44 @@ +/* + * Internal memory managment interfaces + * + * Copyright 2011 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Avi Kivity + * + * 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 e950df25c3..a027be96b5 100644 --- a/exec.c +++ b/exec.c @@ -26,16 +26,18 @@ #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 -#include #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #if __FreeBSD_version >= 700104 @@ -51,6 +53,9 @@ #include #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, ¤t_pc, ¤t_cs_base, ¤t_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, ¤t_pc, ¤t_cs_base, ¤t_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 diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h index 783822820e..e82ce2332d 100644 --- a/fpu/softfloat-macros.h +++ b/fpu/softfloat-macros.h @@ -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<>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 ); diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index eb644b2273..c5e2dab9f6 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -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 diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 17842f43da..81a7d1ae09 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -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 ); - 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 ); - 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 ) & 63 ) ); - if ( (bits64) ( aSig1<>( - 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 diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 4a5345ceca..063d3dd618 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -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 -#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 index 0000000000..c823fe0aee --- /dev/null +++ b/fsdev/file-op-9p.h @@ -0,0 +1,133 @@ +/* + * Virtio 9p + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Aneesh Kumar K.V + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..4e700dd4e4 --- /dev/null +++ b/fsdev/qemu-fsdev-dummy.c @@ -0,0 +1,28 @@ +/* + * Virtio 9p + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Gautham R Shenoy + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#include +#include +#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); diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c index 0b332907bd..6684f7ea90 100644 --- a/fsdev/qemu-fsdev.c +++ b/fsdev/qemu-fsdev.c @@ -18,45 +18,58 @@ #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; } diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h index a704043beb..8ef847374a 100644 --- a/fsdev/qemu-fsdev.h +++ b/fsdev/qemu-fsdev.h @@ -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" /* @@ -29,27 +29,29 @@ * ----------------- * 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 diff --git a/gdbstub.c b/gdbstub.c index d6556c9a2f..640cf4ee2a 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -37,15 +37,29 @@ #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)); } diff --git a/gen-icount.h b/gen-icount.h index 8879da6335..5fb3829781 100644 --- a/gen-icount.h +++ b/gen-icount.h @@ -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 index 0000000000..99aaa48655 --- /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 diff --git a/hmp-commands.hx b/hmp-commands.hx index 372bef4290..089c1ac23d 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -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 index 0000000000..443d3a7ff4 --- /dev/null +++ b/hmp.c @@ -0,0 +1,523 @@ +/* + * Human Monitor Interface + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..4422578448 --- /dev/null +++ b/hmp.h @@ -0,0 +1,41 @@ +/* + * Human Monitor Interface + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 diff --git a/host-utils.h b/host-utils.h index 0ddc176582..821db93671 100644 --- a/host-utils.h +++ b/host-utils.h @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "osdep.h" +#include "compiler.h" /* QEMU_GNUC_PREREQ */ #if defined(__x86_64__) #define __HAVE_FAST_MULU64__ diff --git a/hppa-dis.c b/hppa-dis.c index 49f99c8d9e..435da73553 100644 --- a/hppa-dis.c +++ b/hppa-dis.c @@ -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 9a4b22c022..3555b3e8e8 100644 --- 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 index 0000000000..9b6d47d91d --- /dev/null +++ b/hw/9pfs/codir.c @@ -0,0 +1,168 @@ + +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Aneesh Kumar K.V + * + * 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 index 0000000000..b15838c1e6 --- /dev/null +++ b/hw/9pfs/cofile.c @@ -0,0 +1,261 @@ + +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Aneesh Kumar K.V + * + * 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 index 0000000000..83f125bd47 --- /dev/null +++ b/hw/9pfs/cofs.c @@ -0,0 +1,344 @@ + +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Aneesh Kumar K.V + * + * 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 index 0000000000..8a48228702 --- /dev/null +++ b/hw/9pfs/coxattr.c @@ -0,0 +1,107 @@ + +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Aneesh Kumar K.V + * + * 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 index 0000000000..25556cc6a7 --- /dev/null +++ b/hw/9pfs/virtio-9p-coth.c @@ -0,0 +1,98 @@ +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Harsh Prateek Bora + * Venkateswararao Jujjuri(JV) + * + * 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 index 0000000000..c4b74b0221 --- /dev/null +++ b/hw/9pfs/virtio-9p-coth.h @@ -0,0 +1,107 @@ +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Harsh Prateek Bora + * Venkateswararao Jujjuri(JV) + * + * 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 + +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 index 0000000000..cd343e1d81 --- /dev/null +++ b/hw/9pfs/virtio-9p-device.c @@ -0,0 +1,189 @@ +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..f97d8984bd --- /dev/null +++ b/hw/9pfs/virtio-9p-handle.c @@ -0,0 +1,679 @@ +/* + * Virtio 9p handle callback + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Aneesh Kumar K.V + * + * 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 +#include +#include +#include +#include +#include "qemu-xattr.h" +#include +#include +#ifdef CONFIG_LINUX_MAGIC_H +#include +#endif +#include + +#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 index 0000000000..371a94dfff --- /dev/null +++ b/hw/9pfs/virtio-9p-local.c @@ -0,0 +1,794 @@ +/* + * Virtio 9p Posix callback + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori + * + * 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 +#include +#include +#include +#include +#include "qemu-xattr.h" +#include +#ifdef CONFIG_LINUX_MAGIC_H +#include +#endif +#include + +#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 index 0000000000..a1948e3aff --- /dev/null +++ b/hw/9pfs/virtio-9p-posix-acl.c @@ -0,0 +1,159 @@ +/* + * Virtio 9p system.posix* xattr callback + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Aneesh Kumar K.V + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include +#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 index 0000000000..92e0b09d38 --- /dev/null +++ b/hw/9pfs/virtio-9p-synth.c @@ -0,0 +1,572 @@ +/* + * Virtio 9p synthetic file system support + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Malahal Naineni + * Aneesh Kumar K.V + * + * 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 + +/* 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 index 0000000000..e03f434633 --- /dev/null +++ b/hw/9pfs/virtio-9p-synth.h @@ -0,0 +1,50 @@ +/* + * Virtio 9p + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Aneesh Kumar K.V + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include +#include +#include + +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 index 0000000000..5044a3e5ab --- /dev/null +++ b/hw/9pfs/virtio-9p-xattr-user.c @@ -0,0 +1,112 @@ +/* + * Virtio 9p user. xattr callback + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Aneesh Kumar K.V + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include +#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 index 0000000000..7f08f6e176 --- /dev/null +++ b/hw/9pfs/virtio-9p-xattr.c @@ -0,0 +1,160 @@ +/* + * Virtio 9p xattr callback + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Aneesh Kumar K.V + * + * 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 index 0000000000..9437280c99 --- /dev/null +++ b/hw/9pfs/virtio-9p-xattr.h @@ -0,0 +1,105 @@ +/* + * Virtio 9p + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Aneesh Kumar K.V + * + * 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 index 0000000000..b3fc3d0885 --- /dev/null +++ b/hw/9pfs/virtio-9p.c @@ -0,0 +1,3309 @@ +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include +#include + +#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 index 0000000000..19a797b727 --- /dev/null +++ b/hw/9pfs/virtio-9p.h @@ -0,0 +1,472 @@ +#ifndef _QEMU_VIRTIO_9P_H +#define _QEMU_VIRTIO_9P_H + +#include +#include +#include +#include +#include +#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 diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index b5e5328395..6f108f4ce2 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -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. */ diff --git a/hw/ac97.c b/hw/ac97.c index d71072d456..0dbba3b54a 100644 --- 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) diff --git a/hw/acpi.c b/hw/acpi.c index 8071e7beba..1cf35e116a 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -15,22 +15,34 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see */ +#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; } diff --git a/hw/acpi.h b/hw/acpi.h index 5949958067..c141e65f4f 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -74,5 +74,73 @@ #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 */ diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 5bbc2b5a26..d9075e6611 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -23,6 +23,7 @@ #include "acpi.h" #include "sysemu.h" #include "range.h" +#include "ioport.h" //#define DEBUG @@ -35,17 +36,13 @@ #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); } diff --git a/hw/adb.c b/hw/adb.c index 99b30f6bc7..aa15f55dc9 100644 --- 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 index 0000000000..b2a591c546 --- /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__) */ diff --git a/hw/adlib.c b/hw/adlib.c index 1d8092baca..e4bfcc6420 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -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); diff --git a/hw/ads7846.c b/hw/ads7846.c index b3bbeaf68e..9c58a5f59f 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -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 index 0000000000..fcc20e973d --- /dev/null +++ b/hw/alpha_dp264.c @@ -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 index 0000000000..e9757028af --- /dev/null +++ b/hw/alpha_pci.c @@ -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, + }, +}; + +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 index 0000000000..13f017733b --- /dev/null +++ b/hw/alpha_sys.h @@ -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 index 0000000000..c7608bbabd --- /dev/null +++ b/hw/alpha_typhoon.c @@ -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 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); diff --git a/hw/an5206.c b/hw/an5206.c index b9f19a9944..3fe1f00d9b 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -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); diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 84e9af76a2..c232946280 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -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, }; diff --git a/hw/apic.c b/hw/apic.c index 218d1bb6da..8289eef5b8 100644 --- 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; diff --git a/hw/apic.h b/hw/apic.h index 8a0c9d0bf6..a5c910fe0a 100644 --- 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); diff --git a/hw/applesmc.c b/hw/applesmc.c index 23ed3287b4..c47b592747 100644 --- a/hw/applesmc.c +++ b/hw/applesmc.c @@ -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; diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 010acb4cf9..af403a159a 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -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; diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index 3bbd8856cf..974a0d8262 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -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; } diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 620550b5ab..215d5dec64 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -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); + } } diff --git a/hw/arm_gic.c b/hw/arm_gic.c index e6b195324b..f3f35164d0 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -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); } diff --git a/hw/arm_pic.c b/hw/arm_pic.c index f44568cebb..a2e8a73301 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -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); } } diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index d8b062c1bf..477fc6fd47 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -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; } diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 82f05dec84..66db81d5b7 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -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; diff --git a/hw/armv7m.c b/hw/armv7m.c index 304cd34bc2..28d41b82a6 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -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; diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 6c7ce01228..bf8c3c50dc 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -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; } diff --git a/hw/audiodev.h b/hw/audiodev.h index 8e930b21ae..d60c3498ee 100644 --- a/hw/audiodev.h +++ b/hw/audiodev.h @@ -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); diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index 57b5e2f041..73eb39d43b 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -26,18 +26,19 @@ #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) diff --git a/hw/baum.c b/hw/baum.c index 21326ae82b..86d780a617 100644 --- 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; } diff --git a/hw/baum.h b/hw/baum.h index 8af710fa21..3f28cc339a 100644 --- 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); diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c index 4ee99a18b9..431359d615 100644 --- a/hw/bitbang_i2c.c +++ b/hw/bitbang_i2c.c @@ -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; diff --git a/hw/blizzard.c b/hw/blizzard.c index 5f329ad13f..b2c1b22844 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -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; diff --git a/hw/boards.h b/hw/boards.h index 6f0f0d7925..716fd7b1a6 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -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; diff --git a/hw/bonito.c b/hw/bonito.c index 65a4a637bf..fdb8198f62 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -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 = { diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c index 982577d1bb..0dcf897421 100644 --- a/hw/bt-hci-csr.c +++ b/hw/bt-hci-csr.c @@ -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); diff --git a/hw/bt-hci.c b/hw/bt-hci.c index f1ee92cfd4..a3a7fb49e2 100644 --- a/hw/bt-hci.c +++ b/hw/bt-hci.c @@ -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); } diff --git a/hw/bt-hid.c b/hw/bt-hid.c index abdfd35e86..8d7a3dae21 100644 --- a/hw/bt-hid.c +++ b/hw/bt-hid.c @@ -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); } diff --git a/hw/bt-l2cap.c b/hw/bt-l2cap.c index 7e2f668e5a..2ccba6071c 100644 --- a/hw/bt-l2cap.c +++ b/hw/bt-l2cap.c @@ -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; diff --git a/hw/bt-sdp.c b/hw/bt-sdp.c index cdf2d95d52..3e390ab5b9 100644 --- a/hw/bt-sdp.c +++ b/hw/bt-sdp.c @@ -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 34bf004572..dc99fc28fa 100644 --- 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 4a702adef7..a48b8d4b13 100644 --- 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 */ diff --git a/hw/cbus.c b/hw/cbus.c index 8ae24e01de..7216899a09 100644 --- 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 index 0000000000..092301b541 --- /dev/null +++ b/hw/ccid-card-emulated.c @@ -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 +#include +#include +#include + +#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 index 0000000000..9f51c6cb05 --- /dev/null +++ b/hw/ccid-card-passthru.c @@ -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 index 0000000000..9e3abe1b4c --- /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 */ diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 5f45b5dee7..c7e365b2a6 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -31,7 +31,6 @@ #include "pci.h" #include "console.h" #include "vga_int.h" -#include "kvm.h" #include "loader.h" /* @@ -174,8 +173,6 @@ #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 index 0000000000..8dd6e4ec7e --- /dev/null +++ b/hw/collie.c @@ -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) diff --git a/hw/cris-boot.c b/hw/cris-boot.c index 2ef17f606c..37894f8b53 100644 --- a/hw/cris-boot.c +++ b/hw/cris-boot.c @@ -23,7 +23,6 @@ */ #include "hw.h" -#include "sysemu.h" #include "loader.h" #include "elf.h" #include "cris-boot.h" diff --git a/hw/cris_pic_cpu.c b/hw/cris_pic_cpu.c index a92d445f29..06ae484950 100644 --- a/hw/cris_pic_cpu.c +++ b/hw/cris_pic_cpu.c @@ -22,17 +22,12 @@ * 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; diff --git a/hw/cs4231a.c b/hw/cs4231a.c index 598f0322d9..a7e03a313c 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -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); diff --git a/hw/cuda.c b/hw/cuda.c index e4c178dd2a..40774360df 100644 --- 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); } diff --git a/hw/debugcon.c b/hw/debugcon.c index 5ee6821206..c9ee6d90b0 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -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); } diff --git a/hw/dec_pci.c b/hw/dec_pci.c index bf88f2ac80..1aec06611c 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -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, }; diff --git a/hw/devices.h b/hw/devices.h index c788373c8c..1a55c1e905 100644 --- a/hw/devices.h +++ b/hw/devices.h @@ -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 diff --git a/hw/dma.c b/hw/dma.c index 8a7302a42f..0a9322daa3 100644 --- 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); } diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 0ef8abe839..f66844b108 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -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; diff --git a/hw/ds1225y.c b/hw/ds1225y.c index b1c52321fe..6852a61d08 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -22,31 +22,24 @@ * 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) diff --git a/hw/ds1338.c b/hw/ds1338.c index 6f5ae5e6c1..3522af5b5a 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.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 "i2c.h" diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 61efb39896..30146b9c9d 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -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) { diff --git a/hw/e1000.c b/hw/e1000.c index af101bd7b7..e164d79b87 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -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(), diff --git a/hw/e1000_hw.h b/hw/e1000_hw.h index 9bd8a4bdfd..2e341ac27e 100644 --- a/hw/e1000_hw.h +++ b/hw/e1000_hw.h @@ -349,6 +349,23 @@ #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 */ diff --git a/hw/eepro100.c b/hw/eepro100.c index edf48f61d1..29ec5b44f8 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -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. @@ -20,11 +20,10 @@ * along with this program. If not, see . * * 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: @@ -47,6 +46,16 @@ #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 @@ -121,8 +130,6 @@ 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; diff --git a/hw/eeprom93xx.c b/hw/eeprom93xx.c index 660b28f225..4c7158d1a5 100644 --- a/hw/eeprom93xx.c +++ b/hw/eeprom93xx.c @@ -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) diff --git a/hw/elf_ops.h b/hw/elf_ops.h index 0bd72350b4..6af357fc13 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -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; } diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 664b8d9c4d..da8adc4d03 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -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) diff --git a/hw/es1370.c b/hw/es1370.c index 40cb48cbb8..c5c16b0484 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -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) diff --git a/hw/escc.c b/hw/escc.c index f6fd9192ea..13c7e66b36 100644 --- a/hw/escc.c +++ b/hw/escc.c @@ -27,15 +27,7 @@ #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: @@ -69,25 +61,6 @@ * 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, diff --git a/hw/escc.h b/hw/escc.h index 015b9d0089..d1da46fd06 100644 --- 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); diff --git a/hw/esp.c b/hw/esp.c index fa9d2a2706..b698a43fe6 100644 --- 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), @@ -37,13 +35,6 @@ * 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); } diff --git a/hw/etraxfs.h b/hw/etraxfs.h index 01fb9d3e82..24e8fd880b 100644 --- a/hw/etraxfs.h +++ b/hw/etraxfs.h @@ -22,7 +22,25 @@ * 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; +} diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c index c205ec1b8f..02d01836ce 100644 --- a/hw/etraxfs_dma.c +++ b/hw/etraxfs_dma.c @@ -24,6 +24,7 @@ #include #include #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; } diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 6aa4007203..246a279b20 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -23,7 +23,7 @@ */ #include -#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, - ð_readl, -}; - -static CPUWriteMemoryFunc * const eth_write[] = { - NULL, NULL, - ð_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(ð->phy); - mdio_attach(ð->mdio_bus, ð->phy, eth->phyaddr); + memory_region_init_io(&s->mmio, ð_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, ð->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) diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c index 4feffda608..47a56d753c 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -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; } diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 2787ebd5c8..298b9857ca 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -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) diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index 133741b4f5..57dc739710 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -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; } diff --git a/hw/fdc.c b/hw/fdc.c index 4bbcc4715f..ecaad0965c 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -63,21 +63,6 @@ #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, diff --git a/hw/fdc.h b/hw/fdc.h index 242730af8c..506feb6557 100644 --- 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 diff --git a/hw/flash.h b/hw/flash.h index d7d103e66f..9c9e5265b7 100644 --- a/hw/flash.h +++ b/hw/flash.h @@ -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 { diff --git a/hw/fmopl.c b/hw/fmopl.c index 3df1806a91..5ad52ab7d2 100644 --- a/hw/fmopl.c +++ b/hw/fmopl.c @@ -45,6 +45,10 @@ #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<AR_TABLE[i]) * (1000.0 / OPL->rate), ((double)(EG_ENT<DR_TABLE[i]) * (1000.0 / OPL->rate) )); } diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 24cdf25d0b..56cf16e27a 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -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; diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 85c8c3c7bf..dbcb888bbd 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -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); diff --git a/hw/g364fb.c b/hw/g364fb.c index a41e988799..f00ee27b17 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -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 @@ -18,27 +18,18 @@ */ #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); diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index bd3d6b0d9f..94a608ef6d 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -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) diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index 101b150aa5..c90b810413 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -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[] = { diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c index 596a9000a1..85869b95eb 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -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]; diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index f47c491a48..9490a7830d 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -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; diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 923073be94..432683acea 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -27,6 +27,7 @@ #include "pci.h" #include "pci_host.h" #include "pc.h" +#include "exec-memory.h" //#define DEBUG @@ -226,7 +227,7 @@ #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[] = { - >64120_writel, - >64120_writel, - >64120_writel, -}; - -static CPUReadMemoryFunc * const gt64120_read[] = { - >64120_readl, - >64120_readl, - >64120_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) diff --git a/hw/gumstix.c b/hw/gumstix.c index ee63f634cc..686a5ed86d 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -35,10 +35,10 @@ #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"); diff --git a/hw/gus.c b/hw/gus.c index ff9e7c7e3b..b5eb548795 100644 --- 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; diff --git a/hw/hda-audio.c b/hw/hda-audio.c index c699d6fd8b..9b089e65b4 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -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() } }; diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index b19b754b31..16f48d12e1 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -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 index 0000000000..2ba716a4d3 --- /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 index 0000000000..9ce03b118c --- /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 */ diff --git a/hw/hpet.c b/hw/hpet.c index c12064dae6..6e6ea520bc 100644 --- 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; } diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h index 8bf312ab21..6128702533 100644 --- a/hw/hpet_emul.h +++ b/hw/hpet_emul.h @@ -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 5e24329589..ed20f5a27a 100644 --- 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))) diff --git a/hw/i2c.c b/hw/i2c.c index f80d12db4f..9bcf3e1d31 100644 --- 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; diff --git a/hw/i2c.h b/hw/i2c.h index 83fd91714a..9381d01589 100644 --- 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 diff --git a/hw/i8254.c b/hw/i8254.c index 06b225cf4c..12571efc2a 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -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) diff --git a/hw/i8259.c b/hw/i8259.c index a8dbee6476..ab519de5d8 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -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) diff --git a/hw/ide.h b/hw/ide.h index 73fb550574..9059aae289 100644 --- 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 */ diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 98bdf7059a..0af201de2f 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -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); } } diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index a4560c41b6..b223d2c055 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -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 @@ -212,6 +212,10 @@ #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 index 0000000000..8af1cfdd7e --- /dev/null +++ b/hw/ide/atapi.c @@ -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); +} diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 5d5464ae83..5fe98b1bb3 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -27,7 +27,6 @@ #include #include #include "block.h" -#include "block_int.h" #include "sysemu.h" #include "dma.h" @@ -44,35 +43,95 @@ 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(), diff --git a/hw/ide/core.c b/hw/ide/core.c index dd63664c0d..93a1a689c4 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -25,42 +25,40 @@ #include #include #include -#include +#include #include "qemu-error.h" #include "qemu-timer.h" #include "sysemu.h" #include "dma.h" #include "blockdev.h" +#include "block_int.h" #include -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); + } +} diff --git a/hw/ide/ich.c b/hw/ide/ich.c index f242d7a81f..3f7510f52e 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -66,23 +66,33 @@ #include #include #include "block.h" -#include "block_int.h" -#include "sysemu.h" #include "dma.h" #include #include +#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 */ } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index d533fb63b3..00b28dfdbc 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -7,8 +7,11 @@ * non-internal declarations are in hw/ide.h */ #include -#include "block_int.h" +#include #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 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); diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 8c59c5a47c..01a9e59cb9 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -26,8 +26,6 @@ #include #include #include "block.h" -#include "block_int.h" -#include "sysemu.h" #include "dma.h" #include @@ -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; diff --git a/hw/ide/macio.c b/hw/ide/macio.c index c1b4caab5b..70b33422d2 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -26,8 +26,6 @@ #include #include #include "block.h" -#include "block_int.h" -#include "sysemu.h" #include "dma.h" #include @@ -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; } diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 2ceeb87c0c..9eee5b50ba 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -26,8 +26,6 @@ #include #include #include "block.h" -#include "block_int.h" -#include "sysemu.h" #include "dma.h" #include @@ -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); diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 82b24b673b..2ec21b0163 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -24,8 +24,6 @@ */ #include #include "block.h" -#include "block_int.h" -#include "sysemu.h" #include "dma.h" #include @@ -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); diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 35168cb469..49b823df79 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -27,8 +27,6 @@ #include #include #include "block.h" -#include "block_int.h" -#include "sysemu.h" #include "dma.h" #include @@ -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; } diff --git a/hw/ide/pci.h b/hw/ide/pci.h index cd72cbaeb9..a694e546d7 100644 --- a/hw/ide/pci.h +++ b/hw/ide/pci.h @@ -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; diff --git a/hw/ide/piix.c b/hw/ide/piix.c index c3496448c3..08cbbe2032 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -27,17 +27,20 @@ #include #include #include "block.h" -#include "block_int.h" #include "sysemu.h" #include "dma.h" #include -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 */ } diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 2bb5c27341..42071277bb 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -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); diff --git a/hw/ide/via.c b/hw/ide/via.c index 04f3290960..098f150bb2 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -28,17 +28,21 @@ #include #include #include "block.h" -#include "block_int.h" #include "sysemu.h" #include "dma.h" #include -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) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index b049940821..9a289b4776 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -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); diff --git a/hw/intel-hda.c b/hw/intel-hda.c index b2b67082e7..10769e0f49 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -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), diff --git a/hw/intel-hda.h b/hw/intel-hda.h index 4e44e3894f..65fd2a85bb 100644 --- a/hw/intel-hda.h +++ b/hw/intel-hda.h @@ -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, diff --git a/hw/ioapic.c b/hw/ioapic.c index 569327d1e9..61991d7679 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -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); } diff --git a/hw/ioapic.h b/hw/ioapic.h index cb2642ae53..86e63dac74 100644 --- a/hw/ioapic.h +++ b/hw/ioapic.h @@ -17,4 +17,11 @@ * License along with this library; if not, see . */ +#ifndef HW_IOAPIC_H +#define HW_IOAPIC_H + +#define IOAPIC_NUM_PINS 24 + void ioapic_eoi_broadcast(int vector); + +#endif /* !HW_IOAPIC_H */ diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 95adf0978f..a6bfbb9173 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -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), diff --git a/hw/irq.c b/hw/irq.c index 7703f62c6c..62f766eb6f 100644 --- 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); +} diff --git a/hw/irq.h b/hw/irq.h index 5daae44909..64da2fd601 100644 --- 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 diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 9e33e71b9f..7c2c2619d0 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -17,13 +17,14 @@ * License along with this library; if not, see . */ #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) diff --git a/hw/isa.h b/hw/isa.h index f1335ff2d6..5eb9c78e9e 100644 --- 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 */ diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c index ca957fb010..fd755ab4a8 100644 --- a/hw/isa_mmio.c +++ b/hw/isa_mmio.c @@ -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); } diff --git a/hw/ivshmem.c b/hw/ivshmem.c index 7b19a81a47..7b4dbf66a9 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -18,6 +18,8 @@ #include "pci.h" #include "msix.h" #include "kvm.h" +#include "migration.h" +#include "qerror.h" #include #include @@ -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), diff --git a/hw/jazz_led.c b/hw/jazz_led.c index 1dc22cf2e3..eb472a04c3 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -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 index 0000000000..5388bc489d --- /dev/null +++ b/hw/kvmclock.c @@ -0,0 +1,118 @@ +/* + * QEMU KVM support, paravirtual clock device + * + * Copyright (C) 2011 Siemens AG + * + * Authors: + * Jan Kiszka + * + * 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 +#include + +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 index 0000000000..252ea13461 --- /dev/null +++ b/hw/kvmclock.h @@ -0,0 +1,24 @@ +/* + * QEMU KVM support, paravirtual clock device + * + * Copyright (C) 2011 Siemens AG + * + * Authors: + * Jan Kiszka + * + * 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 */ diff --git a/hw/lan9118.c b/hw/lan9118.c index 4ce9eb3694..f8149e6983 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -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); diff --git a/hw/lance.c b/hw/lance.c index ddb1cbb7a4..93d5fda35b 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -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); diff --git a/hw/leon3.c b/hw/leon3.c index 919f49fc1c..607ec852fe 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -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 index 0000000000..0a676329fd --- /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 index 0000000000..97e1c001b9 --- /dev/null +++ b/hw/lm32_boards.c @@ -0,0 +1,303 @@ +/* + * QEMU models for LatticeMico32 uclinux and evr32 boards. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +#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 index 0000000000..8fc285efc2 --- /dev/null +++ b/hw/lm32_hwsetup.h @@ -0,0 +1,178 @@ +/* + * LatticeMico32 hwsetup helper functions. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +/* + * 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 index 0000000000..5454aa4e4d --- /dev/null +++ b/hw/lm32_juart.c @@ -0,0 +1,150 @@ +/* + * LatticeMico32 JTAG UART model. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +#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 index 0000000000..67fc5866ea --- /dev/null +++ b/hw/lm32_juart.h @@ -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 index 0000000000..8dd005077c --- /dev/null +++ b/hw/lm32_pic.c @@ -0,0 +1,190 @@ +/* + * LatticeMico32 CPU interrupt controller logic. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +#include + +#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 index 0000000000..14456f37cb --- /dev/null +++ b/hw/lm32_pic.h @@ -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 index 0000000000..e5ff962f43 --- /dev/null +++ b/hw/lm32_sys.c @@ -0,0 +1,161 @@ +/* + * QEMU model of the LatticeMico32 system control block. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +/* + * 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 index 0000000000..49cbb22993 --- /dev/null +++ b/hw/lm32_timer.c @@ -0,0 +1,222 @@ +/* + * QEMU model of the LatticeMico32 timer block. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..367854550c --- /dev/null +++ b/hw/lm32_uart.c @@ -0,0 +1,288 @@ +/* + * QEMU model of the LatticeMico32 UART block. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..4d5b83125f --- /dev/null +++ b/hw/lm4549.c @@ -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 +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 index 0000000000..70d0ac1750 --- /dev/null +++ b/hw/lm4549.h @@ -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 */ diff --git a/hw/lm832x.c b/hw/lm832x.c index ce7dcac688..992ce49729 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -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; diff --git a/hw/loader.c b/hw/loader.c index 35d792e647..9bbcddd424 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -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, diff --git a/hw/loader.h b/hw/loader.h index fc6bdff6bb..fbcaba9f0c 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -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); diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index e4b51a8eaf..fcc27d726f 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -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) diff --git a/hw/m48t59.c b/hw/m48t59.c index 2020487bbe..a77937ef68 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -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) diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 5680fa9c1c..1791ec12e1 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -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); diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h index d236c5b3f2..6d1abe6aae 100644 --- a/hw/mac_dbdma.h +++ b/hw/mac_dbdma.h @@ -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); diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index c2a2fc21e4..ed0a2b7ef2 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -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 */ diff --git a/hw/macio.c b/hw/macio.c index 789ca5529d..cc6ae40050 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -30,58 +30,55 @@ 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); } diff --git a/hw/mainstone.c b/hw/mainstone.c index 58e3f8670d..3ed6649204 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -14,10 +14,32 @@ #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); } diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c index 3eff925b0e..f8c5242867 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -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" diff --git a/hw/max111x.c b/hw/max111x.c index 2844665ba3..70cd1af24f 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -15,7 +15,7 @@ typedef struct { uint8_t tb1, rb2, rb3; int cycle; - int input[8]; + uint8_t input[8]; int inputs, com; } MAX111xState; @@ -94,36 +94,22 @@ static uint32_t max111x_transfer(SSISlave *dev, uint32_t value) return max111x_read(s); } -static void max111x_save(QEMUFile *f, void *opaque) -{ - MAX111xState *s = (MAX111xState *) opaque; - int i; - - qemu_put_8s(f, &s->tb1); - qemu_put_8s(f, &s->rb2); - qemu_put_8s(f, &s->rb3); - qemu_put_be32(f, s->inputs); - qemu_put_be32(f, s->com); - for (i = 0; i < s->inputs; i ++) - qemu_put_byte(f, s->input[i]); -} - -static int max111x_load(QEMUFile *f, void *opaque, int version_id) -{ - MAX111xState *s = (MAX111xState *) opaque; - int i; - - qemu_get_8s(f, &s->tb1); - qemu_get_8s(f, &s->rb2); - qemu_get_8s(f, &s->rb3); - if (s->inputs != qemu_get_be32(f)) - return -EINVAL; - s->com = qemu_get_be32(f); - for (i = 0; i < s->inputs; i ++) - s->input[i] = qemu_get_byte(f); - - return 0; -} +static const VMStateDescription vmstate_max111x = { + .name = "max111x", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(tb1, MAX111xState), + VMSTATE_UINT8(rb2, MAX111xState), + VMSTATE_UINT8(rb3, MAX111xState), + VMSTATE_INT32_EQUAL(inputs, MAX111xState), + VMSTATE_INT32(com, MAX111xState), + VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs, + vmstate_info_uint8, uint8_t), + VMSTATE_END_OF_LIST() + } +}; static int max111x_init(SSISlave *dev, int inputs) { @@ -143,8 +129,7 @@ static int max111x_init(SSISlave *dev, int inputs) s->input[7] = 0x80; s->com = 0; - register_savevm(&dev->qdev, "max111x", -1, 0, - max111x_save, max111x_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_max111x, s); return 0; } diff --git a/hw/max7310.c b/hw/max7310.c index c302eb6aa4..c1bdb2ee0c 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -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, diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index a1b0e31ee5..2aaca2ff41 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -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); diff --git a/hw/mcf5206.c b/hw/mcf5206.c index 2a618d4446..15d6f22f13 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -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); diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 17a692d4a3..1c2c0c48aa 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -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"); diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 21035da345..42a5d77952 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -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; diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index ac04295198..99092e72d1 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -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); diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c index db57096af2..e6b2ab067a 100644 --- a/hw/mcf_uart.c +++ b/hw/mcf_uart.c @@ -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) { diff --git a/hw/microblaze_pic_cpu.c b/hw/microblaze_pic_cpu.c index 7c59382fbe..8b5623ce28 100644 --- a/hw/microblaze_pic_cpu.c +++ b/hw/microblaze_pic_cpu.c @@ -23,15 +23,10 @@ */ #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 index 0000000000..4c76275976 --- /dev/null +++ b/hw/microblaze_pic_cpu.h @@ -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 index 0000000000..5c5ed275b3 --- /dev/null +++ b/hw/milkymist-ac97.c @@ -0,0 +1,335 @@ +/* + * QEMU model of the Milkymist System Controller. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..17c840ff08 --- /dev/null +++ b/hw/milkymist-hpdmc.c @@ -0,0 +1,161 @@ +/* + * QEMU model of the Milkymist High Performance Dynamic Memory Controller. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..9f358a7d69 --- /dev/null +++ b/hw/milkymist-hw.h @@ -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 +#include +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 index 0000000000..fb6e558755 --- /dev/null +++ b/hw/milkymist-memcard.c @@ -0,0 +1,294 @@ +/* + * QEMU model of the Milkymist SD Card Controller. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..85d9400c67 --- /dev/null +++ b/hw/milkymist-minimac2.c @@ -0,0 +1,538 @@ +/* + * QEMU model of the Milkymist minimac2 block. + * + * Copyright (c) 2011 Michael Walle + * + * 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 . + * + * + * 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 + +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 index 0000000000..672f6e43eb --- /dev/null +++ b/hw/milkymist-pfpu.c @@ -0,0 +1,535 @@ +/* + * QEMU model of the Milkymist programmable FPU. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 + +/* #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 \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 -> 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 index 0000000000..ec5f3343d4 --- /dev/null +++ b/hw/milkymist-softusb.c @@ -0,0 +1,326 @@ +/* + * QEMU model of the Milkymist SoftUSB block. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..5783f083b1 --- /dev/null +++ b/hw/milkymist-sysctl.c @@ -0,0 +1,318 @@ +/* + * QEMU model of the Milkymist System Controller. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..aad0ed06d4 --- /dev/null +++ b/hw/milkymist-tmu2.c @@ -0,0 +1,481 @@ +/* + * QEMU model of the Milkymist texture mapping unit. + * + * Copyright (c) 2010 Michael Walle + * Copyright (c) 2010 Sebastien Bourdeauducq + * + * + * 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 . + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/tmu2.pdf + * + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "qemu-error.h" + +#include +#include +#include + +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 index 0000000000..5404ca998c --- /dev/null +++ b/hw/milkymist-uart.c @@ -0,0 +1,234 @@ +/* + * QEMU model of the Milkymist UART block. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..be81abdb08 --- /dev/null +++ b/hw/milkymist-vgafb.c @@ -0,0 +1,320 @@ + +/* + * QEMU model of the Milkymist VGA framebuffer. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + * + * 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 index 0000000000..69af9ef3f6 --- /dev/null +++ b/hw/milkymist-vgafb_template.h @@ -0,0 +1,74 @@ +/* + * QEMU model of the Milkymist VGA framebuffer. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + * + */ + +#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 index 0000000000..b7a8c1c256 --- /dev/null +++ b/hw/milkymist.c @@ -0,0 +1,215 @@ +/* + * QEMU model for the Milkymist board. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +#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); diff --git a/hw/mips.h b/hw/mips.h index 73aa8f8b0e..6fa9a3ae75 100644 --- 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); diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 3b0abdba8a..04921c147e 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -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); diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 85eba5a69a..14beea2d64 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -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 = { diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 7211d98a19..941b9bdd8e 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -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); diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 380a7eb78c..b56cba619e 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -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; } diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index fb34dcfcdc..d0564d4449 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -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], diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 9c95f282a2..cf6ac694e3 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -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); } diff --git a/hw/mipsnet.c b/hw/mipsnet.c index c5e54ffc35..605367bc5f 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -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 index 0000000000..c685f3e08c --- /dev/null +++ b/hw/mpc8544_guts.c @@ -0,0 +1,135 @@ +/* + * QEMU PowerPC MPC8544 global util pseudo-device + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, + * + * 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); diff --git a/hw/mpcore.c b/hw/mpcore.c index fc0521549a..d6175cfc2d 100644 --- a/hw/mpcore.c +++ b/hw/mpcore.c @@ -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); } diff --git a/hw/msi.c b/hw/msi.c index 3dc3a24b77..f214fcf579 100644 --- 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(). */ diff --git a/hw/msix.c b/hw/msix.c index daaf9b7878..149eed22fb 100644 --- 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 */ @@ -26,14 +23,6 @@ #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) diff --git a/hw/msix.h b/hw/msix.h index a9f7993c39..7e04336618 100644 --- 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); diff --git a/hw/msmouse.c b/hw/msmouse.c index 05f893ca93..c3b57ea31c 100644 --- a/hw/msmouse.c +++ b/hw/msmouse.c @@ -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; } diff --git a/hw/msmouse.h b/hw/msmouse.h index 456cb21424..8b853b35bf 100644 --- a/hw/msmouse.h +++ b/hw/msmouse.h @@ -1,2 +1,2 @@ /* msmouse.c */ -CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts); +int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr); diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index 5252fc5e1c..7bcd5d75e8 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -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 @@ -27,9 +26,16 @@ #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); diff --git a/hw/multiboot.c b/hw/multiboot.c index 0d2bfb4973..b4484a3262 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -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 */ diff --git a/hw/musicpal.c b/hw/musicpal.c index d98aa8d03c..20553b525b 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -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, diff --git a/hw/nand.c b/hw/nand.c index f414aa139b..7f25814ddd 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -6,6 +6,10 @@ * Copyright (c) 2006 Openedhand Ltd. * Written by Andrzej Zaborowski * + * 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 @@ -44,30 +49,45 @@ # 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 { diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index 3ff0d89a74..11ffee7d7c 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -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), diff --git a/hw/ne2000.c b/hw/ne2000.c index 5966359852..62e082f8a9 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -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(), diff --git a/hw/ne2000.h b/hw/ne2000.h index 54fdfca133..5fee052194 100644 --- a/hw/ne2000.h +++ b/hw/ne2000.h @@ -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); diff --git a/hw/nseries.c b/hw/nseries.c index 2f6f473d64..eb991431a4 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -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; diff --git a/hw/omap.h b/hw/omap.h index c227a82b2c..cc09a3c0ee 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -17,6 +17,7 @@ * with this program; if not, see . */ #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; diff --git a/hw/omap1.c b/hw/omap1.c index d5e4dabc87..619812c176 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -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); diff --git a/hw/omap2.c b/hw/omap2.c index 0f13272c7b..5197fef2d8 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -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 value. */ - 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 ch. */ } 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"), diff --git a/hw/omap_clk.c b/hw/omap_clk.c index 6bcabef8ac..8448006067 100644 --- a/hw/omap_clk.c +++ b/hw/omap_clk.c @@ -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)); diff --git a/hw/omap_dma.c b/hw/omap_dma.c index 8e2dcc90c8..f943d4e147 100644 --- a/hw/omap_dma.c +++ b/hw/omap_dma.c @@ -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; diff --git a/hw/omap_dss.c b/hw/omap_dss.c index afe287a43e..b4a8b4c45d 100644 --- a/hw/omap_dss.c +++ b/hw/omap_dss.c @@ -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; diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index 478f7d9825..30630a8aa9 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -20,10 +20,10 @@ #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) diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c index 8bf3343a61..414f9f5c37 100644 --- a/hw/omap_gpmc.c +++ b/hw/omap_gpmc.c @@ -21,77 +21,418 @@ #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 size bytes * starting from base. */ - 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); } diff --git a/hw/omap_gptimer.c b/hw/omap_gptimer.c index 9c0f9f2b33..704b000636 100644 --- a/hw/omap_gptimer.c +++ b/hw/omap_gptimer.c @@ -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); diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index 5cabb5a7b3..11577b1eec 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -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; diff --git a/hw/omap_intc.c b/hw/omap_intc.c index 001e20b9d3..45efa25109 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -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) diff --git a/hw/omap_l4.c b/hw/omap_l4.c index 4af0ca8ea6..a4a8883d2a 100644 --- a/hw/omap_l4.c +++ b/hw/omap_l4.c @@ -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; diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 0c2c55012b..29e604863d 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -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, diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index e9ec2f398b..a1afeb5c91 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -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; diff --git a/hw/omap_sdrc.c b/hw/omap_sdrc.c index e18376260e..1df2fd82bd 100644 --- a/hw/omap_sdrc.c +++ b/hw/omap_sdrc.c @@ -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); diff --git a/hw/omap_spi.c b/hw/omap_spi.c index a6b03496c4..6030ad9551 100644 --- a/hw/omap_spi.c +++ b/hw/omap_spi.c @@ -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; diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index 06bccbdc4e..fe535459df 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -26,13 +26,13 @@ * with this program; if not, see . */ #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)) { diff --git a/hw/omap_synctimer.c b/hw/omap_synctimer.c index 118668aead..b47ca88195 100644 --- a/hw/omap_synctimer.c +++ b/hw/omap_synctimer.c @@ -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( diff --git a/hw/omap_uart.c b/hw/omap_uart.c index 9cee81d7c9..19f8e6eec9 100644 --- a/hw/omap_uart.c +++ b/hw/omap_uart.c @@ -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); } diff --git a/hw/onenand.c b/hw/onenand.c index 71c1ab40b4..7898da9321 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -23,6 +23,10 @@ #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 @@ -31,7 +35,12 @@ #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 index 0000000000..2c1e475395 --- /dev/null +++ b/hw/opencores_eth.c @@ -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) diff --git a/hw/openpic.c b/hw/openpic.c index 6d2cf994ba..22fc275b62 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -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 @@ -56,13 +57,13 @@ #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; } diff --git a/hw/openpic.h b/hw/openpic.h index 0957c1ff00..715f0847bf 100644 --- a/hw/openpic.h +++ b/hw/openpic.h @@ -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__ */ diff --git a/hw/palm.c b/hw/palm.c index f22d7775ee..094bfde369 100644 --- 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); diff --git a/hw/parallel.c b/hw/parallel.c index ce311aa424..8494d94f69 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -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 07b4c51687..0a7b597124 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -41,6 +41,13 @@ #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 new mode 100644 index 2358bcedd3..b22ad393f7 --- 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). */ @@ -12,70 +16,108 @@ 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 diff --git a/hw/pc_piix.c b/hw/pc_piix.c index ca0ed9e209..05000e3cc1 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -22,6 +22,8 @@ * THE SOFTWARE. */ +#include + #include "hw.h" #include "pc.h" #include "apic.h" @@ -32,10 +34,18 @@ #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 +#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); diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index 478fe9b836..12f61fea6e 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -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; diff --git a/hw/pci-stub.c b/hw/pci-stub.c index c5a0aa8979..636171c16f 100644 --- a/hw/pci-stub.c +++ b/hw/pci-stub.c @@ -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 * VA Linux Systems Japan K.K. @@ -21,20 +21,17 @@ #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, diff --git a/hw/pci.c b/hw/pci.c index d5bbba975b..399227fc3d 100644 --- 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; +} diff --git a/hw/pci.h b/hw/pci.h index e086064351..b0473b0d8d 100644 --- 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 diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c index 464d89708f..650d1650c5 100644 --- a/hw/pci_bridge.c +++ b/hw/pci_bridge.c @@ -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; } diff --git a/hw/pci_host.c b/hw/pci_host.c index 7c40155b95..44c6c207a9 100644 --- a/hw/pci_host.c +++ b/hw/pci_host.c @@ -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); -} diff --git a/hw/pci_host.h b/hw/pci_host.h index 0a585951e0..0211086d70 100644 --- a/hw/pci_host.h +++ b/hw/pci_host.h @@ -29,25 +29,28 @@ #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 */ diff --git a/hw/pci_ids.h b/hw/pci_ids.h index 97b819d8a8..83f38934ec 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -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 @@ -69,14 +68,6 @@ #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 @@ -109,6 +100,7 @@ #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 @@ -117,3 +109,14 @@ #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 diff --git a/hw/pci_internals.h b/hw/pci_internals.h index e3c93a3cc5..96690b72d3 100644 --- a/hw/pci_internals.h +++ b/hw/pci_internals.h @@ -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; }; diff --git a/hw/pci_regs.h b/hw/pci_regs.h index dd0bed4f1c..e8357c3ea6 100644 --- a/hw/pci_regs.h +++ b/hw/pci_regs.h @@ -211,6 +211,7 @@ #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) */ @@ -223,7 +224,7 @@ #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 */ @@ -300,12 +301,22 @@ #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 */ @@ -365,6 +376,11 @@ #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 */ @@ -420,7 +436,7 @@ #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 */ @@ -437,7 +453,10 @@ #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 */ @@ -486,10 +505,22 @@ #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 */ @@ -502,9 +533,12 @@ #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 */ @@ -556,8 +590,7 @@ #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 @@ -662,4 +695,22 @@ #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 */ diff --git a/hw/pcie.c b/hw/pcie.c index 6a113a9327..5c9eb2f0ac 100644 --- a/hw/pcie.c +++ b/hw/pcie.c @@ -18,8 +18,7 @@ * with this program; if not, see . */ -#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; } diff --git a/hw/pcie.h b/hw/pcie.h index bc909e2793..a213fbaee8 100644 --- 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. */ diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c index 6e653ddb92..62c06eafd6 100644 --- a/hw/pcie_aer.c +++ b/hw/pcie_aer.c @@ -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")) { diff --git a/hw/pcie_host.c b/hw/pcie_host.c index 21069eed83..28bbe72b37 100644 --- a/hw/pcie_host.c +++ b/hw/pcie_host.c @@ -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); } } diff --git a/hw/pcie_host.h b/hw/pcie_host.h index a2026617b7..0074508b43 100644 --- a/hw/pcie_host.h +++ b/hw/pcie_host.h @@ -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 */ diff --git a/hw/pcie_port.c b/hw/pcie_port.c index 340dcdb3c4..8a36f5cfc7 100644 --- a/hw/pcie_port.c +++ b/hw/pcie_port.c @@ -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); diff --git a/hw/pckbd.c b/hw/pckbd.c index ae65c04da1..06b40c540c 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -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); diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 339a401967..4e164da3ac 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -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(), diff --git a/hw/pcnet.c b/hw/pcnet.c index db52dc59e1..cba253ba7b 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -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; } diff --git a/hw/pcnet.h b/hw/pcnet.h index 534bdf9c2b..edc81c90ac 100644 --- a/hw/pcnet.h +++ b/hw/pcnet.h @@ -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; diff --git a/hw/pcspk.c b/hw/pcspk.c index 26a0ecb9df..7fa2d36620 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -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 index 0000000000..fb4ba29bf8 --- /dev/null +++ b/hw/petalogix_ml605_mmu.c @@ -0,0 +1,267 @@ +/* + * Model of Petalogix linux reference design targeting Xilinx Spartan ml605 + * board. + * + * Copyright (c) 2011 Michal Simek + * 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); diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c index 42de45963b..17da2fd87c 100644 --- a/hw/petalogix_s3adsp1800_mmu.c +++ b/hw/petalogix_s3adsp1800_mmu.c @@ -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 }; diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index fb20dfb6ff..69b8e3d539 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -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; +} diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 3594a36f8d..e5a63da595 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -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; diff --git a/hw/piix4.c b/hw/piix4.c index 72073cd0a0..2fd1171328 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -30,10 +30,14 @@ 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 */ } diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 358da58a80..d183443b2f 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -29,6 +29,7 @@ #include "isa.h" #include "sysbus.h" #include "range.h" +#include "xen.h" /* * I440FX chipset data sheet. @@ -37,16 +38,50 @@ 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 */ } diff --git a/hw/pl011.c b/hw/pl011.c index 77f0dbf137..707a161046 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -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; } diff --git a/hw/pl022.c b/hw/pl022.c index ffe05ab747..9a1cb710f3 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -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; } diff --git a/hw/pl031.c b/hw/pl031.c index c488f69511..017a313fda 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -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 index 0000000000..efd52ac42f --- /dev/null +++ b/hw/pl041.c @@ -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 index 0000000000..1f224326e5 --- /dev/null +++ b/hw/pl041.h @@ -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 index 0000000000..e972996725 --- /dev/null +++ b/hw/pl041.hx @@ -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 ) diff --git a/hw/pl050.c b/hw/pl050.c index b155cc07b6..f7fa2e253c 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -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" diff --git a/hw/pl061.c b/hw/pl061.c index 1997b7cd2f..cf5adbe1fb 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -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) diff --git a/hw/pl080.c b/hw/pl080.c index 901f04a844..5ba3b0859b 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -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; } diff --git a/hw/pl110.c b/hw/pl110.c index 06d2dfada6..4ac710a6ec 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -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) diff --git a/hw/pl110_template.h b/hw/pl110_template.h index b3c9077dcc..1dce32a0c3 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -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. */ @@ -43,49 +43,61 @@ #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 diff --git a/hw/pl181.c b/hw/pl181.c index 36d9d02d6a..0943c09eca 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -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); diff --git a/hw/pl190.c b/hw/pl190.c index 75f2ba1966..8dc7e42861 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -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 index 0000000000..d8e365db1e --- /dev/null +++ b/hw/ppc-viosrp.h @@ -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 diff --git a/hw/ppc.c b/hw/ppc.c index 968aec1b16..d29af0bb35 100644 --- 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; diff --git a/hw/ppc.h b/hw/ppc.h index 34f54cf5da..9f911704af 100644 --- 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); diff --git a/hw/ppc405.h b/hw/ppc405.h index e042a05b3b..d8fdf0930a 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -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); diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 9abede7e05..672e9347ac 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -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) { diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 334187e53b..a6e7431882 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -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); diff --git a/hw/ppc440.c b/hw/ppc440.c index 1ed001a031..cd8a95d52b 100644 --- a/hw/ppc440.c +++ b/hw/ppc440.c @@ -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; diff --git a/hw/ppc440.h b/hw/ppc440.h index a40f9176db..9c27c36fd0 100644 --- a/hw/ppc440.h +++ b/hw/ppc440.h @@ -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 diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 34ddf45477..b734e3a56c 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -17,13 +17,13 @@ #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; diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h index bc4ee019a5..f969e44e1b 100644 --- a/hw/ppc4xx.h +++ b/hw/ppc4xx.h @@ -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); diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 5f581fe2c4..d18caa4192 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -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; } diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index f62f1f91d5..339b38ec7a 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -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 index 0000000000..88719458b0 --- /dev/null +++ b/hw/ppc_booke.c @@ -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); +} diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index ea8759324c..af75e45cc2 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -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 @@ -35,79 +37,44 @@ #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__) */ diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index b9245f066a..8c84f9e9a5 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -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 @@ -82,12 +84,13 @@ #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()); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 8a4e088a38..aac3526f55 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -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()); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 6b221221c2..f22d5b98c5 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -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) { diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index b7670ae27c..51b6abddd3 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -14,8 +14,6 @@ * (at your option) any later version. */ -#include - #include "config.h" #include "qemu-common.h" #include "net.h" @@ -28,9 +26,11 @@ #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 @@ -49,50 +49,39 @@ #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) diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 11edd03f16..960a5d0c60 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -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 index 0000000000..2b527282b6 --- /dev/null +++ b/hw/ppce500_spin.c @@ -0,0 +1,216 @@ +/* + * QEMU PowerPC e500v2 ePAPR spinning code + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, + * + * 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 . + * + * 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); diff --git a/hw/prep_pci.c b/hw/prep_pci.c index f88b8254c2..149807a7d5 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -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, diff --git a/hw/prep_pci.h b/hw/prep_pci.h index cd6851288c..b6b481a517 100644 --- a/hw/prep_pci.h +++ b/hw/prep_pci.h @@ -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 diff --git a/hw/primecell.h b/hw/primecell.h index fb456ad4a4..de7d6f2df2 100644 --- a/hw/primecell.h +++ b/hw/primecell.h @@ -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 diff --git a/hw/ps2.c b/hw/ps2.c index 9ccf8cb738..beb2292a5d 100644 --- 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; diff --git a/hw/ptimer.c b/hw/ptimer.c index 4ddbc597e6..b6cabd5b7d 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -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; } diff --git a/hw/pxa.h b/hw/pxa.h index f73d33b1a8..7e9838408b 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -4,11 +4,13 @@ * Copyright (c) 2006 Openedhand Ltd. * Written by Andrzej Zaborowski * - * 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 @@ -63,24 +65,16 @@ # 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 */ diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index d966846f94..e9a507ece5 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -4,7 +4,7 @@ * Copyright (c) 2006 Openedhand Ltd. * Written by Andrzej Zaborowski * - * 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) diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index b512d34501..07ec2dbb66 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -5,11 +5,17 @@ * Copyright (c) 2006 Thorsten Zitterell * Written by Andrzej Zaborowski * - * 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); diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 789965d88b..200b0cfe3a 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -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; } diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index 4c999171b9..e33959d25c 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -82,22 +82,45 @@ 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; } diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 5b2b07e02c..b73290cb3f 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -15,6 +15,20 @@ #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; } diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 24d409d1a1..1de497929b 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -10,10 +10,12 @@ #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); diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index 50d4649f60..74c6817baf 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -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, diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index a36da233d3..bdd82e6bf2 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -5,11 +5,12 @@ * Copyright (c) 2006 Thorsten Zitterell * Written by Andrzej Zaborowski * - * 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); diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index b556d11870..4235e42639 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -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); diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index a493087a52..f0b811c806 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -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"); diff --git a/hw/qdev.c b/hw/qdev.c index c7fec44a83..106407f226 100644 --- 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); } diff --git a/hw/qdev.h b/hw/qdev.h index 9808f85119..36a4198c89 100644 --- 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) \ diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c index 76f43e646c..367aad19f4 100644 --- a/hw/qxl-logger.c +++ b/hw/qxl-logger.c @@ -19,6 +19,7 @@ * along with this program; if not, see . */ +#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)" : ""); diff --git a/hw/qxl-render.c b/hw/qxl-render.c index 58965e0179..2c51ba9806 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -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; } } diff --git a/hw/qxl.c b/hw/qxl.c index fe4212bff0..41500e9ea4 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -18,8 +18,6 @@ * along with this program; if not, see . */ -#include - #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) diff --git a/hw/qxl.h b/hw/qxl.h index f6c450d32d..766aa6d68e 100644 --- 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 diff --git a/hw/r2d.c b/hw/r2d.c index a0f8c1f201..b65fd427b7 100644 --- 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, diff --git a/hw/rc4030.c b/hw/rc4030.c index 0a9d98d1d5..33e10709c6 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -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; diff --git a/hw/realview.c b/hw/realview.c index 6eb6c6a1f1..9a8e63c8f5 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -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" @@ -17,19 +17,21 @@ #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; diff --git a/hw/realview_gic.c b/hw/realview_gic.c index db908b6439..cd6a44d9d0 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -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; } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index a22530cf89..aa8ed0a919 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -45,14 +45,20 @@ * 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 + #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 @@ -62,14 +68,6 @@ /* 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 -#endif - #define SET_MASKED(input, mask, curr) \ ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) ) @@ -77,10 +75,24 @@ #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 (hleneth_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(), diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 784dc01b97..c4b9a99e6e 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -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(), }, }; diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 33379a3ba4..f1bece738b 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -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; diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index f29b624e41..61b67e8c3a 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -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" @@ -62,17 +63,6 @@ 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")) { diff --git a/hw/sb16.c b/hw/sb16.c index c9d37ad2b7..f0658ac596 100644 --- 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); diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index ceeb4ecb91..64e709ee9f 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -4,60 +4,134 @@ #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; +} diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index 413cce07b5..354ed7b55b 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -25,14 +25,14 @@ */ #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 @@ -48,14 +48,13 @@ #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 @@ -71,45 +70,74 @@ #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 @@ -154,6 +182,7 @@ #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 @@ -161,6 +190,99 @@ #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 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 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 488eedd2cd..673948c51f 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -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 +#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) diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 9be1cca4c3..e62044f395 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -7,7 +7,7 @@ * * Written by Laurent Vivier * - * 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(), }, }; diff --git a/hw/scsi.h b/hw/scsi.h index d3b5d56cd6..ab6e952327 100644 --- 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 0b90232d14..10e26ade58 100644 --- 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. */ diff --git a/hw/serial.c b/hw/serial.c index 2c4af61a2b..d35c7a9207 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -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 index 0000000000..7ef750adf6 --- /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); diff --git a/hw/sh7750.c b/hw/sh7750.c index 19d5bf8537..9f3ea9285f 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -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, diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h index 5a23a2ca20..6ec13ab6fe 100644 --- a/hw/sh7750_regs.h +++ b/hw/sh7750_regs.h @@ -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)) diff --git a/hw/sh_intc.c b/hw/sh_intc.c index 0734da90f0..e07424f2a1 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -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; diff --git a/hw/sh_pci.c b/hw/sh_pci.c index e99d8dbfb5..36f39300d5 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -26,19 +26,23 @@ #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) diff --git a/hw/sh_serial.c b/hw/sh_serial.c index 191f4a60c6..a20c59ef77 100644 --- a/hw/sh_serial.c +++ b/hw/sh_serial.c @@ -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; diff --git a/hw/sh_timer.c b/hw/sh_timer.c index 5eec6b7c14..dca3c94210 100644 --- a/hw/sh_timer.c +++ b/hw/sh_timer.c @@ -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); diff --git a/hw/shix.c b/hw/shix.c index 638bf16e34..dbf47642df 100644 --- 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" @@ -37,16 +36,6 @@ #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, diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index a83e5b8272..329c251845 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -46,22 +46,22 @@ 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 diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 198360d573..1f5a2d7330 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -37,13 +37,13 @@ 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 { diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 5511313687..84449baa71 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -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; diff --git a/hw/sm501.c b/hw/sm501.c index 0f0bf96609..297bc9c318 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -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 */ diff --git a/hw/sm501_template.h b/hw/sm501_template.h index d1ceef9cb6..2d4a3d8b48 100644 --- a/hw/sm501_template.h +++ b/hw/sm501_template.h @@ -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; diff --git a/hw/smbios.c b/hw/smbios.c index a3ae1de824..c9ba43e8d0 100644 --- a/hw/smbios.c +++ b/hw/smbios.c @@ -21,19 +21,19 @@ 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; diff --git a/hw/smbios.h b/hw/smbios.h index 3a5169dbd3..94e3641f9a 100644 --- a/hw/smbios.h +++ b/hw/smbios.h @@ -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 */ diff --git a/hw/smbus.c b/hw/smbus.c index e464539150..ff027c814f 100644 --- a/hw/smbus.c +++ b/hw/smbus.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. */ /* TODO: Implement PEC. */ diff --git a/hw/smbus.h b/hw/smbus.h index 571c52dfb1..a39871593b 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -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); diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 52463e0f86..5d080abed7 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -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); + } +} diff --git a/hw/smc91c111.c b/hw/smc91c111.c index dafea5cc6e..fc8c4984a7 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -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(), diff --git a/hw/soc_dma.c b/hw/soc_dma.c index 23ec51695a..03bc8468dd 100644 --- a/hw/soc_dma.c +++ b/hw/soc_dma.c @@ -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); diff --git a/hw/soc_dma.h b/hw/soc_dma.h index c0ebb8d715..904b26c5a8 100644 --- a/hw/soc_dma.h +++ b/hw/soc_dma.h @@ -18,6 +18,8 @@ * with this program; if not, see . */ +#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 index 0000000000..5a98d8651f --- /dev/null +++ b/hw/spapr.c @@ -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 + +#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 index 0000000000..df88f6abad --- /dev/null +++ b/hw/spapr.h @@ -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 index 0000000000..84281be9e2 --- /dev/null +++ b/hw/spapr_hcall.c @@ -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 index 0000000000..abe12973e6 --- /dev/null +++ b/hw/spapr_llan.c @@ -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 + +#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 ", , 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 index 0000000000..9b6a032cce --- /dev/null +++ b/hw/spapr_pci.c @@ -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 + +#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 index 0000000000..213340c915 --- /dev/null +++ b/hw/spapr_pci.h @@ -0,0 +1,61 @@ +/* + * QEMU SPAPR PCI BUS definitions + * + * Copyright (c) 2011 Alexey Kardashevskiy + * + * 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 . + */ +#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 index 0000000000..d1ac74cfbd --- /dev/null +++ b/hw/spapr_rtas.c @@ -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 + +#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 index 0000000000..464fe87442 --- /dev/null +++ b/hw/spapr_vio.c @@ -0,0 +1,843 @@ +/* + * QEMU sPAPR VIO code + * + * Copyright (c) 2010 David Gibson, IBM Corporation + * Based on the s390 virtio bus code: + * Copyright (c) 2009 Alexander Graf + * + * 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 . + */ + +#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 +#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 index 0000000000..9fcd304adc --- /dev/null +++ b/hw/spapr_vio.h @@ -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 + * Based on the s390 virtio bus definitions: + * Copyright (c) 2009 Alexander Graf + * + * 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 . + */ + +#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 index 0000000000..00e2d2d5d3 --- /dev/null +++ b/hw/spapr_vscsi.c @@ -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 + +/*#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 index 0000000000..386ccf7206 --- /dev/null +++ b/hw/spapr_vty.c @@ -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); diff --git a/hw/spitz.c b/hw/spitz.c index 5b1e42dff3..23f9d41ff7 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -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" @@ -48,14 +49,15 @@ 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 index 0000000000..3009bd56ce --- /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 */ diff --git a/hw/ssd0303.c b/hw/ssd0303.c index 108c0683c8..401fdf592a 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -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. */ diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 8643961144..1eb3823fed 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -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 diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index fb4b649279..18dabd64a6 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -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" diff --git a/hw/ssi.c b/hw/ssi.c index cfe7c072f1..9842fe7472 100644 --- 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; } diff --git a/hw/stellaris.c b/hw/stellaris.c index b90327305a..2bf1c235dc 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -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); diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 6a0583a256..d5613ffffd 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -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); diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c index 16aae96f2f..68c600c04c 100644 --- a/hw/stellaris_input.c +++ b/hw/stellaris_input.c @@ -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 index 0000000000..a3d908051f --- /dev/null +++ b/hw/strongarm.c @@ -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 + * + * 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 . + */ +#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 index 0000000000..684f61bee3 --- /dev/null +++ b/hw/strongarm.h @@ -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 diff --git a/hw/sun4m.c b/hw/sun4m.c index 30e8a21672..314edc4d87 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -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; } diff --git a/hw/sun4m.h b/hw/sun4m.h index ce97ee5a79..504c3af413 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -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" diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c index bba69eef92..6eeadfa184 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -118,7 +118,7 @@ #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) diff --git a/hw/sun4u.c b/hw/sun4u.c index 90b1ce2770..eaaefe3c94 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -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]); } diff --git a/hw/syborg.c b/hw/syborg.c index 758c69a9cd..248de54c4e 100644 --- a/hw/syborg.c +++ b/hw/syborg.c @@ -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, diff --git a/hw/syborg_fb.c b/hw/syborg_fb.c index 7e37364540..ae3e0ebc64 100644 --- a/hw/syborg_fb.c +++ b/hw/syborg_fb.c @@ -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; diff --git a/hw/syborg_interrupt.c b/hw/syborg_interrupt.c index 5217983f6c..1b0f3bb9b5 100644 --- a/hw/syborg_interrupt.c +++ b/hw/syborg_interrupt.c @@ -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); diff --git a/hw/syborg_keyboard.c b/hw/syborg_keyboard.c index d295e99ebd..82b9dc088e 100644 --- a/hw/syborg_keyboard.c +++ b/hw/syborg_keyboard.c @@ -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; } diff --git a/hw/syborg_pointer.c b/hw/syborg_pointer.c index a886888467..b91214daea 100644 --- a/hw/syborg_pointer.c +++ b/hw/syborg_pointer.c @@ -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; } diff --git a/hw/syborg_rtc.c b/hw/syborg_rtc.c index 329aa42661..69f6ccf29c 100644 --- a/hw/syborg_rtc.c +++ b/hw/syborg_rtc.c @@ -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; } diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c index 34ce076d45..c83f82c36e 100644 --- a/hw/syborg_serial.c +++ b/hw/syborg_serial.c @@ -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(), diff --git a/hw/syborg_timer.c b/hw/syborg_timer.c index cedcd8ed47..50c813e969 100644 --- a/hw/syborg_timer.c +++ b/hw/syborg_timer.c @@ -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; } diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c index ee08c49105..6de952c938 100644 --- a/hw/syborg_virtio.c +++ b/hw/syborg_virtio.c @@ -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); diff --git a/hw/sysbus.c b/hw/sysbus.c index 1583bd8589..fd2fc6a51d 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -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); +} diff --git a/hw/sysbus.h b/hw/sysbus.h index e9eb618a72..6c36537c24 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -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 */ diff --git a/hw/tc58128.c b/hw/tc58128.c index 672a01c467..4ce80b18f3 100644 --- a/hw/tc58128.c +++ b/hw/tc58128.c @@ -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); diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index c3fbe4e205..c144dcf5ff 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -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, diff --git a/hw/tcx.c b/hw/tcx.c index 0e32830a87..cd24100e14 100644 --- 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, diff --git a/hw/tosa.c b/hw/tosa.c index 0bfab1634a..b992b994c7 100644 --- 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" @@ -21,10 +20,12 @@ #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 */ @@ -51,17 +52,13 @@ 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); diff --git a/hw/tsc2005.c b/hw/tsc2005.c index a55853c853..9a500ebb3d 100644 --- a/hw/tsc2005.c +++ b/hw/tsc2005.c @@ -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; diff --git a/hw/tsc210x.c b/hw/tsc210x.c index fca73f16f3..3c448a6f0f 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -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; diff --git a/hw/tusb6010.c b/hw/tusb6010.c index 0005e1cffb..ce7c81f8f2 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -24,9 +24,11 @@ #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) diff --git a/hw/twl92230.c b/hw/twl92230.c index e61f17f0ad..a75448f06a 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -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); diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 5f150589e1..4299052c5e 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -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) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index 22e6845049..f30eec1ea2 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -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, diff --git a/hw/usb-bus.c b/hw/usb-bus.c index abc7e61a59..8cafb76fff 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -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 index 0000000000..cd349f3f17 --- /dev/null +++ b/hw/usb-ccid.c @@ -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 + * 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) diff --git a/hw/usb-desc.c b/hw/usb-desc.c index 62591f20aa..ae2d384bb3 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -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; diff --git a/hw/usb-desc.h b/hw/usb-desc.h index ac734ab088..5c14e4abdc 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -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 */ diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index a58ba0dd9d..a946e1d1fd 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -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 @@ -13,47 +18,36 @@ * 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 . */ #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 @@ -107,10 +101,10 @@ #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 @@ -133,17 +127,11 @@ #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 */ diff --git a/hw/usb-hid.c b/hw/usb-hid.c index b559c50be6..4d1a5d62c6 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -26,7 +26,12 @@ #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 @@ -41,48 +46,9 @@ #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, diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 3dd31ba31f..e1959372e7 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -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 index 0000000000..162b42bd5b --- /dev/null +++ b/hw/usb-libhw.c @@ -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); + } +} diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 76f5b027b2..8162ded7c9 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -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" @@ -18,6 +18,10 @@ #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(), }, diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 782cfa2282..01e2e7c389 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -261,13 +261,30 @@ 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 diff --git a/hw/usb-net.c b/hw/usb-net.c index bf51bb3890..a8b7c8dd76 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -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, diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 09ea0b6260..c27014a88f 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -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<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 = { diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 6763d52040..7dbf6dfc6d 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -5,7 +5,7 @@ * Copyright (c) 2008 Samuel Thibault * 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, diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index b384e1ddec..660c7338cf 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -30,6 +30,13 @@ #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 */ } diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index 53978942ba..25580067f2 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -41,20 +41,18 @@ #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, diff --git a/hw/usb.c b/hw/usb.c index 82a6217a0b..2216efe077 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -25,34 +25,43 @@ */ #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); } diff --git a/hw/usb.h b/hw/usb.h index d3d755db7b..c6e1870e59 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -26,6 +26,12 @@ #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 */ @@ -124,6 +130,8 @@ #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 @@ -131,6 +139,7 @@ #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); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 2fed8a00fd..8a88696f2c 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -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_writeb (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) diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 9f1bfcf941..6370600bb3 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -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 index 0000000000..0940a26d73 --- /dev/null +++ b/hw/vexpress.c @@ -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 . + */ + +#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); diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c index 4954bb18be..f8984c62cb 100644 --- a/hw/vga-isa-mm.c +++ b/hw/vga-isa-mm.c @@ -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; } diff --git a/hw/vga-isa.c b/hw/vga-isa.c index 304605493a..4825313f67 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -29,21 +29,56 @@ #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) diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 098733cf94..6dbde6c029 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -29,12 +29,22 @@ #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); diff --git a/hw/vga.c b/hw/vga.c old mode 100755 new mode 100644 index a7649ec596..ca79aa157d --- 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; } - diff --git a/hw/vga_int.h b/hw/vga_int.h index 9d91ba6e0a..4e8568dfd5 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -23,6 +23,7 @@ */ #include +#include "memory.h" #define MSR_COLOR_EMULATION 0x01 #define MSR_PAGE_SELECT 0x20 @@ -34,7 +35,11 @@ #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; diff --git a/hw/vhost.c b/hw/vhost.c index 6c194f0f81..0870cb7d85 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -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; } diff --git a/hw/vhost.h b/hw/vhost.h index c8c595a147..c9452f0732 100644 --- a/hw/vhost.h +++ b/hw/vhost.h @@ -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 diff --git a/hw/vhost_net.c b/hw/vhost_net.c index 420e05f112..950a6b8d99 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -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; } diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index fa605158e7..5ea0e60e41 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -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); diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 8adddeaa53..e24a2bf1f3 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -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 * * Authors: * Anthony Liguori @@ -15,24 +17,15 @@ #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 #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); +} diff --git a/hw/virtio-balloon.h b/hw/virtio-balloon.h index e20cf6bc0d..73300ddc86 100644 --- a/hw/virtio-balloon.h +++ b/hw/virtio-balloon.h @@ -50,6 +50,6 @@ struct virtio_balloon_config typedef struct VirtIOBalloonStat { uint16_t tag; uint64_t val; -} __attribute__((packed)) VirtIOBalloonStat; +} QEMU_PACKED VirtIOBalloonStat; #endif diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 114c63888f..d6d1f87cda 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -11,11 +11,12 @@ * */ -#include +#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 #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); } diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index fff46da7db..244dce45aa 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -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 diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 62624ec780..d3351c83ff 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -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(), }, }; diff --git a/hw/virtio-net.c b/hw/virtio-net.c index e9775a6e73..8c2f460147 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -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); } diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 8af9a1ce55..44687414c9 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -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. */ diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 5a3acdec83..8fb8b9f1d2 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -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 */ @@ -64,17 +67,14 @@ #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 +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 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 + .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 + /* 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 index 0000000000..344c22b68f --- /dev/null +++ b/hw/virtio-pci.h @@ -0,0 +1,53 @@ +/* + * Virtio PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori + * Paul Brook + * + * 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 diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index e05ab5e609..a4825b9eeb 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -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); } diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h index a308196786..ab138038c0 100644 --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@ -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. */ diff --git a/hw/virtio.c b/hw/virtio.c index 31bd9e32dc..81ecc40b31 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -16,21 +16,12 @@ #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; diff --git a/hw/virtio.h b/hw/virtio.h index 4ceb52ee07..470e3adb1f 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -18,11 +18,12 @@ #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 */ @@ -46,6 +47,11 @@ #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); diff --git a/hw/vmmouse.c b/hw/vmmouse.c index 209711942f..1113f33d68 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -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) diff --git a/hw/vmport.c b/hw/vmport.c index 6c9d7c9651..b5c6fa19cd 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -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 @@ -37,19 +37,21 @@ 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) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 6c59053308..af70bdee09 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -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) diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h index 2e0813c81b..5132573a56 100644 --- a/hw/vmware_vga.h +++ b/hw/vmware_vga.h @@ -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 diff --git a/hw/vt82c686.c b/hw/vt82c686.c index cacc21767b..284595905d 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -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) diff --git a/hw/watchdog.c b/hw/watchdog.c index e9dd56e229..4c18965654 100644 --- a/hw/watchdog.c +++ b/hw/watchdog.c @@ -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: diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 90bf5f65a7..20d8673186 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -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) diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index 1248464ff5..81f22d0261 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -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); diff --git a/hw/wm8750.c b/hw/wm8750.c index c9c674451b..39383f43e5 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -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 diff --git a/hw/xen.h b/hw/xen.h index 780dcf713a..21621115e4 100644 --- a/hw/xen.h +++ b/hw/xen.h @@ -8,6 +8,8 @@ */ #include +#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 */ diff --git a/hw/xen_backend.c b/hw/xen_backend.c index a2e408fa0e..d876cabb12 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -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); diff --git a/hw/xen_backend.h b/hw/xen_backend.h index 1b428e3bf4..3305630903 100644 --- a/hw/xen_backend.h +++ b/hw/xen_backend.h @@ -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; diff --git a/hw/xen_common.h b/hw/xen_common.h index 8a55b44f0b..0409ac7971 100644 --- a/hw/xen_common.h +++ b/hw/xen_common.h @@ -1,6 +1,8 @@ #ifndef QEMU_HW_XEN_COMMON_H #define QEMU_HW_XEN_COMMON_H 1 +#include "config-host.h" + #include #include @@ -13,22 +15,124 @@ #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 -#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 */ diff --git a/hw/xen_console.c b/hw/xen_console.c index d2261f4139..edcb31ce66 100644 --- a/hw/xen_console.c +++ b/hw/xen_console.c @@ -33,7 +33,6 @@ #include #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, }; diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c index 8d50216c04..41accbbfa9 100644 --- a/hw/xen_devconfig.c +++ b/hw/xen_devconfig.c @@ -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)); diff --git a/hw/xen_disk.c b/hw/xen_disk.c index ed9e5eb4d7..286bbac54a 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -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 = ""; - 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 = ""; + 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, diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index 7f1fd66eaf..a6a12e5930 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -1,7 +1,6 @@ #include #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: diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 77a34bf111..7985d11d5a 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -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) diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 08055b83ff..ef2a2d6997 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -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 index 0000000000..5e792f56f6 --- /dev/null +++ b/hw/xen_platform.c @@ -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 + +#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 + +//#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); diff --git a/hw/xenfb.c b/hw/xenfb.c index da5297b498..1bcf171b01 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -44,7 +44,6 @@ #include #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 index 0000000000..1c5eaa4135 --- /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 index 0000000000..83c1182598 --- /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__ */ diff --git a/hw/xilinx.h b/hw/xilinx.h index 705ff5b84b..35f35bd7fc 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -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 index 0000000000..571a5b0661 --- /dev/null +++ b/hw/xilinx_axidma.c @@ -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 index 0000000000..37cb6f0911 --- /dev/null +++ b/hw/xilinx_axidma.h @@ -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 index 0000000000..b875aad019 --- /dev/null +++ b/hw/xilinx_axienet.c @@ -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) diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 54b57d774f..6f44c8466e 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -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, ð_readl, -}; - -static CPUWriteMemoryFunc * const eth_write[] = { - NULL, NULL, ð_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, ð_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, diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index cb72d5a14e..58b73d95cc 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -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; } diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index 30827b03cd..8779c56f0b 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -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; } diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index 9b94e98fe3..ceb7b4d9ed 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -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) diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 5aa6a6b149..d3c387d6cb 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -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), diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index a7640f518a..82836958a4 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -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 index 0000000000..38ef32bdb6 --- /dev/null +++ b/hw/xtensa_bootparam.h @@ -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 index 0000000000..8947157bfc --- /dev/null +++ b/hw/xtensa_lx60.c @@ -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 index 0000000000..71d5fc89d4 --- /dev/null +++ b/hw/xtensa_pic.c @@ -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 index 0000000000..a94e4e561e --- /dev/null +++ b/hw/xtensa_sim.c @@ -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 index 0000000000..a03bb33d1b --- /dev/null +++ b/hw/z2.c @@ -0,0 +1,360 @@ +/* + * PXA270-based Zipit Z2 device + * + * Copyright (c) 2011 by Vasily Khoruzhick + * + * 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); diff --git a/hw/zaurus.c b/hw/zaurus.c index fca11a5333..0eeacf7cb3 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -16,7 +16,6 @@ * with this program; if not, see . */ #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 f8df7bf8dd..cc3f160af0 100644 --- 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 : diff --git a/ia64-dis.c b/ia64-dis.c index 2886df3614..2a103e6b5c 100644 --- a/ia64-dis.c +++ b/ia64-dis.c @@ -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 7e5fa1ac50..37c88c7895 100644 --- a/input.c +++ b/input.c @@ -26,12 +26,15 @@ #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 index 0000000000..b3864b6cd4 --- /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 index 0000000000..5640d49388 --- /dev/null +++ b/iohandler.c @@ -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 +#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 diff --git a/ioport.c b/ioport.c index aa4188a40f..36fa3a477e 100644 --- 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; + } +} diff --git a/ioport.h b/ioport.h index 5ae62a3a2c..ae3e9da0b5 100644 --- 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 588cd04288..e7385c41f4 100644 --- a/iov.c +++ b/iov.c @@ -14,57 +14,116 @@ #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 60a85470bd..94d2f78284 100644 --- a/iov.h +++ b/iov.h @@ -12,8 +12,12 @@ #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); diff --git a/json-lexer.c b/json-lexer.c index c736f42900..c21338f66d 100644 --- a/json-lexer.c +++ b/json-lexer.c @@ -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) diff --git a/json-lexer.h b/json-lexer.h index 3b50c4634b..10bc0a7798 100644 --- a/json-lexer.h +++ b/json-lexer.h @@ -25,6 +25,7 @@ typedef enum json_token_type { JSON_STRING, JSON_ESCAPE, JSON_SKIP, + JSON_ERROR, } JSONTokenType; typedef struct JSONLexer JSONLexer; diff --git a/json-parser.c b/json-parser.c index 6c06ef91a6..849e2156da 100644 --- a/json-parser.c +++ b/json-parser.c @@ -22,9 +22,11 @@ #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; } diff --git a/json-parser.h b/json-parser.h index 97f43f67d4..8f2b5ec4bc 100644 --- a/json-parser.h +++ b/json-parser.h @@ -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 diff --git a/json-streamer.c b/json-streamer.c index f7e7a68d40..c255c7818f 100644 --- a/json-streamer.c +++ b/json-streamer.c @@ -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); } diff --git a/json-streamer.h b/json-streamer.h index 09f3bd70e4..f09bc4daec 100644 --- a/json-streamer.h +++ b/json-streamer.h @@ -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, diff --git a/kvm-all.c b/kvm-all.c index 91518313b7..4c466d6aba 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -19,7 +19,6 @@ #include #include -#include #include "qemu-common.h" #include "qemu-barrier.h" @@ -41,313 +40,324 @@ #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(¤t_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(¤t_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(¤t_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(¤t_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); } diff --git a/kvm-stub.c b/kvm-stub.c index 88682f288b..06064b9a86 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -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 ca57517af2..e764682a20 100644 --- 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 index 0000000000..a145569044 --- /dev/null +++ b/libcacard/Makefile @@ -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 index 0000000000..927a4ca296 --- /dev/null +++ b/libcacard/cac.c @@ -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 index 0000000000..15a61be980 --- /dev/null +++ b/libcacard/cac.h @@ -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 index 0000000000..6fe27d5631 --- /dev/null +++ b/libcacard/card_7816.c @@ -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 index 0000000000..2bb2a0d8aa --- /dev/null +++ b/libcacard/card_7816.h @@ -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 index 0000000000..9333285d73 --- /dev/null +++ b/libcacard/card_7816t.h @@ -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 index 0000000000..61923761c9 --- /dev/null +++ b/libcacard/event.c @@ -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 index 0000000000..0dc7bd468c --- /dev/null +++ b/libcacard/eventt.h @@ -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 index 0000000000..b6859b0c1f --- /dev/null +++ b/libcacard/libcacard.pc.in @@ -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 index 0000000000..6f67a23d95 --- /dev/null +++ b/libcacard/link_test.c @@ -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 +#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 index 0000000000..b02556ee0c --- /dev/null +++ b/libcacard/vcard.c @@ -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 index 0000000000..47dc70382b --- /dev/null +++ b/libcacard/vcard.h @@ -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 index 0000000000..963563f86d --- /dev/null +++ b/libcacard/vcard_emul.h @@ -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 index 0000000000..397485c753 --- /dev/null +++ b/libcacard/vcard_emul_nss.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..59a1458201 --- /dev/null +++ b/libcacard/vcard_emul_type.c @@ -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 +#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 index 0000000000..0242f40eb1 --- /dev/null +++ b/libcacard/vcard_emul_type.h @@ -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 index 0000000000..538bdde3df --- /dev/null +++ b/libcacard/vcardt.h @@ -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 +#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 index 0000000000..38c3482c35 --- /dev/null +++ b/libcacard/vevent.h @@ -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 index 0000000000..ec126dfa46 --- /dev/null +++ b/libcacard/vreader.c @@ -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 index 0000000000..ec2042136c --- /dev/null +++ b/libcacard/vreader.h @@ -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 index 0000000000..f97e0a79ec --- /dev/null +++ b/libcacard/vreadert.h @@ -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 index 0000000000..609ae98bcf --- /dev/null +++ b/libcacard/vscard_common.h @@ -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 + +#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 index 0000000000..e317a25faf --- /dev/null +++ b/libcacard/vscclient.c @@ -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 + +#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 .. -e -d %s] " + " \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; +} diff --git a/libfdt_env.h b/libfdt_env.h index ee0419f7ce..90d7f3b162 100644 --- a/libfdt_env.h +++ b/libfdt_env.h @@ -19,13 +19,9 @@ #ifndef _LIBFDT_ENV_H #define _LIBFDT_ENV_H -#include -#include -#include -#include -#include +#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) diff --git a/linux-aio.c b/linux-aio.c index 68f4b3d757..1c635ef12d 100644 --- a/linux-aio.c +++ b/linux-aio.c @@ -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 index 0000000000..ca442d313d --- /dev/null +++ b/linux-headers/COPYING @@ -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. + + 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.) + +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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 0000000000..5c9026b3da --- /dev/null +++ b/linux-headers/README @@ -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 index 0000000000..fb3fddcd87 --- /dev/null +++ b/linux-headers/asm-powerpc/kvm.h @@ -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 + */ + +#ifndef __LINUX_KVM_POWERPC_H +#define __LINUX_KVM_POWERPC_H + +#include + +/* Select powerpc specific features in */ +#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 index 0000000000..ad58c90bf5 --- /dev/null +++ b/linux-headers/asm-powerpc/kvm_para.h @@ -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 + */ + +#ifndef __POWERPC_KVM_PARA_H__ +#define __POWERPC_KVM_PARA_H__ + +#include + +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 index 0000000000..82b32a100c --- /dev/null +++ b/linux-headers/asm-s390/kvm.h @@ -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 + * Christian Borntraeger + */ +#include + +#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 index 0000000000..8e2dd6706b --- /dev/null +++ b/linux-headers/asm-s390/kvm_para.h @@ -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 + */ + +#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 index 0000000000..5df477ac3a --- /dev/null +++ b/linux-headers/asm-x86/hyperv.h @@ -0,0 +1,193 @@ +#ifndef _ASM_X86_HYPERV_H +#define _ASM_X86_HYPERV_H + +#include + +/* + * 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 index 0000000000..4d8dcbdfc1 --- /dev/null +++ b/linux-headers/asm-x86/kvm.h @@ -0,0 +1,324 @@ +#ifndef _ASM_X86_KVM_H +#define _ASM_X86_KVM_H + +/* + * KVM x86 specific structures and definitions + * + */ + +#include +#include + +/* Select x86 specific features in */ +#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 index 0000000000..f2ac46a2a2 --- /dev/null +++ b/linux-headers/asm-x86/kvm_para.h @@ -0,0 +1,93 @@ +#ifndef _ASM_X86_KVM_PARA_H +#define _ASM_X86_KVM_PARA_H + +#include +#include + +/* 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 index 0000000000..a8761d3be6 --- /dev/null +++ b/linux-headers/linux/kvm.h @@ -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 + +#include +#include + +#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 index 0000000000..b315e27a9c --- /dev/null +++ b/linux-headers/linux/kvm_para.h @@ -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 + +#endif /* __LINUX_KVM_PARA_H */ + diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h new file mode 100644 index 0000000000..165a4848c6 --- /dev/null +++ b/linux-headers/linux/vhost.h @@ -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 + +#include +#include +#include + +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 index 0000000000..4f51d8f3af --- /dev/null +++ b/linux-headers/linux/virtio_config.h @@ -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 + +/* 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 index 0000000000..78289eedf2 --- /dev/null +++ b/linux-headers/linux/virtio_ring.h @@ -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 + +/* 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 */ diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h index 7182223381..f6284db22f 100644 --- a/linux-user/alpha/syscall_nr.h +++ b/linux-user/alpha/syscall_nr.h @@ -411,11 +411,25 @@ #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 diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c index 0a87c43133..eebd93fc00 100644 --- a/linux-user/arm/nwfpe/fpa11.c +++ b/linux-user/arm/nwfpe/fpa11.c @@ -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(); diff --git a/linux-user/arm/nwfpe/fpa11.h b/linux-user/arm/nwfpe/fpa11.h index f17647bdb9..002b3cbb82 100644 --- a/linux-user/arm/nwfpe/fpa11.h +++ b/linux-user/arm/nwfpe/fpa11.h @@ -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); diff --git a/linux-user/arm/nwfpe/fpa11_cpdt.c b/linux-user/arm/nwfpe/fpa11_cpdt.c index 1346fd619d..3e7a938253 100644 --- a/linux-user/arm/nwfpe/fpa11_cpdt.c +++ b/linux-user/arm/nwfpe/fpa11_cpdt.c @@ -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; diff --git a/linux-user/arm/nwfpe/fpa11_cprt.c b/linux-user/arm/nwfpe/fpa11_cprt.c index be54e9515d..801189798b 100644 --- a/linux-user/arm/nwfpe/fpa11_cprt.c +++ b/linux-user/arm/nwfpe/fpa11_cprt.c @@ -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; } diff --git a/linux-user/arm/nwfpe/fpopcode.c b/linux-user/arm/nwfpe/fpopcode.c index 240061dd61..82ac92f0ce 100644 --- a/linux-user/arm/nwfpe/fpopcode.c +++ b/linux-user/arm/nwfpe/fpopcode.c @@ -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) diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index 79a216a137..7f05879ea3 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -365,3 +365,16 @@ #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) diff --git a/linux-user/cris/syscall_nr.h b/linux-user/cris/syscall_nr.h index 6132817105..98f1a0b415 100644 --- a/linux-user/cris/syscall_nr.h +++ b/linux-user/cris/syscall_nr.h @@ -333,3 +333,5 @@ #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 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 08c44d8933..4635bb2e5d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -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; diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 8f9f4a5fcc..1062da3852 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -41,6 +41,8 @@ #include "qemu.h" #include "flat.h" +#define ntohl(x) be32_to_cpu(x) +#include //#define DEBUG @@ -50,14 +52,6 @@ #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 diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index 3ef71ce004..74abfcacb4 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -335,3 +335,15 @@ #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 diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 526aaa2a76..6514502dc4 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -59,6 +59,10 @@ 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)) @@ -112,7 +116,8 @@ 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))) @@ -121,6 +126,7 @@ 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) @@ -323,6 +329,11 @@ 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))) @@ -330,3 +341,7 @@ 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) diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index ac8c486c5f..b47025f08a 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -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 ; ipage[i]); + g_free(bprm->page[i]); } return(retval); } diff --git a/linux-user/m68k/syscall_nr.h b/linux-user/m68k/syscall_nr.h index 1c0ba07bfb..4d0937e505 100644 --- a/linux-user/m68k/syscall_nr.h +++ b/linux-user/m68k/syscall_nr.h @@ -328,3 +328,19 @@ #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 diff --git a/linux-user/main.c b/linux-user/main.c index 0d627d68dd..d1bbc577e5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -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" @@ -40,6 +39,11 @@ 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 = ®s1; 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); diff --git a/linux-user/microblaze/syscall_nr.h b/linux-user/microblaze/syscall_nr.h index 3e641cdb4d..f1fe0e7d8f 100644 --- a/linux-user/microblaze/syscall_nr.h +++ b/linux-user/microblaze/syscall_nr.h @@ -364,6 +364,16 @@ #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 diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h index 059530801b..fbdc348ffc 100644 --- a/linux-user/mips/syscall_nr.h +++ b/linux-user/mips/syscall_nr.h @@ -332,3 +332,16 @@ #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) diff --git a/linux-user/mips64/syscall_nr.h b/linux-user/mips64/syscall_nr.h index ee1d134146..36d27b5159 100644 --- a/linux-user/mips64/syscall_nr.h +++ b/linux-user/mips64/syscall_nr.h @@ -291,3 +291,16 @@ #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) diff --git a/linux-user/mipsn32/syscall_nr.h b/linux-user/mipsn32/syscall_nr.h index 60a99ddf6e..4e1aca3a9b 100644 --- a/linux-user/mipsn32/syscall_nr.h +++ b/linux-user/mipsn32/syscall_nr.h @@ -295,3 +295,17 @@ #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) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index abf21f6064..994c02bb77 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -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); diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h index cc84a4c04d..0673b7d169 100644 --- a/linux-user/ppc/syscall_nr.h +++ b/linux-user/ppc/syscall_nr.h @@ -332,3 +332,33 @@ #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 diff --git a/linux-user/qemu-types.h b/linux-user/qemu-types.h index 1adda9fbdb..fe7f6624f9 100644 --- a/linux-user/qemu-types.h +++ b/linux-user/qemu-types.h @@ -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 diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 32de2413f8..55ad9d8586 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -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 index 0000000000..c2ea151ea5 --- /dev/null +++ b/linux-user/s390x/syscall.h @@ -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 index 0000000000..d4529ac03c --- /dev/null +++ b/linux-user/s390x/syscall_nr.h @@ -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 index 0000000000..b4816b040f --- /dev/null +++ b/linux-user/s390x/target_signal.h @@ -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 index 0000000000..2a78a05594 --- /dev/null +++ b/linux-user/s390x/termbits.h @@ -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 */ + diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h index 262b236333..365db586c7 100644 --- a/linux-user/sh4/syscall_nr.h +++ b/linux-user/sh4/syscall_nr.h @@ -125,7 +125,7 @@ #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 @@ -334,3 +334,35 @@ #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 diff --git a/linux-user/signal.c b/linux-user/signal.c index b01bd64011..78e3380702 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -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 * -. 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(¤t->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 diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index 5d1ac21ac9..f201f9f788 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -136,6 +136,7 @@ #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 */ @@ -153,6 +154,7 @@ #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 */ @@ -177,6 +179,7 @@ #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 */ @@ -285,3 +288,15 @@ #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 diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h index bdca2a7331..70988b2ec9 100644 --- a/linux-user/sparc64/syscall_nr.h +++ b/linux-user/sparc64/syscall_nr.h @@ -322,3 +322,15 @@ #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 diff --git a/linux-user/strace.c b/linux-user/strace.c index bf9a0d9391..90027a1106 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -9,6 +9,7 @@ #include #include #include +#include #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 diff --git a/linux-user/strace.list b/linux-user/strace.list index d7be0e7a68..a7eeaef99f 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -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 }, @@ -292,7 +292,7 @@ { 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 }, @@ -418,7 +418,7 @@ { 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 }, @@ -448,7 +448,7 @@ { 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 }, @@ -495,6 +495,9 @@ #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 @@ -1060,13 +1063,13 @@ { 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 }, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 499c4d7d62..f227097801 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -59,13 +59,20 @@ int __clone2(int (*fn)(void *), void *child_stack_base, //#include #include #include -#include +#include +#include "qemu-common.h" #ifdef TARGET_GPROF #include #endif #ifdef CONFIG_EVENTFD #include #endif +#ifdef CONFIG_EPOLL +#include +#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_. */ 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: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index d02a9bf401..9dd1b8e4cf 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -49,13 +49,17 @@ #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 */ + +#define TARGET_SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ /* From */ @@ -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; +}; diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 0e67cd8f30..c370125170 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -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 index 0000000000..0ba6bdd12e --- /dev/null +++ b/linux-user/target_flat.h @@ -0,0 +1,10 @@ +/* If your arch needs to do custom stuff, create your own target_flat.h + * header file in linux-user// + */ +#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 index 0000000000..010cdd896e --- /dev/null +++ b/linux-user/unicore32/syscall.h @@ -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 index 0000000000..9c72d84d80 --- /dev/null +++ b/linux-user/unicore32/syscall_nr.h @@ -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 index 0000000000..8b255c4550 --- /dev/null +++ b/linux-user/unicore32/target_signal.h @@ -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 index 0000000000..a5fcd64abf --- /dev/null +++ b/linux-user/unicore32/termbits.h @@ -0,0 +1,2 @@ +/* NOTE: exactly the same as i386 */ +#include "../i386/termbits.h" diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 0b2439dfa3..2c4ffeb551 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -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); diff --git a/linux-user/x86_64/syscall_nr.h b/linux-user/x86_64/syscall_nr.h index 568a901d71..947e961ce4 100644 --- a/linux-user/x86_64/syscall_nr.h +++ b/linux-user/x86_64/syscall_nr.h @@ -293,3 +293,15 @@ #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 diff --git a/m68k-semi.c b/m68k-semi.c index 0371089b98..bab01ee863 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -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 index 0000000000..cd5a352cbd --- /dev/null +++ b/main-loop.c @@ -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 index 0000000000..8a716b133f --- /dev/null +++ b/main-loop.h @@ -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 index 0000000000..7c20a0703f --- /dev/null +++ b/memory.c @@ -0,0 +1,1437 @@ +/* + * Physical memory management + * + * Copyright 2011 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Avi Kivity + * + * 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 + +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 index 0000000000..7fb36d16ec --- /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 + * + * 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 +#include +#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 diff --git a/migration-exec.c b/migration-exec.c index 14718dd1d1..b7b1055e88 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -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 @@ -33,17 +32,17 @@ 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) diff --git a/migration-fd.c b/migration-fd.c index 6d14505632..6211124a05 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -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" @@ -31,41 +30,53 @@ 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) diff --git a/migration-tcp.c b/migration-tcp.c index b55f419b65..5aa742c34b 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -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" @@ -29,17 +28,17 @@ 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; diff --git a/migration-unix.c b/migration-unix.c index 57232c07a9..8596353d7d 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -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" @@ -29,17 +28,17 @@ 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; } diff --git a/migration.c b/migration.c index 36125720a4..8280d7189a 100644 --- a/migration.c +++ b/migration.c @@ -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 @@ -31,14 +31,33 @@ 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 ¤t_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; } diff --git a/migration.h b/migration.h index 21707922ef..0682179bde 100644 --- a/migration.h +++ b/migration.h @@ -17,38 +17,23 @@ #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 diff --git a/mips-dis.c b/mips-dis.c index 4d8e85bd94..e3a6e0b49e 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -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 4294761c19..7b610ceed4 100644 --- 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 : { diff --git a/module.c b/module.c index e77d569768..91f0e61cbb 100644 --- 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); diff --git a/module.h b/module.h index 9263f1c7e2..ef667304c4 100644 --- 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); diff --git a/monitor.c b/monitor.c index 7fc311d720..1be222ee18 100644 --- a/monitor.c +++ b/monitor.c @@ -56,11 +56,22 @@ #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) diff --git a/monitor.h b/monitor.h index 4f2d328db5..e76795f1f3 100644 --- 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 d8ebc4298f..e6c931c5ce 100644 --- a/nbd.c +++ b/nbd.c @@ -17,6 +17,7 @@ */ #include "nbd.h" +#include "block.h" #include #include @@ -29,6 +30,10 @@ #include #include +#ifdef __linux__ +#include +#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 @@ -59,11 +64,13 @@ #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 fc3a5944f4..61553f4128 100644 --- a/nbd.h +++ b/nbd.h @@ -21,25 +21,38 @@ #include -#include -#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 21d44432eb..cb52050bfd 100644 --- a/net.c +++ b/net.c @@ -32,10 +32,10 @@ #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 6ceca50fc3..9f633f8432 100644 --- 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); diff --git a/net/dump.c b/net/dump.c index 6db7ecf959..0d0cbb2591 100644 --- a/net/dump.c +++ b/net/dump.c @@ -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; diff --git a/net/queue.c b/net/queue.c index 2ea6cd0b6a..1ab5247a32 100644 --- a/net/queue.c +++ b/net/queue.c @@ -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); } } diff --git a/net/slirp.c b/net/slirp.c index 96dff619a3..6646ecb1c8 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -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; diff --git a/net/socket.c b/net/socket.c index 3182b371a7..e9ef12877f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -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; } diff --git a/net/tap-bsd.c b/net/tap-bsd.c index 2f3efdee03..4b6b3a41a0 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -28,6 +28,8 @@ #include "qemu-error.h" #ifdef __NetBSD__ +#include +#include #include #endif @@ -40,8 +42,12 @@ 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 */ diff --git a/net/tap-linux.c b/net/tap-linux.c index ff8cad0ea0..41d581b734 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -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; } diff --git a/net/tap-win32.c b/net/tap-win32.c index 081904e8d7..cb886d7fe1 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -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; } diff --git a/net/tap.c b/net/tap.c index b8cd25267c..1f26dc9992 100644 --- a/net/tap.c +++ b/net/tap.c @@ -27,7 +27,6 @@ #include "config-host.h" -#include #include #include #include diff --git a/net/vde.c b/net/vde.c index 0b46fa6405..ac48ab2f0a 100644 --- 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 index 0000000000..e69de29bb2 diff --git a/notify.c b/notify.c index bcd3fc532f..a6bac1f783 100644 --- 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); } } diff --git a/notify.h b/notify.h index b40522f582..54fc57cec1 100644 --- 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 diff --git a/os-posix.c b/os-posix.c index 38c29d1afe..dc4a6bb3ff 100644 --- a/os-posix.c +++ b/os-posix.c @@ -31,6 +31,7 @@ /*needed for MAP_POPULATE before including qemu-options.h */ #include #include +#include #include /* Needed early for CONFIG_BSD etc. */ @@ -41,6 +42,7 @@ #ifdef CONFIG_LINUX #include +#include #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 +} diff --git a/os-win32.c b/os-win32.c index 566d5e9853..b85d0768b9 100644 --- a/os-win32.c +++ b/os-win32.c @@ -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 327583baf7..56e6963f15 100644 --- 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 8bd30d764d..432b91ea72 100644 --- a/osdep.h +++ b/osdep.h @@ -8,9 +8,7 @@ #include #endif -#ifndef _WIN32 #include -#endif #ifndef glue #define xglue(x, y) x ## y @@ -57,6 +55,10 @@ #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 @@ -79,13 +81,7 @@ #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 diff --git a/oslib-posix.c b/oslib-posix.c index 7bc5f7cf09..ce755496b5 100644 --- a/oslib-posix.c +++ b/oslib-posix.c @@ -26,11 +26,41 @@ * 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 +#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; } diff --git a/oslib-win32.c b/oslib-win32.c index ab29eae45c..5e3de7dc8a 100644 --- a/oslib-win32.c +++ b/oslib-win32.c @@ -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) diff --git a/package/build.linux b/package/build.linux index 9d69c62d28..995b355dd7 100755 --- a/package/build.linux +++ b/package/build.linux @@ -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 diff --git a/package/build.windows b/package/build.windows index 64281a58fe..7e4174a804 100755 --- a/package/build.windows +++ b/package/build.windows @@ -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 diff --git a/package/pkginfo.manifest b/package/pkginfo.manifest index 3d15f16d51..bdf7b415e4 100644 --- a/package/pkginfo.manifest +++ b/package/pkginfo.manifest @@ -1,17 +1,18 @@ Package: emulator -Version: 1.2.22 +Version: 1.2.90 OS: linux Build-host-os: linux Maintainer: Yeong-Kyoon Lee -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 -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 0d2bf149e4..ef3f277f17 100644 --- 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; } diff --git a/pc-bios/README b/pc-bios/README index 3fc09449fa..1cebbbc89a 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -10,20 +10,34 @@ - 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 diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index e191908bbb06d6ab8fc6a3f16a63c57ce4eb1d6b..bd9ad0e78255baf80fdb0c0ad67853db0a9e7c06 100644 GIT binary patch delta 65777 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 z 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 delta 53931 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 diff --git a/pc-bios/linuxboot.bin b/pc-bios/linuxboot.bin old mode 100755 new mode 100644 index 708a22dbcc2b3f7b153184279fd0e4b8a445adec..e7c36694f997c3c34f7f4af3c2923bd2ef6094e7 GIT binary patch delta 82 zcmZqRXy9N8UBz^Iaw3zMk_>}NKwbbN69W{~Fg3#2Hej)d5}O%QHlFEW6by9r4Q24j W%qy)>$jMJkNiEu($W+A0_zwV_ffC>V delta 49 zcmZqRXyA|tUB#3ZAZK`>@5XVq6b1=~9=x-N!Xmp87&{9)_ zwB_2^)Mn6Ld$vS_K~(3c4;%a7yYHUwd*|G9&hd6PnCJw)-vE4F0LTJ(JNQi?!^jX4 z!KP5ZIGdZey$dlZT-PiwBg#yCb6^7#+%gJgE}coGNK%k)q)vhSQs(8A5{}m>LXhi6 zo*<`@E~Jyulut^G>9VJ+{`3E`JH{?$(>>{ewrsgKj^G~au|G8*hB3XvN@lfKFjc#5 zm`2^;BF9q*bOt@p&|Y1b$-R9on@OkDl3f>lchvV9jFZye4fRcUL{fbh$bct`10+3* zQFsREk?X*R7s_}+zROe3>p~N6POr{RBB(h#L5=J_e(NYQ1-lcF&`OMu6RoZu3 zet6f}m`t%)us?0NvCpjoLsTuP`?hASLZ!q76m6mE7O&a7qBTI{rl}g09exO!S=Dw& WmR#}Y1GJ2CL8z9fYnD9sFaH7$iDUKv literal 12288 zcmeHIJ8u&~5Z)um5MBxr1r@SLgOE>gBs)q$VJkovDTp5sUCx{MlzVY^28Sx5qJ!T+ zNtKd0PEYG{D@_IA$pB`MM&G$W079^cH)ez$l2eEs)#rP_+*gHo3YTJMqG zBwZpUakiCed@SvM>esQ;EYNxd_U6{cdbiVg__RzQev7m*jT>t`E)mFIB*j_Li~Xkc z9WM;LT<7GP+#On5D|zB$lb&vuvXbj8@WNiF+cqptv7NKAYqQuJ)c3(k>IbIhI<>`) zN?jmz{B&dnAe-kqZC>D=t>lHywl-R3zOo6|^r;Up>~F#$VgCu)%^BaX`BZ#Jp$h-1 z=D$Ibg!{cK-O4|*KF(y$73nC+4onm^mq`1y*ky|GoB*1-I{iqH@V=*UGy81&RL}UU zWHj<1N<;1LSeDV}8tE~qn&4*%Kc>H#XJT9vUI1>d1eH(GU zy4LNQhsH5F`y)!3YtFrxN5*_1zpNKajOD$+n+q*5c!wJPFiTrWs$-XSFey{NNM?UNT=m8G z0X(3$;p^mU$XGS|9G3{+*v-RMl;U&HcBzg+6}CU)6V|z_)KBDDz&Xw|pZPvoXU;JqM=H)9PC?E8)1UpUd%nwtg?SFOXZglP8AL7SI9mACdrzzN&0PY5^G&jOf8cTV zkb|1LHc^LUE|D6X;}4Tu$8ZgX{ui9hv%mG#{{r@aE=I{fhssZ))GLCWP^)EcFvxVC zyS@&?TrKCpOKt7)ThUhKx~k}2wbejB4}85{9Hd%hdQS~p-}8ss4TD&_C|1FV2xI2b z#wmhG@6aEeyPN4}BOUt(iav)ko*yRu{*0e_@gDsxVpunb2YRf6xX@WPN{f7Ix~Z4x zxR?p}NnB(}80t(dR~7c0H2P@VN{3!NAVQ|u$V=VG%lGF)W; #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 { @@ -82,6 +70,12 @@ 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 { @@ -119,4 +113,7 @@ chosen { linux,stdout-path = "/soc8544@e0000000/serial@4500"; }; + + hypervisor { + }; }; diff --git a/pc-bios/multiboot.bin b/pc-bios/multiboot.bin index d7da6e04ad6d71d26f577d9d6a019719bcce8766..f74a6e142fddc054d7f40ab346a108532afac40f 100644 GIT binary patch delta 130 zcmZqRXy9N8UBz^IvLch1k_>}NKwbbN69W|3F*(E8Hej)d650wJOlgdVQ`0)-7#MbQ zFr;?Mu`qPYSug<^Yz%4La#jcdDVPs61{F2d7QUGW|psQ~vLvCqKNoG=heu+X( Qequ^$(Pl-aHH?gB0YzjTu>b%7 delta 97 zcmZqRXyA|tUB#3ZAZK`>@5XVq6b1=~9=#D3-}pp@k%fVQ!ErJtlOfXw#?6UL^B5-=Fu5{T0RW9z B8_WOz diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc index ee6f5ae3b93a0570ff1eea5998716c361b15e989..83b7794ad1ca6edf4693bb8636ddb6e0b30e683a 100644 GIT binary patch delta 47467 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

lwYtk80;`@m|8X#YfHqeV)&p z$BV&QUjGbhM5=V`8N3Rd=JpG$@jRwFoRLiSGrZ=w7}Zw54D)&goP|9;pTfo9lhKB- z;Hv%XOWWpQ3JE2lnOZjyYVc` zO$|z^@U16dl|9Q!Qk9?zgoY)l^F}PR%iwQ6%QBHiTzr-_rZr%5Uynk53Smn_8E<+H z3r896d5--_(uHNt8d+nGJE{d{aQve$sx@M}+=w0<$%(#lHbSU-gBxJj_C8l@^mD zG<9BpkRV*$45Jv4mr1%jT3mHk&0?$rl~7h_R{94z^eo&WCVxKGgt{$J?Q{aD+!O5{ zDhIBpN4xT2p4Y-M_K%=5q-dL`aLvQnk8E7UUsP*B+|iPWVpE{lh44wU*-@>dEULN7 zTs|*eq~XwiC*>LBrU(t4DA|0X1v#9i8!jyL-Mq$yDKXBkyV!+Y>p)O=#Ey;3Zv{uf1?YGd#~tFA{i@n?1e@#sRl3-pkMdq~JUn4uqOpJ>g41m8EuFvIba;$Dz&I-O-WC9HXvgug#ZaJ+!Qo+{|`_-Uu_AxBQ} zz%8VWu>jF=sFof+gKl7^tQ9k;hc~pclemnuB8z3=HEkHfY#wfd>{T|HzRSYzx5HoL z5vbsibMf}r6?J&R?E$xnL)!a!gO{C#Mn=8t3TgDSY`geQ6~Z9!fuIzI!1^GhcY=?j znjfoW5A!d4mO1dLBmj+&&~}lXOdFIsz`PdnH{)B5i|lyneFcU}0GhpsA$M|{4?)5p zcly94T%!-VnCF8&_IZazDFN#WE&D=~xR=ovzBQz8t%6-*Li&byT?bzLO!9#aDB8@& zJJ`vTaY+DuZSk{L@zaoE{^4=Vk1#TuFZfx;Mn>rB43@A5ev>!%bf@3LG@RJPGFUi69g-!xw_Aac>=}$i|2qW-SFSop6mJm_b*t zJ1saF#Cu*GY*#U85M%H>+pcqTwGUi%qqtGpMNfu*h-2c&7S%!n1gC9-!`Iv*&Vk_> z2>mENZti4{JB9(FDS^W};%z1drX876pQn?)SJj@siz={7x!dP&@?a;sk}6%J1da0t zop|5n=GQ_np__am1RG%TX`G(Yx#xe9(pLQ?Xa$=1tuP#hnfG_G9G=?64k0S7>%w>n zP#a8Ou?vRPe!J`imX#!ubHZcna;cBhwHIf=kA(U3!!R%2kHI=Z>X62Z%Q0A}v$IgR zgl;lQ*%q)O2_vs4VL{i+xCfuzG=l-dCUaM3p$@E#A$At&u%CEsDYBeG2 zM?~?=&;YE6pHzz-J=N<87dTebFZ1hH5y{y3})$_04+dcS)_~((+k?1cUtCljG5y_dc$1@|^GmoL%LHS3N ze@6K>3VyuH{1(a#$}9?E6*HoE^E}E=P!>@>LRrS|KP91BPL%p>Zr3t@Vbb!k7#q7W3wjFE#I%&^!KCxph1xyQc8TzVq=i0>o1#j|J3jhEB delta 48446 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

c$nfz#*!oARbj*$8v5+Uh7x_l)1kXt6 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⪻pjjEDKS5_}m4+8)dEs4DjH-V(HV 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 literal 377388 zcmd444|rA8mG{5z&CR_b1h@$y|ItIBNs1H$qT-*LQ%fziwo+>?ZLPftR;hJ5jAO0S zSIZ$rq}FjlM4Dl&Jp_u>I&EYqrHnPVw;9TG94Et2OPy9PXl=%6ZH7UN7;@jw_uO+~ zgF0`2&oj^OAuT76_-V#5p(=6YNEVHazg=Tfhqp+#o?P{ zBBsT}O|jDXUn-h_t~i}GWm%CW_%G2*(yMw*M1}vPSAD26=|n8}72qIe;YfcOxX4O> z2{=}OH!e2jktL$5X%)_b-yiZn3w@$MkGyAqODuRV@B|Bf8o1Pge+E3!f_DR#S#Sn; zk_A5rJlTSG0Z*~u9l%Ko-UeK5!QTb0u;535r&{n9;7SYb1Dw!<~wotDk6`iFE-N7(CL((4Q9z^j29EVvVRdI1jkM=ky@lYV9)9sb*Z z9Sgn%c!mXk0l3kEZvvia!8ZWUvfvKjcUbUsz)cqXN#JG+z6Q9(g0BL8rv-l)c(w&! z4t$mcUj{tKf-ePrmjzz}JlBFR1U}n>&jSv8RXFT1A9$XXJ{Net1p@Im1BS@3hfms#+$z(Fh!j`;Ho@M0@{FYpH} z_-WwFE%;}^AGF}zz*kss2KYl3{3P&)EqE93l@`1Mc!>pX1OA8we;4>F3w{*%qZYgc z_-YI81OAu=KMZ`01#bZUxCO5VUTVQTz@M<-`++}c!S@1x%7Rw|Uu(ggz@N6@uK-_X z!Cwacj0N8YoU-6sfZHwj3&0%~d=v083%&vPdJFCV{;UOG2YiDCe-ijc3%&+;xdmSZ z{5cE$Fz`(ld^zyvE%-9vn=SZK;6Jh8OMt&%!50GmsRf@0yuyO#1OJ%?&jr54f@cH& zxdk@?-)g~)z+bfBGk|Zi;5y(hS#TBb?G{`C{1+BH8TiWqrd z8wdW11s?@oX~9Q;Jqtbryvl-K0q(Tmmx1rH;Fo~AEchVs-4^^D@M;Tw7Wf_ueg=4r z1@8s^ss%p{e6I!n4ESpnyc_sF3(f%lr3F6;e7^TJU#)do1`- z;0G*t3-CG%?gM_%f*%H6Z^0XYziz?nfqN~u2l%fo_;hoSnxH# zTP^r1;BQ;-hk+lp;LCx(W5JgJKW4#~0{^WAUjqDH3%(Hedlq~iaK8o52Y%dw=K^oD z;Mu@`XTeRt+by^e`1=-o2Jj9Gt^@vo1y=#@wBQQhA6oEa;9VA63jFsL90z{Ff}_Ac zIssRX13ziOM}Y?{_y};?f)4@z*n(dH&RFovz(29zmw*Q?_#p5%0Dj$qCj%d~;8Nf>EI1B4 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 z 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 vO>N0kW$+{XdFLs0mK diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 70a223d573aead9505cf2579e59af37b897c6202..c8972acaeb320a74a49dceee3c2cb1190d2c8882 100644 GIT binary patch delta 39840 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

~`tczr*OLVD-)$))F2 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 diff --git a/pc-bios/optionrom/multiboot.S b/pc-bios/optionrom/multiboot.S index 913183739c..cc5ca1b7d1 100644 --- a/pc-bios/optionrom/multiboot.S +++ b/pc-bios/optionrom/multiboot.S @@ -20,6 +20,8 @@ #include "optionrom.h" +#define BOOT_ROM_PRODUCT "multiboot loader" + #define MULTIBOOT_MAGIC 0x2badb002 #define GS_PROT_JUMP 0 diff --git a/pc-bios/optionrom/optionrom.h b/pc-bios/optionrom/optionrom.h index fbdd48a021..aa783deed1 100644 --- a/pc-bios/optionrom/optionrom.h +++ b/pc-bios/optionrom/optionrom.h @@ -97,22 +97,28 @@ #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; @@ -122,5 +128,9 @@ _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 index 0000000000000000000000000000000000000000..a92372c107af72071e265e1ca94b9ae5573bd317 GIT binary patch literal 185703 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 literal 0 HcmV?d00001 diff --git a/pc-bios/petalogix-ml605.dtb b/pc-bios/petalogix-ml605.dtb new file mode 100644 index 0000000000000000000000000000000000000000..fbbd45fdad06489c6333b6de868f44dfaed405bf GIT binary patch literal 9982 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 literal 0 HcmV?d00001 diff --git a/pc-bios/pxe-pcnet.rom b/pc-bios/pxe-pcnet.rom new file mode 100644 index 0000000000000000000000000000000000000000..512d6d4339b7b3e3ea8b132d261d553f09bb3d96 GIT binary patch literal 61440 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 literal 0 HcmV?d00001 diff --git a/pc-bios/pxe-rtl8139.rom b/pc-bios/pxe-rtl8139.rom new file mode 100644 index 0000000000000000000000000000000000000000..67c77fbf73135d9f81467cb36d3d1c64362ba8c5 GIT binary patch literal 61440 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 K|8M^%8TcRg_~}Lf literal 0 HcmV?d00001 diff --git a/pc-bios/pxe-virtio.rom b/pc-bios/pxe-virtio.rom new file mode 100644 index 0000000000000000000000000000000000000000..b1ec909628998aa9289b915e59416717e718a618 GIT binary patch literal 60416 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 literal 3336 zcmZuzeQ*@z8GrU}!=CwoO@I&xl{ev#L=cZaAwY_|;lp4po`M#rtvN`5laQn#p@LPe zB}Fa$I8w2#w&S5(-WJ<>L#L%d9k+hWl==q@GXbpA61t^!ygyhlb*O=Cf6se~(y2GI zd+$E`eEgo@`#jIP^6D;PT1nzbK~v=%3d(LO#(zL|(nL8(1+MA+f(|@o z(uBSVQ~`-Dt9@S%nJE=tH-`H)uQwV(gn!FH{{zDShP>>n-Z~0PO(Q(rhwHbv-h$6E z*Ayn{t|f>{Wi^o-F#~jmQOO3RsBSMxb#=05!3tJIU7==xljYtL1N2CT*1lR&v0c2c8y27SgmKiXHvnRbq zaCiztoRmZUI-sn_wdQD^mqO+#XwRiWDpW{KRs+%sXyo;UD2V?*f{|&iutKEo4d+o` zfbIu_rJrRF%h`PuU^q-;WEE+!G+_xuax!=j0z9l2mM**fck!NFlfBAXqG-g@t%zCZ zT9;WH60lMkjhLbA$;;3&2H^`eLFAae|L%_LC9fUq5BZG;xemH%29TEEy>6SPR%Vyi zD|x5?G2}JywcHV~dt9!Ehl{@NSE%QmauHGX(q*vd3_{wHTN}fMk>d>!8e|#J==7#s zMJDVuSD;?PcEn3X!JqQ85jvajbeMe)e+cb5C4WG!3Xoi{1(p1L*c^iwO}%S?JfP(7 zsb`C^C~VbWp$ZiwyknF^{$RuyM1UtgJlKz@T;r+dI#AbCkg zp4+_02;TjS67_{BT7_aJz`K3!QCR$)`&~VCIT^^h)N?ylhn+^;A9fPBKkg)P-|x}@ zQL=>V;vcR#pn*kHB^9C4^N`6+RO5<)0443{K%N{+0efDQ>}7)N!-8$PAPXYX*IX-8 zMqxLSF>xQrp#R(y+A!=!Ga(8eq(*|)k=Ke(k$j7KT?^fK06iYgmT-@c^mGJ0t;_Op zzU>Tr&W$8sX;((j4GDO)D}gh=yKd}#CQjb2s{TBd>bGU`s+ z3OVO0jqOlhr?}FxFMClnG1f`g!g~$!T7+4RO5utQ7N5qH7sTtpopyzwgNCYxnb3XH zNkLj?XS`l8SFmhuis~a?FW2bxY-Ynrcf@!2C$hG6>Fg0<`Tvxgw zbSn3DHBPxfn#Guuyvd0WY3F1EW^dF>Q&LuG;2Xl^Ydzz(eJ6xE4Jt5=?@H$APs6SQf8H^LFrN&bK2 zWDx=q=J_(_%pR|n_y2k$&LKp!9rZ1tCfD^s=3YDBAM{e{G*L57`wOGG_NRm7=s>j9 zPC3HC#5uDE=o{QbJG{7=6yK96%xGpASFN&g)vTN$PXN`c3Fx3UUcuY-oC9lOe{Oc` zFb#6K&m76U2l9OR4o;ern4O)zi!Y9T&R2U@`Q3}y)9qAB*yfc~pP)m~FL%whLhkW(!G4*bPtnz)=`j96x&fM&tE9b!2NWbtN zYOio_p3!+HT_%d_m~&9vU2Emu(Cq%8L#UnZ-1(s8-rdTxy8nGwz)Z(}!&b#ytLoEm z99XUZo`tT-@A`x0jXtI*-4I9be_O5tlctJZs}0zesp`Vw>134f7YU#KA-MriEK8FM z{42IFP4t}3Sqxo-}hL(GJ- zxQcH(RGhN=J>UH;$m}o`s3--Wepw93(Ju?c$^8PDpD_O9H?H2wt$lw))}(=+K+w3! z*n_jZps;A{IJ3B9ypbO=$|ggiep3x2e^R+x=8eH$DKB-tO_*p*5&qup@1%@(+0$Zu}Jbk-0VV=6`;{!rDcK@hqNmOw6I8e4^Wy3R zyNTkhJ7X>JCb2!XCBBI^$Kox`O`@eO))a5uB6c)y+1}jRnLjG;=xS|c`R;go3w-U2 zcXY@M`SW64L*%;fjO?0*)c57FxMS!wc rS4*cr#ExB~81iXl4iog)xwvPI*xb>!U2KhYG>NA8j&1*w6w>=Il#<+z diff --git a/pc-bios/sgabios.bin b/pc-bios/sgabios.bin new file mode 100755 index 0000000000000000000000000000000000000000..c3da4c3d0a34e4eca9b0cda38d0538b332f7b09e GIT binary patch literal 4096 zcmeHJeRNah8Gmw(K=NZ!#YiO_$Hpho3C>|*k=364AM}*OQ+`H$d;Erd1?wtL_ zdrscx_dM_O{NCq%?)%)_<*#K9x2T8LsLwZz!svOLz$lClLt13p+N?4PpsPn6{(7CgLT_|Gwe#g&&%N@y-~Z{Y=U;g8 z>EAx{?3=%M{g=D%kmB#V#y>;iFGT)H-|_$IkH7wd2FlAf&4 z(K9!L)zW+!O&LAG>I~YmE02WU@_&ZX!e`URplc_v)&RTzVJbtb^y zKF2cAH_MXAswSND$*AVA7@giGOh@BQ&zsL_)_w&O$}D71UB{0iB=(`uU6m?*QDyz~kk)R`zx zRE2jGq6-zEh%Uq{j~62G1{rfZ@mh`wT@r?XUYW%G@}l}aPm2{P@T$dN(PozWQu zN)|Qpw^ZR_WGrPqnT|5@E0yUo@aF~=XyCs&8^7bMC$5Z?#Ji+j(HQ|5f8xmCI4ggc z|7=M8&70D3=Vth(rkOjVf*dP!-OAq4c@Zc&4>LV-k(Q&tSedaagIl1H5}3y@6)?|g zgL#bE+yNGbsRWC)4uQF_14a+C}WuUP-b-?Fwg3M2NtQQXh^$+!F4)Et zBB7nZJsk|%mRRS*65MPdgRTpiMPOxc-O4P0Mb-*fggM)+m0-hUYZ%xV3du$omosuL zKI3bP7_mFZMbT&Mk@@aUo4@YyvlqC2okrgavg7*f&D?(Ouw^q#g)+B>8CRsveBkT_ z@}YQotUj{bQD^hCfcXG_j{H;fm2nF|*jMczQ}{B-ry@Jr`>mWmM|a&@m3h`To$i`h zm3hH;^PE;-<<+s#ah<&y`@$6F&+!Wsf&B_+J+m@mv)5q`Q@H)_j*7$~_83l&af9jH zM(Qzn2d38J_bIbC_jb#UTMX@rUOy(vL@X+w){^PF$)fhDu&d3}iDe{pRQ<8g9 z`F3HGw$}*8vWFGb9XNG+_#E~SAix{fI&@2p{grSp!{+I?m)WX4-QW%I)rlWMp z)L!ta=q?n(LAs=PZ(2hk{DZVnI_w&LY8L2S5!;I7?k!=gK(QFR(%?+%q(eLtm#_mD z$&ba|T!eVx%(o4UWILwjBiz+vYA(tRN|9M65*IR)J{5Nr;YEQvfr1EJxZ1fF2=|qiBqMIycl046@k2wvP@&;WGEHX-3h!Z5TOEzGOxT>2Rs_2cg*mL zv0>-fD*jyHgGqQXGWeic!!tdpciTyR%5>Is$UU4fX0sE0%BRBnEGI3Z%Q-ydDjqnU+9(8d zS&;Mbm6JLDx^gP>D67J9KAAF|^ougYYO*C|68#C$r}ifVHY=1#+EX~SN*)Qx!$4N2 zy+u|{{6eULI4}TT+;Z}aF#h!M89Clok!J;l1XB^RLx`y)eH-dtAnQ|sG1&%rO)N$% z5Fs=0&8XD#BRv$GMH+>z2axD+Dkdk#Q#~@Qp&Z}I5u22{c26{0b$C!=<0Jg7dS^uE zKx0?gY9OaXMvpC#_BrJrQXL-hM{L1cgPK)r+yH3Bh>kBq=DM|j4 z3@sy(1TN8?Wmy1WRvy?-MOI-e*_ZR@f-5vD*FB`(a+Z}3&lLSh3gs@rpOm8FDaW#_-nRi+9QP?-3y2T1mrY@mPVYl~Hh8^s z8pAqFCwE&+-damZyEDU5r*I|-7PUeoBwOJnQ^S&--}2XZz}N)vrcft-w!S&6<@AV=dQ zFL9lwzV8^2a2%7SyL;i~#V~-U1oCA(^cXomMtAQ8Zolw%&bS3QV;zuzIJp=fP}YEa zK-mQMMU{k(>ojNV1){$~-oMg! z5=d>F-f5z?4U+aa-nY&8Z$p~nn+a literal 0 HcmV?d00001 diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin new file mode 100644 index 0000000000000000000000000000000000000000..1e84582cc695ff6e5973e045ef31ca951ca15c79 GIT binary patch literal 738744 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 z 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 g&v$NbNACO62EL2Bi{{=neEz@X&Uz@PvCJTV0q literal 0 HcmV?d00001 diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile new file mode 100644 index 0000000000..dc8b23e3ce --- /dev/null +++ b/pc-bios/spapr-rtas/Makefile @@ -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 index 0000000000..903bec2150 --- /dev/null +++ b/pc-bios/spapr-rtas/spapr-rtas.S @@ -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 index 0000000000000000000000000000000000000000..41006f40370a739eaddc05627049cd78a7758136 GIT binary patch literal 38912 zcmd^o4}4VBmH(YTnG9jb3?aY>kwgs&2r{6B2m^@_2W_d0P!+Mu27ys&7HCL9`r8zP z{Anf;ySwe$?b^EjYWr)~-ECv5?MPZX5RAH}2(`6TT$`$uHx33=3?WQre&2KMeQ(~& z1pjpR_u1d)voFcKd(S=h+;h)8_uO;tyKi#KW6Kkl*+kAYmSHz8`K$=nZfvTUH+#vJ z^>=S8yLH)hOYYgSt!!F&>5bFN#QKK1x{aIbXRUACRyJpTS=ro^4}HCCZeY&bf-z#+ z(&TE%V=~Kbx`jy*N zgyL8(Ac+==P#IJmsc8zxK{ujR0 zlJYjVw2RgyelA*4laO3kn|K__(MV2To%laukz*{9@86Yp2+*R2#VzN3$S>NIXcsN# z14!PwDba%DoQ6E@;Z4cLmh*Fw`st=*ZOi$qk^1*d$va!lU(>KcdvjBA^`gnX`s-U# zJ{0uSByVg$+DmuiGTlka$>Lm ziF0317P_X?bc*-`$F&XDtSim`_KWDhQ^YcMNPzElb$6({(`L7$+?J>AE*nsh&lfhQ z=*WmMHm6fOlCc%4yVvHhAuoI~Zyzi3_9B%ZXUlV=+_6dJCr68u&;G~^_`c6s+nt&-U#Mc;aChYeK z9~iPnsQxWG!T*Xeg;Waur+FWI>d}mF%gg7NSE2B_xw@~w`#*mCSrGq;4;ufnQC^In zp+9j+PU+7Z8DX^!v<~;I{&N36x<1RVIKSfB1q*|V7FXJYNq(}e|GA&jF#p|d z%>TPs{~oc-|Kd`f|HI_xG3I}v$$s25lKuDu_5V!!6Ta97je!2VA@yhUVo@bW^X>cp zFio6rLVqf)KbG(cqr<4QCT@-{P-E;D`!-WhtvoiREPvB6Gf2Ys^ftQJVN4{s77@_hH3+Z z3}K*{Nq#c zUQuZ+FhNHym^G_%&aBFLvnm(Ns;s2n1(mbrRnD4IX)Q28M=lVeBwv&iijwi7q=bIQ zmx#g=kzZmhFhNHyC@d@)TUau_u*6?jQbND}lEU#Ng=0&s1t#do1;xcB6N*dx#U+!9 zOG@Z>Qc1DDq(ma>3})KF?_1n9)A(XrGUMy}r?7e4{-+Yk>(mask_c5k4}# z>q`CidnL4anT1T@1l2?pVu zWHKkZfS(b;$dV?0W@BMO5Pft@Y5{U%;JN%VbR|W!GPxs!t9(Mn( zx8mPi6FhMuxaONJy#wii-WFjmT%2B9Xb06De*cc3AJrle5fS$uKmON~Cr=iO*H_fm zR`fIx&pUSPU_78@7$4pex$4M+El=8mn+VjTYXXEFkH^!vl}9p>a@{$f)hq&A1GrM6smD`M(FQ@d1ccqr~Wo~ zzxLW|@g@-ffmBbANJS#ekw^-|3AtfB2Wl}6wF4r3=iNt^j8Uye zKzg{E#1s$M1V3*@YMW{!Z;8_o&z+I9=i! z>b%Eg7fqxf{wC-%kh51Nz_KAglcyQu+FMhD{=Z83o;cbs@c;}sJWY{078U?!QM!0rb|80N!FK@g+nL2>|y2>H*UuISKJ9Bu)gG-W22;BTSza zPxu1OfxtC1epHS4zzzL}LcW|%ldeJl+$F%l561Z)0vl4IBoOEg1WIUL@E>IW5{=X~ zx=0Y+kQ4RN?`aY}M0kfNQT^P}6?83*R02$L*&%w>9ev?EAe#ZdR2p2MJmUy_f0C&I`B z&U}KPyi*?i?(zr8(8z8857r@p`-6V}v90JY z_oqVf#{!^sOBDS99xzPao|CCpdql9dcCpwYpa)RiW=t~}8qyP7sd$`jBISW)?dtA% z?dnL67x&}yx4h_3CQ1kZBUb|ppAo3RrLFSkmdE7J@$JX^=nq0Ot^rOB_~||mS3mx! zp)}uhc)yF_`h`-J?{|^;BRJjtpaLb~OVaiGOBwF>lUbxI!|ef%JLmC1APFyJIMJI= zAM@r1DhWwc24w!MkaRNQtSToss4{%syt53a)(DSKbbO*ulrmgz-aMj9T$B<}$aX1J zsmckDxYGI6`$c?b)J6D|JgqLTx(G&Pn0K!}_bTR9Q_n!p07fv?1H%`G_^=Yd{-=6s z0%VV|>Kr?EY%ABqI$=VLtk7Ty4S?X ze#dJnNSWz^w(t+;1C$d_B2n#-(*Xa$!P9wqSS zg&8_o8!Tz!UI?)j1c@6Vg19&_;s^Nw>S&M7Ru|2fH4VDc9Ux!y{Ya z>2Bsy`hYMvZBW5D>ohT7vW!PgZvmysJ>kNvlOnUqRgsx#@IR)>Bw6c<=4RC#HQd}> z0q1Ol3xbASQ@ViOkjtZAFa&EfS1s>$w) zPKEsrESoTLxNxTnzJ$DV_ebVng%x#GjCKuFA*H96;I44(x^u)u(nIQ2a`#s>Nr|d5 zM#VZtS97<^6?C~2rboI?@SW&NL$)cS46`tvf(s$XGTlv7a4}{x!HqIX?Qpp~QU@i6 zMwd9DcZfM5XM?HW1KNOJzSs#t8#SB*O%JLnGRVONdo?b3k;^g~Wy};t5bg;4F}i}0 zgXqPr>*GbG|79D{u`mfhl3A8 z-WXlv$w^<1a>}1mRN&R6$*t41hscw6M;G@2HBWPnUiUi9#1H^cj_asl0G%p3w|U08XY~ zewjT|DkV1*7bo$-!(?zxWz7aRk{30v*j>%?+1$OgMD@?dOIl!FiB1z;F!h#Nqj*hT zJb-fi08l=?QASgcTwA)*J+M+z%L~z)t@vYABFn`Q;qXDoiSm zi~5TtIm;(ztZ7uB2J9@Vv8ABL7-?FpvpEEbrW~jSBQ?|j4GK{)jWnoab3`SZqlKt~ zdPUW+RGD*xnJw$?*3AYGsc}+&^0HA4HYXjaX|7Q+Lk}D0!IjxeG|Ag0cN_jTF3Fi` zj)50FCppt|@Oey9qOz>a5Ru`RN301WN&Y@AX$w@5n#Jf?1R6@q6)s)n;j7an*Lt;j zz-b>i)bmr7_BX`jB}WOoQuc1dyWNaUft{QFBU@PB8MMd%*Cv$v{tK%^JezI69qGEdGuE`^{lCCmr}C@aGSBor?)IFT7W zWRXPlz(tnn;fpNOgBZP@qQZqTfI*TAWmtnG^I|R2LmZu^>XFPE;f`#hQbL)E9{Na- z(IZt)4})Yq6*S4#Et2pLlf053Tx`>&^CCfdv?T9(%p~uslB&SB##fIWqZo>>=I&H? zH)7!`HNT%;_W z@-^7lz{l<5vMKP!789-{qK9IfbGQ(Xy^ny5b0q<6`_$9~N+c%R3|K9h1B3FHv&yBF zibw7qnHju zZIXM)lx7;)kWj{p*`N^RdQ_;wLaeP)9dv2R$j}H4g^Uf2;E=>QEId4oE$Gv|*#L3M z;`HJvx+6F&MwA->Xi*OnX@^?Ii5w_my{REBthGdn&>%fn%+gcxl+hz8h?JjFm2Aie zjx9kWf-Ze;TOUWvu(Y1WUEk|gAZzeQyj(DRL=7218sQ1LYK|d+U=AZ8Oc_U-0!hJ< zWKH*8*}NW0Dz^##c8x4hpO`g#sen>o2Jw}R6OBD}yRA*;(XxRGC{nBGosK^q5qi?{A^0CW@-w zlI_X3G}|6Mjlyu^lI6N%r<-%#xa;GQ0`IW>27jtNCq~uVLph>Um*D_rj(<~5S+&ey zIOWwW+hW?+%H5?^9>Q!Mc z89o{JD*e(UUlscDF0nzG6C5n+<}ACbBm-bPL9y@;-9vw~<4IAXML&RV&QmmK&Kt3C zRvt3!li{$6I&9R$h{Rw<^`! z!`jz{+1I6StQylx1+d?~H7Lk$a!>+31a;hkF*PyOkx9+9>v!je#qr11xV#1 zhaZ%IHLZ@A5vI@@0h%SaCSO?(uZ20frnEJ}zU472?jmoLMK~I$%_$&`2HXk0H8#@&SzFvQL z|CC(yTcyq_<5}Z${ZSZN{vugMNHXX9xIaUrlMyJ z=*dFx=A{bhIg3ZCdQdO)s9yKiK?R{aJ!4guHMGZ*SdQ(D;NGyWFud}@WRbrrZwc}F z5f{17hD(h!jJO`=Tc6PCZyn$A(4zSWZ7Q_}_of(b3hn|B$1@*|+~0M~A(y^PfJoO3Q?*tGo2~t;%oQu%Jx6 zrgYW%nT=(0u9`oW-n5!CJ1}qd-1&I>YQd)}7F<2Itg)_PD_*UtFT1{JYgzf20x>04 zB_24|=@aewQ(w%CDHGBB&OM^T*P7q?712?HTdU|ehg(#1+>F~s(J`tuzqIRdyNGiK zNBHQ9;WeRSPhTpuapLL4LK`EV-Yc|x@pPxqY@+M_V-LimXXiYB_GloUdhds4kKTB5 zOgK6P-jTXJW*gTzT0}qim9OiT=%3m{MXkMoHxs{ewuOoUZ-%upS9LX#<@YAbQ5J}M zDx;yI7f5fYkrSwo^tG4 zTa;z@ANxmsnJZMN82}(c%0_|ONl=UorJ6<$z~eenZ^l< z<-FOu4izRmHi@8s_XFrmoD~*eVSs?ITY=wT;ID+Fsa-UOaGnMZ4Uyg`_@WlI6p#xN zk0=USUjW1UcY5xRl-sT6enYuNp)1V3wQeZRgzQK>Nu-juCOK0mhLrQ?)eK+4@S7O|9Mr1g&;P}r_i<@kCNV(bNCvg(bCXM1X1cWA zn+tuFlcb0zi4xfHxz*JsaADFjv#dTobA0`QnYQ}li67W>nVU8DLR$1yG~!FtqYfs~ z1RB%m)kd?E(QINh_$x|Yy>G2&6^LkwYasPx0GN#L(^3GqlBHR|lM4tyY>E2k!P0N= z_eaTa2@%Y9wWn60YGN-&SaRcI==ocqbjdI3Ko0}$w-NC3 zk}WV!O3np=H8fgFW5Py4Td3|=tNWF(G-rYZ+b=OJO>kl7g2M~mSa8Y00sP6Iu?sI+ znEX}Jr7B_QXTkcfSX3gmFI5I=+rsF)6Z6vZisoNAf64st{Py|J%ztJ6;QS{RPO6w+ zv9jWcgAxV$x$97h490Vgu=e9Bh_)@{OkUbK zry#mEot)A6F5fThe0((JCv|?&L-(Sj53+p)a(xYdujB76vSO*kw;)kx;LT`P+gJY0 z9(Z$MC{_3Q_E0K%@My2?h$ECnK|W3B=h0dDX6b@T){vi!TPpt)aeHs{;H;0^W&572shBIMo(9Rqoy$Z&<;+Jno>@ zcXnNjmRuy{ZV2WNgql-KW1!j7)XP)l_Mp9C3=}O)T@PLX{Maj~`Bn6o2DLv~k!kFY z#R2*|NzCXe^{PG8Z|iDXb{REDIGYIvK*+lvw?*SbV?0(2#;NdTDx_heOtqdlgv@-( z;N|CV>>1>ybIvBH^-5};P>Kl%k~hHA4r4*Hb)hfI@`wqlpIBsN!YLY`GWF#!P`U{v zhYVU7B^QA>y0mW?774}!%^5Us?@lziXi9F5-5APsJ2cig+@0OllA)vO*i zD9zyxaK{{cliymfbKIlN z{H+B$L}`2IbYihkaPOlY8+`gl3vH#zYZYvw2{u*1rkY@5lipcwQU8lsE>Yhz%P#7V zEAzbT&;Xg?N;bo;^3v82It+8%dMFULhg>bcfq_V68dI?vC6lgeX?S$WZ$}P>^qeuK zUm`%1toXTd2&z8P9!f95q+Z(=as}PnZX;bU+lJYIHmY!g6J-e zFp;zyz*4f9F{-jaf)0m)XG81GRdD-*u>vv?gW3|}hbd$34`S}mAwX=jEG?I%WXfgf zIA&k2T)Pfod2t5w8+k3tG)lo7?ad1-QN+-eD|V;K)l$oth^Vt5H00eA6UN-xpfjaU zg(?C-0MQVn@518P4nf2z{E!P^;LY}%2G1slsrH)&&L%t=ta&7|uT@2Ve>PzcWiT*~ z(0kR@FyBVshvtJS7R6X0_3n%oqE?`Xk}`;$q5cz)j0ItoQ>G0V)PE`+M*w~0UXF4M zC2KWoL0Wqj4bY5X=QFLvC~Fdtp(FLg2(Y-)-zh9|#thM|R2XpM)7ny>l)G@?8$e|Uf7iIw|7bOu9eoZQxlPv(MBG8}`_l1#Cu{>KiMhpLcpg|{?4xLXf zZ41%5%Ot7(d08KxXgDSw83CSRxb`$6jsl=pfe3C3LWOlt#_}L_qW@*0Z}cE#5I6Mz zjaqvU%d^YMRXTG+$vNB~Fd>6W)FBqJE>hoh7PSO|C0Z`Q3MTi^f{>@~S%a1LC{!|7 z`A}gV)$E~6^|IWsXpPbu|PSL!U;%Nih!0 z2IFYAqh|%lB^RVBMKB^UM~DV07S_fS4a-1z@4HEN{t@_m*x+Qlnx?J}B^w}L?rDW} zWH2PMzxuG|^jBMoAlIFo^%3>-9%;pdZXMKJ#xTOLxG~Jq@IyM#KAAS`(Y>e+dz69y zNA_sU2rf$1=mRSeH+}cx%YR8oDqvK!5=N z3VA96qcM*J2MYiVo)Ic&c~!^>lj~%7_k2 zsTr^>uZsVoPHhEoOlsMiZT93ibnpi5AVv!v@a~ivW6KNzPK$zxDHck8Hl!J z_Qcmv1B2<^(@p}R#C=FW)4Y4WgyH9~(-`@NyK;2x7Q=}DHEk&Bnx~95+k2@Y7YL$C zuY$}B(>CU!Yi3h-m)SP4!&yO6%`6w3NBEmT=pe3m#CT0iE0`o&hx;c}0 z2QnHqn2y#EOgqiY?b2jyl_uk!oMF5zXBe*^Y2auOQ)&OgIc^5j%L~TeFqjO;&u?2-Mek1?{z;$#tRZv~;^KJQ4Wb#OWS|C#XrcO81qSogkiC9iwrl98(4KZDjics+wzKm0xT;iq*!{Ace= zKOFX;9p1PKaZ<+WIG^YZTOH>Sj7M)U*L_DE2`y1(ZiuZud;#mS27+=~bA7{$Y%)WlLP=^Uvd=84g6j}I$Br&h2(nt1agyNF5=F^m3?d)IuE;+WT%R~?{sp@ z$kJG**Dk|O(2P(TYcE-?a_m31-}K%~z17uoLn)#)cE39 zXT@jfhDR0fH*+Ke{l$h1);5?KSeAY}#`ZUeJ85?O2v0^)&e6#55&PGyo>QM1vmwxF z!+PF``ZQFMxOUT2vYup1bFC+BNoil|83J$xs4MhMNk_gy#AklzY% zn1=k0%RXYr_n!RlA$JkIVMCrrunP_O=09i1lhdVSM;_uIT*g!SOcljESy?o^ka+*k z8FpI1hN*)+39s^_M*UWHg+9ipKf-R?hmQJAD8`>R>PvXkTQZ{F)snH*S9OI~-Mn)D zD~^-<%6Uuj;vQ#O2Cg0nsTWGY&L{;V z2ZkM&pZS^q@xkL(HbYr6|3NTT2xsDLTf%LJ&BKUdGcJui)pX*lje46- zoPtH+-TuU%kfNO$c7bRvB26a&v}qY^LhM_s$GQa9UU+jvme{bC=cA#YB>o=shAnk4 zz;YW5v-A@?X5{^hyhc0GSIDOTUoL-{$M(WUE!)XUX6Ac$`&ezq@aGKvoRpsF@b31c6JNm7E$PEGcvu0{ z=(FL(9=mtX^SK@h4;zIW7`7We;kaFBBxX$FS?8v6sZ!T?>kL824aQ*(gg{{`*KRq1 zLw(6BE{uz~oDpXdqU4if7BGzMe#8@G^JGfKI7suRJu7p%m*xr{gv%qzt2*x#ZTWY! zKD!DBk=w3ld9$VSMgZKsou5Ybj?%86Xs{>O;hc^=*?{#BngGpnB)%>1FAN+ATk#JJ z9EsnH;3(XBMbL-aBwMfux0$x!INUyK3y#MvY70)p?c27XAGfD%!HaM^XbVolt=rbs za=v(baai}ST95U$4)l@dw7P56PsVD!nLF5jioQe+*yBRFPnWml_bnwa%h&L3$Jjo~ zW}PjaREJMGWoO}a#ous9XN%C_l2M~m%#D)!*7~gOk5Oe+6a3ca-}o-_nd%o1sR z7OeDl*}&B)yUr&IT6w&504qF^j?c-HZfhn&U+E~=08R_z6lv^PAY4yCKD;;;sPH;C zeG#YAoF2nzdaR2_S0&gw!o-6uc*67H{@=^I8NQ(}?0=Mrd$RrD$}; zDg|=XB%Sa4^#n9215s|^;IRCUhvmOR`Sy?#3l(kyxDDX8Fy!*ySCQdEf}18(R~x6# zwh=l_OT2=B^Mt2jcIT;>GyfEh?4KgX*lCyhYA)xgEQ$jt_#>1a#2vPHuiaD7dZ>e3 zX%t}_F3)$WYtFCFzAq1}W)CF%%Xn%ol#Y#}2YPAk4CV2txhkx^G@c}Smg7WvB6zkO zVi`?GQW$y`c1j|~sSeO!0er@(solo`O!~QY-cSbhv6SVdGGT2Km2fs}94cA?60TU0 zwyh?6_pppJ^I)#z1wveiLpHS{5M!O((Z7|&$ z`k*cJ0c?8M*kyUDm|EA*!Tker5D8p9V71?rqBA04;}qQY2-k3a2ejMhRsQ8;7+B}!KF%Ll~EpxntN#~VlP9ihR;^9VW3Ez|oEaMgJ0I>nLE zSI1!?q$5mHF&Bmk>YmVs=qysuSBGeTYG{|>G^&ZWP87R_@dh9BLcCo^OdX^?Oh3X; zSCG##MQ4uM*ADFL+BtC*4yS=V$yk4pg)y8BuKSs`K`}OpYH4jl7PiVi8Cwg94KT%m zGBbqZfRZ7vg`thP4E;iT3ByT}8Wlq=?OaMS1e0~h(fVqK;}ndRv^&~fV15FjF?Y@p zxbx}UO|@|MEZ!0^jU$Qc7uu%`?odm+Lvcs%NfTFiO!H;DI{-ys5HRJ380B|nlvau2)lr%l`N4bSj{??4LM5263N103cBux?|JdZF+Lku}$YUUHpa0FC>3! z*roU4-j zPdFOvKeMea?dqDcYGvy|`94?_t`=cl(K2YOA76KI%b>m9o}5vBugBN&=INH6Q4PiA zTU4r`{FJAK({8*a#&3+ZUJ)xQS_3DINw&Ohi@)y35-vaMKGK@6FwkZfJcX9`ZAaeV z#bOAa&_PEZ7aR3k-m@Kf-9%x?L_u!@I3|p=34^s3=T7Ok-oCYicvQ$9=l#EfaPTY( zabgjoKpb+xy9DsZv8?b37=9v-eeksOTPbA^74ieNG=!_DgkHvQBv;^76qv%I8=##& z?bn5X@e2gbay#O%@s`pjWT_kbFfh*KUrSPa);X*#eixCRX_NDNm}eBgH+W&cQ6n$xbur%yoltcnWSwf zjGiP#MZT(vAu9P(%m%)wxnCx>OeJpd$S=^igDZJ$C0! zmBoJo1ZILNTrMFmQ3bL}09_$L@hs9b3Hc!*kzobWbP0NhKsc37pcxX>nyq)GgfwO$ zGbLmLRRil(ZH@%poJE=|A(e!Lla7kht0nYyk6Of*FQ-+L44=NElFkbW1)+h)lfN{W zQV<+gkPs){At3cJ$Y{YafWU>*evrZ0IAzg(?@_Z=xt#hb%?AO82Y}rkZr8gzV&^0I z2R!7Bpf>EEOWQ@Y(L1Oi@`Ku=meP%;Qa;kS+fp1d7n7^I5ykvQ$LARjiyg23+|os6 z5+Dv|(- ztorN#UT@-rZa6x-roDM?t7rts7%PH(b^~5suE1L&qRa z4ZroE8KoB)))+?7)&8H%D8I0vDD$J;Lnv8hT6838X^*sC+G;bIMjeA&(%%5N)Jo=B z9f`=aDl%!erK#~|9R1~lSFAYiB5On3E}>+_cB76&{Z;PVrDiHsIs!{gxpl&fF~x$Re7o23O@roIPRF6*X?S4{lWc}NG^A!1pj!GO;6#P?5ag({2-kAG_rTBJJFLj!D~jjcz+NLR0g6E2S}lY)W6GjI#VD=3qPz>BjS4O?9s^*ZrEQ zu6)ZarG1rP(pUvSZ_!v$e>s?d`=M664SX1i>cYt-Yc?nAP;Lg3306~rR{fG zzrL5J+uI;T;bs&52w^HYPE$15wtq#EluK-~pmTQp-$) zUvvVI28itYRU;FIML$HtMzf0g>7-GYVYc>Fy*@2{eUwp~HL84zDyKo=wyecry*lyr zBU5!N+H{46AGwKA`IcPT{;wIALQYaOoJ-M}_jNMA6^l zdjna+FesGoN)&x1h>w7>nNUc;`dY9{N6NPJ7m|#=5`0O=Ffnt5PDWn~f;v)`j6=uK z*8+bo&L8ZG9epi01HdrZ944Hw@zT=UItH;Lr`v43|BMM8G_3@kW^|K!;$^?*Rkgp8 z4e0L*Ma?x7%6vj0vFUG-E!UB<{k>e0Q7gex9l<0ur^HYz!6hSLyl&&Zs+Ayv-0(4u zOANIV{D&FCF#ZqHb4^pbU!po{Gt>-UC*kt-XeO-c>E``k2|>#E3MGkIdL4S#{C>)) zIwsk|z8^I>803ZGPK9as@*NpG!lTDHnIs;3VFQ;phj0$*V*7%SvjOjX5JD1fQ0T`J zgWkrMvFocSgl~4;hNs@U&WU=HI@WUuqv239O~w{}&6= zlv~?x@(`_wSz17Q;20vxXm{%U@2)NVMEKt`;jfxPG>^5fb+zS}-obojLG3yyoQ0ti z__CNgR2Q;vFcdZ5E8A~%o?OG!DEW>|hAE9`7d!b<0F;Mhuru}-UH2c6yJIK!t#wA% z_G^6^oC~7S#kU?{HAy(})H4&DikD_-2~|LPMvg_tyZc2vM9TyNbvQ7e30}MX65OyA zd?bU=5c`csd+BQp=+%z5>0$n0;$cQ_^6vS2(Z05S=~6U^)c_AcwKPsDW8KE1t-(F< z1{XHAflnM@2XzqVwN7(7c{5(7C91T``W`}O;@i>x7bZEByA(o=w%vMBR^%q?v=UWH0-w0VSH@B%WA9bZlBX> zbBJmS4VBq24Cu(=qs$>`*xYWXxWt0qD|2P)pK0r5&Ky2k=-;C|h!49%OxN+ucVJkq zyc|A2foa&>9;Ya_Aor@A(*hN)96lbwzs?j+;=|#{et(s@7BDPVel8z*l7`J)>=dId z$h|6;XMy6MzUS&kmF+qFQ%9TE?h^NjyaN0~Px=?OxO!z>8e22C@WM2FlE!EkXvoV< z!vyx`(1<$}AAW~R+zN*9Uq!7n;uu>q*q1{?R({0vF}bXvtT6_`NPM*21(dk9=!i#^uncaw%Q+f`-q+w4zbvvi7C;!Zdu6hKXr2 z4HI~L4vm^oiVyz;mnayiFEyjAeVLF$1OKaA&KIxWB}R?Z7y57BW*wV&VH!S3!^E^c zE=0ow_UF>@C_enq{{#K#Eo zXn{=4;3*fT;gd8>9anrX4HLLDheo_e@!?pY^Lqp^#8f9#QWMABVTBj8s7<)z9&0jLQ zG>1mq(Q7NiI%o6YtIvxqOe-2>PtAR)&Y|&0o}%F|a)~h`_2m(R55d>Q*%TS7!N; zOe-2&VGGSu;4?WiszxgsW!GlyhegM#;8EyZB;xwNgp>{ad7n$RtiOBP>~QVIriyuG zw=TJU+S2J|a|3~^%kHkP-@0J->}~5B*KOXs?(VBLZ`pj;=7y`b)ZI0EYu%Pj8`sxw zo2|ZLbGEQhsovPQv33i-Rdbsa4(essZCJOpeq)`G-_UvIM)mES^R7mt^zEG2%${>i z*_?R`<^&c5t{wL6oRS(bSyp||wym}6zNC{Y+qik%owXY`6pSetBW_wz#_TZSDtx`? z7JR)YdT~!J;atKvL}ST4Teg+`IeegvV(}S~g3=zgy@;P9Hu{#@$gcBv_J}~h))k2! zi6Eee>_2Ra#PUSsRAhBz|BE)<--)b=TzjwqXe;o|*Rd6Jp01_7pv9;fzIo-Xw;g!h zxATuQx}%OB_@h1goTB6+N<`-!@6Vo-#2qHk>D9Z^&iaYFy7Le8IlMnQjN?S_MxTuy z!M#7}IhxS(M|-o(xy{V2i9`poMWZZ5f4O$e?W?m~uSC}n@|*%U@2u%s8CKcV$e&t6 zu_#V%0K>)@2$DHU1vrN1l(EA$dYFy(N#thJFvSu|@ZTa%fxjX249GAAQ zO}CdWTB{(z9ulgFmQ2_4hs-~LRB$L>AK9gzqG4>ef{D?eA z(D@XO7tkxGINK46cW7r)+8e1w@s5TGS%eN7P8yWPp6SqDPIW#PU8SwUJJDU*&okKY zA06Yb2Hp`(418ZEzZ*@w^Zm$Fn*EUjZ}=jkj?Iglof?UDMGhqSOMr3O$lHepV>=HG z41t%u{X@%_$1WAoy=R8-WiQm{hffb-YT*He_E+!FhRog+BMuD3gk3#o+xKvK2#0gh z+Od;3?$ow7JrumP!QZwwGZb9X;A`6}(!uMoQ@7Wa4$iGFQ{|;xetpA4E??E)zM?j6OS z1^hW0Pq|&uy@j~ZL5k>JPny0*j7`QU>I@rJx_gU?WoDMUog?syk_WhsJ zL)+)I18pHXw0$OFX6B>!4vZ&1$N3GKceP`ft7xp-0mkzYd?p3qlBN>fN&{ zlS|~QLMe+|2iblq8cX*%$G=9xEzd+BzB~i< zO!N7Z;yLk7QZhHd1)0uq_eURgXQRP!Y78onzN&dgw#r33JSrsED|jcT#JOAB^XN$2^=fjb{U#e4=`8ht>q@*Ji8qAk)H4b9TY@TAqjLM&L8w#E z*)S@$36HEisIEY6fbcX>8~T9`!h;U&?*}-S*yRXhK4#~v$5y~!N~gUJ zxOVIu1~|4K6A@2nwIvV~&WWA%)X;Mi{W(!FK_%bGVpb)*-|brD5ZDOj-ax2I?QDd~ zR+LX;X%7rcwTb#so%?YFFWS{Gir;LYLtCg=O5Oxc9(4UX&__hxpPNM$aiFspRyq9VtrI1OC}$r47?Zgn+_34S?!b< z%&3RblF?0+)Z4ZS>lwquXrDX5(S&e(n4jf@^{P=m9R&P<8GLY|9Q~hnEHo|rk(kjOMCy!)G|?T|Cw9oxNGconv_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); } } diff --git a/poison.h b/poison.h index d7db7f43b6..5354e7779c 100644 --- 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 @@ -36,15 +37,27 @@ #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 diff --git a/posix-aio-compat.c b/posix-aio-compat.c index fa5494db8c..0c0035cb18 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -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 5248ef15a5..2a0dcad63d 100644 --- 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 : { diff --git a/ppc64.ld b/ppc64.ld index dea0dbda21..e2dafa0b53 100644 --- 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 index 0000000000..fde5971e87 --- /dev/null +++ b/qapi-schema-guest.json @@ -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 index 0000000000..3acedad7ee --- /dev/null +++ b/qapi-schema-test.json @@ -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 index 0000000000..cb1ba776df --- /dev/null +++ b/qapi-schema.json @@ -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 index 0000000000..a154523731 --- /dev/null +++ b/qapi/qapi-dealloc-visitor.c @@ -0,0 +1,171 @@ +/* + * Dealloc Visitor + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Michael Roth + * + * 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 index 0000000000..5842bc79bd --- /dev/null +++ b/qapi/qapi-dealloc-visitor.h @@ -0,0 +1,26 @@ +/* + * Dealloc Visitor + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Michael Roth + * + * 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 index 0000000000..27e6be0a87 --- /dev/null +++ b/qapi/qapi-types-core.h @@ -0,0 +1,23 @@ +/* + * Core Definitions for QAPI-generated Types + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..ddef3eda12 --- /dev/null +++ b/qapi/qapi-visit-core.c @@ -0,0 +1,118 @@ +/* + * Core Definitions for QAPI Visitor Classes + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..e850746b75 --- /dev/null +++ b/qapi/qapi-visit-core.h @@ -0,0 +1,76 @@ +/* + * Core Definitions for QAPI Visitor Classes + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 + +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 index 0000000000..f1c26e4b2e --- /dev/null +++ b/qapi/qmp-core.h @@ -0,0 +1,41 @@ +/* + * Core Definitions for QAPI/QMP Dispatch + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..558469325c --- /dev/null +++ b/qapi/qmp-dispatch.c @@ -0,0 +1,124 @@ +/* + * Core Definitions for QAPI/QMP Dispatch + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..8cbc0abcfd --- /dev/null +++ b/qapi/qmp-input-visitor.c @@ -0,0 +1,301 @@ +/* + * Input Visitor + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..3f798f0335 --- /dev/null +++ b/qapi/qmp-input-visitor.h @@ -0,0 +1,27 @@ +/* + * Input Visitor + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..f76d0159cd --- /dev/null +++ b/qapi/qmp-output-visitor.c @@ -0,0 +1,251 @@ +/* + * Core Definitions for QAPI/QMP Command Registry + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..4a649c2504 --- /dev/null +++ b/qapi/qmp-output-visitor.h @@ -0,0 +1,28 @@ +/* + * Output Visitor + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 index 0000000000..5ff99cff14 --- /dev/null +++ b/qapi/qmp-registry.c @@ -0,0 +1,40 @@ +/* + * Core Definitions for QAPI/QMP Dispatch + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * Michael Roth + * + * 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 ad4873f62c..590cd716ea 100644 --- 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 dee0fb447c..4bf308b61c 100644 --- 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); } diff --git a/qemu-barrier.h b/qemu-barrier.h index b77fce23a9..c11bb2b59f 100644 --- a/qemu-barrier.h +++ b/qemu-barrier.h @@ -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 diff --git a/qemu-char.c b/qemu-char.c index 795aec092f..202533f4d4 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -31,11 +31,10 @@ #include "hw/usb.h" #include "hw/baum.h" #include "hw/msmouse.h" -#include "qemu-objects.h" +#include "qmp-commands.h" #include #include -#include #include #include #include @@ -107,7 +106,7 @@ 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) diff --git a/qemu-char.h b/qemu-char.h index 56d9954c52..8ca1e2d54e 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -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 diff --git a/qemu-common.h b/qemu-common.h index 14ed6b92d3..2ce47aa12d 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -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 #include @@ -33,7 +33,18 @@ typedef struct DeviceState DeviceState; #include #include #include +#include #include +#include +#include + +#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 #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 #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) diff --git a/qemu-config.c b/qemu-config.c index 323d3c2c29..597d7e10b1 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -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 index 0000000000..d495615cf6 --- /dev/null +++ b/qemu-coroutine-int.h @@ -0,0 +1,49 @@ +/* + * Coroutine internals + * + * Copyright (c) 2011 Kevin Wolf + * + * 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 index 0000000000..6b58160058 --- /dev/null +++ b/qemu-coroutine-lock.c @@ -0,0 +1,162 @@ +/* + * coroutine queues and locks + * + * Copyright (c) 2011 Kevin Wolf + * + * 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 index 0000000000..600be2643c --- /dev/null +++ b/qemu-coroutine.c @@ -0,0 +1,75 @@ +/* + * QEMU coroutines + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi + * Kevin Wolf + * + * 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 index 0000000000..b8fc4f4332 --- /dev/null +++ b/qemu-coroutine.h @@ -0,0 +1,191 @@ +/* + * QEMU coroutine implementation + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi + * Kevin Wolf + * + * 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 +#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 */ diff --git a/qemu-doc.texi b/qemu-doc.texi index 86e017ccfa..9c3cb62ee3 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -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://[[%]@@][:]// +@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= +export LIBISCSI_CHAP_PASSWORD= +iscsi://// +@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 diff --git a/qemu-error.c b/qemu-error.c index 5a35e7c1c2..4b20d283a2 100644 --- a/qemu-error.c +++ b/qemu-error.c @@ -12,7 +12,6 @@ #include #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 index 0000000000..49320133c6 --- /dev/null +++ b/qemu-ga.c @@ -0,0 +1,637 @@ +/* + * QEMU Guest Agent + * + * Copyright IBM Corp. 2011 + * + * Authors: + * Adam Litke + * Michael Roth + * + * 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 +#include +#include +#include +#include +#include +#include +#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 \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 \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; +} diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 6c7176f8b4..49dce7c928 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -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, diff --git a/qemu-img.c b/qemu-img.c index 7e3cc4cbd5..01cc0d35ad 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -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]) { diff --git a/qemu-img.texi b/qemu-img.texi index ced64a40ed..b2ca3a542c 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -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 diff --git a/qemu-io.c b/qemu-io.c index 4470e49bc8..de26422fcf 100644 --- 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; } diff --git a/qemu-lock.h b/qemu-lock.h index 65ca084326..a72edda1d2 100644 --- a/qemu-lock.h +++ b/qemu-lock.h @@ -15,15 +15,11 @@ * License along with this library; if not, see */ -/* 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 #define spin_lock pthread_mutex_lock @@ -33,198 +29,15 @@ #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 - -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 diff --git a/qemu-nbd.c b/qemu-nbd.c index e858033e06..291cba2eaa 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -16,7 +16,7 @@ * along with this program; if not, see . */ -#include +#include "qemu-common.h" #include "block_int.h" #include "nbd.h" @@ -31,12 +31,17 @@ #include #include #include +#include #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); + } } diff --git a/qemu-option.c b/qemu-option.c index 65db54292b..f97a758a95 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -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) diff --git a/qemu-option.h b/qemu-option.h index b515813891..07958e4e90 100644 --- a/qemu-option.h +++ b/qemu-option.h @@ -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); diff --git a/qemu-options.hx b/qemu-options.hx index 945edf3562..76d0826ac0 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -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=[,]\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 +@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= 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= 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 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://[:]//'' + +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::[:exportname=]'' + +Syntax for specifying a NBD device using Unix Domain Sockets +``nbd:unix:[:exportname=]'' + + +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:'' + +``sheepdog::'' + +``sheepdog::'' + +``sheepdog:::'' + +``sheepdog::::'' + +``sheepdog::::'' +@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=]\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 diff --git a/qemu-os-posix.h b/qemu-os-posix.h index 81fd9ab389..8e1149d964 100644 --- a/qemu-os-posix.h +++ b/qemu-os-posix.h @@ -26,10 +26,6 @@ #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 diff --git a/qemu-os-win32.h b/qemu-os-win32.h index 1a07e5e264..8eda4bdc20 100644 --- a/qemu-os-win32.h +++ b/qemu-os-win32.h @@ -26,21 +26,12 @@ #ifndef QEMU_OS_WIN32_H #define QEMU_OS_WIN32_H -/* Polling handling */ +#include +#include +#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 index 0000000000..5f1b8dfb97 --- /dev/null +++ b/qemu-progress.c @@ -0,0 +1,150 @@ +/* + * QEMU progress printing utility functions + * + * Copyright (C) 2011 Jes Sorensen + * + * 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 + +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(); + } +} diff --git a/qemu-queue.h b/qemu-queue.h index 1d077458ce..22142305a6 100644 --- a/qemu-queue.h +++ b/qemu-queue.h @@ -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 = \ diff --git a/qemu-sockets.c b/qemu-sockets.c index 70419e97db..fc5b465cf3 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -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; +} diff --git a/qemu-tech.texi b/qemu-tech.texi index 138e3ce9ad..62afe45dc2 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -42,13 +42,14 @@ @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 index 0000000000..ac3c0c9d14 --- /dev/null +++ b/qemu-thread-posix.c @@ -0,0 +1,149 @@ +/* + * Wrappers around mutex/cond/thread functions + * + * Copyright Red Hat, Inc. 2009 + * + * Author: + * Marcelo Tosatti + * + * 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 +#include +#include +#include +#include +#include +#include +#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 index 0000000000..ee4618e620 --- /dev/null +++ b/qemu-thread-posix.h @@ -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 index 0000000000..db8e744729 --- /dev/null +++ b/qemu-thread-win32.c @@ -0,0 +1,281 @@ +/* + * Win32 implementation for mutex/cond/thread functions + * + * Copyright Red Hat, Inc. 2010 + * + * Author: + * Paolo Bonzini + * + * 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 +#include +#include + +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 index 0000000000..878f86a910 --- /dev/null +++ b/qemu-thread-win32.h @@ -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 diff --git a/qemu-thread.h b/qemu-thread.h index 19bb30c940..e008b60028 100644 --- a/qemu-thread.h +++ b/qemu-thread.h @@ -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 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 diff --git a/qemu-timer.c b/qemu-timer.c index b0db780a1e..cd026c6495 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -39,15 +39,6 @@ #include #endif -#ifdef __linux__ -#include -#include -/* For the benefit of older linux systems which don't supply it, - we use a local copy of hpet.h. */ -/* #include */ -#include "hpet.h" -#endif - #ifdef _WIN32 #include #include @@ -55,96 +46,6 @@ #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, ¤t_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; } diff --git a/qemu-timer.h b/qemu-timer.h index 8cd8f8368a..67ca72e045 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -2,16 +2,21 @@ #define QEMU_TIMER_H #include "qemu-common.h" +#include "main-loop.h" +#include "notify.h" #include #include #ifdef _WIN32 #include -#include #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 index 0000000000..5b70f10f8f --- /dev/null +++ b/qemu-tls.h @@ -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 + * Peter Maydell + * + * 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 . + */ + +#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 diff --git a/qemu-tool.c b/qemu-tool.c index 392e1c9505..5df7279745 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -15,11 +15,12 @@ #include "monitor.h" #include "qemu-timer.h" #include "qemu-log.h" -#include "sysemu.h" +#include "migration.h" #include 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 index 0000000000..f910d96eaf --- /dev/null +++ b/qemu-xattr.h @@ -0,0 +1,30 @@ +/* + * Host xattr.h abstraction + * + * Copyright 2011 Red Hat Inc. and/or its affiliates + * + * Authors: + * Avi Kivity + * + * 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 +#else +# define ENOATTR ENODATA +# include +#endif + +#endif diff --git a/qemu_socket.h b/qemu_socket.h index 2f33e646e6..9e32fac651 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -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 */ diff --git a/qerror.c b/qerror.c index 485560418b..25bc91e587 100644 --- 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); } diff --git a/qerror.h b/qerror.h index f732d45e80..6414cd9d5b 100644 --- a/qerror.h +++ b/qerror.h @@ -15,6 +15,7 @@ #include "qdict.h" #include "qstring.h" #include "qemu-error.h" +#include "error.h" #include 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 */ diff --git a/qfloat.c b/qfloat.c index f8c8a2eb21..98338f3b71 100644 --- 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 index 0000000000..969da23282 --- /dev/null +++ b/qga/guest-agent-command-state.c @@ -0,0 +1,73 @@ +/* + * QEMU Guest Agent command state interfaces + * + * Copyright IBM Corp. 2011 + * + * Authors: + * Michael Roth + * + * 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 +#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 index 0000000000..6da9904819 --- /dev/null +++ b/qga/guest-agent-commands.c @@ -0,0 +1,561 @@ +/* + * QEMU Guest Agent commands + * + * Copyright IBM Corp. 2011 + * + * Authors: + * Michael Roth + * + * 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 + +#if defined(__linux__) +#include +#include + +#if defined(__linux__) && defined(FIFREEZE) +#define CONFIG_FSFREEZE +#endif +#endif + +#include +#include +#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 index 0000000000..e42b91d364 --- /dev/null +++ b/qga/guest-agent-core.h @@ -0,0 +1,31 @@ +/* + * QEMU Guest Agent core declarations + * + * Copyright IBM Corp. 2011 + * + * Authors: + * Adam Litke + * Michael Roth + * + * 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 fb3823a7f4..ee51804fbe 100644 --- 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 5730fb87f7..88498b157f 100644 --- 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 dbe7b92db5..d426bd4a4b 100644 --- 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 */ diff --git a/qmp-commands.hx b/qmp-commands.hx index df40a3d42e..97975a5207 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -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 index 0000000000..511dd624b5 --- /dev/null +++ b/qmp.c @@ -0,0 +1,119 @@ +/* + * QEMU Management Protocol + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * 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 diff --git a/qstring.c b/qstring.c index 4e2ba083b7..b7e12e4015 100644 --- 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); } diff --git a/readline.c b/readline.c index 92f9cd1569..a6c0039ad2 100644 --- a/readline.c +++ b/readline.c @@ -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; diff --git a/rules.mak b/rules.mak index ed59c9e82b..04a91983ec 100644 --- 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,$^) diff --git a/savevm.c b/savevm.c index 3d519745ca..f53cd4c154 100644 --- a/savevm.c +++ b/savevm.c @@ -23,7 +23,6 @@ */ #include #include -#include #include #include #include @@ -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 index 0000000000..b6d58fde96 --- /dev/null +++ b/scripts/analyse-9p-simpletrace.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# Pretty print 9p simpletrace log +# Usage: ./analyse-9p-simpletrace +# +# 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()) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl old mode 100644 new mode 100755 index 4fa06c002e..04ab990cc0 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -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; diff --git a/scripts/create_config b/scripts/create_config old mode 100644 new mode 100755 diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl new file mode 100755 index 0000000000..d9c48e0982 --- /dev/null +++ b/scripts/get_maintainer.pl @@ -0,0 +1,2149 @@ +#!/usr/bin/perl -w +# (c) 2007, Joe Perches +# 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] +# perl scripts/get_maintainer.pl [OPTIONS] -f +# +# 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 + # + # name1 + # name1 name2 + # (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 < 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 ' + --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"] + may not work because of additional output after . + 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/(?"; + } + } 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 <; + 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 <[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 index 0000000000..56d2bd7f21 --- /dev/null +++ b/scripts/kvm/kvm_stat @@ -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 +# +# 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 index 0000000000..a74ce71917 --- /dev/null +++ b/scripts/kvm/vmxcap @@ -0,0 +1,224 @@ +#!/usr/bin/python +# +# tool for querying VMX capabilities +# +# Copyright 2009-2010 Red Hat, Inc. +# +# Authors: +# Avi Kivity +# +# 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 index 0000000000..7242b5060d --- /dev/null +++ b/scripts/ordereddict.py @@ -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 index 0000000000..f7def16662 --- /dev/null +++ b/scripts/qapi-commands.py @@ -0,0 +1,445 @@ +# +# QAPI command marshaller generator +# +# Copyright IBM, Corp. 2011 +# +# Authors: +# Anthony Liguori +# Michael Roth +# +# 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 + * + * 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 + * + * 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 index 0000000000..f64d84c39e --- /dev/null +++ b/scripts/qapi-types.py @@ -0,0 +1,278 @@ +# +# QAPI types generator +# +# Copyright IBM, Corp. 2011 +# +# Authors: +# Anthony Liguori +# +# 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 + * Michael Roth + * + * 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 + * + * 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 index 0000000000..62de83d0f0 --- /dev/null +++ b/scripts/qapi-visit.py @@ -0,0 +1,246 @@ +# +# QAPI visitor generator +# +# Copyright IBM, Corp. 2011 +# +# Authors: +# Anthony Liguori +# Michael Roth +# +# 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 + * + * 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 + * + * 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 index 0000000000..6e05469e6d --- /dev/null +++ b/scripts/qapi.py @@ -0,0 +1,206 @@ +# +# QAPI helper library +# +# Copyright IBM, Corp. 2011 +# +# Authors: +# Anthony Liguori +# +# 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' diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index c50beb7337..83a44d8e2a 100644 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -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 index 0000000000..14d586070f --- /dev/null +++ b/scripts/refresh-pxe-roms.sh @@ -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 . +# +# Copyright (C) 2011 Red Hat, Inc. +# Authors: Alex Williamson +# +# 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 diff --git a/scripts/signrom.sh b/scripts/signrom.sh old mode 100644 new mode 100755 diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py old mode 100644 new mode 100755 index 553a72709f..f55e5e63f9 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -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 ' % 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 \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()) diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl old mode 100644 new mode 100755 diff --git a/scripts/tracetool b/scripts/tracetool old mode 100644 new mode 100755 index e04668322d..4c9951d0aa --- a/scripts/tracetool +++ b/scripts/tracetool @@ -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 < +#include "trace/stderr.h" + +extern TraceEvent trace_list[]; EOF + + stderr_event_num=0 } linetoh_stderr() @@ -261,29 +271,47 @@ linetoh_stderr() cat < +# +# 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 index 0000000000..5d7b8acd1d --- /dev/null +++ b/slirp/arp_table.c @@ -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; +} diff --git a/slirp/bootp.c b/slirp/bootp.c index 0905c6d1be..efd1fe777a 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -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; diff --git a/slirp/if.c b/slirp/if.c index 0f04e13989..2852396a4a 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -6,6 +6,7 @@ */ #include +#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; } diff --git a/slirp/ip.h b/slirp/ip.h index 48ea38e5ec..88c903fccd 100644 --- a/slirp/ip.h +++ b/slirp/ip.h @@ -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 diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 154884e2eb..4b43994dbc 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -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); +} diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h index 2692822f87..b3da1f2697 100644 --- a/slirp/ip_icmp.h +++ b/slirp/ip_icmp.h @@ -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 diff --git a/slirp/ip_input.c b/slirp/ip_input.c index 768ab0cd49..c7b3eb4806 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -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, diff --git a/slirp/ip_output.c b/slirp/ip_output.c index 542f3180be..c82830fe7d 100644 --- a/slirp/ip_output.c +++ b/slirp/ip_output.c @@ -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; } diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 67c70e32e3..890fd86c3c 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -1,9 +1,7 @@ #ifndef _LIBSLIRP_H #define _LIBSLIRP_H -#include - -#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 diff --git a/slirp/main.h b/slirp/main.h index 0dd8d81ce4..028df4b361 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -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); diff --git a/slirp/mbuf.c b/slirp/mbuf.c index ce2eb843f5..c699c75096 100644 --- a/slirp/mbuf.c +++ b/slirp/mbuf.c @@ -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; diff --git a/slirp/mbuf.h b/slirp/mbuf.h index 97729e24b0..0708840f04 100644 --- a/slirp/mbuf.h +++ b/slirp/mbuf.h @@ -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_; diff --git a/slirp/misc.c b/slirp/misc.c index 19dbec491f..6c80e69685 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -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); + } } diff --git a/slirp/slirp.c b/slirp/slirp.c index 332d83b64d..19d69eb623 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -31,11 +31,11 @@ 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; } diff --git a/slirp/slirp.h b/slirp/slirp.h index 954289a8c8..28a5c037e6 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -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; }; diff --git a/slirp/socket.c b/slirp/socket.c index c97691c096..77b0c98197 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -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 */ diff --git a/slirp/tcp.h b/slirp/tcp.h index 9d06836626..b3817cb13c 100644 --- a/slirp/tcp.h +++ b/slirp/tcp.h @@ -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; diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index e4a77310d0..942aaf44f1 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -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]; diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index b661d2623c..143a2383c8 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -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); } } diff --git a/slirp/tftp.c b/slirp/tftp.c index 1821648251..b78765f3af 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -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) { diff --git a/slirp/tftp.h b/slirp/tftp.h index b9f0847eb9..72e5e91bef 100644 --- a/slirp/tftp.h +++ b/slirp/tftp.h @@ -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; }; diff --git a/slirp/udp.c b/slirp/udp.c index 02b3793e9f..5b060f397b 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -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; } diff --git a/softmmu-semi.h b/softmmu-semi.h index 79278cc763..86a9f8a846 100644 --- a/softmmu-semi.h +++ b/softmmu-semi.h @@ -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) diff --git a/softmmu_defs.h b/softmmu_defs.h index e38bb752f1..c5a2bcd3e2 100644 --- a/softmmu_defs.h +++ b/softmmu_defs.h @@ -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 diff --git a/softmmu_exec.h b/softmmu_exec.h index 28d1d53d61..8c73985599 100644 --- a/softmmu_exec.h +++ b/softmmu_exec.h @@ -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 diff --git a/softmmu_header.h b/softmmu_header.h index 2f95c33409..818d7b662e 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -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 diff --git a/softmmu_template.h b/softmmu_template.h index 73136ae1b1..71360c14ff 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -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) */ diff --git a/sparc.ld b/sparc.ld index 31321be532..56efe34e73 100644 --- 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 : { diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 517f337c43..7e8eaa9fd8 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -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; } diff --git a/sysemu.h b/sysemu.h index b1529c7edf..0362e5f5b7 100644 --- 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 -#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); diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 686fb4a6a7..9d61d45ab6 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -28,8 +28,6 @@ #include "cpu-defs.h" -#include - #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__) */ diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 3ba4478c8e..06d2565a5c 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -22,7 +22,6 @@ #include #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 = ""; + + 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, diff --git a/target-alpha/helper.h b/target-alpha/helper.h index ccf6a2aae9..b693ceea97 100644 --- a/target-alpha/helper.h +++ b/target-alpha/helper.h @@ -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 index 0000000000..76d70d9b35 --- /dev/null +++ b/target-alpha/machine.c @@ -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); +} diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 6c2ae2061f..cc102dbd63 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -17,25 +17,69 @@ * License along with this library; if not, see . */ -#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 diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 3a1c625f73..a961159d5d 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -22,7 +22,6 @@ #include #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]; } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 5bcd53ac73..c4d742f084 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -55,6 +55,10 @@ #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 diff --git a/target-arm/helper.c b/target-arm/helper.c index b562767279..97af4d0bba 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3,9 +3,8 @@ #include #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 index 0000000000..16dd5fcc89 --- /dev/null +++ b/target-arm/helper.h @@ -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" diff --git a/target-arm/iwmmxt_helper.c b/target-arm/iwmmxt_helper.c index 3332f708c9..843994d8d5 100644 --- a/target-arm/iwmmxt_helper.c +++ b/target-arm/iwmmxt_helper.c @@ -24,7 +24,7 @@ #include "cpu.h" #include "exec-all.h" -#include "helpers.h" +#include "helper.h" /* iwMMXt macros extracted from GNU gdb. */ diff --git a/target-arm/machine.c b/target-arm/machine.c index 3925d3a2d5..aaee9b9c11 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -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); diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 268af33a6c..b51e35a30f 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -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 #include #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 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); } diff --git a/target-arm/op_addsub.h b/target-arm/op_addsub.h index c02c92adfa..ca4a1893c3 100644 --- a/target-arm/op_addsub.h +++ b/target-arm/op_addsub.h @@ -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 diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 3de2610348..1892b35ecc 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -16,17 +16,20 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#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) diff --git a/target-arm/translate.c b/target-arm/translate.c index 514954300d..0f35b60946 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -25,15 +25,18 @@ #include #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]; diff --git a/target-cris/cpu.h b/target-cris/cpu.h index d9087759d3..453afbb66e 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -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 diff --git a/target-cris/helper.c b/target-cris/helper.c index 2a4403b847..5bc6d810cb 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -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, diff --git a/target-cris/mmu.c b/target-cris/mmu.c index 1243745598..d481e39352 100644 --- a/target-cris/mmu.c +++ b/target-cris/mmu.c @@ -27,7 +27,6 @@ #include "config.h" #include "cpu.h" #include "mmu.h" -#include "exec-all.h" #ifdef DEBUG #define D(x) x diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index be9eb06fd0..1eacc5fd7f 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -18,7 +18,8 @@ * License along with this library; if not, see . */ -#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 @@ -54,21 +56,20 @@ 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) diff --git a/target-cris/opcode-cris.h b/target-cris/opcode-cris.h index 8d4749debe..779d4aab70 100644 --- a/target-cris/opcode-cris.h +++ b/target-cris/opcode-cris.h @@ -29,8 +29,8 @@ along with this program; if not, see . */ /* 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) diff --git a/target-cris/translate.c b/target-cris/translate.c index b4648a01de..70abf8a095 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -30,7 +30,6 @@ #include #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]; } diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c index 41db158965..95053b64fb 100644 --- a/target-cris/translate_v10.c +++ b/target-cris/translate_v10.c @@ -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); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index af701a4412..a08ce9d873 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -283,6 +283,7 @@ #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 @@ -299,6 +300,10 @@ #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) @@ -438,9 +443,13 @@ #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 */ @@ -466,6 +475,15 @@ #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 */ diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 5382a283f5..0b3af9060c 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -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 index 0000000000..6c3354aad3 --- /dev/null +++ b/target-i386/hax-all.c @@ -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(®s, 0, sizeof(struct vcpu_state_t)); + + if (!set) + { + ret = hax_sync_vcpu_state(env, ®s, 0); + if (ret < 0) + return -1; + } + + /*generic register */ + hax_getput_reg(®s._rax, &env->regs[R_EAX], set); + hax_getput_reg(®s._rbx, &env->regs[R_EBX], set); + hax_getput_reg(®s._rcx, &env->regs[R_ECX], set); + hax_getput_reg(®s._rdx, &env->regs[R_EDX], set); + hax_getput_reg(®s._rsi, &env->regs[R_ESI], set); + hax_getput_reg(®s._rdi, &env->regs[R_EDI], set); + hax_getput_reg(®s._rsp, &env->regs[R_ESP], set); + hax_getput_reg(®s._rbp, &env->regs[R_EBP], set); + + hax_getput_reg(®s._rflags, &env->eflags, set); + hax_getput_reg(®s._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, ®s); + } + 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, ®s); + } + + if (set) + { + ret = hax_sync_vcpu_state(env, ®s, 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 index 0000000000..4d7a08383b --- /dev/null +++ b/target-i386/hax-i386.h @@ -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 index 0000000000..b9126904ca --- /dev/null +++ b/target-i386/hax-interface.h @@ -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 index 0000000000..bfa3f95a84 --- /dev/null +++ b/target-i386/hax-windows.c @@ -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 index 0000000000..48569cdb86 --- /dev/null +++ b/target-i386/hax-windows.h @@ -0,0 +1,53 @@ +#ifndef __HAX_WINDOWS_H +#define __HAX_WINDOWS_H + +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/target-i386/helper.c b/target-i386/helper.c index f0c546df5c..2586aff700 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -21,13 +21,14 @@ #include #include #include -#include #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, ¶ms); + 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, ¶ms); } } } @@ -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); } diff --git a/target-i386/helper.h b/target-i386/helper.h index e3a2f56129..6b518ad89f 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -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) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 05010bbc38..5bfc21fc53 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -18,6 +18,7 @@ #include #include +#include #include "qemu-common.h" #include "sysemu.h" @@ -28,12 +29,7 @@ #include "hw/pc.h" #include "hw/apic.h" #include "ioport.h" -#include "kvm_x86.h" -#ifdef CONFIG_KVM_PARA -#include -#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); } diff --git a/target-i386/machine.c b/target-i386/machine.c index 1b75b1cf4e..d6e98ff37b 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -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 */ + } } }; diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 3232abd965..47dde78f89 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -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; diff --git a/target-i386/svm.h b/target-i386/svm.h index a224aead17..04193ed60f 100644 --- a/target-i386/svm.h +++ b/target-i386/svm.h @@ -130,7 +130,7 @@ #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; }; diff --git a/target-i386/translate.c b/target-i386/translate.c index df66f720e6..475614c31b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -24,13 +24,13 @@ #include #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, ®_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 index 0000000000..a1c2c7eb1e --- /dev/null +++ b/target-lm32/README @@ -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 index 0000000000..b9ea0c8db9 --- /dev/null +++ b/target-lm32/TODO @@ -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 index 0000000000..037ef528ed --- /dev/null +++ b/target-lm32/cpu.h @@ -0,0 +1,257 @@ +/* + * LatticeMico32 virtual CPU header. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +#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 index 0000000000..fc0b444d81 --- /dev/null +++ b/target-lm32/helper.c @@ -0,0 +1,255 @@ +/* + * LatticeMico32 helper routines. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +#include +#include +#include + +#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 index 0000000000..9d335efc45 --- /dev/null +++ b/target-lm32/helper.h @@ -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 index 0000000000..70ca52a0fa --- /dev/null +++ b/target-lm32/machine.c @@ -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 index 0000000000..02be13412e --- /dev/null +++ b/target-lm32/op_helper.c @@ -0,0 +1,106 @@ +#include +#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 index 0000000000..0be105d018 --- /dev/null +++ b/target-lm32/translate.c @@ -0,0 +1,1239 @@ +/* + * LatticeMico32 main translation routines. + * + * Copyright (c) 2010 Michael Walle + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +#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"); +} + diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index b025b6689d..0667f8214a 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -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 diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 514b03904f..674c8e6f07 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -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; diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 07111073f8..2f7fe6bc4e 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -16,20 +16,27 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#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) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 6f72a2bdd2..0e7f1fe2c7 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -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]; } diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 3aa28bfd40..35302863cb 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -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 diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c index 5230b52c18..2cf28022bd 100644 --- a/target-microblaze/helper.c +++ b/target-microblaze/helper.c @@ -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. */ diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h index 1696b885b6..b92aa34d05 100644 --- a/target-microblaze/helper.h +++ b/target-microblaze/helper.h @@ -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" diff --git a/target-microblaze/microblaze-decode.h b/target-microblaze/microblaze-decode.h index 4a274768d3..401319ed46 100644 --- a/target-microblaze/microblaze-decode.h +++ b/target-microblaze/microblaze-decode.h @@ -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)} + diff --git a/target-microblaze/mmu.c b/target-microblaze/mmu.c index b38f7d98b7..281fc8d8c4 100644 --- a/target-microblaze/mmu.c +++ b/target-microblaze/mmu.c @@ -22,7 +22,6 @@ #include "config.h" #include "cpu.h" -#include "exec-all.h" #define D(x) diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index d75a53cc54..7433cec291 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -18,13 +18,16 @@ */ #include -#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" @@ -39,19 +42,18 @@ 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)) { diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 220743195c..366fd3e607 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -25,7 +25,6 @@ #include #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]; } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 2419aa93d2..79e25583ff 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -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__) */ diff --git a/target-mips/helper.c b/target-mips/helper.c index bdc1e53669..1c58e0cc21 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -24,7 +24,6 @@ #include #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 diff --git a/target-mips/helper.h b/target-mips/helper.h index 297ab64bda..442f684697 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -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) diff --git a/target-mips/machine.c b/target-mips/machine.c index 9ffac711ce..be72b36de6 100644 --- a/target-mips/machine.c +++ b/target-mips/machine.c @@ -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) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 669faf17ae..c51b9cb6f0 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -17,16 +17,70 @@ * License along with this library; if not, see . */ #include -#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)) diff --git a/target-mips/translate.c b/target-mips/translate.c index 0f93e2abb1..d5b1c765fb 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -27,7 +27,6 @@ #include #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; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 590e092a1d..c39138f3c5 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -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); diff --git a/target-ppc/STATUS b/target-ppc/STATUS index 32e7ffa493..c8e9018bfc 100644 --- a/target-ppc/STATUS +++ b/target-ppc/STATUS @@ -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 diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index deb8d7c9c5..e84108c49a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -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 - #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__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4b491012d7..137a494201 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -21,13 +21,13 @@ #include #include #include -#include #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 @@ -70,13 +70,17 @@ # 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); } diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 2bf9283486..470e42f676 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -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) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 710eca1dca..0410901b56 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -2,6 +2,7 @@ * PowerPC implementation of KVM hooks * * Copyright IBM Corp. 2007 + * Copyright (C) 2011 Freescale Semiconductor, Inc. * * Authors: * Jerone Young @@ -13,6 +14,7 @@ * */ +#include #include #include #include @@ -26,6 +28,12 @@ #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 @@ -37,12 +45,19 @@ 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)¶ms; + 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, ®s); 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, ®); + 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; +} diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c index 6f0468cdec..24fc6bce3b 100644 --- a/target-ppc/kvm_ppc.c +++ b/target-ppc/kvm_ppc.c @@ -21,75 +21,10 @@ 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); } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 911b19e378..f9c0198311 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -9,14 +9,104 @@ #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 diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 67de951959..1c40d4358a 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -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); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 17e070ae75..134b0c6587 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -17,12 +17,17 @@ * License along with this library; if not, see . */ #include -#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 */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 89413c5395..66eae30209 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -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 #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]; } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index dfcd94980f..8a7233fc82 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -24,6 +24,8 @@ #include "dis-asm.h" #include "gdbstub.h" +#include +#include "kvm_ppc.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -32,21 +34,6 @@ #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 @@ -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); } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index e47c372fbd..202c098ee0 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -26,24 +26,35 @@ #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 diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 4a5297be18..10cc9dd5fa 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -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 @@ -22,30 +23,107 @@ #include #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 -#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 index 0000000000..01c8d0ea84 --- /dev/null +++ b/target-s390x/helpers.h @@ -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" diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 38823f54f7..b1404bfd2f 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -49,13 +49,6 @@ #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; +} diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index 402df2d85e..5ddc7b93ca 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -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 @@ -17,11 +18,25 @@ * License along with this library; if not, see . */ -#include "exec.h" +#include "cpu.h" +#include "dyngen-exec.h" +#include "host-utils.h" +#include "helpers.h" +#include +#include "kvm.h" +#include "qemu-timer.h" +#ifdef CONFIG_KVM +#include +#endif + +#if !defined (CONFIG_USER_ONLY) +#include "sysemu.h" +#endif /*****************************************************************************/ /* Softmmu support */ #if !defined (CONFIG_USER_ONLY) +#include "softmmu_exec.h" #define MMUSUFFIX _mmu @@ -41,18 +56,17 @@ 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 diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d33bfb1f31..ee15672185 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -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 @@ -16,46 +17,5233 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ +#include +#include +#include +#include +#include + +/* #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; + } } diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 789d1880b7..7d7fdde019 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -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 */ diff --git a/target-sh4/helper.c b/target-sh4/helper.c index d2038bd842..5a1e15e63d 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -24,7 +24,6 @@ #include #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; diff --git a/target-sh4/helper.h b/target-sh4/helper.h index 2e52768414..95e3c7c8f7 100644 --- a/target-sh4/helper.h +++ b/target-sh4/helper.h @@ -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) diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index 30f9842295..b299576651 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -18,7 +18,8 @@ */ #include #include -#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; } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 58e9b8f93b..e04a6e0f5c 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -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 index 0000000000..04bd2cf9c7 --- /dev/null +++ b/target-sparc/cc_helper.c @@ -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 . + */ + +#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; +} diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 320530ec9f..38a707466c 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -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 index 0000000000..c7269b54a8 --- /dev/null +++ b/target-sparc/cpu_init.c @@ -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 . + */ + +#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 index 0000000000..c7a2512117 --- /dev/null +++ b/target-sparc/fop_helper.c @@ -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 . + */ + +#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 diff --git a/target-sparc/helper.c b/target-sparc/helper.c index b2d4d70a11..037a72ce4e 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -1,5 +1,5 @@ /* - * sparc helpers + * Misc Sparc helpers * * Copyright (c) 2003-2005 Fabrice Bellard * @@ -16,1531 +16,126 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#include -#include -#include -#include -#include -#include #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); } diff --git a/target-sparc/helper.h b/target-sparc/helper.h index 12e8557133..1f67b08065 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -1,166 +1,170 @@ #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 index 0000000000..ac9d01ecba --- /dev/null +++ b/target-sparc/int32_helper.c @@ -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 . + */ + +#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 index 0000000000..1d471db999 --- /dev/null +++ b/target-sparc/int64_helper.c @@ -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 . + */ + +#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 index 0000000000..b59707ecd2 --- /dev/null +++ b/target-sparc/ldst_helper.c @@ -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 . + */ + +#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 diff --git a/target-sparc/machine.c b/target-sparc/machine.c index 752e431778..235b088a45 100644 --- a/target-sparc/machine.c +++ b/target-sparc/machine.c @@ -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 index 0000000000..8cdc224ae3 --- /dev/null +++ b/target-sparc/mmu_helper.c @@ -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 . + */ + +#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 diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 854f168c60..02b660ddf9 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1,4349 +1,8 @@ -#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 diff --git a/target-sparc/translate.c b/target-sparc/translate.c index e26462eef5..d26111209e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -25,7 +25,6 @@ #include #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 index 0000000000..a992c293af --- /dev/null +++ b/target-sparc/vis_helper.c @@ -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 . + */ + +#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 index 0000000000..a68c649e7e --- /dev/null +++ b/target-sparc/win_helper.c @@ -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 . + */ + +#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 index 0000000000..b4e72cfa6e --- /dev/null +++ b/target-unicore32/cpu.h @@ -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 index 0000000000..b5b1cb7c9b --- /dev/null +++ b/target-unicore32/helper.c @@ -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 +#include +#include + +#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 index 0000000000..615de2add9 --- /dev/null +++ b/target-unicore32/helper.h @@ -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 index 0000000000..6cf5255b26 --- /dev/null +++ b/target-unicore32/op_helper.c @@ -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 index 0000000000..4d0aa43da2 --- /dev/null +++ b/target-unicore32/translate.c @@ -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 +#include +#include +#include +#include + +#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 index 0000000000..4d9bd559d4 --- /dev/null +++ b/target-xtensa/core-dc232b.c @@ -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 index 0000000000..69f1065574 --- /dev/null +++ b/target-xtensa/core-dc232b/core-isa.h @@ -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 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 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 index 0000000000..13aba5edec --- /dev/null +++ b/target-xtensa/core-dc232b/gdb-config.c @@ -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 index 0000000000..7650462f2f --- /dev/null +++ b/target-xtensa/core-fsf.c @@ -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 index 0000000000..b519d6c741 --- /dev/null +++ b/target-xtensa/core-fsf/core-isa.h @@ -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 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 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 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 index 0000000000..0db83a6fd7 --- /dev/null +++ b/target-xtensa/cpu.h @@ -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 index 0000000000..2a0cb1a562 --- /dev/null +++ b/target-xtensa/helper.c @@ -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 index 0000000000..09ab3325c9 --- /dev/null +++ b/target-xtensa/helpers.h @@ -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 index 0000000000..ddeffb2da4 --- /dev/null +++ b/target-xtensa/machine.c @@ -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 index 0000000000..0605611031 --- /dev/null +++ b/target-xtensa/op_helper.c @@ -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 index 0000000000..df19cc96ea --- /dev/null +++ b/target-xtensa/overlay_tool.h @@ -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 index 0000000000..c81450d1a5 --- /dev/null +++ b/target-xtensa/translate.c @@ -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 + +#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]; +} diff --git a/tcg/README b/tcg/README index 660012281f..cfdfd96d09 100644 --- a/tcg/README +++ b/tcg/README @@ -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 diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 918e2f73cb..e05a64f75c 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -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); } diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index d8d7d948ce..48586c3e60 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -24,11 +24,10 @@ */ #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 diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index 7f4653e342..59d4d12ba6 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -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); diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h index a5cc440d49..7f3c4cc3e5 100644 --- a/tcg/hppa/tcg-target.h +++ b/tcg/hppa/tcg-target.h @@ -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 diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index cc750b46f4..7705733e5b 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -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); } diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index bfafbfcbae..7756e7b03c 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -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 */ diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 8dac7f72fd..e3de79fdb6 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -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)); } diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index e56e88fe91..c388089004 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -24,11 +24,9 @@ */ #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 diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index e04b0dc32f..c5c32825f0 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -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)); } diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 0028bfa562..477bc38b01 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -25,14 +25,13 @@ */ #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 +#else #include +#endif static inline void flush_icache_range(unsigned long start, unsigned long stop) { diff --git a/tcg/optimize.c b/tcg/optimize.c index 07710080b0..9c65474a8c 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -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 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,284 +27,265 @@ #include #include -#include -#include -#ifdef _WIN32 -#include -#endif -#ifdef _AIX -#include -#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; } diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 7970268e5a..f5d9bf3b00 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -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 }, }; diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index a1f85997c6..3f22aaac9d 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -23,11 +23,10 @@ */ #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) diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index ebbee343fd..44193784f2 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -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" } }, diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h index 8a6db111a7..97eec0843d 100644 --- a/tcg/ppc64/tcg-target.h +++ b/tcg/ppc64/tcg-target.h @@ -23,11 +23,10 @@ */ #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 diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 450fcabd70..9317fe88ef 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -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(); -} diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index 4e45cf3141..e4cd6418a9 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -23,12 +23,6 @@ */ #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 diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 5f1353adf8..5cd5a3b6f6 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -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) diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index df0785ec68..c3fe131119 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -23,17 +23,11 @@ */ #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 */ diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 2b93b7d20f..82e04e7f30 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -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 */ diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index bca40bb636..8e06d03b17 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -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 diff --git a/tcg/tcg.c b/tcg/tcg.c index 777a4232a3..bea603199e 100644 --- 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" @@ -65,16 +63,33 @@ #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; } diff --git a/tcg/tcg.h b/tcg/tcg.h index a3061c11c4..05682807e4 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -22,6 +22,16 @@ * 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 index 0000000000..6ac1ac99d6 --- /dev/null +++ b/tcg/tci/README @@ -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 index 0000000000..fc0880cec5 --- /dev/null +++ b/tcg/tci/tcg-target.c @@ -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 index 0000000000..03e0fd1a7f --- /dev/null +++ b/tcg/tci/tcg-target.h @@ -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 index 0000000000..10c411be8c --- /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 . + */ + +#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 index 0000000000..a20a7142ed --- /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 . + */ + +#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 index 0000000000..bf9f3e91b5 --- /dev/null +++ b/test-coroutine.c @@ -0,0 +1,192 @@ +/* + * Coroutine tests + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi + * + * 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 +#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 index 0000000000..fa5a7bd8dc --- /dev/null +++ b/test-qmp-commands.c @@ -0,0 +1,142 @@ +#include +#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 index 0000000000..847ce14ea1 --- /dev/null +++ b/test-visitor.c @@ -0,0 +1,338 @@ +#include +#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, <s, 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, <s, 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; +} diff --git a/tests/Makefile b/tests/Makefile index 9ded4b7349..430e0c1776 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -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 index 0000000000..5e8c1d32f3 --- /dev/null +++ b/tests/cris/.gdbinit @@ -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 diff --git a/tests/cris/check_openpf1.c b/tests/cris/check_openpf1.c index 1d71e0bddb..fdcf4c5c3f 100644 --- a/tests/cris/check_openpf1.c +++ b/tests/cris/check_openpf1.c @@ -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 diff --git a/tests/cris/check_openpf2.c b/tests/cris/check_openpf2.c index f44a8f34bb..5d56189f8e 100644 --- a/tests/cris/check_openpf2.c +++ b/tests/cris/check_openpf2.c @@ -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; } diff --git a/tests/cris/check_stat3.c b/tests/cris/check_stat3.c index 3b5b217a1c..36a9d5d274 100644 --- a/tests/cris/check_stat3.c +++ b/tests/cris/check_stat3.c @@ -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 (); diff --git a/tests/cris/check_stat4.c b/tests/cris/check_stat4.c index e1955cab34..04f21fe7c4 100644 --- a/tests/cris/check_stat4.c +++ b/tests/cris/check_stat4.c @@ -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 (); diff --git a/tests/linux-test.c b/tests/linux-test.c index 9986e299b2..2e4a746ac3 100644 --- a/tests/linux-test.c +++ b/tests/linux-test.c @@ -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 index 0000000000..03a1abbcfb --- /dev/null +++ b/tests/lm32/Makefile @@ -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 index 0000000000..5f9cfd95d3 --- /dev/null +++ b/tests/lm32/crt.S @@ -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 index 0000000000..52d43a4c74 --- /dev/null +++ b/tests/lm32/linker.ld @@ -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 index 0000000000..367c7c50d8 --- /dev/null +++ b/tests/lm32/macros.inc @@ -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 index 0000000000..030ad197bb --- /dev/null +++ b/tests/lm32/test_add.S @@ -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 index 0000000000..68e766d1e5 --- /dev/null +++ b/tests/lm32/test_addi.S @@ -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 index 0000000000..80962ce7a2 --- /dev/null +++ b/tests/lm32/test_and.S @@ -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 index 0000000000..4f73af550b --- /dev/null +++ b/tests/lm32/test_andhi.S @@ -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 index 0000000000..da1b0a32f7 --- /dev/null +++ b/tests/lm32/test_andi.S @@ -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 index 0000000000..98172d8a95 --- /dev/null +++ b/tests/lm32/test_b.S @@ -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 index 0000000000..635cabacad --- /dev/null +++ b/tests/lm32/test_be.S @@ -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 index 0000000000..81823c2304 --- /dev/null +++ b/tests/lm32/test_bg.S @@ -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 index 0000000000..6684d15a55 --- /dev/null +++ b/tests/lm32/test_bge.S @@ -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 index 0000000000..be440308fd --- /dev/null +++ b/tests/lm32/test_bgeu.S @@ -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 index 0000000000..8cc695b310 --- /dev/null +++ b/tests/lm32/test_bgu.S @@ -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 index 0000000000..a1fbd6fc07 --- /dev/null +++ b/tests/lm32/test_bi.S @@ -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 index 0000000000..871a006755 --- /dev/null +++ b/tests/lm32/test_bne.S @@ -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 index 0000000000..0384fc6128 --- /dev/null +++ b/tests/lm32/test_break.S @@ -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 index 0000000000..645210e434 --- /dev/null +++ b/tests/lm32/test_bret.S @@ -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 index 0000000000..1b91a5f2be --- /dev/null +++ b/tests/lm32/test_call.S @@ -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 index 0000000000..1d87ae6e21 --- /dev/null +++ b/tests/lm32/test_calli.S @@ -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 index 0000000000..60a885500b --- /dev/null +++ b/tests/lm32/test_cmpe.S @@ -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 index 0000000000..c3d3566ad3 --- /dev/null +++ b/tests/lm32/test_cmpei.S @@ -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 index 0000000000..012407874c --- /dev/null +++ b/tests/lm32/test_cmpg.S @@ -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 index 0000000000..84620a00e3 --- /dev/null +++ b/tests/lm32/test_cmpge.S @@ -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 index 0000000000..6a8870f4c3 --- /dev/null +++ b/tests/lm32/test_cmpgei.S @@ -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 index 0000000000..2110ccb6b7 --- /dev/null +++ b/tests/lm32/test_cmpgeu.S @@ -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 index 0000000000..b9d1755e22 --- /dev/null +++ b/tests/lm32/test_cmpgeui.S @@ -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 index 0000000000..1f622d2900 --- /dev/null +++ b/tests/lm32/test_cmpgi.S @@ -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 index 0000000000..dd465471ea --- /dev/null +++ b/tests/lm32/test_cmpgu.S @@ -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 index 0000000000..759bb64b3c --- /dev/null +++ b/tests/lm32/test_cmpgui.S @@ -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 index 0000000000..0f1078114c --- /dev/null +++ b/tests/lm32/test_cmpne.S @@ -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 index 0000000000..060dd9d394 --- /dev/null +++ b/tests/lm32/test_cmpnei.S @@ -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 index 0000000000..f381d095c5 --- /dev/null +++ b/tests/lm32/test_divu.S @@ -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 index 0000000000..6830bd1abf --- /dev/null +++ b/tests/lm32/test_eret.S @@ -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 index 0000000000..f84d21ead9 --- /dev/null +++ b/tests/lm32/test_lb.S @@ -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 index 0000000000..4c1786ad71 --- /dev/null +++ b/tests/lm32/test_lbu.S @@ -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 index 0000000000..e57d9e35cf --- /dev/null +++ b/tests/lm32/test_lh.S @@ -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 index 0000000000..e648775d94 --- /dev/null +++ b/tests/lm32/test_lhu.S @@ -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 index 0000000000..f8c919d2b8 --- /dev/null +++ b/tests/lm32/test_lw.S @@ -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 index 0000000000..42486900b4 --- /dev/null +++ b/tests/lm32/test_modu.S @@ -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 index 0000000000..e9b937e648 --- /dev/null +++ b/tests/lm32/test_mul.S @@ -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 index 0000000000..d6dd4a0f7e --- /dev/null +++ b/tests/lm32/test_muli.S @@ -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 index 0000000000..74d7592565 --- /dev/null +++ b/tests/lm32/test_nor.S @@ -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 index 0000000000..d00309c73e --- /dev/null +++ b/tests/lm32/test_nori.S @@ -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 index 0000000000..4ed292330e --- /dev/null +++ b/tests/lm32/test_or.S @@ -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 index 0000000000..78b7600e03 --- /dev/null +++ b/tests/lm32/test_orhi.S @@ -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 index 0000000000..3d576cdb8b --- /dev/null +++ b/tests/lm32/test_ori.S @@ -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 index 0000000000..320264f148 --- /dev/null +++ b/tests/lm32/test_ret.S @@ -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 index 0000000000..89e39d621d --- /dev/null +++ b/tests/lm32/test_sb.S @@ -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 index 0000000000..b442e32374 --- /dev/null +++ b/tests/lm32/test_scall.S @@ -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 index 0000000000..58db8ee8b9 --- /dev/null +++ b/tests/lm32/test_sextb.S @@ -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 index 0000000000..a059ec3ee6 --- /dev/null +++ b/tests/lm32/test_sexth.S @@ -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 index 0000000000..ea8b3f2067 --- /dev/null +++ b/tests/lm32/test_sh.S @@ -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 index 0000000000..0aee17fdb8 --- /dev/null +++ b/tests/lm32/test_sl.S @@ -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 index 0000000000..a421de9014 --- /dev/null +++ b/tests/lm32/test_sli.S @@ -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 index 0000000000..62431a9864 --- /dev/null +++ b/tests/lm32/test_sr.S @@ -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 index 0000000000..c1be907b5b --- /dev/null +++ b/tests/lm32/test_sri.S @@ -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 index 0000000000..2ab0b54c77 --- /dev/null +++ b/tests/lm32/test_sru.S @@ -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 index 0000000000..872c374121 --- /dev/null +++ b/tests/lm32/test_srui.S @@ -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 index 0000000000..44b74a9e10 --- /dev/null +++ b/tests/lm32/test_sub.S @@ -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 index 0000000000..d1fdadce61 --- /dev/null +++ b/tests/lm32/test_sw.S @@ -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 index 0000000000..14a62075f6 --- /dev/null +++ b/tests/lm32/test_xnor.S @@ -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 index 0000000000..9d9c3c6780 --- /dev/null +++ b/tests/lm32/test_xnori.S @@ -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 index 0000000000..6c6e712bae --- /dev/null +++ b/tests/lm32/test_xor.S @@ -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 index 0000000000..2051699f12 --- /dev/null +++ b/tests/lm32/test_xori.S @@ -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 diff --git a/tests/qruncom.c b/tests/qruncom.c index 079f7a2973..2e93aafb87 100644 --- a/tests/qruncom.c +++ b/tests/qruncom.c @@ -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); diff --git a/tests/test-i386.c b/tests/test-i386.c index 8f481c7f7a..8e64bbaf38 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -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) \ diff --git a/tests/test-mmap.c b/tests/test-mmap.c index fcb365f40c..c67174a260 100644 --- a/tests/test-mmap.c +++ b/tests/test-mmap.c @@ -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); diff --git a/tests/test_path.c b/tests/test_path.c index 234ed97088..7265a9445d 100644 --- a/tests/test_path.c +++ b/tests/test_path.c @@ -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 index 0000000000..8713af16eb --- /dev/null +++ b/tests/xtensa/Makefile @@ -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 index 0000000000..d9846acace --- /dev/null +++ b/tests/xtensa/crt.S @@ -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 index 0000000000..4d0b307fd2 --- /dev/null +++ b/tests/xtensa/linker.ld @@ -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 index 0000000000..2d4515e14f --- /dev/null +++ b/tests/xtensa/macros.inc @@ -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 index 0000000000..6cbe5f1fca --- /dev/null +++ b/tests/xtensa/test_b.S @@ -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 index 0000000000..6a5f1dffc9 --- /dev/null +++ b/tests/xtensa/test_bi.S @@ -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 index 0000000000..50e6d2c22a --- /dev/null +++ b/tests/xtensa/test_boolean.S @@ -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 index 0000000000..f9ba6e22e8 --- /dev/null +++ b/tests/xtensa/test_bz.S @@ -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 index 0000000000..c186cc98d8 --- /dev/null +++ b/tests/xtensa/test_clamps.S @@ -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 index 0000000000..e8d1b425bc --- /dev/null +++ b/tests/xtensa/test_fail.S @@ -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 index 0000000000..68b3ee1492 --- /dev/null +++ b/tests/xtensa/test_interrupt.S @@ -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 index 0000000000..a5ea933913 --- /dev/null +++ b/tests/xtensa/test_loop.S @@ -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 index 0000000000..5ddd160ffc --- /dev/null +++ b/tests/xtensa/test_mac16.S @@ -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 index 0000000000..2534c9d90b --- /dev/null +++ b/tests/xtensa/test_max.S @@ -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 index 0000000000..6d9ddeb1ac --- /dev/null +++ b/tests/xtensa/test_min.S @@ -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 index 0000000000..52d5774212 --- /dev/null +++ b/tests/xtensa/test_mmu.S @@ -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 index 0000000000..bf94376649 --- /dev/null +++ b/tests/xtensa/test_mul16.S @@ -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 index 0000000000..fdaf57331b --- /dev/null +++ b/tests/xtensa/test_mul32.S @@ -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 index 0000000000..a5fe5debe4 --- /dev/null +++ b/tests/xtensa/test_nsa.S @@ -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 index 0000000000..6be6085fc3 --- /dev/null +++ b/tests/xtensa/test_pipeline.S @@ -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 index 0000000000..12debf1fe0 --- /dev/null +++ b/tests/xtensa/test_quo.S @@ -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 index 0000000000..bb0d5fe202 --- /dev/null +++ b/tests/xtensa/test_rem.S @@ -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 index 0000000000..3eda565e8a --- /dev/null +++ b/tests/xtensa/test_rst0.S @@ -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 index 0000000000..40c649ffb8 --- /dev/null +++ b/tests/xtensa/test_sar.S @@ -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 index 0000000000..04dc6500c1 --- /dev/null +++ b/tests/xtensa/test_sext.S @@ -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 index 0000000000..a8e43645b7 --- /dev/null +++ b/tests/xtensa/test_shift.S @@ -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 index 0000000000..1041cc6658 --- /dev/null +++ b/tests/xtensa/test_timer.S @@ -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 index 0000000000..cb2d39e1fd --- /dev/null +++ b/tests/xtensa/test_windowed.S @@ -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 index 0000000000..265a181239 --- /dev/null +++ b/tests/xtensa/vectors.S @@ -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 index 0000000000..05d761f025 --- /dev/null +++ b/tizen/Makefile @@ -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 diff --git a/tizen/build.sh b/tizen/build.sh index e615c2c071..dbc266c1fb 100755 --- a/tizen/build.sh +++ b/tizen/build.sh @@ -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 index 0000000000000000000000000000000000000000..5df59685c084414b05846688de5daa12ae5b1b07 GIT binary patch literal 1850894 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%0A?3Xd7vti7LZ*~K$Qeeg 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%0AgkY~& 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

%UP&hZ22b<9_%(79aQtDFj?b z7V7uz=*WdC@l#pMkZgD6xeyq1+OliAWT`p%m=)4dZo#^Xa=R~BkH@~@!nx%2xjOnw z>u}FY(eyCp_NqBflIK^v@yUt<1*jvwju!+9S{ZsiP;e z5lC|C<)A%gkrdSugatGe3LT?`x<;Qz$7%FlJjbBYi?2 z;!rlDAzFB#6-}qQdgi~(@a1B*M2ByteoxM!MFd*&5rNi&25E%VDJs{eK-$bT-!mFO zB%s5)J71l8BM`1r_}u~;vUR%@>7X9z^Zv1&W80(Gi(ZHaNU&)$2H%JO7F-9F+6eEV zaI1}unWl*RdxfsrtJ>w9hq>+X*nOa3@vvGQk7-T5hb=!EmJ6216|!1rO-hm+S4(R( zw_(*F7-)+eYN)2L;s7cf$)2MyMm4!I*@HMhC(*K!LM{eC%gySSTO#ia-A#xk*uf)v zZx9rDy+K`(e?5w37iB5#U*cceJOzNZF-!9MZI%YF_a4A^cRqHikBVAzS2_P(WUwN! zT-b>ch8->L!^iHJ@Uf+5o~>e}cxQ#EW3hyQSfca)RT6}WOk$t}yJW`cz4`Tp2pR2Un zm{*l{7Ah4ELY6)_gQ|`4asyqppR6TUB-BjZ>Q`AGy0d7l-5{7FwI zS1919LbYzi3UpdL-oXTW7c(92xDqqdJYv0@$GW0<#M+Z#P@E%&D-VV9hYQqDTb$<{ z-vFjQ8t8Y{@c(mIn135!VgBvw(wnyZ=h6D>WE4wO{{}Af9;&~^{92g4;Hi4|70rCi z)D_CiaV(VT-IJg5J;|RPIwljxI~Lb?JE(>bBU_D%DhYVV+h!c(<&4lLR%tzIxXx`S z`BqJ?8H*G~DZ9MXdLl3B!{Bcq*hj zuVLKptI7SB(qV=AB_a-}t1tIILke#b)!BayyXC z^%?b)$NF+vya8{tu+ykJcL50+>_3Awzj^c2)}g-e@ySisPXu}YUizG^vmG1cl{0JK z6XcaMYd5D|d$Jab`eN&B4+VMU%-Wv@dF9O7e;^P2;=a*5B7$1xG=Vcpv0<-OqWd;k zHuH`HibYAYK{1Z9*Yr^Q*Gq_H*Y373YLsB`7Ive}eN z>&|AYxl&Z`K5Zh*j8Lr07!i|>dR?<(_4YDJL47lo2jkgbd zU~D5)z{a?PJYv@G_g!gecv<=6(v=MP^X6Nchrp2*KV#`qO06ZGdJDQ zRh6_%f8iW1S{v`C%T3Wm*C39d%4QnXCnU95yvw^sYIT6VSg)|^mbzYPi=Zo`V^{}h zsG55_06gf{_|mExb?J7}JLwdiU_C+|L=i_-8}~rt-E$82?qih@aQT&R77%g)#0HHB8{HV?TwGo;A6!N3Th1+EX)Fi68dxRL-H+Ndz$hp*5ZSK zVKLSBE~a#zZU#j+w>s`BGeb}$eTy)YGClgZE+v|(0?|mrV}JN9m71e&H(xE4qPM*g z%{fe)Mr57cjd+TnEK4pSy)* z;=g4{c%Snj5;6{O^U=b5XbQTbtF&^jnXqYsl|a1p~pL``|35wojbMl`sUNQ=EQzfo%`7fr}G;ljH^(N&RY{6eW!tiD>ys08HO z!atJnV$>oa)UY~`+l6_O7q&&yQzUxm8t}@;?~*LuUH0T9f03AN35kcBc>)+(LLwk( z1xXnvaf2=mh$Ku?92R15-KE5A-D{-Rh3-vEQc?E;k_K66#NEXV0NEtz6&Agt0YGil z+E^o(mfmrro`voyhU!D=mt?r>n`trYTYj#(a=nCshe&(9N9fz)G;^O`lo3~LVs|0QUxXp(*xkbJY(Naa!qt|nY(P3EBOD$5)SFb3g_t3JL zW^7Rc=ynsXLx9c7X2S9c+`E$5B}4cZJa?^1XXolB*sA5e3Cw2;-n*5jD%Q}<{C~%a z(%pMr<8HWD+sTF!v*x`xm#68Ax)lA^DD7FNzuZkQOW?<&=1lGNqS4j4##b)m-QAO-tG`;= zc-Lj`;Y-vUGO?-g(K(!o^0`VL7$V}#_l}Am*)nHukK9sGJJH~+iMceNui}Br-gT=J zkL;t>@T9Gl9qXn!`#07ic#0l*=`sh;E!F$c>fSqE7U6uW=TtV1<|pNz#<5^h+)_~H zh0y8tF17dix{Xr9gD|h?MxUqnFX^ilM&JI>pF+LcAco$x;TfTdv44@9J@zk(_rLY2 zPt@`a2vPR15qwp!ur!>QOHIg@S@WK&XfV1q_Lv`?%7J=o3UoYtu4~AM@>^^4%!q3> z>~m8Qy)9A+8^}Li&{A1>B}ALq9*X|`^KfMJw*JJB$47WGJ4v~Qlx$WGLpHORuCe}} zStHZ`}m4i)$K~*%nRGFh*_6I7O{Z4Rqt=*-AyB2<{GBfz=Wm=VUUBw^M zpJD43ph*f`+44s;6;^s%V(7|9O`i2m>!E~J&D@cZLyXTt8Y9__ajIf%BX~hNbr@N5 zRglBb+!gBzv$89$+oXcAYO*Cfybi)yD@@ubSa-9)UlL5u$raTIay~yZ19s(SR;9O% z>D|Ue46WP2Q(6NAvRdj|rb~{gBUK`Y)M?1V7?-MEeazgYEeeGfy(BS}dn^o1^)5={P56E#&cd!noP%2sowx0bGqdoR(E5!aEn(vB3iHd{xe zYG`6sX4GEur*(_17kUA~(pvafz7Xzlg!*=R@ZCqyk@R59wm*;AuGM*WYN9Q;LQLr` zL}qhz_-d%`txq+Dqr>+@k8Y!Dc8Ov%{>*AGGnWfi5B%`Kp3#zalsIBqB4V;Kq9!ZQ z&V?1|=7QMNa`oFuTfgNO9B;+o^YbwI;F*a6{0vd6eo{?^Aq$N>@cAJN^nV{S(9tC( zHaAw%12I$88Qt%)WwoG|gWr9&{HJO;nCgs4&)=bO=EE8fe)rk<4G%NZu5l(@@27%* z3DZ3~v2Vi5V^7S%IuZPqcA^Zq)vFU~+1L-@B?u6bv%?idRJT|ZI}Ou<->~L2o4Hca z$#7!RD~lo(H)4@|qNsT9ViS(Y%;@k%ih|slc$kNDTH1Kn>3p*QhNn-lOo^7@qVu5%Ss@*)qXGBh-6e20#oTqFo_N$27PXwTT!(%F_+5h3#c>SEw}QZVHf<`vb6@T z`(w*s_v(X~XHytEafK0QlUyZ6rT6NQAO2508NDr4X>#AmS`+l&28HNtEj){hg^*B>o3g7V$r?F7Bs5rY32LJ@kR;0XHx>$*BdW zg`O`f zFn6EO+KSwhf!laFVp+mGc!#Y?ZsV_xbn9T>D$V<)^411<+B01A+-u6aF39_KnY=|o z-j7T3tj@2K2Uc#4?7xNcvczlpS($i8KP&jeG(W?M-{@`zoW4yL3bC*}W=m$+R_ttY zi)Xlk(-3;(vWc-)R{=fP$tHOo)0<;B9t^t)p=a!EG2|e)tpQ+rB1SjOuhMGJEBJF^0w~ALeg#c%B+{8+WE* z&kj;e4DKEf_cP843QXl+UKmHxF95o-G13m)h|ExkUw)n6f6^4oav%3A62D=>jpO)Sh$kDJfw2j*EBFfT8S0%sQe9C^ic^Y>k;>@&OI3nN8GZH;1~1LT zU6bDu4F&p?>NGg3?gR?^XE?uyQlZhR;1TBtTZM1%alYuP5z`~lRl~L_tnje2MyOOX zOs~~cbk)*?kW@LLZKPKys2QT5rcDI|U1@Y@ICBaDri}`5`8eDj*49TT# zNbZEL=%PVH4w$H+{Gi<_O&EzbcGl>=Cfo#J+d(2z1IkgJ-%=3@x(TQD!;7^P9ArM? zKtBMRPNPBNSTXU4<5jqD1ZJ)^VOr)Fg>XBh6aJ>-M9Z(NLRO@UC zbV8_>@)AOEYLyV0M!SI!iZQxC2uZO9LZ~n#YAFm!QENAzbN|c6!vKiHGmZ|Pyq1zK zXjM;<-8HUZt74^W{Hqs7hxj#M!D0*uz3_)fZh*^1O5NMXss=&JVw zYf}M4%k@Oz?P|TP+J}-s`gRSa>F`{#{qW(szdS*&C7O9a5i8HkE^az@%6kEGAmB=-Wj7b3f;g>>PLE z6UVc4dUxkO?|dOg&Y_0`RAD#qpq9kP#in$)nK>RJTg2#h93Bd+=L1Rw0jWz{-Yhp? zYh6S2r92j}-Tw2~4<#=q<1ysO?~TDs>%W1sZsXV|d;P6|cJuK2U@z-UkL%4om@B&Q zW-a#>F<3E7xqo#2N+~Ve09hO;TA-@D(6wIw=pn<1hq_k`m~ z30fsgNQ>yAzX(h%o>C!r$JB{C{UEyN&@gGxTA)Ezs>tt6gFHhF!Ze7QDNwiTGaXw_ zDxy#8qPCVh%jt?mW-q{q4Bws@%;vQ&qXfqRYLvhi^=&Gn1 z)QAv#Qh){NXhT3|-|B1*Cq3y@7g9unLA&t=1JT{RYLi=?Hqpl*hn+SlQrOf|M!S7o zA%NQvc}5VcB)FY&EA3iz(Q}UbL>$I_LBHr??nDH!Lo!%XD-tFLisU843##TeA_Ybu zW)kG-onJ@nHs7u*hIL?U1e8!j^$VYqIfa@plGpXxKXo5kQ`WF4(BK4+yK~oQE!f3G zm=Mhd$RzeGtB7iUobZp7+>16TPb(A`_b>d5oFj9+ zcwp$QU{t^Blz>lRO7a%o8LorN0tq2m;iSgyvf_0f2G_i-$o&!T^p*A$y1E)`i{W)P zGl9GFF^F_BS>I7T&es)R<&OHzJ|8jOFM6a^JUhXj$`+ocASH*(H}vB-?I~x|l_|e_ zE6-_wju{;OxnuPDtBuaJa^SQ}el~7eYve-pba2Aja}J7|7j1kk@(H2~pI2xP(N>NT za`(7>BE}lhJa^~*LU?md+!>5SFJ{&9>~H5<6?6E6EA!Uf8iKcN{|E3E(l*#ek;i)^ zP>{I|lEkI_5KKv-$fh8y{3FPq$Ylu2Ww>dIixdjFqP+jctJw69LEaBb^M0Vbc|o4k zX3=x~%KK~b?E6piel2qf2nGFIU1}5j+#t%QGf8{0-wYys?T~y=*0X4zVp#p${ikh@ z*L!#(r@0A50yWcm?z>NLmt9b&G+f^74=vco@@w`A#a<}a1vB1BqnVANW^P-u-?Z?I z^Pz7g!`c|}e;KhVW>MTyhvz@66xat`=c=pjMcr1qRKU z?!|Pqxph8&IQLk_gHEz;I+eqkTB9Q!BzUhe@6Gsf?a@WN-7OPsgy(SYwaLCCI`UB^ zx&TH!+xQv*Bf97)CAyZpemj=H4wOfUrMPeKw$Oeb)l@8Q98}FI%5z1VcRLd|W!~eW zW!!N^Gna7Xjr!rcgAkdc^RCeC)S1v{ZVzE3-JF|;kp>oZOi!YbBcE@fkpNhd75g0G z3B^8VF%L4qOf_`NqYwVT%d03zn&>C~3+4(3XX|lgx#VeH#jpX?O^$a(hZhwuKboq;VBCa zi)i-11*-mi0h4BVQ}pr=-=7?qbQxe?+D~BWs9lHOP0$OpF@vE4&Y74*TmjCp&Nymv zEVUiBcPzDzE0y=dx0l0*tR_c0Gtf}5R)Ki#fIJTvPc^9vhSJymd2*DR_C!g~?H#A1 znd}*P-qNPYCTaM<+Y2`N`QTvkA<9ByOlvX{fH1DB1$eU9> z?-$DZV)?w~$~(P$UPgJx1$lp4+Fq~n-djHJOy#|?)Ae(==T1`IW99SyM0qy{d6$&7 z_dex)uY6uec~_Lr`yXM}TRv~C^3DqKcEkFI$~(S%p0B*a%jaFHytm$o1ZPXk`?Y2h zwbTkZwxewl1!KeB{wWw64bX0D!PwBT3$58zW^8b39#qp>FgB!!TC?Aju|b{9?zzC| z=ycDS;W3EeVb2A|huB2guV8#wHGu)5m*85n^I}x`C*u^#zdX3|$7YKRV!F6pdfBB{ znJt3N;@xgvj;%$(^<9?Vuw2Vn2Ts9Eouh;N^!~eE;~BtasEscAKH`Wz>wtxZ#y2k0 z`F=g7$vG>m@!>go$6s2#hjlfn?jhE*2NQKz4L#9C9TH_oTKKdfy67(n8gZ45jx;KK zgvLb>_C*&(m5yf^9m&bcAYJl}y?&v`skqj?@}A0K%7u8d{u5MKYhq_(J&OZXFfH9_ z<86)}l=v*V)3o_d7B_aO#g}ELbg9L)s+seGLeEf7%1_l(5#Q*gt208cG@cqA{+H1ly}+e8>uR#z*3^!>FL$nm;wVX1@gpB-;>=#`vnx@i_M0DghuDsV+U<85`BbpW3K&Lo4Y73n$eM|V4g;*p9(a|s%@s*kA$d9qkm4A%YLrHS+r;6r{}Ah!znFe`yy9kOpg93iJX-|IH z9|2;la!^5lFqC#LDM{;nEnM_k{944C;>i5wjm0TC zm(P1vc}J25XEx-{l&uU6=1$ZFQ;>TfCa(8ju96>gXhZH%g%-OgaXT04`R5O zIq=JVf!7Lf6RB864_Ixk3tx0F0 zVef&*K6D@PDw)DOWFalJIDCZ}mpT)|yDx$+O)S#a`-GF4b_Jc%>Qhk)s4xPY$ivUJo`&9$R z8a;pnq<|s7IbV4Mwk-w$*}wls%2KS6AeL7OLG1nBQ|q3u$2Y*7{%GjFeFMPT-&M;j zG$7L$0^%=MA|U=k3J}oW$N(liI&zszx8>+~G zSyu`s02b&8+S(gEX?6#^=|)feoJ+dG_!yr<*zlJtVZ&bw11=hotxS4!yu+$gws_A0R@@nR(c`Y0*MswOWSN<|$Y#b_1S+y_Xi`+09st z5#!qB+0U%`;;3;E%Q=XWf+%yV!4rxu{3zxPL?-&Xl2J@ff8PftM}I?HK_D}VNT-$# zIsr6;Zq5p=htKNpzIEVOLJpR^BRI=g(Ydl(K$9!0b6?&~Y&~$WIyZgUH{y{GH^U<9 z;>OxN2ncT63qox4!&yfrN$VX&cSJ*^(AT+ixnzig3{jgBhh%e8DA71II{dZieb zmYFW)1LmJ%48shC9RSjQ-04T((Yjo*7M`G%mfTY;$tm_YfL~7wo3G{XKvvpdaPzWp z_t56sWuaXMUGbZ@BF)t{5`+YK{&?oD>`19)>$uvhT@XKB~0`Fki@ zCePqqL7sbuK`~>^C0rraOBd|CR%Vfv#9+}CVW>%kS zU3!&SeMIN6@ho-akIm|XPpPXjP4W3wzv&cO z>?jj7{Jw@zB58GwlO%21yOgv%k}z%5vMF>W4w-_6t@)s#>#c%@oKr>6u%ENaR(*z0 zp+yZ9LLzF2@=4Ee_SQ5?YF)J7baXm%N2TGp@B>5+>8^ku+k_%YB=2C%!1!g%yietG zwh3O24A=gD3HV-K018hX2V;r4vH-{ef=BE#_?`8PPPzkKs!aV!EVIeXM^~9`Z5uM@dOb`;vU}7 z5JxZ@iRi*3H5&!q(Qc)_Y_oYwnN3>Llb-Kklk~_FVMBaCTgI*w#SJEgPG^Nmt{JOh zEN{(KD#|jmMh|v*_dyKZ(S_e&s(oydX0M}g z?F0|$%+*?(qI|Gj-!kZcd)2u4SPTDDCJHVuHE&LRjckhL{LFeacC}q?TC1?XZ^UTnER#8^1z>3|Q=Y!%XT) zB*0?HqDd`gu`-jo8;i+a3|LID`L5`~qw}%(!n;u2(M6ZJ@O-!7zi=*hD2_U&L7HE@ z$ocQgtgfQNmy$kR?*yiIwmkImg)k{W*!a$7uB*BdLo_pq%c3Q92kFUN>668EeCuog zH>KMgmTs|j(lM_5@S6qSq?QSpfrDoe>-U)}<5rmy=IPy}o*xjQ z7nqkVo8FrVtgz3B7+P(nS`Mu+S1-?Q@*h^=;=)4-`FwP*Gx;cgB@<;8B}%+MW5C0x zsn0u-I{Uqg^<7{`Z&!)=)(3b&XCSM*aD2W~PBgk%OT(dDf6(^4#e@6jX%O zWyxKHnw;3cqn8tFUM^=9OWR8YN`}1WmGSW+n}Y5H%<}(J_dak|R@MIh9Oj^-Og%%4 zMX5Q~WDrvgHQCH{yiGdTRAW+6(T#3YSEP`?K~w=RD`kGl&TF`tf=(XFq%GKWneO_TFo+wf5e> zrmp;8c{P3Sx^NZVWNxG=j`VTkBdmLS!;u;w7tTH010*B673^G-NyycV={=K1DyC1w zZgVonqmPt8^*kiuH!I72RNB8!+*j@i^FvMt7-8n$4E1BuzgOuekY2DPBOy|jlmFsj zPX7B#Y(5kC?umz)z_;4No{Yi$hrrwn_*Yu!I<*;6xQ;%SP)sX6t5$q2m-DB&oJ#L< zZgI1UOsiFM*2I)COJ$twG5bd$W>)^lc$n#uGk_3O_{vdF)?tl!+U4J zsf@`fIk{VUu_-yZTeHEGoPJd{PEvaPYMrGl)UQs<=~t)c^sBlZ>}e{`$=Oz<*RM{t zA}`6=>yfiHhqN%m==bE!M3`*dRlS4nysA~+^cIs-wa)bOk1oqO>J_BTsz@6_bXI47 zl2*6T9&RfyN9Jg69-mfN?@m58;)heHN ziz5BaVa|sxSbp4HF1rK;-$Lr$?y~n;`?6Kv>#{FYWG?%F%YJ!5_6J>d?W^*&54!A& z3$pKU*{?3hzSCu2Qjq;=mwj15_T4VKCiXn?&%5lJ;+eo2Gp{1x^{^&8HP-4mtkAL?@|Vy!TdU6;yb2g#qS}kR4t0`l-)40@3W$yLR`i74nPW;5-FP5aYrI(gAR(k0f;3>WIfCEV{ z{h)$OoAkj>1)W}6jF-yU+NTVD=9{)w*QZ#k-KG<*tW!+8r8=sZ<^sgLB5{zC+(xCv z6w|ZJy}?OPEg~p-u@2G_~SHp?@vucFaDKq|+r=5Q!Nw?&Hq?_Z^MsVFnrGRo=x9otV8?7uxx<}E4{cA~A z(tadKCy{3O0sC%R@8-JW33<{<;2ECl?ncMsNVkGelyr^52`AMioS1BOcvsksUp3NI z=Y^BTA;L+{WQ=fTAxlsDF~FKL z`#H6Stxpm>l2;|Pz(^xenn?X{!R>kO4BjlK=WCYCBhAq;QsU@bUpz`->I>?x<8^`& zsk`Zp0txZwxlZ^tq0|$)=cQG4duM*ubJ!abf0p+wI{dKmXNWS|A4q6SYzF=Ih7sO| z?=F5gT+(9QSJ>n0!i{!nYctQxsj12(=2+FVO-eyBx%B1P8ZJUR-5>+_OX7H%d43pP)ZJFJj;T%{AH_(WIa-efd)PIp)3$Z z%oN`qRzAw*Jw_#z`C<8G5M;Jlt}#gJMv^%?uA?~xLD0nOmnb7TgXEOK(pg3@ZNyZg zyf@WR5N%#+@KPzuJ<*bS->of5I52CA5Dv{ii+OB{aOX*}tcU0t&xQnIIQ|k6<@gH; z@MK+wmVglR<`smfxjvC`PMbBL&>AM^QAn+bq&}j$YQ8lnYQ;T9jKjq}I-oOU@EJ4- z#yyRE)*APiPgJUMZXpL5F=|pgKs*8cx3~!GYT}9UCg;A|q5&nZ#9{Va(!{!H?IVQ3 znx`~)j2C_iFN`y_sON@1}T|)%SlMrc0-3XI7tS z^`+xsR^ON7VOHOV<6&0cJAu))exb_fP9A52*05xlYQL{bC9xiRUD!+pZvNox6j%&D z!Q8=F6tw9p&DW4uaS50Ol7 zLn3djPVBQ|x08c;TP0WeTeY062l7ghr)nC0ixC^GBeFqD5bFF42Df8a95};Iy_^0%aHfvTU=dF|-f(o#b*(6~(E60t%i~E0fMlA}0x8qnI#K|V%ijhC zTg_UsMM3BCr_N2~tR-4nW(+1iZ^Bi5Dxj*FspMPL)JwBw;#ovCN~@%0%RK+u@?zX( zigOyKX6~)fS_MmRn<111g$`BL06xvwencFdX2x~zUMa6#4|&hP)b5q?=RsSue`npB}zg;u~+y20fR#Vw8Wp4o3U)u-{Vxe7Ufb zOTLTmX4#SEsGINb-Ry0z^mbxfu9M%N@8dF+s+X;LUPCC~$Kw=_yGGFSeo2VK_VN4w z8GU@>f4$T`#=h5l;fw5J#Hb1Gs3zB(Xru=7CMK_Gl`ejtyJ4CIB9 zyp7%;QZG6-ncxokhm95aQGJdQ+NidRof*40?M-I}tLy*ksPKeW(}i;At0RW){vF*N zwpS!lH|^Ty{RMNqefGJLF|Cb;tN%{glJD;UzFdF5Pw~U`_gVjx{(kf4UTS|cP+s(y zcAbonHid3i-v;wqSdQr<&F=Kk0Y|j;x8sRycb-s@A7>Tp7aZMRr=5daC=!ubTxSkk ze}_tN5dG~73EPiOgwyPSH#dbB^!Meoz|||4xqN@?LQ&V>uT^y{7$Mgj=)_*Z9Dde6 zWez|6v;T_zM#4#t;8eD{y1hQK=+om}#4(Z1X!ySDZ*$JgnyZ|!kQt3pnhTl7$u{jA zHT{Co@aprg-R~Ib(N&~)48e+@&6qy<`6Y&WNwFItc|^*ygU>%+XA)WS+zrd9J11!;YNc2%DslAsglUdKh$T%|yLU4L*RuhG4?q!YS4 zF)u&0HiWF%`1Fh{v0IGTw!1q&g5?Nb311k7ZKnRli{37(S) z+ns&4(P6ApyiM-So3_lSad7D4tW)nv&eNey85qSg^qV=8NaYoYkXUn;H`EJ^{L{UH|I4FG64z-n{|KX8fE_a0{ zb~Kc?ipXp>C71xI*`o~-^iWruIIgYpky2o~gBX;JkI+c%rNSN;)${|x17s!DgDOEA zzODUxPU2gxcQm6$DP1DiLy0DI8SMCl1`DoUKO(U%v5tbKD#t>$J>+otSsavq!a}R$ z_#S5fURb@DV!p7a{CWnQ3fJeZ`zfK8#0i~ht0Ta|BmlbL{RFQjNJv3ZoCU>h8FMY< znE=smMrTGYf^+o68g`DhxC+B;+TwO8%x1oGy`I&Wna$H*N}e{CXL8u6yT5i*15HpD zhRF}Pi`nf?eR`4RE11x6ymcf<^^0C^=SHWgD_tRS%ci>aTnUYeVANBBf>y$cNC_(m z`)+q7=#DGMqrMF*Z9pxoZgzz0&|qQ9h>G-&@osH)3}E0a9)zEgd*DOx}^$LZ75dg7tLzVx|3<_* z>Pl_u-+vN`g*%B=Anj6FdAe5d1!}rj61wWk(^WA_zD_@mlF(I6fv#!^xvcjcB}r-J z_gML!u7X2XV+@B9$%GAbRY}m*O7iGB7)gwPOhaMvGQ|4HSz`F+7%|)(>@*pAUB*67 ze9I(N<=Q+4m-Z-8=JM4+3dzXsIBJ$Qw-O6eS3&veJXO>ev@hwXqAyPs#fU0~q0?GH z6}23y2r+W0WpIJ@w)`Gjp|0aIL7<0092yiQ44{X~fF4$cN72E=6WK|vLN)YMSMn2F zy>(>&10$(VIf+zGx=>#pS;eU1$MH)=n#!Qm0Fh(7FN=dwhMy)?J}FgxV%_LF$2<6| zJ>1PGv?tdw>KyA8R3YHme&GHX6gtMFh5ccD=R0?q(hTVjYq!ITChE&KQJ4y26#UC09XE zLS;lKA<{#M9WG6Wew>QSbEe?X!{F|XD2h@U5qcPkE*8|wsE@%pmDcViorv)RWJewM z*6IML5zu6UHY{zGVI%-{I2&WI{HBDMVez77}pQXDki@E35Cak4s-~AKUHYE$-u9`&jEf z2JGX?36|_Z`>3h0k3sv`;vhThWA9t@O<&=fp;aQ=bVcQxUPTs~Ud>Oo>FZpc4VEX` zbOFS0!!>;lg&aiF_wn+3uIY24O|ObJ{g=_E-#jkT^yW83nm#z*K3vnUc}u?O+g&rX zAY_}asC?74^w9KVr0JVoo?9(XwCMsIsOcRC*Yx)u7is#JqD_BAwCO*JHvKixrZ06L zuGi0TAFk=2e=|+*F}~M1SX&2I+KR;xX$L*{ywKm$*F3EKjtT1sJ~FZkKQnO`jBH@ZUyz*>|~X`u=DyUsP=ra!n83 zU>~mO*Eopl<+@1I2VFC?u4EZpQTe8~xTd#8nyz(*?$+v4IIRhApr+5Hkb`LYcPb+c ze!-`AlY8u?V6z#CfjsH(e#_by3r{6 zwTg{dX=|Eaxq{_dEzk+brJ;kwwhkz;Ylb=bH`%n-jN5tBn06M9WltU3zfUuI+ku*X z(`k$RjDEDn_98!{k5X$Fd4}(=vJcnvw>XGv`uksJ5ZCk{iyszMyI%i<`*2M^nx>;c zy&PouDF>fPoo)x5WS4d|(dyKx#Iw*&<0s+v%cI?H8Sg1&O$Ob|q@2}q>(*Hr!d#|# zzIZqm1gp=ZrT{zk+tgycXdfEb6;DeqYyOh(zWFOVFr#qz>bSc|| z-fsg9u3OOYMv!qzhv2%-OZ4TqqjPlyJc?7wMmQRZOf6lo0_`7ZSAeGYsI+sXBHV6^ zh^cxq?t5bxCJXumAdiwM_9w*BGuz2IVZlNN)U(=(=zO4*zEhzHF2dDyELFA(M7g>6 z4ifpa{kyffPQqw4$-|-I>ThTb3iEIRWBpBuWrGu zP-p*?OPVaL%htJWNG_ttI3yDh)|Pc;1$7IBF!>mN3oyyiaB^t{WJ;2IfFv9)cX&aW z#eAnb9Zr2sTyp|niul$*cVbY57h>p;$QM)GG!avT<45Eb$@p>fBFlj_v}Z14EoZf{k(z^H*`Kek@-6;(R4^+gra z+naDIr~qH8%$~nYcTK3JK_J2dwN@o8k~+bdW50i5h{~9G>zO&4!sbx3u>4Y|hf_lI zOA~Ykis2eu+sb)UK&gJBP(|~JdA3m#Z!3YR4LzpZz9@j|y4z_6lY_L~?`d#a{$T!p zYq(eLOE>RJYF9pj0YKWO)Oy!djS}s3D_8EB^X~gFBBeVuL1c%+f|dHvepxBW9oAd| zLuryho3M%>o%l*quj8+kC8z*f^{yqln3+)g+hIo?ja&By%i9<-o44*xYy`)}s%%+x2S4~c5TUH4OE;(sTr|b4BaWKO zDWKix>+^}YGd0s|0kgf|nWDGGd>`=Xq#H{%>oOhRb6#!47MSU} zoS9Djmg^Cj=`hdz9CH-OXM$G;rH7Tr5K=vft-kSLdA(H6njBFg^xr>HwzihAfs?N$I4?Si0td}kH0^Tz&{BG9CqeWHVP!V~LdQD0 zn#@f~j7A?(h-&{*PqkadZ}tfRs}O)(j!2v8E25UOJSwjq*U5~DOKk>skhqnwa_V> zxOI!v;}qixn}B~IIkejcYZW;`SDJJ=r5L48a9OlTB8%$rS+s>f2RBPUzk?q;Xc3Zm zBj37{oMo|{?!xHU`EV&UXi=pGRc%J-;94YDuj<+it3kudNfK7po`&*Nsd^qf8A~&Y zPJQ%NonjxR7U;e14fbKXq}~s>58Ea6KEw`~Jhn^fZ9?zGhwYMj?_oR4#||s)KS)M% z)NHUhoj*gcSzLt81yxLB9-E#IjI$4?q<9GC2V&Ut%yA!X&o;(=xINpY+OB$RdQNs9 zhE2~ZN&}m+17IWmiPENmWiyA(V(CKQB<1gUr~7c&-0rGz*nG}?IBb4}<}ZiMd)J#q6I;`hOm&_rR;sY$ibXhF&>;reN14{;z8{MyjpAzeHXq8EWknOoQ z)ke_jckOnxn(96rT92b0%%OGeMEh`P?R5n>v=;IKt!9Fj#?5e?y&3GHy?5pD5sYTP zErLpYnV6@Fq&0+KtS^-9F2gHckF08A~DVWcC4W(rj%;ipp zkZ=2X>}hCogM1lmA>EhsjF6cb;MQf!=dwTKJfo-^z(QEVVlpUGwI6#h?2lV z6Kri-^b@UfG)VY;oim~*+%X1Hu280&4RcUmZsz1Ekw&x@mq^HWvl1GMMyQZ^@8f3f zpFy~c^x+!QE?@L@IFUa9T4v~55arRuz3G?@SlbE_b-1Tyw6vP0(#FL7VjtjW_XJyhH{F! z*>j5cqL5QGbvsTGz4bMePn0XmC-;5d@HW;dOCPurODudDYwZDVd7V~&x~!LXm;_6foAPATbr zu*>Z!D0FJ(13O|;Nn005)t;F|DnG{*Hc>OrVdbaZ@4gT}eNibQ{DiO=&rG*72uOGU zCFTIMVY;2l5!;(zZIjjksO2VilDCumqPXM*Wb>AJr_fsHJgB^eaiEk%MDstYp0M%~ zNg~ zN|dj|tK)K&P@XcTJDmcsugOt#m6Vn_l_qN8HHz@<6Gg?nLHECpjiKu05$@_-S4A$v z(-HP5F2@DW?4%A zFXp!)bX#0VH+7`v-~Wh9esv_d>zERw+hgQYZ;S3;Lz`o0Lt`jIkIOT(QskITT%Tt) zQ|o}WI?zvj^rQ0T)!;-33z-FS!^c?+RIq1grO4GWP*6tJ9$tiBkXN-F6(m7KI3EQP|c3ATzQw+7L21j>=tS(Y|qBG0p zdo@S##Y%|A(PfTMoO(0oB3gxAw%0_ET_S$T3$j(@^ec-GO6I6=v1LB^n^L~L5S%%O zS7s?rTkH@Uo{9r0zh?Q2TBvGW87i(UU))%NcEU4T++>bx97gOCt~hN)LR4VF4uRTZ zr^0#raB9oPq^Cdjk&7hq1BO^33#MZ0vuz z;tp41$GYMUSI>@q@~}2`{S#K);cD#HTyaAiEADvlqoQ@Vo>g(4!^CW!jm2ySngaHU zc1{-s8!sj`6I7F=e4%!|jV(lW4XjlfQa46NXqA}OX=)homn$=hUS$>{*Bc6CR{g6~ z+>NBj4e!6IAx_5xr`puW9zdC^NOisb@X@G}R_V`;(TVUU!*S4|5q0@+9CT*n3tGL)*hH-QoHEojZ3TUC zD(N>IwaziYsjj#ORU9@F6_;N!jDH+<0-=qt&@uLJSEhw zH>9AHFj^&CZj9pcA>rawn>5XE@k2p~TyH3lS@o|{NjFAoKF&2{D4Az~#5htz0rkGe zUL^8lR-1;9`I*PS1xXMXC`Eeh(29GUoh`);?KKrA(s=BQK#tA1D zo>A1D2O8dwbGJ8qHH#o%WOpN zMq>|GaW{+aoVAY`#jx{|L=%-xyhV~gl|t)ojAHS_!`rAO!!>FKO%@`4nk1y4$W`Tn z;#~bJpwa((co-TTT5%5?-s0ZxwEiVvuF>o})|-B5-BR+zhK)QzUUy@wqA+i+SWCE+rIIDwXKB|h218C(JLb1FwEz=O}*f|P0i6iYg>-B zhP2H(DAI4ET-$tSiGQuLT)zo1_1oVr%(bn9DpI+A>rjIDe*5ykzr1a4721x9ew@X$ z?bzYkHfQ*@jl9p=CR!Huo9IrziEh5%RO8U$CUVF1Tdo_1^qXNG>9-Hhv9?(cx$)-v zTyuyJQ@_1Mi5yQB_S;U3=y|EHPdkIbnfxpjtLFBNXdY z`V%^(QD#n56EZ8Yk>!$0GmVOKfD$vG7r^OuCv-~H?^XPnvCPA{9I_gaLpWr%FyH5L zm}|K+3S>f=e4K{VJEZ#@lbk_R6f5i

~LqAsBRk&B4tV*Ii(JW4$o!T=*R&8aiL# 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�a^EN099eeecy+Qkc=nf)VdqBCf%Qwth5&1@e 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 IOYOOj z5g6wZh%c?Qr;iI`;T)419G$Utpa#6{%_p}%X4qxuQpv9>cE47!;1if!zn$tLOxn$7 zRr%YMq#&kU`498Bf#=!zSv&zB^!&1Dkoyy#(ytIRIGS+n?aWW3!2^Nv=@PZ7JO^Hl zZ!ieQ%gVldy31Y8unN5V-_TL|@?ZRMaT zHS&^sDfjk{j3&4Dsv5wn_x6%rKUNc@+qq$Q&ss{1><=m`^Tz?e*rJ;AKYqlq9~-(+ zaWH_K?Ei(hZ`Hrj5F?iGSQKq2hh{WiCPh0}Xid`pFMRi}*F=O|?tflyA46&CAJvl? zz*g;C{vM8lUAU+!x$03;@$EiR%_u*7{-Vm|C+myFV`YC%zse7DiU_}nN)?aO=;-Q8 zIJGoh0HK1W`*!c;vsYg;`V~Ij1D3`QY+1I!OVy0Fli;n^XWXAF{CGYc;?O|!KL%%4 zLF8um0x@UU`A?BFfBe9|f)0lUzJ5br zH%+N^M~1uS_l)O{fpaH|8Vu>TZB}RRv1LrJY$yO$xfd@xGpndYU{GJSK?ES#M#Rn?=MNJnd zoa6wZCM6Xyh+N4!q`e zPE&(Fy_hjr)CR!)!{HYtKWfP>N`9Q=U@7t5&jeS+{M=@sh>hy7db0hqvaNoZB<0Mi z$G$QInLP<_Q71?1<_;&4{W_kT8?~~3VH%%viIBSBs zV@6AW7w(p#+Etg3gZX^b|HJQ4qK4|rMn7N;|ANQd&Ps1lyT_5Zr&`($(xP1B7YRI3 zx8>?kt^<~~leFE7y5hKfdJU3vwpv&T8q$NmDp$UTE#E!lQ`f#H+*seeMXgj{Mf&Jw z%Ob<2!2A&7exS{EPSpuF*V$L;M5;h1X48Ou>9j9(;g=7&FV!k@xqX@EzO4ETHA2NR{2*EV)hhK1$bq4t3ICW*F1gTAt#@z1&=}dU7b6mS+wqf z1icu1QMQ0$)UNf4`_4!_4+u(n7 zv)ZDkf6r_FU?`941goZ#{5XFEKUY&ocs;JP17Vt@xt3EnaR}euwUo{8< )V&!|- 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 Hp`Cf#iOc1gHRp5M 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

q%CERmTgdVun<;+ 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

dd$~9WxV>yJe1E-#c?^)r*;1Kljeu*;AW2 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%0A)6G77((YEM?B>SJ8E%=QgH`)u_L+Fg6*+P=rp+5 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%0A?3Xd7vti7LZ*~K$Qeeg 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%0AgkY~& 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

%UP&hZ22b<9_%(79aQtDFj?b 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

~LqAsBRk&B4tV*Ii(JW4$o!T=*R&8aiL# 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�a^EN099eeecy+Qkc=nf)VdqBCf%Qwth5&1@e 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 IOYOOj z5g6wZh%c?Qr;iI`;T)419G$Utpa#6{%_p}%X4qxuQpv9>cE47!;1if!zn$tLOxn$7 zRr%YMq#&kU`498Bf#=!zSv&zB^!&1Dkoyy#(ytIRIGS+n?aWW3!2^Nv=@PZ7JO^Hl zZ!ieQ%gVldy31Y8unN5V-_TL|@?ZRMaT zHS&^sDfjk{j3&4Dsv5wn_x6%rKUNc@+qq$Q&ss{1><=m`^Tz?e*rJ;AKYqlq9~-(+ zaWH_K?Ei(hZ`Hrj5F?iGSQKq2hh{WiCPh0}Xid`pFMRi}*F=O|?tflyA46&CAJvl? zz*g;C{vM8lUAU+!x$03;@$EiR%_u*7{-Vm|C+myFV`YC%zse7DiU_}nN)?aO=;-Q8 zIJGoh0HK1W`*!c;vsYg;`V~Ij1D3`QY+1I!OVy0Fli;n^XWXAF{CGYc;?O|!KL%%4 zLF8um0x@UU`A?BFfBe9|f)0lUzJ5br zH%+N^M~1uS_l)O{fpaH|8Vu>TZB}RRv1LrJY$yO$xfd@xGpndYU{GJSK?ES#M#Rn?=MNJnd zoa6wZCM6Xyh+N4!q`e zPE&(Fy_hjr)CR!)!{HYtKWfP>N`9Q=U@7t5&jeS+{M=@sh>hy7db0hqvaNoZB<0Mi z$G$QInLP<_Q71?1<_;&4{W_kT8?~~3VH%%viIBSBs zV@6AW7w(p#+Etg3gZX^b|HJQ4qK4|rMn7N;|ANQd&Ps1lyT_5Zr&`($(xP1B7YRI3 zx8>?kt^<~~leFE7y5hKfdJU3vwpv&T8q$NmDp$UTE#E!lQ`f#H+*seeMXgj{Mf&Jw z%Ob<2!2A&7exS{EPSpuF*V$L;M5;h1X48Ou>9j9(;g=7&FV!k@xqX@EzO4ETHA2NR{2*EV)hhK1$bq4t3ICW*F1gTAt#@z1&=}dU7b6mS+wqf z1icu1QMQ0$)UNf4`_4!_4+u(n7 zv)ZDkf6r_FU?`941goZ#{5XFEKUY&ocs;JP17Vt@xt3EnaR}euwUo{8< )V&!|- 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 Hp`Cf#iOc1gHRp5M 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

q%CERmTgdVun<;+ zojmFvk3xn1@wnVQ37>l8a@FiP+Og2fz-!qVSxqC^S;uj5W)Dvb5f6^ViBLd9M>_&3t&=K9sr-EuMZOIS{miqo!Wt&XS zMYrvgmbH1c-R8^g`wHdQJO}Rz9L9L|qIkJonifS~G0;R2T~Z!>B@J-eXi3E~dr}nY zQ&O*$%{-lgmpb{7ttlCIKiO2{fZZTVmKAz=jnfv*nS=X--uM0mIxf?Bke$R+=Gns_ zwk`A8{viA3y#In|T|>H6?sQ&Yc5VV4NNr`WvK?H{kCxfp;19K3%rd5~?E+A%E@t+Y zliJ2xCvQ`DJW~xUdFi9n;f9pYqK;dZ`O0!HS1R}VhsvolH z*08V^D&fY7T54V;m}a(dXKt_E0S8Mr1)DXeXVfczBpUUTtm|pwp4I?ZQL8$Y0k2i5 zHw+dU<)bJo+?fY+HhuE(4&VmH7Udi`1WcOgB5OQ=y7OZIRRhZ2$x~*}VdPXBd*e-j zbvs`eUy~rKqHJxbSz`5(AV0H))IA1Z-<=r7ml%vM8Uf>C06sTk6c}p+f-%jtVF+&u zmTV?lA)JAd&0Vfd19eRv)Qg~r)`d_BpnmsE8Zh_2Y}GdEMScqI=I;Zzm)qriRL~~S zw^C`tQE3_YY5>uNX-~82ql3Fx7PvJydN%&9IQe*oTXHoR%v)%xL1hvQv;yY_aL_JD zkQl=^dnF$-PapPVsdD6O1tVW00gSYIjI>fheG0m+AVKabWE~A7ml{Sc9)Xcz;BE+( zbeut7hEu-AH-(<7_h6+pSaK=Z%pVD{EBPUlf2Vs?FrucA8x@?q9jfX9CmkLqKZJ4; zoTzL8P8x)hEvkfOgp&?%(wg8zoRP>EWpj-1COBz50!~^JoV03G2~Ij3qVLIVsn z!O5TVp$I3!UI#dN9|_>3!{ekQ!O7_)IGnT|9VZ%0Ud#-`3BYchMqh>ttYJ9m2$ozx zwxi&rp%^Fb4tS52PkodY;)#)+L@uvLSfw%8>}C|ilKQ6CE`i^z20T~9g1=KKNGL8& zcAR2aooI5*(o2r8UuZ$n3_LULo#iax(wL>4+!SUXXp3m&`MVAuLr2_?rR$ zARhsLvw@#t2(yl$YY$)L=hvF*XZ~oXzV;}xDd6t5dSixpi04jKlPf2+MPhFXzsUcV zV99qr#3-D0te(scaQ{wr5+?!LlBl?AD)G>eEVHTB(XD z4JX#~%6uBDT9reab!laEqy>jx&GYQY9j9#SBU@Z2;KwW%MV*DA7wNa5^fjx(bf95o z`gJo#D+wpMx{p?X9;AH_2pcR{OOE`WosN6Kh|U}1(+MQ39*&9A#<(78I^*10(nFq$ z8l=9FJsg8L7CjuHlf%l;2^&A)JuctL<(-D|oycq{ zJJup}2d1Il$IuLA;GbhFli33Nj#Na5A8j;ajp12zUKSs7?_jKAe8=cPV!~m@$!viYkF8XfalvS0^JeWi{Us^6KqNeW4BDcUcYDl}FwC7ze;bB@ zIq4sH$po2`KU*=6=f;@)9l3G-3m!N%J3o}}Xc~)AWlii$m96u=f_H@8 z4I1x|IKgu9zgq_d(x;n3#hH^)2tcdUizre>|Uo5$23Wjp`7WeYjiljvLEM&`K!9%yzv z&|Js^&BZ+6#-kjL31pqnY)LIJK*dQUG-u~u;;CRm}=1-ivC=4d9H>m)WR2 zt#q*Dd_v_$w!y^>ya$N@u&^(4klQoIV%g3dOta@_87%UozF+$VDnk)q!(pKRX-OzH z@N_q%0@<`gmuh-#jxI{i^_L4cB_x_Xo(;3E<33E`Rcq-MQ>X^OHo;hX>9iLMv)F<$ z;gQUD-38 z0}wZsecYK9v*+xeitP|f8Oz=Gx6m7h{mfwHREKMlusu|`B+Wb=bAEf-Dzi-5jwXbn zdQ&@Ce!KlUx1y%YF7o$kw|$3s&Y#9&jX6|xqZ>E7ko2dCBLb0ta(g9Jg@d~fvYyiU zdf9$tRI;9H+s$n@hg_e)nxL>2n61gxv0Et8(en;S#|8Z*T9N9d6xM>Fstr-bqL%7X zsf_t3II!6UbJSHf8T#c~<7nMSs(G6JP-dfOv^4m(&cNUuGoC%!?)P2-w4$}DSN5s+ z+Kvu3u|;>Hg{{ui(Mg_c&B@{KowcJ0bh@>w+u06Zf#3-&n8qXt+7Y#EX$cq@^k!a5 zRe$JzaboHvZSjVGfV#H#zcewmo!7R^bEVMjxR(SAs3V&`h;c@s;sfzqN`XncR{MU_ zIvN{YnT~D{NSdRKtI3ynxpJxwh93%+lwL_O%!~T8sk)QI+Sh_5FML(>1s+(#rFH?+ zb{TwISVbAmAHkw!Mr6?xabZv9kRc@_+tErrk^-{{RmAvkSXAr62gm+-8d|>5qIDZ9 zWV;qO+U~btu-ORWkiR&UrVXbpg_JO~AXDy$si@>`xunY90BP64Zj~Gn7+@1$%{76r zbLzutb6be!WXf|_zZX2=pP?PIgWH9<RAwIvyKYLk+SslA9%0G#y~@+FpK zJJoV5%OtftfqBX0#hE0YiL(_vgxj2q>*N^`qEE*=89^hP^wG9Zz5EEbnaFA(r^JaH zwuxLMN;^Gn_d-pAPC`wBu8lcBqKLq5)r$dvd&4{7L;@S-1>D+@w`C^aICl8Mf2D6e zyhXTm;1KNLyEkqx0BUg(PMyf6b!J9Sv>A)ya1bvIC%M(LvMD-kDmvtdf@KB9(cAE@ z5I;h0?Ajvz@`BE-?GR|~!IF1&N)^TTX=by2Bt>ZNL+wAR24@*U`$Rz zI{q|>?@0qZV@5`{LCm(BxFcJs;x3-K9})1A!|L<0W%a90t~ig!*si=nskhl&zRpeT z?p`G46@sIYif5inQBfyP1JCgwHgVDyk{I_WUo-$}(Nw<9ZID5KM1x2@iXd(GwG134 zE<^(#8sv1-wUEp%(oMK?;GoZg@GWy~`gSCQ_oT*cXXdsETIOp_&~Eya6n1(F^z4L) z&CpS0bQVO`XxpxhQAQ}xqznEXfgW-My28GTKs$LNiOrecIszp;kt17)c_vVAli{N( zOYLOJXJd)PMggA9^(skg_^E|>&7^S40^bvAc6ISdR(nm#9U;3nZswHS9ICoGnX)-Z zWYhI#BjZ>)`-xs&GH7vD%Y2v@U#F_INzsCNIu_8#AupU8^TJttO@e&NqV(F_lX8$r zWb+OeVAW)^=C{>OFnc9!FpIAYK(MIgG!jX+$AnTh1vc7e2B0K2%GSc?~W+jNwVMvySmS1L`~|Fll;lfGQilMkR!c2qwQkcc z`|15tF^02!*cdFi=kKW6Eil;ln(CJQB(aONMoA8zP;RkaL6xb;61w&CAXEnyW52AB z{g&lUTCf-zs`_R^e~@Ng+boj8o=vrjiMEY2R%Mccs*EXRsOqMqmI5kv+NSfq01r;# zT<#<$3}gj+l70I|FM(HShL8*1DAIQuT{r2w6>FuaDHg!m<=^C_@A@)7ZcKK@N22eTDBfBbEjAha_3`q`eQrJoxNWV5zs}9Bu?&`U z!MjjOu9virO8mA}x0>wjRFUoOOAA6%@5eh8Yz2>r5H<$iK5&>yYywzkQ#m4;nwq_^ zMI1NlHGH&KG=JeL+Q^IM@KL04w(8W7juZ-GH?PW*&rMzZhe~Y=Rx3*9#zp*6@3bX% ziyrl_%RqzIZGlW~LGZHCxAd!)E_#>J;AAxd`5XE!(Y(fC6Y6M2AWPBUi}(Qy+ITeu z`z0EW5NtziS?L~XtE6*{CY2iq$PW!BG)_P-Dltt%vROekXH~-)Q9IhEH}BsZW{5x7Y!oZG5?mef!{+_8v;A~g)?#w4})qt~g?9Z2|1iI|>&`zkJ6 zsK&O^A2Wm3O(vYPm!)cVwG~k7D$|o+eCyPzPNS*D3d9Kc+`Z&)Y0a(3{QAm~Y#T~o zWc2D+rk-Bgp;xFj-i2-$_W-ZB37eK6%4|c@J`htRFP-`8xLIO>Ax`eq! z3r<&PfG&}vKe~~DJ5;*w?R;lJ|1Evj(;AdJu-eE*C7A4_e6Z$GI^CL`aYnXkdg>2G zeQxb$AvRO@r0y5>Rg#r_9SqEgSLY4}^&!|5Eywl_hN>1N#6#|;>hU(SQMGxVQ7*w z^+J>fZh_Yup62CPViGFqDOiI!<#WpQWOjm2n&HTGeQS7+*7XZ;(4-d`fF#*@@#3t2S{iG&U405Qv^yecuH70ee)UImVYze0Uv10f zK3pFK;QJJ^v&(=yO*QI-rnIrVD{k&L|9qU{Uo10zKZFJEG#Fo99JYL>U!wth9tIT! z-D1LbihtK>;^2*IX%3mPLaoLNUrA3;s7XhWF3n!&mb9i`nH1ZRc|JvI>$o={4hd_@L`sP{+KW>%#A=J>z6Z=1gkKYfz7% zvHhZy`neP$RHMf`-DlunHa!TGBq^crX5iY#WB3U1iPktZ1!b)fqSr)I_5qv@!ZcuC4`nKPEcEZEsM~=N2M{i@%vw)G4EJuM!QaOyXh*UBsiai>^q7U zvQAX6mTgOTJei-I%`S1dr+I@UhUlRMS#PXFZwdE~Zn9%YbX4)d4JAcN)KJwg6aFro zrIK|p&M3ABmR{^;r*#Y_)a*pbqnPZLo5>E#o!RT|PV99u1vGnm-A}&&G-AFU&0g0o zxtz*Ye2hYkhF6H9Y20hY#yT;zjCI-hC+O&lpdAi4t6gID=z8NizHXD*ZV+gQ9UkF@ zF*RmuJ`nEBJY!mlG=v5d{W5p9DNdP8b~;}mV~lAd#Ns+v%aexa?~62&CfuRacCh4Z zr+l=+)Km7?_6JL*@xg3%>>Vph>OtDEIl$sPqmee4jie!^Sd-4ov2g<#BWKSQ&`3*2 zBNqQ1$m?S9@91b~c_weXlVs0!-6#W|Gu<7&$!3DxnkQw^br^Qb>;f}K-iTLFgPTMO z4SDTHmHsl~{p=)*$&*O?c@t~}rilS;W_Bp*Y*Xay*Fw!6fSb2U6e<<5CgDVnDPSl& z(S>ppYmcr?BccRe#?+`=NdTGzOaJp_w9pdkm*YJ3gpWDl)DdeNtpm@Gd(ip3nb%>1 zoSU;VVc8AxVT;k*^%1^g4v{pagaU#_+#Cfqr%=q&OJ9t?doKN&md(Wy*F zMqzUS3cq+o9))U#eI33S3eVu70EHjqHIG8INk0+?#S!>(>bpZzgGXTlC~PnkYP|V0 zp|F7%X${}FlyNAHsweR%Nbq=cEIJ{cjuI4}@UaAiki~HPwZPO)Tz9H=R?EYYr*$Qa zU|`)KWW~JW_^?MCF4@I7m6k}{gCk%Wr}Nh8gI~tSs9eD}=UM7`&``<3DO>f3p_0c! zR2u5tbe65!OKk>>2V-uuEgFo3aN}d18?^(|XxzB4c{nP+z!y7f@DU!|Sp!fObbW}| zkPs!0aMr*tl>k(H+Bj3EftA)_X_!#H@fn{+ zp-H|99w&g#BQqquBfS8X=ga_=4zZwF%v(;6j1S|yPI(G3AKTJ$13xiN{5qB&o8D0_ z5)O5|UDhXDvXE^9)XEdH=rle@oi+L!v#61S!)qc~8wv!gU!sp=0NTP5H)cCtmVu=; z9B>ZZJ?gvH`&zQI#vPC7H8eVoG&J`9%V*Gt{B)W9M_w||%X_$!vSQ2LSJ}zK>eLWq zU*akA{2M^MA!bYm6wEfxZ8+%qCdC{om+&O1m}k3|DPlXZF0^VwD z_i3U^z8oy$1d-VnCY#Nwst5mT8d#8DM$HdnR!TNk%6&E!NDPTXm-?LzJ5@Q!DfIR{;YckP zREXA}d;b`%ZF}9)!U^?GfB?oPXh!3ARB6B%b&OB8&0>kbfEEnaXdH=DV4Mqb9~{7! z12JPl*h!o%Y6poUsl@Miep~q+2`jbZ$1^1d5T}2oBg20 zu%Pq?*O(-o?}FM@dumtP3&-B>xkqgGFYZ4|yGMj6m?uq#g6A`~0`C0vhmrwu5-j)B z-42$ck4a~g$5YRU@c@wqtN#eF9K1@+L`IBW`2&u*$L_JQI6abu1;IUc60Sh!yq@BL z({b5f>BF;cgaf(9d0MFRA`SlJN^<_FtMgtm*@>gxr92Ay@u`+!%vt+1Ys+=G0IbzsdP>?sq&!=3Z!9nYi4 z+|GAoPgcS+Z}6c5I5p=gdGCv-Wybvx;7&nKvGsnOM_Nu!uVtqzZI4EvUNVBF+=uyu zJ;QlEW%eNbIwcRuV%BkUhaaUYZX=V3hS3CC+hDqN)tx*hdpafyoaH>;!f}@JVhcI2D>k6(+_4Pk?Lem8HZo`9j>Jah zw>ngNY*0VDm2M2%_8D$YciZr8dUQKK>MUk;n!t4W3O^X#u=C4a@4;6#O|v5hp1m?; z?s75;j^ZoV;Y{lrXVWofvy(N|VV5LaOIDC%dzQCJ++B$RR8n2I-*4vRr*lma^7*(+$)>a)$uUlQZRQcBdDMqy@!nA0 zL$25D{Q1MccPfZ2`-w-vXueJ&741wMJH}nBg!StD$lMz=?K<_= zH+ODz<=#n*tA%}c*z=&p7e$|Ki7t|7LNl=yyv6uR%st7Td;vW>8clrh zT4hhy9%Y-+vsf|Sjqe!uQcT9qE6UMtOR~wsXj}ZwPjmQyZA6MrTg+ViYaH}27vG+t z8ws8M%MDa76&EY+uF-7zx+#tw9~lSRWz}yHY34LQ8Hz=)7>b*LrkL9d#YUavj!6?! z6PxdpZ!EM4i#VIF)>Wheg){Rz=g!6VYArZ?cc=%*63(1PZ)-aPYl|)m2hP{L$X@mMme<3nrFHZtu#paVe{p zQ%(_<+G%p6@?+LWQW9^Ha8~tThDNgISMs^}O)F*v9*?2WP~|w%Dwd&F%%fESma6wr zxzuGncey7`?w^8|nx9x0sdZ|;m>)BGc>zUBL zxL#u0dq2fnpYC}Zu|4W)IA9yxZMaX9SiJ}5Y_@nq?0OO+v2?uXY_YMyOCq$WxNWfhZ;qRwL7Pe}BL5Q+^=&XE*vV7<)3!6qQE<{;JJ{lO@@8m(E zyn!|ypkEM&C;LC!z6*DjZ6Qb*!O|SavK24WwS0gw8dtYqk$O54Q(}gdfkIbVfHDg+ z=B#$nMhA96Q8}>hN`ZOrNR?VuIy?n^6bIQ3Tv_Q5FK(M&kFvwezjv+$EIe$07)uCQ;OdQ9_ehj5X@0 zjxr)8p3p-qJep#?AGsT`@nxMYB6DB34PG#D*$#{wxd4Nj8r4~I1IZi0SK4x`)Ap#C zXDxI>_;SYW3ub3&FRtWxZ4siM=zNo#i2C0s#ZSa-g_&G*TZ&AJsh!a!>C78!0e+uJ zj%mq)T%cihQjv@{TppswpzEb3pm#~R?OlAHyv~ZUHR$@BW=E4@x*2YODNkZt%vg4* zH)j7cFVQN^t8~Jq(HA9$bk4VBiu-LNb`ewUAFfeOBXH6(mQ8NOtz>J)_}%;si7Oov zm_#G0ipL26OL}RiUPsaPAZ6!w9IKRr-+dSAq#0V117 zZc=vSsj=A|vEVdW@~I_SX-@kmGHowircyjKOWy6NSlP zX4gfA8MC2*8RhVp(PPl{rN7H#rjNV{W+GmSG1D*{Gb^Ye!AvJF4&*waA&~309n4_x z{)ejzFw^d`sXF0+oVGJz$kBeCkfYiPkfXl7HRSy1w4)-&Ngc5XhpqDXv2DNtWV93Z zl`V)u{Iq7jW7~kR6+!%>mQ&JEr*@RI8&QUqU_CZwiUX`=>2%5Q?hOo;x%E@5jxeET zYhILCVVoV}ra|G%9an*+{_{c*=afz%Y&6`}vP~Ov)ikmvxSPt0kLA)&a817rAEWOg z&scZRc7i@B9KwrNvOH>%H)#u8swKrVSaQ}k5^TDBuAmY<>ZZ7?XS)7><1&wGk6g9& zR*p~3_)PURc1`qczjjFs@zqhn>xfM)s_ zEqSO5vc_RC)Y~K5_%lNqGrMhSQZR9St*Ahv_ph z9~vdb4tkw}jXRkm>y|gSXvrx%p&dvA7-nmcIC2p%L)ls$L8Z&qdr+I1h1zQE+(z=x9P)ablFxxmO>x2F@r@($mT4ntXV9`Dy|&+YM^ zxWLO7X9A5O-#YGoTC+8kTj{$qCT#%IjyY-qZ!28Wk-Jkpfz1)AdIbJ0nIT*xzu8(+ zaxrI3t|K{dk(~Gs>ZYCa;{@YYtWCO#TDNq@E|QvE?~C@E)Y-S6BiIA>^wO9U4ZF$%m# ziCXqQ#8KwL6RXa3BlU>Z{^e?HKC~;%B(G45$D9+1Sf=n~iI!w!^k?jTsq)xhi&V#ru@i+BR$o9}7;S$s%JPnWE=W$l%AOUk4%ew7ovqpseYQM0Pp1MJG6&=U z+u=iMfA}m$5U+&VyeIRf>P`wKhn1{5+R(>&LW~~MOY^vwV?QWo6?ML|?JmHsv{&44 zahz?TP)o?Qb%4E4x8RzZ*GS2&b&@cIQ zM#E{u@Z1V@)eBoJ%-+#ihua@kijn08NQIc?oh0meyIB{5>q?LwNts=;YWKH1@qp?kNFKMqNxCAFU>--=vQW@7CVo( zf;4?;W?w<9XU8d9NN%O$?QBeTl(e0~Xw{q4{o*g0A*F!)Y*7!^W#HE)WM~FRlc3%J z8CwJ(lp`E$g0@7&^iQ^3S)Md7qn*4%uBg`=6x@j>H(AN}DymZ{4c}3m?hI|nY}a+n z4G4tK|NjUG=qAE2jN@;;o)F-191xOR6XmaL6D(5$yLB+Z0LRKl# z3TQ=s9d3z~H&#p39s{8$;JOG!np=U1ve0vT6hhHjPlO`p43%1!5K68Q0zj^#8L;%$ z)w8L;1S(7_nQe85kk}zNuddj#87b}0#rL|Coz6Vy6vGZtM;X#db7!`~>4rGs_Yaji ztwMWdy1c5L23q*aBQaeq#Cp|ZbP?z8wd$c4g)ZQw6aBW7Z**H$_T220+F7OHAsn7S z(7-`z4`j7V3$j&*kYY9=$1YOoK0w<>&)Ct?9*(-{ z=&fuf^|!_HLWK}PCUV@&XWQ7?VzX~f1eR4g@kdUPkQ5lF%1Gv2{mz);BnPKLpL}f% z7SBVI@hS9W5|1j&qqcuqjaG|xWlknlWM&&cjy}oktl06Q0kAHBb}k=$=6KZ9jm5h_ z>GR1it4W(xj>s1L&3IG1B}DV&l%2qa@9hNaC|Ud3#3|UkiNzUJhiu+_Sq<}?A;vdJ z|7Y58Mm6m@wuHEQjZqsSPPM5<7%`n)LB}{`adKIq8$HQ(2C$Kg4pxcbA_kV7s9=$- z9GM-3nfwBp>Xk>pM+=lX;v{+8tt3u99crLs+L0QO*-g>~7Bn)-e^|;(!guDC>s_eV z*%4E;Un7gdndiz(hqrZ^o0_u~|3P<3#tpz7Y}J?{m#raAlaaGMJlub{l!t`r9yO+m z50gs1B@4?&$7PP=vNKMm7ze6!Om4g1nX+A@!vlxWt2-$v?&G-qLAG;`r-|?Yp1hv> zSRp4&J$fnoAC^q?E%$65`IUP`Q4>gzlg_FQ4;`jKRD$hQvpAo#o z@Vw_YB7EjicuymZrv%S?pA+vT9>U_iPBPI=b8aJ2H;+eVKIebv{00)v6W6trLzuS> z|s>W;?X!59gk&?9isIB^&SyYv*L}spXXlqjn>)P0Ko(*qqSJp-NrI6 zB_9x{60vs6)=XyhwMYQF-*9)1usy^zGbO($V_Z`PWFldu;%xvmmp-puIvmsnzi}UX^cW2 zGkZ^}-5V^v?kWvIgqOYI<=VloT}-2L=~NaTomrUvGX|pw%`uW-`ZaY%E;2==zGzHB z>RGgvX)2|NwvJ(I$clt;^ z)RR^viiXH-*QuNwNkz^h+NpnHJUC!z+5F?<9**Mee59_4yxL5i)QPP|146!ogEy9e zerKGdPs6%tU2LI?Ed^baj;1MC<4oc*xX$H%@ZAD?mShBT*;snNuDa7+Y`>f-jjhW* zKFEj2O^fD6w3<(`TU;wy^vF67?%<1ToxzIF$YRc*;ns+zyD>dw_SfthK{8?i2JMz;{)diWUh)L0zpL*^JPF1q>E z1K$~AB!Wp|)8cHB@V^*th*5<_Q9e4=0_zNLsTrsvG(*fvzS636nbBNv%2g;1C+Czl z8DXrqq6bZTM+|cR6VhfGdtqbLJCno#Xb!yrnI+jjm89e{Cl9gdMd4xee!NWGNi0L;7cYiRXS&l7QN1z;0G7gdT^5AUd@}TXmDyvk$sK&R z+Hi+by%EEmOHJumltg=SF4ZL?M|~UaT(dgG?5Uh2#Ro@xoXBy&vNf8_-;R-X86RNq zk7KL?;a&?8r;0i2%#%t2K{^k;f^?BxO7>f|rjG&}O?L8AY(`-**$n+u75QkWG_`3a z5eYDi75o_a2<=6hIP_ptgxs(RKQ^eC8;`f<-CjgU`85!v=k6#=ta(U8Z_UfcoEfoX zb{jtG4i&iL7$f{O&R@rVv-v{e?A^T=r}*3+{&=5A+{C+Y)3+bmx9Ae?AjA^0le;!? zN9^avvm0W5lBNP0lB1~9FR3acCR@^NZDH&cPq>3shhOoo(oSQ~Rz2iy3P2lK3q(iC zbuS`lVmyE~Vjt~fgL4Yi6qM)!(wrK?ifVdLKlo2?&@k`pNxYSo5{=r%HIAMM_4@Vh zr(QWz_0pGTx#}+uAGAiDM1cP4bN^s|r?IExAb`YE@@c`-*#qgF^OSUI?0Cuxfg|DR zOpTg&TA;WDqFevOz=nBA&N){rfc7J5&WqHBo7Juw1{2AcPmjAwNTJXXdRt4U;7 zW-HbL!`eN_i&5fL@vUAH+=DNv#u0&h1VCXPsSudV1rz7L8?*BgGRV&Sfv+=+YMxDr?^bk6hrqBh|mA)yvR^9@P zFqu!&Sjt4GOFws9N$%n`$UX8mP`~a7H3oAxhvvSpQEBsw&f5tD=unL)Pg*sa@;R&8 zIi$A&-G`~ZtTcB8?r-eDIa_pZb*CDQ=VwW&Btno)?0$Y0`pxC1EjhM7`aW7?ypPra z9W+9i+TgV?ZGIjmENnavmrMl-NpJ`@DT*BWX@gm$?7URj}6E7warMWrP+!|`SPC9yKfYadsHFUGG zqS7uVg$5=DDv&s6rr=*HOEk54G8HueQ<>lUv(|o|^PHJ81NP^BU#}mp7jvHd{Mmoj zUVHuDYYSy!fvugIRUR)rHuz}WV^Jco#gVh3U_n4+8X*`)(Yds&e#w*O;*;j=et5f1 zLwrxBr+&6e{dZFwx*4WS4m9sVF)@w29ljWilI8A9&3UrpV2r%3ZFIm^Mu@{Z!sJAW z&M@{n_^CQRP1Azo^MWXF=ajvPthlt;F*4&O`#BPeiuTd=#;*vXwX8;}l5G-cv*iVDdqhR1c!$pFDu zv0FhC*8~~Gf8`Ga4x9r1gqH;oa}vnLj)~SEi1$LIm{y`uMV!De^?+;(N!n7Ovr-+E z25WCAQ3C=J#MXd>X$Jb#O_f9Glej#f;IvfH@Ac9H5}&>!8Kj8sOLLi#Eb`LCnGdl_ zJhSC0h*f})W>+ZsLwsh5ZGLeoy-BdmcQE0euIx(^P2IHKVV+W%FI<5P;W$Ay4iPzB z#SMKy^lBeHD5ot(r{eym##3n{k(*ja%vE|*gY~TwxOMhBC zEd{GZ_Tbfg8niu=aG~eoGp=U_wm~5TBCy!dHxI*i+g>U3YDu(Anx<~&eY07IC>s)_ zJbI6g!T44sSP>Ab*%7Nm!8D;PMk~=H%a6wy7`_D+6(Kd(g8~Juq}T`{@iCtT&|4e_f+#* zOz(^w^jVP7{ju0@6wiD;A>X3wh8CyPqdqDbIMC|Crxb@{nBb4wmD?S;n|zOzTnC-X z9Ztof6$)j}J_mQa1F`zCQvniPNqG?4NKX+6nSvGobCqy`jFLjI!rOJ! zg4{rm#_8H|?W8Lvjly3t@-2F$9)U>*$l6xJ>(n6LVmK!yGqGdCpk+5<8cR(YsjO}K zK4lqeS0#LAb5SB{jq3XkDhPvDph`-_QdrVyHTiSpI&IEAp<`)PwWCY#oz+}Ax-hrw zND$F-6*RGv35zU;ccJ!$)ZLYPP9hjHVaF#JPxVN)=THrUpcR7IB#=p7W!~giAgC!Y z#MPEcBEgTIOI}MG&&edFXeZ4;PPK)gCC_ZENF@$gcno0cg#=d&z&`)d4xJh?|H4Yz z7qSrC%}lnLJ-RZW`GX$u=1@s4A-9aFmFx3gpXa$d|V+Nk@MD2Z<`*0%}8 z3L#2nOrg!|d1#vmG@!V=lh%)AtB>updBQ%u`5+yq|@2}|s{L2_$1 zO4pUs87|;%=eV0h!+htBVVI~{q3I}DMKo6;XtpUMQ4-(v>NI8wr%Ew%C3jMosTUH= z)XXx$dWCz8xtlBegxoW%v`DaklwyU7Gf@SlIOzb+EIRyXt4#xsd2qYv)Ke1lgLJnG zn2C`JFC3@jB521&pwU&5rfzEx)F204?26_uH*8peV#X9Nz0(dPs`SSRE@?H(3E(73 zbQKh!Qqf=7YtiP)y+r6LVXiE(7?T_)5~cE>FeybM6MYh7ieBJ$!x&F&$rO2@E%`D$ zP!O8kO1&$0p))SyhM#_mal>b4@+iTn=C{T;C0klY zn$QW86Lf+GCAegj`z)7GIm0n0Wn~zoo@Um76HKyd0KsgnIFFS49#+5e$WR#0CeOzW z3|a}8F`E>`gnsk&$m8K$jIWg7V1&wmCaJwzKs^D&=t5G0dQ^a6Mc%TX$wUPbQ$#S}{yZ2j%kX6ye?ejuwF z0n2KrtzWr?hTEp&*a=s$6WjD_9>R)ir6Jb-c~1YzSo;Aky_8*A1R`#%#4cSl^)vl8 zB$j3l!?EoAYagUZmhNbFekbAw*9M4PoeM_(4|?5mbH7vzv@D%+PV_wvDU0pXV6^M=E)Xx|?eqVT&17*zRaoRRGBI3*4Q$D;Aw^$dwtEx>W$ z(`t_E(d_$i{R#OR#kenHndS!#WZ+1zy9wW}s}0RjJx16Veyb5yf!`%XaW(}%q4L4N zk10$1BLHFUz_)+TfXezv&=4;N&&q@jCXNw#WCY7m1{l~DT}@y(NlhLAhJj(p4RgRI z(lEUBeydwB)QtIBjehhM*^!`;lK^a?`uzM!h@cNJxcrQ2=;Z)c(I5X?@8oS)1&;og zypkoR{5NddQ9OZS;6gY-$G<4IN%L<~P zDR-}EmJ{IU#rM08h;85O@(Km<6SkroQ6HDbbm^peqf1lxfh??~KJXx>OJcdlAoR7c zP=~Ln5$Mv=`vBk&x-@yth%_mM3a(|A#fBnTf_KuxYN#w2F=wEj)(Y<)&FyG%i*Wn- zx*fOfVj#kuTN!>UlRqbV(Kls-j`N*$11<8^{|LwK2l*53Z^`t&hmBX!EYC+3=>NKx z8=QZ{4;@)u3g>2nvyW^zoZX&2g!)fZ=Y~MpPK6)Y*Bevjg93ATNAFMWHIR(z=#85> zC~&73zz4i;X8_HJ2a5rcL483qI2dQ*ZO-&&Rs-EC{_u`)n>A|Ny&hjFybc0@yRTXS z>K`y_zu?HIv1KO zx|TOuLkLj|FSL68tY$8CDuta{6(=kr-;1AJ!NV?vIPz_a`9tTv+5Dk1r_&8HXDWK= z11HhZAxX8$_z|#YxjU*omAuFja-@v3$u3IshvH*u!zhBt4hXkv?Ap6UMHKI#NMa)w z`Rq)fPWe8`UF5{b{h@wN(86gJ4_;D0B#W3O|2T9=E&2#$7g%Elq5yl$D2~BMn70)xVyz=byi|*w7i$h z3&z82O-a}DLpj`2lo*Um0JWnze8C25W5^ENGEQn#x3IA2Od;h(b)}S{*7zKVqPFx& z=xWhTtJ7OTGMi-ADc{NI;QQBPW|5ZX>AczslaEJ;H+qvCF;s)xA-p%$yJX*53l<(%JVYV!Q1a!xN>JG+g9l%iwZrNnX zb052Qi(46hDt7W{{I^AWW8bXdqSH}GV<4g-Av?*tsWsVT+``sH%MEY#W9?h?u>E-J z;yk?B8Yi$+EbF|mdr?P#c-Y9+HyW8d0v)=zx9llyrpe^pY-}vq$!NYZ&*|3XPFDF5 zjpQSbW!4}`864a+sECo(VHO{SM0Noa!uMp`^#qyo(ek;F~zVgmFV6Mi%M(2C%7Y#7KwD+CfB&SS>#9;8ZGNr1S)z;SnQ`5(0w#U3@K( zHQQoY^CL*K%VYgx;Kd%F#ShrKidm)CCTrU27Xj6XjY5}fV=8KIY3*a6;cjSiS zgq74^s2ewu4q_BLQ4*}p5%y9f3rGHK83p*XY2bhFGRDv;U3erl$Gt-0l0gU^tr;d( zL_HVu;dgrdQjWAKQ2Pypp3%}jIDK_H#RQ~tl$lgHK1FCZKQra_e6r6OYivpZ^nG{L6#3j@^*~ zbS5x72}~n=vrOO2C!qpsKk47G>fcS|(k#>-rem~l6OIQ+C28Y8M=?t{uogvh!xawW z#PRpsOL(|jj=$YOZ65cijcy;GXnFv3XLMH&@Q?Y8(9iAsZl3k1#K&6!wsbtBNl>cOyPv(Ax2!`7`}s@=gfD1r4lzQ&r1r-wz_g`IW+ zW@J^#UM)>k*8M7(aiA2`PLkLPFqRoH3rcO7hk0 zTUbhi-z_>ej7M}+foz7ZD0;lK@j8coXLRA04F9#A@Rw|6u&hhbFStt6_aCI|_A}wf zGwXqfL8VxLUCjSVT8qZq$^7G|@jPohRL-s_^HXofiA1KbX@we#k9di$r5K-Eu&hni zvVfgFchQmbNPYYy(V*VPvn?((`R0d56~AF@(Q9~&KB{lN14s04zGb|TZ@TGdX4%K| zjeA~2>Z7?l);G|aOkvyC^p%b+=!|aQdj4{p{i6Mu!dL8(`mS=coFasjZ*Kgme?uYa z=Q{OGpFK*x`7%ZS<~Ej#A7|4UZRZ-eyZ>~8aRI`=qc^%d0?RTv!Ml&tU}D4*1$~2z zBE~HWH3H+lYZ8q6!^^ccW4o6qsoTBGx)qYk2TNCocoec&Fs;^hZ2syR_Y^#_n>!)v zhf+kXbIzz^SL4IiJD|`cGKyp?+bB6~mmuEwQ8_r*Ny*B9capd4xl% z{u&{c>rigskgdwxz}aZyTaYKc&K6`nORy-=o+yFVc+2E5CebFce!Lsewm;CC2%_6pQgO-Ei-VvGSZxoa ztkK|x~LpT)C zdM_Dr#;WQjv_Q3{LJPVnvN{~05*rM(RdJ%Gb(D`2WdpisSZOFrvQ$chR~M&q$igna zwvqn1eBdZresQ_g&;fN;B1Bjlp$?^w{?zTp3!Vu3lkIfkF+28+y8#bm=r*}=m<+=& z*;-9)gcd|s{M>jSd-9=q_m5#azHc`jr!X-gPN(TXHWw^6t3@5*Nk?=TE>Q41(dE`+ z>KPKmiR~}Zd2Ag7g)^vwpWZ3G&itQ5s{U^D?=_U%ozae8^G%R5e}Z!xK606S+{65t zZP+N7JV|C^kVY0uNbv|R%?;O&AZp4v(oH9bdK}5YX_VMCpW$SFE|>}}4+K+}WaDWp;XG-u3Q>7!7+C+X<@tftO+!HV zAR)U*^%o%<*2|peqTRN>iZ+w>W9Z;8d3`nAmb~uHS~n30D$Gt2E^r7cYiwR{ifc4k znfuxO!zL(8zN0Wuot-0!tQwuxd(?n>Rbq5lsU}#-x$V&@pR=`GV%Ker?Yg~L;fL(_ zk~gu3&`53c%%6O0tIcx~+TBi-AakOxG&+rtk1dcLxH*Js9q&c?PSu;N|39;glNbtY zGsO0e$NX*tMD(aL_e8YyGV7-bPWQoOnbNwcFQ98QezU#f@@_}slaf8pBSKUAEjp+u zKBRJ-L{=k>mLV+obX&=p#L*f!YE6>mSJy$nwPpdDzoCPbbO+CFtGvR-T3>g9t*336 zjEdVdexQwpLW2Xyy4ncZ>4GjUkV5S~?U++`vUXe~Eev?EntMxboA0X-P}Bh)Xd)~v zSu+K@7pElyTKXz|IE{7%wS4|4(9IlNFwG$LA{NAA?|;40#NJQvqxa}oJu6MQk=#Hc z*=h7(EN%2N8j!=PE`j&G*Rg8KB_tc!MiSFKH`?0j9Kmi;D(VhAcr9(w$E@Wb`+J;F z<32D>X=`P&*F?*W2eE`Y5koVRHvw$wWKGvbhY)xtKdvvPV3%%* zZPvZ#X`QlgV_md^HMh%f09A4K!>??lL%g|3x|B>q8#DsuMBj~b+ z>D?dxP<>fzGQ*xs&v|Kj>NJB&+S#6m@Eb%AW`d>L7QMa8=t5$@{&D)-#J2hK1i=3#g! zBXwB6U*2GAs?FEb$Vn37MLUwPQZ#A0Om6K6-D(>KUgvFyvaO^Gz^V-_RBxE)rs$=A zj!&fAlIi)DXe_Me_WJ=$YjhvhqignIhMG2z>6x!*^!@f-oDUhj0lSnPV5T!2yZuqC zJ)-S-(Vi=@&O9`RFuq-55TnIIxNXv}mM=1Ko5dG2M}_NzQ`!5*fC|XZJ0P~|CR?Rk zb8Xx4wD6-SMN^0#{7>+rMCR_+H{x;9cKL=Os-fKDd=86>9>jv9H5CMex?l2;JZYK5 zZ$OxT`=A8$?#V2Ev7YT8gYm`c@}DVt7)o=r{wiAwE*|*i)Hc;uQ#Tl&B#37}nO-NmLGx0-4$4S3ZzpR+ebQtxRh@i3>)Q0^_e&Ir z#Ux*vj9s7DehsbcFwjEvZaQj}31e=FeundndX)fDO1VAprlT`3zrjoga9GvkwlSS$ zgeTh$>GBhYAH`d;-MgWgj3%~P{bG6(XhU9s+UPuFq0|yZDF zd873r!|HVi=W)56#$P(BTy{ps#hX0K zU3ASCc;tRQbzQEN5lHQKUIeKWQ5%t?qLPTV1yH^LXC`l&0=ae%~aUytjD!1OgznDO;`j9w(-e>)YfwPW9=YJ}* zw1y40RMMV%3fyd_iHiJZ?Z}lSFFTw!c4wBpgx}om1amzpXskfYQ|`RI2ye09w`z)I z&ztX}5~FD$k$ZH+$+IylF1$v8>9(h&aK>ZPwtZ#>&+CD13%|#*lI`#uTAGk{7r|^x zQ$!BD`=`)Q4@jra<5^S6mv=}5m2=H3d%nEpBwyZTmM;%=`Kzx?<;#ofP0SW?zP!Hc z)lbWn7w5^lOTZLl3sY~%J$5^YYYBL#_m|C+_k$MzI`ZUwpI^(9=YX|5c{(9{VlB@( zA^g?+=K81HC`!rJUi`U8F6bX7h@NUnf#=KHDh_B{(n&c#$MWS}q@B_ROC?&!J~D3F zW0?!S#e2T3ftrp5a^>^o(Hzf}<5){_h=lprI-m>t;kA8dVftH`?G}X;AfPrECX=$+oCJfJp7!HXrx%!Rq+<*uz(|YR@dvQ4Q%Pu*y}py= zvS3A_b~`^EmLr;M2^TGhS0ucGsOOj-+q-CzcJbX~^-GyEd{! zE_$io@7DcYR4ma;K(>N{JxPzCo$oC`y_2LWP-XHZRBltxELB2~uUbe5O6vI+mKZEc zx3WtDQh=arfvY{ZobY(r6B9m&a&dm5Tm=7mSu3TOgD;-pi4w3)mOJ&}b_qYV3`4eM zEjtmslvR=)cSRf;Ej_}?M+$8umV!3MrsE(&qDTV*3C_8IK&^&AZD|BjaGs}g0dp+K z+VdPc?x2?!raw`1F#UUdMa8v#^2L5lQEuDU_wLVaHuu(!hcrjRoEvljWvUyHh`@?z zE>tfD(1tT?5(bkIMGR@i!SC$0n?QUEaW`FdQ*}0)FbP(HV-dtzAOvx71W_@n;YsVX zTQiG3qWcKO7QfQW8ya$9@;E8^N(J3gsLhbiK<)XQ$kF}BX1y9oeX>#VSJ2`!cVY`1HNU3pSISDt+@rwFTMIZ#MBn6-E) zW`#TnmOmr6#ZSZ#Zm@`xa1G3iTFW|2({!oL_vuuOd6l<@AVi*%yTj!a=z?jmNLyT5 zwgg|YJa-NDs%Sp)l}i{BAUmSV@y04@U+glNzE?6-tuqtbZ7mkX_U~~dqCR)Tiv^M^ zkPi{J6|&!{FKJJ+fuyOrqK}=;D_s><2gIi&>u0P5a&ZHVkglzkqxcd-c##re=12E(3SefZ}ctc z4AmHoku?vdQXA1bB<6eCb6FBaLu#YLv62eaSxzRhY6^mR;jmBJBT+nAE0is&HoD?5 z;1|SOmLr$u6aU?(c-I363R4peX+CVsgylo%yO9~uh1#d+jp;V0==op9RPF%zTXoYE zt`1C|MXi4Vpi8v=WUf`2)ohAe?vK&NpRskNo4dvAye!K)##x&7w#l>}1z7ur`E@Q~ zOf@$^kT4(*jJKsK!`#k^)*w({1C(T5YS%BPXtig0Zijf>t}QC_qPs2`9OTGC>3zRE zmVWIYBU0!Zg%rEXb+ec%FQ|dHTy7vUA{?}8bPG^pqX6L;65Xgd3o6m%tvsm6ZDV`N z;ssu1VfI)9v?Pz6~unim&$}?%Iv$$whax*$r+cN`#PEHW?3BoA#F?qrH zTEs#s_Z_-hObF)lh5Kt@Ep_0XvpU>C)TWJBSykd5U!|Kv=f7Q_ zh&)9t9~&HubEfv(3$EP$U@nSoc@h{u!Aj8H6s5Zm!Hw=EBBm%r6a`U<0#(d~UWyN+ zYv;5sH~0Br2dst;^yR;d!6xt0KpWx&3x)A?5w7}|F=o&&u8u^G?N(P~ry$vRZ4I2+ zwC9G(OwUH4C8F!0@(NT<{c8QhM?aBcN6VoS5~`}b`~*Rk4^@u4E2radBjuA8%`rM)A0wL=%G5WO!7t5n_~lia@5va$N?Bq zG{t!oAvIlTqkiy_FG1x68@j2-H?IhI1T|Shi$0~N9v&CBM%OIp5%oCC=9Awz2e}R)xg+u*ZCLK3aAj z=$060=c8pLrjLZ|s{e+31B|$n-jW6@`nT?sL2ogbXg0v+sOj+{p};n=dp@pJJvu*uN@~@NDwCJX z#K@HQ3AM{T$1qw0g+w0f z)&Q|~Mqj)UUVUFx?_g%}+mS3dH$~@WZ8VB4UfrOZ#;f(U-n_7BSE& zjy?fGh5F7&*C$+5eXlF2Z>86_9_zT|eFMAnNiFxZ`KS@n5H0z3EIz(oD!&6_ynI{2 zGU&BH5hTYQ`=XbV%2iat6cFV7sPWubPCNocE5Z7(RsfN$Kka*IvxF+$R0-sWg^w0t z%*8sbL44f@VQfYXdaCp4Yv7b^Fs}FD>Y!COjfal@ZYj+L86Sk07bGu3$8FKa;jl?(TBD`;q!<|9 zZ*$xcRD<}Sc}@aaT60^YpS;)Vmqj~>$cYE;51?97d0X^SB7|ucv&U0(&*uNzFt5O_ zX+!Wtz&Kww|1!o>9l-!hz-WnX`Z-^3FkuO6%V$82p=U*E75iC{K|2E40i1SRq~IF8 z`Bti7mKe`U%9`3(N(n;cCT3Qg#^4tObBCyK2Rr@~pI1*V=WA9*w<@u%rEDm4yOP@o ztf)ocRs#2Dn4zG>Fcjj^F;3Lih>zO}wC_-k&&PC>y?a30w8@m4?T9{h5~z!*l-jF; z#ESA^{`_aaW8!0e#d64+S*jw_GnYaFC&;2K3ut)O1G7oB7(HRE@ERwpyc4VoDAZtN zW{sny1+bfD9(AGQajzD8`9M=1+3<}(71aN;stgGc6t07_c$MQ zbKmU_z6f~8uGVXK=mw{{5`z5*^3}U+)9(#8C(xG-qPn;^=RsiL8NvgkCH4b zEIHqm>Pk~dil;9P<<$Gwm=n|cHEzG8`j5e5j6^;Brc?qc(y52*&soG>>AA8iKF2FN2WmQNj5npYYV0}aZ<;t}r5IMp0< ztc>|#x6aK#lX~ELEZ-RWQt*d^+$KdhCFmG#IgcuJ95N4c2PS-j*&dS3YWis- zVHCjB^c@3?l6VgofVHFF)B%oeAGZ1Dn72#6PTHM!PGEXQKD#ll8)Gb=jTV?S8#Ua6 zrW8mrFq_Jw#i(g8+YYHMKnB}NDexYH@Q@WRm?Q;M$;UzI2&RrdTuL2Clf-w>Qz@(S zviE1M>E`9!K+)r;S9o4WFHMDoT2;^=hi;N%gQrabv0LLNnbQ^gQhp@aEbFv((=`Ox z#%Iwnt0F(yO*ITL9BB1+T@c_+=Sc+i&m#VhfWsdN?mTWW09lRsGCXX*KZF=HDH?SI$KI< z*wICDu1EL%!WAUch|hrOK^FFQB_OU!3M!ND2C#xo@wrmb8^1?urFKnY(J(|8S~Vc-nh2xO zQ+HBFU|bu=8soZ>pCIfpF){CIE%Gke4o2f$lI}`)*N?vng|XnWn0L8crR8-1=0#Vf z6OYDYH2c1%SHxOtZs4tIkU<^<0|R+l;_-~YAptS9CQNMC3aeaHP`+@pIY!SALPkLu z2t^naovgV6Z4Q$|A+eOq0JsT42TKXdsbEK$$__=QnyBTDlvW)FWh6#4f-+32p8q>* zvKed&)2nnRU7~=wZPD47iE}%0kI@l5jV^sZZ?{o>kij%;7g1RlqJ_~(ALI>JySwO! zJWV?E&Uor}k7m1nMyBV&YKEnr%R`pihV-@L>2celS*+%3c~pTrRO>QuBzZ@v6ko~q z`KDC2MqkG|c8$OJ90W`9pIltxC%pX}_L$bNny1{RrEP0^?9B{ErYrB@2oXoGdva_= z^m76x`A(bmDrE;M+LxSZU|iZ!s6K&qoXHpSiEg{y2HP=S;zF>d zbW>T;nzHyY-T*VDXfR|Ln{%^2ru<8aUm?gSvE;-!ml)o7I)|YS=VZ>Y>!^9o&>F&t zs^z%YWxq)yizW%5W+|qKIL+O`qzB8W**F6w2Sbbl8O4tcKE}M<;Isc)14>(r;L?~v zbez|KE#%k5cLXmcSz1*`SPZ=IUK#epr{1%Ni;Zy{oK}rF3a@-0%<+b*=-#{d-BcBA z;MXG&q7N_O)|RU11$XfEf_= zNugtKN?@D5X?%D}3ub6G-dmiDc(r~|pOtbT12X-vmwNv)8&A{;BY=Lg0)kp{cSqlrylJr~(WyJV;~k!?_pj=^THF*H2jO&!8- z&bkE1x}vXvJtkGj5FpS*?`5$igF2ZuhhksRoMfxu&ge=EA>PFYG*OAYw#(>#5Wbwk zJW5BUcB_-{44or`m=R@hFJD*9$IL=vs^S{#GJSu`{9pn(gQl{ZtD;^3ikbK~{W7|7 zd%gS^i%;e6>zC&X^~?LK1qI4W12jGl`%(EU{qp|%!t*!t8#5d0Xws{?L*Pg1>)jB@ zA;>DY0drg~nre$6Yl+r~kU}Q-s0~Id_!@7#GwM~~E-&hn7$NVD&QraCdIi6Z5iDN> zOsy)TZa#`;QUlbtjdt0cfJ`=JQ?z{%KQ~5?Lp*rYY>#g8LaP-{!$_Mv`5+%rm}gJU z;nSp0$!qWb;0Mk;|4%m~OXhwqI$r3Whl`d4)K>V3uCC?@hV>^e$zQNrUe2uk<}WxA zi71!V-~0tr?OK2H7o23*`kTLCz2arF`kTLClU?g?{(|f6T7UBw=-A3!R)6ys+-%qS zo4;VYUF&cDf;;S5fAbgYv}^tC&)&md{p-)JqCNe~|8Tq7zf6Dg7Yyh+tH1fL?3>7S zpZ+4i?q*E+BXT=7-*;G5{^sL(lHbPPLhbv&!d*NpOueaajyyx{S06&P41VndKJDGp zaa!`Zzx_aXd&6v=$1kt*7LN8;l%Y)(ZkU>SWuw26!MV^ojW+UYW$VapXr&+cga1pn zJX>K?!z@w|3G}lY<`kxz)t#O-<@=5q&rOyM^-Hbrp9}p*Iv_V!`p?Dwv&w%~^ON83 z0C2%Y)cY~aYI|nBt%iP}s|L3;Oq;l9*6l1Jsc5)4w>Pt9U*)Y;8!nU%K%WQ(fh#uV zws2@Q@=0Spe-TeCdC$D6zLi|_xRoQwRmt0_W!jF+vVl52ewS>?E!>`?+eACJWR@N( zf|u7R_Swz#Jf6*CN%v;M02yUekW6OMzEo;(*j-D6y#fvG$ef)cBlbsfCW6l?_#TGB z^gS5Jsju?syh4hpqTbHv=E6*1)Y~|;UcjR`JV|f!cxK{#Q^O3pGkxH>#neBmVRoVG zq?+M1(u)}kTc(yqeoK0rs#SVGbq>qN8fv5W656Iy{X7WB?0o*uOt$i~K90(_XXYu@ zocDShJ&H$~6|Ux__fG@?3LjLMZlgVw?bn`W2fC9NsJp51X~ERqk!i%<8CwC&i*L

`Z(ML&ft{fA42Vp~XN|sqdxBA(HmZC!G@r*ZBhPATW;M*pc?)z~ zpOTyLYY_7}RhOxw`3;RUp6{EbNd;}E+?L&-DX++Ubqkqgmf&q2oU-TP%>3o2<@U|b zRlb9iF0;BOW`5dpOaZ%?Biv*Y)^xRVgAp4U(XGqGy& z7#e>h(|a^!@T^WN0T4`}_ogS+zU#J+||o7BWMt5}@aud2w&D}n)A3U;W7oUJ1Bd^qd{rYO`=r%zWA8> z9L%C0i?3q1>zU|^X`8$L8wBjViv2)S_5g|5+^m@L$iw57pZC#IPn-65*QCr(H~y2r zp1E%Nf79sV21r{}{dya~)|%q>!Pvfy5I_K)4nUlUW=NWh(V74(uhnqyd)?so2U z&8mjO_>ltMMsfb~!p4Tn0a0P?QC7-nW?G1qIkdgK!;(Rqv3 z+H8EKHdD7|*6hb=+8h{-s8a1#22~*>FVxwkMJrXxE-tUWNW#zsxs6204reC7}g#eh@8uJhnQpGl}7VP;KsrT1z!!6o@@HDJqJRo$3bbK8#l z#SK0Rm>}iLjrIav8RVd_Mt|XduhZit&R8LuhpI@tCTJs~dEYDTWuw2myg|hx{r!p7 zLy`V2Q86TkU+{8jF-lA=FPLbx7$v5b`1pT&W?@_wu5w@iCCWvd%&+&WPa>`$LF{-sfxaq-DOGN>x{(O%D()sdo?d<~sb;#( zr^wx~L3?+-Qlc~E(uu1qUtOl~G%@Xiz3RbYr{nx4Dg~^Oy_JECTo(`XXop_ zlnLzoDWYC*Pwl$dAu|p&bt0m_NO3+AUo*xyPsNKX**- z>0Dln1ZI)lGGp@}56$)6Ls6pEf=}nO^{RhHlkg{VZS{nlEsWy_a%K|Ao^#BY1!rXU zjX8Jh`Z07fyKny&$F7G24aUz;Jbb|kK{HwK%7mfMW?5u6On`}Frg%LC_WIJ!^2!0B z7D~{-xxdazk&b>>ry9NUcklo*IvU`5!^h+5`bw_JxP$B(f!{uH$%nIwgFpt;vTwmYu zf_$IpObF)l&=>OAW|UI&^)t`kAoX>|r4M|f3>uGV)+4J%n%mO#qF)5#&I}zD3 zJA=RQkV)AlE+%EC>+fYJ+21+*EwpV#aLTS1FXois&uKCAxYbRgtt)I0qb;m6^(j`I zRy6#n2DR{n^IFfp{${Q|{ICD^k)ICvFly8!FY%XW^YS`> zS*C)Lmv{b&weeD329CKC_+mFrWv5hvHgm_;Nn&2BzgNr9Wu{l%mofH=np{6v)P{=Z zcGwO=ZWfwF)@-r4g(qs5S+mG4G>dH3EV2vDB5StT+`{$9*{C~`wilX3Hft8yg=Ud8 zTWoHjS!AKdR?8>1NPmfMvTOa#XSH~8 zi}W|2?Pd++7U^#=1T8W#K5NG1Mf#h@8n<&sug34tZ`CuKvQ<-+{`r#1uk8dvA(hFF zePgw3aCgqno!>nM<3a9xk;7=N+;!|}t6?>=;J<-B4RV=4z9-ZBtUDQ+{3O{zPs0Q% z$wdQKAW=s5@-QLZw;=G8)y8`CgoQW({#IMa9s`9I8-=-26^#Y1&4H_U%3&xF<$*tr zRb`7!{G3=+?O1EMlFH^nWa7%i5Lx!!{N%!>U$5+2RA!QD&j%!w8K`-wM7V;oO8QXv zfm_?^Xq%cF3)N2zeYa3|sOU=U$~WVjUg!J9%FTr@x5Mc~9qyq=<1#%DkQ)+(Y3Z*B z)+p4zDG@4whPCQ~p<1O@)9nZQ;@0Drsai(d+Cuf4HCz^Rvt_9$_Lbf=0=ya1w&>l= z(z9vJhbp+ZEe7y?4^tO>qKPQ=(|N-M`0KEoaC4|qY$o7$#%gdG6<9CO=A23$rar_> zJj4WyW?Yz^G3&gwRMd;Rg%7dC*_GQR;2=^?BI6ZJz|p(S`?-=Kxws?g6|-CrcN(9E zxHIdZ#hp*3#hu0x#GTU*AnqI=i#zqnikZw@B;w8sWP>zurzq_#-=0W2ufk)weDA%{ zxA0Kv_fA%RQFZS)i&Z3@K^E@^wO)vVQxU`Hg(?zk6V`X5itF5LioCQ>x?Ry8{vH*J z_VE3}>Qck#uK|70d~-9UqJUKx%`kdqZBevZAkiusDq7W?_Yv%(x15JLy3{WED(KX3 zx$5EDq3&)Jef9k1e}zr7;|P{YVh@epEe=~MO@32@O{B>}$zWq?QmbYJX|f$fGDwq| zC35U**dG86B@*Qk%QMRk=b^@)S#}4@Vd(hV_(bEsyTmU1@U4lA_nt(?dq%IuGTyyb z2r}N!tq^3q|FuGp@gB5-*c0^sMhcSTPLCzIj<@}d93~b5Gd*YQ85}GMf_QEyOBno{ zWI;HUTdy;%HS2k#MN5#DOVjWusVruXYm z5_z;HWP09<*q=5kNin0oCMsuFknQ~8>wI30UDI>T^MInYRH+vL?<_vh?`-`}*#jx* z$g@Qk*|qmK=T4fki3K_b4l}DTS!Ie3#g zfKC%G6Is|B<-S_5fx5IeuhDWbHB!So0*7UTHdh4;7mM>oT85`$(V^3DQJ_*qxg|0G zH)Wq@sB7U#0swxzYb7F~iSfN6kr-)zRY><`U(!w^UZ$mI0i9uEyb<=-3gMc^Si3aN zJvL6c1e-O^SI}R^`I0csV-G$4*HyJ)oV&v~n_;=UOdlH2DK$>jNqx3+wG|n?-p15S zT`h^jyvgUU=S9VlG-)KjN8-uP5CVqvc2nqS%W~`IZ31!JPn(YyXMQ^SDCXnX7ajkr zs_KH~;~mqU7}igrexuDt3m|UYyz5Z>Wu0VGk4PFlSXg3WrF+-T-_mWGqr_jyI`pZU zcx;)4WeUrYz;WlmDfjKimLSPFnn@%Q6)fi!uOM-xCL$)E%6;pfR@tW#=V5fgY216U zLbK=v#Mdj4>nwK2T0N4Y)CDlv>)EhNT`(meaZ2`{?e#2A>VZq>x}+*-y{cNCRMl=( znGTUSG<)9=y2RTFV1`u%q^wtm#Jzg8Rb?tjVvO&7lE^lJC{>k2|I%Jb7+0^7s(yX1 z251^gV#x2k%Bz~7DKcj$(>1Ir24=lt+8kEPtSVE05+`i$IiXjnsw#%fJiW1AB~{I` zs-!6ePyfMrxyb=#Tb| zOs8_L#vm}b*+GTCEvXqb21}+HaN`MzL8W)1Cy6#Juf{OXCwVAnqCslh7H%hI z^!SxR^rHw(qp)I(6gZK@2k!xFr5aoOb!b4J!cZ{(T0=0jxG6BqG`9Ey z*W8Mo0vBefxmaKO0&SJi*9O&p*VlA#Vt=;hIK;HU^D3f(g7>nmp%}}2y%X(rTXNf_ zzuuSI?e^rh%YnUhcDp0F?Gj<{VRpMSx$UxHZ-w3NN^WZvVrAW9R*3F!JNg5~wCgCE z$2tWJ&f_0JC_56qms$47L@t~9Jms?BXpb)5Wg<}=wD5fy?k!dUh&AUeLniYSq>+B- z?JQZ7MudfPoT2xATw$LuDB{$bxlB!=Hd58X17%yS2|T}Oqwm&IxFK;`<5e?Z0*%=7 zQc46e!N3F93e}rww2A8HiP-YnsNW>TOKbE4S_d|IBKutQB?M%>ZiNq0@TJ7!mP;C0E^ zhE>3aszBm^k8Pn%Adr7u+H=~qhWYV^54TSx z^+dbmIAK&`sm^E~xDyQe2#ZO575~@mc>}-H?Kg8fCf#Ym&Csa1glLx#?DX>@M_mek zqV73=S9UOsO8;@}V2QH>7Q?(9F9mar^De z{Of~sATd?98wWP(c8%XQL0GqE4P2tz_rsHgJ|LvY63cb-S~2Pr@6G?6o!~Ow6v=U` z$Zsc-`ag}v%F{4Ni)3*{tre~PP~ut7$1}k)t=v-hk_6k7 zXX3{YX&EYh&px6dgw0wV#WPWqa|2-;)iW^*R7yzO0$M90>B>75NZXmbQ6z1{d^|l) z+DaToS3eB7IfCzkuqH?NLhb7L3$~jRVdQ{t4s~`!|EfJYChYaBVf>n5pxF_f7Vcx= zid>kQAhC;{cMK5%n?&uC$dWE;B(D`u{qnA7IXCo(hvNEszZ>e2N}hC5;s@y!`n;vsrL^TbE$vaZR67FSl3YVeqLYK(88Uw! z_HipEZqDO}x10H?_YdcCsejykfJ@auw|8<`*w`=^rxz35#NO9k+~L7J{P5}>{M7qb z+qu*~?ylp~Dj?e*mxa|029wndms0`?tNG!zi}|VdFIIA?f86ci(mne`R)A86f7EOT|+a6S3_=^HTRWV67*6y zTbYC|;w`3RUL!X#WrE->lelbZm`o_|FY#{};yo}#z{=tIriZ@Wpk95d_v;DXG2eap#2*%zujRwzb183Uv zc_AXKq!UPx;Xu91FKaOov|}E80_=rJ@V9ry-s2(GPSU-=CzP|VA+-AMXMel73#=*flbMI=K@<{$`hJ?3uyeYt7k~IqI z>HZ{ZyNH0b!RldYUUJhL25*a(;g?^p1z6{YcG*f?!5uR~Qp6k;eDBmYX0Ye=5Fzk-WuiVC?z{ z+rS1O^KhO&`Oj|u`LqA*^Pgw^r-Bv6o7MajH-+`SxuW7yy2JQyK8XjuE6nrJ;*b`q z;F!^@Z@#~puh(;x>t}lyr&IVYWY3ipcKULFMdkLe33)R_w42w%elSlslYdt=D5d($ zb-pdL>=*PvW@=;u?(%R|cxcPi@8YBG%q*S40B3m!;AH-7G>~j=l2+HTQ^7B zs4PskWJIk4m(OMsmp5COzLolr?)K<3JsLGveEaatVvv4q6q6mV{PyCWhHfgNX9_21 z2My?0+rX)6iVIa;m|at5@A3gFPPR7KhG;<{g~nl#{6v&Wm)vk8!|8g!`hii>U)-)f&*Y ztAAIKNa67EG!=;AtJZ?COSY-qV)nPC_M~5W`VsHqQ!@ue%D0 zd^18~4NXH}hwggz7RzsZCd068t!DK4nmFsFupPBlviCVV3qHkcca`jYh5==kd>HWo z_tW9Uz0d6S5}ZzOyPPfSa^0%!!|2O zHs;CARxozPIaCzr_#OP{AD1g>S^t7a$j98^{;uTyKKLH>?1l>wr;X65s6@WdC>5^F zvk7Oaf;unMsSu~iIIgg~03MMb7}65+Rdw`$RGOgne_O@p-M zXl${{?une}AF=O3Sv1$oPwUvo-1IUL&VoH!(YJ|bm0L2`9hS>Wc+On+zA?EzJL946 z&yMN(?2Wm;xje1v>D$K5%ykoTeaG6{GsfhyI#!BRR56L46%G5Sn6-6`>gTskzXitt zPf|Negw$%MP%jzWB_CqruxLS$);1XAKEpCUV80h*f;(sj38_W@~;0t`7gq}VqKQfwa?DV{Bd6g&S{|N-={8SJWS;+LRM9jCG3O(NjZ_eLnL`bT4rl-IS2=#ecFms)INCp=QDWI_J~oaY4Y;PK}B z#ula?W@Z|eNfX>EUs133rZ-|S+sS){bq$^0qzT-#r7zFX%OaKG;2`%(w7_ca&7VD0e^X?zf7K`bf0JGWtkQ-*Ht&dWq0Xigj8Nmy=Z&G zl-P5TrUU>VlV7Bn;;N3fO@4cR9IABbVxb6*rxXP48UX^rm{98qB+=n;-8r<@o>Z-$8lhI9 zRsz>uR%Zq(`OjazcdKj?nckm( z3Fkj3bA6^a!?kpzGki6FXdFng!H|~Cq1b~$cL4L7K0TazlXt&tc$ z-mQX#RO8vOLWqlAX$6aH#_VW?i;uGoud;%oyr^xp6%=Ji;c_b|wvfU)E7%rEbVF;@ z_DBL48>DTLgm}@job8pw+L(XWyxex#38!wYXMo4wlAqav`F>_g_UTug_bTj~n+J|r zJmwua-keFae+^IgBunZS{yzPRb9eR6oTm@_XSVRyYzp*56fe8GvQXV!sO#o%xd-*=upYvvRrn9!sxY*yU z_NL0?pkMX+#O0yS{+ZoZ&+Wo%QU9$v4Pggv3O=o;6aDrM7Y7)Kd0u=V(yTO)i+4Oa z=-6PxVGMmTf#>tGe5=(cwJcl1wo zmXRmGTwmUADS+ztpSG*t`aJHpZ}?8^#%_UCnu3t&3lAF8E0f8%L+M!9+Knl6@mTfK zj7>Lo9E+aM(RW`}r>e56ko)HMb2-0%#u&5zc4vAztMtB%|JX^Oo6*pJ1gl?$k1Hy+(Uxg3|2Ng!LmAnXmv~Mz$fYKYaPZFCL!s61Cp;W^_bR!_@ z=1XMdmHf=t{+WMbKhs5y6vCs)M^ftHVPX1_+P`S~n#%0=(ZNn#>}%3Nd!5tpoGe(& zhuwTgy5XU45^PZ03{EWuCpjD$+G4#Q(ox5`wbVFMb|F7ic{%0*R5yjlcs#+t~Sip=W{N&8Fn(Naj^BbBm zK=lrG9Of(g=%a9=g>3WgpPFWF$jq`u#2WB~B`+SMpK00c{LL&ojwjfFCQ5SXI6Awp z>bxUd<)~axBXixUzzos#(JlBikDRh8`!n?k@%60wq^dGrrTn|vCYk$d&)8M3Jo@a) zj_Sd$`&&^X)S-z5flnD_mwG76=+dtmr~TtosT=JFG>sM3#nGZjs2=9M{rSA7XAW-ZqBJ%ScVklRt z$*Sx|7)s{46EoL!j!9Wc%XJrM)Ca z1>~8y>k+Os2Vvi*Tr5fxrdI{RWJ4vduBQyMsY-ogR*3W`m6r^gXZ!@moSZI9*bY&1^H~F2oMYMT1B~SbPWWz z%*`(aFur=@#9_XytFo5^&Ks&HR7QC|8EUptw~I)cl0Nc%>p+&Wrf6gr!z0YCQyF>Y zI+@;NJo!hB|6-8kazZV=^GHI&W<NU;b+F=)(-C>D0~cv z_Sd8F7r#%>4oiCGcp+<`{-wYQYc14WqnlNItK*&te=^spXTqOS*!|5t`~COm**rG< zIm|}t+5aIHzgIo_#UBpTqmo&a0Bp1P4~5lLoZJ+htf1OB@8^40(#@p`I@wOQ$)BA2ne!=JhSe5XoKNGo242QgOb(!8*v0(uL+gEY# zQ7RP~-?tz;fh~T0?*_T-yXl->l`Ru zuaYHNI*TrzD82Dv^F6=uE$0o(Z~PR*VMrd2F6B4A<=i`ikcg<)^~G0>oXdl*<$Be% zEK_LtjXeN^P>S|U?>pq4JyR)RIt7Nu=}<9y$L}c>#~reFylX>*po8L{cMW5y`iLN+KLl^v;>+ead*vGPiBJV$9lsyJQ9KQ?DvW>FsTi@b5` zJa61eW)-raym2O@HVu_gFPie~VDv$WY-G#P%ZiC!=P%1XQ6ih3`5k1@6L^`FB;#@W z^HWVswFgD?{#?5nv7MW^1i}Z|xJR{0HV(=fGFE?e12;(&+HKB?cEn#g*v+k=-mbMU z!#LWyE3?MJt1@ern0`B&cDSL1=JS`CcIY}c4isrr`OBu((-Ft3Lha+EI72h6jN_id z7@kUxLEaaKosB`Tb43y$m5w2LE4wn6Yg0zA&ZHC+B)6kfb}@9Nz_S`8XeJX;tU>!3 zJe&o{ck|ut`$gmO4uuUHxdSXoX)9|=W)1ni4-5y>AM>U^j-n+C4i>sjh7BK@;J_#z zNsofXOMhyiWi|>$%dfV6GPcrDME?x@mZN8P(`Ta8z9ivq6qFF@8HNuY78p`b+nDK_ zv`0<}+CYVI{dDt$Q2$84hGIfBOZ!-A##(C@D(4WKd-P!{EST#~Ubvv}c~ZfY`9qq5vr<5Ykyu=y7dqoyASi@G&4* z9bptQ-cg*urNv9I(UMDxmjD^Lw0H>y$fd<#4}D!Cj~dXw=piJa`6QU6 zyFZY0vuGPxQMl2KivMZ)tY_pGkM7b}Qb5$LvX1n=R2<1+A&z8fL5<{>cpS;&nd^>l z?`P(^_m;+yAd$K=eXgLj#NtRQ{e5>a>-~D30j8CzlYd-_a_L{xMgKxp^(AJh3wzXY zLGU=qt$w`5Hay^QF(W-_Pmrr*=&BjdZPT#rw~`;fp;^QSi}1eND0VUhUpkQ z3rg~y$lSZ6;bvO)4C@NY8!f}S*U4U?F05Cw(d02{T9S2z>eVvqN-8%jT+dpBE}=(4 zNu-F9f@6gpvaCGoI54=CRAB0?j0hlFg5{g;G+awI9fYeZRsWDIfqAg^3oI zaJf1pdJd}tSBhXEnmd#Xl&eGX>aaSN7-VT*+{-|lrdH*uQ2=8}H6s5j3_oo+OB%Y> zs{@TFnUxqS&P9aTHlku+>8QYs!!olQ#A9(GHfsfeX+!qE`U0}}S&g)tcdZbEo&L7P zxto*eqnMmqN5U`>ZKOE8qFd zVAQsQ5xC6(fSRdjRXvGho4Bu+|L|qBr{AI-=PxsNg&!fAw?KPViYC!hXcTIn<62We zMzQA?pPkP?fW(J}(mNL>a4EIabiCZN99G3Ck*sGwI1hVjoUo%k#A|z$EeCl3X-z1m zBo?mLa_*MQn!S}bRISyPM+T|R>d>eVV;;X=#p|o|`gS6?tNc3OXJ<)?7n@x zY5uLdU(Txw*sS8oGix$S>wtJVSi8$pk<V*$`H$UWA-aCWTNE$iJ+lL|IF6sayb zsWPv4V({#}FJ#SiRX#C17Mqrhl`HVVqvff;{P7)*hmsF+@HJ%)TKjSfp6)7iOeqtM z{k*E~VF*?=U2djYbU@vr+dAE{TbB$d7XLFn=Z%Zm!jm$3AslEqL#)#LU?TLb@E$P& zjnO>rf=)umOG2{|vE0MyMY`xx1M=BkgM4 zN&6%0rYKL^O^zgMrm9MgoyzoRa*^6Zi;)Pv#^;noRVkf;z(7g#kCLLe=?+QLLyY!$xo(i3 zeGN-{!7pgm0IMJ8RxSapGjBZhL%IEPSfa*$aZxE-AGNJkSB5>Vn;pW1*D+Z{myN}TVd zfD&)?Qb38vF|klfK#A|k;Bs~&YD1S&xDGH?@i|_x{RUbrfki1-U1{3;TXZ(V*AAx0 z4|hTt(z#Oa(aA{E#S7h36<8%G-ko8rX2-F#@#k+= za99DCd7%AtA^$&SAz|w-F4oHsdPzS5ExIz{V4$4qeYOp_BuPF>$&9PU$A{nO_bQL{;PuXxwhzhu4y`- z%j{Q0`%TmxXtCR`-X@fc?Kj1ouD2pzC-$4QRtWZ+uUR43Z_cqou-{y5g|G2bt#Fp#O$*ASmc|vd;?Ljm(c@Zp7ydt(~_5e@d^w&3-z+Q=uMsumJn&~B`;r4 zK+yUSFJsBsNBCJfzgcoLPS1lFH()p;r{uX_-6kc^l7>xO(M$0Yw9sc(l}*gUdGb;h zx_F6|3AM8vw3Q?X@SI-#WLirhDQC!)&1Z{^_2FAXKHDL6U5WhXb)Cc2^QkMpp>87c zO!~L~LCVRWqr+(t+_a~WIbx4z^r9PptsR$YH~LmG3X*nX9TAl(On*yA+gx`1x+~X&+(9f+lHec?X5|cF-yf(?)P1f#{{E(7KEbpA<0q`h+3q&C3 zan)r?H$YcSAU$e4CvqIGsp|+x0<-9Ox#4#L7^V z1%u+>DaBu+by4d-B+OtC4c&Aws^&i)rKP-hn2$C8Z31FAXKjgTDdmq^Yk~v^nbMHz ze=!cT`If+<8^AiQ>NCB4*MkNrt5O`C0CwV_{1GiB4$8v-ijlSAKBPeMY&%kP4prst z87doGE?NfBknxJxr9s4BUDEas!zEU_qm#zrrz4oOw4Fhn!8Ub5*c&p{x`m0#_J+8L z%ALA0QOV4g>NF2}rgALWUZSr)Y<0xfjDX4cEp=p!_q-3RCO?`8V5Hdu^8D zt~ImtMo$|G!$7Zq2DNg9-SwuUfQ@wIyQ2S9CQ+1{Z*eCAq=MqWn|q-M7X!8h##z&Y?E-To-Inf1{SQu?O7QZz=zDrt;`dL_ZaU7)*YS4fiRe5G=G8rL0v zG$ExK7*Q7u)lyn-jB08k>ZR)Ps3!gc2t=fO$__GfE*%J&b6X3=REZs1hT+qY28zfO zGUpCMruc(0sS-=@sD`%6RdvdM7;q zAxbM4>lN($Zd}1kt3Z-{^cTbj^&nM&s98Bn#?Up$Dl7w3T z|1}6s{#j{@G-xgQHv*AX?aqNi?Nccz(Pt%d6|*V7`94D;o>+3_ms+taE)FtN{n^gA z_ZOnsUdTnp2=f{IFNegn}zi(wOP29I`NE6w(lewXtVGLqQO@-fB|c@ z3q)%@(D4vsSD1c6P%&zMmdo$to&VgCXDEfAsCzp3a8mx0?NDav74L7Gb{BfZ6G5+l zzUNHF%iV;|lHF1~0r665s2NGK=t^rAg~J&xW|vaUVnb_e>W(HP5n$9AAndSKM3vu@ z^k!G(MWe5<=Q}Mkmf7suXPaFKH1(aRO;niMTbO#KYDE~c?aMB>snxVE^4Vi4+os;& zhtyWr=(DK7L5T}S6*QS2k$lhlL6lV*StPqwyX+bQTqj_vk!WX;i9RZ+@~j3io`GlH z@QjQg(R#LVdyOJMMbB`ay;_CfNzGdnWZBN=6$KfD%u<1L1WanAz3iq#qaU-C*xMab z+O9%%>kMjf0OMO2zebYV;4QErK9<5I`9@E%_c}c}i9nx@IP@sG6VMc`Dhr~voz-zw z!hq<9NmZrrjhQ6BBJ>uxeD&*}k%MTZ%KS@7(t>MCQj^1VM2rE>On&UUt}Upp{5r>% zTgt9_;R|Y7+IPLqw@3T?Ln(pu3CFKyuBh9T2!GchD#{>GCQ3xS!Q7RIXgz7Xvu24v zmEHXlXet=={{O(T^ZQU}q!7}D<@?M!fkcOO;tN-%3Ggv2J0W2VM#%0ehMO~6jVaH_ zV=$2SeXXpa=6*$i6!VmS4rw}-r~E7{CJf;eD<%x#I4dTsrpby4t2v3H%Ys3)6DLOE zz!UKL|ArIHV*Mx2yXi8|C6Vy_1$ut8(Fbjr(?5o1@;X9ZE%eefiSa68v>XdeIr?R8gy)9`Svz)bFtc$ACs)hF=exLCv zB@x=iDVn1^pV`i(VkgkB%%+giEbLU5qeQ7hQzYlw`kLZzeP+*$c_Ipj6@PlQWcCWyCoHzW)+z1b_<~@ zLIx@*Dn~Erq;G53(;+lK`hi%s=bjj-((U(g`|qo%^o)fV0nM(!4x$|o#6Ta4KFno} z?lJFW)e8_Zex*>oKVX=!qO5vx2`p#`Ld9Q)2K1@xszJTz8j4Nv2aZ+6P6@*STcV~; zqpdQCv=7NXL8PP9A0QsjMK>cISo%4DeiRVVEUompV6|-0v(M<+!{Mv=86;-lLwaz% zKaj|46Zn^bcj)$abQ_%0`!UW{avgipje5n>`bBilaPCOvKAc%l5MqFHsR~Ax){_cu z`@AYJY5f$hz&d6<7*Sf6ylu^|u&+&8e?qXJc@4|HF6}vRsVIc}qtlf}@I&^gN$Z#L zX>dChO{)Kl6r7q>Ihso>k)uX@3=OBryMI|RC^A%1m#jvjDzX}lTGh~~np9OXT&gNC zW%N3RM%CE7&t^Pq`c@sHdyYF)H+ofNBWv8#&QQ{Zicv>ZHnL`gvqcAvSsD%moMDkQ zdlYhlS$9}ujYw?eHXCVALw8(=$Lfo@Ri>0;U=;O?8d)Ry?NuIBWX*@^8q$)&=vh}W zWfKlWd(l%No|+H!Gt5V~E{nF7;U>r=azkJ@c%_Vh@C(+68x9lW&-c&?K%maV1ZiN= zVN*f?HF)qQNE^O=3WFTlI)ox=J(?`<#3L-GP8z@``tXsNWpa19FZ7Abl6nd$6%v1F zXT5x(J9Ttod4Fg>E~k6uUy>ad6HU5yaPZ>GUlF~CU%zwqMutg_Yu!DQ>(Nh7CCJ`3 zfS3TyP7W)CNX36)s^U{rd;du!p_t^kfnrD*el)hk12yt5_}dbP^E<2%8o3FmB#lhu zNve?-Q$$1|SR=(<|1RdbG;94F9wP_cV!$P^b@1zV>cgGdc~E>uv27FV+V_5y|ix(1L`>OF$zQ z$svNM)r27C|NZWL&dG#F?c;ZU|L|eX+57Cr+H0@1_S$=|z4k*0!cDiMLS4FlK(Gq~ zgmmJ~<=Y?pPf}nXtkmdlTYs+tzcNWk5d44i#)cIM`Sp%HF*6 z&AYW|D>{&&p6~8O=vh0ovX0;8qU3^oFzC*M)8M@vQR_qbn79{qePv4Xlp8z^bfXZ|I60%LKYT9@GHa=XcgAKkHGHGC_{Rjh zDilUP1e=K*g$^QTW#4e%WC!ZXGQz(=ZwJL^@y~{%IT>OXZ0`U_hPJ%Zd#wAgnQ@`m zBz9|0f7agjNj$qQ4JrF@wUnp+syUZUX&!m@k8=;#`x`+@eRJX z8p@&w#xq}PD2RiJM3H8G1$hWBZ3-_V=WnQx+oJG^`~0PkPda*cL7zA-dbKCkofq#o zFZcMxz1p(v=f```xAIZG+p&4FTkm(f6%EaUM~35PbZr~!1J(7T`mgHRvETg*U8|qb zwG9Kiw!bp;>x&P|cHu6uvvjeX()ohuvCiFaF5!0Z8Y>fkuf+bPCznHNZ36cIlz#Ep z-FVhyBNoqUJRJO4ciooeX(oR*zPBII7_E-;@nkc9n`=2#L8Hd0szsNQL0}Gz4=A`C zzIsj!N554VF=&j8sut_xCx?R(YtR?9^45T9U0;KzZhZFeN`hPK#Pq46WSW>>n;76} z1zkT4lr>eJW{Um~k^}X0e^6yS_9E3FLzlW)0t5yksL+;g2LF_6%XfR*x@&M(d&V$i zs78hw$#|UQLJ7qH-MQutbjb6eKcf&Y?rGSLr`Q-jHL#eS{l(Oym|7IW-DwQ_PBHhP z7>uPXCil1|t^!RJv|_{Q6YENn7h2mFYa*a!rPyuekPB3OiU;kPVm<^H%Aj#`k#SR) zCf;(%b6BfiG(3 zmemg`M!NfNK#>{fgG}IID)3MXJkS;|i2nBf`OC8ZCAk=79Q`|g2&WUUFR-?vc${10 zWf2s{F;*m6Sdp!_&|GRMsNfIieUA}?yyEFZf?PZ%SeF7(5qpVos(HmDGi01<)b%Bq zTJ$h70|=l1CFg}YKTXFwlypK}tIT6W3fa^N)4DlZsFdZ>LIwWW>?Rm>FVfzx z3jJ3}d%F!Jag1=rTDA%3s|M+?L^N+RAJCJGsXk+}zx^ceRq1r9?;#0X#zQi*W~?el zL9xCWsrtGgzEl_EvJQ{|FcI5Vcd_`O{S@rBcSAs0A3cE+4!jz-YTS&YV1r7C=*m2TZleR#5`Xnm;{gX@B`o%-rueB@x*vou;Y`m8@yV} zI_sM_Z3lX0H$P2U1rJxl(r=43lJZ>fktzA;QG9JkZ`YzbnXFxG)7N|TT|6l|6(mtB zmP%H5foT!Pbt}nB*;guF%0|4+OIO|u%h0W#%Bw@8!vFxu9e_!4KX0&0?k}_=PVS96 zf=*J5!9wG)e+uOu#6~5@WK+AhKxg)`CGE z{Ig^b@j9x-`Yx_n->@IG$e|HTG*xU;qj#;92LKE9S#3xNlC08}ze)=H=n3mV#*FlV zv5HGz5Arn986*8Nhy!ZBK+w7mNw`EVh{TIYDgO!}3^NN|3^_J6wgs+NW(Tnp`&Gn? zOA;l81k#8#;8&DHB0|1dkF%T}cvm_?8`vIf`nThSZK|}<8f1n5?vR*}hS`YYH6=y6 z-yDsFpBTQPS`vHL1xD5|<6DJbsKNTl)VdV0sa!wei?u#**zo;cp9vCzK-e@qo53tf>OM7gA_yK=BJrc-0oR0yGf0uddvfREpgO@<>5z zSAnsV*f9RdxTVz02wvY30H4eb8Cg1e>9?@|y=O;xYD*BY#w|JG*22j3YIvHn$!KI5 zl<#-3TW8>2F}cYB%(lofGg9vaed#2eKO;)bq`a<{+I?t#5hBO96gRg&`wE> z+kKEvWz@sV&6aRBK45GzOZFQCuP^3+x9vvWK%z6m55BeR8616n9wjIl*H?rHomtSvw8{h<51MbHF9Y}!?* zucZ#Z`Wky4m*Dbme98!OCSs=uvw=xs42YI`CPYu++KMGemWZ`FK*%;qg8e2wz$sAO z75bX@asa6oo99RMlk)Z63@v&e-t}JOzgI?vKiLFE+KTsvgCI5@wFTsfn6nL}ucBV% zopaU8d*w)Y5!q9=3P`V-phY*6 z$bpx}R;1OI$GF{zV-)dDzmV_h!=vmI^hSm8!hR&smhVEKQhn=w7dKd8*zxXe+|&RN z^xYn9*=PQEpI^wtrUVQas!FZP)mP0#J)RlaMq?+Sm(G&b^q@#^^=|-*-Jv0p^vI)OuO8qnMoLiN)5p5wxjFs#U?;8Fl z8r;5FNuu$t;cueBAs}NV3CO#KzljEin0PV$vxXuVNo!(W2sMe=r|4DaFGwuraqJVZ z9>h3OCk?)u0M$cbd?{{W#dFS61cgp5xB#H8DFx|xW_;PO2?g9S(10(nqvp$pESlNqiG`F*_PNdAexN%MS6`&RrHrK8K===`p6<{54FPB#S2gmMDOW*J}$WVK{WC5ajRDpQ2}n3UfX>bhn`UElGuC9(^Sn zjOOxz>{MzvTQ4_WQsnr^{t&*m@Ha7^zx*>E>5#GfP0Z)7id_jTdRzFLn9pAoOHZKQ z7XBvYJC{@$kI*Hkw}ron`TSLB=^NDB!r#Pv{;F6y3H7${H!+{TDwf_ty)FDr%;&F) zrQ1+%3x5;y`Kx00$XNa+=JQv@cF0)%q7`mzEfDK%;csF-e^pxEhh;3LYd&ua--nre zPt4~#{}S^V=AZG1blta@?&-WOd>>}=Ju#o}{7cMdn19A2)p#=&Q)+r!_&&_!dtyG{ z`Inf_F#q(G73d^ST?r@&C^sJAulakf9GE}jF9vB$&6FFIR=ium35jOk4OE zGyq5JK-qyz0`8&v%fYqrab&{O3sIu+G5O986OD2*79#MT`>Jx)J5eK^bG%w{hx#ldy%b!64nFbP_`z>r%p? z)T0@twi;;Pdvcx@TMO0Ef%ZA7k(2VFf|Of(@DBIxYv_70Ra?4Fw6I0i3buN7J~imB z&8+3&ViTOVtF%5^-Is= zp2SF5ablz_H8E0ZI*CS3k@+Xy0OBs6fDKhSFShz%IAX+tZvR-{0ve#-+8J_Z+a4N3|qKq86J>iz8SlcnFTFJRe%lefR1opdz;e8$|wpCC&KkiS&Vy zX&z%nZBiQu=-kn4#GugvUmWquMsyu)YHNQ-dsTc<-{iwbeO+e3K5<92m{bF;^bh66 z9o2fTf6g26cl`Phf7hXb%@xNXlHAsk6CRBKiMCxExAO*sO3|CkExz(U^dWiy z#8dkbj8v8BuV}A`3vHCNX3DQ(Qne_n8K<9w=cZps-m5msYV;oeoM*9x((p>3-s$gp zLsqCC33e@rzZ=BUDu)6^-uO2xfmwHP?mjycGoMbDU=!wp94_SCf|D{3LWPdetxv~H zqwg++n(y>_Ugi%cbeL#RpW<~}6;uY&@Bw8Fbn6>|kiNk;F!D`nV0iDb z1J+v|pKK_bkwa>HDTx{})&s)Q1K3gO9D8G$=KwY%pa4RoVU3GKvNvsW&au1S+;ZC+ zg{&dfu7js#-dpowiF5iUu zuzCWFd90r!uQ8pgtrWdgh~f!cR$9(?JgXu1I5(UIG}M7yD#@L2E6=a}XM*q=Wd{5q zO|>(Ot60r^2$k9K6ulUx79C^K=cSP)_9b2lJ&rIIIqlWU7OX`3PuF3< zjv4V(BV)1mLqzzody(ohY?;{Ck`Du41ZF~P=&P0iZr}ZP84vNLFNC=j4z1#&w!F0) z>yS)`BI?DCc<*q*!yGvX=Ao*Y1w5nH%z9x;buG3b0Ud<{lq(slJP?jRj!Tili%pVY z@E_f$EIjp1G>9Vt*wA7XsV%$$Jc|^>5rh7Ov8k1_po&MOAgZNDu%MVJ+C6 zyIn^98lceca@Fjgq8qBZe#}JL@*Mzqrr6F^1O+`(Y0G=t4l{Fi2iqvwx}ITVsds?2 zzCn1<$y{Jbtt&wB!0hTE3MU;@OWM!?nK`QOp4Rfz7+0ziksQ*3^-U6!+6b!S@`I-? z9pzU&%AG~yQ7)E=J&zXm&iz)sulS?;CmB-H0W9T4BNxyJExU6f<*>H=4dgBF{uRG4 zjrR?F;+Awd;H|)Bp+Da1FWwDd1k1~MfAJ^r_AND;&g`#VV(ZUYXmbW~P2UhpaGt3?+ zL)bPP>BVvK?e*{LvkM`CUn4V>^)InF`*i(NTsc)m1LZ@vZnc1R2zLE(kDH zM5dxcSSQuDPb-0j+|IXANhNR@0VU9MSE3+WmL!)Oz{f6Bu3cer56o-mrOa{jMr2;O zJR$Si@SHX8=+p8xoK~;h;l!kV@g zyLb?n;dN&TI;C|=sbsm&f zm)89T1i7|i#}x7K46eJ&WsN@?F<$6l_+pVuj@^wd7<8zJ)#F!N5%FW%#FS`Lmd!|+ zlw}BK$e}P6zCyM>2noy`v49b4Rx!{!n$(*Q;(VG2hdOBul#mlg=Cvv*+U$wdhPBYkWV+w^JM9mQFvDI$9jixNsR1)1U6zWL!FDh=hc(G znQSFNU#w(lO2sjJ#fAs^(-VxcJ$&9vzXVS*Vzf{1I1bvLX58l24<5Jm z5V03dw*b^KBmvL_g?~WMRQXie7+g||_hw&I%HOTXDBHccUi$37p@3Ks8qkW8h7JJkM;$(lAXb>m*!$gGW?hg|c z;$s;efQ;Bjh-*yz87L`eg~~cp`z00IsTg*ugKF%7{uhLXSB;q^?*CiD8LT2Kyv8UO?aTJ$MNu4qq!#s5-r%*^(Dji zC{`c7Y&^pPzG2LUP~!UPqupyWz@^2T<_;;jUNQNc*9$(0?VFQoPN#p6jK;(~$<9a| zDLy{un8mZFju3q(8_<;1TDQ=y^*)cXr}TkaGEr|9O;`R4`HZiVud!9Lcrij)Cpc`} z7LYqOVsCD|y(|4BR!c6?*ZIV40ljtjT42s2zAi@l0C*vjLzJ)bBQiHGcDKJTP8f3n zLjxggi_r9hPs~B4OmQL7({QiuO4$CbSQ5DtW6_HfCtvnz<=!?9dHNZ_lJrQ@cqV{9ul^bF%! zd2ibSViR75ZZ6n|b>4YJ*=Tn7r^dVv3~NSUrI{y8-%%v-2ukrBk2jHSOlxcy-K zNH=DeAu|JKU9aJBKdv{j<6#F>i1W0_2lcIKJ!Y8tXZLH-jp!tpS`Wu8-%8b1`23=c z<#dcvX`@(&eG^IazEo{-2VRV)>Nw2T!d`Zvyg9M$?NlSeF@NpI&y0sxX8;}DJG8ZV zH#>nhw6z&GL%Az7mUN;yaL5+0Z%~YG09=sjIdC3gvAr;Lg|V}mz2+DhEs^S@cO#gc z3gg&rE=q;KGI?fcng>>S*H$-XKLMQHx;O%9)De$O-X3al$5MKnZ!Xt(kT5Gi-KKSd1k z6eXw}5HWddz1VJDjBs-jVbp*ytboLdT>NZI#TjNLByE(FN z^>yiP?}{s=5|Ya7N6(Wwsv!3o7eqD(?n_ETgW00 zVYTt7_ZV;$GAF(OT5w2D#3=bHu)0tI0>FQk67YlNE2N#a%w2<55R_epq~71#MObCX zPy4}8Zl~5nMjBBY%F~)?OAHR12Fw&C(0>wJA@6atV@|HIgl(9jE#E#x4AVDMNzOwJ zMTs(|Bw~>ia?V&nVm>V)oSRpB~-$YC*Qu@4fLrfRrKf`xJIzjroDWwZvh%{s_hgS6fsM&z6g;4VrKiy(v4td z?y4(Fwg^37rSw_+TS#f+fiM zLy;72-82DRC{}mG%~*sRj}dJ|6&zhJJBhIpeRY}seyZp-qO0@K5#Hk>x`Z!IpTPjO zuj?S>u*AktizBjGHq_e7XXQ|fdp>AVPW(_RXtW&7%J1I8#HMc@9{Fb87raMEtqjBu zrrZCJg-N*;Uc*ILwc%$_=n8H^8dg0IPBXtjZ0rDmTEY7|3H++f`8v# zfK|BxR^x z+R$lXc4_i=z&jvJtV)UC6euHHh*j+qgKl%22;zP~7Ps+E3b%Dmgxf@ii0$^ME_MTM zRZQkq!+=`_18(sQxJ84)Ty}IzbX&uu|48xVd?5ILi`zqr1y%9fo0D}BdN)Am-2jo} z28bLtK;*aqB1Z;LJi7mXt9UuMox#qhH$f7w3)BRF}c!IYbMHV`f_qY{Rky59d0i|Gs)ah#QR@|wX?@~pRdL1IDi!sa1 zEEkAO*5RxG%emTj71R_Eh^?l`84?v(rKUiT8orcdRYlH^e2x9;intk;CD59o>8k0} zFzpq%1V+UR@E>n#YK0l>5wq|bfEF@+&n9L60Y0(f-pq=2p6wjVay5`_XMZ#o3UWY!dm)j(j{%{VVwiB7_qZsQUx0%8sj_G_<+y_`E7j=#@ie?Aj#zqPf+SR>HZK9GWQz&Ds# z!?BzY4teTl)qPoJlM_^#tD{6*5^a4TwL2@6ie2*0;=-94O340D?&wFZ4Kh9S;)=lusO32 z>loa=G{>fz88^ib`f^_}11%kU-n$zmSIG0EMJZa#daT`4nJ-KZ0k}G7yrsbaR^s1d zGHCbk&H~n0BjV#9IW-Hij(4l_IL2T${VMJJhaYu&tS70_f2y) z90qzTjEReV+RGV~s*(7~KC!2uGj|WN-8ETj3gXR( z$?J;bUY@+&!rtZjUTzW-!jKDG_=C&9M@!iQ#!^WJ`>@l1ifmJ~Iq9*!IcaNeq=*B> zh?nHecrYB;P_O2z*i=qLm(oiGV8jxh^8s>0ykg>XA2tD&W5Z5t;*84+;Lx4rsdK-t zD9rTTf|VoMo5m#Vl=37cr@Js9Ek3R-T!ltbLzp728Ayx?B4f?tNC}#V?qmq(mAL1Z ziY(^R*S`dcs|pob8}JEpvz9%eXMJ7jSu5m3oE2`GvqX_Uh*NHXjXo1$U(b>@9{L)t z++f?`+i12m2tUp7!|7z_&)Sc{Py*NrnQrG>gCN87^(l%_>L~07LD(x9LHfqJ21y+U zm2h`^p2wU;=E?(&l^TnCxE_TYig=pJnExq4058(?YWKdTs?hD?)ddxyNcUdxKGrHb z`3}3>jq#&>Z5;^Q-rlLG_hN5q6&8Aq)}?gsfuU%nw!AbHhSpnYPQ1tqv_-iH(73J@ zKv)@Sj(t{O6@+0={Qcf|$KZHRkG@`uwa$G;mNx?Bb^TAYg^ela%sx?8Yl#GDy56>>x$+BqpWJQnCl(uhe{Zwps7OUaH{s2lld_0RX=F& z^mYPyz_+fgm9ozojO7dRAsTxMix03-#L4>eWZU5%y6uoTD^09#ig)jA0-;!=NW;)$ zYDxTfmg6aBIuMj{FR*D4T+^A7j)1KpK3CJ9v+p|4h= z_dQ+jtb|1KbnRaWq2uY=xe^Oio~~^xv77DbN(_`Gxv0!qjzZmN?#d9$Qq=g)gr)tW z0iq`QIF8HUto3RR2q3HI}%-BC%TN|z$0AEW1>_$5qk}Z zjzhI&Nj{mV!A_K7Ct|N7(W`c%E?J!iS;g@-E?)v74opn*TRTm=0tspKcfF!8w2E|r z@AK{NYw?|g(?>r&b zG$~-A5~_90!^p=44ZF+gL!rUi{2u@S&|4_pgNvs*(u0LU`oUC6!CBnYOna(NL9q+E}VvuUv}pBx*^a(J5qT_FjfB~Y+_CYxPy3x9YP0Q$g9Mk z^w+ra>W}(Nxm9Fu8&x3fk65T^6JF1P*ArOAPQ9Q`;&g~2&0A8uIBP>i z)4JQ1`>i>x5dOpXIV-9B=5C)2ngvUkk&t`vvue{naJJxQ;V{9aqNG~fT4PMlpdX##p1C)1s`oVV#y=aP_YR#~f-*W* zVHokCjBcllcybvRi0Lc?_kTbZr_9Yk+tvfNm-{e^qlh_c;vGZNH|a-)4oEj=5Bik@ zYOi;0g#?rcJtv^U6`*$6@pseGkLyR$tQ*knsH<^PAE-^9F=%dkH~sk7uI=_by%zS* z4Jg=X@PKE)C*^5DzgMdMFx!w{ek=!lh&_l?8W(b*rNVwz&i%fk%A+RfA!wdeauN-Lf8;A$YaNize2FTW> z+*8D~H+qNz$VBX$9!xi|Ct+ss5JtIoFXtRsZ#p>GEW8`vOU-2$W`AqgJ;{Y;{7CGM zA0FiGH6On4a(n~bXG3Yu>dM5?L4Cbn-0~KqMiUIR3mc)a5>IGf;YclZ0kF!!6A32H2>^hJXkQU9Kn*OvxGGeMSo{)AP*x|S zh$12vK1_J31MRIKrc&y-tTP$ysaTbbF=5YM|wfg!m!Vahb>2Q)$+)-n^z-gC$5-j==a-)eI2C0Fihvf1e9^9QwC1{pp2MQMQKCw9h6}ca$+7WNXSKrdE4DL zDo85s&v@e>&vq3Xqx{gVqd}z6u63Nqnf5 zN_?;m0k}?ItdufETl5>ky;8P7i>8xJY_@J@n~llUMg&KY0L43mBHsRv62fs?2>18Q z-lU#s9qxc2k2K++C(4qg+{FIH(I}^sH~&Ka_LqX=Vr4ZpV2K7!Uip`3;Ix&0`i5Ft z?k6*O2FKS3X4!9pz3(DJ;0^pxWCs3^cs2gcAn#uDvGXOrV;#d>_;tP(a6vO0WSAM-?IKs~F`IF^6LkF>(rU3=b48wZ&X&i@DSmbEwUF6>19f znDp&>SBmukN{e@-VL0eYvvTmIadw7hGr(9hgbd!oT#}mFKm_28cb&m>J62%&dE+=% zeY_5DB=_PSHC7y@w!N!w^NzEAhF9C8SnN+I`O)qkz4b!Ld)L_1>hRvW0lY_QJ(Kq& z|GH$l;4Ea?hYDRX-QS+`577Yhd4C`VoDRBt}jovxwcm z-eH)|HXvZ!Rx3G9d;nflM+2{c!HL7yx059$vnKJw9W~{!frNCVUQ;QB9bo=kVdr*+ zM3yxP{oQsjy}jJp&9`^cKOAR`M^7Ve`?#+5wuAaB(0`gF*jyNQ03Kb-8XcK2ngGH( zm}-rqr=90R04F|E~f)_ZxpNowrKb8E2)DUL?KKV~~97+S&Gw{wgd$7Z{b* zMtKcQK>yVltxIbADW{}XYS2lP^Nkwo-&wFM@C_CSUHUCmoQ0cR`ua<}`mZkWmv%YS z$)$~{J*O}hHh;=Bf@g?Uqj@0)RBc7=kUsHh?nm9bp#5np!j~-YT~g#LsMACbhJ`FK z#2zEW5p4wxo17T6R>j3GPR3~0k*A-CYbJ}<;}N|V?^N9NbrC(D4W-JbucM))-)N?M zHUmG7!+H}3DKMlAtwQwg>khmJbKAmi8;{n=xA1gBOy%2(K!L!e1yiey$u-4$>+c0G z9>QP{FajYcJEyRlW*Jj!hhqMP(GuxR#(tdN*lEhg8P89y#A+*ysX>WcIY zLD?ex#Ese_P62gG0=w{5zV{+>JYSAPq}kk*=JrGB@8`bSwE_*qRBX`P?@^Gg;!@PiNlkuI=lTV%j+pWa zj`!%ae+9c@)X)4D=R+z65h})>pOmBcD#MU_Mp%9ylMXsrLKaQlWC_b%9pgDFLvYuF zQ&7K*bKYP+C3gg|HjZmYZe18T4y zQvv0nVlnSP%+_Ac8-@#b%4;VCVRWdpE7z*N%k-P;cto;~@45n|x8Y~A& zaceCgL?80I0#3vuRFt%ZjcKx>5!igBvBlNe+PX=!vVO~~?8|+nV2eaN+$(`+Ik%1h zeS{h9&6C7XAIgf%y-)9r%>55V2V!gdkT3rB5VPVu58nrwdAWwc>8p1uI|&p3-=wLe z0d9O`VIGMaE_ri&Kx&bA0cPTFvuAk|br4@Oyj!vL9q{f%ILFMRnwi<>`yJrT(ZRjw zT%%&S4;jMJ2Qs#1a}A9p7H`$eBkUHNTC|q~!_e1R+Tz#I*NDwBYe4}}Mj;b^;Kxgm zSz+R2SuS3KcBf?;_f#9>Y6y>_9Lg-VXMGh%j?inas?x{sR84zknkcobV zXp*oQctI9%Pqi3VgSTu+pwTZ;36n&4lmrYqSpXtbn&b#%f#8I)H?CIBNu-uH&Za>t z3vwJ#W?KbdC-nCMKn8h)N>F^p2vjffLc;25!Z%gLuN99dI>$!TxLT1*#ndShSl~K9 zfL)DN1jIN=hU|20@$W(Kh|Iwh-Kbsc!)uoIaxHqj4XxaY>PnG4Lu(R9SB9^!e+%RS zzD(Kvpu#0>j~S;#5av(gRH-!9%)t63J0cU932KXQ@RuZ-jiNHNmqA{tC%>XHWZ_e$ z-J2OQLzEl|VuKOy;(znYynzKEgd~neXaGx_w~<>=QoiD8c^(jbkY)2UYDNgI^%iL_ zUZcH;%Z{+zSA0ZUxR*T5(M~a@!_%A-kEhN)({Fe!RAL9kPn8$QY3HA5^jtL6n!%&j3MpaFqqXaa4tF~4Av-u54#rO{CiDUt>OZB0|_#71US7W?iY_f+9gK(lLQkLIK^8K6T zxFdeeM!AlwZzz{Kh5<4+CtmGI2ag+hq4Cx@d}bda9v303DqTA`P$dsUw& zbb{nZM!s{mnX-nhUiY;QRzH!j?#N|RiB|nT17C89K5Y`C1 zzYLK84=h9B=3LuGfl#0X0@mI#vvZNPziVVtU=^@ra>R4`Y0+em8p;i{zni{`A4lLz zKlT^l>Pb$fFdB`wsC%N^%C9Y! za!v_{z$$hXWTYz{$l2k6E&mggJ2Xjd@kMq$}?8W6Hf4L zjpQ}PGCd<3kqdQd?a7Co#1Woz3g3(;jyU1GlXJXj=qJdBjn|PN8I&9JgZq>u3(C_? z+*%0spKjvSR~hnjQx+=BFnxn@xXBL>6bz`NPJaC}Fmwaa_mn)=gadgeNrD*k(STlj z;4A7p3D?M~Ezxaw)fWE@zs6JY-0s9sjegLpc2!K@C}1Je%s2|H(LYE{o4u)G(&hhl z#NcDEq00jz>wx_Xb;yJptJ}Z?fG(JH;3%sD`?Gmz>%_iKxJ1XBMj zOH@TioTAr{$HMY4<|jKK zS(ZR~Ruc-Mo}E0hW?Hv`IFa9OKQ}JW;2OO%6|Q-rdOq>Z`WDL5F*rTRn-+kn#oQj2 zSCkv!jn(;s?lCep*6;z{s-y;P@D}EPpfTAdvr)8*ow*w&*PdE{@{&b6_oAj_wIMrq zyJ8J-iX%!%jhcG6#$9UOVO@ucArHXJP)5^tvP=Xr^`nD8+yUzr$WY2bN^yN#YA!yp zqbNhIY+#x47h+!maWH+?2xLzZWo5vIBg&TA_=4Qgw|IedA`YTwoAolR5l{{sOkr+z z)NkF7lnRHL5DmwP!(>SugjkU>g5suM9tWY%&+wSzIj~V0XBtn*K@t$Tk{B7FOUUPSAO__KW_h^epLC{%Ikdj!3hT@n$YG2LOP})HAw5;7>caty!J3R$( zm_RWa-s$5jmS)jsz+#3ms|II{v*EIlg&h+o;hmANgaM*{XDMH)4?-!WVg_(d zX$#LIFx!%V$vuTcJRBTc0PILY%1}CjO-PCC5p0y4pE4QSCM@bZvuY%ZQtdDdx$$uV z+b54AC=s5!P4C6I)H>9N854Oc%b3M2%;H_z!ZO5SWAHHBjg`wbX_|M!nB~mxl6-H4t2P+0p==xf#jI5VWpPg6@=iqY4j(S>@NoV=$~${N0%uO!VXgv!F72&K z%_Y(f3+w#_ThzY!SorS4$+uR^i=Je{#VasI%L9dLIpSHr<&cdoB_ZZwb%2C86i*PM zxeD41gie70UQu)Bq2UBYzO6)RB-p1%SP#V%mcUbT-?Je)Dr!XhVl zRf>R;8tY~hVV{uPkL>F7V-`*~@`U6%76@N(sp5z{AIUIMSZ|Oy!SC^R{SY`hh?A~~ zl*B1Qd%E{9h~D>DZ9t!Zg(TYgp|uNCAXTA2xiymw+i1@5vjNjWp8-TL8F(rmmp#rhND#tgN- zhT3?DF^kVhDvV(w2sejFnsd*_9x4V@UD2PJX8pbJR>#FW264*vX+DGZ?Bwm4nA6E4 zj5vZL4?5ZB+2mm;=beXEoOhmCao%}k#d+t675iPD7qQ>}x6a-04AoSpN)SdS7EI)s zC|R!)L5uML5j?yyAi`~$lf`YH6X7<}iEvtqDl>{uUM6vj>Wg^t&JD0?H^6G$0IPHZ ztj-OvDmTF0{Y)?X7-T$YW?aNN5W%B4|F`RLDkTB^FE`1qDu}8;cM^Lv&_T7TRc?UT za|6Vl8zA=F0I}x=h&?wz>;;LvpmhEgyyw(lES2NL0&3-P#)(BK>XE7*KJ`dbk3r_d z3$V0aT4bL^glhpXR8SpW%5e@a?Uu)FSdrqpJP6hd97MGFE}wiy&h6(tup)R5-KcmE zM?+_(knha!b$Fzzhfh7y)MJo(43^Ev1`PsnKk7-P#N=4NqW&vx0FdA$VEuK;5wNZp z7y(Kh7y*(R7y+mdfzk_E3s9A#;KP|e2@B5S*-r&24*A((1uKsB*}zJ8RL^qjfMpf2 zXWamM)(x;{-2i*m4X|h30NGCl&|I|cf2(+E=Pp-6|5kModN)Am-2kC?1BBiU5PCO2 z=o$Ebz|81Jg&bF;{NpkS(96;!JE8P5@S+HGB4{wF(SHk~lDIBUa$Tn4x;%&LP_DJ@ z1B}>D(d~wsH)_i_rb>%HoCpR4HO9kBq@RuLm|A97bC_D{JoJw+9EXQGb9akVe0@Ln zeQG{`hW^i{SY3F**vqY7u@gG$q4bTppIKE<5HK)rM=W(gj}~2zbXFAQx^`iYg&GKs z@+xIKB{z7E&bYzZ;L)OQab7EpD&-~*roxCAu+cLcdRPBO59c|n#M3J^);nki9bU&PC(N-+G+RJw=Di`n67QV@8 zCXT97^+Q}abi2~rHpE1veqSz)7IATpPn6V-fXNxOY$Sx5ye_x^X1l;reo6Cf2-Jo?Sx(8WqbglI2H|%g^mqr5CBv4P(!hI3`*$)%Ko` zN$QgQh!Hw}bKAUeAyb$z*8>V@6-ne;=21VG$CGG01gLBjh6kW9{FhL;P&#)TQGugu(S6(uw42Ng_q3d`*=KhA`2_ znj>N>KsjZO$FRFBT{WH*gMJIA;|YpNCmKc~ZMe8iTWBaUDzYIYXf8RYzmGyl5Pj36v=AeITwf@b`w?5|5tTY?Pl<=1@e}^govv!ml zKa?gLv_$U9uYLjzH+1gHFQ^FiHSuiT&fHVoyD^wX%rMlPKn|Lkw;+&1QZ5Soixzzt zEVcm6Yzj~-%7d%jqWIx7WGFJ8k{o`NHR237xC&K8u$c#0R+`SWm@xM7vQgtxvfd@K z-qIm`O{Jj;;E`c~?2AFJ<*u3c6M{ zjlw%mE(xJ&Qi^S{tFJ)yAgK7;DQH1a`U#@ZSmN)mJ{jv1#BRIwMP?qcPNUGA1%V>w zEvjJa?_%{RlxTOWPZjAhsrk=rq=MgU!o#lk+! zr2FOSmr)0%gFt3jZC6IX#^M!mLVr6I3)JKZ%2RTIl%-@*Fu^w|j*$o8Mda*}m!TGo zKu8?H3=*^=4MJ@}fRvFDkObz~Yzl*MG+xmb{~A@dAHu#%j*_|N&D;@p%#CfyC{Dz& ze6r%Dbjn*oL0Jn-Nmi^R@SyO4tVnAONg`NlcSI3tCnJhkl;xi%ZRMFI3S@wTbyCQx zI-FyJl|%R~xz+?@YAmxp*uXD1j>0cj*k4lQ7aBo0U;OqL435l`^yS!_sx)*CzQ{vD zc4@EMU%=9^^KL+)4g`O|7h?&pEI~K*j~64bj%g$f7_UGd5jvCg>Ac6pF~h`o-EWg& zjfBe33?r$9sAj10$(P=vMd_nW?Ow}ndX0hw21WyW3f7qD$y;l{z2y#_Et-J>^+d$T zJLS1rj=M!h_>>Q?l1EIDj7BYdXhP?}mT zu&?O-eeSp{{sh&a0}tbTOp%ga`nut8kFVs5yNUH*q2rN6!g>A;%I}Kcw%AT7)s|SiP!j zY0n}h!U5uVphQp`^$|#gS6sOewz#gFBuTjGe_B4s{3J} zoW{7$h&5Qn5y!ya`?;@J+WtRT+oXaxq-=#=^+RK`|VyYYf@aDe;fKJi;UB7A&+6DN|qE+bYF0nZt z=$DzVRIMU27daWv0su00HNqaJpB}CSs@RvMNpWA4ZGAEPv?mW5*o%2jr{HO0kn>r< zO1MdWLbDeA*Z#ec-ANlFHq{E(-T! z6Iz`l(#x^*An{lP`U`Xafq1rfjEQxg0Htrt?Iqcfq-cM7Nu9l8sr2hozJ_FjV zJfHlTIUz-P5aq7<5^BiYx}X1B^tssV9BH-_pEM^7w%v{D+}9KO>-fcNE4mEY@K{_~ zi3;^o@Vm-wYuH@Mptt^JjMGkeJOC_KWTUjrNhxAomXJR1|Q%y`6~T6d7YWE?O{q~+rzj1Bji(>6FQUeuj}>C z!O(GYLeOsXE6zz-HUQ`S@hMw!nu-n%->OID~laTfH-*+8Vmmy+U^w0 zG3j=WBgnBsNLYFBV%OOcmwQ!5wAzVfbJ$-jQFfQ!iU|R^z)3<{!Y$d_@)Dms52r1@ z8zmRC5-Jd$_6yLYJpAU;TJ&Lz4K6Z5F8Y8-76w!eK%|X6AdNoKeRxR=04 zK2ryz&**}`6RXx87{r??7wEd7Skke!@HxCIQnqMJ(F~p8=b#kuBB_vnXVgE_t00c< zfCG3osn_mN&d$Mtr}e4yCvbYBtnH{w(&Z6AwK5y^jKEl}_u#IzyHI9A$_`n*y`K0z zyI*L;i5p5l;<0ugbn1*`j|gy>wi(>M=+^{`u0WDV7pP4pG&YZf+xYoONwx_|bp*)b zzBcj14RiXJ3EMr&p+X8#^Y-)l9X<16ywj;dPn>^Rr;{q}?oONoaH9MBX93n6Gk}HQ zL0lsHFSnjevVMSJSMSNx7SaDPg-F90IKF(x8925cVY|`((HQ#p{Gy^4=fI)0mHH`* z8*)Z*JKB748;LJ*(M%2x4 zH@zjih%f-52M6H$d_15PNokdT28w@xRkf8!(P#Z9v~wrjO-R?Z3uVGjf&N}LAjvm= zN_GI)g*c6ryVqzw4oK(@XK85&m(J9OhU*C&E3dEfk8ps|wvcFb{U zxSAO+Vq5$eyyX0=wvEIOA2}bJ#KihxLV{q6{$^r= z>OeLOh}S0?7~~(a*L7lPO}2M{6p#bm+}C{lxu8RwPR26PH@yj3MuKr!CWWIGb0F1WmG+@dB}h<*z(C5*$u#NBJIPa1T|5EP89pH>dUC{43Ih z^?1Ku!Lafx2-RMmAjyMYL7qw}ALvam`w#3!L;A8qS-9g}`VzzmB2Jpb2iB7S5gR~x zP*Y-nfW8D@z|-+1$U6pHUxGP~2fu8SJ~&-pf~9EK0AGUTjxWK&WM6{$oQEX&5-d#i zC79#*60F4@UNeBgvhjsD&=|$5?NKmvPLG1w{Z8e$4{}^)Px2^uDR6K$kAe?NkAg)5 zJqk*n|NR~XPoi?NVZIu6!P^0OB@&CgyQ>~?>FatHd^%i(;p-_IU3 zVAs!Hp?FpLM;n7#OJS0iy~1QKdt;=RJ@l*evRCMO+53jJTzQrVn-i~-UiNq-)b_I1 zOZ~y|u{QwFbNJYMR+csbQnBlq0Y3IXqqdJdmrmaUVM{uN1=-nr>_w7&?9ul{j_YIZ zyM)X2vA39`iQ{8$0<@n2KK5WbYrEfTlAksLx3-Tx>DX5K*sH@Q@Ged`l;j|B5`iq92-Rvp3J}{V`(1TNcEYkCRer?PNi&$H{jXg3A<~T8ZT%m+f&L48R1 z^Rpd?R>At(_U9+PdL{ewL*Kgo{BU!voP$FrcK!KjQCi!%zUjtbfGRr8|6pOV|3N9( z=zlQe_#c#29-qcmpl; z`yW)eJl+3b4vwoTT+;ub@{hO=JwctN&${Wh%ty~t3#x-whqBEUdC*l|aB5x1NadGMN&c>7((#n^FqqTt zVQ`G~Rf%EOFIFtsFVnU| z4auDv?C%KKzi07I_*K-I)W6X?P%}($=K-nCT22_ZTV^zo4T4sLK#Y39q~h$%1vh+Oxc7a?j}vt4>@ZrNpdDh|BpcQ5ZnEuJ%bb< z&@&!=68`_?880!|kNs%&q^n;jP{^ylDpi+O6&cFGAGumCH_BP4(jU}iQ_8t?kyHq2 z{h82q>-b@QTOsE@b~V;yuu`sxlX2;}1<3^}fWT?|V`+_jMPOa;q=_}ghng;5>#o$%>z z^9)Ln@th}HYTX0sTTqeDx+diAqMj}5DrLRiO(+ZYCK+rSj{}7l1nB>@v?y?)7QKg^ zeR`d|do7awfvgKgAGViG2t(X!#hL-zIa)d)sinLwoD?Qt&Rg@sH?~@{HzuDOs>_&?O$2ro&7ZyxizK?WnE~Y-jR|XM|2)~G<};P z{b+Vg1y3dOf$`PXc_k5$i>@w`%g^xa59Afe&Ssii5xc*yk!v^&GKyC zmbzj?t*3K2O5M$-)}!J_PD$^Le?lX)wL^G28;ow%0*o+t8JJo#gxf(swV$IbRNu_0 zt?#U!TaUmEYQwLTztyi&RcdKKma}+n{g$0*f=ndMFV6Jb`ZYUIfhq}2Vo9fYZXISP zTA@n9@0p%kk3OzIqWdp^gkQ30zvtGi_V;>x86Z1sL7}dq3)@%G9X7{Gp0iikPf+H` zQ|p*o#NX!$F1?cNil9xguH~QE6tlvYpbKiC%_HDt3)_gghswIl+rLLnx)TD#* zBkZ`s3vpBzoG(WfY_T3o1$E*h#1t-nP=2?0mqV4(XOOojoq%vqf)|%9;FgHIMWVEO zPm^uOz_Mx}Oi&MIJ>~E$y$M;urtkOtR4c|pUqo!Fmx9JFFk^`J3g20Pbij!#CBO!z z?RO?%=5nS-(eH2YW=_OdkFk_f3SdO4Jc#C!5@ao?2mWE;-VmSiJHNae#wQHWLk%Jj zDUFBHancV5f;RWjB=aF?dS`V~OFdW5xC|^qBT(t67Q+*^A*_{Xyj0mN-f1dzIExpO zO8w31+ z|EOl8B+wU%ZAJq4EwC@@unVoz`%Ad{v=V-0mvG-&^jzR2_0|8Q(^AbsD$4AV9Qbm^ zPT|F^dWWUAmH|=;*P7GPk3)KyIK@tUL~kuUSK==^iGz0HJ$mbH=Suv+YP)2=o%pEU zI`UkJH#mv2?Zo@^)?3e&_z{^H4&UptoFuKMHLDIufF}Qj)8ea`bzB~nm!dS0u+gqX z{RoH;G1Yz_Obh~u(PE2~`m+uAqH`pwV4~OTM30;!(N#?J-*%#3o+D8T z6Y;J|o1f~%da>(3R8B4rz;ix0HjIhaPr(nE{c`6NeV0$k1OIl9Gd9(j=?8;l8iUcZ zU&Z``HjUWaX)Tw`m5HUNR52TCn=>w3iMIDS*Kz2H{JM9TX~tGuR=Bs>xZNMyF=zii z=xPU`kG_S|$^c+8-Y4(bvUlD73E6wM9C-V!jstr?*-%z@A!9NRSZ{S8G$VXq5C3%y zQcr-8!7`9va!;pfyj%*PQRR7XmA>*#z+(LXKi+nIZeY-TnFGsMiF?fZtO@ur#*pzd z796|#z}~&}pul3l=5k&3$RwktlsitmsC*``bF7KKF# z;VZ!xcdmwek05uq8XndA|BUq#_WzYm@2?vzd;jak7(edz(7fwyGLWc-gCyKX#qrOR z7%4|HG@~%Vu-f@>t5>@kM9GbD;7*IxzJ=q1+-7OhhEe{lz$I3t7-C3NbMb zV~v2SN5%o8 z_Y`;5rD1fN5f^)$7Eso4u)D%3YwT$mUT22=U0bI#7wqfLhAO~pbwP7fzA-i*9@tXW zV;^um*SvfHI^tii+SK^oOXwwV`s;i=9O6AGMv7|GMY7`3W>Kp^-42%?AGVkwX=*FYjDl=mSz;chxvBQ2uj{dN(yrV5Rqk! z3+N{XiDv!%;Ql;F;Sk-2gOwx_XlF1%yJaP3ACs1S~k&RS^X5VtiLw3y~C3`=+%cuelrAhHRizPaU%=Vf81M?*$O-n0hB zT7N{twU=8_@#M1pcFPm*2lk-)D&t3az^P;guQ3f%&bl&V5V-J05dBobiYhTgN)BE% zQnJOp#%MD46f{gm|5`=g);LG1r8o+MS@hZpN;phUR&j{<=r>v{41}_O4~z*~830S) zlwY@3*45rm?y|s}Wr20eyY@pSFxj(Arp4~X2-fu*i0?)y^M7xrsJ;Y3{Aiu*6ts>2 zuu}qO>6G1|p}jAK=Aju=Kv#Tn#Ega-@J6KXRok=})@I_B-ywTu0=e~nRX?63dmXaZ zhw4RKuKr9FZStHmB}0C6zQjyaEX5p8x;h`CV;a3pJD93 zu-E^Ok#YRAW~Q;j!8{W|R7r9q=SC8w7K5vDvVGNoQQ6k2f1ss*GsCXNtn}}s4H55d z6T7;ppng8DpM^$j61$u$b<-~AYGWPfW7=tm`y;mv_F>25TD%+>9khOiCowshn6yWk zK&bQ08zgJAtMyT^syn_iyVOEpU%zae@ zyGO`E>vCA%clgN`C&>MM`ALf%1KsZJ+}mNLpu)Y!tdn3iES(XlEj2GKHVqW_GUN-ab|3Bj49r~#kUK9Xh?^kZBpW0!l1}cr z${e+Q!OdRnAL-2gPy)vaC2&cwLFSZyUfIwR3|=gOm3LWO8_s^8tF5P(<-!Gc!4Co6mWn?l z14SOcaUh&CRl#S#srH9>9p*&n){{X&yl$-$s;C@&^W=zlCFY*?=vsQ6l zkFvNH|MRlJ1y**|t*&;f+up5BWVONWwMk9wN)kvV=qf?E8Z5VeZc3H5sV16gl)xsE zhldAqEv=wXxxMyYT5Y8*wfI&Nf`&I0e9aO9zMD0^;R_%N{Jv-A+08B_0)6{<{}}g~ zXP$XEGjq)sqRs!64!uZX0~~;lqr78NJsmx zpM>L;NGup$2&hh;vRvWdnQu4*1E)}374Sv-t_M*>zlM8@mB2^XhmeQplzfY=t?ZOD zrvzlx_SoBX35JaS(rQZ|;l~^-Q7i-4p+L{qW-wz^@`FNgAw2vbE zv9;BmZQ^q1h3Wzbr$H3juc0}MV6Mh|vpwbkpc6iR-~Zyzw;r=xci$A)x$qkA6<2nu z^#UEVZB5mbRtHTtjOnqse+IdgqN`C@&5@|2H}Z15=)Lb2@2P(c>nnGyxSP+W)z_C{ zZFJxA9fBN#Sa-R3f{;!U9EYtwVZau~Uu(de{eT4V-%W#RmHyiQ%eL5_VeV$xi*k(t zf!8&Evx#v1AJt)2G+Hr(-cnD`nN1Yf-9gV4NiSv&yu0}eKw+LB<3V;g+S@~~o-Mt4 zw(iwJdb5yTb@DuWQ0@nieK)^}wMkadmH#8;I?F8OKy5G33m@qF!~eimw$M^Y29_O8 zuaI!YR3PkH$~;5L{I!%xJ2GJ$B#Y+6lJC8K^8MJ(H&|yY#QS1p4E;gQMbWhs8ddgKEum~F^qGUs@wyP%c_-lUnv4&&|jf7KOhBP{>AVv?+mv*jQoeQ+Oa`S7o+Haxt37{oZE14~t*eEcauSK9g&! znWOt&`UL}4>Jvhgy*Q*XC;E-9_wVk)SWPwK9r7?OsRrSufProzqVG47PgO2i1!v7a zNty=&1j+v^^JfAN8c8b4^(u>sCCl$s7I_=U(h^qS){QhilSV##q@Kb@f zP#2?9{?N2k$`>8xpCq$DK9HjgD?m!uUT(`*LXtvD?MrR7{h;zas{CZf$%Yu&%6=eG z&yN*Tl>o(U*TG}C&8-;&hC`Lq{^wh>B90UtgX$KC!JjpE!jsx zz}D0iDddsW6%ieysjDfU+=?MIg;Jqal7fF-O%LlpmRajDqh7NjYEG#t-s+zJGveI~ zVt{1MaGDLS;*Z^yTogF`o%);12LH$gUwyr~Y8|OW`7~E;l2A!-BrkQ<<|@HubNNDv zY$!Blgw2Lpb4H!fkZ;TgnX6=;F_+66W2_SJjO7BF+2Av0_zRvqxz|`F02<2$xMFY6 zed`WByRGk2f16n`#hg+tAl}B;SZ_k-wh5JvYKeHO{MK zoMUU9icHlc#fawrw~B1DWtp;I0Q1YJF}t{>TTl1Y zX?{V{Ag+I*|Fz;$N8KsKrOvv~6_>i|JjJCR_}UfuXagIIbL(G(kqYPPJAW~Z^f9B0 zs{h2Lz-FnaPJN>#R+eT?F@-s^P8tp#z;0Q0vN=q?e@(ulvr0NV#T#fv*Z2y`gJa8} zWp&N%%eRexL(QU32%OLZ75UO8kT6Bnrru^S+ubOv^=3;rN9H_LS{Dy@6YIfS7C?4^g+ZxN;@D24> z*&O1#862X@Y*QSfRdI-Dp-~Yw+Z2arRU9IkZ&ZZLHpL-Y6^Ce39HLcmh^Wu3@E2@7 zd8g5)I7F*(2=PDDJmS#teo!W=)OfETwR^!6NJ6Rcwl?!7JVNFqoBmrg$J$KHp>xEK z{+>9{6`7)FDN@a2mcoca360Pg5hOf-5BDqRr({5Xl?}bjDM{!TNO*`Dgt>W{eEwTz zkb`ifD>6;DVS1_!Ghu|uHcTTtfG?Nu=C;Dph9tf$cw5FOZ5DAi%ef_ge>~}m%+P?& z6hISQaBq04d%+FRT?!u-G|JoH0*t$vO`-?>CL!jazEdMEH{Q5!t)XZ=>SytuxQy2} za8(9NO9+^qg=Pd-&mcu|v`>}rQ1E7}kHY5uN}=l@c)KD|-Gx=Dv2J2n)qU$Cel_&9 zgc1fn(zmzD4)5ZA_bqBZoXkrb655=rB+Zw3llfHMQM403VbFPRbdrAV4ZKK8qq2sm zXYQ6VNhNo$sxqFDw{m{$GM-UoChI+qfYkdXi5tQ%N5Qk26qKWN$VPjoHqI#` z7n=Bq$YWtpu~=DKW4V=A;eMXl+}x>7A^q#sv!Ke9`i;o>%aLhypYkiIQ!k> z_L?_V@>Uk>@|l$%yT)uGLp34in2wQz>i&Zjh_drJzS5Xbi3vuw=!T5CjZvdn*i8V_$2=G)c0(FrK>kDw?4{A)6=t&lAY z3ieV5_GB+h%FFlyXdW81M1riN5tON!p!h6Ec?89vbs#DikV`UiIGX0^<|Lmv!Ea1* z8WUW`8fBc#o#Z)Tg4dYD?JR!mQ&Kb9XRFA+>U(yn=eP;pq@yPNj)idsALThyo)%7s z#(V{qhPPSBgrejlHhXhY$S5r`CY6|_h32HNQ5rEOm6Z%zdu!KV0T{$ z>ywFNHGQxme7(?(jP>j{=SzW0bWQiFp=7vaDx}de7h=ha((o!?+a-2>aIM6O^Sq4S z%AgDjJt)J%a8IKbrwbCuI)ZIsXE}uQf&^@N$v=UhIiZr=m9Y*V4|e%%bd7n=tlS79 z4Bx5Hpz=u3Ac}NWWelLf6wshL6AeI?X{4GC3JE%ZLV^lrX@%Guly+~UfktRR_0Yv7U_k>R2NERFV5LfCo`+k~QJ_Ig3K928jRv#V$`~k>MAjx6co95kl&8hw zjq$K1GzD<8IL!X_co1f(D&b1u!F5SIh`lM-3q!CSU<%|gJoRnByurFLclbhTvMGS>^B>rp{b)fa zgW~Uh1m9DCcDIpZ+j;iR7lp#S-e+E<%sbWuCq}EgS21L0ZrZ>yaMvwLO1^lgM$mEU z@`N}y>yvLDl44j-i*ccC;&;4=OsDU*O|ErU)4rLY@U>W*+zY<0aKd3u@|$0q=Q^>~ zH7tTx?pTBO3BGR|6MQY}XT54p#J1#a`K7=DyIJCHexIOGDmSH78Kr&$xA;<&Gn575 z1vOiq`UwZWal=)>yfH{g5|=y4nJX)5A@Ix3ZqgT=++aGq&nWei;BNu2v4)<-YRwRaOjTOwUh>|QN|u@VC}{Uxsx0M8x>A5Po%-r88V)G|889Vvr8R#cl6(> z&Jd}hg;@#F+-P#*C1z1++n{yaMjedLSw^mTwIlmcnp73z7Ex7$@s1R3yU!@+<0(c? zqJ!eJ0ctcAh>wT(g?QAOs3*48m3U~L+RwoS0Cnu;ouSURB)wO&~M6 zddr=?ON(UWJn=jqmBrh;=S`#C@uebpch9R;;cCM1InyOPXNLNnsp3V$h|gIG2QZt| z++TjT-dFWJ zA~Jl(%Q-qB&IQKif^MTleOIU!ODnRK_#@c6{>M z_|*0>J@FUfODl;n9+8zPbMg|?afcPoGAAx_|Jggnn7p~Cd^2muMvGWg`<9)QmldD- zO1%6PbK=5`1o5RlNib_5fy!Y{W{+S=&f?uS-D^zVWR$Oq=eYz^*t5YNjd+V>ayP$< zD#SjD4*TOvdIQIZ-mUTV@%8-<<@+#k{w~KDmaJy$v@J5C-Fbe&gsIDW%bP%6CxF^; zj6X3it9#<|-l^Ta<=qqeKa%gnJVl|%W7 z$c`0vuMJ%PF|3LA=k&&Vek)_UeSN%d`-}W4IC{0!RCWcM0%@Sbv2AXB`2tvT^- zCW-~yLCfBjB7lgm>3+`!pnO?;>L%Q*|0D!pOkQVBUTIEU(O<@Hl(*uWq`r+?>z8eR zL%;zB0i)jyKbP$@@r}gNr{|wL@$R}Cl5hRaWGLRz?V1;Nm^^pt>bf`DjVj-i^sJE1 zy3ME`7y#KqBfET-rU1BfYgh&`0|=?J{^z}0d$;yG~_WI&+c$cH+=R>GB|ZE zy5#*N5_EUQfACDt)Xni9JZDbcTs(Q%O}{iJFB>Rw)^GJ*CD3R%xTOEH{^J9LwDp~4 zi%@@Y`8xN4pP_K|#?2OC1G(kv5>t3@Gk+$$qj>VBo4;?i2>Zw_-;{9ig)vMLim=wi zQ(EUzl-VMDL&%On^4f&gyHxRsb;k>zSgz@RNU z^$!ys0xtH&+k4;8m~%{TygyIjXz|l^!&UBA$r5k3?zrDU*0Q+A99L(BBUX5Y72ahz zhKU5iT2`1s=OH|H4d8->OxF@5w~+e7jpE#fco-qJJc zalMP?iTL@A@fYK>rGY4AK04YLuMYa-NR8ba=x{}7+dAmL#^8xH2xKP;xm54CpcV^-o@(iidBswV+MIxSI0oXASQ z;Dx7SlE^fU;7lHUOFem6wmvE%hP_3yiJyxh%Zr! zSe%_mM0T$y*D?aVY^&g5Ug$xW9ySQb&7YiwN(yCyQV6AqT&52#8jr6DIQ z-1q?xFhSXTw2fxRz3NRWknQxDMQwjC{y6(h#Jb@-v#g5X!vsJ6;_wK;c7or(%q#n< z))E}CIxj+Qv2Mg4C$L!pf+^h+5Da^P01Q+%zw}9PNl=tNVhRcF(Lq50#buga2~)WInPWi^i2X#^t@ToSC%4_4VLFto-@dvw>T^+-o7oioZjudQ+~JUQ~RiD83o&9mDGXC z-OazE9)v8}Ad{BBJi(kNz~Ui(!5GA3(Mk8av^^c>>T$ zFt^^5_!eO`uOahv*R%~j=gnR#TuWJSNUNx|f!?u+_iZ8GgxHUnE8+)nqK>2TQ3C&0ly4E_-}DcO06zv#J&SvxVEAaI%&mgQa;(Nn?2HoJp!CCxo66@Xj&AF|Dg>8}B-Lf(* zlcJ5xOpE#4)}0qY5=?wkWE(rY8L*P!C28RqY2o~|@LOWvrrH5Es$6cxTh?q-jxP4` zSwBfru7xI|H#itWcK>`CNa!bRClyY?ytFXbB!MTO0pSSd`7$R>Ge`E!Rzyhundb*U zv}XBuagg+_5_+Hv1i_FemOgW~kgd(OENxzdIA!KSP?%=3JqD zYN>5$myxgYVxSc!w0L(Tarj<}>k|zXR%Gvm|0LpW{s=1W(YrIZ>VrlZ%thn_ba@CW zZ+lO%wDj0^5(|`>iK((lBD3huX%OhE923whuK7~a_kd4okFUolQHwpIwmZ??&g_s` zUuU`;*1SQuvzFk{6ruwfgu8j8v}a@YpDU$Y5s5d5F1k^ACBA_wWDMe{Ch&A;X3JzXW8>?E zMhCIQ08dmkz7VJ)eeMP*m5~FYs6fX55iP0?FrtO@W>2$PR!B0U^ifDEweIE|fh!(g zZ|v(oUdi1(A|h)UJidObKBX`dY!P15PeqWkcY$SEcl)+FHC?6GbZ|e&ZcPqJkV!Z_ z+1wexVPnBI=OMjUDY-ti_s$-o?_?b5zrw!wb-LGN41u-~&Xr=@pWa)x0fc)a6cqFn zYCZfq4!>@ZIW)6F>Mx)jLT!*>TETWHb$+IpW@Yo&_^PnOC8(%u3hbIEYm(R7C9!}a ziv-2pb@v=ps9zIvV;+bKb1;@8Al+;Cu}s(;V9^xdDU)SsO!ik*%N_z{i>Cv2iC1UW<+!gO5H$aI;(G^X zcY2T|Q>!w2u5sAw&HDbA6U-X|=2b!S4>FUQ^JK;}=cuU?#RvVec>*y#97M3~9-m02 zC{T<_QSVRX4H8cpBe(~TguUIYH>sUGmu*!zA&1_SKpi_3;;1*o;vxzxVk&6wes%jR z;BI5^9NAiQj^0`%n{dKCRK)WfmN$yx9fm7Nd9k&QWc_?9BuQ$&PVt(?GvU9;kAtS* zh#6yZ@do#;a%O*gLw_DP9^Vk%>PRnBw<$F{)km37kDV?&KvBD=uQ?k^A7mR;Iw0th zki2Kszr=1VJhuJ|@w{mipiUd>KTYNkSuCnljEu8%y^lgXvb3qXj1wE~lwLJY*fmEH zUfnYYAPN!A`&ch^C}Q&liO%mk^~aD1fr0XR?6e*!nzWqKs6^SfYmu;IS%iqh zWZ^sU4aT~}?hJWLhW}o*=Nd)kUf$$iI&QJn)+BNq3T^XUIDsQdNiy2tqjIk#=P7l| z)8#v$0CxuU)3J=FU~qZcu0%o#(nu<ZJS75734f>$I2q%1!7%&8LTY^jf^UFF~8x}^`1 zD7#t~@&3uLcRtnCvV_pY??wT4St{=CRNV4Z+`Xx|6{)zDc3gby3}jO!{fgYy{M|g5 z>>RO(3|MrNYRg*SG0TOiH2`H+;_JM_YQ$n8@9TpSt3gME3^e(X%8tL%+#q)cu(}C|6ijR@Tf?f(-}k>NN{UIpw~9K zH7na2Cas;@KSE|+Dv5BhXqb&Zj+42@-7IQ-yh$(%95Sty(rxq88`5*;GCBb{ph2&! zZr>m)jF}Y}ow3ebcdPhhc6^+}6xy(O_s62r*CA<|Q_D)zqFP7a~zeVr4}lf>spdUa=oB>KY)u%X4nxEM=a{F*N^GBDL z0q6qhBo0wLalF|gl^JVBPcAFo>t66B;*ISo;MwSK$8O+azi6G~v8=38FmAad!HG~3 z-9Q%@Bw8woC>=DG&q4|Lbj7)0ofP@!Q zLu}6|&Nri*PbL0oUxI?=m*r|_27&>&>32sR)E3-j0dHEL`F ze%Pmw)3gLfz}Y5J$Uj*6B6+OTo}N!6e#cu6i%OX+j8!hG5bH$WEUBh!ADy_*Ydxe{ z*gja;K3JGoE8MLMRS}-dBDSyB95AA@GZgz=<~Y53KgqG?r*o{_ao)w*&D*5C$1U8} z%;SItJN8(G;9{|Ut1B{3HLlEO5zKl>bLM?;=6%AM4e>j%X-@XW#MkQ=G~cPbVy2L$ zKI;-7K^6Q+=^J$J>lKXJB+-PUqE%Lj#SFHdI-^vaATL5M@paHEc2 zL9z#g(rJ_wCbv&6RBJ69blt30aX^80`I687@w^$p)x$Z8yb$l8jq(p8>Jqg&q=}D= zF21M|HuKqP5#fc{XLtdP_Q+#p@Dm=|ucqf-RpK_i(qfkdy_ikHKjccZ)41M!%N~kI zoAIfFZ;at=EQV+;#o|jK*qgn#*Dez0p*YjmmX~1r{_Ul@D`H(0#hs1M z7>{x0nv;sSTy*6y>U)1e!@pYLo{raYjoo&Ers5}NRZ)JgV>`1VW$oOd%8I>HG2tgK zB%yFG_$^FQrv};&fCU7R-r#K^Z(z+j9@+2F&70(1FO_kcUlxhljQHsJDgiXVTt3^m zQ0U~XF+U&OP6i5B;RR<&RRbh!FTE$lv|lmNVgBqcSSOfDme`tn{BtF9b{v(m!RYPP zuG)0?GGgQH*t%dF1Q9Kip>IiWo4j=yPxqgQJw}eP#XqQfe0i+1;@p|RhPtZ{5<=Q# zO@rZ-La>F3oo*+`TfEhkYM8Ao-0NRc8q=Ltaqbe;#qJilT$g^69+veq>h9!&k?i)gkfnQp*MDZ+pMCc{q zV8!v9?xnnV{~xgbAx|Gnpq6W-(Va=1{Vr90i~kfAfnz40|s z?b_D;Q3?SUs(!kkep;xSnrtzvu6A=VPub?Ld+iCZ5D>K_Bq9Q%CJR#2`n*?a(#RyO z9wpah#wk||C0xCENRfSyPh~#U;Ae@1!T;0T%@@&{RHK@|#@qIt-Cy=I;BSd|Pz|sS=ZrW2A;(XO=KWO1RW6VO?77wzzsD03;rucCma){wC7&Z%w}W z?HmD0wR3!1a;yWfl4*XO3D;7A>y>_G`E;0V&E&MaPj$SMo7*OQSWM{37B5EhHZjkO zja;uKhv;K;^oTs>N=7(Z6A$wwFmS#EZnZ7(jkdwl-F!JXj6vOvM&To$)vQnzfAmIn zJ@hS%GZOBe^MhM|5&#)wYKENTAv!EEZ3MxcCLTFAe-1(|qY%+FZ=+oCZGd{mmwY+P zp@0#X+|BO@d>S&*Q2vF*2K)8gxgxB%tq@UGsJ-LW+}!(Aqo)SU`XGs<5j_#7Id@Nx zOt*i+Z$bCT@6k?~mT09+-*8-c%Y?T(!2#|1Y+zXPf{SJtJ3SIm;PXo(pq zvSf#F)9_Ar^VP)ljQ1YF;BH^PO<#hCYK7=l+ZRM}5Dm_<1w-Nzj{t~y*9TM>`}a(dS6Gg&-ljs5Y-`Qu zw|9~HwPOM*Mt+rJL{oYS6}w^bRu^6fF}$KXw(nJzoHQ~+rdTA&68AGJv7eoDmW|2z z#$-W$5Yw1kXx^^6esVaTC)Tm}WQTdXTC1BJF>hDPcazJy%DoK9p-p7fWLjVC>+qV& zV58;uHZ9rKs-R-gP`5^{*rx&XZFlp_4j5^95e4#a$s=VoJUr4hlN=PZkxt%>a?WZ? znG)NjxIuBV+{qA$OuHC5U&3=tyMR5rLo2IKqO3lt%!pmUmpPi5RFq~$RAapRyQ%|f zjj|`v#h>)*QrA$*j+sxQk3XqQieQuwhCux3#VsEw4&D4ou_+4F@J0bz3eRqSQri`u z)ON*Nm0fY}a>jYv>J|KU+kSDF7v~3?$Ys320dHS>R>{_Dc~3Eyl#jw0N}Wl*wg3Zj zZ@!@M9yQ9}ed>_RjB$#guz{Hz!q{>+zwLUDu)1GTQPTf9PAi1@#v?N@THh+x^-TU6 zU%&0vWrxOM?#N8nd%NUi_E>W;s`uV5`47goxK@Kw4b~8=yF}bA)im0=-A6XSYXUqZ z4B22}B#b@CPSg4pZ9TZvOkXl*ZJp)aHdng3_b&Mzu;OFhN2HtPZh0YxQr$`B-FyLV zU*<*LRZma+u4i|`#=wrf!#X}XtzbiPdet<@gB|;Zad9~th#m!5g!@zOa>=0OY|6S<-k5f@L_dv@t?hgB7A`#KK{-i8SgwNjeIYQ1=k*HV)Bok_b$=yCr=ZV^-B>%F$& zuTYAVL%I9hlhpEVZK54xFT8NBbZ}xCFKz5?Pk6%cit03+s>e_mdH}N~2UW5swylBX-P4?;F?8?>%IIPy4aPM?gj;;7ker8ZRh+ zyMWdB(4JLNJaxw%o$+JhWu1=rcq#G4?k7^|*LJV%elqp8VS6VERY2SXQ*oQNzsv&P zrqp|9cV$Z!+l1IpH3z`_o#?_6vnIY)Vmjj0)T0t@@8=UyxE97w6SyQD3D)a$-*H4@ z?>LLs!35Do9qtg9vS~UmK8e4y4ed& z%0}t~m&!FP)3MP{Gsi{jOb1?Qvo6#r)cNePaNvbh{W`USf%F?L@+P^mLoPe^KDfVeb3oa$^Fvkp^Rx2ET#@_5Qy#1ao;LVzg>=C1=;!n7a_}a z>9aDsiSL19(!3BO79w1o471B`ipQw+8Z&%Gtsi?@t}(+87}E{THGqE^rLq@&x&bHo z*&N|dxdw+EaH$*-&B=(cT+X&9yY5^_$xH1*QksfU)CD0xF15ZPVIY)8-~HFUbpXSV z;9oWol=-PeP^6es6}8G!0Jv5a5tJgDh>G3l&zUujE(s_G2|p9=2>3I3%9iCB0te4( zo(`T<3<}v!HygQKS$(KCe%{$~16qK`?-{YhG-lC+eh^1NDQ zNnB`a-<#5sC1LZCMD3yi{)2Ev;Yu}qn8cM2DhF`o1>%noS3bN+aHXqM%xRn~Df&xl zaKGPl5Uxx~M*LN{GOsR$E8?m3*Wk){RfNKoRsdDFav?+GRjwG&-QvZGZ}FbOTc$uY z@)7~AWZ=wi_&7Aq{Q6UHrfI^UICI>OhsK$SWU+B(jUWdIaFr@0g)>jr4&*)${UN@4@CD`0$;Fu}_1 ziJtDfLI)FCV{n{!8IIFlhGlV%YwZzEIWssec9U#DS)ss|rDwIb=3H2)d(NGLhvjm( zK@m3oh&~_n+qfT$dCIDUVODZDL^WrvJZ-GW)qrey$-sX6zg$ZV=MEZ{gfc>3VWdO<2O;*WnV3r)rzp4^)TwE^sfnf@!P* zKFEU^L{_7#m|jYNV+zk{R9TIcOFD%8V+&T23{6l+)R^8_jp3yis$w|=&W~^g{Tt*6 z)3QR$IFc*3-o;zKYNvaFECo_cAqSV+jV(3n7JpLQ%`waF``ZCmCeRR1Q4Hl?MH#$C z-lY^-2xrg~58sWPM|6PX`J*LCxogV{M8Kbyssy)GNb{Gnao@G&Me1y{!k0>a0ZDQ9 z&6k-~OQfN}#Eo!6k+rqSsDS_#?bmy2d^Wn&d#4pPYXKKU7196vpfu(a@>(%fb0m2@II4gz0~-qPRV)Bbo@e6{A4^{7=j${(3-F` z<$J_Xb%_C1Tp?kqO*^~>h>8F-B5g^0M@%m4cfQFBHmh}b!3x9%tX~V{1{hEQmj;Rp zn7FRjnEvrKhJOyv^J|RiIXRKyckACs?5DTd%*j64P~0+4>_X&Gc*ZF|m@^fYxEIV6 zl(diR;iv~Bq9Ap~|XA#(0nE0ICM~%Tiu6sedP48Ly7uZVPcEc#eiKn$53g7 zY6=s-vbD3;GzrOO3DspvISUBxQg#MfGZu-f?5r!u+TUqvML6LGJ#CCEOpGUqbUR31 zl#rF$q(8hqndVg3pT$8_P}YG`Id<78!4FhWO-~6GR4imWL3{cwo%t5$>nM^fA_#vE z#Nr{ykeymW-S*ST8_^f<;_NYYghT*(l5s3CA+6CF>YE0ZVMG}17Um0 z@8+xu3W>K*!aN#V>tMeJGu-y|X8jUYhx$6JF6ppgQQ3&gM9+5*7*!iVSYUz1o3U9qj8~E+}a0|L|iv(Hp7n`gquji)a zJ-?Ma`uvZc-%1WPl(l!irxSFq>pn9g^Ke?lYMW1iu9e+pcCG1k_Ps-G@w{r)yi`HQ zPUGFKcaTcsed=<{c%SsFvDtm!n$!v;TWfUlJ5V6k*x`+1d;531AieNGr2g?XoxC5H*jJ^?7Mz5 z<1)xiJBU;PM5@z;poK5XT{IkuWlhdz7?|;)znKCI=Z8&lN`cBE*|!`EJ`v`%4x^8R zR@t~5tMd5$N&w)NTL?GdzHeOxEN^U$5xxMLkIE@wNI&lTo;4lV*cgl8=_#Qzy<4UyPK&)LciLKvKWE&7DpCBAt>qi$KxF<+N zoCyK*T2V5CyWb|6NI1+ZPGdvI-qUz-^*zWWUGSK3EhlEl1wo9N9+#OguqHagjCf&; z0hp_LyF`oyLBwtKHi1*6{Co}@>tv^C*m#x~aVr!7G-6&6fEN|P2by1z**95WkdI{) zA(lm95+Wm}K05d)HcVCiB_fh}nYPv2w?$y9Bx7?HgT#J7B#C^2!i~d=$rmMc6`kxw zro{|PTlf9vUM+fGyaq8&%*drRG`i{1AS>kKuH=+;VHB41wN6`jLW^Gi@5I_>&GFq#272~j3Q&KfXx=4 znW?>xb@Umhmh7V>>Q{YMasxAQHB^(n; z@9yq@miz1yVPfR|yBlK<3w}U!c#3*>&n)%zTj#nMok6WQ%7xY^p4f;N-Mw z74DYTfzp~W45{8_Bp9d=gBa-8JF>=z?h#ZNO_X{)jyE44J^JHbUOjyD@k(i^CMOY- zZ+TD9-#?MJg01p(X3$?Fi{c6kPSl_G%Ui*F#&aF}sj3hr$kKub&gYaLzlX(6uhZQu zS7Mumbg4t?Fuz4tyUdDDhVLByk$ZJ?@9-_|mUAFI!h3MSnT?06!txhAC}7m3DHi0pqyAa_Qdv$SM&@z*Vp}o6g83Q8tKAjHBQUVuHZzcdtIl?p{WJ zm{npJCBcEw3H_SkqVEf>&}}>%R^xB8tdhM}h`%?;UT8J$%c9Vb84Bue)G2>J6t+s9 z;!)V~dTzn|s)*Bu~E$%C{zTre}}D`*rJvm7<@tTn~_-P%x_G29+Vt@}9KirGgFFoa4*Ibbk>Y5&B|2 ziK2H_fvR%eXO-o+pE)H8k$cBHwR=0Gna|wnxY&41Xz#JvkG*i<7-+BTV#q5Z#Mfz+ zbf*#D6szPcfc9Dbb|JpbB=I>KEdMYn@f*7fx=7$q#OIQdJfyY4y{dhWf&Cq?IkF$K zN>*6@MV5aGze0MQtLCd+@n-#qHM%?ldIrQRc3I7B<~SGv8qeKg@iWFXdq`Zf9!avEq>V&NuXYhfE>!od|2pm|93W z+(l2ur8zU- zDTp)XyHwW<%y&LL-}yivL_U!L2j)9~KGONl2g&726VPu;eN|ImKu>)PT@_isnfxg4_9Ph8lOVZ0hvW_xyo)%u->b7T!Om+QrfXJn zZ9vV3nCI865(19cuXfrzXD*V{&xyNv3c2{r>Zk@s9J<49P6%DHk#u z2b$`sa&g*JY3qVT6jCWJOI%$NTch+r1XQk|7{NU0WzKYog!tF%gGV@Dg5pOzUmlG< zh?Mzv&=RZ{+^c2Vp_0O9#eOe!c0HHHw6m+llU|2$*-ZHyGt9(&3zDq>od)f+P z%t#qLF1NxbGqg_V2F;B#_jilAWw+%;?>vqP#$`NS@GR8tDUi*e^l8+C9&h;{7jmXB z|D7m`*%W$*<(g-?F5tK0#k_2}d&pt=Z?jx?S}wGB^;e>`#2uFZLCb%KsFM^|X!)O# z8I~Ba%J}aPeUWmnw8FQg>3X)_taQD!xev8V&wbA(bv@C`3qDf1-g{Q~JJy`ahbV828Aa23s;=6-`Y9oK(e>WYf7w`kWM$SbGvBiV znqDCLSu6CL0@3!#u8&mxnaVsa4^)Dp_f%b(s^lqA^`1|udRIvmOnpwPp#Woum_p#Ue!>DVGv8Bn7bPLq-NL;08~OA1W3~`;hx!9Qfs&RD*cY&8 zxPGFWWUF@1W6dgfj`E#K5{HpUWe)g|t79*3QF#^XkA4#)xK}Y5`Bo@z1@Gxk5lL9U zvWa|&^5PmzLHczXuTBx}8uJC`lBc6*kL-BbGj>}Sf7q{ z>R2DKI08gZ(Xk_R>?y>eT}PRfq+FMd^%Faa*i&`vC>?t$u>oR1bV(b~u`KCVe2Lhz zb?ldP?AgR3#YDq8HmGC6#GX#DYW7TSV*`#C}7^o}pvEL2QWF z5*-`Tu_eTwMeKPx_ADKH9J66YDLTnkaRXVmz$5s)G9V2?F zjvc3C!S{*^VyEcX3LVQ>R$M?VlrOz=fsVbL*h*rnb!?@MttR$DVz1P(7wXt6iJeAl zt&W|hV{3{1F0t3>*zfAtYlxjrY@Lpsu4C(nts(Y09b2PguOoH_u?;$QhK_9@_9|j; z(6LwP*c*tQNo=EzovC9RiTxq5H|y9R>e!n(HpHrM!62R16tS3llF|`oyQ0K$lvU=- z3l6rIU+~GN+ROb%W=}vqYERnBJ8XM-hgH%_g`Z+CUm=#fl0{^hvi9GwSydAI%( zhBCChd^yIWgYD%VGIOWNM^}lx+>3m~(vFs?F=CJ1!>dTMp^iPgX7eWUIMyBcC`&j2 zJ|fTB@{yQ@5UH^@$@fp>O{8S8mwRgDQYn@>l*BEc_sg4>v3WgP$wzBa_Hs{#d~`Nb z=YYMOa~*Aa`PjX~JCgSDu^1I|xjPYyQAY>naz{4RI;qvj0T$ZQFY?hhY}+F^VB5>H zEmynP%R5r`@)>FN@-&-**K$R~Ud}kKOS6|(&}j7Hq6tE1Db@K-xt z8_B9wR<_*r;3>cuJ974;>Q%ZWd?&FOQQx=1k0_Z4Ppnf{h!lVC>@RKx;gNM1AzEsW1+yDQ(2kHbV-%eoR@!a=LDH$r z!6HXGkqGr#s2GQBArtl+&EeG+7X_0`YK#+!@uiHz4tZ0?VZAIGq*z;t9!7fqXqJ^& z_yj@V^z~dVEh??kto1W?tZ#a4efD@6wmU|tg=x>h(Y#r45M#!(#Efh^fHe2U>wg^Sph)oC$S82AT@?^1$;mo`0;tFF;3vUkgP#n zuw0ZAWE=}+9F@J}>n693gER=W0v9s#@GT<=piX{C2J+V!o6z|K2M=U$sDac3=o^Xv z#SAPy2ZtTV(?3H434V{PlYzVow6+@LqF|>rL-wn>tmqkZUy)UD7Ts57JYl>;kEac# z=yC%?DFl}`l3(I=U?jyAVPGW10%MQlOc_aq1!+Thdiqc@fXG)UFnTCuV*^7OP7USR zGL-k@z06P+9z2xcfAmnE^I06qI!-aP8jAE#mgu4Uh91iE)KI>S2U5mRiXuKRlu71l z6Xn@_92iO&=YgRN%Uc>_O&i5?(nk?qA&iw(F|iHd-ye|Svi#>+p*yY6)mG>p1RQKc zvpbc@gxrF4NmPXISpK`LlDjZ_%pD=DaD4UpUHE)e3KC z$nA)Y7Wd7)m@5V*|K*Z}6g`&r@`4Q_B4_XH_(*(GrYQ^f{F7zIZ{?;{_O)auEdNP} zOx&;pAN63!d*dK;&`r7M`RckCRAxz#%paKAb#n;VJrqY&p7g?@bt?;d^h-k&%aYfgq(M9ev3zhmQUiYITeC5OA4mI`nQlC0 z-okIFDP__zNVU_gs&kLAN`|Rv=!|(wzN$W*f)qTxfYn}Da!zucH%B5V1m{>alkp)} zrOt`j7f!SZSsVMs=Wjo=G7gmodtO?V|0-UW&H>Mq(4ebq-V2!PLIqn$>!R8aOActE z*>!UG@dyMD2q!wisu+dvLEl!4QYMdmNju2zF?*mfV064qDGs6gQ_Cm}Oukk3VHQPU zPhe?cz}phPNAb4IAH>_Tus|#vYW0Fq_;seMWg%r24J;Xj@x}cE#uqvl=Zc%N-`B>- zI(#f~QGCL3iA4s`eq)8NQ7Q4UJW=^rqIuBjFd0LMOLofM5!TZVae6g4@0kOjIqunG z_l4aLiQDZw(ZWG8l^6)ToGl$KOsw0b%Z>&HNf$EEaiT#Z8c4)B2T)*$4hDqZKu6;| z>Zm92+Iy1D;@k&O;8r*IY!tAfeuhf4BmaOeg{qP=^@4pjB}S z!!P3BDOT;N3^WT`6{jAG3F3H*{}JBPDJ-xt0Jo3~45-i;fRE!L{Pp7j6&!+7u;@w?H zA293E4R?x(x8xzbeI=aQobmAIW$#A8hgLN-T;0q6OZk6l7Dn&^mx6m$B1|c2hP~6+ zjsrJ4mNKU7KhRq6RKOAmD8wHc$ZQV-R>Lx$?m@f;YcUi{3h(CER3N|q_U zt^FNxWcNlw60>=O!NQfmdzB2%SZ5~(E1Vpxb7)nBR*j`qG9QlnztE~6t%?k^ zYHYGqWyw~Jqg7E_bqTG4n^dsE{}~@ES`-~<(Iv?iRV7<=DJ_~ti@r;XrqiOD{|hae zHqfH)CR;Q;*`gX+R7;Dlp+$AH2(O0E{utE`wCI{-i|Udsy3V~C2O>7Gq0c;*+{1(- zl9E&XObxwC>4;nY3#^i_p+4}{78{-vkG3bpqb+nc{3zep$sRP(YGjcXj)Q1S+9Psl z^BmTt4Jli!s7LM7mbQQCh<(~PNkw+91ykFXQa){I+n4fL_!qSeC!)jpw7IkcnBLz= zSEYQ~(swW6GiLj=;g&t%K*k2OBk^f->FrBH`LyK&X$ZTkt3X41R6cD$d89sVdI3?q zw=0!{wXKRz&dSA~o0f}kD%%Y6I}YFz{e!G|3zb4HVpZ!Ds}NfWY4ib*06yYD|^ zs8nqAJ8y_oKoHHAm9(&S$)z^D#TTBZ6neFM61A#6C+7l%3Z5`9Y?I*ZdGp7p?;}ve zqG&1kqmhXQ|Kux(s}H9n?JFaIx>9yM<-;R#GKdOTyckHBtnK}m>2!r_r&`oxuf$Wb zH}L7?-azpbJzEIQ_)vL@27nW-5U?nW?SX$c(h6bopvXzKeSj692anWaG>y8#N%zdd zd5p64>J7%lTVviZh}US^h6!;!4uH3^36<2BDbG>nl%YIFLkCe=IO#b$IF*572UD3{ zk@6m`7|MGzq&H3sMQJ`!;2H5y0ecGV0{>Ce=F%RdHnn9Z4PTSx79v@8l*1=vKZ8)5 zPf=VNDS1-_CrL0C*#rk644DcmfK70Rq)HK-y(fBTf)hj@g5Z2Z6P#;Mg5x9xNCc@J zb5Z&{1~e#Ohaov;oxw@YWs{swkz4?hqp%|&&kHrpqY6I@P;cya(Wt<+GmycIp9+3Z?(K_Qk=J~}KhjL~&id$v5Du|P<6qGr^@;4>-*l$-G1=$s!yL&rL30UDD z+KUV+H_L*(ER)+lxQ=eNy2E)a{~l?0jd|0+WR}|P?j4{k+3oI;-R@)}^>`+;!8W`n z^!C4iOl4`?-Gh4j-`i91IB?bC5;2Yf*sn9i21MqelF(2im-5Qp67_Bkj-I2cp$M|3lAjx zkl=`KDJI=-Em6i%__uE~GobQDVpG~(;*<0bH;-DOGdf2_ zw<>IUk-rCbt%9)}f%A<&_>c8N$!uz-V^w%a$Eu@htV4J>(my=29>e~pcw_u?8=L7? zC5;{2t?H;6JB-HC&~m%6pW=q08vD=i!T^VF%uPzhlf+RVj28x;8-sXZga`A&2%Erq zs1t@??O0Uj)3Or@ULzT=NzD zr-vCFYk3kSnd%nbJVM4WO5J3ax>jIV)Bh|Jx&v9sVMcAWF`oZg z!aI4~U3n5>TUu7%lK*sMsdQxeJY`tXAX!PY%Q&U0G$;_q);h1~d{D~j?@yIweohtk zR7PPJr4@DxYruyoYn2?^FYp1h0O+DqJ;tIX94TqEEt7*KTNm-WyXWbTclQ`m@^^22 zdhhP7Ml^Iqr!Bw8;RJpxX`(0xDJ4I4L-;KBEpsW?yseL4&QRshJ2~jiAy0L&%0tp{ z^DL`+^nriD=f*hIJlU!~?ZCfqyVA+Az5co>ETdXeoLv!@916sl%lhF^k1Y9(?LDb( zL~QTWy1dxlE9;|OxzdoXZ1tNZztUxTkE?lk_&{)JlR8^A)|q3R{AtD7xng_2Q+H2n z?+@$#C#@XSoY>wRceCvDmfbDQZ>qqLxVKCNX1JT>99WvnDzR#^JXZ@m56Mr$$*b-b z>+%h;k8@5w5PN;!MNBaRVH|Pnm)!Bj$BE}SM2B-D?Yd8LH!oH-jjo#z+k1B1IMtKJ zj@>&b1I^4~>`2@#hdCy@evb{u3j&99+(Q9@qbZe!QtBTBU{0S<0LybV3({E+$xq@k z5`vSuy#Bc)l#*mHRm-F>-LkV3oDW4L(@c^moEI7u3uB=vV^_0?|8X<6uSH)|a;oR)a6}z{7 zakG&dTN?x?p))y8GEALCE$eSSsio)U6Re*$0hBdces{kV+naUWnbhc^I(<)k-oV`> z)Kh3c<=KhctW|H&ivE!`ZQrD2?&~*kW9ZuaE9^bf_MHzagUcwC<0S8v$A#i=(P&;7 zqWA{x80FycmY2bF^DlBlYwW;jv&x2s>EfYa!VRVG$9=#9I0yPqQ)llx+tPrR1kq%I zw6pCs+{?{dywuLotIcv3gYhxv6;~uokVFL2L8H=QRgFAr7r2aXH|@!4k4#UVmeh!Kw``ZT*)My!rgp^ z)N`Ef8)Nh6T%)|wIH9X$5vlmXS>g_(JYbf3Wh*I%iI;P;usTPooF=FcnnHConDf$_6V{O-DC zDYZ4#j~dgS)^%-=lE*-h0MVVB?7l9PO!W0DujO(nL|SU-L()|rG$s#|P7PY(dx|#b z)P~~HB6rI@yqe>}#ib?eBO#pFr@lj55k{kLKKTqaXu5L}6@0e1G3f!J$T98j-va^F z3gPgqE{!2cO4)~v}UPN&F-vB=iVliu^u}&$1 zWEPu*AjQ6i9lL}K8;!2rJHFVZj)!XGy-ZF#tunR{j7Ts#T!Ix6oT7r2609D+rT!k` z1pt>WSY2xb^jX}4QD|^4!xh7J9Wc7Mm{-m`9Hakwur0tnrE&Ft;EF4n$om`V zKX=Orq36cnj4XHa0VzaQj7o!WIIAqjE&M1K>@Af$J*G=V_vwmctmJsjS{f0e;xdi~ zPpf$4E4pH5TE%A`RIwZ}Z&xfAzcPANkOCFYW9{|nJyz8*2h^0#Yd)`z9ENXCE`(Dm zn{#IfFgb$*Q^5h{X~2BN2F8^J%rb5ZNbd#r05A>>%oM2bu)w&CQa`}VWJrHPFC5$} zmE4?_2FNd7*1h6M1LUL(Kh0U%2|KBjs3z~prh4U zApf|0n29_FiQK%g@VJ_1VnUr0gQ#qpo^sFX*|thfU2 zl^?!>)cp$s@+1DaouIM=J4vxVxfiBA|d=K+M zB$EFHJklDj`SWhJmvBw}D%aE!*VIc%Q8oMbX8goJ#iZ(-qP_Zot_50a*G&l7lZebeI)?G{2<&p zs2$lwW8yiR#>C=c5=Y&TS|;KQGWPjz9LRODcqaUG&>OguAo2^jh{rU}YR|#K*1m$~ zbaejiQhKt}+)m!0PUF+A(25% zXcGDj4d4Tr&!q|{hDckFcU2PAlK#2(LM>7qc{+bXTcelSC&gmFr4;+zc<|zOc`2WW za-vmYt6Lnktt}3WoHF(s7Ps+owR<9R1D{$!oRBaQFM#9f#4YXzL>jk;*-L3uPSO1I zLX`UK1bGdSWS2h0FGMmoedN7{+`H{dU3gA;$e7nJ1-5Hm=9HDxq4g4X9<5Miz%aKO7ecvt*lnDME4Hw!*j!qucRYl;ZvtO3H zN>6s)FSq19cWy}l^?lb>{LJgZ%}?w2pp2Dkn4eG|0#OZi*#&}=TEAfa`{Rk zX5>ZMe`v14p;^AQrSoj;Yj|xt@*eQ3?Q>>mwA(=;Kl{#Cl>KTu1Pw&Bl`4~XRdLpZ zcFV^hQBTa@da7qkomS7)rGgx9Jv&g(Ul)SRF7>2?ME&bIP1F;XR}@A`*Y^f!jgA8V zsnO$wAT^KXeYGq%**>JGt>Z+PF8^_R8V-R;ORsUJls_%@Bf+;YI2RGQc>jGcn%8lf zsH0#b)l|G7E|EMBiRg4*Q2UK@X!WY3G1>S@fV{_g(_i;(FEiIHk@n}!b~{Oa^F1Iq z!hWwAdMVj{d(rtonm4I5lg{a+`2j&Q&h5dVR$4`)9W)Pjsp196aWI-++0!%4x!&~G zOSyDq*>N;EOqY2Y-`7Wg?=)Mb`ITyxg87>4@xF|R3=lxx%3QCCjJ98m4km;t3q)7= zoK=KR>3s7eA01Mn;SdKGk(!ORcM2pOSOgsc4XpWdZ-f0lkj5o)=;mH8%`@wA&!l7+ z^G-HfZw$+2P*j8Da^dbhC~vOt`lL&m^9I5C!wF1;wA6kbIe$y)^9Fc4_D3wR)jox5 z1Sn6#8BG!cl{4*U1`PChPA!uU9eD#i=2Afec7upU4?0amoakM7(f;LqHqF00ZH}|j zQiyhkfxnP0Z}LNaa86MPf3(xUs&NN2&5K5-?>BOsF*jat;Y3jzjBOn&egc}Ka7`t^ z@sMPI3Bn&d1Lf-MQc$wTo~#YqhG)J5CUD`ZLWk&_v~a#;VnVOYPC6_l=KulSMs(P( z;#}RCYsdH)VSms9Y50@Xr9yuQTX&#M6dKpZ$%hjI!Xh#f9yqMKgjF_=$>_71- z))-FYUWF-Ob7dGS82}eVb0v-_`4Ig;qZ9+!19)Uh{ujSetAV}DPl%am0E3Djf_{O& z0>2${%jy4Xskv`;?GGQ1Y&juU(}DNxH^jNLYBqM3&mABJtoX`st4s$GT3zi+<538l zki~R-`|9Dyg6xr66($gh#TFVRpiMZZZbfc;S`yhoF!e32BTZ*<@}56Q)Cs5;KhzBc zM=)RKRvat&GdMu?>L6>zuU_^v@?XKDH%qIK)D5~{1D*S?K!CZ8%6o-Cz4KB|_#9rS zl^m{TQD|qixZmjy$Uq%rLT$KC(AZjEZ|`f+zt+i^_m z$ALercqnKh9_6FlkUI0wz;{u@CL zC7u-DL@oTnEtKO5dQoCW8edsjjaJurw)l%Lxzb5ds6BmZH!XDzb8Nd*3anseNed9U zQmUbTTEEMd^h1N#Ct0);yJ(9y_~T=K3tj@P!PT?_6IC>azg)nFO8#RDXB?o_d#-Qh zcSFT9pu+tt)W;u{M*Oe4$#yqo`xx0i_%jwFw)SL~FdO zBaMwS=$bW%U!~(FbvZiMAXS8fi5wgi4^k>u)W&gfCa4qR~{0;G5r>-T* z{EhEg(zELUtNbm5dJQ^Zw5o7ZrXh5{xQ+`)=4@crUc;V6I)CzKv_v3a(RgAA9C*-Y;>k zI54x9UcfK!n{)5w`m&;wYp-YS;r%i9M^9(+ewcSyEWZPWtK!^io@HDGKl>q9zi2Bi zYI*BQdH1GgQhjqJuJ)e(Ggo=fyw3%Hfc zIj=x2hZl+w(Qe4~)Y$F|kRVz|no?oSD`)P%We!h9`Zo|^EmnlM94C{`2hQ4@ZmC6uZOv1$UX_wq89 zsR>L?xJyg;i<;0pMNmbf3eT}pO=wUPu0jGe^moB3vcB#FCb<7CiU6S~{iOOWdXU(22LSSWr?9d}@;j$9GCg?snnz_j^tAU&Hs+!dHVRDm+i3 zw|L1(ngQ9P!eYlV9UaR1_!dZNxm+zzGRT8GzvTS`F*F7%2?nZX$A>0YLNq`NO>0%Z zyXXLQrM#ngYDE9@Y!Q9dQ(n5dAByw5SGt;9A)bGfz8&FtQ)<;;Q|A6YlukCuDY{!E zCbhJMEsu9b*uo7Ei~gn7l#2YJ>|JwF%IUl_?A^?wu$0g9j*%oHxz+bQJ@sZbmn2&btBCjUA4v;L1-mfN;j}Ii`CsAc$wN%S|{he80Cp#}HaH8=bhx zQI8PWg%$qu z7}m2e6)6QI9;e~<72MkCc$N(Nc=C@=0j30w2@VPM8mnHpZbNzu6@_awUG3w^SfT^b z%;-S$8d@B$AEe0%4aW4537^&sz-!VE=Q=PeL4ivA04x!?e!dApTt#P9#%@{1_8~mlmZmv*pZj=jF|KHHE!9ar}9B z5QfVe>yf2ys%2JPx@8uiCMNF8md*EO%kgP-<`=D_Q)&tt8ywi>h|o;L0l^vh{X3Aw z^CtjLm1*PXEGR*sNBT5bFE8VqlqwfMz#nzLxiMTl`+0$VB~P*co;YovY{iN2qkdF@ zfr+VIp65WD+V7_jn`2U&vEZ;hpD*EeOBzd&%(KHdPo9~9 zv+G|Z6Q^jNF(LyN->YS8RT%;UXx%Oej&Cr9tV7}#pKvbR1AS61OXJXFJff}ksJtc} z57PW}7~KCvSBK|=grU4WTsj=CjG;qflQFseZOi>d7ga z^TXuLR#}<|G*xL6sV(aIRp&O&m@H1I2dAfk(^Ii-grG`9p?wC$VxN#upO&O0vA0g4 zW>e5EQ?yt6+O#`dc}rp7^M}~t82mAcaqz-$C^-%l$h1seg}pPdvo{VS&%~kRQ*fOO z^)yBLNYB^ONC`si7Ra zDJ54#+-9jYEPsK05?-yaVoLB`2oH-%Eq8{cw4!BOQ#L(+CGV!0gOla*?6_0e^2ABTF)3B~lhG-X zs1DcUPLMZwR-o*n&(nx$ORfWHGs~{&=e)9U22EL~W5i&qXlj-;v*vas_sV&RJ8=|s z5>t+VB(`c+q&{1|Z8Q$3_P9_OhFANvnGmi4>z5(tZ(GiTuH@QQx!ArKm}`y(%7SA{ zeOkQ6*nMrPNC*)~;vxVt<+b))Vi|CQGpUI?ahUW889M?PfNmVIWF&UQdwvW|uXOfq z`m^(t^nTQHlI6yc*s1z?0}|*6SK2-&BV{9)voWRdd4{KPh@Y7i*DlYJ45P;qgy$Xk z75j1&b`PSJ(rpNF`lZT&u=8r zUqbPXMCWp%^H!o0^vJE*ajtAReeS%m^4w|e33y#4WuPEb92#Y!F83$W{Bh_Pe})8C zNs(j2bOZPNF}0yzDY}8fPS0AK@nEUMvZr=_cbfr$ebCpw%D}OuZkc4-q}N$T>0&T( zax^%2AXU-)c&?Ies~-^qlnv-^2|JrB$K>8vKOzz@sQ)F>3--zeZsuU$y$zoJ4GvFO zgJb5-SmmF(t6;3INCnMB8_aaS)QWq>9#6kZX)skJ1Aft?49W^}=aNnMk5A~(cZ7JwRfnok#^jBl8q{rpz6Gl>=SNO@_Jom^A?2$v*8M7y>PO@NpDb%9#TtmG4 zFL*ApSKl>Vry*D>8&I*@1d1@Wug2c#{5nWn#aao)3ct}bW_(4B!ez3<@W?s;IvO3R|02o2{75mP9*;o zp-^7rA`0N9&tX%&NMcJ_Z(0XG!HXoy^kn8wT!it|A5Y4QB({{cn&%@?rl(_TDIbY9 zJ$=HTxIp9SBRr{VW2l=lHj_Y}qwJiXVjf`h;%Dgal#qo4_oL8v;1}7Se6ldoKG!HW zmAk^(Dno>PN;(ix>r^J|drkmus#&RbcP)$Y~`4rZZrL+$H zwSyNT5D6M&cdbhglR<>$6Ko{GQYg7+=X!F>taH)*CShYwL^Y>DK`v08%QUvck9^Zo z2tcNsf~496Y&;dWEkxwd`G(X}Jr7QM4y3yHvjk6iT1#*^+B1#{x?Z zd)M#~PB|sk(I5%-=~ebEEQbcB&3of-JXz+BV5_#=SAO6IDP7&X*In)CPk%S ziH-0ftkQlTZTg1LWFx*C0fR7$wVSVITjg?6WX? z8#xj7)D*UZpDv!T2r;rPbqgn2?i2`);>De{jrz}l7+8MggN1zH7{C&63XYq;wTZTy z7~2A3Vnx|VCK?8bP5wqRUC0X!Fxi6wsnj|GS5`wl}Ggh5Cch`FoQ z6~2;l8qAVUQGQ`gF~N5)VteX9wnK2{XnEs#f!sjcn>9-B zUQ1R1rXf>cV&ZC`o&$2TGT3OAcOz%xh>`Cb!{~ zC;L>~q2Dgh5J3VK_~)lL`cv`*p4|i;Br;}FMnv=Sj%6N5lFj?%0<}{^!WYyYqp>B; zl(LI0`Cu4wwnBO(xSC+XP=0WPC|(b)=rnqd$Sbl4Kq4ONn?_3MxU!e$BD;NNg8U|* z_Dk)U-o*}v@wZmE0oalZ;$j+cCGkXJGg@IekP7O=JzHfWzk{G}Q6{K6h^~b>tZCsZ zcl?|RS+#Y*_OU4|ImUuYI4cOn@U@mgT+n3XXQ1WUHUubD6=Q!ZVSn=JttcpIAp1yE z|48}CHmNKE$n`DK`GVa2$WIwa7~`S(Au>sL#BwEJmCCaqDarIA-EJB#rf72$z#f{8 z!zYR;J>?b4n|P27i|!e@n7_|EL#8h#j`Vte;!X?#gp3AuLpTbc5qsn-9F!^Ffss(S z_DZTJviuKz?Qe2$`{Flf{s7P6lEw6PCcYh^Ae#mHa?n(WSK#H_ba~UV92cy^@g~=p znlw<}C>@T#$aRExDWB&0YOB0ycrJLo_+1^^1>TTvqd3B1U;HLjLv;!bU;NLv@g$3v zBa1DC0LlA3QVDjnRAuEpKviJZkmSf~NMz+TTz<~G--GegQ7ljw^SY*pC${*9u!HPN zNz_x85;QBWrIIz7orKS=%mY{3F=m;~m^U1w#idIP*6&4mCIp&|)5hyI8wKqK-R@ zy_mBFw=vLNd_jl$9psgJx(JiwDTcGpjCqVkBDxzjIsn6{{#vM%~?ED0M{%6D!M7c@_BXV8%CIY+|<30~HXcyT! zB+`80E2u}x{MY^l^~#i!Y;iK|ZM*dPb78tsQR%y9u;PAKlD^|=aiwJ?3N5P8jfIX} zW+6W?G?582O(Ue4(lGxrps`84%4S4&BCh*pe5fv;K@TPvv$`E*t)wQi z9i&5%d`=l3A(EGOlRQWyJG)6{B01)Y;K*Tg^0K>09;TMvP4c(Yvb#yXK`k4;mAYjX zC%D+9eyILUDhUKN6(Y-7U`S@0`7l!MYL_%W;DXsRUfg#HAXSx?)ZhUOMRs9TB%Wv?CIz6g<(T?quT5 zx_%kYA+D*ec&VAZ0cDO)9a~YUsREcT^>6YL9mn9A3rr{k7RNEiwk`?FDZvvY2N8>e zt-xBQ!F0t-mFSusGxb0MoIwGBoNB9*@ZC|-#Ygf2^ z<yD+%pxZhv51~iY!srX7{WO^ugDtSq>Hz$0@U@A-I9)M^tK+9q z98R-s49sOnm(P};xIurmrk&J$;o3ohloC@|C#4Z^c`nfBM!u)B@^NG>H!LxfaFd8; zQa3~UB zuE7b=VtqyQZcwhVnb)D}P4;3*qk~2-a2{hrPRG(5A_8~%V^GnQOUZl{gDOs( zQgi>U102T?2T`Ef>morA_{Nk~co41Sei<^Qu0q6}mz&mu$vXIY(G<&Z2M;vv3UQ}o z!VgPdw$e(H@K$d2Aq+(>C#YgOH}q*_!k{Jiw2~+3&nxNg=#-T!I6##~d6y7uemdt~^+x>wXFn!$keFHi(2WeP_&7gF;hGKqE z^Pv+^mjwMCi-cKQ`#OJvgyq0X|Gc9vsV$hd)G<*-vQ1!jF9!ruCek!jv~{P^l>mtH z!-Js|thm#=KpwR=s!y2o$H3bKYV+9FB0d4t9FYaRw|6l&yBqMSmKrO84vJKZ)iox? zpp6qCfy%BcUO~EM-{*k}xUM`ZY4!fXD9+B)y!ckg)@5Ut2!vfyj=|r z>Vo8oMU6Sr#B^bJrX3$~a<(<%D-WeZR2)QxD8BsPfz~VP7y<$951`R9mV=(*P6K>DUJ;I0G#V2+9Co zvSr>=NTgeArMp0$X@X{6Sb;|+_pX!j+l9CrEtMHkUa`xERLAvF#eAhtaBK zKw5hO2gj;9s|&^MA5wW-Kg$xIgY#*zEHw5cgP8HSe+SPW1lD-tGd?~IzPn1n{|b-B zS!x14VMLd3qF6-FJYZjH;zkav=q6A@?NjS3V~)j3X_12j>>b_cqJtgqbdMdmlIPF+ z5JDzy`N6>)6@-#Ea{J=Z2TMiVRvV^)8;ss>WYwD}xE+mM|d$|ENz0ipE zYwSi$K(kBg*^)mX6Rg29>|di%au9v*^E$(?9GhX|_!%kI6i413%v-uun)}+wAgWtd zJc~*cw9sfI391da5|uQ=DZ@1dI*Juf0IXK_A(V|%jeigJ76QOM9zs!f(qs2!#>}$Y zF|hMG0kzuw!(ZVQ#|c8{aAn9U7HY5VN7Y+z!3&5wy=N~rpj+E#PEmW7eI}pB2+bh; z*lHg%=zZMTtr((7uoc5gbfmBtYO$$h82nWWkE1g~1E-nLw1oiDv4val%Kj#QQgZLC zRK})`q6J6x(rZYlGrUv%EP{hf{6Z^0WcnEz>bO3mvHINzu~jXMOX+C1)Df0@h13zA zYy1&D`Wq;1Fa-QaE<;IK!C`k4*d=>VE^!AubfQR&wOri6I4+kf`6!_nUR33#t_;x2 z0WBnoTogzlP*vLjaYret_cmT3mi?wM;OF*$CZGmYxRi7~B0Df8r?y!sO2aoZtT=+Q z2$85O<^qDIBXo|nuaLN4M6F+7vBIj(z%|SDFME>7sH?|PE)4MuT(cUm6$V>EACTK6t`z)4eBVcP+x>;U?!$fC>bCCtSC@%F zMc@#axD!6{x?-_hdNZjIdAG*>BM|KKs0dZTVfu$Ul3^i!LEd(#7kGxaZs8PpOc<;h z8um8qrA5WME!3wpJVI#+FQJn3qB^=@U?WbVdl91yU^6|Y2(83kPFH6T5U)D$h!2;q zaPQji+@&xyxlzJLTy?T(c!|cVEo5$Sin`Vm)2GF}qBJ5~d1Yx_b~QL;p2J;AnN^=2 z!~t#X1WDXi&u2~OH%o4SPzlYPScZ8hX<$|Nf>WgccNmJ~O-ZQu+v zaQ~8iqh1&cGFQ}CsVqbFHS3;CP8vU!V`&jr;S=ZM$KB|e7-u}Y z8yu7;3HR=ou+AxMG|G+S*HASDUx;y_!w}c8yhIm#am<&(jxH>(Z46he zL`fQq-nE)?*T1Aq{p7hOscfLU2`&nusKn(WG*dn%g$N!Ibp|u}lu(g$VzGeQnyiJ9 z6B3wm`w377h;ru;RSc9QeaVUZbjVN)6b0fK2V|E*;TIxTo#Dm$WtO$1?iTZl@}3Uw zi;j}rojU-5^hKvI9oJ>c1Fb2pye(p?sF+KTmz-_%dEbKagC;)m5*do&1wP+Htii6^ z3_5l6qH@D{$TtbXU=oCUI1=Obko%5axgbyc+ncy5?bT*_^&3n$Ivt;4(sJf+neWffFJaT5t2j}*ChI*aYpCHez~Uy##IR1|5J^isX;++QY z1)Fj*tg%SlDwQE*7iUb|o6?w9hbqQ^GK-QKrU&CZXcfw$jWtz_(Q;f%XU zIW$~4*h((`4RH3$ONr&>t+c)#6<3ZAORd=Q;XawmoU)YK3nNW57Q*+OdEK)d(P3rS zEn*$HGETcsf>crkKkG6z`Sic=Va*wWQa{2j>;h6wAk_d7{d9q9ZrcAqol_oZe<;fS z5?_t78b|SX)8dc7)ltR_`dVuRZV^+rh3Jvzj*}-?29K)+DceyAg1!othITrAfzwH^w|`xd9L?AroE z&^0g)u9dR7Wh=-xJvQZJ-pA`DNKZq*9N_ZAk)73VF>cjB*Dgk(&gyzL7DNJrae5d+ zpI$(<^0sBKKd)=(HxC)>TnO1p2cAG0hzEdGc~kv?V{j>ft8{}l+*)1N0{Q*0D6O#1 z)Fe1<%N*s7Lntx|MeaLBK9dzuaQI@mGw(MrA?~G>C=6ec2v@F<3Znb5C244M_U>qd zX9%9d;r18LVe%&Fh@KYXxM&*O-^P0om!J|CuU=!-t3|!Wkh%q2w0ez-x%LEEI^5uel`c8KQVp_B));^nE=s4@{r(6v0Q=K!DaX0<#D zMpq;)TNYva>J!<1B(vg)6iOSujoh2eIG zzUTn?OX)UjHQ);c#!+laGx`!sSXPVi$ zX3}oZWAqgs(O^~#SClHbx9FIyKeOGhXEuZ)*`{8N8z-|JWAz7Ey@xe!W{rDU{YR{R zADdgFXLD=y?A!r%&ch16!wTYu={M=CE*gR4#^>*OkUV^^Lf^T3f%G!lSR-mXfY~yy z#?92LaTi*3pER<9S;LGMUExbY0p}QvE#O!W{6fp%>|&b<4QoatAK>lkWc6;=Sk4-^ zvieQbv~#P`u4vnHPIk`i*RGV&ATqjG{Xw3whGe3CH_y0J&3Mp1BdE)hwYF^Rpyr&j zn?dG;{NWo{l0hyu*$}tQ%yt}d&$5oP={wl;M%LhD4erD;{YR>N5(%081>{~1xramU zXAK)z!#37%gf*NLx!9bK!`Pf%VeHAntiTeX2X3nQG|Ih~m$QeLv!9o9kTrN%!zR}7 z5o@Sq4cpnAYUHj#?s8UOKyK+6c4(L{B$I!BMF+WyPq0uMA*b}sBiMujOem?Ec?5^R zSMap8h839gddK*@Pe>PZhlBcI2zZz+T@R_9*dISZ3d+xx^!t{*qNkD{-FAdT*sKsb=3jZ8p609I)Y0wu7_4!x1;I>vtM{zzaR>330)EjE@E8w zIGHD4Tqk=CV|%NUwe~Qsdk*r9zT-M&B&C1QKV#syZoBg@m?d2v*T2H!dZ00KsmJxu z@CO;!L&1G*~+(|8?qh5NsM^M%k&iO4f`Rz)$%Lb&Y(I%o zG545DDvyyohCBtv7|mrKn%o0FY?Coln2PDV4`bNm0iXucdyPk|;2})lr}|9b$v*Ef zr6bE*rdX7 zjbI)oN_q<=_0YHc7^JlUpZ8iK7^^_RA9iUIjZM5zFDzt)!}_+-A46#)QC052L2o6I z<64hll1f$9h~iu@4bzyc35W)rPS7NcS{pKeG7c{$(p+eM(=*>uzH_XeIYEG?RyEhB zPg3x<>`_l#$9u1z&UL~$7m~_#ZeY%BsyYo-;Rem4s#~rNx{+rwym&RHml@8<1DKQi zsA4SY)RjK$={}d2VV(JSYrL$o& zx)mbetW|q!51Q2%OmynMtNkjdPU`R1rz!K+pjy>g!<_K1`1aQ-6>pDq@k0-#*?kF= z*tHPVMhQy0P@2yE%!&TyYxnpjc*RLDV+)AxPCpA>%EcI}lsO}q6N*vTOr3gEOXvDS zz^JVvN_ZC~gsMXYH#Dv2tYFR$1Gz7l;-@_!1_bBZ7H@>o7No9J|2cWUh5qE~%L(;~ ziVAY5P8g@u&dZky;BFUiP@JOPyrrDO1f-A7e4Y49yON1B0kO`AgT0vzcEWwIdsJJ* z_E-$FJr&Dra}t>Cxn%OKKUqsY!zWu&&C-zZI#&uGTVbNJ|6}tk0-Dv#v9oa4@R*k9*$*CJf6(XZD!}H**OO-ffT?@ zG~+LN9LS1N3=5fUJZO3_1G%%1I|sSPA@>yIo{rq}ddSVsn^gVqnIH-avhdL=(Yh`? zx{2AaRg(?tAXo%xWG5=wiS5jGl4Z5<$KC8igUUEE6wP7!y~-Ta1r2*Y>Ny!z`;RDQ z>kAgt?V_pq z-$=&{d3%8Af_NSS*MQ45D-lf%0ek`%(;ZmhyTj6%t?}eCyo;(sDCUyi`1mi&K;|So|PYdKj{$haq2j7&4}ZA!mA6 zPQOC5{Jfp&dKP_;q^`dy6HXx{&?1~0rZDP+1-PgSNT?FMm>6c1$|6%X&vRgZ#39hr zi%k7>rZDW5Sa22`5qm05g|La4Fzw15tvo=8F%za$M_Oq+haFDNO^g7O3=ouw;T&c4 zynQL<`9l_&Bf`x67n;MZDdh#H#av39k&1}Tz)@d#^dWNk-STO$@h!?6e&PD=KP7AkdiEz8=e{_nuL(q88HgtgXcBwCHe1iK z%GhIN?C~;Ia8E1#n$QUPRyKVLduj`tu?39``+Fi5{Mu4ZJ-vfIW;g%|8PDFz#Aa%A z^b{f+u;gQHX}|&s4Fgui{2*RN;W%0ZEh?!~=)>w+SRaByj@wIFP`b4o0XK*Y1EJP9 z2X;y^BWQ(3Ny+#E51Y3_c8JKhn&GtLZM;RlOWsXw3#y~hrqD|LAs^S{??3SO11u_~ zoP7ESvY6w_wJaO4^DAxKic>(k&w|ftOa@S80TD5%h$#iTn-)kC&JRIx2pW^QX z5q1fPEF~hj9Vi_)V^__O;9qM4cS*`(I4>}KZKm~X(cg1ir7WlE9v+i`rP9+zHup>< zoBLT5o6a@C^rNgD>^;rePq4PLEXUQK?YgrJ{u$O@NxgnozewU*+eX%Yr%vVH9A`gP zfEXiYv-V>)7qc~C^#_P|Me>GhWbM_gy@9pwWNnCqz_R}CDAF#lFm_!hP;X`JN7$~x z0`(`XeXu}X$L1UYMp$|5$!)9vYxCpqcYxXIuxy9|K1KmhVIbMf$pgt~L=R$xqChA| zowc8}*OGp-?cy2@#GFQrcuDR3d}{y-bI!K0_Rm<(;q@%%gpIWyVC~0Pdo$^_UDxp} zyKd%K+fbXEMdm|n&Zqs@la>7=pou4oxZ0vqpK&OtLIQ0 z+4cQ+BpZ*YQ)u%+u#m<-^P(#jW?F_|&mnXV^P)%e3%M%)7uJmF?0EB{ABM42rxuL~ z$A(hZvQ-Z30fn6!Em4bphz&K`vH^Cz+}_fVJ$x45tJk34qojVIELf*g;;&X_{ajab zI6JP9#!n?aoSv2V?`A_UB?AvzwZIZd7)T$P7g_tE2#g}F^y(%JDWw^3T)G$Qm0qk$ z{7@f^-{LCVz^bI9g`!lp`qmmY!yhMz*B+Gs8SWJ;fg_L ziq!A$R`yyiE{q=rCFvO@>8@-n?_1fbCV^rANJ8uJ%Ef4CXqWs*B{i&*EQ5Z#7nKry zy%PP15`9B9RQ_nTYN}<39Bo0#=0!gp$X0oXbqOsE#LsK9<#UK^M?LsQ92Q5Ag$OjcK3QlJ{XT2&IW7(>DkVPX7$T6w7t{1p&vZq?~ zEn2O(P<7XAIE|?}rek+jwTMRA7n*+Rmm@k`g*wY9d>eYq?e+!iNPI6E#HF5~66NMDolWlM;{J zt+Y-PZ&9Le>ujm}simT5lor?`f$b)aO>U>|7enn9rNl=PRRF>58~l|h;(84+fDjrF zi~K%ZqNwdM*s6(^n~0nQB_8dovB#j_rDbYV;;*55wUr*swv%um$L%EKB=ai$o$Z0G z06Ke7CS~BPyPh&A<~YUtOU3+aB`FcSsyUJ!cUtd4N6~MfJ~tV1K_9Qc?!|yI&d4<7 zDO5EL0do#O4m$>#0T;w zFMoXd=GC2j6C-D)<>r>XwAb&gcIdKHKAxH12SujNM*1APyLo$PDs75=HRXs^3`2N( zzF;>)VO;n9Tj?r)C10PsKoe+}<;XmoVLx)2|;`J5KbM*ODrXF&Jz8V7r zQ?O@x3@dp8Q+lb=+SymXd|R}Mo2Z-E7hsDD)L*zQ>RW?e+oB?KA8gTyuto8i)n!}s zvMs6_IhSow&DgqZi+*ivQKA0^^GkQOXm>DQeOpveE(W*0+M)u77{x-gMRBMGxj8S} zqL*#aFWnaHuCw;m7Nt2>(Qyl=Q}QAC$Ol6)pTd3>$#~}TN6b}efflaIhy7PX$g93& zA)r~oujm_AR`C1Z-~#u${@9Q5HYw%-O42TxoymLRTIBQ6Cc_8x1uV0LGus59n}iwg zBbWh~GuzF=a|pk6S`4$zjAZRD)^-?o0J}r;w!+DHlIGIw2$fCdcs$;!%|%7wJw0_HM1m%NK3PTeR6c=~bHPgCmhL5^#tDuKM$N?X$J`j= zf8SV@0c0RV@M@>3#~afq3_(v0x}SyatrM_H@T18nhs1LMCBG* zbgs4U+{ytm5TbGmO*(g6AGtLTm_UfiEi~!ej6QQqD&*aCCTLL^hE|=T7e<&xrdVMCBP8c5Y6nJS(ao#iwt=Qbs(!Mk}f$^~opq zVqce{<8*GAeCPxErXJe#FSvASQ?brOp$!wp;oCM+mxq<;0ZQtinxifIr7DAbknjJ= zY*4-khY{g1Q30xQGvM;KVVvUI7LXc-f0aHxK zg4~5ws3K6Pf;ew9r-nGp*5dQ2$fsXhH?7V`&r2^;GZh0B%$R}Odd}- zviP0|v_*uGq#1ri_snDb+eYa)Ee26C`DDrKZIUVt;+$|g(`PE&&p9|;H4>Q({E)*W z3*T%9kh8ECjRk0`418Y?`INjDxTd=*v2~JEIhDtL1eTA@P(=AVu(J%-a=R%%5j#L3 zPO0d4G{rEi6sKI!zN(;t>>3$V5Gw3j6%PmyQUH7)gySbdius|j zp~QM^W(82`&&wPjP1ZCn%%xDxEgvfVc{vXVt(xM6y%eg|6+opQFE7UW@*&iZofl(- z1<>lxQDVRpFGnE-AsS;og!*%onkdW5QAk0EHkl8VKDOCPtdM@KY%?Fe_%&c3O*9{_ z=pC2FRP&+GujTq`u?3Lm*A@C~x%m+3&qnn5J{fQURQh#-2b23~$oWv|&&q^8+H*cs zYIYqR+~{N1bz?UjhUo>n>B4r~EN54{?JqudTQ~UE!JO)yU3RoCs9l!(jj+pv=kDTt zSAlpg!Vn8Yg~8lUCPVgJ1tPjA-&G(oQ03R3Ct%18&EyKi6pU3Nn_7X$x-e@B$O_5E z3d9tQTOr$4fylaWD`cZ85K}O2g=|a(BJ0AfdEiz^R#YISAl&Me^%RINkYT+tn*xyq z;~CX7By%YcSr?v#Y$pX`iZ}Y$M_+y4RUr9+O%$qO6o?0{(^rEi5LIB?glq`~A`&$9 z(E~eGbplRM(ufELUb{A?g{luaisdP0L!kthAKjqEJL47RQ0X&;7?YqFzBpBskCg zf`|~;9D#K__3ZoH@*^&DkDQQ`|oE}0hcWXnCa(~;}bFF#FP47~zwUYU_kZPUR z@=9qWAYh)lgRh4j%FW@*ppt`jF-rXO|$^8mY+^xU&hZ@QPhEeyZSK@@GA`j#@&Kf z{DsdzP|VLSa{U8z7gZ8I5(4_x5DfQS8{zqAZRCSpU;yoh1itm6{DqWF@Xe0|bWd7< za3%N=pvnRTT%dmZ;Fx86%>wn~1BJI*V8Q+SkDxah5HR z#+Da=8`_!oE-|(w0HG%b<>!J(3)%k| zh%C?rF(G9CV<4tr+zQ$M7>KM3w?g(m24V`rtzP*b1MvkitXKZWKxDyq7P9{_5Lp+V zh3tO}#Pl`uKL(N?*hHcF9|Q5Ab^7Xm3`7;!HX-{T0}%RAx=+1j2`*dN;Q~(_`MOBM)z)= z_J4uR-`wMN(x=~ub=rUqg7tc5<0TEBBXq&^G@Rmn_~4+EKF6gBp6evgPc2+b>|9V5 z_SKG}h=)!Z{lYRP_0^o}j*Wdas{Cp6=VM=Ot4Ye@doqq(izZQQZ z?61Hj|G>%Dgjgt3qZTFJ{WqS0crL=^3Pcq+`MMk@=ksmt1(`Jk?RPm&PW__!g4~)H zs^JufNyxk3aM3G^DG*;^KkSvQ6o@QXXQY~jWF!S5>(U)VHje@^ea-w-f#e4^QK%MC zARe?%U;R{pr~=z2WFsgLk)X*>oI|&M0+DrL)a5uionO3JB6)bQZq7rle8M9rPHx?Q zg%T&%h~OU)7ZFNaUO7Q`7biEdvp`xm?Q5J|KaS=Lj+0ydTW>I4-{QUAB_lFu5YI6z zwB7^ss)^Yd)D%LT+yLbB38>Q6=X)9N^)1lWL!8{}zX?KI2yt?=kk5y>zVWR90W;n6 zZ9p*6LW+~y@oPWg`V=R32mvrX@NE`~=+dYm#mU|7Pn;HqL?L8Y&<`z6ZY+rFQhEq+ za;tttjG>}vai7N%^s3yCL^zCp$Y)4#a;bhL_dZT8lS&TS#VD3x->Y7J@UPU1EpMZa zu8WM5b0To1hd8;Xf*0ERIJtQuK!)pW?Hl_padN?9y1)_$Z%28~IYq}p1p~uR7g19x3gKp|J)DLaKI%_k-}#pT`bajq5=Z=N{$&vIln`U( z-a}>|Cib1iH~-or4<86dq$|W&IkP{JeT!Ec1OmIXV)lh&<$nDO;*b`q*0-`>{!5Uu zkA)a3ceNh@y^WPKQ_(?XhsKxpOTC1t;|q_K`_aY4$}Rt2ua4|0vJTgn;Dzq(d#v1d zQJ~tkYBl&8@WOytIq(jl({${MIj%af{ypexI%g*81JXS>bY&opu^5QuJj1m(;_O=7 zgfZuMI@t&3AmOke{pla&)v5M{hG#TKgss9m`ho~LiyyZl4kg1`32|E!>({H)=;>@5 zqUIVT5pkoHt9HzYarVOvOtGZ7;%l_d%UCKvccjyi^H*`%19nxtI3PM+)-{W zcUkvg0IVe)Ts8$XQPr)pOGPWlGHe5h8Iyvm1tz0HGxHoGZ~U{P+y{QL`Zn zi4JAc>me+hz^>&8S?QsuPWcLyjUF;_8%pJ$AALd&dLq$}hfzV=y{F9Ch*7y<8$bU- zZ`;^O+C;RotJm!un7L~kKz{`C(n%Uav^PrZReL*e)|1-ioY=1A1#k0!B13QYfQ-Ft z`#^Gg-Tr|He9P}~%wUFVacVFI4g7}TZ#-^%$BkXR88<>g*2z=oSagqIV+S)_LsVTu zRMC0R_i?H^#}82DuV?)FSC{dF84?LyqCdLMF@#q#2wlO(kWfeqX&ea!k-r@Hj*-E} zl8~y|oAD$hgrG45ee>FXhOBRd6hRnOZF7u7knC4&Eb4Ad37Rp8o#NFqq6r{is+K`X zpj^RJ=PnN%Qvxv6dPESQNMY7UMum_@BLt1=X=0G z>Wy7?Xsu@LW&A8X95ixB&)Tt@`~f{{`;ecYxS7sDqI4X$hvlm~6XnJNe2ivc2JK5SbsJfdv@<&CvdED70cIQYwI}&y)SFnlY3ZxB)vT3eObqz+|Tl( z=;f#0mj~FBM_GOhohMD3g2Gx=qOIVKDI2FrN8;y!82tPs0Y6V=;Ac)2exA$0&j$P* z$tF_qa|AzaA7^9hY`i^y7oXxqJ8s$!;qNeBZp2F`y~Is>6`;%Uw+(+DJnz7@5den( zFy|3G{U+Qat%W!v(L$oloYZDO--gQBZp0sNv*Re@Q@o_2+VMwxhXAxw`_Ox8FOc5e zfqPW49c<<8*Muty<1ir6ugyqU3rJWSJI=8D+d;s={@FNsGn<`2%RGrD-+cuVl88>H zmIB02LU?u?!YFApk`8D|A0cTAl1!s1=~^Tm(vr{)Pu3$T`dY>Of?C*NEfFpEBqnNH!Zs2hWDKn;jp;KB;D(IM^pn_KAx*YM7&rISw#~ z8;S(S!r~8L`SDSYkgn)mIkre~ne2K*GuEX8`@H-3c%K6>RxO4Km>v7k??{2`|_4rP>aQ-d08^!Ow zgS)A?gKqBLI8EX(w-{(-M zPI00i6rHtau#YtgC^LsbRg16kgUS+6CINM_l}ZE~ira9mtGC3GLa;{wMhd`<91vV8 z-s=ar+zV(HfXg@_m{`2V53tM&7$pGbazOC7c$pud(+e0a0LODcG(qw6et`v=fUPZ5Ycyc--F|>pFJPQ_JI@2z-m#ZxAKPrdBh{CyVQXW=P|zo$NT6um&y5QZF zJeB(Je(*$*bofOoUGT03m%@DN*Z<8^V?-)l@a|=vN`3tio@y1TbiunH@>J^o*YMOV zkxCc58^lvdC+xv9>MK&|f_Gc+TbNIJ;#HoyT%^(k?_T1mx9IXFC{me7p^Gl>p2Ga^ z=<*&`B&T>w7qtBt)R9a_oV6JbS&t33rK0h@t=|7^M@M$4K&65id6&31S??m%bNDlK z31H6sv%u{6Cv0d%S`O^~@JRyx9l*OEfo2ia@`p(fFux#}YdB0+7d-I-=H~>n2Yp77 ztX*JY1lUBFgFv-Bo3qN0uv)(^aL}M!#Ke-f10BOOv4$#>_A5Xue!iQ z37Gc?M&U5ayTF(Q%&P=5fx{Gbfr%6_a|mVt!K7vR6Jrtp83eEu!ROQ#X;yz2qkxGg zm?auaj6aM)z!(YUK>_0hKpcQQLZrJ+BmG*Dt_@BX)DZ(9r7d7J`V(Z2`V%gA=f=Cj z{DHXp2T!FHK%~+I@BYYBhvIG~Pqm6vy5QZTJoO6P-ON+7L@HhIZWvF!5qJCX48aqr zbiunC{1)clguCDJ)a4?TE_i3>sd2izAE9AI3SD%0V+!+c)#d#ZQZL@ph58f9Qd!0O zlYNXK{NAbPGTtt=;*@9?j?T+f8iEOQ3U#VdfDroJ*93ac->DBSM+sfvGYLKm@b1af zVW{sF27}8WxMYHh)ZntZ!0E#8ok(zz1hp8+4hnWX20d|Nv z&M?Qp&Xn&y#InSlNKb$kPoixEOFGz+dr1eZ_^R`%)(?6Z%+#iddz4x=$4Xkw=^T5MldV|?A-+(<|M{H>u#M&kqS=;ZH0}pHa z<6r3V#8&piC+yru?A$))*v=dc?1^pC##pI6cEMWdLxnI(!o2{QN;@EL5=O-sX@MoC zBQFD-$Y8cHSW5gMYWic$VjhhmaeAzrdv&(5$7(U}XEq0Wd;^=Ym)Sn%UY#0NfIJ0{ zVjA-^OlN)^B~_+!gC6)|N>1c`7u3xH+o^e@QEta-`gxyz@MgN&;L{9XqI(E>6SC!? z5jnUf1)g1yt;v(*3i%_P3tmV1Vhv^BM-kmzO>%1+!9O&dJ+6aK^rq<9Y-<>U&nRmT z%i7OyR8c$JR<(G0p3R;TPA~Afy@Jg-9Y)@#T_3|)!@W^B-yGA%e7(L}e`-SB-{Fwt z>o+L8THcDv&`itRrDVB|U3}TIuf^1y7tbnizzH29eoFuOWyD@qs6J`5#SUr-xv2%m znU4nV8`11I#|nNz`iZ2UDEf)P4>h${4vvz>n~iAsGi**XTK*KAVszsBt~$H4(c~v^;Bo<*U!>_M!?=x6r6P2`~k7pn- z1WJA{)nPj4&UAE#4Xk||o6{5qb%Z0kGLRz+SM>GcR5l>8jEakY<32^)$|D7+mH@FE>0^HU9x=_JrL>-xpdDt0G^h!0@1-($dwBX16_W`D#pkq)G#yD`C;}OEnUi?VHWuFPoq8Huqid7-9|Yayx#VCr?^`6n-qD zTqW<8x6$YgSB3bJEZ*X}0d5IpvQfF0pU29-gNnDvb*>1!mnx0CLwjw2NO-V}@-ARe z*JsHCC8t_kgW-l&CK#0;Qyhv>Dl=*cpTYmE7}{YG==2-8I}1KP{YEAFj0zzfAhOG~ zl^`dGQ)@S1Wt33F`Yvz%6#)F(Q|Y)7w#aUIGt~u@#3<&w;Z`#!nIm*$gzS}1VLoku zhs**Q#?%m>2-qG-KrBqMcg{BFU_XQa@VVQQwT$Tyd1X$CZsEqm`3|LmcRoz}AV-q|x7F_33Oc4A*(U;8Thd~9)yZRGwF z>Y%J7TeyC@^RIpteLtO55FPugnAzTou6bgC4}TB`Mp3v zVIxvdKgsg|_@ezJwp+#A2kYtaxZQbF7QA!W-XlNkd(}#(4it z{*b;pLPWmadq70K-n%|1-`BxUdL(nWga8O%ig;lM84kp97Mjp#l2pRZ)p$eL=ZgvW`|!~j&J#f1(jcpZ=r8Y zzWyHvXnx)=A-?6R?)*0ALXL0Qd7=20e|&NAElwSCnv;V>x0GpanlIN!gMbg`Chu2C z|BKL;;NMGpfpIPHr+BHj^ieI}DD3|x{|(lNoJ|)K&f+|!=I*^O2YzPfX*GB6Jvvxg zabhc&uaRE|K?BZ>onJ9MDMDG`&ko)%ziP28@DX@x@YRZBxlCE_qcJY?>@v^3*e^D{ zo*;j%(TzW-x3Me9UsCMK*M4;Di`NKoE6&fGd~tUk$nGW30+0v1I>$?W_MzoWxvMy9>mqq;(UcLa{5_ME}AuDg&^W zR?u&GnnI3I*>s^8l|OxPF)FIB0}(1TqY(ir&Rv1=DJy*V5$szHb>mU&!hwk#w&B1p z_Tj)UHsZi9cH+Qpq}XUSYX|E728GWM_|Kl+)gM= z728GWNnncuHYiRN+ePV1VEe+_RMnq3mq34l%*)NI4yx!eA)72;Wb;6rf(4&wvA{r4d*AAL6(>AL|g>hBZvnEBl&e0?yc(j;>iKIGZ|H2KDd|9g&@ z!1GYdoZwQQq6gqoJZ7Og(f5&hZ$HUlUvKff%ShO_*yO1-AW>geu8dlH+(Rvd;wS#=Dxj_ zGS|NDrY$D@iA1+TkM6$4dbF1e?V#4njb3hWSfwx%o>19{MgPv%)4x+<*1unlrhkX@ zH2oXED%QjESPyf&ISyb1*Gtyd=}N!Hcyq}jQJM(<;DfOa6m!jk4C@Uwp--Ie8_VCu zIWV}7GExX6xQ^#oZY>A?jDZX>-{?7oIg{R*=)G%4%kclg*c6iI_scnt66=T}2U!q> z4vy8$_?RZNTtEUIH=M007|+s?Aj4Az*H$+BKZtDC1y`GIB1$GtS^U6eM-=S~C@IbN z8ZtX;Q%F2Qa6E1ZK-1>4=^&ZqM?$`WBhj%Bb@W(o2_S_D$<)UYLdRk~B&YtQ)<%!V zh$J4$w@soY-#daH#xlXvwo!bB)q3jm+rkrn5!?}|8F8FSTC$CW^!-a?C*Kp+K zkM}CS)4UpCfd{aMQX~&xln(*8$o*H%{8}Osjs2t~o1rpz_^&)aLK_+(OIElZOMyJu zAWN=&uG6k|UpDccU99mlUpoD7JP6_w44Vvf{)9LA6QTpT_Bq*+LCZz7vp%1nM)53% zGCS8XgWOA*tBN!-^GK-MUXg^FAIL&oX-`2FeS?5Vtu6WR@HbH)PQP$5mNwsS^pV!$ zl^<#Bbmk+UEc7a=Zkf>OG2#rN^TSp8NN)~6iarU+wR)^M$3tKB$NC|qUp06fFi6uOV!8WZ%Wq2ZNA!NI!F$njpf>C zc?|7oqD2dh8!b=$gZZg_&!I}BG386E!?nRwsonJ3AQ{=@Hpqv-6hQ|RdnCF^b#vhu zUii1ow}RBCq}1g%a9WsaALn}m(@UK#mC;ir@W-AhyL-pR%OJahi=kGIw=5Y>~vPIRNE;;4_RWw=@(vE zUrvpH^wrn2wU^>Jhs>!wYiRHYokfK{(VbUKt&Sv18&S1TJ#;soM$|(;MuMn%=mQ8! zz+^_AS3QEvG3%j~I!MfZB+>NHw}B$89;!zZ$b~5X$3o zgfNn>e*xLT%&X3Ajntk)wnfnm^Qc(O9A!HFA5J$s?oX)I4LNwMuN!^`;$rV}=}1ii zqINh4NToDK8H-o`=|nub;q5KDND~5(#!hD?Q0mQ5R^pwXP<@0c<%z8*}@*~meg@F0V^SdIo!MD*up>6Oh^zevn za2K-4Z4kr!#7DzJxcSKml%qF4d1_xIx~uS3;=RuNWH+QltAlFk|8P3!MSnuA4qA-I z`Z_2X#q0M&SqQij(mH8Hovylgtx?;x? z;V7QY>Rx)SuKWFKd+!JfGN!0+T%VA+c+wGmuD3=G zmZw6X(HYa`Z`5)$9(n3Kpo=s;0BP*YuV)Yu31~L*d4d zfz2$_`a1McWDD#o8k~Gz-b6KeJQEIihyZ6`XUE^YgeHB?vq zw=YV4|A=h5I1j%YrM~%uUNfi8qW{Cy_ZELbZGBC6tY6=!QGD!jxEpF)NB{i#uvWC= z=`R)fNOJ>_#!hECQ0n!UHm{aYeVifv%N0Z8@v7_7?{0i|Bs?1t*-(t79q2uLdekdiF~J2+%t z=jc*}c8e%Qe-Vz)c%`7J{4;T0L^ebAsYtp5ZLpDNNU% zjhrQ!Fle&SCc-bI*d6Nrn9WsRczs*AU@iJ>i`)PrC2U~>RV#+TVn3^5?6+y z(b-}suTyCtWZ)eTT7fVHLXu*djljlb_Edyiq5TURel4_HHsPBsKe~iQr+Bs3lJ}(< z!n?gIEr1xO-g?eR?ch>*Al3h>wF5%GAr!TyHEKW!$#Z;d@x30>7GgU#JL2ySXbe#= z<)qg5QI~koDe>SN+#d=ds^~kWVfCJT(^^u*!y3fPHR9zRqO@IGSK@=AaHh8R0;EW|j8qYG;;j*q_6`y%L`Q;-ChtM~zdV@kk@u!GSc_M>{%Phn(+T z@?@X#WOtYl>K(DDNI}|=j5hzDY?*exvy=9*FBi`;90%?WJaj{l)U*YIN7aG35A%5m zXqe%faR$SIn{Wt&)j(n2#oLR7IJ8K7_w+5|)SD#c2lk0WhlObT9YO;Cr>LOCva==; z{-rTQ-MgitM)aMqVUdJ8?aoygZGk^O0DoGdNHdAYcZ$aki1iJLV*S2EQMgAu{-#Jf zDhl_Bv4_RDMp0BNhNXyMKyGxdw>YaUKwdim=O{=MdW=m5|$vxu9gQ`%7VTFmQVpvgPhSQfb=d}$ii=dazA(;%-9`gvp`g4tF zh7m)+`w=F57ml#tyJ$qp5HYnzOx-25Mj^zq+A?bo#8L;xoyHO3PM{EX0)w~{2*Tvw zC%&hXzeG$hj=)#J2ulevmQb-&;=4E}>^cTbO4~?lZ0@y>)rbw0r2zGkLNT++&;Fc};HHB3HfZG%9NwNtLC7Mp8i|g9@tJ zJohH|Snu%a61VNa64&4y!-ae6%TIUaH9PaXi74aVvCZW#dY(B01-Y5^tU{OjNwa&b z)jc}JRnJo8LY52HiOOGr6xTCe*WQ}r*Lfba_zpb>l5;__x6PBihX{3^BB{%~A78WY zH;PSX(b5>thh?r6!)C9wR2*{7u_TJh_oz;DOdi`$Jee8i_SYP_4qeSXx)~yIqZq%* zQ+ZQ7eJ6RV@>xxu4|k zk52WaVyL#Go2JnrzJ0m&40PMfeedtveDLrg@4W+`*b-n3w&6 zMi^)`!!E;Kk9D9(Gh?hU-Y(M8p&jj?W1YR}?H8%brDI>JYxLu;CUToTV zvlwQ+LkzPfVK{JZw9H=Tti?JB$HNvO24&_xoFv3VAsu$HG)xxkm@K5q30g7|PVzYK zY>l1vsao0*l2c2&Feko>VFK|N(hUGWy*#|{#^7}jpRM?8#Ag=2U z?I!0&)9iJkuR=X^el+^0ceZv)dS-s>I_hmtTHIqZUC&gyM`xgcN?c>T_#DBf8K2|s zJbO*MvBZ`4Lwp+X*^f^XKJU2m(xo@^@LvNyJMr0#&t7+VhR65?S6;oVuBP)A*PN~H zJZp|CZ;^O;gR`1d+8f_xmG)JrG*|huwLCTSy60HG?k-Oswn@BvPP{zF?wYgIJtuWo zoqPjgSbI`liYsr4drq3>iOrR_`0hNLd(P6NIVpF~Nx7ljJ!gshYx87(`R+Nk8`_h~ z7vEiOgY3^)k~C*2zunbdRV}JMi#vy?;f;BzH|C|?n3ujnh^m|DS$WE?OYS_|u6EaY z@$xRi>7=n{*VvWrv02XdO!w{;&L=3**z7yTTJLQT&I0_$m3U!v#xAcYZKH+%#IyKw z=cN#n?qK%))t#4G<1@O)+G;M~*;p`c>>Bsjw3_#f?sBVm`NO)rh3F;;!^#(Wva0|j zl(^=sE^&|ktD&aEHTusUb3%!G&R-30;qfw$(NL0<_gCWpVH;Cn~@&zSsMuCxF?4Lo+diUsM$Xx3#Us~cS--Nf6 zX{~$g61@DUd-P(wT<0!dgqN?oM_a2liy!|Hh}`9-r1BN+yp_W@pSX@>5EImAs)ge_ zYemO1jiTc_4Wa`7SK$8{yUk+89<#@qA{={#W4k!NTb$n}9P5RnN$i2m=AhWKhi3kz z>Gz4!Pr>5?hf2rO-SDSn5Qw8LKiWpNo{rI8+=>$&HKJp^*pXMy%ar61hIj5CZ535z zq}1~k81hy+^HzZGt4j=H|BBC_@mYq?QupXpC5F*!@L7V-Vtg=OtT2hn*SS^;4dp9a z_DTB6otKTcxtZ?KS$ zP70D(&<&7;PcOS6Pc%6hZE~6IzTAT+I^EAyDuWirg=|`ry@}w}9(Tjl70#lFq z25LPVf_9g$#2ce~&N3I`_s+lmRHtjs%9a@&r294aFsX2DfR?qo+Rin4az|i2boSgK zXB`e-vxy20G7#&VzTh4MA@1o5&N1Yb7|d6Qa*u%Z4z07L4!(8>9}>7_N=+g;ZotwS z`Cyi-7!Lmz0>*-lGjtzS_HzMe5%7RPc$MV!l>7rxF$40T_3+ri9xdP&0=_QTNGC_Z z+Ck}0BRwJkYkfLOo~?-%Py~t<{QD{Whe)6A!GYlR|9`4$X!newH6+>qEcmx?U0iD0 zM@El-k^-e|J++- zwgJ-sn)5nar(wA=%Y)?-I-t>Iq$x@n9!>YXgt+R?+G!i4eTG@?b@qj%E|%IC;fD@u zBU1{xr?JjxCvsfpaTZ|~GLb2tAE;-x7vQyTIP{dWb`}-Pc6?`Rj5zJUDckZ@v^ZqN zNSkJ=NaLcj0rm$SI`gVjl=0Cy8#wjoY^zj}%J(FVu8pp@(UvyM15;tWsJVcJK^q1v zMSG3<2k>>?!AAG(p7BQ4dAJZrwUqa5abX~)wyQB28b|dQ;fJb^YR;l{z1P7GcSzep=R(;lSz0N}N66B~S>hQ2UP(ox z#WxJRG6q?yc8aQdX?22Wcg@FiV<^>Qd=$GYGoFooz)qnFMh$n=N@)`+*!WBDaWkrmA`*!`HQc+zA}%c zJf6wOE2}sQO|@w9!}FtP9P@IPxO%Jw+AzLJ+ba~YH_jeQep}+?*fP!%7sncqh4jK7 zFyyryh5n}_Mh)NzhTUfTVAwTd*e$@&C0!AbhF_Rx65I>z#5|0_OJVCrqDPfPG|o{9 z7mddlIGd2n_oE-vCODyn5tYZe-nnz{-1*;mWpuf7=hAzHsKb`9GKF48Gua69=f5cP zXUPV58S}lLLM!yn_pr!`HhNU^?v^`YZYeVg|p+4Jv+mpRE{Ft|L*@oXcmyToe`;~t; z8|u5i>9wIYaD3k0^9Q}>4`Mlg02`{e&Tm3}jZCPEdTpq*^~~F2(T)T4&i8u$o;hr& zka5+7`V+qi^@oZH73Z~k&u&m$seje88@=B|! z$Q~S*NZK!yNDhhLhC^b=4#d(iF=P)8L?oRRlc){}+=c^V$d0%}(vdM_4~{$(Bft6h z7_xVf=ju_i?KlqIwWDO${v27aoYP>~E9Vh(3(GmWNf*@%A74ZEu4-Lp=q(pe`u z4CNcfc_|C>()cc4!b-vI8yjE3!Xlk+J*$iKS3zOt9pq2w<#(JLq(!>TQvQjSdYab2 zj@PT}dUahax{j`O&>9_=_-qzYxfWL$UG1(G5=xuI8ndu>b* zm&kU#-nDn{+FRCJRrweXNpJm=4iw9Zt2h-(YYJ(vEPR^qK`c=RbdsZ%^wvh!UfWoE z?P2Y8khRybAnoOVHPvwppM#X^T~2=vY3>t;fT80!-XO(&;uPaJ2OJ%T@OfWScjr+q z>pom=^*;F-W@TDyq^k-m_}#lAU42xftvWFMmJ8&d~LF z2-!z^=OJk2A-(gESoC<%Jf!-X%tNr1buU5=BRsr1ANh~o`3R1H^vW^sgY?cv;GCjF z_D%tr(Cjw$?gfY{+6$1@QB^trp7Rk0sYlFi{PPmKIxmUSUh-Q^NxEt;naFu%d&%RE zxi-P|<__0sj+YECB=GzS$FGQ2GsAnGm~r?zaxnz=^Imu|H)oJvGjFY!3wO$Ja^~Fz zhsO7LjMF{V9|*??95jC@Kjv(buOjjpI$PiW5U#b6gCaOU_~K@sgbh_39xT9P-}v0^>Ogmn{+=X@4liJq^Ab%j}s-xFGgXMB#w9Vk*hug80ck ztn|}0v4TEHCumA zkj5M?4VLxJ6UOpaoE-ZZ{vH)tXNRHn0%%PIt*(pN=0H2wM2peWIklX zm;4gWiIGY}FC`jbqEzNEsbq>@QYgm0nM88|_&W*wodW)vR96-VyUZ3s;&aOXUh4GZ z8D8TDM0~M^&4buS4zn5ViNR)~uYy_aAeUhdatNnJTUK5&@fAe8CXpI0B z_yV5ANVdiKt!6S?uH#_Qh$%&(rIbqWbxb98G&R5%|NBy>6gQe0U@=ET)>I>ns}T}8 znkW&Yz|=?~q(c(PxVS--SkfVh)b<-N6=VhX8aaxY{Due)>M=?*v!E1mZvkJW z-a>qp`^w6weT6#w%s)zmb0-SZS?o$@(S~6I5#CXza2>^84{ZW}C(%?xn?UX$f7f&n zzLN>BUD5l87ZC=$=pMvZLh40_@REaaZO>?+opYa4VcM2Un=)C*Ix4c1{Z*i zdh(?UXOmOj64QN)#Pqfi!hwhnN5st2CNc9viE0oP$IV$XFJK9##sblgMBY0x9EcF4$%^0P!9Rd(J#1 zIvU7pSjSFr9;NOTGxs960i09%~WOnR>`2`rsoBiZ1!f~tc zZWR?bzz&YjVeJ)dE$=TRrg(L={k zF{2rin_A(Rh^DF)6(dZB2Ezwm7gf*mY{1IxB#&1Zqf(&@$uoF5Zrqy|q3I^Q(0@Up zy{}la6G!wWy)ePBfI=Uv`569BjWoW!Fgj7J`QU}Tqy@S50b)&~ShKkVUQn$sj5dlj z=Sz@mu&d+T!IC?s!Obf27~b||zu}qvT7oBifM?ow5_TLb8FmWdVf3UY(f^+G&zHES z+0%hXtbtEf!eGPuNiXDFhaymPJ3ShzAfLi$9TKPnBy^CUjmNbCDwoxa&{o$Gs#q?D7b83p~di)TG_!Wt|Yjb^<+Nh z$^2poJkDl{HEj}#8$c3TkC|pu&{*-#;>k|*lVvn)Q&D+rLp`<$9@{M?@R9iiv8Kr0 z7xPh+Jn4m}`iM0rh;?b_4iY~Hlnm<#YSm;FPmRYU^_5k;f2aAwBjNjLdWy(phDFzW_W29I@^$NDpm^;e$E z;o#Md<0ZpR8+_;}hV|6vMnNtp#t<$QVHCmKQqh&4VAZd#>1u?d4^N#j$#mqvuVg;_ z`CTUs51~mhn9(%5;sFylGR3eT1r-~h^g5vy*@3C3I)NZE%HYp)O4>&tA;sWkW^b3S zb60V2E1hy3xpwA(VVmgK3rHRt5JTyhJg~{bmpr7wbEb4AUdW>ud}Y!AhM~b=XfvE2 zC52j$)~(XGkcn|2MIIOI%D7O#<3fM2Wk^KQ^U#&e*Ru~0OLa23!{?o ze27@HL#(ML4L20bDiCX?7+o#$NRjG#OX_{}%4lfx80UG6Kk{S`^<-D@4bGcFJ2rGHE91B;JF7>m&lsOUURUhLpal+-bUBdJ0LZ;S}MzjnM!LXfLq$ z=b=l&mkfLZLF2i7^sv9{Es|#RnY$GE=K}oQF$wW){GBn4I^#eW)Fu%({(5LXLh~ut zHhC=cWJ3Y-KnQs^YX=3hUG9Fe=DeLWXA!VWFsb^%^>N7^qy#DJMkYw=%NDm*eL{gr z{Re{s2GTMbRcXT>6&Z?zNyx48N82w4`1>VB%|iQ-bNfr~D71gd4Lz34W101zpvdfR zqzfKnvf4W{O3*d?Qx3R=?aS@?L$?*mY5@4N<7mmSMpV!Y{bH!+K@TjV9+xkfWFmFu z8>J4K1W6fV*Z@_RZ-6+Vf2N>+rkF(4x9FHcZKi+C7o*)rBw&4K&LHDJRAWz2TJ#j` zx5a4Rx#^E#>^qOeZ{OMShcNb?zAB!W?OkeJVDS>QTzxWmiERL**t{ZVmGno6+BvhCOiHd21OosIa44)V`qoi@ZZ!G^C zY?D|DJ6kErmlQ4ra|H|=W?tydhKqJgPhB>WGSr2> zG;C5{*Ew5^OiYx(_mFz1>xKXoKmzqk1a=OI&QWP(H!`g>C5^6 zzHEbGW;fttrZ4LVeAxz}Jv`PQdd&07-;({~QhkX=!(OWWKO_lIYwmaqGEg)Cb00qo z#A7#r8$|=~EpbCsJPyey8fen8C2~%+TK>Guvmb@>OphXkL&E#m4Z;g@VxlG_mmVcQ z0VO3;d^l@Ny!L|4UgEWvcLR&`hi_KvvT);sM$y)?!L$V|6OIAWpD5)X4h<_OH%avD)z=jbQ@Y{d_Aj@63 zzf}KQ9_Gf7q*4h1l~GD^-%3?!;Hq$+jQ^fgu~bfE-{GGQET@Y+`)H|do0NQ}8`|U- zz^~UP*98>N#Wu;L0t)Ss+vJwv0c{eeZ_XXRq1=AooL%gjF93~>9(!vjmCy}(>^794 z*Z-dlC`7AcNX^BhkFmQ;x*JOQwf{sxi!l)U^>$$0+I>Gnc^;TukSrC+JYS`aL)P$` zl)j<>s@QhlMgHCnk~ElIAGj`{PqGUC)#tj2zngxo&)>TO3b{=FK1l^d=Igr0nv2K%r6tC zE=%vPT*>7`*84XGmeWPOKLSNjXHf@A?kqf1-uD1i{Y) z1E{(jz5m=_boo2-;cnt@f0Uue-*-l73%N}G{$)i}{+>m7(fQjDKo#lzxbFA8ww5X- z-|y?9j`==t=;)ZUcM$r^)G>pAUr+DX@~EM*-1v%=1}PmCMrmW2AB->;0Po z%jsg999yH?CJ$tHLz`3qzh0Xh<}R-^dKcToP6b43lU-j8Xp=bY7B#R!c7xsG2SB4U zAARE6l_o=oe5x7yHZ-Dj-^)`PCiR;+tqoF`sRvv_tJiz*+2Ant_GwS=iMzwtR(h$A0eDLdkRQ zNeF-N_mh08L38jo`1qoF=$BpuA6*pcVPEyFd~ESG<>Z32w-TKv-@YzXUWg@C2`Wo? z4yxtvqfT43cG7;2)K)?5u1i;?9lc9ToN+Vos zOd)Tq;d-P#4ZtvblE{K#T$=gptdYv)vz zuwY!e?L1o#+3)?xV&vCwpbE#Yd+t)nioIVn<9bXuWIh;SbYxji{(cQqA^MjDaH$5D zuFOn;jYQR9g*aL=4V#A3m1F-r$ZGE{q*L+$9X3UC>ffr>VK{^xtit4z%c_b(a-0+A zD-Ft_W%Zq`zG|Gch0wxJ^10%ebh_(H;aU6AP?fc@w^OzbvSL57U|G~_rw_1b2-{9p zeO$V7y<87j-4L~wG0OFLpb967Pkvs-6g$7nI>;=3WU=zAhKwWDTLMUf7?1PS!cMEx zM|AmBribi%eq=H7YZy=k5CwZ6k@eF&m8{tL)pTEYWVwE1vGVJuKoyo>?YSyp!MJq! zm8*yBML)6_`E~x@@KyZ7Ln>LZ^J}FJvO+(y;5zE{$B94{mS3h|Tv5-X{NV9O=TVCA z)_)!)mh&>dd?FIQS$M0#r|toDVQ=czdEmifd;bV~Q^zqQk!@(7(%+k^Mk@a@o!j$r z=yFv=rRzCtQ%9$33{nNsg_*qeTnvqH-Ety`>KqxjdPF7ktda6cJ+xxrQ!{ib2zT>b z$GEH6TpL_tn>@KU40U?jeEnMtbR&6Fk%sl>8gbQa;b)47-M zw3hh%wC0(rs^^x+Nb8-(k>XB}D((cO;!Y46hR%KBdoj`Z8x5VbJf!OueDetlJ34W1 zbAD_n8|?fzv229%b_r*;%s4-QTd;V;yCv$KhZx!8i(E1*70a zW@-&i1Q|`Z*EZ{2PLDQo-{pS7=sI0&$^y4A6U;YK4$;59L`?K&JS=5g zgn`A9j24v2#YIt+i^f+d81ynWEiD)s1w$@|&pqdfHD{g#MV_y>tzd=!(RzH`8O`*K(xlMt&W0MdjCB ze!3#?%N$BqEOUl<-5zM>BGKm!!Z@5x*AFM33Uto?Ap(qi;@-eM75uXY_NkzmlW51# z*Tc*m;zdp8y`#?`gmDlNJSdRhe)Oy#6YQTwfM7bWA22?Ln?uBjQp;a04?^Y<@iHKo z){wbGoP^RHK^P0Im^RZy&n6uAEW@>YFeKIWj_Z`ih&%Dg!`{NZg}%79kc@Rr<95lN z$(!U&L*Vwp_0mgYvY}3Xy#t)C$7?IU#uDf~WBF?`X3tEMXAa%|#O<teI)gkCUir(Fdt9aWZ%z9XlDrNP11#f&vcUn`h zAsFiWh}_vU9ECd@oYy5E$HD%DuBzuFT0^66Ia~GpG?|rsM5Z^G+N1*`vz;RjCK zRI;eVom^5?U0yKKxhd88v8C)@vBv3xBb0gBi3w##aMhVF+F>e?1}&YQWc;-iKYh8)F_&~qRA&3cZkM)qVce3Y!P!UVlI-+MY6f+rWTyj=#*qU6%=FwX%;GF zh6>KcaFT=i=6W)3_LzralifD2;)VoKwF5n~#O+BS-?3GjMb%3H=2i5;8?txdO{((d zv;3wX-h3>*;b20P=Mi|(pI6ZzZ^+z z{AL*5jF;Y2D{p=Qai3RlJKoHY-guQaH{p%5HkH{7nS_1GNg#Hm0fB?i~bN%^@-h9Wfss$PkXCuhhB%8;*QxI@hVj#ScRS*e8L zpbP~{h6|e&lEA3Sx77^ulnkTDo(7u6C^_oY9AIGO8)}Ya!8r<*9KTd^fU%YEFeVdK z9h_sFl4FvZ0}QYHiIgLI{zfn5m}bv%KWcR2*hbPLMc`|u%>0(mAs6n#zOfmbj5X&W z=`|se-iIpV&dD{@fZt>!vayRh8&rXPIHcX6FYWyx?Smlg!y)a47Dor!@FJF#NF=%+ z$}!Y)=ceft_pB6@1-FFJdR7X`%HW>WaxrRIa=i*JyIxyjE-U}C%gT#hmLz@doWjd4 z>^2k@xxJLK#$0w;%RY`)7UY+D)tDm42*jd46z*V%#a$4KKKdfqA0jvyVsRJ5qK~3- zBFdmrr*W5Erv$2#q~ER3>6y^yS)SZGY2Y#&e463w4$^_s!i`Wq&&Erg^2j7A$xEg@ ztcf+o>#M5En)AyyNh4p`>rqB4xQ0wJ{wH^^LS@9lXayf$rRf%Z2GWRy(F)1trdt$B zs-A;hh3|5Cq@+4VT{mF$gB8%%V4*JRYoK)w{`N{MpH<)*b+E(E~Tb+7V@fB3{=t&6cuJ6 z(Y8d71w@6X>^As8x;k{k$0IE0JgaX*w+*1ri<%2B*o0bBGrTFh*W+eA7W?FT!OtNn z9T>#?k=D}Qfl^8hZE3ZrLkL;4A1b`51?KQX_bbBx9v&45i#cM%-5!6ePbYfv*(A@(8do$Y23uy{XO|Zig+kT_#wncsC$Y^mTCi{HxFzAV+~lb!D;<&Z4eNECS5w z8-m2?a?vTg)sw5_VQ)k52hcQy<~lX#SG)m0<2XqM-pCsOescL8=09+?v;ha8WSM<1 zw6k^t^2joAx!egB;mgG*^L45{FXVlw2z^Dt9lH0V;MQzA)kW+l z@u7;Zk0`ifW4B?oYB_`L1$-Bhl zV`B0-Y3&PA?N5n{%vzT~RJl!mwJ}VrpV$X3g z}bcl{isJ~sDZx!dyz|Z*@cKiM=dEKp;M84j!co=1L59o)VHM~hq z=HZilN*%jnXK(U*aCA-VDWtD$Vh`M#bWHDn`GPQPv#Zdp?z3-I&P_Yo<9H?ATqKXeP!2K#J zdr~+)<0Uutj_;Yo#FOIblT?%Q$Eps@-7uW)<1kg$yVzO&ewjFO6@N(VsTF&+iamR{ z0-Hn!$Xzcwwul)G;MI;K61<88967E3>b-}`*D92_wx6hSZNh|1U6<2p3lR{KF)H-M z`g9YQ81RH5vb?Pz08L@f%;Gqp%`_W3|7Gydi$kgSO~o&Hq?QlQegp$J`$`QtZ%cVo zBIf-E<(1@!a&y>Y*z&kTq69j%n?@{leYB&)b;$YdB~SJ#Pj-jt`BTrb%U~jg4))S1 z-lv{yd6sSQJZ4blGWeLEW=|zST#WXC^i+BAYk0?XuI63Suyf8j69l%Z8qZ!Q7yBim zv=fowzHnMh?@SN_&WZt@$WvJcAqF8U)xuXpDvi8AOQ6G2>EXE<s1yq=1_g{ppx&$$xe_#9UkUuRM0 zPER_))65ji5<=45$ZQzKIV-*rXW2M^!FtmsyczdK{F(ASv)41gfR+o` zOOpLW(i)NMGkn?wLYo3EkqTo$Cnb0J5Ee=ZaUlQ1OVarOt$jRj zZie}3U%@9o3dt-8OQ2QAYhT$;ta&e40y&K|n#!x=zXwm#x(6!@g6>*58HEgxNr#VD zCLJ~ci7>>W34HG-9Wy#If)A9IHh<^49hevE-$&`DQiA8mLG#1zVOhvhr+d&UeO;{s zg&&9RHteEW1bDUW4sJ=c=ytTR$dhz5tB`yV^VWfNAnhhd5~IkJKaI3?KwAt*7a&(J zOLvBX_NK!0JsBDAMld3w76@BB32|T9J1{z^yjLNolM0mk;LBnAV7Fmcc^9#t_&Ia= z+*4&uUQ>qaFWpwX@cpLS(8t$*x{ZtB`%$-{mt-QiodRTBGCO*cv2E0s#T8p>?1o$W zLhfM7ZrkP{N!BKf8HXyb5$vo?)&L1*fOT1Vp^zny6r0hb_3UdzBDTh;nsMO^=3StS zcd6pRlH4UEA@Ulw4|WN4x6&7OEkySR=c@CxV*fntzD+vwG-2#RcQO0WT}FjOigdZ-$@||F zD$OSj9N~;R#Ho65U@vFfDQ7$qn2`>FyChPAx@R)xtJjDg7SrH96a&9bc*Thzet}oS zvv#j&kHD`JM>wOFUz8C%Yd;d0F)n^xEqa(=I(;UY?%W#6zE2&;?(Z|n8%Ul5*CVIl zH7o3T=d${d=3X!Er^L}`UQ^CMhuFA2kQRDu-;1AEte*Irj$*S8>H{Mx8sBRfEtbvfCuBHO+WcCY>F z$85i1tF*=#_7F~}(luc_0VdaubNf8zd@PdE+}OQ=4b$9DIAElR-BjGqP>@zq+??KE{2M z=LA8v6#sSCd3hR;(Qq0V~E`jeZQ1XZ@n3KNfg>UZZr%&ts%3MP znr;`Tvud{TU&InOWFI?le1R4EvSDow!wo7w>d%jx8THT(Q82CpfuP%(dSF_tqiiuBwPAU(He&&LEvkDN}H9!@8n zm3c9iGY1aa<(I>ijIB>9XRH+A5gTA6-ik?bP`{MVTLtt?fh!4|R@*oK6ldS`6CeqZ zpMb#r8AyPfRwY2wNBC1nL+?Tt*Jh@NvY7TqJm{Cx)^)y$u-B)Th z;NC5~6Jh}eTj$qtzU6VO;GV)UquYcd6DRmuMe)00$|-TOR-D`>9Pf+bbNugKaq^&i z_K1#lSciIy13X{H(Il(`9|D?3fMz_<;7KNaVnKt+zct0s;Q4w^H(+tr6^B$QURvY> zP?-16Z>4h^?#1?H^t05yoPH|pEAUg|Oak8Lrwhl(F~Tt+LpY|Q>R#d4CT27n#EioR z(cu*xh@br~4j$m>4V|Gme?pw!AUaNo^L1jzQKWj;z|ZQ01IyO)$d!oaIQer>%s7Uh zdNISB$Y+w;h2tA2Z)UM@91)I9QW?jQ8)abad=tpX;e$Fm#d(|`Y7-sR;`}DjafHKl z@22BT9cRV)bE2bFbTl(L`}x%_Duoi)z{wCyw(IO<{1J|J-pIco9J|HDWG;if0dsihD)HLs*86NEH?1GZ3it-;9@K2s|AZFCPRip93%Ff|n(6^76}~ z;%ngLgW%;iA&B3fE*vAqpdSMMw<SiOvfA;l)wlXQ&es8;Y-O7%h36OZP#Qc27~PLq{0ZG^LR&)FpQVHe zuwY0DQ~e2_Ruc|QD03oV*8Gk0C?T#xC(X^k(ZmdyqLwcrDc0#+CGzVLFc0Y4I}Zpy zwMn2ki82ph-ld`iGhhT~S1Dr6KNIGheAYAOk|*;9kFBpL&4HmBhg(Z=q?Rtw7uVoS zCLOMoPQ%T`(cWjP#auccJeM4sJiD2GQ#{5OL@73J%(yLXg(n7EN=VLJyHU<+rYu%D ztId=76*|)E0A`07A9(e^-EMpp*NG`_3F$2F`Ss#F23!90ZaQ?@yr?VOoupiT%5vu<+wP1O3c`eBfxub1o)Wv);TJ@bgwAh zDgQO@7LNU*u}QR};%Z^1-XRQ4cyUC?@J{iq8ZoI|oT?M;nE2F-#`U5dyR@HJMOOP6 zI}*jIw?z9}!jX<@;lwX(KVHP90j8m~qWFX;J}#zg5mPn^$3famnAj>N){Ad9iEp=w zxwngFPYSpspo5y?*#r22mjV;>3_PBjnJ=C_iyt&Cc}Y=i|3xqbO-Da3^PrKb&w3uX z$Fa4nW0w-{W~6xeg*7R&eK{?8>( zdK&s@s>f`iJr$2F1^ba`dx*ejeENyfo5Kh|ri?C|(B;bL3PA3x(LhEq6=oAK#xu>H zgI|k#rJdA^`#TBpnNrK^bPktwqJk;It62x4={JH_FpHws*IROH{bM2XgBAZa;5{iNl z6bXzWNzCob2u8!PP7$kkWxuEpGBX9}ra@-X6q(6P3z8SOScxnvX>#Mj!3xz$QVcnM zS+NDk3Pdlmtfb56G6`L_j4l^sPA3r|p(!IEAH#PRM36ksTRC2kaNrt*`3~X0tj#uz zq@#ePBftBk0~>g>&v#gyIw}r)hPUy&TSVhl@@0or%_*Gqke@aPXcIVfXx}E&bKnJD9fwvPSUI@(-=C|752?#wd3qPLO7}}TGO&E!>b!+U0PUlLu^J!14 zAv4KkP^0gg{o#AxXr~+7{KmB(&W$&J=91)W+STYfkF*(-_CwdHa~pswp)8H#p5&WU zKbM9!cmo$A5$3c}EUJinIeC(Ui7 z`cmysU-J3tUTwGI2a{~03qf3{O0M@%#jpNJc6P>3_MtvDB-6xkxt8@I`a|loPPabf zyzhH|g!4YG3pwxWnYEGTcnGhE=5nuN0iuvu!Qz;$ietJYj&F$&acuM5_h~d>CEr7M zmFxWhYMn+I-su4nNmZoLTargiVM!iI5Fw9g_@UrJ0rEKYQ^E2`(%VDik?7aTBiCo0 zZhc4|e{*Y~Jod!eKprEt59vpiEUn%c`3baBoK$Wf^!224iq!78bZI4{%!Ok9d+FuqLyQfSDJ~? zRjwe_$FG}%`iL6kTEc1%;34%brHuxm=K_6 zF>{tewn+14?5TKh#W2jQSqbbCn7}_{R-y<7VUTCbe~0IOWi(g&1jPhEpP-2e<|pa+ z37Ic{xFdLeLbDmoXmPb`K{Wg2ets+0VV!Ors2x6!I%wy}J*5U}JH)VVar`5=9fH;^ zSGyg$uvU3-ZD2d}lp3HNcnpkpeex?qnDxotFQK6#u1~IZO9ie;;+balU|#8e_($K zT9RC|8pwK$<|NV9A(=Ep(lkqsJ)oVL;7E~w9pbGK7}$bWA^tIummpp^^$1*nXa+@X z3VHQ`^V|jgvBcRLJqB>vCRuElW?Fk_V*p8VR9Z>LWPsM5Apf*R zbGF*CAx?2MQt+D%dr}Uzl5*WR_vFdG8DWocX2I$){}!VT1(dLfHIJFAc9wl+6#R3M z9hpqDw4;Y@>m-Yd4@y{k?nXW+VL{@)NSuzu2}tbm%p)w61sk%QWsI8Vaep40oQGB` zh?M+EQi6*#_wqW~31R*`N2 z6}GPBg#62-Z;<#=;{FA(rGzT&#k~*OM@!026>sc}LN{#+!uDdn7j*a2^=e;%OLa(A zfn*iw{m@W0kCpc7Q1SjiFc=8#0|NcH0u}v%fE>}?2Lyduia;XjAhkbeCoy2!+i;0Q zqTSL{X`d$Db189;l}PTRkZkIy6#oasrI7lz4Skx=LEtwNeLD+%I~#pFNA24df8S2g z@7q?TZ<~ELJ%jKrxGEH_Z(Ea;zHRm$nxy85*td~K?%QVHi~c-e`*s%kcBa%{t?1k8 zIjNb*N3zB`Ahd5=qx5YYtHB>SZQOkuS-O&w`?hrGOt)`aqxWqT-NnA0BK2(`xFUTU zv`6dP*Nk?ZzHLp4*0--2#cJQic?AprSo3Dm&uTlIjV5?-CWdUQd|tu7_VxMx_CZJI ztNgUx)xv?MUGK^Jzqsfi*;SQ2D#@}M#-yqwP|dA=YpQ?iO35c1QfuS`5(xbK9?sim zfJon)*c`-Z1c1Dng#5>CD?W;GLu;c<1u~75^$OQXV;q+D5M}#Ahz%vg&P@~5&w}bGsK7W5!=bELbfJy&KZ&c>O1tyn0!K6d%&f(dpk`E1iA zsGzGyl;#wZsyCRgOJm{de(-fgtISu=NQ1=M9>Cb2cXsp~#wt23K6xE;qUXtL_9duV zX?MZ(agPw%0N%zdvu9d*pv)e+*wdIRk7q2mah&7)rLQCO9H#-bd!5IUu;)0h_}D>} z;OSA9_S!bQ8&ah<-{(G78%*ac;1#cxvbpBh-I%z=IEOuTya&x;kDTuaJBQ^tIr=qK zE5e+d2BKR~AO9G1ttaLE0xJ}tr(&M76ddb$V?b7W)S>lS9%5Gexn_>Yq|}GcgGIjgQ87Kxei3w*>Wa^M)Zvn?GUs^v>jdzY6Emd%=43s#%S}CD@J=5RdM#Fs20O3M$YBi3Y+)#D82g^TtkXt ze!UvZ?3!FI+0&Ec@|*o)8^W$SKVzN~a_Vv`l`*OV*|W`HBzj9O8dla`#3hN=&z@)W<{Pd2W-J>Y)>)IGwR>!N&5W9H%1*Aui0uOV7!c3zfalTqxAco zeR?i~m3|nP9nZ9_C&}-2ld6{^?o?hgAy#-CyUzaaEj>bKFU7<}V>Hs%BQ~9V=*^y? zvv*-8qN#|avtzJ*eQRFex;x1Bb;X9A`L(LmOG9g9e=~otKsU&}C&BMH;u=t^=<68n z$|n6Xkhej1Wv?J_i8$ULCf>$!cWf)hYrQ)MpJX$j#)n1l%`wf7Y@2Hd34b2ZW@T`zgO9P zhH}u2(#Z$iu2`#MicbYgw2*Dv;v0`0581|I!4bDrL@gb0yBg%ouT?KRDLRPxxHKvs z={&&+jJM23I#j@{ln%CC4a&nX((+D^U}XIA_$Q3_Jx3llW9tWkIgV$A*HR*-F+2`= zoUpk^$>Y2OJ%o|!o(c0ZRv$Z`sAuDpUtN*2!Ijtoif~8sis?;_qUypO+6U@Fs?z2= zyiaN#9e+qyuqsQS;xUs7@_n?9buNyDkov?BW}(RnYgPYbz~}qkCaiJzDc!5!Ax*hg zam6T>b*+4(f(9txa_sqN+a#o~Mydym9WQSL_tjzJ+EwJh+W{5P)FZaJ#JjaUNq2t& zwTUv9xK?hkx-h?RZ|G6_d=>VSdMI<_pL2YEeNU3xvDjLQI_J1nlB>}PvCWHjRre^l zZO67uk7aJ)+$6R!aON95Vhqg2{O+>Gz!zWd8Dro~OzJchA$bq7M}*i-$S%<|0;VXQ zfrR=fy<&5bF!r5jK8&WX)3=|%y+D8uqhK?XdU!3=2<1P%7HER1QAkwy7|s6F@G8VW z&;E2J3DnrgG(1#oJJiPQIOnU^##fTGFuYUgBAZh&oj)eCEz4i9kJ&3pS-?CdwmIUd ze?%K=uLQwiEF`y|i8_P15|jk#mieu5tm*%@HtJY_nMv}f8U{7{L$=kSD1m?bw;dqqz_hy7+>0b%T7hK zBVFNY$mg5L4g*6w88kdmeQMtxT8%c}K3tinHqo&mU72bq<|ECzB({0;Xx?cCR zyo^mh|9n+X(a+o7>tW2)=!e+k@~bcR5V`yzybnYj>aMP22F|@=lg)E4^%U704u=Ch zjG+O#KeqAfzgJ%C@$37TgK1QMKpiBRh&Fy5ees%)U#l_q(o}+VZY=hmt&i&4d#=RL z8?PND9rRsGn}8GksiXONUNAL~hgx6HSB8g@J8EexSV$9IIU;$b6p?(jH2pPi#4Gl; z>MdCHxTgOgBgiZCNSMhteU3H#Jg!fhZ3*R(U4iyWslYntH#YKGJBEsP% z;;XO^zKZU<7!nSTf-g#uOoM`3;~LYaypqGFOv#Wcj}SOFf5cCEBm;urr? zFdq7M9)1zGBMUsWf>#!{St0r=0w$WL3J1n9+vmmf<(v(16QvB@7do-@Hc{LxCN_(* z1Hy4eOgbtm%Ivemfs3MIwtc#A+$WzZEr-c`hVly4$z&#w<5eOZi^}ytu1JZ9}V!h6UBnNy00&puVr7FjmWpz_espX9z7Z# zt3Z#wC4?!t;FhEjg8I@r?n_^Ht&{rFI_^vKFZZR{_AKs0D8h_>1ko@<;%j?+M{-brT^<2)DWq-}I?{cY z&(MbX9Z02`++ zMt$s$=!y`^qfuAU#qj0p7okTYi4anDs|bAqVR>H|msB|pO7ItG9%qf|Ypyah%#)oM zGgCaaM_t>8y@U1{fcAMz(>`dK>C>o{x~+YR!}W1Z0}YMT$HO+zZISvoD)g_=K#!q; zoRTAZ#65rP8|YeQH!P;;R#x(*4n=Gq>D*%2b#w%cel}4$$(|}oPl(bF#PkDbq-K0h zCUDqy%Fy@E8uy!Do)L%{(r%+aGjpH|#ndz~lEr zdCdM(frI0H_t7T@339;eQ4z?Y_c@p&A>y5GlhOMeOgKiFBcw4K_8S@>5>->Mpg;{3 z87k7qP|WpXHs7dUnB4LYN2nLc*aM*Z;RyAj_Ya_64@aoi17?poshdPdqUfO*D0(O& zMcpRTy#$HU$m*k)LsyMM-KJlqHbYcTU4^D}{QQXBOx4r9V`0Du{(!OD6i_cB8mA(w zpk5yR|IMRr(~G_OEc}Y3SD#_TjIM^dUk+j13s_^qM)ZL5O~bAu0qdXlLf1c{G%4a5 zGYRWQj}>XKP>8gEj7hcj#6+SL7P3;aL4S&4Ohk9b8uMR+$FbK(Su-PU9Aw9~>-eiM zCnfAUy5nPyZ75kKQWUF%YLW0@{acEqu-T%ptCp=28^y_OWR*C)T}-YMliw0^VYx>l zUNf83>7!m^teoeXO&%k56s{C|1bI;hkA%PhOo7>CI<7B!XpOq^=X`90&gAD2Ai0{6Y*mn zBr2v2GO3)7l7@Kyx3Ij|w4V-tg#){V4s6doSxkI(4tuMACRsx=a*> zA{@Di=&S{X@IAIL(IlTuqWMpNE|>LijC%a>$9V5zHlN|Lvb#@@vA=L!4{bG2c$00+;1goucxqLvY<=z4J(- ztHycQQa94HEZz5P-AHr#o%Ca^=AZPk4Eir4A3v@-=ewq|zI7whmr4(7>BpH0e3_po z$PTD}FhOa6%t`M7N(W@Tm7XnA(=7+o)}NlO0MullbSnX+529zqfR+y-XcC}lLkXG! zsF1Ntqqhus0d4&xy=?}xcmP2@K(iT3E4^iiB8Inqj^0wVMH|yc!Nc2crf1oJ7TX9~ zrKVdAD2M4=3ng}eeHlU z2GZM$fYMR`jZ7>0QVSj!Zv=|r^vVRNh@mrp*4;(V(g3aEXX$_z4<(i@yDlN&;)j%X zIUw8T30ey%>kL8WehCR>3|Ro#Gh3dm+9@iBV*IRgwgX4~e-U14vgv7D0-#0jQ%-7t zg_j7T21suwh#H`%FO^D6oc3ADK}^iNogiXK8$-mBoIB_lv1B=*vk&&2SDp70jq5$*5Nvr0g-pCCFG09yP5dbAorGOTFlb~gQ)^gtEfNYcK*$P0r`PoW9&HQW?pv6V> zb~T`;rwCdLsNh=!tpk)kk)UcoOOFwKwSd|x=vh4=E92V=Xwf`+)&MATK0&(yP5B`~ zjesWoh@d7w%bf&yDIMo+2Gq8Ip7{Wc;b*OYR=em~8=$R>?+l>kN_y4~D4la$1Z4jY zdN$7p3MBpkTK6;J+5$kfpELgeTLeNS;lNeeB$jVq&16s*>*8-Z(Io1Ih!P&)c zfXtH#N(GcvNu}8VHGG?%r2#7BXX${JJWJ0q04=|VpiDs1rVx|`sOfHkvH_)xCnyI{ z8q=2xDE*7{EFX~ZH$+tdpu(RKGzQScY4O<4N%!4dNv)<7{*ry$l{@Avj8o>kD%FrihoQ{1GLh*<3z!3(pf_ZY6O&W z3qehQW-;UiR6Lb(Gy__~&wPOFt0-M7pjLj?2B?{_oS|p@wjGe~WlDDuP|9|K5|Y93 zX@t)RC?}PknE)-|9A-d^`I!Y!8PjJ4w1_dM09whA4NxsZserP6O8D%6mcK^$(g3Bs zL{K`QHhz`?sFI;fK&|{Xi=dU1E*ntc{}Pk~sFCsI0?K}!p5+5tz&Q#C;%8$3ZMD(c zLO|(52pR_{pP?c^#S9e#GX0d^P69NKpG^Ve8&A)s0jlL^(*ao-Dg#vf2YNe;-g3Ix zfKvF`JV2A)rni-VOw5A?fU=*UXA1!p@UsR$Qxb?Ty8+GnG`(#Ew3MMHKo=SE0!m@o zZ3bksQ#v1@%2x<#1vH(XwE>#KInDqo_$$3_2ef1=K^Fm8b`X?sJvez6w=bYt&T9hX zV|->nDW9Qq7C^H)39a{B_>&Ad+ow2oUV9Z>2Uls5y= z3eJ%UXdX*l7N8=gFB{OLiIgq}P!8kE1vHKG<^!^Ejsk+XmSX_phZ43z;Y^ANsSfQ-)&G@IV?vw48bjr6P% zP%77G0ib57eF074XAOX)@pm_%^k0)^XatnKobomSD&uEfK-CO20~+(6l+LH7YX!8J zpS2Nmit?UOp>{x)Khm>{fO6UhN`P-SBj=!)4NVN00HyDxw`M?Tzo9ZLfTZ!)3TQb$ zO95p16Q#2OYT{?9fUHX?2l?Qi%}|<}E*;P+ewG0!o9W9`p)5eN7)v&wES@Rl0LtYY zxqzA($_HetqjC!XrT&&mYXBsTAG-mSZKk)4fL5O;s0mO5j~`w@)3(sFWc4Sfio4bU{qWiiu&mS4=zRstHw&?-PHGU)AUK&cF^ z0JP+D^eh##-Z7b2$6(Q8bZvAVvpPF0qVl4^dT6t#^kQ{{sTY#3;~^szYG(G&s8CW{ zi-r@F3ejAYMGy@^(^$D=;O$!O+N8D$Z=<3zkS>#<1U#$cbUA<;Ib8zYZskct4xlC; zu4%xV#yRXrH@lj!kdj>YS%U0Hx3Y#H8t~R~lV;*=^WXRxpjizBWg^|I|0BqVXI9Re zOAzNZ;_aj~dYcOq`MhnEHydvY zm=+oUyl?R{q|2O1kQvXWaD58^6?0xQ-mYbQ1%MWzzANU5%GCFt$ z;5FuUeunfH`5CoKD?g)lX=0vHyDUhjbkr{9T7sxud|L^kc3HWWp8?8eI;mZ9{z=cM zT^8R#5VcF$27ZRO8F%tCK+72)O^;?X1u00E#t;pu)0mbNq)TCl+HcZ-QC@04A9I=7 zFa6K_4C!Y7gCJ_ZG)_nDx02Jf1Dd{&-ctKzGDPiH&*`ZB^0^+=ev23%wOr3t2#QdXn9>?{ib{@n0qjt7(8Pv|JwiA8X zNVn8U5Vf<9@liWhGd^nPO6DK6b2ejMOZ7cRIY?2gVr4`N=C-r+j8w)fezqJ?^Kg1b z%46YO1d*aJ-s8i9xojxZIR3lHDrX#^)%UdUl2%my-V9}vTJ~v7obf#M3zTybprzSL zitiu=E1Rm$vPlx6ambE&IFc>Ammosf%FhVNBt}vUs9i(ech?vV)= zl}#5qJ0Ug5>{Sf~#!r(nPDB5hbb^X424rg?hztcQJ|>6^1?~MvLz1E33|nf*P|#$j zyksa?_8Ef6P;iDJG87cw7HB9iA0}L6C@}3Nhztdj7y}s!vN#_Z3Yw14TQU?h0fS^H zSn&sXMuvj)2Z;_c6pZ@@y(L3|kDrmDVEI?+Eg1^T4-rI$g0im>M23P%qX=3CXcp%s zLqX~odPatV#r%v61#SF{3nW%X!IAu=+WAMuq|_(?^Da z+25mQWGEQNSjbSY;JfsU3*QTondGpAnP=Gwg^xe zLyH0Be21Pb0aWiGXel5sKU)T9E2moysCGKNT>)t241!hy%3^30ARnh&4QO5|y5v0t-fG)u>TJiFR#+VjEg)6OC%G-`ZEJh2g@T#~5Q3=Tp(H>g zym#4z1SC&M^8cRs{WcE>$jjFM{lkaN@BHR*=FFLM&di*d-;9RV0okWZSe2yH&?ca; zA4ym>Q1%RgwgJ7M!|DXm>2?EU&Xia`P>QZ^J`e&L@TsQOuf96;-SDNuw!qlC{+pd+yYMFN%FB~TR5Yc7GJf#RkL6a(aZKuU7~ zrB9NuSfJ55Y&6hw-+v+l&?!{D$vASfzp7MUN2BO(2}PF$^d#jUFdsQV&_X(CeS(^HXEoQPr|Z* zp8uLa*+5607AO~}dbB|EfYRm(RD}(W-6ync0!q77An6ISH6(q`CJo6b?cp@ZA^r1V z9VR{D=>L)&(&r>!CXkHM7F{Bc^v{QNtn`FUuS%HoImN343ZpN1S*Mf!`30ReYUy*c4K#>}Yj2cpPUg@8Ubq?tXm*}t*pxlckM=H=J4W$7! zX(%1Y5h<}5KubRo=wYB(9hM37@pJg3pf;Uu5zt{BRwe1Qery7&yF&0)10B)OHlXw?C9Do;_E&WK0?pH5exODF zEwS}LRXVH*XpPQ$7%25MiER_;9)XSk#jX}8OvVq_2tFADyP_pbMm0?upNt=Jb(j;V zME7WsK(QLLjI}0eNJcg38j1mm*0L)jz?^8km=AtS(rTIyu1 z6{YEuQBBMgNtXnaah=d7BlB1OCSfwxa_Jm0s+p&;qySBflGs$Bmo=0IRHC7DplS_e z0A((gbPofy>99Ovx0?h+*>97KzrPUHv2vnf+ zE(BVl@ht*csl%#(%>H*1P==noRRcZ$q2%2L^qLN<13IFi-9XPR(RQ~dT|Lk?9o7U? zRWErD_dsnxP3D*psIWm|#ZfR(=MYCh>`Q`A90jlZR$|3bkgLPQQDFAJ;wWg-Vd5xw z{of^>I11waUGj>fAX7u)D5%nqI10>k;wZ5HR?>;1AWG9Gjsg=BN5MLcSsVq~I#wJ7 z&uc8=D2Ug2#ZgeArBfUQ**Z)d1!n&tj)GUTlS>>0yN?Kc;wX5%SRio}EZr!OI0_;( zB#r_zoj3}XZje}U6l7j3awU!e6B0*3lD2wBfYKu+RvZNx8jCmz(sf>O6fEr&EaE5# z(_!K$F#8X26l~Kpi=!a%Q%NU|f~c1@|A5joG6-Pm?=8HHA3U!!_>)VD%4jIkArpNW-JQzDv!o+#- z##n~Ep}BvNy-7y7F^nIVd|l|t0IJuJ^hD`edYo7h(>W~GYt742Qzw!q4#hxuV|VxT zV#eL6o{sSBJ3Spr70Q+$PsatS=tUM{_2Q~3e48+alMJVw-wuM{WuO;s7U%__*W(28 z15tvxC>xkXW-~|fE1?|O8j>9G8j>80-NFK6Nz8d4=1d^bzJF$*@RRQDVurk=NQxJd zWscxrsWp&H3~9|(;$h|*abWWfsfS4ey>Xv~;lNI!NUxWQWws-gsBaRKQi-$?!dW4y zU{r8s;4dULlPo$IN|JI(C`t8I!I{STKrxAmxnRV>Vz$$N)AiOuwk%ZNEKZmS*=^FA z6XuzZ+(nlPf&$1gp@l#z{#)8h4t^?(me^vTnE#Qm=YWpg)h zSIb*g@|(PcAO3^9*pIv+4~J{1JR&A8mxnV<$3-4qA#YLsx8xDM;+s-V?7A1_ZS-sZ zCXcx6m*p{b;;ZtA&-{%%64(8=Jd)ymFOP}wA1ff zSpVzUlNKr8`FVl`zOloW7H|Ly=kWNlzhdr7EThfL!OeD-1qeUJM;J-w%_@plVq>jbntz`(LMYkSC%93a=YB*~T{*)k+s*8SyrAD~$;{RN!4T{Q|? zbRFgV8`&4fSyjhWuf0sQzuQwu+acRQPl+?9ipmvFm2Dr!n%3&lI=fNUx`mU;9CB(jPhXaGu2G#^RA-Iq{KU2+8UqdJ>S$SF|XCkuAT<_x3y zemUbu@AaGLa_IAVRAY&h<7SV@eV|{fGS{e#DmiT`vsz`;spd-6yg@Z@Rn5Cq*Lu~p zOLcW{@J!c{+j7<__Xq0n%`vKrj}+HP9pp%gK1b`U4}`GO*qjL#O(k66a)_54v$$4q zjAQkOa*QKek%Amy2f}SCvr1*wsSK#7)+O)OBy44Cq%V4c>RPM1wyCam)%EFZIlt>i zfUesyH1wxHs`x{Gr$YhT`pWy4|LXC|pQ4XXiefWmk_IbBA%aWEuoG|w9Kc$0&zp8Trd6~a(sZP(4z zTH0Q!+Be!ZD)*O_d!2gxu$6WbY3p^`eR9ZFW}|3y`wrC}RP8HO`-iG=t7@!Nk5sEi z)~d#G)wo`@m#g;ms-cyacRAWH3?^5jn)me|wpMCl~ zfkCS1`(no2tJQ-QYDTN-Y7$uVt!uT)D?yR@9?E#%cW;+bVbp|J%HFFx^+wYH`M6oR zziK8p1LlF`gr%Gm$IcEVnoW%4oZ~TDhCh3+$@2_%&iy zEt`7WI&df1AhSBErB1aVpwI_pS1b2S>Zn>)s+RYZlq%)rtXFwWml1Q+2J;CNX!nTk%z@4T;>W8n>STC((GpIm^Pi zNww96aGo}M?>rHE^EqNu_k_KxuKC%Zg%e#v!7y6Ad8HBUQg7OfTH7ikc5Tu+>FXLZM0hckOFXC>a+Gy3EP<~fsw5f~| z)n37eA)IrNc$vy*R~eP6{R0m0(m5y+>SWcpNPY*p>s)njsk zw`Ahv@7=0>pL%Sxm8nx@G^qAQ_1IWG15H#aqf2G9sPP)?C zw=(sz-OAL<_Vd8Pp__f!9!tnCVEeE7u|4*S$?~KacpeM?;^2AwN%P!IL+B=OCnYI& zaW;ljaZ+~#HX}y4Gcj9P zaWFFe@5_sLP4?%_3a2imFDGCF+>ilvRZI`$6v!Gncvfchwe@1(<2g4v5&JxmyHCY& z7{*emd^ntBV4AqDz;29n`Cnq4)TlT*g$%63hE0-(PWKe)e2MX%d9Gw<_IXBI=rG-4 zUt}$)!)zZi(M;-#$6zpKl>!*$|F)Dg(G}e{4VFL3Q|6GQo>igL{_{y0PD)!vpK{Li z0q6RFbA7-+whv%vb3k_h?d|G-w*KuM>Ojc!GX^;jvit2v)Pa!EXZ&&?WbqmA9O!HA zt^8kHTYomItj&6FjZK@LwdMjb<5_EL$69mqo2iqw0S5T@O+iTJlN@H%DSqiX+vQ0<>h#7~vc!4D4> zCCpbRkx0Ueiyt~Aut8pA56kk{SJ_1IIk5}X9B(#ChMgqnPg2c-S>EhQy zXe-`YyGuf!;g5X*!Qv6_CJI8`cGq-9ApAD+gT78F72jI>7T`Vn$lnR}PRUTu54@da z{NCjUkP`5tPersOt@>}GV|jB ze+X$zafFb8m+>d=Jfa2Mpd6XK9S8_JB zcvR4E96xng#g9yyXTnPmwo4u1MJEMo9*7)Jcssc}X^c)hqrxxEOK5M0m`-@nxr3kZ zSkhBUJ4AP`<_B?_XYjMViJ!C+b?t|z4SE13*V3T+9f3Fi<7*+z9ZAFKzz|Yuh;g_GfvPP% zgps%)1lR6(6i=FXYaU6vlq3jQ!I4jke_O-9BT#94^N?X6%=C?AY%P(wSqw z3~TI{sAuZ^#(rsiOX@%Ni}jx;B~5gV?wbb9k3Dwmx8qYi_8V=E{j74%*^6`b;{OqQ z5kG>iD}DqPCw>H`N325p2<(`cgZL2`9I*rOBe3FP0OChr>P7S8M_^)VF)1gl?Wd^g z%T7|)e}2Zge&hwp76(sL;sOOs_`Ri`9RJFVh^jv zz4QzNI2+t4I1se+0LMWlv-mT@g-;?a1-df8m34-=lEIY*u1s*{o)IoY=L8M{y|!>7 z-nJi72SSYP9m?b7Jgg3cSlTm`AAp~ynEx0ao?`xE_;yP9^@w|bfp>Ya$RC|BTHJ^d zyJg&zCVw(w_>&n&Fe=;5=;8n)iUB))iD$HOfDy_-oj#5(!I>gBGX!VWnd3YetHJo- zGwXITHftdIPbS~V(kM&+=J`R`f!&_{4u(Y-0sCF7c--YsnQZjfpyupys5v_wvI~N} z5VEzPM0M>@U3K~I%hLbj8(B!*rSj^mvoNCMB%(PVsnVT8S@bYBTF5d>1fwnW*nah3 z1OMfG46Z=ZM{Dd^rS{-(U#&XdS99uYYR(Ru>SRwzr!2b6;q;3+JBFwa?fj+;aY*5i z&{eADR@qfo8>=xl7vK|{`$y$&HTN}iskxgueyfdzUDh{P=8>~G-J*I?s^-kn1>W>>2l!dXMtF&YIbX(-OBu`sX&R+6|sb*8mr8|clpFw^2qgMS@srUYR8a!EkvOIwuH+Qi+>|}US zx(l*%g3ql0`hx!aWuUaKYHms5kJf^MkHoqG{QO-VU;Ujokp2=o+}O!<}2nt zyJF-T*l(~K<=dyXE5;W&*O&NY|9vsP>$@-JJ!7=Xs4))te_ku|76G9w&i@RrqbdMn zi%PO%in?>-WNP6Zr2e?H5dHDmT|WCz&&o)1&O&^oceKklu`{eEtaW>E9Y4QW-zn5H zgZb0L)N(fU&MMlP{Q#dDIk{?4{O6fHbEs%n_b=wLbx@`@#zCXQ@cSoy3~j6AMN;~| z#p|e5xmS3@)gNEc)R5FSaWG|1G3jZo4ekVaqOo5xz|_P(EXD5KhyBaocUl{bIyhXm z-$ti?8;#zjF++6wgs1G@vFOedo|flc1Sd!P>{~+AVw+mG2KUQ4b?ETAOXLinmNND} z{s1ZU{!2Q4i?*u544$4(!&Tw;0gTO_eS<2(oO{^(mt=3!kFgW?@>UQ5|H2MPc#J)q zjiO1jCmxo!tf)qL#J^4|<0H>rrz-k0n3gZv$9r08MN*mrsG{I7*^`0-MG{?b9w-W; zfQp9)XL|3ASg?!0u$;(>g54xct(S!L6q!0y5;g((H584c*n#-eZ49Jj*flB64xu3{ zx;a#m9RyOl@sve5;LU}z~T$o{J2Isyr1p$@2% zVut9nqX)?&E2^9Qk2~$zQAJyGhMQ#0a}cA+JOX6Ub0KR^BquO>JZu%dSm+ZaOn3|#~^~@S?d4!)`ySJG*h4lr)*l62qzDuJ#+(7&vd&_hx z;%{azhxTVIsMm}Bg|6pG`gYd5#+l1A__HjIKgykih9ol#uVO?MBNs8cGg8!?CU&gE zs)k*vf#La_!@M=A0J|A(bE?2f77gRno;9i=H%ZND4p$9_*$YFGJu1*BM{76iQ^E7p zoI`fCX9n1hr~qUAz+QSxZiH-LIW{>?&H2Qx0?7pO zY*Bllq+BT5bGZsaVxtOl$zB7eYN!`qTAT{hNH&(@(_LA#zFXP zCR^?`+47*pmQk85Gy1XRc9ShnnQVFL_-whrWXmj*E%%yixzpszZ5CHY~jvO*mAjM%e^LB!cDe3ZnEXOnk#OTDYK4c%9ScOB*c_kO`hbNEOEn; z|C6=6AP)&C5D9sVj#NF!cv897vlB5!JhtjV_J{gKS^`+rD!swsLwx|{y(D{(+Rb2@ znI>{S6|0)psOBxInftdrW5j>RP1b?;bgx({y9MP~=D&Nd zm^D-AVIS&0f}CSJ!Y>3ly?x&of}Gy&?h8RqZx8o{Ag8xe`$CY@+mHQ2$vL{~;tqAI z=X%a1-#;ETyPM8I$>MpREMD>|e)r*mZ(z~e{SeM`CV4>D62kU^hM73gndlMHG@Yp) zPx(YIz*?L8>A2}k_ek?Jes?B(KzQew@)5_ve}J|42A1L)SfdY~N5moA|IGY|W#v9_ zUkZQlNE=72=9tzyrm1hXGv&$oE8bs=~iX%A9V@M4m( zAHjVE3EAxsxG#%8Aa=8o&y)~g4h8I?dV0&j9%z(#A>nK&U}i{aHU%_nA&pR6&W|K} zE(bN48wd+PoXinWb3^#Y;hTW{s9Lna`I>%;&3BJkMsqQe>(tMHifQbirq{pp?)ky?pBOs(c(0P5k*= zG1Cd0r%d_7%x&#B4=$IlHtZm~n&r@CNR96{_2y{TX>r~e&)v-s- ztvgT6-F=>#wMNa_B@V8+o1AKHt5fAWRPcznC@jAkP7sK@H>odm$$hEI=u2ISNnNI< z4zIN)FU=$`%Oo#XlQ-URy7VRE8WaK{j4vwO$+4Qie+(?Ok;_>_wsRp z=!_XY_dbM+Dwu@(1=55^nS@tMfQZ7YO#*4c+jN)^9(CG;$C-pfaOe{hMB;Sh z^}d+n3+(uq)21)Uq%RrzQebS_*<&nfhJyY4#EgwSZNgJb!XY>*1Hv=Uo+#s;6vChH zk%)mrIqtLx&oBvx;3U*KIad>YdPXAN6o~eY2cu&pvUq@A*hIysH9y|8_sldX@n8ssP_G^BMIa)eumDCKcGB8mg50 z#}4^WJwG!}HLT?;I2_=7teS}_ssLMtUUlzMd-&=O%)3-zwH!;~&cYSmsTw{~fsd7Y zznoYA@`h^FP^lVrYd3b2_WrL{4K;c-V%HEAXjgOg@?f<>mK*jBk@X4LcaYD9C`iiB z!Yhswou!F6dx$)w=IkaC9bhR!z64|~B0rWb5(H-8><3qV3Ll?Ai^-LElPhU`xdO+8 zD^aJ*m3WgYX(m@6u`miPW%-9m&pDi?;uqD=HOIm-nq?v5V)NIL=ts}yh zT#GO9e=NPU?xIUo$6onvv+G0MSJN+dbeLWAKDy{?HH!`}N@aEb zX`qhTBqv!`hc!7Fz2sybO^$TQ<5Em|(oA}?OnT^+p@(kyqzOU@O^T@4F+H&+%It(K zy8g68Y*C0)X0Lk`v!nwyJ7!^+p^cYxVn5f$OW5}6Qf<(LQidxsx;Yuvu_|a%iZ~wA z^_rCGUN=N(T|Y{7H+wXt^tcOjPpm1`{ez}dcf6X?wjN5OPJz-mi_&-~MNQ>XA56~W z%)w4x=A@TBkT4EP^29n9lX|SVy0F(yWU;1xiyaN|EbhdehSrM>^4y7RR_# zpcD<&s+^g_Mer`gJ|`eam@j`M`79DfQFWmy#Ep6f5q^_SK#;-vb^V*Gb{52br> z$}^4PQo>i{#xa%kE}oy+CHRI0J9R|!`7!#LwQ)J$`fMfQk~lMBM3R1X;r8mnebzO& zsX$}G!PJGvsRL|tcjA>}&Wbas>JvIO3dt8|+WpRBN~>BRnVZkA)6YJoHJK43!j38} zOozLVU)mw5()}^VlvHe$wB+cLUbjjr(a+v`IraMqO49Y3N=c2oIckMz*X{HJQ<>gO zO;+31sBKkhbE(?AmMw0=>HFi3At}Wy`TPw1>{IzHGh#%6e)f_Squ)i~cf$^~hsxA1M3|-(J zK4;VUk-P?k%zb@?1QQT(<(f%tr zUD7S3WgJslu_>A7FVW9FBKx`-F``62dqp-$zkg=sGT4x(wIu79BCAZyCvPG?v&arH z5&dMIcUoPj6mi@miwh#wJOitEBGP+sn2UHfAm)M1r2Ukih&Q6HMf?NeRugtIVt%tF z=0A)f!{fqbWPMK;zk0C9BE|v2ME13qiR~2O-b*A!x*)4^^PhZ$7sV%fa^P`#HG{Nvebdu>WjMPy#0tP zKqk1z)DP1RjY0ZJNYRJaLY_Ws)k$z?RbP$3uA;Zi?&6SdE5OJ9V;QaS>9dSY#vTtJ=xkg1^LscS(}TZM)vfJ^oRge;MWP4)@!PT= zA7P`d!jumM{-GiK{g^2w^fs);PZ($`WpLH=JvF<{BdNPdU!PW%+&v9_G(V4FB-AaT zm4%(K(zc~neysXWri@hh%h}zZ!HacTsIBqez%peDQ%{*x|5n>k{NU8~x>V$=x4aYZ zrqYzP9)#o_XR=A}#uxtFCisxIUVO*nm8M_I9?BeP%8Sqbp=e)gwNc)>RX*dk)r4~v z!gSXx(ZIqAF!Zt9cH@7KN^96HhPw2zJ8)PvS7#`@M8U-tQ7_w zaJ!@iL-cXcwQA0KzBk=yQ$OOk`yFyoMsS^Sms*V`&DBIhy?SCo=@U+pPTNM?Cqif6 z_JVJJe|pWiniIy3?Z;U4M|PZ=@P9c zI_yZH13`_$2B07CK0-LmGkVB?{6`XzP&uyqr1>5gGSfp5wMB9OW~ zuxbABJWhMVVI=lc$~#eedsfQV zZogCHXZ4Bo$GV!<9FutJWuzv@Q-tL5kLwY~jjdaaHKVE!M&aFP+sAS!7H=YYv9|4S zlEa$e9degC1oGA#ecO>fLSD;Ds_^#V!6ahiS-o``5;t0Khf3!rkx2LTOQmPD4xL{m za)U9|#&b^9APmMJ^`lZ%&8--#R1o9O1v*&xeR{0LO%r9@oWbotzY;n%!@q>WixrLa zrAHyOW(!MKcRVWPcCp_69!uqZSn6~tsOU~!up}kp|igbK8H7SU`O^3I1^(y zccCTA5fgr(-WnByTO_E-1)Jv4bpdTLfwXdf`@qq}VzgE5*j? zSSdD+SkKN#Plq#mPHIB=Ku8?6@?ht4fwB!mD*VcVj8iC20TCUaU) zQDx3(Pgl5Fyc`tjo#E<_3v(&zcF(&u&(bA8VcA!_{S2p4EX@NBx=1o+s}+;8*Zaon z&tFZxH{XbR-i3VIzt#Hj`n^8;AoW;V zA98Y4B(LebKC($YvQ0H|qCPi6RH#nQTCP%!H7ch<<$R#Fm#OV?`xpB;$?I9|%zJaX zG2Cirlk{u|4kXDL8Zt+8U~wX4pyyq*&?Iw_!z6PUrY6D{ebHpkT3c()`W@=APeSDG zKZ;zlKXO2?qnBP@(|J8PdO3NDyq;3%HSap%Vd?AJ|UX4+n-wzJig z7Zb!OgQR}gl-Zo+b>jMUmT>s3B|-h`I*7W0XHK1+y4pXpu7jxSAgQZb_#`#E zzr3F=O+lBQPalO6ZB<3@(r7)c`G#&yU-Y+(R%tZds%1yD>J`2>vZPh}FrcSJt%-ln z{P1kH?+M#9?-y2^z9TxnTy*~J@A5}#@a%U8>eJQbhEW-R)3aGue=R zAK#%~t@3%z=QaPnD8$-R7K2^lTBAa?9mss=)ajPJQ2a{x^*uQ95jGP&!dH-uRs7iA z(auv2`*!c-7o1Kl_}%L~HbFjN?Di+sVSa2Jd2k=cbGPzrMpilOYn1M>@(7&Y~|9Io_bceWY;rB``-qW^5)2dr27$Gh26XVD#we73_ZUE;4g2D5g6# zI!pIBd~d`S2yHSk8Xb#QG?7!JquDhUX1wqHUes-#cANU?r@VUKd^pzJOD4+aTV5bx zBt;Dq>HK2fF8R{InZDOtdhhmQ)#|~m@?X52?6|uYpQmacqi^2qJAWOjZyH>q8o8>l zRMo7OuNi`M)@wcoxk;ZaQ;Ph=p=vuRs#Rw-M`-7kv$aZ}L#ac|7pEDm@~YLFB@FPR z1L4$zb2*=RuBW!onYB&rTiempBur{8&k%2|s{dp#t?JX4!-6qhD(l%_06(Wlojrj9 zxMVURo`5Ou9G?m1t)u)X)#oP_t+u&t{z+=1M^`hd>GV^56e%6543t1oUr6h zJ+?4e22&4K%Kw@j>PNd(-c{a(THY#E;TVw<5g6m*khuKZc^S63gX88>i1c)DckTr4 zBIdf9Xq#HxG)SZ_)phrDW2)RXmcdg-9$7qNB#m7yUT39wh%hSa6u{R_Fhf%Oy9wV7DAxjm zW1`@XQj52V?+E;&34agpH4{viV&e0DAhCZlgJuG* zF~M93UTeZn1FkT^*%JH*6V^H3HsQwzUT1>yB+2_GoF`}fMkg;=xs7-2(19ZT{9Q81>1-R1qiYqvcH0MQKCMgPoh49BtXD78-sZTb+milNRwA4qm%2FR~#ZaFeohI#;`XoY- zsLy1fOw{K_0YrU7t}XTXnpDGfdmhrK3^i(QlFVpOuSlrrBw?{h0;l3snB#mVyVzPKud+bC&88qJuR@MLO%es zROm4Y4yjN;&de{C(&$2d4=ijE`IqUm$p6t@h+(A>9gt;N(E%-(q66BlqXQ3%{+T*( zksuTuh^5p5vqcB!LcXEV_UM2}mgs;MYtaFbEYShGpc5U?GKvngbC(7|q650O5*-ku zZRx-_q_S2Qk_@=Sq~JJRh={AD1LK7!=)k{#UvOADAZA#)5SP#)Iv^u2(Sacn(61G@V| z2Wqiwg6}9D_=-?=ye{NhlEKn}DS(y^=&sGu0WF;9KpyBxVd=nJ$!O_-*mSE4(b{Y2 zfQYZ916nl((1AW(h*mXp;4-TgmJZAYiKPR&*E&`Qv}#y7aGY-B2_d#e2maFDa}KL? zCCAPe=KYD9p4xojdb;o4`9l7Q<_q&br};uq>e4e`kQ)p?d%lphHEf{S!qMv+eaFk6 zJzqGWCkv}pR`~_$Ks67WJbEVxpFrA~%?~a)qxnHkrSA=B3GW0$1bl^QJ%?YOiuaF2lr!XCOLZj`mj2w+F|0X~86ohw{ICC+TF(2fJ@^wtsvWQe(< z(7PX9_%Y~MelTm`sx+9w7RwWJ2BxsS(3dl>oeXFC&n6&MuP?yNN@+h@r)I}=78%T6 z-<5`Mo@i=ucW7!csds8|NRRJNJhgb=N^`=g#jECc{}iScPinNMF}3)PS=8q?wfNW? zo}bmJg<&E6oTnC7Tg7}%Q;YJy%hW=z1buE(3+4mITWeTz{JF)qkC|KCd~R+bi%{q0 z7U$*`+Tnk0twGe`+**S%_1szm-K6YITK8|KJhzxc2j08Z@INP-Tm0#Bnp?;opWeAe z^I4i($g+bqzmU_0^u6PKCl>L;m_3|$R#9>?W9PtN$d^9;O!g?rYW!KBS3IHX&upNl z{sT`Wj^V_yvxt+LU!C?W;@o~EW9nFOZ(EDa=k_a|+pk2|e#ZNi?mT7=G40$O;@liU z@8vtUK5=e+;@tYg|EKE{<~MIWA38qlb$AWAmz=K=`A8|_F8QL+50rYhK%0Q-HB=2$ zHI;7?lfF|RH*jy`{k2p{QwOwS8h2rD^z3rxTvkyaA3{{!!+qhE*_ZK6Q1(Ug4U8GQ z@cR;+6X4qKoU6FX`$EsoK{+lym;^^=T5#t5}QObSI8VTK6r-D0FaHk6HQnT14UpI{JF}5(pQ0^acqJEun&*Hdx zF1Fwn<>mkax>L^vsoIl*v zNmR0qI-(CiMu}yZU|NO``&x#2jb-j0 zP-7XYRhMNM%;G@EcfWae#|Tb7s?M7mr}7?3Qh75|1UcOR?Hy+Aqs-c8nzct0 zInVhl)jqbT_VLs{nc8FNwEdsr0!nqoOYJH0AJFy@X6^ZwS=xTKS$n>xQ>cA~FK#xe(=U+*VWBBcKy<3CRQ!x@nA`5XU}u=~~s z@F;`t{xO#RQ+6=Fe8WM z&RT19_ysf;1K5evrugq<4F)g-r%&?VN8Ja|^wTH#^VaA0B2HGH@3H?c9~&HRPDtaK z!@geK)^4Exw`P9FoAjN%+WkYPcE_95oyF=M&wBhl=5EKEww=Z59naEyzLT>%9AZ_( zFQe73|D?2E?e0%f&0BiCEIlq3e2(R+gE6zXSY*uH&&9$(d~&agMf?jp@!K$b;fnKh zssn$DjNvVR$|2RU(;R!_yOFUE&Xmc=ccy5SI!hGyQ63?=*DrE9Bp=@cqSfSVk=&~g zLULx0Gvjnfj_sMaAMLi#qJOqX?iF$&d3KKn;&ezJ-9vJ(uOUx+5PIB<{mJgX;?T3q z&@;&t$3DK9WJZuq)x4H&CrUMQ>-LXXsrVExV65tDS6!8=gA44@gbk`=qxLdtRoI2Z z?vrD@L=R?_t9%@c`8a&@AIj45t*4aYf!wb+3d_`#gDM{nVgB4Cf^a(Y`p8a|?kJ%< z?M&!?h&7E6;haV`J`=)ok0l(BzNokm&K=crlOa4UFiek3dYC?dAvv1!$8+mqV%82| zV(_zavvQ4TVuaECOw3l5ci(^}rdF<&78663V@%8}$woVfrNPY54wldMp<|}^1K63* zp+bEukdQW@1^Vn7xq53fwx>qNOz#IUL!U>DdJUA+Xg~w?*)>AsLTwb^Q=?<1_XAj| z&!a}Y_DgCsp#A#n8jbF)QDRSx%;~)x0AqH?{Y-#xK-7~?8WVMlb<#SyLmMBlFlGIW zPd@98`43@c5bXT%Av1G4^jMPPq8A$x!ryBn^2f)58*6~GJAZtdr@nxtVo$xDPcR&w zmG(g84$kY4b8h9(#d)0i%2gajwg1lqbE#Dnr|3m;n4g^S9r#+|k?!dOr2WYNX|FDl zOGmn|Y5S*3XUWt43-eiTy~kMZ(bhA}dit&S2<>W6xAieWdr2u@nOu&yC?vjPcyubk(J^24xSg7_0&Ed)hcpPWHii z+H9&&PV~}9ybl}^%oT&3qc5E$RNuI`;{@7Zr=XQ!SQ28#ALuv&6F3coOk^h#(gmeJQu0%j4A~Wfg%kw((dk_d78e)@_Xyw1c%pdqa zGzm3yNRtUs)bx3&>Bq8Z`i-v;5;`wk*DwC1Dv=bbNCoE~f#&|zTbi=Capv`Yqj9FE zZD_?{Ni1y4+u~_EZ@C2L#d>d+XHj>~m%KOB3)GSm={>(mpvs)#%MSw-i@ta-F4~Zj z?wx=n=S=fXaESO9oewrodBlQGrJTnLv7wu0lEizSdULA7)?_=#Vcgz?>>qkMVpO4g z9qs9GWam^&+AS49JMGjjtdRP3ae$YJMR{(72O5)aejUh`A*x}vCa*L6Vo$llm{w#jXtl9JSWgVNBZ{T*@o&q1T^D zlTxR3(q`9!K_uJ!r`yZ%(vrIRnO;sx&AzO=O27D0?A|21afw90+CXKwdEPJS@4+BB zy(6|Qub=7pv^)FyqOI8%`^Nr8-lrFLU+Otv_XKS@EtFUF``}D}$AkWEk6hV+SU(Xq zW@~VeQSO^y^F|g)4qC4%_!be?`N<|d-t+5_3GB$A%JPcA0t;U%gA0nMX|=_~V%4Mu zA$neFlME#}Lw%35Nl}#Uxcbsr{sKOW^p1!H6l=FN`#Nv9D8_9B6JV_N-wH&&2<~Hc z(5%K-S9g{7eg~VPJ`CZQXePEW4S ztfJL^q5PTTe<{Qkn%(P6*plN2PLyZ%NTbx7BzX^pl8-Zsvru_c9L8O`|H}DkZ$(B} zByExCO9XdtTd4mEHP2v8ikK1HoWcUBp#M$|STo9(!l-VVXdAZED%S{yv&ICwe;Fw> zxrS~_14XA7usHZKkz+~-2)3%g#PI`GNhs8RxqI%6F> z?vm^&vWX3zF&y#KkM`y`yz?XIrM-7V8f%KW)xv)fDktq0%EoM^ms|K-0*st(sG_L+ z8e=_Nx;UZZiLVeS=%7+VTdO@A!dka@R*q(1 zQ(2DOpQjsk%m#9mdgt#Rv%zQstT538E3h4JHF;V_=1c_FT!(kswuEVQPrf#$`)%P_ z@ORUTTR-+}=Ae1YZY|gBD^bP+02H)7thL7b!0y2Jc%5Eslo(Rvd06(z9+kh2q&VKw~5|q4(}Zi-W;cQex%XHwZ{uTgqDg) zYxpZiG%u8|e|-1hBnB{ZwIsyv5A8q-$hJV>^=gKwI@ z?#c7LIh(w9tQ*yS`D){ib>2zqjBw*|d+;yxL_O`*YE*!qhHE9hwKXt97;d&jKza#_ z`P7YR2kH4eZog`ug#7(4tXc7xNg#>%hw79KSPQ3jeCbR$;*Do zo@x(#O3y&sufJ|m)s=UwBWv(o>YXrY#oVBAF!)X%*^lXk$CQ&CjM6kJE1~#Z$wNtCLOMM^zioi{+dTy zybt(|8hA6!Z#+=H{ZT*H3@l`%74~tU2Tk^M{Zc<-Cs)crrGWS?$L z-N1>BjmG=eJy3UL&Ta!;;V<>}tkju`YpW|J)lsHcEP3=pNgGrTj)Q(JuAzE5YbQCR zVq=eAv1xvc7}d&=YE_>fPf9A)x8Bvdd#^0-z9!O|8##OCL=0JLaATQFc=5?0H65On z5#_bj{;3OK>EP$VRuOg;#7Z#oh#8J2LsCtotA< z>t1|%h${Su0C}mcSuQR7qWZ}?35j(1xSmMz%aGRpIz@4?_~@caf}%kcT{}35f~zaH z4Nf+n*Q8kQX*@qBJcDN_wJv<2d>Lk}`P)6yrcG%Y88#$`XXTO{Nq}?Vb5obT_ zX=e`hYmz}B<9=p&x(ZKGJOia3Y$er|g7M>nHKiZ#s2!Z8OZ>Pr6rVGsrY<7=Vy{5_#1OP&|0G@GS(bJQ??6wvcFza$@NY8pky#0SLB~f z{(uZikO|&z5PUV2!4EC`H%L71t7wj5D7DvgZ?Ahb45OQ4E3XMwm(*0&G>1Z(Yinw{ zX*iv(D-=3#x-Qbe9sV_a_t~=M*z{*Ne3zD38l0(f@7Z2gQ}W{65!E|uN@{j&8<9-J z_PT=Ild=a>NIODPbFlpB9kn&JHSk5~+Vkt}b#G3J*;~*xIQwEU9oZIuwx$|C-0URP zt6_|`v+ZO&AhIPTd+MV_Hjs-5FFPDXK6vU$8qXLR8_qzKuxXN`7{A37(vKyblV_rp zFIDDRFEcdeUHlp;l5ZSawT&{*&Y_-;Ay1CzcKtFJK63VAybQ*h@}&`Y8_P5H6-TyX z0TKy81+|djSve&%KI2X3qyS>ux`Q&U>k~rHUnW?P=S0Dz@t1y+#wpzqxnO5^cVqXk z^#-Vezc%MbR*8~MCmEUlTSdEUY)i zM6i{6z)nV9q>l2BQI}ksfG=n)6HK|JEgpZ69M7G|h&;h_Ky*vgI6_aSx#WRSpJep^ z`wiTq)MS)B>0E8UIE+j#kif~&<;J04J;=n*qH{`PNtRH~Omg;3Z&h7CDA?|u?DUO~ z^iBC$Bxe#j8L6oXnOt>yO6&=xPd0o~?%8iMoaLIoGHw(PmQWt!dwgVR*WjD7?D><8 z8qcngrR{?~pV~Y%-M*AaU-rVtghNKM^YJT;^%XXauhgFK{*#}yZm=CH-9N~eS{%hd zarm+rNF7zPapn=v%1G|Q5Yf7H0-`n6<^KWC;LE1w``(c{h02fdKJN5Qfaw2;^g1~e zG3VL}i4HSquD|JVhtV|u%M}wnkzy!4B{pM%)4*^`37#^l6MA6|B(W5Fa6D|9>hwkY zQn=@v8ey#VB}E`x4j5~f6wl6sEG*q8{v1hri!=Bl`hvG%qOsYBu#ql;XDp48Nb@Dp zKxy2LkxaM)Jkhmb*h&ArRLc8x7$0kt!^P2~{I;?pxqCwLa}M%NqK}<7WRLZ9*|H~j zx(5ACs*rs%y0)Lm{%~}h%&A2iRN?oC@lK6gzu&Xd7L3;ZfhojrA;VZfk{?0(Yk}yf zP1(>ck=WaHHJG1KXq1p}c}wd@p1s;x=YRTp8b5NNie%_5gnDnaCzQ>9+$bHjKH)uM zE!kp~uNtbzoIa+dVgmCG)lq$!|HRo||Y=8cJc52QCx4Fs3E&Fi-EDPPkY!LO^i% zp6+JI{#;2>civTnCE24iH|LoSrY*N=OitZ|Q6wUP0|w9x*?(dT)?V5+*t26K1!+;- z_^{mj<%zs%3T|JKE4VQ94vivGxLLHJLacb0Dk|l#6fVxj{}7n!y)7IL$VvCsw44Fp zN1}FnM|xAekxWTM6ap7Wf;UO3&uEY{e+&FA5h7bf4cSiWqxEu;4lyo7rE;0eB{46&mL{If zv4C<_2i!3|q=_#7tGB=gvj~{)|JR%Kt8je5N~sQ$od?Q2i*y?}f^UX68MsaKrI+r& zVuY?3#3=}EntD4vp;Z-@;qNzEQM)OwbYv!t%$cB+3S`OC)6Hz-g>V5LQH8$%7*i?P zMdssCgX^ZaGOc;pAeFYN7wD<~Lb-Y$HV4Q2LW$(qPZ&Ab2BbZHJgN(b(`n z1P78OeNju^CVnoU!!(1fbO zUxCN7+J*!z_5xa1FsgE+hFmmNktEH>BT_$11Cau33=haSp{PX_C5V)yV~4o`PtLa| zdzKjWVKj-S`+KVJ1~RK>NATCveVb*kRMCFK&i8`WBC2PvLs7*>e{+JCt-^PS_PnN} zZ4$rBioaOL=Qup3J+MKjFwhcSitLej?|26aE46^9#-tEkg}4)YYHD&ty5K8?i>C4+ zt+~!H^>1aK9c{J^!`8Nx#nD>3$)*bBVhPXMBW651};x`T+Rpz6NF+9`=EI{ zp2+M2zFR-=v^msIcL^nCLQi8HgRT@5U>=P+uWz2GY@Y6~=iTDzPRJi;tRXhVQ!)sy z6o5ZCe0niyB`(SrY51mmpKdTjw3PPs{5o#-H4}@exsC!TJ3m73ENCCe$S7~{GI@BZ zkl3gch-$3~+$P+IA}Y89?yAKBsTu*7s%Oik0Zko;ktszb-iWtKiuh8t@aBt1x}s|7 z4bV19ZWK=Ona#_#q8Es~3E(P{N&vSB2+Cm>B6h`t%#VJF7hH!zd}6;%L84 zxlWr=t``3ci$%rKyt5)ICeRe5v_{T<`-V1zi!VZ0q%T|aihO5Lc$c}tI813@E@-1EUtfCDt zAek=IR2`Q5!I7AAy~l66X`E9ndVMJA5X*!@EjOx21_$&dbr29}mPJ|$$b%ivm`>5wg1!=KX?4>$RdP?mFk;M*V$jYlXkE5trAS+5f(t^Mb3 z@?`k;Up&E0M44L>LuJkA0DPwhSxu`q-n7 zlG3U^%c*qvzZR6MtuWs`5#D5{$h*m3UxbfV7t7)Be?zjO8ZcUFRbj4`jao%>We_H9 zZCm9}L}roa6evz9{d8pOMiF4J7Z6?AG4jhqT~&rK)UbNOz)vmwF-)`hkrL6U>ky@I z@Lf0CH9G-KCP{kUa6+?f`vnGTx_7oK-BxCMk5z~Ld4r5VLMeYs*}=f%EN}RzHKW#! zdQV_zO=VR59T<}eEaom*t2>q6E1D%Nl5pO?f@X={PIOK2--!N@ehOtJ8>=Zh)6>B) zd18HXwcF_q}{l-U!i zp8UjE%S=@j?rrJrUKT@^QR_Em9tmvbRmKN!xkvAk5mMPTNcnvcLqk*aPv(t-51p)<3cZ~?Kipl7qo>KcS5zQt5 z?bm|M^A*tA4D`a}mj9wS8VVyYoM#_~2gS&vCV_a0#J@dQsPlB%wpG?tUS8?h;pEa> zUN3L(?6KAIg;?$2Sg8xO!b=aaOc}+*qE)Fcs-HH{JUEz5s~WNreQa~!pBM{T_5Kqh zhU)8MdO1^5Y1LkC9Sg{Tg3SNTp^7-CwoAWk-eERoKSMAvW2*3n!^Bu;f0aUHo)2u=D;*bajT_3RJK zT1e}ldb5#v@rIf+Dmv&o!r`UeziU6OY&KmWji%`xFU+=x8}*?i6s5ULOu!V^>``Xx z(u$Qi-V8Q#c4z*yXUYjvvOZP{5+7*^;4M}|~F0&!G)s@zSA%6vp zSf?=Mg2-5F<|K>n4V_RzG~Ts>7w@NeWusbrJ2kU#j@b|l$4B;xEqf^bjW8%%-!}A=frT(k6?%mK5sH4@)IPQNpxL8JSJk>*kBOy!qvsBMpR}OS z(;Z)OkE8DGTw5USpgHr~uNGZG%gtgY(-vZ=IhlijqGXoiZQJX5)+P%DCfgxZZ!;7U z>7Om;hdNNRXZ8PTpE-A%-lXSlf20PMeF-^2dIi`Yc!)~txxXbTfo(xezZN_ztbe}W zQn>$5P0ZouCazHC5^Y0hBT+0> z^qSe$dah}?Vy*TI5&3P1M0awT7BT-3mIc0BZx%kPiL^T8dP3ls<%|vd6M0l&wFH(i zY^p+DdmU!u(ZRDBz3TPy>@VhsLFckBoZ#F(zXCbqbeVWNMEBh z#f&WV_tlg)hV<8zx6qXRPNS;SZ=Y4tWGf5l%o>e?ygoCBvE~{<&rk}5k=d@4s}^4Y zSs{ffL19X4EoE9`RwaqXbmTMyex1b;;6i zR|lTZ50cWKNuT@-@4=0}9?8_cVDUAW-L@r@lw|Hy)}t0j;4unZ$}BJJI&{jHaw)T` z6h^EtzrUz&i_k2m6;rU|5lD$N8o2c+5Tru>sETb7omvTIyBt=5Mr26v1A{0_Exye( z0wQvuPIKqAz?KyDHxHxygv&50aOkkMC?b&fh%l;5`pvZ_{EJ9y7Qghs4rCD-zyaXQ zA3CdHI5UE5c$o#`K_r>wO^JFhBB`f)hAP}oWj)=GsiJq$a$m1|Fkrd=BEPO@#f7hl z`8GY&R;MDB#u{s{rDgoR;~c&en<1A8OKAl+#)sD+Cp7hM`UyZ{iYLek++83idabCfZ;UblVmYR!ekUqQ^Q>g(wM*4!>2D%M_VntS#*r%qnuEh$8{% z$}@Nn4WAp?oioyx5(N`e(QYEpDVCnss-MV}ik^h-?54iN!CUrzT|lj8)0JnaMVT@H zGsg%m<0F~#ETkV6=G-IMwYQ@19T`WAclstr`cj{X^xDL;wu9*2mF~4q2Ktl|m?(WY zU*?N9Iv4f?{we`jR`II-hyZiG9#|s5qGnU#x_onNIHC~ZH1+K5=*6t9!^gCQr@OKP zcko8dW;5Wm*mf=MJxyEogI2Lu!K%QQm{=KpMuljfl~fr1%Q)ixf>H6bcdJD&_`zo4 zA+NBQnuv4Ve2CEw3*1d25>NI8Ot-B9U?KnqxJ5c+G_RJ683jxU(vGC zt_l}R0SqOvc46urGK{GVMiP^Azx5`O#D!fGR)97z8aKjyY#9NctgkSE!Q2!V9Bx!H({H)&&FKNkSriglw@LB-T6G-m)r&HMaYr67Gx6a~AC3JWlTw z-pNr5?dK8bDYqH?T^W0Sd9immG)EgOLqWEG`u$qRqx&Z^HNo8PG0j-@{dh?_4dTX(F{wFooN4gqEOYN+KNi@_jy(g zV#7{ROa3yNCOW8?FBn^v#!!HNx5(NA%sf7Kt|uq$$|-swwPJz;4BdgJ_#^382krtA zsUmf6{+Ijb&)FA9CYgL6CH#1QDyN>-N3aG;o!Od^pXt5Dkx)MWo>A2lcZ(x$NXspQ z?b-L>9sZi8|K>2ZO;*_acYrowdrkw%P15dh zqfK?RqfJWGMAMo`)KLPYHrlkJrfszOw=|_lE7gh68Xs9&8Vm|3}{f4fJpw|XP+}6ym)Wx@ACPO^UOZ`W$m@s-h1u6*ItMH zvLAROwf+&U$mXSRJB^w6O`o+q>x$4DuMUkjW?hA9A3B;+vo~^kO3oU?Z^z=++@~P* z!Sxz9f@dj*k;+QB#8aX(NE6-<5ePew3cH$DOd{u%Z-FB^?L z808La4_27^+Nexy{2`sGY)hzfr}6OEH+4rp`wco^b6#Ug_@-`kiBm;O;||jn1gypG z7}{>XT(dNMds@Th>6s~9irEIR@|#<|DS2orMIALCB&{8F$8M|M9EXqN{=)Qcri|Hb zL||O%^qa$9^&V_#hERKBaIo5JTxxh60^?Zuf4JUTa~bElju_mYYHyr=f#mP7BMW}! zh5>J9ydA#XTfg}yrL8HKLVJ7!S6=MH*6Nh#N9_F+-Ld+k_8AM$ri0rMJHmHx{Q#@~t)bU^jW=y4X!nIJ_6w1l^BRXkWZj{n z=|dwoUp4He?TugQvkzH+>DaR8!xmrAYj_q@^26D8;`m)$SZQrn_j3HCLNEIcr#sU?I+Ea8c-i9d`#$XZ%PF z4iEiscQTga2;RBju|{-S!~?}ROEIdOf+MWuV|KKTPC~9jYm>QCfsNEqjXuEO^$>Yq z23Ia5F7HWPog5F`3GUN&r>u`eMcl1FEJ3B8*XeOPb% zX6(b-TO&#Q_h!Cwh9)$K+|LGMt_^v)bDyo$!wC*pCV6w{Oy28@rV;uoyk) zV`uuQ4o%PS1R1l_?e8(>7^pr4Jf!iYwl!; z91~QFHD?uBwz+NQJfv6`nh0JLBdbB1G>ZdP!z&8AEfv{2Gdy-+d(}_mjU;?FPiy&^ zW|Oggb8xV=dJSBF6$r}&+5%ze&SzFaaA#;jObrgRd!mz!0MK887sg^xbE+Jo7pp19 zrnz%u+6?Y-I8$LxJ5!&=&}$_$x24g8B3A-)I?Tjt&ArqKXV96eX^L^zc~PIii-vtQ zR`@pW!8IC|t@>9e{#XQaZ}&ED-CKjLhPNTonPwA{^Dj6688E@lcpJXew-b#Bmy%EP z9wH$B8%*^?;#`fLPA0Lh1Cx5~v1!Cc_4hb!p?cLZ}ydrcYp)_N3Brjt1Wa7xX zHoF-t+*GHXL`0wU&`%s9Ot$+zAoYU|39&24`B(>Z@{7ft*gh49{uO;nDYS5K-rvgc z&F%I}x2^nsb#?VEX6??^(LoVPBT>O%lo6%`l1CKCMCRV}S zzEJy^=x3mh9PF-0$>2V8G!moA>QdVs_8LwcWB-Myut7CCHU1~~=k)cGaKMa~Kcf)l zY7|GaDxn(bR6+}8Ee*0GSbbBST-4D#!ZP_?NH^n^Oo5#)k8>vt0fZIsOj{wPJvxgu zG7Fo+nTI@ewBFj_r5s{Q;peb#r5H@L?zxGw*Og%J+%`6i3DvVg^H*$&n%jxIKYAza zskmeN<4Rw%(TvL68Z00Uow!P*vad72RADmfkOa9wrz&h!eqKXcwc()7fk{QbYIrfH>a7Pj!LaAu!rrB

GB*oxEy~8YjV{ai&p}W$O;v0;9%R3`WhTj``m(xp*W_)qNO*yNp_sviC_?6m1$U+KtAtNQB#YjeEKPg3@?@I8M%%wwL-~4ShFoqC5bZspP2Jb9 z-Bj0V_@W9bqadiBYLRQMqy01%@glS~FXlHHioujKN(>e&#cUW|t(IbnqAM675UZ`Z zH|ghB((Im*@>=%!JJAv)M9n$9_z!8ztCA)sTuIRU^)mj%8-B zkvgd0Ui>yQ{#QglV}5IKbuoP@Ie3BTL#c`AN3`ENupf#I_l>bXM&|P3Y4q1<7g36i z-iM=rBy08HQ14|mdvO2q2E$X)(W!eF3G8!-%7EUf1i%h<*0&+_l`kZL8p6N4W zl}GFK9)8$eN%yDD{EF91TAGid=P~Mp*43I-ma)e#Azol6!$;qYsi#?s)+8l0JHPIG z@5$3(_iDO}CnuKQ*YaAj#KHQ*!A*O%y!D}3ZeY8e)N}e_`mnjM>?D6uX8}1e#Xo*w zLP0cMNi4{y;_Az^y4aty=fib_5&c^j@1|+C|2oQ$e$ACWmKfFk%Fgw1+@#jDn0>QS zIQtFT9Brqbn6XlVt!L=yMr>4!I#?{z$x#|jv{LbW1XOb%U78fT9yTOO3+SDfca&m= z3Yrd~EyRNEJa!K5yo|uANQwX3t)9GCp|pg%(&DclB!&ixnjO6UHihQJUmc+TGM>%c zD=l~CB7X-D4^qXjwgVJi=I`dgW?cXyis+9^rA%A(uMuXgW^B%rHT&$%{9LJSz$j<7 zKItDT08Lsh6;!O52=`YLA>_D9z8bK*_W@Hnca*?%z`>K8()bKgdhqfZde$=o5U zK{w3dY;fi}angu#V!T?uSvL*gpDPbNROo53%W)af8v71u>qbpBVKqabuKMW|PpHga z<+T+z5p5LFXf{3+WX--29O~uvhNMFW@5`Cq{w}qxl+%aL=@~wQ6*4-I)wlpPijd++ z#?K=qcQOfI%R;68F3l^&{^;Ffd9H!Mm3D9RioHZ_ z^+HnYZc@4RV<SNFDCgFTgdGc;=#`99 z%IkBY;A7Rb{vs$9CG}52N$BI`;Ly;=m~w@bBSsGt&f+dziQYkW2J%zwlwi~uWJsL4 z!xOFg!Q^Q7Jk4;~|5|=sXsRlfUG2WbULz;<>om$Ihg#FZH>QTa?zO$Tpj?UMn5%Tr zsi>VQcIv6p{_THG`z^*zr5z=b&3t@((ZBkilUJgaDESeMP_j4QN87=qguGj`WH1=^ zm^*iHNR8F#Sl>pRNAxFH`Y4Mh$)br{tyOif1I~)&M=^qd(^h>BAdEe-*DMk!fHQ@K z#G|>?YF7O}Oq+PE`pYCwPN)i_7b;%#7SkurjNL*hv{n^VZuEV)Mj8uJkpYq0vte*o z^Y&H7vdSDUm@BH+cxWFEyP?2(Vvb`;{Nl{FJ$3wU*h|y8ClPLBMXT@RZ?!h}s~a{{ zBUw_mtoj#;TsaLw4xRf~2O=>|UUf0aJmlf|eFN&u#1nQS7n5hfnWW z^^?7ZPn<8*=K;gR;FMayITj)p4@4~F;n)=+&{zaQW2m>rs((Si#^B3{}Ve)y-z z(aY#lYMS#Y%aLb()gAs4?LjGZhp(i(5-NoZ!@zzSzFg6lT|$Ud1>|Y5*J>z6z;-4_ zklRpe>UMf>3yUsg-ojLREZWyjjJ6WZT+x0_H0Iy_{Jwu;#7#`piuhw9Cd7};*~tcdf7?vp7GX|5rS(YGDZKrU!n6@bX4VxUz=nv*2racXWovBW=%m-f4kLg7QeWG7Kt%mEI3>9^_6E!%jn)YraAnAx(lv)*H(rqJHCR<0a6w4K?ISx$g zZ;yQK3o>Zm&r{t|8^?+9_*TNuAFWw+iNM6LHi|clA4+%~%rptT#}a1gHRFTcUyyiD zze;3$M0;txr+rJY0$xPCc_seKjZ1`7;?>pqFQ?WYi`f2YhgL2nK!-l7-1Mq(^oiY0 ztA3wA75LXgO&F;Y1%{Qtq4yzGii!pj@3imd%C87$7)^w~r^JeRxUCyYb;mmxt^P_A zH1V+Nzd(2_Q!iclHxrih4<;-+W%LzfLgNxgvc1tCxrDA}&!g`Cq${k3e~^@YUqi`p zeQG;Vpf@ts8~zePTH5fTeTCJy1J)qFc58wav43i(%?y++TJyN0q|>uwyWu>EovEtY znX7J40*x0Z4;C?V+(2RIQpe`xuPMQeUOGnjjN>QG*k9=Q{rNYVsqhVkE2>t&1|%>0 ztA_OU4;LOX)JCJ)^=V|L|Ha#+4VRme5(B+kq1buU#O`stp<$Gw{!T)}i=gblV}B;? z&Q2U*bguj%+6|l0;(BzI%keT^SI^wnmr@=2IMm+*=d6SM)q_0giGCLQCjl!5lk+px z(Wa?X0u}6q(J>d+c1DWfD#OkPm^^Ds(z4;Jt}|0!AkaxT47dyqpw!+iFUO&so~S@Qlkrf*UayqNW@1JVy$+G(0V5! zG0qGc`v+a&nF>{1i}qtJ-8Dj{Y+GI*8pXF3wPehQ|Cb3fzcT#s1)+UjathymB=~mx z@6}Cab20PrfE?8ICI|1w^5)$5B`k>;7|j0ji=&w3_j=tJNx|KUHa>*QpS856SJAY9 zlCQfZCMrwwnwtqKSI|$K)cl;NpOgB3rXR&M-?z_*;%QT9HTy@r-->wGE1AvF#yBUc zDM;(EhMyug$0El!Ir;?cBQi7`B*?hfA%jFU=O^fhVR-F$Y%_FhbAF1s?BNakM}DDe z3`Ie&UPruv0Yt4lmd+iYIY>&S&C)s9F9_Z59XjKp{O0JNP>5K=;$pB)wK>zyG9a`r zHNW{=G{L&mZ^fP}H2f7lLEiA-iW^$wSyHE)JsHv4w20^%I^*nc!PCkTe+t#%!M4}@ zi02#UL%5TABjSDRGjO6Mn$ps3{0x4NQrN(34PNBZYftyucS1(=OtEvU`WELu&Y8IU zK1jkdDBB30^!YD7hat-;3c!qc&r(QfIh+#7NS}Gwha^n3Bi`2ED?$91iTQ7D8CL4$ z^p{es%(L0?tDsiK8wa&4p?xGl(Lqq7^>3IT3PY;geb!BAUmCrN9*tdFCnj4_oxUGK*M;O+sjctyx(w03+oe}wl z&#X>rR&o`fNjTN01igZiT~5l4yvqEb!>`iLlF$_@oo5L66tUdSTk-Yqj zUbcBd>%BHRq^w)H?#RxaOq?>|Y!;05Ox-Yw-88(kVP(VK<$G{1^WKZ>7ww%*;Y`N6 zkIsE3)a=F2z`oGiN%ncVNW`|x)HlN4JQBI#2(B&9g_vT)k5JUy`AEe%#{ok*rzVEd z8`2qf3qtO(LL{TXOamonc_R-{sk6Na`P$c!1Yq;hZ)hMz@i zrw>hPX7VUnJL908;g4ROC^_A#mu?(tMs%ltHh;6JZ<|+oo=5TDs}bXH>-2DjJl`F~ zXGr8$Jm_#08eb&A?>*@wB4ho2nlj6NUMZ+Zh04r%Z#bJ zX^zZL9~WqdUKrXgg(6)C{T1mp_m;jc-AW%28o5m!VTsbm?K%{tn6B`(Rg(fg6FGNJx9BQiFl=ujm1*9^u`};Qp2q(Q(~jTl=w?R>naECm*I}{sNELRL9rwM%wO&pn1nvZ z(nV(&K37~BUCbnOOn-64i(+yvr?M5)q&yr*w|9lwGFp!6Doie~#{%r2(6KP}X!gl?guj`zzcqQqD%HL>kKDa~YA!Rjv2} zw|)+Pvfxbtyvf7-r#q!)YRgB-OwiTgFD{i+@DFQ-#~Mi_HP3GSaBWge?xv3rqQPh` z?=DS>Mzw6XOy~JFvCOfX{Z90Cv~l7Fw<3>HtfH?u9esW9JN&ZWjqWGHrjKe?&|)?| zfN|0i_BIsYD4N&MsY*$&_eKk8d{x|Pn7|wtf6;)182Cs0!enghBZxIQvu8U2% z91Z@!E!Q3#j5?hsRzVcR=*Os0(f@L$h}Pe$uEAC(M*MHCl4IQ7r@`>_@M)^QwVL5M z3Fc&R9A>Rf!X@`~oLGNz2G<^ZMV-M{(OB@%)sp0};WU1@!^5i2t3nJ9h)D(+N_5gW zy2ATWq_WXCF}p`j%+e!2@fIDu_wt-g`I{p@dAH@=WX^@cX^+}zO&SFc*SsI`HWjVC z?+j;rRHkM$SUdH7n0TUoMsYgd(t4ph-F~*^qd`U6YKKj~6a!;>Tg{i6q>-02rQ<#t zADlzuzM__Uv(!g%pA~%H)PWk<+v2ad@?xqN4$jZ8-`^77@J>(st<;&$zVDrGaWEH{@Jc% zKCqs+njH-0zz^6@>tkT3y~dNm9MKX>Z+Ry@=>_``XVL89@|z#~`+rp1QDkHwlkGq z+tlY!i8Q=wRLy314H}?Ia<8fx&OU6e131%+|K#EI9}+~CtI`G6$}@oDM~`!XHEED) zcK&J3=#7`stO)cKijPyiN;6+%#~(JW;U;C6S>DrL1|X~Y$8E;TDbBtS>k$q{LaDNd`moXV=D7)>V2cbUO#G1 zD&?f*bVLFlwM3JhX#$tu<7cs4SM=A>d$utTg)3)i64??T<@MKelLia)h78sKnKfU{ z!3Z>&(RECE&5*V+M%xR?`#Zz2x)F!;srPNCw1b-?Y03G`EwN;}M>u1aJH53t9FZ61 z%gfAsNn6C14CsFv?X*1+`C3M#a%M(;bJ4bYKNI>1=7YoIXGxzP#)*+7J}`W4ncDNM zwc#&kSgSUCE2-VMs&wT$x|h??x@)TRX^C(l{^VFIkh8?KGJLu-X6K_z-IyHtW^&!3 zyqa@DYf?mpvsZz&`5KH;^MY)7ZK!)PPuW-v(k!jzSLN@s-{Uy&N^AK@dq3>XBpB1G z!cA5~xr$+^#sy5;nQXN3lZ>q8Y3JB4)o-ZT6GTcX*0b{{a9$1$1&n z;vh|bdd;B7=sx@!Pp}y|$r3o%r_0JGsE#GV{e^7j7{P=O`(77`v zM{cFXewf6CN^ALF%p2IyOC>@dpKCqzE+E0c_#lF2WFKsSxZa@d!RnfvWF(S?f2Nxd zw=eYPQL}}*W}|*5AM8q^jbaaI9i>JwjS>5i(Q(K2!-wJg)66}xU;?bU^@2jNB zX28khYV#%ZztACH~sRQ;-Au z*`kB@#H^>+aG8k;N$VYNzr%hu8v!&+)=0+CmZQn`J?Y_d?Sn0E56WpPdewSp7P^)- z$IsvV4@ssQ=)O^7Qmu!cmwb_jIh75g`>>Joz_&*7x9B5lZlR?7!^qv7LSIN#oXe0g zGi__++_R;dw7FcQYw$iCObNY^Ox{^JAEE7f?Oeav(T`4Kp+Irt^??jZWn<)G$xlLv zPp1eY#JagHL!w@@}6cj=p2F zqw5CI-}c)tTg%UgEre#)&uS`tErZ_v8|5cwD%S#{H&C&swU}@&TOVVLSY{)vr*oJY z%~Gu2pCXo9U;BkbHTt;`pkUaVW$(&4YIJxmmHYw0&p|~vCi=OtW!e)bRkoOc&SfpX z)f1Bg8if($iSL1awOaoeX%1v^UPa-Od_dz)bRyP}*F|pEK$KIZkgVwMP0E@iXpf2@4U0NAqQELf1aF^`eSVfh*z39`QOYlFIEVkj8 zLKif@O}6nr$;G7FZKl(1W_+;ftIaQ@Tssn~v}*G`Yyx6Aq>9{|6#F^^8cvMlR7Jat zJuubKF(utb11kIzgY(D9qSdOu!p&t=O?qu6K9qykaN+U4oh^Pg_T`+F-2hb!MTWRi ziK8!T#YlzNHSo#fnQzpMj09_8*wYshCH6C?Ko#EbB%!hYWbI3WD(txG7b{@C0$7)u z+dgzV2BO%H-~cn$+#TWsB@$>9-(F6%*```g@WEC!msNkh3Si(Eo*#OP-g5!dO>CH3 zXly9I?EOsIjE}Kjv37=ZXNVpJXBf;H*25`0Me}}!{2*zB$i*Fps@ImJzp*ij!Btzz zny<#_GC#O)(h+Oqw`t8}Oz~JUUh?!sN-@`^T02mc4&m29IBV?3Vz-jS?n;b$X3WcC zc5Nv6RR$g)l>bxin!wSQ%3M{6L6Z&+FD5|YM66{vaT*lrz95qEFs)b2fVsvC7po%o z9HFNbwB2w7O0>smEiX^Pk@krA=_n%35AI+c_BGx2Zr!w`Jgffm@DVQ^>=bGr2?pgV zC7I$N*INFyq{#K8cO3p(%m2%rL>uIRf?TZGe*my2nrqGd1<683hs>xN#pZK$)4dfd zweUB4c{%TeuWWfeIcF37E)VneO2^kYg{0Ac^XwNjf3ZwB6i&9+Z+X-18p>|umUr0P z%eE&Sv9Fl=I{l%L6<;27rjh?dyJfXmlkXw^r6T1Xwny?hTL{wI@ zalp6QG$SVVqE8}m9Ua&qQD4W3{WpJTsN#n0v?sn(Ns3Gs7!gGw!3^3-1U&W?SJT%vD%mQ|UVpJOjNqrk*A&7P{mF>a#;7la4L%1EJ36KYAO@$H*% ze&!)4rjJNzjDihzvf)7N5a9zB>%d#{H?tWrbMFGty}-Xpj}&`-sC!80P5gv$n`!la*I>l#qCAGn8f2vm;VO-cPwit1B>*ll-r}aU^lC>lJHKNje{~>a zd1h|V2`5@f$)#VUQP?F3G&FZ!TugNtI2U zcE-W%v&p1{F=K*QJoREKpex!F_~F^1>-(_u9ha!gDP za>iV#G)m88+L%N*4UnCLPY2#r=^Y(xB0ip)fp~0v2hO^`23d1=p2@Ez=AD=CQ8}?t zZ@$m2kM+=9j5nw#xt;bLT{!9N377uL`#m>+xiW` zG=y%vR%EF|hyfcY%?7*e#It8jjwhPxT|Lip*A zUgU_Tc3pg2T0+6eIb=1wNlwZEB}a`NEsmN_f)7X&k7mZNCvy|IA*9~uWJ*Z9ak-Cg z&F85aRVpx5s`XD?aRG?qOpBxeb{9}NX37!#NUB6oWn|hBR-O@z%9`=TV;X}2e)@%? zRpgBtqdL@6M z7$P={p^&jeKhew(?uLcJ^Nb_450lZ7nzYETWuk&k3nvf2J zChcYB`N&o>U(k4y_>_&BuHg|byZS$Y4wI3l?pHOfiaEi{SOt~^B^fXWukbw81gnW* zn5RbMNa3#oe;45Yli#glpxX6Uj9O-*%b@c))v!4@)P;67ndS{0K69OhV!OkgPkF1J z$q8?vQ7uD#zQlQDn{!_IpvrW(!Us0S;k%6O>Yq`iY|^eEZRBR{o|f7hHGhY7OlWJf zl<7VD-ky=PCs+R>C6A`Z2QlB_Ewa!Pxe@OkQlxcMwxK58=Gqw~%rRo><-Fre4Q)sF`&c$9spe{uRw=3X zdUvfE^gL4GoP97U|F-b>BWYwZfCZfJ(4jz zo{mGT&iF9>b*$)=8}i}w0ITsFic?|y*0G2)OImZ!A}i$`nUq9P?`fhQFnF9aXD6ys z=AQ;5r$w&M6FWLLHYV%4XU>PZ@PBC4PtaKA)D*cbx9Yz^-?v}s8nlec(51@Ryj?C1 zB_g4wUZLTk8AqNji@I7m-#?ClCzSeZ;}|X5ckQ9%jXPh*^WwJO)cozIe{pzVACB`O zsGXgvFfEg(!r07!?A+K0bhO0y;mrLFds(Kzp9ya572DBuxPgE)FjAFkX?PxjCe;Q49zJsZ## zqGn)Q?0SvncXX(J(L(SMFVh~h#fHXYS6Kd&v~cp$rR039fo5AYyvuudUeul#4kFqW zahfT974mb6q&pz^lu2hO>4vV2J2vdt*tPM0BhWOSA@aUo(@=cn%QRS*|c)9x}Rv=mG1kjy>3PdIo zRs6v&_*fO|WxGoAk@2LZmlb*$Ya#fUnl(z=Bz6KgAYlHjvgRbgb+}!X(~B2&s*224 z(lG6bW@*$V4QlO6LZjq=1;e|B)ab3dpv2L%%3@PFKRs1-tB8c(wKj7P)1|`81{E5x z`)iQZFxHh4WgB}533Y}?Y7ihqgLj#pOcK(`?U$ra5txS-(*M%%AlDcZQyWL$Fj}iO zx@4$ENT6N@lGuK&jPg5i@l|L0pRH(o(ppW)K`zki|3=A0RQNzkw%N%P zzRx{RX{m_52LdNxDU*Ie+I?h@XsFm?goL3`=3b_PG*q>Yc(UA-VY-ms9e-+;eKEOVunJLSO8dTKSe#RXd)Ej%3SyU~(k+Cnl8oVQ|Fk zSnP^90-c!O)-yHMtl7DZY0b>dU28g9`jri9_I4=S^}6F&oR5*tLb&*J7x(E955b)p!v_>!?mp@f2J6~9WU!~!jypeITEG%=0&e4VH zDwb~n0xLPg4_J}4j!svW(|)XSvA+`7+3ZgKIzn(~)0*Kw9a{GqW5zJaf!mqXGhlo$ zrdt9I>5}#9bYn&lm|g zyKoBBud&C2!qn*b>>)usxjO{za%UUnymZdK$@|oU(_7BV*!2*3V!Ood zMMC6&iSH@U-ONVBCGB^*W+Y zFei3}$Wj7WD&wwPtKkfSSaBE8{;}kK!g|q?l!^j8vA;m2x=JFOM3)&yQY)OvU=@2< zBPLa1Kf6KRr{Zf8_Qd_|bqf-%9DK_1oBR-!#DC~cgELGMsyvM1IV_BgBiI?eKgZI! ze-jqZFuEa%qE?epJ@as%XKGbrx^u9?H(jfnBGinxvga(P39&Xdt{RJ#GsS1>$@>hj zaWbN21~c;z&JIO4T4ZRik1;7#Ok#ihPti<-xy|zhVyu9uzW5`WxQ_E5QvA4&FEDEk z=ZuEKrpNvInGM&*%UU)#1%tzBbkd4^?$_0v6)#F!o77f!f1f9Kom>Oe`YZ0c#Cqav zTRq*J=bc44c#Z0OMg{6<)-kX&=b_{6ykj9M0(GxV^t0QYh=@1#eoPd~ja2$CcA_+r(v7m|M~H4{mrNE`_dr-_S*brF0^CF7sh^!u|$S_nM zRT`o}n;JH(AgjLMTU`Gr@fWwDrf8f=#w$bpLRA^walP^nKu+0okVXU44#BB{o=6W0isxU5X>z!wEkzwZ=k9H*%Svw8E4Q zrNLoNLf4I8^nP>?M>s?6ocG7%eu)Aa2OGY{{>)EjrQz7OW8Rq^KFf$F`;0hAJxeV{ zrG~9+mi=rp8%T_U)UQBIXLGk%hj*3!)N05)pF#R+)3oxXs`@1C7g2R-GslK;vi4tz zo!+4wy)ZD{^pA!QP4CEXdWRY#GkACSZ2H&_*bA=7-_FAC^!Od&v*{gcigwy(-?O0Bi+72wU881(rWOE~Q39~63KbM$Fy5-sT{l=6ZBfhNv2T*Z|L&aw2nv2<3 zar=wxX{89~!O>!f3^>fkGu;&q>%-@*>~!KbRZyNq_4(u=^p|jZ#!Foa zi8du%_NX_sHX~f}h?md&wIm(f&lV-Ui2tQl{YywB*_U9_)@OWkWD_8%&(+h+aKt@$ z2_a^WpH$pOK;g`!tW1r^r^91xj3|mL3M9z0-_74Q625$f+VafincJUXl5XN`3B8eo z`C=ilv+w;aHB=3zkYO2Hvf;8>+G@Q{-|(R-_l`6lj@D6B3H%GhM4BDj$%;B-Gf7;-H-f!3!~Y$vMw@9|M71cbm@5|K$nh%-EY1Ir@iztba3V~V zIB6|$jQvb?5g)E#OvVfrqX=r_&*?e$F!wF^urVH+ol6&m_da6^=VVEBsQsC4R*Yi% z+0^0l=4Qo({dE|s{X@P{eG>f|Bx!8>8|mc6IO*KDF!Cy|yfSvbQ8$mwH7%@2OTBiv zBsM*?E-iL-J0n8B|54+5G}D}RlBF+n=*;`lu%MP>)AXW^_Z_fN@hV7RtaL-V1$q2@ zAo)gW*gUVqp%tcMHp&(DC5%DCb-mPH!>+79o$-7IUQEBpD8ifK09Q-hTSj9 z2C%GfzBB&`-#dR&I?2kH*-TrJ4r*$gDcb}LM|Cbi5y-^ezyE(LUsMFn>pZ7?fBnk# z|LOhv13t3ecX1ZuV^dS##S`6UrTd)YK6BmYLif4IeXeq!h3>P$eO9^8CGK;)`+UxQ zE_R>g?z7!}mblM=`z&^!jqY=W`>b`JP407n`<(ASm$}cS?laqcPIjLi?z7B&PII5@ z+~*Ycxz&BnbDyQ|v(A0iyU%9#Il+Af%`?AwEj;aX!#W>!c)Y`X_PEau_vv-xdEDm_ zH+-x6Yi#}pp7PBsdCujUn{KF$!A)+OebeqR7T~S+ zHoEG$MP1e`-MKutUyg9maF|*)tff0)RWw_JhV^tC=NR^wZma%rem;0p_m;QKCFYSB zZjaf`Wwz+hUVBU@Sns-V>x^x~>)|mwgtziEQ98E7?QI8ZI_)h7zqi|d#cnCua?j-8 zec>@%bK1|{qLfh#YW8#Uxx?P3pL+(-LLV4zl!W}v(Ai>lnrF|!{YI(AhxWEaDRt1^jrQ3tc71UeC0U!8K8x^V}*GE;BKs zJsA+?T%>>h4}4LXvuvrHe<3VV(RbIDVKdjX9Nas}Oe%O6So$zO;+K<6mbJW8u4d$p zlRE(_n$bPOjz)E7lSN+^rvHw)_qd{?GoFt;lJ3R$N`-L~?v?ld+}4n;y(#{My*qtm z8_wA2*8?+GduD}d^Kd19^}?N_Lmzo-ULPAenjZA#Z;y9I8dOB& zzr_htklptFADm(WDu$WAtxg&1Ut66r*FVB_l$&YaPy!rpH}vF)MwBt5oH-nn>w&!R ziYDT()=pjIZz?7JrEvWP0<_MEMC(Mq!|<=0m^Q63`!1NVHo#@3mm>FiXC4iZHkcau zjR!G`uZhg|o#nJz6+4PE+a~B2%Kz8-B?__(1*YexN4|kw;Nbf{hdidycBxhS_v$Fg ztGNc{m9mDbtoFWmm85M%TQWr{mqSUxn85^XEqx`<`&0Vhco*0rPvbwjsDtKhQ|iv zNb|NV8L@05DB_ilh9mAwdwt8tDbui?iVxqr9iHMPgh(*AvFN=sJAPLI9&55O-L`2UqA~H@UVxfrm<3e#_8L+uT zM63c`@@a@z_DMt>I7YN z_^mjx6}WJeh}Z$r2HU?)#Hvps;>a-~&O4ci4iRyVA!4_PxKc#y1s(k~L^OXA5gw;x zjT2cX6VWXqe*PPA;sCJwQW0?k^rKHh#JW!+!h4K}^G_zCM?{P;M0g*E6PJjHG|&s5 zhKTl0A|mw|5x$d&@K9c~@v&%M^eRRt7SG;DXt6sBU&>9iL~Iu4^9M7U~xAc>dWI+U+1u{CxL4!HM^EE1mb+-(6kEbie)5j^4eK zZrhgT53TcJgOkeet$dI}%@l#?Eu8&zW&L;Ep#77^&OExCu$pJv29>}x--Y5-8K~-C zoNK`Q>%1vH)Y^h}Cg4p&u9om-B_(`?>( z_D_nQsdrw#IRqM_JiLC99Q}xJc9yTnf>WNFYw^Isj`w!7-L6Xi_%77Ct_(jg5dGub zFqsXTT^smWhE|8Q>0>@*V)V?9JU&?7%Em}pk@dVly$WtyFPNq^Hck2rPHG+W0v4YH}~c2iWe{nw@^13fR8o(wAa zl;sD~PhEcCj8m51qw-5l`Q9H<{u0>SKMR!nDeK?ulyg$~%^9aGKV9XQn)3a?z~d@E7j)65EZ=k1srm0Y+bRFL z6;wX4X07oK*fl-15&ozWxD~-~LP0e>|{xhRUz}e<;8E6Usj$)2aUn<(I4cQd9l} zVBLKxe=?~2Q`SG=lyg%3o89tHX#Xme-~OoTA5{7LN8{(O=U*(}9lp(VV)4K46Uxs# z_muUYqVh{AKYx2y{1#_6+kR;|k)0ux!L=+g*lu7&+LiTK_YZm|Y0T|n;NRs2P3oD% z`aMwdRNnUOmsXMbmTfq+Sm*7E@7mBgB0zw~=Yg5klCpC|iQZ)G?7r(*mSOXv)OoR+ z7i8?K`A@bP`0{P|=L^=erfXWnUpBU{IYKX~d8=#C!q&Z$y1KhQYo3D^w!6Q0;$JeH zv3_AQsWKY6Cm`b2XyshPK32uI)-v*ILpiT)bcs)bIXYk-q4^IbX-(hP7Ah^`j*US9 zP@Q^ZsEM~iU4sfClgZyKUEP-OYI2E$=5(Z(Wqi$rrhlZm{Y2(ZOq_Xo3;+Il7i)2S zFAzd>gyB1uFpGq4M8ZSth{qO9)+)cTE^zvOs^Ou)n)j$*Yh7T({z)DlXY8NU#|trK z&kB)kud)8tLB#{-^{3cd&6b_Dyy?1c@0)}-%`*b$^D5MPeNB9=vo(>}U=Po#qy+9c z*PPuJnumI@BDiZ(TWCHg`@vo88}ZrW#H-%#bh)nz?(Lcs&u|j7KbA<4@w;73{r~9myS!(Lo%)=CsHh+Jg4Lp1}Vjo<5R3AMR=Cz73pqCsW&ImZS5~9 zb!nm`wRLQkDe26bFF3Sy{34MeI8R6=WtuV*wTa&z>di<*pYwAuR4h60u#lopFsMIz zwv%!CkKT4;_5_6#Gpkl85wk62_r9%@+D3cRd-O<6JD^8e?Lj@#rybHGqxd5|GI#gs zk+nGKB_6)KWIg;VKBGr=!TEaRu2S7c=Pfpmg0z?t6wc8jTJnm}UeK~_LOr0$ok9mddtVdk1(m%abOhA1TgXHGf^P|Fikfnskh}#< znI*PngE9@0RoOc8b|EN3RR}EtH8#8gS_~?jCA0)I(Y(zA^_;GF1)vpY2o-|18l8oKpCdo10e6$l}j&ZjzLF2rIzB=fl^I=^`PPf zqM#8p&!9P=iD`=01Zo~4G!N81OlUsHKU`=5sL3E7Drm21BR{Coa5o!Na;qrF1ugI? zMII>aLZL!XtwF`0UV{Q4uU~IVL5-giDg!lNBvcN1&b%ED%DhcEYg2jN#d@nv<*ZAD zCV&Om9!Z1@85-m15AKnF}% z6R3WP-p&K97%N)lgG!bvYyl{EgTfZ-?ae}qKE z`sRYFhAT{KAHQFy090{~P$6isDXkckai+qW;pCLBEA2Y*)Sz}y$t?jtIAg?59+zabO_HIG+*dqF*~DXa(N-6C`VRQ{GwFR0kW zI|5pw8wJ_`=;vA0XkACv=x;4U7=2)p9<{&wNDi42JP)u z&bvVqrzfj8`R~#rKNRQqU^X z(q$k|P+{eI`>M(v59-)1Q~|0mZ!1B?+Z0v>TC_`O0%-9|LK8uirhO-aO13I&3TVPk zp&)2cr_eM|r^&Atl=h0kIyl+tnJ=^z)cp^kPSCP{3he-8EEDQh*x!YAgBHIi6a_`i z+r1#)3kvH2m2Vb004m%d)C)@gPoX2A32j0ibj7?)Led)NKPQw5s$DLm&y%G+E0iwu zusDZ4Dx}p{-C$oR0rz$tx!E^+3$rKLFIoEngcqrNN6EFzV|ZGw+OT(S4ghV{3C^yfC{b>S_+z0 zAhZm$^a>$4o#+@Pvxw} zG#^wxUb!p)%@Z0uIrB?;Ovyb$o}+7b>sP3bHfkRxR1aEul~5zd>l4x%a&Mtf6{u2S zql?WdV06GJ`J>0r->W4=#n!kUl_h$Fbk};>SCwobsKcxzo&(iht*{Qzb0<_#Hn= zVLJM*_Y3U?c}5By06h13pPa+S7E83ZiCW5<%blO0a|BJI%x7?lM5*KBa;hgjzNCV!ab^GE@=K5z0C%d zFBi%Kbv!S$7j)#HP!FiolvV-CEfy`6pbCSkK=TZm0D8`#iJ-LW6mK%9#GpB#t)msz z1kyOkWSIs!`F ztcAO-j}^QmBjtdSFsQ0H+Lp56HYk2Rqs?xuW{0 z%wblA6xUO8T6mtBooyZjD4Zm2IOCYY2?*ePw`OD5EQm{)YOUE4B|NA2*aKlhr9Ndb zM3`9b$2Rba&8C*nYlAl(YFra~y>RG8{Yt`P;?Rwa^Nz*c9+QPue)EG(RTK728u(^k zEac=u@*yp+r`UW&B<1+TyW`(=N=a#XEk(unRSeNWubmKcTfE4LImA#i?BRtcl=enk zb_S^j?le1m#)QP?*51ZaY#SWgj((e|V(f9sjYIY=Z*0G`d9pU@xRYZ}urkBN5g#GW zhl4tQb?}hgn!hi84wjOcx4P$CG{Lj4XczErV~XB+;7#+H7h6#y<7Xc+reN`*;k4QI zumGPDDQcbZ{_%DvgOBNS+3OOj3vu}+bR(;{Vp$!)}YhTeS0tqwlIsy7ev#=hT6-nk5c&tL#9 ziwoiF*we`R9lI-|bB{c(M_%eHY~hS9Xx0wU=)yYli-R(43>J$piQu2V$v0=v4Lzaz zi#;`GRb#o!Wv$pS-pkl$9_CEr@K_a`zCT}I1rOYe?B>}!11q|B4Le!r#CF@0M^r4k7J4dzuWtb5n>FDIOWVAUxG;SESlg(z>qq zvOQdp&gGHPjIMF!M`qZvOS5n%i+g32S-?%w+)?6xjnE6cbIE$D0;7U4^_(z-;i2uXHAnl1ZuZp zpmlkKFKm<7wdCbyd!>Q8Wf08bF){ns(M?%y7ElK0`O%T0d3K$BcoCY3y~ zUEIZQ?!lPv?1bx@V7Ceh;ZEIHqpfvJs)LwQyT)GZ|Iu04?bIHO&39I2Ei@oCJWKng z_UQ2Pg{8O_Z-={dI;_{~RGxFAW{Gg2Ab{2^++Ba1M{K8ooiyn8lya;q>6t(Bad$<*gtM zuA#$cTlIUD?wru!Gp+jHo3OL22ESq$OSK!H(7l=2XDZ+~ymm?lc-m&oN%448*Vt11 z9Gy)Z9?mIBsK>2GOg`sM^-?M0KRMMKvc<;nRBtq7#K)ZKjo26;d8#)|VJ@wrFFu5k zO2EFw;cSLK`s4dQ>a%A}q1Xh|aWapoU#NFP@N~7-N^nNL$-wBhFnI}@Xws4O|?hoMM9}xAai8uoRvMe zxHd#ZLYX6-!0%MtJRH7;&jp9sbr7^Rs88$!|sa0E@+FKE#g_7w1$k>sL zI7BX6AcPF(vxh}Wk zPSrE5)qH}YJ0)N@i0=4BPIVz4&voI_tZ;cI#+nDFy~C-LBab5)hn}j)Cj$5T&J2eu zfkh9h1s_Pa&C_W{Wf5{sppTtVk=eIq?CZnK`KcY07x7*t8QOgv^tED}TSuarJveTh zxwdk&USFx#>l3d%NRbW!<-y!JePaqcCjF1-@C*^Sb+0p8avvqpPipy&RqF?nxK{gR z^5Dx^{7{>=4O(~M2a~$Z3vPfZYkp~?JJU;MZE81nu8lj!p;I>yIz zmyfcGapHDwypl@cIKE)kcn;tr9Sq zO)$>Pm2?M+icYPeJE;G}>i84M@PsxdSx;{cy>~%q&pDB_t3!uUXIyW;%sQiN%UdIZ z{>e|PZaFWZP?qI9kCItwujggumVJ@5%ka$qR?@*;xV_kPD1U#>{>I@+hZ}E6ilcW7 znK3+arlc*`3@XRh^K zMEf;USebK8-TjokbN9szbH(ABR6bl5@$Te4tS8jn6aDZ8X2@FqIia_Ey5gNTrMauO z&i0*mbnhI~-StlXhWJ>!GpF79TT53?m$S|F_3H7rl5RclF0S*OfIZP}EtwJMz5) z=7N$T+lSU}6l$(<6I)p>;kD z$I@B3BWRdrSmq6TBLT9Jto;hv3h@EKV=A#v!F!7suoIf^^W5uk?lVm0K0_VV#?4bb zkDZQZ5LPtVPjW7;h5o_!|7;e-==Q_0m+Sp*`}vD;+j^HGUnK+#4@P zu8ysHTe_1~`Ye^c-X81I!bWqq{c1~JGM6VBa3ol2H5{g__-T=nr_qA_X6Y9n9vS1+ z56$oRM&(99!jI{hU4y1k+1nix8fYzy4|9TqP0ZKS3|#$;KE{8yQ_iqAJ@UmiOhSq%P z(e5_0=EK2iS9j+IiYV{OI*$nHl)k-|2u~0p%vD_Vo0RMQUESL!`_t8|nPXF6anaG* zUm!Wd#lD+#k4Oue$>tV}?&pWD@eMnydGt*N=e9xmVdlI+OP3wO{_HRV#|qHDI_ip% z3=G<>(=&77E2kbfRyg6>filCHMqK96B@`9C_Q$fsYF4R-4^e(QDEVI;^-nB+-6xd4 zd| zr=L*%{ciaz!c6P$97VT}b8nuKaLaBx0s^!fA+iZqtOGvu`W?I!!D3kVA zrqKtl(3V|sXrnIK4aG!KiP`n)2QqL?>{PCFQY*LfthO- zr&8r!U(LQm#V&nI1o!aPcjFNV?ggn6J>CxZza&^JJCWeMghfXif{y@2aQ8QlI0P#I zf}2sZ69gNs*S={+0GM5Mp_!>chTulP|0Tg{&l3q=LRj?YKM;pk0Y$Lyio*`U3OIpa zBNERVk=T9O;Yn5Jir~GVPdl~Ly?W}QeWnwhO1B(1wRTff^o@xc77nQV(^dYF|A+E_ z{R!p&$EnNjQTg9B<$Ep4=RY^K_*>`D`EQNZv~6bh+fMxlj@X2!z3zmk;^cea)Z(G2 z=o{Zx{WE|*Q+^hI-L>2QTKS<4p;l`P@X z{B&F|yqEMWE7s|QH@(g}c67Bp&(nQ&@?DMdn@>;1Bgwp>5(gzw^M7)Z^GuR6lkaj& z$DLgSacSTH8)5Ewvbo7~*UDyw;1wF)qDBAsfUu4v!a6*6t*CmIu!{+6n_Y4dwd`g3 znOzF%L!)V%T@F$PZL`Mpb0`}2$g}f)NPxsnJo~bm1k?F zs{-XWe>m>ifK{(O`S1lAH)*Wsh+Iuhnc*SfKxW&xpvT9wIBsI3NiXf&r`Y2rw~d=X zpr>tI6@NV+j=R-YGX#H5bx(Z2&9LYX*MHC#{_2D+->-_FVJ*M?yN&-pdv5|C)Ajz3 z-^nDIATdD@nwp_O5L>H=Wab1BR1l^E~G{&w0*r&*JQhG+U>I zI2eb9I~Wb&D)Z2|)XR?|F}Lmp8n!#B2e-9KZW`n!eozqyHsj3L3ur2!T?Y%*cQIsj zF|K7g+sYHgwrD=>O>fgYj<2!ERzvsy=nGyEwJW`ZmgnG}4-PoZo0b8w>C=!jusxXe z8gphNZPhm|nhY;vR=5p5y6GHuFABu#(k&NaiW^Jr@T?0lMh!R9j&zYe_ZzcZDYmX>9>z6>o9I@v<;fn=$yMv>_FpPUwxqv($OYXya>%CjhS&3U(sfcOXD(; zic@~M?Z~-`t!kXJwXJuq_&W6&wj(hot1MQoKiJx& z*nFqw@0{gjsO@IgA)h^Xa~NXW?P#oRrhm&+ZW*tme9yVr#1_(-fSWnHvY6cq+*bo# zZfEGp0{1m=(hp8rDMES7Snqz&7P-TGO2%^cgYW?-!;qD=*n4t(L zUl+NBqk~b0m9I08aKur?%MpTer}h-j#R;7s;-%3}(|Y$b@;!|2#tQt+Rlc_k_u?R& zyc=D^6&_Sr=2+)9f}H3ee0p25+>=;on5fBe_cSrCOQbpOMK02`K8V;H=!=u_ycdYn z=PerQoh`cNx4>1P=j?DQC^3@Jrx6CyCoqdaImbX>-QO-22Li9gn`xj6=#m)BeZI?u zs7y25P_27`12Tf1c+gX{czC*7-qlbd@)yU;84Dzd!M4Ne(dk|Y6R03eaT3tdWZIJM zn+jAzG zT`Z;v;YuUFr{JE7oVd3dhA50Sx-%zexkSYuer6wtl=|FGF#Y zaz&bCbqn0n;4*IQ0i`8B93o5}jdUGiC0CF1-D+TrT`KywN=J1sg9XK1j$eZy#dQMo zuA`bQGu^>qrj;49WYN3vT4(q2%P-3+uc6kuZmo93lZCfs@h$8_6)Q6j*rU1x)#^a8E-BHs_v`pX{F4 zx-7;zTltv1)QX=$4~O9uNW5bTD)7vnGkY)%Rk$8Os1`)gcx@W0Be@Ff{D2T!&+LZb zS&;2cn|LBIuSd_ceU8}oB;Kf0uwHzem4t>j3P-dwJSca)<*}6~mV9t-qfPA4^g17S zwm;yl(s9+L01MFcllyVGwQ4^FvFM#tN4h}^6dhU(R{l= z{Dp}Bv>AQZCM1w@X*#|2vVHo_T*^UR(MaURdgP0g32`dCH;gWq#u@AEb<+!qE!^k7 z7)0oir9XfU1-K8qqe#R@VgA-Lck`WsMK+#F>L*u-l6ok0k{e0=c{|vX?6oESDc>o4JxsHM$XAyx>BLYvAD)tK@t^Bt$P6ZGj!->mPiPwSvXIuu-_bVoyQgsjWEU+ReRS53wQs4S_4Mu&=~S;+dNb zianQ@L&`^#f!M|Y+7R93e=NekPzp|uoNWh_`_Akw*mGtZrlh61`=}Nb?1L>3^~fd1 z7D;dwwaGEZ0WRG5;*#S?Sln{b=z&@4oCW0AmcI?oC88hh7$N_qcrorq6;vx1o`&E~ z=jY%GFb-?Ipk~y*p~A1mqv!`TKgJpxeN&4C#)tmt@RD?buxpdKQ!wHWqxoPa~*JU{FR{@ zOGGB>Y;{i2yUA%sxQh4hwxjMi^-|Ka3h`GNDC4j^Wl>O?)NSpZo4$kk{?b>GWy>C} zZ@@xk%=pcF_9Ding>b3ckt+`_kGAB>hijkcIt5qYGZ$kj25ZxFjj<&F@AvSIEh%v2 zxm}E*X~n5^_v?&Vli|Z){-!U5{|RQc;4PP*MU~DjBpUgMD*Pd1S(&^3N2~Di*n%$6uH5wr$yV)_E0~8 z6s!sE;-zWdbnCS5U|VA@F3S|NbKhhnRm=#Kp*QYsdUrLw1fc`>?izC0E+jQG8O7f9 zI?+tUxnq@9A|ysrlo`f2$z^LE*oRn4^txGRUPma!p1jFO9dffMNW||$OE!%g;icRV zhm(TW{Y0T6DUkOty{lFu;k$0)Usv(33;vpot2vQgf0NOJe2wnp>uvtEg#2%GtfL30 zSFc09F+MTfQvMXOkJviFX%ls~hF2m(LF~U}yL*1z;(~jhN6H9*0S*sDM+;A7Y1(VOl zLFP?VB3{P~=LVYJwP+#EN-n-?#;Lc;4YWKMi)67JLAfCSAAO@`<}9%Y4=FeN@se_b zs1>qmlgkq0TwJra0BfJP44?0SQe2;$-IjO@aihsAy#rnK(F>fIeB28^7em79h2XqQ zF=UAt5>+qc9&$oy;>D1-dLb7qAwgnDV!e>xEFlBL5M8~H?-62_v{{mo*-Q+|4w=kr z@id!>DSBHkz7Zqzwo!Z|;`H{D_(lZjZ8JR&nvB_a8nb9YC#P$Ru9n)_hAZ6MhGf8@ zGSKIG8Yr8+sT+n;EL=fhi`8(#YHX$_Wax(|89sd}$MeLrRjP;bqivWOK0jLp{E8Ui z94fk1z<(eDp;rUFMhsm7i%X<`t{3v07_!t7@=3jrMq!?QzMyP$033K0vUCG3126RP%4xQY25=%x|6PP#bBmZ zE_fD_wy0@_XI~8Vd|<6XA9{vm*+qG9kg^(yoTMs#%WO?U0?arMoakO^4N>^_hs>Mc zsD4ij)PfO}N^Gwfve{Z110Tg;Ux&#C<4y;x8AQ5XHaZ_l^FE~+@}LBr9!)c37{y5v z<6u@#TJKc!Dh;LRRtOjO!tn?*$H7J~Sa$;&SdXi1$R|j;gP6OGt`pdIhn>w>FJFRq z^p^3{_FOo3gDuK^5e|T@L(Qi{P5WfbYmR*axY5;gbO;&c{u#Cju!-)*xvsc+mIm{< zxch<~I1mlz!B(Um%S2T~ayQg>+}7y}4kR;vYSX*Rsadi#C#_}hrmFKHJWbau zFDvK;nVv7ATq2^B%*RbomC$AQIm=AOr4$oIK2D7JlQkxaoMsmhj>TrY&IlX0#a zr*|~Yb?2xd?a%2$MQONj*4)^L$$Z3QVs5C-ooOK*6li05*B4=O(VAuirQqEU?-?#J zrgw+IftxyEE{heByKMtG+d*D?=iMP@*0+R=wxOL9@#<|CR_Hryl;I@go8{kT_=}5s zOcceqUW(vuynkP(Lg_fXRIfvTHl6G~A{GsSu2_x9Xffp)F{N3qf3{&VO7t8hf>pw| z2z6)a(`jYe3X~BSg4)x_xOp|XbxBgYy!D)e`CT&iI9FJ?VVf~mO*j-H9e2=qQmpeX zln;-;iIpYB@u>9@cmkbtHw$-bCTCLv4fXxR!_ru6t9u#o36B`r#Zq!8Rzpnk&YM?hCgN z!3nmpd%I>VaG(zWrp3AVn=uI6NEDQ`q6H;A*iKB^*l4gtC0s!C7oUTlY4Hv*%|84! z<~o}e|3(f&e@-{jS~5S22nt064}DjOz9o`xKeNJW7h6#>WWF#}jF2zdMVzM#Uq|>x ziN5>9_C!x}uaD}6$gvON6nlad#KPwZn&(;kA>78oG>kO84(e|dxA)fJy7Hxm&<_+> zO}V)j9uq31RZ{`t_`o7Xl*JOUEPfNG>p!ZjrGAuD^vVsp>UO1t ze2U?YI4e_*(F)qhw68F?YFzLv6#9KkS}!UDd1IA>PK)DRbY9p1g-Yz-huV_2#SmNN zf+cW}7}MI->#T#T%4Sk$-5G0_kR~JWHjV56QU{f5Nb~ z0fwI~7!IIEZA|Th?mETV+aT6kmRM^M3v_^%a69Q8u^|{`22J4b$whQi4Ke%Mng+X= z{l#q({tSmFNgCi}^Lp4Ky83znVsVS$6?)I@A0pjFWzfV~KhkhshZBP2UpGZ|>Hb`692W)lg;YpXs6n~kuMS2imY z>|lfN);bmTtoY%adfz%sYWUSf<89d#8J9zU%#VG%+%*I@`+S>y%hJhj2z z3js65f(W+oVJ(OyP7ua8pNeg^x_+QYd#Z5gnVqgH4(if%G*-2etjBK+*dK#rSn667 zgIZ$DA|>N=!8DrigaTVE&ZP!vp0%Xui!>rBJ0jpB5pZe$sCaKUN(AU4d81glIbA2Q zGcA^eSA*zVEzwUjq3C2A9*G{@Ao@F&=<5*OJl78&KA*Q_9{H9LTQ(9~3mPPxXi1nv z2_zZ`GmPVHe{L~fLiGks$ct#$*SZ^(LDVyiB>`17k}`mKsNoOF=~9EpKUgB~MP!t&NZaMPMS7a(|N z{UB0>H4Tv5ZY1T@2}q<#%e)3L4qIXrJ5cjQO&hceY`Jqfdt<8FQlihgKbqkcmQ+6@ zRXU$Sg;U4SfP)99HRFhvUJcSjS<T(iP7L=_E)2tID7;v=4keJM^9KEfi zDvW}tl=%&0SEZ23zL^3P4bzw&)XdY!cqe!^5BBpd%7){wBkFA_lF2{hp>`Erq$!fY zuK0_G*h?~2H`c#|E@nHu9}WQn4bnm!`t!i`+XGkj1J{lRuFVz~H6-o9J`Om65BQQU z55!nD%CzlBwdq|-YaO{vn76mPopk z^P;ViOerFclq4^#aPEEh8#vHqL^=3T|7#Du%areJHJOLu-DD0Heb=I>;1xt(bQXun zOwDS=4(giG6^df#4c8H2Hb!SB?ytebG#U$Z-v%?W7iUU2 z=P~KZkpWA#|BUq569RGc6&RuHP72LYV$ZhOfVl- zE{A9=TD(Uu&ln_wZWfKHpU^`j*f2c~ma&x1pYzcCX_Jcu`lr%9LK&3QqT$ANEB6w0 zvBuyOUW-irgy@Z@MPw_A^e+(=`#lvq&}J0OUt*yR%Oq(IYv)aisGj4T5Rxs1BmU@( zxu_|?=!r(hWYp1L437I`DH2Cs3mW4vBGli9r!r(@(Sbtf69>?|%_(pwnqH#|demfm zX)5oHktKB$x)B^np`P_Z;}A;Iih2jiLZ{zhr7hFwqDKymjKv-Q!+>LLFW@k5?t{Nr z6@%$l%-IHFWvZM$Gh(K57;L+>7uF%tycE|X(BZ>N$N8vfUCvT2*ZSTbjm&8C2-o2_ zx*_8YS5QHp&?n=^56Pu-_oc{cY@nLu9BB$jb~NKERygK57PpNwXLGBuwZ)9v6eCUZ z5Ju4{(!x@mQ=~ay2$oJs6vYW*oih@9Mw%UmiryfMNef@)LL9t7^R0o%JZ8t=hlpYJ z9xO9c;oa;{4Va5rZ0X=~&M;Cw;Bqt@mvxY&X*SX%Km2Sl{0N|y?)k6p(g#({?TRQ} zA3;Seqy-f?kx_7tk^pD_ilK=ii?{^a@&xLmf4c4c$9H&5T|P+`GojdWBI~W^f@ssMip1& zipgn3ZjtFhfclXX#pprEQ{(G>|3z?yk-jriE~xpCt+sq!9!Mbp&piyex=IT16+^@? z!-S5IcW{{PaLhm7FW9B2E29G+ z*M|8*mjW$^6hNcAGm$mie}xG{tooI5e*snqYYr^A7u22YW3h=HU*)5BWkVcx=kjq9 zI?}HBp^|o$F9IQK+18)lZRcEo-7-pNtb=rg>vbD!J}E?GsO(cOB_$h-5*F8xB0bd{ zXY#Y|<|5+0q|ykm?&Wd>vBF*bXfKBwoV1sNYwJv_>s%I+2ljF}KufKgPY6X}-H){S zWFJCTA9Di3d2j`S&}VDl_)jvtf*5GP@Ne)dY$-CF4<|8v?y8f-FnNGsU(8Qh8735k zqeO<6oPdNkJA&b5aEbeoLg4sMG8_zi4H;elzrygoB;n<762q&vI!X+a2N)~1i>+p|xSc-&?8h(XsMIOT2H;+9xns|tV zYY~jk)9^sX5b@j`q^B#_TO3unSp1zW{*Jbize9=?&uS|}K&tTL=Sc<&;0)0c{iSfd z_Ak=U?elp0J0$;x^wWrbTamsFPT$T%e;!;r&~N@%@}JiK@$?r+{tf9T68(>RQ~s9| zeHWs?0EG^TAM0Cd5Bm4u%KaDfAJPjL(3fmj{^63p z1C8bpZY}>CAXWHrFUr3y8urzfiM}IT7yecHzJEbq@^46=1F6EcBK`0{``9#*ejHpD zz5Uycf~C5f-^ds$`8%|KwEm|N{f~Q4 z{?|YiLbek9^>Bq_hUl{;=rRA(N@%r#^%W2Y#=~2j^|8p+s(-6V|JsW5e}a?ykmzT_ z6$~5v+0y^#^fwaykGoU;cM$zFqQ4I=IyC*WW&h9V=Mw$4BKi|`X75z{{6`6K^@RFgNx?ho~Gz6^-DZ<0r6cqPpSS{{Kd{X{2gs1e+S=3_0Lzd ze-SawN#yVAjFZ2f2 zVtk$#52IXmg?2=WZuP}0m`GWHY~ahU2Te~HclctQY+1<=hh1oC6qsMQ8_O4@DGqrm zrn&t(U`7fC@$msXRrc`~}+; zz4p&<1uvj;Yv%=Y1_vCo8t7G|Z$wPsWU}IJ2nH9Ezqf&dP}>x{TD(3bFHh0SPNcO& zg+*{UeARX+CS%;NcnzN?>INCB2kJW0dQ;0T zBVMHM4+up1{sVQ*a6BwL24d|?FpSr*;w=aZN{4hw{D>1|uk!&9lg&-d{xk*N2NDki z7MhajPm+&De6gr*pg0gAAR2c~rqi?&zI_+3wjNw0&8-lsK+LiSfy-cV_Tb3Xg(val z1luzlaDST3^_XIN+=Pbbga>CUd0-2LhpFji(i&|0&^bUEYveRx=#Sg6??aK>fD7D40tymR4)U(tCQ z;7Xm6Y;trjY=n1u!{J$UuCvMC(d?4JfhCcHg(ty|^FtIC1_U7Bi0$C?DZu3BUUv|G3eT%*>N3PtEj0Nd zAnk*=&5S87oUTd6U{?xSgCI=&0}cJ^5fFLrT>-4khz-$FS-CgeFp7t#U`-WPCfY*i z4%8xW>D6gke9Y>*v2l8Jhw*TEVrpkTzJE8Od)x2UzQ%E(< z*5cZ}3{jSmnlBrGF%y2|rf0)nVMU2};)+cmaCC+3(@OEL`jo^349yeMHcV53H00-p z+x66yQu@EbFXC;0APVo7{7Yh%hULYad-m#MY1B{h_HpOT9|pI`^!`zn+3VxFE#D32 zGQWAwHWLT4XBtK-Gg}>Z$?SNwO=h

dd$~9WxV>yJe1E-#c?^)r*;1Kljeu*;AW2 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%0A)6G77((YEM?B>SJ8E%=QgH`)u_L+Fg6*+P=rp+5 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%0A?3Xd7vti7LZ*~K$Qeeg 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%0AgkY~& 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

%UP&hZ22b<9_%(79aQtDFj?b z7V7uz=*WdC@l#pMkZgD6xeyq1+OliAWT`p%m=)4dZo#^Xa=R~BkH@~@!nx%2xjOnw z>u}FY(eyCp_NqBflIK^v@yUt<1*jvwju!+9S{ZsiP;e z5lC|C<)A%gkrdSugatGe3LT?`x<;Qz$7%FlJjbBYi?2 z;!rlDAzFB#6-}qQdgi~(@a1B*M2ByteoxM!MFd*&5rNi&25E%VDJs{eK-$bT-!mFO zB%s5)J71l8BM`1r_}u~;vUR%@>7X9z^Zv1&W80(Gi(ZHaNU&)$2H%JO7F-9F+6eEV zaI1}unWl*RdxfsrtJ>w9hq>+X*nOa3@vvGQk7-T5hb=!EmJ6216|!1rO-hm+S4(R( zw_(*F7-)+eYN)2L;s7cf$)2MyMm4!I*@HMhC(*K!LM{eC%gySSTO#ia-A#xk*uf)v zZx9rDy+K`(e?5w37iB5#U*cceJOzNZF-!9MZI%YF_a4A^cRqHikBVAzS2_P(WUwN! zT-b>ch8->L!^iHJ@Uf+5o~>e}cxQ#EW3hyQSfca)RT6}WOk$t}yJW`cz4`Tp2pR2Un zm{*l{7Ah4ELY6)_gQ|`4asyqppR6TUB-BjZ>Q`AGy0d7l-5{7FwI zS1919LbYzi3UpdL-oXTW7c(92xDqqdJYv0@$GW0<#M+Z#P@E%&D-VV9hYQqDTb$<{ z-vFjQ8t8Y{@c(mIn135!VgBvw(wnyZ=h6D>WE4wO{{}Af9;&~^{92g4;Hi4|70rCi z)D_CiaV(VT-IJg5J;|RPIwljxI~Lb?JE(>bBU_D%DhYVV+h!c(<&4lLR%tzIxXx`S z`BqJ?8H*G~DZ9MXdLl3B!{Bcq*hj zuVLKptI7SB(qV=AB_a-}t1tIILke#b)!BayyXC z^%?b)$NF+vya8{tu+ykJcL50+>_3Awzj^c2)}g-e@ySisPXu}YUizG^vmG1cl{0JK z6XcaMYd5D|d$Jab`eN&B4+VMU%-Wv@dF9O7e;^P2;=a*5B7$1xG=Vcpv0<-OqWd;k zHuH`HibYAYK{1Z9*Yr^Q*Gq_H*Y373YLsB`7Ive}eN z>&|AYxl&Z`K5Zh*j8Lr07!i|>dR?<(_4YDJL47lo2jkgbd zU~D5)z{a?PJYv@G_g!gecv<=6(v=MP^X6Nchrp2*KV#`qO06ZGdJDQ zRh6_%f8iW1S{v`C%T3Wm*C39d%4QnXCnU95yvw^sYIT6VSg)|^mbzYPi=Zo`V^{}h zsG55_06gf{_|mExb?J7}JLwdiU_C+|L=i_-8}~rt-E$82?qih@aQT&R77%g)#0HHB8{HV?TwGo;A6!N3Th1+EX)Fi68dxRL-H+Ndz$hp*5ZSK zVKLSBE~a#zZU#j+w>s`BGeb}$eTy)YGClgZE+v|(0?|mrV}JN9m71e&H(xE4qPM*g z%{fe)Mr57cjd+TnEK4pSy)* z;=g4{c%Snj5;6{O^U=b5XbQTbtF&^jnXqYsl|a1p~pL``|35wojbMl`sUNQ=EQzfo%`7fr}G;ljH^(N&RY{6eW!tiD>ys08HO z!atJnV$>oa)UY~`+l6_O7q&&yQzUxm8t}@;?~*LuUH0T9f03AN35kcBc>)+(LLwk( z1xXnvaf2=mh$Ku?92R15-KE5A-D{-Rh3-vEQc?E;k_K66#NEXV0NEtz6&Agt0YGil z+E^o(mfmrro`voyhU!D=mt?r>n`trYTYj#(a=nCshe&(9N9fz)G;^O`lo3~LVs|0QUxXp(*xkbJY(Naa!qt|nY(P3EBOD$5)SFb3g_t3JL zW^7Rc=ynsXLx9c7X2S9c+`E$5B}4cZJa?^1XXolB*sA5e3Cw2;-n*5jD%Q}<{C~%a z(%pMr<8HWD+sTF!v*x`xm#68Ax)lA^DD7FNzuZkQOW?<&=1lGNqS4j4##b)m-QAO-tG`;= zc-Lj`;Y-vUGO?-g(K(!o^0`VL7$V}#_l}Am*)nHukK9sGJJH~+iMceNui}Br-gT=J zkL;t>@T9Gl9qXn!`#07ic#0l*=`sh;E!F$c>fSqE7U6uW=TtV1<|pNz#<5^h+)_~H zh0y8tF17dix{Xr9gD|h?MxUqnFX^ilM&JI>pF+LcAco$x;TfTdv44@9J@zk(_rLY2 zPt@`a2vPR15qwp!ur!>QOHIg@S@WK&XfV1q_Lv`?%7J=o3UoYtu4~AM@>^^4%!q3> z>~m8Qy)9A+8^}Li&{A1>B}ALq9*X|`^KfMJw*JJB$47WGJ4v~Qlx$WGLpHORuCe}} zStHZ`}m4i)$K~*%nRGFh*_6I7O{Z4Rqt=*-AyB2<{GBfz=Wm=VUUBw^M zpJD43ph*f`+44s;6;^s%V(7|9O`i2m>!E~J&D@cZLyXTt8Y9__ajIf%BX~hNbr@N5 zRglBb+!gBzv$89$+oXcAYO*Cfybi)yD@@ubSa-9)UlL5u$raTIay~yZ19s(SR;9O% z>D|Ue46WP2Q(6NAvRdj|rb~{gBUK`Y)M?1V7?-MEeazgYEeeGfy(BS}dn^o1^)5={P56E#&cd!noP%2sowx0bGqdoR(E5!aEn(vB3iHd{xe zYG`6sX4GEur*(_17kUA~(pvafz7Xzlg!*=R@ZCqyk@R59wm*;AuGM*WYN9Q;LQLr` zL}qhz_-d%`txq+Dqr>+@k8Y!Dc8Ov%{>*AGGnWfi5B%`Kp3#zalsIBqB4V;Kq9!ZQ z&V?1|=7QMNa`oFuTfgNO9B;+o^YbwI;F*a6{0vd6eo{?^Aq$N>@cAJN^nV{S(9tC( zHaAw%12I$88Qt%)WwoG|gWr9&{HJO;nCgs4&)=bO=EE8fe)rk<4G%NZu5l(@@27%* z3DZ3~v2Vi5V^7S%IuZPqcA^Zq)vFU~+1L-@B?u6bv%?idRJT|ZI}Ou<->~L2o4Hca z$#7!RD~lo(H)4@|qNsT9ViS(Y%;@k%ih|slc$kNDTH1Kn>3p*QhNn-lOo^7@qVu5%Ss@*)qXGBh-6e20#oTqFo_N$27PXwTT!(%F_+5h3#c>SEw}QZVHf<`vb6@T z`(w*s_v(X~XHytEafK0QlUyZ6rT6NQAO2508NDr4X>#AmS`+l&28HNtEj){hg^*B>o3g7V$r?F7Bs5rY32LJ@kR;0XHx>$*BdW zg`O`f zFn6EO+KSwhf!laFVp+mGc!#Y?ZsV_xbn9T>D$V<)^411<+B01A+-u6aF39_KnY=|o z-j7T3tj@2K2Uc#4?7xNcvczlpS($i8KP&jeG(W?M-{@`zoW4yL3bC*}W=m$+R_ttY zi)Xlk(-3;(vWc-)R{=fP$tHOo)0<;B9t^t)p=a!EG2|e)tpQ+rB1SjOuhMGJEBJF^0w~ALeg#c%B+{8+WE* z&kj;e4DKEf_cP843QXl+UKmHxF95o-G13m)h|ExkUw)n6f6^4oav%3A62D=>jpO)Sh$kDJfw2j*EBFfT8S0%sQe9C^ic^Y>k;>@&OI3nN8GZH;1~1LT zU6bDu4F&p?>NGg3?gR?^XE?uyQlZhR;1TBtTZM1%alYuP5z`~lRl~L_tnje2MyOOX zOs~~cbk)*?kW@LLZKPKys2QT5rcDI|U1@Y@ICBaDri}`5`8eDj*49TT# zNbZEL=%PVH4w$H+{Gi<_O&EzbcGl>=Cfo#J+d(2z1IkgJ-%=3@x(TQD!;7^P9ArM? zKtBMRPNPBNSTXU4<5jqD1ZJ)^VOr)Fg>XBh6aJ>-M9Z(NLRO@UC zbV8_>@)AOEYLyV0M!SI!iZQxC2uZO9LZ~n#YAFm!QENAzbN|c6!vKiHGmZ|Pyq1zK zXjM;<-8HUZt74^W{Hqs7hxj#M!D0*uz3_)fZh*^1O5NMXss=&JVw zYf}M4%k@Oz?P|TP+J}-s`gRSa>F`{#{qW(szdS*&C7O9a5i8HkE^az@%6kEGAmB=-Wj7b3f;g>>PLE z6UVc4dUxkO?|dOg&Y_0`RAD#qpq9kP#in$)nK>RJTg2#h93Bd+=L1Rw0jWz{-Yhp? zYh6S2r92j}-Tw2~4<#=q<1ysO?~TDs>%W1sZsXV|d;P6|cJuK2U@z-UkL%4om@B&Q zW-a#>F<3E7xqo#2N+~Ve09hO;TA-@D(6wIw=pn<1hq_k`m~ z30fsgNQ>yAzX(h%o>C!r$JB{C{UEyN&@gGxTA)Ezs>tt6gFHhF!Ze7QDNwiTGaXw_ zDxy#8qPCVh%jt?mW-q{q4Bws@%;vQ&qXfqRYLvhi^=&Gn1 z)QAv#Qh){NXhT3|-|B1*Cq3y@7g9unLA&t=1JT{RYLi=?Hqpl*hn+SlQrOf|M!S7o zA%NQvc}5VcB)FY&EA3iz(Q}UbL>$I_LBHr??nDH!Lo!%XD-tFLisU843##TeA_Ybu zW)kG-onJ@nHs7u*hIL?U1e8!j^$VYqIfa@plGpXxKXo5kQ`WF4(BK4+yK~oQE!f3G zm=Mhd$RzeGtB7iUobZp7+>16TPb(A`_b>d5oFj9+ zcwp$QU{t^Blz>lRO7a%o8LorN0tq2m;iSgyvf_0f2G_i-$o&!T^p*A$y1E)`i{W)P zGl9GFF^F_BS>I7T&es)R<&OHzJ|8jOFM6a^JUhXj$`+ocASH*(H}vB-?I~x|l_|e_ zE6-_wju{;OxnuPDtBuaJa^SQ}el~7eYve-pba2Aja}J7|7j1kk@(H2~pI2xP(N>NT za`(7>BE}lhJa^~*LU?md+!>5SFJ{&9>~H5<6?6E6EA!Uf8iKcN{|E3E(l*#ek;i)^ zP>{I|lEkI_5KKv-$fh8y{3FPq$Ylu2Ww>dIixdjFqP+jctJw69LEaBb^M0Vbc|o4k zX3=x~%KK~b?E6piel2qf2nGFIU1}5j+#t%QGf8{0-wYys?T~y=*0X4zVp#p${ikh@ z*L!#(r@0A50yWcm?z>NLmt9b&G+f^74=vco@@w`A#a<}a1vB1BqnVANW^P-u-?Z?I z^Pz7g!`c|}e;KhVW>MTyhvz@66xat`=c=pjMcr1qRKU z?!|Pqxph8&IQLk_gHEz;I+eqkTB9Q!BzUhe@6Gsf?a@WN-7OPsgy(SYwaLCCI`UB^ zx&TH!+xQv*Bf97)CAyZpemj=H4wOfUrMPeKw$Oeb)l@8Q98}FI%5z1VcRLd|W!~eW zW!!N^Gna7Xjr!rcgAkdc^RCeC)S1v{ZVzE3-JF|;kp>oZOi!YbBcE@fkpNhd75g0G z3B^8VF%L4qOf_`NqYwVT%d03zn&>C~3+4(3XX|lgx#VeH#jpX?O^$a(hZhwuKboq;VBCa zi)i-11*-mi0h4BVQ}pr=-=7?qbQxe?+D~BWs9lHOP0$OpF@vE4&Y74*TmjCp&Nymv zEVUiBcPzDzE0y=dx0l0*tR_c0Gtf}5R)Ki#fIJTvPc^9vhSJymd2*DR_C!g~?H#A1 znd}*P-qNPYCTaM<+Y2`N`QTvkA<9ByOlvX{fH1DB1$eU9> z?-$DZV)?w~$~(P$UPgJx1$lp4+Fq~n-djHJOy#|?)Ae(==T1`IW99SyM0qy{d6$&7 z_dex)uY6uec~_Lr`yXM}TRv~C^3DqKcEkFI$~(S%p0B*a%jaFHytm$o1ZPXk`?Y2h zwbTkZwxewl1!KeB{wWw64bX0D!PwBT3$58zW^8b39#qp>FgB!!TC?Aju|b{9?zzC| z=ycDS;W3EeVb2A|huB2guV8#wHGu)5m*85n^I}x`C*u^#zdX3|$7YKRV!F6pdfBB{ znJt3N;@xgvj;%$(^<9?Vuw2Vn2Ts9Eouh;N^!~eE;~BtasEscAKH`Wz>wtxZ#y2k0 z`F=g7$vG>m@!>go$6s2#hjlfn?jhE*2NQKz4L#9C9TH_oTKKdfy67(n8gZ45jx;KK zgvLb>_C*&(m5yf^9m&bcAYJl}y?&v`skqj?@}A0K%7u8d{u5MKYhq_(J&OZXFfH9_ z<86)}l=v*V)3o_d7B_aO#g}ELbg9L)s+seGLeEf7%1_l(5#Q*gt208cG@cqA{+H1ly}+e8>uR#z*3^!>FL$nm;wVX1@gpB-;>=#`vnx@i_M0DghuDsV+U<85`BbpW3K&Lo4Y73n$eM|V4g;*p9(a|s%@s*kA$d9qkm4A%YLrHS+r;6r{}Ah!znFe`yy9kOpg93iJX-|IH z9|2;la!^5lFqC#LDM{;nEnM_k{944C;>i5wjm0TC zm(P1vc}J25XEx-{l&uU6=1$ZFQ;>TfCa(8ju96>gXhZH%g%-OgaXT04`R5O zIq=JVf!7Lf6RB864_Ixk3tx0F0 zVef&*K6D@PDw)DOWFalJIDCZ}mpT)|yDx$+O)S#a`-GF4b_Jc%>Qhk)s4xPY$ivUJo`&9$R z8a;pnq<|s7IbV4Mwk-w$*}wls%2KS6AeL7OLG1nBQ|q3u$2Y*7{%GjFeFMPT-&M;j zG$7L$0^%=MA|U=k3J}oW$N(liI&zszx8>+~G zSyu`s02b&8+S(gEX?6#^=|)feoJ+dG_!yr<*zlJtVZ&bw11=hotxS4!yu+$gws_A0R@@nR(c`Y0*MswOWSN<|$Y#b_1S+y_Xi`+09st z5#!qB+0U%`;;3;E%Q=XWf+%yV!4rxu{3zxPL?-&Xl2J@ff8PftM}I?HK_D}VNT-$# zIsr6;Zq5p=htKNpzIEVOLJpR^BRI=g(Ydl(K$9!0b6?&~Y&~$WIyZgUH{y{GH^U<9 z;>OxN2ncT63qox4!&yfrN$VX&cSJ*^(AT+ixnzig3{jgBhh%e8DA71II{dZieb zmYFW)1LmJ%48shC9RSjQ-04T((Yjo*7M`G%mfTY;$tm_YfL~7wo3G{XKvvpdaPzWp z_t56sWuaXMUGbZ@BF)t{5`+YK{&?oD>`19)>$uvhT@XKB~0`Fki@ zCePqqL7sbuK`~>^C0rraOBd|CR%Vfv#9+}CVW>%kS zU3!&SeMIN6@ho-akIm|XPpPXjP4W3wzv&cO z>?jj7{Jw@zB58GwlO%21yOgv%k}z%5vMF>W4w-_6t@)s#>#c%@oKr>6u%ENaR(*z0 zp+yZ9LLzF2@=4Ee_SQ5?YF)J7baXm%N2TGp@B>5+>8^ku+k_%YB=2C%!1!g%yietG zwh3O24A=gD3HV-K018hX2V;r4vH-{ef=BE#_?`8PPPzkKs!aV!EVIeXM^~9`Z5uM@dOb`;vU}7 z5JxZ@iRi*3H5&!q(Qc)_Y_oYwnN3>Llb-Kklk~_FVMBaCTgI*w#SJEgPG^Nmt{JOh zEN{(KD#|jmMh|v*_dyKZ(S_e&s(oydX0M}g z?F0|$%+*?(qI|Gj-!kZcd)2u4SPTDDCJHVuHE&LRjckhL{LFeacC}q?TC1?XZ^UTnER#8^1z>3|Q=Y!%XT) zB*0?HqDd`gu`-jo8;i+a3|LID`L5`~qw}%(!n;u2(M6ZJ@O-!7zi=*hD2_U&L7HE@ z$ocQgtgfQNmy$kR?*yiIwmkImg)k{W*!a$7uB*BdLo_pq%c3Q92kFUN>668EeCuog zH>KMgmTs|j(lM_5@S6qSq?QSpfrDoe>-U)}<5rmy=IPy}o*xjQ z7nqkVo8FrVtgz3B7+P(nS`Mu+S1-?Q@*h^=;=)4-`FwP*Gx;cgB@<;8B}%+MW5C0x zsn0u-I{Uqg^<7{`Z&!)=)(3b&XCSM*aD2W~PBgk%OT(dDf6(^4#e@6jX%O zWyxKHnw;3cqn8tFUM^=9OWR8YN`}1WmGSW+n}Y5H%<}(J_dak|R@MIh9Oj^-Og%%4 zMX5Q~WDrvgHQCH{yiGdTRAW+6(T#3YSEP`?K~w=RD`kGl&TF`tf=(XFq%GKWneO_TFo+wf5e> zrmp;8c{P3Sx^NZVWNxG=j`VTkBdmLS!;u;w7tTH010*B673^G-NyycV={=K1DyC1w zZgVonqmPt8^*kiuH!I72RNB8!+*j@i^FvMt7-8n$4E1BuzgOuekY2DPBOy|jlmFsj zPX7B#Y(5kC?umz)z_;4No{Yi$hrrwn_*Yu!I<*;6xQ;%SP)sX6t5$q2m-DB&oJ#L< zZgI1UOsiFM*2I)COJ$twG5bd$W>)^lc$n#uGk_3O_{vdF)?tl!+U4J zsf@`fIk{VUu_-yZTeHEGoPJd{PEvaPYMrGl)UQs<=~t)c^sBlZ>}e{`$=Oz<*RM{t zA}`6=>yfiHhqN%m==bE!M3`*dRlS4nysA~+^cIs-wa)bOk1oqO>J_BTsz@6_bXI47 zl2*6T9&RfyN9Jg69-mfN?@m58;)heHN ziz5BaVa|sxSbp4HF1rK;-$Lr$?y~n;`?6Kv>#{FYWG?%F%YJ!5_6J>d?W^*&54!A& z3$pKU*{?3hzSCu2Qjq;=mwj15_T4VKCiXn?&%5lJ;+eo2Gp{1x^{^&8HP-4mtkAL?@|Vy!TdU6;yb2g#qS}kR4t0`l-)40@3W$yLR`i74nPW;5-FP5aYrI(gAR(k0f;3>WIfCEV{ z{h)$OoAkj>1)W}6jF-yU+NTVD=9{)w*QZ#k-KG<*tW!+8r8=sZ<^sgLB5{zC+(xCv z6w|ZJy}?OPEg~p-u@2G_~SHp?@vucFaDKq|+r=5Q!Nw?&Hq?_Z^MsVFnrGRo=x9otV8?7uxx<}E4{cA~A z(tadKCy{3O0sC%R@8-JW33<{<;2ECl?ncMsNVkGelyr^52`AMioS1BOcvsksUp3NI z=Y^BTA;L+{WQ=fTAxlsDF~FKL z`#H6Stxpm>l2;|Pz(^xenn?X{!R>kO4BjlK=WCYCBhAq;QsU@bUpz`->I>?x<8^`& zsk`Zp0txZwxlZ^tq0|$)=cQG4duM*ubJ!abf0p+wI{dKmXNWS|A4q6SYzF=Ih7sO| z?=F5gT+(9QSJ>n0!i{!nYctQxsj12(=2+FVO-eyBx%B1P8ZJUR-5>+_OX7H%d43pP)ZJFJj;T%{AH_(WIa-efd)PIp)3$Z z%oN`qRzAw*Jw_#z`C<8G5M;Jlt}#gJMv^%?uA?~xLD0nOmnb7TgXEOK(pg3@ZNyZg zyf@WR5N%#+@KPzuJ<*bS->of5I52CA5Dv{ii+OB{aOX*}tcU0t&xQnIIQ|k6<@gH; z@MK+wmVglR<`smfxjvC`PMbBL&>AM^QAn+bq&}j$YQ8lnYQ;T9jKjq}I-oOU@EJ4- z#yyRE)*APiPgJUMZXpL5F=|pgKs*8cx3~!GYT}9UCg;A|q5&nZ#9{Va(!{!H?IVQ3 znx`~)j2C_iFN`y_sON@1}T|)%SlMrc0-3XI7tS z^`+xsR^ON7VOHOV<6&0cJAu))exb_fP9A52*05xlYQL{bC9xiRUD!+pZvNox6j%&D z!Q8=F6tw9p&DW4uaS50Ol7 zLn3djPVBQ|x08c;TP0WeTeY062l7ghr)nC0ixC^GBeFqD5bFF42Df8a95};Iy_^0%aHfvTU=dF|-f(o#b*(6~(E60t%i~E0fMlA}0x8qnI#K|V%ijhC zTg_UsMM3BCr_N2~tR-4nW(+1iZ^Bi5Dxj*FspMPL)JwBw;#ovCN~@%0%RK+u@?zX( zigOyKX6~)fS_MmRn<111g$`BL06xvwencFdX2x~zUMa6#4|&hP)b5q?=RsSue`npB}zg;u~+y20fR#Vw8Wp4o3U)u-{Vxe7Ufb zOTLTmX4#SEsGINb-Ry0z^mbxfu9M%N@8dF+s+X;LUPCC~$Kw=_yGGFSeo2VK_VN4w z8GU@>f4$T`#=h5l;fw5J#Hb1Gs3zB(Xru=7CMK_Gl`ejtyJ4CIB9 zyp7%;QZG6-ncxokhm95aQGJdQ+NidRof*40?M-I}tLy*ksPKeW(}i;At0RW){vF*N zwpS!lH|^Ty{RMNqefGJLF|Cb;tN%{glJD;UzFdF5Pw~U`_gVjx{(kf4UTS|cP+s(y zcAbonHid3i-v;wqSdQr<&F=Kk0Y|j;x8sRycb-s@A7>Tp7aZMRr=5daC=!ubTxSkk ze}_tN5dG~73EPiOgwyPSH#dbB^!Meoz|||4xqN@?LQ&V>uT^y{7$Mgj=)_*Z9Dde6 zWez|6v;T_zM#4#t;8eD{y1hQK=+om}#4(Z1X!ySDZ*$JgnyZ|!kQt3pnhTl7$u{jA zHT{Co@aprg-R~Ib(N&~)48e+@&6qy<`6Y&WNwFItc|^*ygU>%+XA)WS+zrd9J11!;YNc2%DslAsglUdKh$T%|yLU4L*RuhG4?q!YS4 zF)u&0HiWF%`1Fh{v0IGTw!1q&g5?Nb311k7ZKnRli{37(S) z+ns&4(P6ApyiM-So3_lSad7D4tW)nv&eNey85qSg^qV=8NaYoYkXUn;H`EJ^{L{UH|I4FG64z-n{|KX8fE_a0{ zb~Kc?ipXp>C71xI*`o~-^iWruIIgYpky2o~gBX;JkI+c%rNSN;)${|x17s!DgDOEA zzODUxPU2gxcQm6$DP1DiLy0DI8SMCl1`DoUKO(U%v5tbKD#t>$J>+otSsavq!a}R$ z_#S5fURb@DV!p7a{CWnQ3fJeZ`zfK8#0i~ht0Ta|BmlbL{RFQjNJv3ZoCU>h8FMY< znE=smMrTGYf^+o68g`DhxC+B;+TwO8%x1oGy`I&Wna$H*N}e{CXL8u6yT5i*15HpD zhRF}Pi`nf?eR`4RE11x6ymcf<^^0C^=SHWgD_tRS%ci>aTnUYeVANBBf>y$cNC_(m z`)+q7=#DGMqrMF*Z9pxoZgzz0&|qQ9h>G-&@osH)3}E0a9)zEgd*DOx}^$LZ75dg7tLzVx|3<_* z>Pl_u-+vN`g*%B=Anj6FdAe5d1!}rj61wWk(^WA_zD_@mlF(I6fv#!^xvcjcB}r-J z_gML!u7X2XV+@B9$%GAbRY}m*O7iGB7)gwPOhaMvGQ|4HSz`F+7%|)(>@*pAUB*67 ze9I(N<=Q+4m-Z-8=JM4+3dzXsIBJ$Qw-O6eS3&veJXO>ev@hwXqAyPs#fU0~q0?GH z6}23y2r+W0WpIJ@w)`Gjp|0aIL7<0092yiQ44{X~fF4$cN72E=6WK|vLN)YMSMn2F zy>(>&10$(VIf+zGx=>#pS;eU1$MH)=n#!Qm0Fh(7FN=dwhMy)?J}FgxV%_LF$2<6| zJ>1PGv?tdw>KyA8R3YHme&GHX6gtMFh5ccD=R0?q(hTVjYq!ITChE&KQJ4y26#UC09XE zLS;lKA<{#M9WG6Wew>QSbEe?X!{F|XD2h@U5qcPkE*8|wsE@%pmDcViorv)RWJewM z*6IML5zu6UHY{zGVI%-{I2&WI{HBDMVez77}pQXDki@E35Cak4s-~AKUHYE$-u9`&jEf z2JGX?36|_Z`>3h0k3sv`;vhThWA9t@O<&=fp;aQ=bVcQxUPTs~Ud>Oo>FZpc4VEX` zbOFS0!!>;lg&aiF_wn+3uIY24O|ObJ{g=_E-#jkT^yW83nm#z*K3vnUc}u?O+g&rX zAY_}asC?74^w9KVr0JVoo?9(XwCMsIsOcRC*Yx)u7is#JqD_BAwCO*JHvKixrZ06L zuGi0TAFk=2e=|+*F}~M1SX&2I+KR;xX$L*{ywKm$*F3EKjtT1sJ~FZkKQnO`jBH@ZUyz*>|~X`u=DyUsP=ra!n83 zU>~mO*Eopl<+@1I2VFC?u4EZpQTe8~xTd#8nyz(*?$+v4IIRhApr+5Hkb`LYcPb+c ze!-`AlY8u?V6z#CfjsH(e#_by3r{6 zwTg{dX=|Eaxq{_dEzk+brJ;kwwhkz;Ylb=bH`%n-jN5tBn06M9WltU3zfUuI+ku*X z(`k$RjDEDn_98!{k5X$Fd4}(=vJcnvw>XGv`uksJ5ZCk{iyszMyI%i<`*2M^nx>;c zy&PouDF>fPoo)x5WS4d|(dyKx#Iw*&<0s+v%cI?H8Sg1&O$Ob|q@2}q>(*Hr!d#|# zzIZqm1gp=ZrT{zk+tgycXdfEb6;DeqYyOh(zWFOVFr#qz>bSc|| z-fsg9u3OOYMv!qzhv2%-OZ4TqqjPlyJc?7wMmQRZOf6lo0_`7ZSAeGYsI+sXBHV6^ zh^cxq?t5bxCJXumAdiwM_9w*BGuz2IVZlNN)U(=(=zO4*zEhzHF2dDyELFA(M7g>6 z4ifpa{kyffPQqw4$-|-I>ThTb3iEIRWBpBuWrGu zP-p*?OPVaL%htJWNG_ttI3yDh)|Pc;1$7IBF!>mN3oyyiaB^t{WJ;2IfFv9)cX&aW z#eAnb9Zr2sTyp|niul$*cVbY57h>p;$QM)GG!avT<45Eb$@p>fBFlj_v}Z14EoZf{k(z^H*`Kek@-6;(R4^+gra z+naDIr~qH8%$~nYcTK3JK_J2dwN@o8k~+bdW50i5h{~9G>zO&4!sbx3u>4Y|hf_lI zOA~Ykis2eu+sb)UK&gJBP(|~JdA3m#Z!3YR4LzpZz9@j|y4z_6lY_L~?`d#a{$T!p zYq(eLOE>RJYF9pj0YKWO)Oy!djS}s3D_8EB^X~gFBBeVuL1c%+f|dHvepxBW9oAd| zLuryho3M%>o%l*quj8+kC8z*f^{yqln3+)g+hIo?ja&By%i9<-o44*xYy`)}s%%+x2S4~c5TUH4OE;(sTr|b4BaWKO zDWKix>+^}YGd0s|0kgf|nWDGGd>`=Xq#H{%>oOhRb6#!47MSU} zoS9Djmg^Cj=`hdz9CH-OXM$G;rH7Tr5K=vft-kSLdA(H6njBFg^xr>HwzihAfs?N$I4?Si0td}kH0^Tz&{BG9CqeWHVP!V~LdQD0 zn#@f~j7A?(h-&{*PqkadZ}tfRs}O)(j!2v8E25UOJSwjq*U5~DOKk>skhqnwa_V> zxOI!v;}qixn}B~IIkejcYZW;`SDJJ=r5L48a9OlTB8%$rS+s>f2RBPUzk?q;Xc3Zm zBj37{oMo|{?!xHU`EV&UXi=pGRc%J-;94YDuj<+it3kudNfK7po`&*Nsd^qf8A~&Y zPJQ%NonjxR7U;e14fbKXq}~s>58Ea6KEw`~Jhn^fZ9?zGhwYMj?_oR4#||s)KS)M% z)NHUhoj*gcSzLt81yxLB9-E#IjI$4?q<9GC2V&Ut%yA!X&o;(=xINpY+OB$RdQNs9 zhE2~ZN&}m+17IWmiPENmWiyA(V(CKQB<1gUr~7c&-0rGz*nG}?IBb4}<}ZiMd)J#q6I;`hOm&_rR;sY$ibXhF&>;reN14{;z8{MyjpAzeHXq8EWknOoQ z)ke_jckOnxn(96rT92b0%%OGeMEh`P?R5n>v=;IKt!9Fj#?5e?y&3GHy?5pD5sYTP zErLpYnV6@Fq&0+KtS^-9F2gHckF08A~DVWcC4W(rj%;ipp zkZ=2X>}hCogM1lmA>EhsjF6cb;MQf!=dwTKJfo-^z(QEVVlpUGwI6#h?2lV z6Kri-^b@UfG)VY;oim~*+%X1Hu280&4RcUmZsz1Ekw&x@mq^HWvl1GMMyQZ^@8f3f zpFy~c^x+!QE?@L@IFUa9T4v~55arRuz3G?@SlbE_b-1Tyw6vP0(#FL7VjtjW_XJyhH{F! z*>j5cqL5QGbvsTGz4bMePn0XmC-;5d@HW;dOCPurODudDYwZDVd7V~&x~!LXm;_6foAPATbr zu*>Z!D0FJ(13O|;Nn005)t;F|DnG{*Hc>OrVdbaZ@4gT}eNibQ{DiO=&rG*72uOGU zCFTIMVY;2l5!;(zZIjjksO2VilDCumqPXM*Wb>AJr_fsHJgB^eaiEk%MDstYp0M%~ zNg~ zN|dj|tK)K&P@XcTJDmcsugOt#m6Vn_l_qN8HHz@<6Gg?nLHECpjiKu05$@_-S4A$v z(-HP5F2@DW?4%A zFXp!)bX#0VH+7`v-~Wh9esv_d>zERw+hgQYZ;S3;Lz`o0Lt`jIkIOT(QskITT%Tt) zQ|o}WI?zvj^rQ0T)!;-33z-FS!^c?+RIq1grO4GWP*6tJ9$tiBkXN-F6(m7KI3EQP|c3ATzQw+7L21j>=tS(Y|qBG0p zdo@S##Y%|A(PfTMoO(0oB3gxAw%0_ET_S$T3$j(@^ec-GO6I6=v1LB^n^L~L5S%%O zS7s?rTkH@Uo{9r0zh?Q2TBvGW87i(UU))%NcEU4T++>bx97gOCt~hN)LR4VF4uRTZ zr^0#raB9oPq^Cdjk&7hq1BO^33#MZ0vuz z;tp41$GYMUSI>@q@~}2`{S#K);cD#HTyaAiEADvlqoQ@Vo>g(4!^CW!jm2ySngaHU zc1{-s8!sj`6I7F=e4%!|jV(lW4XjlfQa46NXqA}OX=)homn$=hUS$>{*Bc6CR{g6~ z+>NBj4e!6IAx_5xr`puW9zdC^NOisb@X@G}R_V`;(TVUU!*S4|5q0@+9CT*n3tGL)*hH-QoHEojZ3TUC zD(N>IwaziYsjj#ORU9@F6_;N!jDH+<0-=qt&@uLJSEhw zH>9AHFj^&CZj9pcA>rawn>5XE@k2p~TyH3lS@o|{NjFAoKF&2{D4Az~#5htz0rkGe zUL^8lR-1;9`I*PS1xXMXC`Eeh(29GUoh`);?KKrA(s=BQK#tA1D zo>A1D2O8dwbGJ8qHH#o%WOpN zMq>|GaW{+aoVAY`#jx{|L=%-xyhV~gl|t)ojAHS_!`rAO!!>FKO%@`4nk1y4$W`Tn z;#~bJpwa((co-TTT5%5?-s0ZxwEiVvuF>o})|-B5-BR+zhK)QzUUy@wqA+i+SWCE+rIIDwXKB|h218C(JLb1FwEz=O}*f|P0i6iYg>-B zhP2H(DAI4ET-$tSiGQuLT)zo1_1oVr%(bn9DpI+A>rjIDe*5ykzr1a4721x9ew@X$ z?bzYkHfQ*@jl9p=CR!Huo9IrziEh5%RO8U$CUVF1Tdo_1^qXNG>9-Hhv9?(cx$)-v zTyuyJQ@_1Mi5yQB_S;U3=y|EHPdkIbnfxpjtLFBNXdY z`V%^(QD#n56EZ8Yk>!$0GmVOKfD$vG7r^OuCv-~H?^XPnvCPA{9I_gaLpWr%FyH5L zm}|K+3S>f=e4K{VJEZ#@lbk_R6f5i

~LqAsBRk&B4tV*Ii(JW4$o!T=*R&8aiL# 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�a^EN099eeecy+Qkc=nf)VdqBCf%Qwth5&1@e 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 IOYOOj z5g6wZh%c?Qr;iI`;T)419G$Utpa#6{%_p}%X4qxuQpv9>cE47!;1if!zn$tLOxn$7 zRr%YMq#&kU`498Bf#=!zSv&zB^!&1Dkoyy#(ytIRIGS+n?aWW3!2^Nv=@PZ7JO^Hl zZ!ieQ%gVldy31Y8unN5V-_TL|@?ZRMaT zHS&^sDfjk{j3&4Dsv5wn_x6%rKUNc@+qq$Q&ss{1><=m`^Tz?e*rJ;AKYqlq9~-(+ zaWH_K?Ei(hZ`Hrj5F?iGSQKq2hh{WiCPh0}Xid`pFMRi}*F=O|?tflyA46&CAJvl? zz*g;C{vM8lUAU+!x$03;@$EiR%_u*7{-Vm|C+myFV`YC%zse7DiU_}nN)?aO=;-Q8 zIJGoh0HK1W`*!c;vsYg;`V~Ij1D3`QY+1I!OVy0Fli;n^XWXAF{CGYc;?O|!KL%%4 zLF8um0x@UU`A?BFfBe9|f)0lUzJ5br zH%+N^M~1uS_l)O{fpaH|8Vu>TZB}RRv1LrJY$yO$xfd@xGpndYU{GJSK?ES#M#Rn?=MNJnd zoa6wZCM6Xyh+N4!q`e zPE&(Fy_hjr)CR!)!{HYtKWfP>N`9Q=U@7t5&jeS+{M=@sh>hy7db0hqvaNoZB<0Mi z$G$QInLP<_Q71?1<_;&4{W_kT8?~~3VH%%viIBSBs zV@6AW7w(p#+Etg3gZX^b|HJQ4qK4|rMn7N;|ANQd&Ps1lyT_5Zr&`($(xP1B7YRI3 zx8>?kt^<~~leFE7y5hKfdJU3vwpv&T8q$NmDp$UTE#E!lQ`f#H+*seeMXgj{Mf&Jw z%Ob<2!2A&7exS{EPSpuF*V$L;M5;h1X48Ou>9j9(;g=7&FV!k@xqX@EzO4ETHA2NR{2*EV)hhK1$bq4t3ICW*F1gTAt#@z1&=}dU7b6mS+wqf z1icu1QMQ0$)UNf4`_4!_4+u(n7 zv)ZDkf6r_FU?`941goZ#{5XFEKUY&ocs;JP17Vt@xt3EnaR}euwUo{8< )V&!|- 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 Hp`Cf#iOc1gHRp5M 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

q%CERmTgdVun<;+ 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

dd$~9WxV>yJe1E-#c?^)r*;1Kljeu*;AW2 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%0A)6G77((YEM?B>SJ8E%=QgH`)u_L+Fg6*+P=rp+5 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 OnGH9pq%Px4ANvmv;^~+G literal 0 HcmV?d00001 diff --git a/tizen/distrib/ffmpeg/bin/avdevice-52.dll b/tizen/distrib/ffmpeg/bin/avdevice-52.dll new file mode 100755 index 0000000000000000000000000000000000000000..103660d1d5adf4dd0584b92ee491cf4e75fd25e5 GIT binary patch literal 9742 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 OnGH9pq%Px4ANvmv;^~+G literal 0 HcmV?d00001 diff --git a/tizen/distrib/ffmpeg/bin/avdevice-52.lib b/tizen/distrib/ffmpeg/bin/avdevice-52.lib new file mode 100644 index 0000000000000000000000000000000000000000..4e7928d55bb56c7dc2eb6c78530c8782af20e8c3 GIT binary patch literal 2484 zcmcIlOHWfl6#m-M7OIJ)7&pYEm?q%DQuc(z>brx|j=Hs3-K1T{Nk_F0QfuwjkK z!bn`&)g&8QJ>4a5Ba&oSZy3G4-c_|`(ynG(rHEP{NY*JvS!jvcg$ROU^lWaphb_;4Jr3OsxK&dw3eJu8{Jvq@2~WIq|{A z_+RIQReb!St&t*nWLzJe_kWf2$j`vUT(DC?())yTa#WpPK)m*Utx-JNlEzii#!rr; X(esJcv_N)S;js|FQ2iT5kX<%BjE&YwXe5ZXc0WRu%VPA|9T-d+N> z*wag0MH5xa#BF%pqgp+^Tw#iC@-x<0P|R*A zir&GlGLXmE>?_YNu*_w4^sfL|7)zI-CJ+EDA@eryWOo68YF>8WiO#GojQhnIh>sX} zZB}iJJwxayW8;wXv1JQmUQ+OJCB@jqGmLGA+^!k$IaHM@ty9q{JD(l^@^#V)v{Bkv zQ(IL)R7JFHgb)B^E79kbdge%1DF)#llHmY+0dQd+5t^W@zs_UexT<=zN!~{s;PTpI zF`~4S?@iP?yChhBx=J$i@>sTkhU8r`otE@gg$z0#>nO&_fCXpKrK=iNt|lxuDS-yb z699RI+oy)PeFEWA0HV8sI#Y$yDN9Cd0SmrTcll#i= zY8lc_=G)`dT0YQQ>{@(6kK42jXY>ta$i+aLvPf+o28OY1>()2+>R{IXjqE5QCdx8%|_tJnsi*x{OQAN)|noAC`J05>Ek^x zCbJU@ewc3xzyyFv8O4Y{1;mk%GcSN@CA3SVc@8i%Yrg<8Ic@{`0zwP0lIZIbG6G#< z6=3g(>I7;riTH*o;##7uHAO@wMa%*nv1AX84DqvJ?58QCemgbY78iK#gwjPM=r&W( zqG^H*8<0^w#yKdj>ulxwRiY{+Pe#oi(uX(V*SoX_M$q5AqHCP+RQ`8gU*$PknC74|rjOB1lg zqQWTN0Dp4AQrcGpNl5R~z9)g4 z;D$3;bkp4%+ymxHdL$>#8!jSZN`wcFBqz>)p3o0mqc5epKO6s|UY(}a$#}V5vX5FL z@#5$AqrvwheNO-3_}zK~GCAI?H`pls`%7pY4A~z%O)_GAFEEC+(_q!lFWt4uR`6cI ziR7s=y-w{&o)Sv?HbHaplueBf`$y4aSe;h*mjY|%!+&S9hLqBz4>9191~wdnu-!;i zR`8x)RyZd)WYe0DX{Ry^5e|b~dGmNN=!2=!XUl^9hu6uA4-72vX&Xj&)BZcqJeqkQ zqQ|OJrMt@d4zF7_IZSb&;a6$+qF}1fi{9dcTpQRkdw`#Gt@NR*pyc=#QhNZ`dqR0vCBbJe&;Ua2NTt>zoOf~ami!Bzr znz=r?JzF0phIIVA0cnC%LHpytWFAGl^~(m)OpaS&>6i3ES{Thh1EKvcvkEQn+51nb zHcTr&8uhzuIEVk3lhI@lo04b9ciP{PcT%Q5V!CMCF{6#>>$r)(+_o?K}c?!f{bfUj_YZY>-DjcsmV0vlgDdMKkzDd6)ARRm`^B5l5&>#Yp#S|T-+nx~|tq_sb8myU@K*7z` z_*`mO=;M^pJc2tg=uA@#x2Cd-UXNmHK>dMPzh~BG%=)NVPnfm!K7&4E_L?P*3+j(hXi z12XaEgmp&4dA+C{Q}Kc-pCHy7>kz|I9#JsZ9hEw#A;5zdSyNJj!I-4P(H;xt69lB5 zP=}O{35LR$XTq3sVH&u!%T?o^85=ztP0{kqfR6Ej9@obY<>@e^wNw=IW2vZI~3{c?RGlMmCUc$y>kM&#az5RFOkfGqHLaeNiiOJbhClWr^uRN-yY zC-St1R3R3+UxG?bOFGV#a}hWff&VT7f3V`)3rbVl)VCD+^?eQcUck+OC-5y{J0Jo0 zKA;V_UckeECjrE1VTCNWSyfiM_!gAww|2;pV5l>$@Z~>A)@tr)Q;5kMgovxiB)7TQ zk)Ctqe;I)#e5W=fZc#AD=tuK#$AEi1ub;2mejh%i0G0r51*`=`013bofSrJSfWv@M z0F@6=TOiX8C!%oAC3Vn^lZ`Wf z1c&QK(X6fDMn#euL+y&FtY;q<+$5=uVodcb3JzFyfd%~)av&a-ZWbefu(XV^WrSdkVP%`$G<(3Gv;U0VcS$eAq8zr&lEHrZ#Hp*ha)C;K_t*gT^2wo$G;}Y9zHBV~j zQQ-k&zsX_v+0B@TuIk~i9Ff+ARJMz?N{SM}ui)Z>){xwe&v%yA-cY1lya#UFWD(nC zMP;ij2nhd@)@}&~!|_-bWA|Bt@Sm~umS8VJhSqiqZseTmDGP4r9ntmlb+soLRYDOp z$S0F>=~KXM{*|};8{Nic0@iZyej4bG^>ipI--@{UbB`G!fO}sWZ$@SqIfwd;M__&` zAuj;bHzi~%KIeSK-96{tMcRPRY zeA{{4dBSUKTo(p{TfKX%P>&vOgzo87D2?e3^M;eOaX;NIl^p?in> zIrl#IzubkMi#=C+YCTImt36#F#iM(k@%*6r+3MG-->4p~{zvtxYHQ8xnt3%}uJPBb zuj#9KtmaoW^J`bscGjx3iP}xIPu1?NJz6_aYxOSnUhlop`z`OV_ptX(?+Nc|@0>bs z-Kx5lx`*n1Qn$Nqf8D7%yYE8ZLZ8d$^WEUP)wj~O*4OU4$EW!2_dVo$#P?m_Cf|>I zPx*f7d(QWw?||>H?}+bRAG;m_5sbgz@c+#?jJBQrCzCMRR)@_&|1m+R7;{k14yw;a OnGH9pq%Px4ANvmv;^~+G literal 0 HcmV?d00001 diff --git a/tizen/distrib/ffmpeg/bin/avdevice.lib b/tizen/distrib/ffmpeg/bin/avdevice.lib new file mode 100644 index 0000000000000000000000000000000000000000..4e7928d55bb56c7dc2eb6c78530c8782af20e8c3 GIT binary patch literal 2484 zcmcIlOHWfl6#m-M7OIJ)7&pYEm?q%DQuc(z>brx|j=Hs3-K1T{Nk_F0QfuwjkK z!bn`&)g&8QJ>4a5Ba&oSZy3G4-c_|`(ynG(rHEP{NY*JvS!jvcg$ROU^lWaphb_;4Jr3OsxK&dw3eJu8{Jvq@2~WIq|{A z_+RIQReb!St&t*nWLzJe_kWf2$j`vUT(DC?())yTa#WpPK)m*Utx-JNlEzii#!rr; X(esL@fd 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 literal 0 HcmV?d00001 diff --git a/tizen/distrib/ffmpeg/bin/avformat.dll b/tizen/distrib/ffmpeg/bin/avformat.dll new file mode 100755 index 0000000000000000000000000000000000000000..18aa4461b4ca512677bf5546161bb5ce8de7fb1a GIT binary patch literal 114702 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 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..9814cc88dd204207a2e473354a9da57e5a76ddea GIT binary patch literal 82958 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 EU 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

~o&jLLc`lbLTO8UB)JD@7NROeID~J*#j)s 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 EKN#;Gg8%>k literal 0 HcmV?d00001 diff --git a/tizen/distrib/ffmpeg/bin/avutil-50.dll b/tizen/distrib/ffmpeg/bin/avutil-50.dll new file mode 100755 index 0000000000000000000000000000000000000000..9814cc88dd204207a2e473354a9da57e5a76ddea GIT binary patch literal 82958 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 EU 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

~o&jLLc`lbLTO8UB)JD@7NROeID~J*#j)s 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 EKN#;Gg8%>k literal 0 HcmV?d00001 diff --git a/tizen/distrib/ffmpeg/bin/avutil-50.lib b/tizen/distrib/ffmpeg/bin/avutil-50.lib new file mode 100644 index 0000000000000000000000000000000000000000..74a03292554bbb4ad0987f134ba1f78eeb77528e GIT binary patch literal 20238 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 EU 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

~o&jLLc`lbLTO8UB)JD@7NROeID~J*#j)s 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 EKN#;Gg8%>k literal 0 HcmV?d00001 diff --git a/tizen/distrib/ffmpeg/bin/avutil.lib b/tizen/distrib/ffmpeg/bin/avutil.lib new file mode 100644 index 0000000000000000000000000000000000000000..74a03292554bbb4ad0987f134ba1f78eeb77528e GIT binary patch literal 20238 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%0Ap9DEcn?HVB6flpO2j4*8$oympf9)e0ki;e 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≺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%0D_L(DPpkM@igPrNcdZPd*)smbB_6 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 MgIQct~Y5≠@G{?R`OtE78*Tjpy7W> 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

<52L+HfNvU6FHO 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 z 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

3SPCGzZKXXHwD3XexSYfLhGo7=V8y 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

XvyW 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

MgjSikgA&Dzy_ORn-eHEk^wW%d4sFc#TyR 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

D__xLftML*;F2%mk3Ghxq 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

{!+)gZkCyK=oY&j)jAcoXl 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

;Fx*U^GmSoV*B}^h*tdIqsApw3<+oZ9Weo_1H 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

sF+@9XTe6`jAX{e4JjVHF>S!O zK-^L|kJA*!Z2_mwpSs+BwltE})nvJnhD^7WHNsc3rQR@xD)QR0zQaCrLw(;asT7gDjiGYg4klPkrS?w0cj$-P$Co0P zpnVdpPiif-?gS!Kk`|*J5VF%&=X9NzYma$)x|6lNsiXSX;j!Fqk<%j3Qn1kljT?%Wj?yPt;OC~ICqq`+?}+2 zw(}PqookOfBhoufx>+^I7OP&Pzx+_6zDQE46hE>2&ZyL0)OAE&5@nS^xr+2iN5Pd9 zFI}~DwVitnouAXA>^w0i%k8_fT=UR#UgT)qb-P+Dn&zscD}E7xqb`hqq-Ui?4zw?P zd2-LLOxB(8TG0zdBkZZIV{?pp9C~?jW-nEVCKmM1M6>hF<-P6L`Qh#-c!B=|odlpMFp;OCC*0f$DMaQ*ab=ykK)(xfQt7=M_K3A=;+Mq}NcK)qt znfBuDBYN4V-I{hpZ&gT%*col=v93&v>wX-`I>F7Y%PRIwZr2IR_jefcGwv@{U6Nh4 zCX(5OQH!=lc5atZ1MQO*MmpO&e;mmi=xR=&YTOQxF}F0LDdiDy>M4kml&z*9okdf+ zmyNPl?WHA2D1-2<95)enR43~Zs!dC*o0lHlHx?+3tT_3)7fKmF`VJalW#DD>rb1lx z(fz*+UQ{xH5XV&64R?+`Q7;)ujkv=yH<@5(sD_$${#Qf#v4WYCZJ#tTr>i&Z&t#gc z)YA@K5T2Fo#vpOalFOpI#tzR9lw1_dr?my~1-DffzrfMsgrP?Mu{)GTsOhHLMHDSt zT%_mVd?bjE9;y6DR;2v<-xxM6hQCi8yiUk8bbqMR(FV2CXkxONg}+~3y?ztl*$K!* zSp}NTF~MBVoxi*|!LI09Hs)!6#>4`xH?G-o7G#nP>@gp~Lij2(uD6~w?%44q!F06> zNx!gqZPofp^WB;Co9v5TE$Y27P?!WGZQ@rvuI6b;Io*d&N~%LrcgdR_l?PYM<|8zRiiih-MDFOO%-3dsoYwjzK^8GMd)xm8yjRQ%7nAQ>}I7AL|O*WY@`+ zT3vAW50rt+bn`*m(jO6{nD%}ahX4vJ>HJd7f`H}gqlBxPQTD*cXyHysaZa!lLo!Y`Z;pj0^15N`ol2x7o$;#BV zh%P^B)znt5-Dr(nvuQ)s*mbpIH&$&gJ#%gC*v(ZNwwC6P$+OGvO6_N7^eOGyX=%~o znMF3UtK1Pu>Nbg@WAXNVKP%dm?l)g|zxJZ*QZwz6Z-?~IYAI?ix)QK`lFRbRLvzp@ zzOtols8zXEjePa@rCigctI(||0!!&}ZMA~m$#i#WUEEzQTl7F$Z)Z?5PTN68#&Msg zQ@JteOe_^sVn5fdFh?)3j1E` zIBL4ro#x*+cIW_Ai*6It<&{}1A$Hk{NFQf8IKZefDSJ=$<@b%9FtC!vyBfVt=PH~o zi8J`je{cD5xhe{&8@KayyN`mC=c~2s%po$jr#^JE+OchIrBV#_$w8%7o5)y3kHVa8 z)W4IaU9|41h%?BNZGcmjEiV|CSEBndJv=w|T&+P)*Cs?&M6l=#D~#;C89bkwa}9*k z6j$t+Wm;mgv!A`rRkFHF@;`KCL98o!;65Eo}9M z+8S2iS^c$iA6{C!iO(_C618V`+|=R*YgaW7?Wc{EE}U!IoE&)h)SaDChsy^}njEY{ zL}`L@S4JY!MHt%jIW{(+I9khnDyx%rHx>z1Haq{w!ei~$89B0}q*e>v?qKio;y!kB zX(Y3o>BCv$$+tJ}s~_IEVrwlw^m1Ibj4k6oU1{%(OdoWd)+*^T+>UJG4lJA+qb2B@ zSV5H$F(9pXr434{JbQh5x*K#Vx~mTr_0{`_t_nFVT~C!%Qqss> z6OlWA?n(A1;h`BrRIqoSv-*)Am}=@4+eLNZD(_eKnlM0*ZQZ7-Q*-*&y}wD#9vi3+ z-Oj}FE0ga3DCe5;^{Z#;%`>e60jWtBuB$BA1;}{Ge(vtH{>Q20M0Fhlos#*qdN%SgiW}&96mClBs7M4^vZ+T!5 za@E@M8vT97eWw-=N?coIE6OzGP`}Ek{m{%vwr|NNpOvL9Zt>Obo>Qlx4~7j+vSuSo z6Kch*i#u6Wu@pP@)0Ldz@0msW1tzHx&Zpwv{^o9bBg)AChP zk;X{HYd^CH!RIcWMF_QIXvTWqUgB*k9~hezSUQjyoa&*eTQmImCDZF+I#P95W}@mS z11hCe#aWRnniO#-@?)k)`gL~VI8=7@NPFk}oXiQHeRrF>DW~+xfzrt0^5%PKF=Mkw z9BGd~BhqW6$dAqIE#-QAu5#oy4mDG7#=!P-X+tO4t0oVPq-v?v&7P1eO>tIE)?i&O zcXYCtowmTnFv0fazv`ZCSFj)vmA+6V=H^}(-x&ZEo!BW`4}ipSIOff(=q1Y+<*UJc z_GqHE%GXz~VHY=$c@>}3qOxqOO2^NzdsarGeU)T<$-2v8`;I-!n3Eo8nL9(&(+r>b z?#!N$HPtU%>GXZQG&SM3bwPnTWjwU7Q>Hm);8kUS(N*>5E)Vw&S}k2M(k>R|PK-u!S(%FZGPg*oNF*&D?^lE7N z`~_yIz)i;;D;(;%a+>boyKA*sTT{AW>khTfCNqWHNa46nrRq$DUOG0}cy7tufzy=W zT`B1*cBYttQYMUH;6zQ#{`*=x_v5166k^i0QE!dJb^2O>B7bJDRjb)XDu46p-ow?l zi&hQyJd&FmRVhfp42RTQXCMVOY9yJ{@v^Sy@Gz;GZYEVm1rnv|S}k=FqErp915vqM zt+Iy4o7Su+Q+zvnoO{4)@yw|O1qD;5>wANHNRF8{fAYRlRR;?One zTSr@7GTzdMPt-u!F8Wv3e%WqL?1~v>}o%GZMPm7Isr3StE^x>!tU8p z)O)yUyIOyebRu#TOX-f9?R8SNaGZT;)TF+4At#2MJ&r^D%c8D+o#hP0l?_69-4TRR zUKv2RIaX~&>ycP-?$X)x7B-X)sZpvZf{I7lY*S>^(Mtl6NkzG1Mt9ihT0pIo0VC$N zSVo3MRr8n6?QOTrh~(rrrSYfkNJTG{yE`R2vsRAL%g?9EU_{;GCaQBSqjVJ#H)>Nw zG|MYVs=+lR)x#&AsJG0`R*mW@olZ#)7Nk)2q45j)Xtjt>Uu$jC@QLHQs_NNZ%4gke zM#-6W^z*B`3=43}@Z4fmxb#?=cIwD3${2dIJ#I7WBu>Te?N^#(*FT)rtA9eWGOVTc^tO$RQT9HZ zmYJcd)SY;$Hm*iACmGF+(`ng=x72Yace?A!9`&S$))iHEU-y1?zkg2dHAZE|&*APQ zyT#JY%T?cJ$7Y!`IkDA|E@O=mT3@w|@29JbdeV$PDrdC6r2i!=c*)vnUyZUDy?Cf@8;RGM1MVd732&I59LlM zum`mcJHlSFm_tX-)XhFLa$;}2-r%OA%I_xQjQd#*QQx_*lp_yX4tDwA38VGFia-h6 zuBCi&P9JxEvVU15l5B}f=iC`>>22@%P8UpFuiC^ZwImfLCN8L036orHVby82#f+-8 z^{TAW244^Qbo~VjEmmdidbP~Vck8X%v#U)GlsL8J5yki{Z&IdxZgu2{nDTaKdxwHN4fB&@(vX$@wsXu;|2TB zm&>#4xl7zBO6zmeonuC7X-iIwZhq?Gb$Z4)IIzhTuLwp@8Zw9Wv+Eah>SlkjIg()? zF(cx)Gkx6QlD^w?tNE37(bE^_>N$FvtfKsPy1Q8S+2=*4lDrgyg=dSGm4dt$V-M=)xY9YZ-@$l2eQ9&EJmXB$f!mEw2nx%#fkdzWq;WLlf78 zs4i_&_kOcH%jx{`$4!*YZXKi!ZF(&~7Ri>wV#nu1^yaFRY2S6>9DQg=7RL@<$5SK? z90)M|@^{yTj|nc6x|`auN7MRdCv*tPoT%~S&X>oIvIk$I44ossMH`9-+Lv4(9%y&n z#u3Z2Rz!LXGFCy=c~Ehk(YGCn49$1X1USuKMei35KKU49FL}ka(zW(E`5&Ml_hP&A>Ps&M`12R2_j~FrD z=&$c-0CzZV5|l=+MI;I8EheY0RA(Q>(y`@{W0!n6EZtr_m7O1TFj2I3=kO6(+CmMW z<>(H^%PCbUa;upagi=c*Ks=Zvy$YwAdpGoSga|IjSm?8Ms9{q}J-@zk={ z1R3lGCnvJ%$7V4{@-4MYxuJZ^x~eUfu1foI)_y7(v6v|cgD196H<(o$QFXD^x?6Y0 zkFr?kEiTMkSiCT9=;pVa47++qlsGhx8@Wup)q+N6Gh4Pp-%suxv`sS5w@Xf#v{D^w z>J@S7S@k!f!Daw&Gdgn3A`SQ$XXVe!>5O^H^MmF=>8lwk*?FarzOIE;jis-zb|ocU zJ8B{kVN7O*uF6!cI=i;2###5b)lOyn5Ms&flEr!gG7J-=WzOPg`Nk#cNxgu^IsP0UVW7G%s|R}UPT9ensgOqN>HIYJdc_1!FAl-Alx_`{9# zyc$fH=IbUtj`g~^y|w8MsJbM~V;j?EFDWisJgs!W!Uc1upJJOCpw9Hpks}K1>wXaF zs#;Yib?C~mVMAAD*>#n3N88U&%IOuAC7Qrkf`;s_3bJDq8KaBfuYNILt|WD>N*X1p z-TDS6OsZpd#>Yw<^vcsB*|l*a(FR01d;fz$l<06qUaN_k@ojW^6xSjfvn1V?Dn-De zAQ`P42^K~6g+y6&5gi3xziH!{Q8t%Xt#{6}iPcgEp`89Mf6iHB>0j?x;?gN4NvF;w8n??47eG^hR}qo*roaQ<^5;(vmaR&$v)AmJFyo=q@D#@ zx_H_2S<_r?P^mfVPIl4w%1ry_yy-`nE@1!Qp$qMOvvM-Wi;%pPV|Nn^q~meA!@}1uj-+i+4|Z+Xrgz7pzHT;fhdWZv zA2VW7Um2H}aYLzW=i0gB3a5@%Iu+1*%H!Bl->}3n>gtib@wc)->10_)=fUj@ z{rd{R8t2g?TEBYWR-1z69mV?mXC~V%IZ6AC zpJNunE7q8DT2(u$*mIAY+iUf5hCr%`xJ8oKjEvMsdWzF6aWW-On?RS>r&c;3{wX5I zYN%C#KC*`Ddk(Rtw8q}|-1Oc@5|8S8)JSB;Y@Tt|CkbR)pa$F%MTL@Rsxx2JA+9*w zZe-ET;r=Hok;dhX1g**)oPlSVa6|cy;GsD^9#fq+T-r``aVJ7*vgI3YWiCu+m5suP zomBht=J_j81k0T<DP6yHL%FB4@eNGp)QwN+ifgg8 zxtDgRbgZAuKDJby$-4?1}c2ix{Zieo-V% zpI>Cm*vEZ1B06H|Fttcw_N1>Ek~u)<&mW(XkGr7q_VZ~21|}E+#Aj?Fip$f-V@H|O zb$0hjIX#>yLCcka6Xyl8JZNpIF5kShjlqd`QpGg-+_9rFhXzwmn5&vzP`$t4M3FyB z;T&qJtlFWswpNwKji-Z+LJ68a(thsROEc5VkK>rvhO>fe##$<-!_k%JwHGH9{^G+(lKM z+N8Aivg*^#^#AG}y~U8@R8rhQFFi&my2U#$@YxG#z3se{b{%WqJ-6~mJGvyNQyON5 zxX0O-ZG>w(j_zRa zIM}eh4P9_Ipo}W)A3tJ%J~ClijeEezj*e1euEjZ7W1ZSjy8?Q7!d%+v3^+0ok$rS*PIzdiiyje}?9(vA8ubyJ-G` zKK8%HO=K;Hb%uVjI~6Fclj;4phX?D$@xH1GP2GA^$)b7lSSp^F-OmV8b>gecNvIm9 z3Rov)vM$fc^z1x*oV~0uoM}J#N?KRlx+W%8fofdTfJsbc%9XSVkH7&ERs&k1-6a+te z>~vl}V02^e6_I{PCP`u^r|_g)U!5)WfR}Svf-$1fW74XBu5o14qhc?|Wu)_CVZmHb<4x9TKR=aGix~ z7VUEj6$V1w|DmGmaW@QXOk^^fB)&ddr)38T2wm(`;RXh5qx|~i`!{h zYMp9`UPl$(b2CH2TDJPxY&&$hca~N?q|w=#d*!{JmOIv%#5g0Zl97!1hG4{LAIg~8 zZ>pA$df5O&J>NL*v4LDLTO8(7TofvO$VX2;1) z1kBTUM(v&FW6Y19e@UCD&+f!cM4UO2dQ?yi3gdbN#~i5uJ;&w+1||pFYRW5}aaK{j zrN^tzpuA$6&a_*fP6DmhM3x8N4d&>BiBHYFR+U$*+gh!TtMXV7BRg66R?3nl`ybcd z6`rl0+shS!?kgCYqjhnCGkWpqws$5ySeYtm8L)T~pFOR3_5!C+`7`vZ0*=Ml>Fzhd z6iZ?%z%8qE6RNpn@vN0AP_doT9=*GC7X2+P|KDSe3%;30xvURdI^5VagI-tA*mGj>a?goIVn)#m14@p4Y7 zQepZiSIo&@>8ACSNsFyjOZqES%>jY9&0Hm$pf=uPZ~Dbu=DezVK2N`b%Wi!$Ej6*5 zl|>-kZg}5^E`dtjEt)YP(i@leSy2#tqy+_2H`%R|N95Vh_B|Gq}=dZSb`q=4DSRM67aj{@Y>g_IYg460?EQ-;MpL-UIi#dn?fU6CStpshDmJa(w56uH zyuyqkT*2ybS$x#GwV9mQn|@L}>a&*SoG4KnSMD0SYJ_Rbe^f#BdK>${x+t!2bjD;! ze&_N@1N2bW8KPZTcGhrv^nKxsm?}qb2u2HJek?=9sWTTB1hqsfgJT_%gvfNn9|Pl6 zzs@-00CjULA#o$H1T#I+eYV?|v!dkbC$?TC4B1B3@AOjoz$2-f?1x*@2I+o1pco7= zjAF33)n~4oC6+uU26s|rI&1MljvD_%a7)IU-oR}rCV6}3tja;lRpW{a@SU|?yu2VU z{y8)1S?%p@DR)j6swYEqS6j(C4Z^CfEM?i@lm$6<>`+>_!~(e*tXAvT3pJ(7T|RN@ z@Whtx46nSNec8OFv-K?CNXG=I6nXp3vG(SSk$vsf@5UYx9BoVM*>~d5A@=vhGrQV< zdwBamd)jXpyoseev~brTJ@q_E21QCqeAVFDOWmARXuxVn55;NoO=` zt6BOWS6fYY6#w2BJ-Bt>wIha6TPV|&+4+S-M{C3E+K52k>lWRdI`^81sb9&xndCDE za%`!3o6p*fykG#`w`!Rak?+#gTQ^o{u}NOdbYq;=O`Wgax=J1FG#g%`)@t{wzdQU> z**CX(Yl~{Wu?lumyROa`%`1v~F`gM#I17;8BVc6QQpYyely2HqwPn4t?(fP%8j4+X zOZVPt_LmhiDFvFMlBZueliCKXESra(@=9A|sH7{=&HIWarOOu;xxJWfnohpen&?Y| zre^E6nRr!Wl6O@h7~pIBCc?UePV{sp{Ewi7o6{{T z$4J=Z`0JpATaOG%xGW?1yV?A9C0y9kvd%OT;0+z<@X}yM9hAUB)`tP3?3@;;mvp@Wd^jN@9w!m<{pJ7ulg6aX5W&1O5jtLigmN77~ zMM+o#VV83+HZpwK?yxdvBeJQU(MqbY0Z4mYRf@sMhfVlddYTrk1E> z?ZAco(Ba|oV8+XGE$b8$zCzvqL%H8c-)e$ky^kTh$Z%jjH02GptWmh+cNxD&_`!*E3_F%>8vGnpumYE<0#9zDP%WQ%$D;lESJy`q;q(E?*<1dL;?p4RL(+ zNaG%zw-NJ*Z+GgfJ;$WXxgeZ!KKWBIp6Dc8GSaecr2j$^MY@nh>6yjp>u1?>n<9hk z4KGK!j%Th9%(+fnDys04PMQ*xm2X*nQtTctPwyA*oMP|0H8NmI6hXx0BWX5T zCM3;<-SxpMa_x;TN4kuupVYBj)RUcHE(XS?(Cbjf8R>scJ!N<5u1@pzq%1%d{X3Zw zNF`)Uw=DJPtr_X}hWvc@h7F%+TgEKQ%0(cUU`>Vmro~WsU9iI5K&K3UqO@XK&DKoY z9X=N+)6^uQ#<+-D;v$Ob==nF>v^V0Jk$zKn=I(HKnu*DBHKPokXOa~1r=74Ws>Y?1 zc?&Izuc0KA@(ZVwQmV4W$xBs-zbaLHq2#{ixcj1FRayyHYHn<^6eUYKR#lBBw_jCJ z(oxj7(&B5>IEvHDX7Lt3)eus`vvqyC)+2hFsn4jo11jOSG5o%J=9qh;nu8%4Jg4Ih z#9L%|L=sULlwQO{G34e#0!rg=E)FKp0MFy_%t&txE!&eacX#T1+T2x|N#d!-JUx}b zb4`G!uoU?}nZRTRm@>*xo&=tsYn~DKD{3jTtU9j7QmAar)OK?tW&_iyET^`?uvlf~ ze%@Ge=BVO?T44SKSH(rMT%ZdZt`20dZk1*IGJ$8a=IO5@fua@36*H>pUr{v-ySdIt zZwRY|cBjro8BW%bNRzZGgSwE%?>!0k(9_eTqWCLng6D@^gYhz;f=B6sPQS1!*qovS zC@RChj%)Dd#eoD`;Bo3X6H zdXX#D;fv^cogvYM!nI~}>gqzO(S_|vbfI}I<-dps+hdLruBePLt)mONijwJqwa(QA zACJ+6sE&n?kHX{HnphhqQw=dX(l3-TO6y3!P*xl47wY*vhzz;yUo^Fmfc8wNwbcw? zup6bSL&Os@GsI_@lU9u=-rf8kVGg_mbTtN+yXq{7d6A71uws!1Fjf%4)XNKQuBy z!*0aln1UTd-H-VMcS1zL{-NY2hwmSvm-ubI-{i*GgZ)JGilqHSEYO*>!qi4b;r0_vS028fX!z;j`-!@%l<7zQ z?b&|mR5Gsact6nq?=Q488hw30aLiE1+*s>GEZxr(>?m4bYRl+ENkCEIHD)5nL~pSk zK+e7(%xVX{yEmh3fQNAmcEsUffU(u#aaWZxSg%;5nR+bRoick*xW-ItqxdPRCcKm@ zkt|~Vw!BoZ;N&G4uUGbLT>k3+)qer{PS{NdZ2RfQ;?it1rtH030+Fpx-8F(|rL z7H2Y+?n&95y3{MM+Zk2EGYZz?^vp9=ClyuqK@IrNMDt#*hbxkI&Lj0WsT;*aVDxh5T@GyDuM2fUl$4RRdo~fG0 zkrr8S6jY~g75>uAr7N!ZNb2EHeYdMzP9!3&7Q$!w!>M_HE68iGEM{;jqoiS^wc5-- zJq4+U$!M@EE-A39M6K{RO6p4G+&HO}?Uk@@G#%>q~gROQc>%iEB)clI$RV#MX@p%%z(iYizE`&ESA*_52JG>I#D7iu-oJc zZ%D2~)%edh_qx)OswI9^ezX)OM@tP8N+fD3CCT^=)(&1*TBy2TS|x-#&DNDxd>jq% z6q`7Vfm%iXqau++T49*sXQ&D$Qutf3lAg3Aktp{mYJkUS5h5)quq!R=Mn_t)I180W zK%hBcX4l0jS3Nw-NXWHfNNa7Ja<#%UUGq4)71tUHZ!)cc@xN!!<0EN+DOrj70qr%`@w`DIdl!$jVRdP=oG#A0n6GDwoCpT$xfY>k`lIi=B~){Hiilxa`#>4?oOG{!u3Y25JTm5!td9~ zWKNgW+7cE!cRLHe!dKr!l7?@-njf*|ya={5hs|xR&HF9ufT}`lf|KBlfdm^Kv8=x$ zVa5S&g3F2Nrc_h15l+VHAG55Z(iC6+IlEJ*=@d_f@6nWQhH++hE9&qzJtL#3D68Nz zcBf9BfvBdN_9skv&sx?WxS=?Ggjv^PfiHZu;mLC%YK7-q%g%djduA*0sS!FzDSuZD%>968s+WI^lMWRfHXto&bLK=0+i|+QJBU7`tB?(4f zVmq@_qD))jWLo&TW$o&$MSx6M+QgDA+tn$hI_$`lEd~+Sg65Vup(c@O;i1FJ)cUK^ zK#}QrZOF7+9!$oiqt0)NqGI~lg3B&?}>+nJD7S`E+liE%w1A6IpT z8&}MjGhc}$vKE*MOk}PZRp#+4x>P0u2ck~CqFHU1T+B-gJoMJSws)yhZDuHF)%OWm zwMi12=ww|I%jkFb#G2u`Baj$27~?6KsqY_hC#-v7j1tb%!QMcl6@~~A$iO3GK=5~7 z-0u>8tH?!i)%;fFDo!tXT= z%E*gXioBpm8u{HJrO5A~QjF`UQurC$Q;P8+S)w%-##zg8ML>8!DdK)-6vQh99s#A` zcZZY$zB)vDSf!ZIQKj%PwyPA!1}#hjzx^d{iu>KdZ+`);<2qWYDF!_ z#VJ$S#9&Hw{O*V{g&Tzb*b$|LXPYPbAph zGA8Dpkw;tV@lc|Yh#L9bk&>59?pVn)PVyDV>!?k}Vho}r;U+(0l9CHw^^}ffFj{!{ z464>*HN)tNJU)lM4AvF-_>yE$swQu0Q29#YepmC`F@0ves@`FUs@y=0Q;l}6bYm=b z@6Ze-{PwGNb=>dzIQ~W_JgV=e#Km#yUotJI{?+{Mh!RAnA6~{P&1U$Lh&XYyRyV`P zm_){+1bH(#Bv6AG?_GPdgWohyAB`Jtf0Bx-6=Y;gR8Ro&} zIQTZt{_@NP44lTt?Kg`7=*%$d77mF`Z}6BV;%sn#uY zVqELtdsD|{(u#$jh)ZmK$htc|v7ZDJ%UjT~#2Vmx+m~4QDU+6Dx^7`8)}dUtE(}?J zG7-()l@gxM5k)q24jzzFHI;<)DFd~V;DmFU*$b~<6tb={_v<6UVdqS-dnP$=aY!AD zLBu^4?FrL2hnMNBN=_RIuhHR|OF7uJtJCSKB1l6`p79sHyd@puYZN|q50XY`%z|a* zEe+}2A6A$-;Tc}0ma(HGsHmQ>Gr5}8=V`lAU?@FcP92Edu$G0aiSWqpLVg$UTjGz^ z;ZbBF;c=Flz#4ipVa0CPRvjiHk1h{6yUETe>{+I6CA^OCQ@9t2np4_SO}J#Fh42!k z|KgFiB4ibEgZ!@M_d4J27JjSDNO&G=p;LUntNA^a-;#j_e$U`{ae5TdEZMC#VN_j7 zc&iS_{I|tWcuM;b)VC2nf1$E?N{M z?LLHGcM~Zl5h-!u86mwHM23pf^QP@$e%mEhbRa!d80wQSsPNG$C8&k)>q%TnRKBZ| zN-iZkwcCLrU$LY$)KxIjNKu9APvKdV-?&Gg&wedz8cwF{9yYEH=@a$E>9rNAbP_=e z{{S z4QoTzODs_uiTKXAqjN?!_lNC8Ggq?3;+3jyQ^>lP-!sx%Q`XQiP^#Uj;dP0*tqxfu zl8CRx6Q9b1Rb3O5UZM6SbNIjMWG?%HaI)Mz8n!QA*1dOZDr(|xZPuL~(nlj^q+gT5 zX0+?y{lx0dpH}Y(M`JbJ*@Al{Iief6Sv_<$RoYZj{S3|W8I8T0Wy=?(bZ zeyQxPkUoH}o($R(p2y(pE?ojCVcy-$YWbUyek&8(@M0KVQw&ieSCsdMkhOuUdzylM z%J2+r``yem!1K1^iKY8;^H5^0>+T7uEl48s@$L8cBvaM*hO9?4pJe)$K&A`t3t3+f zZdTcKrk_>}r$+HqRLDO1nOp<8E)3?n5uV2=x!Q!@)u~Jk{n_G4xy;#d(<3_-SKWgl zYi}pLtDmwa2j_^u!y5=U4cEjk4`PZb%xGpc^CTibxdJ1O z5(4hg{!Lv@bH|0-+*ayV$#Y`74WH@Xw9mnUh<-uh0jQj8OFA9p7D}osQs~Ia|ikAUyjRQtgRfrA~`%v z24C%923@{jRhi@ERDp=L{xw&$0i9^Zzl}N!R^jU*>qA`yja}BcRd7v$PSpKH$EO}| zXkW<+-;fdpbFNLSPj{?0+fP^u*b1LfdZjxYFB9d-dn>MP+NhdV_|y{4jP&-artxjb zcsshI+JALR2N>bYJJi7p!q=e;{+0IM-b_hER{f4EvVcxB;@=USsD4)pm{5hm_Mi7& z`*kQ)6@9;B3Aey!3Yd_vqqIu?P{Rl9CoGbv|4<}h2E>w~X8i9W9?^-m3{U+>aa9x3 zQ|UyLS@N;uydC8s!HmCkjISBKWEphZzm%l@?{PV7D}$f3pRh&cHRA^ekxGTtDS{Idg+ zRQi|kx#Xz*x^C_uU;P&y%;3Lh{~a+D8UOBJ2H|t}4D_-KBPZYS1d(9%mm#Z#f)}S( z>+zSF<2>y45$+;n$ya7CO>V5?w>d+{`3Dw?^(uULm3yP`WqcjdFUTlP_w!XG@HKuN z>sXFUzVY#)Feb;|!3#;a6~2ySu;8`&+r+l#Qf6-6qFnlp`v-4!UN zqa1le;V|o(gQ|~Zg`Jlrxexb*omDEAsS%!a++dzWG7siSL{eSRK4Gg&^Egi$#XYxG zNBHUfaOWUzEQ+V178uNGhWEHrd?F=%!`7+rqBG`sJSP&#L?hv=O}Ke_OsP7>jpC;$ znjN;baHSyf;8#pm5?!VSm^K?G_n9c(n4{$;2}L7edHZjh zD2dVj+|q=Dk(9wuZ6a}>xsyml37g^RNV9C}*9M<{y^n7e+t|Mi#<;Dvh5;Sps~^}t zpZj=o-Jq~_gD$PK_X`8|ATJuWt_y_M1w`IV_(w)s3)S(6la)1y)Apv^uyrWN6AS;r zVG@xx4h}nmL*ELqZ)_-h^+Tk8_woJ7?cUvKecjNo^@&c@$M=-*u|O*kRv#6%-ic>? zL>Rqiyvl}!t#2*6>EUqS&IPO+htJ`Y3TI`dpT@n4%7%xn<2u_JPeiijg#Q)yyxWZK zDZh<>;%sL3lukTHmEqs9n1%T~(Zpvp922&(?S~%@XLrscJ)SCSyp@-YMxEfMF<~n$ zq+69M`8VPu-#j+#yap`8<$2NJkw(>=7xvEj`;OE~cwT-WJmx+NAPn_EhJ^6e!-SWN z3nY+me`6p#+j|&6*)2sG;~4^m?Xt(W=Y+$L*oS7U>=XLj&MjY%6*^B{dfN|veQ~!~ z;RG>t>V0i;n8&f)wMPyA1 zTT=o|DJhv|7sTC0Dm*cqbX{F)zv(dHg_E88V{r@fZUn;6MtI>#$ukhu^5Pk3!g>4> z>1Oaeq?w^z7pLQOQ;>h9W^#51;uqy%NER-Mlof`pKbk~z7pBH@=JiTm)kTZi=2>r9 zR5H{8Q@-fxL48ahwYYouORcB8T`)XXE3Uor*pc01(Pm1aiVI0$Ba69#LPxY+$%IoW`vziwg;Pv^Vk{Xg(kkPR= zC}U38c>vMN$gd?MYLKp|1*Si7^_S=dhbd2UFq@nkw!YUqaVL$!^JwJ<4@~R6QXe() zxAn$(Vduq=p61@`E1*ule!dKzoD!ZIEMdliu=W2ib|&yvP5uAh-P1gY#@jp!QMXYk zb)z&7Dw5P~q%_^;2)h&^!$m!(gfb6>GLxam&@WQdgC~-iGK54=(f{*V>+{{`oO@3G zPp?<6_xY^vcdfnF+H39U?)_ae+=lH0enHCaD1iOrLY05PTByqB_lta7PxCLm@Zn8T zVtDuOpA~%T3yOBf+ex)$S-IzCSp-`@c1EREb_48JxH7D={;za(nHm3b2SisB*al)i zu_l`f)i!5fEqZ3chZg&m)nbC*VqSyH$$lg|6+LRP`f z=V-~}VrikujyV6=J~$}2e{}~($AtJ9Ll#sn+NDg^L4QCvr%YBi_bW_!{bR(C|LwrA z?SJ&kz3`t8ASdyHng2Gx@ou~rhf^6ZuX!HBM`y7w?Nr9=m%7dq7evGU|EIDI|KMX& ztM2fupfn!XVWWlTR)06Qx@VYMIeA$D-jn6NaaTSVDK2I?hqP62-iTxS*g)DgGAsBM z4Z;m`O}s)l1}}r+@)mDATJ5%t$_mP5svN&8S4fi&G}~Z5xL=6_`=v>>#o)`&3J&{1qRQ?n zRM`CR=$H+ObcutdIyC^2MF?80k{(zi~+*LKUE%d&zZ{QM~C zJ)QrssaC`Nm*eUeU7q^k={`SHl5R2UUXc~lP4n9u`9+nxGApP6KRmU;oe9EtFT%b0 zhOlTXD3XX2X|?NrRaS74D|AEAi~L(ghgdnY&%-&K`;s9J^^(#1DfW3;!Jn!2?J4&8 zS;4!o;{_voA?O*}ql@+aS7!yk)1iDmFP8n~-;StJ3BLtd?!}=LzYh|A*82Vnvx5Jk zyp-1CQE|98(fH`<0x>$=8UgM_THpF_l53xTZI;5JkJBqy{!@JGo!musVPSS$C?z$n z!gX0eW#7AD(#J=iMb)-3kaK-jP{}(c`Rz{g>wkk4nEa7)dU^SatvvJN3vOA70UIqL(!}Q8G38gO<6(B)Uonoa&K+8+264zjTO9V({%LUp9>5_1fUc|Cc{OBn>_syb`@JFK+im zHn?zMi@|02bC+cWFS<&Z9T(S0_F%bP8gu4_e1Q;`=y2$cO#HVE4wZ^pZC$*d{$2FK zXYs-hJ8&LcUFewz-;TDj_TQCOR)>_b*#4v->=_HQ{a4}Mtf06XXf}E|c(+Bn&w8Nl zeg08W(vcPC_Cya>xIfDUc&9zo(d*S@hv0!M_t{UtJMhF4iTsDNLj1jo1#KvraJ)RtvF@Y)TY=kFXZ>S&)wA4R>z z`CqUuE5KWWg?eF0S}%-v3U`-jeoNE*a-R9$$_t*u(}RC1(7J2e^Z(q!Z7*bQVU+(x zI~(#_Q`bXwHuTru+tz2f_idAoaJXSibm7{U{6o|vJMQBW_JWuF9cR*jT$^mqeCX; z2JV71zk+v;S)N@>Jc}Cmz75zg`B0iTbw!RJ z;BwZrFxfA0DvbPgSb@o3Q)eh|r~S!5mvtc@5p9SL;n7(v_&2%?ElIrPzKR1jvTuN$ zpNl2z_oUe8eTXBWv)fs4S&BX9qpV;Z?703nhvm+}TC^Vy_!tBG7Lo9;EsDRZ^B6uR zec%2kD_EB1H#W^L=aY=(g=vo4KK*!db+VnE_yb<%)c^&=YO z>^9zRr#%r&u>VhJNs0p=T%iCPkipMc!A;3s=URGUS{E1W$Nheq-_SI_y1%kK?Elme zo?hVE-~PEk>!IA=6FsN_>AvBx0hxQy&;67E8Dd0kPZ^Qu0{qMQ!(Xer%J~8L4!grP zmh-2-=1;P_jahHy9Kzo>(|TciS}%m#{+kutmF9S9nq&Tv|E<6ZfB$oN)_}D~T?2hQ zcul#K7Oo9q_DPIQ$&?nZEfNcMp{G*rd|yl)Nv$UevSPs}h5e%Urm+9bF+Ud5N41ID zqpYk%iMAg{;E}XsUDr(w$+UVF%-n7V2iL)PAm%#+u(32rw0D*!FR&Nid%(n zi`GN;X9tTV-A&|JaJ8=x zOK)X=tXT9|)JpHSDnl!SoLG>R(ulpT5!MS8n#Y3sx&ITbyfMXL0~`i%{L8x1jre2f{6>w6fx&I@qiPVrBd7Ym-si_e?VsD7zIb;<-Kv8h_|mCd?Wjn_W0W6353hl&MwQWgEH zpkI6^2n`F0%U113vG}SOOjh5~+qC#vUY*S$y{Y{|)PF_#{Wk} z^Sg3s$@n^Kwqi+G>0tjJhT)f*jVpKLv#~;kpu%i(^E;cW8k|Zcl7lO-OIEdx-+58% z`o*3vTPnzjH``yLLHP|QlnS<;5d^j2IxZH^d9i5q;st$51=}x-=Ql5%8_(HUWDckho2EH;L4jK^I^!c5-ep_d@M9X!_CqFlbA( zQolxjjNBW&J#>#x>K5~BvC`oWX222a1XY0SkCVt)pCM=py&*~WfX=~yG&>K!w$v)i zn*(i2t5V-cdueM>7z^`ZBp+g*i2B%F?f5tuU8f?mv!q(?y8(xxn6CbTVON{xq_fh}E1 z{SdS*RZ5K;=fGAbrQQR*s*+!c6i?@40WQY^TY8lGckje}WWD~VF~ zfwq-HsYgTGN}<%Vp>1JM>f4|hWobF?s@x!X2nnl@@Uiys>(I8+Co}AZwuL>Zf2F;K zU&xcX91n#!7UwB{ZRioue4UW?7SMa3ua-Us+ONYIdWWG%;E3metq4vV#9F*|$O$KsUzrT@81$03>vl z{u#PLgTw~@g3gDwX;r=$#t3wqB0hg3XuoWw*R7y8oamRQWCaF5+cK2YQ=z%sWQfnQ zT?KAMf-NgahbN(J4N2+SZAry&9&htp`b+3vH`EQeRAs)1l?R33_cO z?0+r{MTf_cU~4&2Z>8?;*Knf#5;_;Uj(X@%=n>FerOV-%U`sR7zX9}~B>#5Mwj?9% z{h&wmK>u_7MJD7U!IoL1E}+AJ#0GKF3FblD2494>WfSSY4cb;qr2YolRz{>QUlJ9( zz^`yc-I_Wanwa7#QGWd%Zs29; zx}y_4_A#_A=STa&QrQ2tb{`We;<#*U_fh9S+d6&JeV}v4CR%(c^ayCH;3DWf(C?^1 z_e0wfd(6KPdfp{|l_cujrLlcmI*$p5;b6<;QCGuXD7KCFD;!a`h8}TgqQwKC`LfhX zZEy9z6RPBrlWleUPBLT1v(~t25l?QQU3;Q3(rxPz=?@(dNtMt zYC_urbF?>ywuR-W&w;iz& zw5{((``^&EjvIBua?pzsgS->8EzJgd7+i=1Tbqp;W)w_aiAwYsPq zLEE}q)SaPi2`=hkv@c7XoMtmWG!6}J7u*VMt7y@GHMCaE^5_3IkYGz>(cv>_TM~=< z5VWm;MP2cDl)S>P0YrTow5@DKeGas(Xhod|ZHre?&w=&}RbeDE;Z`Kr%2d>kLc3L{ z)PmQcZP6*(KY_MIrl^01wgsiA%b$Q2lmfT zp<4op35Stjs~u5Su7oap0GYJGX3(~h5$!#oZPg;`(a^R?5%rbOxexk9iKyfBhaRBv z)-o_CE83s%3sO=41#Qdq zP*<%2|FwRJ9_pshp<8PQ7ne-vi3D3Rhk69GEr3HELi>eoy#L+MBT$)=s4%aZABMJ- zZs`9O{a^7b+faWGU9iEg3_@M9D)#@jjeZ3XCN!>!4Zh}ArlIZuZ7a}FPlUErW~gt3 zwgqLVpMds@$M_0vfwpC0Xx|HM%fe8Xt%m(?>%TCeNi}rQ4!_I`bx&wp)`fZ^v@PF4 zeGBxqJ&7aT6SRNsR}P{5edyo|zxEIHPtXNPx@?HMp1NQ9MOEl<8uXs85?$1b_HPnB zG#=X4M4|r;(6;so^%`hf-h_G!v@K;q{Ufwrw#4^PSh6|>$pO>~`RH&Ww5>=&-3{7S z9-$r!Z3~Q0FQES+zn}>9{m`~>2=$xLwl)a$*U+{O2y_^fzHoYHPm=r&FuF>+p-+AzX@&2Z%}_vJKm|nL_&jc{x6C7W=m_(;S^|F zLW8;wv@MrGJ(2!+R5M5wx)$12!=QZ?^VjlWgsESI&Pmccp!-7ufjj^IgkSkcz*uy< zpd_B;?T4NxT_4(3w_t%CpluZk>hqy(wF+w9+1g?i)HgueVinZ)L)&5%?)?8M68Huo z#||C-16?;s{|=oCeYxxvYGa>5yB5H|3G^Ol99>=hbD(Xt36?h!I=6w3?n`|Iv=)!> z=l?hoRyFjiM9^U!bkHbKp)JsLll0fnxk>sc^ayCHP<9=RA!zH-me98N1IzD2`-w$@ z`Sf7IB}lNv9H{3*+oBEBE1+%B2I^;^ZP5nm_n05AL0SdAhvuRUx2Z>Bb&((1dbl?9 ze(F#T?T~=Q8KN#81Z`_Ga064IZEXhX8=!3s2I>cxze%EtH$dBx3bgNnwxtuO4?uIN z1Rj4}50tBi8X>{-iO_zn1aI#IZA&GvfD52)sRZh&(6%H3^$oP+S>1e51a6tP@ z&{)YJj5fFv3AU609e#qgr3|P`)W-&zB`R1CdVi8`4~>-!q8>aCx&YdC$rNZ?$bjWt z4?Ute-YS2{YRCdwB)afr=nYBwL+JdLexU&tupfFGwDnl22B=Vyt`F@O7VtgT9y+I0 zqC$h9`-e!dF)#@U+o0#ELf6uvb)pMbLhnh^&qL?q0T4RM?ZWNQ7WbbO+zV}S|EXgQ zkstonBQ>Ez2L88E+8PNK-=7)!L2rQFS~#8sK-+O(0knnpr~h5h7T%xwIcN*xPraS_ z+a-E|$*GW6Ocdl%?!&{lq! zhXjjJ&lX+|Z87SpmqJ@CdTKsIw3zeMTc9npJoPuw7DAqyk320@Jar9diwF-L25pdF zq2K9nF0_Ssr=AFHk=&_ogto}-)DJ*gly>Tup~qz*4YPt5rT@qLy?u0c+V?SkA0MH| zo&SrTj0*Jik=N-^3)&*AQ+I+!M0NLpJM|D~3!F|p9ohn=Q{Mz_fzhcSg0?v5)UQHY z+;eyS{}2h|in!{!8h_0U1AV}AX84;Kl619GU?1e;m($(`+G3Vd4}iA#HXp7oSeLA#7>89=kZBe+XFM+mT+tl;vf3c62OuYiy zf@xDf1MPxl+p+&WBv^24I(!dpL9nSSpN0)i@zI#5n?dL1`#9FrgP|>6HT6_zi&IT~ zH}hZS<62Qa56!sKE(|0SK0ty6oTfeuZGok!D>V&*5mzQ!bQ-k9ji&t^Xp0X`od<1k zpsD9TTexTH`=JrZIdt#tG2vwvaIFv7O#L;qg=VJyn*}H&GxaIWP(VSVMQ1}>h-KP` zL0f2L>g%B`XfpM^(EXR;{9mDj9|K#FU~!M>@GZ2(JEks@gMErW7BbE;byH}IVoco~ z+M*Rx&xE$1!_>DxTd-m3N1@l^ttJ;`m!|7 zo}m5{+CuA6murFYUMhkRy58OZI_EVXIG6U*Tj2cfBjkFA-f-yurVoruhs&TX5H9uY z&=&BP`Y~t=Y)ich+Tz$!{|;^OYN?NFi7~a=$EBt2&=T{{;?OeTJUCdqS?bBq7FU*f zA+*JjrM?^5LdH@*&;0ND@UYbHLt8jl>V42I{HuDbSl9|R-0H)<(t&?cv+%CeXFyvx zSL#8~4By&O1x#Un=;x$wpk2{f>Hh$Q`8N@7SI+tl=eQ*79x~-9JGZ3b?5*2NU#u~bhv{KyAw5j3fe+? z(*6##Med~jn)yFZ^w{6b5B-dKu=XyF(-e3i&>6|@D& zn1sq81!*^J~?}-AwVF3pd6$s8i z0noQ;A6JLA;D+2lD`<;hNZl9OVi;17gLbhB?fic=64o9{6nG~KQ0zfwcoy1X3{vyG z9*ZSNy%*X-22#h`BmWT}k&n72w1ozwZVk-{fT6XZFA^-&9~~}%wvc|*^Pm;F&+W41 z&=#SO_9vk&5+C&z=7;Ck>Y=Zo@dj`7obfMc1l9}rhc8!Pl@6$3mXEH+0-8a)NO`h% zhqi!tw2y?gz<1P_LtB75>f50$jve(HXp2`z{U&tX5*YthfjvmD_;YmlFSNy(qpox& zYEmlEf~L?GHjei0&=ww!dK9#Ufup_>+9JMDFN0nimhoYlnD7)5EQ}lVR%i>?M*SVM zMQ5Wff|GznW1~J1+9Iw|_kgybYSd$(EqEF=ul+)clE#GPNU&gN)K5WM&@<|Hp)I%> z^|#Qum3LQ)cBIpU)Wi_BJJ{j$;p)DR6bw9rUVe!Y9FdhyTYm9mU3#{s6i&5Xr z0;~CO7}PI7Ti7t_9kgfr5Mk6mLt98N>e9KWS#=-Nfx1y{7z7sXiwU`Ku+U!A7eZSI zFY1}l7O9K60NNsQQ9lZ8k+-NfL0f<=>d&AppceI^5D6ARiwRXaV}tel>+jSppe-;K zbuVZOfJHqP+5%lshtL+!ih3Eek6Yzu*)!1Hi}-b_cy}DGr$b`~uJR7=L%X&P|#tp00|ZViVk-{Tfisk zXQ6$3Ctsm|Lt7vx+JB{gYab1R`na<(2HN;&7SxTQ6@bY#s57+1SaRq8JS12^C1$t^ z+JYxhFM+l=Nz|*MEhZB6o6r^miFyz1XZnyu)JJGf(#Lm!y`${>`+rj;SPUa(=nTzx zMPsmC>hq!ZC+U1>3r9rzVrUCJM12pmk22)*zfOCXL=SxqZ2^OD{KLH-5-c(h_3>R% zK-a`PZUSvVe`xOtZ9#shM?hOZAL_Z#Bf9(8J=6uz7N>{$5opEb@#p{7kYIs$=Q|vHbPe^#v=8u6Xs8cBTT~kA`*8TjUt(E1`Xq81H{K?L!j#bUn1idZGWv&=%8$`d4TR-9lZqJMs_1_&-+_I0Xq7 zi-it7pk3S*9S6okTSyh!7eZV36zXNr7Al4MW$ID><6-Jgpe^bN^{>?9aQ-i;4V3DE zQ9j;BF`+{pXp2}v-45C!lu!?Zwtytmlc6p62=(>Q7HEX}UT6y}Lj4@|6pa6C)dSm* zU_nFZu$OwO4-i6Kv?ug59}I-L2DHWepgsfI;(Ac$K`VBL+r=}XEmQ~X1<-ZFE3#Zn z4koN-0ayCi8`K-2ExZQxhtL*IgZfA6dH!oP>R2!6`953*bv0;_}_=pzNv!E@41@&TRi&#Ou3fdx6P`?OmfheeVKwH2G>Yt!3ump9<-Z=kT z00}14>Wx{TAQ99ppe-l_bvI~>0YQBc{R{jD=+slGZ%wrD2I|}V_hGc(N3DYxDTs9eS9DE$TA;Bfw~d2g-xJt2W?RjsLzGANC(v8 zLnK(V0wyekwx|TuchG*n|2~s?Ewlw4pnenDf(%f90&PJBsDFh<@BsI%KXu8zC|@xG zsKeSwuwVd8Xa#K_{ZsdZE_giA#UrTo9Y5`}sPRF-QO%+osn_|>>S@0h+CImpejeIB zyN3>gtw`Ya^;>it_zK!Sqi2TyQtPvM>I(g!UrdbpM%4N$p7t}K?JIcde$e*SJM|c7 z`^w#&|1U#=ebr8fo1yLNb?W<|?JITa=b=a7o%;J#;di0!qjTE7fVPj!ssEt;ZU4n1 zb=m&V`fl9a|JOr;eIQPUHqiDVICU>*``(*+1Pj=f=z*Ek+Y=kOf%^T#F1eptpJy}w zE7Uu@-JSnGV#3bEMdz>3_E|MEl)y>CKBK0t32mQEQ#XgU&!nl(fwr%rsfR)r{KtQ+ zOr1}E|CO^p|6hXy`pNd+z87xa^-?c^w(oeUABMKi zcBx;2cAx3u`E$SozDRE0<5GVG?Z3PA_CKNR^IF==4#a`y_e6{9QtPu>+FL=}m$B5{ zsr4l+^+nY9@-@6u705?|ec?)nh0yjTEA=vH`(l-P4Ya;Ybq&}+jr0R(80|Z#_2DV? zkI?pkDRuEdC_jez|CKV-L4tiSN{0^6_E9MH5NP}MlX@n!edkGC0BzrMQm=;Qcboid zlll#4`#h8SGumt8{U846jR}X4VBcF(S3D0Jtc$@TdlP8;oRapg(Du0`^>AqWGLm{W zw0!|deG9aG=}7$$bcJHg@u!d=KCec;P0(62)HDxGTk z&!tX4rhh}Pg1!}HQ6GTLtrG-ippw*O&WAz&PRJ@B)KAhCklwbCJ`cJA@|J|{c-#*T zhu((Y(qS+T2_ule%ygIvT^GMC!)4Ic~3$A z3A@)}+2AE4?1>V}2AiOH&1f0kh5jhXz7skJ+BWbhwEe4qv2Xx77YSxR0?ps1%MLbg zq~Y)o)J{%-ZdOR2TS$*Dq^A|q*FvvN+TbnF^OE#3=#!w?z>r8`@k-qR+P-k59sCj4GfAByv{GAmlo3N3+eX?>2C_@zY6IJ z7pg+s|ExfBOOWnXNDnKdr$F0hz3jmS(A=LkXct4TO43W9Hzeu1px=fbYZ)Fw!gomy zPeAWa($7N&NwZ=jbX{mxo?~b;bWV~E#!SzjIb;09yh)ShG>wn!U%hhiIV~vS&GWJo zzlUd6Dt?*L@w@gMFM^S?F3FobC2!i~F?spp=Zu{=y{*f;c6xT@S|}uwUB%O-z5kub z>)7RM)2@E;4Xvvejj^^UuA2R*?2+ja!TIx>0^_(jy>d3Mo%0&a$4S~iBm>TnC>zqC8TNO z2$Jm6Swt{$%$U4Um(3XKvwKyVa-yH$Q=2ZRSkV|Anl+2%9lXlyr{IQp`%A1-$c4FJSad{J`%+4P<-EG$Iw#;Tfsz$b} zo*nPlwt6WQ9qHn}{P?+NW!IC9KO1M4yGf&4L_B}0CfnpS{IE!jdv#5eZLu3;@2J|(;QMXCgclWi|5BRSDZa3hwUshcxbUp3nr zIPC3A9?B!SJEpDQiV5azPV!jx2W<&&%x?g){XBiNORvFvA|8_MqR!$XIS z7c@034XsK`!*){A{8%ZJ*@jgHPnW$&3pa)}6FGzj`%-NL;y60mww|13Teq~74W%T? zGtSYQnDKt_+R*`nrUb?=Yw5;d33Y-Sxy6$W*xLy&Rm^9}X_;ifs5Q6B#S_1=m4sK- zqUKVm1a@?iNcbRw?`B_<#BXFVfx%!^cq&f%0|u(~@htGgGrMGRA4E0@_S#VyFg zr6+!4YjSesV1)W+Fo)^~L!!*eq3t*hxfU}<=DTs{_MUct8@H*JmPw;3)uJY4$fMm+ z*n(5#XziTBCRkef#$>Q)zh$tr^leVHaM)&SX-G@PmeP>1p>7Ifs+cnzYwH;s*)}gc zMk8Idj#ZX5k@G6*f99|zrWve-X@=06m}aqEnQl2?o!EL8Ktzu znwW7|Caxr-JZ{9IEypsUH5pADe;Aq>Z7`up$1T8Fm(+2Di+#S=qH?ZUWNkQ zK*-oGS~9nomdp)ymgFjgQ4hKeWo(n%&@nBU8|(7ehSK&s#;I@W$guDb#z>W^uqA41 zT5(ZZ(=ErWg7$1U+g);{^g^^}(~67Qnr6Xx)y|tX_TsTKMvrp`-XPzUH{uRrT#GiX z^2U!DJtL3T>XWi@>yVt<)+O`aAU-0eYh{1%-@meg*N2WD4KsxEUMtGeuAUDxpE zDXc9|%I@Hhv9e}$U0W)0cCu;a?1gI_6~TT^DuUhIAf<@(YBR6vWYwB|d}5R*rK6HZ zh|9)aRW|-iG&Ut$rrNshRaW+HkCZKDu4QT$7A}>Oh#qnFLF2?7c+}^aGPr7#^3Kf5 z(O!;Kad*eAIQC(oBzoBmG}~P&$`NNIkH`L#pt%i3A=~rbWZikb)w0VJfstM zrtwZAvnx+JhEvLUD{62no-vXS`Sc6B7gC)8n9hY4(afb&}#gcaH$I^`1RqWQ%8LT*0f)2v;s#xD@?GErM z?a8q%6?BdIIc0#dqwGW!ueU7Q8lC23^-AA{?Sc5(?$s-+##82H+ip!S$?CrH%&3o3 zoY==!r_{|Q_kR5IGpi>Cl@nI*x--y`xXp0;FFy6+s3ULfSl#**K8gJRm&ERJ7VGTo zJ(F`-W)5My!EwKJ$HCFe=f`P>JU3|Eaf4%dTxJ(^WM+e1Ri+JB4CG_v@CG-G+oZdw zA2S=Ur)h9w*lwjb=As5;$VIn$9DgM&2ZTR+yJ1;E)uyOqcX9NuYnQw!dz~W@!_{q? zqt*9gnv1UQ-B|T4OLI|mQiqNk=(=O%K=oG*9H+_l%r~kz_c*M8IdQ>XmZ7rN=nwF7wL;lJlxj3e>fT?Fy zuNku+=onnt$!+w+@%b0K(k`AjW#o*!8B_AcPo9Ch4qsTIMC1(8liZ(n+&$TxS>th2 zhT}YMrg(Q%C>32BTzpcYgbgf?fB%j!H^u#HX$2M)Am=6AC4Wr#o?mz$2 z^`l)6;JT(_bTvj1T`;AbQTIsJ-JZ1GIyZ&hG_LOx;tBn1@eHmwW9P0u^mjtY#olf{$ zPfkxty2bkTL`Kb760rR#_2bXdts_~#wPA*b54 z@U=reCMFJb?vD(GcR^CVmVOWTa~F3&OO^2d+cJ*)+H}j-u4AzK{XslBh#q6xNjcm4 z-S5u>-1^1Ih4_2IR_<2IKOac$>NeVZtLCY#0+N`s~VM{Q)GUy3CyN zu*tOni76N6Omq+XQc|NwOev-~Hx*{C4Ym{+k~Wl*W`#wGX`6{GQMK$ZN^F`-3{(E% zX~{{KY_6xQ3Mn^w={q6$@Nl|zLYth_iKLz2dpLh)Sm=J!{wC-)`_EfwZo{li=KXw( zofvI_<2XNbFS{ITB;{BmGTgt|NJ^OwY@J4uYj)J}cHikzlXevT#+Lcfz1zFVlRe6$ zont+i^tYR&-Nu`hD(&2iX9c6ozF2$En$g5j6ZcoeyxiouiYVYxgtOQg3m4D0$I=<#J-pFWC&TVdE-Sw0_G3HQ7*NY> zBi2q=v}|_Y>n?1q0&1rBQ!~Bb4MC!wX!EgdHZ$GYs>N;xu)%h-$@XTrDN}QuJ6n4U z7mY{Pp2VLjd7El~Fl4(+M1L^k&8aSK*)%&fy5Blwy4xQ4aL2ZZ23q2z#(~X|;Ge`L zo%U(qsKCHdBi(P;Navn%+*Ko;i)&5tjsOqWMY#h9mC1B2~MdeD{e6J^Ez6hQ&id{iyr^5lJ$-` z<8UYENAmm*(Zi^;vZBkyw1!2`zHql!xwb1Qy}#^6pEap-tchR`OIVL%Od>sz$k0D} zBEU)<>rq9fCq=FYHF!E>$ zSgw=;HMbI@C@N1Dcj)7tRT+P$0#1^ zVzgOz_Dp`7R>-0;#l4tnvFDQM77cSZIFj>(nB_?qfypM!@?&l&`NAY-X~9NP4THzpH039Xl6#Hrm(mvE#CjE1`RiXvFxPsB>{b*iPipzkTwB zS!x&Hv=fzIXb1VTAKy2vQqo>nb#Eq@&HPI>MY!8Vb};)W~# zfa`DP?)j{1)#4b*xZbkA?z-*c5riMed~>^|J@Vnquv3v;O}f{eYMP3!INf0^j-)W?a!QFdYwr0tn`eWJhp;BZngH>H5&Z6wNY11ZB!@U^diKQxB!r|TKkBlQ_x z+oZuAb&8E;x2K}nfStlu`TVBS4!L$@PR+w(U&#CC47q4aEikzPQP&pUerCh5=WkA3 z9h6h5>^81U?lD`)(`2Esk?Cm8UP!(nPN|+Qhm#M9I_zc4;wqs$VcNERmvNV+Zo`gu z>6YZfNR-DmlA$_BO{@uV$&^E4iRli_Nhj#q;pI8U@Ga_h?Oj!sQYzG#SitvuJhL~3DQ*Wl!-=Js>Q4DLXfJlC8l zvScbLt%B|_lF2izdTwjx8GrJO>=R1B$1XYX2TqDdOgAOfhPXS_MEw{I?iAl> zM5LtJJ#(T2_f$5zU{7_6 z>~mt+!$9}jSJuB4qazm|nuMuij`K5Z<}fjB;%FwPXHT0puFS%N+m(sLke^3JJJ7in zo-@uhQ)1eTp=a8Jab+f72y?HvGMN~1^VYA<)oPlYm^N9Qr`0LNGgG3?l#~tmc@h?G zeW5AgDw-j!@PweBPC}`@ne@aiYIsswbYiuEXM@>oSR*_+t?*Q!pPdep{cLz9rxl(X z$QwrUHKi9boO7&#DSoP8a++;8In6fA%A}s$Y>sd)Wcbsw>sC#dUs|-SrYliglvawb zt=zR(=%%2ZwW3!)nzxz512V6$GTBgSMpN5k=W07AW2O-AnY5i#=p-3cqgCci?%k9^ zdGu~dT3JfZ&>&}-I3o|HLRE{(D%=N=A#;Yb>dL>B8W>+!vx%-{rye<_y1%MzUZ!ou z82a<}b!Do=_t(p*6Q6VO$>rjI-F0%g7I=^ToU^$H@@MC@Xx&=Bnzzx9mS)N^OY3;O zFJ{*`9qujNo*RW1IGhbH%cdWSX!afv=^MLzC4hjp1y)}+PYCad&cZ3ECb`El^+MQ z^V->X=jZUWg`@ILcRxnuHMddS){o*bdBzq9T@kEBteYYiBC>k}1nHT8Wdp&|6A`i! zj7`FdF%7}V2+Dn;x4#e4{$DUQ1%Z|t`}Eg9rtbw~QxNrM)k)s)AV|XoFqV(NN+)B3 zQ?a@qISt{$q^C;1B>jHCE6E`cpY;&LS1ds)8ZRzvnwDRegl`g$M7@LkD{vgYHghY7Hrnx;GfoVVn|{ zi7QE@{{XTDzk=LgeMD+z!7D+gKL9fQRi&3foMh&!Mq+~l#34$*6J)-7LFOCIsJ|?5 zZzpfq57N*h*SBmG$bxPnQSd|3+ogY!uGZPx86%he!=x{leo%UY^bgXd&O%rhW@wGj zvD`pE5_+!mGU-jyyQNE??fn^2mi_~!CrK}tepdQx>7&vN^vdn^3i$&C%vQp!(l1N* zM7&dWS$~i{a|6h+av#WiTS*l3o%9Lkc-@SIeTejQ>AR)ZONZYop-4BM;WQEj_LQC_ zT_F9E^c_8X#a4l=*ddS=JE5m9=S&ji441x6`Y~ySu!KDf{!~H(goI>#>D(3$bC9H4>nE%p0OIJYHL1ySg zqJS~d1=8!JKb5`|QU18g@7S)*oR9g>42(s_mW&~xuabUL`Yq|-q{|`B75&?h z@IPPr8tIkNTc!6&S4Frf`Zp($f7k__|47)21a{4SkX>^M!a%WS&Iai?nS|eU(oae= zoD}Vcq$?u05_Lxs{zIh~N#7&=uJqne2~~#r3^^nUxJdepiN0dFAS<>U5_*($DE)}jnE$UU;U_tineH>3PNHJxN?$2`hxD7$d!)f2f4Ra%eQ$J9H&s&zD{zy+L}9blExHKZk_>MbcMDKP>%@^q? z|6`xUuJ8pnB~fr+={eGOO1~-njr8$XdjHlWDn3$rzVu_#+ok`Ku6337?{Ssp|Nnuk z**1_hJ9(a;|7U?LcoK<^kvfjl72(_GwJdRy?@w*Kd`~UN|-8rm-H#u_@2oD z*)x}dJTfi-neTBD8-82*SLx%f_4alo>;t8*l3w9;7`&x~&*e~VkE8pS|9K?rGya45&lX+&AMfxSNQak6I2`=M>mwxex-a|&o+r71FSP;CZ2)Bc zekAO_eC6$bfV5Zm+S{v;uy_83^B)Qya2Mm zw@768t%lFgucpfo?5hR;D-d|Ow&#!Hm36%S1;H+9zq-C>%LblbiAx%KeHg1kXI+8$ zf5nMD;VJ=OmEfR^P&!(1J3k}b@Y5%9Mj3` z6LLLY2SXMx1MAk34bPH8S2>6?&XK*F=PTm0?p`F+6haGv)c2Erf5|Ix^>0QX|#Lag)%a>E5A3jP3gluv4 zJkO>iD$)vM0YgD%TtT9s*aFX|ul4@hNcjI7r2iq%`7QGKn%mbuAi zxVgYPE&=Jd9;D-85`J55_w2IFZ+JL~4UYlozZj(d783sVt?=Bx()%3*=~ru&_iM0< z^B<0b9`*(1lPGW&NXNTC7I+^CzfabAzbl^f9PyOr1y6g_E^PVrg2%@~#K$iC< z$a0#k$8iA{r5)Cz>v@s6NC`_w=&z-VyySIru`P*=*MKZ|G01|S+~^C=ea)wz12TOS z$PGRYGT(X<<^L`o31#T|y3g1PWX8YW@EIq*g>;OKvTu9#-t75h+%8p7(s_ zIcAS%L#&6%2JP_-gL}S^!!j*P2$1>vi~moLD|LOe|X*dPtUT4Jns@a z{@3f>Bw%z~9MOL<+ZwC5}0lCoYeEa!RVah{bCZJ*^A zJ>K(x_|*wm^@N5U6}@3oCC{g8c-~*rb4e}Fg|$6r)bYHrf#=kQp5q&N_B+vY8i{E- z2jr}J0_17>$BY~`dgt4zk@LxAnrOHycRc~Z9!as+)FOPgUQampo1U_ zYH=3QQL)!ZRP59)-rfSF{Q{61dRpl(D*bz=3NTLV+ za}kIh*h``Za)zs7APf2gEP5RdBqM$LHz3oGg0WdhAEk7V>8(b?|9ae*fUMB(VCjjN z|Nl1*23!(N#EM=tOaqzW7Lb2ftTr9Q9~Qry;qBjp&OXy`Xc>v;2W@9%x#tJHNIX9{ zPi!_D`7p@Wk|_UKkohl|gM1-sy6rOWQ0@xP4p{k%89FcU%w6bN4-1$uJ@*FBk&8X& z-RN0xo98XJdoEhyIcurs3HN!H`M|U64$c2EJAJ~B;-W0%(H({&mT#&;5U#h z7*-q?BWS>#CGczjPeh&|(ef9>PfK}w^)lXm8VUR9V%@U5{=YN>Z#7u-R$T9cvD;!n&`=qp-TtS6o(wiCOG=XS*WX9b2SVZ1m~ zoG;!aE*BpV*NHESo5h{t*WxeYUt+0Fs%R(7e^#KL5>6A_iCx8W#bM%jai%z5yh&Ux zJ|aFNZWP}YKMwWdYw;KHFR@gvYAV(fPZQgTUBz?7Vd8jkrZ```Neq|k#{=Rz@nvzd zxKsRG{82n47VGRQdc0UmJXvflb{6}1hQSaej1{MfSBlq*OT~M{$HW)JH^lAYr{eeG z?_!a&d_~JSV*Y01_L zSn6zz0kNKVn%GY4DxND26UU1)#rfh*pqu~8mGFSLPJCJ1EbbIP7k?BFiN(5T42ZSF zlf~9zXR%Kg&Ho`v7%NT{uN1Ermx}j@kBKjcZ;0E)PsQ)W-^CJLeMKvF4gHTgN@yaU zE%p7ejHe zc$fHu_^KFg(T@+sFU6n5!(zE^zJl3e6Y+HMY_Xp>RJ=r-E{5V_&oGE9;Xd&RalQB! z7`r_dd?5XqxKI2;JgK{{U@I|K>@8j(juG=6G5@bn!gb;jah146d|uonZWBKdzY`CL zK@VS{vSKx{p_oH*{&!G9cX5z7LYyeh5f_RD;+^8d;?v>=@g4Ca@hfpZ=;r?sC6w&x zYg|dJE1oL06}yQ2#f!vzF%%bzaq&L!32}W-&HuNQ@PYW5xKI2;jP>#rJWi}3HWpio zoy1<^U~#lKMV#A9^M8>NZWmXItHtNU*Twh5UE;UmZ{kt0OmAP|s$v7Nnbmmhs3AESH&&jhvJvw&tiC3KT7n$G+Tl{K!WZLNbDvK6vuxa>V>E*3Ty#FV+%I7F&y*#XjONalANN zTp->et`Hv*pAugsIsdmP;Y0CD@n`X{SfanLXhpG(*hD;CJX`E14izsEr;AsDZvJ1d zgr(v=;$z|q;v3?2@l)}8@prMvxxS+1#B8yV*jzmGT+RP}N*F3$B2E`Waj_T|?-QR8 z*Nbn7ABdlc`@}!Q*Z|G{;|BN|*AN?vEyYe^FLAIqTAU)z6&H!Oiz~&|;&bBbp?-WI zekSe{{}5vXeFcvbYlw}-mSQKdmpE7)Elv^Vis2&th>Q1$Pl)Tqx5N*`&%}M=A7X5f zDk|0x8;dQ)PM%@VO9_L;(c%;tS#%;&$;< z@q6)ivCM_)IkAD*Ol&W96NiXnJ;PwC60Q`Niw}tF#Fxd*;!g2%@kjBfSZ1iNSS|5n zv9;LQ5%a%~5{8Il#i`FlJmcX5;}?lz}QOs z$wYdVc(r)5c!&6)_$3%yg})t>_u$F*Fz{ZyfB^D}r>l4_(=qTzfo}d!mf><5=HW3q z$mjgaK|Vfz0OaHI)wJJ+zhZ+daI^T4_?5U{JR+7K?)|HZ4a8={HUHZyp_@2Ryht1? zP8Mg2^Tg}L+r&G>`@}WkGvX`aTf;T~w<+Oc@e6UEctHG1ES~3EbevdCY$P@niwAg3 zuULR(m%&jnEWqqpS*dJf8sXr-{PlY@uI%K zY_YM}T0C1ECtfBl6br=gU;1&Uc(3@d__+AA_@cN$d{cZ!d|&)X+%0}3?iKfYhQUE4 z91*iHXV{e`#qwe$vAS4SJW)JVY$3K4JBnSzo??GT^#A!vxJVo&juR(~GsMfqdE&L= zjpA+MGVyNle(_OpEy?-+tP)-lUlZRJw~9N&|A>3UZ^R$OU&TMgzr~_BB(Y~pixogO z|EnmWme^2iBDNGeiCx8B;<@5rahNz-94}50XNq%+YyQty!Xoh|@pf^!xKeyTTrI8> zpA%meUl%uv?}s(}5^=I4=KoA3Tp=zH zZxC-4mx(LI2gS$4r^WT+YvN{coA{x)o8O8VPYD-^qs2?bsp1?l6t5L;5|@Z8#Cyd@#I@pc;wz;z|KCu;JK_i8 zf5gwl@5GeiTtjmHKdpq9#7*Km;tuf> z@hkBM@ql%@1&UE*G`LIq#* znqoKcd~vKeLtG%WKNjRS8GLlDJdn0i?3nP;4olC7vrz5w8+&5?6~aikroc z#BWK?|AR^>c7oqI524V}bv)I3q=6{|NCW}{!H;OC7N5vP!x5W>|Z^YllqIlTC zU0G4AFE$r*D{KDuQ^Ig@l6Zx*URt3Z+j+p=LmC#EZDozmRii^b+ z;%afdxJBG0?h_A-WvZ(JViS_{zr7NAi9^K+;#_gDxI$blt{1n6yTpCsVX;gNRX}V4 zy7}K;3BAOj;skN7xL8~vt`^seTf|-BKJlBCyQ;xZsPgkSg}e2pRXaw`QK6rw~MR9C&YKeUE*HxkXW*z zFR-e3qPSSRx{O8V{zUK4O`I-1FTNpuAbu|XEdC{yY3$3%78{GL#k0jc zaZ+Q=|G7%IUVKX2C~gyvh-FUl8>%jL6VDgNiZjFo;%(wR;@Xo!U(l;c*edQ8e-i%| z%b)E1Yl}_Aj$&VNxHwt7O1xRTTYNm!k5|O4;%@OL@o%yGDXM_jRO~4B6^DzH#jC`d z#koGe}?-Ynkj83vCl;T3VKxLf>5{97!4 zswyBh6+4Q3#o^*)@hb6V@oq=V|HqZ^invwWE&e3_EtWq`6%d<>9mT%laB;GDm3Xsw zH_7?`xDs9ww~D*PpTxh#@=a9%v8mWm>?;lzCyQ5!H;Z?JZvH>6gjd9^;%@OL@o%ww zGgUxrDs~k6iZ7k+{oWQo5O<4vPuKkaQwhb}`V5uC`eKgQQS2>VD2@|ni3`Qs#8u+s z;>+SYZ8iUQDPga8NSu0xuh3)S^WtvtfEcv*e&xiLVh`~=ag=zScz38DkBZNUpNhYU zN5!%o{DxYH-NixTNO6&Pm-vYItoVr-ey1M?#4>044V)?V5YH25iFb+*i%*MN#9zd} z#8Mr7xu=T5J;UHqCCn197H<(Zitmaai{FUVI{AVdiaFw$;$U&KI7OW6i1~k;5;lq3 z#81S(#0I&3L(RnY;&8D*yi)v*K&w*J9PPeZdXHW@3A>yLh>Ht$3Tb@@&oj z?MnDm{9ZgLR_Nk4R8u@jY$f&*uN1Ermx|AdpNQXy2fBp5;Hq6cdx+DIg zd2y4tU5uUM%R5f2A)X|jCH4*V<3jOb@k;RtalQDK_<^`bJfWN4U~Taf@pN&#I8&T2 zhBxcS2Js#7Bk?Qo7qLNizoBMgd$GHCxp=L3o48VZL)`8e2A?Y7fLOhU-@u7t3$ced zS6n3CF0K^Uh`YtT;z2Ri)0f}c5%a&Z68eZ2iZ_bO#QVjy;>+UC;$g8wFTa6G;yK~~ zakw~v#q-6{;`QQE(9QpQmGHK>L;PI) zSv)M3=;Jq7TkInC7l(-p#9PEW#n;5GeKh}fDWOPTwM48g=8C<=A>v|jnfRdir1*-s zQ~Xl=Sv=fV^Z$f?e#3ReQ^mGoKXI5iUYsf3DBdAHC_X7}7C#if6n_r&qj-N`fr?^n z@no^1*h@TL94XEc7m5Yqo#IpCM)6%S{8&Hsi+_uy&-E3mBAzC;7rTiA#Y@FG;zF@N zd`Nso+~^qw?<&ECEXHj3Rr+tS^Z;LxdSWxNz1U40E>0BZhzrFP;v?cSj+p-&mGF`H zjrgnhw^(_guSheoz1U40C|)Wq6d7}w525cA9~NIFIsZRa!q?(2;$LE=LB4>d;u+#O z;s9~Hc#F6~TrYkk{wV|6%Fl&-dlk5>FAk zi2cQjTo7nv9H)d(TrNH!t`lDtcZffTe~4Lw{f1qTXp~!D`V6tF*k2qvSo1$$3I7t; zh|h~}h@Xirsx&t6hji=$zv1d)D=}B>EnXl_5f_E}ahrIT_^|l0xKrFC?h_A+Wrp|) zoIqv;K^3t&iFa`u$bOo13+b?f5;`kku=FtLF(e8cCr*@ortG2gLg|~OZAVX*QDQ;-bSLl9pXo_e=hqEWQZ32qJ$%IC^8fVv@Dy1 zy^eHak}VaR$=+7>v!%OB50t(@I$wI0^i^Ol7I-xiz-#4jiyZEdUMc;k^b^u=Nx$oL zyz}BFRn9<#zmfeH*$+zpKbr14Q0MahIyr5WCFEBmpEWtWz(9ujO z`~fLJUKQ)n*NF8OtoyMZY<+(mMLvmqF0R2Nc*<(uIs8+G{Sm)T!$0^|7;hzGCE6umOIF1FZH9!l73C#*t5J>~Dxvm_=a`4a-^YW_^(LQLBL`@HF`)@>{I$ zv;L3uYu3q{1Q$qc{bp*yC&c^|N?={9gBoHJtBZETFK{T1wi@`Y)xN3t9r--+HMo`f z&M<{j6fRi}xQaKZKgHLWxM^^qcdh!u~5#3jfgXl6A~x!N53}!0Lw}xz#Jk$T}b!9z6)4Y8Niz`i)ZYTziGg!6H!)xb@- z7k|UsR`c%TW2sZZefgJR#q z{%key3|_`Z_|mFB)Fv>dReusp9Z~Q9Tom$IU7)bl#^P9-ycX8C>TAKeE$i;AzhwOl z&a;}g2$xx1WRvyR|6LT0;~A?1E?I57iZ{q#VzjnFUjpk_#yTzQOswG-{8F4E|`-U3t$ne{gtp5HpPBc_Zf(T zt?n}(r{NM@Wi@Xb9+Htya3?7|up0OT|Fs(UR{Ow2m;tj|4J?4A@DprfHLnA9v6|N( zziH1WxG5B7SPfi)>v0$UVKwj)UbPzd5T9fG4naMM)w~Rt3kzY*4*mqEfpuMw4Xp;Y z#cntVM_3IUZ`D5uqsV8Iuf(75IQeC~LH$8BKWNYs{FjDk9fO13#xzzJ%g8zpmc*)o zQQfZxKc`w#{{n~L468ZIa5L^8{}s>TH4JqM?imx~Sj|a}=`oLteA8US1--BmScZmb zSP$D_53Bw!u^;u}I05J2GOPYoxQ_bHPW+rYMByA>vihOBVYTrN{!2Yh=OBOEDo=(P zsprMQ)QjWC)azrj&itHeMMF1&uWQ8prJ7hov^=c9wYQM>v1^MYX5imz10C5$oJvz_<}stReid6IF%o?Aw7j` zRs(ZlKP*Hi)MB|XkaePV>PfG*24N$8{1--`cT$m zt>#R`DdbCVGj6w<^Q-Nkherg@2x9jL8WLL#Oo}P3E|v?6VQH&5)v+!0POQHQjH>Y@ z_)d^N78Z!g}Y9{IPmH1{?2SUrRL#KS~Z_sNX;G4gM4Xfy8CqKm0-!finw`UTJ9ZT!b-?hDqjdIjsWR_A81dI9faP3kSM1NAO4?8Y80Xy9}j zmf#wzd_8Wq>bpdKAKzfMFO~ZvVznu@VQJ8+Lx z-!1b0FmCVQ%v@N&>g+;T%xYhCY>KU{?%GpEzV#VQ;ai+#wQ(-%6|C2>-fDHw4%|b2 z8n5FWtAk!(ygtD?HD>L@m#Lf-3R)dpjCDDygDT-CKD}GTWx%sbsE;0Sm&@hC^zOKuYh&1q18FRG450f8deU9}d);Fx?-5KDwr5+y8 zkaA#f!)*9JEMs-SimYp}uE)Bm)tr{tmV6xfEL?$`$hSrQAwqpf4pKNm!zrtQ=kQPR zxA-lZWS9jDVrlD(vX1;2x8~IJTGk~WKt3kS!%SR(o2&+HXT9HQfd9ordxZQcdCad> z*9%F88LakaWu4nokTI^c%Y0nae@;9&iZRi27l4Sr@d? z^*_zW5<^M^4XtSCi9>Ll)qqK?zi0hpu#T#cH25LBP5vC?eWQK4cyg=#saa=b9r?E^ zl^5_@7b=9s$Xi(Dk$=Nd4q`oqd?M?aGV-g{xfGUK4P1$9tuAnu{09DuF@^?t9IJzp zvVNC!CaZZ_F$ei)$PbdA#_RYm#uye{Fs{`FlUU73 zj_(fRZCjd#>ev)JSbYS#vF>9v;4A!^d=dEu+>gh|PqV&gwf_oU57UrnxB}fU9p=VT zSjlSRCs^I;VlA;J_OY5X9H-(!Tw}Fw1MBcE3I`}0wL0hoo+iJIFEBJBI4Ciu#}BcH z)j=g$S7u$Ebv+wBR66u|@DLhGFa>8(pMwjm2L3|+M_^Q$biunQ>B!(hnK3_>$EsE@ z>@%!wHLpMUXq-eIg)^-Bc9S2+bL4-@$ge2=azTx8M@jtHD3-OlNJXq-wXX?w z!Jbxg2IEAWgUhYPC!S6f~DN8Dt!?-%?7FIye>0N-FZ@z@|pZM882>zu6fvMy|OP;o3xUK?9s zd#i)`;Bbt>xmM>a3fAG!S_+$J*lBgpUOY&CpZql@8W$Y&uJy%PXSdp)3+qsCjh(4? zkEkF2UVhMknKUfJt+=237uLU99dHK!AdfL#b-nU;Ff-=1nqPo*F{}NhtpA|291R_4 z=!b)?@?kj2YS0?;o%kD`C%?@4rq%wt_>er+1l4uX>@xC=P$3Fstq!Qfx+d%TteaU4 zY=!N}$CH1LD{(XVcGibjA7y=dg5Uodc-{qhk%m|kgBvEtteDs8f(2QZW?hkWHLE!_ zu`c-l@-a9Q7fs}==yD1htq$16dY{$6L-;HC6Y?0}D%XcHDQ3Yu))!@6!fH+#tU%tW z3l05oG|t3DR)bcsUT-yMGj1clO8yvQOj4gNmdI*mlS=M(aV*a3T4_4j8z z#Ol1^IGTJd`7S($SMavgzWeytYHsSu{G7|72VbxVmbYrC!n&r_fV$X_d=U9WoK8Lq z=UB}-NPZfx$X-G?TB5;r;;zkmE>!u z@HJ-xjTdORgD)}m)ZiistuB(>>Y#Tq9eH{3TG$f1koROgko7mQf{{=r6w$gAI z&*3$zkHjt3Pg%cU9V05ZP;88E)t}$$!ey`qHX?7%x|5827vFZgTtdDH z58?^(Gpw($zRCKb)x4+pA9==U!3Fb7UxypR zH2g`!U3`U!zY8vw(rRNG%wTn~isTKbH@5n-sb1v6aEjFnoMkm<4u%)d@CywW39eWT zdO@CGhSoYTjn$y{tOjMrT;w&$TT^duHD?Iw_RwM64KEnF@k1>AGpd~bH!9!Mqj#>4c#Ixj~?}I$4Ri4sn z&PP@ks(`hv<}|YEYlf|4cHHX zkGwv4#~=9qqpJ%VG@OQMxQND8R)f~zM)E(&A5wp6H7D_GsS9VsJXRMfWHqN4mYN+7 z8r#s&mtcU^pzo{(EyFEVgLYdD+K-3HACkwM6XbEM=47^-Qvl0a&8ZUhg9cT@nl$vK zVGQ*NR)dz3Z^gq_gN|FxIfduQqs-whjGzcY*vtmdSg7v$Lk!=XHWP-6isWYyRtXb5$u-plI1vE<+5 z3abOxTg};w+sLnyKcoJ_YEIJm(tlAiOXNX6Hdcd*Sq&BCYS0Yw<+#;q z&K|2d2k>X|N91oUQ117CTt8?~Hmg@&2rF6*s%F(!6YG)>AfG^evelfGpMAsK?5JskZMuTkjtu`$7)bjs|z*8PF8=2{jhHEoz%Qw9ok^EZ;REw<5v5w;3KOG zJh$q5jnNkeeL1Z1;#PTSt2y<_+hZTAzOQBEcXGaQK^sQUu!@G=)c0Erx*N7Fco#weUY<8Jbk)X!QCdQ2X3X>edtt5=rB z>OvXtJ@P8#jj1d&Ma)SreiID^J{G%mtr4Qy7emW~zL*%t>SB4U=9H!0wxS<&U=td; z;y|m$VO9r@!g1v5$q!Qh#cIw~@~0ScMPyD?ndX^O^+gV0EF&_$m1p4FB%rr`h$=cxZ_HRxaR zxNEi6fvKzpWwhF#1>YyHPTqog8>=}($S1Gm2VowK%V=DM>u5YjewX?~t3mPCNnIo@ z=CZm_0jmoY!eZnt$a_)myN=IPlW3Ta>uB6c;||OvK* zE>s1pk@pJIFoIx=)hk;);fa)~Y{?RsZ`~j{4_T{o(dJ zbS3!GYC}JqKt6?h9D$gS$zXMy6!l&5Us<9*Mo>mv= zjs3|dkL#h5Y#v|l^;Uj!zH7EL3sf)(8TBpDdseiQ9pKlZtcR_|3@)&CWa!O2$p zr{PSigID8D+-J4_cf1oOctqj3)u7iH{ik413e1MNtOos$burdeum$yYth-sw{Q~=t zhsW?R6X#eBUX3TIpJ#o=YS4AOP5uTGZ&R*Up3G{_dsqOAS?wxaGuq`MYzmr-VWSrHRmYn-&tRbto3Wms}vq%{O!SjBvu>WwK^ajW+E?$ z6|jm`e*^4Jy*KNy)tn(X-1_^C8Gewf(2FJryVYR*R7N`4eC;#I3T_jiOkMGksG zA;!)iNMm(@OssQQ4bF}E$SYtSY-lyOJ&vP3Iao(^ACfsmPR-p!{UH7tn}C>X`QXN4O7t1IS0P9?NshRq<6i2ASs%Ch zIGn?qI zM`VugAA}LKOv72UE@r)g^-uUa^>eKMvKsj}-XedEiS`CpO=@+u%vecAek#g=5!n63N)&84%`9Zix;T0y_7c?Zd8u%`zvl^HW z|7SI*4C{)lYp|}%x-|}Nig&4PJyBafj9ZJ$S(CLgz7jn}-Kh z1KwcD13_att9n+eK{+rtc^RyMb*=iFvu?w>7mlSqDOiU?GyI^zKj1tXHsS&N#cJ?* z3?0;3uOyaLJ(1O%cQ6HcPArP0too}()R);N6xvt~=zv|U4j7EzVwBZ@xvUql-hlh@ zh}FE~c*<(tExd32KOuTf;f>Wg-l3o|vDG>~{*QWb*5$1Z_!z5_H^Xk&%WBRyI0u)= z$S>=?{$Oqt9oMP2K z9cNkf?nJ{s3k--o|aKlU5% z{}%-Dj|B&2#e7%-D`PWkXLXTI*v;zVQREA83;A}dpCebS`tBU_`(F=FDI_?qwO(;D ztHG(TEcKe$ka`mwL46v|ram7RTb*;1{4eT%hy9=%ML!WV#K(86E|S{nBI)sC>h-Z1 z^;X!<>Y(xD-{UIWXf8<)RV^!*nuod-o_$~FhXZ-%x!Al8N;u#ulV4}0ZL8&o2=CL}s02Z=(WlhLC;~?^( zRzHV+ux0Vh+RkISjA#>f;Unt*;B%`Nl<4M6R6L|#nhMMYO7at zn*0{^dsaVZ;$05%q?p?3m1nlPNVd!2;NdfZX4sB~PT0-rpeXW%xDj_)4cvnVtorYf zzrsX+sjds8uKpJ9 z^#_>ZI`99?dhmgHu#nZk#jupsD{DjE3rCWVwfZ@<$f|EOZnT=a!)o3hyi5Jnb>9DP z-3S`uVgaj-tcD`P`!Vb$LTJ6QEkB%h6IaI;naHry5VgErit;TgucrMfQmw$+AYn98cZ6nQml zifyg>JK_}T3vdVijN#KfT*2oU{dO=Y7RIwWIG@$UN@H#E`c@zM0aks(a6C@6+V{QH z1?L8aL%$GQB)EbJ?*to?TWxq3%Tcd|pHpv&Ev+svihMdQ#kE%RHbm5q{}w-J!(|#C zV6?lc>&9`dHYCI(R{e#^D`9UxK_UHpbRg{q3={RsUoe`T9T41s(Jw{$#abC+@Y{aGU%&#=jrzOKR1h z63bApfeolP#^KbX?(_ctfnXl~O2Y-bM*SuxeGnY{9_F&TKpre$b>W8OovC-X`bj#L zeCh+g|J68)#sxGk!4uT4;BD&n@!f~oua8^~%x86xg4mRLSL{u_KQ0IptjBExyYM#k z7Z~GFa6oK~Z}kH5TV13A^~zSSv^9Ab>}AzA!0MvmK|CxY*ou3oAHbij4thi$?Qt;Z z9ZYRCFg<3r>aR>*AKPPh>+k=21rMRVRvTv1unKqLL8}9P!QZU~Zf>^?; zzl`VKpzoCAx>$os#H3%&?e zw%X7LJ7PDh0mE3&W4#G?Sk2jk2dw6t!<%@|YEH~&e*dc>*R!CpC|1VmR*m(n27iuC z$%m0|!@cAO@fWN47x5lGwwfFFU*7-O{tXHRvAETNrLnx#pnBK_J6a7I#CkDq#Qpe- zRp0McbI;%(VH#rm7c>;bGFFWhu(H(!8evE5W;J*i>v^o#;ufnp+i|zmoSWp~jL(As z*{vFLVIHf-vRDJ_S{>Ml^(fX8t@cmB>Ez3CEAF(~e=1mqLr*BAeh~!OFh7>WDj3G$ zRtJv8@m3e!K)w%u$1C^<-+Jl&`tgtJ2fe>5S`Da)mK|Qe_`9K_O)whWJ9R5ZAH{P=9OY$a|m&0nE=M7)~3%Q^R6vI+9 zw6VItK-S-|9%I!%0gscPA-_cZDrO5siyZiY)x3|a_7~RYzsN&z8fw$f61z|zjT5O) zw;C`D=a6qEKZqx&Kfr&ezqZ;RJsd4~h-LL5NpE$-+*ll2lDB8w-D*HD>`Ok8d^WDa zQ{;cJzG}5Ue1nG~(Sr+=vbsPetA7y3nD zI5d>PXseCe@QBsMm;$dp5zW4AWENV5stkv9#5ySd}MH*_+&;q;T zARKA6aV$=>I_Nv{CAbL>;%`>_e#bLb`!3taumAm^o4vurZw2d=RvXh`2CI$llNZ8@ zSQndE?Q4N;toHT8QTV-#eEr`p=iR80!J6^!>H9u(MO}uNh@$I;Q$*m3^i3{*YJY&^=9p8x;^k>Dw z_z8Bx{(<4pC<;@o27SkR0qb?R3oqbZd@H{8=|fx1>V?$Ax>oaAVkhi{<09(!|Dq_& zvU;TptOhN?739B@U%{9Og8l?n{cmG3tAmS?SHXtZn!JPc`@a{32{cTz8aNYYlOG^I zg@5Bi@_$%IOBh@rw$=Q^R`Zf#O7fC2^8WwS1vNItb~JQm-G}u+*2Am@j>2)|>&f@x z?|6~?D(m~K|4ZoizXrW>K}Jg?^`T3IDY3LwUf$}*x;FLB*n@h1*2AnXh*PQmfQxZW zBESE2;07AE;2s(dS{-QC?$#!3=7Hyn!Z2W?1HRc4K zCVx$yFlo@29d?>%zrb+N5c-Doc-B)`&$1dg2N#h4LVg}^<3Hpt zSjS4{3+NMN0zc>#C9@is3e!d!^t<)sHL(SDChx&|0P7*FM_bJskCVu^kRP)CM0u9N zRT^%xe!}{-)u8Cf17lhJkR`>mSb@B<)labo)H`5L>_a|CM*gDo7#DQF1e|Ggzye%} z8}TQr{+)P;`Vp&xPqV&c^#X5L_20n<{Y9_@c`NdsI0Pr-603bHtma;e zto7@zn*?{QJ`&F{Mw(##fz`&mRvSxGZ-7mxw`JYKs{czIOno#?##z??-Njr#Xv0EW zMZ=F)2X14%-|8c9#H#-|o+5umo*-?|m(i*(3)ZLJjCCs+`Fq#xT+l_v)9^j6wHmMi z@8Ki-$7)}Ubb$%5pw+%2RxhA3^@i9I+okiT6E$?F@RilZudV81s87M~aS<-J>RZox zo7G2XpVgd0_$&Dn@)+rZzNG2-bypS&MXWZKuo~QpbzdA{^@>N~B>ahdr`5jSsNckU z)St1Ao*_6VR@e{P@Q&5sG?)c*V}7f?Vyw$qz0yytE?gaJk@q7XiL=P(;7RKFE>O6P z*Q_p*AY*Vq8q8yLP=Tlncl)Lc_w-V2U*kyp78hFGZ>80?wYY)&0{I<$i3u|W`!Zm5 ztNpn!kM(yUb!ljgy>J*#!`W5?=Hp_kiytNb6CaX4wfaCO$sF{h#`o}j+g#s;6!wE& zVQH%a%HzjY2XrMLh!e@DSRJs&s&5PK!Gq*ytma>`ntv5UNV^ynzdXf*LKFVs}Qu2+gcV^+YYYw`gfxlS|{2k9&4SYkMC~MG{$*M1_)!;H# zeO0g))+cXgHNTtHzAvy()^M=#2O3u5E*kb(9dOy|fLr(&|0R!;O}P$u+vnRG z8V~ib5e=QJ4*J4sV;}s=YU4ce4b-<-4L(PHo%I9O|60upy&uer85j=5@q-5Dv1%ww zLq)5BEyz1!H|m2}kF?r1(dwd8a60);@)Oigbh7)%xe8( zi}|TnW&Ih}rrsPo$jGlkdQuo}b>Mibfs-(bd^`ECcmeNWC|9sQj@AAI__o!B3z1jE zy1DpONLva6tTqn9p;jBe#ThssH(6bHr`5i_c#!-)`D;w{LC~K8^L^m=zXlX>K?6!) z8LNZa(byY@<1}1pwQntMu-dl=f5DS@)9Sp3R{NfYdH9cpjJbn`JXi`p!xq@VYCsq4 zVRi6y^2N9b58-*dVzobforl|21K#;i>V{dZ8gf|uY%XDySHw@K*JjeeJLl z`6Tj%)RzW^Lx(9G!9T19U1fa(?^sy zEVX*2+i5s}zfeEP`hwNqYgQMyiFe79CVFh(5G_e}o#%f~+ z>_R?;d@=RqR{M97AHpNlPqV&gHTSyJ+}n6xM&AD^@&ye!tQvA#4K8DK<0@F4dVSW- ztOmEU+SduYkw=j)rM}W??r!p*^YQinH-fVSm#qfhv>JRDACjlaALO~L@;p|9%UNBx zD%POhkaY{IxgD(bb;ptV0EY{V}Z$&SiB#QLKV>$Q!b5 z&ALn2559oaE0|0$3)fo>+-B9c3-^)VA%B7KKMML&SY0R$>ujv^Sj{P5bzZm*K@)6k zbzo+x1|CRrW0p89s&XLa7M)_+~&SmZ(fV=Ee7(h&cDL1PB1f$w2G>P=a< z#I{ziY#jM4T!EX&x3NBG{r&$jKj?syRyTfTRSy*kjBRz}#8!PtF(r9P@=vibwj=M% zx)19?R&$2Run$~Buo^d79k|1)aSt9KzeoNG6BZ8o(_;aveTA&%cck8vdT;DsnD_r& z8rI-0JdW3`2Hv(Bn4yT&1+!b#b73B&jMhJ`MXp2X-asgOR!p98TkC98bQ%D&L1E z@o#)#b-){|`2~sv{l%>6r7&F154vFo8v5c$oJ>BQ^?cSVtOl*II^YELKk$mx1#esR z-N(n|sf$PQa41Lc5GrBSSO$AhAHaGL4z;@Qa`LVCGoB(p&-!oH_pRnXwz_cg5}u>4 z|LG$S`i{ry#<{H;^I<{qM&uo_KaRmUR{IuM9dL>DReZZ-kSD|Ut-t@zOW`9dZ1oD8 zTIF4EAdVy-$9g*JxmFigXmx>u)Q{mAt9h5K`mV~zZyVmAA#tgoAw7PGMXWAVl67U) zHLV8KwK}j5^+7no>c9zBeUot-`HoV2|9^zWKk+`sEFEl&V|73|)|Id)_Qugx2To!g zg)^*Pz;5zmc&&6;fo^t_#&l(Z0a>l;IWV`?fZF6Ou_q2BAHsSZ>nN)^Gpt^~HtPHF z*RUUSt$ zVGo|btN5SQ##dGcOAcUkrCvpV2E>d`6&^|vst z)rIm}9asu$k=K)v_y1^uNd!?i!)m~8@?&@z?~p%a{gU-tm4b`JwYp#~t2rNGF{=xe ztK|2;UP&bv)rpkWYB#F^xCSTAS2-fI75s{_wdzlyi54t#9Y_Y7ZD^7~&m%lvWB zkPpjXO>Aqmv7^-i3t2D4Q+N*VSsnNf>*x5|>b$I#gZ!f~59P7CRYPsoO(X2_5l+4v70nFeqWvn~eQZhHH4K`3)#H#^zS{8$lk0%g9&Z73#NH z-^a&R`%_m9=I6j7Sl;^2B`Q;>9TY;1tzKwztNRY2J_aXQU3i97-w!yC{4n`hyopc9 z|6?8VQ|cCH|`l@3s@_ytaaXK!=9aj7HSj~S%{f+hK zr5M$MhS*jgvJb5eEP2A+6Ph ztX2o)usYxq>b3E6s|&WY>T8P~$-gC^gKO|7@?ETdsm`xUPP(8$XRQu=L1WC%wAO{< zTOF9xsxKv`Aumf_1Dj(H9B#F5wAK6_)DL{d_a#5maMbF+e`t8ChSoaxU8@1%Qoe$at)2$td+s{=P%HEzRQs(fI@>rc$BdCW% z4QXg@bzpm|#?IKCd>Z*8+=#o$53oMY`n=Vgi&h6lt1Wf0c$mbt(EI;gKd3PsW}@Na zNQ3?+40a^%iu0&1W4#L3Ssiqa{3iZ~G3x|*TLQt}Zd{IfRjg&z|G8CP zQ*22-ihMdQ!5_&tv);@4R~h-f{+3|s9R zVl{sw^&Qmr)aCn<11@ObJsMtN!g{Lf6{p7nRs#!J4eUt0C-vUg-)i1m@-?^%e<43s z&+mU7@CSu!RtMa)Iv{@iU{EqlW7YqjRbO_@MP8GcFi8 zd+}$h15a4>oyPOz(HjJL63m48v69ukPpsyLsSl?f9?ipes}I=*8usB?@(Wf2-dOd; zYAF3fgE{acEQPhPk<~?-VJqve|D$R64p-8!*6P43tgo|9@OfloC^@FbtX3DwZFNvS z{G56h);(}$q^|e>dJK68gBH z#xXQZuo|?~YS22|V%4|X>SFuxF!@9BP?Ml9nN?pZt9eDO=9M9@+=Tc4r!>}}p$`qi zaR&JhR)aQM4cd)|tS)xU>cEruhWa~AgL(=qZPovAQ@{VUp(?>=R)c%fFbuyV|K92X zJFWT-kRK&Kfv3q|lP7GZejS*}>b$I0b4rE%pg|vFb*sjDR*j!yQ}SWtQ*a6S3af!f zt>&E~|C9VL{F^*sbM@(*a9SSnS{?Y2)u3utgX&=us|{_e`Z{12@+su=aTEDZR`dR} zns<%-ZjgsV4}*u$QyS8?2oB1HrK}DtXEms?)u1-m+3I4wtor)m0P^|d>+k^i&(?o0 z>8>9%@CgksX$Z9p2IjOnpaknO*pd1W9Ea0!K5oWcRu|ldhphix;sFhBFlnoxF{RZj z{+M-D*4?f4^}``J%Ic!uS{*bMza!s8{u^GE!S74Dpo8MI4hAQ&8uYH!pmdmt{A2QZ z*pa-e)tr%57yK5dTg{teHE#hfY0dZlztM0JAJg#6YT&zVf`J*W2EA`J=mX44UXQ#D z_9Gu?HD{XD#pdARHsN64Y8rpUO*CAzI`AGwZ>zNqj%79QeXD_atojO(7sFEIZOD7! zNb<2^KWNY*t3j)Aqt(D2RtN6E1LXI}UtyAVL0@vKd4;Uzm9&~uk-Q34BM|NH!2MPOk62yoIG!SZMV_F2(3jDwFN@W@idOSJ4RZb05i~Tw#x#5rG=wJM zBJyQcgZ5bsI)W#yE_T7{z{_}zJVA#bPlI`^|6HS7P@iS_$GO~;@iCziBoENeBel~rFy@}A_qu|N4-@-?`R z{E*e0D^_#v;A0v2`v1ZO9ry-gbP5`CTHU+|ernZM!)jnptAYK<2a^xOQRHjL_fkKI zH#$X&ihE~h!tiq%qIV7sh=uX24#;P9k@D0(#&*~V`&so3W<3l?S1-k_6BG?++;{dAzhq4}tW33MSk$exHz^nM5^-scAe$au1ySku%MgiMl zC;Zy#z!9v+-~_7!H`Hub>UG~bI0MgaMyjk_b~;4NQaCsTahe)JtL| z>aDHjcc$LGJKu!%qG2RX#}!r^4zNCnSMVV|x4O`4jMqbJT{sn{v&u7JPU;``;ET{_ z1hug~4PmPbjKlA774Eefe9-ELBu39*9UBW^A^gN@UM<%3!aRI#b>qP_OvE|377th* z__Ni4vAzh_@$i3G6suVsSeJD}Y+`j@cqk2%aXzlc!&V0#u{tnruV9@Ji(mXUb*-qmWrWb!$zm$F`KHE)a6yzRJ~{3iL!etf%y!{TMhi!YG76TjJ!AbDC*;^F1VU}8|(e7k66t+)!(15H1M1Y@=qGx`YLEh zWmQjWHL#4;1*@^H$GWN2z_wQX9kDCioL#^P2NY)Re&2V4K9 z`6LR9tqxpnb>MZ@w=w0QAWwsNto9dTT?|WE9oUAv7Y@a#xJ*WV(Y(q99eB&?0{1ZW z;9#8|^IIKQlyylgYjt3I@;*2Mr{hYi`D?AtyE~Zo|3iXwLxP4(SkUUg60FN$1*-!) zk@v^ZI1|@c9k|}=zz3|KV8(BvZnW)}C|vlP;GEJ{{pImvt8==N52ilMYTkF`^Kdcs zHLN#V-G7(W+pwYe z?FVi662mysDj#cgk?GWz;yT=7bWX+`ch$b{2x}c zIxk$$4;u8j)q!mZx?x`&NIsnPc&m#LO{Z=4Qb6$Uh)2X8lF53WW|<8@k{?tBZ`sX*idBq18p!Qs0BW;0dew z=dI>m#4F_S#`^uQhID#xLnf<%xvdT^iIuRLRexQp{)X6ud?@)e>NBn8EhgWLyYbLi zzyCGxmXQePIV!=Y7v(4ZXzzu{TDVm08pRo`Rk zF{f#*izUQlRu@cb)t?cwkbgqngnA3>KRNC~Ll{Tkc&mX?Rs(0?59IsF&r-i&b-|nD z&oRby)pgN$R`cGmnwP@*{hykKGBnhtp}y6?J~*8EXx1~V1~13;xWj7h9;^LFsb9jI z_((>+{y%p?8(w4d?}EWOtZrP~Dlcs{uo-rx-jnqZs|!uWS-8k*|1zun8>t`s&hLM1 zI7Z=|)q$6-HeAD-jk^V>NIZ4NGt>Znhe@%WB|0JVgG0JjVAy9@}bO zQmcZ`A;a=PL#QM9K-Yb2 zg13KAK{tHY>Oz^U8na>!^3TXyQg3T@q2V}{`gg3CTFu>xd+~_%`~SEfG~iEy`}i-u zHCws*;$lLpfkj!DwAx>ddQ)tNJ*@VBY1KEF`Xm|oP4Jl%=2^Y+WmX$j;X3kjNz|JkcDjb+MF~-fCVpt9d!`L-IOv`2N2gK_{z$eP|eo-{N$ufpe?|F2E(^zmZ>| ze%)$b?74v{toEg5opWwj1>Lxq3$i>`qp>E9O{jOpJ~+tgLL;pPkHv}Po5+8re$?th zSI8fPDZHT}#=M{*snvzDU~VjAbx<*@L6xXC#x_SEQ`1HU96g)6N3!avcl6Auym zZgqjPtgo`Z$@&TF*H#BbpC6dQYF`G-Lj8TrN4-R_4u{GRR3PZV`b(=xy z2d}j1+d}RY+}{l0^5*} zC7(@wzSX?dv z{!v!@r^?9te-RCqZQ8?e~B8zc3^|P!mSY6;Q_174Cad2=FtNqEX`Z7_^zxe;({}jqvz49tn8>(SV z^1kF_s86sOIFoz@Zoq9;^Y&TIJA}WIKMB(idr8m`-)dk=s}I@xm=6nE4J>UnusnWD z-j#eX^;%kh(Ot~(U*s4D%rnH({lDtNwuD`TX z#}69VoQ59QABR~D8inJiZ)Ls1YX4E{m+&S&w%Y&9sxQWJsf#4De*dSVkj3ieA6RY3 ziyx7HPTqxj537L#$;aa~{K0D8BCC1Ja25F}8TtPICc#~+feBXxrnTCbk#%0H3zxwv zSlg_o#4xR8dW zxYDX`7ygDPtuA_-b?P<20qHS^)xP{#49f?GL!bCT18P~_tR8+IG=v6|Z^m8Z`|yy} z0T0NtuMOrkz&6+e2jT?lzqB_w@}Pg;%WBX9+)aHyo}m5*Uc>w3k1_VTV9wi^-0FqB zi_%X=e!Aw}js=or(vFdMwU9m6u0IQ3Pr2gHH{Q7?$g{4*(*^9s7A9xcV zS{?ip|Fb$c$@*Y_M$Cg{t@G&Zfx5P!ddIwLgPZUoPs!u>w}Lx^Qi){`wL1{%=IX5E`b^@SWAbh2$G? zCmygGc+_g(2|P{ynmozoAWv>JFO$^|O@8aI|HUYjwHjE(YG5_2N#2)y4D|_C1Lu>k zVZD=lFYDjQui-uXS4RF4%u5$ED9#qC3#G^GRu{@+b)f=Sh`b4Tcj~>Y=1jr))EBef zWHtW~9^bELQu%?^7sjb@R$t6B}7IHnSSgiTVH>hU2X+ z6lK*v1AidjPkxsA1>0Qj|A#cZ4ho@!+k*i~tPad%b+Pj5`#|1T%vO1`e)y7Y-y468nk`Kk{T89au?P7Os{=+`?HiAi ztoCgoKZN14Jlw)JRvTmNlR7Y+)y7 zzCe6J{2Ph*zmrJxK8g5`#9Gn*QUQlZBx)tm&{OHMGl_=bBr`nuOtySo<#pM zNW{${`TGAZ6=W-*kVJyVNHlyx{3D6@a@Bt*ex>?-BocJp?8aGQUvU75`cWkMzW{Wu z{}-_Ui7q9PAXNeL#D(JH;)^8WUn0@rJ0#kDB-W_Bo;GozddOmOidXY%fmqf$< z;@KqHjZ^((ai*9}B0h&iqGcrFpAr8i+N%|?kwl{RNHp9men_I>QPp?*(2eU)BJOMw z39gl2FTaCCyL-hvu|V}tlGE_||0yn@qi4kzNHpBy1{k$sqw1STBpkNYZ8w61k0;UY zTJa_^MfJCnSi!qVS(eQ1tQsp%y6741tUnka+i0}Q8TR%`7EnXoek!Y9v zkzW7b$pSRA#eA`l#6bQ?BH=S68a^-nl|;L(s{cYfDEg}1_y7|9gpr7k6fdmS>;Fp? za5afUlSw4HNt{BW;RC9FOngRsjYRxENhI1qBK`}pUi?<|o{v$FJl$+ApkWWO7m0?^ z3K%O+7Sl<@XOc*?m_+<1_Jg0y);+x`Dv7W?$z9lgr&nK?? zlNeA>66O6=K3t4Y`55`-4srdT$OVk(IuadB7H@I_@O2s0KO#P(`sYa`dY{CAJ`!ui zuSoQJfJDCs#UrX8P=j(F|0B2nUMyZqqQUhf65K-~L9V!1{5^?we;^V6XYpy(zpMI> z#l2!1iFm)AJpPej2o{)Nlo%~uN+Q8n5)CGbSF8R`)h`qu6JH<^|2Go-e?X%DPsH8g zzMZ=MA7lX<91*`)z`##YjsZl9mxL?ZAh@mbYxQhkkBFSd%O z?Q+|lK_Wp6iGf@xP7;$y^q)-f`+o~mu~_^)iGloqMBtyrr&a&1>OU6uibqBB3%6Zw z5(7Dp#6T_)$BL6k9{<;K0f}xDZ&AQP67@^O72+%6yCmAZPa;tRi9~H;=iP4m9wg#= ziKml@ivgYM|3nrb(M@6|i3V9DI)0o)gFlNU;!7mj{ewjO>*5=#-=q3NV&^a2_v`ZH=NhBy%{j=g4@olk&M7vs>3rN`IE4QI328jbn z1P&n)7pwB|;bY=?-cJL`T5^p6tGGx6Ss(aNHqMKL?Uai)6nQE4iv*l z#6^&Zo1pR}@n)6JCNZFSB=7&(?$Vu@8v^ zXOV~>Bo0;mB-P(cI`{una6gF#50FSuLL$M-;%nl15((ZR5x+^?qWUJ)cird4^%28K z#7B_m|60(w|92A$kZ8Ji8;JySNi?`iyjS&4ss3egy||r3{0@>cL~@4eU0Pxvk~37# z;~xzMu>c&ZfJq9tS)482Pa^IC5(!=)kzlpBPTWW$!Fwd)H;W&t{;2A^eZ%7)fqlPm zIg&(!(IgUFPa?q-F-^=M(e5r1@%M_h>Yr8pE8?5t4ifR7lIY*h-j4+&=q?6|XOc)T zh(v>-;&9bptNN+p?c)7nF^P76AdzT2i9GL$ABy%)E+Fu85`mo#xPbxU>0&U60fmx? z4->;xf1T>5iFb&(;!+armXXM_f#mW3p1WXd6+a~rxQj%fx4{WCdWdI;{YeaHFp2nK z;t16zs{S|PTrp34g5>f4M=l`IMiNt0DQ*)#Baz?>5^n)A{YVUCAc?pk;yJ3n zM)fITrg$I87wbh);?yk%(VSBGJbrR$!O7Pdr2-u9-w!??Y}}usGP(!Z{=YE+jFs%Skl6N}NC< z!R@Ng5sSpXh-*l+dyPbYwItf@6~7Z(NW|I3VK=ZJiNHZ(xEQJW%Sa4tJc)+C60afA zZocXt6pO_Y@xMs4TTfzOUy(fi8{7q>S?qMg4eUxH@N5zZMu|}>k0UXlcoH2ah>0ZP z?^XTp#3#iU#WIq|e>oSB=xY)U4~i{fmnH@phChk8P!e&Y#S2tEmc)RrCJ}#~IGIHJ z0@W9aeDkm{RBbUfgw+wo8_LcD-Pzn7Be_X=_BQ6B#o z$s7gzR(wPOkCEv3H4d+qT|oRFI4aUy<6W`96=&3l0?7Pf3Mg7Q&@lm zX<`P6j_)GT;9k*I{j;inMSMr~n@DurCiiP`eJF|kBg8Rctjz@^8b=~gyqKVXyHx*x z__+8YiTIaDB>a#>f*SElv7SW#jU?im#1_@tgIe8y(cMsz-ib>*Z676m$k*JtNp5@~6;%daaMiH?wn`(8XoqMsptZvA=UmE!f{Z6w-dkm&z0Km7hB8~%v};B(^3 z3VcO@AF2FHv7W?08cB56B(|u2P$##3w0OCAotQ?VUAoN$jN~B_11J`ki_eir^b&~% ztHpn){!`U|Bese?y>7cfB-#xnk!L)KJd;KH7A_z`Dv7{b#W@OiO!X_oQt=%U@ta6= ze1Js9O`@l>>pl|wTO{HG#UQudHZE1bB=Ht;E{O(rkx1|ai3CrHFN%LBk>E8F@&6Pz zsD7{Nn?zq1H@>e!9RDM^fQF+7#M{MtNyOPCXG-Nyi7$$)R9{9SUj^tK z|CKC22UR2z98o|QpBs3FI8=-w5g$t;VJeAs8RC5LeiCsHkceBZ^1q3zeLVhAv5^HB z(R(BsY!*LM;8E3g>*mJw70(ebCDHB*68+60F`zrdd&Pw$;tEK_J>5;m|H}$kql&jk z4Cs9l4L%UJljyir^#T5FT(B5PBK|xQ2_}<>PZ4K{nI!t3Z*u_+vc(()Jg0y);#=Y; zB;r3Kk-*a(L;`=Yx7d$Ff`KIBhluB>{un9e>rLh7tr7waiju%?F8Vin3yFNkcclNk>F(#30@O7itmzGfe%Q; zZx?r{-qRE1JpL^%fFWX}com6;6G$Y=B$4QD@qTeJiMS#Xaer6&>teb19*I03l8FBZ zbdLW|6yRsN0lmbt#nIwe5)CJkNOU`i0o^0!iiITN9w8C8TIK7+H^oYm$3I52l?7-} zE!HTYlZA5BpC%3z&lSg!Xctc+(H$fPbg!5vK13q!Q4(>bD&Jt~_&iN?czP+eI)YO1zbRbLh%s=tX06<;zweg*h-?Er#Fa1gGeNb z6r)Kbh$RshCyrBnhFfnN3)}_cA@OMv4W1*>@jE0s{y_Xh+(jb6*CgWii{GifZ=hQr zCPs_DA`yQL$0_KSe#9YMF78i=YQ~i@92KE$*cF&40km!Gl>TAV@Gj#lW`nV0xAknZN ziG;Bv8jcsQ6_ZKCrI3ibN9Flqq00YAVnEN3h<{%ED~W!$_Tll5fG-qyQ1k}5<$Xys z>`x-m6(kzQi@z49kcj&YiMZdYe34kB^5rD*m5_*EX=`B>iH<)~z#j3i*uAgYz$B3% zl0^K4;uYcq5(%y)k>GmqM%CY^`XbR@u7y`fG+SR z|K=(nTU;nUOrpW>Ni=v`<+H>)#Jg0#h(!Fu@;|G-M0|OGuK%y8pqxa53K9vns(h!oM?4@N zCb0?HNVM}i%VigmD?*}vgcu{e%>^X7gG7Tx;u7%*)vqMcV3mA}>UW5rsr&$m zghxoke=i;*(f^PTxBfiQj?=<*;xus{i4N{2F~Bt>I(S1YSNSIScJWgZ1K2~N{nz4t z)t`R0TOaDuHqKSS<>EEsbP^q;kr==;BnI#|aka|V$=?(=kr==>674@0camuD9q88g zc8KGDpb8?zSn)a%9ZV)MfF&e4_@nrg%3qY1it9)Wpqxbe3b9i42UYJk2=zSvdvO5_ z5l4xaljz_o5(CI3F@VM5BPxGV{iT~`1#M!F!EOg3BsvHsF@UKg z25_sGq4N3i`@{kg19*f)`^Us5R9~k0&4X<>@KY6hBesa<5VwQgBnFT`VgNUYx2Sxk zJX4%cVgNZL29PJ_tA4raU$V9EPjQo2OQPX!5{X+#Bao0el0vAt{~B{ghYZe5{W+-_o)1Uyh${|5QoG*672&-i$wb{)n6c9UoBrJmXkK39BH{EJvhqTO21dHr9-0wn%cJWL|-F}ZKJTW^s_97LjnU@=7X z(W)OSUN6oN=aXocO``uL!+HE8@hdCIacX zFp5OKvEq2~8WR285YFQt4Q^%u_@FADl>bTmJBf~77t2&$E^bo!b`l+bs`6dp9@Y04 z;ns(c$QNpJ0V9njk>E1%DwSU?Pa@HA3W7x^>dt0el{Aik~g_r$F#w|8;@ z9e=5cz2Y|t2ps9wpHCw3g(L=i6^R6s#S}4(M1Pqi;#aQuI;*H`=lGpz%72GF2B>q7x5nmBEh?~V4@ zk*@b5k#B%J6m+itkt(=A0devP^2zd><+sW+<-e8Z%8TTW%b%7%FJB{H7pd$2J1W?$ zfExKO`2qPMx!-7ajeI25=yds+@-X>G`9<=}cLcSv2gjchJFfVag8c!->bKMf^cPCkRz0rJ0-3-P6Mc{%wk?i0$l zlh5G>hP;lKF}{GnI*d~y!{#Y6d%R(Z7?--~nl$5)x0e1SM6IR&`yQqwo{)aFOn~juacL_tK?hd4f000WqaKY14#@Z zLLMbgkSEGB zM%9lL}fC;OpuR zD1gL(g5<&SFnPE-qW={6bkO-oFkc0W6;L6slsCv5#hruKVEDx8*%H!lI^6BzSd6qwq ze{_(qg2f70DPJYuDzBEe$c^sq00K!Iwn6eJd9*xUo*>VZXLaZCj{z)I!7>Gu$;;)t z<#qB#d6PUSz#Tv^iT+~bvGPQDl6<~A+g8Cc6)cyR$;;)t<#lpj4>w@|iG)$|XnBf! zx;#&wFE5eXD^*aTf=YS4yg}X~H+s4WLr6?{s60+SPM$1Jk>|+s}9D4`rrkgO3k*xBn0l`$VWb(Q#b= zlT?tUfcf%e^5yb!d4+tpyiOi4&`n^GSfOZnj67MMBF`at{m)ZDsRGu@x5}&KEplU! zn;?`#`!IQ&e4IR8o+)1{UnXA%I@kX)71SzVw>&V^O%O!-VH3$?TUKb`w^sV7CJ5 zqU6!?WO<4_Po6JdB3~+BAuo}a+A3J9f*N_Pyk6cQZ;=~A-2sJ=+^gjg z@+f(dJXxM2&y(9FDp;w4D*0AD*0A*S5{Cb@T%I{+Vv84H(3$P-<+jU*LhDiY zl6<=3xc;Z9AWH%B<$3aad5L_be64()yh2_nua?)y>*V$FCX(0x78L|XY7IzEnLI+C zC{L1S%X8!_M`FrCd78XPzC>Ojuaq~+n_Rbzzzf`j zK_s`4JX$_oo+e)`FOsj2m&hySRq{r8lRP-u%@;!ABWWW}1>>9o+>DklmameR%B$ry z@&9sk*|=K$SdVl@_KoLJn%9nAKw3S0SRN=0wY$QEKiZ=$n)eY zwmNgk`<65&y(lNSISq(x5}&KEpj7HYe=I1FnPQ@L7oLV@BinkV6g&< z)z(-<@!sQY2M0t`tU7jgla;2{SOI5H=0cG;t@;Z6IRc=CyPd5OGIUL|j| zRnVk@;Bjuk5E2RF`BM2hd6|5xyjtEOH^#gD+o4?GPNIT%d4fDkK3~3A zUL-G-ua(!xYvtYvZvQ@#`-nWkb=yc(L6QQpd@)CKayh`3EZ<2c_Dj~^)@(6jN zJjrov|7;cHC}4%WL|!Sck~hkm0nRzi{qyi~qc9(cXmK8VC7N+fyxPg22r1!T*Y$(PI5$;;$5@>+R|+?ebp2qw8n@p@2$xgS=55l;n08OkxdU<#FOsUn{Rp()GVa1uY6NZqOQ# zTmyNGJXW48PmyQKbL7k9%jISAa(V3yy8iE0fpMdo&`V+sL*-%eaq@WiTKPJ8t$erK zcaz&+0Ezy>rSi4%YI%*kN!}t4N_GbjOkw~r@>sc@qJrrv zSR!94Un^fHua?)yo8&F>;G5lqAtd(^d7ON@Jk536$WuYS0#?XNwj2^n=qV&$IBDsner@ok$j1~TwWoslh?}wr@H+Ik?22K9s@ep|0ES8D`37nTfR)b zTwW$Gm)FX7%e~Xwggz1pL*-%eaq{?Sy8frDAX5QLS>plLyRj6IvwKP#!H$mZ!+`vg5e^ zr>G!X0Xgzz^5yb%@-q2ud7V69mYdKbxryY_@??36Je%b8KSu>63Ro$xkXOp<$gJV~A*Wpd zzzpRhk9-a1&Z2 z5{Ano*V!v-<@v0fID^l4^lxei2+2*W8~xH@$xizx;$ULSY9EolsC$o$eZx* zQrzVZz;`wmlJW1(&CQ&bH7k9}-Bahz9+@#JB=X#IM_(}df(xReimPIV1bL#1U;fsA zm>ts3aDJkk=P<)GJZ^!Wue*NouNTFI1}=&Z4O(=KchL>LMYjhmy4zYbD{xV_Vebxm zZ`k|8HV@lmj_{Zx0(zMv0{faHf+Nilp<~Pu;ls?^Hk!9pnzwB;Gpi?=Q`eib-ZiIw z=*YAU=B-;yd)j-ZZJ2g~W!mF>x$AwoWkI>=p}~Ik-^{yio^s1g8-M8lOizE)4CsZY zz`l42j>J>w7(9g!>wjVx8P(?84@1mp)f$YA(VQrA$Mlm!TBafG3n=RF^FJD(ebNZc z>eo+96y;wGs-%5TzV*(HYQJqDmhYf*A&;Fd4UIoY8> zX67-&JaE`kjlV~?oYS@mysTXg}{DhMsh!7D>n~qGPiwXZu`t^YcSis zHCwlutvgNI4h%Bw)tkHQdopv4-d$tBB}hMyi>942h1f zC=>Q&!oJ9Yb;VP95JwQ$4^PScIE->UHl<>X@%Rks8u0iw6>E*h&Quetji=-w+sfS- zlKql-+FOi4wzoJo1UpmE?f4X2cRl7H0NcRAHVDKv2-@<6Gs55>jIiMS+&yOQ=MA~L z&_zaQUp$5P%WX5vycateMsAy*nK#;5@S1tg@O<(BoT_bj{>cGg7yO9< zyoX)jm(4&IX8?FUc>qq;Ha!2-0Br6AKQRNpcmQ5!0C+xm08Z65JpaT1Y-cY#^#I<( zzW>W+z|R=~o=+ZtQ?(7xryc{?xsZKIB zuCV*McR0{+HN%<4!kH!zXPO|KX@VDJg@!E34h=OkJZ46fIcKOj_dA^0E6jbn%sB(h zrt{PbgU$6j+sjrr+Lvt@^AXMAtY zJrZrst@4?3x8U&sdj5&njDzOfj}US=+T7RnztqD1@qqplNq#1W{lB&*Ka&JG?3ke3 zjXrbnEp5k+nQIb`6`WzNx#n0wADb_+I$mDQj1fWD@6C+CArAUS5Oc6gm~$JVJzG3g zcrlTIS9%#+%-g^9nJw>fDcX3COVP%gu2s@n)|vbFecJC1g#zi;dJj^>SBRkgb@*7q)Y>PR$%nS>#%p0&dlGdaB{08&1 z3M?KptqSw4GS5LQW4L%d_%R+Eu^yjw!@Gk)hOtMqztMv88`Y>t^LGQB->8PqmzzKO z!IV2cUG+ohgdegyevTdUc#a+G-1*qCZrzR@>(OIYC;an<{2qzn@qFL22cA7RzZ=EY z+e3TWqvl7SkB>+@zGK0=7QPcf#jH8M87ad*^@z)&VRZV$@Py!J!h{(9jC6itCh!N^ z{y;%YOw!1aj2v`Q_=F_>u=xa=&rUNupJ+31`%gDIRgO*{8Xf(zpzTw7;XLkIL<4R3sf>fsqc9UeMj=W*_sVe@D%I%Xz zlsaVI8})H5fJnm7t0>ogpLi=Q`d-VGD6sgRUAmM}7jd&3}X=83uZnR&y^nKz6= zl+FEtyMznu8i>U5K<-Fx+3~9Ox=;)mTX@u{OD1Byv8g9cjGr0rhd=qk!|ED5JcIG* zg?|mBm*+H3C*PUA!M@&|QH~o1I1>5eWhj0wHH=rf8mj!zj*4zctW{rdh=gw}qZj{LDtbGm8If_TX;z+^jpY zrcN_P&b@oK%QThz>vhkZHYL@-(>?mRKtC+IpuOT;{IGr+e%!Li$b0TN@4S2N88had zd!~D)|9;D9{X3sOW$xS=T=I98My6+EWKz4HKjqx%b29GYa)6ePS9Wm0~wh1Q8gktZ^BEIpB`W9f-pJ=`8<%$e?V zdfD2$`gNF8swQ>rZL>0uhx~Y=FU!B8Z-+Uc4t6_cvniQ(WTa=zoQK_aWNc)_dFPEh zF})1+Ve;G&(MHln&YLqeeb&r5Gp0LjBBR>du!qPW_AoNEw~srQJGypbisEnMLQgMl zxO;BrV*AN%eT$Rhhg-!BuX(NFgv+nCY@aa;$7lZWW6^8G!n=0x(eUMXDd7HijjnJ{ zhx%$9=SGM65_k<>TC~UC0w3Tz;pf9gx4Uh4jlDSV*YQ=N^W!zv!BMOqukkQEr-S1k zzQU`46ZPk_zJvR-o@W&2$7_6wQ(jI7|2t2C%7F`ROP}yGymdAGRt%!WCJskA~SRU$nBH-oMo(#U&c7M9^tZanH zIMfTV%$MfwPgi3I7I><3f4UlHw=X*ETD<->?^(rV*v9x5p=NfdJI&8)tb*sLjNXc6 z4wyf5{ySZ(I`~2^Yh_u_e}^llgZIL6Z3j=ma*ihNw9C<;H#S|ZW|tj20I$;iLEi&U z(EdZ8giXnRQ-?qB;`NVuhMoQw$nh&HxKk}ohtX}vVG{<)bRO;smP~&t< z`e4P;C(AgY7>0ZO0lCiYdrT~rJ6@~WC!U)Qt8p&i{_x-LiN+$w$kt>{%-88-epJPOs^%VdD)G4>t$Wf^#E^2Mp^L<`>eVxax~5 z2H3gvzJjPw=T1ddXh1yxF>wu~14SxYm}VeOsSz0S4#H0`J~B4KxFI z>weM%G;c7Q@j;BH!E@BpoLgqitLm`&&Q0L!(S1Nc#gXduwcY}I!;u}G5<`8+gL~t+ zC63t*z$4KQw{Vj2)NzJeE6mm%X6wgh>p@S&e0&VC-<-QW#B4p}E?Hb!aQMDG$ByB+ zZNN&F@@Ow=!HkH-$5G_gPl5KFCGU|F*kVB z;IR#lJ*nnC+tsRGEjTWD6!75B#=aR9TJTox0l$Lg_Pw$T z_x8CBy1R(GjJSiD@iF(!l+9+EbM!Z_H=957Y&SE8-~$fl)}?bNaw}r%o!GCO*aJLM zG=FY3?=zdr&E{>kdEgWCz&qxQYIDZB=7Ejofh}h9MzeW~*;-|`e#Z`fX>zl<)@=T| zy}ufB#wPQ?7v_PzX7d+j^Io&H9*4(C1GMMRxq`CE0LAH(01hYc}3$jAJ1#cCkhXxd8v=!j!anA-=^-0d{ z;-8sp2K?L%|NQuE&G1jB`8THZzcCd12OHa&%h^9Omv82l`3hn}>#l1(b_|CWcUPaM zZV~1!x7^xTg!7QkxxV1WJ5Q%P(c#oH!ROhq?^2!fa4yTh|L>XATg~d7wpm?kR`2Cq z_78&`f@A?@~ab%(3hzcVA}INRVSXY8a6gUDMu%{XgyLkxL?K8V#-6cn1Rz~v7c2y07uaPsRhcbYc=Gx5b92WgbH^?&G}V}PupbW7 zF%@@Im}|PAc{s)$kslY@-CWbvT+^#C!0()28Dln>YxXX<(jHUy+pc4_6;zp%-Za-F zhIZ$AhHc32g*IUrP6XSVYvM*7EARtG9xL!*Z~+*Yg^0l1@*uvH8&kJngVV{c-rV;p zJhwg@tCP7XFEo#@e@a91i6xl+XaUT1MF+fIbF>;zctL1CNrhXY<}CE z6VM0WS~wjg&1T9wX7grqPT*ve{2C=k&6E$!=8rs^J)6uqXSwaZH&Z?_n?Ez>gtoV9 zF;jM%&0m>w!rR-mnknCy%?HdmQ6_rofu7pTl*4B85!rh9KSdNy<@f_ONH5t7l1g-kC?6Bn5~GcH=EncR-9noGh07!Vyet$yh7Y# zwjMBB4?8i9W^=3AT5h)DY_OXRd8NeZV!PRDf7TxKo!R_7zDbf|W;8ipooVK)GJLUT z7S3zc&i7~Vk<~}$v}WfUM_o;O3SQ~kc%eTTUsGYTa&zjJ<}7@6wcnh2#GG}&%xE#E z?J;j{!)eZ(_NIC3A=922i#Fp-du)Pf-<6bG=CyO*@|tt-+1Mo=H-Lo+IiutJC!pZ^ z6VqSedEcB9Y$NmxsqfB$nk*NN41*D{tDc-Ld>h%7cCYpc)Oqpr`Js9r3lWkSvbee&n?eB z{&tz~mZNZL4a2LfSVYF*Y#NThXq-_a5FAsyzOYA-J@4qTV{hYqKJQ-ex>67mS`Zf+ z%0_$v$5Y#tgtu-YB5|4z&CL!SXB7roS*I6Nq2Dm{>0CB)%cGp+-b3ihD8y9`Sz-(D zrHX=hyky43!t*9_`*Pp(ok-Zz$ynFWjJ^?3d@R35Q17_V5DcU49TuW_CwTEA5B2D6 z|I$mvf9OhK|I$mvf9OhK|I$mvkB{d6r7MN~OD`4wp(};W>+~jcUlRV0uLw3@#knuOoJ+$0=1My!{}b!% zp7}E?dh%SKS>bU``4{}uIsads>8C!|qp$soPxOoa6DRu69=x>FMX>K5pXj@}33Z}> zxJRJPi&hNI{ZWXGE{uxR&Eqk+mDYp@?#?y8jWXvhbPR6FrQlXs3T~`5Z$_zeTRH|e z*HVt+f!l6)7x10uTh!p|$_v=X_jr7Q^3UL*yp!$p(SlOkplkjLxB3=@^WL`8Nh^xK zLGb|;M2%)?Bud)wIE>OGxJ&H~W$FER^4^DH-U&a3DvUJ48;UPHuE*m;JTSmkro|n> z<{eo65)ZU*MenU_P>%=tZQX!deXaQBRx8HtG{CLI=8v(A+l;LT@IYdxK_kjByw-9& zHsOKMv$JO0c5KFN%GT|8e1=DR{C6nFy4x`rRR)GP6(gI4sk8AO4JA%7Zb(kGG1^%e z0PkZ?#VBX-%g(qhIu)axg#obbv<<1|t(ai9Gq(fW`=5sHZpE!oesy{p#(OKiVaD5~ z)6m7Ohp=3SZbK2JAbSVzRK2$ zR?f6>I?-b@*AlbQip7}u?^orPhw;Od;wK;KajD;omf}wedxZI2)Kc8}p&mE*)qY=` z@(})x=&RosKlpHu0srp+{C@}F|9=j^=>E7MMEA!r9NixWGY_-q{y5Tkd`0)i5zGTC zxPd<9i;&F7U!^ipUnZh@U|MXCgi~OF^L3FPUqL3En zAhMgkciy;!;EhWdZfED{qXd44iF;dkFXep3^^Tc=H@8W6q=c9mX%W1aIpaI?z;>L8 zPW8qbwTw!yE9V1ayWs4r!VHZeO-Jqr+SN zj0D`oNJ>IyY3OYJzuVal`of0No8k5)_r0)g$m>H?`)8*ZFW~mK&+m!XrMSV@Xzp*H z+2gNEJ5H-+^`((Mh@`;@i zR}~ya2XGW+@Wnt9pHf2bloo+v95chbE=`QnAUGw;s*8V7hFP8Qy4@VUV?J~Itp>G;6B{R^LY`z{~9&4BMT@CyNDrrq|r z*;Z@6&kySP%b)mOz=GP1&d0|1dI#^v;L~IC&co*I+s()_yu#*(2iE#sU3t46FD=YD zUz=0E!T&m*j(?fLi_b6PJwEfxH_b0`fBG%6^?md9T90}A=N_}w+r@0<=NY%x+Fel6 z#oUIEJhsK-V-5@n18ZAv-cjW>+nVr6$Hh4~5#I5VnQ_GZjzXJx$47qnbbHZ>ub<$f zfyt3&*JDWhRb1y&gu=)1she@%(KdVw=gzZJi_A9y$C@u~zi$J-&9wfgf2t?&GJIN+ zYd6Kt+kMNFjatR^d+@0NZgih=jc}WhLp=2wVXe5jHrCt5!tsH>jn19l5v=!N{y3rT z*K#dJ_)v-rqF!zAEvqKA04Od7tY%2KR0X6mn+=gF>!v;&jGb74lV-`*_WcmkgzqYxYKk;NoquMAqPxFoMt8?< zc4Ei+g)?NoZe||oX||nWuSzZYAJ0hVpPG^51Lpp6>K(_Okx<-c4Z?mBjr}DUyH7ao zit-oEcvqHpY`Mb+{@{B#eawtte0&)?>Qvv$Iq7>acFM`$%el2MCgX=+g?a7=Uxncv zUYu#d3%kt(AHbxzSNCztWa=nc_==!#Eoivt?5Vch2Ep>5xMp8n29)O0@j}Qs#7o{wMxdkdVq)V^cIY50boJ5mfDQHga6YV7vGW4vrwmtNz%9t%Uy zvFLT&unh%O>yMrlSv9O`Q6Hp@Ghe!&L&xj2@Z9qFjmX5C4^CEWi9` zfv+T;`Ws31&wNA5^R=h$huh%?UrE}`Rlxe-mO8gX=?}I;Qr!wT1{QvNMQ}q1^BVc~ zu(#d$jN|ZaenlvzAlaFa*t!;cw0_@4te$~&iNm@@p!+DyWb~rnqtIA%+TjfzGw&sw z7#6*pjOX08PUgZ5SSa`?_bba>I0bDBw&(8gL)&08uZ$acHCq;}T7u~>beAJQw#oF` zg{w22rKrNyMffIU!Kwf!jDOguATy+JwS{lD6=bFtt}eqjU<)!c3s=`V@zI5=tC%Y@ zv2b;)vyg-sd?mGDRU^_Bu3jF-nrsu1I=l@WOAhE-HM{INLB59xg}=DSR>H3{ zo0eJlViCU1T2R74n0Xg6{fqpIo&_Zqy2Cy?sPOen&PR0N>k$K)e||{e>pA$BCJN@K z7rxFv)K)M*^YDh8tWgUOn|Zr9w%09=f2}i~*Da2RZI%yEo18P9Ho3dJS-}er&kHF0 zeac{z6glhidwzAdpondqk5;^)&PK-Xu5!< zNt^4xy|v7|ap=8pbpkFXd#~W4UckJbGlY|{mV@2f1G`^)#fuI2n91EZdtW)xpyS?j zd`J5qj&sBhb}MIyPvM(LdNJ5x_uYFDii;n9b^Hs(v%h-y<>EalLqm!u9~#qRWJqVD zQ_l;#U(|hkZ$Ip)XLnHSlLMhX)j|gqTX~nCabakOQnVQybv!5-lQHCk`k~EGXnTS# z#V^-*`vr6e@GpMs_3>v-i|ozcXNv9O>1`MzIvbJBSVlSv=weiqN+L#joW42_4H(}$ zq&uS{HI~lfA^3#`x1MsY(l|9y#kc2LXB77wb8bL!?4a)E5OjONiD<5R^ogE0?lEj$ zJpApX;l(d~9NyUzQ~d4r@W8Z-`+FjLU+ejGm!$4D;H&7DXzh@MeO%hz!xiDcV%s%VZzZN_0L~FOexH`T4 z%kN&#;>+;u?HLHWG7yI!e$IA&>lOh!abS4|N1&*ar^}}}!}t~B$vfn7miTpEIuRwQ z*l)c<`Q>-7xAUwyS%#mz1K)c0hNm*f*Lgg?9PYOS2fR0OzSEKK1Drbic6(7W`gcx8 zUHRvj{QinO-l%0P@pipt0!q%sc)S<=&FQD>Gnb;|b$m;_^9AGGm?M!W3H=qmnIFwu ze*eVGb}8J+Z$o$TcIMxl@q7Oq6g~7dYCCg;e39IR89YW;ug}{Rrz@;j<+(tB_d<4e zBL>>_Lx%YE>5H$>M-E3!w{Olfj3wPnPd!eH{`~!zZkC7r`3*AsdtoxVo$mY!tKT56 z|Lx}?f44K_KL5$XQQb!x;QwkkG)QXs&%x=mTVH9Q{}JpA-TFy`{A;72XG(+ppJP|S z(hz_Cy}@n+q@n&huob(VMYS=mF#iMCcHKf$9q#`Ewn?{vo^x@z6*Q_Y%KB zSNSjMg!%6_+QZ+%@f$SO|1fsYZs&Wha&(;k46ekbp50D#y#MDHK*xEwVf+Rq`v18< zbi6dlzmByNq{;pVs1v0r{)egYp3|{~{02?;U(KnVgh3ZKjUCd%j&~BK8{H?JhVs&Y zR_qS}-CpAa^q3TaqSxKIFnX-vOs#XL!rNmtC#uZdx<13_J&0}Y^Kv)n%>9My;p{>z z<^JH5;vZRZONXMAzmL?@c6KhG_e}h*PUi(E;Y0ggC$BdfgEF6t!TudEmcQR*752o} z_^t1UU?QyL7hw;z_y;ijtTi|;J6YA(kG<9yEO#~nuEi1O^B?>rn)RA9Z?@q-MEhc| z=`-dS{?4)JXAklkevI@FWB;dF-9sXA$n_}4)wBCxju$&`kDfS!yAQt%71(!sq+bOa z{VT_OJ&JLdb-&Q6}7e@Mz;WFR*dR+HVG{tb>DkI#D@mV1t6L;h8)?iV$1ComiE z(!kr}($la9SofU8^}7Z8yJ2NxSM^v|;h^%fuEmbn$+{TFn%5eOeWSDW9De_#i?!9l zfoS~+J@~A?+*z%jI7#?hLFk~nbu;$10PD-qSRv~lama1miup6G=deDOwH+mPFN=SO z=QPVR)-ZZojaaonYicNlY^}zDbB47D&wZ>15ffykj53VARw)M8&x%8aGcEq@&0s44 zo1nkd4?PU9=AzTHtU#|}gjhM)W6rh?U4l!UwG@$qta@zbQ0p4B9c<0O^AK#y?zoIu z51fsECC+*(1pjV;^#RVS=U6^88*YWh;~#Ug!m-{XtV(n@(s~19A7$~cjYn9cP!ehR zu->Ds80Z))2G18-Hdf{$%f1_< zh_OatqAs@fApIrQTpR(HTHj(2WrpRC0k6kz1Y;v_FsyH}XK%y={uPzpo|lyOz%;_ zj+HsX%ED{EK2`;i1zCNt7JaQpoNX04jN9rd3?~ zdI8U8Tf=ee479@0Y>;)%P;RVUUAeK|$MO*C9?bDjYb5rtFzXt0G0d8V=X0#3NHE-b zCY0N%)33O#x?v_pT0=3cQC22aFT&!VZHTnSb>p_;A1FN6s>4w1D62Y_8>8W6VFE9<`eUG%Sbs(QrPf09fNhm^g|n@0 zi*&ZtOE~RqG_1kcQOXS~0UP*D!&-;gddsj%u!Y_>tfgbI{uPE*j~(b8!+IFg`mSO1 z#h~9atZx4J?L@;Gj{|IzVa-OO_YG^;2*cQHSgo)s!%7`w7+VbMI!x>bICQa-euy&^ z2Da6(>M&v34C@9Y+-_LE!*2AEVXc5w8&-D=?PJ3#K-wug4C@;lT%Q=$Ds2B6!+HiY zy3?@!4t#1@@AbjIKw(&S2jZ6j4QnIver{N`!wqAXVV#dj`NFV@vAuU=OxQ)gG^|H4 z7kdmVAEW=uuyz!;&c5YLdod#G4QnAT8{Zh#f1%I)hQ+_9djN^B|27!b0Gy$|#c!Em z1;4{eAkjg?`XkV2SV=g{4jKHXPL0Ecb^ZBFn31{>q+dT z-y2piHeick?Z=F?Vk|Z`dYfV01{^~S)+NVd^~YS?=dpHU=eXZvo#(^5MvwIl&||%eOb>XhRp{nHk5vogd#tChZx(p0T{xJ2=ds3MmtTZ-ShK|*E29hE7kR8? zZ1aaa*6NE4<6$%(jf1SnW4(h}f5c<)PsKj!v4&z7$jR|qiP0Da_;nb@0bYw)$pw8O z7zsFeAcg|=>4&j^2sa)C=VE8i2S3JS7Jyd{!FWLav5!Td7klYq@MTPlU5JH3oX;Kt z&%@sGFgO8Qy$GC*-R%)D7{hxM{0;Wv--DYlKTE))Si{G_71+#=gS@sBgV$k8Ed@h8 zSdryk>yL=L4?G|J+z(;9$*Dl~io8yTbccjR0%6}ll(0#Fgq;uw0xA*^0-^x|1jKQ9APA_a38Ib42&1T| zQBj!z6*Z2iI5J~YbZ`b0M^qe9aYSSk$N!wF+o4gv@B0I?YuYsIPUvO-S%&AU}(83-A%N@LPc!fK|Y2fYrdRsD$;v#poTk0n^<0Z57ip z{cn(N9Q-gwxQ)Q!Q20*ZURd%j;0##!ZicgFY6FqSAh!ZI0(SBCg2G)@^!#x(Z_BkqVe4Vd=u&23S2wf zfABJEDy~2)r4JZUg=v_z1U?f~%Srrj}3DJtYh-Mp# z@M+&jWH~A*Co&4{q=%LH016!l|I;pKj1LfQN8azq)Kk%O1Ch^BIl;(N=u|0@RZ!b+ z5Lt?P2u1q0#?)_Reg_f=e`;@J^!-}7zn{zKXG0;3CsZqv4i!>RDl~vV_$&Ke%07bT zgz*~D?MMj{b|TNis)0yjWRAK=uS$sw>c*wU3{)FzVxe{eVgJAODMtSSCblAf?#JlZ zkU;cCQx?!E?WxG17$n#=-;Y6J#FF5E@eRL!eQID}N_9)oQ|| z!ZEE!!-L(iml1wv>W6pLC%UC4=nFa?6Akw9q0HAv zMW0+aa*EM}>4$5bDg-pFKzqm!|J8jCjW4UBaDlPn}&>VF?OdbBreFwQZxoy;8m?3<` z{aI(+A**5mGX7jL?xO4*gnl7$d#eY~3c{x(G!JJR^AIiDegkPm`2(LHQM6Ftr3lL3 zge46BjqSsz-g29DOWl~!w_ zI>^E&;!aUJ(c3{;drt0D^%%|S1=?%j>1vXXehfZV^Gj75whvF+%gHTQnQWq7z*xOP ztz#2RBweW{Vt4{A(Q%h4eh6Gb-Q10~x-d71Z?e?|tbY^R&D~TW!R! zRWGp3R$rs0z-J z-D9ii7!`daz)Ep*_u6WTDFKV?=GNJ2Q*s2nsv<}$vifyDam}_6?JhhNz+`I$hr_2& z!WXgnz>|K`yFvj5h62@;_3y(kOIV)-dt)dtgn>-jPlVZ46E@CpIPe*?Xu1qFwcQOj z3H+FYmKvsQn`<{)Y8@hlTT5FEs8zIdC!rzJ^LiTU=ccMEcH90E98uHQo(hCU)mv;& zCtDlgmzGR^hwYzsxd~|@B#_#q0T`@et2nM zCI)0Dx3{V)MDVo|oTr|Gclfrz5G>4`+ySa3wcIG7`RY+vD14{T0yPv?3vUVV+|$V& zq4-*u@Bm#M?l<0DDyYW3&# zpoev+o4edrh3u=J314Na47A_y*TUD@>IB>SH-U+0wQlY@TYbk?@U8B>Zf=#WUh5D3 zoyc#nRV5mxA9jOFbOiL+DbzMaZ+5!5=&=v5s11ap$G*k-3kgSu<=b4s4TYn_?xFrl zI6CYOj%tmBqr?7{jU`n$I_$6>EWaln=&>s?Wrw4}(PQ=a(=2E@WUZ|Zqkn~41h3Kx zqX+*?`Llx8!{~1AVOuRkUkJAha?i-kJ%S;JGj6xwCUhn@_o%I|M#S(rlKwGUHS3G< zH#}B6j@xP;>w2Q_leU^q6J8?xl&x-K2J`in9IC`oCuq{8628h&Ke3Un2|l0|ToaXBs)q+iYqsUh|%JZq=J>s#!QIDSuzD4*(M|EOnd`S2vL|~O{4`QPhCEDVs zB3fXV@U4z2WtG&5g4-O`loQRLh1WRhMpn^FlHPVl`8zwo<1fLNw1ztz)r1}CbrIO* zsLxnuZw0x3=jQHqR5z@~!tY6Vt)pt0;UVFB9Cegq)Mvu?Ix0kq91#Wfp+HRU8{u`1 zuZ9QVaZ)_?JL(Bet3L}r;HVF=+6t$na9(wD4?1dQK6o^R{m;!k*irL1 zK(!Wr#8D452k$8SsH6Bf=x`6=$9zY<&2?8F$>6x7P7MN|Ec~RS&S?aGams*J% z`ci>e629D3BiJh{%=n$V%2gk7id`$=YhCp-+t97T*SV?@2cx@FIAprHewC}1P{Vsu zw&*I@=&BiPBo9f1O|BZn`My^87S~L}dxdXx%{=@@3g=-rcblue;yCcGgzt4#K6}mk z!uPrAepb<8!~NVkR}JA(?B61=-&OBWp<}`ixayU5;3tG1bk(Ko1zrPFC5K$qo(e{V zA9mF_T*@^Qe#BK%hJv>ie$-V**l0Uy?z_3iT(yC%x`zlHcU2)9RsRN`Ym1z8RVik? zaG`{sa+Tu9cfRoD0rdnGm@0f#Km}QVS;E%_RQplj<-*rtLL30Th}?(Cssd^m8_}`` zW}w*+P}Ll$S4)JA0rf71%J6#On*ypA=9%!F!nXv}(^2qk!nX$0XIvURDSTT%?PsHW zT6j%BZSDa6QiHEsWBhS*w+B?1Cix3I$ae(P8ut6Q8f?<7epf(wEy4dG3G5E26gHxd zgx3bt7B;#g!uJGJEiLeMgVwoBZ*M@|!bW&P!uJJKh>bW9dcfBi)&ujaBm7W6Ww2Yd7k(J=S;C&ej|5aJD%4l_(SW*>Rag-6 z%e98b0;&y7G$v%K;CMjIVXHk~BAg7U-K>JC!cPTMHa0%OGlee?Dt?bPe3|f7K{a&{ z_(I`pgQ}A0Efc;jsQya}`@VQo1yv3OZWq2GsNQG>{(IpYgQ_*hiTj0b3aYm_9Vhsf zpxVRPvqr+V2Gx@=ZTKnS+k%RplMX*4ye6pPD0$d_Q9QN>)l4zD0WM=SPL_4XRDF@VCPE1=T;%=KSyv zl0aQhtzoOT8%i4pX3bnQ8}ofbqtF5Hg%wsfO~MZb)%-?~&lG+rs9s=+S_nT33vwuL zBm78EWiY(6@S{QX?jWnw3ilF^V?kBT>9nt8cpN6=z%y9FPX^V}PT(Vjp9-pCO!VPm z;mcE0b5_Ar;j2>A>qeaA|FJ9l7m0sWii)#0T`7D+ih7#^pf7x5iW)r>e2wr; zDXL*1_$|V>q^Q2#!8Zusnxe{>-d)1CrKo(?+#iJ3q{QF5ZbZ6&C%f#U;<+P5HKBEO zG`z@k@f5X!4fZ(+uT4?kaY%SYjIk$0pRR=eCh~hzR0I=J_+62&OEIT6{}jGIMeXM5 z>t7;&AjMaFt6=zZ@i>&C#?qR{B!eRpTnwt-5aLZj3ytw2=+^$7>DiK4)U1}dFBbeiyu4b&kjFk6}S zx~YM>CkuSO@Zv2E6yH7>UMe128>rfj;MYn5+Zvb?zLmmj8sI$4rje)MY$Dt43};mT z^rQr-^L9K%wxbaZKeto-og4EBAs*Wt?9TJ?SE@Cys z)j=)YTwTRl*d%G?s0y0k_gW?Hs}!SryTrw*`tKcZAyN)J%Gf#Dhz(=;EJ83CJQ+dSJaW@N*OvNh=+ z2waFDeMS5xIP`+5B`zIPf@>oai7tp5Ti?X_Gu!6!`i#&Tc!UDnbjz@LcF6)50lE-$ z7!YPiDDaw=MLJf~_fgzHAl#x6r%lzq9b{THV)i_zF5?8&zR_r1oB$$zhlm-zR&PAy zP5RoU3&!>08Ks*HAyXR8c}AR)NU8%o8h!$2hwzh%{mrzNU1zqI7tUxcujtl-^Vg6* zkq-Y=ne*sWQ{!(-jYmw4zoV0N&|35^rwhot_AXraJPkZhanK9SMC;0^_Tz;Bpq^H3lN z6NOp*p+JOAZZ6=S3_3YzYju39AGpy+yQ&caDZS>Nr=46^=u^;(;Lxr5XR~v3d4l6+ zi_z$ZY3+v~g0m0fe%kFT5Eu%q!Ed&GFMf4tqdJSzUB)@5IcBc3J08`-Pif(|PYcJ# zFB%gqC_Nh@@ei~JPoT5yAL>PDLeu-4Ie8G<7(}BF1sdTu+wOs1lkIcy@n3hy@|{ak zAahrLEi+ilOs$t;VUw!Xd2c9Wch1qW^YCkGubT3@N_5us`5PrtKg5b+Rod>okn(1s zIix+u5~KTh!+K(^p7uOLc(=(2tp3toFs#4|GV=on(&imxIZP*Q4>N1V+e&++r@e6_ z=4{XD2LCr7fRkw+h=RTKs%8Q2KID}4_E(yPye|V_`wdI={*Bden*WZW5$|5iP-*WP z7WFnz^zW(%6V3AGlN~Uuxz`&8PJ1s$hvj(f2ZO!OtL_+k)91{aX{CL1pJpArR7!sQ zN6or;uVeB~J8W1F?;9%miC?D!dwXfnG3`^s^3oU2m}RAX{;m!ikj~dOr~TWoiQZ=^ zko>~1aNiPI}V5G<1`le#zWQ3(q0x&>eRABBc7YVf$=v8Z`IQjv0Q~ z_69>N?HfZ++1}V}(Ek{^!AZXYm%P%xHM9n_Zyzh|xS@L-@9dTk{?5>Yj(3bnoiOyc zy%K?|M8_O*>`iQP<-V8&7NN zBCQH|9#-sWKWAdJ!S+@_y@Ot!mTEWG94B$t3Sbn4pN$`-0V*#Hw zG{GCHPBCOp#BiB#~(qG4Tz zYK|3L+LQ#3su$5O(=M>TG8x3w&Eyvf-yc&m*&!|xejuju$)^fG7*mC`z{NIu6ZT3D z#njcT!czOVPVjI{HDn1cu{pY-O=qhAVM&=b({7950ZYnE^-MbWEaB@i)m#=}u3fCd zt1{I#W_X$K4Vmf=4wjeOOLX|gOm!B9JRx6&~~L*R{ZwOqGd65I$)1 zAI-OBs_SUNg?1R}U^6CD{gFe(BH=Ze>SnAl(kkt?I(&PkdY*i#gzv~yo0#Dh!gpn= zy58Vd+JhmFy^`IT>J-Q6-`N-I1Zp$Y3mw3(622!>T?o^pU1P7*;d?Vx6ZY~I_Whdg zgTgp#OuNqhO!K--)rA&ZWoIKFH+O%gYR3#$+xeOw$W;5-$k*62dh5NCgPH0xW^jYO zMhhH5gdFgj>?bupoT)Ce!Ed(T*8E7OYRM|Q#s076M>Ew1ocE-~?WWiOz-dLM+QK$; zzn!D`@l5qTE%t;xRr6Ds>gfUCPumZk<1@mlCTbeHNv-{o7FgRvjle=IZIAtl=IffM zl9Avq+bL)Y*xYHNuE%+G+FqN3shhi@iR#=K{59blo2c#)@O{EJHBlF{-@k41>;!wP zP1K#xJncQZwXZ$4Hc|J|<1?GH59+vyYDSHZ=#?P0otvm{sL(NcxRyWKM7_!kzOiR& zeyoW)#47pDzCrWjO;jx{c+$RK^OH@~xwOy^_9L2~YNA@O%73!`X6WuXG0IY>I1ssx zDN$9HdX+rj7>ze%sXw8pX+hx|v($X@6yck))Mf?VK=_s{wKEMoBz$X@>dqxdL*d)9 z)MGJl<%>s6mU@&XYUD^O&QdRr0Z$daBTGHcA>MOLFW8l(PO!vb;k&ccR}4=RUYn(w zP@#zMJy|NwZksNAZn)5%TnWM@=T|dwn$x;dXXk-BD^YF9c6e^r>6wXR!7LxuKeFmW`^VahtHw}(tC?(@OP3^(`qd!>YP7(|6wp8QD=mb54&Sgz z=dW6fHH=lBZwVGm|3-P{Sw{M1RUNGkZilSKFV|P^!T*qQG~S9AzaWTmW>E$ z6^~pq<}4q~bb%NfllE|oz@7v*Dy2aMPLxq?&^A7UwFMOBmZaoe$Z>uX z8%Gi@F$ASiJ@o>=D2qNVy*$xADtZ^ zys~}Ne-l3X!q!J{=opVW3aV52ap@HJhTs}7UE>CB809RnQ@maW$zNfM&r zSRKYS2?ijX?l&DWSNm{PV$Rqpn9$``_y!N*=UE)u@*I}vk)&I{xP52)SUN?r?HEcK z)jy$l-ll0Se7d2zY0{rUMi11Sv2}VFMY*aUoZyX+2B&Y6e*JWIdgw{0#uynkljZFG zi-IPE%6aFTk>Z@6B&DsET-0iW2e}vWIvn+lj1#rlj;U7#g`r3j?l`3Nbv{Ov)NWX3 zL?Y+rVR_=MLK!1{I39EJ!GEmbX&UgFU=*ujzeVDy1Bc=^ zy!1|6ncy@u#q{pgI*#Ry$MBTi!^8=sU$SJjmEM!OF}-~_D@m|a@4Iebz63^eX6a{} zh*8U74(YvzA_Ip*PvaKPz!{^{PVF)fxo6~l&)j+IXhs{3MJ&$KC{0FN!$RI-OfVVk z42xI}qh++OMXb~pu`^SU(eZ2EdEqS{2LDbbXUpRakQtrXzqrH0n^7{ln6Qw?TTe2& z8kXwu#*>V0hDE$#nB+6M8y59=(@KVzA zWZ1zQngQ0^1a|TMhz68#j$u8#J-J}#8rIw6eJmM$49oLwW`=o&4e)eFlzPm!92PgD zpM&*uv)L$Ejh!)QYJZgci{Wg4`E=8Ib7NqGO&S63Ih=B34B=xrtht4#oML>&?O1JY#}MdZX+8wIk@npLNEYTyF`b&u1m!WX$yz z7J^PP!q^V_iE2&WsP)+9q6g-nX@mk_!{9--QWi(|*?<*fNvVY4z7@O=c`&L7gaVHv zhQoTwnDPTsNZpLoJ4BoJ#u=#Yz0nq?Ls`1JM$e)eY^&FyT}4|O7V@?X1Mcjdh~}DzS>8)%NzpcjHTRY=tSxoKopqK&U83zCg1XHt zRNRq{v6pWthF*1O#IaX+U5X8fH{iwgnj``q@4rj1kjLBaVy~I7RL{R2mW=(y(1^!d z24k-q7WKBE#$x-nB7JUYcE;IW?5`%Qx%XNNu)i6Wv$(~YK+leSYv_?ngZOyUcMtYa+okjb8XXtL*JBHp6 zJ27H1g=RK3b_ zHW9uysv0}sS;E&vRV`abwtcvS`BnK*wU-GrwP$IKHbqsJ0`O*fk%oPpsJb0PV63@a zsl#icsxAk-g}qAiT~YM~jd7Oj`y7g@MXa*~KO9vHSuHJX&iL3DimJ&?z;lHAN2BV= zQSfLb9>=2UzfthkHU}9u_jpwGZwa0&{A5(+Vec;1#@?zGI2Bd%+4|es4{N?Wrlw8Mqxj9LrmWt9_u6m8)K@58g~)CDW(<;2Jb3-OH9pc z4Bk!n)|jfsk|x$&__mlrd8}9u;WaV!Kg#zMzCEToVxWxm(j2>)J7VhYVemLx1a`&r zLlCiZ#H71piq{8Y=L)ZlsRe1^eQXY{xW^@?TGJwV!uQ71Mogr!zBbS3+}wRJ^*xry zv3?T2E~cK$0`E`GJHN04{Uc2_Km@P@%_T`}pm6L!AHZB6J5M+^pgCE^1_{Ro^!-8b zeBno8YBSsXVBtrRKD*Np+e~)HV(R)-@SzAt|I<6xBk3_rB4Ee*9u5n`g=5E>m-AyI zgjZ!|;d8oHY?S?3AI8UyHJ2Z;(GtEVPjLYf8zX#gp1PSPA8YdlbXX)$^R%kZFA@c6`l_eT1D`4i?Cz^>V;i{G-cZZ}AMC4IbpoH}+eeMYef1sh zu~ISF@xJQQvmr2D_{qNNAQhS={8Znpc}uO>0^6Cw^p^KihuLc@?1&!6YWu0`9^eb@ zvvhb}KeeJc_#$cJ$NH&rIqog??S5L|c)zT9Wmas7JNrVDOBJ-;X4Y{ z6wW(ah3~@iGi(v}i^X>rsMiX?9}r$!phgTr|BpQ=9(xMZ1GK<4;d=|zKR9(iBz#|i zy0Q`Y!@}zdRBKlGqjrTZ@%{qEt@_w@yUNsPfx3?a?-RmL7O2NLPd;VW=Rn#V zj_nYS<%MbyOYlegNiDFdP_1BzciOzBjd8M2y~9qmOZcu~>QC&HPYd5YT+QUV?-}8> zBUF2oF!r1%uxF%N#Zl#X`)fUJ?j5Oa>x%Iw_JaLqonhTbeXD)!Mg4jVjEf`HY$~+J zHp`O(BUL}v>C3_ojnud5$6gVW9~r5pbKHDY_|cK-J@UQwJtzmR@{H8a7Q|kc@J(aY z13t&Ced4iYtbVv4_E+Is$Lfa*Vt*69ZLEH{Aohmvnz8BwcG5cG+sCT;T$a8me8*V* zutDrC;k(B2VFN5ih3_7#{7czL_KQdDSQQ=){&(Sf#;Wx+;ekY(7^_-vApMtw?;EQo zvWQhk-&3SM zV{+wuZMXEa!#7%Cx)gCHR?{j3ch5xHa zHEs*;2tQn;RC?&f$-zV zfKyFK_{kzQj0!gteyT{dVTMZh@^Pwy{l1a#RpZnMcFR=ZYsaZxY!jZd7rhSapLOHZ zZZ@*8W9E)c;}o}uV`;)`#;H{tt0Ru-x4Xxwb2&7dXGpRB8K<6M3C%O4xX&B$S!L!S zQq1<_)Bv9IMMZ(Saq7RF!DHll{R06em?;7W#;Nnz$eIX0I8Ghl$yb)}L*tZU8_5=a zc$_NX=ik}mlvzaT%xuTzN%Q=%{6dq;cJW4=#JpI!q*k6A352y5nffSN?GM?ovps^ zryGj1DlX}TMYF^6JzRM!){or8+Dn8z#i}*?c?aQpi`89hL>-0iD^@Y~icZ4opa6Mi z;rol#f7zzG2tQD)PH<%H?)auv9xPV3v(9>mz@cKbCI`Hy@WaLG4^*I+W6lbW6ss%H zoMUH8_|alj$41xN*#vKl8^x+8>-<~^KVGa{4s?BmpDb22HuwNvJWds>7gOLd&@tyh z%g3t~&A`u-@O9(W)6_V@tH!IzoO}j5htZ0$1RbxQq{2fa{>Jg@V`eZ^_}1|%NQ(`V z^tO*zRjg8fxOnUsui~te5yE$kS1Xy}Na4H3t1CFNjS^lvUd?2q8ZCU!cy);bK1TT7 z@v0dMG*v58?Um_X#LnY@z_6J?O_7N!VipBv-*IK7k+TOs%9@KaZ)c} zi4ToeU$Waxl<>pj)weY9`NEHk&zgfBgei`h3XZ~{YyuZa@Tu`?0Ol$`HdQ>9Pf!Qj zL*QcJt0t&*tbu7#UYd=p70&WfC|kQzH5S7LIW%izI%e&%gL=m zc?n)DN7U?-0JHM199Lx>5Mv66K8ozf1VO z5>-fxZ4zErqTZ$aJ;L{wsK3yHTZA7d@l`2%)xFLRt>M8E)r}>*Pxzq{bql-gR_Apc zj$M;bU=XH5{SY*F2IW#n+WlF$YdY5P4R}Qg`eG1@>_T1Gk+0zIL?&bD?MB{2^#`nG z59i}mMNVu2w_tpauM5D5BPxnJmwFqjL>{j9_;7t9EXU)s^|2BTn79pHUo}Xu-syZL zL9FB=9hPTyI? ze4;*9Vm5-OdVHWhR?=P;>{c`UJ&ZAfKa8Q0xVwYu8ik1#;yOD@i;<@9`OW zBaHP2HUs$#eIhdU0<(455>L>3e1bk!vH*p{t!K8!2j~;R*!<)3^TzUgdfuC&m1g<) z@VvJvNq9eY3OOlFF?(+ZZ0|3;n=5t!?Zzi}z4utA3u!n$sO#}EeXP=~dXCxY6$@tK z4B1SWCv9&Ad&*KnPuboLY%5n7y4>+z%K=?x=qksn?GE}oL)SXqJoc)qj+f~54=z=F z$xd*!S%0kyc;B%Q*BI$d0euxHCNuSxfWAZ&TW&(P2E3;^t*kJo(c1!El+ENiLu&%w z^)%i}Giz@Tcq2JtuHr>coX`clg0^h^*PFC<;pzkhp_b`ZxI=^?k%{rDXQnmvxkYNa zn{+ydJt?-DeXiN3DBu)3cJu9%5?2Fm;l?}r)aJ&Jx|J#MD#eSmQx(N{S?SMg@YRNO z@G@zZ^`=pe@J@1UyUnmMUfAdCw1N94PHwSR07YZBo4_gF9Q5zl9VUyZ>GNh_b1H7y z|8(!=D8e=xHp}}jv%k|wUg}Lv1G~$xa<3nabGKm?-ZeDM7Q-sNy3uSZe=u~Jxi)aG zVOM+KQMLQX^bY(ocB8F^uCl!WQPBGhU2A)n=72t6D0bk_+V=my)H zkPZ5fran92J}UgM2}UQ(=mh$Rq3DE7Nox$?9Pa@Pvau%(-R^kP(>YZ?WjHRT9bxbeLw7mes2J#<-qbnm zcDx}Rvv(R=>v$!s>B|9?q*>2(NtdON?hoVKe4`jGu}=XK#;@6AFJ&NbKv$f{maV%K}O(mRx;9^ ziQD*^qbR({zbc9MLB<;rJj1-QV{3v_Q3eL-!)?wKj%^l_;T9(MId!t;<}X-;zDFm= z>z*BvnWDSNl=wGIMn#>oro``gep*wzUwp;0BbvnPo}U(Qil@XEHtrbpxp$^h3F4g~ zNSr%Mnh!D~!SV#h&19^5?lehwD8N7+i~CDSx(tHicQA}GxYMJ<8o`&@=@=gvUyNLd z3XR=@IUH~0WQdNKdO^HZM#mQZzv;o{Piq{KQjm8M(yv|@25Mg}jI?iq`mj8BnQG-K zDXMFgk)hB;K(@`rlJTy;4>57W#sVKr+dS_|WSO8l&|IR06nof1dYFUPC?E!WL_z4{OIM&yvG2o0e1~83s2$(bm=<9Vl zkxqq3WSVV3mCJD~hs?+IiAfu^(auSW~sBn7a&NY{fo`XLPyB#0<2()UvPULsF4;i}5B|TTh!*t37XKv9J9j z5;+Uh>hKlDPTTC~9)d?72ll88+=vWX>kR(D40OjZJc@>te$9lWiw_13^ zkc`j zXf@Tcy50>>6t&w{;6iwIdmIkjaN=8CpV2|7U0>E1>HasMU2OH(hRU}a+S-ElG9=Oy ziZ#@GslBvj4fQT!FRhxmwQdb{l%7z|xX#wvDeY@@p*nnT|5(h%ck+Dc1?qP;eyHC- z;LFr+Bpj@>uIKBJ)UGo$M!H`PgnGSsmz-T_)GJ0>|HJVmBAjzE4rp4aHAR}|YGn(x zvf0S^T&=L-U43};(OMU3{haF5JSc9+UK)2lTX~uGE z9JW3rm8YYw(NWtVYM=e1bWA<`SBH$<*65sIH)@d}5u?Rg9hRqay&b>y9+PVoGCZU+ z^#dPDu6xeRb&t+?n%xyK_bSgFY7QGbq-5<)a1$hz6{|ltVnWFsVV7E z$Csj-synJPy$KSgkr=+2N@$ZGP0lqzq^w`+u%{qv^=>o}`Sx>lWgbJG>#!I03PN6& zeEXSKzM*aUx^ec?Z|NFty)Y%dT`eQjg z1IVgxxn2t_3QH6wK|_7?v~ycP48~57Ad&NU zQUS^&-RiY|KRuzC;A@f9pu@_?D2&DJHc0fV=y?gHSxwal?N`yOp7VOVl|Ks;&?y|r zl289aavvoveG}NnNK~&Lx`9T#Iy9OV^&%f}JUlcb_w-%#D6ATV{T=k1u zL%{!U1s>cSD^SSN7^@*`^*%Qb9(PH;$deySIlxqAnr!{M&NTB~XPP-d#msjln>j(m z%y<35%qBR9UO%WeGJXd~Dl#>;GwEjW>o3O4#-j_Qt^6H0zZ`?rZn9`TLXss*C~5T` zIP!GyShS2LmNgqek4f?BOJ}TVa=8Zr#;SJ(eAf1B@Gxdglt~Y!2@)}8HPpj!V)ec$ z8~NUC%$kEdmo~+~hLEYVj9KqK)2er$Y1IUURs9h3m`F@GRn8~F1Cj=NX8U7b=sN1gpX?6Lbo5dJLK0wghv(Wz8+3NK*b~2H(Fvu7? z89o%;m?@#7HdBI#nG9V6S*v#qx|V&PF%!R$vjMB9_Ykt8%w&6CATj=%PJZ8+c1lob zefK4|z6237-FK#$OlS)XEBR}Y@7U%EGnpiNAi$W(Hy#Cg*y{bs(9`jZ9$&@&Cv^j-m{UC zJ`;E=AS-aw3f|I|DA92%@)7rdiEFjOyX0HzxE1wr51bj-yclq{jyt3c>fiprMDBrz zDpyCYsgL}@nUO!x8S}mctN%5e+&?yP`AMWFP23~(aX&sY?#DXrIvuzFD8&67ago1O zi->7$bjC$49N0!9uNCwIgGW zd;>tcxt804dAOJgtd@IRxC-rBq&>AQPCel1T$)I~Fp<1YP*}huSjYtZ8zIjWhcm^; zm}2gte#}m5Jsl~2gM%BHW%a3wn*V>54thyScLcFoK8aF8X?zm`r+O&e2>AY~KK=iv z*4rgTt@M7Tm^Bm*wm7XEav26FoF!hHSQMK^d97ZbvK8t^ znV_;JzBYMvnjn$Bn7w_638I+|=>yx?%eCO(^WgUF6`IUNrUQBAxEWgHKsN}<8DV+i z3{jsmu7RLFi@Y0-#A)Twe8ec=iR0t&#UGw@-0r3Z?G<3r7ltwGpjD6ZTKkgfjs-{4K1caN&5Z7Na{1u-@{SJQ&Vf`GW-6nJu1je247)aLVJDI2d~rZ)f>+Hd!R?#_V5=_ zJ)s8-(YuM8k)&SF{cH_?59^c6yc+n}cKB96uo}ty84k1GXj{YYZ;73u=5H90Cji60 zg{Do$d}MqWX~e5Oa!fN9ERp5^F@MRgS$Tbal6+U=la&0R(=sDoO-|iv7lcVHzOT!+ ze++y0we9#Ve@ID>UwGLasqqIcS>HImZ`j3+<1c(Pph5g^Z?tI?ul=ZP@AxfGHV%z0 zn?JL3-n?bqU|h?ZH>2{>1r>|CU5fN9+&a3Xa&9?8OBc>xTv}N+ucCZLWtkCOTsaG0 z;DRKKx-9S9(wP-Y;^`lcX&ayWuL0qB&faN_`~bG37R-SN95a?OE#t=7@9cSus{Lm! zm{m3tD*am@%*fLIT#Xxh=HLd$96OCaW5M+%FP_*UOwB+a)#Tl=d5&_k8)=XaL;lo?dRMk zv)#F)M!T8MxR(uZvz?*#@tm=4i%PfbI=7{RmtI8O_Rb`GOKZ2UbFCeUws!NJ-`N+o zcKbPx*!CFrq*dvz^+%oOp0K*PH~ItI|6)t*6~_);`dMf9OKX&S2mFp&&RvfE=!))c zlPdQt+im7NYugum=cYkFXPlkuw##wbIM+M&1sAzZa**$xwmr9Xmu_z4KklLdZp7(` z?TLW1gg=igy)?g5(XeNV+@{U|JK(r4Tp7A2V7o7-bkk%&cYF}ltxc)<%gT{UmcZ-9 zD?{Dj^I+&dPMgL~jcOdahv}p^QyK&9(5Mt=SvG@?HvFxij8V?Pl-~+yI?CDf8v$;2 z-&tnc&LJnucDD29klh3>J1Yi_i|l~w-m$dX!6kPOa&w&Jw*6ji=bY!LkemGL9r~13O1Vz|uIKLv{`9DKgdy#+>TMKB-+yiGQdwA&?A>CVG3F;p3v zQ181i)HoD>^dG88hk58(j#ZgToNwId->3g(YQO40JaUJf)!{qMDnmqWZX;&BbOrcv z?FZ?iHodb3@FgKko5)@4WND6D)3sl9eF{l_q4?P3VE*#Kxv$BDiM7TZBEHCb43l%rhvy4g;Iz(3exXF7 z+|PYe%T)%5`a^S8Wr)aq-sChX%WXXdOL~iybCra5< z+V6CtNq%RfDRP*tRi+ZTy_=j7=K_AN5>_TK7}b$Ti5s_zaWDq) zd8~injuN?{o17A5?}cAdeO2({RgLzWkVuju&uXvp6JCsYzllj;1lOuqwmA`A3y-U? zI7zlJ`Eo8;PB$2C!hZM*vH08{he!OQuoqMf5x+EU6x;l98}(D|ciPfPeh4vtl=%Wj zQij|K{RRiEK)k7;$%e=s(u8$j1bn6n0yk>U)A=O%A=LbFv$I+v6E_%lh{#(Ik!UKB zPc^|EAs!Wf;+Mu9B68CdGF%XxPMr6iI#!R(#7}XcKm^Jrmksn=94rH|2D3Wc&57HM zJ3!>gIsFqka3gi3_Uln!fBsx}tifSh=RXQy95@qE7`j+{6)y#BFir~YGR|bdtF+gI z)5+8~Ebe)}go7Fr`H>~ps$6d4>q%H=;$TQ3t*^0a{~r$9nw;?Z8zOPM3>Idl9U`QTuqj3j_+_{8iI6*dljJQ&VR|jqf-Y0G% zKZ{~p<9|amMA1JQ(GYRB7CoQfGa5=&Ok{Shwd8c~Vt&)KK#$GDOK_lQgcaJmx}0dT zp71rCCvY^dDy-`1DXll#Ob>@`)z?G>Gy@0iP4xM0DP0wGa9c6CCK`fg;Yg~9vk-~< zo5?lN_OxGpP3&xJHa3%L;+cA{NeL_E_((k$2XiHEHSRp(Ht{ENvopCSsOfDwygG0{ z@F{TwI_e%MM{mQ`? z;z+VGqjRe?xq_1X>MMwQqbr+A{wqNO*gQl_sMU@T2s0vb2UQ0oa%I$SaWIP@0yDI5 zb$~bsN0RZAL_-v9YeYlDE;xJ`pU7xPZUoWfm(&fI$lr8+JvI~H!hsSKzR}**wIqnm8}8^LeIkz{;E z=LT%D@ss@Ojn56&`TKBH!6f$Bh8;Mw9Pmf}b5@L>!|<&-aOpM&lDreo4k>B41Hew0z=!aG=D5bQ7CQ>FzE$)ZDsDmp5#689xBK~CD zsYJfb5_yM+`jyX||LM4}tqw>f@;O%u5xL2lq^!k^OvLICk>Sual&mXdKET2H`d;Lr zE5$F+$(^43vE%AnGbIn=G2>1paw|4DZwOm+wO@5Ak>T1-=bp9`Wj@t1JvI|5lVm5W z9ViYaOANHLI+5VUGi;ZcfK(!P3+YcBWZZ#4@w5M2*x6?q#;ZC+JK@Gw+;+?2jMqjD@Dg#8Xz0Nt6$bH>p3sBa-K?_%>5-FffaL#EHP{`F0du%3B zCdmZc&rR3Cl>uVZxI@IT#+^zm5`W@2;|>u0TMS7h-fG+-A~%VXm1RaIVs(hfaBZg~ zT`AKI2kkT*NIB?AxLLdtc4G9~aQMuFj%zyT{5lYq8+U-XS^SCIhE3LKB=~e3SWa9E zxYallSuoYM@WMzG`VGH;_TzZb5kg&c++u>sr5f9%=8yb79L$;6y`vsM>$IZ>2m^>; zCIaZ-c5$+Hy!?NtaSUm22bLuwe%D!M5jsxdU;vSu z$!AP2T{~d|8VAla4+7rR5f>hGPB2mzYa9dk3Rn{n0SVR7?vX10O3KZyyKI(nH+Am( zxs}{B)#3M{Dif0N|9#T$QlFcpi^}HU+sT+nN*6AfF{`u^pFSp8Fnc!KhZF8|dxPS|E8Q2yslR$n=WbmYdxr=AcSTxJ(7GF`(AZnN2aiX+UF2Cb| zq!*MgSX5FmV`iDf>o(#sVaEJ9W!9lQEgK7;ZrlY=J} z&zN5_bH;rAG0M}7-()14d3jl-#TU2Nlg~66wrB<(p69C!22V0>zC@lnpg2RZi(Iy> z((1-n$p6BR-y#q%i|@1_JZZ$_!82!;m0RD%XFM@DI+QoI77U$OIHqu{#haNIRFqFg!*XIgv>WMxGe_R?n>555O-VY0^$ZR7UlnVEhMG%ZA)J-58vNb;qY^U6wR z&VwhD;#n#pf4_k<*ezWft$=PPluO2IPu5(nP%fi>>cprpJ)AvKVGi8564qDI0iom zN4vWCoxJl%%2+7*K!Np_iJE z7sE@ycDuuW8vlBDi_iEXw|V^5*9NzVA96b6H2(ES5&zlgFe`p*%F5T`#f|#6i*ISL z@}~H)lv#b^6=OU8K0ahvcANOXhAS7xTc+f7iyw44pZyEXN*6|!G_s&@oONdP zzzAi%;yIsBn%($}D%G~x*=p?QT06d|Lw?gB6YCZ4nNeD?bNP;{bUR*Gbwx?MDwaR0 zA&S}4!cVXG_#^FB#FwAfreVCf-9g18pSO!^BS2kK-8&b4J!y%(v$$D@f8q(4*|5%B zQ8eCj(&(yq@#WdQ;?uuEtw)-bJ`(+9F}1Q=z8QFPyz0`9k2d~AQJ`V`iRPW7@#481 zSHx2nWS7K0Jnyndyhq2CS@FoFLx;x4y-+nY{`jEFUJdi|pA4alHu$eMwu<*?+4+t5 ze}2r3#e3zHZipXSoIN&v=)1uq^%WS18cQc5T85 zOG%%Zv8ZD-KK-if^mw!UqFWonDiZKUi#F%SD;9U09Ivn^UmmY*-+57dz>uQZJJXhQ z+-L8seZA@;J2Y=z>Fn|ua~8)J4$Q-+fpuhU*y?3Nqwzt*if%u%DV#lP{(>uZR(J0( z!HKtg?24xGX*Xu4Wc=Fpz2YC7n?ED|b+74r;`h8+RUEH<{ECa?EgKH$m7ZKE)9c1} zZWC>MMqza}@m9S%+#5SHZIq4b?OfPqWG6c z4O=-e9vPe0I6iCV72S5$E*bq-=eM+5To(W6vfHEaL*I8F8Gm6-$G6is^d&d272)oX`4_d1=lG)s24^jqH}A^$H=}3WxpVuUujppSdz>@!Z}G>!yRk|9nU7Se z&kJWm!>OZJyQ9}Q&ctxw)mN-6JwISZ0ItR{I2; zTa38HXU0YNT!bU8GiSBKs8*^(J%lhW%8`%Rp~%O2a)l8dfsC%8bV3PUQM%@I*y7|c zUKo1JgpEPGEoUf*3}+!DC^%w`Q@Gl7OKfVG19|@O+RHdTwJChAuu%De8L)cb-)>iuqjF_SJ23^a&$75 z#l8PwD9O<9a(lw+!1(K(HLlw-sO7M#)PLOP{uZvG;k@{Yce7)Ca*V&l?dr%cBYz$^ zBQm#UlOuOeMCK0bB(CLIf*xoe?qD|@8q88!iJY;u7{9nKyG4B@?hHoHi1f4b%ShM~ z(~w6QEIBz%n2a1#k=PiWyCUI_JjRQ|KUG6tM3J$|hUE{2Fott&b zt*;#J@u1>-Q?%5A)$ST+iFyTkz8Ve;Zsc4P4!trMQR)-q#!R(I@O+)%vNIF3uu5Kz zaBZqzrROJ-t51)+9JjD*Ktq$@k~0(J*24dv1hI_Nf81Y)z+ywg9nj8-*+`tXOk*0_ zsPvUrUruV8Ji#xb?5J=t`UT`ipy^c_X_WpsBaVGkNt|cHJyEAa!}%jt2FscF>VW$< z+r)TjC|c{z!E=Vsu-tmglI%RZEp7F+)PYSkfSlQIJPU4iJX?)zUHZ4=``8}Sd3dWZ&XxrK; zpK!-z!`nG~?~T{BD{Pmt57j>;J$|ZPVe4Rc2gKt28#c;yDksFZKrAH>UJnN1Rozu< z=jsXZWAJl7+-1dIY+u;cSv4V^e>u|nc~^Y;3+prE*Iqt6lCtw@lyB@E{X4aGen^Q= z?@-vzY1<%v2y!VM8rXO?Azs%*wNBYE!L}-#_`wc^t(|D<9UTkXdCSvb%YbE};ahoe zfAF~GL7ZSWbK?~~)p{S-Z1f*TVF&+O0TZJxIZDsX0zJ}_4`w(xM^%?eEeld7H z2Fw)_J{y=AKpD=o6N4tWZ(Riss>hL%0ylt~k@0gD_r9Mz9gCQ0?s4QzI;q4O*PON_m=Uyoxz7HTM=$M@ zByF6cVf~s5i||WIFP(kmlG1tDRfzi?@;zUl+5Gafh=u*tGW6G;zZEx;^O@208ur&o zE?(@zjK31anZYkSk*Z!f|LQb?O8xTG0)D-I<*BXwOG)I)7f;S4@3v|!J%0c)Gf_#q?GkjC5_}2h zGl9M0@wVV0!A}GgW*x1*V5VRz!7hS*1xE-@7Mv}(L~xbhZG4cN3EwLoPYBiuz9IO5 zARpAGJYRxKYy?{qn+kRm%o7|gI7zTfuu^a(CS{$#dhz&!;C4aY#mEf)CiuSKmx9Ly zap6VFg$0`nUM9FgaJAri!HvE+?h)K7_^{x1!9NK;C-|x0e+3(0Sw%%-g1Let1TPSr zC0HTo^8sB(yjt)&!L@?72yPI(OK^+e1A;YzPYU8KK04j!1@{R4MX=7GZ@nuX2L=Bn zctr3k!Q+BI2wLb@R6Ip6Rj{#Omf%@}Z3H_B_Rxs>KUX{k2o4b(Ay_0hQSd^+>4LKb z%LNw+E)(P5q!;46ZBhL;(=C3rya1Hr?B z{}wz3)cya2c>E+7z_`VP8VP0ywiIkD*jccrU?0JOfM>%7scaM!M_T=E%=_`hk~C7ej)gc z;P-+*3A)&_p(Ps%rU}LboB85sCD>lDtKiv!eFX;z@~zTLc(mYn!O4Ob3-aZVl$$HK zKyZnm&pUi6z?V4?*9hJ$c$?szf|~^&5PVc{hv2hQ?P|#8$o`bgBkV`>?@crI9#wuBkKQr@t7(&Q}8mug@VfjeZkd& zHw$hMyj$>I!G{F53+@zrp2+_HvUuzhd|U7zf*%PU5&T;4gy2tt0i5cxQ)b1!oJ+6RZ@xO7J?t8w7c7&UE8~_cWCLf4_Lt z2tFnFjNprcdj;PRd{^*&!NY>QLz@{L7d#~xP{u!1Fv=GxP_Vgpv=Qtg*jsRbV1eKm z!HI%X1$o_->6Hss3SKR^N^qUv245VT1h)#-2<{NvEx1Q;pWuGMgMxg3C9Rd6r3tJOR!w9Qt)cQRf6jb`ql>V*d(}Butso) z;BLV^g8Kyb3mz0aEO=D#xZo+l02bpcK&nR6e^fl03$_vLBG_ASfM9{(7{Q5xQw3)U zmJ3!2UM;vva2=8Te}i~z65J|SBe+9wx8NSZeS-T14+`|8EeFO@dnmYXo-)?iPGm@GU{U zmz#C^f#6}me+wQHJR$g#pbAU>kAzJEnS#v)TMKp&>@LVRi8I3?f+GZr1Sbk!C^%hk zw%|O$-}&O;8$p@iYQc4a>jm!=d_b^9@JYd4g3k-?5&Vl_o#5XE4-5ML7RNEc6M{bp zD%^BL#Ug^4g3Se63w99fCfHlBzu*YL$%3;D`qmQhxL%N7P+^8Og3k*6Mevy5DZ%#G zIHdf!f`x(;1!oE_668}Bl;UyZWG)o_=?~=f`vM82v@HEKla`Pu!`z_`=7fc zxg>!J`>I?*z@RKiK#dY1C@2Jkh^S#vLWCHWa05idjRDbCL=@CIR;^&G)vB#nwYFj< zh@y4Ht#t=fl!yu{RI3)==Q;Dt&5(fF_4j}O?{AX1pYuKEd)7H~X6AfnK>-}Av*)mm z5C@7Q#fjof@j`K#c$0XyxK?~dd{f*Zej{ddWC5`KI~#{(9U%@BM~V~0nc{`wGVvzy zZgH*njQFOwL;Oa}z;iBU|L;r(w#5LgQ4pRVepg2;TD9#iw6qkuNiFb=@#b?Af#U0`|Vn!G3|D9niHw6#}iX+8|;!N>E zahZ6Nc(=G#d`5gz+#!A=W*nmZzw;p~fH+VbDNYn;iWiE@#GAys#kJxy;x}RjjDf6Z zXYmL}j)CGxaiTa=yii;w-Xz{Ft`(mV-xPO<--sDqRRGaBLJodik0l!^P84T~7mCZo zo5Z`twc<14o8k`f8!;oU0(f++Bjhnq94Sr|XNnh!%fy?+yT!HQGvb@#4sk>`FXPk2 zX@-tvT_TT_;%f0;@lo+P@hx$O__f$9+smMXc$j#UI86Mj$cLiL{@Ll`ZL8@Jv{k5@fYGNpxOVwkw<<{Pw`Cg8u1qK9`RxEb@6@i zGjX5T{4g)Q&SEd|XmQwK+W$|L#}qLkE)#z$@-}6*#Dn5y@e}b|F*n!KJ6b$ZoF`r) zuFS>uXM!|ollO{`iqDB}i95uv#q?fYyiVfb;;~|hI6<5tULaoK$Z?~1m-w*wwD^Yj zk@&Tkez*!C9xfg$mWUI?8R7+^bA=o?ig$?*i%*Mhh#!exi|I$G0OH}|v0{lhL7XAd z7>E{ktSjVkqj;D2u=uq2hWL^AwV2*p1rTWre;@4t&9~D46Ts&4R5hsW<#0yBC|6d`G8^ycChsCGGH^h&`uf_DfDu8&nc&u0= zP7r5^7l3B}zd{~2ig$?*i%*Mhh#!exi|PGT0P%3~Sg}N$AkGjk=%@XE`_WzkyG5(e zlUs;g#KXm7#GzuTc$Rp9c)57Jc)PepTwAF9f4w}O6WgKQG8W=U;IK04^lzIxY$n|1e*Q-WO+;y`HfU|mJ7tC;tk>* z;_t*K#8<@k#LvahU=>8{Cgu;;{y#(>r-)O;IpSh*rFg4&pSWIpQQRtiCWeYt0I{2x zU+j1RL*#LaI7OTzE*4jcw~F_P>%|wvt>R~5Xow0Rb`$d*IfjU*h*QKl;$m^7c&m7y zxL$lw+$w%1hK^SO#BQQ9M2=I$DdHS)vA9yaRlHAJFTN;l6+aV0Cn#gFo0#tr_dUzw z6mg0;M_eqf6mJ#l#7*KBahGTh^)l`%_7ew-V+^tVC(9!tI^xyhD)C-%o%n*dS==e^ z6YXItfY?tQERG?$|4)`jLUhEd#Z}_H;yUpKakIEn+$Y*6ssLg?aj-ZBH2eQ#c_c(f zyjol(-Yc#XUl2EoJH>sXeUb_w_7ew-V@}fkKUp3L(Gjl}SBdwE>%uQ`{%oB`Sc}PaG^dW8|1DCj0>LYH^i#ueeTpLEJ3v6!(etNEJZrCl2=L zSYzZdS#-p!#Z}_H;yUpKakIEn+$Y+jl(E=P94wA8t(Y#dYEf;%0HD zxKFfCRsqC*;$U$MY4(44Bt(9Uk%!-_#Z}_H;`8D=;-}(XvBhXF{-I)DagaD#JPS1Y z|7>|I6t5C*5q~2-Dn2j1BYrCG6 z_i6$`yCF=^{U#Ncl4HTJctq->PHyGve#whvFVFa+;^tQtT@B5sOIf|0CrwL7Xlw z5PvLQFWxRbAZ`_RiTlJBr+WoBMC>gN6iYy}|BshPm3W@`BXQ6fUP7D8JiavE<2z!; z1W#^7hVh1Ju@l)BZ-rBMzBo|+#S^suk5RzsBode)o+ZU|6n?Jg$p2Ew*NQiih<}Ut za}ou(Tj7sM-Xy*{LHqyvQrJl%fiJ`_rPyL3{IRL>NF;cql8Gb9KO!DMx5(OG0mWZc|7n4Y5v3MDYbZ!)XAv$$*AfabT zMA#(0B886>zDM%cl2gv~5=@K(Mo##o! ze~B!>?K$%QP~26{{U3^7(gOvEOz|S5i5VoqyO9Xb69ew z|F6YAPI0`5&q?8Z5*h81!fx>^g?Fs*^m~bYN$8h|r^$b!WPJME6lkWHQ21pEziyfw zzYy1nZ;+_bW-^TNK>SkvX=i)k%}Io}6uZekUo0g1yNh1$)}CFhTHY6nmzZD-nBuSG zf3M`VB$8hzZczB^3g0e%DYl-|6!mkm3 zF5W>xe}nkE{9lp0g+w~i1c`WKBu^mGl4prd zg%r-0!jHwDh^rKSkN8{p|A9n8e-zg%{56GtAnua?-^ECkSI`zDp8vI4c@C=`iIVn_ z!a#9^c&ft7#Y*{ClPJg>@mz&psqh=c+vIl3(_J52HB(PC@S_)f@f@SR#|1PFY z_X^rZ>_npJyOBtzhuBNu#R?xSmdSq_$^Cz(0?s3mz=fhiBK#)`zfHVfd`sLeenCS2 zTN3G5GeC^+T}b%%5DVl#5Of$Yf*z>BX(S?!7tbUSK2PD7h%3d1#V1JUJuUfF$?uRz z?_ClF*(?9FnVx>DnO18P&{-ZiWPdmQp*Jv=7!l?ZaXhk>b7cpY!_xisYn=Sc6>5v&VrPF4tV5eXUB6-LHcxRGlmFOa-K z@^z9|OTJC=Ba-VRzb5%D$-6;^8Ga=XJ|0gQuTC%-7D_IXY@YK&_$bL`3ZEpoR`LSL zDW88Zk`8($H(%>M6FqXEE4Mg$>#Y!xXUC@BC#%#e5vHyB;P6dS;>4$ z0rhuDHjnYa-66t38X21B_u!Em@#NklWPX#B;YE^%OXe2~7+xlMlH@AMd@UivFPD6! zr04hVUvTt*ykm|$+AWc%*3t)ZRuhlp+(z7!b0;w_C%SwY9M_l1I{$#zKC@;0=?26clT>F#v>`$s{>^Zw3?Xv4%v=bwoEW7@3 zJFy_o-u9IJ$%0~g4!$V!$!>ejm(bZ}*YC7HdCvaiLwiRHd(P)kd)ss*|E*nLR%+LO zU^^wqVK4H_v*&yfwd;o$+lkL@r=r;YSB)DG2_X^3jm z5KgisyoR{gYlw?~XhWR2UqhU%hB*0$HN=^g?XW4%G)?huZi!{H&_V9UjG483St+`a zJ^SQLd&<)HfK9m>c z+Iya|_q<{6*<$bc$lkNd-t)D+=fpgF&*_Es-q-EDAKQEP+I!LKLiXO*?7iFVy2P&FvCniJd z925=xC~+Q&<{YqSC!uI(e1FlLre)(+xtN73TwWDl{^%m^R{yc$Isb6eC5tzFc~#!> zN9+Ez;yM3X^Ln>PcRgTX0pDv#BkL|ZA-gP;bquVXs$Wx9bbv56$f%j{`rUT1q|B;c!J!A2R z?#}Yxp^(=9*a6n@jv%`lfAeAGhaX@a?+E)pc7Szos)7Fc-#ft8RL44- z!)gMjQcu`U{d4A+y563FGp(jw|3A|6c}&$I)v1}m@`P=#IQy06zcJ7{O%J30)ep_ zx_~1&D$M@icrFW@WX(x`)!cR##el}s95U<450~{5lmAuM?>u~tI zhjm5`e0DqZ+Es}|Avhunj>qA+Ag>bFn^3x-7)pDf^T}>FzNGRt=O`7Gvu|S9dx&1?F7x|5jdd+KS((dVsb3a9OSSK6?BSn;6NdrSvlqK{|4)Hgw=nI zsBa*MMc#lFD%(0D=~TGk=hUNk&d?l`{gaR3x+n)Ft$*F5Q;Oe7IW^1gw{UruY~Z85 zuot$;!Ozf~7%~};OcLiKQlcBP%tFA^pW8Kcosl3~uzpjeUGa3KUGw7TN?e{{{TtR- zu|8XA@7-MK*n1JW_Z_ULAg;#nvlTxxpF!s7NNikAvB_(ALtg)27T=XaiNn;#<*?X8 zb2=~&w%++Q_?c3SpXsIl&fJ*IxSSf3*#eW9V{-d<=E2l4!(j5rMe09Yja>!&17~f( zTNio!75A+#oPTU{eP>%T&v7~BCg-ZgIm7or{lYm|$N0{in8&!BJd;x)bK2t7=?}X+ z-dgAJSDV0tX~mJKXTw5Pn11T*6qRyr)tj&(JMD!I^ z`H(6LJ5*F<Mm&R2@uRMO_@gpm$ zoP}j4{^g#Z-QsS3oF3f2WntMZ?!VdsrT|XWKVN`b6|k<5u_iFEi4HwGL%u z9GfvPBh(tx=@3$Up=IAtqy>bO!!qM06faPV#ON^ss;wcIPzr6_Tf1kpOKD3#_oVS- z4sl<*V@&7M4+-VBZW(G7D$5w3!sI)pSoy8HWZ)@RI>M=#PB)Hp%Q}R*V?(EdtBXl90ZyFC+vrz~x z_#XK!Xp3+-Z8=oJ(X{6&MblPO3Z>p-!cy{}8HuLgwWC%zmhuzEi=}l#7^cW!4hR?G zE+{MdA>%B+fT7V88a$$}(&wtF@JWfLMrm|Gngih(9SL`&=WzT+iy=o2!)=LHbTgg2 z2g{1SOojX&bUuNkA_Mxv8P1IIeZkRVjRt+vmU6P^x)eKfJL1NE3Y$PmR)~p(yIZl& z@Wbn!uQFmZ##aocw38T%^`zKdVrJ}HB$U!YVpi<8jN4ISn^-o|Na-Z8L+lq6J5$6v zi@SG;^`mwd1;=AEne?F&b7EnNT_xtm+A?xnV(-`*irJy}kVLq9UTi0m$_dpQaX{>R z#_g#p6~;PHJX~T?jIW2XQhJ9HNF&_6I5vxw$P4v0;?P(Lwev$mjCf+~1BMoam_xYx zNiiC$QjQAkGve^rsVv9f&|;%JDn`pu%J2|}&T#i}vB?xiNGyw0QY?YU?caS;teWyj z1((NiDUJ%gZX!>O#aWKgDs@$iFQrT=4W+<0+_G-Ukp3phlbP}`8zN&YRn~fK zVr490Ngwf=B$~01Qk}PvWA0x+T-o0V$D(zJ5spS}1g1uNA;lIqA@|fMf9wHtz;P=|08!XhiTFKpk2 z8FVz^OAyrFl($ouRon)-!*nauIn1qkF%s{%9Nt9`PG)|Ggl(kK>9_E+I{%Up;M?UU zIKnHb%lcFCG-h#Vc%ZKwHOeXQO)4M4?L<8;p>E;M??dhZx$|pq{F;vE;D}(wHop%) zd`qR-<~FMT2gb?`hiXvuxh?QmH1wwN9f@A`b4~S_fLHy)8&&@Z6VA=(Rlm2X{$-F^ z{XVAphaf*w{deL1YP7$#V49UIWJu3D|^+yJ*a#LJ00~( zS&{zX&h3!*6VT|K4#&xe*?Au{_*zID%|dl>hmH-07NM#HR5z+m4A&yT4o`^!QnUH-)T7ftjg^mAu>ZxmB~pJ$DHO_l1WLW3s(m%y7M&xl(7Ylt z)S?RlGM|LT7&y9d*T?xl{1U{Bb(sXOP^iTqAU+-`#zxKdd`u(`0ZSm8WZPTW6B)Je zx-<^LP)5P#A=Hc%zw*`6tnA?|)S!pqlM*SW7GD*aJqTqA9nZHurbP05Uo#}}g^wnS zkd=KE(hUv$tI?v#uf?m3YsRq=9H5XdZ`{eo-5geE%pvFnDG_d4GdyLRA?)UIPY=F< zHfz*mYN843Z(b9rMP_+EffiZVpkrRYkGI}`VBz~=haKYHef-iHG2deDz8J2a;#?mM zJv}^pSewY33rixOTj8HZLy@BJt)bAU$niyRU6*vZKim}=S{oTu$pq@G@QP3<+^emZ z$)AwP1}~GpTTI&-6QMIii`$;*AkKkkk!acU#`tV)x_;!t=Aa?NiWd3a&CPbmC; zxLxF_Q24XdP`C@)@8g2xpJSZqGxq;$argdzA@soD-z5|F|Fep{D;F|&#S*xZF;^;9 z-TqfFt4?+HyL72)e8tjmCF5PGG`@mqeC5*kilyO7#=BB!d<8Sa+3(V2A+EmmzhY^) zlJTxo8ehRQzH<3TTfp%z-n?t4f4%_zmCHZa0?woU#hb1k|LIMD9h3XGwX93d1~|;C z)A?mn45jAfwfM5>nh@V&%foW=>#i7@%<^}P9r)0yMc%+M#X5~R3S%mq#4DbYFfVAf zP9w6AJQRpKJf{*gN9S=I!>qBy*GM>Gt$bx69X~NSj0GI4ze#s2@uKG>5=a{{iRLEV zv4oe!*kBe+F4Zz)+A2S3$Sa_;irFw-$eSqpc|guWkyari$K=EW=;3F_1StD?G6BlW z|0FaY6F|PJ=w@>=K4rgPJc009v~ZQ*qG9XkReqC(t)o_XZHo5CM@Clpts1rltn!;R zZ1qoOh;PdzGvgPE{fu}D6li3Y#Wb=X&a88|Y>B|f-*J}cSo5*XxI2<_ za0+DhQ#yG5nA}gXZFo*uj!Sp$rsStsvFi~I<_h2>vNDa6xYctK1=Op@>EXERE7RlX|IWRT$5%w`Z zW%dzn|5bka>?D-^Ody+1=I6u&*opk?m;hxzPsXRr{Kug67@xZ(-E2+9r>wg3MAuQ1 z7OwJ}l>4dQrrb~cM&)kmw<>p2zgfAP`WbRJ^)n0Zrj6Q|WzlY`{?F6%z(xotcxB}& zISa@du!a1>LS8}HFEC`&f_|YPn-=s7&iHI0zwo#;@tV-@8BD-$LN%Fb!a$S#TRWlZ z@7K??3M&`rd8`|DA?&7f1^OW?i2&@TbOm}PYl{HvrgR1RD65SC?51?F+hBgkbXnFP zA=pp-mI&;pyu9IiWw|$!Kf{#=cGDFhI(Xd^+)aIjkTuQ^M#8%mCVSm=O2H_g{!Czh z4PMm8Okw~GlUQ6;P)Hw0j&Pe&atlkFsi~R7|d%d*0-{{DS@i zjy&pUtI@ZE{p*vyXS-W39@E-A^r35-xn~|Xr`f>$8r7)HO`K=GPINBvEX1eQzvlzM zb9aqt{qY>3xeOP_p4zFb>He9z1`nD z5N+cwJgGdhisud|wpbGyyCkJX-!ANyWqF-2i1*>mt=QH0b;MM@oaw8myQnN9 zJN3vo#=DUDG-BkDV#|Gd>gXPa$Fse=^ZisYB$%ZVzZjscROPrJ$K7;)dOJ6L+{&!f zi_ip{(%g9btak3~X`?e!A1_APko2_C+2K*W-Ay}Iv~wSxHaaWv$`H$aZrbP`DJy#8 zP0{YUaVxt=-h$sDm7{xvi~6`(4i%K2hUVYKZuBqcNi~p2mzPsoSsy-=pP9B0oR)+aBBi(Ee%Duqi zfZQMMQmjmi;X^6Ije*k0oI+%n7e8uErp(3YN8POtN3V9X{+vk16TDykb>cShbFsY>^%BYvM~J737mJ)+=W{_z#pNXW)Ab6!RkHa^7c%~x z{MXBWqhxcHhzrwo#baFe<1mD$=^ygUsys1Y>s1% z+5bDj!34XLC_q0F3Iik$5zVKR5MC~MuJ{GV2h?mAiF9xPGc@A_If7l|vx)xONm4E@#O8nI3^AEiV1mgpo;ahC!tb|M61iJQbN z;x3UFBt}n+i+N(PpmW6_b#MO0JSTOY)VHSCBY}R94pd5A5NYy?8wN z(4PB3QO}N{eD}T|<@V}$Cko7EfceeEaS^lkaA&%!7G-sGF{Pd0>z7OT&@ntBh(2drovUX9FWwErl2F$e=M31uB3iZmn2MjguJh zWhS3S6CdxaxE8^&8swdl6~fzRtuXGa*oQFOS#iG+qp=%7+*#p?u^0_=xU<3&Gh_Tj zGw!UQ=!Cmx#mcGOQNe9u{U~;l*dcZi#m*AD#5y5&+*#qJ6_1_7qz{#t6Z@2*T_xtm zvKconv3G1G#q7|FP~x2xkI+ztTPyxzK7XGMh(hsJtPIX}d6({T3_V~;SjAoR9L`J~vf6psphV#MLGGA1=R^h?wq+M{B} z!5_C)+-D+>iw&hXLSk8rhhE%T;e}3$nL8myN-U4HX6UHUlP2!eSSHIcT7|BP{goM) zhQ5H3xwGO520xI_vjN;$@gfh}8AmgPwO*rG8FLxq5wA(28P$~PycUV!=7}4jn;Lxy znPsxGutLq*Iq1uNVSH&TH@=6VGe&<3Z`_B$@2sar&wysMnu)YahZa93hR&4QVFZL0 zbEjFU9oxf&9@S!cbyA307*i0XQ#Qh)yXovQnX%~{niijc;EW8UpVm$NF@rriE!&f# z8O2ae>)z6&9LwM%(rG!26z=Y1X52y59-f$$!MXFao}SbuV>H7K^OEV1@fsuMdQz8+ zI1@d*+$0mvsA9Y$JSit*ALI4r8ArH#ZpK5D`gl_BjP{iJ-e$t`oQx5S*v}IOWbiJd zv^-BL%y^elzL#N9Mo&rwo>YvsWSgZ%*dB`Bt4&}kg5r44oNy5;YVI?-KyYL7HGwN*+>G(u&iJJKC?WUDFjc}S_^VNMSB(NC^y=ib>rBMY_S zJti1h+l4+KHGb5}l`DUZAFkKp=Dtwq^iu;jwhqqUt6rU8W|k4Gn-wZUz9Ni^=@0Ex=iW|BYh z+*#z0UT@xAj}i#>+{{R<$lOp_>Xho5S<@_zHIPn7P+DMdXA6kz z^+udsJ8c0b9zD^$_5I=T&{B8I`Pa91V>1$&?i=ry%sSg0 zl2YBLnGsnYw>qV|0Jl`mpElRczi>>)f@uqCFtL`OtT}p_iT6EIj$H!9Vw9R`bF0s- zoo3Chm|i>2owEz`o1Bl#_vRy$Gmu`ns;11Uv@oMOx#HYPYx3FW&c!_CtaGbpTeb71 zyU!mtC)-R!W>ig?H+lZFvuhJ`=ed(ot9!dQ44TuohgV=Uba-roCPR^`rr?&k z#`Cw>5zltFY)NnLUNW;sL9`Zgo-Su5BXg(Ccb}Qr<6^gO@tk-&_K+bhVnbSFE{Xgo zJi0|zcz%n_A?}*=yiV?K?oIFFKDuzsVE1Rk%Q5Ad(y61n>#~uf-4(ND%y&;YBco%t zLlB+w4d}FH?F@3TOvTEj$lW(#`C;KA%iVP!X2Am-vPUnB5{ko(o3G1<)@>E!7! zPV6W5x}C@NKonNfU;LO8;L*(Y1RqDtDv&WTxt`3e8g5f3Zzr{W6El;IXI~|Mz%0K- zK9~6d=;w0<+`)W$qmfp_kNGsm>euRLaQkuKw2p3Ox!n#M*4FtcgkS>CA^|o76X40Y zp8(H>f(e|7NSop3FMims;So&ll|Xte5$31&1l)+jlRR%JN;gxYhpdMfOyDgfz+sXF zYVA5Vp3pgE5?Zi>yJX^#-TQuw(6~bVzQW>vfR#nc!^(wUIsHk*T{9sgJKU^=H=X*? zgp924fEH#twN(pfGlIViXmS0pIqlqICuU@&Wa1(y?%p)%$nGhZwy>;hGo9LeQ5*PT zvmJ^kZQOnjM?0si#uaABP2{Ja;;y(gH_xqmIGW{_*IkwEj-GSUXm`u*H296q&2o4B z?1WbNY07IU*b2P@9WuFa_OowN@>*c1`{iTTbR9CKk@vht@{bzH*Ef=X<@Spo)^*r( zjl6>!lkNRkqi}Q7#kA^vLx(@%+0m)4o;>f|nwrF1m>nu7H;lTRB5m;Dc<1{B2Fsuq zhiYFAB-4NDY%`bIFm6uvy_nEo6V3P8KVGBkq2$-XkA(02mi9O++v$cnhp>fvkk~w! zxi{C!{ly{TiQ=guuP=B_Jx!b;o+mC8FB7@fQvWC7&pkTU9rAcY+#o(BzASDLcZz$( z=IFvqxQlp%$m=2c^W>K-6VDOn8{#zTGI?Al{zCk%xL({OZWcck|1O%>A|WF_0l*9o z7mpFm9hvYyLo#n?4>|BSS03j5NRY3Se3N*G_@Ky3duEV|p`2_knrTkR-6iu*e1`KH zo-7y5YmXpb0NG)HdH)f3y%cT}e=F9B&x__YNYMXC@>gOiMmna~M$8uT#6jXH@gCkP z#R&J)17p}j;#v~Jmp}9KhU5=O=zk&l6F>b^JpW82kn{3~OGo8IO^DrM$-bDAec8T+hvwIe$O$mOi%h$rry~|5XIw)&$|+nnHfLFJeECJc z`4)$biA0o#800lwp4#$$LA*53If{BA*3MTl8zKQs%kIdY;qm(+!ppmwuzy2O^O zk1lyEIuKc%`wLU2VHU~|Mc%bbqdBIXP|cx?j!G1xEXB*C52A$D@&RAMcleiYEOF{% zp(i6lb4J;T0jJxEp{L`WM9|g`Z6R6j9uGqiw%%3sgtjiE*Q$`i`CW z8mczJ+QjhFg+E0U{|wd5x7Z7#r`rohjn2fQz@zPjlTOdH=WU9c*EY?234Ga!<9S+S z3Y{n(m_(XTiY}>-EqN?vUs;7$hhbAcJ_+0K%nd7+d|ZUe6)&BX(|c)cPTr&3U})O` zsLN1nmqKjBK)*p7y!-(-z|zmxe;r=l+r>uef*urus@IFqD#N-g-Sy>bOFoS)Z!>mz z8`n;(W&5BZj?w`tsSGzeWrMYJM)Zw#pdQ7bio?7!ooawgB2=O^NOb!H|W`lowJqD*( z9Rjg1G<9rH_U2+c`E#+I8$!%Oap&Tw%1JOR(GU%eq29>sPsRf`tY9$bf;rJ&!yA*d z!yrXCPZB?3DA!6iK{6q^)p1bH=&a+-TOgED1AJFHjo8XheqVQ0h%49=U zS~M1Y6D}0H97>qVy^;~ez$@itsx(^y`MOj)#G_XFV-7M-%?dFU%)F&{gJ){n(5ps_ zrvCy=Z6`67K8DKeC1$2KqjCp{S?QcbOzkMKP5RM{+eu=F^vfuAme?ho2i?>zp;y`d z;qLMDtC{qn3eHJCf?`*Rx#@>9a$I8X^cyK=Yi2VqosZO|=7j!+B*WbYq~q{lrS?>n z3e$%$^l*tq={(C%?aldDC>N(YJncx$3z^N-eQ0_Gwev$gOz?^6oO4et&|`5Yr4OTc zRLF)>xcl(*N~Se9WHx>GQR$blPQydo8hA=B{Yr`>B$lOf#v!#t;-qvln>sS&c-rOZ zM>2R+sNO`LnrP%*7tZ)lmLRV=LopLOI^Zd%7<;L=pCFGS7J+)C>-6k&J>1ChHdX8+5iduS|v z5zZc(w_*C-)E}E)gOFIZCqdU{fu z=93s^cG__F4$aw!v0N|BE>80^DIR`_NhaQW9wQ#%Njc49lzMZv6mz-F>zGU*PwL&A zry#Muv{ z+HvcKhEObo*kStYeB^(;Uzq8*tn(z^^U?urbb@K4l~L5U2a;^b_G}fJhS1QpAzpCv zC~+ayTUF_6_p9`^`&If{Kc5*^=qIf6orvhL(neYfiIu*dRe9bBsHRKlTS!*Nfv8Kf z+qp}JLLF~FO`84E6H-PY_!*SI?5z8&j&TI07rq7`%y6#-Qfi>_DIA@62*6>YBkh41 zUB2PdiqLr*K^=L!N5-h;I4UYu=RdHyI(3In3i3w%H{j>sx3wtEeg1`<47YA;j{#;PKKJaz)M;m%S$A{E-S=$N zg|`@DA{g`WsKA24qb8qSbFRDf{_EPf@o$exjibk7&Tx9d3-_n)QDK~x!!OlL-G?IX zefPKO;PeS~J7fHadq(CRo42wbhP%*s{Df0W%V$vbw; ziN}o^F*Y*4Wc0uj;5{PJtmIPa#q#(YX&*i^M8|OcjN;Gf#(#QApU04Ff(KNK?kn^`qh|D5?&c6ak|In@F;U6(_gf|Z$(6`ngr zVtbpykyAZ)7I}{6=8M%WT843x_AcY-%tIkkYSS6);<>ZPLp*mT$(x;^6C*iv1*=($ zhUIt>C?Kb(Hk%CdR`o)#xk<|^Juj(w3Ifft4D~lQ2s8ps5v#BU+Uo|0Hyf|9gqQV7 z4zgysAHRRZiWr1~c_nEU26N^(#ad~lq9x&!3daDmJi+`Mbm9S>vVcxNB`2W59$*$E zV=9b-u->dM?$^Hu{T#P8UNHXhLrLy{p7v%>Cyj&k*oT`F&Tr=p#A)rm$R*Z(&TmLOT)TF ztMhTI{E!(vy1A99)!D}2HGF@A7kbOQIdf|#!)SLfk)6-wRNk$ z-vwLF>T$9=Xk9q-D0W#`&4&Fr48z%w7Fj2>h!0&7{ZS-5vPIUA4e;6sliHIlqD9c- zQjT?9==$vAJBRLe*WA9;XjU?bXhojxp#NIn^iITdUsKE z4_brwT5evCVV&H{KI!rBvthUViEwu6`-k!j)LqjjJv*Ekp>?e%Xl}OW?Jg5|vwimz z#6CaG+-u)#Kv&BuhTO>=b7D@{)Xg~Ty`tOgYrEsg^cg1|;vU*_Q0$1`!zRV!qrdp> zN_b$fOWt!|*W7YX={cxJ>f?w|5OFW+IVd~juUVK|bU)0>?B496?p`{b+!uNd>Y6gV zB|gyO9^DclmnK8H9yX|JWN<6X9dg*99?hv>k~X&aPJXE!+v!BycBnE>&%(Wc!t3x=5Fpa z=rVUjL3)9?yMTV|NxUsSPC*L|OGoIaW@CGXBCw;k-bMtB-lN-D|S- zY>T^XR^#2ko%5?61-$2A>hyUvQ)DgKp~-#1 zYzohrYBaW)spgbL6s^dMD*9g_|58*WJBlf5-s#1F5|C5dv%qKvJTw9}Yepl`vF@S0 ztFuA_+?#rw)wS1TB)~a#wg@>#WQ$O~OuWLi3)A~K??~JxekAS@`PLRjFP*TPC14Q}PAkQjr%VOy>@dj`cfvJR!a!z9;hfj1hRtE14zoe1L(s64ikOz4DWGbfi4lvUFwi; zmV6iKu01Bbv-7UJc8Pn%OzeY9qLY{_@@YEy4;9CX&+yZA=tU+%Q@%ob}(9z;Rg_kP)EU{Mpi^Z$RY9w^CJbq3h z!F$DL#hoH;tPF20b|o=9_L6**c!GGEc#hc3`y!2-*qxD4!qYz9jbBQl^jAt=A^8Ex zoH?XDP3I{EzKQ5NEJV5g*II~Z85)&S=v#_BE74_t3fhSlp1yRwXBS#N--7v~iDk%s zeXUGF4vZ;}UG)R)Ko9=2cA$fsft>$}9q8a@Ag75Ph~_@M2KYZ<5o&A@>bVwu*RpLG zg0M+4!)p&<0@^AQP{?w#mg4mJ|HJkl-jN)-7&Us6)xyGOm$<-?!f7!7CVgJWHn#sH zpcZ+Wy1xB~2g67vRek%{ihES4%mMlM6`hYrxc|O*nc=h60rZgM6tpC z(~of*>_0BWgWG?uWYP`x9~u<`_MdDYJ*?FReLM+|MS|L~+JVE^GsZNUEXBQ`*T{bxDF2Kx{19tqfgZlV~l{|uqrVE^Gg zBB>4bpB#n;>_4wE_<>9wTYUS^BB~_qKfH^k!TvLc(!Xf`*@E<8|Dlak_8*>D{nPdz zzMIjv|IqE*e|j?gr2XeMv~Yv{=Q7l~!TxhBvTv~eJVwo={ilqnB<(-r7?!mEv|}m_ z_MfvTChb2oJv7*VjIk?e|9OeYB<(*qw-4BVc$(Z`|KYrRgZ(GY9R7Rup9hiMzuW#( ziOL?x{$orbp8Y2Ub$%9VP3%8&S)M}Q6vFAZ|DgScT_j}eKfL{`9XGCL|KUYqJ8oUi z{&NDvgWG?23)sQ!Kjt~xYeT$X;ZcISeG~hSsdUo*V=CRm{&PPfHrRhQLQ2|yUN?eo z|4BnFV4uNn(*Cm&H94sLrvQQ9WB<7u88ov0oR9SPxBr++w zvHXLZfqDkbK#R~v{-3r1p$}Qc21G~5!4GXfJVb^)cNQ7(+?iz5bH_*yUqOq-1a!)8 zum)^E&!B~0#Y$5b4_Vlz2rfM{sd)+l&9dwtvH^KnH`svgMj9Ki!t_GCV4SBA(%jD+ zbPTeWImkFoJywq5h;0^@xn16n4%s=1t0Mo?pGy8ZiIZ8ff z)b!CE--u5W79SX@n1Va>|0~ZyExe_No!xK)|93z51S?S6?n$$WKjm8h6Wuwpr%jC; z%gzCeM91xKB=RfS=&7hih9Q62x!_;33?2U6mZ7AzN>-shT^pH;@Q$X+SyRrLXKtvV zT@ps2quozWm>B=3j6%12Mxm9SQHW}LUCO4$SQPs6RS{a;h}h{Gw>28ycr>B z2TDi%&2pCIZh7pQHla*+&tungJB3pxiexcxt4VlDnu*K0Q5&j;KeGfJd;3Ld1}G`wetM0 zm4_yW|F!b`zhmXWd)Ry@p(JskXE6X(YJGE?aL;deQSlf=?sC{rr&N({J0krExpAEYHq;*WUOt)ZY8l z&i%-q^om{fvGIHVK6`vy4&?Uu9;|^~_KKam&EELYQTE1nZ?kh9`y6|G z^ZiQvtSMbRO1u>%e$JFwekk$QbycO`eOwdfOoP9eex>_V_pK@$cH>zqHGqVY$bniFez%AKK$z zv&V0<$2(uyliss)JJ@Ak+qu|~TiFdzr!q8L73)!K_k!~sd(xL|7?iebx7`b+>{SEr z;dyr1X44akv+T0cJk-4g8xD2fVo%y&mtkWTqg~3HbixFlCwj`Zi(}3$wmm#{qn$vP zOqAgp@bBUQFg!K&-YxddwsH0$e9_*12}Y;Kq4_Zs@s!xpaJ~WO7V|+)d>HsuyJCku z<7L~y(_!T?+o{U3oze~)cEtRSZznVK^MeZWa}wKZdxtXY<7K$Xwm(sZuXq_ghgfgl zXp(0+%j0(9W7{szg?CjhRBH0<#9rI3DTK#@LZtQt;{OFkvJ{h|YGQ9k$k$NmgL+x8 zXkv@OXpYC-p0Mqm2zwHhRvBLO%J3AlHz9*>kUyM%M;S_UZD&EDsSxY%ifw;@sDDP( z9$xYB*xLKZ{xRr(ji`IjY;f*|Gx-72ZKl26Lxu2J-%>SLIa>cOcEy5Rdj|4Id|+49 z6xuV&3z1#i%NEsi$_qDmU*bM!lP3P|wdgkuwb^7Ztje@!RK-jk?Z2Qb*o)-*iKc4gJ$UWnXkP*!wi#sW??BZMAg`+Y}`P}`mTvp%y;&A^9E z`j~B_^RU}LMQ+H>#h8=X(H_6a&K;0vkAL0H zy(lls9>3Kdzuhi-nWOsn=j};2GHkKOZ??yOV2^*&A8Xdz7^ceJ#mM3KgUx_4yH}SR z%wY4jJ!!k0i}7*~N8esZyjSlsJ9k_e#+cX4VQK+fqagMgha7v+g%NGiH)g=O=mvO| zWi6?TFIk_p2|UKJ|uR8?-WQ zfcq@=Z-In^ZJL;MLku6uXI6{=WyI7@!)HF~(9Gemw?TUJP##X!Hb3PKCK>e|C z*-*|@G=^!lp=g=}_WXD4if1@_R{X`D@u7`dMjY<{RG)f7u#LXn%l%r}G_Nl{uzZ?@Dc*`#)SFHNKezR|%H}-FT2F;vO2hZ(u6mvS* zXA#a_6@xd})<4b|xKYK^XXy5o$(TQetB+HR*$zeFd0725h*G)2i-1{XMKDoKghjZ6 zOZsu@R|NGD=4D`F8hyTuM*79nF9_;q;`plwjOs<`l#H;55yHU;xR#fGW>Oz#?#h6t z?)5Ky9jHKFQlBxs^s5^5`S3*j&w~-llMxuzi?FF70=7f_+@OA4QlBwB{neplfv^?o zj}PjjAyom!{P8{q+rYv$@N0l=P~R#T0WGNrjOt~8ZQ$$2q5tmRSYr!IDSyxirMSy& z5!N+Ww_xStNX1xdu&&0s2`e8X&CA63PdOayB&VK^=h`!I(^%H>wkzPbY}^%J?R)90 zi5v9M^X(bCy-s@S7hWeF3HGT&N-B)$q&-o1bPmFK`*T-fr~KK+-ocjeg@!dQDKDJZ#*2u5I6^CB>+r{AcP76kR#)jWO1^z<8b(y*_O?VrMX%@u)By$JjDQuOMtOt1E8 zT%OctOizDPvV~y0L8lJtV;d=b#`N@8dz}>R|1fXNub&%?fRs|9*1)*7suLO{DLj`yF)Xtq4Z=0Yh&=P(RPF0N>c6fvZuc4u6UKlLwpfWCTV%;L!UL4suET zx}-j19&qUWc~Bn>x!=%>jb;_&j=W&6o*Rt7UTrpk#i$1ydXG2yD>(Aumg*Jgkabvh zVU1&xmSSCmbq&@nShFxMUyQW|>uRis4>C?DZzl;43+t_4ax+V+cMKu{T9;$yE)Mu~u^x3IB z{YFFeB|-fT82=Q3QN0L_#_F-b2zg0;_G(YRQLoMp>a%Nl1!7E3e^X$n=JD@y3{lA% zV;d*}qk0jr75q-hq583)K3Y=xjOpoP8~FO@b@kT-_1USt0x{-84!4isbjTH0>#**^8gGrBjdc;$HCW9@TH2szW39ou8f)WDy$OCzhU$z@vHf|rd+jIe zt?}*4$o+fuc68iiujW}Vd-cmkzj*sIV3S_`JH+_mLp9pps=t&`zJII^^y;yQksOGA zz)+nX)DI5TIREtq79_4sP|PBI{#hUcjn&^ZR6iEf{{chwHPXlVhfYAek?x>lbwx0P za&$FMpS}8kLv=w=zb>iIn8Bf%?eCp{go6>-H@yrP)r-)mSHH9?&_e9ho<3uG`i(mE z&yD^joB<#qD-ZKUb2zlojQi9s#9b8`(t%P5x+r%CcXO4DE&V+RNuxJ?9|^mR6FW)7$u-PP#Wtw_ z9Ajd#K{6j>y!J-?D+&Kf^dR#0;yTg1KN0?a zrtH8`uYeq!Mlpi<4h-0nPpN^Ii{`!Jkj>Xuz+cM$58_witaQYi4Lve}(=4(ErOyE8 zpoPe}XeH1I%|lbsqZZ9Yo{J_U=cC!s(L(2;>Bt3WKJt9%le6$(hj@c{v$$HkO}taQ zM_eO5!1)g*^m};U*F_v~cCb3g(fhU^$5j zt{_ptx)#{}tl=(tpoVdrxw3}5v|_;qh=pR2SS$_|hl``cQgNJECQcH|#i@MrCo`%N zFB0z}tMQ07IU5zh&cT`%lc;G8iJGn^QPWK%YRd0bv8H(>YFbXBrYlHPw2nkYcaf;5 z!_#dRAS%YhOfgGrBX$tGh;cDT%oTf!dEx-EP#opau`ZwkHNA&KP2V9=(=41?v8Ki3 z9MqVciyD*jP-7A`wc3EFX&#B1mXoOI3KBJ~BT-YHg0Z5nh_4x9`@bcRE#mv)cJX6z zm$+N}O8i#j>q1RSiZQW^SVE$r7m=vwZ%79<-9iUyn$-?OO^Zp?w1z}YSCh4<0eLQJ z+#Z~d8k4ALIf5umRS(K=$pJ#yhmIkJ^(sY_`N(H5$nXq#izt)#ZBTX;%nl^ zVy6zs7&RS5qNWQ;RCEoAif$oM(X5W#|54N8j_^QDYe>{|HHn&TB2iNdLo#ccM=n5( z$@8I4q5`$z0`Veok$9t%>Kzq*iThQq@E&I_|iUBS&Uu`%#=^Lf;iPd*R5s zJ!*?emN6szkz5=P<`?OR2rVfqqYi3YR8-lo>_BlnZAI|}6S2X+q@>K`NFTWITX|HG zk}@SLa{{Gg!OUWc2p2X@NhOLw7vuJODp?GLBFMyP6xBpzn716D7?Hxh_mrU(u>Fw( z{vi;oHWs-0{^wlbqEJaZj=Gifb>i`EwJga0P&pjGAjxtRq3)Ob*Gl9xYU)7K{8vhZ z?f*R+`afGD=X-KLP$&F%mI(F7@~?LH{Yr!vu7pCPc&x!u3NMGqO6A*)BeBl09x=YA z!@ST17b;kyp<+Y){0WD(13Wk3AC$iH6V#pZ`&sAX&=t?`o8LFj3N1oMte&E{A+Yt1rHK<9?Q!(WZA|>Xh0kR^O@9D$YG;@~r8z zr}^$F6%}}{z?Y`au1p}|Su@&1`N16b>b*Jb+}k&V+qr+N?$PYjd9`!-+N{3w&ad`Z zC7TFxVEt4VyAY1KHq@vb$cIw;M>>a8epD2 z;k!2qlP=?z^s;KE%$sM_eMjF}iA0U(9e8gL6Eqt8`}K7iwE5B?qXNf)6G>_W5=knf zkoeG%3XX3X`IRY1)~n#iWW|ommnzyg)DMuhR8*3W9G}YAAi6hJlJS^<|x!`m%aWeN9Ch zc{^w}Q|U(j@HX{t>TQ~$skhfEP5r$FYU=N`)pV!f)l#fyvVGWYO(N~zgiV6kaoI(@ zo*)-`f?WCN339U4Jf~C3w(>RD6MPl+1i4L1$Ze|c>zke+!K>5+ z=^qME|7hqQ^xv;Bn-nS7t_OH&nYsrbTj5B7^x(w)@AVMltuA8R>LbRjKH}-9lXyz% zB}VYOi4pvM;>Gbhijk5%1rqZ&qlPKYe)aPT=)HI|86Z#AW&ips%ApvT?e^1AYTYM zD0 z*Z6V-@}hwJSDbm32IP+*#{=>^kZJzGg8Wf{m*7F0kheswCn3{L^s61D1aPD#_NFTVtNQ9ynK za%n*RCFFQOrfHX^TtEJWkZImE^=APp;jtp1a0=w|fZQ80XHLB(YITK-yBU&lE6BXV z!CRvE<}qpUoBFc=Tj8;VXTfHPT6_f$Z=>+#ry(y2$TTjL2IL1I z#{)876Uf^#{P?RO^HvRCz8>-l+s_{bmi=$nk(Y67nuy zc$g(>^@L2rg)eu6Tpp1500laWiCV8)C!>bGj7_j9>82xU72r2cr&-dh9$>PQ zTWRK-?Ft0a-1QGfyP9ti_K*G_;=TvKrfU2DoO{o`ch8*5Im4ZqI}C;y36xAsa;Uzjmpv*cnpnOdRC~eM7#$EhhjCD5T6f~+G;o@J{l_D zs>XlfucC>TsTmMBXVik!dr)Xh)d(-j)wD<4li%mnNh)cBL)&7_92fRh1Y@m(a8Us+ zuouRS#}8skO|ixJi&{c4!ihKW(H0qkc$i}+0QWD5U41!OQBE@BkM>Ae$T0es+1%Y* zn001+RH&@x?ip-Rx@bYo6kRmFALuIlk>UZRE!wYW?UunZSyr^nc6IWs1YJn#E46E# zq)kY=%vI$CB*l6d!X?mh79hE^Ye%{FMVOLD|0)z+6sIKo<951<{N{p=wIV-`Wl?@u zXY<~-VePLuu>w4oe96@ES%Tn9{fCYHPwluyF$-X zLLA){o-MHZCC=&M$!^u%-9yW!9k!h|JeF(KR&PxRAKw}H;A5Q?>SNnhY6&iF5YYw! zI4)hYZ8o^$n6nW0gr}{^TwPP?#I}cY4}B{^Qt8Wma=Nq7gag86TW^=)bTuU4sJ02S zuLwO&@d{SXb_7laE90qc%2gE%GO@E}ru9_!Q*aVnJ=2YU8wtktj z$B4H-t$wfi%~ij8AwWO<*EfIC_d+`*v-@QsqG^q_Z0 z&J>gp#u;aQYC?~)RQ=7GQ2Gn3Qk%Uz$gcWJ&=#%w-1Ecx;Mct-D2Ed8%!Rn!othzM zY3hWuytybM7d6R)OL`yVDn=U&wsK2)?Q=i8#b=kVUST!JNw*q|OVzBjvcQj4+BhFR z)Z8dPep+h{UvCZHWDUpnO!#6KUqr34La*YB9`MZs-!S(_wVuj_4!^dZ8snL^(r~Ct z>#4lKR>L6RxWOJPJ^1xB$ic(z^6-fZkKoIMgkh`te7H_Q=!)3^91F-Z@7%-gaEu+8 zmrx~0EylTSU)nXnuVEeC@u5~PE4NQCSQ5S~{m~lU*>4Ru0@m;#e%<}n2`S!>@aqHDaeVY_IjwD~+v}_B7@ft^88y8`e6s)=GT`-zN>m z*GI_S#^{AFw0hwqEEuVM&2`Zu>>ysh8slc!JgaJq02>1G7w_r_Zx}cx!D;BP+tSol zXWZqwJDTS5XuDh-Y4_4f)F%y<8v3%;24~x~k!RaU!9S2E+tu3EbnLK!x zQ|yYcG_X_k)aBAc-ZUn>#!GZJ)F+X{+aBD!(cMrtfWKGn z#ueQSm3xVL91-}6wBI1vh@OVW-95eQk?eC%!)pcH7u^lDFUd0*ANQ=wU66*)K6*K)1x$<7g@h&NNoxdJng z7RXX)p5Q1JXrX@w9yobS6p=Vb-zCw`f?JLUV!NLTu51Fa-A~2wEI4-hofrdc1Y(EZ z31=axW4oUUlhlR!Udj3t(Ua82tHbd6i89I&JN-^9BXK`{wXDMs!Mle*e}xVc&l5dW zp(Dgvq5~9KDy}73qMx@#W-b#B<%sQmDh4xoknTgQCwrWh#Cx^Ca-0Z(yMe$nRD{X% ztOC!vI?+t-ju?2(Rf%EFA-3|w$iC0#g&dm4uOO~>H3BdTgO(6vY$~|Q*w%<`45YqC z7>vZOr#wzAcp`|nDZC`|f{6RSdgWf9Y1xREHv&S0x%Zh2q#5%K{fA3IZ4q|@XTjGoRm#LJlVp$0^%p- zFcVI}Ggp(crHk2SDY>+Av5q3npJe*DJYf!O+su|&$3LKJE102(m2-@xg`T0@;nY)^r-Ft09r zSW2D_;XF>kY9xf-X1IWj8`>g+v^*_UKL=9jS%|^8e*Dt{K8-06wOecTHg4 zRW{f>BZDX4Np;N|L6+Sa<_#Nots<{erKCI-E*%gGkU%m5n&hXvC$z ze(H-3l!Jr!8iQX6MNG$GbTaTbSft}DI*IVcxbe6s3FJ8KanOdLoOGU%cRDc+CFv8e zMd?6dX93ILNqmEddFBnvq?zi2DHTs<%A|qmXUOtzBTf_3&t&Vp#;j245LIs|Y(8=| zVDC!hSpb^;n9io<6PP_9u8*mTHGQmBO&_aO)5pje6=nS%XGI$!GwSEKSbJiq*AtYM zyk$+EBsKw<)`W)^Cg0ByMAw@vg{;XBxJa-B$wiPrjsm}GO*$dbEb5CGU2l*J5Uc>j zxd=3sLyWF9c?WEQnPW)e=neQdw8=lfKUi`VqugB0#vzy9Xf9$n&Y}Ko0gf(*D)+fK z2UW})ZcIWcTjMmEr;{gg&;9eVBaig1&WXH!@_Bvb!Fu%)4%VAIIa2VzyijCipPLLz zo~s8zcs3Bv)oXHjuO>~R=jkE-2N+tklG`Q8#&qUG%`wVl={@?3jzb5uACUjt zaBr~Eds%m{CEgYHJUaDJ9NTAjJUQtE19<5l3!TZ(Bi`ig*g|#usfO-tcpXEP2!)>6 z(&Fqf{g###7Zv2?U)HXm-Ra#*ioKIXrMKRx-pSv3>s5N4$#5-N>YXe%V)fP+OUcgL z(u2*R5s-)RRWT&b_45vQ$y#@3loVu|q#ruh+g{v-Blxo9F@57s?bp%E4O+WnSJ&%w z-TSa}op+1oX`#pWX>EYx`YKKxP|s`O*uK%;6i=S+!SRNAFtuJ4)Dindmc5@Gaw-vp z{W7x%Ip`$ro!Jifc>J&{Ca&`DBwRVlBpjty1#~KY%t?5i8y1Aq+;EU^x*N6$XS(6g zOfEW7VZ+$JbE^!b0Rg8FAqN(OZNjh{4iaX#VL`}EvRN`A$2G|aOy%EVTvy@8JySmi z{0=`z9;HRJes^Tgxi^I!PI+J>2y@+VkPy$nqzHt0Za74k0qc|7y)wYwO_>QfbyH?S zE)5Y55;k$eg0QI@HV8R@dNl`!2S)#Hgw=AF@B|f)Mu{)u7trPn^Cul{aW|1H&|w$U zB@P2Tk46xY$(-I?7H34uh-Hlya|&2og&($lYWWG9G-oe!vh7g$c4|5b!{*K$=$tWv!Xf3 z#m&JCInm02f0UvanfPoPdN&BS;wLwUWq@Ni6QaaialVe9?!+H6-X4vM8~tQNF&h0K znu^_F?Yo(kENkx$8>Ln!14eTIwV|nKp4ywkLjUYl&;|Z>V#MT{A#qbo`3658S8>s# z@t0LzB>f*ai^sMHl^b}HID$zm7JK2SaTiKjvS%lV7t{&Z*a=^8u02MMEW2oOr8=9Ct#GtWUF9KPe14bEhLH_DCN__7 zqt}#Jn?+kP@|efWh@7}$ewI7{(C;4N7&+scfvtPjwGeLdI_aWOWg{ypCux6Z|JTTE z-wZ62CjhoMf}2k#Ou^ziGyh>%FJW^x)_}rDYh3K|uL{4rv8iWT>&E&Gkx^qVNo^NP%feXE z7>14`1W%Ud2llETI;nm|pJ~49jhWsV9`CNm;O0X^k>F<;$xUg!_kdZQO=17`dz-?- zTIc@D$o93sCmZUZz#PNf6E???d&2T7p1C|Iu!Vm)dg@MfQs5oPQGq0NQs8a%aLSY? zQdQovg*Vtb@ua}5cry@vunhrY;n4`AhOv_Z@ixyrDe!w_SgiJhUDy!4+uaj3)S5E{ z3zR1X>Y>=4u$i$Gc~T(0V{lIj%t1U$u5(ggI29vaYzTFQpdg#@Bh1H-f0-FaJ}K~& zj3b{E*e?Sw=-jOG8ZBZEu%v|e&JYWSGRl(zi}2dR-4nL{qGoujg7WcBK|>ApnT;Cz znrqsN?w+u*;{omXwy;T1f&9BHvU=#ej$De!`c?o|;deKF-1c=EVDyjrxBbT8&opleLUf(3Vx#?r&q>X3i6a^;(Q88 z*j+)sk|r+i`vJ!)ocd(^Oa*U|5cc_iig;8(z8fLo%L?*Vk9adEoRCi|341A6q9B(j zjK5aFY6Wjr@ID0}SCHNWIzLU5izUDhRD%3e5%>=Zr(XjZH&n2>f*lp)t4*d4P;j_{ z7b|#~g7RoV(0#7(Zvh=7stet?3*RQzZ{4b}@Qxz*OhFIUT@=7lu%&`>lUc;~QuvvKV0@m! zFHktY3S$0=3a7Ua@mu|9e`Z+32neuP!6k~|{}CenH3he+_^%cGMZu(i%g`bOeWrq4 z6&#`91O=-UoKwI62I5;(#C-}bQ}9IvH!0XY;Y`BFgwo`Cr$Op#*jH2B@s+iBPT?yF zfp1s%7le4EIkxP=%8~FlA35dnv1NGMnQ%5C-*b987e<=4Ny_!!(eyX3IYo6Q-^v9O zUM|Ylf3r)`O>3Sk=Jh5NgAESxzaRE2+h~<%Sff_S%?npr<)ef(_DyU5X6|cP-XEJS zzGdzI)VgGkwI6S+E;(S8Uzuy|f89FV$l8C{+CMmK9sbaA_K(fyK8pJ%7FmZkScg5< z&s(fXpPAO-_157Rtx4Mu`kMRH9bRkwyu+Hb)wCvUH?2$8S(kohl^?VwZL+ONKVX|l zVSRNFJ0L{fb=)AsM#XE$=t%Kc`#tHuST3$5gG;JNMrez26{La!6cU3dzT~l2@_S z60G9b_U!CGqCw~X5rfYEw4)}Gg_U2CoK z^TXDj*R4G}tzGYN-&hRCdv;m7_F22OS$j5G<<|;s@9B)mxAtKFR;OZ+wd+&x&a%p1 z2D?&g$69O0VQa^0RykOIX6<^(Dt{jd#nzrf)}D8*T_1C!-}3Lsea~iV&nwoR?be>X zECBl)W5dfmTdY0bTN6L?Tf2U;Chi1S10CmE6F>J`*b;N%RzEiVv?-HQfz3oARr#<% z*2Eo1{nnbe9jWLEd$1eylu~Qgci3Xwn)oRqODiNZXAm|Tg)pvOid?-6OVkT=M!kgp zh+do{DW(XDK^enbz2v%j8IzzF>`R=Wn125U#bEr!a9T?do`to>*-Oy?DEePr$b)~eV8a7fPVnCdx<_Ycc4d~m*X_y^3PnA|_+=6KBKKmY7b?Vn?6-)voqnLKP&{QCHjCUjSxe%vut%2OJbXG~pr zIFt7pMhX!xY$S(>1YzcWL=R^wS*bmoxr73?%b^edwdbp8k5bP ztm~)?^LBLnqt2=qG6$!=d2;@y<{nzXI4LU@I)7MHG?LUFZ1*=awkxWftjl*{|6Vle z<6CRVDyQeVvSOm1Drayhs+?4$sB*rRqW%~YHT=g#buhHKvKB#BbnDn0{bvl1lk>4G z4-@o}mFFD6^sr~XD-n$BH*<0=?fqfpVJbed@^F)a=4C_2wU>JoS&t;@ASEiS`!|#D zAF)a7rCzt8G55N2@*l9t{68UTsS}5ZrQ>;E**Y_<&i-T z4h%#d&Nk~gmh%1c^>0YGJv;8j=lb`hxbB4wqHcZ-;{?*p?{Pf6!A(B?44v;N_2Ibi zDI@=y;$Z~;;6BHuEgHn@b;N5PAP>X0l`(t{=e=<*fo7*5biZ*4;nm!(@Uoq!}aa+17F~?bo!SF0meRCr=;+}5=)TgOVyu|s3AB=`qC6C z#46aK}6TS8%Ug^e=O0?0=jZEUn^CoBEj>6eQg!mT_iDc zo_;%kC%aheA{zJY+d$&DYu~k$vQXbHS)U^KK-YJ?{=G!|iM~X8>W@lRCE{Ze_tUX( zaKL(q*g?EMaiGJ*Zlb3ubcFbh=m3S5il2#==x<2kGVv_sI9&-nM%>NRLHf_KV7T`2 zow;v$@?=B@ea}!4=4O&S>*^#GKK(?Wb9G{vzfjW1*=O|W=DuBXs*RC)!iK%l|ZNJ1rSK5P@2Yh4mLYuRKbO5Ss0 zWG0HT8@Oa^X$|Fr@jizTYzQ$A=>8*PU-i=1w(|oE={M z;{H3lmgine7lYm4!}WC!Y(zFY%124MRq}A? z-|fM*!wybfJIu`IuiJyhoVCODZ&*9bnA7b+#_!+I{OSwFTrlRk&tK?!ZTOSvy`FiY z?JB-~3Ta8SlLC*1^d`E*Nsb*Izu@ zt3kRk=d|aa>}AYpkbc_p4bmBJ%;`N~$OXLzJd?}c^UIgs*?Yjr@AV$A^v>s(GydfF zE*Nv|uxp3)_^Nrg)uFp0pR8%#?XJk`&?jqFhZuiXWOt$aFZmMpU;Rhif7hLZe-18M zvHS;x+}Gm17F3b8k}>CfboZH~mYxR<^)I9*dJkBVGVE(=Xh{mS!^10)mFG`#_9D8Rm6W(NU!$2+EYcNmNMprw|b3# zVLmnVWG`xB$OR43zy5+6YLHItFy^%9sUiNOKAy>aCYKs|emP@Kes9PHOYfwHns=in zt{t{I)Z;5^XmyC%L5y$MCu{DCxK3PaF?PVOB}mB8Ceg=*cks;=0f5#M!ujwl_PLl|CDvb2^ z^u03jvN1mFX=+8b8RHv9p1W#buqhoECiCNW9#31BePJYJ-@vAkt9;{IM$YRov1!IJ z_nm1RnY3?Ug9wk!YmxkxeH-cFNcq2vEZvHfu7$fn z_m=WS`Lg!#RWG$%r-V{VIwf$w$pe~nN;unQYe%Zi_O(cwgB<)IQ#mD=SRiDmgK9_Q zCOReL;_Ys!+tyM{3~lmnG_D-={3>l$SUDxk32WLgEpkn(6I=MUBizGvN+`>%<&@AI zFP9fZx}*fNlg7nTq*KDG4CRziiFim{*C}BeayIA4uKwJi_qR?7o+d|jN@(BY$W96Q za4|27G6jr|+jX51rbDcJ<&>}hdDKC*2V1}$0J1bj*7QinXN<=Fr8#&y@VHzI5y$|A!R(hk~nJ_*C;zW*gn92eTs; zJwXX+hFo2>RIm*p=Kn&KPOn7L(M67Q0~I`z5OgC{`ZxuzRFI$KGvCt+zUIP9wLL20 zCqk%7zI+EEHz6S2l@NGeg%4EtxeC8X;gb~PT8{Md6ueKtAF+>Cqu|MHrCLJ}lxnD_ zX?Q7Hl$G!oe@DxcMU75fFzz>NlhoSVr{xh|(q5Be;Jd&ez8SR2eWft|(N=jg{8o>) zDqc$&ZH-$w+S-r16ejGimoH((+s}@+#(#i_)M7WG$sh?2uNrL~ej7g@WFx2d5#Bi3 z`Wf6NeQM&e6&L5yjo;xhQDcPCK{L|+O>tXg?)~-lNtjR^x*_FgV%I5-ed}n&$ zY2_ocWJyk9%@(Pmmenn4rJK-XqlEFAWl8+VHH%klD2m#<-6|i5H--c8C~_#?%MI;k zeYnp0aHC_rx5|3&)fp=*FQHKRQm90kN@WrI>s3gYQ2i=5p~+kc<1*z-{1`HQit6v( z199+@ZJ>jvdqeTgYUmhO9x2XSAovvocu_QP3gh4V26FkTq@v4H7XivoF=xDD&1eE- z#!73(HH2?jGw6Ubm?HkJyczKirRw(W0{Z3}q1`A$6T{N?kiS ziUHvv{ckL&`1dU6%f>U_sw`)5rN1d|kt%MPgbDV#(oLw-hn&N{K{DZYt5-VXfZInZ zepBXFm-QbXBH~3lza5ff$NiaOL@kR4j+UpGH0m9%!wP8JfVjLO#Zm@y1@A?{X>;cl& zIC|2=cOnsGmO~ENEq+$nfT^D2mV1>iS9ys|C%YuIl`P2AGxX2zjjJ;Mq9s`lM;vjMas1QV0Sv~%aR#> zw>QD4 ze5N?cMB&c8|Muj>`M2%@_IJzt4^B?bF=wZv8vB22a)Oh}pIfl~hr0yk&sqyMc&T=- z&Xe2GAebN9J0-F*P?G8_|KHA57%Yxug@5^M<=}?xe>qz@N4kUhFV0rc$@+gaTRF$R zm-@?RE9cnvQvczuS*K@Ww!&obKb@_dQg@d4U(HsqKle$?N>`3L_fmiPtrW`tpUze& z|5*1@fB9^M^8cr^Rc_tK3&)zRLUnhga=k}7`dSCGOzuOK;6Z}t_#O0uhCGL$*su1e zDrm^>XBtHA$;Ol9oZ;92xQQYeW)8Txmwx#4m0 z4-k7FVmP|7)DuKRU_OBn;Fs%Oyg7+_obYq5n8!&+(0I#uN$@zK%Y*LkOd)~>cS7=( zA-nQ8ISa%wj}tyUPVhMS1!)N$C##Sv!Q&)}#Bq<4&qy5iIQct?U5^uw1CNsu;&G3Y zM~KEfP6VV%@Hpu~)^U%MEliDjobU;Kg2%}UqH&KC=?D||IN<|wC&A<77xIdGoHS$R zxW`EmD-riNX~)#K$H}WqjeDHX!6?Dw za_b4{cM*V{88yfXN0iF|{05Vw?kIefs}IF~A%hUG`hW>A?vMl@E?)6B1|5%o<-k+; zjv|j3w|E8dR9)vruNipSUkv|K z7Q>Bo_TYttK24V;i~}i)n2f7FQ`fm&FZ*N_@J@K?;Fd76b_p|8363gaX00N6gTN}Hq4n#@xozc!iS;}=Lm5-JKMVBB(*V9e|kghXT2&605nN+#g zMy6Ba(v$Btkgv6hmj-bmZq?1hCIff20QHL2i$t=B-E+2G~;dQkG?-+W`M7?DgqMJ^Fdk$Q5 zqAojh(|KV&eNO15!z;aW=(Q8|)?tWlLUH#Xx(G#GhUg|_%%Rf@-Gq2`=pRJCp{TzQ zLmC~GVh&1lQi?h)(NSsCQhMFcPl;FhC(&;y>aWC*qyA_v{FClIbn#LDqHaHcEu{xg z)E_7cqkckB=sLw*jM0XUE`%K15*=Mw48Od^mNpE^KMrt{6&+z1LkaTa6LR27%+IfK zIg%m2i00?$m96Li9c>-PAu=H3u$IW69SAv2B{JZ9RT>7m0@!n;uH~#kTb85qZ(>JQ zTvjQ^z* z$fb9-%#GB)dSFK5-x5=R$rC447Dlim3%o4;HqeMPeQJKvA93YraK)%`mtHiXKRl4m zaGi1{M<(9YGP9Ork7bP=GU|c?ZRE)E(W7x7M`a{q#r%uwSB{!c0CxrK7>7$I>Dkk) z&K4)NhX^?8(BH=xJ+6FIWZPlvL57`90x4u(sPWoKUOPwjc+KpHxu|8(7++A>B{KEW zmg(lW@(CAbm6cycZ45HZCM|!X2&V(p5(A0@JAbcNT%oao8c+pMkdpI-g$m^n-Wcn($N-=P8YE+IQ^DL)%cbV8(PeF zs9B`vT2C|2D-B)ep-nK6Wky6g4+TT6^H4A(ori*W_us?a(WE~-gmk~_JT$!kpUJ~$ zmGjW4@bGA-oQJv}m*_lHmFYUgxK(o9c^DpzA7+o3^H4s%=^otb#FqZf@QYcgoQJ+g zc!cXbgspNDcQhG<1)*{tDv6~?=b?Sgl=ILK#M>yL&Wf{+ZWs`o_9t|>P-7>RJ-0yn?QkL!YIScpT<}uh4qNURa>VW& z_i~a2R$O+|)Nls3a7l|ik=d?6Bk3^to17eyBL!wrLr12kpa%4|X{%tNf+s0BK*4hr zT&Un81s_-NX$4ka%|mOBB3c!ABJg zV^m>2p87%fi-KN!tV2AcV5WqfH0=TvafyOgD>zNTn-r8s#)HA;$jEbZ(;aR|LVhPH zI6%P>3YIBYso?Dj-lyQN3Z`QTMLzT*Gn(W306;bb&v8#iL!1K0^il=KxG=K+yxbIL zo{D@!!FLt>T*18x{;FUReCx=Jr_K-#R&cn2V-69uV4doeWo{3u$_XP6g)}6Dg|dLc&mh^*sx4RJg(q(3jU&C z5X@PCJgXg0p2-e4K*gV_;A0BDtl;BVm>SuUYc|y=AIq@vu>|bN;RWza1&1kkk%HqC zoT#Amu>}1Lh0jrNo`PJLlHWrL{zJjlE_Ae4Rm27b`LPf)e6HXD1$`W*5RXTY63TH7 zc%j03DL6>MkqYwJ9rOK7!8r=vE+NLqhgHPW3a(S|Jq33vxL-ko;~^L}RIr7D1qv1` zI8ed!6&$bNH44rqbin9#6>+bEe9XuKo>TBu1-Z2-<8u@|Uco*Jo<#`S;R>Edh_xKI z>muZ?!^|%oPC@rK;0`lPRRlLEf?E|_qTsWHpp)A~0ZPwQFnn93%iW?7|B0gej1cMk zwulA(qF^!yY~W1@L66;|+)bC-GXfbpD}r7Mp0D6k1#eQ2-ye|CDnc0bYYKl);oB6x zN8vvx+^Z&pdW6WI;Y0hAK_?Z_QxWu6_*n`csqjk`F1L{agQ*I?U8O&$aJj7%(w|rH zuPOMEf_oMG3D474PWQDts}VM8qM<`8MTEe)UL#(r@G^zZQn>7C=*b-mjypcVJ2xxt zo*OB>=)82JOMdjMm@yAynf}jiO`Nmwj6aNHF>D+O62#^UAvo?F;5is-_l57Qau0sN z!qL_N9lv0~XzS2E{JyCPO{xh_#6c*|2UY`ku`u@9edn)MXSS&PXVcYl?|~JVwzR}z z;G5M7QTT|v+(Y)@PUhfJi}f~_<-b6x)x5y#wB14YZy69f6Fyx$z9s~RVz_pN-I7p9 zR`ssx!>R!A*TEmm{owCc{DZw}I-iUqO`I;Q#j z_0?*+pTayJL#D{3d-^tUY_9Y7+SR7g8cObIbTmy0n$QYcq#$H{=rODlC<5@|!s^>5>iootnd z3azcHtgWxsD%~o7F>bKO5a7==se`SoYPBg^R9{s`BS{bl+HeI*ut5qGGsA>7rupe> z;}tp$#yAAVs5m6FFWUdbnz&j1u{J(he}wlldly>}t#<^Co{CBgL6dHNJt_*e35+#v zE%mNb`7r;51I@iZLb&M^#3VI1NYn8`TdKy`x z*Th*Ss<)PQU!l#quBGTbV%nPE>Kf&*b2dr~xqVz6IK|%a!{+Lje)w4b##@;atUV-J z2xXCf}oZ*AT}iN1Q#`f7{ZBj|0b^kr+z2CMWFYs`Dr zp;gwQx2;1jT8Er{`o<|waNnZI?`CnBk|CR+YxlMM^;euJf#bM%q!GWlpibn-S?P|P zYE*jcU5=d`MsY6Ho7EeC*rLC#Z>VF$IFSev2Ox1k-xrm*#9?eEV)FujSmu5DzA4K% z=hR#y1YoG9M2PB*ztIr5qT7_`=<)I}6qjcrE)NYRHRSxhidft+HB`4v<3@|Uh=#aB zIfoez@pXsvSpQeejwXNkhfivPC)QM+sC%K&_$Eefn`8cwwL&|iMN2oZImdir9a?7{ z!ZuYotTU#Y*R4YzSrgyXt%+~z*2S+`o3~k;U$wqkZ3|df(@xhtL6Xm8|nMIh}vl;zcXyZ|JXrCEPZU8m#^iEfT~*b6ipx zZoy7;If{Pt2O8nex4|`N1NY3me69rZEOg&|SO5kmwuMuDAiC%(mt!HvBDWC&N9@Xf zvJEyKyA5VXS~Qx~Fy09KdV!1fA{aVX!CBFqY2UPc=ohs(r`9t>w5>*7_`=B?J|wboad?zYO(K9`H@ z@3DHY%3sshO}QD$&Y#_#%XtAA^QNs7HQkG9@^WVzIWS;{?F7P2inQ=$K-c@w*nid+;Xh0#CZhG!lNv+rme}Twa1;Bq4{l!K{~XmsI{i3 ze#hbb(q^rkVf3##zqqps7ez;Dzy!19dZUa@{U@4`GZN-@)quTzzXdl=i5yD-weFfi z38ORGI?NFOwHK&)aQ01HjLvRw;6=T1bj_1narapBNERNMRxkSk&nau3MKUZUeUdMbs+Uo?%Wj?a^cRq%YvtS;sg>$M-M^X< z>F|U3VC1;c*7sc0LHE`_!R!XVyZ#Mb&pRH*$b%ZOcN3mi$J5=^X7Qb!@PY+MjI_BT zHKQ(k@Eno6&Hja)Ri9R&?(w2E z?KtMlgm#aY6p*Y7WAMaL{xeyI^E(PhptOv_oy#o50wIu-INpK zq|!O@jsekk@`j#{2Os+9cxSf_&B{L>pFJ4;aXpR=pYHaeTY- zfIS84^0Xd;sOZjEUv)xE-e?jDUk=_OdM;$%f+>=bSQrGd9))@eZ;*@vs|tbeC9bD4 zAIf@-z;3*2_4H?9-S}A6D+1Zf@GBmGd%N^^X`CXwcl6A_NN*IeFwYktF={@NsXo5g z@SN2aF*m-97;dBW15M>a{ArHDg~)&m{&a=ngiLfWe^{Zm=m&N9GZY#U58!EJW$;S}nPCF@hfLDu+qy`4n+i9V@7d+OUIb&1Hy0@_dCE72jM9nt;@9VQBio~qCh zqASq>3N01IL`!r&V)ta1i5J)|r@KNs*<-|HYJQMjAPdGeT8-II%aiwF*bVxhp(4zI zumS(Gu1+*_2>Ctds>CoKwSld4TUo$mk(+J#4I708X)LTyJsJmNX%{lKmx^^X9+-Iw zu=>)ngfSgW8@vz^{KfU*<=5T z_Ve077@}cs$$@2R$$Vod0xe%fwv-8%jn@LLluf3TITuaP0Y4v4K6Py-{mC+)_bfRW3wuSP%D?8UGJ-M+O2>sOP)`cDhRrXGF{|tKq47!p1 zDHPP$o`uv*djYy>6Z=EtZEE)gWixwPE+!;<9Yk+#&%oHy!ZuKWYBCXrETmRJL1KJo_%hw71KWF=N;(!KkCXGzW8q zJs%tj>>d!M&_00pPWD+C1UlPipoNaJJ43AF?X}G@CD`XBVMeewL-elpiuQOxaDqJz z!)rJD46x{K^ZbM!b`RL}iFSQt>uJA(x~|mhGUQ$bX9-|0YWCM?ztvFS{?2Fz^Tdbh zL5n=jOtb$6ee3o^7#KXZ086hu3$16^CxgUik3hZr_ULA8tEXY zGaz2N&G#u`dpp#ZVVh82BfB#Urm?*ooHOm0AOs$F4}pa>wZDa4o7u0y6tnCtxHh-% z2D=vai?EVx`yd3$v6CTaOM5SDtCf8=TB)`DJ_^gVXG1e>>^pF6Yu|vFcJ=_&GS6-y z+bS7(JJ_R9`;PY0FoS%1A@Ua32T}V%+u4bPPWICUY^)k6^EkT|WIWzJ4yM}0z9x%} zWug(g+RMQ71baG~zMFjzTIp^-3(Ky!30-p z_F5FXMzgO1o3)yq1j?5*+vx z*?EZkQnN$N9Bk2}*^i^&?AGjiU@v<#dlIm(Vd)TUuV#Ob2HL0DmqAb8Xf|CMzSZn^ z!RITE0K%(OyBV-0?Bf=|66h@g*g99!76N_=L8=xR_9Wz+3b+9R zTnD%laM~iru&;ydPDeyX6fgtuc{IcIfDw#}GXW1F<1E0>&?%|`>1c5S;Lj*{HeeUT z&jEZB9lZw7$BF=+0lt3+>;^a&Fb8lR;HwxK=L231L2q&pSOfhp0Q?&8X230gw*cM% zBaHyg0^@~%e6xNl;11O6Ho)(Zemh_W+OcY-VdsMJRKP+AUbWS*ze69H3b-7WSXJe- zE70er0**oVx(=`!ns%lkP#+nq7WwSPWB~X*7+eR~A8j`c@Kn@jIw1H!Ltq5P*8@g? z&jfq`a2DX!Bx=ZKKMzgb0C)iTW&^&0n$7{d2v%4F_!0W)jer3g_WyST3ei>P0uF|8 z%>#TCDxD8F9&L9MV7^Ta`RpeEZw73S4s#3ODl|m|a0CXkg@6sAnOgx%VXU_SP6qw$ zfDgb(?*J@-ZiI&a0eFBPXg!7i zeF>HU?nIY<9Ps@tO?v`xOItYL0N#$as@m$an_%Fd3b+Ane;wcs;L`vvMa`!JEONbRaF9?L3BqW8|LNuHngt29O5{(fOHsC zA%bqVgho8}Bd}esy&GZJEtKxl(mp~rG0cs6L!kB>NUyLLfEAVjXnkQ%M_b!=Z!~O{ z{WT0YUrXx+=7#x!PR}K~Qx3U5?VuNW>^87q3<)j4*zRd?h42LA3)p9YQrP_ZB}q%` z4r4IPo%-LHeK%TCx4p>cvGXvL81_lffY1I8VZWBP1O{T5U+d43_CwTNvsXa~-R22U z9(y{P!LZ?-fDg3n00vXPy#NUT`vs^|XlZF7X8%dw#_Z?hGy723vTk1kRvz1jLcChq zmz3J{d76QNJqrz`*(b?bje(Lq_KhZWRu7dj>=n?c&pw3QetQ4d!SzRHzVdqEXF|hc^f~w_ZypD>GHf5lDhzgw2ON z&x1pFY?)>*i!pr|LYPm*m>z#TP-jJq>jAW$`GU+yuE8#lWfQo_dk~Mh6G>TkeY|s3{yI1DT4Of(-;9aWV zJdsY$U#YyE#Te@Oph_*m{iiV=`7-q7APez=`xH9B`Hdw&(pf|Eke4xm5$Kwm&7iT9 z_ATpEPlnlE-@$Iodd2}Hv3f7UK!B3clbt2*OqQryyL|Bu<*#Q*)XDDbYObE)YOYAk zqlhXQTT$z<^cdPlyh2lmruGYuy7;0vS|TRGuw$u%#Dy?5pni5Tdl^gVY}6LYU*eUpyg=>7-*vp;ne`Z^S3%BPLC^RTeqFr}Ws4Y$hd$W&1L&A$XnS+)6ghd0I z<{2tAQ~ZNE9%1mQ13Q5neMYO)Tp>rF(S}1kd9w4w@;0C@SIPMzM15aw(1+TS-C5j> zvERH_r51??I8@zav__>p+1*7?R&k+9Ef&d`3Cvp++DCL|>LP=;sGjV8;>*rJA5f_! zj<^PcwfUgJ2Z;lixy^?aif?CW=8q_Jn0SMB^$&%P5Mw#?Jf+Z5F%Ywk`HbO?%VnaB zs(x0XW5lCuq8Al0IuK3%6-VI}Vk~vLQK6OM6ttbWS)o%z6AruE6t8QKEe)}q;PcDA($)8WQC){Ucf2L z^bMi?d$ZAFui}glR0Qa;Cs3ez3P+Ef&oMNlaCBHX{xtTv9daeUfTT$@@s&z}(Seg_ zKuvvg4)tbl*Tti>)n-0ETJmOpp^JqSsDsbBLkh547vre#<5U6rFvPG1rz!kY^VtHo?cnN0WF2B{45o>C-*pRa)gtA8%E?*|R(%lig#k8b-{=wf zRMC$L-{cW*vIf5@e6vTCu!erWYm^^)#12j?A-~%MTRnmwrI?KszTG2wa0+Xo@Gm@K zdu!Og*+xa|_J|dnFY^_?&m(rV2i`>$@V!TLx#j{{z& z(yP3pE4x{R-?g#nUeO5yxH(Iu&+>`~TfqL!zpIEjUhxw9@$G(&ncnQVUQyuzey@Lq zY=VVep>dRaNYUTn71yvvD;2)T>rTV#6u#K&&chr0oQJ*HOT6Mr4m$6u^mSg*n$KU% zk5t5ZuNcC4Z@a=bdd0KsCSNLilUJm(M*9@L*(-*zA0JTohh8x#1iW6rZIZ2Cv4aJM z6u#XnQmL`V3je|@oH- zRr*1%xR(N*rSK|4+|8xf2!&5KL?*|DGKJ4F9PujKbexKqV~8`^Mw1ji*AN$T88ju} z4m1l4F_R3gSLq84F^t`IzQXS?#A`XgZ&mmrL!@w-y+q-Q4e<*#`h>!lIELtns+do! zh^2-oXSZ1$*d%MX%n)~S9C%gX%MI~>4*acvYg8)?F_;3rukt@q z)e3lq!ap>`5DJ*3@U4d6dD~`dg>N^+>umA@7k9G1FvJ@)s;-J)w;|4A8}|`|rG)zo zaTWVoVrV5v`h%YkT>!k78PWy!!_5$?#g+$S^+OdD1D3ZH1h z+3!7tKj#x6TK&fgU+EJVc{Ou~;5|N;w?5I3O}-mA#viP2eWEjs@H<7Y-Y1@+KtC%6 z8+~Fp=K?)R*?=#6;iS=+?~`1CHUpnnp_!IS|IjBK7Lca!tv+!ro3x3-xBJ9w_JW)w zHUEF%6Pr1?v{MATec}@K<3fe+^NAX&tg9;Ud!IOk1641T{-aN9VVn0?_(7jYqXq{l zyvi@GWRr|g_;kPc0xB^tOp@zQ*nnT8(n>E;1ati2JW4!C;dA}s78=c!3SZzC8dtlH z!Wa65DS*#Z_#J++mEH12g)j1p0o3pUg)jDtg;*q4e79e0=TLq) z>1Vea`^94RvOuzHL*M(wB-nssHcWQ=^^bmWHm$f(GM^}6I`xZ>*+$Ki`Md~As(`3R zfpU}i0LYs?Js_^2iaRFrArG1`AeMxHAD_&pHdy5b1P|^pPfhNR;R3U1Kzv9W7@`DN z5D=>xasEGFMJx=6Tz0e3$*xu35fDR(Pf+-xfN0qP_~i;;91u_N_UKxbe@Vc-E1ahA zr2*Wm?aadKs~(UeL${mrEfp_myl~MF8WK5R&aLnGjS84IZvGHgpSN{>xf1sqUm<(o zK}gZZtWM_YU2tC;b8fPFAM4&(&r9Yq7cXSx1E2ZHT;zJPg?NX3;3g>!p6G~s+5%mW zJQ3>PLyBG0=FQ2s{6)#iB`;z(knfG?rv9m8uUJd!_Qm~H&KcuSASu9E7BIx1d?UK4kw56Fm zlDt=<-9;zrcxm#_5-o;i+CxbhI`2$eZPI)~G%9%k0Vh=XlDz@}dGp*1Z=*@Ub(EWl zA&|Pdc1W0^b0uCYbsi%82A|J0)Ojb$3b+IeA?X!>`b_Z~|B$q(iPq?Oj06TYQ7}2h zih7j4xyj-^xc}Zw#kDr`(fj$v-EX|#0{VBwJ058+e;JY$bIk;qqqXY}BA1-=qf1Uo zu&RfMz-?F(=9*6=v)j4WvZA)Nyim(pUV^niYMP6@=YBnz^`W`Q7Jpl{xb3$1JCZG} zMLw|Hk=$0+BPpUZf^@g;+7e!sDwK|YA^8yXZ>pJO+~q17}4 zE?IWzdIUkc+-z1f*5}s(HTagvi#t5$nmpvMzY@*+}#oBXG^oufP?x z!$q=;cM;DO%y!Fll6F>0ywcCmm&A!9gC~`Q`kaDJ8;m?DX`aS4L*Ec1kxa=?^Sp~m zA-Iq)!tvl#lKC(VxW(QZ8N4?)?05<=YzA+$5f3L2Tr>277!50z(3GAEEUki1b(gfg zadlg3H0fm%$f9HAyPYCPCYOUms->saxDaDkeoAmdla8h21mEn6Fgl=l2<8!d z>l}$0=B;Rv;M-FrCd`j8rw2E=SkT;no)mn?#ccCs3)s6Z7BZ6>0DJFFnJ;X>CuLfeImv-A!H+(ZXimz-<1f^L+m6S~=E=@Ahlh~%SwD&8nNMJ33vPF@ zeDhKkzvDug*4f+(;|}h0v7(g8qsp}4uCX$$dkVI1(1KsO*bwu53i_3cjWe%e?+)%J ziaAp^r&91eE_#Qaa>3Y2E%>#IF4t2gf$d%wTd$kTF<%Dvx#)J?+{~u=#zhb6<`bQP ze(RzOJSkTk*GUV0=b}r2cI~1CzbA?%_8O0Q7wu%foBW~2+>gaf@PLbc?=g8782r&i z=Xg!tg$93e(ZybqH=)6wUGzCT*rY0canVg)leeJ3gD$$;YjWuvJmjL&;hn`DP=mid zB+8;9mR2cCe?US6i*UAVWl1H6UCFoBNVW& z-rUV^iZTqH!Bh1Di7zt61FX;hg)cQl16uTH3SVK03q>hU-&Z{;9(0 zjb&Q!92K!CRosG}8a!9wn^VQj^?;91_=l-tB-Sax^K^D6Z}!$yaS7(r;7EO@WVk(5 zjG(|5=p340(rID>1-MXOA=782iTbQ?nZoC!IpS>t5o7hwB*EM?(UMBxk4#936? zrMf`V;q^qC*kJ=7rx!{5jx;d|b9-=te!j#PrHPl>-OKeE5?`Dq7W#ls)bEk_k~EP; zo0+8WrB0f-ni5v(DiIXV6_4?Zq-<&3%WC1hv?6+fCJP5g@^`fRtGBP8UttBrEl^B|a-%Ou~pCT%%8s_?&dHk2bSbzg6OM(?xd*uukV# zit%Sby6DClydope#_8g7s%*W&??@Mq;ASQGw*F7aU{SijyKxNS3SXQqQked^&WQ+j z?CBzp0&gNyup3?`!fITbnz_$!Ef{f$H`m#ed(e%=a&6?CVG=M`}=gU zH3j&OdXdC`Oc$3>BR}gWO8j8D$Yc!;>Hm=UoUmv}BlLP$Bizh{#RF-;4Ua4Eg0NUd z0elKy7#3B;{lGE);2m37{GAd76v3jfSW6=j3SS%+kKr~Wn56I}VZo32gUJeC8Wv}A z+%P@Lh{NJTcEg~;mxskQkPd|yzY9#(nf!cfAk#SBVF`ri6A&O^;+gLzB6mKf- zLH7t2M)54sgH77W;||SpT8Q3Bz&m68BL|*^EyR4baTm|&vcSbH1b3VW7I`WqzO)4v zMx7v1NM2%VHY}RB1@S9U3p^D{$8d0M7$J(G~qJYxT?q^X1CT{4+Q8)elU zVYdJ-X537w?9&ku#0I~r1|AT=5&Mo_0V z@-C7W=;wJ5xedSxFQM|%8zWlrU6LWEz*-bQW4z)aaIFu@3^_#}Nx~@C6D8GEVtUpi6SSIN>l(^hT66G;lrg0dGr$K-RWi+SEc(m*Wtg=kw^qG*R)bYMd zkz~X=;D*vekM!H_!W7% z{k7jX(Lr2>emgVDOFZ`jhyw*jocjG`uta95k~!8fhZIYOlvr<&*p=-GNyh0sfh>`B zizIM3!PlioB>P#CaoRs36$^`2Gz&x-az)^h^6^e6kzjx%;1VIm%TW}GWaA_m7Y;G9 z+I;3CDYy%l)%Zz`vSWW%JA*_M*|JuCgIR)&Fme4V^J1#hn3*wdX}`%w!iG9IacvTk z%1P8v7Gg8xI>lumTV)9NqO@X}Hi`MeRAHQ)>#&MnE-hq=gDoqQ- z1}EckI(}039H$tOAYHSFerxN7A-_Q)JZWI6yxiU?()Et>GaVvOk89Ug0+GWv=W)pr zV=LGCo1(Z0CY;mVBHT%iGQ|fbRUPJNDEHgul%JrF#47xHJX+nQ;zA&SN~$iAGzaNH zKHfMVftaOn_I97J#6&@5NRrOy5W%hCywJ;#0gqczQK zi1hB*xHUHmm{-VrOvVhEvE<6 zub<~4$an^R{M!M-mX{-CFA&c>t(7CoIgdqR&8oGM5=gWdXlq&Yc`Vv9FPMwcWteyy zslky9>Vvelw_&8#A9lqlMciWi#t?SJHyJ4KVO^D&CkuR7DhPYMJ9)CiC@%73i4RM` zQDi$58Aa^&RPe=MdN+QEo(kR_PD9)R;2nD-fE*pV04_m9hdczHLqN-?Zkgv^{E)98 z8ZI1L1p9;d_R0QZgrh4BOB6x=g$AOBao{TYQh$8K?I|9UW8;Z~p=ygR&t zxFx_lK92xf{7Jy)5Yb@?0vi#~Ix!#fgn^*q4@UECuba>LF`Cha{I14$0LEebsIh1` zuCcaZ+`l8q?aIh>3x2uyRd@e06<76kqSjr<)LDVvU@CV?eOMn2-m>CD5Lc_>V-O)L z&My>P`I$%V00{Y`;kf+G{{^M!b9L`3@ND78?l(8y;%-p3_}plV%YfE)DjrTnE6#7r z(=ZXw1+41vZ&X~>+o{{fsl^w;RDd}OI}f}&JcYRD5Z7@j0&MYn05>9{!z~DGN5HK( z^O$bFf@nBi@wV?Yip$S$=)b|w`4PFVIPu@Fz>(xX8;lpaa%6(Fls^Y}E%}QO(cu;c z72s-8>%@vPQ$7$>d`L87Y2A$UrXd&jm~MCFNCs~yKR>grC4UJbr2M4_Xq}jEI}c3n2Mkj7j%KW^n{ie&<0591 zE#3t+IRQW9D~N{U6>q+a6>q6~mw>0+;w_^sj(8cA4c=1vU~p7#`TvPK6M!nJ{g2Pw zWw^k(cTf>AHx%4RS=`dxP|?)1t|pn~h6?V0id&0=;zkH!3S&J@GP5izN?%%O;!-YU z(XOv7EGx|oeP-Iz{C|IEeiyFR>-GQtdxhTnIlr?nzu!4?X6DY&(6^a{pCqeI{|=`T zy{kU**kH|bUKDi-AG$qhW;d(zHeA1?Z}2VYR^RzVp653BujoD@q-BbM3f_l|=|?Om zY#{P(yBvP5*v0t9$j3e;>4=>w>5BKoZnp{^)aU4tg*a@Z9KN@5iTAnNtwaDlp%Z`6 zv#^WwwTB+)Q5&bYg7C;OrLg-S*q{Vx7!K*O=&){s8i}l9sXex3A-~!p124FV_a%@` zYKI!(cgCcml*t(@qYPwp3uSa&F4{7O7U^0e`$k*lB6qwmk<5$~p8JO~3PO`nt9YNg z-AV%;G*m`X8Xj(r(7metYn0V!h>HZNDZ}aL*>cK*H_IvYXRmLXKUeJA_$Kw)A?b+S zBYCWK($5v|OV;jFc>K-kG^u)2`qx$s z;(czZdM{X!qU+N<%6*}rV?V%WC&GS6H2gc`|JN6^cZos9Pt(Y4P|Fh07oj-LbH%#w zO^v(4eNkccMSJvxA(M=RlBnI)-{=b$v}>8r8ddg2hgnD?d*ZZTPf*#rt@7i2ZrKy~ zVHo{IZ?9F=6Xl3#^nr5KK;R?2{TizEFSWG94 zK#UE@>`gkb#v2hwp6zgdAGDu#=YPafP6~1vnbU(2kfGiOU3mxmXiR%ZirDs&j@Xux zuK3HrnExn2yTS08AzR#7vI28PB}=|A%S|Aa#`}Q>%M~Utmgz^z8dxjq7wGNlB4L~`qGF0G0I6AGOny5-gtvMbWQn%cSvJ2=)@2b)Jows}_QRgKA=zlRo{tQ-C z<&W-a-p-}ilrCGSn)RB%$BCa`phPE}UCu|qH?ouTrLsIv;_Khno$ERd@wu*Cwfo5@ zM)mmBZAn!m)XlGI@9^8Gv5uo`gm&;{5n-P@ zC)NJ2Y8xhf3Q(K5a~`)}Q*HOCz95|Pq}mLQu>btv>mJv6d-0ro_J{&| zvTL6GGsQNzD)6YsOv{VjB^5qpn)z@C!l{oCb{ZHu##x7Q9j^{mwHR%gEf_{dMoGqI{aF%Z{%3>o zPG(}K3 z#C7Zs48f=Bl(J1}zeajo=T}wuSol)}{}=Dkam6O-m+2t(Kmz)*vZEw0JX zWtCO)^Q&x@pI>FOC>@=zMQN33eSR9cgf@GKBLDpS6OkdV$Vv4d6-8j5BRCzg(N}j)|Duqs~&}M=%Bc8L| zAw)XeQdJ1rKNueJG)YzZFW@E5TU2?`*$Fz&@zJd371t>EWd2)opyZ%}n zl&>n+rK7!`f0Iff%Y9%~lW420Pi2 zJ+pM$`1@1fd>;jm=yT_YN$H~}LOjIcH3(wU$DA_377Bp`U|wySsnNnDNPj zW@n@*Pe^%Sa_0Ea>1oN66#8LGx4TJ}BKi97!3SBkv z6X|h7-R|}#r`8S7T8XR_LLLfeL;O6_ILm#?4y$c^Y zUh@6Xn!F01wfN9N?)#%v>Nq}U@S&y6_ebY;yWo?64^6xHv&{Ne0%RziVq1yNdY;UD zQ=JUN*MAD9^IY_U1e)e(y7K+`{5uB^wE`$YhhL5G>)~{E=Kwx58_^Wx`@7!XeCe^+ z8b!JJ>KHIBs zrnzHh(VOO)py)93tH#d9%xSxe+L@~-r`I*_=u;SL+QPD{Z&}}`@K)8dO}EuCcMe#Z zYF>M@sK1%vjt($Wp90uoL9<)Qk~400);667it3o+ z=X+gdy*?cS&9XZS!>#(w;#f!X9eo^Bgt_KGQCsu9km#6()22_Bv!bjvM^rMV%^rct zf})NxTQ1M&4v$q5*Rqv4vSzf`jDEkUQIO19cDh++=HF}%A6&TB^gfW@*o?WS@FBBTA)Xjn z>%*e$X57`lCZ^}3qA0UsNa0*FHat3p`-sO-{kZ5>^WBo*rKWjb;YxEvTW56jUrxE^ zx!TbWY-##wQ76@m8;&8I^O&QT`S{%QhGxu&!fN`oaZ|^qO;o0)q^3+wNgHiWsT+-# z_l_vMnLCTSW$w(Gq2{|I3KyA6{!tWd7LP1!7A~8@8r4dXQX4tO)tWYIXo@G7FEpPI zjS4g?Iyhs^I>q@Ov-#&m^~^hNb&fVa`n;&Fxn@-19O~=JF==Hcbab|1FP|<`jUNdWJa7(kvmr$Tl&ji%2HfH?Pl+l?PQ&Yw${NnMJYaG$$_AiS*G`GJR zJo3i3o!@va%gj=54mCHX7P_7E%JWR~{jp1LF_#`KYGJk;TiC>0vo7E5l5HcqnOoYe zp4sH9qUX)wk**uzAGZr+U$`qDGEU>1iqE zvIJ+SSvJ1#7PBHZJ=DDOx#c+1mf*bGJbSF@JG1Y^rLpFVdFlPkm?qGY{*wxy)~03B z@@0^=*vA}EfE@38ae25o{6tYN zOO@p)v@*Tvg-gkZS{2m_YGGEdeqRmqd{5^zbJq(qYnul$3j3S6y`1-(2c{IhX+D0N zQ#1AF^MlP7rxx}yV{eWgWDc8F*uYHJn+1mS@6*3e4{L-iD>-+%XoOk1X?ZY|%|ORn7}N`t==X_Bhfk{X52L(44}1&6lq=t!aKfd#T%eZ%*M1)4j>j$CF0Cx}2Im zJq-tN$)n8V#F2GPXI5ctGkufe0dsd&;qzvzt9RF~HZBEcu`;ROPzt?h+kC0GaZ9u0 zhlj)H?WmQ1bn2;_$K_pUvn9Ocamd@oC~zb`iTEIF@Iu=}3Q{5<(_aZbEAZ*z3Gptl zEwU#qbl4_(9B=M@3(u>j2>7G>;&y^PJfU|kvS&McFR&#d+FC?2_P(_n2dXj}GQ|Pq z3>i_}w$PSsr=0x5i~miyuOK?>@cu6gdRf*7i?qBH0cG{Dy($L_lA;7^;&W-V= zs~&?!iXukfLw~f}dP_!ZHk!tBp~Jq0D_au4|`M%$Z2nNR3# z+0JoRR<;d6)==~e#xW25ZCT(J$*S7a?E0pyf$f5BmbLXpI$y>X2uqGG8rj-}m=!Mt zH318=8aL6};CT8Ld(m6AM%qLiLKoj|X5H;bGkQ!3Gd-JwT;>Z+ySTJo88{EnuBf_bWY1r(m`5qetLx2*x=q8(`prG46! zjq0*Z*v5c#y15=W5}!ntX)ozBUVX8kbU+<^3#xgwnH+VYo^RT z07%{emP00!uqiEUcxXH_WZkC-WY|6xC;2C4zv?!Drw;if zT*HR5A!MI^S4Sr8ZV3P7MX#!<*IK=3MdA6_&&kUVy3IGIU$@p-f^`JyOYJAMAK^P> zROrZov#<2?ElE|y`e*K+cN6z`7ucU3^GN;yI3Y*=W1voy&jgVCXM*IPi75@` zMk{SGJyHeQU)tD<|E7} zm?g|@%zey{m?xPUG*-o$L^H112p2z?H7%OzxQ_J=__t>N_ROBlzD(?LWqPt@$|sHa z05gl3$9#mjhPjT3=}D%4g}ECvD8qg1@gcLE`3>_YCS6*i_!_esvp%yWvlH`n=Dkds z94P%PCSFy6`)}Y;#2!yEH#2uLKVTkZRxqzIJvJ-jdQ8keGT)BOzRV#^x@n!tor#%J zIu^1AUG|}Xb<9mny3#`aA21IyzhVB9slpa0-kr=;=0xU9CcU4Y;$_p-8FJ(>mof{P ze`C@~8jANeQ{HV2`4r1PFcV=QwrlOAtL8O>(Wjlv`^ zVCFLEx(oT6%+<^%nH!idGUfa25&v~dHmn!j!(%T;ILM?2H&DihnO`!$VV-2lSqAaw zHd~5+m1&3NksQd>nKhYpBr*OC*#mESlL=ZfTQfT_yE1z+Z)egK8!Bipa~N|pb3Bu7 zKBaimnGX=j{^zpCB4!?QIrCBG8s<~X=a?@sw=lOecQf}h-(!Bv{0x-#{}p?jVA8@* zHNC`iU?w9uh#A5RW7cIhVm4#OFxxQYFV&Dw0?WNLw*P+YLAMH0LH96+GsiF|Ff*7l zm=7}PVPlkjF*BdJg83M;n7LkK``^eOFEh6?-(c=x9$=O+KVj1I5UAjD#7npx%Ze#9d9EJ$f_mWZumj#vH?($fQ>VQ9-krS6OHsPg_xI0A7fNgmah@}6nP4Owo^jAwRWc4N|YWJ*7PIfR+a9M7D>oXwm|_dip@ z9Og3Sqs%9m8<;OKUuEuO?q|NwJj^`GJi$E2yv#IIoOYlJ1Tw2JYcm@%n=|8?biIYr zbz}Bn4qy&pCNsw~r!Z$*G?cmQk;7cZe3bbFa|81w=Bvz|%>B&wnTMH2nJ1X%n3pAK z{-^B&^#HRPvo^CKvpF-K*@4-O*@roRIfR+a9M7D>oK2MLKYQdbmoXn@KEd3;e2Mug zb0>2@^L^%F=27Me<~inNP};vr`zGoEW;JGQW&D_s?kNGk4Gv-&!v& z*^t?k*^=3s*@4-W*^_xYb0BjBGld?|Mg>k}PGQbu&SB;XUwmdXPG}R|HV|Xxs^S{bTex(Ycpw6P4QYXJ27u(-fPiNCa}j0 z<}zk6^F`*z%%eF;%uCDw?B6M2 z7_$wt2Xi1ZgGtYRr1<&F)y$2|*NJ5R2iW5<^EmTIrdFK`W;S8AWA39j?1*5-F%y_x=167+GmBZkEM}H4OPOWNa%Kfnsby8b z2w_JAGme?S^fE^>GniS-0%kF@gjvcgW0o^3m~?6zJz(HvnO03Am~qSmrk6RAnZe9r z7BGvMCCpN08MB;O!BlEfxfuTt>A-0~W*jqt>1B>&W-zmu1* zS<6=23O6PRA+NM;5zi&?-dW|lC^nH5Zhe$!4v&WteF5ywnmdYL1c8BBV> zDrHc>EM}H4OPOWNa%KfnX}}d=8WHS>VGS4utG6mvN{5s5N=4Z?k%u7VF|9c{>1S!l+<}zk6^F`(x%!AC&nJ1avC@a5i zjV<5Yt3<5tX>%=yemn8nN&nA?~Kn1`6(GA}Uc8Vu!MpV@+mr_5XS z-&^EnNiHv%lG&NrpE-;AqcIH9m5$0*;Ri?WoSAf})*_qj& zIgB}(NcR5_d*m@!GoNQ}XC7o8VV-7QWx8Xy0?d}o&dmPIVa&;(wEu_LBagY7`8;zw z^C0sG^EC4+(;aJ7;DK8#E@G}{Zf2G;-?@eD|7-R*$Gpl6Y;R>0!EDKF&+NgxhdGlu zk7&cAyO<9Xu>`N-@C_`#AfLa6A=t_u+d0CAEPu=Lc_K2r$oz@JLpoR$Y`~0R-a$nC zfy_}vRA3tOLFPh(BRtG}gjvLViiirn#PZ*nuM&~rdmR1+^EA_at5tz&%!Wk7Z^i7$ zjPJ=2`Vg^#4dH+Z%xTPrh-lGV^X%KRY8k6YM7=gJH#2uIKVp^>k?a`rI1%;unZw;3 zt$gY-I}s5-f$1e8ell}{#a2otN0>!Ky%%$YN11Dx8;QuU#Qd_uuv+8aCK2`il)XP= zen~_*KXACClNGN9vo#Uf+`_z#i1_y~lbI7aJl$;YF1qPq5>cGVT+4i(xr_NO5!rvh z{Dg??PjUFam_ePb{Gy47AH(cItcUB)%zG>v$|!OmVk$F@Ih8q=hzjPhyo^~$tcROG zhzNg;xu1E0hn{{*76}+(tw`rNlmP>>&qg_79G5f_aG<-qlJ_m)U}d_??-(B+XL;QyLlRy zrnebd%Sa`$5vCXB9A*x41M}}hBzu*)orrpT$l+fx&oQfYv*Ooec4hWp_9NC)CMtv3 z<38qS=2&J15e3a6qN4NJe=&0jhp*-Emzbr@av~~zteZLVhe=^Zz3x_i&4}=C!5qd+ zW=P`rS?O&RXHFG2L9U|hFF|RO{ zK9+wVXix^B>=8~xle-b&-;3otS-zKu42LsQnG=}Ph)DMU5e-_z{<+Mh9R3uCZ|MX*@&`kFQz_iqabg{ zIPR2v>}7cn%b6_CVtEzI#Vl`Qxs>J4SuSVUp<4OVL!zj>2+*Jcqu7IPDJQu%%OhDH z!}5HV7qk2f%NtpKhvhPsFR*-xWqRcaHgyjNaUHoJc zKU-h)JTl$V5 z{l&#}FKYG~HTzxlq!T{z7qho6ftRvl-nDDjw$FiU`c1i$qUz>uduDzkBzk3A`}t^H zUW=|jeyLu|YZ0xd8EvBUi5KaA+8O=qHGSe~`hWSVe)d@2<|fEN(bE$<4Qif3OVH?J>_%#>@NN6+xpeL`qlUJvt|0(!}|2S`t0;L7b66@q>U&0VsXs-D-TdiM8f z_5oFYWr<6+!4df5VS8efQ1|O;vi{VB?{8>AL0)DP)Yaia{auyy4}~}sB30k`kM&1l z1BtVDhRk_o_-@KD`;mTpYKR$>d)XyUOC{3R}32CR4+x00&?fT`t z`sMfZlY8}(7%xK(o|Wp$a{bE_x`Frx;%AqJ%vwa_g(jkT7%o@#9?_ZPa>w@l3RBxYc4FbHDMH z!%t&g(y2M@^P;}s5Qe!@1GY&G$hnF!J`E+vYtvQFfA0o8XqC6km_>@<*Cl_B4p=se zh8xh9UyS>l<-aoSXvB7!SKgp`We4^QioTTW)z5reK+L(Aw+-`^qF82JAUo#+eZgsX z!BlS45F_W^AHT>84OB0ZjzB}2v4%|hG>%Lnlue={wE$M|f6)m`8?NrruU1)vPbbP8 zhCbze$91-2^~TvN`q`_ng-UIhGgnVbZ1td?{-Zwa(+K_S&z38MTvLB+08d>%yH}rs zIG80~p&odHy6ZLSu2-qMPSk;Dh2-s^@a$8rTmw@W%^onZ5K^uZx>S)pzhocgX*K73 z&bggmxpp26uovushkbDwzH=_+ZOKA%n(NM%>Sy=s=^=XhJ($mS=_zmX6nwc%zkFCv z|4L6ksUNPUA0FbmF2D%U4Wvl_$k5Y|=*i#d<3H7t&+6m9)PHWI|2)v8|2!c?|M}i< z-Dsp65DkdNz2UHm>|GI<3OiIxozD|P_8u2Z#9Aw;MgO}78U8IwMU(I;#b0Sei^(BrhkRc$yBrtpCO2NV*~?!2IY``0iQQh(a=x|x;5m1< z4P!F*)I0djoga0KurcZskmHDwF>+T#m6Pv08p;Kwc-F^~sAC322#w0=7v;G22)(a5 zce531At}OwQhokiI5x@N7IhpEv6Rqbc5=7LC^?sMO*#U|-6{_duIUTDra)whsQMN) zHy2b=cV4os%oXqFIcz^3MdlQkGbpM(XJYL9#+ABP!=3MmQFT$0l6z-(?xF{2@j9XA zt!S17uk6ceUW;Z(L`Nkp^hFBd`wjiPW|v(`ZsUt zC(Bth907EQkuFr-co0#)M2tiF)kE2(u35YE^xgWj4~SSTQVWuMD7YBssiYhJ-U9oawG_4!$dl>L)UpT7uNMTe}ap6`$e2Ss&f z?IdqUYR&-6u3H90dEpAt;TQ==gr5JYjfxo*HISkOz^^(_4Ba9rq;c$_o zFC0O7{%xG_9!eMvziQ3$g%k3q1vE?2~?nf;5KyuH=_J-<~ z2)l+xQeHEthzR(#BWWBQ&B$>t95<1p9~^=lcfjEx$51%xl4AlK(d3u~M|(a05t-$R zsD&tza%~3hUR3M~s|th2ZLGC~Q6!XD?hJCjY`LeBd!6MTL+&EWeK)xmTkhU^ep9ag z{ZvpK3c8glG6{|rfOo~FQEZj55{fy-vNAAZg_r2s^V!8WKp>q(q3wh>So_ApUS46F{grRfBQqZ%O zG=bb(E%z*Pzh=4bC-+9nJ&D|pTkhfHe!+65k$aovevsU6SnfHzO458Vch5WUyl=QM zBKx>Hj1L&7jtM+Rr{;v6SdWE;HXLl8xkYruT{+#)ulEyXA)fAcs5$RumpXP{vSY?+ zeYQbiZFk=^1us}$lC(D%o{yPzv~5^k5)4RMUJ?|{XL(7XzXw7jGydVT|$<#m>q z6h>9BEH6nasbzRZk~Blh@{**5S(cY1HQchiBxtYC@{*)QT9%iDX>jvZtA~7+mjtVl zmX`#Jl9rbwZ4s821cQ*4mjn}BVHuv0lZ45`XL(6-8n7%c>25v$9+~-dmX{>8-m<(T zKg&y!Q;TJJNz!60%S-Z5p|HFpKg&zPWMCPdfq)5meg!n0ye#WW8cJ@<`jS$~ZCPKE zv?j~?l3=_(>r0YWX<1*Av_#ALlB6YC)|WKrL@t@r4BwjckSr4Oe|J7yBWrRPlNnRPd$}+s+)GVw?Ua79I3@;XnXpZHx3~zOc1s^!!pz=d%nibYHGXUa68;lf1AfpJjMq zWlGpHCl)TVkxhTOjyxsNu;ar5zGQ3ieuqJt7-qJF>&>d+RUX2{E46ht+ zScVr0FV`e53{+Z%w~d}3EVJ~p42-`Qis~~BFU)#Hlw}%TX(pCsc%{`^mf@A!Wm$$- zDy+38d7<9EHOY%5wHR|C745SOZzqzlCV88X18b7EzC8YbX?SDE3yYE$*3YJqtF|n|D>d7)3@;cWBU%2etnDbEXVRK2mg7CG7BjTD$uta&>rRYY*BEfLhc`Y%fbI+ zi(=fkN5K?9Ta+*U_$^BAuWeD#e&2F1K+d{rq4%hQoa(LRV1VCpFhEYb|9Oi-7n7(j zeapeW-J)Pgx_*!HJGLl$P(`ZtAF)L-Zrr2zZBgWE{omZ8U~ghnZcct{Z}L1HO#NbS z;+w|j_x$&JlY#$XZ(>w#PX3y`iP45lE(r%sf5G0wm@oAmo0Gq0Z(=}?EtC6e_9oK) zAGZ1c$CrQl-o&WfocuL=69XsAtj)<^vp1nr(l{u@=H##0o8Xj8u~h{*+gaQ8KXGqj zEJW$F`s0MzU$Hl#Q=-=91dhL8Z-Vhh!)bH!*X&J<%FPMYgZ3s^X*M^(peX;}t1Zal zw>K)IagbnC?NsXF`0(HERO(P5pMLuzH!8;US6f0*rQ98Ir-Dm7bmgLQrxI0)2K~E@ zN-8e5oTmeIT<-b|*T(3|+A&-Piv};^0-ANz1s=GF054o{OW6nROf_)H1sBxbO2xH? zR9tnDp3)B&UQ%(r0cnJaOJlh9l8S2%so15^%>sYdtM4W^3f=ATIS}v6p;W(34Bg5@ z#|{5}BV#nnLbHD3>PrPqul*5MUw*ZRwq_aFDEVKeMROgt>v~9b2KG0pxG00r7HH%z zx=Qw{)mP{=T%Gans*S(ZRk$Q%U8cHz--Fu9t25}{{WPW+u){}Faf!zI;5v=Gc8nVl z=HK;uHbHZIo1g{IV|k`n&$m%Rnty(Ip$48eZh}7MJ;!fvf?niUzk3s8SKtUqgLqX7rsC`vb1i6v!;A&WRbndZA`5Y~ugF32MyM z|E*1s+<#)-`Co5>_M?h_z$OT%WN}XHH#R{jRLFmC6J!jSBX4r@zfAL6JE3QOdnfb_ zmM`Bjal=)b^9cIoRT?_};*$@5$xg_qJo!*{ndZ;j3CZJ+8!prQnL8olS1!~1nL8l^ z=do|RO!H@6rJ?d46Eeu2Zn#YIXYPcIU%5>4XYPcI0y))RcbUd-Mf$Jr zgp6OgO!H^%gyi~j!(|#6#GkekqDxXYUZ(jocS7>~#|@Wh{)nB>@494DRNesd?}88X z`S;;ap=u}O{H>jk{SVyaF{fSUC!rEQ@yB(16pYK1r^xxb88I{*`c;}Pu>yTgH@>pH-oBN$teoxo< zwmXJ(o##LAcPcOX{IU0?(fR*hz3B5N-Ir#_8`FNzMW6r9eQ7xVR<+;x3+_uZ{=kbq z|CjsH40&VP@3`pm_8+s~xpBLL@%Ot2V8EY#UmEQ{?i>DFJDy*^FRk+0&((jw;|cl? z*M4ZjgZ&@QH2gK!e(2JVL3f1yMc01F@G$@UW!HY_(hrS4svxbcuvVS z8B*pTcWHB|WX>nq--b-@ocB7tmjJ(o%h^i5)|uY<;;yXe-4!*{im(sa*U*gQ&_*L&`$RKk^-tr1OKgmjWLn@pK$*Z?qY3K_+ z`D|)I-tvslO8GIf^z|+~&D)2sxZk|?-O>i;;2%1;-SwS#h4rn$9fSMSumzdLlY?st z4~wWnL-X7xEkey{eEU@@vqm52n5{X|4=;ujgAO%Y0kQCiJ>>2pV@ zS<-5XGod;AQzZ~Bnlq7g!aIM0I2FCZrA4rsgeWbmqTpcz<`a>4uh1Qf@>~YebQPTh zUV_CjP?qJPbR4B97()Cx)S(IZ-Q3#tib79urN1+HmJa>dRyM{Ds2az?X;-xw&EOM@ zFME^jc83!p1?wmK-s-iGetv^xUmSq8Q^)W_bD?!>ga0`j`Rhu$RZxCLQ~^9fYa z5q#T^aBB-ZI0VqvHX-+xThSVAEWQn!_5vDj*TzO8s@4{641pscB_26_csr!_sYqd? z*KIiSXp?DoI3r`=GYkow`9C8tfEq?`t8!7rR3*?6H#-tm}#%H$$$=!4bky7h-)D zqr|gRj|MC@6VGDET@fs{5I^97Uam%JG8$luj1x66bgn3MtQ6abOK6L$2{);|n24cv zMYGsR7%h81ZlMOsdL)QfF@ml*^)S*H6x-EK zrT6XFB72Jq)E`~dIx?$%q8C-Gw@L$JiyR~#!LuV=eOSCl^rz6is$m5W6@y5=or6b; z`$+7k_LGUnh&1ZkJGj>4#8zsPSIw3MPg30Nt3%%Gc@TObT(40_=*=VG^}5w3iav#U zY@5|34*h4!yi^WypGcPy0Q2*vfZhi$n6 z8}Btwr!;M7kQCVLafDV635uuz1Jc*wsTDzuDK%6|-wwkFx;YX7&?vo2Pe`p|rR37@ z>J8~uOZkLSL!~qnGn6_Bg;I7k)1cC7kfSZ!A|(Su_{3_}f-(7OS5eV;?L7LRmG%sZY^@D<;>jS| zehg?^Z3kku)Ak{sTeMei!;?a^*(kn)b{D>H)qX@{I%=a(38Ry?8XeVH+lk`4Xw?zW zRVzRxN)>Gwo*uVT(GDT`E=8+_nSD1pzaIh}?k?*wX=?l0EBKB@QdOg;SJ^ayj<9Qo zF&R2E8~Wa5h zwJ>~#XwC6mO?wm-sIEPY?;6@A*iWc-0N*vW2-H7J8&;pj>RA*PuDyaP*4FNqW3{ar zja3M$QdgUfI@i;tp}XsA^u(P8+Nx+YAVPZ<-wm}In9Cb!HIXb*dmqz&l(sK`25Wj# z8mxKd9S=m;GUA%k&`d+;x6oe3bl*}tjE2W(YtVDCS^`=Vr+IqO(8L7N&}>EG)>=7A zZlk@7m~FLv2{bf=;d6`jG)$qrHUY(S(3ZphR_)f?XlNdT&UMmyp}RV3PE@Ol_7viG z)ke@W#xOK@VzI=~9L79{p$WzGuv^g@K`-_w+8gMPHx-SZ>;9Ia-H!p;t7sEYrG1L_ z3Cv`_qWvA6ctFvXq0VnBnmb6r3mUc7P^E*4mV$!bRkXP+@i;+6`vFoJ!XoKylG@IA zgI@Be4S`O6sA$tsvyT*wp3C~NqV+(5pJ1tk)_kgH`H&7NT1Gp1i>o#b<^Ds_($K8W z6fL)bqI|AsSr~{Tik1g_p=g_HDax0MHX~F~$`$Q(lzUXs9>gm1m7=-ODPJqv>>jX} zV~Vy5)6O@FHVJ+4t)kJBR=!iTbI|PLiuR_8ANVWUizx7WMJvO=o>a8qNPkMv#$ZN2 zjh;bCXB6#eSmjwobE3W#$ORg5PSM`SfSkwLkK+HSXobK9MQhR+j{-y=A~WM6>V^gQ zN4%^l8t=qXw1ZfHE-Ttlbm>p%Zm8j26v%1bHG#Rq=&)v z=<8hYiU&0U>11sln1QJ*Z8QK1}gANu!Ua0D8b3$DX>Edf=;&okgS4_nFy2R21Zz>Z)67zHi^ zTVW6$0eiw|mV<5WXbCt1ECl<4Mc_YBkO|U@)>eXXXuzXj5qkD9l5fJ>Gr?D2!dayb zZ4=@dbKwX>S7((ww3+D2x!?lQs4TiNL}Q8N5e3Wxw;*0NI0#CeRqWJ~!MWfB(m8NH z=9g@+7xZL47>6-m01m|vECe6yNIm4#_M)d3gQHr){&L`$T9dlSsqKbF=Yp?5>z9CA zVTyU+3(&@Va3eBY3f_wzD*$IfH#!HU(9bN z7y)}&N&Za?>LLW7pvS;{(AK|!DiW*$UxVVW2ET^+KMvNykgNf}z)V#PPP8e?6X2() z;977SD)=OL0zI;h!qMeVfx~+$%6d>hX`cq^C-l#NrUAzWIOvUv&w`WDRnLK)FzIdt zZ$lS95B|_xQClx}7 zn9H<97$`&gCt8i!A8l5(E*Kh{))~dxwL)5dq5>h>8MHe>qvx^4DPe6fBRbrlsdrG4PY|wZlh6+~?V`+>-o@n9+Mqs~ zHW$?n(2_6=E-kDPjt7*m;}9I~Z`J!L^^3A{onXQ?tu89$&|;`snqi>hG$pJv6u{v= zqi&_h_d=Z%?J9IZ)x5~qrd8`eNuI@==G5MUS!voAXkmah9>az{p~o6J+?UlaDD`9L zVnsWP6sp$TNvU5zpV*bKix_K%+i9zdmS}^a35s^7ftF&I)`gI1 zm^9owWID<`05wq#ArrZOu`)warFA@Vywl1ouJvdg!2e^rxlu4RL~+^M&-W zMTUsAuuu1wcB^%vVh^m%UCv^-ScBnlA7!zwSc?&If6HQopl8jxzq8Z9ye%?H&?`*c z$L-cGt66wP`ZUFT!hWCZw-(}abglcO!HL_5N1-$BD;(S&JC4bSSXyxGhWIBIkV^jq(F=N4DJBYfK~SaGJ3M)8N|o48?1RcxhI+**=p@9T8dQTp z;yr4nuf%(V2`h$3<6(;&DvGEF-G(DX#vUoU!afn)PKx8iBXLrsp0Pzv67)E33ROwW z5M!ZKm04$sNX$DBJIS=OgxRDr)E>D~6-^`kLX4oT(Rk5!}rH4Ioohrs9 z_{qkQo0;m^hq^0KDt#dQf?<@y7kbx2q z2cHO^FH(`!kRRJikRyU#ixlKoMv)2EDJG%rjU*-h6s0G zh>0wQiZ@B02CxE!i*=Z{-2*wat{8&3)jia)*G?J|A>?$D%Aw7KoKAdV3lW4V)SZq{ zlusvfj*;fhaP-7PYm00nMq#FP&*8-F1-<9jz1(qgLkjIAoK(w|9GW2L`M>T*Sxgii z$qI8M-8mfgEJ@+8rivf9sLhG-EFvCJ_D?MLEFk&YF@ zeTai+iM>>hqny`+Vmy{__c0l2kIYg<4B6^;EYDX(4yo^1mKUp{8xFVK=Nz4(wf4v* zsyI(t@K0&I_Q(QN&=b|&KTv$q{}rk@j3v`;cMg{cV6o9uTg^$6l|2#`+mo6az%mT> z0F9rEWf<%_7>YZPWf<(!RR18BVX&)dRtshs277>%MLCXz+yk47KE}4 ziDN0@9o`_!ttKpoh@A zXK?s@oA{cPbdhtZtl(msSVjdFIM+*giA`MV0ePj%{HN9t4 zAJZK59n1S{;tVzLI9K2un~0(OjC1T!W)pW}u-une{>Ua)(+YZx(b!9{b!T z26lxUil1>%h01NBV<6-@EFZIpE7YJyEFZUt#dRS!XZe&(97F>QcN}|E*n~o6aSIo4 z!6r`PfXzLaX zhwNf9t?Uc*+oZscZIt- zdsH9-O*C;VU$Bdwq*NUPK9D_f$u9a}#dG)M@GEwa)dq4B%UKSQO+7S}<@pZrW*x|5 zSYGT9r^u`)vAo0~j9gNxsq9hU5W`7{W(8Oi%?gLOMhnJ54qxdI9qCZw5tdguL^ReJ z_oFNqJH#uYke^|BokQ%ULy?zRe#Rj(Zif6S%NrerxTP69b_X1iEi7?}Av9(OSl;Xq z?Py3o2(XlDt3zC*sq`P5!8V7;jD>uZf#&GP3C(U9he2$stoViwH{ zO<6wX5a(#|if8#aE-%rLbYR&yUC9O^31eZ`C z4Z%>BuQoaGc@w?Ur3@_eUAqy|o5d9hP;r~GDFvJtt&DW0J&HaJ3oQ=Ex{ zT*&eYr+ATSyqe{ePBER7_9>QEImPR=9Q)*Arzj#T*vR4QoPwTG=-$NgGfr`w=8e~+ zjN{*pPH{h)?%v4}N}Qsc3fS+mX12{v5kOsD#^GC?;$uu0?oV0X<`mb+EWcp6)G2ak zt@y@8n|B=EI>joQichh;&neoI68@89TL0g13VP>^`zOwz%qe~#tycqC2b|%fr>0`P z540+D2=bH+#jSJr=T0$^X2vj<%bj8^HK-oT$IwHaAV;x$91Wx%xfwF%AA95}r+Aab zs1--3z>v^X+<^rx?b>T7)0lRa7Yy(meUwE3!*bS_Q?4GViC;~u|ah5 z#vZviKzvDyOS>RC9fPCX0C9#Y)HkRDziUKt?how?)P zsX>-juR;Ogh>*r|ae%nh33&#~>jK1`)B|%kgJ%M)U12uM8w0Re`yQPfa;t;RCWJP` z*#!A@6S*3j=Yk7r7(tFq)CwCv_=V7pE=V4=2RY6nW$-3+S)w~9hz{JvBGRyeAikn% zZK{_Am7*7MNmZV_c_fIAZ*7q-QH{)DxvU9J&xo685n2&69X&y(A_~d;3xghug1Olu zLq&CJXAuX7i;*-?X3(25c3sh*hG7-w6(Js`PFO9gL}yx@WG8EbK9!N1i9IxxJsEUF zinvBkC9MnEi~7^H?sGDl4cvq_qW5huclWbF$7O8n>u8pEF6f_9>?CHwDBT-_ewJba zdL|y7R9mG@iPe#$I-#Ub@(U4qAV^-c&V)nmn;YPIGR2@nC@T@U5Y_5ygCf>e=_vfV z&_a0NG!Ry@8Y*o2&>fbP!il?o2 zA}zd4gWJFt1BQfO(5q^#>fMU?R{qi@8%Bqf*R?JIk*w&nG+NOqCbFsqkKk|MZ03GB zh%C<1maW%o%Z}@`1WpdIvh#&`@3JRfV8`UALiG(b( z2$im7@ItKS6l=0{2Er+i_Y&cdT7Atr!8FJxJ8&10BMlQiew&W>zWcmY#TE?n^fc{` zd~EbSIZxqS1O_?iMu6Jt+Qyhc(F^#JMOT@U?O0z#E_z-@-XtS`h;NQ-4w%|6G_kxD zqL^RED92=!pDLrsJSjWH_A-vnJS&||sMuh9*H+{3ZRNDy9B{T-xM3TsAjQ7-asmQy{lrQd^~%ousXNG^5Uv_-g_9w+xipK z&F`;=lk)sH6w(KKrR30uqa@FVbcq9|rvKo8^pPbA{S_QbdyJ1QF+_h1OPA*pOA6Ij zQPfX^pxd^{aD4_zhb*bCULS+zIUFIwBJ>}-LOSA=QdG6ElSeC_qfbhynSN16*w=rT zQVV@E7In`tON!IaP({Bn%4A?0eNha=Z!M{PwQ0#?6wirIWLT$a)25{;p6@MbkbYD{ z%#)ThNq-yDy5|&0SeI43CbmqT)0VhOtu|_Wrs6qciJR4GQ<3XgOL|AuV-he4cq%OU zn5w^sZt|S7#4D=a4u@%;^Om^6R&8e6){5t!mbejOhg%fS1xwsx)9W@sP^#0xf^wwj(xmbe6uUdPJhxhzE^a-ChLov!C6D|nk-r;V=XUzYfhT_;8JT(QJc zcAbvTJy$JpzC*u=0}s!&FsKerjyc2;7{5oTb)}3g;GI1ohqH_g(Gxf@@RlSX$_XUT9JDCOh0#M9j; zyF{-(kbC&#KyjIRHPI&r8KM?adU~q)RtCZ1Tb%y$^i?01a&fSzhcnxr+gaWiEZ!zv z?9cMnU{M37ay)miyeC+AsDHfb3o?CKu(VLP#FU^5->0C=UHR z!&I^+d!$ibQ>0+a<{6=0kQpAUDL!cgd6Y`C8+1BMjHVtLtv1G-hhxn!v922AF)S|$ z6H#Qy<5jN=F9;K}sK5y7$#UUBu3lo>A2j{D`Q4TJVph5`nEL0Pud?-wqq=bvq?L)ml&^$|(vFZ{RiAE)MHpjTOSs8QO4Z#m!s1#Yl3K7w z{YJ`5Y6-nJB4_1K4M zBbmOqmbeKu_Z(Im8Pa1N3M7y3R9by7#QodA6#8VIbq&_F*E49QtTAHt_Mja44rf^Z( z9UgX@)uMuMv6f_q&8qQ=a1lj1;ADAaxcHoAYmMbq;o`|4$N?-Dhl>|!?QyZZE?nGC zIu^+CGvVU7nvjDG_ShIMmQxo6+gOXkMJBB*g5}NO;!&F7-8Rb#wuXzJsKp+Zw}p%S z6t1&e8ZPQkg+f@~6E5bG*;ZqDU%2RxGdUikI(xhmF8WZHhuP?q5-#+G3qdum#d1My zag4%mvc+5BwM8)vNgZ3Nl(TLUP3u99wB<^9{!QX2&4khaQ{0)rM^U8jzk6nq453Yj z(BT#W1PF&Dfe7J{a3tL17Fj?-Alyedg0SeOQCP(rT(s3ijx{PO3a%(DvVw|;iU^8` z$4XGv6BQL)f5^iBeX5>GCWzNw|K!v2?Wd}`>aFUk>gwvt_k_|*8(FVmmt5r2J>yM{ zte28-{OcHUXkv|%kTIzt-PCG~cH1eW6Ra;#M>_j-*L+h8%f3K#8ugtmtX#B`uD+*K zf)y>Sw(Ufx`;I6rbNLO;HL}wj^}|7*)PEV9VbmBMz-XqSiJ?nakgCC<1X!;Ee1HJz zr)s1nexHbItd8du6%75W9_gv{3MC;4c0&C0s14&6XH9+4;v6fYp_yB?$^Bj(Z%h+M zd|E3X3}`~bM)7Ix#r|$+Q&+r)D{oX+bzy39%#)(VckgF+Kf`hg}6=YRu zhLS+ws6R<$IDo5IqKzmFw{bjH+El-`cEzq&I?9MT)j@)xGARe24zM$%wMn*^fCHtY z3bchxIUs;4gJ?OrgeBmYkT}Azlw(6{EDD5{9aI(IoZP5WH~dKXw3k472jGYomU%V9 z7s~i>6(Np+HA0B2imQ4}V!cv@$07237KUPdScUosp>Xqpqt=)Ob?;H^a%JOw6%JjA zjtxOVaeSxz&<$1li2;r{G*rjTYG>69kY(kE!)KTui(`QD!=cl;Kf6Y;I;yVWN1_<7 zf~`id>K|H;6T9fZ^(w^62%&zCboTO|?CZGu#YLU_9g!8aN6$*=QBpag0}rchaR0fZ zeyZ~6)D<@g5F?0{W1pYuHTudLXbirkSiZ!~tARC>M-N z^f@~MhHSZ2T%#)G=P6lK$)j6>LzrzXJ@c+Mb?Zh45U8OUFZp!TPtZ$WIp#ta>tegE z)Hs__oi&cyDn{u^F|zLy(zPWH9Kv-9Rfn|d&L?CXwy0|&S{&ie$!aLj^sZ7LbtoM7 z!$PTY3(xFw@sGlM$jh=)Rn2g))-y6yrbuQGq&{XHV!HW0z+n3V8EeGaUD9QUVt*og z(C&&J850oh3K8s$vYeTOlx3H76y?%0RwWkOS#RhVKBN$v)=v`f zt&mQp&V^fLH6E*GOdA=UHi&Ea52T*cN1oD1L~n%DS4(cI%UJgy^(S4(ZVpxgWFl+I%vP3jhk2EF4D@fE2M48CnXlwStpoe<36sq zH0{~JUMMFLaTjZqV&mSJxGq|y*|-xXuB%q*b_XPwu2oNaw(R6M?#JGS57~|D?vt~S z#y82{T5rZ>jFxj6`>*{a|8c#sj?$YLFRG7@BVaF;)2_I_yHc)X#SL4k0?U+8Wdo7fTHfTdyCJF^ zEjRh>)37;LOPTap6(KUu#Z0N3)A{YbGCq&X*HPc;w@0@XS%`T;nW^#Hw<5HBk_K{( z-|m+wa<~pGQ$ioXtjq3HcC7PD3%pFWlPfb);8Cch$c}2W0hx}K1Yv~MuA%PU!=?-n z9oQgS_^_YiMx2ruVy>6ilj=4}lj^HlZ`})ZgECZet=kl4psr4ndR4cXRzdqpX+U)o zRw_Tst|z;%Zgbs8W9?TXMYTXkSLW&MD^!MSbrZE}V$XzMt9w;635E~0 z)NTEsnA`ZZ{_+4!Tj%*(a>cG*GA?m;;i45P5^mvhcIzktHtygHsi2J;_?#EDpL~Yt zGAT*tB`srZ+;r%?td(Qqi`CAa3W*=nnswxi&v`}rHLOB>socNhbD-6Ltp($v8T9lR^=Sjo@q8_l$|%VO1E(zv2#ePo;Ge?aNg3Y zw~f2*oVT^gv~dfV^Nv;nZQKCnysOnv8@GQsf72@0#@%Dids-FR1yLA}9M*D#jT<(c zO07oMnKjOEj-rS4wH#~z1+jdjy%yLvWr+G%tE+6>2kd+Tgzdj(p%;_Ru?p#MrMh!Xr*Hvmxk*!R>L%z z+i|Q!lvES5O!=>OtcOv9FEp1Zy~VM3GMp6Z_3>5|>Ub*k#&|1EI!dRL(lVpDDc+iq zB@Ue#V2cEhF@SS1i*#GOh3lj;{?v77N4zyjjss3t6P>HvB@=JGh#aOyHgY_khNXrp!XWf+Fk505S`WA&GMdwah}l5iPnGb)}RD zx{(ZOnS_2QLUeEHkK?VWsPlcOkHuR)bjW>8eXu(&8I~DOr=R${uux{Lv*6I58_2Bn z11Pcq)G}+0EB($u>SgsBl+2xFID^fPx?+2owZ`zn8AAV^=@tec&QR*z>DCn}@?j=! zVV4p~x1MPyI@?UaUFD(k&Y$bScBH=w>~I9%Z=cYK!jdX0^aBxQqc-cC%i_ z1|z7~h(Fr#Z>TG}SqIQVjig@J%~~$C&KX4m)_1ekULtxl4cOMrs*O5uxw#@28Gg5$ zwGo}x7}q?eE$*i7nRkjEsi7v37 z)*oc(;ml`pdot9W;?6?qeHqqibW`Qj2QsX#NH3%hWmxxPdzb$2W?0!Mk44m#8S1GK z=W5r~w=W*eur{EPtuS+yJs)RS`KThdQ!namEk+f+gB|Ccy{$CVkUQDPDtfEiA)P;( zW7YQSdRrN&Q7c2bkGeh5xhJIiTEY6_@2(0t^iy|$I%{a*x=eKksI!)OeWrCYdWAnx zZ_Km~qFcI`dQ+wqh2u^I^_EQQ|4>EmV~KCev{vEhc|Y}zOe;l3uded|9d>3~*P{g1 zQSZ*QGSG+~q~4QhT~S-~L)7~+t!CKekC?Mmjt^v7v2yzAY&4hYJ(_6^Mz{1B^>>+8 zFI2h5&GpLvbf%S=D(&CdM2AILR&(Uw3G>e?z>+NMPULvAiR;?ZPi9$nqfu?4-qPP% zf=2ll>TLt8G3aKtQtudO*^)!&uQXuiAnRuIDo>lOO~ki*kk#oT>3^K<=CdlneS_4^ z`pz@zB^S~!4zl85&`whiPYw;T(y&jTr>-2NZuWO}vB*D`2(!fh1?ppitcRg@o2#U) z%5{%H>gfdMW%{oiW@WkPxAxFs%`o+Ng7XS>#W3}Fg0q);-7xidg7Yf%`e9ZP8tFdj zjl-;A7?$p*-X!s%<9>~L%PZP1+13}0#o+`UHfCGhu)#^{P2wLE{VnyDY^w%{FB<~IGxhcnb7?mu>r;i;gbF6&SYMXj}jx_@#wpgETx7%{8=h2bqr%Pr0 zlVdeQ$D&iNb~urJ5jgi06>t;Rn&*2{>n9s?Z8vHIg! zSD*Ub9BUs=z8X+h=2%gvBMqsK=2%^DaA`#SagKE%GSry*SdR51T16A;<2lvNurxkpU$yXqE#eNFUqz0V2IkBdP%PJg|s)P1@+Qg>jP}x zlKQ4x>nJK^BK5LdYc-CJt$Y=(YNso58_XKlNe0b6obSnv-MQ+a9j6U9*qLkHhIXDr zy*tI@7@5!|SXcg_K_vKpMq1#g*koZuiI#3_VweA}tI@!m&h~Le%uEah|VSvh9 zYg~fpRO+L-RzuX{PCk8B@Nup+U#hdynf}K_qtd1MR;pTlJlATAecpxsCvvSn4-(yt z`nz1~HB)p?mky_Mt*0Wz;S!%d4_cIG6{BD1MgN=ftjVxAq?hGctM{~mLX`K zbu$d^%kA&Xvua_$){nX(&+?(f`ZK9zC0SU!HYZnq{_=Lx%%-)~ARd zm-r&`jzr`PSR0 zgr(Hm@~sseM9-q$k#7Z{-Pv^5nQv|FEe><2cjsGAqSjqOy(iylijHGG^}c*-K6<|2 zQXj~-E`t9;_I!u(t-WaXSJJ;y{H47*S5Y6$w~A$u>N>xp!^ip7-8j2nM13sZ`Vf`s z8W!>KeCr_2))&+NghYUzYl$yT?c?tx$EcLo`Z_7SuE6>V=PlRyvXx$6VEJIsQr{G% zHx^hQsWIIxz8jRorUL6j94wYmZz-_;*+=wk)Y}TIl1`#mQ12+P-fANH4(go+R%0Z1 zC-v?E>opwR?xx;TVC};8E2;MtSf_E|b5_yeK!NpV6yX}`Lj~4&G^0QHHYo$&EwHZc zCi-6L$^z>~w9^XT%gSG-NumQ8(oocM)0hh6wU3Bf8ps{gPTN<-De_j?3r3`0e$B`? z8%X-T$hI=r_D8Oj-5)R-FOkl$r_ag9q>GJr2{;9xO6$i|rJ8pt;G_389=#9wCD?V4 z^#UBX<(71HnINRn>dY#eD}JMtU%H-xW60jIHXg+f1;%Dtc|DbodP~=Z{uNmr(lLMW4euJ zUByr8xIAiaPig_B%`dZEJZkS0;0Zrp%LO)`wAY?^(B5v-vRcYSAD*)h`N~8ep0W=~ zndqA=r5chl(f6gK?iAp{1s<`t@rZrMS0?)KggvC}6*Z%eC+wYq&;$1N?aJiP^YwOV zmCbm%-rk3!o+@QLTyNvydYwN!TW{mp`cO&-OnU*2I3x7L+9A_UMqlw86q~>0QJLx7 zk35Y;!O3$&rhOOcZJ8d@95?ICDjhGUzbGt!%kND4RW#cxv^*^vqh8F{a*@xjND#R| z%OyU$BL?*gwOs16hoS{td7=PO$z_O7QQxnM#gSHYz+Q=x|D6uKGN3N;I6Mrm38?Eo z&LZtw5wH)Vzq(qVBd-hC-yrI1v|Jys_o46>>qGL!fc+?PyaZP?rKIKBRZ!&bbyQmd z^>q`1S*i)iEgMKdhy+!3QDN zYgu8|nL9`7>mv_KQOhK;+$%j{qTxKM<;SLd1Vz6=2VUp1pT$9Eqn7J^_9Hz+{#nb7 zK6`K-OanZwwOlCs65gA%+~Ttb#EX1#ze;JF&(1*iyjjZ~KD!lC+VYX|l{>3XNWF0W zqUCO%JqvYz>lx*{$7jEY_WP8suls!VTj*A{b-hfTh8$ppL>^Qf)b}LujTz6>bd~pJ z;GQa2p~K2i0zuTxP)J?5+T!{qT+u(mh$bs##fTN>&qe8b6_C7R;UZS(BEI+7ZEYIk zcCmnX`B3?t9jQ_ra(kKj#Z-S3Ho#Do38}V(DSD+PE4YBaBusaegja-gUHw9jijan( z@Qi{BrZ9smrE4=J8ca`O4pT*|Z|;&3f$Oo$ydzFVUHLYOIyCycS97|@n@znw@AYkL zcK6KO?u~u9BfQ5}baq_KiK!SO3|w(CFk_^2hVBFwg|yr#hW(BiB>G1O;HkF4yiu4P z8DjJu@WU3E!BKv-#TCh^E#A|va%>Cj%=jbea*&oMnh*pVTEFp%Z|{7e`zahS%4s1B zV~WBZf^e&{1)jInmxzC63%7ypUl8m;H?pyjy^=lXtN6MQZ=ZY&< ze9Mhy7~GjHVU6os9%wpK1Pt;m4>rRkh>)@p@O+Tj>Iw0a;xiKPe3zERkb7j*tL2@L zb)@QP`K(B>ZNJ!dp)HNgoMFa_E$e0ZKzu%=Ju@bblv+_`&`cOaduGIj6j6JjgN{$d|T-d6KB)!|*C}O+MFn%i>J4zSDZWe{B%i_hbr1dr8P*G4>I`Ws1 z^kYb?eS3*}52E`Ut%{7wb3v$#emXPB|>tu7PQgv0bx#7v?)=V}enQXpF_AZGmQ6*cTl3fq2%Ainf z{k&+Sc@YX_xoP69=0_uB-;3)TG-0_m!Ch|XoZl91!fiE82uYf-LYaW`18u_X%7l)h zjpj>buw}kyns{mYmPo@GAg&pg>s-GV%5`g%>GzPLYs{4pts=8zv%@B;dn8J*GNaAh zc{2>NQcd$;homax1j#(2E*spfk}7W`4sr!|ha|H>#`ceh>w`>6UTUVBnoi2`VYj|j zl~TMfl#*MOR6QRq+kIY@RDB zoWNItnzjydpO~xV=OWu(+DGIBnB`wyS>Ara%o4*l(>x@TXp#YWhwNfG_wda^%u-Xk z%FoTNgk?{fbakfq>Rirpr^Wz9_Pkw`qUg+@&(B1 zTv{@I`;lDElIqYQMWU;b%cKQTF3c2OssD+bcIQbX7mwAMa{rBeS2I_iNvxqHt5N3&c;4CWl4 zxli(g_xRr`aSV_=p{t$~YSJBc$d-wCwU0SZwd2DQ$}o~2?<|%2zDd#|Ofz|6YZ3Qr zp@xC8B^p)H&l<@GWf&EoUM?=CYsMA}rQ4Qanyl!NqG=>AY9?=cZn73(%-F?(~YS8%7k_qDtW5%orldhOj zGNH6+#*76W#~bE3PDN!CX3UyiTsA@b%`GdDZzFV^EU6d^(z_ImpEb`r^7snJOE}#n z(i`)B&)QyEv$hSrrjN&UoGy)9ZW5SRHf6eOAY#&lvLboFbFNn65vC?wQOr*R_IO+ax1||eJ9YJj)xYnN8cg+f3@-B* z_Vg$FW|^1x`+e|1Y|3xeL8!J*xIP4RbFjrxThradUJAa&VX+}4Hz1@Et>92K-e?iZg zvRvi=ZOJ(2>2G$>KfcU=p=><9r+=Z(GtFz${drOl*UZZpH)P;-{)~zK z63JB)!9;(P!TyrL{7vx57{PymFHxQbm$(i_e&p{U0WVti$hP4_g3Tw59RA{R`~-(g z8g;2Sh|}moQNek^d9vod2q$s8w(uJ`DMz?T0J_Oqvi9=V4jvqG>m~j#%dhd@=mrl? z_18V{0X_|q%=vV6#Vd)nScIB&mX6MZMm<5dCneke|{I8 zcMo0nYxdAJY7ezI-yU**ei!|sJXY_avR}1_-0;fqi&FZ}?jcw9H>w&dnCzm&b9d3d zxQ8D2MSI9qO)0^*QSGAS^X;Pl_#WCCwujvRL?b$Xeg8#m$W?9h7jyytg*~)d_K^FF zySY{Wl|3Z&?|;$F{pcQYe^D>}YZ_+2^gr&CjxP9Aux`p!|H8qOCq4DlQ^`+ln?I%7 zl$6m!N4@Qz{`Iu3(@HMl+d*4^64PscO{7a>o3p=35~4HP$bZCBm3vie!{32%U}8=Bu%as7xb26yjo$c$P;p4)m5KV9X9P3)3o( z%Yx*=hh%i-iipL^Mp@tiV(ta*p_t#5z~9Sa8kYk9lqF!ylb9c7VDSir{Zc&P9A&79 zjowum2ziKkTdOw9^S&$_*TBX3xg;0_G2;S5LJ__rfh%Q^9RPeNOTf4yEL)f_xtAM( zt7KDH53bSc0T6R4;kkNK!s5Lers2xGss8&$^lAzB1M5Q`V*Rs>OIAahVZLO)jy?ds zh;vBE54caS2SCiJz&*6xw-WYjK;|^U;u3AVB;ja+%nb1lGbG>W2m;_{87oU<7KoV> zS(i=qAHqJO+?H3lC5VPwSe0q5oob|y*^%dDL3H4wazc${K+KwiCxfsR%B?z?<8%v4 z=G!W#suIJj$YYG{F|XYx?b^7{Yw3XRUm!CQMp>nal@DZ*R2}fBUXKO;uGcN_6TKb; zkL&dSh?y4^QK)3*OX07P#b>0h2FJ;{kl$Fot=z@hBw0)&cdFn{SzD7$x+fa;${M$!HFhW2IY+R05RPh69XbOL!z(sv^OJ(QH{zoxnNX;hQJ7bbqg% z9B`pb(5QWfl`CaIB>=C|>#^YP^tuIJt=EI#QoSAkF)>x65_F9>jIpwy5`cBzD7*!>}N_d=%=1@6S_BUcB zkQD>*iV zp!Ad`Ym1(k|ih$GgdMr3YuUp`3y&eP?==A`IX+DX_tu#Xo z`2~soxJoK@HMqTn+K1c9v9ePZ**h-@zLN!21pK%q!(inmiB?sST~+aiRS{%;i;6yF zHHaAfhASNf*1{uYJcr7$@{BA<4MeMIhUzMEOd|PKrwK5UE#)U9l1LTF zaDb6)K_o7B#PaGog6YbyWI-JP@gW*n4}#z5bqhS9*JHtmjw*};_Dw^o)EzEUNXx*EJst{JF3j+KXGk-hV0L8UC% zY2ec`q7Mr35%sj+O988PB0|tlT9FQUejM7!itI zZ5)byj>Nb~mQWSJx_giONFA9c+bxzQR7bF` zQyykRbrpG6w){{aCT=?5r6XaWLhEY^B zdtPx#QJH}ci53-=PMj#~jYI2Q(nJjvHFwIw39@>bto9!?G|On|m(YW9ilpC<0@ zC}$MUnKogLF%H{{uL`=#Te5!SMN$3xW16&R^JD8r_A|Zqt>?Gwhs)@h{R*>&W(_lN z+eGQCqFGZGOqf2mXyUw?;|;t}rfk-P=|wZfYX`hhW_Gy4saBr3dVD<>?;ntjCr+6@ zU5CW$ab`>?8b3oE5!G_h1>=in78Z}2K0&lIz zKJUoR){gn5g6~u}@5m?J<9(}oC=SH~&bgR*4jF^TA!;~OvnSnIVVk2O7ysC}p`+)-fI!B1^t3ePtOa zOXzPxbNSe!ES?-AcFXej=Eit+RD4Gq- zrKSz(6gdtRJ!SLNb+Q}#yxYyiNt-|4+j@~%r(}E?8qmx#w2y*ag(MS3W_KJoL85J9D zki1^A)8@5-L06dGqPj)Ry>T6qbb8)w=i)Y-&(=$F%)004v%J|`qAv838zdd_7WGQ3 zQY&Y;*?!NyxP5mo zE_3noUT(Lsy}g*dLrU)2yz$xj9ZfIg;z4`84JU7?@0AZ2Yq^*k>lfn;yf!fQ_rB}=z5~%Q zf#+Y?)kiMh8V%TTF~_x1*89W+hhOXSE!h=;CFZNT@Ij-r3<(Dpmz zi1?1)exz)_J#2f|SR+TTHp+x7$6pg{4oWx zTf+8>v4&pf8+5JTw;?9*!mcX+9g+CTYPkPF<=@j#SBGUrEJ~&*EUEJi>$S^^sWkl; zMn=ateV&Vn?XxS!>hnTOF!OmNDIK-?!%5%u;o(n4{A74_cR_ggOMg0kj0X4X@I#b6 zmz+O*2ik*CQBz%r0~QBLuJcI|+$p8_!mj7~)-H>FZr2Mjfy~;*=01}K6q{xZjkR(hspTyyZPmi(47y|LfY!c&4|)4qXSI$T`jCwA zF7Qsb&T0{nvsorTy&kn{xAZj`1viGN4M}L4)TtRn?GTj;XTtPtCg?A zAg}i{3DkR=999f(`m_NpA`|{9Cj~?9=+Ul)FRqq1HYuyM?~+$21m6J#6fi4oYkmv9zvfJmZz7M*qP(GiPd0H3OfF z++_S|gsMCAFwvnZ4n1A;4pwLA8%2j|Ftp^?2-Q~T7e$9^C-hs`p0yGBQ_)iSI!o=t zz|m)XFAlnPX?=n0Rb6|uZYG+wV@><4C*4l)=U<#W%_KRm`jbJff!n-7f6&v;(N~|lgxDY;?EwKJQ#9X^eg+#H z5h8&vh5k0;CPO(qTGxO~BvZ&<W;?&46~6T zjYU(2?n-BogUQk46mlkcCAo;anY@i$O;(VPkxyziGM=HsE9C3sTV6rkR&Cr}`+!u@djVEW3E_n-i52>yRN%*I?>(uMKg?M6x~EmCPaw$kpU-@*VOM z&^zn2s_V9sp#t*QgX~Y{lOxD6WC=NyoJHb&`H1H#@)~j}c?-FMyjxSoGjzD0Tu=U) z+(JH0?j&C#ar8jK2g!HI_sNgRFUS+*DMi@{h75)fK_rR$M4{uz24qt*k!(k%kX^{0 zWM6V1nN1dwBSBXZ8cTER&4($xry8=bm6gs z4!g)b!6MY)HxwNQG+^DU+JmpgkQ@$*$xjWIu8c znM2~UQ`mkKSxinMXOMHr-;($sIJWzJr0jpJ+(?Jzq(|OE-b+46ZXll^@z^!ud4_y} ze1&|Se2Y9x{yk*LXLR_A{0I3@(l3WTBv6aA$#}9c*_>=cUPN{#yODUW3*vLLxH5#y zBQGQId^Q4(C#R65@A(DP&i&7nwz36oLo~$dP0*i7TA&FD3DHU+CYF zOF*=LOh~~4lTzSaBqpn%A0QtkpCGr9&yg>Y`^iJ(Ve&)rbMk~xwg2zw;FDn#60AkW zlJ&`^WGk`**_rH4_8|w7IplEiak^6~>yb^#)+9czijwR?_9FX}+2nASD`Uus=p1@(ywpc|Z9m`6T%? zxr^K@RPFyD9o{29B)=fPCC`wN7qA4#dSp|wHQABuLiQs2liBzHCid-cI*cJFk~7IG z$a3;p@)q(AauxXixry9L?jU!OdoE!6e~k`!x(5awCXbO{li!hNNZiMP@OU39Schy% zCX(&Q6tWB1)8$HEav+&QjwZ*ElgXK68F?kSl)QypLE=+aFmMfdKk2UL%Ad)_*Dt?aJcI$SLGZav^y;SwTKdzD53> zjFs6Olt42Q&&R8iuuJGLl*Fq(5pXKGl=R5w$^GPe-kwVq}r_up0^FhvUAnzt0BDaz+k#Cbz z;3C|3-&n%-WC@DkS+y7ZQ zT+l{G*qCffb|tgO0PK;BJ0L~bQtBHt!IB~Ovj9ch42wf}Z>=uQqMN0L*?h2#z7-Q+{$R`MnC zZSqs{6d9dN1MtccG{1Iq=uQqMN0L*?h2+Owbp$6!ywC^n#E?zMc4Rj)lguT@q_h3w zOPPpZDR~EZAGwiyihPEAg?xwng#3>5chm9O*NvgIQcyp?5+)S>v1KK>_qk^v&qZJ>ExB<4dh+qI&w3)i+qDTN`9j$PxkcC zmee5=$Yc_i!m(?Hk*mpv$S292B(8)bd?krnLZMHS(LJ?ppeXylH61P{dy~V+QREbI zKKXm{59C^M1Nm3-W%4cZBl0AO_V2$$TU3W^M&h-pu)GI3h`fxPK+YwvCT}GlBDavc z$T!HNLe>7ip@Xj%4IvZAWU?1Ij2ul)BNvj_lXsF2kWZ4&lLvaS{eM7*uSqk5hLFw4 zRI(45M;4Q_$*albe}hN}}gLWi$Nvo{SOo0F+zA2N?DCTEjZlgr7q8vkwg*o0F+zA2N?DCTEjZlgr7q8vo8%Go0EOWJhGUa zO?|5UCX*Rt4p~H&k}i2GxtiQS zZYN(Q50hUCRr^0n2fIHFAd|@qGKVZ8OG%f!m0V43Ah(mRl84DJ`-jH=bg&1|05X}( zAalqfvXpemTglbr268+3DtVavasb=^SvuGQX#kl_;%fxxigU;!vXpemTglbr268+3 zDtVavGPL1YI@p6~0GUi?kU3-#SxVy7PcZOSay7Yu+)lnq9wyx{xpJ1Y2h#vDnam(_ z$Re_obje%E)#L_pJNYVkSkpDWq{CU#9zp}iWHN)q_w10BUJ4_CR=aNl=hyoFpvK1x1K?j_$NzaYlf(8OlS>20j$|(~n;b*VB+JSB z$j8Xd$QQ|dO+H9&(R7U$=x~tyJ9&bPE6|2CCsW7_GMl`d zoK9Xz-ay_(t|K=q%KqO)hd0PJg*w4bWCl5m97Rqc@kVnrH@qYq`~$g`#2cjHjxTb8 z`1~dK5s3DWFEqlzf2n32vKe_1*^?YXjwGj$3&`upJIMRUP2>^sxKJPe=@2tq8*m}n zf$TvJCVxXtCg+palD#g|@f;qZ`Py$Z-y{DH`sBg#-x%_`JX!f14)JnZ^hh1B3E7TJ z1I51^bwBEX)cMqxQ5RFsP}rgm*Fpd_$>yo&y}(f?8MujFp}ze4>!`6(#z zd@%|gEi7ih;Am}WBH5Yj1&U$)sI#dHsK-#3P)`RX-dSWB{coWE{p1s)+0pJ`famG4 zkNP0>d!R)4KKUX2Pt!l@a&4dmHjSXHf)V-+(f)d|Qmn*ppFp&XfQ(r;7g8DA% z3hIZbp8zGozmR{W|7-L=MxG*rW3-`e99E=g>(ik*bw{!@-7lf;OFfi2k9ra)222MV z$}`4vzlFSu{`Zh;!FbvKPcpzh@;&kx`7J00eoq}yq;(uwACw|*PTiV1h5BOZA)pwT z3yOi4DtA|2C!<#6S!YlJ%qHi7lJE`muORa9Z6{Tf_X@H0m;P_Lw3L%oA~Cv_$DQEGWTf{H&tQxb$O5=^ASSOzGeUPE0$T}geEIzfz9+k>*? zQWt`bym>aYYg$6sUux&how}x_bh|h`At5y-B}IO{T8%B+?B+f5W}vPAbVtM6|3SZa z*Ak2IclEKGKpk10DYnP5} zV3)QE!u6d>`?DkVXYbpeePB;JYL{2m+F>twTZNw(YoDyNOJ_E)Pd+b5uupzsmtK)% zpWJJgmZ!M($y4^3i4x%n`^?|%Qzs=zx_$C9`%M3!eP*|PW`}+18T;h$-u9V)iq}Bp zb=p32)IRl*edbep&PTQFIY(>TrTgtOuh^&Fu;&~RhxcpS)Bew%c0j)Rk|^eisS|T; zw=hv`I3lTzuuo=>wNHL;m+q7F$4s`*NL&Z(Q#;j`b1Ege5A8E=*=N47Pkms|`A}jz zh|Pm4scDtATap<2Su160C!AAMzow*;!b(b_ z?Au$S9wT*2h|3eYD;g#j8MA#`d>LQS8@^2Kuz_22aDEp3;s3%Ji z%#tElP*ntOjTZBGz5jI)xaYK&s}f2-fD~e(mKWA zeaD`5)-Lakc3R#y)}Hp7U7qibRTXfYn3oBwB-`k%&_(puUBnyV_5PTOX3pOwZs{Qo zRrL@$J&AGJw-RXr;+*!mT|OtpE+5z1E}xo<=%teznkcQHFfj?)m&!0PR{9@F?!2Aj ze<%A313Ldw7%KlII{#%bP|W&|Bzq%`Tt}8TRQ(unE&ZI|5w34 zG3!5){|;68?Al z)SJ~^{)={bbd4^*y2sBRVY_nZC}kJF9|sp4CRG2vS9R_$%kWPeB=)e*{l%)zeee%D zclPT)UUzHe$gMt}{i-YtuGx)O_u`VLUy~(Q9k8UsW}c+O9{ht2n|<{!&C{>Rk{dcQ z%Wjg>3Uz2^*IeB*|H?e6EJ+{CEJ+_MW6yK?V0OQ<|0{p=@XPa&f2ZaRuG!mGcebG{ z@%-bLRXyofnJ4L22kU98bM0DJ<1?LN!@b=FjCR{=d8ft1|dw zgNL6!t#kFv-!D6_moddrJ@h;Gye|Bdu4V>*CV%cPp0`-|V_nX_b>60rf1$ChbVSTx z^@-asnc&rPH>wrZJS~$Rw7P205UyLuv~Y8GaW5pL$)5Bvga=K&tIWw%bCrhH1~awkuPS zuFMX*G6#uTuFf|xSNW;!PEF7a<}2HksYG{9Z*h_dwCbs}Uu$>+7(OD*a5?|@m6neS z(sZ%9fh?27@&!M%JgM69bg_J(SU%#DT56~gJ`XJ8|DVpok4*tf8+hqFeT_`X${g`q zy01Z5hxIk~w0G?Cku|#-m+kg%_L+B8UnAT6ps!Ke$*w?`BmIr+3U-s@esKDKo(|{S z>Qo~~t{nJ6v)aEROJQ9R@^s#==;yPPXwPv&c}lCw(+^Jn&(k0MWS)LamgM|n4tLYS z>aGfT`axHPp6ciGB=s(orSz&S{owRp9j{UG+{zz4{jaf~eodajvQ&M{MwZUgkxBjk z`8;)~&Qs5-JPlRTs!ywHtY}d+ni0wXhg;oO{h*stN8uyrh4lFM*&4l&D_1Ptanj#N z^>+J)`kNn%U%HeZjURmlx-!IH-B-AMlO%5G6=Z6BiraU@jrx-FjruzC)jM$^`nj8* z#C6r1x3vKl9}Cj8{8@SZ}sN4^L>+1N6Xr}2iBd-x>Kfc@T zYb{Tu89rY`cR?T!Azynn{7=i4z7BG8r{N1m{9f+HF#NAUq>jU{8JsFx`+QMXNics5 z*3+(pMRO!lpMrhA@GMWO#0Z%PoHtmxw@Q z;AQxjk!j-Sv)sTKgvb=P!0SjU>Qd1wB5dUgGRq9?%g*MWiY3phR@5WYe@F%pDR5+Wk%mcxhEcRwyDJ zk5w}st16!OuOynN`%o=SGrmA#kGdbiHBAep=}L?$t7nb)3&o;f`c2|unsKE9YnFug zldRNJJIOTSr^u$YnrzTP@S(Z*77}Hxq0eX+Y!urKX{Eg>s}X+ODin8({KVc5*Ne3) z(lspXwSP(|m3&ttR_xOEVFzd!thcS9c zCVfU!*ax?FbeS3HjeUP;fAyJdFETEoP91#IMZTgvp=b(UCG8FMvU-^j-qWAoRL@)2 zxpu5{sS%PTsYM4&Gx)9lzM$`(o~Exw{3SzrOb?D2f{!Ur*7R9oA%aTpr(v8uE4BZu zl5h%$xA1I6=-=FNHpASpy5QaxSnh36ydKN*Bl-@(GN{wKIxc?t4jJ(UmL3mmeg(^* zPCXvL0w29>eq~*q&9C$w(&GUvH#SLp4i?DqNeZDX0Om{ml20iuGqHk}0}liW{q+(z z`EU^cZ}}t@U+lk=F$z^q}LNb zw50H`JDN)R&(RSKG*bZ*K(v^EuA)ofy0pT{Yix zyoyUMDp7vO*X@?|x#&=BT{AHE#q-Fi>$B=5%jo4c58 zJ#%kXOJ77Y??_-qU2ogM9Lt+~PpdBNil!+V%b0|BoAYF|6>5rTQ5v+43F?9CvoVs55s#f+LkuxlB z%4=D*y*DnI-Pk*PJSWCW+HzYx6;$Qv>Uz-)63+Po$2kSvalBVNwN*>+wYvjxUPfN+ zXm8qAIc>Zgf9;6K`7=^eQd7L;SLIyn-ST=?tO6SQJi@bOI zwHtc_qNL=m%a}bZie>L@4AidgeVQ?Qg!j_+KUgzSb^FIGGY2j9kGR(7Z{IW~unTQL z?xa+IsHt+fOukVO93bD%sQNYqY9)4KznFx~#r}e8eN**@a%ZRdL-+hce=l}i_8s1$ z8Lb|YsLmK(N~^3!W_|r#2iealpGCEd=wcWn3~%E_@^OWM&GdI21~$WY9sC2E8D5`3 ziSb@c|HRnH*$MK|tqA>Thq1EJWU0XXw8I;%vA$ z0~z@&(iW;;bj0|ZC=2=`ylWhPceXLSyw<&1MXr<$jvL-pt$VeIxG71Vck@1qwOZEN z*G-NI60VW=YU^IjBJhHdzj$5ih|i%apJr`(HS<@r6`R}iYE`RJ+|hkE@=DwEs^2LE zsmR~XwuUi5ED!y`2rLK4P`I`ic^jXIt{3+=x(n1_;YHr@CT;5V`breG3;h+!QGHEF z2t!@h=dzAbR_G6JB*@j@oQP20rSp=HN430QbZ2>VU*c;l;p%(ITLXo!*1-uWA*ms&f$?#NKT2wQyhW$+-3mV#?3 ztYsO7>y#QOmCCe3K$FLc=J*)7}DZ~k}6uSp#6VGll5 z0ygsw=Ow+`UyXu9VpI#~zmPAG>Woj^8%Rr0o00g29CRN=ulJwY*T<_oe?#Z-plEar z2sWR*n(p^d-v>%k50a12|4I74K)y=<*GYVz8Sz)r|4X5ZgwD{xmSzWCACv?dlg&Wc zFp2(MN%h))36Cq8*ls+zh{SjL;Qj=O4@N`34oaQ*TR`?S96q7L83u@s&;jIxTlqI9 qJCeQ0eA4mUMpoBaJ+a&5P|(}k-pHz-P)4}`l76OEIK$ZzRBtQ~&6_HH=1!NNe(GIf6z6}^~ zBO)jwDvBZsDk>@}YGhGR)SxIJs3?e_DF6Fb_W!yzdfw~ zr10ODXYAc8B1h)6uZn*@>OI<6Tt2L;$=|?@pQL=GzgBIowg#)`<%;hPD9N2flI{r%%qjOc`;%cBW@=dk{c(tp(Hdi^vJ zIl4`5F8=;uH5c7wkABz0{$zlCdrGo3O5r5|xP|#TX zo#Teq=fuA|tbZxIsk6A@pN>IYzZd_@hxHE)-Z=AN5jh4gcv$>b$Iaij6@TX#{l_^m zChoI;eKdf)fyF=n_c6ZVIbn{xUSjJgMsfML;eN5~|Mi$ZUo7Kc zML^_y@L{p+pN{1fH;R9Il)fyM{|^uAe_HW>sowDamgg(Fe=q*-vGUkr;T+*3wUf3) zRVed^iyC{2JDu&67EY}hy(Ojgg;XUPHVn_`o)KQ!-J=>c&JI7-eMaRWLxwfDt)aQ> zHh&s5F<0r$n}?V6sN!lIEFRx!Oq!g&sqxrR_muuh0%xNpVfz@hT~3r>6g)+!^$$rn+1ug>qM?DUWTan=NhJiX7tH zYO+zqUhr%{`D;D0q7Zo=(a5;e{c4F2J&MPzUF5%|CrjgHf{f_rQ(uUJ@{*-O6gD-y z*VTGL^tQz`(1#UL$_vq#31LaU7?i}LZvSck5of|jHg+n%D@O=Df@N$({Vx;(C2=(;_l#!eFMXit@nD2$G(91_AiFi(hbEtU!47v6h4z>8jhQMcRE zv;m|$Gm2B!%?(&A#@9mu!N42G~o&e z-LxGF6XhX8-8vt-+V9Y4ot6ojw5DC4F}cXcdPh>xE50t2#7A zzs{yoNZZ43s=inSyt*Td-8`uLWo=nU4rufo$yxw|=TxgCG*G zGo46U>$nb}S#qO^Bu59)A39qyQ?5Wq-6nkRQ`K&H6*EXTm$#aBy6T?vDI|9oo$mT{ z5VWiO)X+Y9Y6@sKhYrxcQJU+}f%-4fJcka}9(veacEaFv1%_*1IQHr4+3gZg_ z?FLq_1;&6Y;P&}Dfi>=EShR0txY;wct*sbaGRB>Y!nn5h<1MWRrB=t-Kr@8vj%!^G zNl@pib51;l9u(^N9L|aA=z5o`g5j^!kYs48BJ5~{t7C92L45_ME2_8gw~{JfTZlw8 zsw(D-YKOl`syPNtvTE2+h|20WI9Ek2N)n=~S`KN7>WXPwO`S*G>Z%3Wtf9U^T&e0b z+Nr6=w?#;`R8Ob|R5Pg7R`;WF9rZN+)>Q$_@H92DrV#0>O{x$XYG8dKGS!|oLex`( z;b@jBK-~3JP8}f{sM;uLs20Wuk*$`(KqK`P;%=H0iE(%OQc$z#`uw{YYzMBvySYmhqyMWC-K*#To$t8RUrtX zRDE<@w5p0BQ%-en&CVK(NmgDd4ncJQVN_5S0*F<=VX^S37!0*IRSkdR)oeJBpu+fD zQI%p8S5jN>H&G2mEPmCd8vE*b*h*H9!NtmIzv-(R(=B$^OYkK{{iWGi(~$4#sy)K0 zp%x>6RP`YK)>PM_H)^Tzs1{H;Sea|9hcLG4s58KIRR=hirrKhJrK=WbAwzY;-%Ry< zI{T_+ZT3}q9{VaDnP{NSA(ai)mUb9_*(#$mJL@Mz)>vhui6-h1`3O4UXWza`XMr0Z>=#$c?zBh)syv|Fexm|X7)^$61Xo>0f(^!q~X zE+@nup;9ooJ`n0hIQF4Xqmk8*gxU(Tr9!n02=TE{OOV&SLfwTyx=*N=;MjhlBqBT@ zRCn0>L?~+t#?hxjO#?kBln1^Y5~>~SekRmTOs>y`s)_zTEY!Wo=odn*!0Ah&s$h72 zCDa9MBxOSNfZZcPiF!hOjr|iz`9`Qa(BDUe+J(OSR;U+|i|>TWK-kBGs)O-$T&U+P zDZ~k(7Q*27LcM{mJ}K10sDDbR!W1EX5K6<+k3!vzY5J2;2QjKoW58o=_*tl8bjUBb zW`X%LLRH7jQGJ^;kO7$&9>^!M%>L|o~sa%){3#1x^$QDY~!He;?NUHaclf_bfh1tJEs&~+9 zOQm`nU9n86N09F2C`A3DBDY%70&d`39s~OxoMVucnK<8rKAMH|d8p6E`5dgz!5Qv~ zdvUH-8{Xi24U#zz=jB+k=HqNtK<_L7I2sF=aDEe+S%h;U7RSXnPlh*3aK35wGihp+FOKk76#K|oOffPSc3DjI4{Ndew>$;Xb7+}FGoRMptw<0Z}o0X(NHn? z5|ppPIS!t##yJ-$ydUSjSo|Kqc`K%B(N4D-3cVRPZ-%_6%&qFe@fkQrhhN>AWR0sM z&_N#cD~4E6307R>VFu3cw`15IwF8UBOq~0o^Jn4wG4eMX=dsA^9GoA*M7bB|7wa=@ zkLrQ*Je+qT%=tJ^!zf*V^BOF}3n|A~T7>h%7-EY{JeF#Yk+B2?8?dA-#d$aKu?*+U zxeVK*Hp2Zd&IN9CAkMwf;7XiN)Caefvf@By5k zMn64>GoHSQhj8ABDgAJXp=6VAtx>8EfWogu{2 z7C>DL-Dhxaf(n~)ZU+aR#knuapTl_rmXs|xKZL1JROV3%>+B4iUxFj|;5?!mx(MfA z(N(i>9-M|Q!ufjeIXG9u6u%eeacH-w$g6I}&QMh1Ro@`fR#8#3NQ%e);Etax&tQR4 zh3F|uEl1Qs{en>-)xyr)onz3mN)1EW+-eoZphqMk57rN3rh(@fI#Rb}ax1v`aKIH9t$VOTE4V*3 z{X0&#VOK@mnxwm8HiH(Lx>K~Qds(UitE6rmxQah0^)gHpr?yHAlt{f78(O3wuukgI z@U&NISTh@3Rk~T~NQ)iq$#PM3{&`EkJ7P9z*4xOT3puHnb3)A&64$z}Usscq)FXGrg=I~ikf6h7i zlf&mq-3;q({Lk)Q7$7RJQ0j>lnVBsVmXkuTF&(Qs0UTq zhm%|dFariKq9})B0&KuS9Utv*On}ERM&rvle1p_8>3@vFH%a|sH46phodV2_F&q@y z;g}m$nEnb5$K3dU5ma(G=7yQiRXz6D-wB5}7pi%t8iz4g>R`KwukOLfgTqIqu8tue zU&CV_R|Jk@E?Hb(8+gVVg;P@3N6q+Vj)BusPo}{h4nHgPRQ72fho6UooG(Kieo^WM zG%(h~K1P?g^fk=rWJf;BrJv-Kx!1GKI5^j(t-EP(sb{+>Sm@F&j^$NOg{3ZimYc=H z4qxHYbDDscIDC~$KgFr=gu@?n=?Afa#&7lr{mxTm!;oj zgKszmn_PM*`{+%l!ObrHJg4n@p4W|o&%5+*?Bn+x`8JoH!Ym%b5~B=H$e!6}zszzDJ( ze%ht0bK4I(2F|+l1RCh?@bfOcl^M9fdreJd;3Dc%KHQNPDg8YcuW?>`jLlN|dTv>B zZMhYgtMqOTq9sm+g-UgwcdwK7pzh`onzz)NB=>kgPp;5I=n>L z+uCl2uT%EE_K}zSnhI=Cx;)3kCq`~z3sL%!+9>$Ksjx@sv)nF@I=ocrRk`5bJAA*= z3+T{khaXh>7^mGihaXnj%~?<(%I=afr7O|FN)A7&^rO5osY-6aqvJ|0KC z=;OT2aQJDZJ2wE&cKBJP^Es$mMIAF4Ij?j>Y;5tJ9Qj41_j2Xy>+mAC{(=q+boeZ{ zewh~$!@(`4WUgE9=e!>6C@ggAO&nAc9KIBnejG$oqU?oc1>{_(=Q#3JZoQ8y<#LBV z=+=+$%51g6OWe98Bi`Wfb#DDmW$@>s=EFYw#I3)}M8Qjr!X~%gmInT2)DI@Y&2Bx4 zefFNipLgq@yMgbGvIo^Rw;qVg+4#?#`a9hEAji-VhwpUjbPl@X4&UY0li7toMOmqs z?id4Z9poT9=P2xP>$^FM-O=_+RqECc(c|*bcAxHd>-F`(6C8fftq(Ec$__v5*5$AS z#-}>G%&iaevL(&oN8Ne?18ihD1;>#>_DM^JpK|M2tk5y~7USS)G{_8fkG8wutXqG| zLEG2SKkwEru?q$|{Gwau;3hkMn8S-ax}XdAEe@aM(Qh*&)_A92u16nbgHs&7(4(8> zQo-R%J$gRnD;>VVqi50KhaA4jqq}m@u6Ou@9-YWp6yYTv{YWS9O^$q>M-M~aTJc+) zf(;(sAO{LBJA9Kz--giRUw8OskKRoK??&4z+w&fMH&b5f$hU!G!HECV;X6F~_PXF- zI((-`Pve;RHrm``26lP0D@imE@u!@E-5$M_DL&)yJsvG-@OP(yQjcC6KDxW1bvOp4 z{&Mrp&@F>mx>?QPM?LysF3`0de%zzW5NCWnhoAE34jfsH9e&!QU*Y=NvYZ{(S&!bw z)uf#xKkw1gGr+q!{G!LwwY?}Pa0-gN`r(e?106ogt0(g=X_&+3dNrm3dfwp+y*k7_ za)QH`dUeGb;8PvG!mB;JkFp%T%B!2U2fx?h4_aRRO$QV#b_zu|9Ud_)N;~#hUX0M*e%bcei{=8RLVFsTsXJ6uPgFOz_R~)&u)2pkp zW8QXBw##eZ6MX1Y*zMJ4Qz8GvsZi>*?;$>S_Z#K6Ar@Z=6UdQ}Zt|F#{3Y_-p3m)*O7<){d_3A!MdBqrevYz+qM)BZP zV$4&Dz(ueAkqdIo81oDwP!y&6vJ2B=%tM91tSEhwlfPk%d2kSz8>KT6!JEhMNdUI2 zg;Bbg9_7XiH4ZF|(!;oX^>G|n5v31txf_bl$-@=)^r`kZhG56|c`>|})~h)_md5ZBi1$!3eD|IdYc5k5 zHVxqEfIdn8R>W`(;jQx@TpL!#JY#4jJ&oSn=SY)vLk{rbn9qzfML)n~J?J!*szc26 zL&mf#P+ON}fv$}?Wt7wPMb55AV>{jPdL6d)pNNhZjAZU zD7VlLaVkF<6O9?jTc_;spbs`z&%|_cyW^{s=U$=j;q0tgo;}TA>xZ*G935veu0{zTH0~qqtH~ajyBW6%SJq%*mCuL-8+bD z<2>Ec>Y~9rv9x${o#gns;xfdO*9l$E&sL}4BF57_(qId8M1*NkgROXae2oUZ-=RYj z(q_U}?=LOG*L|ER$A@QsoGqJ&w|-n#t_^?jaWmkGd+W)!!=b%})-u>k__!X{5C$yBp^A#h}52eOzB$foR`$H`sogY2RqtIbgFmUw=%kgimZ%$v2dmpDr==l6^t4 zgEmX?Ma6*~T5n{jzBXaszN+<3AoU5~T!X73S0KyxA(oefqc+R-O`%8M_BFDmzAwXl z_hnRn1|vM-+rnB6>94to(mmUZ&+n;QubplS7j~MT9p)(3gV?u3*W7~h2 zUSvn)9^DGlDWS1^(dc9ISWBnd${!5JW-%EvA|d2(tkqr&pM-YuPb0@t>Bqv7&_2SW zE#0mg3OYmz%IR`g`Vu-uc#PhKnhBj`MO+Wzp0vE45(Lkc0mDnm>$-T-myqZ1P3846 z_I3}4Z!53ym{cV6boj3Fx-xT7Ae)%_r5(!a4>D0u7%8Zrf1yI}2>0ph>Vfx(@Oa$? z+hIa~$HCHydVcu(0}ZWZ?Ce>wJ2FX#V0%eJM5BuOoIo0SN zP1K)Yg-aMJ*JB!D6#4ZD%a-)&Y_3H`o;KLoh(63*hSED39M8aK`-_m6?c#Bi8 z!mr0P0l!uLZWLDeb-Q-pqh%(F@$|#5-{JfjD+>%S@#|VxOA~IBcNo6TuU9ZF<7L?J z4SszWXV?UXZ}RJ-SeX+h$&E(7+4Af192t`xh3EbHAPwH(@NIrQ9m`3=RQa~4u*0u= zwFI9gzczfQU;mH>ey78C`Sq>r_`75@s^JpfueWk!&XAdg@A2!}NL9i;auO~L6Ty&4-!!mlzG6Hf)sCh5MZ;OAwg;pdZdLuTlAnQi#RBt5DH z_@A=G@P)~GFP9MIvIAP0te+=$yKIM7BY42a|P+81N{Emn7?D zT&|-XzAjnM=SV8&@D0iOuS(!C4&Rildox4jUCvNV*1vJ>)DC|h7c97fPN?8AL){8& zOV%$i;#j*Nup?RDNClt6cP8skD35dau4J9h$r!hhrR7IcR@*Z%-p&kZR6@7q1J=1lK z;d86#&)FsQUG}23u!8%20^J(hE`afGMpVHmv$OsRe;@f!wQT10-DZ{~J{#b!-U)4~+RZTNaiQs(jn!J!v00q22f|WyZC1%Q z8e5A>Ln{_klYP%%9aiafqba^j3|f`h$~2SedjzPE9Sp|S=TS-S6b7*_Rd zmgO6XQq{mRvTWb99I%EqYwBA;S+>nu_`2qSHKM&?xVrSsL!YX~w)q_4od;JdwtE|~ z#}W=yuhMNh53ku;!e{cZ(`Ig8b##(?-Dc5t0J|m`N3`#iaNTd$)LW0BDpilv?%5fv zMx-`A7!Z|GBefq3pZ>P0RW5|GfL&I}_f1!@+BQq}N#waw9h;^2y5rKLQeB&+`uL$j zC1w_ht(`D#qNwELHC=euVXRlmSWCZN!HVFn)O-+DIJE{NQm9@qA=PgkAXM#ISSV4g zkOH^r?ZNe-dPiY|sF-MeD%v0GPqa#G#h0(X!35Q+UnXC;D#hT6Rc-Lsr(S@5oLbxv zSI=rRuCXerpJBI>>ID5n^(IzMzZwmHlGH$yC#&&Tc`B>nXs3#*(*fh6s`{!MU$tt7 zMQIY0o4}G)mGJ!fI4boJ-%x7Y(>6m)e!-t zt6$-6hDyX%nW?6B_;<`Ld;$U|ZiX1iuVKPeKg8HT$?Unyo; zVrZ=CE8#ns29{$px8+O17)@+v(`a86Y=DXFS&LI^7rH#LgDtD%yM)rjjuVY6*|!f@ zfr*{iU9Lbi-?|21oo5+pTYyR_Sc{VVah8W@`HK+#&a@68zS>m7c??fV7YmpHJQEidu-o@BlT@jWK! zKkD%f3|Bu4361c3FY%`S6sJ^{l2zC|krb zcVOXXF}@8LafwTU@Yx+$3jQ2MUE;DXhW`SdPW`YgU-x;8Z!-pe;>!L;KId?Z@A0PK z#Ul(~4!#mgQ{pPS{XO8dF@6(Q-(lpXhhr??6z1!GyWkTjJjX76@Lr>E82px0@P{9@ z`KIy-14LrUYlfBW(Z1!(!P+AZkM*r4U+3`BSRXG05+D1`mhX@CJ%NdnxWVQnU&Z?3 z4{?}mtbok817#;-eQDw6PBmd1`TJtz`Us#Ue;(DVFWd5czP(=k1vrywP_N2;0O_wsaKWbbGbkr%#G>@8! zj`pg)8GMz(wHKR&+aG$4m5*RM6RI1aRCUn*F7*aRPkB`dTVMtC7Wz9@xMrgl@O6Z) zpR&dqSP<~Gi!t{c;&rKH7*fLZsnN=hMwuFdg%GJY>yg_(_AZKD2v4YUD3NMfDjV!u3kB+3>WGTT{;3C{=6kjQ*4Sy>>ba0@CA-sR zZr|bPF^p`BO_wU) zt4NUlc~-?eg7SIbmp>f%rJnpToc~Lz%n6VCCG&dT!}woo3#Guw>i%8F0ek})$6Fj- z?BG-M;BDJGw~w!k_}`%#FU$_%?B8u?Bi;7}CV>B4n|1Zw5dQU-rm|r;^Gw6k4=~vL z2P|mA(PZCr+_(5YIe`4A!1KwzPyFGjXR7v?orBUt9&|NsAp*YF8Qf=yHcj)L;`sTz zj-f>vzSbD({=*LKmN4O_Ny7g{b6Yyf_j8@_ku%HXxbUR20eLjM>g;vEXU^8FHylfY z|6E5bo=ol@rsTXGTDGqzoxIS*gx1v8I~@A8di&#;$9^R<&_lTMiq^B(0dD8UXlabT zja^q>+J2P8=wmV93GxLj4k}QRsn50zulcq5kk>FJ{fSPsgFW}%?u&eu!B)z1x;S>YMyDq7sq zl4|lvAbYO|dNHY%&9J3m<|GAdhTg;SlT_QDf7-_j$)q|qtKj2>WKvz5#rhtD{iHOT z`FxLOf;rbNal)IK0h%!$zND0k7vYM(rO4Ic?BD9h#Be|ST@s%DTNODdT>M)=J{I2o zTcawq(088EaxBJeW@~H#!0ZE&b~Nlg?}(>eC7x!B>um`ap08=wo_Upcrc?X1@WS&| ztC)wH3vBTdwbA%O^TjDq&li6Ee6pMt{_K1$xib9c`Kp$AczL~xPcO5~W6gms`oUd6 zcx;@x2|4l%GUb`I==WgP6~70Y^7&neE087k|$vy zkW+A`)}(NsKWfQc z;XD3lVwXP>DSz>gdaiG4gpdA_jsa5PVuq|44&tv454jkq&=fnEJmRhm>sdMBWfv1= zmub^l7OyA2m_GSR#R z0DZ0$X}g%ax{m4!TXpnbS%U{*QpilB%1qa@E7ktFA-2*s_8@532j9Zj5@Z20+@Ny^^o7oIi^UwbKl zW%sU2HRZG6HJ570BjMLBCDq|>Bo`SsGI^cr;EbEb4v*kWZ}^W(IdcBW)-t66-yo9x zPaXU-t`noHHeZBNFnLcVTK zj?Dcu_NI%AN9NL4;9d4qiDv)3Ww1#7}#N5yzE@1lMugX?Gd*kqn*5)u7U zt@tmOtXriI(~xWXvnxOiJM^?J#ch>Lu}r?JnS7hsTU~PYW;SmO)l@TJGLK=bMDShy zE4VYQJ31Gmui(n;5vQE%c?6&2ic-_GDH_R}ut>UkG?bqTY(DbT01UKrRCM)VL4(1( z3g}^m-&qW4R}X$!PozCx9PO6fWxL|OZdtqEE9|aYog{L8jj^Lo8-lAP`L(pi`+e7< z2R}l0p@a>Jv_eca`L?r$&Ab8Ac*rmod{hX{ro|t*Wz7mV#z1GcX)o)8;y>LoNlq_L z^vIB9X77h)VarU$T$CRv&X~+ISc7G$snNJvRp2+=O-7*c%n4jjJ~3-g{mk=B$RV{D zf{bA|-zMZ|cI}rm%0D-?GtIhj*x)8_U56ITns?N!beXwNGq`WlouNwqqY5yYh_U9+SB%5%{bM zS6n4p*0wE;i&)Bwmcy+sNRz9PGZc5DYwV%e$PC5CNUN*SLR{50FhjAC8H#l~V`3?M zbLdy7*O>@N(BLGdzgo%NvT>4!kC*#Y_`g}=F`&8 zBtI_A`VzCv^O-&K7PSXHY>(QyRg3$SlWpbN;&3?`s_+;mVhyvmWPVWmRXN$PiCMks z*hOae+E~=Pfn%;ll$1+vbjEs(C^Ocxi`&J>q$FN3$eQL2C2kr4gEDU@zAZ)ueb6hhZSKd56BqD2r3<9u%~l zH~|J-QQW$=k&nP#qjC60GPrNESoqk+OeC8(1aFJ&!DiQynJwAov%#^5qY7{JrHBIbQH@q9L6;h#;5^Z{%yZF@5#MX)E%%OD6|2kqpgR+81Vd0O3cz)gMXir=3F6#X%^M3)yzuZpHeH~?+L8SJ4d=mm4g|g4lc;4** z@f83D0W<^%l|d~y18f9XVKG2(E&ePadkUa%8~?n?@&)+w49a^}EwqHV1Bv6$7RcY- zYv^NrNDCr`g)P9~OjVplKq(HBNM3O7iYSJ-D_yPB8A>@+`ptdfveJNmQmO@|aa1~I zxnmKRu^F2CPg>E?Dxub|?k1O&xHesF?{f@%dun31b-}czHzh;)vRc zG7dml(PNLMNC8KaU6mz&u z8^JL+e~yCSRDeGSW&)((hB3GVpbf!lfPn;$0&wvOZU@*%@D9Lx1p5Ha5PSvTjRQCd zP#2)ZZvd8BR$>L80qTRI?!4pL4=)8L>iypQ_27Aj@nMmE8fI1+X@(C$JAWN`RlK zf+pzg@mP$`bhII-x!$0=Il#u+o`}0J6MGJTiJfD<8xF+& z4QsOl`#@-tFbTkpokk9#xk&8%MH9*x`%=hG(}9~@p=eyS(90%bGc+7Gq1fyWT;LDJ z7=5M@ep>;eokg%Q4~70}04o5R7Z35vnpQvX7N3KwWqa;!aSR|Dz#AyaSW|cgEO-fj zCPS&uivaeFn}>!|VOeH*DvXAN6D~T`6(xlX--P}$s+iC}2FT^u-Gy4?po7qV#uCtn zp+^Vu+54gw2kjatJc%O`^tY%8I`X`mL04D5C$;IM}l97DbSPexxN{VEsw#3ma-ya`GESIi`F?J zj^j$HPA8?H<_0K6{A~&W{&nY~v^x9@1tc{qCV8k}WbS$MWl~meou=6L%UW70&v8NDxyE(5MKyn>a=7n#tCKzu; zgY^Ms6141T;nz%n`o@*RXM<=Y*cq~vx&Q?LQwatFJPu$c+B(>L90wjs&m9X39Bto1 zXeL^G8ggKk|CgbXjV7V?7}dD^H#bra*#nRk*wW(C%F=CjLLbOYGovmylYkjN#a28S zX=X8{-Puegq^oRcKK(G2H&JZ&Xt$#|8xx=ha{Ms9fg9) znL8bT>8uS9It@LOyj(Doyt@fnA}{=mwr^Yv@;VMB%$?2vVD9+D*5qy>fXUq{*!&3x zlJYwHi$3#*&+^P<{T|3po(l_0Hrj;VSJY$je3_IoYCeK0u%%uYHLcW#)I{Ijs1?_& zDl1y1-Ut?$Y>h*`Rd&5A*_utUovjbx*=EX}Y;80mdouIo?NZ2Ov?`-bPUcr24;@FL znb04DnW=Y_fK$)<9mouZ6R0h4J%|atowXTHY(12jYk_z?rmBPkGt-2S1&IkNL=`y4 zp*|N1sc1sRDAQBDsl?IE_h(E`g#kh>pkjLJrF!B(^C^5J!ng>^wcSe?Vef)$4*l|#ASDKd;`k(FP9HR z$6>$brMB$uaZN+(7f{v^DtSKu3?euJu!!IQz-t8W0sKg?1)y3(fDHhH078S&RM2xB zYJdfO0KXAb2Jl)=d)9|)EJq%;9|0ALtE->y(>FcAymCJRNuZTRyY%6r`bm-Aud zdK~h&%9{ty-`HUgZ2N5}>ZSl6156_L0^k*b699FZ0sIOumOx&Q3+EuLm7waKlTea? zlEWjGVnZ;xvn!m9DRxUihtqFZIWqLzu zhUf?Yd-9b*FB@$_EkrdAwS|IaktrvQ|1g=k733(f`$fd!WVj3jsn;7)=k09FI!USEJj)We2O0~zjkw3oL8 zWt$+(8w2nY!AyV-tpTP23;_roq=Co5X0%59h0g&M?!X^3$vJo*nmo-W)7&lCB$ru! zJJlrSH2@^phkFjlf?MIsQ4|Gt0;IG7*aOfMz$Cd4P4&ZpN8U3dP4$P+G<7S0WheRD zEIf2To6viNdQ9>>i0u^)ukGP$KSp{b$&XWPC%G{!3})>rc9P#RA|x4QKTU>DW$@`6 z6b4TMc-k_@5CzX)5Bn`agYJR22Lmw6Ex-1;lg$O)^-UJ%ueWgTF#(!sZK~wxI_yVgEcWwQ%1TvDAQKGq$#(h2%IR zy%KhJibeOK`IxDYXH%Zz&YJ{29-_SY0P6^f0QmD}p{`IVTnom3eFuYeodSnj!QoFs z7EouP3)JLGYAj1n5U_E5Im%I{>BwD!>7{Ka<_IQhJPZ92vQ5Jjw{$!yb_&UH)f{g&10Yd!s zso;lTe7ipQ8GyG{2cYkOatM9_7)0_BR5iNdg&cV_tnAxMk`mk=`PCcf1w=I4UU9i zew{HifNT=jSB{Fgzg}An`#o)3<7qezTD*%j_t%xX0Py}g9{>*V7WXKWH&eNzXCRgF zGYXcieRo8gKNE;3shv`S&9gPTI}8^YPPZsh9|CKIA!c7qZb3 zWlg#Q)CU+!;0GuI2#HGYt`nH`9B42f=yL#b=ePyUq(Uw;Rqs1di5Hs}SSg2OI}b0DsjubTHz;bTE^FB?NTfEr6c9w%m!zZ{a}04Op2&`w)cA zsDp%G`iop`ThS03->L#c95@P%^K_t*+81%47386~M3`e2T#v&zFo%E+tjA#-_=%Ni zVvKw`;=oG~+77rHLBhkn+_%JWh>QajG3M~EC-3tsLxWd|vWe=?p~NxJ1oDE2z&Ozb zCB}*C2F7jd91gti0xq8Xd^SV#j`z%dY+ z!8(IF{MWsCf2{I#u(YBT%-Fo%;42^v4Q3}y273Z5SOoAM!9swO1or{d#*7NC1?Wid zG{A6zmjUh|cpHFwt<`raT1zQH(LNNdL6Mn+Po&`@iiWROAK&eC0Iy&}seY((1ng%s z9|IgCVDgg+Q29;(RxW@Z`uGJ_W`J!VGy(Pku;;)Ys995}=S;#oC_)=teFj3vU+k0p z)L&>Lw2gN8;BY0B%)<7h(Kbs}Gbpoy?2B*Gz;=Y23I`(Mm3t z0GaHmj7=*v7t9#lLt8W&+siRp8^8>vOK5SM-Qw>sYDRMl2<;0keg~SrY>aeYai<@} z_-Dd>3L3|0wToI&6p1!98D=boyNU*B`AGtX`#ONJTm_Z~KoPM_L``G)0Gl?Kcx;z< zoBv>$@4Zohz1R)aOQ0aTs?bi_V-I?J18{3f=`FCx@L#i91F$tU!j*my^RD=KJ(=P< z-MiSEB^zc{>jU+TkY@wrUIXu5fnph3?It_VfKvr1>j@#QDTZX>nxan+H0}zeRz}7C zfI}cF90uT|;~?tiKq%|TpHSaCXmy7MP@Ult1&W0(;0HqJ(o?-jhM!Tl5M&^0Zk78Fg?)< zHA|oe(_K*0nC63c+jI{|@gK+-%N94i`4Ii1>822Gqv=ff%@xxJBc@-ZMMnJz0Zm^5 zFnii4)Es9w{tivE{fhlAw{M;@4}yFcb;d~hp+sXSM55+bl+V+2J$b{-%TXs+fgvV* zB2;f7BD2U5Baw(~Svex&XkKegZW&v)Qq7d&Kl`2#sl%eI4;I<7s)*?=w8(_-C7|ik0LJvYs9DNp$I51?X`*&x1{l-IxrBlIP3kzN1CZN6 z!~Q-9w$XG0`F_N-J9IE&x;J!<=?Mfhy%fNhK7pF2+3Z;POvLm$2(M1~mymx$9mn*W zkkd40{2BiK{CS$rmgmtxD7h+3aN3`tEl&IRYpLC{86cnQ)Wsni$;{aZloK}-;(~~v zkn=Y(ciBF*TcAnVSoTMaP(h^mwy0*BA8B1_zcaM?b#uHpHZRit8nz!1T;0CeN~nD^ zYc!KDqeel5n-KVL%-Hziiiy!sp1=ytZPFFvwuexEsa49#VTr6Bi0$E@eCqk+wAAVEIG26%b&E`*`eR5fcl zpSzeYev5!z{3n1}N%o?4c8ck~xvb4atlB_yiCNRXfV3;6&Xoyougw6wn<~z_{wS0N zLka(lNT>*Blbz?F!0cG!q^&AUv_C<>{%|EB89lR=feb5Tng!u=$KMw2kdB%v&Ke zVYY0Fb)Gd7X@M%)XFL zq0|X;C?qD#`>EoDSrtl4p~NsZ<7~qG5DI1xMBQjK?I=e;wUnyYNNep}C(MS>_~$T> zvmMi$5SlQbMOA(RhcNG8&C6jHpwNW*E>umJe-bdvW`mv1e1k4R4^j4FWkhM=F$p8! zrPv1$Z=l!-^KM8?m|Lmhgc*j?PC9@v%V?9+^?N9oFatx3rs&C``vX*)H-l;`dGkCc z$~-9Ku`}-_Sj*3p9w%b2?ga>m8fc0k{{m(%gQC$yDoPRZm2kUKjlJp}3c!`IG6BPF z31BY25>as+^bk*1+UMn04+u?6LjbTiRzq1b^s3>AEK!pv;=kPD8BO`vf!7RAu+WUr zUQpdYe?pSq*EBP-jLkAE^MV-1Y1?5aVN?SFLOba$qnZY0){fa|^nMFE<1l2WA>;o7(_4eXemVF zn{hvEEy5zlml}&C-@Y4-vabA&OObhTcOhsi^Ty>2^Bx}-<8J14%$c$x?xfYSvb!?x zPDInQjJPeoE#}}CP}S^%!(cADCUoY=O9&;D4s7Ptm(U1W+y{dr=(QO+8=(Cv4!J;P zFGQ9j+|;-edS)i>wkxo2c0u_)R#+&9qJrrkH4-%=f`8a_xN&|6?XGlakzBG6{T~_` z@hA!PO#3|m;1JvY5!&TiKzo^dE7JZLwjU9g{-1#or~mEk95qr|Yo+`nQtL6+N^u0H z*2^QYL|t9261pV`hg>V`FLHv}%W4t9)xj7;)UL)FkIEY(HNInwh~OV;tVcl9uFo3J z$j27Jz8T?>LeE-zg#XSaB8A4+*in}ww5za<=4|H)X>K!AL8PPwFIBvg@xHTK6PXlg zXX2r{!ybXM_G0Yw9CbS?nqim4UkiuyQ)E3WvAB9mnQHZD-W+9@>>9fj_KynqbO~O( zv^4Sp=_Ps93#3xIID)rBgYS>JT$s<|cd*<;NX(yTU@kj7+Erl*GV6i|v9|!6gRl<4 zNr2V>p%SRIh_#^LT2>IOjPs2s?#cVDxo$i}!y(_7r6@OR=Uotr?tk2XSG*zFMjLO) zyc&bB8?o7n0521i12_&4D&=si2lgjx;$Pq6D9M0V-T1{h8S7$%_`eOxUW2gr0uL5( zFNBvBe6CU`cvQ)D$|+lqW7K7Noa>m8i!GE>))?uXcUd0q`pd|3o~E3#*Kj;>S)SlZ zT!w++QK?T*fx_<5xURaaP|?Nz3CyF4)=^Fw|F5$Xm*tgQ9gMtW4ds;GTn@7cM(qd_ zUDp};;0GwD>>Q4a%W}VK{4z{Tj~X1N0)=y8Q2DY#l54JQ0DUHUQ|2#^3|y8cyVlqS z=0M(;Z==ksCwy76ow>zW9DC zSxw5J#V1PqDaHsiBUIxBWFx~zdMS5||wz63R^ZlE< z%`YQ28IPoA-V}$L_jvdvEQDm(BHI^{R#N<6Tii#yQC!+q2JJ5%eqgsYskl-|wyt2l zV(`6PG^hB65bk#GEuI&Wp}ODJN3%D0J9dDHCY6D2G_Rv)Ot=Xz$`3YJ)Vrnl$B?X5 z!KA0Zo#2DT)pBGNIk31zjto>bl4enCCCg;4nbFD`SUf2Qw-TY^r*dQ~e~(3NU|@BW z*_v{&Qe8U$v#&So$5jjS1G~4aS1=lL$xt5_z%<{86KSl$>8u zmg@|6-3ERadlej$OWeeQnGI2}-Y84~&*d^U3#rQHba*@}zZeS_m$FR|nx*UqfaYAv z)Uup4p{`IfOIh|fv?zLh-yI)1p!!ER!R$@5)uEBmz+3HSqwb zm@AKa0HDn)$j;E_?`Fz|-o(`~#Vg3w5QlPD%iQ#_7B3)o67T}@djNCK*Bg}wLl0Mm zr(wzD@Gl7M99lyl9*%=|L(E;<+o8jY%t8PGqqum#P|4jc> zgSBl8_!@5`I29@dHu@VQ>PL*a>7G0&AE$CF@3T-g-Ba!k)QZEhVY;UpnCYH;0(Q?- z01k0W3`FfAIM6=}S({^g5u|qijDX}8N}cX0fy8vrUaC0bV>%RCz?N+7ZG?@~IPe|h zp@N75zk?YEDok-4;Aih}0ONlFYA>aUF;cTO9ms*ycHllpR#WOYfbX8#4%|T%$AM>{ zFp>`Bc%O|pumJK+NDkmu4^zW*u)D_tGJIahG$_SG#G^@gcD#UgzUSV5WWB~ zA=E_H*Z_xXLkR8R z%8Lv(9~rKLAYle9F@ZWxq7R`?Hrl|?2lOw20(*Kkr-8V6Q`83#5I(1EW3%m*+0 z=>7*Bkp!NDfDLmKdJW~{*l@0E78(xCWqaK7tva)SxMk%7pd~($x(5dr3YqT;l~9up zqSioeZqx5`q>%?vuR~A}DKxj~`%x0P=cWfK%TXO&xQ!lci;8{(p|wXDK9R6QUJ$6| zY!uZ8xE(;`?p=Y8v|3?nV}(DXmOlz<8Ool8G!&ffdzjBh@Arvbya6jMEI35nQS=c(4!}`@W&jrmG65>zi-yOs z;c;MDV8LksJy^Vy#k0YNuy`4O#p2BgU;NH?XL=0KEa~65I&Tj^I{+{seabj3t-}Pz-aJK!aZZSjOU?K%pEc8;f!C;5jWCYYoASwN3=IHjseUW&_y&Oq!oYng?gV z;_#?C=&^jJIe!5EFuVE8Y(BG^&y0rn1M|Ug7T|ie$8^2}5ZcUgrt@1CGo7)xI}Meg z*rbyNyR%n+X^#i>nJ_mf>OYv`8>POSNqpXdny#ZxkK{f9ofY^lq z%K_Q|gv#i{^I)UFf;#~oCwLFw9Kn8oz#@P$fc6CE0s0cSF_G>dh~q>fI2E>#WgxSY z@_!kPs|PQ>_W0JrCfBAKi(#_`3e8ud3b`NT7ueKjjN(I zf7=DE-onakxgCV|=P>+5w9}M2SC$qe#<$<8f+o0TzSQu&al^y--#hV?2BW++^(pfbHPtXtxYU z#KCeHUHE5g_CtBW|KaS<<6}DCKYn~>&PHl-Oe@mQZUg zBLq=vY*$p3w5qyLT5YJUwwAVPt)f-5w9#5iTNM4it~syv^ZxxFkMBQUk4HT3*LC0L z-tYUIIWy;6TIOlj@V8iID&m_D`?t&qQ2rizUjy1h=MiWl$({dww&NzWbwZtn+UIYyE4~d=2gJ2l1xrvJoH3AlLOLw@uvibt^hm}2izxd8m;WJ| z9fr2VF=HTt=^r!HE$Q18|(M>7AQZL+e`N0Gk8N{&Vf`z@EhPrpW# zzq{{iKz|5W_7!B(Lo*47Y5?W$(FL}J5%)$0FJ zYjBkI|3D3B|K}m#?|&Z-pM^hk>|c7gZgs~I>F@vB2w0`KVLqXy40M!xhov}P)mZKS zD)_r&#WvAc%_I!5R{uZaPp8{k7yMO-^XJm@-&}fXtiS(6QOJ1o|V;+!l{xzJ;0vmGBb+TQzVSfgd#RHv+}h zArOe=9;<;e%Lik2Yp60zdP_ec27xa%P#=N7^$0XYpq>VFS6QZkE(q*Fpj#YD%tmDr z2ElR)7F(xY*hh8KP8bK%V>O}vvh4+XnTpM`w1T=%l*FZ~f6CQCK;wUS0dMnaegyG} zOFQE`#k_OV{BP7rcok|r5+!azz{oo@EnzzXAL;RX5jd@ZBM98pz!?PU;W9AsG6F{4 z)oI9DKdt`M4O!Mh*S+o9{vLWvx8+Vq*E|kJ|F)b3<@4{6YZ3DAk>?Qb&%l5e@cjn< zuqEc}(K>lV-S~=j=P9BJWDIE#nrYoba%b-?u)<_ z1e)h+Ek>mKaI%8*-`zTl18(8Zo@I3UH|+1Zok-#DxvL0R|9a>*!aJ}x?8cw{ufT5W zkzaGnJ?rb-GyZQYaLqK`>Wm*cVHeT5{1~`TC#ZHtzy=)QJE!%~Q>tEx`8%VL2K0o{ z69Io`{Enmlz#lr}4Lw>rV>BZDoiPgmt22s_Z7N~F4n~6Mn+R_(Pg#DRCR)!O_2z?SIwBb4g z-6+*>ij_~(?ctFX!x7W?w3YT_z@JeO0zsqEw#l~iz2fX?4|n|aj70UchuLRI3Z&gB zBYN6HL)uox;Vt{Wua)z^A!;^)sKRwwhiJSRYj;n3{W7&s`OwrW{#2erKzdhk^s+}( z3BcM2?fAetTweoHV=D_bY^@K-v%T!qDzq+>gztds_Cbux=#N%(YlsI^w#*^lG58=y-e#o?jUK~|wZ!Ft4bRw4MmV~ioLjsf53A8>nm_cEAli9aC` z`r1F9)|mfcS^j6t13$o3Zi)|k)sTYMfJ z^z^-GV`!6=R-$ui`Rf^2n!RON9;szkGgzAMv@D@Iiq596wD{7pG*ip}&WH5t@rZ6U z*+07JuUCP1{x2)-QcbJx{|c4RzV_gH)&!~ap}!s01kqZziTxkT|IU?OO$vMUwa-j0 zbgj47bU6+ha_CKals!|PzG<)SvD-SoguD;v`m=TW|A|b}v`HK7(MUUBqdi&Wn;Y?y z-ps<|8|{_d_9lfl-?z^Q>~z?JiDJvM1w;mE@C*DIwu!!Vx7A+izc>w=_%m#ieCyP; zc(ebD(_qVg<77plJ)+pH|BIEc3+*+0|K{yR-t}>X9uN?rMSZWO*e2N$s;|?azfjva zmH!s#Mu9v)%dhUwc!H+Tpw`4?9q?~0{^tO#R9}AzX|%)MN!ISL9|%swti6Xn!F>p5BHl=|1%xgX`dFc>0haV&G(b%i@l*xxE`j5XF3 z4*1D_u~_LDQ5u!EV@7~KTl`nJ;I{onIs5d&$u7s);Ntp1t?gYkue=`8p^T%q-=g0h zsip9pGLG5sT-ybEKK}fPV#_<;@>}#P1i$4>dB?Iaz2mP+`5FG~wlu{_{9!UoUMHiy zj?l<|V*_ntZS|{9vPJxxCJ<@-hLeR0ypCt>a=wD2cVTjfW4%LeR&vzoaHl0Mj-Ip1 z(94TuxIoqNreNn^i$4ul>wqgb{ApNUJ{6Z{g|&fa*hsw*{Bbu)3w2bCsoMxY7Q&xt z%gdP_Fm`%E#cJzRxBbtS<+rsh92x2uYWL`)6?*cr(oY;)c)YUX3wz<4RUPvjk{IC_ zRk$s}(a|hh4|PNP6^rrbUknly>u6N5E~J`~!~JOiWAQ$uYU@;g(OObs9dA|pe~Z^_ ztYaqno|rNTL7VkKwFmdtLsP$usTZKsq5HRTt7nI z#GiJK43Bd}6iS>U&f&M~HLKbSKdzl<3!;Ux- z1MD*;{cFeP?h~&%Y@ShAr*e0nv#O*VcSPGS%h=-f(=oL2mt&S6=RHT3OtcRl=}sm18Fzk@hum_oO4r5w=?@o^sT1?fJuQTOfI1 zab={(DTl`qy<0}8J>_q^Ek&|-nPp^?+T(W1C$QU>%9T?%eAsR=Pb1lbIu6@>NlQyD zBPpjH9wYlDhxFTHmXj*@@LZIxW9v8-CqJcljI#3xa)9~@KFH7(C!vrF3GUdszFpK-ij%v;YkK4ZYh!F3uY z#?}A7U;~+R*)hQ0u+V+Qfge7O=#K($4w|6EHNi{NbEsF6Z;;!_kCixXKlO3)5_wgL zGud?|(%q;1Z|Z;y*o)yzZCU|a2_-5JMpjqiz`E28sGCuDqV7kIP!_`_COJ-t{Bp?o zO60ekI^VBxCB2am+sOmuS4w1Xp8SFKBI=vet^roMVoDTHM(MyW_{d61N?ky`joeN9SL8|Bzo-6{yr*>FwH2UG$0%^1RYMOMLPjc) zFiMGZ^=WTHK1a4wqM|*N7y|t{u(ChnhckW_^-^->KwAg@f$M2_M~MQrkRQ-;v`@t1!sQCRB-f*H&T#o*|o&Eg9dAx+gh~oT@~1e3H>O$t#IJg$MhP z-A*-wM;U#L`UmnB?Y~nSgRS&sl*rCY9Ze?E-h{e6*@yNFavWGrGnh!jT=HcJ-jd~Y zzfbw0jLOaQ`p!~bAb(Y&7w(Y{Xn#z)hFI|>lqjV%S%a)eCXkKERI)uez@pDKgoY7H z6g-KXN#>ESkZ+Lhk^0+VJ#H`gIeCISPyR^$Mn3TqD?4DQ)e=*Q0js1$hSkVevLV@= zY^6l{_S7$sgUI2GA4ffjdM5RJr4I#(2Cxv;kn5P>J#w!SU44N3jP}#y_vB5+-&LYw zPso5_&?u)QSy74ns(}8LU563%l{l~o^>btgvbz!o_EI8UChZewpF+-|eKGk8?XM|u z+&kol`jcj@*={EMoC&{Vg70X*OnsgDck*x2IozsP5LrQqe8b6FwAWRl0*z^JJsjh& zEo#e%?qq)^7*1v>k#0PhP5aB#ixeGs*Exki+;~+Vg2& zOTCf$eR2o6Ux|DVli$$(1F64mMtoh{4Go~+2aIrLS_cLxVfTA52c~*&Z7yR*sjxb|f(~!}2%Q%jlMb4G97CBzo(4dA# zj@%FO$cE-wVbW@2Eyxx*9{K+2%CH#yY^^!gCmWN^$>+&7a;$u&S2q2g=m{A|+eA{| zz^!@Am+5^CuWv170lAI*i2O`h443`nDboMuWY~Y8{*nBZyhZ*=J|Z24m0y5GA3Xk9 zhBBnSpIHm6N=A{j$ogag*_>=ib|JfyeaQi&zA#+#pWr7JX$}p!Rr-+dCJlGVhon9$pc%QG7TshivK(2N3@78sXUHaG z3sPS;s`=_Gv}I|3qioU`T3#flku%AqN!fU)R{F z_6#(NysD!=|UK?0KHlINyVkl$9o`T*;rED*0ZE!@;KS7?P zOxnhflgO#0z9U|9TtcoQUy(lF#6`IaDR;^KPtcAPt+PCmvL6HdASK7+cDt>EgQbtx z>6PeR3p_Egw8fK+$>wA#*7zU`f_@$ z{pX~|=?jq}Qp-3vS+Z_)NHxs%)@o14|}`YuvlA^#%(CiS)Vx-LtQ`ml=Xiev;?gRDc= zBO8&;$mhv67JarZG;}BXkpsz0att|%oJ!6n=aE9LA>Sh3C3lhg{A_GJLZdDEk`brK zv!uSaU*oTn50x0JC$hFJMz&OOOO}(JQ-Y#=&rl|j$>eindoqnoC;O0tN%aY+rHmyf zkkiR*GLKwoQ3BiNl#)X&uva`t!#1(w^LZY(zU*J~x+JlsdZWg{|JHb0`Zu1A!KE;IvGR8 zlh2UPk*Q=Sva6r6s!L9UY`t8mg*@njq0jGwQP^}!H~cSfmOrPV?;8wm5mLR3)i*I@ zJo$`_x`Gi-qwGcwCWlLQNlcPM69gmN4|#8|(Ay(DT)1xN(QSoC5(_bVzGLD`q`rt> z$Kg+j{~RZw$sSCP#Qr!qUqh2M^woovVIlg$eN8uo%qHi^T|F-P1+2LS;|v^pWPwL| zCk*z)++~tK$S0(|oRyWE43^;9nO@1?i3y)f+jBB@0A}kUd&BUmX!KpL6igy#_IZzwnB0rc~D}<8wu{eDgTkY9=OiXcl2u^ zRVB7EuF>jKCXmg^ma_R8&Yp+Hca&K{ZJ9``-k{*q%wXvfuf?0eA_ zu^-p1XcbvsDu-i0yHIwQf{Lisu#p%%bqt_=Fq>3w0;)x(=q?Lt?1HZMY4)qoPz7`+~6cnQghl`l5NS3 zWOuR`IglJGO!}NSCwpy*zqE!lsY@m@#;qQAv2`UG{ftj zL^)NG$7881pU$OM=2Aagbg{`LHjoxQlBkb+(|@epcGg!EnAn*;9_)#o~WZ9d*brjpB1}VwU!p zg8kurCizgtP6_wM9Hl%)s@Db0@JI4D^0w@+;r7M^M_AFN$Oy6qS(mIY1z%$TQ_7(1 zBWLk>^F>BXlI$o9Q@%!Qib9`!#E6{|oNXjXt3g>F^C4|dBBV}pXZe_tkyfc?$ckhY zvN{R1OvFF%1j+)zrc0zpJ=r395AjxrJP#yiVRF|B%XcaEcv2Jj>&bjIy$flGtQio!wu6tIF}uIXxljHABl9 zMNTDsvaLc=l%&i;2Un}x+v7gTh;L;7uM4pcJ|S$`=^@CFaW$=DCz9&wLfbN5wq3$L8TJbHs0Wu8pfWhb{fMzo zrO#4)U=4lQ2$Mt4;WDR7E$guEGQB>oEMBCXMEc0t5<4aN*Cby_x(o0YJ`C56BI zJ(724p*Q_FyFKvZ7pUhx<}NRg&W5Odk3nlM!P` z^?G6TL%coL>s~{-PV7G}@Va+WqL%Ylq1(GTYq2Z zNoq-3YqBHRg&ar@B`1wZkDF@cwCM) z!F)bX+eNu{c5;+dYd+Q!qRuh2n&D(!vcAM$Lp86iz*MX@9$%(Z2*}0c3de5t3X{Ah zeG;*bbN|E^J>C(I9lQJBF!zs){aH3U;=L=gLOt&CaaI`>CAMv5R7fMrW@Kx!tz4Oa zyD;x9G2+~>(Ds^4PeK`o+Gd7@oTBY4d6B##89}*T^KZ(3;-t#NtnxAC;;mBk9n0E6 zb=;w>L;7FH44o`{R*5%6-*BwagGu$_p&Gv)aARJiOv36cE4cW7pAjF*wxzgqI!<|7 zPFBOlu}RZaFws|6cMb8lOV_h?zpp=TR<@0!SG&1zXXPDX4$$ub6YyI%axmo@A15$e+nyN%cpf&3IB@_O|L% zKE~U?()y}FwMURO$hu^GNnU{knHz<@ao7q>?tY9ICQODf^J> zNky|9CuyrtN&n07AQ#ZQj9f*oB@5(ANmNK*OQ%N{O2G}R(4&;ckvmnD>i@( zCQHd4Hx}^v04${Xv?a)>Y1n6S4q%4$rEP#54G4{rO)*JfQmr$#`ZpQzwq%sb^@i-C z+(#ZIk4bhuMq*QbxF_Z|ZTCn=0_#MUAWO@&7QLfF5-1y!sU*I=SdEp@k8+@ly@mF^ zL^(sYAyy7e&k9T0N!uRsD0z(hj=V(PB=5?$G8ofgwJ?1e%)oU-bfQ($+Oq!@3|w={ zmSh^)O@iC@@x~0L%p~Ef-aj&v$T{SEY1$Q6B|C0oNp7L-1Id_)#q#}+x___1%>9KC zze(lb_$YTsl9g9wxvS|$4j3Gks$O(-CZYlP<*lWjUW5XI2lIwA+CmxOPNo5Z@s6viz)?W zAk}A&W_*u)L_TdSC3@g4bkTaufbb?(qUw@%Z-F;e-TUY>f_m=J+P*9C^^&}9_12^EsH9cK3QPP0XM)_ym>endP~?t! zD15~+WU7vOG+k3EwL!NJq;n6TZHQbOHaH>VHOkk?x5>>i>gyq1xBBPN9L~y*kL zxjCLBcXP`YOjaVRl6A;>WD?m_+8-a{P47!NfK(qmTEql$204pdLM|uORgb3MM5@Og z)w?8qBf9Ea%I_rh1p0c%eB87NXkjHW$qHmB8B4}XMmQ#TOUl-Av0S{@J)Cls1fN8X zK@ZT|txgWXhk=*T+k?u-dqTcplJjH{c|-QUjD?#Yk?RRjw>(}9ePSx)w7K7;zBisz8ost<$0+`}0;O5$sv%V$&0llG&L_I`)no|vt)Z727T z`^hiJuO&VS9avNY3n2eJG{Dx%s)$qezlZHjUH@qRRU_+@31l-8UyCiqC*pyWL&=Hc zOHyhHnz~~%mTZs5m;*%`di71*ZOZu;Ly!-f`#KZfl(a1>fQ z3}y5ad|mbeZ9U0>S z*bo{YCff&MAd0r?^=KaET$8bbF>9Wp^7?ST)^?q=@7&uP^8w|@BwiKZk3K+tL4GaM zk-Xv!$~)v=&KxGD-eOxASJme-CZ@CA$uC_>S_Dgf~y}R#b06n!^*)m1=2ss#IB; zRo-2lIz~#>#YwXzWoxnn*;)E@(-8|pODEGdO|E>5N(4FZ5$@B9p>ZMVI7rL7K>kAh zCLxt@b=fKpXWRxa^!9|rx3LmFLpCFyl`Ac98W})2M5e!hLKBlQLyC4_UL?k2DGf`; zMe4AfkY|Qr!t796gJsA%U$CXtY-?p*hg4reTBm2pRIAmT-&wgM3H^wX@=jlaeeWP031jJ+XOR_C;iso&nJPXei) zgS7r_Np&Eky05HFNAKsplH*BNUqWhIM5_BB)dl1x@;y?02xBaR;#smI*+t?5af9wmPpqn8NGKbMu(f&iVtfCBNxmk}k{2ZT zRqTu3KStj7M`EV**pD5lZbz$t`jWjL%daD47ulwA66I9c7PQdoUPt+c#P-IwZ~G_@ zN_)tP>g-4B`WyK>`DaI&@!OE{A?gE2<13MoWRzsPk-0km(dZW>;~-{Y;%m6Qw30Ub z$|41)jtVAP`u)_w9=AH~(Zt_NY<`w^_!CNdnq~HoWywlpRWh2aO+G^=k!{EhWPfsy zG`)pOiw1prhq+hNwpNR&tMUGjZ$KY5r`Cq0_( zykxh*o$z~Og<;2UeD>Cx{Olam#BrTBi|t3CEq6t z$z9|@@^d*>JKmf09pxqR4tbyaoBW3i>S`5RTw*h@T8n})W2QN#;L2+aKG|k4cCg$% zs=Hk~{JcV4`e;QLlj_+=b%E^3=p7|RZ{XZ}KLZ1<4tO-eDe)U}yfGChLrHbZqtWqX zBeI!F_Z^Mz zDy5EN@XnRO&{kWgpIVP&@#MdigCA}%Ng=tHJRnn!;P<&3CSu#${s@=bC3~<=`1uw_ z!}&LM&$9L6JxN^{(Vgr|4j|Plj#gqKIi19hC^lhty^4%N-ly$D@*w%SWS>OEQ_^rc zx<3hLqNj{-;10|}Z;X1k(Y))B&B$lTRI8&_siXqztaWp#(9d_!(d#+S2u zDG!iG$z!DYs?id!$i@2D!=6yuWzSO#>bZANz%xCqBuR4j9W=0O16-L_D2My{;}|iK zR1Y+o*8*}Gxr$s%7Dz@p{5bg|%AKV8sL{iZ$;}2>_g5&dkvGY^FQ-2?v~hR z&=PgStht3tdq@fDn&e4MrtLYhJ()(T4`n^34>_0|PL3rf$i+ACOA+;=qsdp2uafH} zuWOPw{R2vMBdo~|lSj!@hp4eb4I1IKR0-RJt03HU`qCeEdl zIG1)y^2Usy98Idb9<9?Xaz438^1j8y+R+U^Fj0>^n&xA2FL{7GN**K6k{6`?bbR~z zn9|nA%0|8VXm(!7IENyxzKL~vW3S=yr81&D`2yLKRF6M;;23fu`4X8;&LJ0*%gEK_ zT2kEtX@1)**0k-QVK;e@{G9xnJS8V9ER0HjNcn_x_Oss7s|=tVLXIZKkuQ-mq#y*FcDs?iFL~Rr;>$L|4X}3m@$vawMO=}NW9&q79=Sjcmz)yieur|4ENX;h ztlo(fgyfN%f_q`I{C^zfUDK;G_Q~EYhwynVt~!prp1mQXMI&9xPXo zCTR}kd~y}}3i&p3^8o0WaCqndD3445^-n+!{2;34JSV+sR$zKJshw6#3ut)Y9}le0J- zZn6|vj*KLu$ON*nY(^d-9Vxqz1IeKh+alhZK9e$sTtF@%Un5^9-zPsLKOy&$Uy{cq z?KPn1(gzxsefiOE|b*{lg4J^*J;>fa+0wF zw8}+Cs5d5!c$?fw?jaA8N6GW#MHzbyljRAeeTbFK|NrCFRcVhT)gO}<*HAWZ$%=~U zPT7l8*Gw9nMfxAAhMp>8e@3IuJd0}Q@4{uF|LJK&>}0}E$wRVeJ{Eov(!~5q+b!}> z@)2ntY8B>^v|o_7Zu$f^0{2BK;34BYvQ2 zeKKJ{V~avkY^f*JAeP^$wbO~02sN**K6kmo?3CiFkb4EmpB z2Gv!Q+U=PZiv2i?&P@K#%VSp-|UdacpQRVHJ|Sh5-U zEZK(aKz1j4k%P!#_+2JGZXSujh13GtmXP`6s}g?~_1#AKkyKuaEBY@ezn1KSxZeMb z^0tgZtn4_L6BbitlvU{nvKCpFOeCAgF+Jv7&4ppo;!=>u?PJ7j89NNMd%R|FSjY#o zeN65n58`WCbl-X$Cr1vU`#!ydvvsw0xSLUFv{impxl&8-Cmcp>%5eOaq%R`|$k@Z! zy7KSiMuU&G*|PsWS}T-z&yY%W-J|`FXFvZyY1P_eCm;3)4!g~Wdvc{VK16!PSn0}= zRmcb#`x!2#8&WnRTahVbN3x6TM{+qb0zdniP1`(jF}aLfP2w?$KT);!P8pt%1GIfc zeodZ|!LJRDazCJaj9b*12{Cb5R;3$|&B>Nz8?uAgkDyjT4=^>?|A_uhK`2!iyM|O} zLE2SY$dAcSNcAD4@n4f?$qRCEMW#3P56Xw6`VP|M#mTZ{1yWrKX?$(6KA9lh&KOZ4 zeJKZ!ndBH*v=Z0zizxHRSIF1Mx5#%T;}JSHrxVVdXKA}Y{zT%5j8RG6B-c2rLT<7& zS)Qy)Mv}G3IN7F$ccAP{_9FX{!^n}O`ajb4XUn2baCum~0Kcn#5QqD=n;Ef9)~3ZL zg#1YPGkKf5CwY(2GH2)bIGG&3FwCvaku<}eGOBaDH)J&BIC2U(UB*7a!pNgsDFu)r zZ&AKWen5UKX=AXG?{~({nvqdc!sOgnSd3k}U>R+Cs(1azTZPt_)onr(q{lJD9;t^` zsIw)l4IZUfjXk2>IU_FpENvG^^{Aw2ZjtIlNws5w#gb$hGK{Q7)*|c5*srmbsedIs zyqjF?icgH{7fI!GQk@>D&LdwZHO{b>jMEUv<2%N8nmF7${xK++_wq+mQ|)b8(aA7FbAEK7B3q!CL< zb!?>i4M|JDjmW)}2P8Nhm!^rQQLnPE;hv{4#Yz{5Z?KSmRmw;yIE~G2Jd((nbj;Hu zfe~0)dRSs2&X(%3NV8u?zDd3<$rDkp+#sY5eH)80=KwB(cbvf$y}BFHL&}rtbx3s# znM~rrMRx?g)c*#@jHYcInN7|i)kBcxv06qQ%<{&ldmxqjNc9M$`ZRfg{6YGx#|RfC z;S<&a6IBgrgp+ULS$sB8hd+8qC$c-)OD6n)4OQI$X><;`fLtOUAzJbqA;)vbXH}Qb zF!y(iyd={LP~469DV`AZ5TqG|kl|!?$@mr>p4fPyCq|tIX__>$2icn(L5`O2Dd_A^ zZ{uW?-*{nIh&uk!13x17kozUJFBaoBl;>shVQiL@OGJ25?bEG8Tx1EdG+BwPN~#kf zEusP0luVY@cW_I8Vf`r{_XyfX%eBksl*upQif+e86@!c8xHlPxiEp1erjB=1V8Y53Zx96o&bhfl^f!xGK?4pSzLwr=ELa=1*-z*-yhCYHZ?Rnp@& zlOK^gCHZ^&c;*=8N%9JLO){D<>@Ho8qL*6Cw6bU=u^VwmwB_b$=gyW61LJGNL{rx$)%BCMKbcG+ z+et_|_Q{cnQ#!f#(RNTWlCfodOZlCQg$%h(d5?TVK9&9Rnw8b5<(XxbQC6mZndME7 zrmRh>&nSNt$P}_2*^BH)W|8B`siaTVZo+D=HW*WEM}-LdXr2-H(Yz0L6~Cc8PhKZ) zN=67yVu7=*Y7`?YkyXWhImesYg0dCamh4EXZzyfW08%|fsh&uxM<~_vCHNTD_~l-q z_?1#i>~0%|XnkkmyTia7)_^QcmY3u!n2T|g4aml1bGe8d-Tf&C$=Y`^qukk)b7X8N z&L8RsN{fF(77f)edVa(SBd9Vu=^7)h%c8IGyiwU<_$5oFIacDTWDT+=sg9pCGyDQ_ z7_P;-P2fP5~a~sweKU<{gmp{X}Mw^d)(UJSzo7 zISDc9p-Q7mlNHG-WOXt|(&nMLjVYVUH*56w4yjtz>p0EKV8kp^-BfA5E5#m-VcK*Z zKhXJ_wo_uy#i?^zE1ZoV(Dqmc@4;R8Y9C-2b|XSsX=rk8lE>F&ft6Kvau_+1oIp+? zUnUomE6LU5dU6B#Az4U%PJU_8^n0w*w)`aVHPMz8WAyZWHY>~>z0j&zZ3*93v1}-k zw4tQ~*`4eq@wG6yCsR%%=aBQsW#lT!xPj@A@^VrO-xb=fk?IXgYx9V7EV6U}S&}S6 zs?#h@A4S$B>yyut&y(HAbc?2K01ZPV`zChaS(J0hCFF9+j>Y0q|65wzM{-i-x0K(> z^mDi?Z!WfCOORE`NU|1LS1z8ze%5LnHe&Uhr8#DjFOri;^`)ip3uNpV2G7%^H(b;M?nN4b)GlYCpU z?_iTZMtM?BE=o#}8-! zBlF2uCA%4B*bd6wvR~yn%J0SAJi?pwfbubE2^pUeAUU0pjZrrr7+vMhBOug;X@g=+ZY*X7+@;CA} z`6u~^R4;CtzN9>vj;r>RbS$&nCplpu>X%I;29cTM7%51{M>KW1rqLp!X5hH{KV^AR z)ybOLPLb!87_5ubSI8pT)fbzle?Zz^v9wc?dt!AAdWt(-J)Xl-YR-t3lKmVywmW4n zsqBkSNLog@id;(;kekT&$PY<8u=)>nmJL4rbo4y-t1}3>)s>r8s+@$kj_|IUg!9yM zG^NUwBNfZGL*zhOhLWSnapY9eN2)hC&2%MMK)xyQDOis^Qc(JaYgr!OcZ|41-X`yn z>Jm;f3Lt~YQlvVC)A(wnx`tDoM7Ac|lIk2z@<9wHJRaXmX}TKFkNG4jFq(xr`Ok(vLmU!?ljLqJ-mkWAY&R zIjO$#H2z16J#E)%xJmv=J|fkpo*qz=RA=6*LrHbDr#hZYB%8=)!|8Ra|2>WFE5{6H zLdXKjC8T=g)94M7*Aa`ikaCw~2Vi*4QGQQeBd?RclYdI=uQ=iK=!BJWbq-eS{crHI zi)QPsyq}e0PNz4i2W4+^AUTxGBFB@{$!tl^z-QHJE+-yZqHVw2)B*>=CefX7LqUE1 zX*e zA_F#9C7ZH2$mtEKP8mb0V?eD~GZ}RpUrwoeK$U&T(d0OC7CBeK2je>Yb;^z8hh(8- zq(^uQ?*}<+b_%SQ)Zm%8h7Bb<&h2&8Z_uD&oFu0^qa2BYWyXG~Qka|Wykhu5!%%W= zN%*sjwfX;5K{fQBqhT>T;1JZhH^N4ZX#DoWm}P3%8HOW_p{0<-cpC>A#)BZFG;CGX z4VTj%lz?PTN8q5EfHN?WMhlXVvu$;;!MN@%5uK$aSGStU-a%$T?s~ zS!A4u50SrfipL+j|%;LutK*7hGB zg|duzt$)C&Fa+xj)Zp3}1RIRdU=2O2F)ovB&f?A%RbUyX;nN!FZi1s%xJuf8M}L@( zP}J9BpNj}bq|IlB1w)s!ANFgf`5n5)Rh}})?20D1yp+Yw4amV&fzo3>K)<*`D9f7F zD?nDHtYF>_fviLsYUWmh45bV+y-vs~KI&?wEfTsaWwiN$9Wsovwz;tcWQ0A=&|1ft zC-vZJ_J)4h!2ALo;i|zlC7Srv0%#GiF*Q%iI;w72ui6!SdhimSPOhd*&UGqw_Biv6Hpb~PKQOr`8$ zHdfh&vbXuH%C?mK%~X}??d&zsQb*(0e#n+K*`vTn@88u-5N>BM40o zF!X*@pz&F4_>MFRG5y>|Ni1N~sEMUi%-DzY#f{4)Z9ZGD(HGOagmDkql{B>9JjRDu zB&7@!S(G+1tK*bnbi)5-jYY_=obe5+Qr_5t|GmZs#EBMyC8$%w;{ zh8hXTr?T+|j;&(sL&~Z~oe211oYa5qfi8Tgef2m^(K~K~*PGgzI8Do$`ys-|W zQO{Todwrv8HGDB>EW#K(V_d}wYiLZy)JX6dt5DxWL*I9nWat~$8W}ac@Q7m6MYxGk z99c9q(on@_#x@+*+z3TmKeZX9aP)qg(HlF>0gMQS?;wVwEjq|)Hk*L-#wv85%@~3H zwi|&c*I`^k>kPw<7CDWB7)h6L)`x}#81t|P1{(Dd4l4u-z5(F3E@#OR4kn;I{pea(!Hn4QfHeLWh+su>!KvD$=&V63`gULCX< zu_*NrmehTed)Q{oN7B!1#$}Z7xy@LQ33|k497Ge3A`Wf;!e$&o)xWeESJ4Mw*^GxZ z@T`K((6_*TZPTAB*pAx_^-ORADKQ;R+KhDMdCF#t#B4ZiGk!z0&)AGf=&EmQ#tAg^ ztj+MPKoQ^CjCQEaIh*l3rr3F#F%<`1uo<7Brr+6&+bH*Yn}N5P+Ai9RVBiOvVWQfX zY{p&m%VnD}6P3Aw+GEQ7Xfxta`=4yaX7t}xn=t@YyJj=)p!V3y%L|}OD zqWVbrJCfkIdp08wnclY;XJ!B1IV=-U!vFN+l}dH;LCPH9oa0f8^;m1&~6k|!~9!h zH>x1h#daeHYio(!=!7Y?)NT}_qw?%VP1Jjt-S`pnY359)(G*Fu!Il`sS>Oz<2sj2E zkpq5-Qjo48u6{Q>U>MODY>ILIq}Cb{hJ+%xutu3eTMB zGJeGnWC=75-W=pmQUzJ_=b zmX!AeprZ4kGccqtgP$PX0hBg~a$577#lXb+v@+ddQhd^7*i8)|7)Oapf4;7dPUPl+r zoEczzS51dDz!-{_%$ylyE8hoW>NF?XH>0bJ+Nh4t_zJ^jGnS(YcH=B6_*2xJ>)Ki!D%c( zeOyML;#%N7*aM9Q=uY&>F4W3tKD2Mvqen;U(XG%YcH=P`+ts0614&ymYBEx8lRymD+7;l%+1r-S}94I`{<{pmvcubGu87vla4YD^& zIp(4$TsNERP$#oArPI8DoXj$mLFObBXqNRK=!h(C!=>|T)Z05;FO$r2{`$DLNb;Ow z6|1J9T(j`MjC#aE?)Wbw`~+pBvwDdw7+3RCM+z$9z7Q#!=M;V6db2|pzyi8fatf=w|WvIDEtNSx$m|1|uX#Qd>@@G}eeCU*Y4`M<+P4%GP zn5u!uu=0PF#Xz2_g}k!A{J z9OOa2%rfg(u}M~)$D8-8=wkkZC!2?@tTon%%(t6QqWni&`c=Dmp@jGz#Z>Wqh@B3( zTJ}wL^S0F!m5_}Q`JUa({@>%a+RX}BNdKkZZa39I9CWxp{SLd?+$uN9uXo$chE_GL z{14g9P@QwZ&LV%kj@V0^Z&?{?vy8|ScC(ojZTgqWzp}PjJraq>FgDIytgW2rEQ>50 zkqyi(F_1GDn`nNHeb8L)e1zsXBAb|9qOmoY`HXI1?$JJ5P1(v!(GFPe)Q?P#$P}}M zuDp$mZD&r!UShsQ*~$DJCl>P^%C6?t0LXVKdzdL&tu2(j%{kh_LX|#b-QV1fUD5o+ zsXLC|8aS?9y^C^~*;9w;01qB%ZqR+{C}oy8UHkR~<#@9b&JN}|%E{&d-9oM~t7&G2 z*7B-9)`*;GH-BoO)AAP@a_r_(t@mx}T)VkJhvu%cI8I|mS-SRS)=K&rT~ zJE2`y?dEBnl2u*)8yb;Cc5{qYsE%udKmLZ@9Ip*{hWX#In_t#|Zclx`4A!IeKvxyhg)J7JQWOI;JJ{&kpjwZHS3eyPK3q$ix$ zs8={ln~X)arJ8FtTV03!)mx9l@XK}#!zP_a2V6Rju&FrAIl4Fw^60G&^N7ZO;hO3% zZM(yC>vZ^%@jD#mv)U`CTzZ$th}`WkkLelWJmWugm`_w+rat5_`{@e#h5Cpi!n~{F zQp5^;M(Me$b_Z?=uuGQ|;4;(&ohjx3PfcuzMM&x6MS)^-w z5EINa%&9ufvjVK)&oRvTIt;mt&o#_;I;=~m7aC@SwtG#0Zdq6shIvJI$JYaT_&Yk^ zFz4xbz0LHm`V8}ZZPBMRtT(K)%n|AhhIN)X9-wC#BXW~rM(LtI%lIRPS+XYdMe45% zv$gifRq7LlIYsC1uheG@bFen(4z=$bKBVgk`;&(64f7BG88grtlFNqqv;SI#`l?~3 zYL8W-E;7uzTA>K)8-{sVTNp!q2iMn{K92f6j@S6cfd$$lzQ_lLdB_37b4>8qF#BkM z-Kb|e&B<7sW^d{or@2b!<{;`^r@39nbR_jcr}?%H(Kza*PP2rbSWPSdV) zf382?hcmU)4ArH!j0e2xG=Ik>qPd!Sz0(Yjh2BKH!D+s$UHSp_CZ~Bvx8&H%{YxO4eiq! zo^zUeF#XLCCivcIK0#lZVbqtM<}KAx)K{HmmX3KmbrCMaby6i!-*B2X)XZ!ZR4r2T zzvDEwAYir&vWDQk)AZ;j+bw8rx_?X_IL)nEf!@sEvD3VuH6BPk(`CM{8H}LLahdtr z#bc>+UFLlgdNTDwm+6s{Q?R`R>Bz06Ip1aeq{X~R{i@5{r&Hr!y&mye%zKRA;4-V~ zTKJH9lgkXK1^o&2doHu5Za4d>x4O)Udh$6MWNlyDU6JNRox3NPV28_Wqi3IQsdu}~ zr`4qP@?ur$?a&dt5#;}f7kR{GUehUckNPW@*-8t3#N$r5%)KEpZF#XeKDSQQ@@_6x zml>lSUzz%<%N(FnwHkGi%RHm|d@br5F0-btwR+TdTxPsBILU1_;J(Xjq`OHn;~%)p zn>sG3)Q??0bE#f^ccNitfO$iEv^RB5fcd*_=mV*91I$x8lSWW43^0SV!sDoy2AE#W zZwmE_0P`K4>OSiH0CQ*n^gQZUeF5e?EpRan>jTWk+H)(YHw2h_b*jBWy(z#<)u~%R z{a%2%Q)kj!)LR40%DS6urrsW4Hr5f`?k@7r)Exn4UG4EbjQ4#SV79CQ!)NTWLjl(H z_SZb%NPt;MyZkHgf!fn)E=1B#=N7vJglh2}Fo20TOls z1Vlg<2|FUY2#CsnAhIul6e_Qxf}*0LqM#z;3N9$3BCf#ehKhmp<6g*0%++E?V|!nkduO*Zf%v z*&FSysLN~9 zRW!kE_Ej22>=!8iCa*Nb=C5$t%H~~ge^#2^f=gnH*Hwo7Ials~^w|EaY&(lG+-u*j zE9cp3=sow@-FIqSU|&I7Y_m6^79VGB;J^=h!j{Gt@v z;rasUu_%Kvzj!dsy&3YCr?3pWqe@$3 zjx(mHMT^X{S8a#?7vZ!x;a8efUp913c-a$I_>tEoVRBPSZ`xT@W_iMCU5aZ-N?+l@ zuswtN=;lG#g`uJcUpPVA4Erx-Bs4FGK11&x>{TkYx1(o!hzC2{7rFNj_1g5bchNk< zJy>ZUw*W^Z%+S(Q*&|sx(t|VX6mHvBYN)Sx^gWeo-5A@vVfTe{?C4lMmdL`jiN0Yl z$*X`%k;xQoveyAFMf5$8Szh@`@5+6yhjA%#IoHiHuRmOh@OMt_jb1q}J(j=`?E5_Y zn_<6?$u+Vc_cCzlp%=>29=>SU-Bsoi?24OAv^(hayTk9RvlXkOz$mGhSFgN~5E4d8IX6S_3Teu)nJcEUFrrrGyU!lMZnG{mERmcEzJAdeQxc75vo z1ogGkJl)u?PAoC+ik4usy!f<-P$d+P*71$pTQ$B=Uvv`R*tM=1Is)a!r@JT^nvR$l zpD|fmUWP8fiQ+Tsz&u#Yq2ricd=s~3B(x#}D9c4Dp;r*R`3)^~q)w5bG<%Yk%3??IAC;87olcyQm-(K-`c8ThIn; zJH&ekvd}Fn3E>WdPZqhTG{jpdvKXi@s&)vaV^5N;+``TwZV0mVX+62Fp$6zqUgDNj z>Z!^$uEbTLaROzfZrRY#d+F-XQnNHf*=4(@Fkq@NR)uac^V*$*zKql|=+M93Y&0DU z$4EOxBdrfMI*v|^G+qGt*UPjq*G}*mjegNJ!;MZPs_D0w70zqu(r|UUeniF~yfbJf z=f4kE2yJKZH;l}=5IS_f3le^X?Awsx&_e(CGM6Z^%xp4tHMHfVy^jLJ2tSQO=CjbI zQ~9-$+}#*=~;8-=1a5%nyYBf?thVW&X9N?Ed&ijXibO zn&pNXvn?)h&#u(wQU9I>8%&X)?p@cc-kzd@=DA|e^ylL*GgNv-pxd5*wwqJ!_^PYs zji1te`mCv=XR8?p*GyHrR<7;4C;Ucyp|NMs6XtDpxNy?+spAW;o?STMs(GU(UNu|2 z_`|kTRd@5+Rw`p?UdEmd&zoNwMhRZLF%PPY7fe%~dBLpo4_c}ggyVBn^#OC9f5cMN zxNdyzrWZ}q_)Go#jGd^ee#8yuaZA-SE%BHPfleGG?gt%sDdI=NrApNQ`f7 z>^b|g**NY0rC60*Qd-=~rC3$psQTTVowR4hN%L|mdJCM{SOHD9E`&+Ff4rH>fBx6v zu_MLzs76{`fWJnCK#osLXDjg;&KLZGr_w@9sl$8il^J|M0h$$mZyhu%KI#C?sxNK^ z;82CV3pA@Gtm+TUg_{PVb@4RUVa-(grJR_6cA@#kpkti#Bl@LcM+=6H6)52L`~=oa zu)guShNit2E+0(tV9-v$go4Q)l=cyH5KJND&B3s3Ld0MLuQ+07BHRZXdN9R~hxUT0 z9!#@~a{<#lm|OUtNkW49xOJfeUh#= zP>xncXWerTdjyWbHU{s7@kZ-nEcsw3V;`?m{aKavK!l-SPvf9&JjlL+u$Kpi+SP=; zJvhRiNZ7}N)%G;PN~1Yu$~&toX_tPU(39+HYQD-CtOo|^iVseMyCsP?GWcvsCh|i~ z;8DTnT&4IzH?hBcu1d_%W$NU&W*`6iCMdR8u{aL?&dkh@puL?lLH7#U7Sw9zTd)Mq zbwXEQNV`=%je?;nb?G43 zeBvF3b1?*4n_qm4b5$XDm)#WKW@8120`zE!o^Yi&@m5R7EEqfMi27K_w&0zIc+DM> zVsIFG4haVqN)Ywo)Q;$l#$oXS{I0HOgD&ccw5Fu*82B3z8_->S(Fe;rNo3=1vf#-= zia3N-)%0g;`S^)eB@8eW{STvF{LJAC1#K% zKF%P0=P^{x5ijF!t{9KmG!^~PEKi(-=Qk5;n)yKAS&Xjp#YG5OAnrm=3-M8q^quqQ zr%=>EKSd$~q7;ks2n(%54vf%R`~_Qx{1AS*KEcY_ZF#rlOLuJcR zU%UkM`NU9!FGKL`+%GnvOCg?w^-R$f4Flq66ce+=PORiOQOM;jzJ{Q6G`-3e+tFRT zmx%X;Ydz5me-p(XOgJJkkghLwKpjbnv69;aHlG@b5-qB0Q|I__i61l?SmhL>v6g6ywod6LB4! zBunrtJzMOBpgH0gd@EPXf^ba*fB7~~41i{ui81)wT%;l=U%ZHk6^QQWvxS(1$+Q#$ zG5bP+A08&vYBw4ei&?1DN*qN&YrzNLB_a{CzeHSs8?+HU;r?yKW{6lSd@$mrA{TYq zi3>1&d+|85(m}ip(K`wsCQ~L}Mg30V6Zqc&pBRJ5!d9fWz*a9ndQh$Sq=i(gvltgt ztJ_c&RI3XZ0aPpg&M~M~Q*t%cY6#{Is#PIG2i2+}R0^sU&ksShx`<9=R4WN_K(z{C z#e!-z9({sp^*6i$RI6toHmFt&FfOQ8)o>$HtvX@|P_2GME~r+$;9{U!-GYXoTJiJ^ zRI6ba7gVd+m>#HBi*Nwd>O7njRI7=Y=SdKTA3Dgp$mRTA2PY86E$s8+mZ4XRZ_bNC;q zR(w{TDx55)ZwK|G2P_26B!v8?E+K43qs?}$(8mLyU zz=oh&{QyOQYIPUX4XV{pR3X*sNgPSF`hjxb_>doh;CKj%Sb}3GR43JH2((42)&0#~ zs@225q*^@-4U=m1HB_akR+qqlq*{FhKOoiWEBG3zR<|K;kZLstwjkB&N6eU1tEb_8 zq*~2`;YhWbj{!)vdJY|uYSji)Bh~6zSdCPxz0ez}R^8zBq*}cOK}fY4i*}l7^(_P- z)yjvNEynRQtWK)cKn!p*jwLVysa6H(kW{NL(U4TDM<6JvR&6C_g5y>UOsdsiP&lbp zKf!BBwR#8jNVVF7eo3|3iX*93%W>3Hs}B$xNwxY0l9FnbUB{(b^}~@=t4nbt)ryy? zq*{?*N2*l=sGd}-4>2=RtsX`>sa99Pj0+E#q80ij)#?~DNvhQpdJv9V;fbVLt-_L9 z)D?;2aJ!puOoysTwMs!lQmt~>0glTtb5gC=!gh<9j}HG$wfb8*ZPzA8C&6#XwE7&1 zBh!jp1~RQ2EIcx;_)vjND_o{jPGCM{S}lXZ$h4XaOOa`H4E4yg z8k*oTt=7OGWLn(^#gl1u8vSafRWTGnrqxRLCYe?Z(11*B-}RXiG!X*C{#kZE-XIv~@kQn*a3Cm;ZsR&T?X$+TLQ<1($vVHh&4 zaZ7Ms6q^dI8pH|%;pmhKmVEv$IjRC`AIxL$ZB%}k=>U+p$hCVThA(MCsGcd$^SbBcJ=XD4mSl2KC zG+~L4AzqvSjR-xhhEQNyT?%I~Lth(wR3^q?%QD1eXy+FPF(pm1C)0{d5-_d)*3$iG z+{wzN=*%ZhG+~n+P^4cx3^O2-L7ss434>T76Z(o1tD#OXt%?x{%+LknMYisP)eg26 zbYckpD6wB`#eiU1k>+8B0{(wkt1^dIEaIr1RTvfg;+Z%n7l5=zxC& zn%9}EZaQZ+AHD$6hdvj}X);`y-GrDCIw4$qqci858uTqI!p-TQRTMV8I&4&IG2PsJtc;oSqG!LV_t>p>n zGf;|{9I)!Sl$?dG4vev?`_NNrOrnG0u z=!xTFu+p9jAF3^_vZJsnAa_N7)*$;t!M{p}+GX%4l)AbbVSfQ92aNuzYggOdXp)f0 z6C-l6(hw~G|Ipqr#l8nV3wTh&8TRRa4?G)>6m@C3ZadEoW2vGtC#oq~N3a5GF~})X zpvM}lj-EFo(Gu(iH91+Jql|S`RfrBXIjhybd%!*42-aS0ecbZ(yOX&@*9SRkg^Sy3 zj9b8GWAchDuun(_K>IUV!b3))eV^MQ=cmb8=Ob#~1#@+j)($0@Pr^$Yz6u@e5}{=C zUHf zLuqyvT*Vg}=oP2gWz_Bn^A1drUZt1P1g|vD)=Q}d7T7zoQF*#oT4b-_H0PLk=z{Dl z{*-)Zfmd2;pF!*lZ7>tCs>seNYR(JO&0cY5J1+~xw|lUwokIm|HF=fAn+DyvH1GFH zEA8xDzy~~7Wgoz16ne;mgX}tVr-wZ_)b2{L9`)b|`)$r}524G>+J#6Ode&r=;yr|! zRP}QnoMc}^6TRd$o?|ZZ8tx|#F9S)Cruo^-fIDe+Rv#{eU-dH4&noJvE*EjOkF9YjAFXz;N>+S~(doC^CD9}UC1M7nq#G%Fkhyj7W#1jn;kRH(Y zK*-K|kpi_0Ow;9HXDy>zFY)@vBa$2Pfctuw?5r$$+8{3jk4Q4`C0ekvnp6LCylk+u z-lB`$5}2js06XhWuH$uq<*t7H_I;ekX0JZjSs!qscX=4>tU2lwx~=;VyV(_ZU5mHX zZ}(Jn|Ara1(T`pV(2q1bt3Jc}%U)}+vtD8O8-cZYG_bQiWDI=MD+fEPj9NJw;C&^{ z&f@zzp^v=s1AhAf;*%Z*JF7!;;BP!kcGfD2d)gBK?5wBht3P`f?5qRoUCLRH?qFH2 zyMUebDeMr6SgzbB{q}oY)Ttf@JF6AtY~o?Cvk;Gbp=KTiJL@Hc!BCNh!Oj{(>$LUy z2RrLy>S2h7$<7j7fFrFStghKvKXPr4^D2Oy^*)#H49hh?*jcFzV9UI6u(QU~tZO~I zO4v_u8Qp0yWNCI*$Paw4HAO2L?5tlX@Pl4`va_z@j1G7iU}x$5=8%WM&e9vsI~F$_ z&Cc4!9p#u;4tAC(0RGIwZ$SWz6#CM`U}qhr|9n93yxrY~;Hs7cWjqvai)8?BWp>ZAtJ8L9E&J+)?GVS&>(JT*x zopq6?9rNPc2mp50Uu?frm%Hq&bzEwsVe7 zI7+7iJ1Y-8g&KGjz|P8~gc%+_Y1;LOn|k<5)Bb@rFZM9lS;M&*T`DdKm1iiwrj}dKm1i@2H2@gKqfR9cW^&q3<5?DuA6eox9J69tJz>F=d#6 z^x}`{L1%*cs*vQYzZn*P^)Sd;RUG$!UNexho>c?PKw-2E?VeP}TdDzjBh}u>!{BD^ z=GxEpFt}Owa?{WEFt}O!sO4531~=;gPWRF}uK3_)ZKt}rc;(<`@jb~zvVky4SM#CUNL_ubkYh-)P|1Je7f)rBAot_8Nej^)18uF|WZ9%RN2+ z#KYib{l>F}|9bV0TXul>TMwVK?E7i?vtIw;W*y*!{&2D8X1&R9`*)pF?ozYtbzBK? zw(Aq%X5C32NVMIhciytM&;uLV`bGk|S+CMWnYO-5KyDUa5)0*NimV_vOH#vyw!X9{ zH|sTS4{dB-th?MS@}NS!?IOsbxmg1lUI%#sfSa|5!R<;9gPXONYh;3E$>9t!&OS;! z&BI&c?7Q-S=Xe<0tcA4s0tKsje4Wvwd-2$ptspKVglr!JV*IAd8H}#Y5Kg26 z&kH?a(SsG}HhK*rQIQeql)yK0 zZGA1#Ie|XPX%za=v`fMQ6p^ykfor-vfoqUL{s#&PRd_ILe`y1D^B^u#XzCsbu0}F! zeLX(FgV`xFW?zHr%Y-wkS_YD$y(H=m_L`R3gL&>b#Dksf6fTsZUeliTXh;(p?!ijC zI1X?`!V)cGm7T!Sksh33ci?_`rH1l{50L@v%r6S?$R-z2XBu3G*_ z<4^WFz*URBp)$)WKj~fN&-E~_S}M56mU;c*s%17;=|-;{S1Dgp-1|KI8`|UiKN@=6 z%fMBNUR6(f_@ZH-qHdn|1X$=#nK2!jd&wIB*BK}1M+ZGjhF3Y3WkKi-Z8du}o#D-d zty(*HX^=*FOLtDs*-F(O+#NG76wZzU=DV;U^eZB@Q}7cSksQWb7*3&E zRuaMu4xdxxqS6rW;5fxD>JZw3J<)09qRt_1NKWfBS|43Q=h*HNx2#fY$7$nEvMThL z@JXLj>J|g}OkebPdJ4g1^7Law%x zzpbTX2zCKDRShz=)%=&b-3LSGY?O6%k@Q*Y#NUlQ*NcQRD5joc*s~q(=5Si!Cax(> zJ>_tgi-Mti7%!athn}PiwaNg>aZxC=2um-V>!O6vOQ;iW>LMp(U_#+M7lnP+twF$M zH)8O{{4$7WYH$F7xvMwo2BdM1`mk;w%l}P*x>z?*l+hIt#XrTMuVsA+36SP|d_j}C z$j(!h^#Ymwb*;t!s&(Ed8XKYT_nURi_o z*Xaa&x(00oZ9WJ;F(nAKfdx@HK;+LN#a)6pnlrxC;)%&VI0a2sO1d;nNd>ylk)#^3r@0N z1y(>(fzw)7-Hsv3|Ig9Na}m8FrS09i%h}o;sIQyj4upkSzjD;S>bPUhWKKgP{I5Y5 zyOlU-*V%h28U}8&jlt@p?7-i9KFF8e`pUpTW1MO>D$qZ$>V7!7TK_EQgX=~GN&{PfQ`9{-Pfk=Pfz_c= z0jbX4JXxxu>cBGNE%i)wpuf1d)2B`>om^jKj1EMMVQN4yCs7^P+9xc`M|`UA7L?2w z9S8^h*8_oDEqV^UANgT}slxF&Qb<&ZvdRHeF`B4%M+cfhstY&-{@aJYrdNQsBvm~IwPvZAV^BQ%dOV<1_mJ$ki`m=Mi_Dfc;1^qzF@AWqsyi0A=w@&U6qt%# zRKH$5$Lu*dHZZ5KmaTZIVSI|&x@}R3Dn8V{sc~e_JsSd}ZitTS1cP3GDONoEx#nLf zb}s(&&u@=_7wS=sv}g_Yjfy+5#(ZL7JG2rd_=~4|h%Z9SLYOwi?MQ2y;sWe>pefEm zN8l&6heB|8tq2Fh+R03Rpt2|GwymWp&L~H2Fm8EAJmlKa3(vS*n&JX1{N;xMdd zYZ69^Q=@L$m=T=_=d~V13=6vC#3AT8=#mqI2xY;hi~`oKwn(}>#YYikgTB+=i;h5=+YEBVjTr*Xo`&?uf^}))X_A>`1?xmAlY_|x^Q*bE`YlYb}dg)ehNj} z^^K3vAvR^%4t4D$4+iBs5ZX@mpp>H!vFC%TtuMf=Fu>4F8ieB?FNoRLXsA z0DBrAYB)&tL!7jGd2pzFnWeowI6}Tb*vEs_@?FA8qZ{@hJUoyc)#-Xx;}U*p3%Ajq zhc8I`Sx{ngxzh0-)}@ltZwW}z*Lk!8r_AE>+P7n^sa>^3lqH4A#hvbOw&_%Au#OiM<_Gcjai7#N1W`dWZ&Bdq= zB(XgYK?}qx%)5o)HBU=14LOBkflb2U&k(d&JdAm_5_3#)*qUPHmxvWu$CrqEP_vCF zLq8xKcIi$MTXzJXOGO6$wiA6ZoA!cN_8r9kknSkjL5MQZ3qI0GybK`@;PYLjn#6WF zT7$%v;P+|5A?ZG*Q}!HmDK0||pST8+8{*e8+G=nGZPl)rw(5z$AiYGP6-zt?eaDF} zu>yi(Jbb2(_!E-YBG{S6S`X7p@foHO67w*D1W^Ppb3_IHhQ(m~tt)PZ0QJNM{7n=) z;L;JX41ep3`H(+Jgb|ICMFvJm5#K_@1|l+vf|iMH=%JIi3_ZYBKXul&>Q|&~ zwHR>#gu~5n6cP@bU@3rbI1=gt;qV)n2!z9W=oW-SzU7K~|i--Tcx9KL`Vf^ZnYcqANV z!|y>j>2Bf^c{TrUk;`W3WF6hhIUXARPXJ0|f3-}fYhhKNs-*&5pEXK{(9D0ffWCY)v>E zht5DaY>Fv?aJT}o353HJu;xKHYz>WqaJaG|{11e~J&+rO!}<+0;gDDJARPV@HI4p$?KsX!<1@qf(7zu>K&w)TVj6-K29JYd^gK&5P zz7N9T2bdBFhy45?2#5F_tR@`pgDZe=xB)r=;cy(L2EyTg;3gm({sVP`a99DqAmOm2 zEyTcaZ&S#DV_j%vF^+tpdI^q~XF?PlTVr$*4l%6n791B~36O9&2g)Sj@Emlc35Qv* z4he^Rl1swj%g_u7hdU6RNH|P{G$b4zZsigV+hakKaQF=-OTyvjPzVW!)8IfP9G=8d zC*klSj8DR0x`{i1IG%>3NH|P~!AUrrje44Jn1FfSgp3><7vq=WYaRz&NP4 z2*-42bm2);9LFjruki8>`=3sZ9!4%ngnaBw5@8XJBoTIn+DIZKZ<8d#IerSMg<3i&-7vI;MSE0I-r4WtIEFe=Dh zBCXI5HIP>L1CFE>{@s(a4v2doK52zRO_x@fjt=<&w~8h%t?+(?C(;V{!Erz<6e&;} zS%oj79$AGC!vV=ElyE$LzwH+YKvv;)te3mCR$!)RKw4o-1S--B%i&<86_UJ7TH#3u zcpr|BV#cHuJ`MeD$MHRQJZXh9)Y&vEy-5iEMDpOBFh9wINl+xogOO$~dGNPlRouu* zie|wrNEXaSoZx5KUg%D<1VpnIGz;d9?nxGWss|L0;~5xW36Ax#pvV4C@#9lKWtert^t0mM!i< zxgl=PWAA&RWK%ft+{!y3SX(0626D$~26j+f3Y*mNCG*Rbrt`J2md)pD;qJ!j^^2Vt z5QJF#4Tx8<+$>-6(=e;){Ae6z-K1U=>m69w5OvY7U(AD6P4NkI1((ALwnTmCHBPjG z_dq9qmt+2>bHVtP%|C*QePZ&ZY<>n6{Gt-hCw$3wS*#WC^Gs2!?Z8?#W@?B|9a*a{ z<|af_tYZ+U^-zz&2$pC7Pl?0Jobb%B6ZT(^*0MAXXCk#+K{;gvqJ&dR7L@N{aHp0m zD8q;?PDHo#$by$5Y^AVAr@j^^{-u`4a31o1h~683E9lg61?79{?sTh>u~l(0468-d54$^mi3=Qi8_ajyk>)>`iPQpwbQ(7#<$A;{ zCuBN_t~?(>$$+fMORZDTD&Pv}pI1+hV!_qIk_NmP4;W{#v{e4yDps19)mie*h}zm+ z=kkGJq}}Z;)K~?>0jvzjcdJS6d_G>u?0X94&0M{FV9$nSC^z zBn^aBKtAgBXHAhmx6$xJE&B|4GdvxoQFku0<&9Y7zyoySd2)S@hAbryP)2F+8eZTQ zLq3QVRExJ7vaI}Hc$*<-VDZb^ax!RTA74Q{9HbZbhIh8N64jHnJI{{9YtU!6&zw5tm_~NKU zCvii@{&`V4gp*)?g`Cvk(AqBHB%2p9;2k74I%zsh?-+&Aom!@#JkkZQmMQ4EXDw4u zrgQ1kG6iKWEnCYJluK#Z0os(K@VH6di-_gaG6m&PL=|U*xlg!`_a6PQh8mbBuSGbh zg$42owjuL*7H*t)>3SPMm%%^-rc{0iN>ux`c{$miN2<9EHxMb<_`cHq(xfopUFEQY%&ZHyBrd7IgZ zaRTK$^<$2e9zD%96Qlk~zCh{3sDHAL4IHEX$+}d2jQS@>W9x8Y%s+Pprv_Y?K48eF zvQgeBaGe$lOW+ySk1_xJ@+q|@7jj%n*N-v$iH3_2{A2<3F~;M*T{PsY zjHuHBv?QpNetC-Oi824=Hahw(0e&V{WG(Z{4>{htfJ+xz<@d|6s%29vy?6uz;#RNU z&3ztb=GQmrxSpB%xJ^G4uBJ^XIJ zJcymtiBbRLc&hnmfOmLE{llj8Bf8Dx<6bAm@RLt+eVq1&dCM;!P%ZPIyiCT}f4uDD z$fhgC2!67A8F0jMm2(o4pfXZD{H0&kYYyDR!>9f7>Qvxn9zNrj6E6WS^6*)|e4YDm zjNliQpJIo1VhlgIgVPyl@iRjt_{oM8AV%<$uQM3L2!8TMP9R3`lM-hMPK@9uk8@YP z(_*9{!A}-YzQAs_Dw93%L-J4uY-=k6r$SlmfS@RNJ#ZZU$N z4AX661V5QaL&OMv@_V{P4Z$z^zL1I%)iC^y3ptmeJx1`8x6nUB9$W0BkZUMljNm5) z<3WtzC*Nb}ixK?fy<9gjf}b4A~ziDHaC>1VW`7x$s|{EeoZ&G6?k`uMrEsCw zG-`~|C;5$kC&uWLlj(&qMxPwt6!_)1AGDEoner>z=nW6=Hf4L-Kr{Ma!@W^c3Yq#8n<+^vRvv|6`0k*_1PkG5X|B)JTlcCnvFf*WhF=;8{~X z&L~nDbWQM^Df#NC14bVO0ISoK>u7=)qfcI-jbe;Gxq&_qWAw>3T(>bspX|d9V~jqz zf+~)BGh7#t-$N4THV4M)TLN+n&su8m)__c<+sC+mav#HR zjO!;)P~|bMpL`X@cVb*WIgpX(^`INcb_e7XYFtzO)Q}cd(trYPv!8nc9tg-oJ%GOo zy2Ptj0L0S? zj0}{=7<}%Tbd13#H#9=|f4%z0Ewv9qWb&hQ&RMV1)0S+^LI3dZ8B13_8LHdZ`eGR0Nt5+C zOmBM()(*LNayG+AjEg55bCJZjc=hBe3NXQTt-mEs7OO{#tn|98D1MA{CvQ`q7g>|T zsa=r0&h{Su$n|Pyv6a@hh#peQu9KyVtsCtXkb#$|g>>`V?8h{W$fpT6d8H}Rwg8p= zu`W%MzjswHqRZhQm=gCL76z{Y3H-oYYNfG&-5Btk%|)j(WCx zW3%PLsAbOSEBDuIKDh!Z&Ao;=Y`fPGlJj`1wUwXVjT_-Fc7+~1O-^YG_?I{N3|XWu zw6?|>!_}1~)-T2fYQQB{q{)29Vm8>b6ivXHX|N~HKuEPtLLuR%i#rWvWhKs0wYaU-HoOt`2%mWjnIMoF&O!A?Td1Nfu5iO=-P|t?M`Doh&n~=ZIFG1E zsZ|hdh6Nt}-Oc^f?>x&&=Un)k-{FZ!_`C~O;VU9=gYX3xZW9jAgTnuF;XdK;EGYb^ z3*Q$GPlCc1U3f+~4Cdj#T)4z^wqYHG|M^M1P->+__aeB3Q;gsB1WuZAOb|HR!`L`7 zunNLOHRS<07rqp3WyBYA!doqQE2SL9%c+W1`zZyzGUoHr(5o>k1Gre^i?k*~0PPz|mt%Me||L%d;+B+63})u5f#GTMQb z9Bv%c{T{C`(h*F8gEUK4*K@}D^1 z_l!Sv2V0Y66DT13k%zY>%Y5Q*jGZ|3!nIVgd=eLT;nT(n#7&WPI$823Qo?7A3@jLt zbtalDCxnslv%xzScu^%;4ygnDyD>)N-;$+21NgkLK;!et@-5Ezf5sAxFDA?LNQD0~ ze$#kWiX6n)ApGux)}_cc#HQaBcw>rO$k-6@aCCEu?92?y%h-}4vu)rw4{uG8U8sSe zhqt9js}#77hj-u}Z+&3f!#h)C2f9wY-}BWJ*_OdrdU$t=e4Y_DES!De?zaa6Eh#HIzeW zk`{h9tgUJ&`8BC<%Nm>}kJBW@HMp@%;^J&ogEM3gcyqY5AJH-n1FmW!XREwUR=Uw? zPtQ))bwPOum$P+~ct(`4Mjh^9<@Q~JWl*=_hY-NxH$m#AMPP&kCc9c04le_85xcBR zx*0dzZ=e#(qYaymWLXw39dV-IT&6nrv{IwLqOq0xDB6M$?HtAwEls|{txe}Yh`Uyv z+gX~E2@kcJ@76UloJ>RlE8j)gP92D96}+p<@|?G!NUMd53Y-XXt(NC?S&@^2kZ2XU zsKhCbvara7rOq<=h*d)eb|%4qRt+84=U4S`K2o<`30jC>ajgKICGts13eGY7BEJDL zF!cwVzXS)$+psqm~02Wq>U7CW4^#qFWerr}@ecXocq{PNur9m!+a7 z=n7_=Y7Fbl#+oQPxUvHM_1eY$ z_CtQNca3am2pndgZkQQ)O#B>@SxG7lV9=STRBtOYx)_$I=ds9fW!M$SW09M<7XXw| zGnru+pq}RrvfedgX8G!Q?htma!zp?_k3}AFn)Cq5cH5;m|JXn|E=qIwTa@*3U6kRB zxuP?m=Oo$nW?bW|=lMvU&l&@D)N983u!&Y;?yK!FzyCnm#HQ}k44-oot_lnT!0+Lba|BTyj?gnZ<5qz-KLM3D|lPy2`8?Z1@t}P35)4mGIldPSdnve9p}< zVPa<&na&WnQDPSt1)bAy`^0iKqCp2Dsw7spWf5mOaud7WsLN8EzR+Z1x2l7JRU0{c z<0-NGYF(J_yoFGn*yBEpnmL=Xb`yKL-HdRKU>{HH|D-OfcAkP0Bv!owgtLyGI2oN^ zY4wOMg8L>8YlaD%Sqtwqou{DU#Ni%3g~zMSfk$+5%eMxcK3FJ;S6=So`vT5GFi>Lk z)h^x{a2|z}iDN#*Uo&eT@Y9IDiQ}j>GwYR|fqJt?&GaQsSfuN}3hZQJH78D_$Y$0d zG`P5DU|*}mC}~FFCm*4Hj~o%c#OZahRcJp-oZ;Hs=lnqZ&UBIKoX=6u_OlxHsH6>M zySWkPdaR4Y>s*zjIFB^~n(v}C=L77wiPyU*!+D=RaD$7oom7?D-)iOT!l;Q$-OMWI z9yOxBl^>mvjLg-{G_zKHY&(asE)v&vK~*zr9q#@2L)l7|V1)hx%lepRK|1IE(eBj#`>GC6=+D)9Jbcs9MjAN)Uii+5> zURU@OI9}ydS&att;%x8zUT2?tE5WHE-sa&W366oSAn|^qoN}LhKf%eV0N&x^ttS$k z6Lgt}lHKxe6P*2OQTEaPKU*bqM2bFRuNH==^VJhcTT^|wIyF(V}_(LxM{(D=1R z_!oX3k-jUM7a>D`>C6wEg_X(@W+va z&p#TfGb8;^vC=RGAQAn|Vpj(+w|KERjvTqE&}V|^jYaSH{Nw10kzo?OhGN4Ul`%hC;mWA zPeatpV2A(7M2>iam3)aQk?S5uH_nq-t&#cMEg6>g5?${i(|H+dCvt;}g3dE)!DUw7 z@F6&Vh%Dq7iIXC$mqWLXiO3UK<3=9bHHD5NYgxch{5M=Hvd)bS(m4S^BkNt)4?Fyh zU*uMEJ`pCU*CfKeG)!{)_!}L;|UPrbUVFindhKI+ZXxF>B*)GuW}Zt4MVIw#_OujP-~bW z)cr%TNuO+sCg(;%Kh!BDikx?4E^-nn$pxupE^)p_IE?&r1{T3prP*NYr18Fp-|+X= z*pg|Syr{uJdA19%X|ONUx8+`%GTv~7+iJ^?Y~XtFMjdzzZUZ!zJJWL9&hvMDHL!PTY;46x2U5U5A}? z*u_r#@HhNAJgjPnWS9uQ_sBDNR;YM^6?zAm>C4%#o*HKLG2)dm+-hhXRcXVmEMu+e zJlra7m&THr&s1w-)-OZiJtMA`+plo6cW^;A&o} z^YgV3)qd_it`OBazh(1jK69*FSK~vE4S;V?QaFqy8RYHOSKC%>pcE z>wNu;H$SxytqSy`)WX54-AJqT$f1~|zgQFgg|QRWi-#jl`-?wB$Hkj6m|TTeP^`ZY zU(6Q)d`*{PEm-dx;%!vVy#`4pipk@#-sgn`WZ}tu!3*k*kyf_~pt*y2i4(6vK zje~)AtI%J|{F||8jU(Dfz+rk)(_foHpP<-^0j`$UFj0I85#CxuEf;^*oJn5bK;aA$ z1q0MS)fV1jQ4L00rN(7y;ApI*U24u~oO`^lHjTEL7zfoeqpfcKpL=W?V>Qi*&%n5Y z19c!p3!V`nePSTeJPk621ioUrN>z?QH$&8nF;#rrc z*x9_fi;Jz_wbZ8cehb8;++* zmg%+7B8pgoG&v5w0;$GKgw4NH8z)+=jbrN2M40|_l{d*MfInP5$!eK@+>bX1P}kS# zB2HqBM`m8ZJ)#4K@4S{;+ZBOk{y?QpSE)xQSxJ>Pf=b8f*Ut7CPw+-Yd%!OLz;bg@ z2j@aq8=2^$JQq4#jd)10SyMK7=Q%t8dQu#;v>~>vX#~(s}8D^9cR7C$ZZ2yF&l|nm{^F! zZnX;a@_qp>Z;K7D9#(;`XFO8BVFEt5GPa_V!%&)ryteAdWUCQ=3(2c}rTPOnV=)`` z&P9c;m{GOcs845L-RC{3Y*${q^)e0n*bikw|d*^VC0AWBSK|ePvaw$LW91 zVosmG{Hv#bwdy#yju&(DYhzZVNvnrix zrS<$Tu&=C|^*D#$SX@&Ceqh`e*8Clo)ZsAu+`+A`H@%V>Qz7g$)p(kf)_Ma=DJ(w#t%ZFLiLwl=1ug9FKw8*l*kZJ> zQ`J;7Y_bQ~S2l_DDC`?7rm$()JGHRA)x)S~F9X)Y?@;ef!|;dIPdJSHz9!ojsjtiGNc{&sbbgP9z^L`w>0K&6)fhz?l1HMn?2s=qfRHOtEO9NZTVjB1*i4WMD;>Fy9`+CWwM$+1A1AjR?mQ09#cDK zSQ(keQCfDMoy>q1&a*AoQ+xv?xSlf959lPj1Xz1y4*#XcnXqqY@?ka&xU_mSwHg~UlDZctBNV>L~@ zpP06-n~el*o2!1f2Iq_Ilsy|~XxmkD92&oj(()&v?o&wg*@8q_DR+PukorAaO`L6I z*y%aQIFBBBtM#*SYJG=#V7Aq0^j>6_ZDwWq(wD5n@j|&saJ+U%=zX9++-w)4%2cD? zcnn9w^h2SqKV!~Flvd-vInB@py%ip(&I>Iky6q4yerbnH6p!=LRX}0uX~E*a8LUiMOvo1 zdFsP!t;VDI`vGNn+yXiG0YG}7=}d5-B}nLj%FtD3)Wh5>CU|q-j6!#yu_&E@|21=e z8YOz1_toGzR{H4QfXf!v48u2h^e|;iaG0Br(8CNvCp%CN!@OKG%o8Ydhq)T1{JDsl zVUD6i4|7o+!!Tpgnq!#LXs&0|0Z0!sfe8+?6bU^HJHdyP^lT=2vv~=H?l64u>#lzd zeyT>y~j7mF56YpXIz2TC%?L*`|OQ`?z1lt+v&OV`b_DRn!MWGvVZbV5@ydE(Y za;jPEx$z9du9f(2Z1YdL3eD-p(H6e3zHT)oT7V54mjdw7f}Yf~NN9sZ(YlI5z`fW5 z1$dhy=%uyH>%YeCzoJA>*J`PTTxT`TY1k5LW<6@Xi2r&lz9_E8;yc!QtkLR@>#Ve# zEx>NCyHWQA{IBWt9hB%^>ldm|&}(M1La1*Uq|!Zh1kycLF+nqrQw`@Mvd;t7?N+MJ z^P&8^)v)<^kL@+KK3>!Mqng&|Yg&VLbmx34HM>U<1k$IB{B4f2Xh4B@8Z{p!+GSR& zkI`e}_lO^;#LKEkxG^qILKeojM#U=mdc?RM#mHcknWee_cX|o9teUmx0>@ZN3!Gzu zbFf=^F7Ocs{~Z5efyb`KIJ5wMA#CgQR!aAwsN~KN3H#bJyJ2icMq1xSGrDy)ZCg*FKB)9eiY|aD)9H!>q03|O1 z)*?Khw%!0GA5_nxb?%SI?zRmZ+Na#qI7Oqx>mh>)_E1uy{<*xTNk`jyEzeMMEn?r^p$MEPH9|uC5EZo z8^Rtj4SS=$?4B|fc>&RRJ_fElf}+COqHE{tqOAyczJdS2pC*vGUv2T!^}09%>&Z8e zMGxTr)Y{@{J9M!cvA{~i{goLDaCU{;Ebie^_i)%foN*8FQSjaVtJ+4bpG%*@w2c)8 z_46bC{{}d01}>}kkkwdmv62^t*ieiW6{xq-V4dtZxPz)*XeCF7^+0ZtVHkg+O^a)> zoPqYDj~0B?hBVdOViUIFn)DLt%gt{N)u*^u=l_c!*GuyeK~0+PzZnhO%k`@fQ@yk= z?_(M$Pn}z6r8L~tg=u#vK8f|xzPzx?TV%CL(6<_z>l-h=ybsi*MYxRLthOw&QXGAu z|A)Tl$Nh^3)XR%->*Zl}ev#G7*s02IvT}@mYSK+sLEFtZ`!P~Y&d0w#(ryMe1EY}% zBlx{TAb`z;T#r`JFRy z8OFp~Bo<>{fo{7NIWHh*5HzEg?=)zeZ=f1~i|(`0n9KJt z3d_#2F;~(BARR1{J0QW8)B*|YK~Y@sq4fs*N2qGf)(lr&P^uT!R3zM!?M0{(4(p(z z1IkL4cmkB6EDvSIAL8yB0UktoS!ZNw0ZsvF0sdiv0#tWI?2eBh)g7(-Pyp}xc(z)- z#Oet9ytxGLgFTFTzW!hJ_W7o@K^(<@W0NTV6L>#MeEk`~-b1fH;lFV~=-I!EqHZ;r zT7a*RqXh`SJ+uJ1Nazjgb2MD&&TRU%m^Z^^I~3}zMNPcfs%u{bs1>tZ-E=eVvi^si zFwlI*dcL0iS-9QN5?8lW!WpsbMpVy7UJ=4ic{&mcn1~?p5)wV%z?ym$i9@V@M0_&` zg+C$B>WsoQNHA=jWMP6>z(Sr4XQNPW8SD6Q1-)l<`vUb^BVX?ub-So8OR;aX!(!0F zRjaF);_P~OJ7xK)Kg#3KKlrZiPg*7vaqgjG}w)S*{x1 zg2+7rCA#NZROef)9Q&>s{0e??)M{M$HM`)hc7X}@RSz+vTPgaQkN>)_JmmB~LbD@h zU0uv^jK6FLjumH+*#V_`go)~-TM*F~0GIJI4i$lZIFkd?_KwG1(E|UChOWJzM?trm zOl@zz8K~_Y?1}^(t~CU&>b2!o8+&I> z_FKwYVKt5qBSx3k8H7dJLlv&D(){H;RNoa=YNLPols9ZyX`(me7F}_+Vs#Dx&QW_vT9aitUSz4c&c-f33`szTdiJYrRFq5&~eWgfwH(#-SX-FjST7-=y_7G$9zs2MX*I(M zz4Vx>T5UCG{~PM)(Spcx|MfmR)Ah2`9P1lVehxSl#pT~2(U*x6NL;73t%g3g18bYU zsoq&_H4gs(TsEmbGN~tDrTS~Nm7Jp&RZr|3lev3PHR&+B7Pl1>6nCV$bPaCK%mj9q z&tTNufu3qKvlb;<*89|TYj7w3X>}(W*fGabFRrohW2)*nN_(7Uzl^JiecgHW=R$iP zTc3e`4M*rj)*OY}1v?_)E|!`q+G_@?&TBEtnJCqrZBbXRwQ}S4*I;buTh`*XVbgx< zxwTe7PJ2vR_t%dJhOLQ6bgP4X;d1=fecq_#I@}~)j{@E2KGk}im6h@yTg)GV0MZ{S zoRNgm^+3<5Y3r=C=(or$|KoC>Z&4LWix9S}oWZD)ia)<2tEwpyRjrxT34am?Akhnn z$C2oJITB+1qtVK(XqUAJMH7(oC+o~aqHrKI&U3DQ*x3%Cim}Ql&w-8mqM*D15;sJd z3L&)}3Aoiws9n?+!H>1CGS;Hc^4-Y$jP-UP@fQ7zXA!0GDvN`)oRo~N=#8+V}hdi zhao{xS|Cxzvq7z+sX$tk)l5*7BTP_~vrJGFF_ z_CEYa+<1NorpwzaccZYJr=w4(M>gU@@ildDqm?!OJ2qyJNE+?Kzb*{v=L)cEr(xzl zEx8$ucm`aG(y~0{>7gru^w6W2;Lr<^(2@2}wC#*~h_s{Fn2~m)>VF$9Fdsl2Ey1&D z)@@c+{M&5Ip~GX;*4wPK%!)BoQ_Ub_f%G7AnBX9=QyzL=X)e@+KUqYCVDdd z*PQjnk5!E~!6ypGqQ_t(v}eTa52Sk>!vuTWrABN*#C-)=_xK?aZjZ(2tZz=zcHwwnYUW0DowAyYKU#w`C!k-~NI#;}yv8unUzaRHmo(B8l$P~Go}TSO zAT8VmCMetsNN6MZV5I+#uJ-_sqI$!=cXqbTfxw2gYzQGCKoUYpLQCi&AiatL(xn9< z5R|II0!E0^i=0RgMG>ir22fN46;Tib6$?rf5fxC1fE4-eXZK$IyzljXTvzy=`#h(& znc1ClHXGs4TwaMRopfSZfy+PqGJ*t)=NKV5g|do9@adA(f4jn2RfM_urf^oZpn_So z5Qk(n9gbjD35Y8vFd?f2;jEVG0P<1?5GFV@ztQUoFdqJp$WrSn+4@+4t7@IT+4L9# zNAO>*xv3~dTZdtM`GUNJBM;SW9r9FNyFkaj?5f*M?#PYK!LuZi*EWN@OVFLR65*34 zHH1g^ka4QGdj#DzhYucNGae4Q@l|**)ME^#*SzeCDjiI9NGO1<)^GaI%dReX6~edN z)gj?-eI#@RMRLwTF@o043K1HW+8VUB(b;7fGv}ds`iOfqT(wI`ww+z_Hb$t?y10UkhQuCO>1tjr&<^$NxgTKD*^Ak{JaWZ&D@siFTf9N zB8YNGoq8GayJ^NAm(i^io+fheRg7-C8XqeZ=$zHAMEm9XTCa9hDbr*mzF-<7F9f|8 zEXT7W^`X^x1X>CIR*$0@J`=~IaNH6{2Wglm;AjpVL92J$1C{j={yPINZ<}M?@HKFEcpZaR&Cz<& z8dsHJ!OsbOFWPJaM;P zS&iUWAl@H{cPpsv;w|qPeW7o!aYe^mhHkZ|GwzSZpi$fGZjHMj{AKk)kOpIPgSGfZ zrUOjPdGIu4H7a7@#Gt#!p@ zu7+;47^Rg@ZCcHOuzXw)Z zoA*28Zm@{T%ddaV&tN)CA<%e7eM31sM;S^%@*m;&=;=Ms&PlkAg?5M=?&Oi=zV^YvE|_jYqgKP`f0;WH`PO$4ofdPK14s*ylmzLS?-S$3i%| zZG@v!0c>{`!}~+19s0sLyhMK*)>dujU}TA-2^_9TaMXpP5**FtT#u}QP!B_8jf7)@ zIG%#z92}j}VgFzWeBOqSb21zsz|k6x=GhYUGpJ$W{S6$?i{lqKHj3jfI3C(9A*V~o zJCLWu-!m8AK~Iq}g?@yk+e}!p=HtH}@XcBd$1pgW@0M7vLQS5ce^~FTQhzIaTlMIP zCq8k=?ejMh&WnX3>j|hop|Zxq5%n}2)8J_Gw643s22;{@iY5gN9@n0dl+*y_2ikqh6H@d23 zXHG-&pF&32FCk1XScbyK*6Aj^^293xUU~4!Y6Hhwu{E!l067fuBgi&8aH;)XF1Js@ zM~>_Z{p+LCaAfU9IcnK3`sC`Z8}W%(wmytZ%Wgv(`Jx@m#N<7PT>5O+_cr1o^fev# zimQ6L~u6zTV0!I$*S zYawXf-=PG22)aaquF`)>m@jqYtH@+RTZCEPLrW&XU9YKdw)oT!-)-4J-$A&`_LdOe z&Uy%<_}mJ{gByazFU9zr7{}{1ui~5TUiz(9UCH*TZvFGCu4=VkOGVf}s}@M|gDN4c z0cVSyrQv%$J?JavmWEQ8r|WG()T^!ZpiQnCcB7Qe--OmUr#EkMB^p`!g!ukhQQzK# z@4OyG5=Og}ml3%<{%dhQ1-ir4?vjzs36CYZ>1(bUWzvzU(Ww`Lz~2pjrN_VKs{ZKm zO!$wmza2DuAg#L;&i|{s&_U&2Vc%t!#T|Y6&j^IxIw-vr>c49tpHTl5{q>sbR=1+N zw_N37OBPkcbjF|Ewy0fEWF>csVHrNGo3=#`m+lqqo?YTr1uP=?Gi=?8E=Riu8*!Zw zJ{Uk8@)iJ0f<8h23Def-zA^6Tgs|1J<=X01UxfGFs)j>Zwh7bd)kjZ`aZhaeLohBf z6~|BbGi==jXT$#C!5X$(wsGN9^}QJP;JAu@mP#D*A^=JykQWL}1 zDhX8;e-D(ZXkiui6Nd48kt@z!3DmW#x?}aAs_rpG#Z}#fWy{Oyx(?f-l~Y~fO2eOl z*G1+wbk~mzd$?^AQNkx}Rf|4o=>Er3^l=OKrYIv-d;7bS_58=&ua%Uijpq16<991+ z)YpC0EGaKeZ^xf_>6!!G`H|xDBz=V2_56YE3Pnc-x~KSzRz+kReZ^xdEK30pFB`Maot_R+4`(u zdq^*eO)0B8#iw}f(+BFk@Rt{aC0PDIt!_Yms8er1?ii>agLKu5wA;RHuYW8P6{XkS zaC^)d(ATanuQbZ*mHU*}nb_BEYpHh*?ORrRZ=wdVt4!N5oilc5yfb@% z-8MpZpWLLH9(U87;M_gNZtJX5C#IJz+HuqUtYtLNwe6nG_6F(tr=#vl`kLJnXK#?9 zQ%z5KeaY@|>Aj|>lx}Hy%3-fa@!Reydc5hWflglZio2}dW_r?$G+k_Zni=(U6$gOd zZP@1a>xm9eEhLUmRV0ZrI@f{3zH@j=84dM-Pu#v`PEV5V>+nSA?|yby(4Cx~QPu0) zMvu%HF?i&dI*roO(rwuTpUN3Kc6>HeqZC_i_DFH07X9G#92}|huY0^YyH%XmFE7j* z_`6NYOS7U&>8(doeEQI?IbOZ#YPwga-$0bTx12E+8GsUMA?Lt_sPZFMfV?p3_NzrtMk4|@mlj~Sga#rNBR73QWlZ&M!Cd0 ztnVTh?YWa4t9wSFU>*}Gc)Fr==^xGZ`umm$g&Rl?C!f%(O80A|Pu;rAJG!0^)rP89QORg9VIwB90(h)~i_UD!Df*@C*e=UA@)62D zb>ZHb)m9+ z{t~!T7g?J0la=*lBg3Z)dLyx+Ihc&u)vM!T+dU6`U1LtVbeU=#+l5SmjjOp_yQ`RM$k(qi%NsO)5-O&vNJy4BwGb2{7{R!9l zY%{}az0Yt5^b8Xv>>YvOSMlMzSY2+c>GfAA6Urotlz02347GLnwfeq2X-VJ+v!{miM8v%PvZtUCJ> zge&k`Ucc-LkZ^6uN60?9SmK=;gj79|Xp!vQi1+#K$ruHL;n&Uuxgi-Bj87Tkh~Aex z%9l}0`73#myiCeY1If@umLkjOtx^3F^rk~7+1aRmvHIXIDc(5Qg&?6Pkk1Nn;hRpK zhh22IfNOfMp!XWRwbm$Kd)c}mvEL^@X0XH5N6D|r@5o{ya`~0|cU{;d_yydl?qu*@3 zsxmHb>nLB*ks~mYvnyb@$rcZZ_8WPLyrSn#z%_1Z9f#LnRUUv5rUogyKSa0ETkDSU zS&vdaruW6*@>Yx2dyae4kbrb?0!BE^W+Y_r3M6 zSw}~t;XYw<6f#L1jVMbW!{T#DWP!+vmCzQlJwzhEPku}u);W{W7H5A?@kU*u-xcy- z@@|x#zbdVQ?$=^itaeoG7i$fak5Q1?5WVV;6rXDlLhoibl~_I8q0n|jDw{! zbT{oCgdw%*DH$6B(9yZ2F|MvjjEdvoSMVhUQg67DWDkubx{=&U?j&Vvjo3fZ`z|5V zn~3QDhkpN(vbRRUl+}YLpl-6mMq~rs?5`A`B|B_H_R{^I(+NqFD4!vpBjvnl3ATV- zqBAF=WzJW{2u=TSE(#tG*R`o8rU6|3Um5Oq@-q34jypNWr%w*TgexB#O4F~W*1#kj z`gckVFnkvg(WMnXni%6epDvNNe%QAobTnm$uTIhT$5XH%rG_L#l?#FhUPbz?w9< zEN(;+zrbMGR5l|;-+UT3W8X5!Y4TU{cYQGlt(tPRQf!hxK9o#lvIbd`OeGuWd9yJy zyHh@*bDCmRIzJr6IXPR$`WMr%jFkOV(nOoJ^YG*Z|6$6bq#T+l=I`~4;~75dFUqTW z(OEpf)lZg>Oq$`2pmDWOxaRuwuw1Ore~&2pe@z6`Ir#c=;s*Q;BMs$fOc2&EsR_q9OFWh0E< z^&&DJOv5l;=*#dW1t^~*WxtoSlpHT4Ttyb@!FAB@t>@?zOZI???N1#y15@v8OEggL z8K~LPk-1)fT0+R$kZeX~>dQ~y8LU6$U{bb)Nn#VUF%yYx$V6g^r=)_jOs^%oz{L8g zj`U~v{C`sZMaoVvG23;sR-+R1+MAVPb^Uo*;Cg?H6wchljdK2TC|Lez^wPCfNV;bV zZf^G{hN9u;hOw2<#PY%KrT)-+)Z9dv6IVlvbu1@_CYsCiz9@xNbg=xzx61 zD2a~b!(=bLDhCfld3RF08H?$+jC_UMOv+X;DaOa-SLC-k^1sv;{D7)y>ZP3OW>fsJ|^51j4)(12k)S3BM&VQr)Q}3@Vt5PmL zMv#49QiK??23b>gu8$=leH@y*buL;^wth*#3A*s|Twju=TtTiUUnPskcXZ`@xMh$X zViNmjQuc_6{znhKg86;Z$VdOai0Zbp!!`LyQ85Jp;wb2G|$aC30nM2nx1x~q;{mJGiNT*YHcq*6C&)Z(M zc}cjAr2Jry=z-*L@(EHle~En>IgebVkGu2HGdGY=$!{lnE!h<&0l(3mmuZ|L)d_R; zP<)2hUpX~oh$EB8+WPVWe1ai6#exMQdytRn%e9x5)1NLh%j#$QV5zKl9^F@9<$JB| z4DzPlSq%gAtRoeMNqOER*-j>D-6CaIndnkv1u{xso`jpWyv`_NfkGqYSI2YfL|UKL zTb-%C_OgjgBCjW98=2@LQg)DuK0*FM%2}%7FFVSFxAm&Y7%#G=Ok^cec9w~*qr2BY zC93ruhR^!wH$XS*JIrUvW-|%$ypCwy->0v+Qt>eb{ffv>$j`L#G(LKijc5|(itgVP zSB+DD%)wkw!00&?foh&{L}Ng>Q@t6_)enW6P0lA5ld?Na(s_k^i^O*g3DV?k`g{Gq z(eF=EcCbmDd;0jFb9{lw1|eCVlznYtu1Thna(uA(w<2XrjcD2LCSQs6Cx?+E$#LWa zaw<6^#DMJuddwr2k;}<-`2~4`{GR-Ylx=vD&QEk~P=E03AQWc_y;qQH^u>tON&4g?SbfKr!lg_O`llKgBPStp~B|4qsw@_q6EZjiCG^{yz_>@^tA z1$8oFtrAT_kxT3S74v;b)hUz6G_oNnKeZ-#WxaGa$EWAE!L8Q$=kR&%P$LI-hyHwT zpY;qOzl0?rx07#@d&&1m*$gS+j+5V#r^#Q*-}RzAT+>c=!^$i>B_&QJQZ`JAPSuz5 z@*3&-k+@*CtAu(Ux{B+=yTga2_>VBiaZ)xtN|ax9&!It)3rW$xRRZb z;`h6rQ5n(N&Bl%4?#lVz_Od}z3^hsF6Dhhm*^%r@K1x1DjwEyRMJGD)CK9$}XFfV&Qx&xD_`Vq9J---^OFOLtbZY$!UqJR$N?J3?7s>hL zGIBY&j(mmOM!rFQNPbKnCBG!UBYzCBvF#i^{vfZA*GX5)PyrPgNtV|;Uy+Y~C>!X= z1{sa4!IZ=F-F{f1pP>xs%W>$IwL3g`N~nO_jv^Y~ArFzClV6eFl0TE@^t=kVgFpW& zhJ_rAEKOHlM{dIXV*+I|DLY7mJ*_WS&G-2SQ4S@?l275BsbTm$?qA$gF5Kyf&G>|d z&&Z!h`B8C6?-F^1l)b0oZ|T%(7@e~5RAfUv4pMLEj87z@*PF5a*)+%@!4g3BoeJ0K z)XjKw?Y$Wfizn#!4Jmt3CCnds(JegB$wpL>74**PNPB2RjyKSjejUjkq@1KHVMmao zNZE`k{xiuJ$a$n}PZj$*ax=M&lnr%a-yfo~eM*lbIyD2+(Gi7(TsE#spnr8_0@|c( z>yY&683^K+O{`*VM9RKZ(H-@EN#SHyG}+Az+)eD>iq*IGojG1>9fQ20FGi*M{POy= z#CVrHLLS$H8)x{Uexdx0l%1*){8npS$D30@7i>eip1bJr4Uc19p6!MVD{e>o%f?j+ zIDwo-&cye~cseVfTuE*vck03<^hd2Lc>Iywt&+rdI&KHLb^N!(y%{AQ3i*{LtCBUy zx@0}FG1*)jP320o2&-9QQ#?XFNy9{P2Kl_cToVP@v=h^!h<@+r;+-hK?xy&BZ$o7) z^yzP)*1MCj8lA^~R;#w5LOrA-V$h_IQw}G`kWcFUi*c#=d=oyyd53=Q>(nJ!*={yN zAEnnuf=hoG?tQ5po&X&^<(u$!p_DUq;jTDehHRXb78yZ~A)h3lBWIHf$R&DJPkgk{ zb2!%b-Sm4`8wNfHIP_MWH|j6?T_tam_uA?AhL5VCd%ulOyJa`6WZr^oPj)5;lf(3) zm+}()^C=gTvfWmqzp8UaU_IMQ`5r#Q!&?usxmK)a$xGxFJ)@=c+cI1%s&@#5Nz#i_ z&_&t1(FrHx&>c$`;nR|dv_7pe|o>la| zs#pnoE=DS{HCFt(>zrQr2w)iHNNp70M)-Nk7xcJRC{@pRWWHe}#(lN}J$9%So_J;N ztR!$*r`D5k^bW?6?2{G0cpaC8Z|R3Vff$ps(Bt{q*&EE&gwld$m6% zI>C}XvEqF}7r%^=lh_*Rc$VYy5ZMMRhB~C|h83Nur}pXR^ADhWoRsabVxFMKy@#vM zY|1%$C!{`v6fM~yD?vWg|7upyXrBCsTC}Lw@~(#^}Iw3rE+6X*j^e0D>Ii&0amRdfqyRSxX z*6)u=FZ&(D?={`NYIH9>J_$A0-7dqMBpZUo;3KP$aweSk*Cgxc)BRD>PS4`o#IuO) zA40Fd_wsd`6cgP+6J+NZ#O3Kz} z(Zk3ba-42oJvza^i1H%dQrq&pLLn?A6+O?_Ek$R z<@JnD<9tb}lnqGPB_ieyr0lg8-Cv(xk=w{xLaBA-mASq?Z&1EX$|eyBeSrLo{DM41 z{y_dp%6Y;P?+STc$8EsSt@s&MI{zafTV>tsalHP~^C`@Of(?1zK7(i&O6HK`$jRih z?hxGIMm(#kMe3g7%7aze&I{6jca-8piTaNE(_=!AE zUeJ+UaWAKOg>orH`p8PU@MxT`eJW)GvN_p`>_~PcWox_?dMG)H9IGSNl_mb?tq|rO1ouq8Y7rS4do`?nZa%1+zvS|qo+?sPuF%B@oV1hjEmC&d3Bdul}|WJEm{3LQhr2>}v2m25(`Als9jba{ zBC>#7i8nQHC$)oe7rBqzuXnzVuNuFn{E7UVyr#EGY&n8J5|1WpkTvz9uh0&yC?6u_ zpaKcrj~qsh)JN9iOTQN>=aX`hfdpSqzD{n}Gb+r*b*Lw<+Vvaaq4p{bH^_UW*)Nnp z39>ZlBP-$8IWa@iAIb1$G^Ss3Qcg>d%zKcJkpsx#Bwm<(7H^wPqnt^;NX{phk;_Rr zenFDoM!rq%)yE&fx7V$w;;qP*M?Ky?ateb4EJaozqsXdc4YCfIMrM%B$TnnqeWX!p zf`1(41acZVQ%6k0jLY7h7i+yqzaqV8JKjV+LV2A0j{K4Qjr^0mLSEM+Q*lQcGayu< zs``lJup>1(HlqvudXRm|f#e8s6e%Z8NTW>ConOsul<^AXW^yO_7AfaaNbp1Caq=rY zGA%kGaGmlNX$}kpcavVS99fx+BjvOUNxmW3jLan4k)6ng$zCBw*@n~O3GzvDqVC)n zPl)-Hb4fWzL-JdrQ!8N}>}rfVzR7RkviT=PL&E}c4Y^+LYl7wQW6HyN@MBo*7k=sSw!cBY+oXLk%SOs^98#$$ zvO1YW%7GkWZ>lqY#Cj|TafrklZ%r|Uy(jPi*QOuwNrD`@A%@q}hDYSaCj;UOgM@lfRIWC~fI%p%+BoV-!Kq#=|eNIAGe@_w3}K|Zf9 zB6X{Pa;1(tgL~v1l)K1-ueWBqaziWm-%C&+Jf@jIB%atw-?{~_fx6ww|% zZ#(WO&|V^JXP3|S-a1Y7p3-T2C1NkfYJ9&%zPp1yWFe$iz zUff*+FC;a5B9u^LefkYdg7Nc4rRY;bv1G2Cf=@@SLLcdZYi||Gcx^ot z-AHHG!AMR#g#NGJH8oZ*d??y$ZDx>ddd4AKf5&%4tqv~5!)E9;~h-oZ%P&>cx9&Qui!CU+lh%d%W#5yh-jQ-_tWb$B6op@@t)%hFSjy-S45~y>sz#>|**Y zBUh1y@gc+-AFUQQ_I-NE3d#MUXJCF?8lSOkO7@~48631a*fV;6nF61W>v5MQ~Dht z<;WgMqF6^hg@yIdu{>`;&gv1rDr60^CRvYcL^dZ|k#f3^#P3B8B8QT4=#SW^kTc0y zA?l8=42w(JNYB^E9po`4wIN9sZ(r=wrMOEG7A#7o{_|Fr^y*4zKF>{L!?i_)S8@u8>pQ$yrriez{AV#ukiWFAN0GVtseLQB;uJ+Q6qKX zB)kpPi?T2II5`}z$YRV_E5wBDc@TFLasZQ5@ol}cF>Xq}r~HXLNB%+HChzIgZ}0_c z%(J1`Rmo(st}dRO;meRinWN)$`IgA`h=91&}xF%Sw@+s%)MNQ@=B+1E7lGKi2Pho0)$Ki&xy#P!iSkegv`7DVyquk8$7Mi?Xk- zEpig&GkQj81TLi9s0*LQW7i(aeY&_Q%6gpgD{VA`{GIZm&h(-zyVj42^~X(P=4350 zMc*BWG2NZ=5gi$c>~blw+C%D1&tNc|Z#LK4L5`l1X84r+iu{)RnLI~cBrlV;Kq$T= zpf7nG$wlR_c!o81r)AV{kkYWBE{-Zu(a|s?Jw+Ej+&>ZDOdWo>e+`|oYta%NNVSGn ztL;K;`OVqK;dt<$-SG5wV8@5uy-8bXRwZM&uAXK!v_I$6jRHXEJHlTnGKV>=3A?>YaHHob(fvV6q(X&F5h^4IMY3$J66^YS$c0H@K(NpVs zR;@r0YUD^YGJ}~u_|Dtb6#X8qsf6_Yfxr;{t|OHB)l=(RmF%$&-C|{8bBEpGh|)jQxB8cgL0IR;69|Jdtsd8H8(1yM z${{B1=smC)MyVBmx1D~ufz{TC*ToI2WFtvOG_;cKH%#5Qp;gn!)WaZ+wtA7Ev)jEIp?Fy*QVZ>VO2NW`m+q{L!+yn-`J{vpZD9?*y>y{A6?;@;;3m!oVDqQHLtu4-bnsXJXtRU=BlfOEs} zuhdNhDl5m@cxtBp-`*}A+0^Q6|JI=gfkth;t*Mn@%+p^Ba`k^radN>5iCW3grNsY| zEDLwJrMgZttA+ihQ;%(C)iJO&teKT))Ghj?nboG1^QrMeM~=}grdu2J%B_i|if&G~ z=GyT9#CSmU5B zKii78mwH$a*rzJ!ZnG^fx@hohE5VuZFx~>w<4SjnH(KkR;?uLAyqgyJ!V{UgRLh(v zix%cvizENfg`$31{aBsZ$B}^FCCOQCJzoVEC7X=W2mjd(*Za_RyYr-uTw#?fyBf;z znRulkQ&}>$==2pT4nk5&s!7A75%pgLs4oyPw!e|bux}= zV=bzltqa$p&TH4A&UeglqirQ_kZrB5LF@%j*l5s|FYt#q- zT4O1YfA+IpRMpcKEon1PHpL-<=BK5_eWfm9nB}4n#Eh&64|941LYn>SV0hach9?cd z9CmkfOTgjYQzM8Pl>x(5AVKZUS1}2k4(G@*f$_-0nOqgV9(NOz#dR(Q38&9PPOiV9 z?eliR>2Nr=VnDmbH-OLl74UI8Ji&fInr}qHB1@N99k*jP*Fnr7vj#2|HrF?qaMlVY zwhuX*sZtx)4@lQc8zRoYi_PJ#k574Qu5uEu$x=8SB^{M&!{@ZPPl(a_3DK82OB+|P z`lu60D8AR21p|K0NX;wE_4C>?5jGsp^*9(4ybclszxs$Q5_&We=YfV$HX+D~0h zU5tl}qO7PMLhCszQAR6!BgkmVSalmqhckw@cITAU=kS4Upw^p+n zL#7(i`u6yTR0}Cbn$a|va$8kGO4-op6qN1MMvNS13uAXMaG;Y)PlRq~90=;3s)fk* zl)cqMB0Es_Q=LV2q#UGritJ?6z?iki4^_|CgzUmXXR8AkO3rRZk6^~5Z6!*Uh2B*% z4(nJ+=U!=uh?p@LQOS%fcX_Ns_Gs0eeETx86nxPd8c{)ot4b6_j% z95LBv*^i27Eh`MGqEITRY zvq&M;%tUXbncLxC&-}0-LYz^tG7x90b z*#XH_H50H5#+#Q>plW6U3R>OVkFiz5lwSu(Fy*)V63td<*CbQ66W25cz$e+EV=Qb1o_$Dl@EjYI{} zSN~xM9+*UIR`mivY8f& z_Lt2p6N#VNu$g{z?`4}Ahmcon<|jz)Dk1>aZ01_@%s)2Mhc)K9&8!4^Fae6Y61AP6Qu%gWArTolYJ-`*bx~l0V9#%Qg8-p{}R{&y|xS- zigwdr5=MOicohYizSd#ZN4yzp9Rc$f6ksMiZh_B%Kf6#9@OO-i=fNiEhFRc(s;CM0 zJtF3V+fdLKz#1&$T#9*A!`Wdgev21ftCWucBUaLHS9mdElVd(jZQA z0WK;Fz_C~t7lOkb(jZPV2Mx9udJ z%1VPc%{`bS%fSwaumWs}A-obCh#|2GyoQEb4ZenHvj$wBWwWgX?_&NGf~zow*MX>> zZ9N!3#WsMI5N;!wj)r{&lsleR!57fuo7M)L<|OpQYw)-RkIfPQ1$Z4C2)zX?MuTnz z520nYf#p!+?ci;22Y3br*a=p{SbhWa;tKO7cmy3Y{fyH*feAVTtdE|a2_Cc1A>aa3 zJTCx8Svz_J9EuXp0xMt)&jw#b6HTA)GM~UCo4(d%%ATU>(>=BdHgu^&O*FQmFU|d^ zPr$5T$Iu53bA-%RB~uw|M}~i8g7BCC;J#HMUCZ=w=c- zcr1|lJzCLjE<%Q;t-@OLg+n>*e@du=2532C60Fr%=rz0fkF<;_r%GVPp-G+Q6cof| zcEcEO+pLu+k5_r^4KOys66sHds;?%+>4CFK)arEtO{wmhZ%SdVVIG`PB^`Uv zNh(;Ph@e{<=|^;yig0`ilN7KgdLB|j+T&xD6Ri&!DsPG!Qb~{fHz_)Htu%DlyQTV9 znkOtrxU^iZkCs|uLKFqa5Mo~$;7k`}8O zUtp+ZO@ro;UTG*ysy$YffI>SXR>*skp(cfzq7qUu90w(2s`wl~$iGM)vGSthM zaInV(!|yg!R47|HdeV%4*HAzHuXW7$gN90#aTnn@A1u}(qpVtp*$EG+l^K7`Q0FS^ zy0??&1*A7sDaRU=FKQ5KzQa^L$D6V69EnM$qJwVf+NULls_Z<6dfX0KlhP9!Y^jtb z)xVgBstKi6Su!$PQrVSP{qG`Cdu zq|sicY^|w7Q2Yx%!kcSGAP3Jw`cR z^~EJZouZtqo{?3gm`OdW%1J5D2CZiNbVEJVQpV+P^vE+*nw0x5>U=}>l&-n#D2W+k z#?Lj>EtwowIgAz>YO#LxT@3Ff(#|gD{ZT)*6||drt)aHaDDzNnFw}Y6eJG0>)4?s{ zMNwlq+>%O_pvH7qoB~~v8q;A)ByYp00S9aD5 z)&uinv~);}6YY+Aoi$WpUFa&#;D;LV=MB|L3RK7WM9_Z0Q13~zHemXH8|n^j+f--j zYh?{pMp~dJJ#HFmfc|EmRi*ogWOz@ccb;9z57DaG&H=%4m(G ztIIN}D^Z`dt5{i~t5To0t8ZnZCQ)Cot1)shNTL4Qu0EIEX~gue+0`1EtG%di+5>8V zG<$#7HB1LH{*GNWZ4Et?0j8U3tPJy9SE&2*OjQl*tjec7-&Eg8w=STbYpP>1jaIm1 z$ui>?n(9wG^g37XU_%#}s;PAQYYe|KV5-lhMjy~)tr@z?9HQP}hORPSxa2Bh#&0rJ zSDEx*(|*WQ&00X8rvBVi{iH?CQXex_ZyCRTP@gnad#TXh)PYl``den$b$a|@s+qwn zraROnXH0cmGAu`Z7A+txR*Cw&sV0lPD)j|ZeJ?dkqW;@dzdN8)sIQsoD;cp(+=bF2 zf%u!Ink@m^Fu)yCWy&4YBh=F!DogGi`cdaOlzb+ohEnG{RF_83qp9aQRBP#?C#e@Y z)Ij8Z>SGC2;oUkTu@(cbKx-cE{CdahyK!yF@>Ab_}vcGUP|~K6L{C5 z8cP!wQ-6RONei8)K8O~PwfHahcfkw}p+K^>U#IVj(yC1<^r`v?h=W#@G&%fFUGM}S^WqOVRUH{oSE)aDs@EmoTa0!L$yC?RE-6tba8}|~ zusBzpYMr!uW$Lp|)j&pSHR|(DrLoMZWamD#4>0J*KP|tO#8B*XUsTaCb zc}Z^y^-`C5Oh$Tuy1=C@xht7Xy)xiZr)28Pr^i~C>LD$+lzM|pO_R&{a_UVkwOB@O zA@vrQdR_+7tJFJOYJyxKwo>nMsavwR?6S@W2kLH@QnjJ?(H{7~rCP`p=3_S5L09O0 z`zRwEa;bOa%K9}U9CL;4&%dWW=~8uM{r;KZPr1}ZX|dm_&$!e>t)TyA`sZCLTZZtB zkPgIOaH*4WiTuwx5}IphQke>F6&e%QTq;_|Kv@-26g)3Y4gVPxA43ZZ%d~xULF5tjFiO)m^zhG*t5VjpcK$TSdxh(?QAC1Gwb5 zRSP&&PZnUQTYVe{J%GBvt(M3n8LmQuY^7W65j}=_ty?u|3_X#0gIm2VkCM|Ef0G*z zEYQ!1)*F_U=vlcmmhaZ;1tqtpYOeIxLM1mY@~pB+cRyrB2Uf{ET@p+J59R7ZndVDX zYZO!-PFuHxd`XQA%5rLxlz$nm6;)%IBU&vDTBB7fnG!3RRIJ(}GjLTfZ+m<-wNl3O zI`v90aH1M3(|^5sXiHGnQnjQnHmGGNseGx~Q8Ipwg{`m7%B6X;DhdWpSO4MWO}(x@ z49ceJcaQEDaBPqH8&kmHP?bx_@~;j^ig6{Rx23*=^u155fiZvKrXo?jp=3~mnq>F? zn#8GFzFeYGzu*JX5fyqsDjBNR3D(OSs@GS+1nlwULLY(rsw`YOdHc7q%cl$Z}j=!tkxFtQnsN0@hHi3tn|=7pPYBXrA`%>a00 z86`z~f(hV}CHQH{leC}VBmN|6JhDuZ36{_F@W?VpX6RDd@raTy<7z$iHA7WFv)0tECPHdqRCAgW$7L8-lHXNg#9V z^I#$}Vs6V_*pX6)gVu^_O-sn5rS1h~w2G7>epxCqQQ9|FwUIUFM5)xEtQH!4C*^m( ztSUxtedMUMIv`oAuY$wFI*SJKs?w$BA$(}8cuR-JO0jfgWa)Fkq#U84Q>OI6V7{JE z%4JJm2wF?ptm5YQE>ih|!9x?JV(IYO5v-8EbZ893IaDy^sM5{w$RfioxJ<;9?i!RO z)fQdi7+wQA8>thI;fQHTSj7fQSjnh?i;R(iVe!BBRW@P_N6*pQk6Hdk)f_O7J%xF0 z7`7@{n`~M5+lPc>jMfjD#JfBGPKn8@?;W$E>=zs9O2;jKWw#q4UkoRbgHX@lFR3O% z-c8Wm5yV)bM;*7Kq8(UojRoP58lg7g?`a8%6Cn}8{%K>q4-p!5k=z%BL+(eYFYx!7 zgeXcF(!_&X=2i8|s-E2_~Tj56awIP#yc{)@k8)H@~uyw3~hx6nuzFoA@5=! z<_tO_qEjT6eg^#i&xDCKdmwBmy{;i2rl(&#VO0*iA=PbM8p|SzdOIFyLh&Ci>PAzF z@~t46QT!~`ZBB7WdZh)$B8k(IVmB^KMkYl=83C)t z+EO@hZ+KrU@j$erk#?u$BT8>2lf!NYbtP}E097#%6PW>`t{En6Lz6kz$UpHFb#iDO?r)VI-dQeoAW_*}pjwIca;*iYBM<}AvBmv`5 zs!~#tUKHP9%-k0%oe;fgX^fiGqDed)l#^=wEQa-??*92nz28{h5&A4 zi~&^dl!F*ZQA-BPAc}^P(O`-T(%g?ze2%rx7!r;n^J6GQv~>S4ivH>WG06cjJZK3R zF*jrt2`MASFGU@}NVi)*Al}0j&&Z}_oz!(CMeqReu-GSa<_TKPOW{UQT*9@(7)|kk z49A>P)dGMK(@TaeR8X{$6vj}*_#O}sE}H+xG8yxf)HRoJyttV(#!+09{(6$4rcAb{ zC?=PH2#lxdg6p0U7E9_vOrYhUSSC`m&w!Xj(Ml%4WD1W|Zwf_YnK(~V^pS3ThGL?u zgU?d5Z7lTUQXMJp-Xbc$ZmJ~JqK;tFfbq!=P2@HvX7rEp>K zP*aG!kR=eaM_TK7hV#f$FpFY|wAO5j-(*teQ~W23b69+UE0gg8Egfa~2#W`=Pq-q% z!i!bRaw+K?#0g0EuaLCoGKK3hX68|J#+A{SPtilh3@>6a4_?t?p22;Hv5>(&l?sK$ zgO{`a;{p~lG7iBOha2@RQA?P@9%DueD7hLe}f?~9LQb$peUT49crR_IU zOh|n|9G0cvbz1(C!fgp(f5uDiZKdh$2gOLa5^STzCTVY{=+_Kl2Zc{2SXk7PQM;3t z;15x}LD5B8J1iRD*(hMVNt3)FZ|tH7$Rv1+VwNn!Z&N%bjTIIhW$7-WWvLW&T=6j0S($YUrG?B@9n!=I==0}P?vMT*Vu~i1u8H(F-F)pT9BZK^B ziYC&Wzl0~y_p<1orKztJ;a7_DGKa&Wla%KiEe@&CZxrLCuIDL^N|XFfktjC@e^8W= zp8As_3*`yiR}VgX{2z}SF`1PR=@KJNmva9_u|@j&Z;Ig0fn27zC9^3k`bx`Pq2;1j zu2RGVWQ<;;nkz&8ABr@&id?5?E(7fb#W)$GHz^*MuKbtcQyDV%g#^1r%dgcTZij=( zjmMp!zy#VL4Rn{LXt~V(N6}GQ>t0C2T5=JIS`Jg8zNo^nImep2UQ0pU4VvUk#`XRV8c-p7~!T zd{-QMM(!_S!^SjesQXG~LB)k_uS?6^S6gK0RSVm;NhPX>RX^#b`|1(tiW*^CMQPCl zgX>>xf%I?9urWdgRB~8VmXUv7jggkA6}GjNI@J!VKmI?uz63mqVrzS0_2!SLJNZ12J_N;)4fb7V=tANS?vZ=_TTpJY;6crE!6b&jMC<-cI5JVId@FI%> zqN1XL{_p9o$+X}9T%Lz?zqOt^b*ien>(o0mHk*b}Ht8ZagvP+r;i2gLUG-xN$o@EJe66C9wN~? zm~qDOvk`jmIQ3h{P~vk`Y^M;KNHbO~x=2%J=TO{-9f3+h=wX_$ZV91nG@NTuHJNF* zP~3y0;ab!vNXF1T6gh*Y>RMEX*0LUF zqDWH}A>5P~h>qelqM zrP6BAY#Iu;hvNPw+4_aht(5YP5E@0xMgI_LM*UWco(z%|4G2ZHp&4Xg2>t8BUs{kB zfg$pfUfMz$UPD9ZZJL#ag-~y5#PAThkIZI72;D|Cj0~am9cZ-N6@rm85=Vv5zrHP| zIjAqjgyM>+y<7F@$29(`cC#f&m(BlS60`8O@Xs znnrTp&CH+OV`)Rl-0umYcd3QW+=n z7bE`1x!d#2)Wt^e6;HHr|6MIa^@`@|4p7+}l`YhL%B81_gqCU<-|@b~nAr4%2F9|M z>U6#r$e#<8SExE!2cy#4Aj+t?qH6pAVg@0G{l}P7s5azBfj1L=!#E7=I@sOe7+~Bi zRMT+~yIzsnQ0cSOxVnnP8iR{e4TpRuBg}R7eSBp$mLGmGovkwVAcT31i*z|&t+!Ge z@|Xmpg50$rcr#Q_IU@5A#N4xmm#LA)hKgR5v1isL(hU5_rtEe@cbR1oqf zrY6^tdl2Gsx}7gl40D^VZRE$~&KyG7f@|>C-4HhC;Hj_@caB-wG*s!%$Hd{_S1@qh z1z0+83klq9CgRp}KN76)_}LcJf$>-Um^DCssnQHx)8_ z0uqX#m%iJ3;w09*C(v|HyoAx-dIB&(!Z`0`f{79)c{@TNPm+Xb-V;<*ii8>7T~L50 zRl+RqdXhU$!W?f$j4V(6AiIJVU_aJN$ND`P?3xJ+yei3&Dce-!{RCa%$(FFK_X;&4 zhs`mYSnR!v^5(H#CM@wTf_^>u><$xl@g5>Mnz294lDm2hlCmXyf~nqMH}At<;129@ zGj%WT2^fT@8(VF{KHhH$c9-yW??r+=Bpl$qO0cJdgT22K?8S1-yu-a4s9(yY(4)Lf zNazZtnH7W2AO-!@#IsGEivZzyn-t-@MzX$R>BQmto66f^sl@3!>o)G5u2u%0gPl0N z?a!h(opxRvdI7yd=trO0cYVX~@D zZ?Hc7Tigr%8>FwJzY9Sk_4!T=5`889YWmCgtLu-U!n*pJATCk*)9AiveHQ-4=$~Wo z#Okj>lz_e)f8+GAC@5avptN*-Ekw-F6Y;l!{s!8Zsr%5phI(raOGlPY9ubZ7mH3;jC!?CiI(?MP(RZTj zo9IUn(o~;;!JMoAfi!t~9x~_aw;)Y3{TYNe*B^z}3-kxj`WE_eh}cp;fW{Q+PNXl= z>C9FueHqfX)&<0EqyGY}wACwISUTG2_oFrK^^3^RLGOYhc02ST5OR-0pM#dX=g|A2 z#P=O~dsMsEp-)CRA2{?DNco{dAAuV7;rHXw&ixL3Jev5CLw^+&e(caUL-J1?dNtw> zIP|;Fnu88~3CcX=&>eVy`_!QapM&Hz4!t)7I*e{Xp`SVQ_h3v%9Qr^AcGRI?#^rN| zP6Qjr9C|6L_`;zNfH21$`fV6lUpn-L$oG{)e-?tCaOfYP-jfd9jSOEq^e9}u!3AQU za_C>7nWr7P7s8xz=!1gj;cp!}9q#zAL;n)RoOS5*$nu>-XXw*&4t+MnKkv{FLGBB% zPUOGn(CM_?_pn$5{@~Duq7j#n1chC8=q}WB#i3_Gv>zS%%c%aUL!XHnesbt_k@9CK z2>E_-=)3Bm|F1dpkCEe7hu#Ry{>`D!0{R{LLdNS3y%K?cIP}J7)1MB#6J+|!p}&E^ z8xDOT0&hC>oyhRFL*IhSKMwsGnl_v1ZE=~y^nU2?xlE^*vj>^}7!)**>GvZ0e5P-X zME@^f`Y1@ckm*ZtS;X`X=)8xRz7ObOrfW$02-DvNTFmr2p!`RfUW6W5!t}?{X-k<- zC%u=UG{h}udK$!jjOh)K1m_6#9=PHhq5cW3I7g_bkRZ4!$TV-ZGpO%^fH+8~KZlm# zAfZm5F>sJj{~cExB-AHBRX9kfS3!X|NT|Ps4!}7=eF>_=IYPY-rVE@S)Vtw|bAU9y1gM|7W5C{heb=uj&IYK=W1>qc_-V|EEIYPY$!sp|<8r^_%g!+>x z59bK=Wz-N{|0KQQx*rO{IYRvzl>0~!Hxm(ogM@k=REUFw`d^5^K|(!1>c!Q8D-IIs z7tx~SxYDKx&JpSc1jRW*JpmfTIYPYzSDYi%b8*EvLY??1aE?&_8CHUGg!=n1Yn&t0 zhoT;wBh;57K8S;a`czbagM|8W6pVv}`a_T$2MP5YG9g?afy6jSsK-$}uFs&rxwy85 zs&S4`zZc;+N2t%EcwBcNKh6>Az0q|K;<}Zr4p%^E$ff^|u3La>0pxpomRcvc8wKG+ zp}r9+#EC+^KMKH!Lj6?;fD?uKMQ8*k3iY2cK5?Q@UkRhci9-D#;&Gx-FEcgc(m#eK zaiUOv11iUfLVZ2b;Y6W+5m%fj)W1a6;6$N*0}aB7LcKT2qZ5UC8YIMtLj5uHDNYpX zN00$03iUQfh!chSNeF}!h5BD;0ZtU^C5Xp~Lj4^SfD?uK0T>fb6zcTR7$*u*nuAUh z>ffVbI8mrCMY)25aiUOPh$~JM>N_9+P88~`am9&3-3b-rM4{db0^mfUz5!i4 z2iGa+bDSvDzXQgJLcJSx4Nes5(;yK}6zZQM15Om`bh3LPu7e>tP88}hQ6Nqf>Kje$ zb=2*G-gJ8JVM&lk{}Q=_`gq)8qJ;=dKZ(DJUV>`4PA9pY`d84U%YkET>8Qf(JcP7v zXD+ft1{;|7t?8bE`3_VTQPl%jrCY(Cn}d5_Ka|6sr^I+N^!;i>PTzy5iLJBZyl^Xo z{=BT-M#}aOieUBAP%CAtPvWIp37vTAMZ&f$gUXN6*r*G&8AgXPD6n=mMrQD}hY7K< z@0&7s9nmb!m^DXj*mwd3w5KcqM_eOZ@RCf3wL$vW!z5g9D#8)>s8KUVO<-ll54d!% zLJ(icw$o)XlEw@Hq|zPn>>^~rml`UD{^1?lp-gjDBUM5<44mbfGA+jg3Hvj`D4UB? zA2LSIRZ|liqw`ps9ArqTHie*Dl)x@Ijpyg884cfqIk93ZztbvBB5yrn3hRphDK&oM z%3QUuM-PlLyor-klMucN{|Dp$aTq{?sT?{a>QI(D61HNTvODNAnX=rOaHoq9iLWg8 zqVfaL#>5BJjAXO&`$LtRB}n8=Xkl!5Q0B?`4+^*E{Nuu4oJkuQ5l(YqQv)78$3H`H& zgJYDz`#b(}hcXH&c*kdv%SpEblwFaypcON}#@Jg&N%vU!y;l8upP(|+1?tE314|ms zHFD%Mhw|ZQ3QLc6k0&Yi?J`r|?%>Q_4*^_pQI|vz1J*PL_qw(Lapv_<;^8Dgv$n{= z70)b6?eyG6G2H8EVkCZ}J{tWVr8`O$;#A5C0G$Pm9p9*lY^8Dh8#PZk!3_13n#Z0o z+MH7J*)(JPDYZdzH)Oy!=jO188f0yXjI?0IVX>~e(%5_o`74c2PN~Vt_ssbIl$w=# z2j%E!wrshxZWAPC9nDr_B8z748TqHxbSqJpeo2I{yLYU0RHGqigddEppXYBWXW(m;yv`YDuOgq zITs?#nPX<4u6J65mJ28<#9~=UU?L)27Kp1^7l?Dmuq9M$ zy3>0AS9h4`5~IrD4iQ}jh4)=b9cH?GoKlCGE+?XVcY-V{&if|CCQ6v(Jxh6$Buw*G zQPC+9W_S-!-Y`Ap?UXl7#^#u(q}+|_vx7)QU!`a=b7!z4CM@vM`smJ-Z7TBqZ0z_) zO%6s-g?aL`Pl>mX5{2nBU!vGBo#ro8VVF+y9)e*yO^xac(`g0>hUqj@2!`o2=`5SO zCmXpKWhm)`z4WtS?q23o2M#cM>4TR$Os9E>)1AJU|LpR0cb`F3o^Oph%$MD(9H~9uaC-d3Ne=H;f~V-`ApxVkqY&&lEn%E@ zGz#;akub^IhZ3KYFwHy5c#!#WG-`4;+q#vtx%7G)+crR0B8az}vOZLH(I%*c}{$17P&lOHjTb6*lWZ~O|nm|@Kkr6x6? zM;Vsl!6ms1@~gcHt&s09yp#W(9nszwsrML5K95==iiX+JTIJnsFRyy0)3@LGKc>%R zeY-l1E)l-@M*dST);Dq|yy&iOsQL~n=A3HaDMwUC*YQ;-u5L+q?J)*k!YS#~eqS%P z-)N%w%Gr9FVH+CjG~aaNe$8i2vq?sY?#nWgbU@6tNyZ95w%gcx1)us~@Z#H!&8?BjMICZnlb}nv^8K(yZ0Ld>-rkHYSO6Q2Yyu3UBmILf74|7bgzoX$17$W z`cbXV?ytUC*Y~x@J_jc#`OVB70)Do$!zh2fesXn5qHls0w*mHX0RQRV5n)|11y>p$ zH}>`G_ZO7wqWRMNw!Z>b(0}enpmQVc-I?9+*LgRxyRBK%jc#yTG{8?Il{++no<+Db z6Nx?61e$2vpX2M6_B(QV!?Rx|QhCF(-(QMxHpkbx=>wE1Jd-6749{fUsQ>G;;>PfK`EXDdHk5A$BP29Up{St#vc;6SHf)!2}V;E5MB?XEP%JC>4Y4y3yi&az7`#GNQ}XZPoUVTxP21k$ixVw zbei)`;&LQ$=Eoo)afZ=4-!~jj56|ZNTJ<}KAojF1XE+)RM;UC@TD+X%^{|2I1GCDC z^JY@B*=j=Lptpv*DX9thwB3$Ovn3{^bDx}=*+%pR@o(cHI9k?_j$jFuxQ zQIt%S)pCg)=Cpji+Ee5!W^AX?t(C7bY7C?lN%WB&FIVU4;4}Ku#->)j6vThh%9khO zN8017BU}5*Q>&Nv^L6=Oq`Bto^mw$0H?H;f6&e5RQ(~%%2l$FO`hUhC-#$F;bsUUI zD9Knp*!QEcY%nIA#Y220#_S=uJ4tsnL-3-NG1OOq?-P4`c>P*5)Tb%G6k8m^TLAEG zy=N#UnzWAif@N$4-R={^5L#mB!w|Z=6TRKBU3h?9VGN;=jGp+oY_KTbo0WwRN1Xha9Nd$J z9DEkuQ5C+=j{yDyKF2xv6?g*R!x8glBN;X{AI-+a>FI#YWn4bMyE*nEIlgFMUvpmr zn#J&Xk!up{{uYZ+uct9ec7KX_R1)ld4qQvH`zMUqy};Odk1sk%w1#eIBt)sZ5!0EZ z)LqmVw-%*t0_u{Kx(85_q}1Kk2)7oaZbQlzV$^L1@##lbLX5h^v{}oj>rH~ZwT!w! zwJnUuMyX4O&uo;sW6=Z~rS3YIZkSS6tp^EhjJj>(0K<&BZm7$~s7t3%ZH&4OSh6c6 zC`ofO)GPIY!<4$T9cH7{y#R}Lg(-F4rpy_P4nq+`&KW4e#;6-hLWdc3PvPr?jZyb= z${S+T4VI{h4S~ayx_^@#VM^U>RAHmky$V~YrPS@EmcUQJ#;DtqV3<+2ieQ*gw;#bU zqwZjW{lb*GBdBA-l)5{q5jINQN3n{6Qa2uRS%^}XPOOI+b*E8zwT!x78?y(4D}I`B zV6Zc*gSjF8Z$4eajb*czPq!1SKg_55Ch89J>3)dc%OpPC?_g2?;?u3h!-3?}T@9-Y z@#!|wXoS@=)>z_e@o$W(1+Zl6?O8iBs%w^lii%&Na5|wD$7!E4o@b-a6S#mb6M0v3X%Zida*{cH&Q0ORkTR8L!4T4T1?sBDA4T)P zryGM7r1OdRE}FsrLDB|13Ib*F6G+;S??tvO{uc&8BYqeaWb+IZ-I&)v&>VgSAx(Hk z%r8y(dX$sP_h6Xj@kuBlpWlbxXvRNBcym4&1EqkkLm#x@*+Pd4p1IWF{!OMNLwaO!5{_mqZ z217w1K3)2T;NT0OZ^lzlFPQVtI?mJ3A}4a2T_tqwm1c_KNv4*B_D{MGnW{MGq949B|sG5n3id^GN3csrC6 z%U{QM3-Cku8^@PHeerxP)R(|Vqz9?9dZFkf{x^h3=I2mc3MU7~RGyBIG@g&Y_4unO zu0HP$?WXe$5GaG+gtax`&PLQ%=TSmKeg&0f@%GS6BVLZb*?c2H8uOEASPoxi_SNs` z^rn0-TA#~1Cd2;ncq2^x`TS8NYQ|eYpUwGnjDZ4PAFXe}Z$mXL`Bk*3kUxykSi}cH znXPz7q-o8EpzGW40(5j+UW!87@wI4Qdp;7@*@2%$N29OWqp|3#chL~^RT=CGe7Ys5 zmH2dhC>_;iVK5PZ6yqA$Rwy9R9spYAS*4nEz_pabyf{t5d4pY9bD z3O?N#=xgxlE`TwCPxlp=1Nd}jqD=7VE`s%dPgg-H;M1iIPw?sfiiQ%O?iy49KHXuE z27I~`VPfFZU51R{)7=J1!KZr>^@30L7xWDHbRB3V_;l+*U8fw}k9MAR@Hr6XjDw$s z$$?Kd3etm5_dVzje7Zv+8u)a7hWf#$I~>x3Pqz^51fTByAO;8cbPpj1_;iVj7<{@X zpic1Vo`k)CPd5rRflpV5XyDWB47tIln}zNLpKgDo1fOmsN&}y63NGN&rSn_h(_JY{ zKHXd(@aZms*x=KRfG)tNdkS^|KHYX%LD~oBt56#FbUUG;;M08+Il!ko1ebsCVHW*A zoAJ|VA^3Fnpm)Ki`v)2dKHZm~An@rXp-}MY22l$5bZ0|Q@aevU3;1-ug|UE7cQ6_V zKHUkh1n}uzM;!QcUm*`w@aeWdq2SXcGE4C35+?)rbhklK;L}Zp+~Cvw1A4|jIPZg` z*azpdgN}W0K8pmwwI>uY57%AjBy5B8i5M2dr+X9wX(6tMfUynEH$lV1r+WmdGWm4B zhGAnLoHxSUKzzE*F<%g$?)$hBpY9(hnD}%Tqcez4wmBR<^=n8b)r*Nbi^KHZ}jv)Bgbe?bszgY)Ichi&j6e;6&pJ~&^CEB3+pBG@kW z!MTD8=Hpt9Zdicp9Vn3abn8+}aQzMDjD2waIt&8);GB*!5ua`sgcG0cEL2E*y2;cK zT58_IEy4!IjK3yFhLVUX2s3o{w zMqgqdoR5SN5TEXSh$lW>dQrtTIDZL43fth^3Bj=q&UcUn;mRQ}w!t~0_*-x@31)|V zaQ+-r{UEMHPLF+X{uCv^wHgJ?#dQw)4*TGowwtjJUdyLjmT72(OJjrIdPpNKz5tpd zLfvCXhwX3P4-F$i-S!yOM5ya;LK<=L?l4XxA*BGkQs0*FxeF-#QL{^lDnfUy0|4@LZ&P*H*oknROszkp(hP`540AwpdZ z0-J=okD)7wQ1^BO5TR}+W*2OK^K0m0BGjFYj6|sWI0PX=-3cfF+uu9^#!ZB}iy;6J z>b?VGCPLkF82d!1`vH0e+uwWxMkuzwIXM+$`boK&VTfk825aA43Zm zpN27~a1UCA-ygxi2AMK6;pP`1o`*k+s=S=`pFpTv31g@w)O`R`GHAq6t-=EhDEEbW zn95)}03g);!<0@E>UKq84n6@wFitzl3iqNrK#&c2z;Y|7Lh_vRaB>m?q3&mps+Lf9 zMi%8J_W{O<;6UM5p+gYrP9~{Cgt{BiQQ$6n&TQ3GBv5z}jEM6bvm&b zUK^k8_$Gj1KHa9q>2b~mk@Qm`Av)dt=@y;tqY%|br<;%l7^c&$!ML)~>9!;orqf+Q z;)dyTw_`Bc=yYqGCY`RR!@K2$rb*jpT*+`gRGuQyW^L zUc)j67~;}(!K!OxZ&y#jPyj<*x^rN=fFUm3sa6FcF5MY0I>i2B3N=p6fW-m6Z^B9H zEmmwTm+q%lbcjp$RjX)f5hpHPqK!dr3$J4MO8e77Uuy70OmwxuAP@c4QbaA6?)~;` zVBX2aII2xg#5)*kz_nbu^f3>(A(Ucr>6ThjTGfIpG?q**%%xjb-DMR>tuncE`x4 zIE*|ymF{LT%P^JhMQU1@O4l4IA@1BP)f_1yn4?CeBXO8Y_XTQYm`eA9Mu1@|-ES}r z+NgBz%)-oIqtdM=orS4%dy@jz)Kcm8rGXcw(p`wD#73nXNhTbo(p~HZ3{&Y2BC*0$ zx)U%x+NpHuR}*Yhy5~sMVJcnvQ4brH?t56nZB)8Xl5WFPx_4o5uukrqtYEsJ#VAZeTq87 zMx}d``p!nB+aHeub}HQ- zWa~C6-TI_&8sC3WL0%4=ljix#Gv`bDhiaLfyh@DE;Zt zjY^kT5$sgD`6RcEN|%1$!A_;SoCd0mO1F>(jEze7HR>H3m2Nv4t9B~gwWM|%mF`U% z+cqj)I)7!S(tUxt!A7Na zMx}d%hPI7L*F%HDMx`4;0@rog(rRX-(w$7xjg3mTiWZ+R zm2SHF4cV@ZN_PmYJ~k@de=>}m$9*Zyo~9nOap~?Sld^H?j;D%kT)LmfTU@$sQlyPb zH=PETjZ3!`nW~LT_XnEiZCtv;Xsp?|bh}Z5ZCttq)R8tW-3Ur==hA(NY~9AC>!rbI zHb1pWaH9JA%SdMx~)mWHZI+}NMm*`-8_x}8<*~QvH=^HF8x@bol7^3Mv09}w>4oK zm+lqPsEtdPQ=i+obosY|k-kszJmjzC(*1$@FU+O;s&U^eXHu{a4b(7~?)#*& zFqiHd)Z#Fg?lF=-%%!`OY(C7T+mMDtm`nErjodJoZZg?(m`islS&xlNH;?)v%%!`7 zDh_k$Zl-B8%%%Gjb!3=J_g$C8rF#MD2y^K^NhOB4bf+2>zU)EC$DyKHE?rY4VJ_WQ zjSf%xlKPu3NMR~nvsqy(U9(wXDqZvA$9L*YD3_>o>Bu;!bS;>qn%_dgRJwhPq&d#v zteY`sj`Qm19kBmABFX)Qy48GbD2{v|(*RCLsKh@AlH4&32|86bDKkux>!ofAljIH~ zeS}GJ=>VWbl8d})Dm(@vvvYzU_z)VV$X$byZ4|jtWcy)?+^y6-VT#;sWM~5-Cz;Yz zsCQEAKnW+QakOmTX+o1C*L>5pQRMa`%d=DDnvZfeirj%D+89~DZl;=_Kx`Db=FDKD z$em2%#zv7FLj%u7kvo{o#YU0)10HOW?G(A@K(SHejy3Ad!>Sl`BA=Zhw;H2^7;>o_ z)cVx7pF}P;m4ICVQsJ2fe z8=F@95|l$eWB+R3kVq;SytpJ{A{%QIKI?0W0|6tSgQuTS^b~I zT)`SD9MpYhq6PYvzcok#J@;qsjDUFZ06I(*)_iU!G)OY z>Lev%fdZv0{nB0Lrx2)4uO?Q=34~-V_98Yg5@J|~Nd9*%nNLGvQ8Xr;In%1({{OFn zC1yzV{I$NUhtW$4sLD?UFV6a-jbLdtyDkzvTuH*MeUH6lby+{C+_rJ@cmzc zhw;XiN0ydWYajbg`TmCsr@nG&bJI17yfwAzZpVBp73MU~9EX3@3S+~UzH;T-Lq^kQ zmS!4hU-_mhHy$z$5!n5eFH3PgY^1CP&`$WAEXv|_7_fS&W?cUg9#qp;FHHj5!;llc zhD!9q#xA6E4QlCdOf!D!l^tc=KtkonFeCEWrJ3w+e(=!R7I8gC1rf{61*h|Ri zS!M>h@1`V*>-+!wSF|iDMS0F86A?s&4$o2)bLW$pzK1`q{6d5%S#(=q7A>58QKsin zqmqeMO>aX4Jlvn8MCrn-VDf^4y9G7x7Ssm^cMC>)ry1Ls$Z2|tLQ`aDhL<*p;ks@m z%JPmNm?mM4ce7Df5jiZ`=s*|M7^jG2{OtR~xCEzA(r(N!EAQi-L9n}ow|i$3>>=R* z??Qq-B^>M}e?EAXV-bPi!@Z`{d6^_v80GyB#a6JhXsMD8PtLixfmit;NDi;^_kes| zIlhj#-=TXtO}L91wS(A_$#-+3(UFVp`Z~(yq<8Gd7g3R_8&7l5!cT_=l>7+@hR%FX z7^k?XFLbC*DX4=$b)!+oDdJnLMs82zJ4^|kzU_o^EadeyBb2AeBIsbSC*MMvFWwmB z6p6(f5$P!i;;;4`RoE6k?TR{d_;R+To4VvSiZfIATbI1%m9|tkC2 zW02MR0=0{=gvQ1$m*~)$juNU#572DMA_w7;pd()GMZbK6kaiS8n@*mVbjz5a#=nMJ zqLp&|!yE}88^vys6iF_zo}zcnLB9}5&LPy|T zoa8n`6aJ5IKelKf?;&|aSR>X@6mTKrz z2SyoNW;D?F<^YIj?rqb6eP!e)2uw9tOjlWR(xe2Tv1P^_3Z9Oq=_sRKQf7v6m~ciK zyfQ5B&SiKGk1ERR`OoG$Rc4*o~tzrVUT zU5gqMd=NXKP#69=S;}zehkh{KnQMlaf3o&j_e#qFh=}Yu7?9^e$RMBJhVIwH8X511 zzY4z}56qm;DMm_u1B;~T1iBmJ4^E(8wZp~fIXc1ItR3x?z4uRz6 zh0zG~dSZvb%74Zr=qbYD?QlO3f!jylz%58_Zrp;9dkuYwmJvK#iu;AFFaR3dPYFLj zRo=`8>GmL2V{gNU>2}zyxXm$3+JvVHZ~kBkrTt@Xv%Bc_scyI}m_WD3v8H?5tfbpI zlwhb?LU&3qi*CW$lhOl`-B3_O@Q9h`i%g8I{K+siUsWac@qK>Q4Av^1@*+fIlnoP* zcnwqBTuM&2&? zoej~KgzaEDx-03u#Em|H-Pjjqo<8FFCV<@~yj}3VfITD}AXI`qB^)etg1taDMkNmy zD(SFH3O7nzK#_2>HXc}}MdS^`TI|~vIi(Bw$@ez3*55TBLGM@%clZaBT6S3NcKX{I zZ!XiSa1t+Kxkd-_nl0DrH=de}r?m#pneA}+znB8lxVw|;cKWNv0yXPvA{?qWg3Dp9 zfijF3)!84RS~>o>-|vJ}ZLU)ZZJ`F#Lvtw~fmt}nH=)nrcQu?w+3)CJtR5IpoZp1G z!RZI-UHlQu4sPBPo#f%u@txGm_u)Rm{3&gfBND!aQFw+CyrviS=<4uy(L<5^zj)O3 z^LH@zH2y0>bUqZK)#V0~M)4{58_o9=l5-(>RmAdR_#5C`ktUA+0F}k_PU+-a_*(-k z8N6W*`4;}!5A!zv5P4Jh2$Y#>`k1Bh6ezMD|9TLbRGZ>WRAjW47 zqrURN064GHi~6c1{^FOQgV2hb-^7sd@Egtz7|PNcp%fuYcr zN5Hn*abg&6&*}FGgoY#NOwDuz-5qZ_f4+MuJ=wmG% z1FW>@4&~gkjID*EcIUJ`QJOTB>5%e4;062m+gi_!L`VjgXj-b;f zn~tChpbI#HHb=AJ2>J^w9gd*i1QpW}bR8;$Bd7zjBpg9cB0n5KAHqBfN6?O_367vq zIi@4%8?b6Pf<}~@j-d0=A#enJ7fOI5=%={A5%es&8;+neU^lKWX0vth~K+E6= zdPs%+!4b4?U3lg({tk2kN6@D+8sG@}63hgSpeY5WBj{(yPmZ7;^o1C>#=)@35wt%h zFLDHB80PbE)mlIlTrZ<`as-7cOh?cog^&h#Ae2dtpoOg=53a%17-{4P`ZfkXIf5R6 zX2=nAI3`DO1pNXwM2?`-${-c4*I|U@2-*XdLXM!n`ds7vF)!g4{i?!sf``^Cqt3?zw3M>A@A`hvJX` z0UnqG`Fj>)_|3;P_AXKc3LHR+aPhgfkRn|CGia9lKP&5zB3%3**e&^g(kF28{~U=C zNB*Dh!sy8Va|g;J|Ifq;qzD%mumJM^>~c5hA?V`iPzX7I&P3Od1L#f^NDiPqFsqOQ zsMg(b0KM42bO7ZU&?NbP($Ng^|0FL*^8XwF(B;|dQ?$eM z|E%Y<{6ABn>F0(c;s7Lk9@qY`t#!C=gUVmPb;?-F0dyBuPI3T^_mKmri_?)X^8dW# zw){VHp(*nJe739Q|M_32nEXGlcCh?E+Zt=0(gMNxrIx#AGNu%A_l(6vMed$^p;&VF zbTvYc;JRQ6It14zG2_m|^={0dw_ zq8}U#xjlSl6DsNi`YOT^$ZJa3&#^U>{U=knA2F*b{7Y1bF-2nW8yJ~xM}WQzJGCq9 z8%jF^#)E|lJPe6bpK+dR6&85(pCf;)prCNcOGXB6|O7#|s=X`xCRrM^o1)YITaPuEf zp$BgPuvksgl*Py`#t8sjc^GBTtIyv-Or=^~iJf9)Kfovnz2fsafYD}7d~b1pcxpK` z7-yCkV~XQ@1?Cl}ZB#Cx^!U-k9om-K!lMTwcXe&q?a>Ntdu`drdH}v_G>n9TQ8-4)#1(|@DkqLN;TXIK>$1rNN(-OvsT~NGsM#3bq7P{BY zNth-U8J|C+o~tKJAaZG(87d4tKw;*6J{7h4>dDS7o}}XNU`MiDHf0&Sz_|^RZJvNAB6B4 zCS0R!cpVej!)8GH0{0ur16A83mXvq1Up+dE^eEE$?(IuOwidy?H4kZt_WDh#J70z(0-K}RxnZ1 z8<@N1nHew~8j-Yamt}nz4k={L9*Hp=W*B!qk0+^E5>u7Iu=*~!z&?p#^u!*f35j9! zO|Xz@btHz-FSrdjT4ETzIffHmkP~9=W@1Sz#3#ERHpRjqh{p1vrO>L4__Hi1zQ9AV zmg+LUU!-5aFr|sLsS9%s5?o@U7mbP*vVyBjoFT=ON_>rpW7MO4B)-nX#bn^265n9r z4=R6xi@F$!S40Eqrh8=kyr3dpjzqvh*BhpUixlxVRk+M`z|y=TrqjH!Qf64Dh_`&e zt0i8ch&M}t*GRll5iTT@i70fd{&K zVs_){Hxv<10t}b&v$@zqbIByPWg_#q*hh=ZA{oDkiwStt(3VQPn2VFNd_V1`i3&r9 ziY7Wkse=sUaJp}I>qcxz;z`K z9(M{l8=%F@fRj#fmPUD+#HXENNhNSYiO)L4LTX{Y#21|6G<8WUi7z?D)(YSf?|r6# zSDoTJnnikftuDCc6fT;Y`&#LP>DQg&De8g&vVa@dY3K<&Oyb!t(PAR-7>Vb(#I(V{ zlO1Gf=sZ=B?d$E zTD-<3I+59LlJV;x08Q1eOT6ACMh*jhTjEVFLB9d3?U8tkOMFJMfw|=ez!|Jk2fCeJFodln7-E~(r6rCl6b#MJV!S7i^K<9;@oY(f6Dwd zF0tHb`m&ZAyo=_u*a)lVPrHO(2%IeOS(k{v6F5WS3)qJxu^UT#$tB9jlA1|;)g>OM zrN32#)r@N{;i1{0ql~}q5~Pp63<;87KTU?}xWLt#w)V$p-UL&L1DdTs$g@gL^L#d3t zZtE%gkW9bdE%r4-{4trn#%(>7pOE;dTMVUP|E)}a+->B%qUrfxbU@%$S?C3~s7ICl zF7YL|cs>&N?}&^H8v9q>;vQqdD^Or@B7zfC^GiVb4YzoOCe3=P`JSIX+app*?^&w( z;+{UwBc7oVovWHJ=jn?);;(wZEmiYvJAJW7#8I_9R5~0xo@7e2hg5pV6y51D zdYLMBr9`Q*|5Yuiv@w~|<7Q60VT&WQvaV2{hCuX|8BgQkKPsIB0EM17LGTF~8ze-EKAM_^hu*U4`ABE?%>MZGa$I`!&m6p=g*zoI}4 zhK{5KEl{t%{h$opo=l-`FVw~xK1jEp8ckl;8iSR%-|Jc)8)-cJx`v+@Gq%32wP1UU z^Az`}5w%S#XjFwKlzDtdc0+6hok~UlJG-0WI{eu^fOb&??K*yMOxmWUuqtEeHZ9OK z?-s-z_F}X`WB#YpfIe$vBB#F?BJ(3OlA#*^pB|v2783s9oq;~LkmfHjE^pHs^?f-W zfnU;8f|o@9-RN!p^=l@|sC(D=Vfdir%BQ$2|AUnBzX22F_$Omr^0OAo^KT;|zH4U2 z75L{FW8cskrA~$Y@*j%Kz;XWXVJiF*A)Y>u`M-`dUVlT&PJNeZylMrXW&SKoFZ?G9 z-eCSZ#*H_$oZw$n*{@dUNyVSh9q=~`UQ_(^G{vu5a54AO(;WZ9g6p`S9_IL;7Tm%8 z^eD&wvfxqfrzbgn!-AK%pH?J((}MGy{<<)8{?Bydr8l*>;IOd(acq{^0<8CKFv;)? ziLv^XVTAI$P`pdL2RrA@*a|Z}rrR^rwD#;{6JvV47t1a0ATegTjbs2F*;i&fW}`bW zEAUPs?Cm7FV7cR+LjgEGgC`bV62hvuPBwE3yJ{8S6FxjI@E**88J4H7@riE6>}oA_ zD7gajG8w$rC&p8o@jEhRvKpUwt0Qn_2-gv-F^YNb5cZ4GPQZOaSQm6ui{B>2sEHES z(+svpEnB^Xi5laXUkoaVbNF?zGvT-mro_;z;{6Wed#BMdypN$dp)9-vJ zD<(Cj&x;kYy>T;)Ei~g7#fmwYO!;t$7srZaB-d#6ni;<=HYi#TN5B{vup(AGgEv7w zmVIF+SQ#tcrTB5o(;S!dRk5O`Gj1lZCMI4JD?FIZ_(ayn#Oq?k6jID&Hp#^6W5sO& z;3*PsiWMD5(rIj=8NVeMD`ru^Ju<;&xKu zJVw8r#?z0+ii$GaEMU)>_;{>XiTQ;uWbd2!WUT1c6Zj!^(Zr`?MXGW2Ev%av)H6$1 ze@uLM=Z_UH4aAMX?l5o_--9k}2a= zw!zGQDHss#v3l^I*av37)qtQAQ2bZ+gNd&NL=oB4b>^X=l72lP>X3&1WOYn@BOpfg z1-{81F!ACz@g&U^T(KIoEKb}<*r`|ouZR=R(_G<_IJh!SR8fFi2CRw`^iz=BBk`Iz zu`LeREAhHG@$0R?5fZPD6C3LRs}gUD6HUl;e2TQyIPv)1z(V3}abg3F$~uZ^>%sKx zapEp&aikTHz9UY2NeTQC?~W5sP`oDb-Z*h5jZR(S{c(a=ba-8f55$R&V}WCp2ThIC zpg|;XK;mWb;<*5Dg7P@x@$yjq={lpYl{=a?DoJ-LpVvqQJ3V0aEeHz!PzW?)5O9G;N}WuPY()QTwg>O+D^0SfH35m*fV*&TCbioHCmmW80g>QjjAC+h2an>Dr_ee)n{(&I$O-uY|n3Mob zB>ZE#gpp=e7S-I!80~OV4N(OzpfYzm41nn5B-9m4w=D8+4AHol^nO(PNN6G^V`c-Z z_VZ{>Oalvf{o^qA#AE_>L+zTwP5ELP)RWlXLV)t_R-@6!^4vvLvG%nHo#FTkoF)7&a0%fAb& zWlVt;m*daDj1tqrLV14rXd2VfLIr;ML>g0Qp(4Kv8j2~hP+R}xN+8)e#SS+$A*S_k zv?gVZ%hAxWiN$o-g-O-_;RHk!(=Bz#Ef`EO9j!8){)ddONZ2>0BCzCRGfA}nWG2up zq&50H?B9c>C#H)9S1|uV627YiS26#YDS+K9xQ_XoP6F(1!A;EHcNAccuTU^g-^Tn~ zivfF5G&<5xGylCqfJ?tOQ{#E6n&c?6;9|w!oysb=;5Nm7#@Mi5 zOKw+)%rR9~kt?~s01qB9eZDYjSjGLjy?}kKca}BWe{eM5tyW?@Ud=T4N7{g3EGEdT z*rX@gLRmB#Vv{YCbeQ%Zn-Wsi#ioc$wUF1}4%1$28gvV_3jgPBpn8_oYyKg4Oo^>; zrHuC9j|nw4-9mBxj_AbL3=1Xs%Lif~IJQA^bGW2|1|G7+X8IsX$_bQxp;6$2s~F7w ze5`JP4_l-2s1s>FB(UEq!|A8(kP!0vX*VSBkrgNWXVBun#}?B3w1E@r>jK6e8h za0g*W*n;ujiiIa|(27j*f71l$kcHCxh5dmJTPVZ-BWyJAnT4|a=Lj9KP>%nLe4x** z_nSQbKka~yS#bsaofuw$FDz8#r=82d@rP+29B){D`a~7@(uyqh(~d{rD+`tQ>BD^B zgoV2K>9c&`q=kC<>7#t$YYSEQ>63oo8w>UE(+B^+DGS~1r_XYM(-s;~chXQt;4IBp zK_z{#zcFd%ycIXyzjY|k1q)GuMMAW_;(vlv`n?75GSDCD3;bZgMa=I=1H5EG z44wld-DT?w!!qWdM6p+_*pTxY`x(sDWr1u-`A*Vzvy#vW;ee^PN8qt_YU>};vRz-`CFd_qqtYb^6cYU;&-w`;89W&!MMT>q|zXHjOzNGQ= z?a`tm7M?(gd~!M+E!yBUxE7y{78fu*1yUI;jd-$(4vHQb2uPCwm!icK%zc4+5?_rL zJE(W-Gnzek`n705XI}#85|f`khIJr=xo@ZV8_}W?k^~wsVdB{_V&+6(%aa*1Z;W_? z#tVK#!z^!E?-=n~IszI=iC4s!JK}+CnP6p%Am+?Kj>M~CgcENGfhH2Ki4k*?fSXFZ zE=CM7?mYy>4kaVam%&?*tSN9aiMPdw9bm@2U!77%DH3#f?^Q!w)f+DLp9ikSr5 zR${!4(GneKCox{f*66_PCC2Mmp>fxzT54r)GSiMS_)?7cZ~$;8^VhiWX)Q*y!n1#% zvy8`EnjqXoV!Wlr)1=TddlFvMS>RMKre~+7l~`6zEXB;6gB@q zk@%$;xJ=@jBJmW>O63wCEfU2efh#0FUL*$KDJM`V@k!(-yRVY?bWvS#H|e)GOET@| zY>~LrSXiUwvN1+AE<QFi1A)qWZh1n!l^9q3^0P6uX6T+=~BVwn%jlK5x`F^|Lx;o}{| zLdqYM@h3Zo9BR&NiBESh{Xhb9n6)``wu49^<6OaBGv&I_At=UCcl<{N%q|vvsMnv6 z)5^+XQ9!fVN@<?XAEX zDd75GiMhWOSStfIm5AwgAj5MKZz&Nk(Wrf1;%z13(lp?85^paNrPQG>NX_mj5!qva zUzB)viMV4h@JkZ!g|iJN#K3xqgZoQF2Qt_VGT=aom{J#bqr^2OVqYroD~z@@@akP6 z?!!Y-U<>=%#Mes1hcqv3mH2vzh$V}8okjMe^fyXGVNc*~63@Ox#L?>U28*WnVEVjU z#Dmo0YStR#6VHXWh+bsj+a=!KMZ^{Xza{aGuA=oo;I}2--A%Nj7VeY+?Cmc8p$Tjk z+vlM2_IDS(X(oS{WtalhbT>T*0(;Ce8F(Q(+Fb~eXfLzY<>TGOIqK67BtG5UbUg@s zC{=!;yXZ0&@%tpc)Lq;*4tPIvU_!@C(%tlk2z(;rSCyI`5rG2|uPGHX0!V+5u(9i? z7Hhgj1U{AVn@WYZ4DmG*Zz&aR=;`aQ#M??uSBb!95^paxT_plXB;HXf#*#@Km3Vil zSV!`GA@SZ)@jfZ+xa{Hmr9p8I%~9XV1P4lm3!^{qUx{l<#b%nL&N6yKgu+V2r3B#b zWc=AuQHLHc&PjZs)O39aoR|1gDSpxf@fR6AQ$s4%_60a{47iq2hMdD3mf;R@fCh?Xs5l88Nm3Uj3crz0C zH;IGW%fzok5b(PU*ik0%n|pZTk$88R*oS35@R!7U%S0?aGTo4Pf0^l`6u2qz0hHGq z@qbGbswopsjR*cGWMXCF43+0l=!-iB!Ra!w4AvQ7RzUiGZ}q2-Z@VO%bB4cKzY#6nsw-k?{TXemHV zx%j6eaE!!9%kiAp;5gRjN=ggK5C=5}z#>(X?VDNPMAObfv+ODDkCoahPmB zN#d*JA_db_AX(yT<>CUZ*C`TTFBjGAfKw&DQC=nXk@2U=fY}w|P&{xwiRV>_)%4s~ zU*bg-;z@egPM3Ibg`l6O3}i^WtU}B-V!ov34jSYQW$@k#aiknLOXB?%;&C#FMiL*W z5MNV&WJ_FAAsW*gLSu=KR)_|TfO8~1ULp3~9 zA#PR}AAYH&)N4Y|cLfRt5DoSULBH}EXerZOs}Kha*H>C<$5NVP+bP!b`s_;aE!E#% zCR0;W~ib|1fj6gA!2We*LBC~C&6fcmryGpzb7|T?ko5b5I zMI$P; zJ7XkXUuAlz2F6OfsYRp~w^RkiX{vC%4A@pBhy^k*LE`OI;uadK6D8hJB|6co z>?DbISBXiqKunf+ZtrA)ESoeU$7plbbJ%MLSe5p!^dw}Ok4PUJi z>u&*mP{s$ZRf&x>EzDDdmZX+r zD^W|eXoK39(kg1HRBdgoRjpd1)lF6Z-{(2^PG(eFzrOGL&*yV_zUMsW+0K6MGVdh^ z#L^6xYT%v80Xt|IdCkCklLM|1{{n?wr4A$q(8qTJ7a0tPk^`#b0A6h1qsakNhXOA( z@QLJrrZnCzH*jWh0KO@Kg{XngBnNDwaWCD#7m@=W((w9*rEmv|=*8rKZsg!<#yN2w zmmKhljJ#|s-MVLK+)55CSG5KB{4sRlP9I{e`@Dm6i_g}+Nbu>7>h;w^S7V5&YYA*g zdvq&3Mjn_?<7Qrxm7X3COg0`Kx6;GoW?nlhJv$zltj_g1S?SU7z+~geaqBQw zNrJ|c<5qfdJTTdKaNJ4{odzbKXVZpQ>A7)J=m;x4H6EBukLp=UjkeN5<0_Ay8Mo3i z<0iz>4m~n%LLBYT6XPaagAbmRm)~B&=7=5)H-4m}aB{GbQIt@J>+$$SPUv4sKKH7bK@L+8@1RZ!P~ z?I}R?B&~HN8Q*~dM9Ru_eGf?{6o%O~W4{A@Jt1^e>xdElg3_`OqG zVC6TdlT1;&y^X%spC~3Tt6?+4*ZMj6F?AFs66`a4t*P?WYql0Gsg(v!r}iAW17@|; z1LypV7Of6h=PtxhNDcNqnpftL5p?o@nY>FSHo9~1IyJmBh00pbmY0>kvK4W?OJ*;i zjkKjyl64P_2Mbk`YiIqCDtwWW)+ztMu0ymysajl$wO1JO7Aw@lI)VneC5p3;H6{pX zsX_y+$H<>$3JtM-ofjxwp%K=vUDWPQ@X9 zalo|-;tZ1>2@PDQAkHv99t!xTf~jb#WW#y|7wFdfWdPqI7|!kfV>0+{m5p{kwm#qn z1<~#&%YN7KP{b{Y-@7VxJ1#$4diE`glaHqvu zx&+|%>KK>k`DAMZErNC^c)(&EJrHnbJm(&=Shv&y+!bGj@llIa7r?ty7@n|LKdBA4 zN41_z$dYxxw(Zb&?0ERKEnU~s6G$hgA_gI1CcQ_VSSf0h z3;zZ&*Z279`jC#`pqU7W?2PCF4?wd-zwYw>E>Wzb78Ze)=-XdyPFA5viLQVoz3eMc zZIE*VO;QV=0a>iz=5r`0uZ0hR80N2n+W04f%4y*zF&e`uT_5S@-|gXm5fVT7;5%Db zna|M6n0ennGFP_$buidMa=KI>vXv+;e5_2oWsAt$D-JbwnP>Y5eAVQZEezjmdc&Rb zotblna^93bx^o_yIc07mr;luW+ZIuZr0K!_Tz#pS^$Z%?FtY&Y`cT>8wk@Q{UowWs z!?$f!OMB)|MfE&OXjooZ?2fIX9w8I%*op>olbWBG8v{2fgT5sv-obiyk6dxb7Fgpe zjQ9FydAUXC7cl*m>Q4APLK49eKJ$=Z(6{6*CBgr$tt4Enbk|n2v>&zF1S_@ih!JFA z6GboW@20h|cjTbEw%{OcYisH5TUl;vOll=h$(46)<;$F<*fhrzYx`2nCe+;Gw1eh0 z-JF+Z5q>i3uB}9w8Za3ju+sG$T}|e@dN%W2KH30tt$VgA!Q3Rec*yEv%9?Z!vT*-b z)Bk|1g>G4Yc*y$0ly&r;t)z?YZ|7{rM@K&TF%&4fp&_ME2ru?>;Wa-nTUl{>z3U zzr1g&k@p}bY_y$%=%wZM%3@izK+E+4vSyYo+8UXih3-&Oy0VP!;BISjbC#`wt3g<{ zh{2eWOmVxZ0T`mWG^Oz;2py#v7LuiU3?Cso zKCqQgZU(82#r?scQ{}=3wrZ+7nMu^|6s?78^4bGi)xRlT;d?VmL1vT&ey^ew^Uzi) zq}+Ja55#cr4w*r7 z$P^7b7Eq;7$U=G>A=~i7--hh(eYWe9<1;dE{l4Ee-cOgsvXbb1DSRccW zwqq=A`=hObe-|tWkfiIgW#u1jA|G!$~GL6&1I~RvZm|}hE zV^mTW8B;7<5jQVm?p8N%yg~^oIb$hjt6b*J(afBalv7IH zGjsIr#)K`yensb9oeb0as1DB^wy&Z&c>NU34XnSSId}sU&A}U}Xzs9s6wMuWu%aK( zcsE4RKM_4t(Z3Nr%-@ej8hos#vpoH)t-S6hfB)51!}1_WMn1BY1MK|B_M)C^$KFS_ zB;E3(Q|5bYD_f#Bt*UbIe0ASf(`paM#=$x8c^W_2_OUGizw7+QV_P}J9mL$$oF=!z zwSmEXhqy1xsNYR)b?>-JE|Xi~_Q2qt{5!ZmmM4C<1-0WT_g&qB={uJnxOobHmv4=i z29EaY4olzVzNRIG7rAO8a^CGzJ*99(;luq?_b}C$^vxY^#-* z2dgk?C~g}s5wd{6UH%VSh3Em;ZR_C{Jrg^MqJ{8DjC|NC4kM#TTR4}$k2F<2oXh9K zS_kFl{b4Jnza=;QVQQ<*+}&Zb;;zlyQ-Hz!%^$YLB{*P%IQc%7^h(Jf3k5U@21NTU zOccfRW(x<3pia!|VqW^ThT?TGZy#V4Y!@$7jbKk^@Cq`usJ2Nkf3}6gKLmkait9LX zb`M9<6AQ12N|ux1(x!`=md8=Du`bGq53!xlH&|$woe_i&8y%HXbaA0fEgGe1QQr)N z+5|jvQ9s!tHsDvqEBT1B^*qKR`sPqHcPTYC;j6gO9>W2?e;e(w7lJ3zd*pl{akES^ zc3M2j^ceNGda;=(D7X8HT4nN;GD@6(juPc^h*}sZy5$gM)%2pwJBCG_X)X<)WUj{u zO6GbDqGYa@GXdVt*rIvHQKP9Ptzfh(uf;X21in5s?s-MD@e?0J z2li4TGEjVVd3+iLt)a(wv-v42enOgR;mQnpO~$liKyJ}A`a9?)J2D`EzT?&jhb^-w zcnirynx~LF7#U3=0si8Q9wV>$3!@(^y^&?Si_8Hwiwp@6{<2;kaar#wiv@U>n-4QQ zRowyhD0j2gfS$_U^eXtc2>RkgoU^x^1g7T-{o8p((c;g;x#LM*5v%J}WQ^79BWg`k zt}1jH>l&Ib-F-wYN!)$Jgw#jYS;e9KRI-yJwit=ozNXM$a&z(KAeF^b8XkJ!6kNCd6ti z0te+6!QKA%OD;NCskWnN0g+FS{wzjCi=JEk0T;aj@X{-08&*!fgf!K#RERQw(Xg%+ z5=G_2f}%-uU=u?~O{|2Y@SQdMpFG1`NFvfbh0Fprg@hIod0ln7QXMB&$LG?JRi~SY z^jbi8IR%-tQ7=faj~h1U+^S~oOPuS53jm$Jpp+6$<=-R@7Eb6e5a#SDU9~6@q1&PQ z2-0p)!I|D3&@vQ14drRL}GC}wH=7ON=s4Ik_l&eL&aI7)AQGAj#YIVU)S5I zH-Js2ayp=?kC#)Wk(BLJBSLPcdJ@WZYAV5Oryg>y+l$uqDAx@~06J5>oO-1$vACUD z2ZXHM# z=P#zdtcnaKNk+dCYM|+#FbawT zYN+X_7)2368&}_RX#=Fapbw3N*lWIe7V2mo3XeqcvU!?Ti_N;mW?`_eC65&mRxE(O zC?XpwQ5*wg}(qrKU9syhj#neY)mJk{_ z+Jw6px^wT#twlwtHW3XG;l@5#?5!tDvsi9zB-Vc?8;>U36YBvZeg zXcfnCHDN$Bht-5G8&zxs^TwcToqi@t0n!|qeITkz4qZdV4Z`I@>MFMlRoI3fkfv;? z!Zws@Y}!!8+XfRFHV|}CqhuTG%$tm|WP?J(fiy=I=+&ch=yXT^3a;0X8lGmxA)0N- z8E@JU%{J5oR&j{-w!wsk4YEb3C@`QCxJhdr<{b~DIo4rB(49H-tI#+SEo>Q5-*jtr zvQ}$?sny9^YXB>)PH(LygjSguDgs>{!ATk$G2b{K4BcoWdQuL360{XY!&{2f@~@eG zCb7nRm~~aGlUQRUu+o_1tBPL2_=w%?yQLiLy=!JF< z{iP9;H;`(dZ^oe)+fcZfX+tlzp)Rnpp_jJ}CNyj?Aif+;?Y=kjc0*aRL7^!?nqx*D z*f2DQPOp0(#&A1POLF^z3#2&`^b{!k2G>@k?s6+lWu;}3Or@!;ls4o_X{xtU6B>@2kYk^w8X>*u zM>eE!$v1&CM>`8_Se8T2g8pe3Tn;0(?n2Y?Wo$zRV76MSA&+O+I6h9FR)U(&ReYs4Yej@ z*WYB;c_>O+6?zv)a|}e2*Ei?TW1#Uqu1}B}x5)H-a}F1c`Ekjn4V&49KETR`&E7Vc z(6GUTY{M32or|JmgF^2BX^xlj!G^tvKJ-t+pm!3f9~m~(r5v&$wv}naUbbNzU@GoW3fLpo<^Xd?LMxvNImY>c$ziFw=p%IW{rb^mB!QF z8ck@#*@PVD&vLY!1%(SymTdTpOKtJ9SLCpr_fkJ81FjpSF@JL%m`7qMJ5vK z`{iOANWgtySasGkf&AUfnn9yNM%(FEUJPA=|FPNrQTNEMVhBo(OBCXv2slZoo&@x zLT;-L5pr8~osioq3)ZCen-~$wQcrQ30j1~pJ*{jH45Mxrgq0n0>UJ;}M2i}LIlnE7d0QO~svG@03vtMm*Zn5obYgkYvZ`MUtY%#K{8Re|h% z&};HiTZfs7sV|b1nF`MUhM6nS(7>UGfw?4V{Y@m7SpJlmZBx9>Tmx*HnFTuAOlwyl zx0#g*xy@`w$Zh5TAbSv+a8YWIZZp>)+0)Dqfng^7?k1UO2Xh-l@+&0&@wAz*b@Mj! z3b1Krh3?Sej%ETOx0!tjxy_tG$Zh7EK=#FGO?bK0!^|s4_B8VeFwCqm5N3ACsi%PX zHX>Q9ho)_N-5t#?TP|ESiGUek-7jo7^bY{u9!ac7;n|oXC;mbV$*du)92z!Jtp0G#wIuXtepGzB$gm}KusKVuwc3`4s_?A-vzTv3y_Y$s( zIl&0`MZ!_p_%UHeHV#2wt=}LU*CiZp;%FS_Q$nJdfCfakV-dH4<-mx05=Ks{zYN5@ z;wVkqE9X@arE$u!y^65cz6mBidg?F;?QkD>%7cfGpH3i!1pMr$1lW=BHLl3PXz;7$ zgQ}uL3EsY&9mOwxK1MX?;_s!TZFFf(B4k&)r~zftE{f+IgpzNml2!kqq@yq9HZuF_ zXia->48A=t^Hmk4!=5U(uq<=g*5C=Vw67<|&yuaGim*bJ;Rh8yfPxFgVmOB4S7cUI zQ8MZ}Vmgd+^QxxQ6Kt|;$>Sk``H_iU1gp?cRE%XK8KMQ@QI>s$}AKRYfLO>u( zb-d9$jL;YSRmW3!9bxWx3hyG!9Z%uU33JC&_*cT*@e~do4$K`-;o5{BxM}MTjV8gO)Y`{q)8^#z{oZMSv0aKZ*0y?_sFJF(va^N z;LU_R0{kgqj{rX)>=9sr&fyv0aKhOEc4-Zfphh;OFneTExCa&Bkxk*Lgn49Bcnx75 z*%UrRm`65+zb4Eho5H>rRMf~u7$aLaCGg0m7#b4hkxk(qz=(Sbnwe0;Nr?FgTvO%d znmn>ys43c1$^a9OY$Y**#3pv6>hrU|2)<*uc!XPk9QtdrNp_49HPmQkb{{{@F%2Ui zDbP|iZ8)ySa&wd@{S;d~k3pmT)EGp4Kd=1dS< zHf}AAXcs4Fj`0WxJ)V_>B5fApXDKkIy|~eAU1PZO|Bf^@Zz^0AgOzGs>QOH>7+k7_ ze%lCH_M4E^5VBOi9mD;$12R;zQg|R?ZdM9UBFxQ7VHyxsvr_l~VeYpI-yzJ+O5p&E zUq-)G2^A@U`>n!Ffl;ehC`|A-1@=A0+H?StA8qpX_gAEO`Wra@8U9kgHQo2E+kGIR z6Ve)u)1)}?Qx{W;ZFWD2(HOcsP!*!Bz)Xy*lk8GQl&;C`){L()^^eJ(`W?rus@MS(d1)nn z%?8rezay{K6(!W<|2JiCw^C&%px$COr&Mys8)I}ln*3?*_B5dd7B@)H zQy?O86@Fw5)73~R>WY&8XHkz*l&Bbp*@~+nM4e<&PY1%wDhvmXvb9vv11Q$&4LsI> zqTv}F2-W$s17VcS?)-Z@qAZ>}O+mSVt2J#W%D$Olc7`B-+QC$uWOfFH6M$9cS5M5U z&VSG$A`|-{OLG*VaT7v^K;ZkB5f>n}{AO>VVUxXuP6d9Z&_LO-o+y^M6Zsf0%PYwT zAT{`H^k1ZIdP?#P%*U$lDs%S(|ApksB>5upHOF>~k{kx9>o6KTMyh42x6LzO_Lh7Q z_|K9P>SGkVgDhv351!a=5XORO161GRaa(OF=0M&~s7G;q(o$V&G*CDU`D!#!IEFBf z1`4N8c^(bS^1n<}qXFS$%qLWUhXchhp9=73U>2C|Qlo*wTZx}X1BE{$%%g$AKggsQ zQMg@!Y4|;*_q^khjky`&5;X*LB)qPw8;>KLm~G%P!W+7|^Y;Lwd3~85DR_5e z2%41GjweKr?7PhjV=(u#-ZM&>aZ?G?W|(nPucN4r78-|+wi;QO%BXEYY8WKe*o}jE zq`nARop&f9oo0Fq9Sf`)t*6jc5b9csEW5S?&!s_@YPjmTf7Ngmy$ejL;VSHtHp6JR z3V)7#)o>O5l`uD4g@b1SbHi1bKES6Mu1h7*D;TQbDm)NaHC%;#(#(dd@EqdjhO6)< z!rX8bJ_(FiO$k-8ih*y#4&cWKk$e@tX2+_Lrj30S3EYx{xg}>1=9a92nS1ur!82O2 z8B1!(!41)ptAo>CcAuuDK$mLG${f|272Og{sx>P-3|O^hg?-Y{skt>P{2K9dYgTv* zVQ$R|e?*vDvk}V&l;H7_h?oP+tyvYQN|;--!Yv4MYgTwDVQ$R|rvW3D>D1wh`0JD4 z+v~VCBf0-h&3N9S2wJmT9+JNhw&eqy!XADJ*^%#Jrtz7Jpv*ymWw_!lA*CEr@Ykf9 zJm3^H%J2kSgdgR`sGvEvHHM<1{`vv%e~YU%*z4}nWQi3b4ALEqAbm2@B7cIc%_RLK zxNhKz3-5$`Cx-MoGOdxQq4vr}v!!3cFsX<5>$ZbQ zBZ(LJ8$sBMfoT>lUfk2;2l#X33szE6kx};p{E8gXdnhSt7awA3RL2(~{@KSD73#^| zFNjFB;&=0Dj@WuiW(wrx{Sd!9Dy@ypC6Sx$PvRW4TNw_a$ml~@*20wc_pn21Nt9i- zc@<`Te-CW~4o!^D-<|O(VBfSe6IaI1m-`xvsG#v_2*5ip;%DAo!_Zs{Lv!3spj#3@ zZXZ%Oe1K9o3CdpoNYh%*$D!+9R;W%={zBnYSA2fyiWjwlW}^hl4_W~EeN6e6<*9fP zn6nYq=rQ~LtpoKEL{yEV5WxysErNo@rh=MSkyGt;GDCI*>y)GTO+%#T+s_)+QO;j^ z@KneaAY{C{%C6q{K{B8TEC^d{Sg;XChf=3_o*<^o##B3%-B_ z_R&iX3w)Qs0{WBySK>E76ob+ulm&KZ-*#Nnn#`FuVdmx;trt(GUO8MR1N_i3#&&BmbUV?IT z{{GGJY-jQ2qF^CABYzd4?+W46$0Pggr{6U=6CXQJlVYQ%RE ziuXE&n{{$eb5l!b)IS!_Fgn=~6ixaRKeq`BHhl0LoeWJ>j!qO|Vo(bEV2(RD#e6Ff z!71^E5u8mRoJY;z%v)^)r@Rpy=&bsgru{5!N#+UZ-}H*VQu#^}RE}9=sLZhzDt|Fm zehY*@M~OaA8S1acK-~#kiSiy)BG83e2z$u5btpU)@lhm76~~l>5(7TRuP7t^)sJLSD^WrX_r<-3`{EwM{ewaB zT1ycb!PA_ZPjl$Kl+0Afb9{j}(%-^OR+*M8N~$wkH!DWv0m+#9TF5!cqO=;*vom>2 zFYfO>rWg139Miu}MkRa(@jN7Ud7FAj$E;C}aDU~JF~FPga}V&@6^a2qv<)m6m0?)m zvl$lLG%dIRgg=L+uHiGZx4wo4R=40cu>Wfo+#w52K_o}L<5pNuHkVPOj`x%WH#;i} zQlS0DS9oaz>3fg;w_>onE!tEWY-ZSktstCzObZrbH$pKe*-}}M1??lh#xHZr679@U z{y(aK8SS9lg>^hD&$AQC*PF`k0+I4!LMfjF#rtu!miM6?qsqYcqG<3&jL-*-MsfhT zYj0o;vrE(3$%E~AkO!AB$a_>h5Ar6aLH>ym;|vsE^bOqx+t=PyVhr*o`$m^KN-{AO zKaikoOh?g4H?azU1)ENC6{(ff-$Y4{?O+b_rbtpDH*`SL7>)f7$Ho^+JLgq1Hs1hI zZ00sHVgsFBZ(;7=i{b2(|4i@9j;NDN2x7gR_Cc@B&uEhM_A9;DLZLSd8)E3Zg=?M6 z>d4^=>?Ep{ISsBz9T9!P?2fP+iaQIOM{eUZ>3vLtr!@KLUET+zbrOvWwnbX(t0?1} zmN|B1qzlwMdAE}YjKACirORT_LCM{B@w3t3tdWVG9X}ROmN(zg2h5$G!b5=7Ho2@Z zp3`mmW-p4Gfpd|iIb1ymc`IR-$%bbY!y#?1ziz*eE{-cj zegJ9hc&3?avZ)=zyliO>`UHud;jd?*NY*1fXZrzeoS(+n%$wc}4h-4~z4cnPLO-}A2inv;Rgw!E+P2a((vl)VE zC&McYt7-Z!hQp5#b9KC2#?bmPNyJ+ZjIIMUB)i1}oL54be$qd3A@Gf3h&eqzUhFss zdJ=sC2#$4VRCVy3g`e>8dpyE@2|4F5?<+sgdi!~n_0YQwi)D)x5#kzk!u0b3`?>NY z{0z%&`1vKX??+nc9&kayI$bFQioWxS;rm7AtbB?faxXDF%n$`HGaT|M<-+$X46DFM z7dd~G;p>3x{Jr0>GlB*B_saRyGlui0i6G~zoi&`_Nb8(O{<@Y^*Pi6nwbzi*4qVFj zN8Y|aVm0u+4&EvFjX|z9=U@`vDNt}67AbW`yWw?$W5$}ftuNvTgT9ueKlcBs9c?bN zCTLOPyC9)Z9)3+#%cpCLt-7{N9_%U#sTY|G<)MS-a#!%C1HbmHa56AnFZsEv2=6ih zG(CP3m}eH;dL2lM>W6>ys!D1)Bu>G1zV;%gGaRfnlCsW&1I@QKzgu0El~lcIDp9y2 zFqDk#Cc>@LK$DW{tYod+)J+6O9Y*2Mg>A)-rJL*fp6rZp8g#js*0S2laQ zvYD0mV%}9s6s`=6N-WnCmDmF`DcQjua~DV%af~Guy-7xtN`euWlo2)< zpjFVdCNj8}C|>AyFw`54QRWi!m-!BwZpmi7MA??*qEYG!i|vHu`gX!s8LtPXf#4dW zJA}~j6^gk-Di_c!_Ont+>blx-$s?rlIv7~x&#dxiK&bo;DqXDdR~DKFbE8uEh;cVy z9(x$AB}8Klqt7u-YEeH0K&1#!@4Q3Zeq6sIXWbX5-(fv*A65j=Z3vpTCNyGR1%0E( zwPxs2*f088ZN@aDpu#f1UeAoC28$(Kcp zz9lu9;|-GWdVoFztPgPI#{}C6CZ2Yicu3anFN(U@!qeUsnvgC0j4dqn zqq6V}TiBivEL3m>pz{D)b2<90ApMH~x|7!MC`=p;n=T*&X_2>qe+DNzQRpY-M5vYk z3V%@v#P+r7g<)_*;_4?K^cVFaE`x=Fb%RX_{h7ROK=X?wubvLJmNj&&Pg@NTEnMx3 zbFvC}!RQ8kJYW#X@X1U4@eE|t8K&vJjD8^0+e8(90YW=adEE)2jVLq~NQ=6Gg@Rs1 zeJ?Eqy3fVx+FInS{Yr)p6qT_NOdcr0a~AoPmM(I_KvAUhGSG>?z{NpVl{^P)K7wS@ zrO-{eZ=eXY6nZ4j4HWo-=p&UG$E>Yo`$6~&Kp(kmkZ96zrjZxVc{_o$M0&641XciK zZUU!&Yj7#l7E3%WF$tp`trLi=i82D|WQ0OdGIp>Ctnub!mDrS73j9t*C*{QeOmjbq zHs|zlNT;F-eJSUlsI|@$m6*sZOXb$VqH6gkMq&$2?D_}fX;D@CBaq!yAg>~bJKA8; zCG!mt;kGwAaF!Y({4mbPAvNdED2I>^7=j(ZaZT3}HGw;nST&GI!&vmsNG6jMYNn$@ zCHmz@Z!x%rGS^I`6PH4tGuKUUy=8C>XRg{7#ih`4AT9Ai0o)e_S1_p@!EBn3VpFJ% z3>}Inq#B7MndPx;I8>Byb@C+u~&{g>aMt4lgr4lDH z%T^$iEs8nE&@hS9OW_GKDymRRAT2Q{1n)V};t4)YVXkckmqM52kYOUQU$NY(=*!F! z52PjTEQV)AjH1&xeS^WJkdCbePGLfo@Ttr(6lr9FLfG}9ImP^l5#|7zkiD(0;d4I2 zM05QM88cis+ePKUTec^=;G`Xd78N}Jjq8zWcNt)wj<4*!gq$cWYHD?-tn-lPo|+!< z=MQQB#*b5(kXq%X;aGiKfdl&EyfpadO4D+d+UZ=Wwk*Hro!XwZESVGH+r9{%CwbM8 zdAck9MZ$j=`07L&nzVd0G-2(d)o<7sxeC|CtX5~(OM^^24Y+<0r#t`MfG$X&pEx%P zl);v)ekdx+%-j)j$V;MNNT!YICu$5cO7LMs&^ z4}TFGNSXeUC{&zh>PD>39cL3#oX@-@$`;}{H_qoBXDLRCAXkQf(Hyk|j^a1KDrySn z#>A?krf_w_95jUw66PQ&oTmUV2dN1MsRLmSQd2h4MVN!sjIdohhypATN&PrKuK15+F~Zl7*E#g_;9tQ9Y>n z%~vL8rs!IOo>&CRUq)dO{uLN_5k8+ah(Kt(B`c0LRV-i?HIPgy7Bc!YNU2b$CpKnU zl;2RO*rHSWlz1YesYJ-csP-qAts8HxVAT8<bZC||d#YP90BjzjqdGW3leQyN7-V#(MA)MvGa^UcCgpj9poO&D{I zaBedoEowjQgH9?YqoO+JJjs4727`K{Md4Gx@bmMrqG)MW zc#<_-XAJ`5g8qpSE=b=yNY`q}BI86@;jUq(oKKWoV8}@tXUh46L{S6WCN#6kI0njT7hc_>{z0CNNnPE-6oq z7f!vVEHpt>EA(0$X#GrSwL@cxVY(JCJ57Mr-%vzF;WO4+rj)7mGf%B1FtjR|EO$*1 z?flcv+r zLz!AfWM0mvrywI8R}xa+!tO|IAdwNN+C4w_csZYB=v$j769qTQFDHqRz~d}#*b5MM zBcD#9zQl!Rawdzw;#~TMSz7HzP3VVBW5da~v(&jP40=J|5C;*r^XXT~nwNBK0+PSS zhD&t`WWa<6NUP04Z?jN*q7i#sxnZ&h&RK=%40#M9t<6ExY;lJ}HAemcW6Hmd#L~lY znEQP``ZjW%QRt*UFnNU7M}hw#!v`{EiYRO;T3)uBBANzvDNg|_k_+bH%jKys?Mqw} z<(?_Ru75A@Oc51=a#kRo1=YY4VAZc8-#Jp(A}Yu#FN-Sr64~WtQ6X>>GcBR@M37Za z0>f*#PRLa+ixQTy73HCqMft$G6-m;i=3pvm)ziW75LZW;V=5kX+9AtKg`nfiGl{fS z#-d=9uGPeKOZJ^A>Q<>-3Cpw~;PSZeyog@iO75byy`6vpwXHhA7-YI|HIrvh$hr-M zXwa%_rD^dyS$vu(WGPr#)|@7q=4w|NCWS}JnbSmabN&!@YyS9jIsOoJ8%6VnsM{(! zq8Svmv(lIK%YA@urMI`nSBG53_#OZ~t@;6IJ~a-O%ktAjCyTX;oH1R*7fGrDgJxj6 zhcUI;0{%ZBE*<|5mba&i3aytQKT=Dq) z!6q#-0Q~iFz{3T*5J3f9L{Pz%vi~chSeu6?M?oBkFh?X2#L)_b61@tdGe~r2>s(Xx zTf{~-eQXx|&McU_n!Nmq2x;B9n!z%W2-3cS2$H=Ygpz#;vagct6sz`|VRnJ)M#1Vt zP{Cv(sNis!I71X`an$6vX>#~Q8XRRoXbmYM!HBf26hwEkax^9o3z_^n5hQk>S?H47 zH$xOJP@)Dhs)Hkei1Hx%$otS&V7i&H+swEpi_b&`euq+(XhH;)aLGhu6kKm+Tr@Lm zQF78ue2%Dglu=|L5maQAe3xV$Gc%r;8P((!%IH|jC^3%+D)FJT&Jw{D?wA>2wT+Bc zAZS#{(+_@6vFe$KLBa7DRb=ukQP24~vTG(lz)hs*K)OE78rcc>7i8GY#JE04DIHCc zAgXF>h?-&5!@wRgLD!Pyxmlt{&0{?|nfi@!FgcSu(GirRF-W1`31R=Ekfht9CS4EMcdnx}rZ_tat)g{x?OW{s z>y5;?w#Z6{rSp(fZzPV76*-ppfiL0YO=0?6(y*Rb>b$|( z!;r06!rRL2v&D41uXM~2uM`Py07GtK_?)0?ttVr21k-YyA4H#!m*?R0CTD&5^Bhqw zxmtY$V=Am`LBu=|Ly1@lVk!}9L98Ys1H=bJ>;Z9>h{GUm67eaBTrnUnf+!s$htCyd z!kv_mN7J<)L=*<`GKgj+Kv>e6##O}si{$>f*c5F;dR#l;Gen?XwQoV-&yi3OPCT^g zDR5vru183}PENEc$QkCzEPt8zAqRuDW&Gi`hgSOTEI&@0SQgyBVx)wK!c#Di$6`Ro zDTxwO;a97doL{}={OXp|z=dB^1DFpUyNEPKn^2DKcznp^E3xxdx$QTS6ac?4Jj(m_RN|pT-8L_^myxiXM za(l?Dn+vwJ~A3QWab z(Y1Eq>7K*%tf05Df*#5`zb4ANrh+@NBP6aSWyc^RFJ#2IkaC2S&Gc4g8xCbYHa!eX zBXRuzp10k~e7u$UWGidO#oUc{7A=dPSoKLR$T)|qxD&T0+;X0HH`*uOjrNJV(K>!W zFVI(5^s5jNJOekzAf{DL3^3eFR`3^?=OHb6Da~ptEctcnHTb?^cZPT+clvx0Qhyg% zG)EpfZ&_f`!yu>&t_w)r;TE=lg@rUSg)PVyCa=vG;em~ir8yq9fRH%>dI|(A!qroT zED%A_W5bb*W21B=ox$}wm~-cXEH-pnfQk&tH=v${6Vt0;+A|AVO*v=**2iJAP-@1f zHe^44^3H^Q_z=*V1){X8+Y2}lnNB;%ME)!??OQUT>ciRS#`5Sw?0;@StJ<%f;eAV?c!cAYe6mm!jpSYH8D5jON3s^P1gF%Q zD0_IGu5CcdE4k5Z-$Y`q1Q1(643W(iVZ5CSoNyl4uf;X|>%57IZ}BszIG+Ld)EaW* ztROxhq9};3Kr|}@f?h$1s}91_1X=Y#lq8}Fh&UqX7iGH<(H+DTA_jwa0|aVq!C<)g zHl9ZEgMH3a_$lu!5~brfN^cvFU-+qq$v604hVedW3tU<*YLEAT{OE>cTg~wv$yw#E zCqaZWP1h)AUI>buB~c{`-OSrwcPnj zJpFls=5pU+Y=XW7M`SBh$_vflXAt^E++3gwiQcmb0{Enc8&G0iap1jq+V zgdr~b)yMg=-x5(>A1hZZ5e`u$NEJ*+p)aJ4$ItF8;itC>EEUxnR7-@;x_xl>6NLRJ zcus>SZZcA)BPC$~2)`C1@h|=yv1OF3tKccJ0b@?bUGtH& z-3F6pV6k1iErs5{7r`x-=K zI}lkQW)txkL>3W#FfzP7h=L$y5D^CADu@bk6+t!ZfTUU=)`LJ}8clNo-gvUVrE9xz z1$5N4ZbHUx5+zg%C~9^l)dGt8cN5eC8lwfItPoMbjZh%6Bh@(w=cEYOxezF{lgwBl zO4gs=2_r>*uq^GNY589Su?|F6BDR2dA4Kea5L7eg_I2|s1C&fxE1S)lg z(eyc{X++pT>>;8qi2Fn|29ewaL@N-l5Rn4nHWBm<_QVu&HT*Wsv-o_x&pWWE6hDh; z{Nex~2&s?GKkJv(^3zQ6=bu)qS-7AB67fX;fp>AZv02x)LQ&I#QvXbpP!G|DdIv9* zgXfdBo?b_)a!7>PcytW)?^KXt+6m9l&P*54!8N)XF--;G%#1K%TA-V}m@e9cjO&J8 zJs<f)m#sy4I;M zHzO5^XEq}v60hzwBT>{N5=Y+<(LrkHC{(36(Eh}a2YDG`T2d_qJf2uptu z7eRC(;wFf9WwW&+C}+R`T?-0k58&jSwIZ&}5+p^o>4td$=kAdSAkKqu-h?$x={s+} zahvgPb@|g;5z*~9&eY?M0_PeG;tYs7L|g^2nut3f&J*zq2-^@4zEIwf2pfoWB0@m? z4ubw1H}OAxm?ZP4uB|^tE7J+ zSPtX?q}3{`D!T#j7G!a$ak9yqxN+0)C9}@Yp$L7_JOi3a9M`pt$oaB}x#0b$508KF zrs&Y*0*b`;eHoh_x}ocbot2{&=*KM#YE&9AtC$ERpz>$#p(-cpsNyQ)) zgH{G4mNB0$ z2>x>&le*R%*I?viJ-5!cHi&lZkE4h)#ngEVh;{xBq9%=;Wgs>NmpO_Q9Bo)p z0fe$5vLdX&D3S!WoS$ItfSmKidH7Sy%bUo`aEpz{-4#l}jQLjAnG^H(Af+G528&Vw-&NZ_opF)&DaM*nel!r<$flaaSBt}cx=^6vioWs zpKS^+Bh@0pCyho(3PZbVRAQQu*pk7D3e{jhRI<4Bohm6qz<7}3iAg*Z1W=!9OhOqVg|C!Fjt#w*xV0bZz}_Sbt+Htba`UXc66Z1`G|un8wzBA*0@d^>H(i*oP9S=}ZS= z>-U3T>)(M%lhioK%bcH(!Ogw$EYo_sVZ9xe$DhR#NnU>MzhQmDZLt0()UfppUWK7Y zP3sTKMcYJjQ03W3v{g2&9|pwMzb*CcA}IVTV79f$9MjfaNh;Dwu(RSh9NzyTE+b%k`I)l>A8K#n;xrUM?5FDb-kd=;Xvw6-y2CF>)LRIiv*bYEM-+ltYYUe{%5VB3Rl~WD1y+A0nk4h=E zHmK}yLDyCwC$Zvxv~u3F6O|H{W>m^J5Y7~`kvhZ^nRk~+cJ+DuJ-PRnA<_CA>v&Fz$$;?-{g|Lq>aYHX*B4aFYbMAVwqR7p%h z7&hRV1zme8J@5KqgJ@0ucm)=kjR~yAYRIAr+9p?V#QQ zU8c_Ho+BE^r1_N@8Q}B#T-REFXMN@8HKXeu(JtsC6miZl&G;IK&G=bbym zO(!#v!A{--q4c$IDt#GXec=mi`xoijXgeQQ{8?$aeIg~OAvm0NJUPUX9RkEk=gL+4 z;L=85R&fl3QW0iTDv}`H_e)qLFYV+0gu{@c`5UVP$0Gh|Sc+QG`e5r@bw4_CNeMNn zrkdtJtY!cR_H8Sqtw*-$+bm?T;`Jbu;+A!kVjGkm!F5<(-T$|WBi~0?))qr?mZ`WR z5Gzgq!HP#fl3%rK#eI;$il>86iW7s8jnlzQuzr3~*VZ7XMs+?NRGZ-J(?K4^#`qZ@ zMjHq3%N-C^^~GQxvb*> zfuw_Gd&;(AzMOtgRL}FdSvbd1dFUXHzkjHO()6ubl-zk0-DfE}V+}qv#eOm51JOBV z1d@1nRdN|x>wPeuyn>L?p6qv|7<;lzq$L?aqdi&Aa`y+KXpx^^SFv*p?gfp- zaFPOTi@(A>4tf6ruCu})iq0W>Rv5+lu7t8v;MsJ|P}WeUekh7G+?Z}~ytE1jXC0x+ zW_}{mxflkpVfEfHw3Uv9Htgurp{dT-IPpYA$y)!sqyL+8n=Xg2hAO)nR?sy5G6?5U z(o17*&NXt&A2=(AhfY4X*@6^4x48wP0c|$gBKs;uY`5=kQIJMQH6_=A zpwpZVAXIDY3%0U&8U<|3@|wwVSPuM11eYze4n=C4W7a=y6OVo*+SD70BF@E-$(E%8 zv1O}4)F8{c!06$)pfWEcv)b*XhAjJ7b~-GAn_M*UeGsZs^hjna^>h@?a|0{CH+8LX z^z&Nw#bJ!5<50wzWm>irh%MVB6OM=w|Bry#hD&nD5xAaZVxRS<4Z*aoMt$3$zt}gr zRunmHE_GpM?_rv$QSbCJ{Y)S>wv(?tTPM`ZpF<3*o#zWEkbngroCkt z;{?GK_#$*9Asb<;QpX6>1Z1*_o8^R~BDma-Ca(0hX`)XaWnvi2i~3gAh9Rd%U2c+U zK=!mT>!^64^+RyD&AVxu7rX)H(T@wVc`pKStlj{@<_(1WAY{WlM_t3bFObRR**41A zAB&)Jtv4D8b3mwSe2otH5W*PPmUa{SCFFeNVEfb-FWWxefS5;}<`ys1bBh;xOcb+} za>$8m@I8c9o1lz3&AT9+JIQqFG?m|xLyw6zu0`*l)9i!R(a_3HeSs8qD*wBNQy(Ea zQ#rNAVK|k5Om=Dt2-RuMgDs3!Ek>u=ZL-`W7W#9vq$LQA3{dvqJ6&_+$iTZp_5Y=x z%a6m)RrT1e)fSK?B^1B@3?3iqHlql#h~#5E_Tz26n1lh?0P~JXkEL$ z;n_B1uxEEcD9@r$DAU8Uh^+=odl1UACViD>+AUq{a~qQ=a_+^jV`>Na7ZqskAXNo= z>>#sGtp~~SC*f$77*(O=-!mMY2ErK>WjN}$O-?w83LUZyo-TkDiLin_eGe(@=^YT< zN|z&>ei{-rbtJ}cJAAw0QzsD0?RUU7TCwqPw7_IJN-Xr}=tOG;ROk>WyKqO>0(0!p zwefNPCBJum0>AggstR5L$y~t?K{yYXevgv=r$k%Vm7Q?O7Z$vai`_1@%W%6R2zEOF zSr?Q)t>X;0=OdGA`#1>Yb|~1wXo@!4vCnRUB?^RcdrlMO_EoSZ+{30Z2eSMdvfEww zz~Dcq?i7}-?pZW#&be}Pf~7PZ(u~jvd?fe8ia~QD%g&CL}QrAvW{5j&yoCsibfKY z?Y@t@oH>xS*!jPT#$2fRMMdNDhN@4D+HXYTGzh1ywh@ii@5?f$MVq*N?;{-Fpx7!{ z$KlWq7~!Z5g2QnS*=11>wLa8ogkvZ&xpBND-#?AH@0y7V9W;IaX|VGB03_ed!lZ(n zeMqZ z)p`h~HhF-3ZF#j8k>9LCC6L3dp{aI1G(pKQu zi2k(o@r%rh|7#tF8XZI%5cU*Ec9AP}kTOL+JS!rj77<4bUSZn}0=HiB&5|HE{%LZFGB;zggo8DjrGBop3lI5(s-X zExan7jpBRC`q_A0ZhBxVQiXp%MtyxbA~k?>XMt05q@wdvD6*jM;~x<@NGsNaBY{f8 zcXEpMJuy9qJTY=*B)K?I=DmPNF;>dh3!;k4 zLiaxC++t#r|MR)UQ^yvGEQun4M=Kyx#Uzjn!tN;(@!0tjdK)YXX^KO1zU3^x%bh>i z#Y6C)erLoCP|ad6tvZUnf(xP&h6CFYdegtL9q}&$6Pu|1k8FVdb9@Y^qd37gwgUd= zPwi`t%GBpz$^poE>t~F%;M)UJ z6RgO9u#DeugBbZ+n(6YZ-1)=Q#yC3?ym%bthiv$8W-RUp9E{9gz;y#fW0W2JkrjKo zpXxfh@qfi*(EAREED+9i;EKBmSwT8m^~2N}#X?c?ESC z1aMG&(`uX0_bAHododJroQ>O#a~ zT>os*Kr)0{fp6NKaUMZ)lp79{Fg#`Eg&g}Iy0!$Iy_0x+Qs3e$<~?c_Ge^yF>K;Zh zEw?!crC2Yq9TSAl2 zM26F_7ug&C_M^fbLCmGXCSQV!7>w3K1qEzJVb4y~6PG6_wo|E#Y5B~! ztbjm{%TW*-4{!sZCsP&jtk9?9QX@Mq+}-X#fM;MTU=k+Nvmow6AB*+}@=qpv%)Qz3 zV0LY)dC-lGdC+3fZYqOnBtO%O$)6ftYyqLwpm}f+3e|;Lm@qY&=RwywWIiWBoPBPuK+~A+*!B~z`qUv zkGS1X{@MP|qpc>^LK%>AET=`A`g!=I!=gJlvj$gp!CDs7Om-7jEn95)w<8mq8(613~u{OBR+v_uIfKP z80{T}>Ow7i-`|$2x=^WeD6E#Y=DM%dIr;n7qIcoCBaA4a#CLh%Gg!~Ie~#t)7%bOa z-F1|*(CN8~e+0=q{REw->BrxqMd9M3H+N-r}8qy7)9uHS**>m#1H={(|AsQV{l90T!(-E_Ug|3+z%jC0xM;gMLPFj~Vqi6{Z>WzN~Q*jy3A2 zDyzWfe{!td=W^OjF)GJ+WL1~?cjjD}-Dh}d=-x`9Zs@^=Fmq8b#(1#7qm~AxFoUtQ zQp0Oy1nYuoZmm1Ph(B*Lp1=TZZVhUFLGA4aEFO=d)VH{xZZ(zitn&`w;yND>ip4nsPn5R=nf z#2^-o9D|-0<*wUeRL%uR=$-PvbNU_vTUI$ev&%D`E_}&!Iu4X_dQyIiwh|YdK2N1Q zYrhxqlhac{*iBA$debFU`<3sa_6w$Xd479iRLx(Jckf}0wl!1%7y{=r3tO}WU})2wTY}mg{8jTeHV5u; zfHw!?fhZtP-4}T(AMW;)*@dqfW=Dds?}WPZxY+C$uc`_wmW2xQ>F#B4Pbx+gHdDrC zp}XEdl~aY0t@a=+JdwYl$A4gNXyu|ko-#H1nqg`?5cZ%z%qFf={A|hpC&W0Gax!%=3c?*F&WJ z2T|DdBa)w*{i3f!V)0;$_7N_x1so-mhg*NUfHN2I&sf3U!S2+tpgt;kNIx`}}7?ig}1>HKF%YLAnab+#f$iqmc1b$o3-1PGWB0@(LLzz{&q8WaS&FkPU&LM!7>R+EwU#w=ak6 z=}j9?;GXS@CUEzz-kiWaS{P5@ZmcHoxlq)HhOT1%U-p5wf1bd*-9U6`_uF78C^dwa zEoRYPz=cxf`aV?^`-z_hvWp<>CMQ=#j&Ib6FzF|e$JGl3Jt`si8>12&AnYXkFfOmt z0!k=@nEcxa&mN;`j$Cv=ghrV!36e^OS+oJrSHJ)NF2aMLCsjqbf4^r&_#U~=5ib3$ z8DYQT@D&$K-9@E5r-}q{afJJTu$!D5;k0j6gl)ed!at#)M}*f>F&Y;>reY*~9WJj3 zQ$jAp&v}m7{!WInrx(xc?MK~0CE~p5XD`*2=! z&xDn{%^Lza^OR9thCJo_3drXA-wVQSaw1mTL$#Bve{LX zG8+_qU(urZ{D7fkI4e_6B4t0{=;hg&3F@)~q-48%GGfdsn9{yQ( zZ5qems8$IJoyr#NE_gyl{5#z;Scme#KN`xv1mV1CDj)FEpOv4aNBp6j6n|j1XlKCl z`M*_u4$5QN{A?)y0E9CPt6y$UZGQQ)^7_S;@=PessAkdjgJ+S9wd61Pe-65wZ-L`6 zzZ$wXf^fDobvqvYS$EfAN;m1P8EMhhf~UdAe{NpOspG`>Kv|jJ3}y2{I8)uq9{*Wc zT2G}c28t%tfHLr0RmyBUrg$_jd5MHy0SC9ACci`Y0aN%zpr_mJo_0z&3Ctr8eiU{M;tMjk>FoyTkv%tY@|p3^I*o~%jBH-3&?MC zvL2H~7xDvQkV zXJz-gC}kN?^qRw>EeB8RSXQRm`=9PutKrieWJY=Xinpwn3$YEwVLQim76|77Q+X&3 z(4UU&ryZ2?bSR!w-=a+i&y#>2kjJ>TgE<@X_hm3PEhxYHhMw5t0+Pb+^wvli-j2oxtZz)>@u){p;}%3sQjA?|ZX zVCDahwd;Vd@p}L7y}60laS2JR*s()XVkhB7>`=2cVsBzL=B2eMF<*O^)GjJoqiCy& zR;c=^DxphtDcY)P`~N=YeBX>KX#3~$iSIej^PFd$bKdv7=N;FD4Qf|E%lHMS%L&23I)}m1R5jFL^)89~i15}u~Ispd_d6GOg zwr&7Z&ZD-dHu zh|>`Wz!8nha_E@m#=0p#h!K*`CKk%xcgJ9@!Mz| zqZ{{vj~~W71=~Et@>1f^RyR z`Eole;1h9mb2|fi#9=R4#W@QFR|1?;aqdM;#n}Lw6Sb?2pj^57v9ysV?Qf%?UF`s| z0r-QfN+bZAx=N%{esf=LXU$$+Ku`+jK`KcrJpLGkTOsz2R+t`pB`8s`f7}9{CCd*; z%!siY@n9U9tj=9{)N4c@XQ=zMcpx2E5}UrEKS6K`1XXYepeSGNfO$l}8&;2welwFo-ITeg{Q)v;ov3+SH(z=uvm14oeU83l=4^*zDtUmapF-lyE%oMJB8{R$@;ESQ+-_= z#G9&z@wWIvGcLcgsI9j-F~75j`vDZG?>$9^!QWII64dveHlv28FpA(V*84E&*HW3k zI}Le_0xhft{`10`SA7gB3MCIEKPFGopaAVW%Y2UEz56P`$EvUbyly=xr3#D}6!8OdQzO zyM%>nGLel?Q2*+ER+@=~=xZ+^k>CuQsS;UST@5@UkppOu6f(|H+&Q^m)i9P-({^mICEF`YF~a0SF> zOlR*}=2d@Z!J6~IQt8_x1^JfNWhqGZ9!Np5R}RZ*l|7dfBzqIgN(G(mI&DGSwI6y_ z_AUrlvUe8+mAw~`juf!1>^ZSiRzo`!1)aTQW^WfnKkb68FK~v={{LjJX(42<)hv}g z_YJWq*{fVvQqY>&TZ9_3m#Z^Q`k*6wS7v3*-Yv+e!B`S&Y}X`+qz}f{AY~Yg`$eyO znQQ{+Dw}Jhu%ItCJx)kT(s@G)lFt0~QINq{O$w6E{`Jj@0nWCamVn?2Zo_;Y6Sm|t z6$O>g*0^7>xUtp+w7Qsqf=kp4-c4S(oLiBz&yHOjQX0NDxHh98ll=bLuMmzfvPgwA9R)3*-}uM-76)@?DtZT%;t(hK{8uG3X<6#QD$I}Gpf@R z5L`DznY{G9OW2axk5EvV-GEdDv`x?K_h6{Z=DPAU( zGba2bWK_Z*NYhk^q$j*0Ra*TB;og^APEn^l1(K% zHro89urn%PI0&v3Q6>prEo@2nL9L9Fh) z=0BZ*d#eZr?l1Fn9(O^p%HuC6xMJHgkDal0V;<+hg-M{pohgYK^SB=}Dvvi&aGiii zdL9FtWXhvo2jsvAdA2A9ZX5`%{i00r zI7ir$$1NzRfqT6tE-%2g4hbi~P?`N21)bSX^pLPcAgdkw;5w`sZr3b$I+;CP44FMU zUuCw_YA9Bj{Q?D7I5x7>2yNOtEwek|LOLR|;|jsMONjUL1*R*%FG^c48vOqNWnL z6a|$?8#0puww1_zV5mf%M?oj@&+5u^TO356>xZpnaJDT{iTw9Vre(p%-0FpTOwMV= z%$-HS6^v^*mART&L2^uPhRs;ek-5r?GG=ZeWK`zfMZvWcBI%iv6=;UJoho|eG*ui+ zPL;_>DX1|yKuVIzSyGTxz99uk<;PNxROW1BjxB*yhPQ#Ggcq2~UZ|;5zJ!8G<^8^P zV=dTLDz}26Q;C93<*-1ov5OOjG~O79RDy%M3i8p_Lh4}p(B|20vqec~>4-|tL6>@y z0|nPbaYEkYxQ#_{<~KQvdf)PD^cM6Nj<*}nx5EaV`FcqwAE8gX($aT+#_)}jcgI>c z0r=^K2@Ti6LeW8X(Ltt9=(ANVaUbO7+>pk7}Yydp*9X-fPT;P2(~qr zma2FBvD9-VSiuHjg`|c|v$VH=o|W5<*I&f5%J2}X8ZO0_`4f65A+3kx#-ll>jI)w$ zviW8iXO)8a zWyN+E%bCp6p`nB}VLXm;I!mje=~1Dn&g_iEgw>h6rRp%hE9(rg%`^*?Lv-?ST!}6b zkyUsJo9$@OY{h?!?zM7=Zs&53=xTOnbbp}WGO)Z<^XhM$pEF0NIsnPisCrb~s#l|M8p+tJ=IZj!O7@|B zBxZl}T6t$c!Dkxlz*7)($}GFF0!=orQi1DD?njJT^(J0y1!u8}?N@mOR1_x!70@*l zTr;eI{^(~n*X?x{Ft?+Xy=Q;(!wN|JnYy$O+a2fPZhL>6R#q$f`qc2SeKV$_vvj}* z5L8xP82~H$Ei3cPDHWZie15}Oz_sQdhVf%XgmHJZM;K#p3Qz{>4Ti28mVpjK7)G;7 z&SJK=%>k7#J5~fB3fx(XTYwYXV!QF(5W8`Gjk>d@qsVY)t*R2;ZGK(JSvs-|P7KP( zwITk5gASlb1GxTEm-Rj z;vuL|)+Y~#^%%?gRGa}aTi0i@WjK-H4^BL4)LFAF^NEaShM+Y#Gq~g^i70{*L9^Ak zVGdho*QqG`DPm!CjH>vOJR^IsN{HUnf;dE;CyLF1}nVz0(h^IgPtl{(M^t_a= zD06yd%eEfoMk3Ty*k(6&K=Amh|1mvPsv|vNuX>~>6sK=BeD0#)ia_Y7LQJ;%yiHT*p} zJ^db5q|>vulul0y)THdif*XQ)l2m#gdxEfDsxRh#f3rtA3ck#ATtdNh!b->8DW2(2 zCx~`1`a1ryiXrox^qsMYv5pYwFVa`Q-RAxJzMIXfS<(~lHn%WJ-;)!se8T@U#Q)7F z{Ac0H^x-e~KkJUj14WX(L2uv~1vd+9K~9Q*DEF^J6gncq6#7O+D9qJJoV|cXsWKSe zazw7v^vK1On@OBN90v5A@9>%L>r-+~WN$@vM0QHDxy6j@o+NrJs1M*k=shTI4sW9N zfl>tPw5TH})J37;WL)Dv0NXE4*Sbh5AGcoF}asL zMa1MD@_G>yZN-hUkO|T1ez4T-v(%k5>(q1x*1lr3dm!!PU+Gu#vLjj}Ur%^Sz->fG zR^wsmHvS4v$9j7!vRo2G$#NBij>y^yeIuh4>MV~ygNV3)o@F0oxs)wajt#fuxFeLP z9KQ(ju6U_QewU!8^1BZOmES~IoS`iigO@757r<2cy@`U(?|O*s#UJwP5;4i|Um_;? zEi!}oHQs`Vd#zSC$Wj*ywo=zfsqHLK=To6e$~OsJ z@^lFW-Mj~yC+Ow|f>a%7;BrGXFFwm`RofZht}g^>Hyj1^uZAQj32g(BTl8v}BxeV> z(K0T>BsIsRk>utQ3N_>)kWpR^0=Gq8jsnqg2#A*XA1#wVOy<1LY&6HDH;T>1nJm<5 zt8!8UJVo(^b(NR)ps2izL_y_c7o1Dff!(wMOV5kMufEgxF2pY44>9D!@W?VvZbY66 znIx?)T;$|Hk|9q}r$**oh>25@63O_(nKSBrR9_EG8I~RP<0%ZdT=VtE49#pA9*ZgL zmSb>PG(DodxxW)blZV>0L$7rx=Al^)O=**=+x(-UndKqau)A@1FnVxs`piK`#6s~# z{Hcy83ySK9XcSaOv;`{|4Um$l@Kt555149%%|t~;$~e9)1sTUVZ~-5hD)!J^4dap) zrGZdndPjkxveyoUXXOO;1seRO<2brYvey~JEYc@3d9`0RMDF4ADRucFQcjEI#gJ2- zks*6#*ZR06^>D6?dLg;dgN40qacDf|O*~=(2eX@N>N`v7JNt#bWzm3dmFQozv#Po9 zi*~8?@kB&~`B!~sxvJTAV~)!QXQNx;zcBgA?W^;UAo;zLGbn^Efc_NxsZY@UZnkaU ztQj4UsJiS~`P~v<*bc#;t+@A;hjmqiq|((6g-}aY>2jNA8#w)|o{&aC*!YXiga5+p z_;0l|`W3o&OCwPpgTJWKU>!I8Bb=qfzY>X^koa9BV!<6Q5}$*Td%p6m-h+Y2&vVePPw&zv8tiu~kM4R!YXo|Pw^_Cd$sw-DoG@AZ4(t~~7&El&kT z%acyg@|e@J@=&12g^1i+j#46*`5C7GY`4fmIkj1PxfSpoy4Ct*-wgUiQs{V z-~iKoG&)n%2cv6jZf{fENdhf;CH@Ob#D7<$%@h=Fi#wKV)NW9G7Gd_wM}2>VhMb~- zNB1&dC_CYc%rB#yrQNYYsD~!KPzV)cz3>+`5R?QY-A8D_;HbrT&VV^*uFQA{(V!)n)59(OR$i|M8dRJ-*l`ADYLi{|{s< z9v+{;-yt};JsGE*?9eXjQGbPw$Px;DBP%P+)ku6Ffd>1f`wloF=W2T7OOzW;96;;} zv{plH6wMJCEhs0P6ex*Widx`etcGq#Z3AlIs6}l@p(6_F_?8HZ8}J8<)8M5#zP${l zI@y>g7&YXm`Wi$IX)z_T)e<==BJ!{F|KxEE=>+#pDAJ4ef7T0V9U&=7fr0u5?Zy@8 zOx=%^9RN{M_P#<#y+!UIZHoHXUZCq77R5iX>FDuX%SMB zqzy++C2fIu&E?GB_D#5^l5hwNm8Z)n=sewrH@Of35}{8OmWab-p6cDm180vrY!MK9 z6@LNX{BFiXJ1grg%j4=hfB2bf`DIb7;-`j3Lx?9xtnXXH!;hiniqyj+SEL>uxguqF z$anlagG{u790|LwBrC{;s8v!??m&Dl@>h zsf>SLhUd%hd{uak`77OP9t!ZH72vBd?7C$I7`V({S$E^OWn5?#I0Vmn!PWuCwYL~x z-Q^5$lUX$e0p7CeFRZWvTpgqX3`TJCj^gDFa7vl+F;5JzhD`C^Xf+zG{#}69L{}4h zz7c9^QNy*^N*p_d;ughf%q{>)_2xGysCD2V@KbcK4-PQcq*V-7cB+j=GSR0%ELh%A z;s9;~j_UA(A|n6lZIF#cbZ{b!U3?dB8m+{H%r8z3bSyb;1rT4OW0yKf||EYJT zK5T-`vX2j9f+t`RAfIcC1I~aN^?Jiy6kPI?mFjJ=8EdgSlzKm2>zTq2(LjDe6S*0Tc+~{Y zzJd7}X&z|m49xkZRd2b`yxP4nOB{$3~8?j`?3QeQs5B#flj@{l;yB(SA~s#HFI9X63oA*^Sm8)6atl$a8kv5O-8Ue~EqbK>qPyW1#+G-fp^JP)1elfv>HXWCGx zP#To;Eq0^l(%l0q;`)M36`YX>0AH|Q^WZ|AVu9SdWKP{Ik#od!S^sU zJz+3>@~FXZPt3?*h}{RHegildQczR5JeF(?2G|P$8-rmf?5RBM#igA({w~CY2L}Vh zw?Fd&WpkHK&jg8>?p^Yw6I4!vtpWH7uAiV9#R&ZFuu zU_XajDRNzRz|rv?YcOPXPY(vj`3*{sAajsvFszW(Bu+9BuwU;IE&vYOjf3y~$H7pm zH3mb2cRdEfMW|GRp%Kn`u6X#P2E#?vvKkDZ;Mz@mPVkklc|Tz=Jo3n}R?Ns?h&TeH z`=utiJc63aL#A_1%eMFlYCeQPjW#Fg?8<=Nu*tih1k zJv|s8w_nR;5u_RnZk=~q1nk#K#r_da7r(#%9|yze=P($?ANLpxC!kUdhA(Qm z7*3#;)nNDx@k0jb41fQLgW=&LLkoSHh!Ha~7(!3NXq?m}m%C6?xm=HccV>xp&VZ0~_dnF`8ue^FR7PzP@YlSKEd(4Ug3a#j z9$r|huUuz5`8QQ9tt$x?`K!>904@J6@{A`#OGDIBHv-)cZ$i^Z5_+YN*-s7}q*UbF zVKYfb{`(2`(^)W8ztqK4HPnzl4zXKWOm*cpaFj^F3sx?^cIaHJMFhWn>5DgC!D@U` zjd^{Yn7%anC)x1+!fssr^5147;{m|Z5Vh2W*nM$02u&kNHpYXZMr~V6XqAoJuo*sF zjf3Em%tnb%8R{H!NC&)K_Q0z5!Q58=>LrHh(2cKfHo1Y9rNP;CN=5$I6|{Qy|K|>v z-M_(FrfZ7`%pWzox1r!lg-?0~ec5w%t836_zP20p#BW}MK6(MT2nR^L0NjXc47oUS z%-`sCuW|W};LJ{f30H{JBu62bIVwkaF-264y1`Zi*qGTfPccWftIW|v6!eIx4>4n; z5>q4Q7fWO~hLTQOkx-qslpDG59KrW^W(cgn5C3`I@|%M@Idi(>PJ1M;?KLLv2nw!y z@Ioc8Ek>1LeN|tZ4SbOD?)0Lyt)`pDtVyYW;fl&Jg+{|5Q#C^gB?eAHBaUPnRg;H1Ff7x;sh;qX%B=Q5ZoA9hSFy=nC= zME=xbN+bjvCDKboX(`j_z7%8@Ilslx#cHlXtpJKE9--Dyu{J?f#X1TF6>BMY zR~LVXwIuq|Ggfn0XJStqf?KaP}XM2HChAjixhn&n`*9 zXyE>2+J2?Af64t!H5#Oi{JuF%|D(~6^|oazj8oSM83D442*!K}T?@r$@Tc+=0gB2~ z911E=8^PL#KiC}#UsaxFgQ+@vhk2+AmJ%OY^*>S213<#Og=W#n5SoTbh(*3bUG`+d zB*0MA!X&~N6jcA;%OEfPA1Crz^#4d{Dg8fP3eo%U{e(3rg<9=ZY{{UwZXnXuGS*d0 zCqYs%{RKmXwPWqja~?5C3~Cd*I7I5wf4Lp~aF|AE`6+U@3h!b2;F;?Iw*-)}kQIPGUX*UcHMPx8kyZU$QwzeX}X+oQda z0A253V;pt+e80%|73PXOK-@{(pwKtcROpDDt_FWU|mGRa!8#FL>X8eWuRp-um(wM8CX-KAP1I}D1=(gm9u+6arJ}i>Er5Skd%{G z<6!84_VSY~z0?ECfGqGO{2*4oC-6lzwJNsR6QM(NqUskf??I)uin<3 z>o#KGlA)Hy>me61MvX=#lky7(!0_KP4gkojY#eZ?3vs{4MsSxA+`GpJeC8WIrF_?f zN+zJDi5|8^kzR|Whwaaxs4&|8!7#3(#V+mMU!Gwg3bRE|XF!FAd`9=nFK9~lr$A+d z!^`;ff!%0z@gH}8vHNzT1e*Q3?oasBqx(fo>%Ud^&-mZJ>;6@u%j$khkLvzo;Dn}8 zr2Cir#k`d;|uz9Jujr;%Ru3k9p{EPtAWMAmxl|I?UUlsbl z>g%$;UfNx&uPrsoHPw+kMhx;Jrq!_335mz`Fez5BI-nhc~ z8xCc9jc^k*sz_z5_R5i z;P@Qx(w9r3${I|T7S%Hs;BaUfMS5mS zUN7A-ZQ!t4_J5JBh?fzJ5MlR=PuVlSI5~Khn$`MZFhvw({d%DcgGszqfoC2}S$d1Z z2EDyZZ>_OpX;B`}3WUdL6!Exgke4x39XEX7sB-xn?1oNM9&bjb)c8;LxPUd5eumh7 zEv7^s3Ib#4U`aieCLtXsi+LGIMZJtxpFi$0FT>y&(+`8k{h7z$sQ@)<@cf8^tD~EP z=XUWd2Ty>%m$4Os|8DSn?>TrxO+I7_ojCLIzZyKE${IYD7S$Ec2P4aA6zPg8B{+C4 zlw?no@^^a~@dy!id%~{D^O({cEJey%UC{vU-P2-9$dKs0fdKojWsR8wfn{b)mGfK$tYjbAyff!(UuXqfw9Z;zT*ziycuq1e- zj!vVic@D6Kvet=5UmX#z6MPR`#mJELPCm8X2~bBUzoxR<@#9+OUA$)`YaR7+kvcvh z!FbO|Ep7{<*DmS=*r6&~R*N1h#b~(%jh4ewvdjT#8lEeT#w%Nj}5Ah+w~^iH^2mm{flgdR!idQgInovNhNaWtP= z(gf%m+Ul;OA0K*$R!wt4E$q#CcwasFR7P@j=Rw z&i7KYI39T3)lWZ}SZRD=X*!4_? z`QuN-U1sK~RJ{eEhHgI$(>D*2LKW}Qkb70TTj&EakuMfxsB3*~MFjK7xj zH#dyln5q1YyOxE&JBMHi`jEev=Nq^PNkv~>gQd2yUdGX{vRs1lnTO?iWuy z0KE6m0U&+;m#yz*M2MyXjyllvsQK^CcmU`p?#XtF&vP=3q$XW)2{koxR<>hL^nmjH zTDd=ztC7>S11I-e&s+095@G?bC?Awak**XO)7_f?a(_XB-al7~J>dW#0cUjpxQN!u z@y~j}@q1De#}D+T;}iPQ@!2pHFi)BKP&u9(2ds3r%)-O4fXW<6+HB81EVJEGqoQumU(TCUtRl}pfRP^<$jFO>9lk(C zei3%F=nr+|tKSe;14p!67TtrqVJeH20M%USHp$mWR>1B)`=4IUf_CKEN$Bn?re)88Ill?EK zRFnPKa16tQMHq%M*^iIN@?@WgLqj5D;8f)sPn_$IJ=xd5#7q)Z2OJ~6dGut@IM-9e zJDKZMM#_|tnoJq{C}#cL(HuC#p*wi7(%lle)u5P`fIz+Fgm~RtITBN*5tf$f0(RX? z*35=7i7N2qej$!98NdDnmcXJ&k?;&SAvx}Ot-PB~SiJ!%I=rZxq zXLiwKt@JG|DiM8WVWy-}BpG#Pd-3_sFXph%s>1Ht6)MVnuht{*=lbK$>(PU}48PSXSKGgP^iW%h`Wfn{!OBonw`CUhfXE8*7vgN@UPlihQuan*DNKm!M~?Q({k;{*OAZC!w`+ zyy9j!enM*Ec+Mm`{^4tMd@D@d(54z7zhSH7yq@ls`N|lK_{@={o!6`3sC|9xKc4H4 znChaX29B9H1jql7J3je@lgmV8>2GK+5yF^IqD;5Gw3u2=!nzc#{et=Z}vL zp$Ej0w3ufE=7e$1K%dilyo~<0vYh^WP=wzmmqX;>)lbx>+T0!cVq*dLRtm z&xz^xmU((SuIBb1AmRB#dZwy_e!oeKJgZ*!*vWkK1)Zfuxom$M?xaz~=cOLo z@iU;s2`&HdWdDc*fM}UGOLzRIKmV(a&v*dPYS{7X5m#s$MY1^hU3Pr2<4od0*o}Qn zC2`Ns`0#<68%N(~Kll2;I%w~N+(j*?L~@;?$d1z)hQdTFFH|o6)lf)Z0=V`4B}r^Z*wSQ5yVD_-OyrL2O(e0E09NzjtKN=tCe2H z$a6UP-c`qi$KGU6pZ;qy2`l?ncRWt_SD-?z?AL#c6VZ&VI1$Ope$#o+mA$$_eH81E zwUDs})MK{rupP=RJnXs4(h*ni6Wn?W?**Ke_lueXj{0{WeX7s6s!tWqg9ME&}G&ECQAlt^~Zs6^qu&@h+)eMr~KTRAr>pyGGCNU#I7%VJlJFO0hgo z_sT5x5*CYTk*GlAOmEb?+7$lbm=TK+(GBZ{gI{_Xt$)k%Y>{~rh+no$+w9d}%$fi- zyLKy;NxyiEma<=QwA@6&bpld)arkwXqvh-x95hn3sweFD%9kx49xi&c4BUuOE?N#a z%wPZ6XbIkS#6ECOUp_fs=C@*mlcp0`*w5{^L z(ap?Wsm0Kr;?jQQl4m5^al>e1tIz@hrY#Ob<#qfye)BReLucix1%NV5r!BX!PoyKn<^&@z9netsxM+`eE3dPrEVA*P5#X242?Z2x}DMe)c!CL-U9)D8K z`n9Kx6PpZ)Q>v^7o$+C}Ez_J8qq6^jG1qpWVT?k-75o;)hWv70@dub{nckg)H{bW9 zH}J&3Ds(!8#@&BP-Xu&HZ~nBrLBSQ9=FMMOc(Yh#3%P+O_TBIXLQVd7O5Q}za8?Y= z{POLD884jb+gQw&`fthgN4m7IH>1K0a;#v;e zv1tdEG}I0R!}#}D(7s@I7+*at2d;|)pF^W^pote8NVOdJ+)FuN)|%z?^Km&G#-2Z) zQrNp@!Rq_asH{HY4Xb_!I40ls)?v4-qQgFt>}3o-=w(#(aTve+^*9H3H)6E@sBhZW z4aZoM!nzxQNnxAo%pYc8*&hP4n0izG@;EoW4r^*9Gb$ULixB5zB{R=_Z??0F|8Kqy zBeE4<+tN=`HAJaYcGGu`GqTXpO4{vsxLgz~_*U5+Mh!f>5$WR$e#B({w|?(}>W=;AFk|LAtK^8y3$7%4yg6yEv$J;+>Tj9X z<~mD0rF{C~8ezZAXA`@JYZd(H+K(u>QY_bQo3rLQtK@v%N!O-1&B+*2=7o7k;q8t( zg_BMqg;><@hSXWFr19HW^sp+$JcJY z-oZMY{eL4iJ1uhNtk680N33tckczcTFk(%#Vtq4M$GTw=Vl7buu|9Lv%eVs1RIH0Z zQLzp#$yi;b7^}1NL$TfzQhKa2ae$Y;HL$K9fi?7c4D)r_pK7e%FGj3aeLZ3=U6!#X zqTo7W#ag-)QtRFZ1 zmOF#8g@!wfj(MJ95{tRb+#Z?R4I3(R#cCmQsaEE8qn1VHp2bSF8`h2gDsveUhp&2A zDpclzY9n)L6v^CNP*mn#sKd-Pgw1<8bJg-NbI;UerZ$-F6?jWAPd(NrqQFDvH?{PT zoCJUC0Tx>gk%zurlMYvRFPZa-4B} zHK0DclixL|(f~PLdpJ9n1l1$Vfh(P}ZO@v&t#meuTpodBBw=ZL4vR=NC3k?L4yTu; zAjg@aktoQiqbmv?Q*w>Wl3aFqH83BD>SWBIPKw|#K4$I6->c^$hJha+btin6_JW|%8AybyG5mFZMHZ$h$ zGQHOzV;`II*EnM$C%6!5Jl3O2u{udPoWq>R(cjj5UaUDAY-2&{||{H8`QW zpyJbfRI?itrRIthL{0I=RMP?lkBrR~QpSwk7^E}ihitu#HPSW+oGb9OGWNncXR-3# z3wUI#N(?i08wJ-|D`UT!>(^ls-?b^Yhx_3RpXQ}?&gO+ime3v^fp;%s6|xWf_(D(1 z!&U3iryKk|JPdC}4s={yo&w&$N-Ow1;;XDU!vd&J;GUVqxD1UYk4YfSP6$w5}wJy zIm0VRSwH59ry=wftvsfw9|qw|1EOYhS*SVSXcmYUZ{?9(zQ3a%cJ(|%LY3YR6;;;L zAeI(&n2&9P&Pb!kVZQWpNWFaM?)|nr%)3jt9Yzd7gxxZ*tIm)^+am#ThAh+($91(U zx*G1KXfY-7Rws(|ctIcf)hS*AP`UUgH;5QO9X$8V2&|_+Ej20%M;AnqMv*8kf})}r zYv$YR%-`|b$N0S-9;F^t;brZ&9BMmu(1R>ix)G<~lHDD~?jlcXkX_!4L3TaJV~}lx z4Rvuw8dSv~TZ#~2_c-jTp19MOBWOi`Ymjw?d%^FdcUJv@6#05khCwC)s9gMu zK_)L3cnmU2jf!H%5JZtiktjM3WfXtKGm3h!o20#)Rpik@sAcK99zm3o*AYB#Ud&BqP1hklbM^X~T;e&fr!rXG{=ntH+(>@vy~i8B&FPmdF~MQnd}?OD5wp%QG&>Om zSDa>si0e?38G;FH?gehO?)Xo7(^ z(P5k@`Pd9(Ufhnc-mc+wLi&%_VV}G8PAt_rl=L{_roe_e;x59`$aPCxlFjWM=F*+m z+%7m73k>mK+uW)}T=)m*#>D|dTuoyEis z$Rd_JXTjf5?y34Ya4-DqTF%4I=VsH-LUZ8fF3Zotub4;Q!0zW8d!5B{y!;AeI$E}W7uQ!}!+>zDcXJ{^4D16+Azwf{wUmm}(eOmUlLUY;i2(Nr`M%`5p&82UvJ8EAo zs<^z9Ub|6@s?Nd&1U?U32RGKM=aNd?e23BG0G|1=J(Ft+E+f3=-aaXY_BxZKn~TviO+?E%@Uem3}SjK^P% zB@V;80(?cQYJQ?(EGWivwzrjIe(L6XFgz)RKl?~WUC6c_A$Q^;m9$a5Z9P#ib>m4l&+dX$Uo8yj|y(aQIa`ZE4tS z?Ft~e9Gh5q70=x{!jquSX7iJ~j@d#G%3;)t4}nF)X0%I0hXxcmrA4;8f$gMc0-ArG z-l|=@p6IJ)KWU2GC{TL5D^d^c{k7{<03vPfDv@kXSSgjp^)=dg;ey-iIVVUqo8m^G z=qo-HH`;H5!a@bTT7u+;pP|5ZH}b=~X2)dE**dJL0hl!mbZ@V=Dt+j^fAiZ|Lqg?oE?0xoBed^sN^TinSYDK2#UMaFr@9F@`) zD6*u>R=tEL*{>nU4Z=Oik~v!?l{xQ5%8ibaE?Y&FF723=qoLARr>J9w6lozN#{-NH z;~n$$d(9i0J3pxGV+Qw}ADuknE$5y4URO%4HV40ve`50YZ{+{nwlIE^ck;>P{KkAb6G=Biz zra|2ySQLLYqk|bf&VOuPi{Nd%XpA;WChs2SU(Du7ot`q@AAbdtQ^ps%Zzg|UAmE6X z&kR3@vBl5anLohad@&#(pSdp}U~H~4`LJDyKm0VqD05g~K!6z&7|?b%=mvafu(q&&knR{r9*`)uygg$vi`o)Od z2H2;I7XjCG@ebfmT`Y*UMg5HeA{>EoWBj4m1JK`m&_5u+Hr@0e5HQx(+DsgPcfPOx zW;55dS?_PVY91aCP}pnx?=~}Ux1d0;arbRzrGXU#y_)=CGaGI}iO+gpb5j3`KK643(nRvu;|rxV_A%o{K3|ZgBu)?XUD&OVk8QVkcre13i?E&D zg93}=T1dk0KDw_8KU|`JhSAGa%C35Wfwr4wl_6*(i}$=ef&%T+N|@`0ApBPSD*AfK zf;OTDa+KX%I|Mnxs%v3`fFS!TWwp?cLy#jZA{Gt{2r7s3vzY5KXlT!Y-Qs%>A3SPg zZ*?*RaYXNt-Q>J-xxC#>?GfZ}^EP9L1{5qM2mD?m&_VqNb?ZN*|43s$jv0{eKV)?8 z;Ujt**DBi0e8qbe^SXz^(N8{(8lD9Pp%$wg_U$nHp zd8~Y|D#=B=1Rl-fSGC{J!M&>v99gwb|AcOR`{UyEhmEDp?`zd5nEdC!z|ZrT3mOGE z%@YlSf|9+*1%74E8QVXh_n_#Z!v}XCnf&d9z^c!hXNETRPp-5lux=-NUVk%BN??E^ z)azb>`O~<@t)G z%xigr%6X?Q$Y!)R*NqI%ZwC7Xh1({Xo&16-N@QD>wkqj8X?b4!l=ybPpimo@|K_~LTC+tyh(?&h@&%Q%cPwl!&lgnIyLXFR z#(6VeK-v7}+QPH_Y;oqdVB2b$`J8}$W-WpKW_N)Z=1hRk(ZJkBv(e_nBC|_+FMgZb=xW+}zfd~&&$*3wtUqwNH}cudD(CG% z-tmR<7%k1CO)KP2PR$=QGPw169DVe^yhczdeT=f|B~X_Gl~oTxU5-{(y(;QBWTn+> zpx!w7)v%z34vdR$!-Fc?Dj&f)JOUE=jNC@f3MgPGS@jUqBQn$*CbzB~>!Arkm@FgRfW-07mU6Xm`j0G#9id?6@HoN0Gmh{H??T#8bp8f@pVL z5CQnq1H!?)f^HNFNCAwZWP}K!K_y~8;vnKEL9`po`b6S%(i4fxNM9ug{o6_3M?3;_ zi=lTZkV3|%#4iL9`FDbl`-ymm{Gj@pU!GWt*o4?w5bfdw;lLC@IQ|N8L48|6#aKbY zCP6gVV*XICdLj26lJAlHfau*o>&ZhbB#35(1!1Qm>0!kB}fCi6e;#3f+b=Sqe}v zjf`2ug`}?}zDoLQf-vwV>Boqt$xk8wGU;Cte-cCneiMX4e+ar!_?rS{BelS@L>I9= zu{SY65beeb!jZLt2;ep14$_lZKPCwI<3xLuuKNJh*vu;gC@4Ti0I>w=6^PG}UQ-Z; z8c3a%$(6LBZ$`-w+Me@_sGKOy}J@do+dlYftNTO;jY zPC;ZKzaShcn%JEAmV89$C5vd^m)W(g2=!+K{+?Qstd+z6iA`K zPsG27`Jz<=!=Koi*pAp$5CQaLy)QAI^fAPjNS`LS1O2~*j5Wm9D6m}#V4jnHjCfiQ z5u6u93NI2blkbJ66NO)rSdG|75b`m^DS|TpXOJ*o5D_e4eK~Oh>D!2Jkp8A1y5IxS z&k-+^pGyAsr2j(vTM!Ori{bpwiGp~RR}c==5QKn>*p4_r5OPC^(*z+ukGP2RrNnil z?`QoW@dD{rV`TnA!EZuwh#@HdnG7V&M;Qv@M* zp7^7i0zP<(R~R{n#RL&SII$5ime`rtkLV^&7lfYK#Cd{S@U3U^-y?oXzWZ|)yqjym zqJl77Mi7e16DyP7mi(T?7s($dh{!hx!r(UIK|$zyR}lJ65Kn8q+qgpkdkZb-B$gFK zg9?IB93=?F&4{t2cVazW5b`65%SnG%5DuIsJ%xB)@zMW(P#{N3Ef_?sA_#@mi5&&u zKzCxiAQUH%Kb|;={LSR=BOWJS5`^9>f-?Udt+e8zf>2mS5cKlI%7QT5R&XbdaKsVB zDa56MXt$EMR}k$E5s#66oOlM|D)eW-~^9Vw*lURyaj@VCdC%y+~cK>2( z0aE#Ja7u#zum$97Aj_h;}2$pGNvDLFnBCbc?`F zAprLY!nMPKP;`uVoctfie?atWqvZ++LSc15=&3_=k>7;;aiq@{gq?+LxTG;DxPk)5 zC~%GVGtv7wZ7{na43-mw!BApt^6L{jlRlIIlJq}V|C{LFNw+HoRI{>_5TLjmF`QVJ_`Dzt4JHmJeKc`8aW?TV@fh)f zAQFCs_3Om1J8_|r`*|%;gjk8#g4l&POc0KaBEBLB$CeORkiLePMEcvTzeD_#^y|;d ztb~GZ$oP)D=SVj;TC@+W+*;o+mV~Nj`-<3F;bT@Gd=`)B?^T|jeVH@!n>8FS(q@O2#Mf|q2 znP=6Yg6^;`+R?g#a4>?{NDvMVB!4V%7I6h}EAeeXw0}ns0bUbC`=8ChQ%c^t_Z?o?`~S4 z0I@XjS)z;BNe~Wq5k$n}1krv9aW44_h+9bCL)5=oEyS zTI9zNI}-a7CkUe5Wa2VGv|CTyO!`)h)s4MmoFd~4@hj4QB;FzYH?u__Yz{W)sqHi* zb`XT$-B|BQ>?;WSbID&t+)g}9JSPahFA#qeM7!UJ4@ft9DLJ>1T?!Bg)&!$8u{P-q zi7})%Cw3urCoUo`C2kW$AbVNgPdq3HdtWHN8*2qsz^&fix_0gD15b}P+62vmZK7xpN2J8i}u){}_`1mVDS!JRhaXQC}$*9!{5p&(*) zLCDu3Mv&epo_hf;$mm5zKjL`OrxIt8K9{&s5Dsi)J&CwY5C%Uc|2pwD(Px-;Fvl<% z6+5ur5ds>NBUTaw{aMzV2*OZnK}6P$*opi}k}K2-kkL~K^W{Oh<1ZCx{Y`Wm=xGV+($f4yd;Q* zR|H}3wjd1tK{Q5cdUiq3iweSE89}rwPpnLSTg6BJ_f!S!+YnzSnu2J!LJ$Ub3PSOI z;vv$Hvwles2CoaE-PgpM^{Ij|^ok%F&L=J={~-CNh@TO^BmOOjc3xwFk|{yh3)bj1%8*fo zj3_}EY$}L`Es1T&A4C2O;!EwK|8FV4V776(VNPOR zK{Tu(2)>Khj@X+xMi2%k2*TieL9|;=Ttj*i>jwp)?_EK;f;k}t;Aslnp@4n77IYFz z5^D%TzP2C?wiJZH4#du+_hx;JAPi0xM7ycPnLxE$u!{n36VDL85JZD-1Yzh8K^SsO z(3o8ibSLX&1!1U)Alg+Y)*!zD`7McECdm9pg9#LzEC_|G1Yu|saVzP2SwAEQ14l_e zOZp|^m*n3d-X;A{qR&LMhus1bW&WcOOhP4MV?h{bMrr9-#b)m58ClT7qyaiuGtgIM$x@Zp8lNt7R}8 zQh}qLd%7@?fq4{INHhf@u$KIt#KXiZf>3l_5C-j&w0usYpCIUgtd|sod|A?KXu8{I zK!GL{XhG~mdJp0d(uWi05*H9x2*TlwtS1S=f&HW(C7vSxj6&=drjqfkATseY1%4s^ zPJZxY&3{G^k<=u%7KGvFiQP!=NgPD_DAvaa!m*ixa#gs10xK!7mIB*Ie}i~f5Dp#} zgaapuACdnH`Mxh{elB8JLD;EE3?n@psMi0HWHcqCr64@)N_t=7F!D!{KbiDd#D#)z zaD^ZoTtnPI{z>vbC;i$>GXG&H=gYc5UP08$3&P{-#G0f>u--%v23nBbh4enec=AV* zKZ*32#Kq(=cBeJ;Y=!U|b>p z2jT-_?rFMRupru%7KFnwg2+&7VtdlNu|7Z$@ z#B;>Yh+h(aApR~0gMSLb!I0@1s|m{duR%fsLDXZ2tp(Ar9r@i!A3z)_h|G-_gxn!z8>EFb z=`&eh%KAFiw-EOb4-(%aenk8q@e4s1{6-KCmY%KAU0DiS;4ukxSZ_pZA&7>p$?rmX zA7Z>9GL#?)x$(qFxEbkCYBdO zyUOI(B0Wk_=6`c3AcbuOA=r`FSrGh}$zMQRN8C+3N<1%!_7?@=-~&Ol_nxaUhal+r zSuX}u=l_yq)FdN<=py|&)_br%koA$o3B+l{dBml}b;Rw0aPW1(9X8|gT%P~GqQFfu z?y&xV=siz2%r3YCwJ4Z8>;!pVY2-7Mlf(wDNnK@jqrNk2&Xd&HBZUu69o)^D-?J5XK! z+ZSm=If(^`MTupJ)dgX&h9Dg5P8>k~P}UPzpG=%3h<0K^ShzdP`y(LFgIdroas1QsOp2DB2|m!zTpM;4JY1 z=~r3*RS@#`iN#DUUrP`UL<)lMA~qr49Zvx_aUO9EagQJxCJVxmGlFpBBJp$5zh?bU zLCD*dYK$Q^C-xCU`w6=4HYSs?SP-7BVtpO)RY5d3P5x)Z?}&d8^Dff{^9#b!ih^ht zMyy486ziP??YRE$LdH}wHYf(B74azP7g@hdyd?;S@3H=XXe`%;%L#&CgBVS0PaGg9 z`+q~E0FS2$!sB_wMWnA{eXk(o_Y?mndacm(qJk1J>*2)af^eiQ>m7-mfolH0Oo0W& z^~Bx8y&CH-L1=6t2+OUB?Z_Wb{%qn3;!dDiwCxcB z44o2$q4UH~Nx#ne?}9M!C$Z2PEnh_t^ysg7t5R-wC3jNS~|_2kog8*hYZ^#8br2h(8HJ@f|@pnDbR294tT#6a>8_>$L8a#g!qym1e3B&dAB9ha0MC40)AbyJ z@Hm#(Nf7+58^qh>|4OvO zDRC?((O(dmDn+bHtV3)sh=89by1PmNf3r!LCkVqI6E6$m?;7hjS-(SkAP9xVR^84| z5VSyIDM9ed5o?kjq0wzLC8MPv40okKU*a(GM-eBJK8v_W5D~8=e=Tt%`P<1qNIXUS zPEZzYKS=?Gi*FMGwyOnE?@NpqL`0)lpUC=jVxl10Eh2v->D!6POH7 zTo;7l+Z6bN=)GMV$WHVZM7v_dN~DJp>yqA-_#Ck_`EkTSK(%O_Nr44KlL9M<8%ckS z_3gxcq`yr(@qaYkbzD_h*T8X5jEi-#uIQj(AvWr$SR;;wJ_dH64z^<9SXg&ZFfp)} zg${O%f!&JT-Q8V?o$uP5-}}dWzGtnq&))l-d+G)b`IAQ7kelQm;T!77n0hS_Z5g$( z*`l0A-IckG`d?Aw(ySdaoy+dT$J;K9u@+oNeB;n-#XvaFsj-v&F8?`G8X29y5>Cs3bk-n5&J7EoA@3FJ2$wSzY7_^?GalEJmHU7ZyfmDYKvxD2snkXo-Je5A0*q_Wf}f`G1I`a1!}hxRCr} z+-T*UF1u)On8IdN?9WTM7coH8Qb=SVZ_vAmL>jtZy(Ww2{vAEH^X)8@4z^EP7A`Ze%TRwCe6g-KANLx*<6+H}yd3jj;pv zH){Jq8(k&2!RIuY{1;5U$?7;AW;1HPzhM#b#j&oX z{u5(kGMg)Ld-5HP+JAqe=7(W4_3=2D{Bq*ec!>OIyg>d6-X;Hx_?4RSB=&*$TU>uEmB({_FHagj4bYFck>Wf!-t7T22zKB7@ zO^DlKXQQsy9fy#Q#EImm;5_n6aIKp1-RCZo&}}=47x9fz2S~ZC1XBQ77C7 z2OG6MoH&|zGKx|An@4^1HeS3bKUufHDO~mP87PO-r=xNk}tJ9zn zcB0-5SK=DnV$}6^67R*M)C^0$rVG3qsiPw2YKnot^}?hy~8cAOgv8g&;IH|oSo zV>#+=srSU8IN7M}rx~^1RYvm{F&k4B^ihgJBJowDu5c4`@3!K+=xfx86(=r@0px37 zee#WrI&cT_-Hqnr-Jb@7XfTQf6LF?dw>ZwI6N<;B)K5~sfiLivQQN29qw2tUj5=OH z^ixwV-epJx8FhsQI1#7dY@>D%M;wo<$Zy15UuwoI)R)ARh@V~ENIkx3F4YYZC{uC1U2RSpH73>6yk|j;YOpbxRv@5@@Mfn z_1n~+lTSvML)Q9kSOaSxGUvZ`+{h$!=FKRy!cg)(@o(~jjk;xH$xp?()E7`+MSdgh zHtHTdWYlqw9Wv*?E}Wvldm5xZY&Fb=1+aoq+gCQ~1ezLk;vpDHz9(^{QQJq8KZ0ke zUviSTP2vf@HR_7*skL+0Pa32;W;Muc)Q%nKW7G-y8FfM>(4TrM>fLZKPBd!! zDR>Ic;dP_A|KB0;0ACt4{{erJPjy`Lx&>K{TF--pj5?5?QR}~xuZDGvx&e)i+O8S4 zQd8bWJ83W(7vKh?uCT?Z9iKL?a&@_aH_1OD{%+LvE+?$^)v%6nmHx_Q&YZ1Ur2-16t?4jJVE^o-XNch-!aWO zYvS%kop@$+kpIo7TV9m7>^biL6=+z8LSt-0zCHFN|2K{_u5)#njZ1Jn?!u#Z2cH;q zf-lZ-{=YE^-Q_;#tquc?+Mt$EXFQ&G67e~_Zq)VeP=A0g$$!9~zeyvMUZOQ+Q!!a5s7V!Ovy5;$?IQ7z3^H~k5P^g8Cjk>E_iT}hg*_-LAW68|IWw^tr`)rR< zhq`Rk_IL0h`B%hl*R1yGB{)X^L7J(AGceAmt1lv6hU>_0!$k6jj5_Qk^0)CR^_SE? zlXtyt^`F^j{$=H?)`CkjY=xmlok&;Wp7=NU;TTPRyiq4Ihx{V^kNSG*yT~6(Q7^w| z&4TXgt47_CH}P&t1O1ca8&*9h7RE|OZC}l(1Gg~hggano^1X?pjM{!29yglX?`abD zn^uGD=w;Ln^Ai`wQsgUQAo*HGok(-??Xf%cUet$>k5p40zbDgR8eYV!c+aR4c})Bq zlgWR_G`Fk`uo-nCo<_3)Se$xk>Q!!W`qiRAW1~6hX&8ckQ6Ecv7B0grc-(0As8J{I z*r*eDgYU`zAkO~(e?Xh-wzWcgqju1dI2Pv`wWEc^D~JMO}_K<7Rh9K^JDtq$Gs zf7lpX8+AhMi92E#`2jeBe56q~D3<(OTw>LoE-PrTiNbC?ZZ&W@jhXIQ6Z62_Mx97L z;sRKl{O?$ed<~;cqzU=9DLP$Uy3n8p4F=L+B#t-gK^be*T|E=$P~S)W4Bo*vnEJl8 zUOJ;rAfHhuUc_i_za=P?r_jKt0|k>8;(5f!@q$s;ze;?M_&FvUwVzMa(><`-+cCGA za{J9|5<0V@6v|?Cqjpe}`Y4=8eJb%B;zhXHsOznxzL)$_JWu`d19SfC!1pPYfnddANl98r(vDhf&8p{!m|kv*HCB+@irf8oVO^5mP_1CXxn%BI;|&Z^ivaJt&VGbyuIp^VGjkPyg6z zXa0Y0rhO5tV$}7V)y;xVpp{W)9*SMb_az=<)DKTCX(IQ0{&pNvNB$AdUGaRDrD z)P71^b*D>p3PISE1}&`yE}h8t!U*aksPDvs)Q=ILC%%CXjXLmC>Yr2c=JkJS%{YTm z8)Px+9?3(#AeNzC9*5v?+=Kh^gi-gzS>lU$i~M7wIse~KNH*%gsh?RZX2hIEomg(8 z)(ev_g;l6mM<KWze0Lm3Jp#8`>TlFY95U*LA16MISIFPRXXIZQbs|5=r+sa$Z#U|OWH)Nv zo4g;EGwKml#b|z`T0Lb!?_o3uqrp&|fD4S;@gjVPPqFA5t6mZ-7~2e;gK@3?yX-U=f}^O9p+1fLJX}HjKYWev@S9P`ae1ri2Do7+HRbHiX%gBXAB6%& zok&^oRj@YodemEx?|?mx>-5(GMjdDn4y7JXeLe1b>zX%Zg^M)2in)`l4)RLmNxwNP{ahc#I#>J=v_FA8Q(Q z;KD|oa49TDzAAAuqqc8FelGC>;!{Sac68Y+Xh%0FJS2XFAC214SL*KXt@hc_%cyl9 zqxM&Ve0ltndL8P~I9W|OMyHdQZ`6q_#kEH5cmwtQer}0BL5n{7ez5vU zgEpg%Q~CpUpg&AP8#cmDH0);7Epi%lg>g8E{4C-%MxAH^`DEfx#Dzav{gg6lKjnz4 ze&h~Rn?fU_cGQ#xoyhmXLDYv*A47f$&Zqt__1pM_`b**u#6O)Zr2AwIoWZDDoX4m$ zEr=zlm!V#bd>w3R)IHe7s2k88J5mp$J_hHLcdj)H<~7Cx6pk6q!Abnkr~|w-YWuhN zp1R|+=5@lq8MR$8tb{?>%&6^JTd~unGl>|Siwms=E~|*w5$_=0OMIO84Dog1d&JL- zI^kECL_OCRGf{p0eNz_n%Rj7xEiuff9rQKo9vN-aEr`Kb@^gvT8FdeAHR^ghaWD19 z)IS)_4?xmU!gG67@~g58wqgSWYi9>8Fk=S zMjiMgek1Sp-O76!bzmQ(u2%^Cs5hqG0sEp8r+hc(zjm2 zeqz-1-WYYgWc)-u?+>e90;^&JY=_}av!EReH0r?PjXLl&6!QNPZ#L?{yN$YDA|9gt zlKMBy@Y8Ca2aDk!MqS_er&-W}+ZuJ?&e(%|f8y~*U11W&li!3V$)CkfMxE#{;?%#a z_0t)3oRY?M`ubP37F-%&JM4{-MjbfXs1uDdY6r`3HTg}%Cyd(u3_c+L5r1JOmsHwL z@Bbbt3;I9*H0q426W7GLMjfy(^^rIk7vNglZ`27KHtK|L8+H9B_>%kwqj^TnsIAQk zb}VSrdO@BokHHB>T`z(9K0J$e@h!Tg(r*BC*(JR$n3;MTwF5saNxlMc zL!-8Df?dh?#aQw)ahFjidXV@io;2z>$*FYzn+B;;TMe^fek_BvjXH2WqfWG=Q9B63 ze&i#Fry8~W4BSEf0A4WaxHnSkHvp#L9U4BMfxDa4z!Uv20E4idQP&SO>ck?9IcplRbz*aH0eRu07TZ(%ACz=KA;4p>bc!B&)e1xyjHNCZ--KblZ z%cukWhThccP;Y@zFXU5Yu<98wJNjaIqi$HW44nTpOhN~&O@rPv z7>+SGAOFLBMqTfqQMc@-Q785YpOa4}cF$#2qn=`~Vz5KGLWI z$C96mOQ^4)zKQ&9JZjWE;5=&wPuHV9_6X|2r4H%5W z$ww2O@?!sJhiQ%xu)WgSezo+m|8VALpdx^&%8U z;x0ZjYKN~=8o0Q;!*Ar>>{dM!=0rcNWYhtx;Vhhsi;dd<3ZwZN{67ktDeS=`corYv zd!z2k??zqU#lzCgs2vwGYP}NH!#3CxN2)0gA)`z}ciCK{cCZ*%kWU~!YSaNwlFyjc zTCc28^A&I?j>NG>?Kg&aD$dEuMQ9NXR^ui-f>(_?z)dWd&5A2xpiu{?O?Q_crPtt!UK#1F<&wM#Np6 zWQ@FHpI{ro%->sS&NcqV9j5-mAQP=avqSQ;ODSw4h ziNc@Qm|<6!*9 zs2xTVkH=}`=iw6aD~vjkZB7b_c!CCJXmEr4LrkLn0W17wO{_B3H0nfxh#O!F@*S`{ zd1o)PpfedxAsVO9U^?}Ma%beZo$KN-Kgu|HkvOX-kAj*_#3+9(^&I1qvrD(b>PBAU9l*Z zq~4r*XB>c0I0IK0b^ZU0+W$T^(x?N!H|mO?@jLYb-d4Q~*1#s% z5eFG{{h>x3c(PH)6L0SS^C>K)u*0YW?>Fj-hw(V|BI-A z4%`KM`Z%q^-z3Hvb>OK+U2z7^HtLFdjaomAxA8Up#H{(P^>Z3^;F3mNzXDbvU&~1% z#Ha)Qg#*Zs#f9V-<8h--^T2@<)m97`6Qa{6yZRkXcXf|M|^=HYkh@j5^ci#I3QNQ3r~mJ{=e1Mm&I5jN0!F zqfRv0sOx`6*TNc`^WWVpXu-#*D-^;2@-?tC`R+Kys1p_9dAQK1{T-%$2_NAHOyg_L zf9=3i7tFw3MxD^_M(v;){z?9S#GQ=Vz8gl8pMXMs98u2Z>XVih7 zQ~!eL{jBy5EM?So<%nw<%|ywE5ceeR>of~G;7A-})Co<%$wuvPBlQ!+w}~Gcm+Hju zHFcMw)_UoT+J82q_Upg`>^Q5Y5Y8vJpP^zN-W5xQql*LL|4I5$;?1)_@^36nF86Mij?zx=Y zYTSrhk~%lHVNVG@48ALtrjP0faxB(`{f!_$Yb5SBoHsp{=>aNrbUD8|UK&+=6>>KOVzVcnPmbV$N|6TN2?1Nr>}t$iwDgcF+8k ztnDm}<*|~4CQWq6kWo?I@;ileh%Ay!ow086(v%oYnRdz)hf&` zvr7lq{l-BgrY8)cVW3sT#~Et|hxHq9Asx0S4B&83Va zl?iZ2@t_cW5z_Rw2aKgK5vQZzGF*ilaEkW)veh+X2cm!Hg$$?(z zgML^7f5!m%5!S^K(10))TVp%yf;})C2TJ5bJq|CP*VANn0X+&nukf*Z9-(>yuj6fT zjnQ-L3*is(Y7nAFPeEPpy~E$`S)qot5tXq9)|T)J0S;S7!mi@+b)v&>6yX@0jMH!~ zE|7M;yEx>1hcJ84UUCQU1fIbwcmrSH8~lXdQaI8LvxlfbN5Dguf)=+eC-0P)%zBev&X*59%UoeC)PH z;Z^wXzW)=+6NC+3z9eY^P1 z+MM2Q3nJA(*612iah)Cu(d5SC9E_8Mbv_QyLxjih8r~BB^?GR^&?(Gr^Q>)+>?QFg zS2tF-z^zG$U5X_5*rjfj0K2p@OHYgHfizB+Y%5sfKS@Z?H7XXXo*`_(ETU@K3P1Q+twCtYTPp^T~qU^TCRH(&yE(r&%()Fu2McEqkSDNIMKn>I%8Ni+J{ZSfSA%9=uYmwp(g`?}oBes;fe z6fWT{yob;5l{9D*;;^|kwC0yadTZ$ELs$qa;~x?^PtT~<$LIK3 zg56_$ZJC3u@v}-|UA?LlCM+s}3!@yKwF&ECOKdA~v->$b2N4d%sW?M|5BWH3>j^hW zq=xc-wjO*p$lZ}O?e$q9neY?-!qiQyX=T7HQeuw2)hIydD+xjRi1;UA9c+Y6u?P0X zffylk_NTAlxsz}&p2qVMS4>ZgiyibRJ6O!$?*5ZPs;2U~Lr6|r&ZgGva*J2Eo?1`q z=@qvIx!N*fuHH~PhlhFFCX<^cp^J2Ht|i=nJ5c}K*ZR8euMyso*i13{mXPp+#A_&@ z7wP$PG?SjhxfVy+14=Zrrr?i(SPL6qFt*2zvhrYhUr!;Nhl_E!BrcBfwOuB>E}NZQ zTFU3lF?L(g=GKTM#UqQ(r^-KFylwr+4Ulsu^o`mq!nwEzm*E!Nf&1|=Uczg54S*WEpg&?)}Q^m5f~fgY@z z$!(W#lgo8l&$*fd!_La4FJ0}nsV%MHXGr)NJ-izqP48{nLvFvgHV*J@{gm(}CgUgk zg{fOvUAbds^gaR zcoA>l9ejhy_!WO*=GN9mW|bdh^z@n?9AI~rAy*!&VGXQ@4Y38b!H(D!`(S?@iX(9h zPOx;kOd~N17vLgXg==vS?#JVJ8ZYB@yoZnQ6(*%9vsOiA4a(5Q+A&$sfq5`L7RD0j zj{#U!yng9DV!$H3uXH5W6$jx^jKpXO&Y@@Xe`EAkyX~UBG1yDtfb6=sT=h z1wGh`tc!Xp2P^6$KSCk24WC4z~X{k+>@Uz5!8$<8Ug@z$Lf>*WpI- z*c|2Sd7tnxzQ%V_wW>birR``<&KC0=`z&t7`>Zb+_)jEK^EWmm$U*dGUp zM~FU}R@@S0_gp}35w60ul4-R*;SAXlP(}J*W%09vF@TaRf$UEY8F@jF-svy2rae@UaIRC3g}p;1zs~ z&oK!<$gS$St+{;6)8Rw?AgojuYeUQ8pI8SQViO7V(Sv_R?$q8={fb_w3$E2G_y($5 zB=lMRlvtA@Uf%G}i&EvwWzs=H^nBSN2>*Xn&EW*e?^O&*HR6CX#wXTtC3*3IfaJ=!rl{)XO?W2Vlo zI$=#o(B5nv2s=q^0o~RWyYzB2irg5Sg>x|;mrC$c?P4F{L5VftUBZWwsG&sF)O(g& zcjkz8%#L2@gML^-N=(#SNFZS?IkjHTt*g8BVSn2*eca5R(9hc@ROiXPg1QM+28Vci z-X?b+lkkI_d#;nZSW9m?y9S5YZT>y1nf)$-FMJ$+!Gz5*1pmTt94HCeTxxF6OXBAj z`XVJz*epJUbrRe5M%i26B6km;;Vb-rU(mIuHJ3D)2|dsgy=3SMM3nYyM=lh* zV=oDOr4zi`S&yRm5h3<~r4&|T0&d1bcnr_sCF#9U2YVS2Qd;UJ>W*Ks(QLD?eo9d$ z%$jd`tcEqjzetQ8=|gqcf#f1^0#3%6I0qNuGVu!1ljj)WDY^GXHz&PcjJM1P(igAQ zTixk?y{rk8kl43c4auuJWH`Bha4b%g;BI;kUQW1Lf|K-MJwkXwA~lo&n|0fcCTZ8{ zdRtv*5Z8Cw&X=&51e&l8VSR}-VK>4sNz_mZ#_Emz^E>TjIfd2YpR9##-SySzo~(tZ z6kbZa7Hq!=Q%gcIJ$lj~(p$E7A8Q5$u^5)Z@>mJ$V0}3>BE(k;PSZ)Oc(0ecu@ola zG@ONT7_WQLx}a?*vs?T>=L?($M5JOy&LFDmc6ev?_5&LN1uVJ6V{aY z!%@CLeF*#GP#lS4aUxDf!4>$Q#DCQHc!`9E@D!fI`}i1N<2(F@zc5|D|9{!TKj{lL zJ4`>j_?=vU1eVl~a$69#!H(D!`{Lgcsm*Ou31>*?XYH|BBRzO$f7WZ)0JC&dmuy#Q za#NDDiR~@nd-3_AVft`uN*N_sLqA`_VptX{U^T2E4QA@6FBuC)cuV@PI$lhqeyBR1 z>c6-G|C7+KI@Ufyy_9PxZaegJXw_TyK@x=zQgv3C!)fbp%_$S+Ku`3;5?Br^VjZlH zO|S)az)sj72U)tij3F^Wl8);eqwJyw`;uUPZ)tTxFHu9j>tX+eCO^>aZ)?u!(G$HS z)L+lJt7gT|x}vP`kMXueP#q!RKXgxg_SgGz=h^z!DS^Ufxz)tq;XFoo3NPU`yoZnQ z6(->q{DEl(ShKXD2j;*+=x6EfQkq0LIrmd1nya6_T5ZU+mo-iG$>(YreZ-waE>=G) z)LZIO!jw`*5?X<2gc{Unsjn))9V|QuSQeUgi^Ys{;N^XXJDOx?{#aT~g6Yj!&cmz+# zxpPsDpj(9Z@F~8;Wc-9bG1U-ja#=8&RBh$&E8_;}K~b z!=M#}|KVobj)`~(PvJSdhPNc{pgwUHxuRdXyA8J{nO;09>%BKWVPPzVWw8d<7T1UX zUzwdrkE^ldCd#=?I_c$vtHmR;zS2dm>Se!G=KOZQClp@bcXSzHO(7j-5T7b~zlgfr zS$|`oE86N%s4qTQbbxMzVG^pL-&n$lI3NGT<){y&*Yx9vTz2j83Aq;%Y}X#sjkIQv zK|hPv(3h~7Bx)$-_P5n9{yg*|Q|>Q+Z(AhQXlbxSfBx~??|T2=^p{?JK5G-dXH;L| z2mFHWPHU*l;&oI%N-9NIRuZ!6P@RwJ+t#BubdO!Frl;+S;Q{*dH=4}D#kgF2{?Oet zJDYCLS#lR8F`FKVPYGY*d;Bc1H_aCb*>#m%|5y|GO@g!QHdi35Eaz_OUTU^XuaX1E z4H4JsI#RA2x(f~-(_P`ZkqQfYqkaDoUY?nk+2HZ#JboRn~6^@9kDxMFA3Jra~xp| zPDhczJNjYU9>V>23{Q!Vr`eB$FD2B3=|@{L%P6rX^d>AQi5dn~B&>q9FbIROIkv-4 z?18<-tE;{Y;|V88Y;N5R@q|n9KU|NAcu3CO)kCOa9z9%g-P5<}8KSI7XF+c)h{doJ zR>zuH9~ERsmG_~C}ot#K)q+V=$Rf+JnT_ATwPIc4GNhbUx9;5Wz+icO+ ztQ?pR3t%xUg%z-}#NXH7+%+O>Dz16;%)NSFkH;c;b(25ql4lInsrWB0k=@<(eqYz^ ze|plAyC@C*(;Mbn!uL|ET0|YsVq>i7mBMORL(bLGlksG=2)nI2xnAPxZH_d;7@UrJ zq}A5%+K&>Rl0;>9xQ;qSPIKxW&A_J zqXQfzn-aFfZWxCBaZrjf^ls<;ev8R1$91?7cj8_NtgH9g8-#c83BJH&{3JeO^b3g$ zVsGzM!}Lr(^WNvGXha z$kpv)KX1=3RDYn`1Z$}D627l`cKO{me>QP@o!ai%fI={~!Vp<=QGXjTgmAb-K8ter z%_f|WYcK(~;V#*opqKdJH6u#fJSJL0=a9hXdR|9e(l6}FldFU^u(rfq(v7M4CbiwK zE4iLH6h~q-j+YT{^k9l3jF;g0dLHZ~+$;VsbeA2}9s{0{dxanIE81eLnP$Qq=qU-> zrBvA%<{i|8TnlW6q1Yb>;RuYxX*f%KCg>Gy$V*Ne^y zvoy{uZMtGUVKYk?%~JXjy7b;G)ip~iUg@_c36reZZByOqrZ~-DP9Bhj+ZsonqN-Y zeWRbluP9+jtbmpAPpl)&x9jhmyAg&-QaRlLV+kjUf3VIjjxZiq;D0jWgMJJ1aJ%_* z^mlzfeuu&Xe2%XrJXz23haYrD=A33tG`9qn*C&lKgype1*2IR`MB=r%T%D@#o`;Yd zE`d$V!)gT`dJ(y0xE?o&f2=u>4(rwN3b`ASX|V3HkA(W&k_j_U=TMYaA9bG>CM+sR zO=2qewI}R|Vb~W3<1o2bQQvV3;XGV~%Ww@Q;5OWa2k;1<#`6;2R5y8CfSwI+$R$hc zG~L9CAN64**9>bTe#643xAIE*!qyZo=4?#}TS#zo zy`1+X>?7eC>W{bs>^-KCn~w8vAuh+&xDmJFQ9Owk@Cx3>`*LcJzBj2@Ro@8yBA0rW zwMFij8FQeg#0}Mtr7qqzm*^I{d4UvaNm5mPbvhDul^@#9Hj;3Z1Xt5DWiH_YT!H`L z7Th6;+FWuS&YemB;Q^Psq#xpId?)^Y=$P(e%{jBQ+o#(z?yG)hS)N=atbw($AvTdo z-}FrBO4w79zUqrKl5muq(yCParU%U`a%*u5?vPC1Q#(9Q6Q0K#ct=WTS<<)CJKl`@ zy4Q-d(hpXO&9_9d6lS}uq{w82QA69#g5ojy!MAV{Du$?$I&`^*)ZdiYCUrYMuD zSXW=G8ISZw35Qtom;{FC-S08sb9{#%C0xrk_xaW|GE1Zh^Ai>puSoq$qY_~?Y=}*; z4YtRw*c1EXARLLKa3W4Y!FiT5lifU8uOqh+cj8_=ix=?*-oeNC9Fy>agtm+E4agd2 z?SP!#0@nsQ#hqdUBg^ z5AGNL|7n}f+D7WOkFf`Rr0^Bp7I3g&R?LZB=!3aka z_Q#<(633u!id(dPE0WsH?ze&57TkmT@i?9q|1{B#pa+Cc@C_#8H~fX^7Frve0kfe) z;?qRek*5vyXwQCJcWF-weQ+Q~$g9+D4!?~=V=lYy{oA5q9$Jh81Q^~E%T^u$?yfxK4vN=@Wlx=IGx0=S}nqe30AwC`T zsU&Kwev>-mr0(g}6xQKZ+$rIv;ifD4hwL}W-NmP9HRc`4B^0||4(!=q3-S0!8KMu!# zBsfE~uYB(u@t5rrxo>hWgPuvlyF`?hx~+77yr1A--4?OL8hM1=Yo&W@*EZcp+281I zl-E<(ggbFB9>(KxFQaxlyS2WqPsqK%clc3!GHIL6XT$70e3n`R7Q#|k7OP?)*2hNJ z8rxwv48wsKA-CS>E%u>~XnWD5jMrP*a5p?m@MtC2Z`Hxy-L6A9^vh`pTc20h3D`# z-j__bbW?v2x-PfoYQsztH(8&TeFzK5n)CW0YYoEMa?4a(6SkAk_IjL05RQ;F+O=&e z;S5RCs^@aT)wmP)O1lf%^##H!65L&%5MB_z!B6;2CTVNGEGw+(X2U#~4@+TL`7uRz zc}0(CyDgYpbMgO6XWNf(fZWpo{l*YZz&RL)OL3)~dZ*uo?j}scV|Yq-PxW`Sen$8T zKjK$RwbGh@T6AC@EP%dP8ueEcp?Ve$NY+EB9l22KfxU4cMqngH<7AvBYhv|=yNqxZ zZon;b*Wh2t=E;&_~dg7YNq zvi`JZBjHv|#6x%nFW@b_hcECAe!(A@Znd>Z888QWTDrSG0$R$o2KvtQNE7GINlhhOjqy8UNuKzhuA z*(5M$w8OIyp&ypUat1#3Gd(oiR`W;)V!wG75cMQNltc49QSbpe;t-BER zz;GOhBQO%j<0Op3cwC8VWW+J7EA;$C_9l z8%bzC{blNqFnx3%Om3J=dZeRFB8-)UetO4WO}I`<+|UE*2;m95gxBx^J`taAeJ&bs zLw9nfb=Dj`r0U}?4nIG_5?BE%V=WAlTRNgGl(38Ro~>8dZQ*)qPa+qKb1)8<;z~@w z&2mcnupJ{jC9gE}yGQs4Kj0U1U2n}ljjXw;r&%|et{?$v`jn+1~qX*`|-_Tn^2gTHB-IlNe_Q2ja7>8jrj>qXJ z7>`S(>ODQJb`vH_yExr|?t}G7eu#Ip-R}d1FPM6hHSKihfjPuukUnh{B`k?mF;HBG z#5jVQ6Sl@s?1H^993yZ9M&o$-v8uFwel#S;?o1%J8FynM9>Y_339sROe2lO09e%~1 zn07NSoTdJ+&q?G&Uo3`Yusl}9K&*@Z!=~60+ha%UfxT0dEkp8W4RDehjT3M(&cr$R zFD{YT2)(Q)66%jY^6ML-><{&Z|AO2b{DMC)-4<&rv#!;7pu@@wgP%U;=K(-FOI(iATX`M~_>C_wX6M!XN0m)!I@U zX2Klki9T2eOQ65>j@KJYZNhrk1Y2Nx>?onb^fhr3j+R@G^s~~3@&4X^tI4gyEw}>{ z@sRk8(6jLh;SIcxk0rE_e&F(%@H=MMW^HE{^h7W8Mg4`Ht}X{3>zlt#i}WAl=|G{A zxE9uDy^=Q=dYvle;bPCRcZaUXP9zjxH@r7V9-S zy>GO4kLKI0*|x?|?1Fu;KaRpNI2otmJY0y&akV7kug)lHiJ3={XuD^s z9o9V3VrI-L9=CI6moJeK1^oUX_b1lJM%WVd2c<={^KwhI^KC`+BeFRZ;^fpbJqU6+ z^#{1~-|64Mxjhf7Zgbmd4V_-vJr8rV_9iTdC9w=v!RlBK8)7RA!LHa-f=BBf7)3Zn zemoDW<9CSg7+%0D_!yr{>_7UT@RKmrE^E&2m{}&h(8s9!goUvrmeHRQ>HVo8VH4@S z+~3ioD`8LUkArX|j>3sJ1qJ8fVqA{vaHHJP;hbj)FX9cngOBk!CgBJCjxM{cZBK_8 zFe~OnFZ8i=cPT=mxFqVoaphT!um%QU14)Y3uNQj~_Q4@I9LL}U2_B=(7ZEPQ^|%T5 z;C@Na=Cb6Kp7!Nd>es>_DSSn@Jsggh6?38&`bg3!eb%i;SOe=}Lu`R#z#8^Mv|nIa+^K_meP{_(bVjpNb{*lbZ5-t@&4y@TeGvvn63$ z?1bI05BA5QI1;Debex9^aV>7Z9k|ER>2jFFaXgQg@iyMa=lB{w;#W+y&)UAUm>IKT zZp@ovW&KB_NfgCOSPg4o5C&s&37=p->LS#Sx=QJLfyso^a4s&uwYWk2OY23@ElEFU zzfSHpKE~%#B1x}@D<&c_dmkM*a}0i6Lu31fBoPk zf^dYy$LK9~3gL8|iwneKte&ZR2>0W0JT0->S&#dKkMT9W!>{-g)9$x6)g7~9PArT? zu?&`%5^MFbzDOB8%KswQS%N3)21F2!z-Sz=Kibq)X6q{YciH}S=N=0C@i?Bw%Xl3h z;1hg<$@mR_VY&mnjF=4_mhLY3NEDESDSC8OC#)&=OxTJrL_DVIRcgjM{n7t8axoIF zIorR4`p|2_ZG^idQNvVc56I-lJ=03Y_5SJQ^HhBZc}jzq;uEXwT@G3kbdz8c<|6z} z&W+c{wbF#;Bwni$wO()GPh<7)>_#CB`{N)Sfsq)CGbMDIzCOzdSK|iUB2_=?ee)>c zNxXpidG_ymv_2zzC53);@%3{*WNkub%z>WhjRob<6#d|@?!(-fGNy8IX-2x0Bx$EX zy$Ji^5FCy%I2Gq$94^CEQeuOCPPUiu0G_}zcn2Tgb9{{-@hiF>wl*@21kcFta5@O{ zU;*^Sl2`@;)gPUPOpovm_(8$-D4T~F zF+1kMd{{st19aT-gq5%c*2V@HEQfA|_y+VN9Du{niDPjhPQzK^QAuxo#czjr_t;17 zAfCjtcm;3Z1AKySFd4t$FU)ex+7sC%(-wVK=1W)%%VGunCv{^SJ?axS!j{+;J7G8M zi+|%VbmCZ?h|^K@cVc>D?_N3D?%YalCmz5fcm^-v1AKz7@g4p^*W(-mm=Uv~!!ox^ zUK07y4@-zgm1u|a55hmO9yY}0*c$)B&KQP$aS#s0NQ}l9oNC$AMM%uUMYs&tU;=K# zU3dgf;CZ}^kMNneR@E!d4?QT;d3^vSRqVGXQ@ z4Y38bk#p7ba2QND3`gTwoPyJF9xlY?xEeR&R@{pR@C2T*ba%Nz;)ec;Sl_?AAxy?^ z_zTmWvi42}%!UrkhXt@0mcj~H8UMsOmhLW%NHo>o9P50#5r*O4I2fHc8YkiuT!@Qt z6|TiSxF3(TT-(~5;5MP_;X={IZiASK`=t>cm#Y$LBny2mR zYimo`L3;1<_w^i3_z#Z7i4t!*TS&MVSK(Uy0bMVLUn1clJc(!VD&7>28qvPa)Mu=j zro+sb6?0==EQw{X8rHyi*brM{TkMS8EoE`4ULMX7BqMP=PQqC@7nk8G+<;r~FdoNq zcnNRfUCZ1qPe{DLclc2n?9pd~w=?z6P_v)4_Eav+hXrJWw(%@aSP28MmP|_BOaD;o ziT*0-;U4`cB$~o_oQgAW9xlXXxJoj)_44&RN_Y}4;1!9lsYl0i!q@l#zsUCOzg3VK zZoTY5CC^z~QU)twHLQg}7>vy^1pnF^wBxrcu0403xB5%OV|WTL;#Ith5Ah|w#n1R1 z-7Z-Dr@tV#6a5Rz!?eBZwrV8x&n4^V4W|WR8%fg8vkzf^9D$K?>bd?86f$P)>TTOd zPCrbpt4~tv=jaEfD_-W#BuV@Iv)R5-{UO)p=!ZbLFIscRtG{3C<#3iJEQgix53G&# zFc_O-2>ylLFbwaG}HpMLSw=Al!m`a6g{M%Xka#;ZuBx$*6x? zTTk!jwoBID$b{K37v{qPaw$_+{k1^7=+Xf_$o0knI0T(I8mHkb8DZ+6SQabbAE^Jh>0y6gTPMP9;&nu?m7VQf^&iY4HxZ|!;6hw1?Q|W#t%N)A z03N|JctLL2^&g-e7Z+o1olNc%{=(E(c}+13Ixr6wKwm6{Wu>Y|SN-?N2QESF01Z=KMCvTZ@l%9wJl)>?1o`D44pU@C*pJzT!@QtHLk<0 zxYN?7pA+;{=sbMzeW2cP3A4VPwEp?2||CYih&Z_RJ%E-tH}EtUF|^;6h>e)j>lM>iE;l&(|rfj z^geJLKV{ZesYEKJj8YV3q^Qi0S;)5t86gSTkt-A;ggjYf3{ckK&QAUngIu_(uGNCGV?QC@XTi%UuIoVl}Ldb+Iuv6@?e& z%d>&RAnb$vF%n1M1dPQ5OvHsKa5b(Ip_S#H$hu2%CAt+P&lo-Bf|vLazhEKiJ>X78 zBdmy)=!7oV5IwOOwo+PYT`78CAM7vE*2^dDS;QofbXjg3n~B@;5FQn#8|0mGjd%+m z;uDc%87_a>fLMs79x^BqYc7u&ZHV^hh7Hjh<(Bxb+}G|&>?88bBRvd~i76t~N=|XN zigNG#3f&FiwsDT5?kn*p>OWGqUmA_k46V=>9ncxQ&rs9|;}-dr&29VSHwIm&yDgf_ z&hrcL2kJdh%U24^p$S$+d8)tYD!bXrXQOs>9kDwG;}9H%V{ih_#5p4Gx*X(c;yPiv zRh~@WM?8cl@C;tYYj_VI;tPC(zfpV2x`*Y&up4rvav(aRJ2paZY>r*98}`D!I08rG zB%FftagowlTS2iJH{mw?5BCWpJNaC>sZY_zd95N%JfCpE3;ckevE(xbj3#IYT#cJ>8y>==coDBijr8OK+@{DA z_F?k%)bGUKSn@feLK8H{DrkpJ=pqVl$%D0SRU+m0{?G+r7!DLkRpgVyc;Y0Sjq_08 za-r8xo>0stp2Qr?#oL&NZ}B7kz(OqjLXFT6t+6V)pqo;sHKu5a?XffVz@FG22jOrW zg%eSSGjR?s!X?Gl*0j|W>u?+H!hLv1aSRXxv=>U1i(vH{>dtqPETwZK2nmAtM*hYHj{v+d$HktURRGH=oi%fc%4ml*unyJ}S@-4hW(Q&y@klPd_f?N}cwN;urq&R*kqkTA(#nM@RI)CfEY~uoDJiKMXI{TGOH^ zqA><13;QARo=zsF;CkGQ>9_~8FdNTe4qnIG_z0ikTl}c>*M3kGVySm(f(+0UE20hB zqZ7J_x7FnVd~;%J?1%y4?L+yTS1Us9GPJ58&zr<@K^)G)Buv4jn1<_dJEr4)%)*m+ z7H?yo(n@7L*l{D9x__j_?a->s5CQB_REB5^C>G;NOv6pM4G-cGyoguuHs%SNT9NX@8pPjNvOo>L zESjJ>RzW*4O#XML2E@kL3|nCb>>@vH;^ycyjyMsgVgjb%Qu!fHx%u6Sl8?!!=+5C4 zyn**IA79}+{E9zO|C1VFX*5PNv_e~@zve*UjPBS7{m>r+F$hC3On5(+E8ryJ6r6=g zn1V}1!yNf$$!&GR?L2SN-Nh&P0^j2&{E2_W$Px0{-sH0yvbk`1A>ZFpkJtd4pf7g9 zKn%uE9Dsvy1dbLqwIe+&cM^BwL6l#OP+M+MSBW?A0Y1jp_#VIEFD&sz4W&S=qaJmSL#<3WSaX1T;FcsI}R@{l1cmT8Uq*A9{pty`T z@h;}$GyI0XQ2#4yHC9ARw8I)$8|xM;PDRI?1^d%=!XOO62#mt97=u$W0q5cZG0a8Y z@f(O+FatC3FdoBmcoFYoKEA?t_yvEU_DxMmNo9!k4@G&j#cJq`uIPbHum$>IM+^|& zu94%M{v+0WMS(HEcG$!8B=^e2Ef8rl3{X;FHp$L5^ccUGM&LXs)+?Vntw#4?> zS;UQ%9}DbH9E8Jh6i!4P&cN9st6rp|QwA{;Pvd#KiZ_MZxOflI%}wrE*#A_^TT{f1 zlMjO}h<+l;P40o5crU+FXf)k;oP|l^?R)u>!&>4-+=qwoB%Z}9cmto~Yy6DgQSX;p z!cro6e0&e59>ktF00-kp93xC8#P_f~O+1g+@RkVuC||sPM=Zc!_!rCmRySS_E21S< zLkE#lKhmOID`Hy=!0y-^`{7U=j^lBXuxSwKXt0sERdg(n55v7~$uDY}Uf^cp^oa|; z;a@CKs1~;ZT8O*`a=)@Rv92hT(Wxb|4R*$^*c1B*?}m{ULnab+n1G3xj48MRSK~(9 ziW!)RS(q(W%A3>OB|gAs_zFMb7yOOdA2s$e_z#+4CA2|%tc7)y{#p|XU-UzN?20|G zFAl(AI8qF2B)9n)#M!tE<>!=Q<*CscpXH~EuhQMb`9fufOByHF2hvZfLkyFGw}!>$MbjzZ{l60q4t>Kx#;*sp877K>1jo0T+3j2 ztbo>76&-ZRzPdT;8WWphM-0Fa?2UtPD2~SQI17_-5iY@1 zxK^ptwo&ZDy?78$;2FG)dH4ih;CuXpKk*Ni(pU3gP^`74nNXOcHCB~BVIiOBJ&E4v zhyK_VdthH2fWvU4(3>is31<*zi+G=K4}&Ab<07o+(woG)B2Gr#TjEF5N~mQoiAHFO zR%nZkSQ{H)V{DGCF$hDH^|byJgKz|n##oF~iuYx$E0vU6r~EnFX>!M7FBc!g6Lja07>jW@ z6Xz&JSMNyEAsZ;S;BMTDNAU#aU@qRl`}iI|;ZOV{vb^QR1Qsp(lD{Ck(`%*heY)`$n1?jG>$$vVO~#d*%@r;tE_X0%pk9XATpO;d#6y(&WXW z%F_vbJ)4wK!|=r}*bPH53?nc~2go#e*=^4Ann0W0Ch)-epci7i@ryQ;gi@%Pu7OvP+_TWQ`z3;TW8NQ*b)Y z#(B5|SKwCMiTm&np2V|C(PMVJslfxv$0D?)JRzuOsP3IoXpClPja9K0))9|p%ayLf z%L#V6UUYqNB#y!9I1}gLLR^NaxE<4RKW5=6Jg2nM?oiyvXDC14ukS9;E6$0x3%2-2 z4b&Q|qa%7?6KsiXFbG4iABKyQZNht4W)L&+Fdh>fOSoGE-yq(>e0+xA@E4XWrHnE2%f@on2Xo(9zMk9 z_!mq!b< z#%kz*uIP?l=!1UfuQb#`D0&N*PI6B|N1TT9a3QY1)wm6JiBP$(%hP|+_@a`@CAOuUrIx*M5X`VqshzU;Z8N81G=KS7-k|Dw-YfC zL$EhSVKm0zWK6(BT!4!)71!Vv+@bW>GARz=F+7DA@e1bSGkk{y!X;3yjHVW9^cB$t z?Xe+x?sYPsjR_X?gup(NbJ=R1QbVE<{ z#@5&l1F$;|#34$twxYYKE}n80CSwYCND+i?%>$80=_Ihc#LF;A(}o>IKTA6ST` ztkoCOHI7ei!iFa)GA8{WZ#S?f9Z{b6Hf^YDHXudYyBiP194bC2&&;=W!C$__m*d2qh zFAfk%!SYo=9dQ~iM1iYtEpEk~cm$7&VZFmGboYt*_zK_QSNw_kwrX^x(HPCp3T@E= zozWc|DXlagiWcaPokVPi9Bw~iI7VSK#^7X3z(ibt@{{R(X}pA2@ebY>-l35ehJT3q_M&%aWTjvWdo>no ztd5S@7@J}%Y>Qp68}`ILBD8n?voaZ9|3=L9Z|#RN>m1-KYfagA{4Bk$@=;sHF4 zr|}YA#k=?bpW|!sXp7wUD^p#KHd(F1+31$M-oQ zgy@TY=#M?I4~Am|PDCBfz}dJAQ*i@sQ95h;DYEb+p2b@zzcy&Q+|a%ee_@H5te0ql z<|1p5TzAd;$&(?U2g#2#H|Q5Bzhu?+H!o7G?a?3EgaNRT8rczauAJ)O|ccW#U9vGZoYCiquUUoHw@iszk9OsFb@Fw2HSNKlk?uz#?u&Sj-WGg?mBTt;W6C0rq zwm^UEguSsJMqm`iVw|vvln<;a#HE;q>qUCH{OORB#Iu--*D((t;Ya*}g{bGG24#Zg zSOw+VtHb3nU=yM*cEUgm#!%tyAWxZ0AjV=M&c&6OhC47rnC_PQ3b%;&@FRXfeP^}M zrO_IzieZC_&bSNF&_)?t5T7dy?7AM<0ZU_ckvaz!>{;LsnhgbSk2KG&Cm*M z(G}g%3w^L724FCT;y@fytb8$QB*hqv#WxBbwFpk5CVo#-*ah5lUckwYk7s>nMEewAV|GJ8B zix>w>hq~$(ozV>&ijVTohjbx!!(P}IhvO)W!O0kpvv4V{#PzsY#Jb4!|0MA&-o`w9 ziZAg87GlYIYBXiBB3hyYIt#ah@~vL&iJh?z_Q#<(9CbJiXX88(>ne91Gl-cYNk-j8 z;uU;^Pw_K;N6n2pAI-5c+F=cBfQ_*kwo-a&-6;OWK{ynnaV$>586v5!9L{FqcCo!E zo+ai8(=7Q6_LBG(zu*rva95)-!YXJdM#}%LYfNm4?XffV#(o%qQ8*c=Vj|APR9u5w zaEDT-9i}*jxp*D#;X{0jA5p8%y@eIf0;^(mtdAbW_S7_Aik8?Fdte{zkE3uLCSW2a zV~U6!Dfegg5clI5ynxqGeni4e?(2Ofe#f#6)bProIabD6SO=S+FZ!Xs@Q#*C6G4o^ zSd7D2m?YdBtj)!qqwy7-vgoq$EaqSyJ`&#b}Hd1p? zR-_%1kLJ~g4(Nhz*ch8)d+dxs7=mFq5F>Gfus<%}+?q(7D_k1N$HPs;ZMYlv;$b|7 zXE6uw;X{0mudx8XVj=2z6i}ArD)} z6DQ#`oPl$3fk-a;^KHakxEBxNIlL%xi~jr}@d>`h_xK0(h3QH8=jM&o9bXx%Vs&)K zMj}A|xj|cE2hnk?JiO>tO`hGHL^nmG%RdQTMoh)^xEXihe|Q{E<3+rJw=qv-dB_v_ z--y3Z-%|~sG#a6)cq{*0%sf@}Yd>^e!rsZ+yyz8*ZZ!X5AMB427$v+L%U5kvh)XdI z*W-3f$NiWkk{Zhu`Zh5SpW;jWj=%9AFEys}=zz}Xh7GYPHp8yiL+P*eq3Dl8aX5~{ zi8u{s;5=L?hIz_KJuyDAneIMaKEA?tScrN})L=}pBHExm*24za0{yTT_ElPG!zf1L zc$_4X&&pMG88KDFddd6X5b-Ep#4Gp$-{21{#F9x5*Gs^{Zi!l|~ zh?U;%<8-Bc)%|CPW>^Vru^PH#BlO1R7=Ya|6vJ>Nj!`;m(# zWw-`6;10}C>a+tChw(I?$E$b~AK+trjqmXr{=$D+sPUIa3$!j)v}oaOX5d2SCT4lt zIEq`j^0ln~bb~MoqcH|2V-h9{w<~hXUr*eO>9_~8FdK96I_BXce1-4u59+t%?nPsz zPOC^^iFQ~6>!SzyVoUVLP8ftC7>*G*0b`35fm7v{pG=p6D=|&Dw353@S;TBSi#d25 zZ;Py{^3dxG@duV|rG{P(&9Sm@yCyf3#>A%B3ftnp*b4{XU>t#?MWI|+gZacoB28Yq z(@x@UJdNk^D&7=X)8tE=pNQY^FP3Pn#_$i8$EsKzYhzuJ)mko0d!qc9{B`+|)Soy= zq{-+sk*LFYxDc1)D*48Kd1d>FSwioIoVQ!Vd-w!j;0OGSzftp3Ln({p#CCb@V*CyH z)7|yyJkSsQF%W~q+oJz-M*bhmSh_fzg-ODujXXoSnYbPI;C{@;lXx9(<0E`3Lgm%z zeh>?>R2wxK12n~oXp7a*8C|gvdSMIn!%i5eG}QW0go`l^V;r645a*-7<+uhni2W^X z91U`axuR5~7)RX);%6+`miq=x&>X9v9oE7+*Z>=2Gi-$&F+i!)f+<3AAP&KiI0j=e z4wEqjS7I9O!vF9P9xe7CO*>1GBZjqem*2N}TmDRQ#dc~IEYTioq6@lVV{D48uq_5- zC=SFS!pPs<(Q*cHHZH*xB4?(2tMgvsK|GG9@e*FeyZAtC_m>ZzpNZd5^H+l_iRI8l zc+ZkAP1hjS5+@rM?Sc@yiCB55(+J{doQOJ{iwi{hU3toMJ24%P;VI0)T+GL3!X{Df z6E(gkk9m#StK~Hnp|W#wA-Z7;^uvxAAky#2r`KV`kvJ6-FbR`!4Q{~gn2yKsG+x51 zco!ciBedrfukkZ}N38>Q2bMzMjSy~U$E`5N*d;!qrg<8TU2$2mA3({Md* z$8qb9;0%Ck!5 zoz%!HqaD`3I#>^zVJqx_T`(9!#mdfdYmXsL#(12C3sH!t-Z6U(+&inKX(W=m$mi4V zkBWXdcdq<)o55TVDYE1Ro(aT6T!4#l18%_#%oK6?aw|MXyofjO4(8)Ce1`@26aQf8 zE^4t2(F`l0Eml+dYwi?{&<9&!JM4(PurChANb#tVwRs15;w^zD5f|WM+<;p!12ge3 z%8zW$m+z&yLA-VItQ$Zaj1w>xr{hda#uQwKn=l>s;2}JUxp-X}q1~f+h%fOi{z3h&YM2ISgjLWE z9kDjLV!3Ez7fNE$X8TL2XSws8CF6Yv`05=h)uB>w#5#jP~Q5GLBydr z3df-ir{O{rxC+10Q@L^mqP?)}x7ufZ%X*T2l-C;b5XE7JA<2`(cAMi8& z!oOHLn6**lERmbfLwTE?fpkF_ieWeehv8@(FXG4u-FTjO32)#Xe2H)I3;sa8-fEPk zMDs6l-^!9`gD&VMeuUaMdUhsu#SrX`;TVAtZlLD<-Aycy z(w)Eycv&QWlUsku)$$_=_4?Y>^R(=%mdyrhU@feN4X_FN3b*g_igwBCu#BaP!}fc!3(-$X4;EooUShvrxr?XU(mL{Dsnt*||I#vlw) zT4`Yv12Gaui1Z(F$8tV#5vJlA+=jdG03OCOcmZ$V9ejc>@FRXvT4{eM^!up^s(=3ZCAwCauZ|3=p?iZHmuNI{Ymd6Tcja9|R zU-6EXZHVo$EA|j>zvJ6@t|G3*Ew}^s;C?)cCq(vdxsJ9PB+tLRq5B{{{*L$1RU4od z&;ec19lg*8{m>r+F$nu$e;kU#aU4!mI&0G?X5c(ri0g2Za2YJ$c6Wey7*FC^yo}fI zETn%EAzVh`+#18^9Q#HpBob8!JK!&KaW zTa?aP21O?s`B2L2@I1d+! z<|X9{w3E0S58+Wfi#d1$@8D~Ek6-a8mWWVeD}%;prj*|zLt%q;u%0k2C6})iu`LE* zcMQh}9EoFa5>CMxI2)H?Dz3-PN-;Yu#$I=k@(SL@JbZ#L@I8J){h?|SN}~~)q7~Yr zBi2?rYwi?{&=*^xKXwvnr4t-QuYNHmx~X&tI1d-%GEBvtxEl}QQ9O<3@fzO32l!a& zrM;o}fZy;JmWx!gVuF>iibyXb*YkSB1|nBR%eKT0*d2p~UfBfsX?)^HoPe>o74N@#=jSPSc56Z9>z=%+*dDEzT2_P{>aA0sdd$Kgbr ziU~Lu7vNglDAg5xk^K&e4BU@dcmmJhO}vZw_zd6UC;Wwf(PV_0LGuxM#>L;HZ%rY; z@4TFRbZ{d!#8%iAJ7ZVuiG45}BXAUs!znl&XX8Aj@Gwd+HP}kIQv?{vhr{E<(_*BI zy1T>&_yXTxA?l4(LoJKtup(Nb9o9e>bi>BjRH@TiQ?$b_*bN8b5FCkPFc#x*7A9c| zF2yulU##5m+fI>=*?3YkjEEWJR6be_yaHOGE!IRQ@zGe$XA`0?`k_AtV0Y|=eQ`LB z!ilKE1Wd$aOi>zYD=1cru<{8O?J|g&n1$JR1~1@MyovWQU!;{!kZ*A(mKddG#So3L zB3hyYI-?slM1SmrK^TJlFkBg-MNvd!3{J)bOvDAa7*lZ#W?&{}VYWy&k$2}+;!V7d z`S=pw;%EGhf3d`9<_nFnB3hyy)=+wBwJGXiBlN=N*cv-v7ZGME_jU#oBXJ_?M6zju zhi)TrD`sFOW??p-!3%g5Z{mH-$CvmPKjU|$zxJ1+#2DrWjjiT2CJWj#sI0xtBYFvlg zaF^7kXist<#UVU_XGHwyqIWYBKjSa_i=|`Kgcza?+M^S?U_vhRn2ag764P)qZZEQEJr{NilSGk> zOK=6Q#f`WFGw?K?7tO8ZS;)u4=lB6XV1Y{fOZhh0z#;lQ97kaT%uK2Hb)fn2Cq+n9@+YLUBXr z*(O*7zaqZFulN&7=+r!v!SYxEt+6UPVr>yuboFhB?J*F8FciaZFh=4i9EX!}s?e({ zuYNsoGw#N{coa`y4(8$=ypPZEwTP2fuhW~N244y*p%qp`2XsYu^gLw^j!Anc9( zlsYYfA_^ztR7}LVxEPn=8r*<8FawX_DZGeRiWM8|63leZ=w9JZ{DY$4c?d zKEYJ?jq(?kn962@<*@?Rz*<-r>!TO?U~6oLU9g+dS?fvB2g5M}bvR9=SCbpga^fo7 zjN5T99>kM)7O&z>e27nkTXlJ#=ucC_FO9}%hE`~c4(N>T*a&^F1^Qzr48jnl+;AwO za4g2)R7}9RxB!=7D(=7xJb;Js6rL+q?n_;vxPi~`6&B!E{Db<_*_zN8ZLu0UqboK- zuOf?{sasI^VGxF3KMcnxjK&z8jB{}TF2hvZfLo-+&(s+dnRpnF;d#7-H}Nh$#^?AR zKjAO@ize}E=FH>uqSV=AimK><&gg~>u_-pgHrO5mF$jm^a1rMqH>nxK*_eV$aV>7d zblihS@Hk$;%R)y{Haf!@YI%&Y5?Wz3bU;^h#}?>^oiGqXus4Qdgi_p{9uuJ3OL-8F<7vEvSMe@B zz~}fHf1@^24XzCSgJxJs>95&P*kdiMgZ0q^eXs@gz@8$&Il*GcDB?Jb!+4yB3vnf; z;a1#<`|uE+#Ixd2(ak+0zQO|hihodlmYNPjG{#D3h1JjjUC~{H)s}}Oorr-Lg1s>u zBQP4riuf6FjXO*{hUf4i-oQJUkI(Qc{zUymHLB8RjAm$swo0AmO5u)P=!1UfkAWD3 z;TVC@I2I@4R7}LV#mZ-v#T3hMEpEh}xEl}R5j>6O@haZL7x)H0;kP22%4e286#BE( z)ES@=nqy_Giq%EBi(CO(65C(^cE>*0ABW*cVH#p>UPUgzESe+~xLh=Ml{+8l#65Tl z&*2rkf%h>VU*S9aia$|*4yz0rqnT2tSy9-cE4rf>`k){BV;}}$Z|sNBI2I@4)MDi- zl1MQZ7vnPAf;%u158yF8g%|M(=HoMbhXq9z?R@;C_=BaB)RY;b722W$I-@%_LLY2_ zff$6nv7fYf=Ocn53ddp$PQ?VAhYN8zuELGD6?fxaJc7rQ^yJU2%Ne*vaSI>f6MTao z@H_s-l5^FJmBq?f1#4g}tcMNe`l|ofl%g4S!EV?K`{H1X6ngIRm9Ck@Ik*Uyi01NQ z-8SMbJc=jq0$#>jcn_c83;d41vE)34k0xlYjL@o3*kLWKgALIWn`3M2hyfUkp*RqS zh_L$dNiu<$hzoErrs5jhf;;dq9>a5Z5pUof@krjB?kn*p>d#lxQ5ucW46V=>UC|xA z&~a_u@sJcSqWil~?z(_@HTvKnp; ztc`WC5qe>BY>geT3--XC*bl?S$A1!5E37aXe1J>BY+Zt3?z`a22k_49vtV%*M-j4e#Oue1`@2 z0}G2R`u5mzi`A5vU}da=HL#Y5Ya;KlR>Zd01-oG{?299CG)_bv&cy||6j$Ol+@;iM zdnpd$IlPG1@ixA|H~1O9qn=RXFNH>Eiq+7eSb2}RQn;fR`d}vvMEUmR;@!AVlzT#=Uq7&*2r6FVhs?@B@5|ukk%{E*t1-|C*VFYA7A2I z{D!~KaH*OAW2}T$SREa)F4o6Z*j8z%b*AVl+>j>g#oQzX(7AD~;Tq}}&zWUY)LxsJDU@4UMoOTB1GHL>F{JPxQvt*bW1*yD~x>NHGLQ;AotPI!wSs zOvV&kfva&NZWRFo)K@`e(PZNpynt8nCf>( ziQd=>+hS+ziXqrr>8}l>7=j~kG)_bvCSW2aV~R*?RkVT;w_*lnVisoO8N7g3@utvg zEvM%j@fVgzRnt@k%VPz!#;WLuwXr^Wpf9$>_Sjje)A~^K$DueJ$KgbrhBI&;F2v=y z3OC|bJcvh%m2W0JO>rKt;0?^fM2y1*hX|oG0Ac$kC(`*W)(ag?sTJ9>Y_ZgSmJM@8M&7F5JS^ z=KX`F5KFFB^HvtiV+FLs8dw|a3e&a;ZGuM=$Kw>7j&pE6F2NPJ4R_&QJSfuJ%FQE( zn2WdY9zMqB_zny32Nq(xA5t3EV+j1!tz)F ztcETVG!G0KyQ5cOeI2jW#5f|WMrB2&Gu>~_Q6A$AtJck$Y2HwHP z_#EHkC;Wwfiusvx3u_(H=H5@qj4-w#;Ldf7voAy!%esicjI0>h3D4u8qigW zoA>}9<12iJU-2jEZ(zo-B3hz7)n+O0J~!-hT%vYgRvNg^Kp>~ z=pr||OyU7Ni#d1?AL4ubgk?6W#r_8?paoXN>R21=D*ZJNiYC|++hAwxiaoIp4#J@# zAV40oFC(Vnc1*{Ucoy^U5q`kWSYneJUm3K;8hT}hFKn{hiH!lQTwFNm-R^@j0>G*9pien4%rnv;@fgr-;-t6+6> zL|1gj*4R$kvFL@^0E+GyieWeehhZ$n;Y^$(vb)N4Je9Zx({T?T#$$L6FX9cngZcOj zzu*tl+oI;Dlv1Y|QJA77+Mo-%p%?mKYix&Iup9QoJ{XN-i{w9o>(4GJjT!X9ZPOiQ&tu&(FSXx6S`qT^v34c4m(PVKg|?M z5r%^?QatJ|SCPrYsW=Oha1Cz29hiX!@Gzdjb9e{u<5PU8)M+0mK4T&3ZBr9tg63$0 z_UMEz*bqIjIkv{`7+kDeMZzcs;xHVE6EGH&Fd3KN3S5gDaR+ALe#|Pe=p8~=C~n|= z%ooW$do2B%^IF2-e2F(5d>T(^TJ0}tR~JcZ}*4&KLS_zDZ~EB-Nl7={CtV%~7;N=576 zWcmb5#09t*Q*jM$!5w%6kK;MKh}ZEpK9mkD+An!R@fzRbSNw^3>1virp%vOjcuxe#Ki7REe!)W2`;U1+Bdmy)=!~w|5IwOOw!-$< zS*g>4C_*p{2Vx|Sz<8X63sGPiuE(9Y8?!LG*rKOdic5GK^Y9tI!cX`O%kEJ#RSwOu zGTLDctb_H6EP9x0OwkluVO#8i-LMz-#Su6fC*c&FiF0rfE|C_Wgjr3o4*$b_coa|I z1-y*6@E*Rw5BME_W64Z4V`Vcr31dQGjy13r*24za6q{jN?0~(nFAl~?9F5~Mebtgo zp_q<~a0#x$wYUX$h`9c8BRWI8fYs`Kl{&31MSX07 zzSsuaV>kR4`{DqM#1S|iC*gFQS*+ZMmQt+5b+`$4;%+>Ehw&ty#mjgN@8SdejNgkC zUj`&p7-F(dO`18{Vl}LT_0S7_uq}4L?ih^yFkHk9l=t~G;tZUJ3voHF!i~5UcjI0> zg2(YZUcv|XSgF%qQ@qD-_zO$ySMyN@%VPzsj*eIt>thr2#WvW!SZht|Nzn%f;ZTts zE+fF2_~48MotJJcuXoj8doNQe4Mp_zDZ~EB-VhqaHdqs#&>b70 z54J#m?1Vumzl%&>y>1+FB2L8wOu}Sbf-7(>Zp0m!f%`EFuiy=3g!Yi)3BJPu{EgZX zwkI^k%2)**&>8Eahj=thj<-887{hQN4#SZ+0b?;9XJIm?;7Uxx&A45u)3PYC@hs-x zb-ay_@F~8Z#y631XH#^EeXDzfNk zBZXoqZpQ7n2lrz(p2Qr?#YgxQ-{1%QhQFl4icYHNXR9eIjTO-ntDytBqC0w`H@3!h z7=YbH`UrVGVFYos$SsO9iF3q98FgvI^|&3=aX)6^Nj!_WcpabND=fgT_y_fm6;Fbp zW~lz58H?nR367SHh+fzN{Y36axw!p^;TVO{7=x2B0TXcac1VrT4uJ+U8#V-!YX3{J)*Ova_S z64&EqrA|wy*n?S^jpy(p-oQJUkI(QO7T{0(gXK@C`KVB=e0;E`sEUqQ8|$M7`eIA$ ziaoFo_Q#<(9LM3rB8wg$W>d^Vfy;3%Zp59q8;|2@yo6WrE3tbi8c(P+8K)F*nN54ON|*b%$ozc>ho;%FR?Q*b)Y#(ByJO;9YywYU*8|3}k( zz~5B=e*nKmM3fP-N6AQ{Y!X?KEt`rESs5YZW{*;297Tyr5=uste%Ujt$S6BxlpP}e z=X=ld|9JFxJio8k_v_pJyzjZ^o_p^2@;k2K25#riJitRd$uq&~*TVJQ5mRh17T(8f z%*h8?h~-#`)mV$o*oqz4IWqjvcSRo#<0ww$2mF+C`5phq4cx+A+`~WkXTsp0e&Od` z{ijQ|F&aWfW?^pTXJHm&DVAex)?-t)WM_7Zd?nUbF@SG!1mETaPU8%I#xJ;tOZfv= z2S@vdSNa}tKhN-QUgZtOHbrwu$t=vy2U&>a`6O$wc4UrNL&bA!!xw{D1H#KUL>$Jk z9M75jg!8zN%ej(Uxr2N88~@;+kwLB3!_W7+Yjd>dG|a&JnTG{flBM}1tFjL3vl&~l zD|<%9WBn8ZIf7#ta60F4A(!zxuHgo5=g&OALkWXX14m_Qd0BUjcbH;}-39MsHs)k8 zmS8zn3N8)|uju+>W42^lc3@}rWFHRX5RT+nPT*ut=gi39@VM+T1aUqv-1vl|0{>lS9#|yl}6uY8%+{62r zjX5LZu?H1}_!ysHC05}xtjp)vf-kZIyYW>H<;aBL`+LVLCI-ERhXeUWT*g&g$6tAX z$9R%|@gh_IY!J-C?0kfeMaE-g6%|>Hwb+17*qSe}GrO@b2k=df;M<&#FqktUd@Qj* zw}{KRl54q<`}jLg@(gb=_DeL3yP1xenJqFN%d2>h#aMz>S%Y=iknP!t-PwzS80R~D zFJXB1|AFEo&fz?M!)5#**KjL$a4&!3ah~FNUQROUqcUzP?l8mdXms~87xM+ZMunSg z1+g+~ur`~pIlHhsU*qc>%8?w;iF}_QMuu#`wRunjw~Ghbz24(6LlCS7A=72`RD?{gME3o?!gKTB$b z_yf1|=b&o%?II_{)4anJzeej$&y2yu@W5)BKmWdDq@(nQ4MWW5Z!RC>COIJ|0{QzumIA*qYth zi-Q>FL{8y{oW;4EAM_d*eul1y<)Xp^3xLR*L7@kzF`|gE^d|`3~RXEPlqNT*0;6c)%a{*snOq zKlmpv@gLs(TQrGuyq^yQz1|78>0)9DmSZK>U~M*HQ?_M0c42qE#@9KH??l##O;Nnh z*_^`#T*Nipz@6M3^m;dZw0%*$8cYmhk^6pkOJNS?;iD`W91VZGO9Qb9JF*L3WnT{A zFiz$)e#}ofpI-;PCWO1Qb>b%O;vOF4QJ!Y_c_HCHk0(1AE$%L6WeyhL!+ew_`7~>? zA)jL>zQSI7Eiy-JgklWe<)mQZ#PISh5EpSZ*K-Gd;R&AR1zzE8CO;Id`+h#ae0(S} z9xJ9O!E&s`>U@Tc*pzMAj$PQDukm#b<;a9Vj>`iJ#24rmaSbR8f*uS%VGOB$zcRyv4jK_T>-`<77??E`~pzX1@4!ka2Q&wq%{S ziMzOm2YHmI`4_M9M$j(&b@8l6qQ&N5eimdYmg7^b#yYIej_krd?9Z_rA6X|hSuu^X zIfu)+lIysMI~nesriAPHQ#{A3yuoBgqxIg!^vuZY%*}!x>fa#cl4=@)C zvPi=42(5ymGM`~xKF{`ig+17h138SN_zvIWbk0n&TX=-_x#CMM=C}NjYq^y>c!YoO zEYI^clLz_V4F*NAn%N#}D`sKj)WR$yJec zVp|m3d4zxP953)XZ!zVGXnl7FjXnrZ#}2+ZFkhO|y7Ix4n*$5AY%g|VclP2y4&g|S zLVSczvMQfpT{dGYcH^rY zz`>F6*a*cKPT*wD;K%%e3%HakxSH#^jk~y?2NQ<7xW5&bf>|@dd&pF$qJg9hR)?|3 z!(vgEVma1f{UGCq;W#^s-PniyIfTPFkyH2?zu;ni%gx-z-P{)$j~!E-c1p0GNyUSeV5k z>%>Ya%CQQovo0I5CEKziy96aa3D@(6IFw^Ko*!{Gzu*F{gKZ@z^az z>@S1hz0AjlSd1lDmK9lt_1TQA*q)sdwvNSmD0*`shj29C;v@!~$xrwtzY2y<&6zF! zlem-n_&bmD6#wQW-r#>s`L|mT?_*}>V4leEozjXTEXPW$$vS+FE!du&_$vEy2#4`) zPDmKuq(4x6#JQZ$W&Dn-xt=@t3y<+6|K=tB%iBpN-HoL>Z_{EXW@R20U{Mxl8CGB& z)@L)eVtaN9P27$3Q1s>?#yOgAaS{X0bNJfu&-4W@J7-#NvFMl~{#!Sf4G}CNiiscT~nAeU$?^jH5V#lY^milO7MG z8I-T~Pr9Al$KUw}|KtT;;Vs63WM702sd8P6)}4=qSuCg;emh=8tj@Y@$d+u&j_kr- ze2s5#D93Ugvf7UpJt7G-gk zVFfCPdS%gaWU6$Lu5R*Q?Z+ec#P+Gf&cP0@4g-lEFH5l2OnZ# zKF%@;!_V}oqNvVhY{mBM6jc2t9N0i{2uE=o-{Vw%#Mzw3h5R4aa0|EdS00G06Fa6j z$-jAtH+hGtZ$tyShnblzD7iR1U-yXkSkNwv@w#F|HfL+LXD4=NFAm^f4(DjT!}s_; zKa7mW<}1GDxBQ;#xtYIkFOTvB&+{_>W3qpZh4&>4AGu^#7&RFb};w-Q7M$l+kIG~KTq5)-LF6LuV7Uz?!%G#{QrfkV}?8xry6&a7cu6TnZ zIhGSSg`e>YF5*)Dk88Mv+j*GB6Na~;vx@WlhyOC!f6;{QVmfAEHs)jjKFmj1lI2(_ z$-3cf=vhSrwq#qr%&vTmuX8v@2PKz>j}d2zpKt*e1?|Fb$2W>w`8$vBPoCoyUT5rf zG>()^#|(Ucx%dzZM+T>shi|#7u6%|K`5fEuMRsO4_T>N$?~9^s!n$1A)ZB>O&mu|c|6^2B+d z419pO_z(-T1WU0xp9$K1AAY)f7qL5sa2Ut&9Zuo<{FtBeOMb;={En-+J~AHrNwJfA z`5VvhZ(ipurV8KDp7f^nw7j1WumB%s36@G2ZeNuZPqQu?vL)NH6JOyVCY>G(|BH?0 zTb#szGxD!$^k{GMyMkvsSckMk7I^D=Mp4pS$OF6cd>PljFWe#HaK$A?&q zC0LH(J63-P-^a|XvCIm%Z}{AUVM#ja45%eJg4w|&f;e&!rfxh z^|n;8f~&cn+qjGSd5|Y~nwR(wZ!>wyXkux3Z^{NykyVj{1^6(_vLdUo7VEQdFl$wK zhucBy%%1GSfgHk-9Louu%uo0^7xEjfQ$$_wje0BxBOqT(w5W3p7ypwcis^RNJmvN%h#JgcxepJjuD;c41tidJmLj_k%)*`I?rj_+_9 zX9TO)h67$AF6SC<;7;!5As*v7Uf{pH&AU@ab4tfNED#xtUKbuBmQhyV)2zw*Y|K`C zo}Ks#d$S)$aU9>{)W{sMj})^xkKrFeUmw0$Xsx)BJNOHKmSyWdXYn(B#l`%As}qJV%-gEi5mfy=d`-f6@iK4n4pZL~ z4d@P zDejF1mYVl66SFfni?IYNuri-v-Gt#2M$Hth*nyqdoBjAEM+A+wg#(-+e$07X$faDt zwcN;Gd4R`wl7I6O|K;t-cr4X@wkT#|R_0*=7G-f(=F_ah`fSElY|l;!!_xpg6umi+ zLpX}#_yIrS9M0n+F6BCI;!f^PGU+tHZ;HeGo0s@6Z!>*{Xkr^6q8^-p^dj$HFYeQY^@m2QcAdcfZoXQV^{6B~5TOuy! zDz4)%+{?o}&P)76*D!T)$y zmS}`&n2}k6{CmRZ*^7ve235ltuPxSNGqz%Tc480q=0FbND30TMoXU?lJ2D>oMzM@P za5Xn`8+UUbkMIwk;{{&hO{T~ijVE=&@HpgNMJDE89zM*XEXmTr#9za61x>`}e1R|V z74`^rg+JbMs5p}2Ig!&igP(FPzv5zk&mV)5d&5)BZORPFSN@{zD*t1$Y_<%hXBK7; zW`)0__M>7+mgkeK$3|?)w(P*pL9%_}iU*2AIFe&Ifs^?OKj&9m%j5)hMrL7d=4TN;%F-;)s;t3!Y{Yi#7+ELQL(!W9IfSD)j_+|Q zKjQ45*Zy!l%f#=vh1%9#BLWm#6{(?Q7t z;bm+pwq!eYWOw%B01oB|j^VqU#Oa*L&-rC!xQ|gR<9cr9Ztmj|{=u_6&uhHNNmSQDV3EKS@4zP*XoX@j8d$S*ha2Ut&9Zuy3oXt60$ZsO! zvF{ZB<97bc13bhNJk1Nd!kfIqR5_yore#KENf;i7HefA z)>88xW@1+6W_}iCvB+0qPbkW=GM{DxHeq{qVh{G_Kn~$3jtep#3ZKNECobeNe#b4` z&b|DN$9an9d6_qPhpBT%bGj!oZ7j1QTkv}2JcZ(A#fq%PT5P~3Y|R(=GP|-5`!mkr z9LIMegS=1W$rzud{EQ2@h%5L5*K;#>aSspjC{Ob*UgeF*@G06n(Uk6DdS+yH=4L?_ zVM&(eldQ_xtjD%&moU7UzoO{DejLbQ9L0C|9zWnmoWptihRgUru1T_Pcstsn*v?;h zfX8@}fAbRmJlYlI8hiFf{yj`9@+>wq-kZVRyd9*Mrqb z|FiMp#NcRB{7n2JNOmlYKZxPS`GzsRN8HcT{EJt3ow0n;N>cJ3-p6dr$p=}8#rb$- zj#vdnW!7NrV0F^vYb&;6XLe&>4q%+a`4->hRDQtOoWliN6d8}LQ2fAk+{B&S&EI&K zr+Ai^_z!P0dH!gyX?btL@R%XDB0r0<1k14!tFcy)@sIGZyOsDnJMk6v;%j_^Lpg?T zb26s|z5WPy;LF7CxP}|Jjk~y?2l)s8gP2OSZ0@0Z6iHyfGDY7yT3$O?uWoedY z6;@|mHe_?Q=1Y7zVb1XMtD-jta!AnYMEJO5iugW1=BJ#`uY*}9!g+2Nf93%m;t8JS zMPB7C#vY93bT`v6GqW)-AB=n@R#Z`(Wmth#S%dZ1h%MNL9oU&Y*(aEIGF_Z(iaJ{>PLB zZFxbvKf@h(4lxf4vItAC6sxfo8?Xsm^98=luI$79kws&1#c;mGcNuVcQ1Wzmd6$Xb zaSbU3$Q4Qvoy=IDr>MV8?pu4@Fl*S zFeq~-eA;)QZU{$l94B%LKjbWa!3A8x^{*FOwIFCYXx% zG81z!46^<64f%h{P^RW;g;o~gBCs~!xur8ahd1O5HyrMn3usi#50OK6aaeRkU z_&z`8r~Hy%B@ACivP|(^Q1Y+vc=mvJC}+KMDt3^dzqCvSbz_+I3Eud zg}=Uh1F;EP^98=luI$79!NsHt`$!*fd5kCdH!tyD-e#&tY!Z>L#4;(eG7k%|D2uZUEAVO7WPLVfD?T4o zy%4Uqx7d$EIE>@?4yW=1e#S4jh)ekcS93GBMaE-$6#IFUC-@gH@&^CoUB#jSreQ{A zVQ%JU5k8tQe3)NaQJz&m?bwms_$mi*Fo$zA-{qtv>xK{Wrz>W14(IV3F5?ee z&CT2vEV>w8qesL)c#ao%jW?O%(P)6Fc`q|D2lKEXi?Ae1N4APpQdHqHtji{B&KLL+ zUttgS6ImzLSka7a*^XV< zoqaigZ*oM?@wq{TYR?wua3R0p3jVUA&lBg5_9=)mV$o*_to2D|@pa-{4S=;oFh%*d#^3k2srOZ~>QaIe+9@ZsB(B z;eHPBI?eUK%Q%V{5*^PJD&E z_!RSaO9!}%89`ck`B^YBN358l1k15fF!6eLvcG}YgzecWSRH;l zK2RLOQ5?tjIF%o9HoxRo{FdKyEjMxpe~An~Hb-%or+AjP7%OGN;yuj7tjx{)EX-o8 z${Gp7eMAFA6SieLc4bcv;9!pASiZ-p{G4BMF~3bRX&>>UVlB6F2lw(f9_J~Z=VhiS zZBoq0EX>OXLzCW{8!M$K$EvKs`fSXX_%eI44+k+GRJ|GALKcZjxst26kz09yhj@ag z`7dwtt}<>p%)t92)5Z!aiUb#LhMRmfu@>vIF#5l+BZBAmqxtt$aA+|)Z zoU6EwySa~tc|6#4E4=*wiOI@F>%N=mn3H+=FpIJzOS3wkVFNZ{dv=O!73-ns&4C=k zQ5?tjIF%o9HoxRo!L0wnJ=R)rBX{tZV0HNI_$l!$Z!uQRX3u+=iCLMO`B|97Sd}%{ zfK4Lfv9^kK?8=^eoo{dy$8iz^&gFbA;c~9xx`g2#>nFud?&I(LgMab@uP|kK8xAuu zEA#OomSKe?llEBE6t&op&#@!BuoqwB8yw1soWhSdn~V8vXyT~me~LBS%x(OgM|g^7 zd5f_Mwi({TOw7tce56A1%83`cJgz9i8m!HRe2#6|Zc4Aw+0wir4V^M^boj7VdY|*S zkjwZT*Kh-WY8o%3rvbfASnJ^BQk6dH4u7ygw`&OA~z&OV9iH z03T(^U}Ey{3al;GV{^7=Mi4u z72am@C!?E0I%Z%2KFr7XL}airybvuLDVwq_+p!C~^9>H=IKIP~{3NKFG92_$aRoQ= zC;q~{{FCQ+nb&xm$ty=|&dhAg!vc}*_W<5T~7VN_A?8ku|%8{JP4-y77 z?;4#czEJlK*Kh;3aTky951!?D-e&Trq9LSVdgfxj$at)f;t^J0W!7XJHfA$E&-Q$U zJ=l)}Ih>;thWCH(DkgC{XYzA?$;JGZKXNU1a~}`$IM49!B;(=z-&Ms8#;Qc4OUdla z%|d*HrCFZUSc{F=l+Uw$XyX2_tD-00mtj&6C%9iZH?(D~b!Rot5myItGm-9!imc!Ae=lj)w0R+E9*m@_gSE2=2Y(k#!XS(EkHi0#>lJ=upNIEE8AIbryDC^Hlv z^J^~Q_xzFD`7`(PU~pHr@O8myt3?aGmsyydg;|WHSdLX#opsreE!c(~*g3L7te4_7 zzQLg!%kiAT_k;ZRgm)YZ#6?`g4cx|E+{fQ}oTvCVFEMrXXg>Ea3$sUte_mZth$UH? zPq7;7vLRctEqkyx2XY8Uaa_W1pZT6*DnH_E&f`KZ<9FP`?cB%Td6H*%i?JHvWRmuo zX_CGOP0y^%!AJNQ%d#S?u@;-NH9N2~U*{X4iGAh>#TdTJNu13&T);*Aj{oC&Zsq|V z;t8Ivk-T_f<^L*f^RAlFMAGm9<_em=8s6qAichg2pJQ9LV{i835Dw!wzQd0=n_qB2 zWIVP~v5FhHl?Ql;CwQ9Id5bA(Me9w?tjxgzd^lma%@$WY&I+u|nykadY{nP(61%b| z`*RS7b99p7bEL6%6_YrfGx;@_1hei7_c9yAE!@RD{GCU5l{c8;83STQW?^1F$VXW+ zG9Ig-sLWb?mTmYVJF^@6asc1t2)@k;oW>am!)xqQ#au4uN^am5?&dz8;orQ*n@m|d zn$X?M&fG~R?PUroim)V0vj%IkF`Myac4cq&;~N~x37j07IF~wIF_UvSpNsh|H}NO_ z!oB>H=Yn>b!c8nyooE1QnUPtThXq)KkFqkK=Cf?T7ukW`_-bU1*Z{>~zRd|i{>-DZ z6`3b4GKY_xTPoYK zBfGE{U*j7b%CQ{Jk2srOZ~>Qad1O5Hqhc+$a66Cl6fg2B?=VH(Xj;vda!;#c;DPr?8zY<#<3jFsr-Pm_!*b+JFez>{>lT9 z6=FvfCwPU|d50~kg#$T+BRQ7SID? z%k%t)|MH&3(X#L31I)z-StwYPGhA0D||{JTa#${Ia!P)SdNugjkQ>xjoFfI*@2zelYJuNv4M&q z9Lceqz{#A>nViFUT*ReZ$yMCQtqH^T`TVT-l?Qn=Se-k(!f%VopR=D}2IgQM7G^P) zVFgy_Gi=Oee32a@i^h5=dUG(}VQ=J&3b%} zE%*Xo;w$XI*Z4Ze@a@QWY^ve|e#*K0hRe8$>$sgi^LHNM8UD@dyp^zZ_$NA>+theJ zA7BAK%n~fc%6yu2*)YgoARKUKu^anwAm8Q$PU8%I%DMcSOSqD&xQRbS7LDyz?Bfys z!7IET98J2s=~_hN$iN4fix06dOR_YdWL4H?JvL=awqwW0c&wjdAct`j$8#d5aRxu( z=Um8dxPm`$9XBNmJ{py$K>UR6G%xT9Z}JXPwX_W}BeO6U^RW;gVFgx>jK^vyYO@KO zvmHCKC;RXX4&_^Xm+$jKe$Fowh6n0P6)U)w8@Y>nc$mle7ccTA?=VfPXkzJ^jX9G{ zoKjL0VMRX0T6~sG*qkr$C3a;`_U9lD=jhPHiR*V2llTcg=R$tNm0ZOg{Dr^qFi-I; zFY{U}FX6qTNYOePRXS$i1I)#TSePYPij`P}jo6fJ*{<~q(f_csq8t0LKZkG_$8tO; za~fyzlOW5uLCxbw#S=Wo3%tggOx`BCSgDwW+4&#~u_R0LDOQV&$Lc8>u{B>{7j|cV z4&q3T#1?>mNyBl$Kb@B@Ct1zf}x{DJGanY*}$2YEEILhOvgb7(S^!PVo+>aR%pb9+z-A*Kk8n^^tI(hs0yN!t0E^7;PgdnT{Fw0CVvn7G?>S zVkK6IjK`i))MXpK$d}obeb}F4Ii8a_jk7t2OSvLp#aL{$Vm-HU7x(iZPw;dwwAkq8 z!S53W6Y>J#L$Rd1#Wm%Oq*nmygmhIS;J^4D{NHQMo!AC3J z;uOBmPxv_(aVdY~T5jVm{>H;R&A&nuhe>x7DPD?3a}V!hHs<7mEX2q71S|3>*5b2l z!sahIOnO<-mA%=IZ*l}DG2l#o!Y}z1zvcH_%Z)ER7Oi-vVmE*15&p?@!NteI{ZFhz z^v_Z<3$rsn3$hqXuq-R`Y1U*tHew65iA)=NN%3;9d2*gYX-0@+f<-05*Mxl_e#FoC z1;6GJe$OAdfm?!%CBxPJA^yor{D-lQronreiMg1MMOmEXScx@RC$d89IYkS$XD7bO zz8u0~L9)lg%m0D+5$AF~m+?EU<0c;9A)e$JUgAHz&E%aDbEyzZ8+{SGmsy#E1^6(F z^YNfyFsM-Qz!Twqx~HxW2XY9<@NG`#On%NUxtQPbN3P{o?uZP&eIk6m_YdWtyud5G z#n{Wy7I8PzF*ozG2p?rBmg7^b78yJ{ZBWK8O_eSAB0I1vd$Jz~awtdgZBAgo>A|8> z;nuT2T*T#E$+g_b?fjWXd4lJ8ng20a=V)g4@V>|#vFwW6EW}5GcBRA1S52(NMr_I# z_!7Ib7Y8xUu^i8U)A<>{h>XV;E57AwuICQ^!UH_SKY5Nfd55XH7z{HrTf$&enedg} zkLVs_Syp5<)?x!T;Y)m(J=mLr`6l1xq{s@f>57@0%lTZw<=o6|LA$cyqn5McdH%zH zne3Hl26r(XGcX%-vH&0Eqb$jCtP~mSEgRmt>nj_xCEKzCJF_SIa3F_pJSTEGXYva! zh)f&%R`Gq%u3Wff|03??QJ&y=Ugm#H*3|~X`72>W`DMcJ&~&llTmHzk+{zu?%inmMr+AGwnW9@XsnooWnUhR9G|j2V z%R+pFrC5$tSef`mBJl= z!Jg4Him)V0vl6SY7N2EfHe*}1V`p|_ANG$-8ylh+7PNaZoZn<|8fWqo&f`KZlS9&A%e!v1^K(yz5oBBW7kc=4U}Z#wYkBtMXYkU`w`57@k>qS<#iR@pTU8 zXinsmU}EKPfD6P${GLB@Gq>?q9^hG?=QZABieAw?Qu97$j*Q20D)O=rAK?=$%coe4 zP1u|-@FjL-Pxj}agyFO6BNSsefs=!wPmRu&eXcm4KX7%hDExMOx44god7NkXH?Q&r zW4)vKq~txkk6D?6`B^YB{7?`@36^EWAY+yA^3@X?u?5@kCBDoa?9HJZ$#*%4A95DI z`dMW1L+>6wu^nU_WQD9f@UYp^z(usPeYV`QCJ zPemV&`;)is{ zc$$Cl3a|4HQ@j=pCoS(~7G`HYKEx+jHZmTotazGr*^sUHJUg=+`*9#ga17t$RDR4) z6NU#N3l-mRC0B6^w+9)khg-!-@eHrmf#BQi(qZ^b3vVl0?dYxL;&z}KUB4B<$Q;(1=?P2OSZfzbuNhnbm;g;|WHSdLGzTEd`a?a`Ua zH`TS|i|oLz?8$x{7;OG3{7~aSoX**t!v$Q#-sDRSx4Qj^{*9 z=S(i-H~fzO;|6YtjK_Xf{K`W-#{IhmIwSSn$7Tu@0-g|+xB z8#DZ1`Fi1}B@7XVaV*DkGN*ASKjAzsd@VB!iB^6; z^RNJmu>>oyGM`~xHe;)xSN-rb#hc;?zQgx8gCBDq7jijQas#(;H}~-vPe#UL*A=&z zGCVt(EZoBHW(MBRT+GM9EXGnS$11GOx@?&6o>=TfMTekQgK!{kixW7FGx#az@@p>P zO0ME&ZsQ*A=TV-B4FCGO;v#SGKi>OhG@wk(!8|O;A}qmDtjMQWlXVh?5Az!-nz9XF z3~nsTQz)3$FnrQ-jP7ktV!)3$n_qANmvA|M%gyA)IP;r!}`4_M929phsCUzIIG6xIrVLr-|EXPVowh6DXYKmH{ z&&F)Yw(P*p?8!bH$RWYSCgI!jCWw=RWY3K*lxC5*G|2y4c>Qk_xAFiF@lT%PKm3;| zM?}-Oo0*uE`S=iv^YO@{u}X?6ti$?j!8XCsq|4h^9Kc~5#R;6uk2st2`8B`e|G0@i z@fYrmjK_{DPVfq^Gd40BNJ^$-20p-Ce29fvf~8oART75V>obbFY{M7%GQ09MzRodx zo0B<>AM;br=hsPA3b)tgij`c)P29=d{GCUFMa{x%@Rk@GWy@hY=3+h;W-(S`6+Xkd zY{M7%D*Hwjjg3%@;k%r~*_;#1Y92lzwME>{Lp;XQ{42N^{&?-XM@P#_$DGW|LVScz zuq>Zqwczys@)YXwlK3+Fa}bAfG^g?d&gL90<9A%c4Z+bC;bPB-fAcnzkBL^5hUtTn zEyKl@5KFN-pJ5BO;Y)m({WvgK6#lv*Q^fZr2UW%n(^8mRIp0AK_!H%%@qK_4piH1j*WjH{{-8KMvtAj^%hx=S(i- zH(bLFJitS|#D5~=u~ctG3r@>CEWk3Xz^7T0&De_V*pYoXfN>5_7!+MSs6d)|x`n~S zw&51MM%=*d{Fw)MC>XhVP@(Lp-nIf}V%8wz^WkrMTr9(yti#4^78F^Rr%?8>;&@Ks z`@yWF-?mu%mjB}#?&6-{X!zst3*r^tVr+bLnX@oE^RpmJu^gXbHP&H$wq?7>pyJv= z8G{n*^W=+9_nnzs%x}4sJ9wDKd5Qlp?K{y5?qvZ!%;J1JGDqxbMNKwk%V5`w;iTRW zhjJ{(a|++*EPloXT*MXpf$O=MySOJZ9y_Qw%G3OdS9ycU-i-!u7t=E%vokjfvItAE zbi(kMy{o+;+A01OW{X=oDfg*2LEIFiP3s8GCOm#7)!7mD+MJxg!jY^#pl?DF9z+BzTH7P$ia+pPw6mjEycSGIGwXOhs*dK*Kh-Ob6-%kQ_=yo7@HKW^KPbNW@ckS7GX)2 zW_3Qp=4{QE_;O_0SPw<-;Aqn2881%cG|u3c{EFZ5dv4)&9^x@x;y+9^Ia+tx$Q-du zimWWiBEhVe!-Lj_;&bf4&K$tO9KkURI6cVUd32#7o5gM1!~HzU6G8cHdCJDKPl+yV zZWd$_mSZJW=QC`_c?J_#USQ`CkdwG*4W}AGn&E zxsAW`2ruvoQwDBXe1N(55DQ1$aP&fI*MMOl)i zS&3Cxi_fw#o3Sn1B@7R;IxD(y5aS%fw>gFHb2jJjD=y|ruHq*Clw{ID)^5c<9^oH6 z#|ym9TTJ2Zw5$^goid*?Jf8{|Q4HhN+c-raF`tM~n=H!Dc6kO~PZt)exr&x>6vNc~|XLe&B z_U8}|<5-U841OFL^zRwIM`Vd|IahHVf8tK==Ruy}XNl9+`5=PG9JsLD8QmD z&N8gPr&*Kr*_f^PJUj6f_GZ6?;mvM{Vi@1!RDQ@=oXh!K%y0QWuHj~G<8JOtGFN!B zJEb_wE4&`$5C1|={N4|v$z}RKn(jN$=KB8w_%V_sJ0T&-ULhoVW)+f|?3rX_WgKLO zLY$K9kWE5DnPr3|d#@y4*(>oo=X@T&zaH=R({=Cpyw2zOx#ylc4xeRK=4O5tV@Z~0 zW!7RHHsafC!w!LwatE{2ZTy|^dv4-3?&0q|%9H$)fAa?KMCx`Q@ysh}rv=CO46`sh z^RNJmv1DX?^uLGe**0Kvwq|E`WgqtEP>$rM{ESmMgY&s4FjHuq;3xjfospM%L~q}5 z+ta+r%e=umOfo$fM>3{idS+pE=4C+^XQ{wUp-O^ke1mUBev93{_O|b`2YYiQ$M7?L z&gq=Z1zf`K_&tB(mcVdmr(h2c@CZ-yJa6(Y6V3<*mV~L8j#-$U`B^w_WZMVPUpahD zR*MbTgl*V?-PwyHIfkF{bI#x#F54Le!_{I${GBIi{ri<3T+T<;tuZS0UqHQUf>m8=f8Z!$G;9H_he+_htYv& zwS9s4Scv6WnYCDl4cU~f*pBb98~d<-VBXM2f)O0Y3H*XzMY{Eiehcmw+g&`sBRt28 zyw2MU&2Ii-S0n z<2WH^IQl4Zs$d2ea0%CN9k+1@_wx|X@B;7h0TVAWv8eHH1>3MQyDswQxB3YBb0|mhQ+~#&oWc2A#FbpbpSXp)xOY)>{t2RY!70Hx{*Tvq zpAY%?;^6;1$#l%X=lLQFvIt*gxfT|$u@>KAW42;DzRw=)&p{l;v61l~MO!}Gb{>~; zCD(H!_wfKv@+>d&D(~?>CRq~9Cs|-PlveNzvoQw?@FkXFSyp3B)@LKOWLtJ&_qfrP z_Y;IUl4CfDUvL)Zaw)&%7XHHD_y6wYynUe)sgr!)PRat}e*dT876lo{u#P00H zfgHlo9LLF=!r7e1rTmsZ@W+^?qxaCyf}Q-G2YHc~d6Rb|bw7@NuOr!a!QfKxX=Y?L z=3qV+ihOr1dR44%+lZ~$j$Qcy2XY9<@YBe(=&cFQw_U_lT+1!|h5LAb7kQaCd6%J8 z!O#Cl*d#PZFrUk~ zlI!>r_i{gv^E5Bqd0++Ii0h)h|8jui9I6tUa+3qxP!m*AW!jJWc&Rr)jDSTAs9#w=4WA+ zWNB9BYiz`~*_IvIoxLJ0Cq&QKF}9!b3x379T)=O+nm=(1f8}pH!V~TUA?88wU%gLM)*eNtyFptZ)lIyvVJGh$%c!Xzofme7vQejf`kw=;h!FiINS(u%9 zS&+q9iWOOv4cLUO*p6M;Juv#jxL_cMb9Cg|r0D%I-F7w?aw%8y2X5xiJj7!>$BX=j zH+Y{91EW76`C~AkCzy)q_$;$BC-d?pzRb#ejrG`oE!ZY*`NTob7fiO%$p?J=I?MPB7iK49plU=&H2oavZ>*_ea*SvW9nsJx&uYq1U+@$JZC z527!&+~0N(M{*25XZ}Kh^YzzkT7*j9}pJi6& zX8y>`&!hK8Mcb-;gKzR}wqQrT$6ox9A8`af3`#4OCkd@RP2tiURP(H}q%)MHaNX9sp>Pxj>y4(BJF$T^(P<@_#g z^x@bB!6xqH9vSE-}nbl@C^UvKbw7b=dR!ZAKMa)?g^%0 zdS>Md%+JDng=JWkHTWhQZYdXhpbmo0?8&|y!r}ac6C;DCMxOxr#&$7RaVztA$f-4Q@p`W@a|#W_}i9NxsHfe2b0QitYG5djxh0^%o4{D30Z1PT_3M<1((~ zdT!(n?v5mw7QH5(v%Sb`yv2u1xGk8=lT67B%*+COiLbB>tFU@tI8;~g7MrmpJMumD zWM2;EFplMT&g9oz!WD6wM*r-Z;79(#UHpTGd4?DG4{z`RLy?!JN1u{O|8p?7Onia4 zSeV5k-J)+Eu3`H+8?q_eumk&Y0EcrlCo;kroWsRj9+)Y#R+TCf*SYB`H%e z9Wyf<3$qwYvwUFmh4ciqSf7p9f^FEDUD=2IIg}&$DL>;>&WIa*fU-=mlIyvVJGh$% zd6egPk=J;O51DXhFu5n0GG^!K1C$Jc%zTk~ScJt{j+I!8b=a8A*p8hdspmvbyFs=? zIhNx&i*vb@-*O#);&%SZ13bdB{4+2dx+=KI|CnG`FrZ{i!Dsj^b1*kw;>#?{imb^u z;zoZawvpg%wq-|lXD^2N5kKSSoXM}bgexK~zm7gn@Q3YTp5X=l!yA0S(67Nfp5RkV z&rE!Qxmbur13QIY6_jH&*5sRP$mVR#9_-CQ9LljAA89!^`g@@BY!`AR*Ki}ZayR$! zC{OYtFY^}fMXp6ZTsY!p&gBAr%hi$JqHiAAn3-D#W z5|}qsK~ROYS(lC3EYk9u=RL@xs+?Tj$65%`*j(m^3_+g~(g6IH0wf&4=aV8gV z30H9~H*p(xb03fJ1TXMXV2#jq!EHWd!hHtC6im-d%+8#Vo+t7-~ z%62R#a|&m39+zjz;GnyG9-m9N{@$b z<)8eAH~23fG3AM1lxdln*_ej~Se&I;DQdj`)dY1|pUv2ko!EuF*^fgxlH)mv(>RL@ zPw4+r!5XgPR&M7$9^gry;IfNgFEk5DroXW5H4VUvfuIEN>=db*Ohk2Uk8NOw4j|oo&6G_69Ov}v7#yl** z;w;5Vtj0R59~cfb6SQP^_F|YHaST7@7yOEIxqvIUiW|5oZnXb91iN{FM|g=>c$@c` z@U)3B1=H|ZW@Rqsiy4mgzo?)D%drycvk_ac4d3Pa?8Of`n8P@RpGJ-MKO*>&vpAQF zxtu?73wLuLkMR^Q@e1$q!D;8{wqP4}X4f;(`6r0p z1$_klIg}&$DL>;>&ft75;yV7sU$~3=c_?ggisyKlS9zBYnD}gP!;>-<(=ju%F*ozG zG{faBs!J9DxSi?TG!v-)}cuPtc6CTz|2 z?8*-~fP*=KlR2HUxrod7y_d)etru+NcK*gcc$}yC7yrjwyvHXl1QUCT>6wWyge`Kh zFpIGaE3gJ%XG1n+8+Kqf_T+GmW_Y4SgflpYi@BU@xq;ibgZp@ZCwPXJcqOn&=%FCt zpTVe-F$L2z6SFfX3$h4Hv25g(!dXjH?{3?R1384_If-9!CYSTO$Tx+v<_aIPJ;jT> z%!C(%qe#LOOvBvF&tfdea;(ItVnySa~Nc!Br%FmCj6 zndYzH2-7n!3$i#%u{vwBDVwt=`*H+7<`?`bX6$mgNU)4+xQ<)+3-@wAkMR^Q@-lDo zE<=}s15Ob4kd1j* zfW=vgl~|2+Sf9<B6&(je|_OS+ivX30UX9r9M4Jon%{5*SMf(~<}U6H zjDF%49OngI;tk$m=tgk7iTM;$GZV8g7xS?gOU8|stb(8lUuQiwWplRYyX?W<9K@j< z%kiATX)$9Zny8ZTK&L0V>JHs)r27Gp`i z##(%fjoE^2_%7eSsbswbA965FDV&L^3M>G>R=4_oABeimg3mSsg&XKmJJBQ|Gic48OyWVo-zAP(in z{DhM^g){jz7jYR^^9SzbejX2uK8g`s;uYTEzf62P7;RFf=F`l=?99hPEXmTW5;xla z>VkS~z~*et&g{y*9Kc~5#qpfPuQ-znV#fNvM6jAaa0`FoZ~TKNc!q!TAKv8yK6WRV z;1f&}HQxX9f~8R0a};x}B(m0ZIg zxtTk-n}6KV|HFb)JjcKJ4{!566Wk3(`WTZl6`$d=%)#6&6t*bJQY_0Vtj;>D&!%k7 zcI?D%?8*Kd#PA4ELXCcPJoI60r= z^UT8ne3`GX0;{k#>&A`tzpa5NBY{cel%}(rcU;ldw z`f?D5@?(C&$(+KO{F;lnjH~$rH*wp2{r^?)8xQdq&+<=R;dS2Qe@y&uF#4oS$+XPG zEMbcmnTLg0jIXjB>$4GCvMsx?JNxnfKiZwuP8BfGN~!~BS2_$j~O zSDecQT)|b`5Hr^QO@bZV%>z8bGrYjtyw8OH1(Qp{6imZR%)*>eUyeQc%_}I%5-i6` ztjRYb9cx6N((Gf~pCdVjUvVZEb2&G08+UUbkMIO9@KRtnbX{;o|%}P zIa!cJSc+v?l{MlqurZsl9XqiHdvg%OLoLQ~Jg0CP=W!udat$|fD|d4rkMblh z28KhI1-E#Q2@?b(OTv^)%goHiJS@QCEX7K!#yW8mg+lcs-@Flh4((Ivmu+tja~@b2s*GE zdvYL$a5TqpGN*7h=W!WVay>W33`Z}7I|RFVkVkor7kQ1h_>c(`1rvOdDVc$p`6BZ~ zjb8|h2#T{DE3qcuU_&#7{~C_M2W)j>qA8FC1-Ii7jrq+a2+@EXYS@c z9_DeLft$FEzw$R8;xS(1Ej|nkhY~*KtYu1OU}nC^JS@WE zEXPW$#X4-vW^5NX+W$_19_-CQ9LljA&ncY7xm>^%T*VFC#GNr?{of-v#A7_qzj&Ru z`G|><1QSfoRLscdn3H)~G-|y6B?RSJnYCG$P52Jm^Ii5}Z-)61Co;lmN%Vh~;2SRH zO0MCL+{_)^%|CdUr+AKk^B>+$qW|{=2_6qd`52Qk6`$d=%+8!Fz?WE(rCEj5Sto2! zpUv2k9oU&Y*qZ}6grhi?pYd}}=WK=-SS;ap{GLB?3wLr45AX<2^E@x}D(~>$z-a%I z1|v_xr`iZ%HL8?q@|vpwHukGRqP_Y;IUf**4tBb?6JT*#$d%^$d#KXVU% zj~VO#QNc<6$-jAncld~jo(LxQBvUdgUtnGqje{=z-{okw_r=lRzY`hQh$lmGG&lOzj9os6mZ zG&3_Bb1@%_usF-GLfGOp*5aFN$amO^9r+%Ia5z8VL{8-le#7u$i&b39&HR~rxu3^* znwNNmcla+8KN(CgDN_fALr)8`Fgx?H5KFQ&tFSuju>qU2H9NB_`^Js-e}G^(M{^=0 zoWVI<%;j9m4g8rqxu1u4DrT(z=LDB|m3R4oiIW>4Q!yQLFgFXc7)!G}UyB;=e=R|M zHeyS*<$LVLz8t_|9L4dR#JOC+70LB~m0&$L@)z#n?>xv8Jj1{EKi=eBK4PM$)cGm> zPa$}k8JUean2&{6oTXTSRalF4*pN-xDQwY&eb}GFIhvpGbI#&iF5^mW;3n?kUWSiY zoZv-X=55|*;uKCoreS(!V-6N%5te58z;LLB;B_|Q+w8*b{E!1VoTE8`lR1sExPVLI zM*F`?u$G&+jR$yyXLx~Ec%Aq8kV#TH*_ejuW5)WQMUb6&S&+q9iWOOvud^PT@Ex{e zCw6DAsPX;}6b#{Lj^kub;Q}tay z{=*x5z))(F<5Nt}a3+fvn2Uv3jAdAX_1J*T*_xf%m3=vY!vn*i(SnJLa0cgaF_&{K zH}Gffuoo3JAdULJj~NP&s)65glU80O~RB+%goFc7!KtT6ku_dVkK5% z9oA1P>zfnz30XYCUF{PaUqv-HGkk{{>;7H&*MDJOS}>@cICb!_?L;( z1tUz#)O?y*n4S4ph$UH?Ral+%*dS{B%H3Shnw{B|eb}EvIg+1qD!=A8T)|cRk(<-G za_)ScR{%9-Fc`JFqi*vM+~l zI6vXUu*Fo);5S^%Rb0!>{F!^XpT~Kcmw1JD82;BHae5~mQ}bzNVRq(YA(m%l)@EHc z;X7;}7!JKF_<(&ln8P@Z6Zj>kb3PaGJAThi+{Qg|qy7I~aEzz;7yrjwyvGF31QUCV zPcbz!F$;4sAB)9|^}nQ`0;}+K)?-sPX9sp>Pxj>y4(BJF$f;4|{huNDhKsq1Yq^Qr zxSRWUh8Oq`Z}0&_8G^|@kwO2T5~OD)zQ9~8%wjCV3ar7`*^o`yh8@@~gZ}pv4CD}g z%uo0^r}Arl!xdb`AGw*kxR-~+7RPykmw1DB7|IxoE-{~CYGz^<=3+h;V@ZZ9SXANb ztjDHo&JOI%p6tuf9LLF=!daXf7!EBFtl(O1;5P2yJ|5r+p5Y~4;ceb$!c4&glf;eo zKZPI-GcgNuGB1m;ILopkYw&fx!&ZEk@5hYwzmK3lhjA1qa5ATJHWzUjzvp^x;|~7L zgHhxCKP5QF|M42{^C2I9HW=ZPOvem-o-eW>i||#JdshEn6V&2cY|K_{$M@NT{W*xE zIF^$+g|j*DS^ZxoSjqL=$Q|6xgFMP}yvS?3#Uz=7i6vuNJ`=Xc#vClbmspBrS&cPW zpN-g(ZP|t0*^lA>zX2l!V>pRla2DrsDZk}9{>1J4l?Ql)X9L5bKLuBLlm9Wnb4JG$ ze1^|52Xpf!zRa?$$eMAZ{eMHyh;OqEJFqK1V1EwcNRHuW{G9W-h$~~p`oBi-6Sr^| z_wo>r@jUz~G7VEGfo3a(#@jZ59pDg;{ zU+@t}a2zM_3x35poX@5FmTS3zTe+Qkv*`bR!BL*%6<+59hO#;-nSvRZnK_x4#aNOR z!xmLphxPdmTd^~{@2u!3)7ek}(CJ z;j_%a+#{MMu`N5YF9&cqM{^=0oWVJP;m~5i za<1hD{>+`+&qF-T^Sr|A{FjfI^u=HR$>T<^tWOIvGCOm!5R39vmSZ*6WPLVbOSWYf zc8?jmvi1{%Ig(>IiC=IQ=W;2(Iaiwn6lrz`6k!8&f`cJAW=p5$3x z=2hO~e@v1qm|QZZf zKZl?IUt%eiWmVQ-JvLxFc480q<{%E`*gX0_UND8zIFAdtl54n;Te+M2c$6o3k(YTZ zkN)2iB+MI(ED2LGEi*G4^RNJmvlJ__8tbq=n}sb}vJ<7fdh>GcgNuGH+lwR76mmWm%Cm_&OV~30tupyRbVy z)ScR{%9-Fc`JFqi*vM)z-93%WPY%z!Pxt!l| z12=Ie_wW#p@jU8M9h7%PGMwgtan32yhC-br>ORzjEvo`Cp3EyG+!02~Y1s|{v z2Xh$5aRR^Obk64@e#h^*iQBj*ZnXcu3y$#=FY+>P@-9P#oODdiRLsE4%+JCs88g=Z z(t^r-jdfU`Z?gqE@;&xsUk>Ilj^%iM5jEcbuLMiDf@`^fTe+Qkxt~XQk{5W1*LaH$ z3h95Sa4^cp`6SaYJ)h(A%+35P$`UNgimcAstY29F8wr}THM_GH2XQFJaRR4u1{ZJ% z*Ki%Tg)Me)KM(N?FYqdF@*xwxq{d9eOw7XE%+GLfi&Cu2*I17Y*n(}?iyv|bhjSb! za0;gdhC_1&3%G)-xPhCvgS&ZxXLyNMc$@c`ut+eeBypqtPa#OdOw7WZ%*!Gy&a$k? z8ho7%*o3XvE@rI%T?F0vAqR3eM{@!va~fxH1y}J$ZssoTjT-O&VZm`;;3eMR9fpbq zBTUSvn3|cGg}IoI#aOba{#OuG;p?o&rfkj*?986*%OM=jPdJfNIislle z{F!^XpT~Kcmw1JD_%9O|3nrK}Y>}EzGYhjb9}BT0OS1~AvmP6;Ia~7shWl6y<}i-q z1b)fsoX1OSWYfc4t5S|Nk3l zKZcX|1!r+Cm-1VN*IE3;?fjJoc!X#9C$I7*|6_uZCdU+fhR+6uLpcPw`4V4dSyp6C zzQIO(n{C;V-Pwy_eiS#_|1pA3`31k?*ZhXd`5o7DBX@8&5ArC_@nXza|E~#d@gWnw zqOVNJ49v_InTJJKoaI=FwOA)=y#I{_&Df5e*qyyNkV80ulR2HUxrod7J=edY|JwvR z_&X2s6wmR0yvF-{$j3{W9MdrapXZCE^uM5>2w!D6zQ$U7i;dZe?f5=>us;WJ6vu`w zCUXjBa~_v*CD(H!cW^fk@+i;oBCj!g%iGe2MEE3C+>e1mWDZMI;?GW!3Xpcg;nM;yUV`5C|B zOfKLOuI3Ni!e97X*y0bK;2HkSe|VP<_*mIsa!)V~(=#hyV15>6_!WyXtjZdElMUH| zZTKF$@k0*e2!71Z_<3MBG*j?3mv9At;E();yZ8qW^9(QWAKu^thRVez7w!KO@kR9I zMwp(N_yTjWFpIGaE3gJ%XG1n+8+M2p>wj0l2kg&59L2Gm%qg7Bd0fVoT+fZ%!QD~g z{XZx;%5%KPYrMsWOjtfR`JQA-W?*K%$UJ zX6B2`!y+usa&e>muOz6&I&92lY{yRQ!QLFip&ZNcoWg0G7c*hn(f(@AH8M9CaP+5OvQ|Rjyai^MOlL7SvhLF|8EHzvlZL%efD5~4&o?|jfLRgS&ZMrD^SF>JxrQ6LmAko*M|qML8NO_Bi}#rDwP18f_za)r3(Unr zEXr3|j@4L`Zw7`#4F%2Fn(y*`_GUkR#1Z_26Zs{la~>D++qlvGuNM5s&D_a7JjkQ` zoB!}GAMmm2!33XR8m4E~n6du9Ajr?ce1&CLl{NS#8?pu4@I7|phaAWeQRDspSnwG? z=S+UhC0xND_#=PeF8;y8Ji`n8r@H>%5IkV0hSBjUre`L;z+5cMVl2Z7tijjWu!jCO z6|`Xoc4JQtFF#WBnd?#kC|Lp{w*qyyNkV80{<2ad9IE!<+ zge$m~8=}VhzfG`%`*?sSc!rmFg|~U1$!Z6aOu=XPEORh-ZT){q@G{G?B5U#uHsafC z%Z}{MUJUaij^U@Z_5TaOSDecQ{FbZv6SweJ{>CFb!9V#oZ}RT{-?9X+2P1ooDVT=O zGAna4KVRl6tjMZ-gKzR}hFe&4d7Kw` zi8pwMp*MnwCFWC1%}mU~T+GK}aije&DX73Ie4X{!l+D?Jo!OIpIfTRc2`6%D%vk?t z2)^NBuHss5=Fi;A{XEXoyu>TK!+)8$j{YZ&E@H1QlZxq>nc0||`B{u5S)P?ypN-gp zZP>Yv{&yAhVSf(gNRHoz>a4^1Y|7?r$4>0Vp6t&-43Dt*m{T~7^SOwtxRzV^3-|E= zPw^bD@OohMH8BLCdci1@F$FU)GjlR8i?JjtvMTGaKHp)hxY7Q17Ifu@9LSLz!)ctw z1zf^aT+2<|#@*Z(GuHnjf)l*JOT5n8O!B5lF%8o*3$rsX3$i#%MU8*{uPCU>*IAEE z_zv5#6T7n)2XY8Ua~vmg%A5K>OE8y9xPoiBf!nx)M|gsN@^9YcT_&g>Oz^S#`kz9O zhR-r9b2C3*<}0kos(gcQ@@=+YN4^)f=*18D5l8S-e#WmjlMA?ntN8=B@E88Z@E;Z@ zc!q!TAKv8yKK52H!Y7!9>6w);Fh2|PmB4VQjG!uO@J%*k3%22V?8Xl{kR$jpr*a0r zi5u730)T*mLi7VEif@)XbU zf4s)~e8|Te1rvLc>6n4x=Ph1jK^EbwEXUVai*K0Q-WX!fBkxgwh`5O=OIM4GhUgvE-VxlJM%2dqA=bGq$ zPC;H4WeJvNW!7e0HsL#L&v*F&`*1LaHPQcZf(e|$X`IUiT+0ponLD|khj^Ojd4<=* z7XR`QlQuOvKFy5G&YUd7qAbnwtj^kOz;F|b)@;wN{D1>En4>w45q`-zoX_R_jvE5Q zp-qCF+`~gW#`FA(*Lj?fEW0U>^?V zFpi5E>;DA7mz>V|T*UAAJvVV1_waWf<0<~d|M7Ozc>nJU5;Y4(_c&8A9iQX#%*%o- z!B<(Cudy!Q;ycaszm?!!zRy1F&tV+J37pL7oXtgC#_zeF+nVYB4#Dp{$WuJW|M42{ z^C2I9Cz#-q%*<@e!vZWGwkX9)tj0R5&t`1NPVB;D145uW9ryvm#Wj|p0s98>TaKFb`;&6oIc)Oi2P z3M#TD-(VxY&9>~w?(D@dKjIjE%Fj8qh5pYG%;$1`#|_-Xo!rAiJjV0=s zI2d8_mVv35k;ZS)&b=GDBHeqYFXIFl}0UXTH9LEU1 z&%bz`xA};PTAN(VSpQQAGV(d*WL_3!36^JN)@EHc z;X7>4clkloc>ntd26Gt4aRR^Obk64@e#h^*iQBk`zw=mY{XZr6i~r+o-e;mV!RQ`m zDyHLee4cq(kR|vkE4R`A*93L>7T;kjzRUO7hy6K>qd0++Ii0h)C~UEe-*Y{;aR-m` zB>&{!yumws#6)d_$vw%G3_oM>EMH(Q7GhDp%5tp6ntYQD*_^HUF5eFfhk6V8@gt7l zC!EMHIi2&kkU#K8{=!}SgNNfr`+r7of&cIZA28G|7~vCqis_k&FEAGivlz>;Ld;nI zYY1LvLpEg_c3?O5#-@DvjaPG00+0%|IvbRjPOg&;e0OVcig~D+{ryW z#A7_qzrq&Rd7F=zs6#NiA_CHt#c0$6#`gGZoYExwz5(KQGA3f-J{MtjRan zkWJZ|?fE`?uph%55i{2Rj|CGM;dIXCLN4WM{=m)rnS1y3<_ZOSWYfc4t3^Ig(>IiC=IQ=W;2(<+@J#|C3-l zf8_xl;aUF4tGvnonBd)DV#%0-&+z|fy6kYpy=LS|BCBzt6! zaI#m~JK3^lQnn~N$;=EPWD`RAopZkL-(T;~ed^VH-KXz!&WmzydS(kda`9EZ&No?x zRal+xvjIP5D|TWx{{Qn0`2WYBJ4SN~zv97I_ zvP4YG)J(^$%*g^Q#F8w{%B;q^tRFM7|7L=g?8vU{%l;g}QJlWK72l%)#6dWBV^CD9krmhLu^3jo6f}*`D3li~Tv6 zBRRI6{ZAE4=hs}sRb0bO+{)eD$0Iz>bG*pwyxq?J9}1o@L3{gUa;9bmW??}VW+|3s zRo37KY#4SlXKQw5cYel!{DNaRmD4$&i@BQL^9P21a_r*)p5X7i#H;+9|1fTcps@r@ z$`pK&nfP*GIP{93FpIM+E3yXPWkWV$Yqn>1e#(Iy$}uq``=20~&e>ed<@}x-_!D>W zI8XCW{>8g|z&M}SfBfhXc^yc?nHYqSa6!>_!n>R0UtAd$Dp}HOwQEI$gIrE0xa6m{@)Ok zV1{>ud2q76p&|4i%%g;MYZW@0wJ!dF?GZ?Yn*@Lj&oCj6M~qel1NN$@Gd z9Lmo*fm1k}UvoLX;g8(OUwN3PBgXcBPVg6R@Btq)e)r&^OT^?%&5X>-yezWH0vR5RTw@PUbAms|ju&}@clem09-3of zrVcyOF)MSj01L4sOS3You`cVg8C$X=yD~i3F`VN#i8DEuOSzKkxQRQshlltZ&+|13A?Zl`*Ao&auUDf zTrS{Bej7Eq|4o9e+{0h^8&C2AFY`9<@jpJ*OLKglY57vb*#2_}a`QD7;ae=ncUY74 z*oZCIhF#c${Wz$X{f`uk<(Hhn1zf^!xt3eGoxkuPPx1^e^I9+a|6A}6<9r%a7oUll zjOmzxIhlurSd^t%p4C_@?5NMiY{|Cl%AV}c!5qbLoW_}4$faDv@H)pbxvHu-{{XE1|Jj*M*&ij1CczuHgpJp~9usq*pExyOb{D^J&345{+2Xi>bg&mVPlXJP0E4hxFxPyCmh`;eHFYr2V zGyKT$AD`C9b4~+*}9*9hn)r8`56cD3y$GbPUn0s=4yV=E&P#txj*bU z##6k=E4;(|4D}Bhi^s%F#&pcUoXo>Q3>S5jW_ea)E!Jmawq#p&Wl#3wAb!CyoD~=j z%@Zu+Dz4{d?&Mw`<}se*Mc&{YK4xe@&|IRJk^LtYq-Hv1Wlk1gA(mumR%SKUWqmed zOLmMJ-G5g>U-st+j^boa<2)|pDz4#XZsT6==dp;f{htzC^S-}Nf=WRYUIH)WklQIR74+{PXJg$MZu|Kv^H<-d$GBxv#(CW#o^{|kcj z%*I@Nm9O(nmSGiE=lg8HkJ*Zy*lmdYhXn)pIY)B}zv9XGZ2?UcSy^EW-+6M|IX_1AfR>Y{zcw#Q_|`(HzftT*y@n zuW@YVHtywq9^)xq{CKqxk*Ki%TaR>MF5Kr+euSAXR|GMBlA2HtWpu(q_jH#G`S(u0U zS(IAa{xzh6esaZ&f$D6=QmtG-2OKUc5n|5@+g1jAN-3q zc%P5>)QF(LgiOj5Oh3Z@GYWDt4@tyvQrO&3k;pxT8FTOv2Pm$1DuzaO7h_7U!F+z{;%0Mr^@0?7|-G z$3Yw!7!HjUe90MHz$N^aYq^!%`3n#7B+u|Nukl{Y$o?M+o*ErgmypjhC0}A@=4L(? zVF{LFCDvpeHi{bEe^Wslc3=UgIss z9TPN`fJvExFESHf<|`~b#{P>7%CaJB@Le`!6Sii1cIT%Y$e|p=37kI0{$~pob2-1~ z2L8ldJisIToqzBuZ}K1h%LL)E_R17|fti?%ukckC=bNm^Dtwpk^FuacxUJ(8_F!)g zE%U?INAGOWrPtj9*40!wP(l_1Kin*`A%)i+wqm!#S1{ zIi2CzjzwI?HC)H7+|GSGz~em4i@d_yyvHYj;ZWR(s$>$TW;*6(J{DmKmSZK>WF0nQ zQ?`j2*?$K?5BBCD4&zu(;0;{t&8}LK6Vmo$Y zFAfL{hlU77b3DJ|EH2_Qe#iCvkvsV-5A!t7@k-3d{;vz}@gbl2DyT3CUtoG>V=lhR z*ZC&PunMd5{ixCXHxPWxR_w%X408ZK=V(shSNxib_zl0~mWZ+a|0wvGzw$Uw^H2W8 zyL`Yn(}Tw1GYOM3Ju@=bbonz0=_ zvKRYu2uE-{Cvz6(aT!-}JvRr2Lpud~d6>s|ju&}@clem0nVMr_re->3WzLw9{TC1v zVo8=}WmaQd)@NIO!k+BI!5q$UoD?;>|CxfhT*{SP$4%V9Jv_wUc$ODmW1?icQxtN!)vlz>;0;{t&8}LK6Vmo#V zJ9=>dhj28<^DEBcA}-^1T+bi5lfUvX!>1kR_!n>R0UtB|*FlAen4GDZky)9S1z3zF z1H+*Tg37GTy8MvM*p409i+wqSBRHOuIg9gRM)to732QT+Z*gfj{$C9_MNP88fo~zXW&rfN>TD zmBnWgCTDtPWG?3A>nz4Htib9~qx-KdXuuEIitX5qy*PkFIGW@66=!h~m+`xZvHh)ssQ}6|5WLD;3eimT~ zmSshTt2=7*Bevit?7}|m$Kf2wN&J#?xqvJAZD2UGNwAfB_zQpINnYS(-sV02$ETJC z%{|BGnU*ibjO;&$AU9uQ5x&K8e1|nzkB!)ZZP?%Y6nv4H_%dG!I|{Qn z%d#SC@Le`!6Sii1c4II0=U|Rxc&uY8r*j!saUC~tJ9qN{kMK0l@d~f=USK%%P!M;8 z3Ymn-nT{ElgSlCdh507SurjOhy_k{x*Ap~lbGBzE_UB-Z;y6y@OfKY7uHiaviyGbk z4#9pN;whfx6<+6kK4QF;L4!{-8B;L>voKG@*#7eiit-JX=i98s_t=;pu`NGgPxj$p z4(GU)_CHB5lXJP0E4hxFxPyCmh`;eHFYr2V^U+HC|4;Drs-VK>n2KqcoB3FTC0LG? zSd(?wh)vlh?C8KA?9D+O#<85p8Jxop5b|3<1Ieq6DIs7XzW?0 zWEy5>cIIQjz;LL9pcE^yD(mnAHf3{mU}yH`XB^7UIi8baM)p5bFqccXg5Prk_i{gf z<4K<9CEny+K4xgO{U?eZk=KF5OvSX!%6{<&|V!>*D&mZ^`_wfKv@ONI~RsPL?CcRuBQ^oM>-v`ANV`-M>JFLkM z*pThmk-gZLLpXxtIXN&KnkAUWWn9Je+{~Ta%fmdzbG*nKyu-%~t&M)+kw-02?1;S5 zGd0sOD|0eGUt>R zTg_3y37+RA-sD|AW@ugT>^#que2JNvoB3FTCDwVXDJQ7JnykY{Y|1w5z#i<)K^(@h zoX8oRv(8)162S_tSNJN6^G#Na8QFgo!Ml8)P53d}u_Jr34+n7=$8sWPa1NJ5jqZPiU@bRtJ9qOS zkMa!9^BQmQA)heeMh_iRMvU!0jUY3#Gan1GINxLiR%SgmVhgrm7xrMkjrKoCFp^{W zC1-E}m+)Jz)6Qc+|7eL$}>FAYrMs{n}fy@FbR`09Ww-m zLpcPwS&)VKCd;rgtMNV7V^cO~dv;&pvq^MgfB2XvoRN6IF^vw7}IQScL3G(uF7GoJ! zV0G4J1AfR>Y{$Or&k-CIc1-3p&f`L^;u>z|Htywq9^)xqtGhC_`7E!mb`*^~V_n4>t3(>Rk0xs+?Tj@x2J_P;~0pNDvo zXLyNMd6y3u+NME1$LE=e*_bzKbpHheMfnEHu@YKH4&i8y=U1G?MO?=3xSl_T9Xt6e5A!t7@h{%s13qT_pMnMxF*#E+ zBeOD`*HM7QSdtZ3nYCG$AF>(Su_Jr2FNbhMU^p~hFqyMBkIT4<>$#abxtE7|jOTcf zH+UyzWdDx^q3x<;VrF0#=3#yoE_If!BGPkN6*--VrqS98)nZvoHtq^R*pMWr+PI`x}C{_%`2} zbh%9A_o#;X@C#1h6wcy2F6B!8z@NB}2Y7NtuE#G813s zD=f_7EX#_l!FOXup3#PaCTz|2?9NX)fI~Qn<2a2oxsXe_hU=n6pV4iC9o)}DJjJuT z!t1=xM~t^CXz*z!V=87~mWZ)uG>;%Zi}DSYVAdci%ei<{e{~3Y>T*7a;mOt<({>)!_jHh^!S9pi_ z8QN?A@uElMbs#a5F9C-blni?TG!vl?r$J{z-T#Mu7Z3c9i<`*ScyaxABEI+t-3 z*K;#>axV|>wf|#+bG*nKyu-%~{Twuwh>4k+>6n!{S%8ID@@M-mEvU?Dtjqdr#+K~J zuI$VH9KlhX%xRn#b}Zy7uHj~G<6iFPF`nW@Uf~_yXJ}v0Ts(#oJCZRSGcYIfun>!~ zG|Tfn)?-sPXM1)E42OCN`f@Obb1WxvI%jhcmvIf(aVxiT9}mQg?EkpnG%xZBZ}T3X zFzzowmCrBp)V)?^(vVpFzZ2lilZ4&pG5f0^J{4;xeP1!iJ4zQR{ooNuxs z!&Myb@_jbp$866|{FGr1<>#EhDV)u(xjZl&`bMyUTeyoq^9Yag5B|xUyvu(X=YZyz zgfGO5>_5FA8*{M$3-JxU#Y(Koclka)WHWYQ4}KOky8nTK&pDctIgRtUkSqBuH}VJW z;?F$IbG#BUw*TvbzxfYC2ZQS3@mVHiYNlgmW@la&U=fyJnS=IULGTW1@_jboM{L3N z?8Khz!+{*iQ5?tF|Nl`qUkg@nH8*i9_i{gv^E5BRX{xr%GJncKLR`+1C~c#&6*c>lj6xX;khpt^WW%w$Z*49v+qEX1NL z&GM|qT46^$Hez$OW+!%IU-sv4j^uRC=3*}A_Y7}v{KQ>6z$5&ffAA`A@*n=o1iu9h zKEo7zftdosp=^Rz_$rI@O;%(TzRUO7gdej#JMmM7IW%Tu|DOvca0+MhYcA(E+`ui| z#h-bE$N2~U6wkW_$puLn=HdBtj-T3#`fP#(2gD1i+wqS zBRHOuIg9hSjH|ewo4NCt{qGeV<}se*Mc&{YK4$26&{!fSW@@HmR_0`Zg!&D_Sl+|Oe?#f!YcJG{?u=tNLmJSJu` zW?>HI=WBd}Z}Dxu!}nN^AF)MXIP{623;VDihjSz+@k`F-0axV|_SlDrn7kPts_?V&7s$*iNW;$kNP8MJx zmSniJqcW?pF6*-yTe2g&vM>8{1V?cu=W=OaIJ8o*j+?lHdw7Vy@hmU!I&bq4|KroY z2hBalR52s_PbvKj#Ea;cR}*<@|;l zxP`m;Gmr2%|A-jd|DS@Jyvu(X=S)!DGfcu4n4Z~~i?8x^mSkzZea8OZ5j12IwqiSW zWl#3wAb!CyoWid-j|;i-OgQ+;z7=fb58TC{d6>s|mKS)9xA+hLW&E?j=S#$7VMi*y z#LRq|udpObvofo(F6*-yTe2g>hhEpCdSmlR1s^xR9&3hMT#Kd%2&-cq%X)x+u89 zJG{@(xuCLmOw43V#|+HLJS@bbEY0#UtAs+;1hrV7joFfI*_A!npMxhAYZmz*Dz^G? zJNNMbkMlGy@(LgF2^0PieErWdCDSl7vj>Jl`2+=7f~8oARau80uqm6f13R-fKjScd z5i|0FI#Do{b2y(XxSAXJ19x*DkMac1^Ad0I@2Jri)F*3$ql< zvMOuv12&8pdqHh3XwA;-&d)fIUvLbkaysX8F*k4vcXID}FQ|tEzwr#u^BQmQAO6eu z7lP&zF&R@a2XnI^3t#YpT2fG&l~|RvS(lC2l&#o~UD$(R4&ZQ({QqB=Aeh3LoXf>r z&NW=eANUjZazBsq1g|iB-SL2rnc!kj=`&2pG|a*rEWkp1lVwYF*ozE2urXWE3qc)uo0WG%_aNqAn3u~9K>N9%ZZ%9Ib6aOT+5Bz&fPp1 zb{ypyp64~*;zK@R!plK(&oU*`Ff+3=9}6;E!cmHqSe1470h_WpJFqi*^D_?P7o5nc zf#J|>!Pi{IRb0nS+|J!Rz$3iKE4;(|3|$Etix)Gp|HOi1Oven&$viB?qAbnwtj1cb z&&F)Ywo#+|?<(lY{v6Cv9LH&#$%S0XHC)GS+`;`k6fw5{Q-ZU+!t1=xM~wGZP~p=| z##GF}EX>3FEXp_jvj6gew^@ttu`xelTYkcx?8Ctv&T*W?1zhsi|9?RxSj(;4&R=+t zCwYdKd5!n@kWXC=8cWFMnKJBniJ6(3`B;P{SdNuglXcjLP1%MW*n{ETjzJv8v7E>m zoWmtt!L{7T?cB|SJjyeH;m~=(HQwSwK4HRZL50sUCDSl7vojwHvII-9Qq0Kys|xDy z1GZ*+cIT%Y$e|p=37pQ^T+HSCK5BIT8w5Xb7Z30Vf9D^(%A5R$|1!b#ps{C|f-f*r z#Mu6`3G%W4i}DSYVyvCIEPEPf@`^v+qs(ud6Z{( zp4YD1|1H5oK4F3zDr9n|W)9}&Yb?UISdQR_ zTdrkzt7AKV;X$6{8D8c!-s3|)bu(xzA)jYTzQoLd;ZSZtJ{DmKmSZK>WF0nQQ?_9T z_F!)g;;@*J{f`w)732QT+Z*fp4+(Nmi_M+9O5aS^WV1rqJlSAo^P`j-(zEb#J2o|J=uqYIE-UBA?%pPgmoWmtt!L{7T?J*tO1%^Z21id(bLpYk_`4wkz5ts2huIG>3 z$zORmX5>*iEjY)&c!Ll4nDOr!9g{OPGcqglvH***WYp-RR6$UgwON-RvKia4BYUwg zhj0YPb24XfUc}g2$uhwzuIFa%b1J&?3reqrC zVqO+vQI=v^R%SK6$9inVa63m=_T*V57k}nap5O&u<{jSW6UKcKH1`~ze`5a`1zDMg z`B{V|Se6x8owZq?joE^2*qPnKjv*Yuah${%oWsRj&hNOMKXNDc^AJxme8zE!S9zBY znCL$b9aAwaGcg z7BRN}F9Z`fg|j%1%eac`xQW}jn+JG=r+JQdLh-_}itY>k<5O{h>YiZ|rea!VVm9Vs zeimkNmS%ZYjS~(&Q4K+3e#Ca{$WIyOFn+;F{F3vykl*k-{_y{Q&`*M2c#x-fmUnoc z|M97~!58u@lkx?oXIAE9IKSgHmS8DXWEIwDW42%$c4l{mIe;TLDli|gVkTo+zQpW&nXmHo zc=lgj@HT6*4jZxwTd^IxvM2jHenlvJ2-l>4~K9BCvXbqa6VV^TkhZ<9^_H} z9vJ!l(SpBtgZKG}PbCPNO30*4!Su|?{CtfiSc(;6M)qGtP@8qxm>;n%KVc8{=0FbR zXpZMJ&g9Cd(fxlb*vKEalY4oPM|qm(c$wFDmk;G?swRGi6{nlvR+E`B;!|@GVwnZPsUFwqP4}W_N};AZBF$p9@BF zGN*Aa7jOkva|5^VS03gmp5-N8jT+tm9l?D*Vcche>Jl+AQ!))RGAna4A75uNzQuA8 zWBacnsLuCTk4^Y7+wv23=cnw?!JNP;oWuFg*#Anwx7^Ha{F%S<1b^pcUgLc}V*F<{ z$rOCyS^Li{$jxqPVjgB$-j7q_xT^6N*pxxER!-5voS9Vut?PC{!0kTumay{so}Ji}eK?RqIVxgo|KkKxIi2&kkSn;F>$#cRxtqW8FwgT6Zzs0@dxB7spvrhm z!sL9BnV6gTSd?$D0xR=fzR#vf?7z9-6Lw)=_UGpu&8eKu1zf^4T*n`|lLx|%BfP|` zyvqj+CDjn0VAKXF&Y*#7qm4)Fwk=XKuZV}_Cil|I8HOv4wM zgSlCVMU&Zo89@cs;Ja+Zrfkbk*o%ERl%I1Vr*bYAB(wijf;HU2AGwbQc#>y$oA>yH zag%F^Ntl}H!j3G=!F(*p;(U`8SefYvDg$H?@r+I;w`GAj^Af<=ApGJ^{Iaq*& z_$JG+Dr>MF8?hzZvKxDGU`qQRDj3U&oXNRd##P+FE!@q0{Ea7hkyrRQrTvFe1=T#w z=a`adn2Fh#mjzgqZ?GIIu?F8|v#_HjJFqkRupdWrJg0Lu7jh{#a~t>Y7lw~IPVf)@ z$s4@G#|)*`7@uQGreP*#V_p^r42Mb!%JUu8bhXXm3qc|>RWdBnI z(>ad|xq_>?o}0OyyZI{*^CZvkPyQ7(y8qjPdyM}=P;DZn;0w&m?99*CSdyh#h1K~1 z8%B)nzlER;yRs(-a0th60%vdzmvSZ7b2E4G=NIh%sNe)I@G|f4J`<%08cNJmOv}v7 z&R6&AU74cUYp*_FNd8HaNuzv3(|=JK#(4cBom_wzTN;+%rtV)J(_R>FqzCpa@H_ z94oOV>#z}N^Ss7ej2nJ2s44-I zG6i2`Ccey9SeV6GmK9lp@3JAAFx=YFp56H=2XZLKZ~~`uHWza_zvl-2#9e{m&~d?O z{>i_1mk$`{rJ%9+Ov2<$&y38;JbaBsVn+5~N>G+nSe3L-d+;+3}JTBuZuIFa%Ohv$=@N zVn+7AMzD@sxt;rXfX8{77kP!Zd5=#RH(StPa;AHs)dh7GepOVg*)aP1a!pe#jPq;ZPevCw5~W_Ty-d z=XB2I60YDnZsJbv<&l_?{T~;c=Oy0eJ%)06D4B%GnT@$vfQ9%5-(sbx(fwByyvz6b zA)B!+KVc8{=I0#E$(+WyT)-6(WBXq%*uX8^$-O+p-*|@Sd6hRA%B3+TW-_MBW&arj zIhlurSd^t%p4C{3_1Ty$*_K_|ll^nq|6su=j^i}WP_Y4yt>O&oeDwVh-l!Yb?UISdQqek~XN$@4-asgNJTW;c3?%^-|jVF15mwB7_BF6UrpWvxH9y&hHw0wyIkj?Vge;Yvuc4II0;~;*{(VWCDIh$W|DOd7)ZpdT*+XOqfj|X^+r+A*1 zc!PKNkWZL6Z_sQqrsYdvM|QrUgIr3 z%xC{k1PSv86+X+9OvB8~&U`G$vaHA&e3uQ`gssDl_Uz72Igmp+h7&lQv$>ed`8_xA zC+=eSfa3^%=O4VvoBW6WGC_f$v1gc`8JUZD`8taQhC^ip6wK(>a?fYmYDE~i>&)jqG!Md0myZ5d$dyBQ?xLAkmVhP!^Q%FK`3Q3Z1FE%8xX>+S2BuUaH zIfW!ilGZUvlH`<}lTd!2Yv#4z$M5^cKJWKu=AL`zn(Mk|?!z~&D742;n1MMs5QpF> z9E%fi3eLdUI3E|_V$m7@%P6eEHMkx(;||<~NAMW_hG+2#-oSs+Y(~p9WBiw;5Q~*D zfOW7THpSMMf)CX4k7{WJkIj+Qy@l)J|d+;FsfG6=ZUc@VoGJoBoa2LJFZi_^s52LXP*1$%X zgl#YtJ7YKOj=i;d{u)4GFg}S-;d3|{U%(gf6?_ff!lk$t*W)(aAv*KdHx$0ZLwFQ_ z!Qb!#Uc$fdA2eFJE$GG4Xk#^uZ^`^spF$&Sg>A7jcEg_72M6O&9E;;I5A$&@&Tq;5 zwTQwJT#M^*8}7h8xDSuuF+7E5@Dg6b+xTCQ2jQ*UCX2#KSPg4qA~wP1*cRJkSIoek z*art8Z-`4_z8c(v-k&I$G`C&TCLrd zD~&eBVr2|q9c<_*G z_$7Xg#drvR#$WLQUc$fe4tm=#{v+jq{!ikT!x*fF@z@kwU@E3zI%Z=Z?2k|22preO zTibcz2^6N{3pf|&hko2I*Qz7LV|WVB;3d3Foom%p3NPRsEWi-HiOX;Weuy9A zM%;p5;@7wj547c4^&^F!@id;p%Xl4c<9`^I;x=(9^kFns#_HGro1_HYC$^!Gid``S zdt*Nwg2QnfPQYn60}HSa7vr)Z4_0FlZpLl68~5T7Jcg(79A3klXr$5!u`CA5^PmdW zz$Vxn+hTj{iW%4w``|zvf}?OOPIL_#Qz*>9+4u%7#x=MWzre5XIG)7IcpW|M+!hGO zs*W=LYf@;0N!S4&#Qr!CpTcJ_A7|m)_zteZHMmu)$Nv`;_Typv8Gps|_$U60W_$O@ zd>D-Ztb=W_J!Xr}`0qhsB#yx#PRIGU06)Z!aU*WQZ}EHl0e`~Z+B5#oQn-xQ@eba@ z$PVt2DvZWBtbw(#J~qN+Y=h|?BHRsThwA=VV`lJU>Yw5k+>T%4w|D@L;LrFgp2LfH z9skDv(39ruM$jndJ}_diItK85Y>cfj1-oE6_QJmSI1a<7@mWV13{xq*fb;NGd<&Q2 z2lx?g!maoK%K7NQ>@e3@*L$30l5~FYy|3gnF_jt--4A#N~Ou-JAgFW$a9EN$A z?J$Rl1e;?zX5#=Hj8EgU zI2Y&R>-ZL~#v;*~-ZoO$f;(|H7ULm2jwkUv{)vC#KWKJ#k2nm=V7bmrZxtz2#Rk{} zTVY%5h+QxXyJKH`6o=q&dFTynIF`loSjkbwe>DoVF%g?!b8L(4u`6a^ ze;kOz@JW0YpU2r+J^trXcnx32ckn%2kDGA^?!tX|0FU7bJcAeTy6BAmzbV{9>mj%4 zN~4XjSQ!IY2a~Z4reSBy#9Zw25aYi;g~xFij=^#GJO*(F&c;{pHC%*C@ICwh*FMDf zUr%8xeu2AjFCN4n@C2U1^Y|y;MWdVBqET2Dg0(RblQ0?EV<*hQ?${p(;z%5W z6LAU#XYpVTF2FZ%Ij+RDxE{CTPTYqF@Hn2t3wX)3l3}E~P2)v{zEH)}a(~i>n2MdT z8+OOuI21?XB+SEEI0p-HA+E&Lu0i873ZLUXJb>r%PrQpphI?E#R=`ATfDd3h%);)D zGCz%=FdE0>M0^on#aWn3~UAPYq;7|Aqp2a`#I{uyMZQy)Vc#ndW<+ea+ zw6O-(3ROHS?~?L~vv3~1if`azd>7xxB3y@`;peyu_uzg!>?;4#D}{4-4R4~6?H-30 z%VK$~f;BJ^8(=cF!A{uKQTl9m3cYb44#6=v4yWKWoP!1U1}?^xxEj~vX07hCJ1OkO z19$|_;YGZGx6sI;g;1dn@e<94yG; zn!1p}B3zCuu?W}U7Tk`zaW5Xiqj(Ze<3+rZ!!`95g}dm@b(=I2eHe|kFaaB5Gi;0P z@gdB_-qYj;WfOY)#Lvjg~%Rm6Do|siWrZzu^~3aHkgWCFdchh9~>k) z)-I-@tc*Ja`X_a2;;NFK`d;!yoV` zJdNk@D*lE4p{JMIV!_fpurUs+;C)yZn_zQH!4B9Bv+!Yj1c%^o*P!teBM_#S?M>u@7}fnVW1Jm4tf|0fE+;5odAf8jsq>FqXMIL2aStc3~K7@J{RY_HYh z{~-#Q*cw4Y{2cf6Tid#_#^&|zvFqlhBxsZ zS`RZ!(f4r4XKECxVr@*srq}{gF%8o(8~b2?d;&+{IGpe><9{lJ7jQ1l$2V{>uE15e z8Moor_$?m7qxdWS9^}C#yoPu19!B<|=`aQ>Vm#KyhS(I_U@CUOU^)+aVjmoYPv96F zhm&zC&c?YI!Z&d_uEdXBgT|*6w&4!^7Qe@%cpQJn^LPz!;ytwb(sJm-ijFe=t5T?q ziP#idU@E3zI%eZQ9D<|qX`F<4_@cJEjQ^J@EWkJL9efXqa2;;NFK`d;3w8OcMz3IO zKli{ZV*u-5Lu`s|FcrICI`+gqI0&D>F*wdOXiTOs6=&mI4B?x&99QDU_$h9~9r!JN zk4N#iqnz2(6wculyn)_F+!l&NA4X#ptbqwwACoW{Q!!1eXZCIsvamPy!@)Qd$KW`e zgn2j%=U^ci^~bY}L|6pC;oZo!?n8;{~~{2kBZHN1)U(CY8Dq(Wc+l9`=CRjiGP z*c4k}DyCsNW@8`hk5AwT9ETJ7m(1)GUck9HAK%2caV4(CPjM6Oz+Lz~9>n8#GRTAT z_$S`P+h{%NHeCezFdD03O-#fF*c@A7dkl8sK?devAMB4qa5zrHDL4~f!a`h#OYvP? z;~F&9Ququ%$KALW595z`3eVtWypDI#7~r;CDJ+A2M;ZT>C6L@tE6m zUMz#qw!gM9;f3>oQJRCa$FgD@veM| z89C5B9)%S!7OP=A*2ViV36n7eJ78DLz#jOpYtR@niI|VGa6T@;CAb{d;9A^* z+i?%>bCkY*l)`a5gBS1y-a^kHx5dKIhtXIK$hvFCjCc?978~?1BApAdbM%H~}Z&3-}_=#|8K{ zzJse>gGLdBO}G_z;T}AQKj29`jep`*yp8{1#1OXyOJfB`8UL{qs$&4_VMA0`nIjn@$uuhN%^)LyOu^o2A49vm4_$Us=k@yTg zhtqHd2IukMRa}Hi@O}Ic*W+gV62Hb`JcK{vuXq73xdx5DDcnKtFt-UKu^h%=HH^o4 z*btMk4R*vXn1ekXW&A%%VGxeQG58!##u+#p-^90ZC9cL#aTD&qU0OZ0XPhw#PK*0r{hd4z(Rb>QO5sL3afApZotoQ zC+^1mco@&%1-y=bqw%EMVqPqx)t_RPqfiN}VI8c8Ntlf7up?$*PH0n9&0fJbiErb3 z_yK-`8*n@B#P4uF9>WuO7XQE-c*`|tn4{<-SQg7;Wvq?~SRb2VOKgvwFcWjJ9}aMo zGdq;RNF0X~a2C$NLR^STa5=8VBHV~ua3}88>Y2Tm!XZ44C-EF!#2a`EjnQ-&ROrJv ztb(;LL3C#JMii2;4W?pe?1uet01m?^aXe1M={OS$uyAzA%uZn`uEI6A0YAf?xEuH5 zVLXAS@DIFRZ2CzOh!j|{|cEYZhi@k6F4i56*Nqh+Pvf(ghxzz2zJhN!%J^SQ;XV8S*WpI|0>8q2cmRLGU+^4W#J}(# z^o(WvhwBG257<}%t6&YRi}z!5Y=s^0LCnJL_y|6R!$oKOkD~A_K9Bi03tz$4a0RZy zwYVO);SSt``|!wE#{V%2zu{TDjMwoF-ouEe>3moLV=)2iV-hA~%F~Sh4ivg#2KK;* zaR3g+5jYyh<3yZ_FJK`q#AQJqtiU2%hud%m?!{s}h9~eGUc{St8@=P)7K_ASc^>$& zD%Qk$*bv)dd+drC*c1EUKpcXjaI9<4m`Gs?&cN9?9~a;XT!m|KJ#NDtxCi&)5j^H7 z4}2I0;9wkqqj5Y=#HsiK z7UDu&hATv8{1;JJhud%m?!{s}h9~eGUc{St8@=P{bXXq!;~D=|Db&Pz*bv)dd+drC z*c1EUKpcXja4b&5DdQRcGbqf)`M3aA;3`~;>v0?Iz&*GRkKi%<4bKL7a2c=T9lVDT z&(i6z0>)wj*2g4F#uV&;T``!!gC6)W4#2@U0!QO`oQPBL1uVpcxC~cdk*oak(G<4f z4%~~ycnnYAIlPEB@iuxV(CM%|`Z2*##(#YZNtleOn15ua8pdNHHo)dV9<;*t*a7fB2K{>I2-5V0t_zZ!7^NhYj6X8 zhF{{>_&pxPpYRtvi+|uGg+ACH zhv0A=i{o($PQ#aQ9)|Eud1bP6uq&^j2a19!T6c*w#T!BTn4!7YB+>6C{3{T)WyofjP zwxdjx-aJMRmPbF%d>LQCH}P#;gKKd! zZo^%;2M^#8(U~YuP&kDb@Dkp{+vu6-K4#rD`~DidWog>3ALkK!mC zixY7Q&cN9?9~aFxn4^kXGQ z8C10>Bw!P4j;WZ28JL6pZ~zX+Q8)o7;S8Lub>4kYScuDT1%8Mh<7fCe?!yCk3{T)0 zynxs6rsxc+|0sC!-KL7dvgpT37>~8FIkv)f*by@^7YE{ydc15CjVq4RZQ5WYiv z57*#Y+=N?kC+^1Y@gN?<6Zkux$18ZlHE38f+~bMBau|cvF@X1DV{DBn*ag$E7xu-+ zahRhF!lx-bi&OChoQJRCTeuWIz>jbfZpE+hTReKMR!*brM_YwUmziq0U+q>zh!@lhO&Pvb-p2o2gGQMb-2*I#m9aY3#rv@Zw#JUw1#__%K8BCuXnfjH2F+v& zQ}HF7hp*#X_#S?MpW-I`62Hd%co=`d-?Vzr{7K;|-oblVZnoP(F<2FAVqLr+n_)|A zhaE8;vqfjnJWSycd>n`2b2u6EaTd0f5WqQ z39sQl_%C|rxVstY8Z=@lRL1+TE;hv$*bX~lCg$QJ_!y4B(fAxrc9cOglfp~*8orM2 z;CuKneu|&tm-rp-$Di;QJdb~B^`QBi!W|5I*=?dySQ)Eh9ju2Q4SQg7; zWvq^MupTzW7IPUiDHJ;3LzsyJaB%3KCNgMt5_jYGco2`_3H%+;;}yJtckmvD&vTD2 z3d>=PYtX1gApx6Ub46C{ z3{T)WyofjPwpI@sZ-LuHkysx6n1J;$36n7u)36(6VQ=h*gK?+aTd8~xh zur>x0dC&x#V_R>`>cDVjmocLvR$1#fdltXSm8gkV9cUF2KdO3|HYAT#uV^2kyds zcmR*#2|VK{Tx zdGup7jK@T5fX%TLw#QDGfjQU*`{R(3PrZjz7>na^3Qoh>I2RY-8@LQt;2K61b0#D%uyo5LLHhNxT9>B6#9xGur4A$mBA~wP1*cRJkSIoek*arvV5FCYL zaUxD}4H`2j%*Oe+02kvjT!m|JJ#NMwxC{5;0X&8$9A*5Up>P4O;Z6JxJqwrzuq^tq z62@a~Y_5IRG+JSM?4%9Kf(!~d*a!RL5FCyZaSG1B+4u^+hRbm!7U4QEsP}9Oh3&W- z_u?TuiYM_jUc@VS3-6*goOGy=IHhQyrhIV`gng|0MocR&YR$ zVVLJS7)Dwh!};HUZmyoi^1xf>!G030*b0Ubv?7}5$DXNi&RE&Ap ziC#5ES~bc~j8u=dkQhr;D!Qe_IHFG-tRk@@F4cpOi;(9p`vOK>#Lp8EK%`hPdNZjppj}IXDh0f+0Thds=FLzRBa9^ zSvBb;F_G9tz1Blw{fg!a=MYoXgL1~A8kvKfn5Nc;=7k69_no5mF2&sFRJ*Ceog{WP z4?3~CI(DDLF2vsIxL(?o*iZeY<3q#&>Vl5l%yzO@p1@#rC*+R^RBQfXtW?*PT_9aT zMQzqcV*grKN}st0W!MY!A#ZVy$!mY7k9hlx(A6@nqC-<60*%ejLq!pR1mVYsKzzMN z0Al9M9s_)zUg>3@6L$qjN)dM(57TYcqktTjf~iL?HZ)~jgMtt$Uf601*j z!>DYnmZep!eKNAET6JX$)vUd8zN=gB$g$M0o|ZPPY4y&OLyEVC%BlftjjUSBnkY}c z&zdWLYg>nH!>D6@TF)>NtY(RZQP*nN$}keG#09 zR+{woMpnF38e661xSLol!sQ=%vueorO0u#_8%8thD_OI-6(QSc5wu44HH>8IKADMH zTIXaZT3K;z45PKROm?D;bwnONV7)6Z-`2V=FP~yPC4aXY)|@W#ui+ThGI{n6!`kDK ze}`V54q526+kQ|+PRie%^|?AL=gqV(XX}N3_0s3cld8{EJ^34E%?wJbgj;E{Ai}yT zGh?K6x1T;)Wo5>UvMS~3lT}GJp{)1iFv?hMtZuUZeyegFeXg3xS&g$ovWpe1n^p9=`aLPAPgYCWmnznta{6Rl zmiDe@70F>$w|+MC$@)Y7*0gH-3?trpMV=P0+BebXDmO}>tGd#wYFnjb=jvEX<#B?Q zD_f{*4VJ%&)}UtkT#c7*Q{OuOs6JPFr6n3z+gs~%^>D8Azed(L=^u@)FG}l^HA^

!($~>y-*1#>$oW5RSa+pGe>SXA^$p{MVI8Vw7{3_S^h$HcZ)p^4@Dld4!uxiTO z_=jvw&i+NiS}n8dpN6$bUg?ryEtFw;SvDj4d&RJRkS=r8um;Krxn@|$q!F&m@d`H# z>meC@e;L+z={GlJ7^KO^o`!Y0x%^YBhSfLAF#a*D2GXLp4J$q%{qK%pwU_FbD8mkdxrI)9ATbm^_B*jYFbxw<-a>*TFa#GO*gHV@q%d; zNaM{gt)tT1GfgW}Ha5$&Vr5c#(X{6DGK|@#wWGHDD>J6GNsereX-$rl{`azJt&pxT zSGFc?GS9RgltU{ptyR)ZUNNl{Y3})^bxNL}m*=$xJSe*%j!TmL5WUhW)5SOC9Oa8w zWc3%s`ts`X!x&2r-k2#immx4qJSC0!qFAM|?2j1iCvE+bJlI@8c1heXEhE3Au};eD zG*{d!eQ2K8RQf`J7%tsaeqm$%D+fDYoG*R*RWVljZ=vWA|4fASyI|-m5P)j zkwPH!pdF~*$ zYt5Agn<~B;`p6E%2G2@)dS00IgLJXHC1KWSajH01cO>ysnKY)0KgraeFP@Y3dqFIc zcAX(U-Ax~Mn6Kg>#(KD|&ZlxBKe>?zxQ zL)=qKAAXoMSvuMx@kzN#z9lLdAB)9rW&O9svp)HkMa2iCKP?q|%Kj`9$I0%zBi51Q zTfQW$yk*B5#=BB@RN8Zem>r5J7pNXAmgOHv94h^7wYW#x?L#qD#_<~Ql5~%c#5}M3 zvy@^rd7Y2NtagU6R$L`lzfZ(OnSJt3hFJ%t-KL6<$;(X>hdm_h;Sllk%;{~y) zoR1kN!-7`TD$?*$NS6)g<%L`2bMy%ew^F42^70}Lf87rHT07qSOR}jTthTb#hSf!SUZnN6 z?10Y-J|gF#hLzb(?j{U>fgH5g{>jYMPdO_q$ehtkZ@#*;y4U(r&Ow;9NCrf>^^Nq4 z2#_F83(APqyJhW>_6#@tUF2ZA_9Zj8 zRj>TYqk6w8$i_@-p={V=rFPLz*_EW9a$SaSxb?X-Y=m_sOkU9NuaarXYyV^Zrk_1a znpj#!I<{$T4A;-@-A4+BUzO5pg?Vbqep_E>=(Qe@12wJPnR>0}a%fd7>+g#Cr7p;M z3A47!NeH+4%Gii7O0NmEtq`c({&krU?DC!&@^rboRjL;0@?P$*kc?nNI z8D6hM`%3?ih3@{PDzBWq|HU+w9(q<*3XYXC z^uKDBIwq%3qAgw46X>ooYX85by;YWUdRgi=KtE+>Ix)ssd4T#%29PXm?Zly~Tw5oW zmHFQj7^(dF?3M8zbk5!wb)P;jWxT!Jy&I?I%PcFoo%7@g>Q}j3Nz_ZNz(P|+HTZvd zk*P-M#x7aD#8glB{C|15sYZrI_+?TV)%yRHi%eBldfNYuI$~=J@s#&OBoOGBcq#N0z zS*ejapf@?*+f^o9PasLv4Lu<%1t;s*UC2tQ>eF0_uM^XhA#;_z#H-(rcmkc(S29c3 zD_Gi1oqRyzd&Df&Lm%KOVt2JopW_dRz13E^KGfMZ@yjnV~9>}H1(y7nslc~tk zssGe7R~fQ&>M)tY?P#)eYG))?4s$#0c2n(aB+ILY4Rdx&I{8$+ezh>U2*`1rHa*H4 zdROm9jPBgc*v=IhgZlW>$u~@OtFPqlg{dxsq`n{*Lug9Zyg*sLaRBt?0E}r%hp107WzSjNpeexoY zdRh03qOilx{x9*UrJ>j4Y1x14r|sb7S9??|-K<~ov?5teuDSM}u#cUWTjx>VRgnBG z%Qt$Ir>x`yVfv#ME3n0*wuZv01gh7(Emu?fEUWGIs3CfMoa1Ho%FBd0%4)&Q=~BK& z`KU+zrn_QzxO?u8dsO*s$%)kIk_#f>yj^eRMn1> z8w_y7>JV8~MC52uTZh4fxIj|oIPn3Dr3f%Rmb9(t;mgiaOEj<~G2_NpX zV!ox?>&bo=%V$~YcYSu}k>^-yt?qSihU+OsI=`h_=p9@ZKG$i^g+WW*)>HKRJYkWg zradfqJ9&xaUJ-Vams{=?;rnoXMX&-ZEfuM|+Yy%Uwp3HyZGR^3wNyx-h|}a^OC{(F z@C9=4kfq+$dvt}uQA>TKC-0l&K7~bI)xDhL z*U3w~YHuaUE6K~fYP6g^do6jTSKZdVa1(j8SJjpKLi@{zpPiFj+#By{bT;v&#`aX$ZOCdQ~&s>u$1q zuUBo*z1AD)&KbpC)k5!Z=}7k+9`dT7yo<2QlY>XSYN|fsiWH7})h~LK*C3yiCQXxE zhkRO^u&Lz6Se!qghw#6faFn5v+c zzeX+$Q$zI*zvbkh+)9P1<+_``%L*YRLy`t`;#V;Pq6;>F!ijSzJHH& z-c<#5hN*Y;IKD{U9j12Z7QIg18>Sx7`+u9~7l*0cp~E!;4TBr?eC99Zp81nuYNFn) zs^rsQ>b9PMYmv`|sW0_m)gxaFQ@Oe)H6dRKQ;+JaQ_E8BVcZB)Z#I_Pj^($)RF=M6 zbRpjj3r&v?lq>f`FDdq;m>;g@h2D*q$-lh5B8{b75UvvSO!FMMFkEfYQ&o_>FkDU4 zGs{f!qHwi9Pn~ngOTyIwJ+l;&mxrrcdQ`nZUKy^2=_X%FUL79l5D1hDj@LI|A5vTw zu58^P>q@!zvKzzIY2DGbvV42EdRDjdE*fBGxO?xrkM(zltILV9{0Qq8hr9R6KamfG ztF`(zY8r1RZ)LBD<`X0^_ch|>XsARs70a7+JT~K;Wgxax7V&(TF3&|bv~C*xo}^BwYMsDH_oz1hzoUA+PN0g_l=}`rsq>+)>ICXn->R>2*P@!r z4WuVfMLBQV|K(U~$U8G%LSV4@-iBuq0&!-|x1^Uv=w_ZFt4Hb!g=vJpFNf@_6O<61 z5n59>P|v&&I#xH($ZQ-cofxQXJ{@Y37H#q(g2}c1OK$hu!3}>xV|w3)Jn=P!8Gmqy9ut-cH#Udmg6}W4dfa0lmI=Uj(~UPg zw!VGw-E!j`%htC~zJJ`f+_LrElkc`0w^+8mckZwMv$UDWiwvMkUL`RJ|IK zo0#eD^TXAL`as&6)155S-Bmelz7(>|JjHR6+nIe{bykq+Vn;J6v^U9-s+C-Fd>u-1 zDU~8O!M?PT9Hk;tBzH95cb{Kc4eTVjtGUVDfzmQdnGFIBv#-h}#Fu4$(R^ll9_|B*o;UB<5tbd)^EOm&ve@~f>f zxA_K>=lIn;y<5Y~5zg`ge^5=*FF2e+p)ywR_U+Dm@U?B_gTi(j>p+fLs^bApq%`&AdYE%iN5-sx9Q>3LwX zx!760+ph|Ahns3{ck*7pikCh2O*1|6G%Ju+>{rKi6Xu&qPT`PWS^5QMn0=jm)UR&n z9y!yT;8CsX6BmF(*3N!MZbDWF1fyt+04mT{A#K0 z0PmWuoqWTuUacVcWAj-j-<2~Z_xHX{rtZFSCS%pXev-GFC!9PhR{dIE@=nu`i;KKN zj#Vf6O8&~M>Ewdgpt>Nlt8cfdCm1VG7^{ZFO8$ntFjghTNZw0c6sz_`Nj_*k;A~(? zteU2e`$zKfSoM<5XH7k$%9)H+W6DcD=lsON3Y?2oOLeKC|bPH_rX zV%1rBhvNIoT<+u>v8s>UMEGu*+nszXRyEKqblcqJ;*?)!ugBft!Z`J+o*Kf)!G&?El`e!+SQMu|D8@0Y zyfRMxr|0A-^6EHMNq3#n9{OsW`ruK?io7mPWy`IduZ+j(>%qXrI2Ep6u&i4MY>^k# zE7;`iajK49?j!GvQ*Zbsmm}|vQ-8%vE>GSYr&j1D_j}qnEm9n(e$p)zOD?FWmgzoJ z$Ki>vC3=dTJgbsAqEE^F9(Puo zQ%PNyPVH+@lB=kzdNOQWlB=l(xsscdoY8iT^X`s59zv1Ji zf#)K#1N!yLHP4k<$8IT8Q@Iu;m+Jx2IZBe(4wu1EuH_853D6heg|b)W(%htsaJ`Xo z9m~o#%8m>@-zHEoI8?@X`9|&v-f{z<8Df-g?0!%kX(gid{g&% z(MI^l?y@kczic@CicEVIsveeyG5VodwpP0Qo*_C=UZy*Hs2p{4t9o zdW{5QwHclAtUSSfLZmPjwS_cH?r>&gv_%iyK#)_7<54qPxB-8@2-L zO#7}(Akh!$SGNMkO?$FTL($!47|nD(Y1*T*B&WaQtSz@sHS~UDxN(lhF4Eh|bmKaY z-87V#5~%7kWE@53xSL#P*$YCwbTz7%RC~Hrxot8+`6+>ZEtbjaCB#(8loRIk@tCS^ zSCo(Zq*upOD`}Rxa`IxTyD8E>5sFO>)D6BU-6baA7US$kWhY~5xv7dhLNB|op{d)r zh7qn`C#LpJS*7wMY5j9`{a?K=hi0eA^~k@gVomo{=r6qdyGveEf8SM-B5nPdzyBL| znX;?N(FFZ_+~~9Q7ZUz&-4t!lkg3kU_jB34e4}75jFR-7yR3@cy0)Z!ZmMCQdPvfK zH`THS$nBZ`fSVHRE;=1_Q+?Yj!`gpX|KLpCz1aHt>JJ`q7be;I2G9S4o04t)g_{4U zo7&j=a~%JVZc4TF2mAhGZc4ND2h;wa+|=3DA4~g>yQ!P4Ka}?W?4~SRf28d{;im5L zj$6_%p{?x#kwN{*mH(u>q+hu)0}cP_&y)3D4zPRaO`LTXO|ZLXOFHMKNw)sZ&3|4e z{S|_Ju&2ZeZj_t%3>iuOKioJ=dSNAr7u_h`|C;o7|DW#r@nC^zpVEsjxr-N?_R})r zN}>#hC333#m))gHOnatW2K-mtD5K-1bPWGhH?B18-(_U^uenhMOFO;K#3Iwqlmqi$ zcbCf8(O)Vm{|z^9G;J&NeS7(8AySLdF~-oJuma4-($9uxmIpVJZf~RhRZS*jxWCoqp7DcPU zJtS8)Z_BRB?Mt*;(?W6;bDpz&b+nqNdt+7eZ6|MxR@dZ$LGKMzb5%gw5ncNa=fW011oSNT78xvIY7P@t!BxM zsK1u^xw8Xzqt!{>lkYRXa&lgbIxd6U@BYG7X3QA%m>wZ@cz!`{jC!Z46za0ag)z=I zw*Ev`SQw)|(tBK=yeLL>%8`6Oc}a{~87sK~dATeP-Aa>&ovpiOW6DJ_YHe-FO~~tF z)Uw`^o02!iIN#0to3R^PV$>PA*!Y{1x5udZ(UM!3!<})mGe))2$DK^x9iz_ac4}$5 zUry|e$x*LJ5Ae5Q1I01wr|ObhlMltHkRIf1$nu^^Ut9eTkmWto^)iy%l267cBXq7~ zpnAKnbvJEC`C^Q^r{|IOW*6s#UWrjN8%@40Y}lXxLa^FZ~Zu z-kGfQ71Q61ygOMX$u#dzH=9+^r+sg-svla}NnTw^|MzE6KANnK=&3QAd^}nGuDf#% z`DC)n(5;qh9(H=e>16qSF!I4bLvwE^S$J%}-uFJNy|SeW=^3mqYp-spRHo#9<{!?p zx3pCCb(20~ekAj`Tq9em(=saj{mlqzIr-YJrSpxl|4|O&MoYCZwEMw8gT{aBS!s+} z&l$VhTd7fcC_ZJjbe>k+N_D6uc`RMwN-I?>RHt*GT5yNF6Y)RG*7l}2U#9vel8aN+ zv>vj23i(iq8l?BGBp*#thxPM=EI*#2wq;1pBcDuheth7cYP#PxB6 zE~Sb3Q0@r)uTjWLRg3hgT)KQ=x#g+yb@$EA()0B<8veJ;=bi1WY_Hbq z0k*g#cW}P4@h@RNR;D>$+4z@|SEs3#`ck-zT$HAM(*y1u^13wDR?nNu$s5zuSv_OC zOY?0>3#v!teEC;U*q)|7(5LY|^3F8%m_E>ziYbB zXujke(4jOnprhm>^8+W}NK&chgi?J*loE=XF%Q^$~n( ze&;OD@2E2M5pOWB%M>BEVja~0-HSJpH+E7pbuZsU-twU8tM5)Wlec$Pv-JUPWe1XW zc2V{8^>&;2r88OV?xN1?S@?7FXXgcryExxx`@e90c5ej^by3|yySmEvz4~i!|1Mhg zTo=_;*7tu+zSu>b)OokLNye@fxYEV>Hs1d&%NM0P-^Tm*l9!~*XlwqEbO?Rl?Ejwf z>U344FRjJoqI5M!<_`aU^15{A+j;*1^2T)M+j;*%@|JWJribYv^7eEU^RVO}$UD>3 zU%EMtmYm=8@@j>idrz^#-gNoY=#1=FyLR%v(f>Q;)9LE|WXWg9=hB^T+x=(B7t_^N zJ=32z^)0F#e!9vJb?PRE*R8&kFR|K^4E2egIIohIXQ-xCBwr)1%uq3U;=N8@ouR&x z&yf8$$VD0I>B^G-BCpF(Q}tcMP4dPJbzG(&|KH>-89^1TFLAdhY|l^uJ=5PI@61qN z=E1>aXQ<7(J@1i^W~h#Odxoc?+(OG+feiIZSIH*% zR4_w@HIjmd!s!fER`*|vd?rJs>H*_*elI2${S5V*9$;bQi?V}ygW=>W8LF$jej@>JeF*oS&&u^?*_2S(&PtKJ#Tfzd7S! zPNr(9o3yOQouLmieI9o_ZOK&s=mB2N-CoDQ&PZU&L zb;*0P)K1;(iR9uebzA3pwI%UZZPQK9HA<5(3J6*|AGjuaIXSEwyYDs8DmfVw+(gU$ABJ z-k75j^>L0SZ^=;seF+;w-kzgI>k;%6d8d^l-#3QkN*^4ghsd+ki*wXLJ(Qm#AIec< z_40`f<)b<3tnT~Iv;1U^x~tz6P9mR{1NTXuOg@*RK2DLGN4}V&>JN}SjfT9E6R$S3 zlEQRWxRIld>#I?|=YHn|-pWyxLSM;#=2XzHJIj;rl#6neFIDnf&$~`um#YTqNx6W$ zF;`{lF+HEWC0D(y*DoY*&sCReg_?H{R4cbo&%JL@-?RgoU@?~qUCstch{y9a9b*jHV?==9gUAOq71$$gz+9gy~s|I0=Vd1G%~ z=_v*4T{+WUqjI-w`9Ju0{5krqq^*B+>(AA{zttaX>9@!JTz+zEw+=Px5vVLbx$Pzd zowxtFGi1}AK&q{OaqB0g+39+kCUq|N*b|TcFLkr^uW(D2W!d^ixc*#zgKKB#>pjow zZR?-l`g7e+lls~E7r6dhet>I#7SuC)EPtv|P21-;u7Z2j9?cbWd_t*w80TN34S2mQ<2k|>`$=pWve#O0Q0j|>g%DIXT- zAKsRfU)}n1OMY}~>mS{gtSlci=-=G>bKUE?e9)kO za_b(4{>81We{ox~@*&eUi@qcb>PMcSG{g zp-)erliW-19It&@@9boE>5tVL>5lh`n-c7Wp*6jw7guT`#X|kY&=bhAQ}oz=&Fyi$ zZKIc@1@6ZBm3#8BF@`_ncDMod(Mqyxp_>NVmG#{8y1V93yJEDYH{3MR{z)Isn{FCo zU(n-giJQjRF9h}EyVQ*n+>ia1xoMJ})l`cE_Y+TX}8on@U9!>^ELg0 zKK}|g%I9le=*i?gHx`(7RlN@@-B@Vavuj9vU&mTbw=dE=yvkiH-TsK~!5_F$y8X|g zKOUBE*k97k_mNv&>9POO7sDbquJ+igx=CE?#v+eBNKXKtxKTb=-#yxU_>DkFJwMJMi+{m_d) zb30G5$IcIJ?GxBw=52VUZ(xaO`a=Fk0@s5217rWY9^IeI9+#P_QEc5IQYtrc^s`3n z|Gt(uC0mZIr}t8Ko~Py1#QyJViLd3(HMWua?TxY<%8VM@*iAk=O-5~O6E{Wc&rf5U zx}TrM8R7cXV(TW|l4A-_kX{xSufGor|5GN|xPboIMA`H5E_-2I!dkf#w#$Z!`b(!w z?J7$fT$76KlxyXJ8Q0KF-R-xNBsH!e=hqYHZQqh7$2Dr;xK#a}yC*QtUfM%aJ2y?R z$4k4%wRh7b`y;v5{U2j*0v<)tg^hOg^h{@};)>k&R96!G@BiKB=1I>v z?>VRTQ`OZ~H9e8-2niQ`hhXkW#3Rmc9FGEQ|D%9#(FfqbksT}u7u`&-V+6*3IzS$p zQX4Q&Xe-_x>Yc#aQpH4eT7q`+(3aDssLoG=gl<3|jp{-yb@*pczft)W0%e7^!d)+_ zE6rx{H4Ka#GlzSV!*o=5RL^iUr&!D_=Ld#+cXy#EqY6!Y#%kK?RiwQhN_}k>@`bM^ zCLs=61zOf-djf5bZxzDSZhH%IhwW=WeJ?21Mc)f@9N^F1?==I*QFu*uWi50$8eEfI z*%?~e5J+@ooQMi-kD_X#C*wd==p8qZ=*X%!B6L2+YfbcH+IU!mbTrY8ak?n z^kO=BGnvAPPON%;q1|}*5%8Sja7=Bt<-#dqRbAU-p$xI8uI;r@X6RuGF1oYo#TG*l zkm${HGarQxsqMEcb3mkMHwQXO;e;EubpjsqF@hK=FT$O*;}(P)=1>j4W*Nf` z3vdI_POKdc;{f^LBsi4zx}`3)hc2bIf5U=n?V;xgzG=br_Rw#ry5HJHfxR2;p|O~v zXeSQ|_>VpGr3QdvzX|tRM`#%aVNL8eA(ug+tFr;$v7%ZS6gnnO@hIB67G4?@`j40A zjq=8{IvotN_hklxLf@xmJ0mj?6zZkc5W7#vKu~BIJXrhC(v}B>s(i~R?}*s$WOTu5 z2b>cnBzKIo&_O(5G;01V#v@H`4uy$3yY~6*`>A##LjP?Io!lOZ361gtU8N+*317!_ zLi@r(zEH0N=t~PFg^r{0UOOQylS5y_Xrz5*=`uo3CjfnIq0G=r{P1XRNXyJ&5X$YP z)>hqqOLePybFHfV&Z^pNEOZe1wD!G(YG?(wjqx@Jl?lM-h8 z4sNO1eqs>V2H0R@n~P7o?KQ;WP#hxIUo{ZQa|~myTf4gwyn77Qyuv6pj5O}fIv7u| zsM5>*EqPq9T=OgG?S7E-AtGj*cWH0;pD2hHD)EZm?x0v;>un|&IeWYFsSk!jAD{@= zLO@;_Ap@-M?e2vss8&njjlJC$qkwBmT;ALLYz^Q@iMRE3|Bk^>i;@}I+1tGf_bn}2 z>i6|_Pw5OCBk_UW?z0ZyShkq&8taV=ypOwqR=F?qdT;j$bW$xrTA%FgPSSzBtXSL@ z-tFyvp%1W+(IWu%iF!wlEgGR{Cd(D$^&h?6HK}-hxnJ^eUw1O~?s^iR>+7CHxl5Ax zQs02vL4H?X3a<2Z|EmEv5DkHeabI^V`D_X+M#Eq=5D`!}&14e=F7N05nCiO~TPX0p ze(pF-hqP=~ZrKlTtK_EbW%V2z=zfN(vvXwu0|VVHX%sAAFNpx}4s;vTD|<4UEMg~X zu={vx;9e4!4t6i;2V5v4SUcG54g>BZ@%q8;m#D|~m3ZS|cL^ofU*ht??q)P543L=T zJm~cX>QRy-*qb5?e~fXTq_K1)`vO?={;@!HzeD$+QS4t!@R7}3ngPLR=9@$orT7X- z2IXR`h*k5hhhT4i2p$mI4w`o(1fNAi@SwCPhhTa<1mhsUyj$~bgJcwquH&W2P6*~U zhhUNv?1o@{I|z!TU>^jpP(~(8!2t-y@k*R->7KMu+bv!TM(2NK(LF=5rUF` zo$gCCWIZcuqx`PZ-CKoVH(MVNCfgvXpk(&4okH*~1U7Pv=fwFt&3g%gbu>)vlY)&U zF87yS2=>b$mmp}<41(vS#SI8P!`xMSK?-)ybGg%7LU2HAQll{QT;cAwX|#AzN^ZiW zKW{nFn-)l+LcJ{ICG%bGbu@oDEQ`Gmg03_dctr}9LeQ}h1V^P{1q5L<5Wgk`r4XE> zj&VW?)k5Rn2RbFymqC0O8cPbR$ zg&c3W%RQBP(s|kUk3o>o6N1lV&R&OL0mXV*3Qj`sGNt>u6ub+;b9EuOBF0V4dj)3FEd za=u}j*W1K{x=_1Xo15$`*#x&B$w#PG?-I=T)vi>--rJbAsa@$^V@g60|7DstDUuc^ zY~n#aar*G_U}?JV{UVO1P4~7@|LDS}P4}AYW&Xr;Z&c)Oa76n!5!KxAN>;gV5`TBP zw{s{(#jMqvGG`-|n=`yAfg_j$u+6j(n))CfQdl{$X}i%@YzswH56Pv`(xL?efQ=uN z;4tY9r9-!sR`$L`4^MNqsf312QPMF^DDO{&{3yxA<3@7-g380d`6d#V_%5dU2;N_}t;yK{+s$d^cFt$0lz2MKhK-ey zcs!g07*NvBA@pSHV+Y17tCs1I{K$$N zc!3k1ptB%uI9*Ya;Tb=YXM6%d^2n*hfV8Z08<2lE(;HPNT1FfaQ>kS#C>ly!Eps=% zf9Onw{X{4p@dD10unAz=pGe2j_9nO$_ZkZ>=Q*>yJp(_Yr?5XLblO{R4)!Op2gtNF zGS2=Y_zuB0O~Ahi{!UQG%#8g*&=UlBj)_KkOEky6G!{2?hxx*T;6h!$Od~Y+vYiC)$*?@fWJOs&8MvaCMwX2GmH_x5p zP43nlTocz6oOu2hW?g}De*-g|m>XcG5%UF@WnkK5A?|j#+Q%Wp&i_anLh=@Wbq=-$ zFHo2VfPVs`w4)KRGXmX@i#2PBY~@BksfFB|awL#QIhhzrxivAAav_*Dl@W-P$Nfi= zg~;YZg1-)w79Tj*8ya|uf>XgNh@rxrB8Ce0IWd$3oj4Oo1Yx{tQ-u7T!PSfk$9htH zEe1q_9mAMX18-eR!dviQ*k`Wgsbhqv-VaGf_5ft-!DYLst;e!H0SIoAfX;xj@$6S0 z&a9(#vgyPqn;>vs!gOSmO%!+`aPtQgW<6#c0m^(0vpI>gf6lDpYayH2bR3IWPaw?* z({U_``-CC6>{cj)6cm%eo0JtRz+T|I^?b#{-iCpT;Mv^U>u##Sca4k{(?0-5T+(zNj)5&rIbrcJ~ zO1K4OsHY{k0zvvdgp8+QcoeaasQlqs_Kw8&y7jXx5A z8{Wl8#dZmsClIDN?rYBqv<-o?ccwwRTi^u|z#XZk_XupDGiC1U3cOcDm_08V{BuIL z47%*4g!c)28aO=@w~f*{P$)F8S<^me0FSQOj%vX)!XLD&GPp|kJjNSlO$$?N19ziQ z+``id_v%%J4-@XvtqLn}&Fs)2Rk%Ijq-y)xbRbko>4&^!-@*KkS?4L<=dYA_{jp=< zhDw*gNKQ+@+y0RG=HnEWA!bD0b@RN@Jw8Gql{T4P+_Q1>Agy&W;a8HAirnQiF3UYe zil8(!LUpp9qRgsNEfTfZj*p+`Z4!t>JF}-%b_MDV^%dm-gxHNH&%)UMv`S-@T84p$ zo$3#}11c+k&7@?!4-IyIJ#5(>sI+UfGhSGUF|AB%_1wMC+3JI+d$jIWp8yU)oR)Q1 ztNG+0l`tYRt_R?YD)rRN_4(jm5`6ZnJ;7H9{(WR3dm#1Lg986W_}3&a3;ytY zeCPI~SVif!ehO+LcQrn{@?G=2vEido*|{WrgBVhL#V^eFMn}`>7NyN5bh0zJvdhRP zu8a86dDsGPVqkA0NUWm^IT#-#2YOs5!AM2O6nva4(}MK6*zq6b-gy@i;USv_W| zRb0`9iv_RLTMKQ@ScT12H=s2XUuHn4ms|0Rj9 zP6QS;XyHwS_rd#R_;h3|JFcJ#2Z~9sB%@039O0{-s_-?!VmAM?$Uqbvw$mR-mHnd9 z^jZv`&FpZItll=B>?N0O|L{_zX>!IA)6OHfXckB(mDMy;2r@^{h+UwzEeY7 z^WiC?pM=;%eWxFTG#k?F_6=YbDWnGwF6A5)mQzLBs1I3Xju8g8fHB;(YK-^);hJ9+ zzL8KTV1P;a1L0{X!Q0JKMFhhkwIWFqR$G8E*oMKeKCFtMolqU62$G<%#-a`){9OpM z6BCikj>0I%5B#DEoF{NkV8quN!TzE6gl7-74W`UbB3sdDLxk-!WSc$=rv3$$rqe|# zUy|ja9Kn6HRQ z1``eUXx|h}A7a{q2@ul_%wA#!fO!v0`a#6;3espl4idFKKeGgzB54>h+Z;t_>)RBX zz0f=WN&7=!I2b5NLFc^MFN18CkSXcc5m)@e%F-sfawRu2PWkVWq3VMGobcc!O(k~+wTE0 zn3#iLiikN5=5H|R*AZeWa^L;}Brz=&M1uWvrTzOQ${?kbFo}{Nvhq7X?z<9WcM(wz^53<1D(TLDmbgIg)nR; zKK^$W3V%lC?3u?z@US;2Ei3g8Es2$SXXGdU+C4V^%}592pecn#`6xSjb$%)uuJi_l z@w`pm-p)_xj-?cQ&NpoG4s=CReJBM!Tg9)Nyj|StBQ?6G9|a7-U;u^DqB=>^$onngymK^-|~JP&YrLM>4G<$Rs8e8x^}E0|1)oV zEuQA=RKH^9uik5+d~2+)CRcxMb+jU&`BZmU*$J`vAzvzaKQsJ zM~&|=Y08A*#eCj?2Qw><$NM^l^Hqsk>Q}VR@b#$4TmKjo!N)(-&Rub!lW(L=y}5FRrv#q+COecfGue8>GZzo6l>XiKV{+KJTy|&cnLFN;qJ=fgGzmD;tujn;-0T3(X!wV3ma2-?5@cpkK;c^nk`_?n1K4+r_`Z((W ze5{-)4SAc>J0Gn$*2CAf>wkV~#Gc+XB_or!>5mQ7h>EV8eb?h#f32ZG*Qg5K+ASJc z$%?h8%A9lHPO2J|46UjKeF_7RUx+Zr^RQA?`#L`Dn6If?PvZ$Iw}*RfBSerEl=?fg z&K>;pF<*2*M+znJPU_$##}sFR9khfwse(&NRA*Q6U?+o->YNB(bN)+#6>T^~HnRuL$3b-i9L+Dx|6L}(NFQo$9=JZ zRK#Vk%~lC1Uf_c4*drwj(=~*&M@bk#zu>Ld>qr=>N04!}gfaRfNX{N3VZ5G0Ve3lh z(~nZvI0=*V9D?!8WhI=fx97E9^Ch!!yd9D4yy!JwEbGNr0R_gAZ6~%u6TW)v694>! zFTHsSsF-gY%y8x@JUr~=cf>bJ86~{ zp+snG#x?}4`2&P(CRJ#2db5>^c7T8$MsiRfwG9$Xuy4 zl_$UHi(<=phc|uQ0CQx1Ro&{XXcky$Q%l3#r500aaEX~`VJ)hkK57bcYSMLeA*nt?AUyoHmV{-H8(O| z`o{M7ig#_MQ*)Kiz`PFGP2@c?v*Y=lAagUj&Nn&D?(7WzfylXvRxUFKOZj}R4yf?= zh&Xv{Fi04m5N!5h4fye3)2ntG$%nk6*W&*Kn_;Y&vrECXxzBBe*^5Ww;hOh&xLY{S z2gV&?u-mL>-!~fT(44)hd)WcLha?fxunx^9$M_$u7$0Kpty^_ZNJuuLY#Avj;*Ow> z?8H4^)lZ1(HSfkC)cEp+z9Nw8|J=QMcisuqpu+bgn@c>)3wrDipgcLrXeG@alk7StX_aV+9=TSFBJ!M%2iJBT9>6&IX-FA5mM>RZ~CY#~PY3oHsY;I99%d+$j|i zEzBoXK6+w%PvpECn4OR#?fyR;>9Z_zTTNs>53%p|l_J=EC<#*C$&clr>V|eV>#3LC z=B3@uh>Gu9nM)YY&Np)_Udl1Yvuw(<uyPd%=en5di$ussRALq?F|Yn`}2H&zx^H z3-8g{ti#Xbm~AVLbjCnrHIVQZBuq|4Wg@4daYZ`SJq3iKm{PVHXm(W@WdqI6H-N7rz|beKhm%$1dvLKrpMp48#|ep`?c6A&ZEL z+iY}(V)L{JZW-JuJjb2o#=X|Bbb>)_0!U-r%#{m4xF>>QV!>+D?dBasQ&R}Al;N`& z%zZmTjJfYD2yFCodBvEN*w;|76SR4*rsAOpb7W_8VHflx;>5u@h%!czLJOKoz!}tw zh!)g_^iU|aOgtwm+7w{hO6nD=X8(mGV@a}VHdwpn&~}lAIo_nuZVk^8inf5PKBCxz z0(2IFCcz64$mv2cFbSsFF(!A;J)6$pW;v88o8A0y*P3B#Pd zNE;<#gcG+Jni^Zik?_^XYzbsOw^BK}MkTA>XLi&n5nJogr;dZB;@{z)N z37G4AgRE1TDPRZZa?+-;(<17Q&KnfADZ4CSp7RlcxTgu@eCO9>oX55bSm^wLU?&Ot zId2i{%(hbcs&|m{Z^B)qdYDtCg!38QoG?pw?kCty=6bAi8yOd{Ya-$Cipxu7JfN3A zj9EHWMDP_dIc(L55?q(i5vxkH;2MOES&huU>1{R(45yeh?HweCv%r`g*GmTL&{Rb1 z(Ef(j^8o~`1GD`LQE0IMG~L55jgXwC(P2@<=8<(+-D=ib%_dc|4XfES6_p^vHLDh9 zRkO2+?Ia@pno_pdCDqcERcwvfX$tF1rZr|~RB@@P)ogkd+eBeqgk=Ex4Eaqt{ zn;Ua$pcWQVE!2uaDPzDa4MBF7)=sqwUE2?;!EkeAr7|iDqNtAa(UU#~)5lnR)R~G8 z>P&SW1`~_aqLz_vEq!dpN1a{xm`m~(ZAd@r7%5KC$H(+RCzI;j!pBxZ-{Av)Zp!se zG)BlMpd2(-7f|*xOF=`?fJ+Z>4vflHW4-*J#yTwOQuw9CipH|ofM_j?7p-NnqO~km zw3Nk)MzUDZNJm7(!Y>7DHIiUybH{2V0j&yuh1{vKzF!sf9iR%&Mf==xS$;t zpd)HZ3QR>)+*P7406Q~VLBd!}JcxS$B)!1IQe!DhiFP3xR}3v(!=x=p^v5L0pAtm< z-wIXpZ?bK<6k5Az^cbqG|D6w+?g1-ON>?WHrX{&2nRC@P%A#O&WBj%rrTe!hgkOBK zyO$45soy_n^zh*mM~*1wjUU^Q!5i&v-y-Oa!fZX9yLp#Ermv=L+I*Y4a}(Qy&LG3j zJ+;}HuwWq{Gt^Ar+XtDQ`45B55Vn9{8H(xELqjoXOc`Qo{FTAxziO+7ywy<5rq2v9 z2lIl#rpLH{Ns4V&R(7ileA=S3Y~x4s?nBLGeEMK>E-Vg93BTXgZx4oT)n;6)h#6)MWkJq?w#Nd<>+<1d!wB27-Bwarl zgS7Z40`&&d7Z)NU@^ht}W(GHK38PzJZmUQiR-np8IJ8jAL}@nQ5@0KsZMa}Wq%#c; zRJI1_s(H8spv|$KxL`!&k4icD^letvUjw7#rXWCNZPQuXPF7`HK{2o6Lbz2Z3@voAfHE)( z`OUSm{~a><3ocl!NAl%XPC6iwZdQ8#APG9P27}53&V%_J7eqw9#3eFt7fgMmR@roO zz&~uIz8GYw#RiDdO+|!hfGj0bwv>VNd%#UCmdL}EHGc-ohqz#J0pya!5=pA8>e*oC zSf!w$>Jf`2@`W<4&L zl!I)wSR&-4|7i#8wFpmCm6Xlok>qcxlG$@JF^!OYRcXDM=<8?-Rms~-)bbK%{AOY- zXK*HMCdO)XXUb+`=;)sf1N>%UOzs_T<_20=T{D8{&py%@@3s;13oh#8L}}|3d>BzW zpa9-Y^f!xl5~W-By?y*fBI3Y>G84IlOBD2XFmHP++dI%CXBq-NgbRj5=He2D%fV2j zm5zam5r5C4iay6BjD7&~6D|ZMvd56}kHaC0kRTLH4O}oH@_wcKr<&;3UaSF%s8YeC z5U6UM8dH_DC8~bC<+}E6JQ#c8Mt6Xq)D`t55kOV87^VO z!8{&=aSc|FgYSzy7@>H$E`B-^mjLwZv4?TNh{&usDc>BA-@U~pjI4UWIS16hMOhgr z{~f9W6d47H!v!`SS#Be9kBp6|V~uMwko+QCloKTKw3XfoME?OUNGlV_M&!9x0z~p~ zi405ya~oA(*;EfAd13P;Fa z0y${0M0!-#JADED1TL7I1^LusiA<=h^G`XV4)zJYY&ti#?lm4e2+Mq9yCsH3K`W74xeRwm`vuFwG!bCrh#Qc}~ zFc|42=)>eLmNTFa6Ej(40ezU52?>-K`Y zs?GOBSmw*OJ{H0^rVklc@#r+O2BVDr`>K}ciY&0k{%Ah@v>L}U`OnkMdKRh8kKNG2 z?3pIEr}@>;V6T0LA1ih|;fL*BS9wo_(=dbNKOfcN>Z|bg zr?oWg^h2}?zj_FJtMN0%N_y%{EI<~t<_lXz`*BiT3wr;yMLHl zP3em-E0})!Cdk*yec@SVn3~y_C(eRAHCL(J0Uic~Va7{%;SAq8_I>v)Bpe}UMi$u|S^yue8horAIkbIoPcGbe$h(b>b45ZhI0@K-K z!adOr0uv2KUppuTLva5hgMWx3z!2QS2#+QT?1n!R-b<7)Zfk@ihyuSa@gUrX2_GT~ z{c94B#hs6^j@bz5#}W+>;L%J9YT<5326U$1g+Q+og<(8yj3iGY3fv6yO46?*iWQJJva?RHKj?~N>bWXBY7`Lhe-N>q{Wg3Bz;8E$0RM6^jS$?l9ZNT zDc&HWG{FzH82kVm1n`GQY2cTX4iQj*EJ-^`N?uO#!IF+4itytlo-Xl25-*mtOwx^l z!Z~*kgMiOU#dnfA&`Xd*g?@O3s8`Z@l6E4Ba6Kh`P|_8W?jni|?k9@yFG~8d)W1eF z00Wvcli@{4zn1i8NvXS%J_y~Es3B>rq)C#dOPVbyJpoY$yGq5G`l~h$)kT z$0V&Fih#!?Jtyg3k_KUXpo~OFnks3bq@yLBDd|F@@V!+MKOyPPASF~pbVv%`4dO!< znnhK+rt?xz*ysc{d_4PA)&-qec0Z#eV+j zYO_6l-6^)zOl7xu_foS?T9g@sN3(Wa){vlb*F|iqEak^~ znGu27P+*^BGQw$H5S889XQ2}#YaMc%r7Z>$NA)(#@6b7_w^{Zhl%sl^s6bsY$VEZIBUd06v1` z7K@W2wYFI5gH>lRGO^Jynb6^Y=|K3^D#XE35d)@Fn4!?$7<8c;bQ}r22*xWRs*!~c zmP)J1yTKW_0b_VhrAZbxEsUPRm?Bimv~V0)PPKSvIL=T@-fbL2DwQZK0($~!Wc4nt znnNgpbZV_yQ&X_Jk|EfU)$G*NW>wNkHUQ(arcxX+vWop4G1i*e1p5*)nku&TDyUc! ziu^9P+T#1M0@6lp?OG^~r8NnPyS>mB0M@)sVVhFe+OG;$?59u^wI8JH3l*JSto?VD zB^~pMj6<|f;lBAA-8*Mg;4>-(qVv#M${P^T`9C)E<4PrM>RC$K5f*pRSwB}Q>9zzV z%`Rp_TSh@=d+;gZt!ZhYJPgstqFOXu2jydQcj0rH7O?@sZ?&SQoahs7o;pYU#Wbv zN?8N9$OgFBWcp^dC}`l9Ds6vgrjT|@I5H-*rf>K7Wh!K5eAt`KS zx8{<=FCvGh%_nQe=`d7cn}cHit*%yD+0$sFn3Y<+E1+2k zmRboqtpv-g1pg2Tt|7~QhzbedLt&fP8AMKZvl);+RF%M{|0J-fT()uth0Br%?jSFYUslMrt{4PNTA&OP| zP9kwyzJDDT5-eAVc>@>aiYR&Ny@^mPErl#)a}Q8j?#D5HKKQfn$iOwBD0UJph6jom ziJ@<)Q;bB(HSdj)-1U1AFl94MyLDWM(aJQwg9-*-fWKa7GP-lg1%(H&*QQVhtHRC^ z#Y2aW9Enw!@3xx>IO6QyVQym6`K}$|m9toyWbvwpi`q*`}(?u|RbK>r`)g z&{yIqzxbot+5rmNwhLfauBxT5IdQKImH&U)@Y3`lGb$c^me#1IyZMjbJ?hmO;-0`0 zIydmLgZ$^+Se_C@E>9gqNCjY*A>KK)d~zUG|$5_z<(C2?!a!~J&RTSd~&gBfvqDOnxiRb-aFw;9sqppU!c?eWT#@B(maQVoWA#VUma@wFG z`NvXzLCS9nIe)cJrxv`R%w?~rf51G!0yM#=+kXd1I}^piP%olb$Dwl)gzuMlyu@^3 zp7dfx0(85?ho%0Q#BR7Jg|9~xc4C16SZrt2z=}j`Y0zF8beFhL;vo``ka(h`v^7Z) z)3*dD;w2KVka(TMn~9=;G+`q8yp+>DhN-BOV^V={!bcR;Zc1|}iubk@|0SslzD)9P zqKK!qq<$giL(W9k4nW;iihD>pOsKI`B=JN^=Suk!iI+>dLCWc9J|#nkNQhQQ`EiNg zkW@^^knUw*vApnwREYHqDE^lCuB09eVN{MtqKG&~()*;miNwt%73&(X7n{1U?<3{I zrTqg$QU65_eD#weym!Ha5}GFsR!h1=27E~WC9Op_YS_gR zt-%}Jaf$#&U9u}9_DN!HTF*7D)QI#UPBTn1&9aDfIp4Zpk6o+ z$Sr1TLaLk;THfcJ85W=&am_mFiM5B#Ft9o8BS7q0AACA&%t;S)HZ|x8SlYCp!9tl4y7b7-n)4kTIt{l7Ds1 zj2}qAUS}`VYAmra--C4$o9l?D!-={BAC82UWPvX{?Io0GAx-Z?$V+B;JG#CUHV)qn zf!z8>eAsz2x_2(3a@4Z|MCvA)Bv~j%PbXai@#QaXy#6KW?z50j-$^JrlnUid(!TR9@ojw7Y1Fv--9kV&c)b(X$>J1>}{njAnZYATxtVq;Wep_eFosU!#; zER-~B3VnzoNv#hSKR3>|UN94DQAt@Q#b-=VSPNp5@NWFV1@lw&N44UGi{?$n9^>0S z!;$3;yxwK=EDNr|C7MPsWzG@DSp}Jx(^}{0yy-^8`JOpgW zBVc13eC<`7iJ8N%T{YJ-H=p%|xs@H`F<+X`vS%tzerYyk>c7gmugoT_8*lm*OxN(m zUzuyw-xMD6wOPhS^1WZf=q>)$*JkUe-%%LW4#{D)57$x54hCZXputN#`x{Im=JL@X ztg8CC@v?B%DvF%ts|U`3VF zi{xH>sai0HAZ<7w5>`lVXN=+ZuZI#MUC7quB9C>T2mB&dLprCO|`b$X9(P@9R_Ht#= z93`E4yrVN^UdBsr^bv{Tjc5pug{JSTl~e|yysM-qQSZoiLLx&_LFhNOmAgzy?@L<> zj;?04y0A)Z!+UTjaJP2V+9_396!ud}xBKvFZE2MjrA?(Q7X+%cd#ki4?IbE~k4+E- zWWL_5Qlq?$De9hws{?;mrA2{#6m_rjmX^AD5cZ=)fy0#aE~G4sfP}G--(i#51bqEU z3y%`aNZ_Us2K}dg0HDcr@N5jDR})zejv-NCn^JQ!pJ+}?+?3jonW7D)gxZbyMY~A} zH5RKU8cRwLNMT8$g`|XSyX#C#a+WNrTuP{#Swm6H zQbJYB8d23&#!R)z8jISLHdKQwMbw}vMO1GrtsCw=GMK15#f?0u%0cT{cb^s<$;1B4 z&)_9Xbx*~x8)mo~a1K7w<$Pi4G-v;Yt;RYV;{#^^`%beJ7q>23Q&vWgw6@^gL|W2E z0zOz@`shX<9q1zsAF89+VQb_3#g_Alv!ShBR^#%9jY(%~;rwK*t&y`d|112pvc=5* zrOTc@ty(TvfQ5a=dh?%tG9L?MEid*J-m_b=vcta%{_un@8Gy=Ip6e@E_VZi0Vyi>> zXr#~gGRmqfOL?nx1Ssi!kN^JX@hi4vnoq=m@0JuSI<~B>J9J?bMUe0Ft<+rqr`8#| z@NX-4zW{xuR(XpyR*7UGkg}|;wtNBMWo?rxndC|)rIN|0WHP^ZEz9zC6zMnr{o!9J zSE+C3Ez9*Ke_u=)O1%wH0lu>mv%IHs`B;q%@I{y;`aVNIS@4G%h(ktWmYrO1g@rzM z2I?gC%kLMwg}&s`%iINRzHj`&AB%E*G1D~m;rC}!-?mWb+T+XKZ+>T55c}l#7wY#1 zmwo#C=U~{s-|uOOV$WHOq*3^@q9B#klaG9~iAX*6eGX-5!7*pcWtA#{-T#GQ|Ai5i zaKXvD3trFS?QWTSc-UrFM8(ZpW~Z<~H?$5`0?sJJbjO9K{|KT579U2mhsC>z(qc2M z77(TJ`rg$7`u+~x1Mq49A{DssR)Bn>v=j?5k?T@S6kn4Oaw;+XkqZsMg|`t9xgQr2 z5R{gBZOV+mW@0EM*jRzELIQ^FLP)K!QnnN(l!P7cC2)AjWyD{l*fPbulKx0|PsS-2 zW!zF?B^UT@Tv)InLh5_gZm1RtWla#J*Bny~5$$L3ZldcfKAtF-^81KcZviJ!y8Yc- zr5%tKMEEPjdVs%YfbR3Os4}{E=%|S!m7W+n0Y^-lIyAMZGO`+_rzz8`5hlJ%t5IrN zrm~?LrZs7*?5>7QQqz=It6^#iM*B0Bc;M8bX?S~p@d=go=1rAb)i^V?d79$D z*jAOV^vnz;vRaUy)~so!(x6(wUHWd8o7j(A(dciY_+kv07I5vUV<-s7ud*bBVJrKoUT|8i8Yimd(>;ZIc6 zZ6kQy+KA*^{`1Sa*S-gbBMSNP+J3J~8;#82nZswDLt?3zxmK_7xGog|BjY~aqgz3o zy#}TYk5e2t8dUDW3K7(2gnA3q>anJLZ=~O^9+}KPAsXL||4Y<2h5MsG2Q}l}K<&et zQ7U4AXhoDiOf720pCoxP_qVbYCez%&jn6Dz`>riG|%6BPH)?$8{NI(o{eQAPLmsEW>B|A64YN0?Kyc(fQ%L{Enbh|+udi5f()k`ygz z98n+U>_ibRT~d1MC*d|yPw(O++>0pU89)^A&@V3&z2DLYl%>*OyQHs4`njb4NE$_x z4@A^V(%zEN2~3igN&1|mbR?AI-%IL5&n28CX(ys|3bmIM3?teI=Yb@iLKM@S84@of znvPqq#OsK{d+EKA6!A`?O|0{egbxvJil-c@f0roS@dJr36CIR^1L0C|lW23CEtXit z$iZ4*CQ1|$Mi9mGNR-5WqL@71CvhgxR*KR};?DfN6n{>Do+nhSHf{yg8!E~bP^~ST zM^f7Tx20lcN;CyuOd{G2C%K5`;;u-vy`l^S)v|H8mMFs4#+akwA>S`)6G?L=?GK7{ z>nTIQP{I?XVwR-zZ7_;pwV)MWr22b?izheo4|)P3x=PYDlG3>{l0PZw(~{DA`bbXC zctl^7R7{zHKa`lB(MbQTr1Ydl_>M*KGbiLP5QxVcPZa8%sMR4zk{Kj{?74|S$Q=BKh#6B?!brL-xgA=_pHY_s@BBgxV;|DO61Csx);7~ zPsYuFR*xQmL#ZEQRo|XElO)VZFOXI*U`(^8VaP)~L5C^kdFXNW4Dwm5EA`ETqyp}2 zZ%GS5SX8R*h6h6PP6{+WUeMQH+c5^dr5@!I`ucr=(`itd`IkuXyKG955l!WexU#T6rAygnluu&#tYy&13fP+si7hf#yB zL`HkW_-3$v7%uAaF;l<{{SV~Q<(GNS)GwfhT@576(#y~|u4ML>C`xNR3)SXIVN}!j z#UY*X_xt&i2i{M)$YJM&G+%!kqm?U<-4d`+|1<`$lZ5^BGo^k87jOWkEt7l(A<>CAF(hdQeQ~L=+pM5F{Lzjb^iP1`+ z8>3(7hq%LNkrk!TgpF4sE6Si%YNTNB)7%~3g477X+EKs=^FwZQXo0ZCZ48~N(Zmf0 zFy5{YOXFRvncA_+3D0A@a*9G@}a=5B85De3zSCt+*nf#d4V4v0Ehbt4#%7tZAf_NJfu1gZV}v)-pEs< z52{xS$)ZDo2EETUU_1vWQH=A{wG2!ak>4-Ss5WCO{8KYBVQ)85aVK^dBOwnmh6N$( z#xvCLMl8CAZop6pHd4_`+{P!Vc(4dD?x3kX#?=tioAESq9A?C{L+VB@T+T4kF?5F; zetbq4%e**YVtkD<)-qnjXKmwA*hCu5aodYB?6q(p!FZ-NZuUkf+CIiOi7JgX@)5SK z@iJ10GjtR&-gwTZC<(?G+-m}f#yg0}YwU!n&!8_Wn8qo5`i)hn{d&d+@iZSt*p7C;NTWrO^o%im@3vXT~zLm}-pArMAjR zrM4Q2PrI=ofLd`FU!cB&j91~3PGcp;ESK><@}nCYT2o_vh^BWNP81--C_w={2EKlR zwwjL5FoTXG*DzKf1BOBCjNt~Y9z_^M_^fHnL;htE`c%BJ3!e$bt7wfxV=f@Wt^j*wrgeVLyocydX;;QaRb8> z8s&pFqET{EM5AyFDJK-;J$S_HiV=sRzM&ZTsFpVs;{uxEEyXy6ES*%0IW_R$su*;a zJf#@Fpq<}QjDs#Z_GO$8#gT2rxPgqFMmJ2x8TtanC`Php6yvEx%*Pa?9xCud#W)LZ z{75m}F#Q-ud{M-+it#Pt{sfK!*ZNd3GLZZ^#rPHTyz`1dbJ7cnag(2#mlqvKfyaFg z&%*uciej`t3Re~5vj#YBq!?pS{x5;rD#|s4gO7Zr7=NPFUn@p46!06xD1pmdN47D7 zeybQXz5Pxx&M26{D#oh_enT-{L9hHlF%pr`kBad(I^Iu;u^4`O6Yq@=q~WVuig5>Z z{|gF%}3;H^q1mvE5dTY~=oT#kg7@k1UE&fL#2k7_=Dj7b+I+_&0Kh zSpHFrHc^-vA&02Se-)z+$X&&_ivpG~V-IpTj~Q*yX7ibGjlKoFfEkJCvkRG#fvQ}@ zjOUTkVrKjfw1gSyh;1n|eueKYV@3p;@DXN=fp0Ho#wiqS1vBWIqAQu9!8cYhqd%%- zH8U2b;-QTh`{55|h$TT$)Zw;7ZsF6oO2g6s^g7!lHe+=|HH2yl!W*Q#bLHoiN*MqiVC`q|y+(u2z z1FegA=7VCnLRkRX0X=RZ=yOPT5$L3N6a;h}O1=cN9x|}BTx(#ALynd~kWvdJ0lf&i z9Mm0wl7KEmgeyUN@<$ftb?n?0Y7R)d#_K_+A^pceZ=zy0fNnvBJpoz^ovh@TW~_$Y zJkS|F;47N(8M^5_&>zBi^rF1Ffpzeil5)H86zDwA8?C7vc4HKJ-~!OI&8ZxAqa5|I z2=p@QX)$PUODYFwLn?>e*nxUk26_S6egt$P+-^B&Ei~*3P&z@n67*NN%qq|rH1z6n zd%!q^jFv)h4!xxebWLYPSp)hNGX5wioeEeB+8q%-20Abi4Fb9kLkkDp2v1lKdcU74 z!fyNqyA7ZTNazXB$?&9&prhcOn?RSL2RsS73ig}J15jY(D2IR!nr;D&L5*$&O-2r% z0v(4EZv(xAn%xfiYA%l5fIb1&dKz>DyniR?RM2NY>4gxxKz~BGXF)firFVlaLk;f% z?OPw;6aw|5>pvF&GscGRAc5u}1N%Wspm-kiJ~;ggpoihxC0Fc5Q&jal&?xlw`JnG& zKw1F$Jeq1DXdm>YMWFa{fU+1g30-yxC_TcJlsJstIn>k+2BT^U$(3qa~_MGv0&u+3~Bmu-80iSaS+j*cOW)#zbTq zH$&*1#tLL0%qT_Gd z6lCm0`#FupXg!w_*${1_dA?>(QSeleIeHDYYAi&8nz4(rWvIx4Ly5c&2hcn}va4kK zEWAlE`XDZ597MdTu?Dq@-i5?b<8?<+f{CcuAfqqZ4V99H=G8oZvLIyA_#RcP7!RWl zFoTYXsD=lXXHz0SL}P0nyV{+luN*Am9-wfU80c`en;F}&*-KYsoXZRELQb0B8dSk(17k6Ux2aJon`MDX+| z_BsY3Ply%+73JVPzJCmIyq&)f68A6~7fLHXt@Y(-(khs%U*N%G{jq^0RBx5EKyTGa zz+@3&p&oH>n11^2@K_jI1sG+jk6V!!$9nRd6?uCDRHGh`_6uq^CLhD|KAWeu=0Jw@EtGtW z;Hi2G5#Ez1Yf#fqq2qZPNa(a$G*v>ko;?y#&}vv3-l3Gl3fxO>M7(#&q~-&zm6X1*(>27eGi61PlbfT z^n9xOLz>ldM(TO|IV2Fbh{C)rjf(U&s8-Jz35)fA`QcT04Fl`QL%tDG`dwx{I0N`6 ziI+0{6m{93wV~*X_?c9u&!YPORU@CFUkKMHp~riEllE(wPQL-{vDr(6{d%T9LYZ*b zE$`XL^ktOQAc@PFs`um%tj^0xr2~N;x0J(OY6@4C81B*+LzX8(;v)>%KffC8^AZ0O zp%Z_iTy~Y(TS$fKr%>WQU~TXLrFnI0Y^2;ym-2^on zUey~=<31ztMpeIwyMSk({kGK;R6UW`pXiTcejZhp7ni!TKD4Lor$xyRsQMO+y`Fbu z=!2@hno9VgogUF`-Xki$vHUnfC-lI*+w+YyJE`h)%-VBZtS{KS@2dKFeja9lWQ?z# zyHb2k)u& zzM<*`xRrQPB)*B<(%9Tg#(zr<=rbvSzEbdqs((hs8SLnYK8hdGR`nN2KT_&TZ2D2^ zC`Dp<1de6Xd(gmNwab>4Xe~r5y&5KLWsamf|>oYdJZD-)`B>vc@J9(!^ z^BTA5kK4N^BFL)7Yc_pD1aP#(*KPWX)O8ajzG2gkkQ>&Q_@+&t!M`m+>->aUkf*&A z|6|kD4B*}pmuUKzl*}NB7izjmg&QgHQcZ7{2RvTl6`Ed$T6c=XrJ7!kT61R5Ez#O* zHGLHI<;7CJUJK~2Qnyr%OPO1upb(rEm=#5*MIZ{yt6rf;!kKi4SP{66zWs25l4>I>hQVU*{aU9chgIfH$#II{Q z{kD?lr=W&jYT=W}6M4XGsef0~7m^2Q&ix|IGn#&fS~l2ODAM>CN8>Pg^cWJK)AUcN zj8PI_(t7GIP>+k3f-9Q-H?=}NiLYt;SSnPi#Md>w4P~gg#5Xj3IoanrXNU~m)bMKe zmmfpN-bQshNSghl=|52AkC3>;u1}}?^@9>GwCkt2YaIraKY4wS)KE%flhm%a>$k~+ zwoAOxuG7m*s&F~zH-u>)#iQOu1Au$ z-;nsEU4NXK^H+)Awd>DOqJPOm&)D^W{DESBV^)hlz>!vGz6_*B9@T%Exc%cNxb0ZX zeVMdlxNDj}u0}T+$OlR7LWh2YH;0(5=k?d4lpj&|3P|mGhrW~g%@T<>I`r<;c~?nX z?$8ZB3&Ge?{x%|MGl2&CJyLtXp>HAgKj0c@d6z@~l|1PcsXyk>-=^Zc>9T6&bqDSt zf3DB#o{&u=@J%Vc?$GB^u-_%V;n277$EW)n2V69htE1Dz9V3@Rr>z`Mf=<(No3|uL zze#yb(rKQJkt;~oX=rS$(_9)q{T`%uq+4cFohHY)B?jp;DVfgtBp>0@ApHUI>q6b~ z+qFS@59(_}Bwin6=tY!)(YlrWjX}DN_n(2P+|N60$eXRY+VVFxe%O%y>IhYf$7+PRnf@9hc<|k%1JLUZD)acRMe!#Pr4}X7xUiV??X?KWBgbp| zjP&=HLKCg8*q9Gq#Vya$&j|tTJ*<$|dL2TvA6!zNoBj>VQTm5IR7mpt=Jw}zhg+p@ zhf<_}+*Jh@Skvu>_k*{iY1PHz#9_lY!&VtV^{yibtVBE6$A*vX$P7PE!D;U3HKYm-G75>4-;@&05n zf$yEu`x=j^1e}ji;C^xJ7f-VsmceYytL zWGhEyjN!xHF{$uimUx1Atj343#0<9XBBPla%p+N1H>G>A(Lkj?nk5Ee8m3=j`~n5W zU}uZ3VQtbcHF~M|nb~4U2Jl3UXJ?Dc*{rLKD^&cP?3nPCBH(HrFfUsyKur2I#%z^f zLAJP)@so@#3NOwU?Wx_@8DA*8BwLgZ1is!#?ZgJG$QCim+U__eWYQOE(lRVUbxEq-T(w`sgFTkuCe(r-6LsSI1PMSWM`I}G?tp~9`% zVh@((^gA`)o-K+wes>!SRs7Cu@irA~s#y<+%lUJ4po6%J|{XXM@ z5;X|fBA-IP-@+y}lM3hM2!4i|{*J~Aa>VPj6uUHDoFmAhlfKWu_ghH6BuA`dKR?!Z zMUHr$_#1;34s$6-Jc>Zdsg1-fvE;L@9 zE5=en4NR?#x#F!MzyXanHQt&l-e$bi zczdqk=Mw1|8t=>%Yp|N9XKK7FSL~$7v(0WwBK5gqJ|&c+@tlU@R_ahAvmC+MNrm+d zh2)qtHt$v$Y8r_edtz;Qy9q^61Q(l*Ihx%>dky=o*&sik zeqd-Pr?jZGFB7Q5$x&o|0HcuE*+K0s1FKGE7YCJCJO#<@>Y#4cWJoHrn}d2;r%QnJ zfRuVnb|te%Lo_>&UW==Z%sw}vqgEcwdBe<7-cvMtLP*xvDZ^_?d(WJ3=!4fQ~unE{iALp>K)sY-Lz?qNAbj9LSw*3E=k*oM~9^ zu%P1(geHCt)eHSFM&*soF|3jh@Q+UP0>cVpBNKm{*-2+hz2FwuD+5+f?l}S*Yzj)^-tdx6-xE z%Tg~iLahx>+@!(vO1B;}u!rcKaF|eSes`(?JKX z%@Sng40Y6a1GeGRmQEUP%o0oOS+A7mo4=>ot6wQ^I^ypTqPrW;>E^C1@iryiL$|U% zOXR>-g?ehdKTEWwsC#LQrvNT4p>s6GQ$UT~cr(szzGk+*I{0{&m`e-M&$v;E@?@6q za+3Df@pu?G1S20Bs4*S}itWt{!tFY6VF;b8gSU4RTpB_{HQw1xY-VSN8C950I799x z3hl;^*?;|nB8+>xVYJ13VgB=Q7XT+hq#O?eS^_iWvlNYHrN-wT3$RMg!L|To6fzfk9u7Z zxp&o{`OTIXKi4k=Nnh3 z+G|QhBaX{sdL}I>728UI7ijfZQ7WFduUdp-V4jkOo-l4x*=qZV$<*y9`0 z*jgrDvA=x{-Fbuh@r(}MRVK(_5_(qS`ZBSKc6W_&ziRjXGVvd~`|IWTeV5R5y=c6t zg8wQL&$b8NpmEIraU+}alJSm;pFTiD*!((!M=V(W2Z&Sl<0xjt57eMnbnw=4@i;Z+ zRpV)uZTn!s&%;Bn8Ap|!-#J*^N_+FV@v(}pAFN(ehPD}}Rs8a*UzRC)Hqw(=!B9jL1 zTZ4Naba$Be!hT>Ix-*c?J*AVas1Uuml>DS|ZH0Ib+n3PK8n3Pp6^(&UYrM8XEaklX zMdJ+>qRtQetHv8E#53&9ZyIl@5C_@aGa7HLXfE!^LBO9nV0(pli0%GMh@6zy!14*t4A@X2IrRBjVtrlZMQhKmTzNQN$N`*5+0t#!VCz#EX^q9zsC`2YfT zdU$j3B6o!$ouPiX__Z}~md5*si?(*drC8jCGg+<-*BO5rt$PjaXn{X zbB$+KiUG72g&NPU6yrIDEi|4}X^H|nbs5^h_o|_Y4&PoWLNrfNjdxaxel$<5G~QJy z=2GmfHLkA|JBZt8yuVU(Zvk!~}8Xu|@WfXIJjgM5?x4l)KVJx;EcniCd zT8grZjyqk6#qalJ;dU9@SY&SM~Nt z9~~in9&BH@BAl18jY>R5hyOJ~+-#590VUpLPr;??MYib@t(0@B#5@|XOLgicRqFLs z=qim@REZlo8dqyvTZQjAfUnVbb(J`gZGXE1o6^M;$#pt>W0kmwt-D_1Emh(z8mP${ zZ>{N_%=23I03f@vJzF~FqG~QY*I@-0&-HLmx zg*tdwwdi6WL~w^*tZRu5K3FZ%s87qx_f%fZ`WFKqsQ>IY0{*uXhx*Kh4wf>UH;+IUJ z>T6YdCt3WEDO7!0p~)7%V~Q7gvo+72@LqYF0)EBh1o9&$iytw?A)XF@>0=+N4L2Fe zkC@`Ycn;(@OmT?kKz_m$s*ZobWHqHGR`b^q@I8lN{r7COcqMCCRd#4sc~P+^4T(lM zk6;J!mWHNoG&_aOFe>1_@lyULs7Kf=B2 z9Zv8}(^|rn`pyQxIJPmZ`SyWb<#}Uyx)h2ziI#ZP(Nn0#fh)Y$UIVdHowxe6UTY{# z!@Uk%?X^a;L(`m@ves+ySUfbn2!Ytmd99yQ?3!o8l_RKOq5G(dc`ua|ti4`g0D1<~1N(J<^`I8WX!O=f(?8T&-yZX{**caJ6am;uKx)z_q4z zl9TL32jW2N9>#8P;6~GWAq4pHF^HI77g^uYveY?nt7*-k$T$9@Vz--C1x6{f>7R(g zJ58%GQ@@gR0W?@Z(8Tr?bn3sjF;+;tqCtNj7#hXUI_mb<-u2IrFlLE zCBF~$-boQ-E~S}%A-;K?0!ZY^zt>*AHe84u){eE|4h6qqxi!ZbixJaeSXkY&2Ohtd z2h#bM+PUkH_&;{9b>R+;RN_gl#FNyv(E~!l``3k=by4xtT=CPK_-3LLN`AmlF-ez> zQA9Ps_n>7hp0)ezFVAf>83w>yY8Xj(>FA{@+S6=+E!T%TgNA6}`fv-Q+`eXgxN&+B z%#D%D(*SdBpmmeF`Rl{)7@!QgctbcM_rPcvE!mAPU`4y^sC#Tf_)^3C({KOzQn;~5 zPsOX{`KY>`UGQ?ap>d<#M~o(OYRG&!Do4v@-yf;Y^4j(vu?N5HyZ19-K{QMoc;%b zi|BjVHVeIPWZzO3E^IamLsOKC9;gOQ0a8US=M9TIWpAoOkv>d2Rb)&1zbvxS{vEk{ z%tmnA^HJJf+`x(EXXMz58s5f#t$bUlrA(&vTO2-2C?8tr|En2reiYg3E+5aRs!Z}hz55>&VyLCX+b6h)Zo z)yqH~DP~pXJMl8{Q*pm-45t~N*~y#2O?#YVo|CHNn2 zOMiRZrf{RG35YK`7|(wTP@>M6@x0d}{){W{Vnpzt-+K(b?9m%4>|fau9W{&|`|Wo( zg_{@`+23pmHxHd`idRWZrd`UYw99bmaTHYbuY?~r1?zt>VrJH@-WR@3)^+p`UXfy- z$QmQ+KK(v?mDgUD*CMO#i-&7Bnsx1e4tGxZAK4^Y*vGr~%(nB-te90-e{-wPjk=S6 zg=eMMdn+sE*-yp#-&nV#)!;ItLFH9bE}Jy)`WvsE0A7U)ubyll8Qk+cyK+_S9Q%b$ zw+*U`6%Afs)LA0(NuFJQ{h(0YUy;aNrs1`3ZyniTjJ5l=i3~U9*>l@OZo>mdY7s8` z?WskPYU2evqjGT2UNW%UYacI)1bhdkfu2(TG)>!xw3`ec?6;$BBL%*a>F|lLGjhX0 zdpu&mW_Cl{NW}NmOxRf`!&(N1>}?G8J%Bf8_S}N@!N-at(wFtH$J5^)F#>f(fz44L zJHJz334k9=oKTD`(?5oz8aY5i5|V}`I{UAMy^aaWKVc#2$LbH+MmvOT`4T^9;*dDh zkG-L|?#FhKL*4#2_w1yuox9kjqrFkXQc5F}i&ph4& zdsn_eBpKhkcnUSA;g2`mk0GY7*IL2C;Z;HpLWasNb^3{bZ^{G z`?d^(&`;az_-R*~DSW^+%iAF+?x_9KAcX9~1n|ZkwRd3K2|sOqEp6@`0(;Z#ayF4{ z-M)wRvO!*787#iJ*si%b(jqnm8V<+p4^gT)AN40Yj@#3)CrEJ|wrXgte}=K~=W9RisQ3p1;xEv!NaRD({)9hwJxrCqh2zg{FS{j@S$qqm?@#z} zcg4W@6F%I>AyR+BhkK>{#VwJdF@4yegb(-lE`SLi?zfr%CVaTBU~IyN`#Qpe5BDvE z2_No@V`Q5bnAX>>-?J?zjTlF7JIpcR*-wtXjl9Fs$PRH zfQR=S>_z?u5ASB!)26@K1Ip51&^qLjrC7~k@>dvBkNmhhv|B!azoxtr>uZu+)e0%) zzgUv#%WaRkEfQ6p+o@4z&Xl4c4DGZ?b1TkzZm-Au5N*03f^F(v2Gp^iLVl~le(g4B z+~d$Vcy5;?G>yLB<~Znu==l{2P45JudIP;ulF_0Uu};L~c4&!5#yI!nL8yc&f5Y%4 z$!DOTUYUjTK6xP)ykvPh!c(O3+?HgaNR@wJhbANvdK$}@-;kVEh{Z*Ij6P<|b@-bjJE0M|(u3j}%0}7Pe#o^s za0ZtArMD(>3&z+gq9n! z9Y)NQDPl=)KUq+!bsqzvirjVtj9IUMv`hZlP+wuu? zAWdG?h+}mZ{z~}>{$@z!xh<9Fwwwpe4#^q#n>o08AoIzSmdaD5GAydi}1I#ygtgY+5xpGl1~reSOp-7Vz~pNY$tCjg}YvRnL2=j z6-wn`1yDpM$uFNuPHddnjxKwNKo#HpN7kD3=$4z%==VJGdo*;HNB)S~c6($#D%#_b%OKVFJ@RRwdXIdfIUTy? zkEn33M;?Nb?(@h#0XlTcFCnlGJ@OwE{SnmYW9ZQVk0cM!L63Z}Gd;RxF(NL;m)hO&&kNgm;;BOxJS}VGF zOAlJ{J5oZTe|Y4PMlt$%OP-AXgrm7gP*tT3RS>|gvT-aA2H;)=-M1ZmP1YE8nRh45B$94Y2=5Ww|obo@bi`* zK~Lf4EvG;#aPyXZ^U)Gq=O8)Uyk!+?hnu&Av^;S0mh&+M;N~p{K$vjzmZdGx9$aHf zA#3<~%Q{Sc_<2k1=Phet<>2Qn>!CyN^OnDM^myRsEiI@k{JiBNbQW&j@^a`l+`J`u zqTuE&`$AdZ<}K%7@ZshywVSsrfr7%#TWU9Nc@&a>n|DmUgo5DbEqCDxKW}*{EDZd- zl9q)E@|MEWc_{=0ngh1y(f|%y8z|DA6#mGaCs>j3V(3< z9V7^UaJd+gg+I7lhnWh0aH;*l<<-zS_=8J+wF7@}X;N=$e9#b%m`^^M#1Zq!29W$T zTyKKv)-3VK8eFI1`e-TT;EPEsE}z8Ifup!2cRn1& zpTrb`qqw{V>7Qaa4AK%@wV$}83+1vF2xx>BF2^+kJ%*#W zlIk|rs28+@`v}g?1U)>?{C=(7~bFVoGi#4 zSMB{RtNL&NljU^CkKW(e??EHI)~&`Vm?8NCN{z`8`IzCbRv24Dc89=CIS#{>Br72c zuiOt^^LeuG#N6{*^+qAC@(=WCvdl%JVeAm^mrKzADH}uT1#%h&zr82>W^~bOeQHc# zj=6|8&E$w-S)^;$m~?=kIg=!i#_p)5o0M!BZ!1PkMp-$GVC*%q3bEdNCZ zQ>5ekoxQt1!o1e+#wljM4YiPG4aNyD8RBAl#@o+NNBc|dUAPo9 zg&rW%sjyVsj=?_*%ftz3r_P8piM+KZ0R&{uic&dwnrxlzm-hxUZ@hGQxH;YFw*@4Sd<|*R) zmI^W!UvL>>E`|%y4u%Ubzp_7z;ZVM}p9{mGe3AXv3|RH4nCxeh!J)h})axvUhwwHsN#!4-nzhpq)lM@{D_n1g58dha8}`EcA~i9N zpq1u51g&WlZ0~_zx|QQSS%Bf(j|povQTH59I(=CQzx2uMQ^GG@=~Kclogb}R3BPo6 zFkr$j{S4-+HA0P)@=N~`mcvT;rIU5X8teT8ixZXcLVL^ok-YpZuwYigFa2Zc!mZv> zSP$rzKFL0VL^1lMTM57PwWWXwzw}=*->oHHK8cux<)R3AtyNkFhl)=KhStujEVTe7h(zxK=7rG#I*m|;Km0F?Moq_>3j?p|$(KRGEI zXbh#U z7mTKO*6#8k+VK*VyR$C$q#@?8T$jUq3yzS>VLnK8zC@@0%MiP0>#o!8=QXBiNAb8E z>EEG7-|t(b+A-4erPeJ< zrb$u0_lwxTWy$lEI2Xi{#5w&D;PSoC;mWgBd($sTa#n<$8m~xlR)qJHxgx+XDM?&P zb^A!i?@SVxP;Ecccvq70X0=@2`d`x`#=Z4paMvegm~~QTIG7~1(Rlx=@u4KKl=^9< z(7@o+nIv(V)6?bG&$pwN%ddY-UtpJC|3#cPF2DYfoX+i?^6XO&MM5#Y2C`f({>x}l zTrU3iP$VuF|2Ax~%fye+_4l%f-KpO5<|zFQWN#yZE2S_08qtf0WCp%f-JF zyXbQ9Z{7&l<>LQ5wb13_KPv+KX39}D$Z+wW#xZ(VW4QRY;TW8C@sD}MNbKX_e&EP> zi&reB*0}urH&e@8{{EzEv`(btz)~xJ|4!68m%o2&YOUAr*bMmlpW!ybC5~RR0HAf|5GdAq5jiK ziB5aP1Ju&<{HnvT!ZTjclSANQ0@%PYaxnp9;JLzbF#+6$eX(_eQ$XQNpLmP~PSJR_ zPdq^p$26Yf6a5%JU*mZ`k;Mi(+yOCcrF_Dsn!3mXx^a6F#~=@wOSNCE3s~V3pV17z zsBx`NH0}fZipHx!RX{tsP2;sb_5G3Mq8r#o9jj-&{qLMe_K0dOvxjy1tv+!J&G%P+ zK0YZPf_xg(;~Im9;8yC~&l-b=ppxx(@enk(FP|G}7aL4_maYB!kAMS#&C1jGD7w)T zxP`{Yd}0XW+h}~;C(cmLF6M%FX+XPc$N$qlv4+;7uTFo)C(1a`gEjukXNMk*WMq6x z8|NZ8c+>9kD2)FtT#;_nY3C%1dd`B|HJ+C&ZW{vZVm_##WpObd{L&BD#eDEFEz3Ne ze?_u*lI1Pb81B$NQRGWCUY%_3N84g0+a5d%ZB1lks-#wa8 zVP~=!T!8qGbR}>wQG4Z2HHHs%5*zh}PJb}jp7@_gMzhA0nu}hcH7j+|D{QkL`ws@Q zDIb6u2|gJsdWENG7@G+`_bPgYS(I~B@IhA5D=g(KY$y1zs^}HQa_iPb@aYp|mAi#8fna&uV1bu;zuFUh1drLCilVzRGtL)LVwziXT@oixSL3aVX~gnybZm? zd-jp}k+n?+=i&j|YvnbdVHNGE+6iWcS@!dfMJ73&+L-8+-P(>ck?Nsfw{RW`0-%XH z-;NaJU(AK=CovEOk*7gDivO+qS|BRzrFLYZ5v)sI5CKm^5qg*A@HF(bn?4?CV|;86 zc|6kI{G)??*W;0v_`+n_pc7L!bq$0NTZteaWhzIJS|zRVF1%U8=+8(j4Q6a6pS@I{=+Y#S?iec%a;`@ zvNACR(vCW)y>$&6@zn<^uEcu59=j;gHDfDAFYWjN1gcNS@WIcDMUmF|6IjPdCm7%O z9ViAoFZ%6Kq z(*AHDXdAdUO8e7+`;#ngjne*d;PE7jCO++N2Tu1|H(_?A{hQ;kFKBj$w1APy-_lEtO$NN?jRRUXV)0mrM4#;`2= zaTJo)*SPR@l>qDxyD=@(`WYJgMYnR`{&ActF2k-Mtt^g(D1*4u2E^GO8VC>885LTkJ5pisZ@t8bm_zc5|PZxr^Gct}dL@ms4 z+6B5=usu9xpF***%Q?1Vj1wvw{Ji=TkJXrdUTp0}Mgyf2N3sOzj?*qSeo^Vc_E5@Z zU1IzfW2D#~?#5$f+NB10Fk$?%#l;!G6E&WlE&8)rR~aKzJlP(eV})1i0I)suLrmH= z#;qy=*dCgd0#7nlDGas;i*xBZW0%5Udr(YN*Bd`847P`{l*b}g%4(nMjV3sjY|{;_rtwZmN~4*=r?bTz3TBuPFp3MJoN3aV17#^8b=xoeux7+esy zQ*|1cT32($RkY6mjll)+8*Q#-DqUAx5C_@gG$(*u5E1q`U1M-T{LXl(F}NUlafmWB z1{cJO*m{7^)R{csg78vDvd!j7BH)7P!UpGP3@(VL7~jYwdj|IN;DY#vO48W8LS+CK z#C16OODi<_bwA8QBhi^wsDmmPhi9E9;sqkANIvBActTf=>txq&4E(;`{yDJW5+SjW}F-%gX9oq2j?K# zZ>@p>ilczF7`x**lB!^{lT$F9!AhY}W=RLec?O0f)Pw03ItSbQImah4o{ zM}HY-$suOgM^;A~r}N-0qn&Q5b-69pL>kBPp>P=;oxm2>21p^}EGfjXOrW!*5R+gX zGR~4h@YFD)i<7U!;u&GaSyG5$kWj{1Qixe4KzblbJtn)5(IW}XZ5&I&FW9U$GWuME z9$Fg*AflAF+){lR0_y9O@3k7(@3FB12P3fTDwQN;&CCT#kV0GzA!j5=A=a_+2~vnH zShF({q!9B50wzcyhW7&;aytrEq!9J30MBLRiWDLOE0h6J2xV1{7*?=1@URC|YV4ja zWjiVy2rq~JENi#}@eTZ`!ST70(0#h$|mJXsXmZ;zdPFxFX z9c)Q(uY;miEzv#)65VEKX{^0P7e|GbJdI{1+jSz^t{W+iyQLES9A$_SoimEe&~ z@M9;g)Z!U^@GPqY&zOT}StWSF96ZY^!Sm(dXHLFK>!oIP<8_fnF&;Suk2s-YGr%zs zJh~Dy(<~fsoyQE{I8jrq*P$fAV-C8@;@h&|w?v9#BAded&Vkbn>y{G0?;Qxwj>9Y{ z!7;&Cb3qr!#NZHcf@2~H+ow2$FUOlK`h-)~62m$Pr41%HCit@-!Bb8wI3_k=&IEsQ zAUGygv&|a9w)hUEsf_Ct^v0L%vsR+y&|lcV07bri0J%tsp!}%c+_jbTB9^2EZT%J8BFHiz~4X1v_aB3Jb1M z!OqGB1};EZq6#V%?4t43EYTd>sbE*fDW-6HmdInjyJ@@=&7cBwH=MT$yRxdpL(qVr zi}ZqQ>OmLj#ZC&wMS8(SGw33{cu@fN)(tq4C6?HuUW(-R{ei`}NHAK!L=~s#LY*4y z828bFjnS#Wj#9+sGx-syLS`|+A5ZBvwU8HI3B^b}3i!Fn1L4z)~ z46?Na|}lyTgH9tjf*W~3pHk{;k-gP+D9Z&v_GBFQ7kt+e zbn$5LT}#l#qwxY~f{RBZmDRX-H2$KLT|62;a?Dq1@og!KiN|Q?SLp!oXk2;@@Y5P^ zFB6|N2d>q4XPFpH-Frr35Nwc~EBLI&AlTRpB@C`HZcrTp!A5Hs!{AzDuEM9w#FI2B z>oh(SD-(B9FJ3g(s05(ixS>7p28}_zkxk40lJTO72ld7)>~Wp(F{ZSl-k43Jyiwzg z1I0m(%qESu3=%b*bFXL&PL6);;H$a;B_QQ!#TL6rIjU)eU)S6pAm!kT=%9;~L)cwj z!HZhHuMWCMIoi@BxJWrx5$`k{Rxglpa4#Knk#g`gdeBA6F~eSkV%2N(;QQK=tR5yF z6piTkBg*(TjrpPq=UQj;J&zN93}!(02fKer)-9cq+059m$d9Il8(>0wz)_;_?kTEBI$_Gq73gTWtl^OjVI z+u3{3IP#Y1aNmF$poY?i zrZt)!0L2IyK!Yxd5qq$`G-E-?zGhn_HMWJ5$i*{q39and_@Gyb16XZ>7im1bO6+B~ z$C=JXdnTAgD9Z^tes-1E$^KlT=LDEZ?qzu{W)i+m4vZRps2AzL<61YUs(->?f1@_7}@#=Itt?@z~3^tP^_J;`W@D;ngLFR^WcOJ%)x5?`K&eGUa~#X7@yB>!KJA>5U3uBqRqlmi(k(M zH3HYAwEJW&Xrw-#jfYlR{B|~2tv{W$_~~psZj_}S=c=7UqOle~oDFIgmGPF^0axqK zW-Wd;8$8QOqP9rYr&TK^Tl{D?Ugpi#BSRVz>Q81ZelqJs@{3uEU(CiKP96BcY#id$ zf#1u<;R*wXT?gO7NdZ5XjfdiRfnUqUA&wXLv23t9{;jOVZ)Jnk@lRzfzW$FV#wi28 z76?|4QAQ4@4E#_wsQQ6t4a4Ghvhl?G4XaZc;Ha-67$NYV8`faXvC;glSTUT;V%smI zfE2^Y+xDWj(b&JJ@V9b+@Gix$_t@F8gyTgItJ^2qeJ9qw~ z>cffPPAc79&bm9>Yn^0c?{*R|_F6nw4JPPNc<36e8EJRj5y@%SqY1#h&ch4XPyV1x zra8t7>?b=*0HKD#%E$#`1+$N-?Z4vJd6?4~<$_?k*nI**TqW?`lEEvNB(N8?6W{V^kgk2!^n z&A4{LWKYm`G;X}rCxo~K4w`8F!-^hvQeJ7Lvy_Dnnq+M%0Xj>NGT0Ba#EHAvx;aKe zyVQYGoFl$v4!X-a$)+tQQm1P#QgK%}5T|P&Vq}9W9f;F4euo!a=5Pmf)fnRlsekV zwGISl%KJS4*E1o-k^42Zjt&Vk@eDPTn#9SRk2 zrj&Dwy6M(T9u;r1qdwqF`O7%t z!NHX#*ONT{?sc3q<#(9OrU}lJ`Sz0Ck>*)9W~D&I1D`1`1?z`lan#`$!%yLiKF8*o!Z?g3TZAt05lll=m-ZLxPS z+xy8n+Yh{9HY>y$@dkpJBWZFb1|lmF8Seqy}3c zV<2a?IoBKEmy>bi58rspb!Sl^@^i6WxGz%Jnx;xM^cUVxSXr3=MQ7p-?F^(E`iMPw zAB6Q&$bMj7B(HTFJi4iT7x0Gprs1Y&JbIvn%-=>=`C8ib$Y(rcAKQnq*^Jq%vSsDy zY<+Q4R3FcFEs)CQx7+VWwwPVMA7^%JU=-VBqLSUbNx==zOFK~TsZjj(kcw#;O7d1i zT|+nCuwkQcQ#6Y6hoe6QNYy}sL?!t)D4{L>Yso)`aQ(q|&P#utMe%jZu(c^upA zNTB*~lsBxwi`BQNHeN#uAXUR%xKTAciBgs%YS@GDcm=fxu18K|@GtT5Q?LZ9@*})q z`LRK`E0Rd6x^M-Ms^Bx+s0#S2qx%yT@K8Kn!6yiYgRaLIavs!0b>JpMs|vR9h828{ zo1z+|Qso;>b@_8~!}5E3{Lndp|5`?WBLe^0(?kamyp|OVZPx@vwZUSihU#42aHy`a zn|&0?jm;vaL4BDwto0+@6djA#`YVv?)%^v!SA9`(|3sx9BV7IKc(@~+=QIyc$5&bc zXxbk2YexP{;b6BIDgX6!yb)R*>XwBNd*eruhQY&Vcvh2cz+m2KgiFV5_R)_b&5ZBu zzIfk@Oyv8xV5BE}~BjsuZSvHxpzy7=OWs<<^b;_ZoBlS2e;YvgC;h!YhJtU z&!^K@*BW)#kEyuDu;s{}*W3R*UmL5-zj#5RQFo&3;;>Xrl} zc_1>{Q2Ss~-93Y&%hK$Bc9_|A`&Yezy3$e6nWj-^z=T!oLXS0`m0=Xy&sPo( z`&L7#;^aa|Y;GyG|6%wpDw{pxvN6HO#zm!X*K$w;*jeMEh31PtYGNUTn}>h2PcFvK z%S~aTBR}HpH|d2yccd~E8=m&|)L#7xeLGKJuVEXPjcH*U7o#!l&tOk9OM}wsklc1ixv1op$W>4ae zY52nkHqDefv4Wf4l(2K@#EX%915%o%uf%@$@n{$06WdrA4fU9b4Bmg4i;u}3?@$zO zcEA+$cw-DL>BL+C?|ziwZG!uxeGEzY-LQu*jCLzN%KSOT!%S5e@J~i|Z?1;YKY+O! zY8dh#v0qvkEh>JPp-pvY3;#&w$=5LI|A{3QXjtUWv(pzvi;U;(Uc6M<7q`AP%f4q( z)DNzy`wv)Ob@Rp6Gv>EvYbuD|n^9Ib$o0 z6YO~5Bv0y(jNTx!a0z%{*^S@^``Nn9yu~9>1N@>|z~kMrPeE^kT)X$;XlYsj()(62 z5JqXYJ$rGqPshF}I;F{I{56d9p17nfL#mXa*Ek^!8S;PR`+IS;Y0$~{j60uQ{6w_7 z(Z;^=iD<+y?Kw|GvvaqgF#qW8UKH;`T6~+t5;G>)uOZeLZGZSgG@SboTI7H5VOOF_ zxX*Z@F8E~h!L(TMp~ zwljTd81|LD6k)!ZjXa+5_Nz-%3youSr`AVX`P_6{4UKMgpV8h{X6xuzLb0M0Q6sO$Uimjg6084yQ#|K$XCo|<=lxlu~dXnOlTRaRk z^RU-Sic@a=*$2RzQiN5&>|kH~UNlGSD#m?7EFNC_h6}<4vCI-A33#vXfZ$|Q>2p}N zPGf77?67PN=mP446wR_lwyu-}%T_shm6BlD+S(Z~!Lr3uz?1~bR!&>M1j|-WY~xZ~ zEL-UffD5uGX%4+o2Y~IQxcS0x0eAXD7Okq0TYy4DfZ!Aum@Y%x&-Cc;BJ5k%B>He zCn*WaE&A%DBq+B?x1W-r+!{xipxnx!&??jmA+zvG@diderPAOGrL}0#3w!vK4aI@> z?O-la94@ZS1qeIK#g$E2oaN#QQWW+&F=wC`bX@n?#vV-7tL>$i4-Iwuv=_8O4BCdW z<;_s%n5>GRI{9f&=(?PRzouM?Q>P@!<6N)og?kWijkPE4iAHJT^AAq))vJ@kmB>A1PS3ZjLJ~{`ItR%0xmMr1!SX6pr^3pS7oSMjzIU*`eAx_L zERa99^nlapTufCEa4kgALfIKfTgYN$ZYlYDp<($?1ClzK%}MH%-i)M9S(wPJC4XAB zjch%XTl-Y>yR9t3co)mJ(DZh)2)WwJWvHNo{1r0jC|^aDo#bpEIh}sMh;^3P$lFD> zL^&Yf%EysNH~9pr?=Ek{-yZTg^rojgAC2fGFNUDbk=3Zax7>{C`^fJ2yVWBv?V(7W zdLuUoxI!jLojmC$p}O8c?|1NoE%!k0JaStB$Ldmym?^J;0wl>LFil|c!C!Ep#2}Sq z`8wpCBKb{?U;YOsEmcnJ#lgC{9|^clW9S32J33&=Ptk!i`7Nwgy8H`&rQ~k{XUNCU zfK0gpe}nQfOpuV=gTGmFKl+j_7sF!b$X`)cuH<(a4dpmBR+qGjaj*`cEluPkG&)a) znscy*qFecL6*^ELH{fqGSq#l@E`P`4X`!4N;aL5a!m(-ztqMyUGLFcpxQ|L60JoBd z@wc`72#Y}*nTyfDSPkP?@w?k%S&e43lTY_k1YFlbKRU>&R1VgaD58^mA5AHd4Ux37 zYzG;1krfE(D!aGkSUrx4yDOrU9&$-J$Ld;4grzFn%uYEyqT zR!d;;F;+R<6am*cP!tky)nJ4{!1XM|1p=;*F+?EXsz;MR!1W0x4hXo`L#!a+8h}QF zfGa8#0asTj7YMk|t~C%82)G`FCV+tJ z7FAmI8DvmXRpUt!chz|{e20s^jy5H|?8 z1|mNRxHce^1YGApvG2vTC!|6Gu3Ioh({ZIU9tpVKMD1<@uCH65H3)wh!XyFL;xO8S zYm8rykbvv^G&BiUZhRlY^-EYM5^!CO){uZ}PKn1u0m;_wsqGu%Fx)I|=0xmDolYna!l!*jf zX4E0z`aa@O1YG-Zox3F9l@pR30?hH)ycn-O1g#4CHF;Zt#~Mnh_95)536lQ?8PIToTP0~gOh&0qqEnhaboWA2cFYcl3M8Mu;hB?H$`7)LU2 z9fsnPfol^iGa0z{Vakz#>j!8Z8Mt~wSIEG%6&)Z0*I`I#F0KoPY6h-u==pyTumWR8 z1}@TjlYwhhp~JwH(SZ^Ibycpzz_kdXBm>uFsE7<)r=XN%;93S{Bm>un&~GwueS=v} z2Cf}QPX?|J19)7=^-Ad6Qe3kkX~n=*ffka1s~SBf1J@-G`AS@09q2G{U1dLaAetXL zfM_ysorFq|f$KX+lnh+!T00C}SHnoW0DMD|$FmmK!Kh~)uG-W#Yl z_(D?lD)WGnYdxRG<-<@;zx)CXkTUiXmW~2B1L^=yu2bl=H}I)(1GDT!0z-xoWXeBO z!Tik#pX9FvC(AKtc8aWpI{0N>b1e5bu!88lfv=4xn7aYwYRDd#kf!vYL0;L2&5{Gr z1W`${d(zucX_tPfmdDCd>PaS>ZiUC-9W8me5W8{kNg)oKsktsWXcd^m*mNAnZi^)vkz0f3u6Q;jgA^}b04O92BpW63T)KS4+rfVK8d!p zSU_N_$t`l~ID7dg(bmI!tnY9V_sjIhehhOekl^y#j42XGaC!X-VFwaiUiU%XfdrS= zpS|rypGMor>k1H@AoDtCKegY^wy*g#n$v9@lp*kU5|}7GsYjtp2Lk~`+a**p;uKyU zkq%=Pi1TkrF~xr6(`cTt!ZscnmzTd0rWcVTF(~*ZLCk>eoP}kgn?3GBJ1E~t7LF8Y?mVN!LQD-Lc7!licrnI+&M&Ks7lmjjV3o>yr64sU;I*pyN#a2c zr{z7Z;AD};@p2J*c`%uYRpu#T5Nr=1+pY+`zHpK|7=&J9De!pw5<`RrxG)I4-nadq z!SsYUknv>TK3WWYJc~i-^rksA^m^85r1N_#AoR+1R|~GA7ceoAe~fAt2)$ki zE6h&uLj}>)ogRch~dq1Vl@4S})V?~*vo1>#0~ z=izAHnBOggCJ4QHvdCM#SHd2U(Cc}M_#UlJ-2`dQ1OM?3LO;yHUZNSBli>L}3d0#l z@O*W!OaF@s+EXPGgkI;eg9$<}e#sC>5PE$B0~AOQdc6qiAE?vSj~DA;s{#o=ug>;H zR1hP}Vj#ii^)u^B@OeE2%M?iPc}-${2|lleQ9u`;S0;ze#pgAaWAEbgIv>kY;FNbX zEHivGpi4nKrUYDkUS3w`;`2HLOC3n^-Jvpo&+7p;*2U+=pI8mJ_`Ej3ZU_9DaSA%k z_s4-$jcW}tlFW@C;9~kxQ`E)uRYvX3^VO&Z zL;FX;{s)@+9)#BLLmP3p065>rg9o_97~FY4e<|h23!@UpfK1xWU>}w6st&F&#l0Mot(qjP){KeqB?xe_ zhGlY$T&!Ux=i$4)ovMLg4f}^<>|zc3mqX@a4ZE)k@W;BrTTSsLD?Fm{c2m5A6+dv6 zPAp~$!FlN76C2C|Pw5uco8oRC@EMKwo8k|yhc2Qq{sdOQMKrdl6xc;Hb}>cnA{rwB zMj%c!7CUAN@-YWoOk?k{2QH>D$#p!zG$yK8fs1HtSOegTlKW!l717uujCT=@wWGvb zL}Q(~2x+3RSmDeh@hz3e#WdEFTE8fnwoWmP-NptkOJ1plU_p|IQAb=vV|NY$b`g!K zmC8jlrdF!=letpCxhzRkP$wLsF?d*mY3#+82yiit-ODj@F^!dTcMxY91JT$4HpoRZ zmdCZvMKtzd0kDf`Y!n;lA{q;Dd!dNNVw{Ib;)(tUa50V1DKp?=8l!7MKr@XMo=y^1 zQmJ~T{HP>yCP@s#N)>SNj#bn0xp>FEWdmHiV>`JmAnzFL4=5$PV(<_IxQNHz;=FYc zkKIcpauJWcO*@?+9uvK}47+&8nsH%r@s3Ro0lRp|)^HgI?-=Umn1D#E2mvnQv7cz$ z-%L5JdI;jN>o{ibY7FABhdA%g5|4Ss%zR)M?^qY=kc)ThSL}2HF5a;>ID{usViDLM zMLc#FmC!{zHjY~C^*fdd#ADOgVi)mP9UB}c9s}>#AokeBJ0`Ie4Y+v6uHme5@s6!# z2Rp=hy^eXsFB}sW@z^nrVVVC1)j$xBUC(*zA|CsMN~?*-$UD}8L*U{atH9%Oz{NXu zS2?hYcWgbUVa!E5_6-Yk5s&>#5yu+{;<5iQ-bFmNo(*=0#}x0_3@UA$XKb-gkaYMg zUg8tKaP@TYj)l>)SinU*HoPwqxQNH{X^LIMV<%aGi+JoGZpIYx7>018PwY+tKHwjz zbZU!FyufMcA|g9NCI8CLXGTRtHYdkZ>0&4w%B9Q2P0&6Wp!{77 zWok3;Vko;COHRPWP^LEjXBo=Ml0{p#FhNl!POw4WYRa-B$zlN|>tZXrj16$HmHq3t zmwy*6j$M&~@J52C28ymsa4t0yJQ7fJW&C6_5EXpLS9E1}aI&`(e2!OiWpC2pcM*It z$IdfFjAcDT#8prnMOXGdjgO12>_8*n1YOxcv4;(C(Uskq3w)ip2^tSZrW7&S2Yjo> zD^f%%JLcjsQ;#`z{`8@v?GxWeEqRJVogg$DWCxB%o5XfASAx+jmqvS@n2T2O3Hkx9 ziu1+G3Wh{7oA8*9%@vPOCvEY$iftlZ3Va~{_spG`{eI7%=OK6Bsb|hPbLN)0@3qdJ&E1f` z1=6`(D$PRyUe3%xnOXw0zSfpsb4Rz=N~k43(^s$`N;+A_Q@!K|a2MheNvF!#kS+D4 z)o0Sav{G`Tb@y+%c^PYH-90aRX;D(`8z9$=N;2hV*81OaN4n_>QdzIe?0r?eiE(=y zbs?oRw9>0{8-t6yS9NYaKL7PZb#9J(Ct|qQYBsxff%Q#wZk{{6nDD~cz4L=VBIuNO zw|<6^ck++{7eBpA{yBr4f z9@wjq%gd>$FE3~m4gO%DgEms$9wg{jHu8ICTR)u34GwOA(R#n7{Qxkj_YN4%dt|Ui zHcOiK*cy#;z31WR-k-K;l;>@aS?E1(qkQjH65{8tbY7vioi*%yZfk!KCib5F9*LSI zt&O$(d~V|m`VxS*+D<*ry!3vn_nZy!LO{s+^*o+ezd^14VW)y5ts!aSPaA?Hjn1sR zmuv`R?|*Fwk~BK4^Io+fNYZFI@?NtcNYcK;oc3N% z`G+L!EBK99vHIv=lcc?IBXF|8RW7+B8aTTqAN-XhS$<8vTONhSdYiM>c6}kQ(P%rc zhcpIB+E|#|+tFZ$hbopUGd|ckOWCz)A0^77%XY$NZjGfr+os%06lR! z;k}bx*5$#HwvgnyoBaf}XqL3QNc?*keHKEqq^*eq9%(RG(sq(u53s>HpIFk4Qir2V z0$9=xw*Y>SJ+2FYC2cU~sdqG6t1(#8%4kkJ%=T$qo+$ew4tXD8e`ySsv~O|t;2q2A zpc$OfCd#FV{@!s0gC%Vg8F)Mk>3m{Idyx_zH3h(u_9b=rn89F4%f=a?cM_w!!+7-o zG;BBr_CC(;*0?fJ#s`6)Fc>Up3!obBWHw9ZgC$K>I`${-*`1}CFrWRc zlfja91k1YDVi^!$v!pE`4_L_>Y7CaN?WCBu*j*ZfB~3F=zsuHX43@M}yPciZ7%XWMdIIlY9xSppOWMacPw?(y6k#+=THScy-3EgtEx`}G*I=-u{fnmJ zm#mR)04!-gLvru827@K-H^L_vg;ZEFNjgd32$r--q_=8DpJumN(*8pooMZRv1hAxC z$K{gu4>n(8u%tDq4}6KO)fg;k50Zwiunii6C2b+a{c9`}E{yYoWErBk&z<&wz>=m2 zyPUSbU`acJk$T+*6HD51N)RRiENLG|;3$K^lD3ipa%Nu2#S zC95YNPXo?!62FjUNt;1oD&*XvF<8<@l1Z94?XU)xv@tZ9n%3Y{IhIUPP=nLuG@6{v zYcLjfc%!$46VcMJqzQ{%$<1*8971}<8_)E9AljPm45}OZLJ)s!s~f1j6EJve>zakT z5?)e+T;6(^C9#I3E82S_#EUH+q)(qfm)6&+at0F{7dAy|FFO@qCV`vA-qgE}z3^+I zJaA+YiuTsE>hoY-@3Xj$cg5cP1$F+cHD=QtAw@~C1D7C0O|vGWPC((= zz5@G+L9{muQL_dqZ!S(2YLH*c=xbru1M}LnuE;F>4h=hRgJk}+{;*jB{bcGcI6Row z=93lQfhKF2*FKF21OCIj_B+NM!MsNG;u_tGYHB-9fWW*qgXa1QtgW@oYxJP0mU)eC z($+Gs(Jk4yCbo>qOE+ZWn%c2n6CEOF|6SaJ7eW9CLKDGkr zx|Waa8^obnJ~q0!Tg%5rcXDg_*uH|@YWdiROfiCwjRqFi_IZpkWp)i8+XW2Cn}r1? zt`q&FlebQoqP2W%Pg=v>5O&Q?NG!gtiv+xvlYwga*c?!O1RvWKM8ya`wsfjm%g5%R z!PN4x5lMJlFCTnG^Re}540sbMPV=#iLA)bAHXV_xn74Z;;653;G)~kGk{o?)h_^3G zsjZuBi1+ITT6rRv=0Am~9zn;JXx&Ds^x|U#9ordeh6oO8JrDhXj_p%)pyyD0n(dzm z0hl$lbZl$!5T%xm?PsfQR4^Fc4IiqdW4i)V)Y7qiM0pLDYY)hDIH{lb9D4IEg(zl; zj;&#T^y$XJSLc&__$FC`o=Dc&WqT36)+B0Cw3nX9)Kau9$7sT}9BuTtsFtH`6=G_g zy_eBGakRCB8`g5P(I-G^Ioi5HpjwVLC(d|kIojx&sg|SdhfJWa?2DFsZ#H6Do$%MT zq=nvdSkG!X+UV(2Ek_&OzN+PDqvtNQ9BuRvpq8VJ9s$&Hw9x~AT8=h)d{E~HyT3u+ zX;DB&tq-Gv(P6q@_kUR1+M!uz)(G#*)Wiw9(nRkCxKb@^8$A(?U~L-$eMYdh^~FSr zU~Ov_0IX$g>qzbXIuy3$Sz)|b`T}LwvbN2@>0AxOi=^oY8xgE+-y@7gu(ln8V??mF z^(C=tS=*{e=33UanTVMYtZn*{Zv<=GZPxynU|P612BrR5K7_=>`_vzhtuEOR?^B;4 z>s%S6h2P7()9M1&vbJ4C2(5GVHC-31ZGXTq!P@r3U}_5wNxUt9qYVaYn@9wXH5jaI zH|N`|ZFU8)w%vdz2iCTibc0}Ri?*JY!Hn>aWa_%CjcymLZP%z+J@&3H2G+LQF|ong zc3g)6u(q8=lmKhnZk-R-wi`&UH1@5=U~Q8KivO^*fwk>ZGC>4u8?lUowT;$Co3$-3 z2??1d0jzBw^a8GLFj(96kx3gc3I>|Bjb5b!YnzS1+O_~^ykKp+tOWpT+q~|;4cT># zrzFTFnBj|cZ&r*7UNe69Pe*`Yjw%O%C+qRdyv4z2)ZKEYFlD2I*&H4!1 zw&6Ixi==IvL<5hYZJU$;+=kiDXo$A05nLdWwrxQ&a0G2z3o?BKZ5yq)k+f~qWXcHI zwo}$=70l>-2l;6PZCiT^m0j2fZBfv+jaR@Cv~9f!N6@y-wR(Aj%?fC}jHGR&6*H2y z?LVZhK8#L%G;P~tYpoZ(7vT&9v~6}WXxna~NZH?D(6&8E?lZt((6)t1YXh0@Hfjd6 zZ84UN4K`!5thPAZ6-%<;Zc2l;?IeY;p{6uw+k72?hp~pbHfY;4vBPk-3jtlzwv7%U z{|?sKZoQ492mXjv2jrN9sw#|M3 z1KPGhoK-=~r#i%95)8&i7|^!G;tB(_ zZ9i)a+O{hcQ{FO|XxlDPq~FNc?c^t*ZS&B{#U_J6+cuF#@E=C6isH(po7_qxu3$&d zj;3wBsggF)LCBrkv0V9>TLA-~;XFlgH*(*WN$0uXK6I9eDZXxqM~F#I7)(j9`f zjdm48(zcDZcEtrV`qSovNZPiA6cQq6+lagzv~7mBtf$^B5lP!dyCouN+upT`;^7c< z-W*BWmR$%OLEBbNr$Q05ZFFWGN!vze@sYG`50k+oXxloHSP`^sCrKTLYU~Tzwr&(m zB52zz>m=mroEL}W2--IKz-J_F8*Ocfq-`5RA^jAib5u>+w$HpjYzYT#8xxf*$ZRO<1nRTmGCE=u`dkT_k2-@cMmmgApH5i0# zdnk}~cDB)O1H!fp>tqt*h$f7QAZ&Yz)EhzAcCamQ1Yz53YBqwfZL!rOIe0VPL0ys@ z%xJ!sT&ceq1Gw4_ldlbQ-laPQS6e^IkKk&%e3Q-9b}cy=6YfqLi{NT|m_lm=S6d76 zgb1#-0W{(}oc38MxY|~c0wcKE;%Fhc+e`#-wausYBDmUU3&Q_!wM`@!h~R4bf=-ts zxZ3U{*NNb2J3$>raJ4lcfg-rt4pHcc;A+dEl`Mj*Z8c4#u|`|O)mGn%ss~qmf@Vqt zS6h3U(Ggs2Pg8ybSK9%a0ufwoU1$nKaJAj9fFrot?xKNDG5vz8t+)^HG^5Ds0S#oB z*1`y`wl8Q=Dslcxn-N@Xr>&ikvp-R=fU4~SoeZkBH>lnD&Z8QGs%<94<}!mp)%Gu% z+RqpasC(Flq2StjmGiK@PgecX=PdvK0t^ zjB{hUJGsvV6ml03Qr>%Uz7c3_BfobY+6d&)Sv1|0t43@NG@6?Z{2y}7T190DQ1&rhHC*v>ke~NUce*#YVxIY?ailB=-(+TgC zfi8}&YQ3~OyM`bR_p528G6Zja??kH_ojF(BXuZF^QN1*MD`KEMo=#rcn{5-EIkSqr zMOKG|B`JDqc1>bGFYU~(Gtg|z_R_}en!F)ieH}TFCYCd6n3uL?*BO|n2RXv4&%6f? z(CB_IZOX2ti_@oOnr6+JHO5OD-D=t#?{)O5N6>7@_R`~QJ5%#!{rFE=o`u^Tv>m%9 zx14!tH+BtN!MtBsx#_q?L7TB_Qb89-d$DUE=;CNAcAbGWJF&fMVZ}NFYc^tgX)i`i zVcg!Jts4<^akLFPf-a7>C)5-MUEIGY01s)C3kzwwxCS)MZzKI^y0~2=`|YG4O&2$! zg|+k(eCc{IO^#Z=xC6AR*Yd@+qO*cpzPKN0XpfUM@vso|ajAe$^wb^Vj-{JC`$>Dj z2VY!oQsrd3F!_oOIDZb76}sy1{(j z{lgd6iz3ns_AD6feTK&KqK(FQ=`&!pd~sig$^ZZ1i_^CoU$u)q>FrG`&2mCG#bDlS za-|hEEMeZ90N_d+f-ml?Ou$t(1Yg_`ie9U2h}(K;BttDnlCO}`+X$|T+0`C z2d$U2d~x?$uh$Reg}e7aYAs#da`Kg0y0{Z`g88=HA?V`z#sO}$A#P^}$= zzLPVAMz+=Iy`4O%!iJ!WD~h;!ZGcS$sCy!J6RcZHH_eGkcKTJ7zWIpILX1DA+($_ zQ(zPJERAa~!Fa6tY!Sg~f{zo_jvBx+(Ks31zc?J}Td0=yiXxWWPy`PqnV*22%>?t|&W6H%Y^o zAUSjo(uSWAd?ls^{u{p>P1yB9t4A=Hi>Aj0gKg0C>%m}qR((YQS#amNC7DdbQyaA&1LnoqMHO8hyPaugc@N; zr;4^AASM)Twi^nO1h!0j>=aujxK?8C!?k5JRn<9QO;wfQX!APaPVyyw4+OL+Sz?bN zw=KhTPZlgC?*C>?wzf41Hmd7{8zd*Qp%K|cZ`Ed*#hYScR9g8>;lnGe?oER^(B{KH z$>+MEPQ!~4Ro2kWPJitD}y^@ z4*!Ko&;mijI`^R~!+LU6FgIpyV}@4=DXkz`WmtPx1^Z!dTH5O1%~tB_pt2^e4laTQ zylaAu@%hfUQqwRaqFem(A1bS z;100Z2QrK8vwo$Net$R|qph*2InP$CTO0Io*0N&j`k-k25A%&?glbV(Sd_0Bq1d7d z@6W;MJbaXb!o&bxiN{p}{hP_`qcaOZ+ZEk?7$83a&kplP5SSf&C)MD@%;DtI5REwh z8On0;Z8*1cJ6tR}8^v7CC>6rN6_tTi4TqVS4lX9HQBkLRGNOmu<$mDdX5-O^dv79A zqodBCWw92rIE&_?C-HJ7e$IOfKf$WwK`;?FTW>w;34~vSXreO-({Lgc9Fc>cIbr&l zgE+(UboBs22`?b|#dDeX*&Ocd5Z!|KSvZP*9)T3R-6H&SDHnanSB#_IUs7gF5VaS% zeTlhM zbT?r6oTSc|A5i6N)=I-dISz_&=a?}S$wM%ZJ7i#cNq6Mjd2E#)VJCTp>gF@jpfd}% zZ}&sv?gB>IcV^uvcaj{D+~r zWcMZ&!n&p0TSzQ#&nzUpXX^x8^r*e9wn|*yx2!26!1FcH+B?FP+i@bsEOH-0rFef- z=8sgFh#8|A-i@DhGI|aAjcR;eBbRp}`i^S;w?^PDZeV>j$&(fS8KVRP4jImW33h zK^-22zX9GGO(gI)a1N5lXX0-XACL3xWS)cO>hdbIQ;(-Xmnl33BBt`AaOE_9JL;zM zB`BG}&(%lleS_+q3q;R6sfn(}*~iDrB;rfELUfhYxht^lbDr_YVH;GS%ds_^?@ zgO+?Q#A?NFf@`!6^XZVch-agrHoP~gwdJWewQ9$Ife`KaWj9z=cxQ;%f!~H|9eD!A zTIt|_!7)B^aQfc*#||D3^KFAUXxpbtc9?+joJeULd>Hi2coim(lP^V+oc{>bxcCNG z(#<~$V_3guz{347P!$(3LlGELE5B~ysQoIcm;pHbFPb}|_*yH23=F<6RP)7#mNXg`J_*~`=cF!ntTJ`fo!PgS`&EA%_@n_~&T!a|fRUTYmw8e;fTC zcJN3VU9U?6AV4No%e0ms@Am6iknqIMUZbz<|T&LPcP};TxfUFyQd;5*QE+IQ%I501P-h2Jr$6IQ)4W z!GObwKNk!*{23Sn3^<%#)&T zf&qtrfQn$i;rlTuz<|Tc;SgZJ;oYE9FyL^yv+6cpQxc$6sMfFyruM zZ~`#n@Xjz8m~prlW&|@1r*D0N8HaxdO@bMRk0TGl@fs`&W*oi^CY;(0Kl0&rpvK`F zVM9>k@S9N))Hs}WZGjqx&%?+;jl=JP?ZAw~gJ=-UI2_X&8gg@2j^%H?ATfLarUDZV z?+lZI35OFm5SVay0%jhVaQOSs5SVcIyO@_?!r^IX08BXiUgU!bhi`;0feDANgT|i0 zu_;UiA{<_bav;Lt@8Ad`96lQsS&Sot+k*&)zldnD1k^ozHZ%h!9KHok3ML%>7%G4X zhd0NF!Gy#2V<2F{;eF8&m~i+$GyonW4dCTdXRd{*iT@VTsIoEQj_Ajg_)gF%EkFbSqo%}Nl$;IEQk5K03GaI71Bk@};-EV9r6+VZt zV}*bajJJo2I{6-$!NnIq9yh1&2nxOq=~28s)Cr25MUcuRFSGSjyCM2@@K(?Xf*@LQ z@>S>%6ge|VYUy?obr=6P428F}@7JSBM*$~q4kzL~7Nc_U{;;>3$7582e~)Pgikv*i z=NXVYDNmtA znV{u~8EbVe_0-GgihgCqKMfHdsoeZeL$OxXXjjA7v9PPGboPKCF$=S-^`#!{rG=>S z2R?!9gO~cg!zkoYZp#;tD`0e4Wni+TFZar02BykcB{w7rEj44$pyIXh6@HDw)A@nG(@r@+Q@9@AwQn}uR!lV|+tACS*+GE7h>)MSh zlCKlY4oD^GJ;FKgen4B?eA&!8Hp7#aF@}^}liEoVvE4tgSPr(*W_r@XZ@@MFN$n@! zp}xJYZ*{|iWC^_bpWGpG8O8)?YiXFA3Eu@gstb>hJ?#$MXpx9a+aU%Z_kyPbfy*Szsay4p(okE zn9e1i#2l3&1EXzED=<*WDojDy&OpB$KrU5mU_kzg$te44>x8j)TE0epIlyG&HB1`X zFxO%n$Y=CaxzFV0NgC6# z@@P4k;?iyd$H<3BxBCnnFKL&9JY?WRSxO<~m}%-sIgq40u5;*^?}v=5C?Kf$8x$86@3}=!9_{XL2#c(G0h~p+U?#!$_c}?om1)#5%Xr z09u;%t1-YF;64Ul3@~|uX3HRxaEZwsL2Kz;Px^p^WV}aBdWlnJlfTY%-=PHogHAtq zxh!)}uodi-sig2FraTCATF{E~vccFJ{;kha^E~NsPHJa^dxsXV+$j^RW#eH8V%L-( zyUCLfR-CeZ7VtJxeS=eeNcnr*Pw4JIhx1&!%H#vxKs8gIU5)Z(wp09ss;@{>y(#iImkD-+9~fR`?NOgUv$coq=#D# zz69Q&)ui{~;$kKZ^r}&4W|@4D-uP%@Eiia4Fpc{~ zK|xEC-W;R&_^KG96%EpxUNoTBO!=i@E|<}WDosK;uBHg@GI#~I*O@N_tuvbSCW@y0 z*CrpNHx)GHju^a`OGz3zZty-X?;{UBZ7@i02GD@24GtgTGMeVtpC;ijm!Io3Gs-qe z6*NE{1`IyVWlz#rioqbgp-+#=1_qzy(xMRt4X)-gmdfWF4AL8lA+lZ6GSWym3#>QW zok-|r3S0#X4hb~a;3+QI46{=XGq?ntG31*g4F>7WgA{>B8$8z~pC=QIGq}tp9kk3( zjM}EB$Rd}#MD=Ire7tkG#3f^Bu03NaEOklRmM)(+xZEYH$S2kqyuyWP3H-LfAidd0 zbNgL`*SX|wnjG7rR?`TxKzeh8d}5EmAiWt*K5-xlK1IAin_coWo%nob8rbTRcaqAE z8C>a-3rRyK4c_jOQ%K<7qrTG}>~hIf1tJ?N5Y zwC=zV?GUGf@qB{L1Ka>?HaH!}FROZFq17Z?oEn_tMO+8BJ+CAX0i z7Ds1iQTrghxfefV@91sX1Q%WMOVaS*=oz=^gi9{@?@S~NGYwpI$vq_TJqAy4%iE}d zQ3jW|;xPSGeUR8s|oX*SO^yA>b_ruXD>5v_gMm@CG*|2HqWQhp$cUEV+n$cb_Q$Zkx`u z{(NIFxNZKEZRI`dNpJoHS@3MMzR1f0h0PjrsS5^!!saY>e8tq;hkA9bC!h5+4ezCT zi7{rfq8uqc&EVs1c{90cw!tUe@)KJ48ykGqE$h)-Yi@A0TS}VzZDQ;JTy)E8WS7n+ z|B_oCA-nW6_^LZBAE1ES&m@4u<|Ju!n877NzD5hfJqFJb@&GI@M;Sa<$WKY&aR!$O zSxttWWbh&(Epqj+!Apc3B!FicyfiH2BZRiAtCpX#!eYrCFE_5fvZjXCxuKVll*1laMoE! zgfJlgj`<9NW3mbPE6s%{Y5T-QAzP6T)REit2rdcvF!^9Tsc#HqT@~^b>af1lSN&Na zpm>P{%9Z*$KC2{3`bophq`p+oniVC3q_I|#F1`^zL4!jNpJXqY3QcJmoIVs_2N?kt zMafbMZ+95HBnp88_&#Yn+0rO^6XAyqE{~Eca)2K-7%VseviVb{{+cM6L`&p!!WK^I z2c_^NdCnpH(B0DbHtL1bm3H4P5NJIn#z>R$RA$Pee0`d^5<72-GU%WoNnYC%jJ#h zG|rPZk}X!q#V{E?&}>H?zh;Cjl$8`l*UAcAxCjCQzAiu3u)W;pwuXgWZ>C>{I$Q|i z9*X~REwxzR17)B^%w4OWCv<1pMyLo+Qzbct)GFB=p^}czds2t$OQg@FeTk&(VSQ$+C*#_jv=jr@^*7$#0$+8)Rp6;>s z$TMMS78}Y7)An8?V(Rpe|044YHL$nb0nN%`v17C}{bYc0 zhZ{IXCNsc0G}PBT`mV|dT^Y+flP)MnhVRjR(c9Mcsoedh04_%8jR-l)G=Pf{eHUb$ z$*(fk?vELai;?a$Z)TbHa53@?1?NR39~U2E$z7Hke38jdF}O7OmPx?Hhn^_!75ka1!+`ztYa3 z{(@WOdQ#s(dGB$=X-}Gc=LV!1Xwj2yo7&}_2~B%4Y!vNniU8@!9Ho6mc`w7GJoRH> zE6i-~4h+@Pz%Ci^_Q?dwvQe^kCVI>9WZN*+dl^IVGz{p9nGQj+cyby;loaN(dc=iV z`8PvUW(%<}I{k+vYkpj)UJ`Z4GO5F*_>bMwB!1>j>%+KEqc;D6Y^+NM$crymruBfw zvaZKSI}4-JZb4jOUFpihxlpCvJ>fnFE2h=PxzL}s*~*9yrKFR_Sa*`J4|;Lb-;U*1 zt)zI%Sp5uZNPH-j4Ywx5hZ=~4_O=LEa+3=-{aZpw5A+neD7bI33>lQk~{{K6%thgl$T38*%Oi!$E^#~<9Sr03%S7>L<{SP`ERahWX z?A=uArcf^LF~ebfF`*s$@7pih8gx@ApY^j!ZwkG_MpzAdhZ?hER{!3iEOx&&p?9c} zyQC%TZ||Pk)H~$I#}{`{@(LuUTjx;F`SIOW?9pd(oWI^}fBS1hk@UN(@5VzC`_p-y zZs_L6?)Z6qP;J&d@I!m2RH}7^QnrqAIG(naO>AdXl=lraNc-O%QbmQ$Yj#LwS9nL` zo4CHMQFzSr+-R7o^nkDAD{IbpxXo5;&G=B7{~atJvv+>NNc_+gVC`it(?L zZ{~Pw{iC7O0f&$|^>R~qsBgv)c-+*>H|XD8^zZxi@22=&dSFhsLB3hpmOtMmRybTv za}LbZ*~QuY=9E(WnLQ}G_nhaV?X(_qN|l{9#M*-5EeFjm^;5!g0s1@dQVulGJG@QICgG!o99szh1Drpt9h=sloVp zU)k)u?2}ioU%x*6(nw!vhyPx`K1T~aXHfRUIrA=(X0Q87*Ih<>H^-a}V-Orl|MZo< zh=l1MMSXOc|Jkhr^Od{}wHF*{tOfJ++<)o`g7B#*UVh>1RG7+>zcCHUwVM7G`lN}tlJ=@8AHt&fRvQd1CyE{`BZO!vU%fk95w1V zb;|1SWT;;My2zNmD;jN_>Oulgnd!S+gmY>zHBbUz^m;GGuFK6CoIm}F*H;ol{&&Ug zE4={iS<9w`60HxP3}wnc{(?-<^Qq6QQ%{D{G3_%Sot3n>B2QYu$)Ullixr+68kRH; zwWhzn7YiqRx*35>+*gugou3?P>U-`_v@u_s1ruz5)$FNI181|}tbtF3`b3XHSf73J zPh6!+XPVC52TqL_yg7UTt7A3x@}6RRgzZYDbF>Oebg~;I+eb!?9>C+%Tq%2hWwXI zL#k*5_nq_pNeD@yWHr3`Q~*h(yEj8%hp%|oyv{LgKK9+b|J279kX-q$o&3?f9x-k9 z_-@{J>UAX7jP}%Q%Rdzn>?^Cu)KGHE34f#S(&O-}*`=Fd0{q50J-c)(exG^;UCl1c zzTPhrGL!gTls?t+g7x^+P$+*I3F1Q2H99M4j%>&;ahQHN$~S*01~&bD3S|7OAE=$~^zLp-`{Scsqa(&M9$+Sv?$qH=De6sP;{UP!qw8Y%Ru0xlx3e|5aW zIjRULd84QdSnrEbW(ZcmsDdYTJJI27xZrbMN1sv6=j(=|imB;#`A8`&rxaII{hml^ zgR73Hc5hQkbkxxfc%(|KN3PiJ)kqRk>4H%_PaY*=kj})rZBa=q#wjHiqeCbu8sN8^ z+FMwFtlw_J`Bahh>da8QXw(!5cUxO#hO)CBYk?a07%K#DrbE=2FU!%WlfDos3x>jX zJYkE?LM-jt8NU-)0g`Zep%SqKdlC(dR_D;AC&@si=zPhOY@lD=gtKo?T>}HES_0NH zFj-B5l07K~rm9;T1Ew07ss6@oZBIIDWp|vd6v>fcvUAlkn8}lAV4i9V{d*d)+hIjq z6slBf|Ey42(-km;C&b85cu1x0>k631oO&po6uoQa$!BB_yt$@6wNhu};>SZ`bY%8P zY;W~sYrr0?nXWTP-G;MCPfr7fsOgm3%fMmkX@WNyI6^HX*qe3Jbw?`t1em9-B& zCHnRBV^3<4M}yE3)6cUh6k7%>DbE%fiZ3M-Y46#ia`^72F>f8AE4X}Jt#h+O18~w+ z{B$U{Ll3y5%6%Dmb^PAUI`A|f?H2MjoU4mFe23s&-o{zTfEj)FcLQqPOrvNYNJE|u zWrvr*CvXkc5~=!WxGSG$RVHUKAy<`5!ToQ3-8iiHra zp3om^6pN9YD&}CKq=`gK<8(0}ZDxpu7-FUgRUg+@;xX7HDCo0rA<^XqY<(2JLC`#*Kh!9mLUT>UY@{?3UewALCm?8n zxC|XM7w@6V7J~Mm6^fr=v6kXHlx!t3&`#^H_^CU#K8jD#eH*b7f7=QVl+#Y!f?3&K zypP{Ei1*Na2a$+Tb`*;sM5RN#(1x}?3TF@6`Y0MA&TWJ8dma^Y@HwrYyMZZRYbtq8HMn2gl|hKm-r!e?T{GYB+NJklA?CkDavN;JU$ zykb8F5Gzj9BU@d;U%&9e2oNv+gTHk|6`VRC_Tz7YD1`ipA{#+BN&JMqlEoH? zSXVr(ZM8l(j7tX59?Uke6-}XureY&h*-X6J z8UB|qir^mwqDKrFYcrZ?A-;qtg(3-6?I6lgzN6TLXaifV>Y{B$ulT}Noe?3nIYc@f1>01`575vKhgc7F zec})+V4|H4u?QmVa)=|CIJ+HU8`Qc7FFZl$Pq79_+NLVn!nr<=}HyCK*?hagg@uNL(IeB2ZvabMB7xwhybqp5E0PtF^4E?OxsiieOvV> zhj<(IKJE}d!InQe#7EG@FAgya(w}gMuJEsu4)LY^p+@lzIy~(VXJG0xD1-WE9ik)R z?yvB4^z@rUOv5z&-681R^J<6K43|0Q5S1{Pd;uP$v<6|~RiZ-;mghwE5=F~TWK&{pcH zOeDgT)0k+CX)v9M>99cw6ZVH1#V{yu1{0If%1kEctBV`3=WWFZsuNaz_RvfvlkrYepj728zBv|Px6 zqk>kZC)L?>)h6<@%IuuWCamuIj|Ra}M>Vwe!|#K7{eHO;rqY;mQCwb7GsS*a`(>o2nQHH^DYlF(3BAHdWCS zn!+|!k=otzMy*MYX(9A(RME-$bYUnX{5h&&)2TS^)|*bnUoZ(aor)U!qC`+Du&%e zdI-D0i>G&?3fcsTU8tfQ4PqCnI0F~LE>tlppETqa=5vhVOpe}!DsDta*n}#U!}YKU zRWOvtCRFhbycnBM#c9lCY(f=Djr1l|@d@G%Hld11PQ3|LybJ+f%|-&fRj?e#P8czE zp^6bu`AQsTb#u@zRB?|r=UG^4JF>CYR18C)#9mWDn_98gR9p$_y{6&|I12WfifPb1 z_L_>@(GT{TiXc1|drid&IL<~KOA&{#*HruoMNY->C3J_qrebkV7y`#SG?{Tc3c0b> zR7`+@u+=myHbLVvkuVz#Pnjab_)cU}A&BIk_L?UB09SPRA7wvyv6wyxdxXW$7#m^_ zjLpRTuz*wKp<6DNLOCwc4ZiAjByEkQdi$6kM?s%}9V3z;G~R!Mb4H6_A%I_mV_}C( zu@UZ&??`HkFy``q&-zl8BPhVcaOlA)uIYw9gALr`4#*?K1c)6a=#89ck=Ou>x+CdL z0GIz4_BhoR&?^%Uw4&PdtO{2VB$jv``V@|&HZZfxkIyk~rot28H4bqICTF4;4Le2O zHdN&~#348}CbJMfVuVrRNw^bqaXM*mHImIF9gyWnbib}bi zsThfP;|40V3}>4alK2%q;(3U^W zIRuU15s6BJ+5Pbby3|N??yqBDw0bxiFrX{aUQ_OJJ%j+3tQ$1bo?aXZ_5Ot<_<^s2BjF~xqHiwxk8)d} zfLe!n;IA?;S#5zv{l^SURg0li|1Sn+s-ugoP@eyDc#;2%Ni0+&toBx@Nzq*}wf`E| zcls~FQx5r+>olZSx___!O&S=KjdETW5#N$HW!5q)l*S&hKExp-4L*WQTewcj3x)mz zi&Z=8zbF(w4=eqX+D}FG(ooi+1_!Cd@TPxqho~pu_<;84hpCgWCZJyz9-&%5P{39i z-ml(D*`WN zstaklCcm6124DOKuV8AA_4^V8mXS>(k~c6#d(i$Vwuz}DcCR+m#%8AW+d>k<2sU>y z^@x#Di?N+4cS~LWPK|dl^(U49v`2%YEu-qO$nyBu;=JcWQ^I6Gf2?aCd?qCx-nD`I zlU&C$Va@ZH%l=gTo2g8M${m1N|zO3|DMmK+Pq? z_1Bi7k1eV<5mfvGOm?aojG6Br=GuvPiVdXdY3t1w;4s$^-29K2Liy@CrnLW2S2xUd z>=acmT4zuwOxyGQOH83oioP-6f8M}i)dh3KU+$u-6YL08mk=8Kt4wZhHJe;wwSoOq z5e;yyfrC^f+4yw>hp4x)M)=<_aF}|m2VjLO*>;!_N|9-|xF{}QN2rRoUU?DH-At8s zn@VHU5Sq;U3>>dMLg4WqGH{}Li#j}Jns`z@&2AY5`4TkHK*2Pso_cU^w+b3R_--;nZ~y#{B_<;naF2rnqgV ztz>F(L*%EqN9u9F$%#7OpYDEFJNa?uR2{6~OOWGMa_*Lt;mAO}GJlE+| zMb>V}QE+<;q?em|OPuN=`RQv0FLkO7SfuS8XNL>=5}5-vFvJs0v17Y*yvaIQKP zk!boyn*1qT=?_Sc5#`zoO1P?v<=Q{X;DjTPI!z~H%D(dXU$FA54Nw7pZ&OQil+ z#cZw4C1I{cQ;2@eR9MQ@jkNMq8eGop6=9dbE4aNPd?9E>pzWRNDRQ^3P5v&fF45X| z#NfSL(U))h#|_@cm7>-6w87znTrD7ps!hTnu13-t^QXawxoS!N>5Z~YQpHsk2^cW= zI9EBeey13GlB=h?05>rBELRh0-UJP<=BhPK=X@Jm$IEfMx*wJRe>YR&Dp$)Wq6{{8 zic77h9)}rR;!>~CdOOnKSuW)zPakdYT$egRGiaQ_WiB<5oMvK_J+l|NRAUN%Gfe&x zS6JOo5$G9{u+*jEDdInGaJfsBlTp_gyuzhkr}gn|gV(rJ33=hW2Cs9e*15pjq7G>z zZ*ZxX$wqq&-sDpKdjTJavYlvi*riTV?E20$u+^m&k=GnExYDJ*qf?5L25)z%$H`{D zM|m(;=_7_JOflt8lfT!cdXv|>qV1Tm&!wi4z@BK^h6i0L23HdPc!R@-T&jphT-PKV zcBx#N<(URoxztLUM~w_V?o#JyQ7AC@q)Y7}le97TtV?yE^2O1EwSd(w^#MhZ-qE%R zF1l0(1=qoLdF<(RslH@_VWxqrF13+tbdSMP+^SP|;86ybxYc5scVi8nm`A;yHsCxz)2I@Jkxgo?f?lo7{AzDX`S7-lS!&2A8{4C9O*9O#TYD z3d6YmjRvoAs~b82Z!vhCTaCof{T~^;!L8CL^6ZYbBiSam`khYI_EEldet9Ud|8<&n zKbZ2BZnc7(`sZl6vZ9X`sxq3#XAR!vR=vsRE*QMmtsW%#ubBG#+^W8H+lo-L@V_XY zCB~T9>sGXp&7WrQakq*m&&oFVq+3HNzDzecB?Bij5aa$FfO`PKN7pM z$-m@Qk__F`;Hz#cYGo)cE}3*U%p{fwRcHlQBKQxX6=|GFE)!~G2Jj?<7YX$eg{rW@ zON5%-1$d^xONGj&&^h1Wa-numWLaeJ3Za@)doLKgMyO13@?{3E6V^`17H&i*U+Ycc zCJ50UcvH-sI>2uh>OFF__f3AKP^F~jPmBV#3;W#nb5nkoP(M?+{MwY?C+u_O?+rdE zltokhM^pZgux?!yifeEzh{S5s=t-e^Qm20zd{(GGK+L}?)HFOQ4(atIT{dHN66$k` zjP)g56XV<=N^K#Hjeb zQ|+fXGDzCqvM5S@MRDT}gO^0btNkRvebP4n(kS(W)pK>xMPBqI=95io=~3DVn`1ztNewsxHmMBcLZJqhBpg+w+L05fA8TCD+D7r++u$H|R z8tvEP-CR3fD{XBk)vqrYK9lwZgMw~)t_|g7y-thXdD#{Xf#K4=XuoF0n`vvq>cejv z!Qv|}uMNer*000yqDb+Np-OZ)dS;H)q4@2pTQLuZw9$^b70)5r;k*Kc#5IC%IGn?* z4(mdVo!5I=53UO}b6#$4EnOFC==`g-wQXH!1oK$g>qCXXZHN*jaa&JgGW!O@2jbqR zcPKD2UlpcD+y|6F57K_Lrmn}XhHX~)`cP8$m6*SA`*&fjqLRB|vA6@LG;;ZRpnlw! ze$<9>ebH{9gEmsWwItqGHuC!xTYs+)1qU~TKH|RZqAO(jdUpakGESrH_*Sd4;|gtta0Iwf6r4lgFLCghWgV=4)nc zdn431V>)$FZKob*zAqqn+&LRwWxkN*eG|_|>1E%zKkU@QPTx~#BkoTdUUd5CR449| z4d-$noodBhw&4oyqcg3zD>mH9eRQ4`_g@ zs`<#E`h^24)&Z*`PTpN=Qa9jagRwrphl_-`?3#SH`iUgVugQ0-qshR{*&w^VP`A)P zIjD?oV5z#I zVq7=2!LIL7by@@WVwD<~dsMcya6_nBe_}F?>&N!#Ph;TzHQ1~Er2K(3*r%!} ze^3pMQ(t2hjl0!!yRVM&T5)e-)tg1O9m@Q;p-0~sRQD1dX7J$zb)BRg&hoTNR3)g} zu-M1l$r5$>;|c2P2EcbS2W$kFNmOO6fbU`5b^feG^?DreNQ37ls=DOS53q4MAKw^M z-%*F7Ov0i>)wu=mgUr$emL#fvxIYj#n(fqhX`=d`8hDufs&RRuibq(AdxQm0jc2V$ zRLyDJV_Ck&YZBFKh~RPK3|^P0Mv;BTv+g<{-xyRcQo^IAz@|j?Id%A$!J8A+xI*Ab z>>gcVYoeN41pGJ)Yh0PAZpA5V+!F?GPgEDlVJ5ScI)7K9N{RuV%64kJH&M~PpSWo( z2F>y;d}B~uCKZ;jb~@o;qS}v=aWmN68Xrnj&yxvevgsNhPE=Fj0&%n1YZ_N2stXp| zh;xLiG!f>rl$O-)*+g{=%X6H?+G|{$sHTtutYlp@zKCu}F>kS_G`O=Shqlil17*v7;KB@Of;M+Gz>H`v} zn$g{9{f$AjnL0SfN_9eYlBy!j|G{3@_+pZJE))0?+o|!TBsHBze1(0c@zo@?nP%QK zb^{I=VX{i<3e27MfXb59k;O)t37R}B$gLfsX0-Wo|#T&dgS+ysXCpx=ojqFQS{Yl^? zgUjlwD$1|t9Eg1VjX_mTHc4^L(iNuEQ$(d2m*rfqaY;S(DMhJ}^Baw4)l+-PBu$)l zRGV8*y+@O&X$?+QOHeSbpa!R_$uv2e*WgT*1@DY&;Y6@(L^f-n{vt0gqy*q44O9sO zZtXmxJ6zE~HLd9UPH0ke|C3l_{LWUlV?e${IDoTt%{u-DbXbF2J_p)!wi)8ESLZh% zuCv%i_~sxr;_Q}yHew&KJRgSYhR?ty;`8kSu6Wvb9$#SJ?T+?6iO5ugly6qkTIBap z!|^TbdiYS_Bk;8N!h6xM^8-YKI%$XTGm(C>*h%o(I9#Fl9>Mw;2-!V5eDnw;(3sAh=p=^j zF9!1LylCGiiz`DZKDs#=XlADcd_AoY62lvDY7uB|CuaLrLkWQvb|bmI!a6{Oc3z(E zMMRB2OB?0;=+0!Im5mC0bRRO%+D1jbd?+YTWTW=Jmtp9Du|p?^lSU9|n++YLzhHk6 zFwpU-b{Niy8`Au%mk+vG{3SB;cbj0tUK~mf%0kcQ14t zxY34-nC}{5SfINNmondvh>3w7HeA7c+p+cpdfIRu^F4)l5$N>-8m4ztd`m-sH&N&G zML^%b5uF0Phtzx#(ATmfaG$lhG|s9Hk{o?)IM?YLM{V6~!%a?KlC|X{Y$@-8=@l4Y zH@SrS`dBBB8uw%|Qg5+SaW?gv-%9v6G_-XYI?PQ-y#;pHE}oEPd!j=-bwWB-AS*YA z@e(p@6zw};t^PO^41b1N30ZbxvTrbKk&tbpRNoHDYq(lh&vZDcpM;!GF_84D(EiCF z-?5<|`W!`b@RI<%kWBG3D)C)4eQp)CDB4HQ4ft+5Px;C)oG{;GL%)w6YVc2O6!48g z2;_S|LHl?r;j51T$v?C6Qhn1AZ20Fk%JhvT&F;5Rwy!%*+xP(+<@)HY5&or(@_ZdI z`S@4%bm$Ops$j$f3vffFyDThebqqBhx63*?{;oE^LdH@t8IwsaU71p&)IMd z^KEPac;1GXEuWLj25w-!ZyN(%uyZka=)t7o7j3+m`DR*o?!e=jwg}GruQ9jcFFpzA ziwWY#B^&NyzBkD_SL`}_nXe2dPW-<%+{b)>Az1ROkLtPy@$dwW$?XK&4Mf zqYcLGh{Qx>#2P%;qt+wvrSpJE*yU4;^HCs?jnWO41k|4$t-7Ct(!;CB)^(ZC4VMMf z-82vCu^GDD(tzrYsm)Uu(KO?{CZM{}$Wz&3oxd)iR+2lWu~iyx4yZFU=5%x3Qx#B& zxS0G0A4mJ7<_t#bm;NT8Donz!Op|anpr#>e@%jc=2h?e@X#+;lfW8T+5;N$B!IuK+ zD7kz#`$P+HHK6`30&d9mYCI)D4MW%iS*Wepxd|$l$~Q9g%LXQ>Q>40}DX=I(KlbGz zQ(#GgdWm`lf2ZL1yg5NX&*v?T7+Vt*F;wtY23IDihq27@)~sAR`}PD?N#iIocvpfV+DqPs z*-tp|NkCN!7vOD81N#ybeG-tjGx%VF`im6P-e6oz(b~#yFc=q8`?0`*kkVFMRf6hb zP23gA=scSIw6jS*o1g|!sO-Y}X@gcLsM~Q4!n>M$Tw^sSe51j*##&$<+7)V6Kno^F z(CpT?7b#jYd2fSv6{#B#=XoENPcuAgZ;{$-741gv4RNl)`A}oti9oQk^0P9vOCm_^|p55a90k=e!D5Xrj1%hA#A8Ay{?VAa0Bo# zc3#)s+D2uNN{6#|`r(juxQ$vyGx`n|i&20zrj33q&F?gWxY$N5w1(^nH7)pxTzCv? zuIE@~Ta}RyJeGCR)%LYj?NWiq8CR%ot2|c49!$-BIAP$Anb!7p)K6sj;|A~Rs0Py1 ze9GX19o4NQT@60eQT;^q!zTZ5N41hhGsWPlj(P_JpUUjV8OJ-S=gH$1v2j`~d=gOI zigN<~oJp9{NsS>>E;g}ZNhh_KV$>4jaw|Hi*4B(q;raAfgule5>2}t1QCDe#ygPVZ+{m$}SU>jx%`1vSi|dNjQJmKCR}J1!tcs|cRP*5G}`DwpiHo;{-n zbg)?6K*4YWdt2j+#i}z+#kUN`CjnJ6@{5g(R(IUbEmmVFsBSWNN;lP>M(`hYQ0JF) zQ>SUf6^uSD`2T2o6X+<4wrzO2XQs2zqyr2gVFC#RLYSl>3rip@fv|)nJNu%nvhS;c zP6QNCR1mNcQKF!rqM{%H1RvZG0Tl%m5fvYmMR^ny6=m_euIiekKhO95=Rg1Rzd2{p z_jOlwt#{p3-Ccb(KMAP6MyI@6;@v&;skHJv67TD&Z>QbvmH0ruK9UvOFAIQA0_t-( zY+hFq6daNc_0k*B3;#>`PGoqjmv|`denaf>cPE|brKej1-p4~@K09|Glr4L{mp+Ux z;a!O@_R>EgKBOEF%fL&$#3Oz85gERrKs?fSACUWHj^G`BbMWJr7{Ff!(T&N$WYyL&zt%dqpdfs0p-d3o8><7Lg@%BR9 zWc=SG-dU)JM*#mW@$N!>1{WiLNW8Bws6WL9xGEI~3iV&=0bi5&?LwWO+;d--_)wwP z5aYff@zFwkJu7fiu@_Ru3iUxu?{A4u7V3H|uuEMmM(CMBeHiUkk@(+1)Q|?MO2v1D z`UD!VTjH~YdIOFakJzk+S-(*4#u4U~_+p`c7ZcPZzEr5sst+6{@s&b-0V@zL@zp}z z&jLqC9K2qrCo;oGsVFbfqd1gmNW7#-U&}7jC0@$0N9_Ftiy;&5n zPZr={T@z}4JE!>q&G?dPLTL|k-mwBoG5X5v7XPxO(Thy6zi#U1dSzLR;-`k z`AHJ5DAxH+Kz9>~R~D=KX)F0-l!Kd7+|8u^?PC4iR=_C|A1c;Yv)`Lbe6&~}OiK<( ze5_c1h&WZ^6UF*|+CiGcCyVt1eSlj^e7aa)%T`X8_)Kway8!<;$wjNDNeSFWrQneDf*Tr zYAex!S4;JJR{u{i*+wwmW$OJxy}eAYlL`Ewx=rAnW%^nAxRny`F4OyQOg}8~zA}9! z6IqCvYjE4HTcU184!yKQ`L#!m z8(W3?8r;eo3M)3alh<7)H}V?X$Que9WN;s^yUf0wG|b>OUU!+?#cO2obryG-+{J6W zl1?;36lSu)t%L3|Zf?QX`3&yi4JA6;;0|7QncTo@a09O$hWogR(TodBQEq;m&*1jm z5X6lK?%oZ-&2GgwY+XHxy9M068&cyI12^x6AZ{^m@2*>XMG#DJxV0gQ7TURMaOZ9) zGVU~R_#D(_EyTW6vW>em2N8aEOw_x2t8&-J4{aJVUAZy^MK)n_pFrh{E^~*Mo zQ8ycKvF*^ddyFqwk0ou{P)R#IMtf_+sX$2yt<-%l?YZG>6l;*;exPzd=>Fe>(_pAH z*p>9)4>4EXbM(+;Rx%nNdcRJ?TVO5wn>BgPmKovHc zZLAN{{GYVpeEYuNQ#M*?Y@p-cL?mvob)X?_w&4=kCJXSi4RM35HGA$E8{!6AJm>Q* zHe9I~16hWxHe7=z?s0(65{hs08An*)=j>pZ{p#j`&)X1YzusDKny)7Jg!Uy{yHz#5 zY^M!(t42;;z+JzhU${lp$f*IL(uN0A zqlo>qJ7OS1-&T#U=!5n|G!yucYD}it?M)Q$sA?SG7C;pdA|x& zC`v=?nXd!CMDdQX`)PF~ijnwx9qXAhf!<1lb@@!7zLIL`-+;Sghn4gJ=Bg0x%&{@D;Lj!PKoM4;$^2eAa)YEo$&6QU%ZnX^iLQh$V6apnk zZ;+NjuNFwg6r*KWZitTrDDo|DSE^EgRj9JSP6G;fBJuYg&QIfwa%F)SD63rNESGX8 zOAZsqYpBm#)BYVuN!EC|8wfNh>t2KW_4d63*diy$+-MLIGwN0D{x!MRN7Yrhb`%F|;Qh8`eqw1K^;#|Ku*S?rzp!s>Z8V5VJz4Ju^{ z_W^_GsplcgC(7+geiR0svO%2zw~{|P4e~zqm)cgvS+LK{uqK@g^sChe&PdrP77cvv z*?zut>|7uPoI!t{3$#f6G7I+bG+&xml-|Q(P?68rAdGX>HWWI%0>a;}-tSnY=fMIs zGXXCs$Dc+3SfF0Vq4zAbS-rkL*_sVFgmLH6O$dEleK+7__a~}8O2q$_p-i|Lut?Yt z{}oqn4F!p9*2<1o3kMOeC=@SI#tZg7f`*Sx9cD*t7m7F|6w&YMO$&_8xXX?)5{KUZ z*IM>|2SyN+{hS?_h3{=waG$MlRPY0#86C|?p=$9%gJ=d;OIF}lTf+*-l6psrI4r3w zSv_0Bk`-9F2tB1nz)8rj7rF{7FJB0B@p|g3V-&01&w)f`r8VT|KudhlVNm7zp97f+ z1nd1vfrakJ+;b`mF9-I5v!OEVN}!8U+4r}=Q7yQg(}Zhwg+gHmeyVG>kH?+19L?ja zwyg8G%a+4=sU3xBl!l730@*)~pVu|#;zzEH;zaB18-aGdP#Rv>bXQjL zMkaHMRqJM;yVr&MJ=V~hfs|GhHT;kw4>j;ZN-ixaHk3iH2)qr7pWC%6e%t{JX5!K--JJ$@rGGek!*6@K;0c?z+ea!DxV9F%zge&`2&s2~?V_M-fI z2p;Aa{1n%~?wB2i;|K8~4!_!BC}NN?PvWP#(l_#GpHXUIAD`JK>(()2 zM^76wcBTk=0S;3}8f`^)m^a2Mp4W1XRivgySH65`(M+ZCq&u~RYURtyxD}cB=flVe06J|04}x6YFBToER(N>gM|^kIio0NwJ1*n>X2dDY4g(%IMV8 zX<__SYi(sl+F_<^AvLY+>mjCU0t(7-grH+rVI`zxxQu$J+)RI_btfdT0ZKaM6 zw?1mswN7R4fvJZTwQh`c^L0<-h}|&G6inxht&tz#R>UA{n+ z#$)A>KH9qZf!a9Yj9YOX$mB`>ZS+kR@^HM0^;QXB~JH?~Ga{ z;Z0FGoTbjsv;G>En(UqaIOtlek})IdSm`Cu-+96Q((H)gNNno`n?SJ~A>OSQuw=DA zHM<>w-t+ma|46-QlK0pTY%+dsHsbBecs(8VlVmkIyDGuk>Q5~G*qEy;kKK}*?^ecE z#*Ip~RHctKcG}Q{Mzb{A)c7Cv?^^s1yw;lWm6~9MFB}uCylHh`zBnQHpMOO0N^1=z z5&sXI`VXA>58PMcZb+aO_Qmk?ETKOZY25#gD?c2YnxR=A$M*48Hkq87tyB)3lG;uU zlD;4Uw^?rRh-G3dT!g0;7z=pBJ+-D7@*cRqF+7d|Qwoj|iTFYukA8SSECM1LVPh7L zjlodFV-glEIC{o{RR(48+=ls|$8m7AI7T!9RRVDtSye7X;_NzINjyC1MY?|U_Z;_Ofbyw zI1B3ow2gwbJ?iUH>Qt_up4vV$_%{}V3KC4g@{Y%1d7LSaOXP8tJU$_h+vV|1c|0MH z=j8EEd8~mJWV#LHF_p*JV4_oS40lKVcF^3cgz;i2q*pwPyyNbZG=C0KGYG#%- zqx+O*?(^e4R-aKbGMC=7E4A{TU1@FF1ltV3No}$)vjlLu{7Yw2_*190MqQh>f(Y_A zvKpv=WJ8nOgBsPl5PhQ_!F7t>jEk8N`I}V;O^E#M)msp!1KL;*k-rU(gXTDzQqO#l zUf->T#WU$A@}O!}L5(M@Cc0njGt@)mZ)0$M?VVYMY-;zsgh<+UbQU#)!M)H6u$m2S2(Ch- ztJ&b@;l^onH5=S^jF{+ZHn?mUeRMS&+^KxPYBspDOsbjt?tb)J zbYc}7+&FYdbTu2?SnKppX$@L+=d@Dg1*_;%S_%&HFQsLsKAsG(Rz>vo3oNNtYMuxEhZ}G=Q0ZEk zMFNEz6Rb}zr8NnjLU)7ctv|HUy%?mUr)uT=;)d~zM~yvoI*>44Tbf3Tt3bcGv}6t( z?KX6{s_n-mf?Hb*>+op35#Ot|#buJFY0!sh4@Y9*q?JLA&_-ut0ZBEu!*trawx|dE zSWWFRT0ctb4U;ys`!TGdwHOSXT3Qawptk0Li>af1GXnb^wcQx3b+!M%0AjRv@V}mR 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

BJw<3Gdmm7ido(&@USCnY%nQuT~ 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 Qk&Ta{+1NGskp;USx%n&%B*o@m8yf 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%0AR_*UK-7wvN})?4A>B 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�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

c#F$!yy>< zh>=Q*vA3nc*ay;J?9b9*>}zQ-_M`1b&oMjVHr}Ceo#*cZv>5j_8jQPm1`NjCng-(@K!b5lr@^>a!^rH0 zlHD=i4duptkp|AP1ABJ%!ZsQrcC-eNhjTYlB-WUes?ni@hkEX%67t&zd z@56B8K1PFa--Mxmtp~;W@TYEkMi*Q-yMIF3EE>c6mC{X+r*#vY6rRKDUw2a9vm#7> zg2|a<5RCVB*G~8LVjjJCzQT8t%nmW`yN~Ozryj=svmR-$wD4|`I>h8ZUU5Gi&><%O z(*f?SN(Z+A_;5hxQk0+V-cfdr`5?@jsBWDGIor?mjE$sa;t34yW4gGRZ$fo+Khx#u zGEJd}mPISN##{{H89((I>U-V%FH%2J4Z54FZ$M{mMs1z&d8GSYSHEVcfOkp{xNDNd_eq?Yt=z2qg&*vY~~#}kR`Z(jPn)OJAvN0aCUP4Qpr-+xswMn z=vQ5N+LdVOGFNtN;l*hrmc&!hzUBdb3@sXCc0;7Iu!(I#`eNsm3q6yYx_??T>K?^U zez-%wSwnB9yM3`)siAatCgjT^_?XDw7kXBWWVG}d**p0_VvBNi?ik|3Zcm1h>~-5V zH~C5E%*~7k&EMs^7Qp2W>uy(Whr~KFGq6#-_Bm|Re0XYAh}S(4(-yZEyIPq>nL5Z9 zF--i@dj-5VUHTw=rkS`2c(@%Nf>;?pdmcVtc{o@Tc{*Re%k%$PgUU;7{r@a4-Sga4 zUi;X5SG3wMJ&!*SEzu$SRG`4Qf;g8N^HxNn)w*WSHlru+&7L2dvKQ0dGUlaPb?;e1 z`w(7u+)P|d;sK)~&V+DwnM%h>{Wl}+w9;Pc5*n!p7G{K(7UtFB= zq%qt~ofohwEMd7v@uF{(;rTfK`7b|zyn*+#c|fcVU_)FdkD&8=d=m3lyj6VF%GAco&2~SG z$#~&c>fQpj=lf|GIQQ{z_6`3n!y0BB1sDg$E5%%rAI)8^{Fv@?eb*ZGGqk&W`2pVL z$`A7{SAMW}x$;B4%atGaU9KI7mJ!QUf{o1&{H|>GI}65US2ypE?iib0w5D@vWp=x0 z)~f8fW_0T6?A^9Cd4geNJrivg%|7YR7v;BPw~Q}$d@?&NmnbmBH4~@d%R6|%d*Afv z>`${_j4N_#8T)zOgb0mh%bD0cTK%i+^JZr90!&-HVvXU(yrmJ$D#yW}A;9auo`Nso z1{tsadZsPH`-qF20td2dWDcJT8!vo0k61R(t?TA^8XNG!G9pU8AU}=jc)?%Y8FwJN zwpr4N9>{K-+89;j;Dv&S!Ked`zB!)81iWy-glN%&*~NqP|K9@Q+~B{ai}4X|ypa6` zV6kgK{p{Q94yHLUTJ~7>yTODStMGmlUa05#c;~B=*(Y7sxYcq+*PqIs zoMJumJ-%%5eKga``PEGDgqvaIxM;Q5oV7)wKbFp^SvH#5B2jint2j|55 ztunpvM8B8w?690p=1}M4u$(F#jy_eU2_Gv;h98SKV_j2!V6gj08i)p-+*y3 z8aF(rp6Qf+JSR4K@8dbYnZ5!2oL5HX6pudsM9%nxgfn6MMY8+clD3bJUYd~8Hm>Mr z%kV_Wm}iq&%UN)4*79imnK>T??0o}F?z;Hc&Qdd)FgGVA-u&E2{!h+N(L#%J>iV7R zB{`>}ZI zTrH8)Ig3r_(oZ?Dh0xna#z*Fu#v;62;bi@s^HlVUpL3QKv}XOsG@{F*gRbTD^hFQ+ znUfxLirvZ?99@1Z=P@fk)fdP;?@Qp9S!3K)hqI3JxRqPX`NPUxRiNHd)|nT4HTrT) zZhJGn{wsLz5-%)_==ZU?p@7pOA-7_3@w=PAYTw1nZBO?%@pk5$&S2y!R%)G`G|JQ_6$ouZKu>VopH?bIu(fhtMoay)G zz7V-}9iMc8AH9LefDc_!R7IwMF&c_iTfFWhQ}As_FWFo7xTpJ{Qt)Z5yGnuj-%{YX zQ%cYn4e1o_mfIpZzj-mn=&PAl%0)kOwMJcXID@<8rlc~LH*zixVbA3jZN&Q#WF0VQOrOEShCbS7c%LDopDDKgjc$D|w}2V_d~WWc`<;5R9jZjXzmPj4!C6)&wWzbBYX1q*d;ZGp78j~LaM+MX zYX56wZC3H7JEW*;;zYZ+sJUdiSbQp+M`)G58y}Eavegoyz&2{Lb%0w!{^6PGseUV#a>wH?Fqy zIf+X<6?NAd?Yk) zf`n43mXYiovA;!L$iEl~&mqCrB-M#)nODgw^@L?y>+Ynt%&XuJePTI%wxassEs?be z)NhONj^0A3VCE;5F~RvQwN7DYJ9NU@D=|h0V}m<9qm*-UYh0<|2m36efn#oqOG&u; zHFD$AdgYM%lT&vaQb(R*+fTmLs&KS#tGx4xW*w(f&%8Efx-+k5UNv7vLuYHxyz0(_ zowAENw|nLli%HKg28Gjf#fsc%FRq=*tbu)}nLk9MF;*p0&^c%>8 zS`8bdJ4wan756ttukXyx&MS_Rzsk-l=1*%>-`SR(SKVyjoX^f{hGD3hlULuY?>v~3 zSJl@bgSmM?Z=|=xSBOd8Dk_{{4Ps>PmYUbwE@YVH-t&~x}K^lJWe8`}YJTN1zeqCcU za?`4B41DN`fwa=pga&Ep(YJH+?i(0+VI;0Sn&E@;WIEnfB3t4akNg|OZQ{pD-!FYg z`ndEN@v?YB^o{cBi5H7_j2NY8pu$uo)D+Xj=3;xXyV#q=w0Kw?BL8SHB2E|QiHpSL zE^&>$R*sG0HgT7@Upy)vCsFY!@q+wU#ap5^+KV_*EFqQ`tC10OeSJAH#TF!bq@#3C zvK5}akc?Oyp!6rj$>NJ7@-G+P5%-Em#WP@p8L!FVf6_a!D2a+nl4wX35)G{@HWpin zoy8onxA>?yTpUHByz$c0p2S&+1<#Gn_$aUPph$(=UPaYOG@v$#0~*WUO6)G)FZL4$ zi=)Kx;xuut_>#Cxe1mL>M*!>O;9p2*!*+;!#e?Ga;?LqG@wym`Qz9E)lteixVomw8 zNCeng8lNXZz6joEa}C3ISp1hbQhZvRDn2JJ6kiwL7B`cq=mQcB+AaTA;c;zn_s zxJ&$oM0w|=eFQAw;VW{54sj$%)-m-vV{lthIiNHk=; z{L{p_;!EN(AMO#@fHiV#AW^_(5(RuL|32|s@kjBZcuo9AjPZNrhQyL$1+ltVCqe@i zHIk#H*h$P59~1|O!^AP-L~$;O@|H=jAra8q@^6uUrx^KM#$oXX@vQip_?PGpc#+v+ zQL(I8nM8%vNi?LP{8?fLv4_Wq@qirt#UUgLc$`E5eIej~HWd{i6XP7-UJY0*L}Dktm?9{Efx- zVt4U=v7b0t93_qyr-^gLmn^OSSLi@RZzy4%_@1~!+$$awzZZWNFNpzslZyewk|?(b zi2%!pmBiXHTK^exv=BRrJ;h$)BjQl;2@(~Ilb$Uu5LbwAid)2;;^z?=hs7Vnv*K^! zU!p(Oi^LX-ie<%GWIC1|i5_S|qJf>1o-IBoMh3_jCXNv&iqDEKhzm&+_^R}35*58A zzAyjB;y&?^cw9W=F=AYn(7Bj>aVn?y3*h_pw9O@G5 z|4BI}h;u|oTudV3RnqIlEhHNFp}1H6gW~t%&*CNVx@gAXc&`6A8en0uv{+HBB{m>Y zVI#4n{GG&X@j>xn5)B_FJw}{JqMRw9d;XuNghk?Vajm#f+$Qc4_lrlxQ{n~js`xjF z3U7;cJTw9>8n5+VmJVd7K%&L9l%b)RC3X;dh!2SU#UbKoF(OVE=ZOnR)VDaE>mSA{ zC9D^>D8q*&8njpbgW~t%&*CNVx@g)sjzcRJ7E6m2#aa;=4M;Skk=RoHPGYwFVG<4M zFaHp6w3uJsbm@8GB5}F6R*YB zq+56z-xOCuPZB+lrwsk%A1sa%$BWa%x#COWGI5Rgp14EYN1}m8U5)jBMhU+uAyCk3 zNGyqrMM#Wg8L^UBTg(t!h#keAVlVMA@d zeQ|f9*8f*>93|0^%OoniDs6HSJSDxMNAh*!m1qE*Oic%oQBtR&X< z7%>{sKm%GUp@-N@{$V5<@`Q9m>C?q|;v#XmxK`XKZWDKjhg@R)AD8225)HW}9aGrT z_mF5nS?OvdhNQljDYg;2ig{vRagaDdoIvvYKSPdrBpR?%dcE`~BpUFU^dY4m7te^7 z#T%lph}Y0~v4~hktPZ;CKTVEI5)J4eohLpd|40%I86!Pe>9fTJ;u3MC_>TC#__4UJ zh}QqNa{MS>Akh$CQLjRagf2v)$4ZH*Vofn!Y%aDJyNmaW{lvjVwf;xRF^)t9Tq`SLFp*Nai5?;yGUcggX!GJGR_O8SiS@6vxt`${qb+$oWW zun>uRzv3i%GFkrWB=WTryOZd#956!T5hV;2pA;vONS`9UDE}+s8{#`k-$;E5Rh`9#|XlW9Oj73RgtSEmiv7y+4M7}m8^5w|iTYOY}oJ77+ zB=Sv>f6hHx|Bf85D&uR)xKaLX;x6$k5(OS2QQ%MV|0@0|-c)+96!Iakf?`P$$CruF zKmk>iP)}?kwiY{($k#*q0kOY0L>w);<)Xsr((}Yc;`01_Yh`Q{w~4#N{o+yalz2hB zD&7*U(q3e7BpO_dL_^AnRm8d;BSvF6T8W*-9I?0fs5o4FN_0rf{#D{e@gwmI@mmsI zeq207a{XU*4SZXHL_vWvOu)q^30*?0ET)THN#uJ_94tPr^l{S9NiULKBE6dA`hQ!F z_m$y8={?e4N`EW;BZ)}Pkm%w+ZXt2}hf4pltk(Y#WjLh_KP$r@^4}I?%b@`D zSRoPx6(iA*O7hnhGsKo8^0g(AuZR2(i2ch&kbnY*$T5OM#<9|q#o6Klaf!H6d`Em= z{8-#49ukj>XT-}988<{Niz6@MUZSNd6{UlWb;$cLUSKq7wviH4Suzmms@QAZill%cgUbP@BE z{(#aSm4CSSB#DMC7q^Rh#h=6m6})_7#b;e&{Xb6wEnFZjBGK}7ZU)R&@kja3O5c_) znBwIxBUT{MpqkS4q?<~&lrLwiF~h-$hT4c zZQ?F*A3pr-W;i6raq%390)7#1$!}GJACcN53NA{btCQugC|yUo5s7k|lE~jh{#>z7 z#Rw8m;6OQsDC219vC@;J=aMLJzPLjEH^oijhvH5W`FD$7$$w1xM1%%fc3BD6r2moj zSMmyo5kn*zTv9A6e+99+{7t1>kc?dZ9?}m;NBYu03;T;hlrUNxD}O|sF26&f;H4yn zV2%9iq_;@#BvJlu68VqFf6`;bI4{Rl5*e?P$QY;$BGLr0m{^8HdLDQFLO8)oc-zL3FdLN1M_KQd5KP8?a zBgk+;8Lle9s^T3ON220;Nc2QG=_=ASNgQ8SY%G5(u|0|7yG!>Yk^fQop8(zUKTa8@ zh;zgjNEEPGdWH0xB)WdH{9C1WOMgY8qC+H(|4IJy(pRLfSK<0c#+!72!Kxr4EhrWy z;V&*G%U@4AokRsKk5O*)6f@%M=j%l|KNcvY@{WEiOoPb*;-iGt^mh;*_1tHpOo z92X^#Z*lv8UKed_){7J}FKR zXNZyKW&B56K_ar1BwD;d{;lGt;+NtP@uYZOydvHdgVnu23yQ@(MvQVaP*D{UU0q)p z8j)y7Q?aemyDR+x`TLMKewh4Y#EIgw;&UYOEtGzl#IGk9uet`lPpE|T(woE&Ni=Ma z()W`n=#cy;yKcNPQp)N#1mm+!oPo{y4sbWnM{&ca4{LRJo^4~Ar zn?!++$v;ebjP%na%AY7cEB_0iyZ#p{VX^p{GJHiM^6%w8DgLDNzm*wN?j!w}^!S=w|EORF9k{Z2o>zd}k)9{rSNs==0){C)BL8%8p7FB=tiO|v&Arpu^p=Pr^N;0t8The zt7mvbBstB?Ta`o^HAxIdEBQN%Ps{(D^db`ZUy=VU`J>`a`M;I^iA4T$^55|M_!Za& zNI+xb#Sn=Gl$5R@Ru|L6rea(1UNI~_Bt9lSA&wKLxWpzmM-E3^Dy|aOi(AB<;$adI zeM_Rj=jFd5-V}rBUVsI~;$kw%O|GgO^~8oG3e1x3AodU+5c`WG#IfRJakjWXTq3R% z-vQlC?tM8vB2n=k=>y_%5_`}&@v3-(M1EgGkV7bjNchW0R}yQB8Di6hy2-hh4j+D} zgT#UTlwq(qN*pgv6X%LAiOa+_;yM!Ly(hgx+$$bzsGFSc<+vbT6>o`F1`0xiiDC({ zyjV@FFE%C-P&4sf5)J7qj*x$JM2=@jR4`MVFTO0kF1{^p7C#dAh+mSZ=!o=5@w|9N zyeUTF8hI5L7E6m2#ad!RF-zF>nT;xFPKVxX}XSb|tgEGJfRiS=Jsj>cjuv9p*>qT&H0B701Fw9+Huba9@z zNL((i6*r38NUr~nX`q6AN;o7Q7te^7#ec+@CO8hqhs2U%1+luACN>q@id{kXLr#6^ zKxF+%G-S9kJS9FO&J^d1FN?2>Z;PA7tt86(RQgNthG~iKoTi z#lOWsQ!l`Th>T)lIkAdZS8Ob{BvCQHB+JOc(*2b_L>w*Vmp@&4p13GKeYuRa;yWZN zcwhQsai4fdJT6`ouZjPNG0nUPLt;s>f>_;S#7L7PlSIW`NkrB|y0_9F6^DyYiO+~L z#rfjP;_KoX66J4@-s%$T|5G`>6px5Mi378s#81R8#AD)5pnLxRRgOPJBg<=00kM!+ zN=y~&kccQvY)axvy}i=A%HKnLKincxM3>vUL^8AD*s^l z$4So=7m2G$|1+1I(0yJYts%D{kYNp>s|byP2%KS*oo6 zt->#*&K#E-o^m^J^2^Sw72!yUjR}S^>90WIbH|Wl=8I>m;;H}FiIcx@QeF#B4^G*h zIK8K{^|f%b;$qhJt&T^QDOIZBn_f(v z9Q@D&`TV#kz1UbD}eRUHE>plCyVRxS{!L)c;O+oN2!AOjsXI zH^(~B_2HCyjefsiCr+y&?2#_&+HjPt;z@IA$v zvxQqZLCli3C++fM24tVB=FHp_&TBCSzYgX03w8pxU+^__W5&D?GS8S-#G6y&Dllzw z>MVfM3+8lyIWeVEqTx(4$LSjl*E1JHUx?yKMA@e3hyinFqMP4~MXpKzG#@a-9+Nod z-?wkyK9}sA-W=X&c5oKG7yiSn8=d!l_==e}=A(1|8M9K?Av>d+bTS5N1J&%SRZzr7 zaWfFSmua(?X}GibgYdWIhL?pzo0vK1nJh&EJSO_i*6_2YImXHSFkB5kBJ${m;Y^>e z>^UcCbo-(UqBY{2ogd+IqP3!jKf=J3Df#2=+tr_)h3;tdMdIvusB_7guUk020rEpk9_?g* zg0)yM`oSk`(IltcE)4q7==fdX$^OKJXHe>teU;n;r=M_=_M$`oVAaTXzG!2+{?B&1-}e8NO%#hCJUI5ID3ZE?aOe{CC zE#s~_r*wp8ZuH2P;qEbkynVNCJKYY{DC)HQCcMR*6#eI$aIVkEinoe6+j^w0amvLs zp6I+)V?h~biEUMJE_@gM#%Wp5D(oc8427ICv5k|1J}l03r(5FUA}I}nhQDCr_$I*) zh3U<>OJdV*l!jC%soRR`&gJE^t%|kGx`mU>LS~j_7REF3pi#H5580Zf!N8{h2%qJc z{*)r!nN}JbZ_9Wy$IacUj1CUR-xuWJt=+>>X`8!K@UaQ{@v#tkd*EQ^$Aypc>c4vz z!))$;E3R0iBib4J-)48ZOQJoU+3f$Oc8ODFd`Q^9=V$H|i{{-MZ!#eK84S;0!@8G2 z1L*Z??h)roJVLqCPUoL4^nPP)q^B1kYD1%IO z$GHW?jzv_y1?c^ldUM=@Vpg!|EL=~;q%EZ<5YwOsJlVzIX|kT4*q9}#G}yBhswvp+ zGF(<%2-R3WR;S&nCBm?-w7@~uQJm)eY1aDM$Z9FIzhOBFH()d!^+BI>aiLYl4aBFI3Uyp%IH%Gg&y*->UG&hU5MRm4op;?jm z_I$$t2WQ)r$|JdhWY})NR(F)_WoJ@$lI&}@qU?;nOvhvU+ZWllUDfD;_FrgEd^dBP zTk&8cp-2(v4Fy}Hop${D?1;qlRJgX3@;b#xe3V`Gf!il3fkYFNI)1_B8eM%Y3OH?^ ztyZ~t3ru{w$}2dsa3~?UFyc%sfH6p@ILocWNGyoukx)Ga3783qH_(X*^=i8+HgQCE zXU(&iZ09i9@VCtxz#Xc}v^UZ0geG63h+uzoP9QP!DprcsGli4=D@+i>TEsPL^~Y@R zS$|{X{MJa!&4ASw`GZzg60%rN!yjWUjKw6kcEB!RU9N%oYjKswTZbE<>DG=6{A59b zRSOHWptT=Af|6)$Mw3HU7kHAaW{vUwp0%SZ;kYlDy~ zSQk)GiZvTqQ?2PZxT3Wf|5vhXtlY}hwu;!Atc9s~=x+U555He&9d3==E30!hep=Y- zhq!B6Poub6)_yd-wv~z{Q^)!N4XtavgShKi?a_VpEeoqO%{qo5YhYE!vFX+;D5qh> z+Sd)|Co72kqmi`>jc9D0L^MsTb!bGUwHzJQ)cP6KH?v;HCehp~g#Wi2*2`J=tw6)N zfTMR9*1bMF6h!CmKnnw*X0M~^){W-qYO5sqF`u;yGr(`P&)`@+j{k$!h6sAa zvg#or#`-+O!TMJZ4%RWWC(h#U%g0-NG4vQLgppwFK>!7SW*p;jbXk2A0RFh-%6iTRS zJ&XUVSz~K)th!<}YFJs=duv+7&=a++8R+8L)`kw4e|4-|m>+emws9ORABw1N6~?=0u?v1PNJa3Rs%G&iPgRd$Lb9Fuc_4>4Q*zfK>p?y zfA0`ub-klIR_(E&W2~;=haf*TtOho|4}>MP6Fu~aVLgNH`qZ!@n)PZ-v(XvImx@?q~dWmtZ6%8!Osurq$+ z-LTGd$A?x7YZdz9XTy38tv_Q}Q!u~IV){l*+yxlcP*ivx6+&Gwtov~MMZ@|l86R51 zfvD+M!zu-J$*|JV-phs+z_#_9VKqY7zZ=$eRDZ>=_5)YZU09CS3~RE1AIm_;;#~Qs zVeP4nPeU2j4>(ucFszlBu75$5#r*r*u$rOWH_=}>+1@g&shA1>7}g-*wqbpa2q&1< zQM7QPX;r~cK4V&`SO$|!t4SgJkfv!_=-?@)RREng)wF(xnr2!RP}p?Ss)mU^!?Xr< z!OwJ>)=n&hnWhy3%rdPOF_?d|O=~cw!W`4eMV~xpTC*`~b4@Fu89p&%TJ`*I}top6YT)!l|w_o%NV1{;8tXx0=7l%Q^6kSglS-DEP?6Zx9H3nVBzX$ z4;XnBeLWM#LQLLSU{B1o+2F)BXcJfnt$7aY))=h(GGd;3H_z3~&NE_*t+sBAW?*i}9KTo#-&xgxJo=15O*h^2N|2YoODxg{}p+ zp)216v#{3R0;@O^E{2Oo9>-p>9&%H2d<__!(VZg|w5Fm1CxT_mqUXVVSS*vky%>PW zU{$QKDPSV>RIpO-2V!m=J3e&%=Hh2#q$6C*Y)d5v4{f zBNa;=TNwt|w9?SyKI=7%m*2`pX9TQ!FlmEE@itg|fzW<4gdVY`AgbY3A2iyq9>!#h zwO&I5LRMjPd$M(_C9W@w;u8>JAoQKtl}F4(x@kpgvGk2@xqqR{gVsqb5zC60Xm^Zt z0izOYy^1j@U=)8AT^$JhZ2p^vmq0h0Rxzv>pY;|#|2jt6mlCosW9@`~@OzCcVqe0H37wEEVb{!oJSkb)u7Lpz z{VbVmzl81yo$+sTi%PX03pgRCTIr;7ST&&w%9Uos7 z60!s53!$If7A3eg`>74~uTVnZFC@7QWU%?E$@Xk?H>B6zI=0c(*^WAs$6$utac9|Q zF|F>%*7lV`&Q0WsY`ga^cQ?ChPglmFVZ6tB{O*Io_D!rCl;L$$FMAn-O$dbC%zf?8 z*cAzZbXN|vzsH(@eB2%D!S*l?bwa?qdmC>5j>!%g@mf97o`ih_I@3LPjD4WGE1Bv~ zS!mj4IE%a({V9u0dn^YfUoSQ72Rq-TSD5xDtp7XdD@~jCw$PnXygy~FX_vy8is_HJ z6|6Ju7MR6%4%lGYy}eL-xCd-D?HOM4!><0owEyzj?=^6zX^+SLg5&$R_<6@-Q8h}_)<#P*J?xeP;zPeA#5U{UV&Yh zM!u9}+g(Znlv>4hmr}m0VK>EG4GmLj9lI@S8XahZ6Q~c*21<5;9Iw<2`;j2z3xVpW z-rPH#wdv*)uv zR!e5vZ&ra^BN?^_b%lIOvX?!$J7km+pHNHbYcH-3{eFO35}yXV%vNua9B8*=#XEHH zVEY79Ka(78|A%|Ye#wz`ajwN9l4I=W*^ZMcYMlKpPN$*MZmK_Jf@yD#lz`)m9FtAE zCa29M>FK838t1{#Z-J)RJN+rMO#1|9!4-Ga_*3SZ_DF2Jp=-)N9|hvf5b_6myZNzB zeqv*-pf@eCPL49t7-_7N$i3|3SUIpzzT(0tAdQ96mjT2{W1&2Sl0)&*SSLSnve?pC zC+~AVO_0VqiOGU4B8_$8F8fkJZyjtmBlgSHkfBVlzuRIgoacE!+2DKb!Z~f)eNv&z z1^HmZpK{i;ABcsn6{aa2(aJE{XaB*qG%fg?+ra5QyDhh#xxv?6JG?i;StIDB(hGfdH7=1=(vihJJBwqoF32s(pR&|vzsU$TORwj0XV2qu-VT7ej`{4T+rd%9@`m7q&+ZuqT}t}2&mL0;x`OmspMA3&bXDn#7y<@RNBXkQ zey9a>L$?Bd%2l6TjOFJ^U-#K))Sp6BRN;e`T29x8LHfHr(ZEfdQN(l-;QwB|HtB%iDl`xce8=ZtQqbQEcDywIY(A0|6;!#e=qcQ z=!iS!e(&_RTNzgPz0=>97Egcvl$CxvlXK#*(s%pq%e(^kUV5M3o`;Lm&}r%Ye)}<8 z`-RR+AN1Q*lA$k4AMx9(szd)_g;75$IOex=xe5|uyp7_7-#*J7vxxL*zr7w8kfBo2 zXZ`juT!@A$NMH2ZW3!;EN?-QdyEv)qNMA(*IfuyYE+@sjk?fPIl;yi$5az^=h7fc4TVkazW0zL@X|K=n*DZM>l&*!8&E4?#d z7v>mViiuC*knKi<+{yk>`o4f&fs;58>upr~1GbM1j*s<*^kBe#rY>|L=_3JqECP;% zO3HC8VDI2Ykt}@z5p!8pmOdS@n=rz<(q{v9TMkJh>5Bn7${}nWo8va{a=;F-hdRf4 zLvS@ApdXW-9JKity+e;nPY>GFS>PDy zSwXu9XMIF^ZqVM(Rq~?re5A9%FH0{B+8eVXaJ(kR;-LKmug3EA(xCk$SHW7PuL#;{ zm7(92UKzC0+e5!Ey*6m4ax4BwdL8m}Bl;}X+t@Y)?RuPJ`<1>qXm@@n0LM3Sd=Rud z@B-nu^!A|rEob>pvAj$5r|b;cOSsN2O79NZ8`#BHr1u5wpG=IYyMIIH{uR|~ zMaFZ-D^@_uJ7_<^hL({&9klsJWJ0OZXM^@q23lSEV$lAEJzr1yG6HJ}-Kc;U*wvu@ zBKMOPO23Yg;yI{;^vz(zt`Gx9H#sI)_HtgB^pc)z*>mtDF4RwYx@BYWVCbc1S@u`; zphrm0wd~=TWTB^|=Ua9t2Rb6X(6Ybe{xnT`am2DGa0{Lz$5PAw53l&=ORuo(W-M@# z^h(R_$Dw*vdaY&Svr)L-lwN1qHF*8`rt}8O-q{LzLxDbMw?AdGWshQyZB=??yJb)3 z(0r;c+i7`s2w&)c-H4zf(huu^{g!t}@tyQR%jUWcol^cImW@B(XoSv5pRnx8?DESh z|Ey*E*?>Pi9Z9)p*}w8a=AQ!pc+1nW3vozd;=DO=)v`yj%L~VO%k{ctSHQ_9bWa=~ zbYO?J>_yy>%g6CC1}>Ch>?{spl{h|^@TW|Uv72zas2#^=5B`+tG4`Mm(CKk}n1Iv# ztQh+*ZfG6jy5LlUvt*3DpBq@V8ZbY`&gF*HTY6!PJ%bGx5a&&@#WD6FUWW{oUK(Sc z3PO*TUJ+w2ss%k>$FGdRJr?vNYUi0Zs%1yEAmG-a8F9Rtw(E34;@mjB|K{Cb&Wqz^ zC*FW7IjBEQ4spEb^rghwz1X!cxCP_EgMBa04D;hgAr9VtFXWnhF>aA7i`ZFg^8}ll4=j(G+!3?jaya~+vNVTJnnl}*057p z^oqD$Xg}YHeVlWCl|o3fTXDBs9e38voMDgT5?>Q{#g&=%kZOKtXO?;2+6qOm*aCr2 znRuQ{Y(Lj-`FPF)-e_*-Ch6SoyRUD_(E2#e7O$^1-_=)6+11rb^>J_ZK9BQm_G~Y* z1Bxu#5M>qQq-Eo?11P6O!8ee^chvibAX^sXqU1Op zVWh1jL-u~OCDcZ;1Rj(?wkzoML$ddXp}S;i$>AfPz)f<&h*wsXlKrWB>fk!|feaj+ zE16-x$EleonPpexHXc@4?d@MUV;+#~Y`@8~POpM*x{dB;zshDkC^_7IAr7*)E3s;D z!{R=1>gyiuPr)tNCNA`TZe9Kq+=97}QU)p=w_G<9k^Yzp*lv2yhejy zn&pvyy2`^H*RUk$`AU!A7VFt|a4eStw^$RoGrc2?TP%0oZIZre+NoSGTh)LGzLLX- zq3d?20^IPF;>l^3G~Vuszlo_^BecgIMtgq|r0y;FncF)?cW-X&b4%yE+R5b43tn=Q zOW3u!t$$IFCt|L)H+Wk4x?s91@i>lMb)aCbD^tBGioYy$U-=+sRmdqFbKhd~E$6+M z`%)|2kBf^y>F7(yTV}9PI{G3ek>Ps+3pA-RiZOiMvS2#?*!wC6AIzp%JNCXB!5)oh z_Km%-LU1D{b&@kJ_Pz#YlCzch9>u1U%_YHh?kj+!mBEOsf3=7x{OB<=hVnafVa8mN<$^yOwWF);<# z-$`E`go$O57>}#>q_3~JDv;O?$48P5ltvb;io_+Dt4RkvWhbT}Q_>+%g%ZnQ0VN&w zRFT9?=KLnZJ+4GzF{&e;DxLT}W=Yb~u5Ma#Vw?6*-;Z}yYN1Dm^fQu9e&wnvi5r3;-Pt{3GWlMkh$4yI1yceUH^s}cj3O(^qe>gD2O6q{f(u+rZZ4TWS!!DII1 zIPL1lJ!T(9-CY%H1Ci!*Mv|fK78;ACCoukEgEoz|N_`IK{_0_oW2tZgXXe-}hxVHH z7g%5na2U~M2)BDlPNyu_GNu1M?&su+X7>W~dwJQ4SqzHo+<; zc8u*{)kWqij?=LY9cQ{R`C>z=IYtZa@5Y;tV0y+D+4Qk^b16sFIGa8mZ(0+`7;iH^ zj5ims1uj#ZPVS`YcryYgh1iLzjTk%?Z{E!aCM#|Q$C&n;m#{^qs6vsi^qW)IB2#U8 zjo-Y30bH(b6nUxNe1-L0VbkmVmbr?F>Pp33E4ZcZH-`=dJxd)GdZXVQ#Y8Y${U&so z-#m$hOYGGu5nb<2+UhsgvIXa=enM~ao86fz=GpXizj+XgmDmNUP~_!)^JmhFZ22zB zZ&tIyYi!0IDD(w=ow`~I?DLz$f}pQgtA(!gn-!fv-(b@R{bp~DktOOWkstD#F`VT~ z)ls33_{~2#MV6^}sG&>z=3cho3N=`0>zLo{$O>;(yfffVI_@_cvI}lew+sCtA^?b8 zrJfPG8geY9Vppqbp-=hE-R$$VN+Cnz)+Cyov+g$4PUvs^X8&x^VZ}{6?xZt*^Q8u$ zA5yubt)#Plb1s|gDRrwTocEja27unH-W7U9V>7D&bfx-1=#`DlCsIHkR2QM=u%K>i zb{+}(Wfc&*w6XbPCg?+oxzwGszOnfO$HZZq-q6@Q&dhs6XspOLHa15@gK<>li-EGn z=3{J;6E?lIvAL7<7m8;e+=gmw4#H9*_O$GiL&S~E8`-31)Iur$O=ELTBhWvnbwZzM zY<|No`B_y6eYUZ=n=N=w9qohs<4!u)*gVOIe^)0&;e2Cr5l@-_Q$tZNB1|ynGZDF6 zI-=49^HS0gF75F81al}lJJw^<8xqVfFj`|HZF*yZxvxIxD4Q-zF!R|0UeL%t7{v+Z z5)QIxTVY#**)sujJ)7R1U_Q(is_(K#af0c(6trp6yC7$ZZ{X6iU=QT1u%S)wOECXK zxzDC66U-#aV_g0CLJ+R#6UFunBp2ZMys0d#tOd)rl zu}H35xtxIO?rcq&hU?DofuvfPCSC_NCK&@9x%>WoCtsH-*>(P;9*=|-b& z`dO&gcd9F7Hf8$yp<0KE5w{!l(B<`O;8!T-uX3U-)>56W88p z8a`f+>%hxvHVq#Y#dUO=hR=oKI%&%E@u^T;XHCWU_>3p6%UG}ULY(hJcuDh6GwX4z zOK$5?vXW zuBm>$wg@NA?)*%{#lYhFz6fSZZv`Xs$ zHMz#+dy}^EG`Y*=TNrN8GSnjG4V(qy3be@$Zr>x}zU2Ns0^HG>i`C=9;TbJM<9iQ5 zeW~%y&!PgESMe?M05xPL#kX{tr2#rGzLloDzU1)lEkkKmC!D|HlQc8I$6ea-$(m~J zYfD+%M`Q>j8ZOoopTcKvEu#iwyI`9C<=j!Ia|fn~|CPAbx-0l7*?-8XlTVTz%Io8U zWdC6;Gkpy)7%l&6nvC)B;kW;FO~v{C3(Ni^Z7!wJ1Yc8RX#X2p*4#G%Rr%l4RHE;> zEKqN2D%qEw2I?J6rTV&%I;yFTK0apjzpHQfboCwX1j_o476yDvI)HpnQ|UflfBTPX zs-KT{(fubhmFeT-U;q1>%J#86{2yp)h>uSq{U2&-gpbc5{r}ZezK>5a{U2#+l#kCi z{U3+R5<^~#j}83QS~9-ToXLj&)Km<4S5mQW15JFPMc4Wcquu?dHMQ8s-5&lgN%29m z?1(y8BQYj9pN8EzCF&Y;vj9IT;o}OPn`KHLvCp=$ExGZ+u1V?eJaju%EoV{ zcq+wmEzUBdn}U&OGroy4_Y{C`ZPRDs%%SY*Hi|g{4^HFEHc6n9Z2DZBnbr|>vT7p^ zoR2eGAk+HWs#Kv%;>}LTg?{}m2oh<$c@-y4JG*>oVZ8Z#6EMXL4hHVypfhZ`I^KLE z{CaYzRsT<#gWca|e}lM~Ua}PLh2e@K-n_E`=mEAI7ll`n9%R$FD7-n`p>3#3H=aiQ z!)^A#bdx7i{|K8tlx`*<`}=bg7fA>w-E0(I-4?a?<}}E+*~in(JDD*@+VqF%<|vMy z0-LT*H`}w-3RSv{hEwV0+u^TKJKjxgmJ;eR>1O&~WNUBhWB$a%HqO@G-pAZA5cGJJ zE2a1KF@Fw#zD)gqWRE85WB$PjJwaWet@n{lP5y~?5NG?CpN1b#33cw)m_vAux=rR- zWnVLyQ*o}^D8;J!ntb2UKhGWtXZo7KaJ_b+me$csu&=SL9SO=t9RKw;T@^H+|CT(Ke3+%^>S27AbD%{0T|6YVha`IOmzzxqh*Y|Ap=<^+4dp$Eug zbbp!c$F^*FjPBoT)7!JnCd{c@Y`Q$#?8a&ywCP>hW(k_#ztyJqWSisIYY*AYw=df= zhco>@Y%?me&3;(X_#d(9gV|;l1KnoRhqBG@E(ZOmO&`fNSDBz6v+1gAa{$jpJJfd) z(6Mauy?&s}Rm00T49;eoH#4O?Wz**@7~r_rsoIOe`D}A1lj<&;E*WUv%LtxPT}8fP zpqb2wE3n(226qiKUtm(+W7B&EnG-q6_uBNn!DdW0=x1%Za){ZC0q(aQ2pk-0&WZ=) zdDTkM;Gv=Bz1=~-pfaVxs-d#w$$vmzJ#!}=8*1Jbel#uAYGf2g%qw=wo*rs`%Z7Z_ zroS0#u3?Heq$Z$)G1rI6RxbbRwtQobY~}JFvFWlLGcVkvJq84q)Bd+?_Vyg}eVk1E zRW@CoV;)Te{kBc-%8?CR{&#G8PmXNh@*lP7eL3cJ?C@hYU72IPMYrCw>4Q1u&1{b2 zPXFdKGPg1JerhWm$uZ}J55uqiUof+OX0uP_m}%WWe{R#Kb7b3<{|lS`CdV8S2l`k%Gw z@?3K-)5Xs=y(`yLJf;3((|dBw!CayIYSa62Eps+cdFO0KWv?#5B_MIw$A68@vN|(%_zw;GdLsb+w_V&^JgY{)23JEnIEv{8@L9^d{~ob z?&pYU=+YT_W1jg2N2t%Hx96EAQ&@~k&!>HPW(+f<-X!iGm~=4D{EZRnUE-K19?z03ZTeiEd1WWit!(;yo_Q??a-vO_C$|c`EmHV&hUf#2>tDB{=s}RlZiFerVr(t zkFnp=Z2CyP*@Yvyy-io;o6|^lu<2v@W(ICN`8(S5@qDw#rJ%dm^oMvX$yV-a)7ANn zOg{hice5F%^36lxv@W4mt#@)b1YBh@fY0Qc_2ix?nk!C}V?jbh4XQcT! z%?`EceIw2F;k2%yJl7Z5;p@AGT6WuZ3B)69@rNVLD>>E*UAIcD)g#T0l#jCIr$(9) z;ln6qmA3$UoXtKz(%hT~db~}S6qs*ty?B{TuP89zX0Q`ndR@J;z--OnCfV{e1?B}t zG1;C1r3K~z+M8m_%L-&;l>c&@-dbRp%h~x?*oDlj+Gq1iUQ2Q;VD)i%Aaz*OBq&#~#s0&^ax&|I57=q@nh!>7Ap5Jq#3Tx0XA z3d|olm#?$wV+CeM%CEQQ^6>(5EeHP%w!FH)?27d6Uu@H-3d~!$>RDpbrwh#JbkHR> z{Y`;+0|(_YyCKgMv@x&f0mgD$;cS6<6_d*fSE+R1xdJmeysbMlv%mdruP(@4|7uAVbl8x%@3)+-li)H&57ZJ9-&sTzcLlxYqO6O zn(5&oU=MkoQJ2~5z7Mce#K|g5I)rIB*oT^)0Lq&e7(5M%20qxST zQTWLop~jcKjiqMeROWNuri)JimG(7;HSd6q^MGpKIY7$v4a)%4K~pilWaQz-9l3ty zEv`}7pgQq=1w0q`Z4WmKgqo@0;ogBzU#n3xWZgzV)AJ#+O@u!!2kjhr2b{o*JNT<2 z+al|^BCAKBy&}IK0v)5}0VI%qE`PyfxaQ* zd(ue?nDTwkL_KzLJ9G^mhbiAjEF5A3xsy)eRwbP;VgtF8zEQr|@DVzj zkq+)6_9pg-DPJ#)GXFK2EOGe`Gwocf$rUbNYm8+7^_pDi@>RA1dBZ%=xLM%xxj73K z>t(^32;V{8Dq5nIH%7=!W52y!xGX~MDEmvsq7PAcYlN?{3))Nd<<+(b-*t%~muYf) zgzqR@X}M0nBRQV^H*@5-EP|tBm4EF;hL$KI)ju%23G&R-tDl582YtHojj2krmdo?x7H=W_!r>Qxv#u(+lJZ3{N`nkS1}HkUPZv4{H)P z2@?xIKBCD|R^4y z_IpyZx4C@1+JY?CDBGbsznk;wuqA?QvJ2i=$Y2A?ao8TU|zU< z1sq!ynyhsB;#kq1X(GiwjsGxR?VZ+6=tC~wD(35F7Ylg=w%UVyPLG}{mv44>Lf=q@ zDyr~b94b?)QMjUC=*MQf?d^Za#l+n#h)mkCy}CUj4O7o-7Cv}MD8uqYL9LI_9vNFH+o`+Q>5JfP(zPH-8Et+X z6n-Zo)JC-r|C|wOo8ANKKlezvkV*03yyq@ZC~KsAj#aLSJ=#S%3ohcu5Zy8sYT&2nW5G* z#s2a-^5u5<2u}7@N+j-ClQ1slll}oAr^rLa)w<9*3-mH}SCcD69 zDPSaLg{w0$wdL93I2Z4mrO8uAy##~_l+!pRgj0}vf-F#UQx&_)Al6M)Ed2KEW*ct3 z+Do|uS6>bmzov*fenjIarj+{$m&D`lI2jRyukRl+)vWL>{X>cUUx5>9kQS?b6wfC; z7$_|o-382UN#lbr8;fsBFP2k!girSmwQjf%6UAm3shQ!%S)pWWX(#Z~y-IbQ0t0-c z1B&^u?Hoh(@$&X^+MUR-z^o#LPdnAc!f&6#rzI*=1ZdG+-4VnIwCLq9#V$A@Et)3J zeBYNF(P?dA%Kg5?nUXvld)nL|>P}3(1sO@@!ja!<9Ld#=@Zqb)l@;nZa0@bk z8l^p&&Vn|612a_Vw-8e1_pilVv#ZhC(Rwm-+x*%iJZ=CU^wz_~iA-T^9oe0csRH*S z32SI{QoG`D3h1V9@~F8}4Wq+r2-Ve%i-rzGXdzd(up98hE`bj+3q4#@ zC`SrS#q4tBu%?E(RF0HNem|_TL(MuT)AeByZ=#mAvkf&|5=9E%cu+Zl+fAL~z?A*r zVcDV95{Jsw(s{GcU=gdQp})BOQ02?}pec`Z1s)l(j(k2JRs|8?p{Lu+*j1NDl))bv zyTJ5~V^>|JE9cmCFvl)1)$yqp(HO%Z{8e_y95xh}_v$yd9>?M7dZ7O1mVqik{qA;x z`a|B3)ToGLNBya#4C;crHYg*473iQ;ouFJ2RLTpuT2XEthYqlX z9bmX}V8~x60kzh_NkFZgfMR$yNWKB*K=rg8%H$b3l&9;2va=?XU3Mtpv_YX>6QsrW zxWzeX<-KmUvi9LwcNv;YH}bPmtn;+lQw{ZlTN?Wnl+ZT zEUIx}oa4avaKI7=CTa(y%ZuH$T|P-WBds&Jjsx4=_Ar=H$HN(-Af7F)sc5$fZyg+p(;i0Gco^+?_|{;@!v=MlsG)eJn%4 zC&ieOYL}f&Ke}9Z-7cLj*>d3(Lqd&IRX9Av@#R@p?O1xwRohzoT?#(IGipI5c!|>fr=vydxQC zGw$`;um|B$deU_|igi4k5Z*mBG@#)#-N1iIQGj1g3dar$U1YVm5 zm82AZvIoD|feL$nMo*rLINrv>Z)QM{UazMxc=}KU=|wJl?TaAgT4(ghYzlIJggn<+ zcjm^vaPfJWh_|7r(Tnd%sNK={!C<}&fZrs+u@|+Z%h_pnw5-T)pQ;3W&?J0fE#zJvGR z&pH>tLjaM;^T8(pnh>l77z&Vi(c*z!8F%0lomp+5q`QC?EU^ob(8QvjBXVENGyL>*-I{OyQP@@E)XeAWb{~=@uN24q|aBT|u!in5Eal zd=*Piat&fhd@_5(nfJgy140$J#=_Hp7j&=?f{#!(IMD*?;Gy>5>BabMP1KMG4K>D< zy$tkK5Cw*S5nKamDX8EEfb|4h0bTHH{2ODUbLvgv$7 z^uGkq20!;ApCM`u*01V1RRz`m;TR0TAF$LNL+3iqJ9M@&RK3R4^iqZ2KQS_JxE4et z&elpx9i=wodO_y}ePSB~Dd+ABly;OHe}EIlNWOh2w5Dd;si)`FI`vGgO+9Lw%Q*o~ z*ZD%`+f2c70@M&Ez_U4_4ys-_F*oGbDgDYiNorP|Bz2V}DLZ}NP$xO*dvTJ!tvboc z#*&;YCplgGSr0Zsq(qpBRycsGy7_F#J29Y!&F@AbCtEi!<~yH|f@aV+gB~tRv}KVk zG5*n{>9Sy4CSupR2u{=$k!-7np*uom@lBDO#ea}K$5qMAk<4Pvqd~{D0)30n{XpkT zyLvwUuZgiy_t(R);41YIc*nu7Zi`HqgFep(ZxS@KvjJ`;=nL>7K%k1FY&@uB6h?9O z>z{56UKYPIvXaHSfj0=^fEObq*cVhOsNCtrS~V41OC6Ar`vleUsm77}CMX%X+zBfq zH^06;H@jmV@TVLxHn*@2j?e2Ll<|2FfSzA1p>i$EVSvlvK0*mUGRww7S_-MU&x-sO zRswribKxZXL>u&i69F#6iXK&-FUCxVHh0aajgd)nQBxemcR-xy2!buac^I6G_5esU z)iBp#9)3elP6!W4cd3HG%w@-6h|@tm6q$|OWf`xcTsHI91p;Qa-VNYUDs&`s%?Bk( z?P&rgwdM^G29wCIu$2!zB#{T{7!%1T2#vrTmS&cl0aCKu!vxH7`&gQ@ybtF424+g+ zsLxTnHcx#_8&X4S=#*=f2*e{bL}2FYBo_neML1wU`k@UZ(ho&c;U|;Vj1^F+f)TYP zayE<%W}A|C8a&IrMM;BNC=$T^Q9~N@PEdAZ8u|QTgu5|cwxjR}xk}m>$rIjAD2*6C z9ELUhCFyhRLGPCq=Nnu`Rsw8(H6N0t$&f@w$!v&0WtkB4u@bYvZ5YM*rt(MZZG$hL zP+g#t`4n7z3FmeW7!@B?3_F9~055PY7{T{|a-bGG32+s`_W;~lERA;v1vfy?eS-?3 zpfnyAz&go(0BL!I1@U54+w^-Ww=2FH8i!c%MN!9VDn9L0{59)4S&XSfz=~VN+7(}q zf?hNlDz0!U9tfeX_*O_0DP_HUF;BW|3g!3-<%Sp{!=X`#1MLEfT;|09;3uXH_20sNPz`3#eT89EUj$$RgmGCEj0b3ptH)qVfR72%03O7(WiSA62`*-WL4ZgL z3zpz8pj!ZBZvNU0rzTXV%GA;YsG$m2re-m&k)%fM8G2JEr+JYqC8ym-`#c*zL9i9z1b`(Yr2qvJp@?iXmGy8Ue+#LeW-}nY z0*7-t?$OHbv%vuJ5ohZ`B@2fNsoslhXN#bb=Lp1EKFJqn$xV;8{_1VM<82Al#M?Uw z=N>Hteb+x<})9@g8*?aJ3Aat^y09XSMsAL3hf;t2$_&&f` zjFI3efTIN80h}j@oq-=z<*GW^0%!^*elQJyFP|0k1Q^!=Dd=}-2R)!}2V2&Lad5gZ z4t2sEe~lg5#}G;a{2zdk`Rhd9z67cVwGZ6=s1{p{_aT!3ya1N~=(hZY<3E9V@4H7s zPp<`~nYTmIm6Gq=3uuAOe7O{){pFD6Q~Iv^K1yl!7TRY;4^b^^Cd83wsbB{D-wRf7 z2*9@lqX67(84>6IA=r8YhkDEXIc@QjngXeG+XMjJv)>}59~k*t?%I5{m||lf&qf(A zF@R>Cch@Xwrx#-xipkFNzWSef0Pe`?{$3Odl!Ix>+}Ht9Mq4GpRuuXLK+aOPp>!1# zF`kyOG@Xk{v7Ji-(3Rf|wbeMB^ZgJ?U?OWKeqb>U=NdYY>RNR@+V~3avM1orxD=d! zvqu5l1@%B;eN?^x)Im_e5`eGU0o)2OHWgq!z*2$=fM);-ULptCD5DG@_&ENY0y{94 zhK_)0lLl}c;3$BMi`~eMWe}?#?)>ZEhQ|W^Ik3)5HUqd}!e4L;f zIgu;I|1k+bU%jA zW)7hgX9#ip4X4}~z<9n#SDnS7;@necM+SXO@m(ld!QwsLVt6fUV1w)x3uqIru%b~O zzu#x5-&NNepui;+?^1HPW&A|I)z*WZ&{0E73z6`Ov9L1$7guWuc*VFIAgdU5;$S3$ zYpDz_pE7vKD3^F0QBM~f&g$pZE-=k_`*vkKGAH;O#L3i|i%9!99B0gHEjo%U zK}YFd2^7RXZekYKD**xNx2Qw0`7VHtRTLLuPgs&oygmfZn1 z0Q4i^99|6|7rXbOa3b`a$+-yvd@}1@j`=qv2InCNRX11ijj)_@Ic_^ZVNiE~?B@8> zrU&XNW7Zz92 zqE!a+YbtC9sOn{p!y(}0;7~8RK1H}XpJnYqiJT?S-3wj5<`{el;2gnQ01eaa+2Dbh zdN^?7suR>@h<1Zen)Px3J%C<@igj4))n?RNC^rUhhCT)lcF~LXT?=T(Ta4UJJFx(J zs3#r&IaI3If`7X1pc*^=NR6~VDli&C`mw9rk$y#~Ok8US#KY;sN3QoM<^cBg0pPqE z4xsbaRH!70Qw#vE^ zeLnDfaV^uiAh>`Md5)%B6kLQ}b1n)BxuEL}8-=v<%YCqt=a905=mce1LWBTtSw#Kc za1zL;cR#-b{lH2Wv(|6EgifFBfXM}_%9eNghv0!I}V=X-}fjJI0Hroul^jr zGIeN_0@h0C1+N9!zaPK~fPRZDO28C)0U+xftxXHLMlPG9R#;!if=_o<#cnf@-=oOSo(EA}h@b{p%P^^P~ z3l&tcv>o)TA~JICorv~di6%b{VPvoD-LU#TWC3or3|4}24+b~_z{l{x;{a&{rvUl^ z$O>&M`wa!$A=O}+9l|&W2Qigs2UtfsRYvK%F|#3-Prw?>s(!^-T|>j}tMO-u-8l8p zR}FEfQrG1)Onc8jD2;R!0PT#@RgeW^Q1A<|f=vNZhGHnE07x5uh}8HA)1&1ocl_%I z4Y6mH0O?kIyrE${i357IL+1gCbv9lB8@JKUO4qNn<1NNbAKHlp*h@X>s#l?M2yUqx zUGd8yWmmmXBW;BWswrLT>OrYRF<Kk=#xAPhBMYGuXm##GQeM?z1r#`mtEtIhYzzn3Jjp^@2MX|EybS0;pkzR= zCg6bH1(1~wxerEUK)(adUzZWadDL|Q2L`D4dLAm`ee)6YN0tF!K|T|9oMD&^5$e~M z{pkr<{LtB_)mYRMD5pcbBR3gZlF08AOIf_pa3wt{x&q;lmvs)Tt8Ri%Gr-E2k3T^R zfBt02TLBj30Ne%O$%T9qKqhwrbWTM5+-Izgs3;Vda|C}zW)FGKendB_0mY3$C@OBu z1i&RU&nGnCjfd{uzz}?ip5^HE&ZC|&m^HoE3b#wBcvwj#Gf_!7>1VA0s5o%kDSa6V zNiAV1Ew!*P_O`Q@RD4M-2OPbj`BICK$>-p!lW_W&wC_y@iMpo5-i_@9CaVgc3@v;cUMAQj*ff&c)2 zD>;}+5rCX>*29@9Ix{}vo|UMYr<_isU^cZeROO5V%92w~Au^HCC>hxoM`W*OZic>- zjPe}5B&1T5k%aUh0Ta@00w$!x05Stvpahj5+mzB0rsP9tf zaH2Hx1^u8QgksY?(0`dRL`R_Qx;rVYcitCv}P;>q>FtFFahRmFoDB}6=8v;51 zxklS_{}`%#4+o}DF6;c4^WRe)k#1oVYO|=u=-R@DPGW~4<;4!9wMlFM#d;3DfC@O( zoH=OC6q%8G6P((NrpbpevXh+N?}z9g&V41&kbqx+Tmp8F0jN3ml|z05dRzj&m?8!| zm4N5I>j5M$e~sF{v+xJLUcwRbFXz7H2THAPpEz;E|PsF&jS?CfGY@-=^ zm{o-NFHTQ}nr_c!X?XC21A4UssDxsEGB?6z>$bRMfhzHzKKHl{rVfJl05r1q0K7)< z1VF?%cveNv-UQVHRPcR(Jph+}27uM=57SWp>y-QfhJQSOXF5s|!~*c8#b677CkX-o zFA`(|#9an30$>0^D!?=VNj!8frYS0D5TVw>877_wAq>m}QxeZyZ-xc)MU2fiu@7`#cP5Ml%_39-3okFN2m5NB~zR#a%4KN%8yy z3y8Dg7+BIzdr^EJ4vh8@EdDQ9;KvS#mbFZAUE$R7D{GMjVSP*p-`^)iJRIRi^4kOL z45Jw3t;kN+8dSsOd|xR1!+hue7$!j%LoPvYC2;1u1Wj}0bZ3(5oa4@itS?Z-(!BTZ zJqt1Dgkk{3+!?@%Y4M72%JWe`} zegk2hwJs}}NfmpodjVqk1Xi-95Qb_Cv_fziz{6aBWo-k0IYw%59$0@+wiuu@ zARj8%uu6CA2_#1sx}w$gkEWd?5o(Csh*4ot=Ywc2*rPq9uYYhhwN&7?&m@y8Xv>#heDns zkS7~e;K-8=auexVoyRcgpyf8zNodJ!s$U4UTE)0mj|3qRUxtGDP{e(zJ*qPnt@E&86$@N zHg{#;3i^H;z7gOnf&~ES(=d}ZFogA>R)Pwa0TfLKcnsiMf?WXhaRlGPpI!tf@n;Uf z_xN)VN5LQXGcq07uafN7XCVJ}nF-s6XgdPvUL3&~{MmZB-6$jBowp^tyW0Ia;*mzV z_6kIsl?raJQs}pU{@q{&+X1{r&;y_vKnBCmF6bB>YN^`~br}QhD*-SnEaPGz-N0W% z=Xw8e2!IOM?a*O*i+Tl34hITk^!_<>r>;w}tsrHcj2CA_aAFq)vgtUax zHST*LwM2ZFV)6ABh#7cdE$+*ga4wqm{L8slDkesCeN=Gz`BHJ!zL)`b;>u`Teo=`tF%YyvL49HIkBl;@PIf6+LkLqK50s91?x#sS3m>F9`$cW zDY+!{UJbw#!Bl`iCiEo9zY0q7f9xCpxknBlO-*~n&_mikiAbd_Uxv^Kl(00@{&5y! z+V3g7A^+HZwWkJ&qH+jy8R?r(!c+}}qPd;(`smR;0GI^q*yCx3w}R&{ff8taFO%DfX- z{jz!I<|uC7NlOhcpBHM~;Rdc^c0!9vZ`LU76s5MZGiX;7cS5Ay8GdVCDAD!Rfbb9V zLb<73*6Zz2Z+f^lD6M@C%X|1~bjQOFC7fl}q)<+S#n#CxZwj=!T{7_=2 z4-z5xB!a(V*S_5x?2G&e!{vX;NZCB11{TZcXr6hc2K`1dfwjIixguRzVlbDTTq^8o?b_g!q z6%H&6wQ0;NMD?W9WTejUf%q2Er0`V>Lrr`3ECijUH*={Q?$+&`C3~=Rcv-SHMepp- zl1ZJiBfJlGt&6jIqU=epG)`4N+*v^qUN;~Ah1_$vmo4pdQugI{SOA(kN7O0rDs(3(X%-!A3B>FYGhfx{r-udSBRQvJKz0&dYsaUwGLLSE6WN{Q9ms?X?*0ji5*H zSJu>*Qg$6_*;DhC&^xI=Z`uMweJ#cgQ9hqdr|Hj0NAw5%jmWQCh#{VcaneUN-kkBG zaSivn^;YHupkL8gnGmY}(I4GsVP-TygY8~~A~V4aCV=`1lY9zz!Z?>QZ=ZI4PeU?J$0RZRn3B3q2oN!YX<>7@~H3` z$nrUbT#?5dqeCFK0&^UzGeOo`T?I-~ElZYat532d6aAAA>QwtKq{ne^{l(Mr2}mU8 zn%CD>K4Fw$Y-8m=dq&-BN7NDWKxH!HUsH_C4pLTtcM@y`=RE*9BTYx?%Wv6z!E3EBcK!A z7u&5s3%qLq>pN+Itxyc1ZiP#2D^4p|kcfMSsA45C_|Xnhq-16W~n%j9{KLS-#Ikeg6Jg@?Ec`kY&w5 zp-%TB6Uq+TP&D@xUJA(w*}Yp7Jr+tAKW2Ehk7YE;KVo>(9y}gs5EeC+HKi+ zI}>HZfyn^)$Vr15neE`fM6Xe1x4<&U12e&t%C~@$%HJT^T8zi}0MY_1Tnat50KI1m zv|DA^EwCKYn{il9vKRu9IIxyF2!N0L1JKC8p(c0-m!ahO;#!{b$bSd)^BhIllJEvN zHIM!|=r{_>8OLPr9GD3lr~6#Re7nl38E}KCc{eoqR*RbM4W!~*v>MzBz>Nrf0Qkw| zwLxruOa!VniXQg}e7^#`0w`op0N6%Q0N`JZ`ZmzgB2cqH1(yQsCRhz%8Eb&TKrIO# z1ei#$17Hb31;BoQ0ld_>7LzGrD(d_=>buRT!L=Tf6~gRaAUs3x6+ol40M!6NfIO#6 zupyK$11E5X?lb{)%UaYQOaiI^UtV6>f*NAdP{UDueyC=Fu3$)am)-`z*|wKpE5IoL znQbqk;LAABpKsAM&bD(9%4|!%9jzvh8)-iu<}fN`L|8c#$tRN$&YX;866=3A>a{H> z%?PiAibS}YfD!H>V1(}j1UAq;Mt6=>B`HSNrWAm|6#z(Z$6@>&jn@We;SO+n=&dQn ziG>9i-75r)?gs#g?i@<~fdkP!PPZ7HXB_|+Bi#V(=NeE+hdC#@X_UxE=F@HrnXwS7 z15v{sMB!z{X#eHV3CwYPcomfRpzg4J7zrRgynxa#;(!mGS(;VPfl!=z20*WaSP4}f zAAY06p3oNfE9t=VQLkwSEaWV-V_=)(z&KFiz(xW#!Z!foz&$9vk(OtxCmaWwqJ71I zg#fw{Sji!na~#-9iS57?$g1hU{-|MF*#cHEIuQy1qXVjAFSNuZia5}ZfDWtykd(sG ziO_@Pwk*w*@;HP#sooCh9XQ~gw9OGn#I>KP0uvplV1WRIOqfv5MXjOqY{e$UX)L%%n>^fAtSbd7hE}hw`N?|7uk9Lr`7@-b9E4KD73?`JxRVmQ1$R!sqcb}2TGT4Xfma|8cstq- z{0K@M@L;(v4vYYh2CP8gROrF*R2H7a^ItKfx&^BsK8nL>!5bkF*Va)5Hkcw$LSYDO zsMn)*!$x2x>t!gQ);?WGfJ0Hl=!7E2qV7VGKq9aNmvl&!(1E{AcbkD^|Ia-Ks= zfxDdo+oeEOCM=zRR`5kksZYooXgyVoB{hyj9O_GbFYGKtc@8sp5|TJ9Rpky?cY^o8 z83Z7WM7^;vj9X!WN9;zL3ZZVK7Ld}kb1Q5$Br-c5rwY$MdR`2}u$;r7J4WA2E1VXG zsms;eja=w)S`1j1e-=^oqpRAnOwKJsR=-mK1v#}DYI@4koC2-(n%K;+ z1#|G{ewGXY><5q)Rwoqfj>A1sJ;8z;p(i2KPg43qatWoyN^VF;ZGj5=s~G@37@-y_ zfkr+nKj3Lb*EvKpp%9n}rYvYifszp_+n1@|n^sq-n)T{=7$vWSc3$#KbnGmooef~t z?uQf`)TMWBtJcV1w!}a%%W33Ak8TATI79>eA=Rw_mbAk20MZJDC^VMVCaR}dGh5*u z2z4tIL2?YY*@_l@rI1XP{{FBK}XF5nN<8(kp$!t>5! z5OQ5Go`$&cSxmrn!2<+b7rYJ-NQJ(v3%(@9|He_)1s5Up%DP|xfF%oqQdnO}>$M95 zoDx}JO)>Hj3v2+WAmGsb6hKaiNw+w1e}Pa&ZX2XWozQ9j5X?CvcQhsP zv1DC0rvM9Q9O|^^>Bmu;(Jg?EM7N%R(J|dhbSDAwoH7!jVxl@thq?0Uz#PMs&o}@H z@Lm}AcKus`sbJ_=Jyx&)Biup22#*6ugwLYnejJGKPP)bjzkyI9Ou%f_5we0Iu;)bB zpAz{<_l+Nkr5)@4(sSE(6lQ=Ep^|N}|12U#xQT%McLX3%iUJbdSETlkVsx!A(ImP& z0EzA$SeJ|by4{!14QlMZ+o{jsULx2E@Ew2z_v1*6zn@VW(Opfy7@dnln2W2<06IEW zkPdrJbdxEOk96Phe8U(G74?;8_6`(gbS1RH;MNl`xNQUs?hrtpT?XrKu3SF=D=-!{ zNQA$Gk_g*lOi6^lqlOZQ|1vR;Z_SA2r!SXF~El)lmK6T zjPp;{<*c9*_M8Y$LPvk(G{?CapN;yz@N9yaJcpLkoWi(}^I~HF)XVc?Ybf_+fzzHU z7I0`OaEVjkvd2-sT_OwG<5=QLkHYlNb7(2?kW=DisbV0jm;&Vz7Wm4O=U`E8fSwe8 z(gEi=m#e8Xy?PpL=O#Gr$f2SxbBa z6EWRk;z7?QCMYKAN(cj~VAdvBXiqOjWzf!~_7+dGC!xIzykpcZ22;B2G$^a~j_V(+ zhxZOxvII)#i(gm|(`gzSQJ>L&hV&c`^r-aaV0J5q>o}^QG0zucNeu;>QJXzEtemc{ zWIs3p$6bp>#NYRzUPgb*Jck{BH=;;@{|BG=TMnw$-IqX#yDV6x-QCK9boWyTwY#4~ z`Xvs!OD}zlh@-F*0OHrfWeYUq*Ea6;{0U zUskg;1HBYN9q2WXUXQ~GbO9t1=oYG=U+6#y6z;&G?)L;Z3g!A|Hx%+5iL~@<;D{67 z5^zE{K!xH2^)j^+K3bp?9U;_C+zu)2J5CIzpKR^xr~)NAu>lH?;ZP5FvMmnFwGiex zTybDCIO4!T0y^*+fH*+CvD$ S0%+v;&XWwjBqOs6q!uQiY!Zd;mFqAl5vC;eypI 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