diff options
249 files changed, 6486 insertions, 2304 deletions
@@ -33,7 +33,7 @@ configure: ; .PHONY: all clean cscope distclean dvi html info install install-doc \ pdf recurse-all speed tar tarbin test build-all -$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) +$(call set-vpath, $(SRC_PATH)) LIBS+=-lz $(LIBS_TOOLS) @@ -91,19 +91,18 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) -subdir-%: $(GENERATED_HEADERS) +subdir-%: $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,) ifneq ($(wildcard config-host.mak),) include $(SRC_PATH)/Makefile.objs endif -$(universal-obj-y) $(common-obj-y): $(GENERATED_HEADERS) subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o -$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) subdir-libdis +$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) subdir-libdis -$(filter %-user,$(SUBDIR_RULES)): $(GENERATED_HEADERS) $(universal-obj-y) $(trace-obj-y) subdir-libdis-user subdir-libuser +$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) subdir-libdis-user subdir-libuser ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) romsubdir-%: @@ -121,7 +120,7 @@ QEMU_CFLAGS += -I$(SRC_PATH)/include ui/cocoa.o: ui/cocoa.m -ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) +ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o hw/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) @@ -142,16 +141,19 @@ libcacard.la: 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))) +libcacard.la: $(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,) install-libcacard: libcacard.la $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,) endif + +vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) qemu-timer-common.o libcacard/vscclient.o + $(call quiet-command,$(CC) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@") + ###################################################################### qemu-img.o: qemu-img-cmds.h -qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS) tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ qemu-timer-common.o main-loop.o notify.o iohandler.o cutils.o async.o @@ -162,7 +164,6 @@ 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-bridge-helper$(EXESUF): qemu-bridge-helper.o -qemu-bridge-helper.o: $(GENERATED_HEADERS) fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y) fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap @@ -170,7 +171,6 @@ fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@") -$(qapi-obj-y): $(GENERATED_HEADERS) qapi-dir := $(BUILD_DIR)/qapi-generated qemu-ga$(EXESUF): LIBS = $(LIBS_QGA) qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir) @@ -203,8 +203,8 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py 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) +$(QGALIB_OBJ): $(QGALIB_GEN) +$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) $(QGALIB_OBJ) @@ -218,6 +218,7 @@ clean: rm -Rf .libs rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d rm -f qom/*.o qom/*.d + rm -f usb/*.o usb/*.d hw/*.o hw/*.d rm -f qemu-img-cmds.h rm -f trace/*.o trace/*.d rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp @@ -399,5 +400,10 @@ tar: cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn rm -rf /tmp/$(FILE) +# Add a dependency on the generated files, so that they are always +# rebuilt before other object files +Makefile: $(GENERATED_HEADERS) + # Include automatically generated dependency files --include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d) +-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d) +-include $(wildcard qga/*.d hw/*.d hw/usb/*.d) diff --git a/Makefile.hw b/Makefile.hw index 33f1ab0183..2bcbaffb4f 100644 --- a/Makefile.hw +++ b/Makefile.hw @@ -7,7 +7,7 @@ include $(SRC_PATH)/rules.mak .PHONY: all -$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) +$(call set-vpath, $(SRC_PATH)) QEMU_CFLAGS+=-I.. QEMU_CFLAGS += -I$(SRC_PATH)/include @@ -19,7 +19,8 @@ all: $(hw-obj-y) @true clean: - rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ + rm -f $(addsuffix /*.o, $(dir $(sort $(hw-obj-y)))) + rm -f $(addsuffix /*.d, $(dir $(sort $(hw-obj-y)))) # Include automatically generated dependency files --include $(wildcard *.d */*.d) +-include $(patsubst %.o, %.d, $(hw-obj-y)) diff --git a/Makefile.objs b/Makefile.objs index 70c5c79a6e..74110dda7e 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -12,9 +12,7 @@ universal-obj-y += $(qobject-obj-y) ####################################################################### # QOM -include $(SRC_PATH)/qom/Makefile -qom-obj-y = $(addprefix qom/, $(qom-y)) -qom-obj-twice-y = $(addprefix qom/, $(qom-twice-y)) +qom-obj-y = qom/ universal-obj-y += $(qom-obj-y) @@ -47,45 +45,13 @@ block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sock 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 - -block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o -block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o -block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o -block-nested-y += qed-check.o -block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o -block-nested-y += stream.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 - -block-obj-y += $(addprefix block/, $(block-nested-y)) - -net-obj-y = net.o -net-nested-y = queue.o checksum.o util.o -net-nested-y += socket.o -net-nested-y += dump.o -net-nested-$(CONFIG_POSIX) += tap.o -net-nested-$(CONFIG_LINUX) += tap-linux.o -net-nested-$(CONFIG_WIN32) += tap-win32.o -net-nested-$(CONFIG_BSD) += tap-bsd.o -net-nested-$(CONFIG_SOLARIS) += tap-solaris.o -net-nested-$(CONFIG_AIX) += tap-aix.o -net-nested-$(CONFIG_HAIKU) += tap-haiku.o -net-nested-$(CONFIG_SLIRP) += slirp.o -net-nested-$(CONFIG_VDE) += vde.o -net-obj-y += $(addprefix net/, $(net-nested-y)) +block-obj-y += block/ ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. # only pull in the actual virtio-9p device if we also enabled virtio. CONFIG_REALLY_VIRTFS=y -fsdev-nested-y = qemu-fsdev.o virtio-9p-marshal.o -else -fsdev-nested-y = qemu-fsdev-dummy.o endif -fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y)) ###################################################################### # Target independent part of system emulation. The long term path is to @@ -93,104 +59,40 @@ fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y)) # single QEMU executable should support all CPUs and machines. common-obj-y = $(block-obj-y) blockdev.o -common-obj-y += $(net-obj-y) -common-obj-y += $(qom-obj-twice-y) -common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX)) +common-obj-y += net.o net/ +common-obj-y += qom/ 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-$(CONFIG_LINUX) += fsdev/ +extra-obj-$(CONFIG_LINUX) += fsdev/ + 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 -common-obj-$(CONFIG_TWL92230) += twl92230.o -common-obj-$(CONFIG_TSC2005) += tsc2005.o -common-obj-$(CONFIG_LM832X) += lm832x.o -common-obj-$(CONFIG_TMP105) += tmp105.o -common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o -common-obj-$(CONFIG_SSD0303) += ssd0303.o -common-obj-$(CONFIG_SSD0323) += ssd0323.o -common-obj-$(CONFIG_ADS7846) += ads7846.o -common-obj-$(CONFIG_MAX111X) += max111x.o -common-obj-$(CONFIG_DS1338) += ds1338.o -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/core.o usb/bus.o usb/desc.o usb/dev-hub.o -common-obj-y += usb/host-$(HOST_USB).o -common-obj-y += usb/dev-hid.o usb/dev-storage.o usb/dev-wacom.o -common-obj-y += usb/dev-serial.o usb/dev-network.o usb/dev-audio.o -common-obj-$(CONFIG_SSI) += ssi.o -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 -common-obj-y += bt-hci-csr.o usb/dev-bluetooth.o +common-obj-y += input.o common-obj-y += buffered_file.o migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o -common-obj-y += msmouse.o ps2.o -common-obj-y += qdev.o qdev-properties.o qdev-monitor.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 common-obj-$(CONFIG_WIN32) += version.o -common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o spice-qemu-char.o - -audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o -audio-obj-$(CONFIG_SDL) += sdlaudio.o -audio-obj-$(CONFIG_OSS) += ossaudio.o -audio-obj-$(CONFIG_SPICE) += spiceaudio.o -audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o -audio-obj-$(CONFIG_ALSA) += alsaaudio.o -audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o -audio-obj-$(CONFIG_FMOD) += fmodaudio.o -audio-obj-$(CONFIG_ESD) += esdaudio.o -audio-obj-$(CONFIG_PA) += paaudio.o -audio-obj-$(CONFIG_WINWAVE) += winwaveaudio.o -audio-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o -audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o -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 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 -vnc-obj-y += vnc-jobs-async.o -else -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-$(CONFIG_SPICE) += spice-qemu-char.o + +common-obj-y += audio/ +common-obj-y += hw/ +common-obj-y += ui/ +common-obj-y += bt-host.o bt-vhci.o common-obj-y += iov.o acl.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 arp_table.o -common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y)) - -# xen backend driver support -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 +common-obj-$(CONFIG_SLIRP) += slirp/ ###################################################################### # libuser @@ -202,152 +104,12 @@ user-obj-y += cutils.o cache-utils.o user-obj-y += module.o user-obj-y += qemu-user.o user-obj-y += $(trace-obj-y) -user-obj-y += $(qom-obj-twice-y) +user-obj-y += qom/ ###################################################################### # libhw -hw-obj-y = -hw-obj-y += vl.o loader.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 pci_bridge_dev.o -hw-obj-$(CONFIG_PCI) += msix.o msi.o -hw-obj-$(CONFIG_PCI) += shpc.o -hw-obj-$(CONFIG_PCI) += slotid_cap.o -hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o -hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o -hw-obj-y += watchdog.o -hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o -hw-obj-$(CONFIG_ECC) += ecc.o -hw-obj-$(CONFIG_NAND) += nand.o -hw-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o -hw-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o - -hw-obj-$(CONFIG_M48T59) += m48t59.o -hw-obj-$(CONFIG_ESCC) += escc.o -hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o - -hw-obj-$(CONFIG_SERIAL) += serial.o -hw-obj-$(CONFIG_PARALLEL) += parallel.o -hw-obj-$(CONFIG_I8254) += i8254_common.o i8254.o -hw-obj-$(CONFIG_PCSPK) += pcspk.o -hw-obj-$(CONFIG_PCKBD) += pckbd.o -hw-obj-$(CONFIG_USB_UHCI) += usb/hcd-uhci.o -hw-obj-$(CONFIG_USB_OHCI) += usb/hcd-ohci.o -hw-obj-$(CONFIG_USB_EHCI) += usb/hcd-ehci.o -hw-obj-$(CONFIG_USB_XHCI) += usb/hcd-xhci.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_I82374) += i82374.o -hw-obj-$(CONFIG_HPET) += hpet.o -hw-obj-$(CONFIG_APPLESMC) += applesmc.o -hw-obj-$(CONFIG_SMARTCARD) += usb/dev-smartcard-reader.o ccid-card-passthru.o -hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o -hw-obj-$(CONFIG_USB_REDIR) += usb/redirect.o -hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o - -# PPC devices -hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o -hw-obj-$(CONFIG_I82378) += i82378.o -# Mac shared devices -hw-obj-$(CONFIG_MACIO) += macio.o -hw-obj-$(CONFIG_CUDA) += cuda.o -hw-obj-$(CONFIG_ADB) += adb.o -hw-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o -hw-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o -# OldWorld PowerMac -hw-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o -hw-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o -# NewWorld PowerMac -hw-obj-$(CONFIG_UNIN_PCI) += unin_pci.o -hw-obj-$(CONFIG_DEC_PCI) += dec_pci.o -# PowerPC E500 boards -hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o - -# MIPS devices -hw-obj-$(CONFIG_PIIX4) += piix4.o -hw-obj-$(CONFIG_G364FB) += g364fb.o -hw-obj-$(CONFIG_JAZZ_LED) += jazz_led.o - -# PCI watchdog devices -hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o - -hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o - -# PCI network cards -hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o -hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o -hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o -hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o -hw-obj-$(CONFIG_E1000_PCI) += e1000.o -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 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 -hw-obj-$(CONFIG_IDE_PIIX) += ide/piix.o -hw-obj-$(CONFIG_IDE_CMD646) += ide/cmd646.o -hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o -hw-obj-$(CONFIG_IDE_VIA) += ide/via.o -hw-obj-$(CONFIG_AHCI) += ide/ahci.o -hw-obj-$(CONFIG_AHCI) += ide/ich.o - -# SCSI layer -hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o -hw-obj-$(CONFIG_ESP) += esp.o - -hw-obj-y += dma-helpers.o sysbus.o isa-bus.o -hw-obj-y += qdev-addr.o - -# VGA -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_VGA_CIRRUS) += cirrus_vga.o - -hw-obj-$(CONFIG_RC4030) += rc4030.o -hw-obj-$(CONFIG_DP8393X) += dp8393x.o -hw-obj-$(CONFIG_DS1225Y) += ds1225y.o -hw-obj-$(CONFIG_MIPSNET) += mipsnet.o - -hw-obj-y += qtest.o - -# Sound -sound-obj-y = -sound-obj-$(CONFIG_SB16) += sb16.o -sound-obj-$(CONFIG_ES1370) += es1370.o -sound-obj-$(CONFIG_AC97) += ac97.o -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 - -adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 -hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) - -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 -9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-proxy.o - -hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y)) +hw-obj-y = vl.o dma-helpers.o qtest.o hw/ ###################################################################### # libdis @@ -425,31 +187,29 @@ 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_DEFAULT) += trace/default.o +trace-obj-$(CONFIG_TRACE_SIMPLE) += trace/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-$(CONFIG_TRACE_STDERR) += trace/stderr.o +trace-obj-y += trace/control.o $(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 +libcacard-y += libcacard/cac.o libcacard/event.o +libcacard-y += libcacard/vcard.o libcacard/vreader.o +libcacard-y += libcacard/vcard_emul_nss.o +libcacard-y += libcacard/vcard_emul_type.o +libcacard-y += libcacard/card_7816.o + +common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) ###################################################################### # qapi -qapi-nested-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o -qapi-nested-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o -qapi-nested-y += string-input-visitor.o string-output-visitor.o -qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y)) +qapi-obj-y = qapi/ common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o common-obj-y += qmp.o hmp.o @@ -459,11 +219,7 @@ universal-obj-y += $(qapi-obj-y) ###################################################################### # guest agent -qga-nested-y = commands.o guest-agent-command-state.o -qga-nested-$(CONFIG_POSIX) += commands-posix.o channel-posix.o -qga-nested-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o -qga-obj-y = $(addprefix qga/, $(qga-nested-y)) -qga-obj-y += qemu-ga.o module.o +qga-obj-y = qga/ qemu-ga.o module.o qga-obj-$(CONFIG_WIN32) += oslib-win32.o qga-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-sockets.o qemu-option.o @@ -473,3 +229,13 @@ vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) QEMU_CFLAGS+=$(GLIB_CFLAGS) +nested-vars += \ + hw-obj-y \ + qga-obj-y \ + block-obj-y \ + qom-obj-y \ + qapi-obj-y \ + user-obj-y \ + common-obj-y \ + extra-obj-y +dummy := $(call unnest-vars) diff --git a/Makefile.target b/Makefile.target index 15829041c7..2907aad0c4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -1,10 +1,5 @@ # -*- Mode: makefile -*- -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 include config-target.mak @@ -13,14 +8,11 @@ ifneq ($(HWDIR),) include $(HWDIR)/config.mak endif -TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw) +$(call set-vpath, $(SRC_PATH)) ifdef CONFIG_LINUX QEMU_CFLAGS += -I../linux-headers endif -QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H - -include $(SRC_PATH)/Makefile.objs +QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -DNEED_CPU_H QEMU_CFLAGS+=-I$(SRC_PATH)/include @@ -77,78 +69,34 @@ all: $(PROGS) stap ######################################################### # 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_TCG_INTERPRETER) += tci.o -libobj-y += fpu/softfloat.o -ifneq ($(TARGET_BASE_ARCH), sparc) -ifneq ($(TARGET_BASE_ARCH), alpha) -libobj-y += op_helper.o -endif -endif -libobj-y += helper.o -ifneq ($(TARGET_BASE_ARCH), ppc) -libobj-y += cpu.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 -endif -libobj-$(TARGET_SPARC) += int32_helper.o -libobj-$(TARGET_SPARC64) += int64_helper.o -libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o mem_helper.o - -libobj-y += disas.o -libobj-$(CONFIG_TCI_DIS) += tci-dis.o +obj-y = exec.o translate-all.o cpu-exec.o +obj-y += tcg/tcg.o tcg/optimize.o +obj-$(CONFIG_TCG_INTERPRETER) += tci.o +obj-y += fpu/softfloat.o +obj-y += disas.o +obj-$(CONFIG_TCI_DIS) += tci-dis.o +obj-y += target-$(TARGET_BASE_ARCH)/ +obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci -$(libobj-y): $(GENERATED_HEADERS) - # HELPER_CFLAGS is used for all the legacy code compiled with static register # variables -ifneq ($(TARGET_BASE_ARCH), sparc) -op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) -endif user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) # Note: this is a workaround. The real fix is to avoid compiling # cpu_signal_handler() in user-exec.c. -signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +%/signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ######################################################### # Linux user emulator target 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/$(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 \ - user-exec.o $(oslib-obj-y) - -obj-$(TARGET_HAS_BFLT) += flatload.o - -obj-$(TARGET_I386) += vm86.o -obj-i386-y += ioport-user.o - -nwfpe-obj-y = fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o fpopcode.o -nwfpe-obj-y += single_cpdo.o double_cpdo.o extended_cpdo.o -obj-arm-y += $(addprefix nwfpe/, $(nwfpe-obj-y)) -obj-arm-y += arm-semi.o - -obj-m68k-y += m68k-sim.o m68k-semi.o - -$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) - -obj-y += $(addprefix ../, $(universal-obj-y)) -obj-y += $(addprefix ../libuser/, $(user-obj-y)) -obj-y += $(addprefix ../libdis-user/, $(libdis-y)) -obj-y += $(libobj-y) +obj-y += linux-user/ +obj-y += gdbstub.o thunk.o user-exec.o $(oslib-obj-y) endif #CONFIG_LINUX_USER @@ -157,269 +105,81 @@ endif #CONFIG_LINUX_USER ifdef CONFIG_BSD_USER -$(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 user-exec.o - -obj-i386-y += ioport-user.o - -$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) - -obj-y += $(addprefix ../, $(universal-obj-y)) -obj-y += $(addprefix ../libuser/, $(user-obj-y)) -obj-y += $(addprefix ../libdis-user/, $(libdis-y)) -obj-y += $(libobj-y) +obj-y += bsd-user/ +obj-y += gdbstub.o user-exec.o endif #CONFIG_BSD_USER ######################################################### # System emulator target ifdef CONFIG_SOFTMMU +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) +CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y) +CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y) -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.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o -obj-$(CONFIG_VIRTIO) += virtio-scsi.o -obj-y += vhost_net.o -obj-$(CONFIG_VHOST_NET) += vhost.o -obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o -obj-$(CONFIG_KVM) += kvm.o kvm-all.o +obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o +obj-y += hw/ +obj-$(CONFIG_KVM) += kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o -obj-$(CONFIG_VGA) += vga.o obj-y += memory.o savevm.o cputlb.o +obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o +obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o +obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o +obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o LIBS+=-lz -obj-i386-$(CONFIG_KVM) += hyperv.o - QEMU_CFLAGS += $(VNC_TLS_CFLAGS) QEMU_CFLAGS += $(VNC_SASL_CFLAGS) QEMU_CFLAGS += $(VNC_JPEG_CFLAGS) QEMU_CFLAGS += $(VNC_PNG_CFLAGS) # xen support -obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o +obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o obj-$(CONFIG_NO_XEN) += xen-stub.o -obj-i386-$(CONFIG_XEN) += xen_platform.o xen_apic.o - -# Inter-VM PCI shared memory -CONFIG_IVSHMEM = -ifeq ($(CONFIG_KVM), y) - ifeq ($(CONFIG_PCI), y) - CONFIG_IVSHMEM = y - endif -endif -obj-$(CONFIG_IVSHMEM) += ivshmem.o - -# Generic hotplugging -obj-y += device-hotplug.o - # Hardware support -obj-i386-y += mc146818rtc.o pc.o -obj-i386-y += apic_common.o apic.o kvmvapic.o -obj-i386-y += sga.o ioapic_common.o ioapic.o piix_pci.o -obj-i386-y += vmport.o -obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o -obj-i386-y += debugcon.o multiboot.o -obj-i386-y += pc_piix.o -obj-i386-y += pc_sysfw.o -obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o kvm/i8254.o -obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o - -# shared objects -obj-ppc-y = ppc.o ppc_booke.o -# PREP target -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_bamboo.o -# PowerPC E500 boards -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 -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 += gt64xxx.o mc146818rtc.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_boot.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 += axis_dev88.o - -# IO blocks -obj-cris-y += etraxfs_dma.o -obj-cris-y += etraxfs_pic.o -obj-cris-y += etraxfs_eth.o -obj-cris-y += etraxfs_timer.o -obj-cris-y += etraxfs_ser.o - ifeq ($(TARGET_ARCH), sparc64) -obj-sparc-y = sun4u.o apb_pci.o -obj-sparc-y += mc146818rtc.o +obj-y += hw/sparc64/ else -obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o -obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o -obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o - -# GRLIB -obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o +obj-y += hw/$(TARGET_BASE_ARCH)/ endif -obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o -obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o -obj-arm-y += versatile_pci.o -obj-arm-y += versatile_i2c.o -obj-arm-y += cadence_uart.o -obj-arm-y += cadence_ttc.o -obj-arm-y += cadence_gem.o -obj-arm-y += xilinx_zynq.o zynq_slcr.o -obj-arm-y += arm_gic.o -obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o -obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o -obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o -obj-arm-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o -obj-arm-y += arm_l2x0.o -obj-arm-y += arm_mptimer.o a15mpcore.o -obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o -obj-arm-y += highbank.o -obj-arm-y += pl061.o -obj-arm-y += xgmac.o -obj-arm-y += arm-semi.o -obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o -obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o -obj-arm-y += gumstix.o -obj-arm-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o -obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ - omap_gpio.o omap_intc.o omap_uart.o -obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ - omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o -obj-arm-y += omap_sx1.o palm.o tsc210x.o -obj-arm-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-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 += vexpress.o -obj-arm-y += strongarm.o -obj-arm-y += collie.o -obj-arm-y += pl041.o lm4549.o -obj-arm-$(CONFIG_FDT) += device_tree.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 -obj-sh4-y += ide/mmio.o - -obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o -obj-m68k-y += m68k-semi.o dummy_m68k.o - -obj-s390x-y = s390-virtio-bus.o s390-virtio.o - -obj-alpha-y = mc146818rtc.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-dc233c.o -obj-xtensa-y += core-fsf.o - main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) -monitor.o: hmp-commands.h qmp-commands-old.h +GENERATED_HEADERS += hmp-commands.h qmp-commands-old.h -$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) +endif # CONFIG_SOFTMMU -obj-y += $(addprefix ../, $(universal-obj-y)) -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)) +nested-vars += obj-y -endif # CONFIG_SOFTMMU +# This resolves all nested paths, so it must come last +include $(SRC_PATH)/Makefile.objs -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 +all-obj-y = $(obj-y) +all-obj-y += $(addprefix ../, $(universal-obj-y)) -obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o +ifdef CONFIG_SOFTMMU +all-obj-y += $(addprefix ../, $(common-obj-y)) +all-obj-y += $(addprefix ../libdis/, $(libdis-y)) +all-obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) +all-obj-y += $(addprefix ../, $(trace-obj-y)) +else +all-obj-y += $(addprefix ../libuser/, $(user-obj-y)) +all-obj-y += $(addprefix ../libdis-user/, $(libdis-y)) +endif #CONFIG_LINUX_USER ifdef QEMU_PROGW # The linker builds a windows executable. Make also a console executable. -$(QEMU_PROGW): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) +$(QEMU_PROGW): $(all-obj-y) $(call LINK,$^) $(QEMU_PROG): $(QEMU_PROGW) $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)") else -$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) +$(QEMU_PROG): $(all-obj-y) $(call LINK,$^) endif @@ -452,5 +212,8 @@ ifdef CONFIG_TRACE_SYSTEMTAP $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset" endif +GENERATED_HEADERS += config-target.h +Makefile: $(GENERATED_HEADERS) + # Include automatically generated dependency files -include $(wildcard *.d */*.d) diff --git a/audio/Makefile.objs b/audio/Makefile.objs new file mode 100644 index 0000000000..0f2932d1b3 --- /dev/null +++ b/audio/Makefile.objs @@ -0,0 +1,14 @@ +common-obj-y = audio.o noaudio.o wavaudio.o mixeng.o +common-obj-$(CONFIG_SDL) += sdlaudio.o +common-obj-$(CONFIG_OSS) += ossaudio.o +common-obj-$(CONFIG_SPICE) += spiceaudio.o +common-obj-$(CONFIG_COREAUDIO) += coreaudio.o +common-obj-$(CONFIG_ALSA) += alsaaudio.o +common-obj-$(CONFIG_DSOUND) += dsoundaudio.o +common-obj-$(CONFIG_FMOD) += fmodaudio.o +common-obj-$(CONFIG_ESD) += esdaudio.o +common-obj-$(CONFIG_PA) += paaudio.o +common-obj-$(CONFIG_WINWAVE) += winwaveaudio.o +common-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o +common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o +common-obj-y += wavcapture.o diff --git a/audio/winwaveaudio.c b/audio/winwaveaudio.c index 87e7493270..663abb9b50 100644 --- a/audio/winwaveaudio.c +++ b/audio/winwaveaudio.c @@ -72,7 +72,7 @@ static void winwave_log_mmresult (MMRESULT mr) break; case MMSYSERR_NOMEM: - str = "Unable to allocate or locl memory"; + str = "Unable to allocate or lock memory"; break; case WAVERR_SYNC: diff --git a/block/Makefile.objs b/block/Makefile.objs new file mode 100644 index 0000000000..b5754d39bf --- /dev/null +++ b/block/Makefile.objs @@ -0,0 +1,11 @@ +block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o +block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o +block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o +block-obj-y += qed-check.o +block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o +block-obj-y += stream.o +block-obj-$(CONFIG_WIN32) += raw-win32.o +block-obj-$(CONFIG_POSIX) += raw-posix.o +block-obj-$(CONFIG_LIBISCSI) += iscsi.o +block-obj-$(CONFIG_CURL) += curl.o +block-obj-$(CONFIG_RBD) += rbd.o diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 4b3345b11b..c173fcd488 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -471,6 +471,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO); *cluster_offset &= L2E_OFFSET_MASK; break; + default: + abort(); } qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); diff --git a/blockdev.c b/blockdev.c index 67895b25d5..622ecba04e 100644 --- a/blockdev.c +++ b/blockdev.c @@ -569,7 +569,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) break; case IF_VIRTIO: /* add virtio block device */ - opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0); + opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, NULL); if (arch_type == QEMU_ARCH_S390X) { qemu_opt_set(opts, "driver", "virtio-blk-s390"); } else { diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs new file mode 100644 index 0000000000..5e77f57782 --- /dev/null +++ b/bsd-user/Makefile.objs @@ -0,0 +1,2 @@ +obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ + uaccess.o diff --git a/bsd-user/main.c b/bsd-user/main.c index 0689e38fb8..cd33d655f5 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -918,7 +918,7 @@ int main(int argc, char **argv) exit(1); } #if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) - cpu_state_reset(env); + cpu_reset(ENV_GET_CPU(env)); #endif thread_env = env; @@ -42,6 +42,7 @@ compile_prog() { # symbolically link $1 to $2. Portable version of "ln -sf". symlink() { rm -rf "$2" + mkdir -p "$(dirname "$2")" ln -s "$1" "$2" } @@ -2811,7 +2812,11 @@ fi open_by_hande_at=no cat > $TMPC << EOF #include <fcntl.h> +#if !defined(AT_EMPTY_PATH) +# error missing definition +#else int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); } +#endif EOF if compile_prog "" "" ; then open_by_handle_at=yes @@ -2915,7 +2920,8 @@ if test "$softmmu" = yes ; then tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)" else if test "$virtfs" = yes; then - feature_not_found "virtfs" + echo "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel" + exit 1 fi virtfs=no fi @@ -2927,6 +2933,9 @@ if test "$softmmu" = yes ; then fi fi fi +if test "$smartcard_nss" = "yes" ; then + tools="vscclient\$(EXESUF) $tools" +fi # Mac OS X ships with a broken assembler roms= @@ -3451,14 +3460,12 @@ if test -f ${config_host_ld}~ ; then fi for d in libdis libdis-user; do - mkdir -p $d symlink "$source_path/Makefile.dis" "$d/Makefile" echo > $d/config.mak done # use included Linux headers if test "$linux" = "yes" ; then - mkdir -p linux-headers case "$cpu" in i386|x86_64) symlink "$source_path/linux-headers/asm-x86" linux-headers/asm @@ -3514,18 +3521,6 @@ case "$target" in esac mkdir -p $target_dir -mkdir -p $target_dir/fpu -mkdir -p $target_dir/tcg -mkdir -p $target_dir/ide -mkdir -p $target_dir/usb -mkdir -p $target_dir/9pfs -mkdir -p $target_dir/kvm -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 -symlink "$source_path/Makefile.target" "$target_dir/Makefile" - - echo "# Automatically generated by configure - do not modify" > $config_target_mak bflt="no" @@ -3676,9 +3671,16 @@ case "$target_arch2" in exit 1 ;; esac +# TARGET_BASE_ARCH needs to be defined after TARGET_ARCH +if [ "$TARGET_BASE_ARCH" = "" ]; then + TARGET_BASE_ARCH=$TARGET_ARCH +fi + +symlink "$source_path/Makefile.target" "$target_dir/Makefile" + case "$target_arch2" in - alpha | sparc*) + alpha | sparc* | xtensa*) echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak ;; esac @@ -3691,10 +3693,6 @@ echo "TARGET_ARCH=$TARGET_ARCH" >> $config_target_mak target_arch_name="`echo $TARGET_ARCH | LC_ALL=C tr '[a-z]' '[A-Z]'`" echo "TARGET_$target_arch_name=y" >> $config_target_mak echo "TARGET_ARCH2=$target_arch2" >> $config_target_mak -# TARGET_BASE_ARCH needs to be defined after TARGET_ARCH -if [ "$TARGET_BASE_ARCH" = "" ]; then - TARGET_BASE_ARCH=$TARGET_ARCH -fi echo "TARGET_BASE_ARCH=$TARGET_BASE_ARCH" >> $config_target_mak if [ "$TARGET_ABI_DIR" = "" ]; then TARGET_ABI_DIR=$TARGET_ARCH @@ -3729,6 +3727,10 @@ case "$target_arch2" in fi fi esac +case "$target_arch2" in + i386|x86_64) + echo "CONFIG_HAVE_GET_MEMORY_MAPPING=y" >> $config_target_mak +esac if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then echo "CONFIG_PSERIES=y" >> $config_target_mak fi @@ -3744,6 +3746,10 @@ if test "$target_softmmu" = "yes" ; then if test "$smartcard_nss" = "yes" ; then echo "subdir-$target: subdir-libcacard" >> $config_host_mak fi + case "$target_arch2" in + i386|x86_64) + echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak + esac fi if test "$target_user_only" = "yes" ; then echo "CONFIG_USER_ONLY=y" >> $config_target_mak @@ -3893,12 +3899,6 @@ if test "$target_softmmu" = "yes" ; then esac fi -if test "$target_softmmu" = "yes" -a \( \ - "$TARGET_ARCH" = "microblaze" -o \ - "$TARGET_ARCH" = "cris" \) ; then - echo "CONFIG_NEED_MMU=y" >> $config_target_mak -fi - if test "$gprof" = "yes" ; then echo "TARGET_GPROF=yes" >> $config_target_mak if test "$target_linux_user" = "yes" ; then @@ -3940,15 +3940,13 @@ done # for target in $targets # build tree in object directory in case the source is not in the current directory DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32" -DIRS="$DIRS slirp audio block net pc-bios/optionrom" -DIRS="$DIRS pc-bios/spapr-rtas" +DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas" DIRS="$DIRS roms/seabios roms/vgabios" -DIRS="$DIRS fsdev ui usb" -DIRS="$DIRS qapi qapi-generated" -DIRS="$DIRS qga trace qom" +DIRS="$DIRS qapi-generated" +DIRS="$DIRS libcacard libcacard/libcacard libcacard/trace" FILES="Makefile tests/tcg/Makefile qdict-test-data.txt" FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" -FILES="$FILES tests/tcg/lm32/Makefile" +FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile" FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" @@ -3983,24 +3981,11 @@ done for hwlib in 32 64; do d=libhw$hwlib - mkdir -p $d - mkdir -p $d/ide - mkdir -p $d/usb 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 - symlink "$source_path/libcacard/Makefile" libcacard/Makefile -fi - d=libuser -mkdir -p $d -mkdir -p $d/trace -mkdir -p $d/qom symlink "$source_path/Makefile.user" "$d/Makefile" if test "$docs" = "yes" ; then @@ -443,7 +443,6 @@ void cpu_watchpoint_remove_all(CPUArchState *env, int mask); #define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */ void cpu_single_step(CPUArchState *env, int enabled); -void cpu_state_reset(CPUArchState *s); int cpu_is_stopped(CPUArchState *env); void run_on_cpu(CPUArchState *env, void (*func)(void *data), void *data); diff --git a/cpu-common.h b/cpu-common.h index dca5175652..1fe3280701 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -71,6 +71,10 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)); void cpu_unregister_map_client(void *cookie); +#ifndef CONFIG_USER_ONLY +bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr); +#endif + /* Coalesced MMIO regions are areas where write operations can be reordered. * This usually implies that write operations are side-effect free. This allows * batching which can make a major impact on performance when using diff --git a/cpu-exec.c b/cpu-exec.c index 0344cd5c59..624c409f7b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -184,6 +184,9 @@ volatile sig_atomic_t exit_request; int cpu_exec(CPUArchState *env) { +#ifdef TARGET_PPC + CPUState *cpu = ENV_GET_CPU(env); +#endif int ret, interrupt_request; TranslationBlock *tb; uint8_t *tc_ptr; @@ -287,11 +290,11 @@ int cpu_exec(CPUArchState *env) #if defined(TARGET_I386) if (interrupt_request & CPU_INTERRUPT_INIT) { svm_check_intercept(env, SVM_EXIT_INIT); - do_cpu_init(env); + do_cpu_init(x86_env_get_cpu(env)); env->exception_index = EXCP_HALTED; cpu_loop_exit(env); } else if (interrupt_request & CPU_INTERRUPT_SIPI) { - do_cpu_sipi(env); + do_cpu_sipi(x86_env_get_cpu(env)); } else if (env->hflags2 & HF2_GIF_MASK) { if ((interrupt_request & CPU_INTERRUPT_SMI) && !(env->hflags & HF_SMM_MASK)) { @@ -341,7 +344,7 @@ int cpu_exec(CPUArchState *env) } #elif defined(TARGET_PPC) if ((interrupt_request & CPU_INTERRUPT_RESET)) { - cpu_state_reset(env); + cpu_reset(cpu); } if (interrupt_request & CPU_INTERRUPT_HARD) { ppc_hw_interrupt(env); @@ -464,11 +467,18 @@ int cpu_exec(CPUArchState *env) do_interrupt(env); next_tb = 0; } - if (interrupt_request & CPU_INTERRUPT_NMI - && (env->pregs[PR_CCS] & M_FLAG)) { - env->exception_index = EXCP_NMI; - do_interrupt(env); - next_tb = 0; + if (interrupt_request & CPU_INTERRUPT_NMI) { + unsigned int m_flag_archval; + if (env->pregs[PR_VR] < 32) { + m_flag_archval = M_FLAG_V10; + } else { + m_flag_archval = M_FLAG_V32; + } + if ((env->pregs[PR_CCS] & m_flag_archval)) { + env->exception_index = EXCP_NMI; + do_interrupt(env); + next_tb = 0; + } } #elif defined(TARGET_M68K) if (interrupt_request & CPU_INTERRUPT_HARD diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak index 613edab742..64c9485de4 100644 --- a/default-configs/microblaze-softmmu.mak +++ b/default-configs/microblaze-softmmu.mak @@ -3,3 +3,5 @@ CONFIG_PTIMER=y CONFIG_PFLASH_CFI01=y CONFIG_SERIAL=y +CONFIG_XILINX=y +CONFIG_XILINX_AXI=y diff --git a/default-configs/microblazeel-softmmu.mak b/default-configs/microblazeel-softmmu.mak index 4b40fb21a5..a9622760c9 100644 --- a/default-configs/microblazeel-softmmu.mak +++ b/default-configs/microblazeel-softmmu.mak @@ -3,3 +3,5 @@ CONFIG_PTIMER=y CONFIG_PFLASH_CFI01=y CONFIG_SERIAL=y +CONFIG_XILINX=y +CONFIG_XILINX_AXI=y diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 1a768fc519..d0fde7b93d 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -36,3 +36,4 @@ CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y +CONFIG_XILINX=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index f490368c64..e4265b4978 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -33,3 +33,4 @@ CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y +CONFIG_XILINX=y diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 829f462105..aaa9cdc1f7 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -33,3 +33,4 @@ CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y +CONFIG_XILINX=y diff --git a/dump-stub.c b/dump-stub.c new file mode 100644 index 0000000000..56d4564f0f --- /dev/null +++ b/dump-stub.c @@ -0,0 +1,64 @@ +/* + * QEMU dump + * + * Copyright Fujitsu, Corp. 2011, 2012 + * + * Authors: + * Wen Congyang <wency@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "dump.h" +#include "qerror.h" +#include "qmp-commands.h" + +/* we need this function in hmp.c */ +void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + int64_t begin, bool has_length, int64_t length, + Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); +} + +int cpu_write_elf64_note(write_core_dump_function f, + CPUArchState *env, int cpuid, + void *opaque) +{ + return -1; +} + +int cpu_write_elf32_note(write_core_dump_function f, + CPUArchState *env, int cpuid, + void *opaque) +{ + return -1; +} + +int cpu_write_elf64_qemunote(write_core_dump_function f, + CPUArchState *env, + void *opaque) +{ + return -1; +} + +int cpu_write_elf32_qemunote(write_core_dump_function f, + CPUArchState *env, + void *opaque) +{ + return -1; +} + +int cpu_get_dump_info(ArchDumpInfo *info) +{ + return -1; +} + +ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) +{ + return -1; +} + diff --git a/dump.c b/dump.c new file mode 100644 index 0000000000..2bf8d8d994 --- /dev/null +++ b/dump.c @@ -0,0 +1,873 @@ +/* + * QEMU dump + * + * Copyright Fujitsu, Corp. 2011, 2012 + * + * Authors: + * Wen Congyang <wency@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "elf.h" +#include "cpu.h" +#include "cpu-all.h" +#include "targphys.h" +#include "monitor.h" +#include "kvm.h" +#include "dump.h" +#include "sysemu.h" +#include "memory_mapping.h" +#include "error.h" +#include "qmp-commands.h" +#include "gdbstub.h" + +static uint16_t cpu_convert_to_target16(uint16_t val, int endian) +{ + if (endian == ELFDATA2LSB) { + val = cpu_to_le16(val); + } else { + val = cpu_to_be16(val); + } + + return val; +} + +static uint32_t cpu_convert_to_target32(uint32_t val, int endian) +{ + if (endian == ELFDATA2LSB) { + val = cpu_to_le32(val); + } else { + val = cpu_to_be32(val); + } + + return val; +} + +static uint64_t cpu_convert_to_target64(uint64_t val, int endian) +{ + if (endian == ELFDATA2LSB) { + val = cpu_to_le64(val); + } else { + val = cpu_to_be64(val); + } + + return val; +} + +typedef struct DumpState { + ArchDumpInfo dump_info; + MemoryMappingList list; + uint16_t phdr_num; + uint32_t sh_info; + bool have_section; + bool resume; + size_t note_size; + target_phys_addr_t memory_offset; + int fd; + + RAMBlock *block; + ram_addr_t start; + bool has_filter; + int64_t begin; + int64_t length; + Error **errp; +} DumpState; + +static int dump_cleanup(DumpState *s) +{ + int ret = 0; + + memory_mapping_list_free(&s->list); + if (s->fd != -1) { + close(s->fd); + } + if (s->resume) { + vm_start(); + } + + return ret; +} + +static void dump_error(DumpState *s, const char *reason) +{ + dump_cleanup(s); +} + +static int fd_write_vmcore(void *buf, size_t size, void *opaque) +{ + DumpState *s = opaque; + int fd = s->fd; + size_t writen_size; + + /* The fd may be passed from user, and it can be non-blocked */ + while (size) { + writen_size = qemu_write_full(fd, buf, size); + if (writen_size != size && errno != EAGAIN) { + return -1; + } + + buf += writen_size; + size -= writen_size; + } + + return 0; +} + +static int write_elf64_header(DumpState *s) +{ + Elf64_Ehdr elf_header; + int ret; + int endian = s->dump_info.d_endian; + + memset(&elf_header, 0, sizeof(Elf64_Ehdr)); + memcpy(&elf_header, ELFMAG, SELFMAG); + elf_header.e_ident[EI_CLASS] = ELFCLASS64; + elf_header.e_ident[EI_DATA] = s->dump_info.d_endian; + elf_header.e_ident[EI_VERSION] = EV_CURRENT; + elf_header.e_type = cpu_convert_to_target16(ET_CORE, endian); + elf_header.e_machine = cpu_convert_to_target16(s->dump_info.d_machine, + endian); + elf_header.e_version = cpu_convert_to_target32(EV_CURRENT, endian); + elf_header.e_ehsize = cpu_convert_to_target16(sizeof(elf_header), endian); + elf_header.e_phoff = cpu_convert_to_target64(sizeof(Elf64_Ehdr), endian); + elf_header.e_phentsize = cpu_convert_to_target16(sizeof(Elf64_Phdr), + endian); + elf_header.e_phnum = cpu_convert_to_target16(s->phdr_num, endian); + if (s->have_section) { + uint64_t shoff = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * s->sh_info; + + elf_header.e_shoff = cpu_convert_to_target64(shoff, endian); + elf_header.e_shentsize = cpu_convert_to_target16(sizeof(Elf64_Shdr), + endian); + elf_header.e_shnum = cpu_convert_to_target16(1, endian); + } + + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + if (ret < 0) { + dump_error(s, "dump: failed to write elf header.\n"); + return -1; + } + + return 0; +} + +static int write_elf32_header(DumpState *s) +{ + Elf32_Ehdr elf_header; + int ret; + int endian = s->dump_info.d_endian; + + memset(&elf_header, 0, sizeof(Elf32_Ehdr)); + memcpy(&elf_header, ELFMAG, SELFMAG); + elf_header.e_ident[EI_CLASS] = ELFCLASS32; + elf_header.e_ident[EI_DATA] = endian; + elf_header.e_ident[EI_VERSION] = EV_CURRENT; + elf_header.e_type = cpu_convert_to_target16(ET_CORE, endian); + elf_header.e_machine = cpu_convert_to_target16(s->dump_info.d_machine, + endian); + elf_header.e_version = cpu_convert_to_target32(EV_CURRENT, endian); + elf_header.e_ehsize = cpu_convert_to_target16(sizeof(elf_header), endian); + elf_header.e_phoff = cpu_convert_to_target32(sizeof(Elf32_Ehdr), endian); + elf_header.e_phentsize = cpu_convert_to_target16(sizeof(Elf32_Phdr), + endian); + elf_header.e_phnum = cpu_convert_to_target16(s->phdr_num, endian); + if (s->have_section) { + uint32_t shoff = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * s->sh_info; + + elf_header.e_shoff = cpu_convert_to_target32(shoff, endian); + elf_header.e_shentsize = cpu_convert_to_target16(sizeof(Elf32_Shdr), + endian); + elf_header.e_shnum = cpu_convert_to_target16(1, endian); + } + + ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + if (ret < 0) { + dump_error(s, "dump: failed to write elf header.\n"); + return -1; + } + + return 0; +} + +static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, + int phdr_index, target_phys_addr_t offset) +{ + Elf64_Phdr phdr; + int ret; + int endian = s->dump_info.d_endian; + + memset(&phdr, 0, sizeof(Elf64_Phdr)); + phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); + phdr.p_offset = cpu_convert_to_target64(offset, endian); + phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian); + if (offset == -1) { + /* When the memory is not stored into vmcore, offset will be -1 */ + phdr.p_filesz = 0; + } else { + phdr.p_filesz = cpu_convert_to_target64(memory_mapping->length, endian); + } + phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian); + phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian); + + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); + if (ret < 0) { + dump_error(s, "dump: failed to write program header table.\n"); + return -1; + } + + return 0; +} + +static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, + int phdr_index, target_phys_addr_t offset) +{ + Elf32_Phdr phdr; + int ret; + int endian = s->dump_info.d_endian; + + memset(&phdr, 0, sizeof(Elf32_Phdr)); + phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); + phdr.p_offset = cpu_convert_to_target32(offset, endian); + phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian); + if (offset == -1) { + /* When the memory is not stored into vmcore, offset will be -1 */ + phdr.p_filesz = 0; + } else { + phdr.p_filesz = cpu_convert_to_target32(memory_mapping->length, endian); + } + phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian); + phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian); + + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); + if (ret < 0) { + dump_error(s, "dump: failed to write program header table.\n"); + return -1; + } + + return 0; +} + +static int write_elf64_note(DumpState *s) +{ + Elf64_Phdr phdr; + int endian = s->dump_info.d_endian; + target_phys_addr_t begin = s->memory_offset - s->note_size; + int ret; + + memset(&phdr, 0, sizeof(Elf64_Phdr)); + phdr.p_type = cpu_convert_to_target32(PT_NOTE, endian); + phdr.p_offset = cpu_convert_to_target64(begin, endian); + phdr.p_paddr = 0; + phdr.p_filesz = cpu_convert_to_target64(s->note_size, endian); + phdr.p_memsz = cpu_convert_to_target64(s->note_size, endian); + phdr.p_vaddr = 0; + + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); + if (ret < 0) { + dump_error(s, "dump: failed to write program header table.\n"); + return -1; + } + + return 0; +} + +static int write_elf64_notes(DumpState *s) +{ + CPUArchState *env; + int ret; + int id; + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + id = cpu_index(env); + ret = cpu_write_elf64_note(fd_write_vmcore, env, id, s); + if (ret < 0) { + dump_error(s, "dump: failed to write elf notes.\n"); + return -1; + } + } + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + ret = cpu_write_elf64_qemunote(fd_write_vmcore, env, s); + if (ret < 0) { + dump_error(s, "dump: failed to write CPU status.\n"); + return -1; + } + } + + return 0; +} + +static int write_elf32_note(DumpState *s) +{ + target_phys_addr_t begin = s->memory_offset - s->note_size; + Elf32_Phdr phdr; + int endian = s->dump_info.d_endian; + int ret; + + memset(&phdr, 0, sizeof(Elf32_Phdr)); + phdr.p_type = cpu_convert_to_target32(PT_NOTE, endian); + phdr.p_offset = cpu_convert_to_target32(begin, endian); + phdr.p_paddr = 0; + phdr.p_filesz = cpu_convert_to_target32(s->note_size, endian); + phdr.p_memsz = cpu_convert_to_target32(s->note_size, endian); + phdr.p_vaddr = 0; + + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); + if (ret < 0) { + dump_error(s, "dump: failed to write program header table.\n"); + return -1; + } + + return 0; +} + +static int write_elf32_notes(DumpState *s) +{ + CPUArchState *env; + int ret; + int id; + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + id = cpu_index(env); + ret = cpu_write_elf32_note(fd_write_vmcore, env, id, s); + if (ret < 0) { + dump_error(s, "dump: failed to write elf notes.\n"); + return -1; + } + } + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + ret = cpu_write_elf32_qemunote(fd_write_vmcore, env, s); + if (ret < 0) { + dump_error(s, "dump: failed to write CPU status.\n"); + return -1; + } + } + + return 0; +} + +static int write_elf_section(DumpState *s, int type) +{ + Elf32_Shdr shdr32; + Elf64_Shdr shdr64; + int endian = s->dump_info.d_endian; + int shdr_size; + void *shdr; + int ret; + + if (type == 0) { + shdr_size = sizeof(Elf32_Shdr); + memset(&shdr32, 0, shdr_size); + shdr32.sh_info = cpu_convert_to_target32(s->sh_info, endian); + shdr = &shdr32; + } else { + shdr_size = sizeof(Elf64_Shdr); + memset(&shdr64, 0, shdr_size); + shdr64.sh_info = cpu_convert_to_target32(s->sh_info, endian); + shdr = &shdr64; + } + + ret = fd_write_vmcore(&shdr, shdr_size, s); + if (ret < 0) { + dump_error(s, "dump: failed to write section header table.\n"); + return -1; + } + + return 0; +} + +static int write_data(DumpState *s, void *buf, int length) +{ + int ret; + + ret = fd_write_vmcore(buf, length, s); + if (ret < 0) { + dump_error(s, "dump: failed to save memory.\n"); + return -1; + } + + return 0; +} + +/* write the memroy to vmcore. 1 page per I/O. */ +static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, + int64_t size) +{ + int64_t i; + int ret; + + for (i = 0; i < size / TARGET_PAGE_SIZE; i++) { + ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE, + TARGET_PAGE_SIZE); + if (ret < 0) { + return ret; + } + } + + if ((size % TARGET_PAGE_SIZE) != 0) { + ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE, + size % TARGET_PAGE_SIZE); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +/* get the memory's offset in the vmcore */ +static target_phys_addr_t get_offset(target_phys_addr_t phys_addr, + DumpState *s) +{ + RAMBlock *block; + target_phys_addr_t offset = s->memory_offset; + int64_t size_in_block, start; + + if (s->has_filter) { + if (phys_addr < s->begin || phys_addr >= s->begin + s->length) { + return -1; + } + } + + QLIST_FOREACH(block, &ram_list.blocks, next) { + if (s->has_filter) { + if (block->offset >= s->begin + s->length || + block->offset + block->length <= s->begin) { + /* This block is out of the range */ + continue; + } + + if (s->begin <= block->offset) { + start = block->offset; + } else { + start = s->begin; + } + + size_in_block = block->length - (start - block->offset); + if (s->begin + s->length < block->offset + block->length) { + size_in_block -= block->offset + block->length - + (s->begin + s->length); + } + } else { + start = block->offset; + size_in_block = block->length; + } + + if (phys_addr >= start && phys_addr < start + size_in_block) { + return phys_addr - start + offset; + } + + offset += size_in_block; + } + + return -1; +} + +static int write_elf_loads(DumpState *s) +{ + target_phys_addr_t offset; + MemoryMapping *memory_mapping; + uint32_t phdr_index = 1; + int ret; + uint32_t max_index; + + if (s->have_section) { + max_index = s->sh_info; + } else { + max_index = s->phdr_num; + } + + QTAILQ_FOREACH(memory_mapping, &s->list.head, next) { + offset = get_offset(memory_mapping->phys_addr, s); + if (s->dump_info.d_class == ELFCLASS64) { + ret = write_elf64_load(s, memory_mapping, phdr_index++, offset); + } else { + ret = write_elf32_load(s, memory_mapping, phdr_index++, offset); + } + + if (ret < 0) { + return -1; + } + + if (phdr_index >= max_index) { + break; + } + } + + return 0; +} + +/* write elf header, PT_NOTE and elf note to vmcore. */ +static int dump_begin(DumpState *s) +{ + int ret; + + /* + * the vmcore's format is: + * -------------- + * | elf header | + * -------------- + * | PT_NOTE | + * -------------- + * | PT_LOAD | + * -------------- + * | ...... | + * -------------- + * | PT_LOAD | + * -------------- + * | sec_hdr | + * -------------- + * | elf note | + * -------------- + * | memory | + * -------------- + * + * we only know where the memory is saved after we write elf note into + * vmcore. + */ + + /* write elf header to vmcore */ + if (s->dump_info.d_class == ELFCLASS64) { + ret = write_elf64_header(s); + } else { + ret = write_elf32_header(s); + } + if (ret < 0) { + return -1; + } + + if (s->dump_info.d_class == ELFCLASS64) { + /* write PT_NOTE to vmcore */ + if (write_elf64_note(s) < 0) { + return -1; + } + + /* write all PT_LOAD to vmcore */ + if (write_elf_loads(s) < 0) { + return -1; + } + + /* write section to vmcore */ + if (s->have_section) { + if (write_elf_section(s, 1) < 0) { + return -1; + } + } + + /* write notes to vmcore */ + if (write_elf64_notes(s) < 0) { + return -1; + } + + } else { + /* write PT_NOTE to vmcore */ + if (write_elf32_note(s) < 0) { + return -1; + } + + /* write all PT_LOAD to vmcore */ + if (write_elf_loads(s) < 0) { + return -1; + } + + /* write section to vmcore */ + if (s->have_section) { + if (write_elf_section(s, 0) < 0) { + return -1; + } + } + + /* write notes to vmcore */ + if (write_elf32_notes(s) < 0) { + return -1; + } + } + + return 0; +} + +/* write PT_LOAD to vmcore */ +static int dump_completed(DumpState *s) +{ + dump_cleanup(s); + return 0; +} + +static int get_next_block(DumpState *s, RAMBlock *block) +{ + while (1) { + block = QLIST_NEXT(block, next); + if (!block) { + /* no more block */ + return 1; + } + + s->start = 0; + s->block = block; + if (s->has_filter) { + if (block->offset >= s->begin + s->length || + block->offset + block->length <= s->begin) { + /* This block is out of the range */ + continue; + } + + if (s->begin > block->offset) { + s->start = s->begin - block->offset; + } + } + + return 0; + } +} + +/* write all memory to vmcore */ +static int dump_iterate(DumpState *s) +{ + RAMBlock *block; + int64_t size; + int ret; + + while (1) { + block = s->block; + + size = block->length; + if (s->has_filter) { + size -= s->start; + if (s->begin + s->length < block->offset + block->length) { + size -= block->offset + block->length - (s->begin + s->length); + } + } + ret = write_memory(s, block, s->start, size); + if (ret == -1) { + return ret; + } + + ret = get_next_block(s, block); + if (ret == 1) { + dump_completed(s); + return 0; + } + } +} + +static int create_vmcore(DumpState *s) +{ + int ret; + + ret = dump_begin(s); + if (ret < 0) { + return -1; + } + + ret = dump_iterate(s); + if (ret < 0) { + return -1; + } + + return 0; +} + +static ram_addr_t get_start_block(DumpState *s) +{ + RAMBlock *block; + + if (!s->has_filter) { + s->block = QLIST_FIRST(&ram_list.blocks); + return 0; + } + + QLIST_FOREACH(block, &ram_list.blocks, next) { + if (block->offset >= s->begin + s->length || + block->offset + block->length <= s->begin) { + /* This block is out of the range */ + continue; + } + + s->block = block; + if (s->begin > block->offset) { + s->start = s->begin - block->offset; + } else { + s->start = 0; + } + return s->start; + } + + return -1; +} + +static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, + int64_t begin, int64_t length, Error **errp) +{ + CPUArchState *env; + int nr_cpus; + int ret; + + if (runstate_is_running()) { + vm_stop(RUN_STATE_SAVE_VM); + s->resume = true; + } else { + s->resume = false; + } + + s->errp = errp; + s->fd = fd; + s->has_filter = has_filter; + s->begin = begin; + s->length = length; + s->start = get_start_block(s); + if (s->start == -1) { + error_set(errp, QERR_INVALID_PARAMETER, "begin"); + goto cleanup; + } + + /* + * get dump info: endian, class and architecture. + * If the target architecture is not supported, cpu_get_dump_info() will + * return -1. + * + * if we use kvm, we should synchronize the register before we get dump + * info. + */ + nr_cpus = 0; + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu_synchronize_state(env); + nr_cpus++; + } + + ret = cpu_get_dump_info(&s->dump_info); + if (ret < 0) { + error_set(errp, QERR_UNSUPPORTED); + goto cleanup; + } + + s->note_size = cpu_get_note_size(s->dump_info.d_class, + s->dump_info.d_machine, nr_cpus); + if (ret < 0) { + error_set(errp, QERR_UNSUPPORTED); + goto cleanup; + } + + /* get memory mapping */ + memory_mapping_list_init(&s->list); + if (paging) { + qemu_get_guest_memory_mapping(&s->list); + } else { + qemu_get_guest_simple_memory_mapping(&s->list); + } + + if (s->has_filter) { + memory_mapping_filter(&s->list, s->begin, s->length); + } + + /* + * calculate phdr_num + * + * the type of ehdr->e_phnum is uint16_t, so we should avoid overflow + */ + s->phdr_num = 1; /* PT_NOTE */ + if (s->list.num < UINT16_MAX - 2) { + s->phdr_num += s->list.num; + s->have_section = false; + } else { + s->have_section = true; + s->phdr_num = PN_XNUM; + s->sh_info = 1; /* PT_NOTE */ + + /* the type of shdr->sh_info is uint32_t, so we should avoid overflow */ + if (s->list.num <= UINT32_MAX - 1) { + s->sh_info += s->list.num; + } else { + s->sh_info = UINT32_MAX; + } + } + + if (s->dump_info.d_class == ELFCLASS64) { + if (s->have_section) { + s->memory_offset = sizeof(Elf64_Ehdr) + + sizeof(Elf64_Phdr) * s->sh_info + + sizeof(Elf64_Shdr) + s->note_size; + } else { + s->memory_offset = sizeof(Elf64_Ehdr) + + sizeof(Elf64_Phdr) * s->phdr_num + s->note_size; + } + } else { + if (s->have_section) { + s->memory_offset = sizeof(Elf32_Ehdr) + + sizeof(Elf32_Phdr) * s->sh_info + + sizeof(Elf32_Shdr) + s->note_size; + } else { + s->memory_offset = sizeof(Elf32_Ehdr) + + sizeof(Elf32_Phdr) * s->phdr_num + s->note_size; + } + } + + return 0; + +cleanup: + if (s->resume) { + vm_start(); + } + + return -1; +} + +void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, + int64_t begin, bool has_length, int64_t length, + Error **errp) +{ + const char *p; + int fd = -1; + DumpState *s; + int ret; + + if (has_begin && !has_length) { + error_set(errp, QERR_MISSING_PARAMETER, "length"); + return; + } + if (!has_begin && has_length) { + error_set(errp, QERR_MISSING_PARAMETER, "begin"); + return; + } + +#if !defined(WIN32) + if (strstart(file, "fd:", &p)) { + fd = monitor_get_fd(cur_mon, p); + if (fd == -1) { + error_set(errp, QERR_FD_NOT_FOUND, p); + return; + } + } +#endif + + if (strstart(file, "file:", &p)) { + fd = qemu_open(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR); + if (fd < 0) { + error_set(errp, QERR_OPEN_FILE_FAILED, p); + return; + } + } + + if (fd == -1) { + error_set(errp, QERR_INVALID_PARAMETER, "protocol"); + return; + } + + s = g_malloc(sizeof(DumpState)); + + ret = dump_init(s, fd, paging, has_begin, begin, length, errp); + if (ret < 0) { + g_free(s); + return; + } + + if (create_vmcore(s) < 0 && !error_is_set(s->errp)) { + error_set(errp, QERR_IO_ERROR); + } + + g_free(s); +} diff --git a/dump.h b/dump.h new file mode 100644 index 0000000000..e25b7cfb73 --- /dev/null +++ b/dump.h @@ -0,0 +1,35 @@ +/* + * QEMU dump + * + * Copyright Fujitsu, Corp. 2011, 2012 + * + * Authors: + * Wen Congyang <wency@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef DUMP_H +#define DUMP_H + +typedef struct ArchDumpInfo { + int d_machine; /* Architecture */ + int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */ + int d_class; /* ELFCLASS32 or ELFCLASS64 */ +} ArchDumpInfo; + +typedef int (*write_core_dump_function)(void *buf, size_t size, void *opaque); +int cpu_write_elf64_note(write_core_dump_function f, CPUArchState *env, + int cpuid, void *opaque); +int cpu_write_elf32_note(write_core_dump_function f, CPUArchState *env, + int cpuid, void *opaque); +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUArchState *env, + void *opaque); +int cpu_write_elf32_qemunote(write_core_dump_function f, CPUArchState *env, + void *opaque); +int cpu_get_dump_info(ArchDumpInfo *info); +ssize_t cpu_get_note_size(int class, int machine, int nr_cpus); + +#endif @@ -1037,6 +1037,11 @@ typedef struct elf64_sym { #define EI_NIDENT 16 +/* Special value for e_phnum. This indicates that the real number of + program headers is too large to fit into e_phnum. Instead the real + value is in the field sh_info of section 0. */ +#define PN_XNUM 0xffff + typedef struct elf32_hdr{ unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; @@ -1076,11 +1076,11 @@ TranslationBlock *tb_gen_code(CPUArchState *env, } /* - * invalidate all TBs which intersect with the target physical pages - * starting in range [start;end[. NOTE: start and end may refer to - * different physical pages. 'is_cpu_write_access' should be true if called - * from a real cpu write access: the virtual CPU will exit the current - * TB if code is modified inside this TB. + * Invalidate all TBs which intersect with the target physical address range + * [start;end[. NOTE: start and end may refer to *different* physical pages. + * 'is_cpu_write_access' should be true if called from a real cpu write + * access: the virtual CPU will exit the current TB if code is modified inside + * this TB. */ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, int is_cpu_write_access) @@ -1092,11 +1092,13 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, } } -/* invalidate all TBs which intersect with the target physical page - starting in range [start;end[. NOTE: start and end must refer to - the same physical page. 'is_cpu_write_access' should be true if called - from a real cpu write access: the virtual CPU will exit the current - TB if code is modified inside this TB. */ +/* + * Invalidate all TBs which intersect with the target physical address range + * [start;end[. NOTE: start and end must refer to the *same* physical page. + * 'is_cpu_write_access' should be true if called from a real cpu write + * access: the virtual CPU will exit the current TB if code is modified inside + * this TB. + */ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, int is_cpu_write_access) { @@ -1492,7 +1494,8 @@ void tb_invalidate_phys_addr(target_phys_addr_t addr) static void breakpoint_invalidate(CPUArchState *env, target_ulong pc) { - tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc)); + tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc) | + (pc & ~TARGET_PAGE_MASK)); } #endif #endif /* TARGET_HAS_ICE */ @@ -4336,3 +4339,15 @@ bool virtio_is_big_endian(void) } #endif + +#ifndef CONFIG_USER_ONLY +bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr) +{ + MemoryRegionSection *section; + + section = phys_page_find(phys_addr >> TARGET_PAGE_BITS); + + return !(memory_region_is_ram(section->mr) || + memory_region_is_romd(section->mr)); +} +#endif diff --git a/fsdev/Makefile.objs b/fsdev/Makefile.objs new file mode 100644 index 0000000000..cb1e2500b9 --- /dev/null +++ b/fsdev/Makefile.objs @@ -0,0 +1,9 @@ +ifeq ($(CONFIG_REALLY_VIRTFS),y) +common-obj-y = qemu-fsdev.o virtio-9p-marshal.o + +# Toplevel always builds this; targets without virtio will put it in +# common-obj-y +extra-obj-y = qemu-fsdev-dummy.o +else +common-obj-y = qemu-fsdev-dummy.o +endif @@ -1937,21 +1937,12 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) #endif } -static inline int gdb_id(CPUArchState *env) -{ -#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL) - return env->host_tid; -#else - return env->cpu_index + 1; -#endif -} - static CPUArchState *find_cpu(uint32_t thread_id) { CPUArchState *env; for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (gdb_id(env) == thread_id) { + if (cpu_index(env) == thread_id) { return env; } } @@ -1979,7 +1970,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) case '?': /* TODO: Make this return the correct value for user-mode. */ snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP, - gdb_id(s->c_cpu)); + cpu_index(s->c_cpu)); put_packet(s, buf); /* Remove all the breakpoints when this query is issued, * because gdb is doing and initial connect and the state @@ -2274,7 +2265,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) } else if (strcmp(p,"sThreadInfo") == 0) { report_cpuinfo: if (s->query_cpu) { - snprintf(buf, sizeof(buf), "m%x", gdb_id(s->query_cpu)); + snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu)); put_packet(s, buf); s->query_cpu = s->query_cpu->next_cpu; } else @@ -2422,7 +2413,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) } snprintf(buf, sizeof(buf), "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", - GDB_SIGNAL_TRAP, gdb_id(env), type, + GDB_SIGNAL_TRAP, cpu_index(env), type, env->watchpoint_hit->vaddr); env->watchpoint_hit = NULL; goto send_packet; @@ -2455,7 +2446,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) ret = GDB_SIGNAL_UNKNOWN; break; } - snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(env)); + snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(env)); send_packet: put_packet(s, buf); @@ -30,6 +30,15 @@ void gdb_register_coprocessor(CPUArchState *env, gdb_reg_cb get_reg, gdb_reg_cb set_reg, int num_regs, const char *xml, int g_pos); +static inline int cpu_index(CPUArchState *env) +{ +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL) + return env->host_tid; +#else + return env->cpu_index + 1; +#endif +} + #endif #ifdef CONFIG_USER_ONLY diff --git a/hmp-commands.hx b/hmp-commands.hx index 18cb415ac4..f5d9d91de8 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -878,6 +878,34 @@ server will ask the spice/vnc client to automatically reconnect using the new parameters (if specified) once the vm migration finished successfully. ETEXI +#if defined(CONFIG_HAVE_CORE_DUMP) + { + .name = "dump-guest-memory", + .args_type = "paging:-p,protocol:s,begin:i?,length:i?", + .params = "[-p] protocol [begin] [length]", + .help = "dump guest memory to file" + "\n\t\t\t begin(optional): the starting physical address" + "\n\t\t\t length(optional): the memory size, in bytes", + .user_print = monitor_user_noop, + .mhandler.cmd = hmp_dump_guest_memory, + }, + + +STEXI +@item dump-guest-memory [-p] @var{protocol} @var{begin} @var{length} +@findex dump-guest-memory +Dump guest memory to @var{protocol}. The file can be processed with crash or +gdb. + protocol: destination file(started with "file:") or destination file + descriptor (started with "fd:") + paging: do paging to get guest's memory mapping + begin: the starting physical address. It's optional, and should be + specified with length together. + length: the memory size, in bytes. It's optional, and should be specified + with begin together. +ETEXI +#endif + { .name = "snapshot_blkdev", .args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?", @@ -1009,8 +1037,7 @@ ETEXI .args_type = "netdev:O", .params = "[user|tap|socket],id=str[,prop=value][,...]", .help = "add host network device", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_netdev_add, + .mhandler.cmd = hmp_netdev_add, }, STEXI @@ -1024,8 +1051,7 @@ ETEXI .args_type = "id:s", .params = "id", .help = "remove host network device", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_netdev_del, + .mhandler.cmd = hmp_netdev_del, }, STEXI @@ -14,6 +14,8 @@ */ #include "hmp.h" +#include "net.h" +#include "qemu-option.h" #include "qemu-timer.h" #include "qmp-commands.h" @@ -947,3 +949,53 @@ void hmp_device_del(Monitor *mon, const QDict *qdict) qmp_device_del(id, &err); hmp_handle_error(mon, &err); } + +void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) +{ + Error *errp = NULL; + int paging = qdict_get_try_bool(qdict, "paging", 0); + const char *file = qdict_get_str(qdict, "protocol"); + bool has_begin = qdict_haskey(qdict, "begin"); + bool has_length = qdict_haskey(qdict, "length"); + int64_t begin = 0; + int64_t length = 0; + + if (has_begin) { + begin = qdict_get_int(qdict, "begin"); + } + if (has_length) { + length = qdict_get_int(qdict, "length"); + } + + qmp_dump_guest_memory(paging, file, has_begin, begin, has_length, length, + &errp); + hmp_handle_error(mon, &errp); +} + +void hmp_netdev_add(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + QemuOpts *opts; + + opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err); + if (error_is_set(&err)) { + goto out; + } + + netdev_add(opts, &err); + if (error_is_set(&err)) { + qemu_opts_del(opts); + } + +out: + hmp_handle_error(mon, &err); +} + +void hmp_netdev_del(Monitor *mon, const QDict *qdict) +{ + const char *id = qdict_get_str(qdict, "id"); + Error *err = NULL; + + qmp_netdev_del(id, &err); + hmp_handle_error(mon, &err); +} @@ -61,5 +61,8 @@ void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict); void hmp_block_job_cancel(Monitor *mon, const QDict *qdict); void hmp_migrate(Monitor *mon, const QDict *qdict); void hmp_device_del(Monitor *mon, const QDict *qdict); +void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict); +void hmp_netdev_add(Monitor *mon, const QDict *qdict); +void hmp_netdev_del(Monitor *mon, const QDict *qdict); #endif diff --git a/hw/9pfs/Makefile.objs b/hw/9pfs/Makefile.objs new file mode 100644 index 0000000000..972df24050 --- /dev/null +++ b/hw/9pfs/Makefile.objs @@ -0,0 +1,9 @@ +hw-obj-y = virtio-9p.o +hw-obj-y += virtio-9p-local.o virtio-9p-xattr.o +hw-obj-y += virtio-9p-xattr-user.o virtio-9p-posix-acl.o +hw-obj-y += virtio-9p-coth.o cofs.o codir.o cofile.o +hw-obj-y += coxattr.o virtio-9p-synth.o +hw-obj-$(CONFIG_OPEN_BY_HANDLE) += virtio-9p-handle.o +hw-obj-y += virtio-9p-proxy.o + +obj-y += virtio-9p-device.o diff --git a/hw/Makefile.objs b/hw/Makefile.objs new file mode 100644 index 0000000000..3d7725934f --- /dev/null +++ b/hw/Makefile.objs @@ -0,0 +1,172 @@ +hw-obj-y = usb/ ide/ +hw-obj-y += loader.o +hw-obj-$(CONFIG_VIRTIO) += virtio-console.o +hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o +hw-obj-y += fw_cfg.o +hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o +hw-obj-$(CONFIG_PCI) += msix.o msi.o +hw-obj-$(CONFIG_PCI) += shpc.o +hw-obj-$(CONFIG_PCI) += slotid_cap.o +hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o +hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o +hw-obj-y += watchdog.o +hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o +hw-obj-$(CONFIG_ECC) += ecc.o +hw-obj-$(CONFIG_NAND) += nand.o +hw-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o +hw-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o + +hw-obj-$(CONFIG_M48T59) += m48t59.o +hw-obj-$(CONFIG_ESCC) += escc.o +hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o + +hw-obj-$(CONFIG_SERIAL) += serial.o +hw-obj-$(CONFIG_PARALLEL) += parallel.o +hw-obj-$(CONFIG_I8254) += i8254_common.o i8254.o +hw-obj-$(CONFIG_PCSPK) += pcspk.o +hw-obj-$(CONFIG_PCKBD) += pckbd.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_I82374) += i82374.o +hw-obj-$(CONFIG_HPET) += hpet.o +hw-obj-$(CONFIG_APPLESMC) += applesmc.o +hw-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o +hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o +hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o + +# PPC devices +hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o +hw-obj-$(CONFIG_I82378) += i82378.o +# Mac shared devices +hw-obj-$(CONFIG_MACIO) += macio.o +hw-obj-$(CONFIG_CUDA) += cuda.o +hw-obj-$(CONFIG_ADB) += adb.o +hw-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o +hw-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o +# OldWorld PowerMac +hw-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o +hw-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o +# NewWorld PowerMac +hw-obj-$(CONFIG_UNIN_PCI) += unin_pci.o +hw-obj-$(CONFIG_DEC_PCI) += dec_pci.o +# PowerPC E500 boards +hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o + +# MIPS devices +hw-obj-$(CONFIG_PIIX4) += piix4.o +hw-obj-$(CONFIG_G364FB) += g364fb.o +hw-obj-$(CONFIG_JAZZ_LED) += jazz_led.o + +# Xilinx devices +hw-obj-$(CONFIG_XILINX) += xilinx_intc.o +hw-obj-$(CONFIG_XILINX) += xilinx_timer.o +hw-obj-$(CONFIG_XILINX) += xilinx_uartlite.o +hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o +hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o + +# PCI watchdog devices +hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o + +hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o + +# PCI network cards +hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o +hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o +hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o +hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o +hw-obj-$(CONFIG_E1000_PCI) += e1000.o +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 + +# SCSI layer +hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o +hw-obj-$(CONFIG_ESP) += esp.o + +hw-obj-y += sysbus.o isa-bus.o +hw-obj-y += qdev-addr.o + +# VGA +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_VGA_CIRRUS) += cirrus_vga.o + +hw-obj-$(CONFIG_RC4030) += rc4030.o +hw-obj-$(CONFIG_DP8393X) += dp8393x.o +hw-obj-$(CONFIG_DS1225Y) += ds1225y.o +hw-obj-$(CONFIG_MIPSNET) += mipsnet.o + +# Sound +sound-obj-y = +sound-obj-$(CONFIG_SB16) += sb16.o +sound-obj-$(CONFIG_ES1370) += es1370.o +sound-obj-$(CONFIG_AC97) += ac97.o +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 + +$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 + +hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) + +hw-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ + +common-obj-y += usb/ +common-obj-y += irq.o +common-obj-$(CONFIG_PTIMER) += ptimer.o +common-obj-$(CONFIG_MAX7310) += max7310.o +common-obj-$(CONFIG_WM8750) += wm8750.o +common-obj-$(CONFIG_TWL92230) += twl92230.o +common-obj-$(CONFIG_TSC2005) += tsc2005.o +common-obj-$(CONFIG_LM832X) += lm832x.o +common-obj-$(CONFIG_TMP105) += tmp105.o +common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o +common-obj-$(CONFIG_SSD0303) += ssd0303.o +common-obj-$(CONFIG_SSD0323) += ssd0323.o +common-obj-$(CONFIG_ADS7846) += ads7846.o +common-obj-$(CONFIG_MAX111X) += max111x.o +common-obj-$(CONFIG_DS1338) += ds1338.o +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-$(CONFIG_SSI) += ssi.o +common-obj-$(CONFIG_SSI_SD) += ssi-sd.o +common-obj-$(CONFIG_SD) += sd.o +common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o +common-obj-y += bt-hci-csr.o +common-obj-y += msmouse.o ps2.o +common-obj-y += qdev.o qdev-properties.o qdev-monitor.o +common-obj-$(CONFIG_BRLAPI) += baum.o + +# xen backend driver support +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 + +# Per-target files +# virtio has to be here due to weird dependency between PCI and virtio-net. +# need to fix this properly +obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o +obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o virtio-scsi.o +obj-$(CONFIG_SOFTMMU) += vhost_net.o +obj-$(CONFIG_VHOST_NET) += vhost.o +obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ +obj-$(CONFIG_NO_PCI) += pci-stub.o +obj-$(CONFIG_VGA) += vga.o +obj-$(CONFIG_SOFTMMU) += device-hotplug.o +obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o + +# Inter-VM PCI shared memory +ifeq ($(CONFIG_PCI), y) +obj-$(CONFIG_KVM) += ivshmem.o +endif diff --git a/hw/alpha/Makefile.objs b/hw/alpha/Makefile.objs new file mode 100644 index 0000000000..af1c07fa7c --- /dev/null +++ b/hw/alpha/Makefile.objs @@ -0,0 +1,4 @@ +obj-y = mc146818rtc.o +obj-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 2f46e214cf..1d51570c88 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -16,7 +16,7 @@ /* 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(CPUARMState *env); +qemu_irq *arm_pic_init_cpu(ARMCPU *cpu); /* armv7m.c */ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, @@ -50,16 +50,16 @@ struct arm_boot_info { * perform any necessary CPU reset handling and set the PC for thei * secondary CPUs to point at this boot blob. */ - void (*write_secondary_boot)(CPUARMState *env, + void (*write_secondary_boot)(ARMCPU *cpu, const struct arm_boot_info *info); - void (*secondary_cpu_reset_hook)(CPUARMState *env, + void (*secondary_cpu_reset_hook)(ARMCPU *cpu, const struct arm_boot_info *info); /* Used internally by arm_boot.c */ int is_linux; target_phys_addr_t initrd_size; target_phys_addr_t entry; }; -void arm_load_kernel(CPUARMState *env, struct arm_boot_info *info); +void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info); /* Multiplication factor to convert from system clock ticks to qemu timer ticks. */ diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs new file mode 100644 index 0000000000..a0ff6a62d6 --- /dev/null +++ b/hw/arm/Makefile.objs @@ -0,0 +1,40 @@ +obj-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o +obj-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o +obj-y += versatile_pci.o +obj-y += versatile_i2c.o +obj-y += cadence_uart.o +obj-y += cadence_ttc.o +obj-y += cadence_gem.o +obj-y += xilinx_zynq.o zynq_slcr.o +obj-y += arm_gic.o +obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o +obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o +obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o +obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o +obj-y += arm_l2x0.o +obj-y += arm_mptimer.o a15mpcore.o +obj-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o +obj-y += highbank.o +obj-y += pl061.o +obj-y += xgmac.o +obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o +obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o +obj-y += gumstix.o +obj-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o +obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ + omap_gpio.o omap_intc.o omap_uart.o +obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ + omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o +obj-y += omap_sx1.o palm.o tsc210x.o +obj-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o +obj-y += mst_fpga.o mainstone.o +obj-y += z2.o +obj-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o +obj-y += framebuffer.o +obj-y += vexpress.o +obj-y += strongarm.o +obj-y += collie.o +obj-y += pl041.o lm4549.o +obj-$(CONFIG_FDT) += ../device_tree.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 7447f5c169..d0e643ba11 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -59,7 +59,7 @@ static uint32_t smpboot[] = { 0 /* bootreg: Boot register address is held here */ }; -static void default_write_secondary(CPUARMState *env, +static void default_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; @@ -72,9 +72,11 @@ static void default_write_secondary(CPUARMState *env, info->smp_loader_start); } -static void default_reset_secondary(CPUARMState *env, +static void default_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { + CPUARMState *env = &cpu->env; + stl_phys_notdirty(info->smp_bootreg_addr, 0); env->regs[15] = info->smp_loader_start; } @@ -274,10 +276,11 @@ static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo) static void do_cpu_reset(void *opaque) { - CPUARMState *env = opaque; + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; const struct arm_boot_info *info = env->boot_info; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); if (info) { if (!info->is_linux) { /* Jump to the entry point. */ @@ -294,14 +297,15 @@ static void do_cpu_reset(void *opaque) } } } else { - info->secondary_cpu_reset_hook(env, info); + info->secondary_cpu_reset_hook(cpu, info); } } } } -void arm_load_kernel(CPUARMState *env, struct arm_boot_info *info) +void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) { + CPUARMState *env = &cpu->env; int kernel_size; int initrd_size; int n; @@ -400,13 +404,14 @@ void arm_load_kernel(CPUARMState *env, struct arm_boot_info *info) rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader), info->loader_start); if (info->nb_cpus > 1) { - info->write_secondary_boot(env, info); + info->write_secondary_boot(cpu, info); } } info->is_linux = is_linux; for (; env; env = env->next_cpu) { + cpu = arm_env_get_cpu(env); env->boot_info = info; - qemu_register_reset(do_cpu_reset, env); + qemu_register_reset(do_cpu_reset, cpu); } } diff --git a/hw/arm_pic.c b/hw/arm_pic.c index 109496528c..ffb4d4171a 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -13,7 +13,9 @@ /* Input 0 is IRQ and input 1 is FIQ. */ static void arm_pic_cpu_handler(void *opaque, int irq, int level) { - CPUARMState *env = (CPUARMState *)opaque; + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + switch (irq) { case ARM_PIC_CPU_IRQ: if (level) @@ -32,7 +34,7 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level) } } -qemu_irq *arm_pic_init_cpu(CPUARMState *env) +qemu_irq *arm_pic_init_cpu(ARMCPU *cpu) { - return qemu_allocate_irqs(arm_pic_cpu_handler, env, 2); + return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2); } diff --git a/hw/armv7m.c b/hw/armv7m.c index 4aac076e48..8cec78db96 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -149,7 +149,9 @@ static void armv7m_bitband_init(void) static void armv7m_reset(void *opaque) { - cpu_state_reset((CPUARMState *)opaque); + ARMCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); } /* Init CPU and memory for a v7-M based board. @@ -160,6 +162,7 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, int flash_size, int sram_size, const char *kernel_filename, const char *cpu_model) { + ARMCPU *cpu; CPUARMState *env; DeviceState *nvic; /* FIXME: make this local state. */ @@ -177,13 +180,15 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, flash_size *= 1024; sram_size *= 1024; - if (!cpu_model) + if (cpu_model == NULL) { cpu_model = "cortex-m3"; - env = cpu_init(cpu_model); - if (!env) { + } + cpu = cpu_arm_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; #if 0 /* > 32Mb SRAM gets complicated because it overlaps the bitband area. @@ -210,7 +215,7 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, nvic = qdev_create(NULL, "armv7m_nvic"); env->nvic = nvic; qdev_init_nofail(nvic); - cpu_pic = arm_pic_init_cpu(env); + cpu_pic = arm_pic_init_cpu(cpu); sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); for (i = 0; i < 64; i++) { pic[i] = qdev_get_gpio_in(nvic, i); @@ -241,7 +246,7 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, vmstate_register_ram_global(hack); memory_region_add_subregion(address_space_mem, 0xfffff000, hack); - qemu_register_reset(armv7m_reset, env); + qemu_register_reset(armv7m_reset, cpu); return pic; } diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index 2304e3533a..eab6327bed 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -247,6 +247,7 @@ void axisdev88_init (ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { + CRISCPU *cpu; CPUCRISState *env; DeviceState *dev; SysBusDevice *s; @@ -263,7 +264,8 @@ void axisdev88_init (ram_addr_t ram_size, if (cpu_model == NULL) { cpu_model = "crisv32"; } - env = cpu_init(cpu_model); + cpu = cpu_cris_init(cpu_model); + env = &cpu->env; /* allocate RAM */ memory_region_init_ram(phys_ram, "axisdev88.ram", ram_size); @@ -344,7 +346,7 @@ void axisdev88_init (ram_addr_t ram_size, li.image_filename = kernel_filename; li.cmdline = kernel_cmdline; - cris_load_image(env, &li); + cris_load_image(cpu, &li); } static QEMUMachine axisdev88_machine = { diff --git a/hw/collie.c b/hw/collie.c index 42f4310816..56f89a9f2e 100644 --- a/hw/collie.c +++ b/hw/collie.c @@ -54,7 +54,7 @@ static void collie_init(ram_addr_t ram_size, collie_binfo.kernel_cmdline = kernel_cmdline; collie_binfo.initrd_filename = initrd_filename; collie_binfo.board_id = 0x208; - arm_load_kernel(s->env, &collie_binfo); + arm_load_kernel(s->cpu, &collie_binfo); } static QEMUMachine collie_machine = { diff --git a/hw/cris-boot.c b/hw/cris-boot.c index ca6c52fa8e..b21326fade 100644 --- a/hw/cris-boot.c +++ b/hw/cris-boot.c @@ -29,12 +29,13 @@ static void main_cpu_reset(void *opaque) { - CPUCRISState *env = opaque; + CRISCPU *cpu = opaque; + CPUCRISState *env = &cpu->env; struct cris_load_info *li; li = env->load_info; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); if (!li) { /* nothing more to do. */ @@ -60,8 +61,9 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return addr - 0x80000000LL; } -void cris_load_image(CPUCRISState *env, struct cris_load_info *li) +void cris_load_image(CRISCPU *cpu, struct cris_load_info *li) { + CPUCRISState *env = &cpu->env; uint64_t entry, high; int kcmdline_len; int image_size; @@ -92,5 +94,5 @@ void cris_load_image(CPUCRISState *env, struct cris_load_info *li) } pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline); } - qemu_register_reset(main_cpu_reset, env); + qemu_register_reset(main_cpu_reset, cpu); } diff --git a/hw/cris-boot.h b/hw/cris-boot.h index ecb9779e49..0a2c242411 100644 --- a/hw/cris-boot.h +++ b/hw/cris-boot.h @@ -8,4 +8,4 @@ struct cris_load_info target_phys_addr_t entry; }; -void cris_load_image(CPUCRISState *env, struct cris_load_info *li); +void cris_load_image(CRISCPU *cpu, struct cris_load_info *li); diff --git a/hw/cris/Makefile.objs b/hw/cris/Makefile.objs new file mode 100644 index 0000000000..aa9298a0ed --- /dev/null +++ b/hw/cris/Makefile.objs @@ -0,0 +1,13 @@ +# Boards +obj-y = cris_pic_cpu.o +obj-y += cris-boot.o +obj-y += axis_dev88.o + +# IO blocks +obj-y += etraxfs_dma.o +obj-y += etraxfs_pic.o +obj-y += etraxfs_eth.o +obj-y += etraxfs_timer.o +obj-y += etraxfs_ser.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/exynos4210.c b/hw/exynos4210.c index afc4bdc7e0..dd14d01b01 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -65,7 +65,7 @@ static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; -void exynos4210_write_secondary(CPUARMState *env, +void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; @@ -107,13 +107,14 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, SysBusDevice *busdev; for (n = 0; n < EXYNOS4210_NCPUS; n++) { - s->env[n] = cpu_init("cortex-a9"); - if (!s->env[n]) { + s->cpu[n] = cpu_arm_init("cortex-a9"); + if (!s->cpu[n]) { fprintf(stderr, "Unable to find CPU %d definition\n", n); exit(1); } + /* Create PIC controller for each processor instance */ - irqp = arm_pic_init_cpu(s->env[n]); + irqp = arm_pic_init_cpu(s->cpu[n]); /* * Get GICs gpio_in cpu_irq to connect a combiner to them later. diff --git a/hw/exynos4210.h b/hw/exynos4210.h index f7c7027302..b1b4609054 100644 --- a/hw/exynos4210.h +++ b/hw/exynos4210.h @@ -83,7 +83,7 @@ typedef struct Exynos4210Irq { } Exynos4210Irq; typedef struct Exynos4210State { - CPUARMState * env[EXYNOS4210_NCPUS]; + ARMCPU *cpu[EXYNOS4210_NCPUS]; Exynos4210Irq irqs; qemu_irq *irq_table; @@ -97,7 +97,7 @@ typedef struct Exynos4210State { MemoryRegion bootreg_mem; } Exynos4210State; -void exynos4210_write_secondary(CPUARMState *env, +void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info); Exynos4210State *exynos4210_init(MemoryRegion *system_mem, diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index ea32c51dcc..e5c2a5f388 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -138,7 +138,7 @@ static void nuri_init(ram_addr_t ram_size, exynos4_boards_init_common(kernel_filename, kernel_cmdline, initrd_filename, EXYNOS4_BOARD_NURI); - arm_load_kernel(first_cpu, &exynos4_board_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); } static void smdkc210_init(ram_addr_t ram_size, @@ -151,7 +151,7 @@ static void smdkc210_init(ram_addr_t ram_size, lan9215_init(SMDK_LAN9118_BASE_ADDR, qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)])); - arm_load_kernel(first_cpu, &exynos4_board_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); } static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = { diff --git a/hw/highbank.c b/hw/highbank.c index 4d6d728a28..4bdea5df7d 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -36,7 +36,7 @@ /* Board init. */ -static void hb_write_secondary(CPUARMState *env, const struct arm_boot_info *info) +static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; uint32_t smpboot[] = { @@ -60,8 +60,10 @@ static void hb_write_secondary(CPUARMState *env, const struct arm_boot_info *inf rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); } -static void hb_reset_secondary(CPUARMState *env, const struct arm_boot_info *info) +static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { + CPUARMState *env = &cpu->env; + switch (info->nb_cpus) { case 4: stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0); @@ -190,7 +192,6 @@ static void highbank_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUARMState *env = NULL; DeviceState *dev; SysBusDevice *busdev; qemu_irq *irqp; @@ -213,10 +214,10 @@ static void highbank_init(ram_addr_t ram_size, fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - env = &cpu->env; + /* This will become a QOM property eventually */ cpu->reset_cbar = GIC_BASE_ADDR; - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } @@ -316,7 +317,7 @@ static void highbank_init(ram_addr_t ram_size, highbank_binfo.loader_start = 0; highbank_binfo.write_secondary_boot = hb_write_secondary; highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary; - arm_load_kernel(first_cpu, &highbank_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &highbank_binfo); } static QEMUMachine highbank_machine = { diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs new file mode 100644 index 0000000000..d43f1df5f0 --- /dev/null +++ b/hw/i386/Makefile.objs @@ -0,0 +1,13 @@ +obj-y += mc146818rtc.o pc.o +obj-y += apic_common.o apic.o kvmvapic.o +obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o +obj-y += vmport.o +obj-y += pci-hotplug.o smbios.o wdt_ib700.o +obj-y += debugcon.o multiboot.o +obj-y += pc_piix.o +obj-y += pc_sysfw.o +obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o +obj-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o kvm/i8254.o +obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/ide/Makefile.objs b/hw/ide/Makefile.objs new file mode 100644 index 0000000000..cf718dd016 --- /dev/null +++ b/hw/ide/Makefile.objs @@ -0,0 +1,10 @@ +hw-obj-$(CONFIG_IDE_CORE) += core.o atapi.o +hw-obj-$(CONFIG_IDE_QDEV) += qdev.o +hw-obj-$(CONFIG_IDE_PCI) += pci.o +hw-obj-$(CONFIG_IDE_ISA) += isa.o +hw-obj-$(CONFIG_IDE_PIIX) += piix.o +hw-obj-$(CONFIG_IDE_CMD646) += cmd646.o +hw-obj-$(CONFIG_IDE_MACIO) += macio.o +hw-obj-$(CONFIG_IDE_VIA) += via.o +hw-obj-$(CONFIG_AHCI) += ahci.o +hw-obj-$(CONFIG_AHCI) += ich.o diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 9bdb9e62d6..deacbf4d0d 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -443,7 +443,7 @@ static void integratorcp_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUARMState *env; + ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *ram_alias = g_new(MemoryRegion, 1); @@ -452,13 +452,15 @@ static void integratorcp_init(ram_addr_t ram_size, DeviceState *dev; int i; - if (!cpu_model) + if (!cpu_model) { cpu_model = "arm926"; - env = cpu_init(cpu_model); - if (!env) { + } + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + memory_region_init_ram(ram, "integrator.ram", ram_size); vmstate_register_ram_global(ram); /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ @@ -474,7 +476,7 @@ static void integratorcp_init(ram_addr_t ram_size, qdev_init_nofail(dev); sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); - cpu_pic = arm_pic_init_cpu(env); + cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("integrator_pic", 0x14000000, cpu_pic[ARM_PIC_CPU_IRQ], cpu_pic[ARM_PIC_CPU_FIQ], NULL); @@ -500,7 +502,7 @@ static void integratorcp_init(ram_addr_t ram_size, integrator_binfo.kernel_filename = kernel_filename; integrator_binfo.kernel_cmdline = kernel_cmdline; integrator_binfo.initrd_filename = initrd_filename; - arm_load_kernel(env, &integrator_binfo); + arm_load_kernel(cpu, &integrator_binfo); } static QEMUMachine integratorcp_machine = { diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c index 8ba4079025..80e3e48333 100644 --- a/hw/kvm/apic.c +++ b/hw/kvm/apic.c @@ -30,7 +30,7 @@ void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic) APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); int i; - memset(kapic, 0, sizeof(kapic)); + memset(kapic, 0, sizeof(*kapic)); kvm_apic_set_reg(kapic, 0x2, s->id << 24); kvm_apic_set_reg(kapic, 0x8, s->tpr); kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24); diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c index bb5fe07d1e..c5d3711a04 100644 --- a/hw/kvm/i8254.c +++ b/hw/kvm/i8254.c @@ -23,31 +23,63 @@ * THE SOFTWARE. */ #include "qemu-timer.h" +#include "sysemu.h" #include "hw/i8254.h" #include "hw/i8254_internal.h" #include "kvm.h" #define KVM_PIT_REINJECT_BIT 0 +#define CALIBRATION_ROUNDS 3 + typedef struct KVMPITState { PITCommonState pit; LostTickPolicy lost_tick_policy; + bool state_valid; } KVMPITState; -static void kvm_pit_get(PITCommonState *s) +static int64_t abs64(int64_t v) { + return v < 0 ? -v : v; +} + +static void kvm_pit_get(PITCommonState *pit) +{ + KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit); struct kvm_pit_state2 kpit; struct kvm_pit_channel_state *kchan; struct PITChannelState *sc; + int64_t offset, clock_offset; + struct timespec ts; int i, ret; + if (s->state_valid) { + return; + } + + /* + * Measure the delta between CLOCK_MONOTONIC, the base used for + * kvm_pit_channel_state::count_load_time, and vm_clock. Take the + * minimum of several samples to filter out scheduling noise. + */ + clock_offset = INT64_MAX; + for (i = 0; i < CALIBRATION_ROUNDS; i++) { + offset = qemu_get_clock_ns(vm_clock); + clock_gettime(CLOCK_MONOTONIC, &ts); + offset -= ts.tv_nsec; + offset -= (int64_t)ts.tv_sec * 1000000000; + if (abs64(offset) < abs64(clock_offset)) { + clock_offset = offset; + } + } + if (kvm_has_pit_state2()) { ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit); if (ret < 0) { fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret)); abort(); } - s->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY; + pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY; } else { /* * kvm_pit_state2 is superset of kvm_pit_state struct, @@ -61,7 +93,7 @@ static void kvm_pit_get(PITCommonState *s) } for (i = 0; i < 3; i++) { kchan = &kpit.channels[i]; - sc = &s->channels[i]; + sc = &pit->channels[i]; sc->count = kchan->count; sc->latched_count = kchan->latched_count; sc->count_latched = kchan->count_latched; @@ -74,10 +106,10 @@ static void kvm_pit_get(PITCommonState *s) sc->mode = kchan->mode; sc->bcd = kchan->bcd; sc->gate = kchan->gate; - sc->count_load_time = kchan->count_load_time; + sc->count_load_time = kchan->count_load_time + clock_offset; } - sc = &s->channels[0]; + sc = &pit->channels[0]; sc->next_transition_time = pit_get_next_transition_time(sc, sc->count_load_time); } @@ -173,6 +205,19 @@ static void kvm_pit_irq_control(void *opaque, int n, int enable) kvm_pit_put(pit); } +static void kvm_pit_vm_state_change(void *opaque, int running, + RunState state) +{ + KVMPITState *s = opaque; + + if (running) { + s->state_valid = false; + } else { + kvm_pit_get(&s->pit); + s->state_valid = true; + } +} + static int kvm_pit_initfn(PITCommonState *pit) { KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit); @@ -215,6 +260,8 @@ static int kvm_pit_initfn(PITCommonState *pit) qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1); + qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s); + return 0; } diff --git a/hw/leon3.c b/hw/leon3.c index 0a5ff165a1..878d3aa557 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -42,16 +42,16 @@ #define MAX_PILS 16 typedef struct ResetData { - CPUSPARCState *env; + SPARCCPU *cpu; uint32_t entry; /* save kernel entry in case of reset */ } ResetData; static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; - CPUSPARCState *env = s->env; + CPUSPARCState *env = &s->cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(s->cpu)); env->halted = 0; env->pc = s->entry; @@ -101,6 +101,7 @@ static void leon3_generic_hw_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { + SPARCCPU *cpu; CPUSPARCState *env; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -117,17 +118,18 @@ static void leon3_generic_hw_init(ram_addr_t ram_size, cpu_model = "LEON3"; } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_sparc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); exit(1); } + env = &cpu->env; cpu_sparc_set_id(env, 0); /* Reset data */ reset_info = g_malloc0(sizeof(ResetData)); - reset_info->env = env; + reset_info->cpu = cpu; qemu_register_reset(main_cpu_reset, reset_info); /* Allocate IRQ manager */ diff --git a/hw/lm32/Makefile.objs b/hw/lm32/Makefile.objs new file mode 100644 index 0000000000..4e1843c11d --- /dev/null +++ b/hw/lm32/Makefile.objs @@ -0,0 +1,23 @@ +# LM32 boards +obj-y += lm32_boards.o +obj-y += milkymist.o + +# LM32 peripherals +obj-y += lm32_pic.o +obj-y += lm32_juart.o +obj-y += lm32_timer.o +obj-y += lm32_uart.o +obj-y += lm32_sys.o +obj-y += milkymist-ac97.o +obj-y += milkymist-hpdmc.o +obj-y += milkymist-memcard.o +obj-y += milkymist-minimac2.o +obj-y += milkymist-pfpu.o +obj-y += milkymist-softusb.o +obj-y += milkymist-sysctl.o +obj-$(CONFIG_OPENGL) += milkymist-tmu2.o +obj-y += milkymist-uart.o +obj-y += milkymist-vgafb.o +obj-y += framebuffer.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c index 4dd4f0ab90..b76d8008be 100644 --- a/hw/lm32_boards.c +++ b/hw/lm32_boards.c @@ -31,7 +31,7 @@ #include "exec-memory.h" typedef struct { - CPULM32State *env; + LM32CPU *cpu; target_phys_addr_t bootstrap_pc; target_phys_addr_t flash_base; target_phys_addr_t hwsetup_base; @@ -54,9 +54,9 @@ static void cpu_irq_handler(void *opaque, int irq, int level) static void main_cpu_reset(void *opaque) { ResetInfo *reset_info = opaque; - CPULM32State *env = reset_info->env; + CPULM32State *env = &reset_info->cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(reset_info->cpu)); /* init defaults */ env->pc = (uint32_t)reset_info->bootstrap_pc; @@ -75,6 +75,7 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { + LM32CPU *cpu; CPULM32State *env; DriveInfo *dinfo; MemoryRegion *address_space_mem = get_system_memory(); @@ -101,8 +102,9 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used, if (cpu_model == NULL) { cpu_model = "lm32-full"; } - env = cpu_init(cpu_model); - reset_info->env = env; + cpu = cpu_lm32_init(cpu_model); + env = &cpu->env; + reset_info->cpu = cpu; reset_info->flash_base = flash_base; @@ -163,6 +165,7 @@ static void lm32_uclinux_init(ram_addr_t ram_size_not_used, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { + LM32CPU *cpu; CPULM32State *env; DriveInfo *dinfo; MemoryRegion *address_space_mem = get_system_memory(); @@ -196,8 +199,9 @@ static void lm32_uclinux_init(ram_addr_t ram_size_not_used, if (cpu_model == NULL) { cpu_model = "lm32-full"; } - env = cpu_init(cpu_model); - reset_info->env = env; + cpu = cpu_lm32_init(cpu_model); + env = &cpu->env; + reset_info->cpu = cpu; reset_info->flash_base = flash_base; diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs new file mode 100644 index 0000000000..93b6d25baf --- /dev/null +++ b/hw/m68k/Makefile.objs @@ -0,0 +1,4 @@ +obj-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o +obj-y += dummy_m68k.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/mainstone.c b/hw/mainstone.c index 27f59009f6..97687b6eeb 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -102,7 +102,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, { uint32_t sector_len = 256 * 1024; target_phys_addr_t mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; - PXA2xxState *cpu; + PXA2xxState *mpu; DeviceState *mst_irq; DriveInfo *dinfo; int i; @@ -113,7 +113,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, cpu_model = "pxa270-c5"; /* Setup CPU & memory */ - cpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model); + mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model); memory_region_init_ram(rom, "mainstone.rom", MAINSTONE_ROM); vmstate_register_ram_global(rom); memory_region_set_readonly(rom, true); @@ -145,19 +145,19 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, } mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS, - qdev_get_gpio_in(cpu->gpio, 0)); + qdev_get_gpio_in(mpu->gpio, 0)); /* setup keypad */ printf("map addr %p\n", &map); - pxa27x_register_keypad(cpu->kp, map, 0xe0); + pxa27x_register_keypad(mpu->kp, map, 0xe0); /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ)); + pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ)); - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], + pxa2xx_pcmcia_set_irq_cb(mpu->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], + pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1], qdev_get_gpio_in(mst_irq, S1_IRQ), qdev_get_gpio_in(mst_irq, S1_CD_IRQ)); @@ -168,7 +168,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, mainstone_binfo.kernel_cmdline = kernel_cmdline; mainstone_binfo.initrd_filename = initrd_filename; mainstone_binfo.board_id = arm_id; - arm_load_kernel(cpu->env, &mainstone_binfo); + arm_load_kernel(mpu->cpu, &mainstone_binfo); } static void mainstone_init(ram_addr_t ram_size, diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 9c64e0ae25..3777f858a1 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -599,13 +599,6 @@ static const MemoryRegionOps cmos_ops = { .old_portio = cmos_portio }; -// FIXME add int32 visitor -static void visit_type_int32(Visitor *v, int *value, const char *name, Error **errp) -{ - int64_t val = *value; - visit_type_int(v, &val, name, errp); -} - static void rtc_get_date(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs new file mode 100644 index 0000000000..274d2c543e --- /dev/null +++ b/hw/microblaze/Makefile.objs @@ -0,0 +1,9 @@ +obj-y = petalogix_s3adsp1800_mmu.o +obj-y += petalogix_ml605_mmu.o +obj-y += microblaze_boot.o + +obj-y += microblaze_pic_cpu.o +obj-y += xilinx_ethlite.o +obj-$(CONFIG_FDT) += ../device_tree.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/microblaze_boot.c b/hw/microblaze_boot.c index b4fbb10dd0..1030e9c8ed 100644 --- a/hw/microblaze_boot.c +++ b/hw/microblaze_boot.c @@ -35,7 +35,7 @@ static struct { - void (*machine_cpu_reset)(CPUMBState *); + void (*machine_cpu_reset)(MicroBlazeCPU *); uint32_t bootstrap_pc; uint32_t cmdline; uint32_t fdt; @@ -43,14 +43,15 @@ static struct static void main_cpu_reset(void *opaque) { - CPUMBState *env = opaque; + MicroBlazeCPU *cpu = opaque; + CPUMBState *env = &cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); env->regs[5] = boot_info.cmdline; env->regs[7] = boot_info.fdt; env->sregs[SR_PC] = boot_info.bootstrap_pc; if (boot_info.machine_cpu_reset) { - boot_info.machine_cpu_reset(env); + boot_info.machine_cpu_reset(cpu); } } @@ -99,11 +100,10 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return addr - 0x30000000LL; } -void microblaze_load_kernel(CPUMBState *env, target_phys_addr_t ddr_base, +void microblaze_load_kernel(MicroBlazeCPU *cpu, target_phys_addr_t ddr_base, uint32_t ramsize, const char *dtb_filename, - void (*machine_cpu_reset)(CPUMBState *)) + void (*machine_cpu_reset)(MicroBlazeCPU *)) { - QemuOpts *machine_opts; const char *kernel_filename = NULL; const char *kernel_cmdline = NULL; @@ -122,7 +122,7 @@ void microblaze_load_kernel(CPUMBState *env, target_phys_addr_t ddr_base, } boot_info.machine_cpu_reset = machine_cpu_reset; - qemu_register_reset(main_cpu_reset, env); + qemu_register_reset(main_cpu_reset, cpu); if (kernel_filename) { int kernel_size; diff --git a/hw/microblaze_boot.h b/hw/microblaze_boot.h index bf9d136f12..c9a3064d27 100644 --- a/hw/microblaze_boot.h +++ b/hw/microblaze_boot.h @@ -3,8 +3,8 @@ #include "hw.h" -void microblaze_load_kernel(CPUMBState *env, target_phys_addr_t ddr_base, +void microblaze_load_kernel(MicroBlazeCPU *cpu, target_phys_addr_t ddr_base, uint32_t ramsize, const char *dtb_filename, - void (*machine_cpu_reset)(CPUMBState *)); + void (*machine_cpu_reset)(MicroBlazeCPU *)); #endif /* __MICROBLAZE_BOOT __ */ diff --git a/hw/milkymist.c b/hw/milkymist.c index 8bb6a97b22..2e7235b4b3 100644 --- a/hw/milkymist.c +++ b/hw/milkymist.c @@ -37,7 +37,7 @@ #define KERNEL_LOAD_ADDR 0x40000000 typedef struct { - CPULM32State *env; + LM32CPU *cpu; target_phys_addr_t bootstrap_pc; target_phys_addr_t flash_base; target_phys_addr_t initrd_base; @@ -59,9 +59,9 @@ static void cpu_irq_handler(void *opaque, int irq, int level) static void main_cpu_reset(void *opaque) { ResetInfo *reset_info = opaque; - CPULM32State *env = reset_info->env; + CPULM32State *env = &reset_info->cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(reset_info->cpu)); /* init defaults */ env->pc = reset_info->bootstrap_pc; @@ -79,6 +79,7 @@ milkymist_init(ram_addr_t ram_size_not_used, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { + LM32CPU *cpu; CPULM32State *env; int kernel_size; DriveInfo *dinfo; @@ -105,8 +106,9 @@ milkymist_init(ram_addr_t ram_size_not_used, if (cpu_model == NULL) { cpu_model = "lm32-full"; } - env = cpu_init(cpu_model); - reset_info->env = env; + cpu = cpu_lm32_init(cpu_model); + env = &cpu->env; + reset_info->cpu = cpu; cpu_lm32_set_phys_msb_ignore(env, 1); diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs new file mode 100644 index 0000000000..29a5d0db04 --- /dev/null +++ b/hw/mips/Makefile.objs @@ -0,0 +1,6 @@ +obj-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o +obj-y += mips_addr.o mips_timer.o mips_int.o +obj-y += gt64xxx.o mc146818rtc.o +obj-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 1a8df10429..38e4b86150 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -198,9 +198,10 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, int64_t kernel_a static void main_cpu_reset(void *opaque) { - CPUMIPSState *env = opaque; + MIPSCPU *cpu = opaque; + CPUMIPSState *env = &cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); /* TODO: 2E reset stuff */ if (loaderparams.kernel_filename) { env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); @@ -272,19 +273,21 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, i2c_bus *smbus; int i; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + MIPSCPU *cpu; CPUMIPSState *env; /* init CPUs */ if (cpu_model == NULL) { cpu_model = "Loongson-2E"; } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; - qemu_register_reset(main_cpu_reset, env); + qemu_register_reset(main_cpu_reset, cpu); /* fulong 2e has 256M ram. */ ram_size = 256 * 1024 * 1024; diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index a6bc7badff..bf1b799c4d 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -50,8 +50,9 @@ enum jazz_model_e static void main_cpu_reset(void *opaque) { - CPUMIPSState *env = opaque; - cpu_state_reset(env); + MIPSCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); } static uint64_t rtc_read(void *opaque, target_phys_addr_t addr, unsigned size) @@ -112,6 +113,7 @@ static void mips_jazz_init(MemoryRegion *address_space, { char *filename; int bios_size, n; + MIPSCPU *cpu; CPUMIPSState *env; qemu_irq *rc4030, *i8259; rc4030_dma *dmas; @@ -140,12 +142,13 @@ static void mips_jazz_init(MemoryRegion *address_space, cpu_model = "24Kf"; #endif } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - qemu_register_reset(main_cpu_reset, env); + env = &cpu->env; + qemu_register_reset(main_cpu_reset, cpu); /* allocate RAM */ memory_region_init_ram(ram, "mips_jazz.ram", ram_size); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 4752bb2865..dfd7b6b113 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -751,8 +751,10 @@ static void malta_mips_config(CPUMIPSState *env) static void main_cpu_reset(void *opaque) { - CPUMIPSState *env = opaque; - cpu_state_reset(env); + MIPSCPU *cpu = opaque; + CPUMIPSState *env = &cpu->env; + + cpu_reset(CPU(cpu)); /* The bootloader does not need to be rewritten as it is located in a read only location. The kernel location and the arguments table @@ -788,6 +790,7 @@ void mips_malta_init (ram_addr_t ram_size, int64_t kernel_entry; PCIBus *pci_bus; ISABus *isa_bus; + MIPSCPU *cpu; CPUMIPSState *env; qemu_irq *isa_irq; qemu_irq *cpu_exit_irq; @@ -825,15 +828,17 @@ void mips_malta_init (ram_addr_t ram_size, } for (i = 0; i < smp_cpus; i++) { - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; + /* 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, cpu); } env = first_cpu; diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 1ea7b58323..eb03047433 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -46,7 +46,7 @@ static struct _loaderparams { } loaderparams; typedef struct ResetData { - CPUMIPSState *env; + MIPSCPU *cpu; uint64_t vector; } ResetData; @@ -105,9 +105,9 @@ static int64_t load_kernel(void) static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; - CPUMIPSState *env = s->env; + CPUMIPSState *env = &s->cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(s->cpu)); env->active_tc.PC = s->vector & ~(target_ulong)1; if (s->vector & 1) { env->hflags |= MIPS_HFLAG_M16; @@ -140,6 +140,7 @@ mips_mipssim_init (ram_addr_t ram_size, MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios = g_new(MemoryRegion, 1); + MIPSCPU *cpu; CPUMIPSState *env; ResetData *reset_info; int bios_size; @@ -152,13 +153,15 @@ mips_mipssim_init (ram_addr_t ram_size, cpu_model = "24Kf"; #endif } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; + reset_info = g_malloc0(sizeof(ResetData)); - reset_info->env = env; + reset_info->cpu = cpu; reset_info->vector = env->active_tc.PC; qemu_register_reset(main_cpu_reset, reset_info); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index e2da49c09d..d68599965a 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -65,7 +65,7 @@ static const MemoryRegionOps mips_qemu_ops = { }; typedef struct ResetData { - CPUMIPSState *env; + MIPSCPU *cpu; uint64_t vector; } ResetData; @@ -143,9 +143,9 @@ static int64_t load_kernel(void) static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; - CPUMIPSState *env = s->env; + CPUMIPSState *env = &s->cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(s->cpu)); env->active_tc.PC = s->vector; } @@ -162,6 +162,7 @@ void mips_r4k_init (ram_addr_t ram_size, MemoryRegion *bios; MemoryRegion *iomem = g_new(MemoryRegion, 1); int bios_size; + MIPSCPU *cpu; CPUMIPSState *env; ResetData *reset_info; int i; @@ -179,13 +180,15 @@ void mips_r4k_init (ram_addr_t ram_size, cpu_model = "24Kf"; #endif } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; + reset_info = g_malloc0(sizeof(ResetData)); - reset_info->env = env; + reset_info->cpu = cpu; reset_info->vector = env->active_tc.PC; qemu_register_reset(main_cpu_reset, reset_info); diff --git a/hw/musicpal.c b/hw/musicpal.c index c9f845a3f2..f14f20d689 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1513,7 +1513,7 @@ static void musicpal_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUARMState *env; + ARMCPU *cpu; qemu_irq *cpu_pic; qemu_irq pic[32]; DeviceState *dev; @@ -1533,12 +1533,12 @@ static void musicpal_init(ram_addr_t ram_size, if (!cpu_model) { cpu_model = "arm926"; } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - cpu_pic = arm_pic_init_cpu(env); + cpu_pic = arm_pic_init_cpu(cpu); /* For now we use a fixed - the original - RAM size */ memory_region_init_ram(ram, "musicpal.ram", MP_RAM_DEFAULT_SIZE); @@ -1651,7 +1651,7 @@ static void musicpal_init(ram_addr_t ram_size, musicpal_binfo.kernel_filename = kernel_filename; musicpal_binfo.kernel_cmdline = kernel_cmdline; musicpal_binfo.initrd_filename = initrd_filename; - arm_load_kernel(env, &musicpal_binfo); + arm_load_kernel(cpu, &musicpal_binfo); } static QEMUMachine musicpal_machine = { diff --git a/hw/nseries.c b/hw/nseries.c index a5cfa8ccbc..fcc85466e7 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -37,7 +37,7 @@ /* Nokia N8x0 support */ struct n800_s { - struct omap_mpu_state_s *cpu; + struct omap_mpu_state_s *mpu; struct rfbi_chip_s blizzard; struct { @@ -135,10 +135,10 @@ 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); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]); + qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->mpu->mmc, 1); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]); - qemu_irq_lower(qdev_get_gpio_in(s->cpu->gpio, N800_BAT_COVER_GPIO)); + qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO)); } #define MAEMO_CAL_HEADER(...) \ @@ -179,8 +179,8 @@ static void n8x0_nand_setup(struct n800_s *s) } 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, + qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO)); + omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS, sysbus_mmio_get_region(sysbus_from_qdev(s->nand), 0)); otp_region = onenand_raw_otp(s->nand); @@ -192,13 +192,13 @@ static void n8x0_nand_setup(struct n800_s *s) static void n8x0_i2c_setup(struct n800_s *s) { DeviceState *dev; - qemu_irq tmp_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TMP105_GPIO); - i2c_bus *i2c = omap_i2c_bus(s->cpu->i2c[0]); + qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO); + i2c_bus *i2c = omap_i2c_bus(s->mpu->i2c[0]); /* Attach a menelaus PM chip */ dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR); qdev_connect_gpio_out(dev, 3, - qdev_get_gpio_in(s->cpu->ih[0], + qdev_get_gpio_in(s->mpu->ih[0], OMAP_INT_24XX_SYS_NIRQ)); qemu_system_powerdown = qdev_get_gpio_in(dev, 3); @@ -263,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 = 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); + qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO); + qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO); s->ts.chip = tsc2301_init(penirq, kbirq, dav); s->ts.opaque = s->ts.chip->opaque; @@ -283,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 = qdev_get_gpio_in(s->cpu->gpio, N810_TSC_TS_GPIO); + qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO); s->ts.opaque = tsc2005_init(pintdav); s->ts.txrx = tsc2005_txrx; @@ -375,7 +375,7 @@ static int n810_keys[0x80] = { static void n810_kbd_setup(struct n800_s *s) { - qemu_irq kbd_irq = qdev_get_gpio_in(s->cpu->gpio, N810_KEYBOARD_GPIO); + qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO); int i; for (i = 0; i < 0x80; i ++) @@ -388,7 +388,7 @@ 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. */ - s->kbd = i2c_create_slave(omap_i2c_bus(s->cpu->i2c[0]), + s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]), "lm8323", N810_LM8323_ADDR); qdev_connect_gpio_out(s->kbd, 0, kbd_irq); } @@ -679,8 +679,8 @@ static void n8x0_spi_setup(struct n800_s *s) void *tsc = s->ts.opaque; void *mipid = mipid_init(); - omap_mcspi_attach(s->cpu->mcspi[0], s->ts.txrx, tsc, 0); - omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, mipid, 1); + omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0); + omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1); } /* This task is normally performed by the bootloader. If we're loading @@ -735,20 +735,20 @@ static void n8x0_dss_setup(struct n800_s *s) s->blizzard.write = s1d13745_write; s->blizzard.read = s1d13745_read; - omap_rfbi_attach(s->cpu->dss, 0, &s->blizzard); + omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard); } static void n8x0_cbus_setup(struct n800_s *s) { - 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); + qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO); + qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO); + qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO); CBus *cbus = cbus_init(dat_out); - 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); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat); + qdev_connect_gpio_out(s->mpu->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)); @@ -757,14 +757,14 @@ static void n8x0_cbus_setup(struct n800_s *s) static void n8x0_uart_setup(struct n800_s *s) { CharDriverState *radio = uart_hci_init( - qdev_get_gpio_in(s->cpu->gpio, N8X0_BT_HOST_WKUP_GPIO)); + qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO)); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_RESET_GPIO, + qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO, csrhci_pins_get(radio)[csrhci_pin_reset]); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_WKUP_GPIO, + qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_WKUP_GPIO, csrhci_pins_get(radio)[csrhci_pin_wakeup]); - omap_uart_attach(s->cpu->uart[BT_UART], radio); + omap_uart_attach(s->mpu->uart[BT_UART], radio); } static void n8x0_usb_setup(struct n800_s *s) @@ -774,13 +774,13 @@ static void n8x0_usb_setup(struct n800_s *s) 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)); + qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO)); /* Using the NOR interface */ - omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_ASYNC_CS, + omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS, sysbus_mmio_get_region(dev, 0)); - omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_SYNC_CS, + omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS, sysbus_mmio_get_region(dev, 1)); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_TUSB_ENABLE_GPIO, + qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO, qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */ } @@ -1023,11 +1023,11 @@ static void n8x0_boot_init(void *opaque) n800_dss_init(&s->blizzard); /* CPU setup */ - s->cpu->env->GE = 0x5; + s->mpu->cpu->env.GE = 0x5; /* If the machine has a slided keyboard, open it */ if (s->kbd) - qemu_irq_raise(qdev_get_gpio_in(s->cpu->gpio, N810_SLIDE_GPIO)); + qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO)); } #define OMAP_TAG_NOKIA_BT 0x4e01 @@ -1281,7 +1281,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, int sdram_size = binfo->ram_size; DisplayState *ds; - s->cpu = omap2420_mpu_init(sysmem, sdram_size, cpu_model); + s->mpu = omap2420_mpu_init(sysmem, sdram_size, cpu_model); /* Setup peripherals * @@ -1329,7 +1329,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, binfo->kernel_filename = kernel_filename; binfo->kernel_cmdline = kernel_cmdline; binfo->initrd_filename = initrd_filename; - arm_load_kernel(s->cpu->env, binfo); + arm_load_kernel(s->mpu->cpu, binfo); qemu_register_reset(n8x0_boot_init, s); } @@ -1338,7 +1338,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, int rom_size; uint8_t nolo_tags[0x10000]; /* No, wait, better start at the ROM. */ - s->cpu->env->regs[15] = OMAP2_Q2_BASE + 0x400000; + s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; /* This is intended for loading the `secondary.bin' program from * Nokia images (the NOLO bootloader). The entry point seems @@ -804,7 +804,7 @@ struct omap_mpu_state_s { omap3630, } mpu_model; - CPUARMState *env; + ARMCPU *cpu; qemu_irq *drq; diff --git a/hw/omap1.c b/hw/omap1.c index 80d47f0b85..ad60cc4919 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -1519,8 +1519,9 @@ static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, { omap_clk clk; - if (value & (1 << 11)) /* SETARM_IDLE */ - cpu_interrupt(s->env, CPU_INTERRUPT_HALT); + if (value & (1 << 11)) { /* SETARM_IDLE */ + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); + } if (!(value & (1 << 10))) /* WKUP_MODE */ qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */ @@ -1734,7 +1735,7 @@ static uint64_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr, case 0x18: /* DSP_SYSST */ return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | - (s->env->halted << 6); /* Quite useless... */ + (s->cpu->env.halted << 6); /* Quite useless... */ } OMAP_BAD_REG(addr); @@ -3701,7 +3702,7 @@ static void omap1_mpu_reset(void *opaque) omap_lpg_reset(mpu->led[0]); omap_lpg_reset(mpu->led[1]); omap_clkm_reset(mpu); - cpu_state_reset(mpu->env); + cpu_reset(CPU(mpu->cpu)); } static const struct omap_map_s { @@ -3751,8 +3752,9 @@ void omap_mpu_wakeup(void *opaque, int irq, int req) { struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - if (mpu->env->halted) - cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); + if (mpu->cpu->env.halted) { + cpu_interrupt(&mpu->cpu->env, CPU_INTERRUPT_EXITTB); + } } static const struct dma_irq_map omap1_dma_irq_map[] = { @@ -3829,8 +3831,8 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, /* Core */ s->mpu_model = omap310; - s->env = cpu_init(core); - if (!s->env) { + s->cpu = cpu_arm_init(core); + if (s->cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } @@ -3852,7 +3854,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s); - cpu_irq = arm_pic_init_cpu(s->env); + cpu_irq = arm_pic_init_cpu(s->cpu); 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")); diff --git a/hw/omap2.c b/hw/omap2.c index 42fce5e986..4278dd19c4 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -2222,7 +2222,7 @@ static void omap2_mpu_reset(void *opaque) omap_mmc_reset(mpu->mmc); omap_mcspi_reset(mpu->mcspi[0]); omap_mcspi_reset(mpu->mcspi[1]); - cpu_state_reset(mpu->env); + cpu_reset(CPU(mpu->cpu)); } static int omap2_validate_addr(struct omap_mpu_state_s *s, @@ -2253,8 +2253,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, /* Core */ s->mpu_model = omap2420; - s->env = cpu_init(core ?: "arm1136-r2"); - if (!s->env) { + s->cpu = cpu_arm_init(core ?: "arm1136-r2"); + if (s->cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } @@ -2277,7 +2277,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54); /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ - cpu_irq = arm_pic_init_cpu(s->env); + cpu_irq = arm_pic_init_cpu(s->cpu); 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")); diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index 4e8ec4a990..abca341926 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -103,7 +103,7 @@ static void sx1_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model, const int version) { - struct omap_mpu_state_s *cpu; + struct omap_mpu_state_s *mpu; MemoryRegion *address_space = get_system_memory(); MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *flash_1 = g_new(MemoryRegion, 1); @@ -121,7 +121,7 @@ static void sx1_init(ram_addr_t ram_size, flash_size = flash2_size; } - cpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model); + mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model); /* External Flash (EMIFS) */ memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size); @@ -202,7 +202,7 @@ static void sx1_init(ram_addr_t ram_size, sx1_binfo.kernel_filename = kernel_filename; sx1_binfo.kernel_cmdline = kernel_cmdline; sx1_binfo.initrd_filename = initrd_filename; - arm_load_kernel(cpu->env, &sx1_binfo); + arm_load_kernel(mpu->cpu, &sx1_binfo); } /* TODO: fix next line */ @@ -196,7 +196,7 @@ static void palmte_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { MemoryRegion *address_space_mem = get_system_memory(); - struct omap_mpu_state_s *cpu; + struct omap_mpu_state_s *mpu; int flash_size = 0x00800000; int sdram_size = palmte_binfo.ram_size; static uint32_t cs0val = 0xffffffff; @@ -208,7 +208,7 @@ static void palmte_init(ram_addr_t ram_size, MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *cs = g_new(MemoryRegion, 4); - cpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model); + mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model); /* External Flash (EMIFS) */ memory_region_init_ram(flash, "palmte.flash", flash_size); @@ -230,11 +230,11 @@ static void palmte_init(ram_addr_t ram_size, OMAP_CS3_SIZE); memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]); - palmte_microwire_setup(cpu); + palmte_microwire_setup(mpu); - qemu_add_kbd_event_handler(palmte_button_event, cpu); + qemu_add_kbd_event_handler(palmte_button_event, mpu); - palmte_gpio_setup(cpu); + palmte_gpio_setup(mpu); /* Setup initial (reset) machine state */ if (nb_option_roms) { @@ -265,7 +265,7 @@ static void palmte_init(ram_addr_t ram_size, palmte_binfo.kernel_filename = kernel_filename; palmte_binfo.kernel_cmdline = kernel_cmdline; palmte_binfo.initrd_filename = initrd_filename; - arm_load_kernel(cpu->env, &palmte_binfo); + arm_load_kernel(mpu->cpu, &palmte_binfo); } /* FIXME: We shouldn't really be doing this here. The LCD controller @@ -926,27 +926,30 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) static void pc_cpu_reset(void *opaque) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); env->halted = !cpu_is_bsp(env); } -static CPUX86State *pc_new_cpu(const char *cpu_model) +static X86CPU *pc_new_cpu(const char *cpu_model) { + X86CPU *cpu; CPUX86State *env; - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_x86_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find x86 CPU definition\n"); exit(1); } + env = &cpu->env; if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) { env->apic_state = apic_init(env, env->cpuid_apic_id); } - qemu_register_reset(pc_cpu_reset, env); - pc_cpu_reset(env); - return env; + qemu_register_reset(pc_cpu_reset, cpu); + pc_cpu_reset(cpu); + return cpu; } void pc_cpus_init(const char *cpu_model) diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index c55d8b9396..61257f457b 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -39,6 +39,7 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, const char *devaddr, const char *opts_str) { + Error *local_err = NULL; QemuOpts *opts; PCIBus *bus; int ret, devfn; @@ -60,9 +61,12 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, qemu_opt_set(opts, "type", "nic"); - ret = net_client_init(mon, opts, 0); - if (ret < 0) + ret = net_client_init(opts, 0, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); return NULL; + } if (nd_table[ret].devaddr) { monitor_printf(mon, "Parameter addr not supported\n"); return NULL; @@ -1545,7 +1545,7 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, DeviceState *dev; dev = qdev_create(&bus->qbus, name); - qdev_prop_set_uint32(dev, "addr", devfn); + qdev_prop_set_int32(dev, "addr", devfn); qdev_prop_set_bit(dev, "multifunction", multifunction); return PCI_DEVICE(dev); } @@ -197,7 +197,7 @@ struct PCIDevice { /* the following fields are read only */ PCIBus *bus; - uint32_t devfn; + int32_t devfn; char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index 31a434872d..6a7d0c0bff 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -54,8 +54,10 @@ #define AXIENET_BASEADDR 0x82780000 #define AXIDMA_BASEADDR 0x84600000 -static void machine_cpu_reset(CPUMBState *env) +static void machine_cpu_reset(MicroBlazeCPU *cpu) { + CPUMBState *env = &cpu->env; + env->pvr.regs[10] = 0x0e000000; /* virtex 6 */ /* setup pvr to match kernel setting */ env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK; @@ -75,6 +77,7 @@ petalogix_ml605_init(ram_addr_t ram_size, { MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev; + MicroBlazeCPU *cpu; CPUMBState *env; DriveInfo *dinfo; int i; @@ -87,7 +90,8 @@ petalogix_ml605_init(ram_addr_t ram_size, if (cpu_model == NULL) { cpu_model = "microblaze"; } - env = cpu_init(cpu_model); + cpu = cpu_mb_init(cpu_model); + env = &cpu->env; /* Attach emulated BRAM through the LMB. */ memory_region_init_ram(phys_lmb_bram, "petalogix_ml605.lmb_bram", @@ -119,7 +123,7 @@ petalogix_ml605_init(ram_addr_t ram_size, 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); + xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000); /* axi ethernet and dma initialization. TODO: Dynamically connect them. */ { @@ -131,7 +135,7 @@ petalogix_ml605_init(ram_addr_t ram_size, irq[1], irq[0], 100 * 1000000); } - microblaze_load_kernel(env, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, + microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, machine_cpu_reset); } diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c index 8b37336001..2cf68828ed 100644 --- a/hw/petalogix_s3adsp1800_mmu.c +++ b/hw/petalogix_s3adsp1800_mmu.c @@ -49,8 +49,10 @@ #define UARTLITE_BASEADDR 0x84000000 #define ETHLITE_BASEADDR 0x81000000 -static void machine_cpu_reset(CPUMBState *env) +static void machine_cpu_reset(MicroBlazeCPU *cpu) { + CPUMBState *env = &cpu->env; + env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family. */ } @@ -62,6 +64,7 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { DeviceState *dev; + MicroBlazeCPU *cpu; CPUMBState *env; DriveInfo *dinfo; int i; @@ -75,7 +78,8 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size, if (cpu_model == NULL) { cpu_model = "microblaze"; } - env = cpu_init(cpu_model); + cpu = cpu_mb_init(cpu_model); + env = &cpu->env; /* Attach emulated BRAM through the LMB. */ memory_region_init_ram(phys_lmb_bram, @@ -100,12 +104,12 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size, irq[i] = qdev_get_gpio_in(dev, i); } - sysbus_create_simple("xilinx,uartlite", UARTLITE_BASEADDR, irq[3]); + sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, irq[3]); /* 2 timers at irq 2 @ 62 Mhz. */ - xilinx_timer_create(TIMER_BASEADDR, irq[0], 2, 62 * 1000000); + xilinx_timer_create(TIMER_BASEADDR, irq[0], 0, 62 * 1000000); xilinx_ethlite_create(&nd_table[0], ETHLITE_BASEADDR, irq[1], 0, 0); - microblaze_load_kernel(env, ddr_base, ram_size, + microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, machine_cpu_reset); } diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs new file mode 100644 index 0000000000..44a1e8cdab --- /dev/null +++ b/hw/ppc/Makefile.objs @@ -0,0 +1,28 @@ +# shared objects +obj-y = ppc.o ppc_booke.o +# PREP target +obj-y += mc146818rtc.o +obj-y += ppc_prep.o +# OldWorld PowerMac +obj-y += ppc_oldworld.o +# NewWorld PowerMac +obj-y += ppc_newworld.o +# IBM pSeries (sPAPR) +obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o +obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o +obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o +# PowerPC 4xx boards +obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o +obj-y += ppc440_bamboo.o +# PowerPC E500 boards +obj-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o +# PowerPC 440 Xilinx ML507 reference board. +obj-y += virtex_ml507.o +# PowerPC OpenPIC +obj-y += openpic.o +obj-$(CONFIG_FDT) += ../device_tree.o + +# Xilinx PPC peripherals +obj-y += xilinx_ethlite.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index f0a3ae49e6..0dd4dab318 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -145,9 +145,10 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env, static void main_cpu_reset(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); env->gpr[1] = (16<<20) - 8; env->gpr[3] = FDT_ADDR; env->nip = entry; @@ -172,6 +173,7 @@ static void bamboo_init(ram_addr_t ram_size, qemu_irq *pic; qemu_irq *irqs; PCIBus *pcibus; + PowerPCCPU *cpu; CPUPPCState *env; uint64_t elf_entry; uint64_t elf_lowaddr; @@ -185,13 +187,14 @@ static void bamboo_init(ram_addr_t ram_size, if (cpu_model == NULL) { cpu_model = "440EP"; } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to initialize CPU!\n"); exit(1); } + env = &cpu->env; - qemu_register_reset(main_cpu_reset, env); + qemu_register_reset(main_cpu_reset, cpu); ppc_booke_timers_init(env, 400000000, 0); ppc_dcr_init(env, NULL, NULL); diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 00e36f4109..41163e607d 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -40,9 +40,9 @@ static void ppc4xx_reset(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); } /*****************************************************************************/ @@ -51,15 +51,18 @@ CPUPPCState *ppc4xx_init (const char *cpu_model, clk_setup_t *cpu_clk, clk_setup_t *tb_clk, uint32_t sysclk) { + PowerPCCPU *cpu; CPUPPCState *env; /* init CPUs */ - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find PowerPC %s CPU definition\n", cpu_model); exit(1); } + env = &cpu->env; + cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ cpu_clk->opaque = env; /* Set time-base frequency to sysclk */ @@ -67,7 +70,7 @@ CPUPPCState *ppc4xx_init (const char *cpu_model, tb_clk->opaque = env; ppc_dcr_init(env, NULL, NULL); /* Register qemu callbacks */ - qemu_register_reset(ppc4xx_reset, env); + qemu_register_reset(ppc4xx_reset, cpu); return env; } diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 879651018b..4e2a6e691b 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -123,9 +123,9 @@ static target_phys_addr_t round_page(target_phys_addr_t addr) static void ppc_core99_reset(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); } /* PowerPC Mac99 hardware initialisation */ @@ -136,6 +136,7 @@ static void ppc_core99_init (ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { + PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; qemu_irq *pic, **openpic_irqs; @@ -166,14 +167,16 @@ static void ppc_core99_init (ram_addr_t ram_size, cpu_model = "G4"; #endif for (i = 0; i < smp_cpus; i++) { - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find PowerPC CPU definition\n"); exit(1); } + env = &cpu->env; + /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); - qemu_register_reset(ppc_core99_reset, env); + qemu_register_reset(ppc_core99_reset, cpu); } /* allocate RAM */ diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 7e73d37c34..f2c6908534 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -67,9 +67,9 @@ static target_phys_addr_t round_page(target_phys_addr_t addr) static void ppc_heathrow_reset(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); } static void ppc_heathrow_init (ram_addr_t ram_size, @@ -80,6 +80,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, const char *cpu_model) { MemoryRegion *sysmem = get_system_memory(); + PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; qemu_irq *pic, **heathrow_irqs; @@ -104,14 +105,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size, if (cpu_model == NULL) cpu_model = "G3"; for (i = 0; i < smp_cpus; i++) { - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find PowerPC CPU definition\n"); exit(1); } + env = &cpu->env; + /* Set time-base frequency to 16.6 Mhz */ cpu_ppc_tb_init(env, 16600000UL); - qemu_register_reset(ppc_heathrow_reset, env); + qemu_register_reset(ppc_heathrow_reset, cpu); } /* allocate RAM */ diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index b1da114114..be2b26830d 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -441,9 +441,9 @@ static void cpu_request_exit(void *opaque, int irq, int level) static void ppc_prep_reset(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); } /* PowerPC PREP hardware initialisation */ @@ -455,6 +455,7 @@ static void ppc_prep_init (ram_addr_t ram_size, const char *cpu_model) { MemoryRegion *sysmem = get_system_memory(); + PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; nvram_t nvram; @@ -487,11 +488,13 @@ static void ppc_prep_init (ram_addr_t ram_size, if (cpu_model == NULL) cpu_model = "602"; for (i = 0; i < smp_cpus; i++) { - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find PowerPC CPU definition\n"); exit(1); } + env = &cpu->env; + if (env->flags & POWERPC_FLAG_RTC_CLK) { /* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */ cpu_ppc_tb_init(env, 7812500UL); @@ -499,7 +502,7 @@ static void ppc_prep_init (ram_addr_t ram_size, /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); } - qemu_register_reset(ppc_prep_reset, env); + qemu_register_reset(ppc_prep_reset, cpu); } /* allocate RAM */ diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index f1dfbe181c..3eb8a23779 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -196,9 +196,10 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env, static void mpc8544ds_cpu_reset_sec(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); /* Secondary CPU starts in halted state for now. Needs to change when implementing non-kernel boot. */ @@ -208,10 +209,11 @@ static void mpc8544ds_cpu_reset_sec(void *opaque) static void mpc8544ds_cpu_reset(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; struct boot_info *bi = env->load_info; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); /* Set initial guest state. */ env->halted = 0; @@ -254,12 +256,15 @@ static void mpc8544ds_init(ram_addr_t ram_size, 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++) { + PowerPCCPU *cpu; qemu_irq *input; - env = cpu_ppc_init(cpu_model); - if (!env) { + + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to initialize CPU!\n"); exit(1); } + env = &cpu->env; if (!firstenv) { firstenv = env; @@ -278,11 +283,11 @@ static void mpc8544ds_init(ram_addr_t ram_size, /* Primary CPU */ struct boot_info *boot_info; boot_info = g_malloc0(sizeof(struct boot_info)); - qemu_register_reset(mpc8544ds_cpu_reset, env); + qemu_register_reset(mpc8544ds_cpu_reset, cpu); env->load_info = boot_info; } else { /* Secondary CPUs */ - qemu_register_reset(mpc8544ds_cpu_reset_sec, env); + qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu); } } @@ -65,7 +65,7 @@ # define PXA2XX_INTERNAL_SIZE 0x40000 /* pxa2xx_pic.c */ -DeviceState *pxa2xx_pic_init(target_phys_addr_t base, CPUARMState *env); +DeviceState *pxa2xx_pic_init(target_phys_addr_t base, ARMCPU *cpu); /* pxa2xx_gpio.c */ DeviceState *pxa2xx_gpio_init(target_phys_addr_t base, @@ -122,7 +122,7 @@ typedef struct PXA2xxI2SState PXA2xxI2SState; typedef struct PXA2xxFIrState PXA2xxFIrState; typedef struct { - CPUARMState *env; + ARMCPU *cpu; DeviceState *pic; qemu_irq reset; MemoryRegion sdram; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index ddaa846882..7958d14003 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -269,24 +269,24 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, case 1: /* Idle */ if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ - cpu_interrupt(s->env, CPU_INTERRUPT_HALT); + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); break; } /* Fall through. */ case 2: /* Deep-Idle */ - cpu_interrupt(s->env, CPU_INTERRUPT_HALT); + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ goto message; case 3: - s->env->uncached_cpsr = + s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; - s->env->cp15.c1_sys = 0; - s->env->cp15.c1_coproc = 0; - s->env->cp15.c2_base0 = 0; - s->env->cp15.c3 = 0; + s->cpu->env.cp15.c1_sys = 0; + s->cpu->env.cp15.c1_coproc = 0; + s->cpu->env.cp15.c2_base0 = 0; + s->cpu->env.cp15.c3 = 0; s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ @@ -296,8 +296,8 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, * lack of a resuming bootloader, perform a jump * directly to that address. */ - memset(s->env->regs, 0, 4 * 15); - s->env->regs[15] = s->pm_regs[PSPR >> 2]; + memset(s->cpu->env.regs, 0, 4 * 15); + s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2]; #if 0 buffer = 0xe59ff000; /* ldr pc, [pc, #0] */ @@ -2044,7 +2044,7 @@ static void pxa2xx_reset(void *opaque, int line, int level) PXA2xxState *s = (PXA2xxState *) opaque; if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */ - cpu_state_reset(s->env); + cpu_reset(CPU(s->cpu)); /* TODO: reset peripherals */ } } @@ -2065,8 +2065,8 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, if (!revision) revision = "pxa270"; - s->env = cpu_init(revision); - if (!s->env) { + s->cpu = cpu_arm_init(revision); + if (s->cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } @@ -2081,7 +2081,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, &s->internal); - s->pic = pxa2xx_pic_init(0x40d00000, s->env); + s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); s->dma = pxa27x_dma_init(0x40000000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); @@ -2094,7 +2094,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11), NULL); - s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); + s->gpio = pxa2xx_gpio_init(0x40e00000, &s->cpu->env, s->pic, 121); dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { @@ -2133,7 +2133,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, 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); + cpu_arm_set_cp_io(&s->cpu->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); s->mm_base = 0x48000000; s->mm_regs[MDMRS >> 2] = 0x00020002; @@ -2196,8 +2196,8 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState)); - s->env = cpu_init("pxa255"); - if (!s->env) { + s->cpu = cpu_arm_init("pxa255"); + if (s->cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } @@ -2213,7 +2213,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, &s->internal); - s->pic = pxa2xx_pic_init(0x40d00000, s->env); + s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); s->dma = pxa255_dma_init(0x40000000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); @@ -2225,7 +2225,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), NULL); - s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85); + s->gpio = pxa2xx_gpio_init(0x40e00000, &s->cpu->env, s->pic, 85); dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { @@ -2264,7 +2264,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) 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); + cpu_arm_set_cp_io(&s->cpu->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); s->mm_base = 0x48000000; s->mm_regs[MDMRS >> 2] = 0x00020002; diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 09a408b781..3c90c9c4e0 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -20,7 +20,7 @@ struct PXA2xxGPIOInfo { qemu_irq irq0, irq1, irqX; int lines; int ncpu; - CPUARMState *cpu_env; + ARMCPU *cpu; /* XXX: GNU C vectors are more suitable */ uint32_t ilevel[PXA2XX_GPIO_BANKS]; @@ -118,8 +118,9 @@ static void pxa2xx_gpio_set(void *opaque, int line, int level) pxa2xx_gpio_irq_update(s); /* Wake-up GPIOs */ - if (s->cpu_env->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB); + if (s->cpu->env.halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); + } } static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) { @@ -275,7 +276,7 @@ static int pxa2xx_gpio_initfn(SysBusDevice *dev) s = FROM_SYSBUS(PXA2xxGPIOInfo, dev); - s->cpu_env = qemu_get_cpu(s->ncpu); + s->cpu = arm_env_get_cpu(qemu_get_cpu(s->ncpu)); qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines); qdev_init_gpio_out(&dev->qdev, s->handler, s->lines); diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index a806b80b0f..c560133930 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -34,7 +34,7 @@ typedef struct { SysBusDevice busdev; MemoryRegion iomem; - CPUARMState *cpu_env; + ARMCPU *cpu; uint32_t int_enabled[2]; uint32_t int_pending[2]; uint32_t is_fiq[2]; @@ -47,25 +47,28 @@ static void pxa2xx_pic_update(void *opaque) uint32_t mask[2]; PXA2xxPICState *s = (PXA2xxPICState *) opaque; - if (s->cpu_env->halted) { + if (s->cpu->env.halted) { mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); - if (mask[0] || mask[1]) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB); + if (mask[0] || mask[1]) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); + } } mask[0] = s->int_pending[0] & s->int_enabled[0]; mask[1] = s->int_pending[1] & s->int_enabled[1]; - if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); - else - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); + } else { + cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); + } - if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + } } /* Note: Here level means state of the signal on a pin, not @@ -245,12 +248,13 @@ static int pxa2xx_pic_post_load(void *opaque, int version_id) return 0; } -DeviceState *pxa2xx_pic_init(target_phys_addr_t base, CPUARMState *env) +DeviceState *pxa2xx_pic_init(target_phys_addr_t base, ARMCPU *cpu) { + CPUARMState *env = &cpu->env; DeviceState *dev = qdev_create(NULL, "pxa2xx_pic"); PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, sysbus_from_qdev(dev)); - s->cpu_env = env; + s->cpu = cpu; s->int_pending[0] = 0; s->int_pending[1] = 0; diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index 0bb16c7eb3..b711b6bf96 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -27,7 +27,7 @@ static void get_taddr(Object *obj, Visitor *v, void *opaque, int64_t value; value = *ptr; - visit_type_int(v, &value, name, errp); + visit_type_int64(v, &value, name, errp); } static void set_taddr(Object *obj, Visitor *v, void *opaque, @@ -44,7 +44,7 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque, return; } - visit_type_int(v, &value, name, &local_err); + visit_type_int64(v, &value, name, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index eed781d2f0..b01ef0600e 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -554,10 +554,13 @@ void do_info_qdm(Monitor *mon) int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) { + Error *local_err = NULL; QemuOpts *opts; - opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict); - if (!opts) { + opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); return -1; } if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index b7b5597c62..9ae318717e 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -76,52 +76,35 @@ PropertyInfo qdev_prop_bit = { /* --- 8bit integer --- */ -static void get_int8(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void get_uint8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int8_t *ptr = qdev_get_prop_ptr(dev, prop); - int64_t value; + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - value = *ptr; - visit_type_int(v, &value, name, errp); + visit_type_uint8(v, ptr, name, errp); } -static void set_int8(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void set_uint8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int8_t *ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int64_t value; + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (value >= prop->info->min && value <= prop->info->max) { - *ptr = value; - } else { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, value, prop->info->min, - prop->info->max); - } + visit_type_uint8(v, ptr, name, errp); } PropertyInfo qdev_prop_uint8 = { .name = "uint8", - .get = get_int8, - .set = set_int8, - .min = 0, - .max = 255, + .get = get_uint8, + .set = set_uint8, }; /* --- 8bit hex value --- */ @@ -154,74 +137,78 @@ PropertyInfo qdev_prop_hex8 = { .legacy_name = "hex8", .parse = parse_hex8, .print = print_hex8, - .get = get_int8, - .set = set_int8, - .min = 0, - .max = 255, + .get = get_uint8, + .set = set_uint8, }; /* --- 16bit integer --- */ -static void get_int16(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void get_uint16(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int16_t *ptr = qdev_get_prop_ptr(dev, prop); - int64_t value; + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - value = *ptr; - visit_type_int(v, &value, name, errp); + visit_type_uint16(v, ptr, name, errp); } -static void set_int16(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void set_uint16(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int16_t *ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int64_t value; + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (value >= prop->info->min && value <= prop->info->max) { - *ptr = value; - } else { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, value, prop->info->min, - prop->info->max); - } + visit_type_uint16(v, ptr, name, errp); } PropertyInfo qdev_prop_uint16 = { .name = "uint16", - .get = get_int16, - .set = set_int16, - .min = 0, - .max = 65535, + .get = get_uint16, + .set = set_uint16, }; /* --- 32bit integer --- */ +static void get_uint32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_uint32(v, ptr, name, errp); +} + +static void set_uint32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint32(v, ptr, name, errp); +} + static void get_int32(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); - int64_t value; - value = *ptr; - visit_type_int(v, &value, name, errp); + visit_type_int32(v, ptr, name, errp); } static void set_int32(Object *obj, Visitor *v, void *opaque, @@ -230,42 +217,25 @@ static void set_int32(Object *obj, Visitor *v, void *opaque, DeviceState *dev = DEVICE(obj); Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int64_t value; if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (value >= prop->info->min && value <= prop->info->max) { - *ptr = value; - } else { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, value, prop->info->min, - prop->info->max); - } + visit_type_int32(v, ptr, name, errp); } PropertyInfo qdev_prop_uint32 = { .name = "uint32", - .get = get_int32, - .set = set_int32, - .min = 0, - .max = 0xFFFFFFFFULL, + .get = get_uint32, + .set = set_uint32, }; PropertyInfo qdev_prop_int32 = { .name = "int32", .get = get_int32, .set = set_int32, - .min = -0x80000000LL, - .max = 0x7FFFFFFFLL, }; /* --- 32bit hex value --- */ @@ -298,43 +268,41 @@ PropertyInfo qdev_prop_hex32 = { .legacy_name = "hex32", .parse = parse_hex32, .print = print_hex32, - .get = get_int32, - .set = set_int32, - .min = 0, - .max = 0xFFFFFFFFULL, + .get = get_uint32, + .set = set_uint32, }; /* --- 64bit integer --- */ -static void get_int64(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void get_uint64(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int64_t *ptr = qdev_get_prop_ptr(dev, prop); + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - visit_type_int(v, ptr, name, errp); + visit_type_uint64(v, ptr, name, errp); } -static void set_int64(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void set_uint64(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int64_t *ptr = qdev_get_prop_ptr(dev, prop); + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, ptr, name, errp); + visit_type_uint64(v, ptr, name, errp); } PropertyInfo qdev_prop_uint64 = { .name = "uint64", - .get = get_int64, - .set = set_int64, + .get = get_uint64, + .set = set_uint64, }; /* --- 64bit hex value --- */ @@ -367,8 +335,8 @@ PropertyInfo qdev_prop_hex64 = { .legacy_name = "hex64", .parse = parse_hex64, .print = print_hex64, - .get = get_int64, - .set = set_int64, + .get = get_uint64, + .set = set_uint64, }; /* --- string --- */ @@ -645,7 +613,7 @@ static void get_vlan(Object *obj, Visitor *v, void *opaque, int64_t id; id = *ptr ? (*ptr)->id : -1; - visit_type_int(v, &id, name, errp); + visit_type_int64(v, &id, name, errp); } static void set_vlan(Object *obj, Visitor *v, void *opaque, @@ -663,7 +631,7 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque, return; } - visit_type_int(v, &id, name, &local_err); + visit_type_int64(v, &id, name, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -824,7 +792,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; Error *local_err = NULL; char *str; @@ -837,7 +805,17 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, visit_type_str(v, &str, name, &local_err); if (local_err) { error_free(local_err); - return set_int32(obj, v, opaque, name, errp); + local_err = NULL; + visit_type_int32(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } else if (value < -1 || value > 255) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "pci_devfn"); + } else { + *ptr = value; + } + return; } if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { @@ -860,7 +838,7 @@ invalid: static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) { - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + int32_t *ptr = qdev_get_prop_ptr(dev, prop); if (*ptr == -1) { return snprintf(dest, len, "<unset>"); @@ -875,11 +853,6 @@ PropertyInfo qdev_prop_pci_devfn = { .print = print_pci_devfn, .get = get_int32, .set = set_pci_devfn, - /* FIXME: this should be -1...255, but the address is stored - * into an uint32_t rather than int32_t. - */ - .min = 0, - .max = 0xFFFFFFFFULL, }; /* --- blocksize --- */ @@ -889,31 +862,31 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int16_t *ptr = qdev_get_prop_ptr(dev, prop); + uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; - int64_t value; + const int64_t min = 512; + const int64_t max = 32768; if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, &value, name, &local_err); + visit_type_uint16(v, &value, name, &local_err); if (local_err) { error_propagate(errp, local_err); return; } - if (value < prop->info->min || value > prop->info->max) { + if (value < min || value > max) { error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, value, prop->info->min, - prop->info->max); + dev->id?:"", name, (int64_t)value, min, max); return; } /* We rely on power-of-2 blocksizes for bitmasks */ if ((value & (value - 1)) != 0) { error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, - dev->id?:"", name, value); + dev->id?:"", name, (int64_t)value); return; } @@ -922,10 +895,8 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_blocksize = { .name = "blocksize", - .get = get_int16, + .get = get_uint16, .set = set_blocksize, - .min = 512, - .max = 65024, }; /* --- public helpers --- */ @@ -122,8 +122,6 @@ struct PropertyInfo { const char *name; const char *legacy_name; const char **enum_table; - int64_t min; - int64_t max; int (*parse)(DeviceState *dev, Property *prop, const char *str); int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); ObjectPropertyAccessor *get; @@ -267,7 +265,7 @@ extern PropertyInfo qdev_prop_blocksize; #define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, uint32_t) + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) #define DEFINE_PROP_PTR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*) @@ -192,16 +192,16 @@ static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem, } typedef struct ResetData { - CPUSH4State *env; + SuperHCPU *cpu; uint32_t vector; } ResetData; static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; - CPUSH4State *env = s->env; + CPUSH4State *env = &s->cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(s->cpu)); env->pc = s->vector; } @@ -224,6 +224,7 @@ static void r2d_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { + SuperHCPU *cpu; CPUSH4State *env; ResetData *reset_info; struct SH7750State *s; @@ -235,16 +236,19 @@ static void r2d_init(ram_addr_t ram_size, SysBusDevice *busdev; MemoryRegion *address_space_mem = get_system_memory(); - if (!cpu_model) + if (cpu_model == NULL) { cpu_model = "SH7751R"; + } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_sh4_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; + reset_info = g_malloc0(sizeof(ResetData)); - reset_info->env = env; + reset_info->cpu = cpu; reset_info->vector = env->pc; qemu_register_reset(main_cpu_reset, reset_info); diff --git a/hw/realview.c b/hw/realview.c index ecf470179a..19db4d026b 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -50,7 +50,8 @@ static void realview_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model, enum realview_board_type board_type) { - CPUARMState *env = NULL; + ARMCPU *cpu = NULL; + CPUARMState *env; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram_lo = g_new(MemoryRegion, 1); MemoryRegion *ram_hi = g_new(MemoryRegion, 1); @@ -88,14 +89,15 @@ static void realview_init(ram_addr_t ram_size, break; } for (n = 0; n < smp_cpus; n++) { - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } + env = &cpu->env; if (arm_feature(env, ARM_FEATURE_V7)) { if (is_mpcore) { proc_id = 0x0c000000; @@ -325,7 +327,7 @@ static void realview_init(ram_addr_t ram_size, realview_binfo.nb_cpus = smp_cpus; realview_binfo.board_id = realview_board_id[board_type]; realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); - arm_load_kernel(first_cpu, &realview_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &realview_binfo); } static void realview_eb_init(ram_addr_t ram_size, diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 060404c137..f6f144b525 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -791,6 +791,9 @@ static int rtl8139_can_receive(VLANClientState *nc) return 1; if (!rtl8139_receiver_enabled(s)) return 1; + /* network/host communication happens only in normal mode */ + if ((s->Cfg9346 & Chip9346_op_mask) != Cfg9346_Normal) + return 0; if (rtl8139_cp_receiver_enabled(s)) { /* ??? Flow control not implemented in c+ mode. @@ -833,6 +836,12 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ return -1; } + /* check whether we are in normal mode */ + if ((s->Cfg9346 & Chip9346_op_mask) != Cfg9346_Normal) { + DPRINTF("not in normal op mode\n"); + return -1; + } + /* XXX: check this */ if (s->RxConfig & AcceptAllPhys) { /* promiscuous: receive all */ diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 1d38a8f5c5..23ef35b3bb 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -140,7 +140,8 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) s390_virtio_device_sync(dev); s390_virtio_reset_idx(dev); if (dev->qdev.hotplugged) { - CPUS390XState *env = s390_cpu_addr2state(0); + S390CPU *cpu = s390_cpu_addr2state(0); + CPUS390XState *env = &cpu->env; s390_virtio_irq(env, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); } @@ -354,7 +355,8 @@ static void virtio_s390_notify(void *opaque, uint16_t vector) { VirtIOS390Device *dev = (VirtIOS390Device*)opaque; uint64_t token = s390_virtio_device_vq_token(dev, vector); - CPUS390XState *env = s390_cpu_addr2state(0); + S390CPU *cpu = s390_cpu_addr2state(0); + CPUS390XState *env = &cpu->env; s390_virtio_irq(env, 0, token); } diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index c0e19fd66d..47eed35da3 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -61,9 +61,9 @@ #define MAX_BLK_DEVS 10 static VirtIOS390Bus *s390_bus; -static CPUS390XState **ipi_states; +static S390CPU **ipi_states; -CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr) +S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) { if (cpu_addr >= smp_cpus) { return NULL; @@ -206,16 +206,18 @@ static void s390_init(ram_addr_t my_ram_size, cpu_model = "host"; } - ipi_states = g_malloc(sizeof(CPUS390XState *) * smp_cpus); + ipi_states = g_malloc(sizeof(S390CPU *) * smp_cpus); for (i = 0; i < smp_cpus; i++) { + S390CPU *cpu; CPUS390XState *tmp_env; - tmp_env = cpu_init(cpu_model); + cpu = cpu_s390x_init(cpu_model); + tmp_env = &cpu->env; if (!env) { env = tmp_env; } - ipi_states[i] = tmp_env; + ipi_states[i] = cpu; tmp_env->halted = 1; tmp_env->exception_index = EXCP_HLT; tmp_env->storage_keys = storage_keys; diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs new file mode 100644 index 0000000000..dcdcac8a81 --- /dev/null +++ b/hw/s390x/Makefile.objs @@ -0,0 +1,3 @@ +obj-y = s390-virtio-bus.o s390-virtio.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index f10f3ec25c..4a798210ce 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1507,10 +1507,9 @@ static void put_scsi_requests(QEMUFile *f, void *pv, size_t size) QTAILQ_FOREACH(req, &s->requests, next) { assert(!req->io_canceled); assert(req->status == -1); - assert(req->retry); assert(req->enqueued); - qemu_put_sbyte(f, 1); + qemu_put_sbyte(f, req->retry ? 1 : 2); qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf)); qemu_put_be32s(f, &req->tag); qemu_put_be32s(f, &req->lun); @@ -1528,8 +1527,9 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) { SCSIDevice *s = pv; SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); + int8_t sbyte; - while (qemu_get_sbyte(f)) { + while ((sbyte = qemu_get_sbyte(f)) > 0) { uint8_t buf[SCSI_CMD_BUF_SIZE]; uint32_t tag; uint32_t lun; @@ -1539,6 +1539,7 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) qemu_get_be32s(f, &tag); qemu_get_be32s(f, &lun); req = scsi_req_new(s, tag, lun, buf, NULL); + req->retry = (sbyte == 1); if (bus->info->load_request) { req->hba_private = bus->info->load_request(f, req); } @@ -1547,7 +1548,6 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) } /* Just restart it later. */ - req->retry = true; scsi_req_enqueue_internal(req); /* At this point, the request will be kept alive by the reference diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 045c764d9b..1691491c03 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -132,8 +132,14 @@ static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req) qemu_put_be64s(f, &r->sector); qemu_put_be32s(f, &r->sector_count); qemu_put_be32s(f, &r->buflen); - if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { - qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); + if (r->buflen) { + if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { + qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); + } else if (!req->retry) { + uint32_t len = r->iov.iov_len; + qemu_put_be32s(f, &len); + qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); + } } } @@ -148,6 +154,12 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) scsi_init_iovec(r, r->buflen); if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); + } else if (!r->req.retry) { + uint32_t len; + qemu_get_be32s(f, &len); + r->iov.iov_len = len; + assert(r->iov.iov_len <= r->buflen); + qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); } } diff --git a/hw/sh4/Makefile.objs b/hw/sh4/Makefile.objs new file mode 100644 index 0000000000..68c5921790 --- /dev/null +++ b/hw/sh4/Makefile.objs @@ -0,0 +1,5 @@ +obj-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o +obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o +obj-y += ide/mmio.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/spapr.c b/hw/spapr.c index cca20f9a51..d0bddbce95 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -505,9 +505,9 @@ static void spapr_reset(void *opaque) static void spapr_cpu_reset(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); } /* pSeries LPAR / sPAPR hardware init */ @@ -518,6 +518,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { + PowerPCCPU *cpu; CPUPPCState *env; int i; MemoryRegion *sysmem = get_system_memory(); @@ -560,15 +561,16 @@ static void ppc_spapr_init(ram_addr_t ram_size, cpu_model = kvm_enabled() ? "host" : "POWER7"; } for (i = 0; i < smp_cpus; i++) { - env = cpu_init(cpu_model); - - if (!env) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find PowerPC CPU definition\n"); exit(1); } + env = &cpu->env; + /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); - qemu_register_reset(spapr_cpu_reset, env); + qemu_register_reset(spapr_cpu_reset, cpu); env->hreset_vector = 0x60; env->hreset_excp_prefix = 0; diff --git a/hw/sparc/Makefile.objs b/hw/sparc/Makefile.objs new file mode 100644 index 0000000000..a39a511c52 --- /dev/null +++ b/hw/sparc/Makefile.objs @@ -0,0 +1,8 @@ +obj-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o +obj-y += slavio_timer.o slavio_misc.o sparc32_dma.o +obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o + +# GRLIB +obj-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/sparc64/Makefile.objs b/hw/sparc64/Makefile.objs new file mode 100644 index 0000000000..8c65fc4215 --- /dev/null +++ b/hw/sparc64/Makefile.objs @@ -0,0 +1,4 @@ +obj-y = sun4u.o apb_pci.o +obj-y += mc146818rtc.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/spitz.c b/hw/spitz.c index 1d6d2b0e1b..20e7835191 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -884,7 +884,7 @@ static void spitz_common_init(ram_addr_t ram_size, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, enum spitz_model_e model, int arm_id) { - PXA2xxState *cpu; + PXA2xxState *mpu; DeviceState *scp0, *scp1 = NULL; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); @@ -893,9 +893,9 @@ static void spitz_common_init(ram_addr_t ram_size, cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; /* Setup CPU & memory */ - cpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model); + mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model); - sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M); + sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M); memory_region_init_ram(rom, "spitz.rom", SPITZ_ROM); vmstate_register_ram_global(rom); @@ -903,36 +903,36 @@ static void spitz_common_init(ram_addr_t ram_size, memory_region_add_subregion(address_space_mem, 0, rom); /* Setup peripherals */ - spitz_keyboard_register(cpu); + spitz_keyboard_register(mpu); - spitz_ssp_attach(cpu); + spitz_ssp_attach(mpu); scp0 = sysbus_create_simple("scoop", 0x10800000, NULL); if (model != akita) { scp1 = sysbus_create_simple("scoop", 0x08800040, NULL); } - spitz_scoop_gpio_setup(cpu, scp0, scp1); + spitz_scoop_gpio_setup(mpu, scp0, scp1); - spitz_gpio_setup(cpu, (model == akita) ? 1 : 2); + spitz_gpio_setup(mpu, (model == akita) ? 1 : 2); - spitz_i2c_setup(cpu); + spitz_i2c_setup(mpu); if (model == akita) - spitz_akita_i2c_setup(cpu); + spitz_akita_i2c_setup(mpu); if (model == terrier) /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */ - spitz_microdrive_attach(cpu, 1); + spitz_microdrive_attach(mpu, 1); else if (model != akita) /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ - spitz_microdrive_attach(cpu, 0); + spitz_microdrive_attach(mpu, 0); spitz_binfo.kernel_filename = kernel_filename; spitz_binfo.kernel_cmdline = kernel_cmdline; spitz_binfo.initrd_filename = initrd_filename; spitz_binfo.board_id = arm_id; - arm_load_kernel(cpu->env, &spitz_binfo); + arm_load_kernel(mpu->cpu, &spitz_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } diff --git a/hw/strongarm.c b/hw/strongarm.c index 1b15f399f1..7150eeb2db 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -1563,9 +1563,9 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, exit(1); } - s->env = cpu_init(rev); + s->cpu = cpu_arm_init(rev); - if (!s->env) { + if (!s->cpu) { error_report("Unable to find CPU definition"); exit(1); } @@ -1574,7 +1574,7 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, vmstate_register_ram_global(&s->sdram); memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram); - pic = arm_pic_init_cpu(s->env); + pic = arm_pic_init_cpu(s->cpu); s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000, pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL); diff --git a/hw/strongarm.h b/hw/strongarm.h index 02acac3db1..d30dd6ac5e 100644 --- a/hw/strongarm.h +++ b/hw/strongarm.h @@ -53,7 +53,7 @@ enum { }; typedef struct { - CPUARMState *env; + ARMCPU *cpu; MemoryRegion sdram; DeviceState *pic; DeviceState *gpio; diff --git a/hw/sun4m.c b/hw/sun4m.c index 34088ad185..a959261209 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -281,17 +281,19 @@ static void dummy_cpu_set_irq(void *opaque, int irq, int level) static void main_cpu_reset(void *opaque) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); env->halted = 0; } static void secondary_cpu_reset(void *opaque) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); env->halted = 1; } @@ -809,19 +811,21 @@ static TypeInfo ram_info = { static void cpu_devinit(const char *cpu_model, unsigned int id, uint64_t prom_addr, qemu_irq **cpu_irqs) { + SPARCCPU *cpu; CPUSPARCState *env; - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_sparc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); exit(1); } + env = &cpu->env; cpu_sparc_set_id(env, id); if (id == 0) { - qemu_register_reset(main_cpu_reset, env); + qemu_register_reset(main_cpu_reset, cpu); } else { - qemu_register_reset(secondary_cpu_reset, env); + qemu_register_reset(secondary_cpu_reset, cpu); env->halted = 1; } *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); diff --git a/hw/sun4u.c b/hw/sun4u.c index 517bdb818d..137a7c6666 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -342,7 +342,7 @@ static void cpu_set_ivec_irq(void *opaque, int irq, int level) } typedef struct ResetData { - CPUSPARCState *env; + SPARCCPU *cpu; uint64_t prom_addr; } ResetData; @@ -395,10 +395,10 @@ static void cpu_timer_reset(CPUTimer *timer) static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; - CPUSPARCState *env = s->env; + CPUSPARCState *env = &s->cpu->env; static unsigned int nr_resets; - cpu_state_reset(env); + cpu_reset(CPU(s->cpu)); cpu_timer_reset(env->tick); cpu_timer_reset(env->stick); @@ -752,8 +752,9 @@ static TypeInfo ram_info = { .class_init = ram_class_init, }; -static CPUSPARCState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) +static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) { + SPARCCPU *cpu; CPUSPARCState *env; ResetData *reset_info; @@ -761,13 +762,15 @@ static CPUSPARCState *cpu_devinit(const char *cpu_model, const struct hwdef *hwd uint32_t stick_frequency = 100*1000000; uint32_t hstick_frequency = 100*1000000; - if (!cpu_model) + if (cpu_model == NULL) { cpu_model = hwdef->default_cpu_model; - env = cpu_init(cpu_model); - if (!env) { + } + cpu = cpu_sparc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find Sparc CPU definition\n"); exit(1); } + env = &cpu->env; env->tick = cpu_timer_create("tick", env, tick_irq, tick_frequency, TICK_NPT_MASK); @@ -779,11 +782,11 @@ static CPUSPARCState *cpu_devinit(const char *cpu_model, const struct hwdef *hwd hstick_frequency, TICK_INT_DIS); reset_info = g_malloc0(sizeof(ResetData)); - reset_info->env = env; + reset_info->cpu = cpu; reset_info->prom_addr = hwdef->prom_addr; qemu_register_reset(main_cpu_reset, reset_info); - return env; + return cpu; } static void sun4uv_init(MemoryRegion *address_space_mem, @@ -793,6 +796,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, const char *initrd_filename, const char *cpu_model, const struct hwdef *hwdef) { + SPARCCPU *cpu; CPUSPARCState *env; M48t59State *nvram; unsigned int i; @@ -805,7 +809,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, void *fw_cfg; /* init CPUs */ - env = cpu_devinit(cpu_model, hwdef); + cpu = cpu_devinit(cpu_model, hwdef); + env = &cpu->env; /* set up devices */ ram_init(0, RAM_size); @@ -212,14 +212,14 @@ static void tosa_init(ram_addr_t ram_size, { MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); - PXA2xxState *cpu; + PXA2xxState *mpu; TC6393xbState *tmio; DeviceState *scp0, *scp1; if (!cpu_model) cpu_model = "pxa255"; - cpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); + mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); memory_region_init_ram(rom, "tosa.rom", TOSA_ROM); vmstate_register_ram_global(rom); @@ -227,22 +227,22 @@ static void tosa_init(ram_addr_t ram_size, memory_region_add_subregion(address_space_mem, 0, rom); tmio = tc6393xb_init(address_space_mem, 0x10000000, - qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_TC6393XB_INT)); + qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT)); scp0 = sysbus_create_simple("scoop", 0x08800000, NULL); scp1 = sysbus_create_simple("scoop", 0x14800040, NULL); - tosa_gpio_setup(cpu, scp0, scp1, tmio); + tosa_gpio_setup(mpu, scp0, scp1, tmio); - tosa_microdrive_attach(cpu); + tosa_microdrive_attach(mpu); - tosa_tg_init(cpu); + tosa_tg_init(mpu); tosa_binfo.kernel_filename = kernel_filename; tosa_binfo.kernel_cmdline = kernel_cmdline; tosa_binfo.initrd_filename = initrd_filename; tosa_binfo.board_id = 0x208; - arm_load_kernel(cpu->env, &tosa_binfo); + arm_load_kernel(mpu->cpu, &tosa_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs new file mode 100644 index 0000000000..9c7ddf5cb2 --- /dev/null +++ b/hw/usb/Makefile.objs @@ -0,0 +1,13 @@ +hw-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o +hw-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o +hw-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o +hw-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o +hw-obj-y += libhw.o + +hw-obj-$(CONFIG_SMARTCARD) += dev-smartcard-reader.o +hw-obj-$(CONFIG_USB_REDIR) += redirect.o + +common-obj-y += core.o bus.o desc.o dev-hub.o +common-obj-y += host-$(HOST_USB).o dev-bluetooth.o +common-obj-y += dev-hid.o dev-storage.o dev-wacom.o +common-obj-y += dev-serial.o dev-network.o dev-audio.o diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index b238a0973d..5d2f0982c9 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1356,6 +1356,7 @@ static int usb_net_initfn(USBDevice *dev) static USBDevice *usb_net_init(USBBus *bus, const char *cmdline) { + Error *local_err = NULL; USBDevice *dev; QemuOpts *opts; int idx; @@ -1367,8 +1368,10 @@ static USBDevice *usb_net_init(USBBus *bus, const char *cmdline) qemu_opt_set(opts, "type", "nic"); qemu_opt_set(opts, "model", "usb"); - idx = net_client_init(NULL, opts, 0); - if (idx == -1) { + idx = net_client_init(opts, 0, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); return NULL; } diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index ae22fb1c97..097d7b4a6d 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -48,10 +48,9 @@ struct usb_msd_csw { typedef struct { USBDevice dev; enum USBMSDMode mode; + uint32_t scsi_off; uint32_t scsi_len; - uint8_t *scsi_buf; uint32_t data_len; - uint32_t residue; struct usb_msd_csw csw; SCSIRequest *req; SCSIBus bus; @@ -179,9 +178,9 @@ static void usb_msd_copy_data(MSDState *s, USBPacket *p) len = p->iov.size - p->result; if (len > s->scsi_len) len = s->scsi_len; - usb_packet_copy(p, s->scsi_buf, len); + usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len); s->scsi_len -= len; - s->scsi_buf += len; + s->scsi_off += len; s->data_len -= len; if (s->scsi_len == 0 || s->data_len == 0) { scsi_req_continue(s->req); @@ -201,6 +200,18 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p) memset(&s->csw, 0, sizeof(s->csw)); } +static void usb_msd_packet_complete(MSDState *s) +{ + USBPacket *p = s->packet; + + /* Set s->packet to NULL before calling usb_packet_complete + because another request may be issued before + usb_packet_complete returns. */ + DPRINTF("Packet complete %p\n", p); + s->packet = NULL; + usb_packet_complete(&s->dev, p); +} + static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); @@ -208,17 +219,12 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) 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); + s->scsi_off = 0; if (p) { 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 another request may be issued before - usb_packet_complete returns. */ - DPRINTF("Packet complete %p\n", p); - s->packet = NULL; - usb_packet_complete(&s->dev, p); + usb_msd_packet_complete(s); } } } @@ -229,11 +235,10 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r 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 = cpu_to_le32(s->residue); + s->csw.residue = cpu_to_le32(s->data_len); s->csw.status = status != 0; if (s->packet) { @@ -252,8 +257,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r s->mode = USB_MSDM_CSW; } } - s->packet = NULL; - usb_packet_complete(&s->dev, p); + usb_msd_packet_complete(s); } else if (s->data_len == 0) { s->mode = USB_MSDM_CSW; } @@ -283,10 +287,8 @@ static void usb_msd_handle_reset(USBDevice *dev) 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->packet->result = USB_RET_STALL; + usb_msd_packet_complete(s); } s->mode = USB_MSDM_CBW; @@ -378,7 +380,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", tag, cbw.flags, cbw.cmd_len, s->data_len); - s->residue = 0; + assert(le32_to_cpu(s->csw.residue) == 0); s->scsi_len = 0; s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL); scsi_req_enqueue(s->req); @@ -397,7 +399,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (s->scsi_len) { usb_msd_copy_data(s, p); } - if (s->residue) { + if (le32_to_cpu(s->csw.residue)) { int len = p->iov.size - p->result; if (len) { usb_packet_skip(p, len); @@ -458,7 +460,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (s->scsi_len) { usb_msd_copy_data(s, p); } - if (s->residue) { + if (le32_to_cpu(s->csw.residue)) { int len = p->iov.size - p->result; if (len) { usb_packet_skip(p, len); @@ -504,6 +506,17 @@ static void usb_msd_password_cb(void *opaque, int err) qdev_unplug(&s->dev.qdev, NULL); } +static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req) +{ + MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); + + /* nothing to load, just store req in our state struct */ + assert(s->req == NULL); + scsi_req_ref(req); + s->req = req; + return NULL; +} + static const struct SCSIBusInfo usb_msd_scsi_info = { .tcq = false, .max_target = 0, @@ -511,7 +524,8 @@ static const struct SCSIBusInfo usb_msd_scsi_info = { .transfer_data = usb_msd_transfer_data, .complete = usb_msd_command_complete, - .cancel = usb_msd_request_cancelled + .cancel = usb_msd_request_cancelled, + .load_request = usb_msd_load_request, }; static int usb_msd_initfn(USBDevice *dev) @@ -584,7 +598,7 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename) /* parse -usbdevice disk: syntax into drive opts */ snprintf(id, sizeof(id), "usb%d", nr++); - opts = qemu_opts_create(qemu_find_opts("drive"), id, 0); + opts = qemu_opts_create(qemu_find_opts("drive"), id, 0, NULL); p1 = strchr(filename, ':'); if (p1++) { @@ -631,11 +645,18 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename) 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_UINT32(mode, MSDState), + VMSTATE_UINT32(scsi_len, MSDState), + VMSTATE_UINT32(scsi_off, MSDState), + VMSTATE_UINT32(data_len, MSDState), + VMSTATE_UINT32(csw.sig, MSDState), + VMSTATE_UINT32(csw.tag, MSDState), + VMSTATE_UINT32(csw.residue, MSDState), + VMSTATE_UINT8(csw.status, MSDState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index e759c996ce..5298204d9d 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -334,6 +334,7 @@ typedef struct EHCIfstn { uint32_t backptr; // Standard next link pointer } EHCIfstn; +typedef struct EHCIPacket EHCIPacket; typedef struct EHCIQueue EHCIQueue; typedef struct EHCIState EHCIState; @@ -343,26 +344,36 @@ enum async_state { EHCI_ASYNC_FINISHED, }; +struct EHCIPacket { + EHCIQueue *queue; + QTAILQ_ENTRY(EHCIPacket) next; + + 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 EHCIQueue { EHCIState *ehci; QTAILQ_ENTRY(EHCIQueue) next; uint32_t seen; uint64_t ts; + int async; /* 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; + EHCIqh qh; /* copy of current QH (being worked on) */ + uint32_t qhaddr; /* address QH read from */ + uint32_t qtdaddr; /* address QTD read from */ + USBDevice *dev; + QTAILQ_HEAD(, EHCIPacket) packets; }; typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; @@ -375,7 +386,6 @@ struct EHCIState { int companion_count; /* properties */ - uint32_t freq; uint32_t maxframes; /* @@ -403,7 +413,7 @@ struct EHCIState { * Internal states, shadow registers, etc */ QEMUTimer *frame_timer; - int attach_poll_counter; + QEMUBH *async_bh; int astate; // Current state in asynchronous schedule int pstate; // Current state in periodic schedule USBPort ports[NB_PORTS]; @@ -419,6 +429,7 @@ struct EHCIState { QEMUSGList isgl; uint64_t last_run_ns; + uint32_t async_stepdown; }; #define SET_LAST_RUN_CLOCK(s) \ @@ -574,14 +585,37 @@ static inline void ehci_commit_interrupt(EHCIState *s) s->usbsts_pending = 0; } +static void ehci_update_halt(EHCIState *s) +{ + if (s->usbcmd & USBCMD_RUNSTOP) { + ehci_clear_usbsts(s, USBSTS_HALT); + } else { + if (s->astate == EST_INACTIVE && s->pstate == EST_INACTIVE) { + ehci_set_usbsts(s, USBSTS_HALT); + } + } +} + static void ehci_set_state(EHCIState *s, int async, int state) { if (async) { trace_usb_ehci_state("async", state2str(state)); s->astate = state; + if (s->astate == EST_INACTIVE) { + ehci_clear_usbsts(s, USBSTS_ASS); + ehci_update_halt(s); + } else { + ehci_set_usbsts(s, USBSTS_ASS); + } } else { trace_usb_ehci_state("periodic", state2str(state)); s->pstate = state; + if (s->pstate == EST_INACTIVE) { + ehci_clear_usbsts(s, USBSTS_PSS); + ehci_update_halt(s); + } else { + ehci_set_usbsts(s, USBSTS_PSS); + } } } @@ -655,27 +689,71 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, (bool)(sitd->results & SITD_RESULTS_ACTIVE)); } +static inline bool ehci_enabled(EHCIState *s) +{ + return s->usbcmd & USBCMD_RUNSTOP; +} + +static inline bool ehci_async_enabled(EHCIState *s) +{ + return ehci_enabled(s) && (s->usbcmd & USBCMD_ASE); +} + +static inline bool ehci_periodic_enabled(EHCIState *s) +{ + return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE); +} + +/* packet management */ + +static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) +{ + EHCIPacket *p; + + p = g_new0(EHCIPacket, 1); + p->queue = q; + usb_packet_init(&p->packet); + QTAILQ_INSERT_TAIL(&q->packets, p, next); + trace_usb_ehci_packet_action(p->queue, p, "alloc"); + return p; +} + +static void ehci_free_packet(EHCIPacket *p) +{ + trace_usb_ehci_packet_action(p->queue, p, "free"); + if (p->async == EHCI_ASYNC_INFLIGHT) { + usb_cancel_packet(&p->packet); + } + QTAILQ_REMOVE(&p->queue->packets, p, next); + usb_packet_cleanup(&p->packet); + g_free(p); +} + /* queue management */ -static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async) +static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; EHCIQueue *q; q = g_malloc0(sizeof(*q)); q->ehci = ehci; - usb_packet_init(&q->packet); + q->qhaddr = addr; + q->async = async; + QTAILQ_INIT(&q->packets); QTAILQ_INSERT_HEAD(head, q, next); trace_usb_ehci_queue_action(q, "alloc"); return q; } -static void ehci_free_queue(EHCIQueue *q, int async) +static void ehci_free_queue(EHCIQueue *q) { - EHCIQueueHead *head = async ? &q->ehci->aqueues : &q->ehci->pqueues; + EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; + EHCIPacket *p; + trace_usb_ehci_queue_action(q, "free"); - if (q->async == EHCI_ASYNC_INFLIGHT) { - usb_cancel_packet(&q->packet); + while ((p = QTAILQ_FIRST(&q->packets)) != NULL) { + ehci_free_packet(p); } QTAILQ_REMOVE(head, q, next); g_free(q); @@ -698,6 +776,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, head, next, tmp) { @@ -706,11 +785,10 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) q->ts = ehci->last_run_ns; continue; } - if (!flush && ehci->last_run_ns < q->ts + 250000000) { - /* allow 0.25 sec idle */ + if (!flush && ehci->last_run_ns < q->ts + maxage) { continue; } - ehci_free_queue(q, async); + ehci_free_queue(q); } } @@ -720,11 +798,10 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, head, next, tmp) { - if (!usb_packet_is_inflight(&q->packet) || - q->packet.ep->dev != dev) { + if (q->dev != dev) { continue; } - ehci_free_queue(q, async); + ehci_free_queue(q); } } @@ -734,7 +811,7 @@ static void ehci_queues_rip_all(EHCIState *ehci, int async) EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, head, next, tmp) { - ehci_free_queue(q, async); + ehci_free_queue(q); } } @@ -812,6 +889,8 @@ static void ehci_wakeup(USBPort *port) USBPort *companion = s->companion_ports[port->index]; if (companion->ops->wakeup) { companion->ops->wakeup(companion); + } else { + qemu_bh_schedule(s->async_bh); } } } @@ -904,7 +983,6 @@ static void ehci_reset(void *opaque) s->astate = EST_INACTIVE; s->pstate = EST_INACTIVE; - s->attach_poll_counter = 0; for(i = 0; i < NB_PORTS; i++) { if (s->companion_ports[i]) { @@ -920,6 +998,7 @@ static void ehci_reset(void *opaque) ehci_queues_rip_all(s, 0); ehci_queues_rip_all(s, 1); qemu_del_timer(s->frame_timer); + qemu_bh_cancel(s->async_bh); } static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) @@ -1064,22 +1143,20 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) /* Do any register specific pre-write processing here. */ switch(addr) { case USBCMD: - if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) { - qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); - SET_LAST_RUN_CLOCK(s); - ehci_clear_usbsts(s, USBSTS_HALT); - } - - if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) { - qemu_del_timer(s->frame_timer); - ehci_queues_rip_all(s, 0); - ehci_queues_rip_all(s, 1); - ehci_set_usbsts(s, USBSTS_HALT); - } - if (val & USBCMD_HCRESET) { ehci_reset(s); val = s->usbcmd; + break; + } + + if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) != + ((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) { + if (s->pstate == EST_INACTIVE) { + SET_LAST_RUN_CLOCK(s); + } + ehci_update_halt(s); + s->async_stepdown = 0; + qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); } /* not supporting dynamic frame list size at the moment */ @@ -1114,7 +1191,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) break; case PERIODICLISTBASE: - if ((s->usbcmd & USBCMD_PSE) && (s->usbcmd & USBCMD_RUNSTOP)) { + if (ehci_periodic_enabled(s)) { fprintf(stderr, "ehci: PERIODIC list base register set while periodic schedule\n" " is enabled and HC is enabled\n"); @@ -1122,7 +1199,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) break; case ASYNCLISTADDR: - if ((s->usbcmd & USBCMD_ASE) && (s->usbcmd & USBCMD_RUNSTOP)) { + if (ehci_async_enabled(s)) { fprintf(stderr, "ehci: ASYNC list address register set while async schedule\n" " is enabled and HC is enabled\n"); @@ -1169,21 +1246,25 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr, static int ehci_qh_do_overlay(EHCIQueue *q) { + EHCIPacket *p = QTAILQ_FIRST(&q->packets); int i; int dtoggle; int ping; int eps; int reload; + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + // remember values in fields to preserve in qh after overlay dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE; ping = q->qh.token & QTD_TOKEN_PING; - 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; + q->qh.current_qtd = p->qtdaddr; + q->qh.next_qtd = p->qtd.next; + q->qh.altnext_qtd = p->qtd.altnext; + q->qh.token = p->qtd.token; eps = get_field(q->qh.epchar, QH_EPCHAR_EPS); @@ -1196,7 +1277,7 @@ static int ehci_qh_do_overlay(EHCIQueue *q) set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT); for (i = 0; i < 5; i++) { - q->qh.bufptr[i] = q->qtd.bufptr[i]; + q->qh.bufptr[i] = p->qtd.bufptr[i]; } if (!(q->qh.epchar & QH_EPCHAR_DTC)) { @@ -1214,15 +1295,15 @@ static int ehci_qh_do_overlay(EHCIQueue *q) return 0; } -static int ehci_init_transfer(EHCIQueue *q) +static int ehci_init_transfer(EHCIPacket *p) { uint32_t cpage, offset, bytes, plen; dma_addr_t page; - 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(p->qtd.token, QTD_TOKEN_CPAGE); + bytes = get_field(p->qtd.token, QTD_TOKEN_TBYTES); + offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK; + pci_dma_sglist_init(&p->sgl, &p->queue->ehci->dev, 5); while (bytes > 0) { if (cpage > 4) { @@ -1230,7 +1311,7 @@ static int ehci_init_transfer(EHCIQueue *q) return USB_RET_PROCERR; } - page = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK; + page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK; page += offset; plen = bytes; if (plen > 4096 - offset) { @@ -1239,7 +1320,7 @@ static int ehci_init_transfer(EHCIQueue *q) cpage++; } - qemu_sglist_add(&q->sgl, page, plen); + qemu_sglist_add(&p->sgl, page, plen); bytes -= plen; } return 0; @@ -1249,8 +1330,6 @@ static void ehci_finish_transfer(EHCIQueue *q, int status) { uint32_t cpage, offset; - qemu_sglist_destroy(&q->sgl); - if (status > 0) { /* update cpage & offset */ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); @@ -1268,7 +1347,7 @@ static void ehci_finish_transfer(EHCIQueue *q, int status) static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) { - EHCIQueue *q; + EHCIPacket *p; EHCIState *s = port->opaque; uint32_t portsc = s->portsc[port->index]; @@ -1278,23 +1357,31 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) return; } - 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; + p = container_of(packet, EHCIPacket, packet); + trace_usb_ehci_packet_action(p->queue, p, "wakeup"); + assert(p->async == EHCI_ASYNC_INFLIGHT); + p->async = EHCI_ASYNC_FINISHED; + p->usb_status = packet->result; + + if (p->queue->async) { + qemu_bh_schedule(p->queue->ehci->async_bh); + } } static void ehci_execute_complete(EHCIQueue *q) { - assert(q->async != EHCI_ASYNC_INFLIGHT); - q->async = EHCI_ASYNC_NONE; + EHCIPacket *p = QTAILQ_FIRST(&q->packets); + + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + assert(p->async != EHCI_ASYNC_INFLIGHT); + p->async = EHCI_ASYNC_NONE; DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n", q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); - if (q->usb_status < 0) { - switch(q->usb_status) { + if (p->usb_status < 0) { + switch (p->usb_status) { case USB_RET_IOERROR: case USB_RET_NODEV: q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); @@ -1314,28 +1401,29 @@ static void ehci_execute_complete(EHCIQueue *q) break; default: /* should not be triggerable */ - fprintf(stderr, "USB invalid response %d to handle\n", q->usb_status); + fprintf(stderr, "USB invalid response %d\n", p->usb_status); assert(0); break; } - } else if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) { - q->usb_status = USB_RET_BABBLE; + } else if ((p->usb_status > p->tbytes) && (p->pid == USB_TOKEN_IN)) { + p->usb_status = USB_RET_BABBLE; q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); ehci_record_interrupt(q->ehci, USBSTS_ERRINT); } else { // TODO check 4.12 for splits - if (q->tbytes && q->pid == USB_TOKEN_IN) { - q->tbytes -= q->usb_status; + if (p->tbytes && p->pid == USB_TOKEN_IN) { + p->tbytes -= p->usb_status; } else { - q->tbytes = 0; + p->tbytes = 0; } - DPRINTF("updating tbytes to %d\n", q->tbytes); - set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES); + DPRINTF("updating tbytes to %d\n", p->tbytes); + set_field(&q->qh.token, p->tbytes, QTD_TOKEN_TBYTES); } - ehci_finish_transfer(q, q->usb_status); - usb_packet_unmap(&q->packet); + ehci_finish_transfer(q, p->usb_status); + qemu_sglist_destroy(&p->sgl); + usb_packet_unmap(&p->packet); q->qh.token ^= QTD_TOKEN_DTOGGLE; q->qh.token &= ~QTD_TOKEN_ACTIVE; @@ -1347,48 +1435,51 @@ static void ehci_execute_complete(EHCIQueue *q) // 4.10.3 -static int ehci_execute(EHCIQueue *q) +static int ehci_execute(EHCIPacket *p, const char *action) { - USBDevice *dev; USBEndpoint *ep; int ret; int endp; - int devadr; - if ( !(q->qh.token & QTD_TOKEN_ACTIVE)) { - fprintf(stderr, "Attempting to execute inactive QH\n"); + if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) { + fprintf(stderr, "Attempting to execute inactive qtd\n"); return USB_RET_PROCERR; } - q->tbytes = (q->qh.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH; - if (q->tbytes > BUFF_SIZE) { + p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH; + if (p->tbytes > BUFF_SIZE) { fprintf(stderr, "Request for more bytes than allowed\n"); return USB_RET_PROCERR; } - 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; + p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH; + switch (p->pid) { + case 0: + p->pid = USB_TOKEN_OUT; + break; + case 1: + p->pid = USB_TOKEN_IN; + break; + case 2: + p->pid = USB_TOKEN_SETUP; + break; + default: + fprintf(stderr, "bad token\n"); + break; } - if (ehci_init_transfer(q) != 0) { + if (ehci_init_transfer(p) != 0) { return USB_RET_PROCERR; } - endp = get_field(q->qh.epchar, QH_EPCHAR_EP); - devadr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); + endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); + ep = usb_ep_get(p->queue->dev, p->pid, endp); - /* TODO: associating device with ehci port */ - dev = ehci_find_device(q->ehci, devadr); - ep = usb_ep_get(dev, q->pid, endp); + usb_packet_setup(&p->packet, p->pid, ep); + usb_packet_map(&p->packet, &p->sgl); - usb_packet_setup(&q->packet, q->pid, ep); - usb_packet_map(&q->packet, &q->sgl); - - ret = usb_handle_packet(dev, &q->packet); + trace_usb_ehci_packet_action(p->queue, p, action); + ret = usb_handle_packet(p->queue->dev, &p->packet); 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, @@ -1504,6 +1595,24 @@ static int ehci_process_itd(EHCIState *ehci, return 0; } + +/* + * 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); +} + /* This state is the entry point for asynchronous schedule * processing. Entry here consitutes a EHCI start event state (4.8.5) */ @@ -1601,17 +1710,18 @@ out: static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) { - uint32_t entry; + EHCIPacket *p; + uint32_t entry, devaddr; EHCIQueue *q; entry = ehci_get_fetch_addr(ehci, async); q = ehci_find_queue_by_qh(ehci, entry, async); if (NULL == q) { - q = ehci_alloc_queue(ehci, async); + q = ehci_alloc_queue(ehci, entry, async); } - q->qhaddr = entry; - q->seen++; + p = QTAILQ_FIRST(&q->packets); + q->seen++; if (q->seen > 1) { /* we are going in circles -- stop processing */ ehci_set_state(ehci, async, EST_ACTIVE); @@ -1623,14 +1733,28 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); - if (q->async == EHCI_ASYNC_INFLIGHT) { + devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); + if (q->dev != NULL && q->dev->addr != devaddr) { + if (!QTAILQ_EMPTY(&q->packets)) { + /* should not happen (guest bug) */ + while ((p = QTAILQ_FIRST(&q->packets)) != NULL) { + ehci_free_packet(p); + } + } + q->dev = NULL; + } + if (q->dev == NULL) { + q->dev = ehci_find_device(q->ehci, devaddr); + } + + if (p && p->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) { + if (p && p->async == EHCI_ASYNC_FINISHED) { /* I/O finished -- continue processing queue */ - trace_usb_ehci_queue_action(q, "resume"); + trace_usb_ehci_packet_action(p->queue, p, "complete"); ehci_set_state(ehci, async, EST_EXECUTING); goto out; } @@ -1726,7 +1850,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async) } /* Section 4.10.2 - paragraph 3 */ -static int ehci_state_advqueue(EHCIQueue *q, int async) +static int ehci_state_advqueue(EHCIQueue *q) { #if 0 /* TO-DO: 4.10.2 - paragraph 2 @@ -1745,81 +1869,117 @@ static int ehci_state_advqueue(EHCIQueue *q, int async) if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) && (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) { q->qtdaddr = q->qh.altnext_qtd; - ehci_set_state(q->ehci, async, EST_FETCHQTD); + ehci_set_state(q->ehci, q->async, EST_FETCHQTD); /* * next qTD is valid */ } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) { q->qtdaddr = q->qh.next_qtd; - ehci_set_state(q->ehci, async, EST_FETCHQTD); + ehci_set_state(q->ehci, q->async, EST_FETCHQTD); /* * no valid qTD, try next QH */ } else { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); } return 1; } /* Section 4.10.2 - paragraph 4 */ -static int ehci_state_fetchqtd(EHCIQueue *q, int async) +static int ehci_state_fetchqtd(EHCIQueue *q) { + EHCIqtd qtd; + EHCIPacket *p; int again = 0; - get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &q->qtd, + get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); - ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &q->qtd); + ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd); - if (q->qtd.token & QTD_TOKEN_ACTIVE) { - ehci_set_state(q->ehci, async, EST_EXECUTE); + p = QTAILQ_FIRST(&q->packets); + while (p != NULL && p->qtdaddr != q->qtdaddr) { + /* should not happen (guest bug) */ + ehci_free_packet(p); + p = QTAILQ_FIRST(&q->packets); + } + if (p != NULL) { + ehci_qh_do_overlay(q); + ehci_flush_qh(q); + if (p->async == EHCI_ASYNC_INFLIGHT) { + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); + } else { + ehci_set_state(q->ehci, q->async, EST_EXECUTING); + } + again = 1; + } else if (qtd.token & QTD_TOKEN_ACTIVE) { + p = ehci_alloc_packet(q); + p->qtdaddr = q->qtdaddr; + p->qtd = qtd; + ehci_set_state(q->ehci, q->async, EST_EXECUTE); again = 1; } else { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1; } return again; } -static int ehci_state_horizqh(EHCIQueue *q, int async) +static int ehci_state_horizqh(EHCIQueue *q) { int again = 0; - 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); + if (ehci_get_fetch_addr(q->ehci, q->async) != q->qh.next) { + ehci_set_fetch_addr(q->ehci, q->async, q->qh.next); + ehci_set_state(q->ehci, q->async, EST_FETCHENTRY); again = 1; } else { - ehci_set_state(q->ehci, async, EST_ACTIVE); + ehci_set_state(q->ehci, q->async, EST_ACTIVE); } return again; } -/* - * 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) +static void ehci_fill_queue(EHCIPacket *p) { - uint32_t *qh = (uint32_t *) &q->qh; - uint32_t dwords = sizeof(EHCIqh) >> 2; - uint32_t addr = NLPTR_GET(q->qhaddr); + EHCIQueue *q = p->queue; + EHCIqtd qtd = p->qtd; + uint32_t qtdaddr; - put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3); + for (;;) { + if (NLPTR_TBIT(qtd.altnext) == 0) { + break; + } + if (NLPTR_TBIT(qtd.next) != 0) { + break; + } + qtdaddr = qtd.next; + get_dwords(q->ehci, NLPTR_GET(qtdaddr), + (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); + ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd); + if (!(qtd.token & QTD_TOKEN_ACTIVE)) { + break; + } + p = ehci_alloc_packet(q); + p->qtdaddr = qtdaddr; + p->qtd = qtd; + p->usb_status = ehci_execute(p, "queue"); + assert(p->usb_status = USB_RET_ASYNC); + p->async = EHCI_ASYNC_INFLIGHT; + } } -static int ehci_state_execute(EHCIQueue *q, int async) +static int ehci_state_execute(EHCIQueue *q) { + EHCIPacket *p = QTAILQ_FIRST(&q->packets); int again = 0; + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + if (ehci_qh_do_overlay(q) != 0) { return -1; } @@ -1828,55 +1988,60 @@ static int ehci_state_execute(EHCIQueue *q, int async) // 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) { + if (!q->async) { int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); if (!transactCtr) { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1; goto out; } } - if (async) { + if (q->async) { ehci_set_usbsts(q->ehci, USBSTS_REC); } - q->usb_status = ehci_execute(q); - if (q->usb_status == USB_RET_PROCERR) { + p->usb_status = ehci_execute(p, "process"); + if (p->usb_status == USB_RET_PROCERR) { again = -1; goto out; } - if (q->usb_status == USB_RET_ASYNC) { + if (p->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); + trace_usb_ehci_packet_action(p->queue, p, "async"); + p->async = EHCI_ASYNC_INFLIGHT; + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1; + ehci_fill_queue(p); goto out; } - ehci_set_state(q->ehci, async, EST_EXECUTING); + ehci_set_state(q->ehci, q->async, EST_EXECUTING); again = 1; out: return again; } -static int ehci_state_executing(EHCIQueue *q, int async) +static int ehci_state_executing(EHCIQueue *q) { + EHCIPacket *p = QTAILQ_FIRST(&q->packets); int again = 0; + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + ehci_execute_complete(q); - if (q->usb_status == USB_RET_ASYNC) { + if (p->usb_status == USB_RET_ASYNC) { goto out; } - if (q->usb_status == USB_RET_PROCERR) { + if (p->usb_status == USB_RET_PROCERR) { again = -1; goto out; } // 4.10.3 - if (!async) { + if (!q->async) { int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); transactCtr--; set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT); @@ -1885,10 +2050,10 @@ static int ehci_state_executing(EHCIQueue *q, int async) } /* 4.10.5 */ - if (q->usb_status == USB_RET_NAK) { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + if (p->usb_status == USB_RET_NAK) { + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); } else { - ehci_set_state(q->ehci, async, EST_WRITEBACK); + ehci_set_state(q->ehci, q->async, EST_WRITEBACK); } again = 1; @@ -1899,14 +2064,19 @@ out: } -static int ehci_state_writeback(EHCIQueue *q, int async) +static int ehci_state_writeback(EHCIQueue *q) { + EHCIPacket *p = QTAILQ_FIRST(&q->packets); int again = 0; /* Write back the QTD from the QH area */ - 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, + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + + ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd); + put_dwords(q->ehci, NLPTR_GET(p->qtdaddr), (uint32_t *) &q->qh.next_qtd, sizeof(EHCIqtd) >> 2); + ehci_free_packet(p); /* * EHCI specs say go horizontal here. @@ -1917,10 +2087,10 @@ static int ehci_state_writeback(EHCIQueue *q, int async) * bit is clear. */ if (q->qh.token & QTD_TOKEN_HALT) { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1; } else { - ehci_set_state(q->ehci, async, EST_ADVANCEQUEUE); + ehci_set_state(q->ehci, q->async, EST_ADVANCEQUEUE); again = 1; } return again; @@ -1930,8 +2100,7 @@ static int ehci_state_writeback(EHCIQueue *q, int async) * This is the state machine that is common to both async and periodic */ -static void ehci_advance_state(EHCIState *ehci, - int async) +static void ehci_advance_state(EHCIState *ehci, int async) { EHCIQueue *q = NULL; int again; @@ -1948,7 +2117,12 @@ static void ehci_advance_state(EHCIState *ehci, case EST_FETCHQH: q = ehci_state_fetchqh(ehci, async); - again = q ? 1 : 0; + if (q != NULL) { + assert(q->async == async); + again = 1; + } else { + again = 0; + } break; case EST_FETCHITD: @@ -1960,29 +2134,35 @@ static void ehci_advance_state(EHCIState *ehci, break; case EST_ADVANCEQUEUE: - again = ehci_state_advqueue(q, async); + again = ehci_state_advqueue(q); break; case EST_FETCHQTD: - again = ehci_state_fetchqtd(q, async); + again = ehci_state_fetchqtd(q); break; case EST_HORIZONTALQH: - again = ehci_state_horizqh(q, async); + again = ehci_state_horizqh(q); break; case EST_EXECUTE: - again = ehci_state_execute(q, async); + again = ehci_state_execute(q); + if (async) { + ehci->async_stepdown = 0; + } break; case EST_EXECUTING: assert(q != NULL); - again = ehci_state_executing(q, async); + if (async) { + ehci->async_stepdown = 0; + } + again = ehci_state_executing(q); break; case EST_WRITEBACK: assert(q != NULL); - again = ehci_state_writeback(q, async); + again = ehci_state_writeback(q); break; default: @@ -2009,17 +2189,15 @@ static void ehci_advance_async_state(EHCIState *ehci) switch(ehci_get_state(ehci, async)) { case EST_INACTIVE: - if (!(ehci->usbcmd & USBCMD_ASE)) { + if (!ehci_async_enabled(ehci)) { break; } - 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)) { + if (!ehci_async_enabled(ehci)) { ehci_queues_rip_all(ehci, async); - ehci_clear_usbsts(ehci, USBSTS_ASS); ehci_set_state(ehci, async, EST_INACTIVE); break; } @@ -2070,17 +2248,15 @@ static void ehci_advance_periodic_state(EHCIState *ehci) switch(ehci_get_state(ehci, async)) { case EST_INACTIVE: - if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) { - ehci_set_usbsts(ehci, USBSTS_PSS); + if (!(ehci->frindex & 7) && ehci_periodic_enabled(ehci)) { 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)) { + if (!(ehci->frindex & 7) && !ehci_periodic_enabled(ehci)) { ehci_queues_rip_all(ehci, async); - ehci_clear_usbsts(ehci, USBSTS_PSS); ehci_set_state(ehci, async, EST_INACTIVE); break; } @@ -2111,58 +2287,86 @@ static void ehci_advance_periodic_state(EHCIState *ehci) } } +static void ehci_update_frindex(EHCIState *ehci, int frames) +{ + int i; + + if (!ehci_enabled(ehci)) { + return; + } + + for (i = 0; i < frames; i++) { + ehci->frindex += 8; + + if (ehci->frindex == 0x00002000) { + ehci_set_interrupt(ehci, USBSTS_FLR); + } + + if (ehci->frindex == 0x00004000) { + ehci_set_interrupt(ehci, USBSTS_FLR); + ehci->frindex = 0; + } + } +} + static void ehci_frame_timer(void *opaque) { EHCIState *ehci = opaque; + int schedules = 0; int64_t expire_time, t_now; uint64_t ns_elapsed; - int frames; + int frames, skipped_frames; int i; - int skipped_frames = 0; t_now = qemu_get_clock_ns(vm_clock); - expire_time = t_now + (get_ticks_per_sec() / ehci->freq); - ns_elapsed = t_now - ehci->last_run_ns; frames = ns_elapsed / FRAME_TIMER_NS; - for (i = 0; i < frames; i++) { - if ( !(ehci->usbsts & USBSTS_HALT)) { - ehci->frindex += 8; - - if (ehci->frindex == 0x00002000) { - ehci_set_interrupt(ehci, USBSTS_FLR); - } + if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) { + schedules++; + expire_time = t_now + (get_ticks_per_sec() / FRAME_TIMER_FREQ); - if (ehci->frindex == 0x00004000) { - ehci_set_interrupt(ehci, USBSTS_FLR); - ehci->frindex = 0; - } + if (frames > ehci->maxframes) { + skipped_frames = frames - ehci->maxframes; + ehci_update_frindex(ehci, skipped_frames); + ehci->last_run_ns += FRAME_TIMER_NS * skipped_frames; + frames -= skipped_frames; + DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames); } - if (frames - i > ehci->maxframes) { - skipped_frames++; - } else { + for (i = 0; i < frames; i++) { + ehci_update_frindex(ehci, 1); ehci_advance_periodic_state(ehci); + ehci->last_run_ns += FRAME_TIMER_NS; } - - ehci->last_run_ns += FRAME_TIMER_NS; - } - -#if 0 - if (skipped_frames) { - DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames); + } else { + if (ehci->async_stepdown < ehci->maxframes / 2) { + ehci->async_stepdown++; + } + expire_time = t_now + (get_ticks_per_sec() + * ehci->async_stepdown / FRAME_TIMER_FREQ); + ehci_update_frindex(ehci, frames); + ehci->last_run_ns += FRAME_TIMER_NS * frames; } -#endif /* Async is not inside loop since it executes everything it can once * called */ - ehci_advance_async_state(ehci); + if (ehci_async_enabled(ehci) || ehci->astate != EST_INACTIVE) { + schedules++; + qemu_bh_schedule(ehci->async_bh); + } - qemu_mod_timer(ehci->frame_timer, expire_time); + if (schedules) { + qemu_mod_timer(ehci->frame_timer, expire_time); + } } +static void ehci_async_bh(void *opaque) +{ + EHCIState *ehci = opaque; + ehci_advance_async_state(ehci); +} static const MemoryRegionOps ehci_mem_ops = { .old_mmio = { @@ -2192,7 +2396,6 @@ static const VMStateDescription vmstate_ehci = { }; 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(), }; @@ -2298,6 +2501,7 @@ static int usb_ehci_initfn(PCIDevice *dev) } s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s); + s->async_bh = qemu_bh_new(ehci_async_bh, s); QTAILQ_INIT(&s->aqueues); QTAILQ_INIT(&s->pqueues); diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 9e211a0bb4..9871e24f50 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -131,10 +131,14 @@ struct UHCIState { uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ int64_t expire_time; QEMUTimer *frame_timer; + QEMUBH *bh; + uint32_t frame_bytes; + uint32_t frame_bandwidth; UHCIPort ports[NB_PORTS]; /* Interrupts that should be raised at the end of the current frame. */ uint32_t pending_int_mask; + int irq_pin; /* Active packets */ QTAILQ_HEAD(, UHCIQueue) queues; @@ -337,7 +341,7 @@ static void uhci_update_irq(UHCIState *s) } else { level = 0; } - qemu_set_irq(s->dev.irq[3], level); + qemu_set_irq(s->dev.irq[s->irq_pin], level); } static void uhci_reset(void *opaque) @@ -369,16 +373,10 @@ static void uhci_reset(void *opaque) } uhci_async_cancel_all(s); + qemu_bh_cancel(s->bh); uhci_update_irq(s); } -static void uhci_pre_save(void *opaque) -{ - UHCIState *s = opaque; - - uhci_async_cancel_all(s); -} - static const VMStateDescription vmstate_uhci_port = { .name = "uhci port", .version_id = 1, @@ -395,7 +393,6 @@ static const VMStateDescription vmstate_uhci = { .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, - .pre_save = uhci_pre_save, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, UHCIState), VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState), @@ -905,7 +902,9 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet) uhci_async_free(async); } else { async->done = 1; - uhci_process_frame(s); + if (s->frame_bytes < s->frame_bandwidth) { + qemu_bh_schedule(s->bh); + } } } @@ -985,7 +984,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) static void uhci_process_frame(UHCIState *s) { uint32_t frame_addr, link, old_td_ctrl, val, int_mask; - uint32_t curr_qh, td_count = 0, bytes_count = 0; + uint32_t curr_qh, td_count = 0; int cnt, ret; UHCI_TD td; UHCI_QH qh; @@ -1002,6 +1001,12 @@ static void uhci_process_frame(UHCIState *s) qhdb_reset(&qhdb); for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) { + if (s->frame_bytes >= s->frame_bandwidth) { + /* We've reached the usb 1.1 bandwidth, which is + 1280 bytes/frame, stop processing */ + trace_usb_uhci_frame_stop_bandwidth(); + break; + } if (is_qh(link)) { /* QH */ trace_usb_uhci_qh_load(link & ~0xf); @@ -1011,18 +1016,12 @@ static void uhci_process_frame(UHCIState *s) * We're going in circles. Which is not a bug because * HCD is allowed to do that as part of the BW management. * - * Stop processing here if - * (a) no transaction has been done since we've been - * here last time, or - * (b) we've reached the usb 1.1 bandwidth, which is - * 1280 bytes/frame. + * Stop processing here if no transaction has been done + * since we've been here last time. */ if (td_count == 0) { trace_usb_uhci_frame_loop_stop_idle(); break; - } else if (bytes_count >= 1280) { - trace_usb_uhci_frame_loop_stop_bandwidth(); - break; } else { trace_usb_uhci_frame_loop_continue(); td_count = 0; @@ -1085,7 +1084,7 @@ static void uhci_process_frame(UHCIState *s) trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf); link = td.link; td_count++; - bytes_count += (td.ctrl & 0x7ff) + 1; + s->frame_bytes += (td.ctrl & 0x7ff) + 1; if (curr_qh) { /* update QH element link */ @@ -1112,12 +1111,20 @@ out: s->pending_int_mask |= int_mask; } +static void uhci_bh(void *opaque) +{ + UHCIState *s = opaque; + uhci_process_frame(s); +} + static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; /* prepare the timer for the next frame */ s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); + s->frame_bytes = 0; + qemu_bh_cancel(s->bh); if (!(s->cmd & UHCI_CMD_RS)) { /* Full stop */ @@ -1178,15 +1185,31 @@ static USBBusOps uhci_bus_ops = { static int usb_uhci_common_initfn(PCIDevice *dev) { + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); UHCIState *s = DO_UPCAST(UHCIState, dev, dev); uint8_t *pci_conf = s->dev.config; int i; pci_conf[PCI_CLASS_PROG] = 0x00; /* TODO: reset value should be 0. */ - pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */ pci_conf[USB_SBRN] = USB_RELEASE_1; // release number + switch (pc->device_id) { + case PCI_DEVICE_ID_INTEL_82801I_UHCI1: + s->irq_pin = 0; /* A */ + break; + case PCI_DEVICE_ID_INTEL_82801I_UHCI2: + s->irq_pin = 1; /* B */ + break; + case PCI_DEVICE_ID_INTEL_82801I_UHCI3: + s->irq_pin = 2; /* C */ + break; + default: + s->irq_pin = 3; /* D */ + break; + } + pci_config_set_interrupt_pin(pci_conf, s->irq_pin + 1); + if (s->masterbus) { USBPort *ports[NB_PORTS]; for(i = 0; i < NB_PORTS; i++) { @@ -1204,6 +1227,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); } } + s->bh = qemu_bh_new(uhci_bh, s); s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); s->num_ports_vmstate = NB_PORTS; QTAILQ_INIT(&s->queues); @@ -1244,6 +1268,7 @@ static int usb_uhci_exit(PCIDevice *dev) static Property uhci_properties[] = { DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), + DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 5cf1a64699..6c2ff024e0 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -23,6 +23,7 @@ #include "hw/usb.h" #include "hw/pci.h" #include "hw/msi.h" +#include "trace.h" //#define DEBUG_XHCI //#define DEBUG_DATA @@ -421,7 +422,6 @@ typedef struct XHCIEvRingSeg { uint32_t rsvd; } XHCIEvRingSeg; -#ifdef DEBUG_XHCI static const char *TRBType_names[] = { [TRB_RESERVED] = "TRB_RESERVED", [TR_NORMAL] = "TR_NORMAL", @@ -473,7 +473,6 @@ static const char *trb_name(XHCITRB *trb) return lookup_name(TRB_TYPE(*trb), TRBType_names, ARRAY_SIZE(TRBType_names)); } -#endif static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid); @@ -505,14 +504,13 @@ static void xhci_irq_update(XHCIState *xhci) level = 1; } - DPRINTF("xhci_irq_update(): %d\n", level); - if (xhci->msi && msi_enabled(&xhci->pci_dev)) { if (level) { - DPRINTF("xhci_irq_update(): MSI signal\n"); + trace_usb_xhci_irq_msi(0); msi_notify(&xhci->pci_dev, 0); } } else { + trace_usb_xhci_irq_intx(level); qemu_set_irq(xhci->irq, level); } } @@ -542,9 +540,8 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) } ev_trb.control = cpu_to_le32(ev_trb.control); - DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x %s\n", - xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control, - trb_name(&ev_trb)); + trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb), + ev_trb.parameter, ev_trb.status, ev_trb.control); addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); @@ -704,10 +701,8 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, le32_to_cpus(&trb->status); le32_to_cpus(&trb->control); - DPRINTF("xhci: TRB fetched [" DMA_ADDR_FMT "]: " - "%016" PRIx64 " %08x %08x %s\n", - ring->dequeue, trb->parameter, trb->status, trb->control, - trb_name(trb)); + trace_usb_xhci_fetch_trb(ring->dequeue, trb_name(trb), + trb->parameter, trb->status, trb->control); if ((trb->control & TRB_C) != ring->ccs) { return 0; @@ -746,10 +741,6 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) le32_to_cpus(&trb.status); le32_to_cpus(&trb.control); - DPRINTF("xhci: TRB peeked [" DMA_ADDR_FMT "]: " - "%016" PRIx64 " %08x %08x\n", - dequeue, trb.parameter, trb.status, trb.control); - if ((trb.control & TRB_C) != ccs) { return -length; } @@ -812,14 +803,13 @@ static void xhci_er_reset(XHCIState *xhci) static void xhci_run(XHCIState *xhci) { - DPRINTF("xhci_run()\n"); - + trace_usb_xhci_run(); xhci->usbsts &= ~USBSTS_HCH; } static void xhci_stop(XHCIState *xhci) { - DPRINTF("xhci_stop()\n"); + trace_usb_xhci_stop(); xhci->usbsts |= USBSTS_HCH; xhci->crcr_low &= ~CRCR_CRR; } @@ -852,11 +842,10 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, dma_addr_t dequeue; int i; + trace_usb_xhci_ep_enable(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); assert(epid >= 1 && epid <= 31); - DPRINTF("xhci_enable_ep(%d, %d)\n", slotid, epid); - slot = &xhci->slots[slotid-1]; if (slot->eps[epid-1]) { fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid); @@ -971,11 +960,10 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, XHCISlot *slot; XHCIEPContext *epctx; + trace_usb_xhci_ep_disable(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); assert(epid >= 1 && epid <= 31); - DPRINTF("xhci_disable_ep(%d, %d)\n", slotid, epid); - slot = &xhci->slots[slotid-1]; if (!slot->eps[epid-1]) { @@ -1001,8 +989,7 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid, XHCISlot *slot; XHCIEPContext *epctx; - DPRINTF("xhci_stop_ep(%d, %d)\n", slotid, epid); - + trace_usb_xhci_ep_stop(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); if (epid < 1 || epid > 31) { @@ -1036,10 +1023,9 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, XHCIEPContext *epctx; USBDevice *dev; + trace_usb_xhci_ep_reset(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_reset_ep(%d, %d)\n", slotid, epid); - if (epid < 1 || epid > 31) { fprintf(stderr, "xhci: bad ep %d\n", epid); return CC_TRB_ERROR; @@ -1416,12 +1402,14 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) static int xhci_complete_packet(XHCITransfer *xfer, int ret) { if (ret == USB_RET_ASYNC) { + trace_usb_xhci_xfer_async(xfer); xfer->running_async = 1; xfer->running_retry = 0; xfer->complete = 0; xfer->cancelled = 0; return 0; } else if (ret == USB_RET_NAK) { + trace_usb_xhci_xfer_nak(xfer); xfer->running_async = 0; xfer->running_retry = 1; xfer->complete = 0; @@ -1436,10 +1424,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) if (ret >= 0) { xfer->status = CC_SUCCESS; xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1); + trace_usb_xhci_xfer_success(xfer, ret); return 0; } /* error */ + trace_usb_xhci_xfer_error(xfer, ret); switch (ret) { case USB_RET_NODEV: xfer->status = CC_USB_TRANSACTION_ERROR; @@ -1475,11 +1465,12 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) USBDevice *dev; int ret; - DPRINTF("xhci_fire_ctl_transfer(slot=%d)\n", xfer->slotid); - trb_setup = &xfer->trbs[0]; trb_status = &xfer->trbs[xfer->trb_count-1]; + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, + trb_setup->parameter >> 48); + /* at most one Event Data TRB allowed after STATUS */ if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { trb_status--; @@ -1620,15 +1611,14 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext unsigned int length = 0; XHCITRB *trb; - DPRINTF("xhci_fire_transfer(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); - for (i = 0; i < xfer->trb_count; i++) { trb = &xfer->trbs[i]; if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) { length += trb->status & 0x1ffff; } } - DPRINTF("xhci: total TD length=%d\n", length); + + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length); if (!epctx->has_bg) { xfer->data_length = length; @@ -1664,9 +1654,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid int length; int i; + trace_usb_xhci_ep_kick(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); assert(epid >= 1 && epid <= 31); - DPRINTF("xhci_kick_ep(%d, %d)\n", slotid, epid); if (!xhci->slots[slotid-1].enabled) { fprintf(stderr, "xhci: xhci_kick_ep for disabled slot %d\n", slotid); @@ -1684,15 +1674,13 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid XHCITransfer *xfer = epctx->retry; int result; - DPRINTF("xhci: retry nack'ed transfer ...\n"); + trace_usb_xhci_xfer_retry(xfer); assert(xfer->running_retry); xhci_setup_packet(xfer, xfer->packet.ep->dev); result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); if (result == USB_RET_NAK) { - DPRINTF("xhci: ... xfer still nacked\n"); return; } - DPRINTF("xhci: ... result %d\n", result); xhci_complete_packet(xfer, result); assert(!xfer->running_retry); epctx->retry = NULL; @@ -1708,21 +1696,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid while (1) { XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; if (xfer->running_async || xfer->running_retry || xfer->backgrounded) { - DPRINTF("xhci: ep is busy (#%d,%d,%d,%d)\n", - epctx->next_xfer, xfer->running_async, - xfer->running_retry, xfer->backgrounded); break; - } else { - DPRINTF("xhci: ep: using #%d\n", epctx->next_xfer); } length = xhci_ring_chain_length(xhci, &epctx->ring); if (length < 0) { - DPRINTF("xhci: incomplete TD (%d TRBs)\n", -length); break; } else if (length == 0) { break; } - DPRINTF("xhci: fetching %d-TRB TD\n", length); if (xfer->trbs && xfer->trb_alloced < length) { xfer->trb_count = 0; xfer->trb_alloced = 0; @@ -1757,7 +1738,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid } if (epctx->state == EP_HALTED) { - DPRINTF("xhci: ep halted, stopping schedule\n"); break; } if (xfer->running_retry) { @@ -1770,8 +1750,8 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid) { + trace_usb_xhci_slot_enable(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_enable_slot(%d)\n", slotid); xhci->slots[slotid-1].enabled = 1; xhci->slots[slotid-1].port = 0; memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31); @@ -1783,8 +1763,8 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid) { int i; + trace_usb_xhci_slot_disable(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_disable_slot(%d)\n", slotid); for (i = 1; i <= 31; i++) { if (xhci->slots[slotid-1].eps[i-1]) { @@ -1810,8 +1790,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, int i; TRBCCode res; + trace_usb_xhci_slot_address(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_address_slot(%d)\n", slotid); dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx)); @@ -1897,8 +1877,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, int i; TRBCCode res; + trace_usb_xhci_slot_configure(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_configure_slot(%d)\n", slotid); ictx = xhci_mask64(pictx); octx = xhci->slots[slotid-1].ctx; @@ -1985,8 +1965,8 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, uint32_t islot_ctx[4]; uint32_t slot_ctx[4]; + trace_usb_xhci_slot_evaluate(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_evaluate_slot(%d)\n", slotid); ictx = xhci_mask64(pictx); octx = xhci->slots[slotid-1].ctx; @@ -2048,8 +2028,8 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid) dma_addr_t octx; int i; + trace_usb_xhci_slot_reset(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_reset_slot(%d)\n", slotid); octx = xhci->slots[slotid-1].ctx; @@ -2296,12 +2276,12 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) } } -static void xhci_reset(void *opaque) +static void xhci_reset(DeviceState *dev) { - XHCIState *xhci = opaque; + XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev.qdev, dev); int i; - DPRINTF("xhci: full reset\n"); + trace_usb_xhci_reset(); if (!(xhci->usbsts & USBSTS_HCH)) { fprintf(stderr, "xhci: reset while running!\n"); } @@ -2342,77 +2322,98 @@ static void xhci_reset(void *opaque) static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) { - DPRINTF("xhci_cap_read(0x%x)\n", reg); + uint32_t ret; switch (reg) { case 0x00: /* HCIVERSION, CAPLENGTH */ - return 0x01000000 | LEN_CAP; + ret = 0x01000000 | LEN_CAP; + break; case 0x04: /* HCSPARAMS 1 */ - return (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; + ret = (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; + break; case 0x08: /* HCSPARAMS 2 */ - return 0x0000000f; + ret = 0x0000000f; + break; case 0x0c: /* HCSPARAMS 3 */ - return 0x00000000; + ret = 0x00000000; + break; case 0x10: /* HCCPARAMS */ -#if TARGET_PHYS_ADDR_BITS > 32 - return 0x00081001; -#else - return 0x00081000; -#endif + if (sizeof(dma_addr_t) == 4) { + ret = 0x00081000; + } else { + ret = 0x00081001; + } + break; case 0x14: /* DBOFF */ - return OFF_DOORBELL; + ret = OFF_DOORBELL; + break; case 0x18: /* RTSOFF */ - return OFF_RUNTIME; + ret = OFF_RUNTIME; + break; /* extended capabilities */ case 0x20: /* Supported Protocol:00 */ -#if USB3_PORTS > 0 - return 0x02000402; /* USB 2.0 */ -#else - return 0x02000002; /* USB 2.0 */ -#endif + ret = 0x02000402; /* USB 2.0 */ + break; case 0x24: /* Supported Protocol:04 */ - return 0x20425455; /* "USB " */ + ret = 0x20425455; /* "USB " */ + break; case 0x28: /* Supported Protocol:08 */ - return 0x00000001 | (USB2_PORTS<<8); + ret = 0x00000001 | (USB2_PORTS<<8); + break; case 0x2c: /* Supported Protocol:0c */ - return 0x00000000; /* reserved */ -#if USB3_PORTS > 0 + ret = 0x00000000; /* reserved */ + break; case 0x30: /* Supported Protocol:00 */ - return 0x03000002; /* USB 3.0 */ + ret = 0x03000002; /* USB 3.0 */ + break; case 0x34: /* Supported Protocol:04 */ - return 0x20425455; /* "USB " */ + ret = 0x20425455; /* "USB " */ + break; case 0x38: /* Supported Protocol:08 */ - return 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); + ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); + break; case 0x3c: /* Supported Protocol:0c */ - return 0x00000000; /* reserved */ -#endif + ret = 0x00000000; /* reserved */ + break; default: fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg); + ret = 0; } - return 0; + + trace_usb_xhci_cap_read(reg, ret); + return ret; } static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) { uint32_t port = reg >> 4; + uint32_t ret; + if (port >= MAXPORTS) { fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); - return 0; + ret = 0; + goto out; } switch (reg & 0xf) { case 0x00: /* PORTSC */ - return xhci->ports[port].portsc; + ret = xhci->ports[port].portsc; + break; case 0x04: /* PORTPMSC */ case 0x08: /* PORTLI */ - return 0; + ret = 0; + break; case 0x0c: /* reserved */ default: fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n", port, reg); - return 0; + ret = 0; } + +out: + trace_usb_xhci_port_read(port, reg & 0x0f, ret); + return ret; } static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) @@ -2420,6 +2421,8 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) uint32_t port = reg >> 4; uint32_t portsc; + trace_usb_xhci_port_write(port, reg & 0x0f, val); + if (port >= MAXPORTS) { fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); return; @@ -2457,7 +2460,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) { - DPRINTF("xhci_oper_read(0x%x)\n", reg); + uint32_t ret; if (reg >= 0x400) { return xhci_port_read(xhci, reg - 0x400); @@ -2465,38 +2468,50 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) switch (reg) { case 0x00: /* USBCMD */ - return xhci->usbcmd; + ret = xhci->usbcmd; + break; case 0x04: /* USBSTS */ - return xhci->usbsts; + ret = xhci->usbsts; + break; case 0x08: /* PAGESIZE */ - return 1; /* 4KiB */ + ret = 1; /* 4KiB */ + break; case 0x14: /* DNCTRL */ - return xhci->dnctrl; + ret = xhci->dnctrl; + break; case 0x18: /* CRCR low */ - return xhci->crcr_low & ~0xe; + ret = xhci->crcr_low & ~0xe; + break; case 0x1c: /* CRCR high */ - return xhci->crcr_high; + ret = xhci->crcr_high; + break; case 0x30: /* DCBAAP low */ - return xhci->dcbaap_low; + ret = xhci->dcbaap_low; + break; case 0x34: /* DCBAAP high */ - return xhci->dcbaap_high; + ret = xhci->dcbaap_high; + break; case 0x38: /* CONFIG */ - return xhci->config; + ret = xhci->config; + break; default: fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg); + ret = 0; } - return 0; + + trace_usb_xhci_oper_read(reg, ret); + return ret; } static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) { - DPRINTF("xhci_oper_write(0x%x, 0x%08x)\n", reg, val); - if (reg >= 0x400) { xhci_port_write(xhci, reg - 0x400, val); return; } + trace_usb_xhci_oper_write(reg, val); + switch (reg) { case 0x00: /* USBCMD */ if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) { @@ -2506,7 +2521,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) } xhci->usbcmd = val & 0xc0f; if (val & USBCMD_HCRST) { - xhci_reset(xhci); + xhci_reset(&xhci->pci_dev.qdev); } xhci_irq_update(xhci); break; @@ -2552,35 +2567,46 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) { - DPRINTF("xhci_runtime_read(0x%x)\n", reg); + uint32_t ret; switch (reg) { case 0x00: /* MFINDEX */ fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n"); - return xhci->mfindex; + ret = xhci->mfindex; + break; case 0x20: /* IMAN */ - return xhci->iman; + ret = xhci->iman; + break; case 0x24: /* IMOD */ - return xhci->imod; + ret = xhci->imod; + break; case 0x28: /* ERSTSZ */ - return xhci->erstsz; + ret = xhci->erstsz; + break; case 0x30: /* ERSTBA low */ - return xhci->erstba_low; + ret = xhci->erstba_low; + break; case 0x34: /* ERSTBA high */ - return xhci->erstba_high; + ret = xhci->erstba_high; + break; case 0x38: /* ERDP low */ - return xhci->erdp_low; + ret = xhci->erdp_low; + break; case 0x3c: /* ERDP high */ - return xhci->erdp_high; + ret = xhci->erdp_high; + break; default: fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); + ret = 0; } - return 0; + + trace_usb_xhci_runtime_read(reg, ret); + return ret; } static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) { - DPRINTF("xhci_runtime_write(0x%x, 0x%08x)\n", reg, val); + trace_usb_xhci_runtime_read(reg, val); switch (reg) { case 0x20: /* IMAN */ @@ -2623,14 +2649,14 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg) { - DPRINTF("xhci_doorbell_read(0x%x)\n", reg); /* doorbells always read as 0 */ + trace_usb_xhci_doorbell_read(reg, 0); return 0; } static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) { - DPRINTF("xhci_doorbell_write(0x%x, 0x%08x)\n", reg, val); + trace_usb_xhci_doorbell_write(reg, val); if (!xhci_running(xhci)) { fprintf(stderr, "xhci: wrote doorbell while xHC stopped or paused\n"); @@ -2831,8 +2857,6 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) for (i = 0; i < MAXSLOTS; i++) { xhci->slots[i].enabled = 0; } - - qemu_register_reset(xhci_reset, xhci); } static int usb_xhci_initfn(struct PCIDevice *dev) @@ -2895,6 +2919,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xhci; dc->props = xhci_properties; + dc->reset = xhci_reset; k->init = usb_xhci_initfn; k->vendor_id = PCI_VENDOR_ID_NEC; k->device_id = PCI_DEVICE_ID_NEC_UPD720200; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 7c79c54d08..4fd5d9b04b 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -173,7 +173,7 @@ static void versatile_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model, int board_id) { - CPUARMState *env; + ARMCPU *cpu; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); qemu_irq *cpu_pic; @@ -189,10 +189,11 @@ static void versatile_init(ram_addr_t ram_size, int done_smc = 0; DriveInfo *dinfo; - if (!cpu_model) + if (!cpu_model) { cpu_model = "arm926"; - env = cpu_init(cpu_model); - if (!env) { + } + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } @@ -208,7 +209,7 @@ static void versatile_init(ram_addr_t ram_size, qdev_init_nofail(sysctl); sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); - cpu_pic = arm_pic_init_cpu(env); + cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("pl190", 0x10140000, cpu_pic[0], cpu_pic[1], NULL); for (n = 0; n < 32; n++) { @@ -338,7 +339,7 @@ static void versatile_init(ram_addr_t ram_size, versatile_binfo.kernel_cmdline = kernel_cmdline; versatile_binfo.initrd_filename = initrd_filename; versatile_binfo.board_id = board_id; - arm_load_kernel(env, &versatile_binfo); + arm_load_kernel(cpu, &versatile_binfo); } static void vpb_init(ram_addr_t ram_size, diff --git a/hw/vexpress.c b/hw/vexpress.c index 18d87ac378..8072c5ada9 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -159,7 +159,6 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, const char *cpu_model, qemu_irq *pic, uint32_t *proc_id) { - CPUARMState *env = NULL; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *lowram = g_new(MemoryRegion, 1); @@ -177,12 +176,12 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, *proc_id = 0x0c000191; for (n = 0; n < smp_cpus; n++) { - env = cpu_init(cpu_model); - if (!env) { + ARMCPU *cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } @@ -259,7 +258,6 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, qemu_irq *pic, uint32_t *proc_id) { int n; - CPUARMState *env = NULL; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); @@ -274,13 +272,15 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, *proc_id = 0x14000217; for (n = 0; n < smp_cpus; n++) { + ARMCPU *cpu; qemu_irq *irqp; - env = cpu_init(cpu_model); - if (!env) { + + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } @@ -438,7 +438,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, vexpress_binfo.smp_loader_start = map[VE_SRAM]; vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30; vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr; - arm_load_kernel(first_cpu, &vexpress_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &vexpress_binfo); } static void vexpress_a9_init(ram_addr_t ram_size, diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index 4a133b5d1e..79bc0d10ee 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -78,19 +78,21 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env, tlb->PID = 0; } -static CPUPPCState *ppc440_init_xilinx(ram_addr_t *ram_size, - int do_init, - const char *cpu_model, - uint32_t sysclk) +static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size, + int do_init, + const char *cpu_model, + uint32_t sysclk) { + PowerPCCPU *cpu; CPUPPCState *env; qemu_irq *irqs; - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to initialize CPU!\n"); exit(1); } + env = &cpu->env; ppc_booke_timers_init(env, sysclk, 0/* no flags */); @@ -101,15 +103,16 @@ static CPUPPCState *ppc440_init_xilinx(ram_addr_t *ram_size, 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); - return env; + return cpu; } static void main_cpu_reset(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; struct boot_info *bi = env->load_info; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); /* Linux Kernel Parameters (passing device tree): * r3: pointer to the fdt * r4: 0 @@ -188,6 +191,7 @@ static void virtex_init(ram_addr_t ram_size, { MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev; + PowerPCCPU *cpu; CPUPPCState *env; target_phys_addr_t ram_base = 0; DriveInfo *dinfo; @@ -201,8 +205,9 @@ static void virtex_init(ram_addr_t ram_size, cpu_model = "440-Xilinx"; } - env = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000); - qemu_register_reset(main_cpu_reset, env); + cpu = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000); + env = &cpu->env; + qemu_register_reset(main_cpu_reset, cpu); memory_region_init_ram(phys_ram, "ram", ram_size); vmstate_register_ram_global(phys_ram); @@ -224,7 +229,7 @@ static void virtex_init(ram_addr_t ram_size, serial_hds[0], DEVICE_LITTLE_ENDIAN); /* 2 timers at irq 2 @ 62 Mhz. */ - xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000); + xilinx_timer_create(0x83c00000, irq[3], 0, 62 * 1000000); if (kernel_filename) { uint64_t entry, low, high; diff --git a/hw/watchdog.c b/hw/watchdog.c index 4c18965654..a42124d520 100644 --- a/hw/watchdog.c +++ b/hw/watchdog.c @@ -66,7 +66,7 @@ int select_watchdog(const char *p) QLIST_FOREACH(model, &watchdog_list, entry) { if (strcasecmp(model->wdt_name, p) == 0) { /* add the device */ - opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0); + opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, NULL); qemu_opt_set(opts, "driver", p); return 0; } diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 07594bc0c8..de7e8a4a5c 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -537,6 +537,15 @@ static void blk_bh(void *opaque) blk_handle_requests(blkdev); } +/* + * We need to account for the grant allocations requiring contiguous + * chunks; the worst case number would be + * max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1, + * but in order to keep things simple just use + * 2 * max_req * max_seg. + */ +#define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg)) + static void blk_alloc(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); @@ -548,6 +557,11 @@ static void blk_alloc(struct XenDevice *xendev) if (xen_mode != XEN_EMULATE) { batch_maps = 1; } + if (xc_gnttab_set_max_grants(xendev->gnttabdev, + MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) { + xen_be_printf(xendev, 0, "xc_gnttab_set_max_grants failed: %s\n", + strerror(errno)); + } } static int blk_init(struct XenDevice *xendev) diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 7eee770eea..4b72aa7557 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -36,6 +36,7 @@ static void xen_init_pv(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { + X86CPU *cpu; CPUX86State *env; DriveInfo *dinfo; int i; @@ -48,7 +49,8 @@ static void xen_init_pv(ram_addr_t ram_size, cpu_model = "qemu32"; #endif } - env = cpu_init(cpu_model); + cpu = cpu_x86_init(cpu_model); + env = &cpu->env; env->halted = 1; /* Initialize backend core & drivers */ diff --git a/hw/xilinx.h b/hw/xilinx.h index 35f35bd7fc..7df21eb958 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -6,7 +6,7 @@ xilinx_intc_create(target_phys_addr_t base, qemu_irq irq, int kind_of_intr) { DeviceState *dev; - dev = qdev_create(NULL, "xilinx,intc"); + dev = qdev_create(NULL, "xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", kind_of_intr); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); @@ -16,12 +16,12 @@ xilinx_intc_create(target_phys_addr_t base, qemu_irq irq, int kind_of_intr) /* OPB Timer/Counter. */ static inline DeviceState * -xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int nr, int freq) +xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int oto, int freq) { DeviceState *dev; - dev = qdev_create(NULL, "xilinx,timer"); - qdev_prop_set_uint32(dev, "nr-timers", nr); + dev = qdev_create(NULL, "xlnx,xps-timer"); + qdev_prop_set_uint32(dev, "one-timer-only", oto); qdev_prop_set_uint32(dev, "frequency", freq); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); @@ -36,12 +36,12 @@ xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq, { DeviceState *dev; - qemu_check_nic_model(nd, "xilinx-ethlite"); + qemu_check_nic_model(nd, "xlnx.xps-ethernetlite"); - dev = qdev_create(NULL, "xilinx,ethlite"); + dev = qdev_create(NULL, "xlnx.xps-ethernetlite"); qdev_set_nic_properties(dev, nd); - qdev_prop_set_uint32(dev, "txpingpong", txpingpong); - qdev_prop_set_uint32(dev, "rxpingpong", rxpingpong); + qdev_prop_set_uint32(dev, "tx-ping-pong", txpingpong); + qdev_prop_set_uint32(dev, "rx-ping-pong", rxpingpong); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); @@ -54,12 +54,12 @@ xilinx_axiethernet_create(void *dmach, int txmem, int rxmem) { DeviceState *dev; - qemu_check_nic_model(nd, "xilinx-axienet"); + qemu_check_nic_model(nd, "xlnx.axi-ethernet"); - dev = qdev_create(NULL, "xilinx,axienet"); + dev = qdev_create(NULL, "xlnx.axi-ethernet"); 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_uint32(dev, "rxmem", rxmem); + qdev_prop_set_uint32(dev, "txmem", txmem); qdev_prop_set_ptr(dev, "dmach", dmach); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); @@ -75,14 +75,14 @@ xilinx_axiethernetdma_create(void *dmach, { DeviceState *dev = NULL; - dev = qdev_create(NULL, "xilinx,axidma"); + dev = qdev_create(NULL, "xlnx.axi-dma"); 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); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq2); return dev; } diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c index 85dfcbf2b9..f4bec37c7a 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -463,8 +463,8 @@ static int xilinx_axidma_init(SysBusDevice *dev) struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), dev); int i; - sysbus_init_irq(dev, &s->streams[1].irq); sysbus_init_irq(dev, &s->streams[0].irq); + sysbus_init_irq(dev, &s->streams[1].irq); if (!s->dmach) { hw_error("Unconnected DMA channel.\n"); @@ -473,7 +473,7 @@ static int xilinx_axidma_init(SysBusDevice *dev) xlx_dma_connect_dma(s->dmach, s, axidma_push); memory_region_init_io(&s->iomem, &axidma_ops, s, - "axidma", R_MAX * 4 * 2); + "xlnx.axi-dma", R_MAX * 4 * 2); sysbus_init_mmio(dev, &s->iomem); for (i = 0; i < 2; i++) { @@ -502,7 +502,7 @@ static void axidma_class_init(ObjectClass *klass, void *data) } static TypeInfo axidma_info = { - .name = "xilinx,axidma", + .name = "xlnx.axi-dma", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct XilinxAXIDMA), .class_init = axidma_class_init, diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index 7526273b4d..2e8d8a59ba 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -872,8 +872,8 @@ static int xilinx_enet_init(SysBusDevice *dev) static Property xilinx_enet_properties[] = { 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_UINT32("rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000), + DEFINE_PROP_UINT32("txmem", struct XilinxAXIEnet, c_txmem, 0x1000), DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach), DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf), DEFINE_PROP_END_OF_LIST(), @@ -889,7 +889,7 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data) } static TypeInfo xilinx_enet_info = { - .name = "xilinx,axienet", + .name = "xlnx.axi-ethernet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct XilinxAXIEnet), .class_init = xilinx_enet_class_init, diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 857b33d172..affbb8bfff 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -216,7 +216,8 @@ static int xilinx_ethlite_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->rxbuf = 0; - memory_region_init_io(&s->mmio, ð_ops, s, "xilinx-ethlite", R_MAX * 4); + memory_region_init_io(&s->mmio, ð_ops, s, "xlnx.xps-ethernetlite", + R_MAX * 4); sysbus_init_mmio(dev, &s->mmio); qemu_macaddr_default_if_unset(&s->conf.macaddr); @@ -227,8 +228,8 @@ static int xilinx_ethlite_init(SysBusDevice *dev) } static Property xilinx_ethlite_properties[] = { - DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1), - DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1), + DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1), + DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1), DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf), DEFINE_PROP_END_OF_LIST(), }; @@ -243,7 +244,7 @@ static void xilinx_ethlite_class_init(ObjectClass *klass, void *data) } static TypeInfo xilinx_ethlite_info = { - .name = "xilinx,ethlite", + .name = "xlnx.xps-ethernetlite", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct xlx_ethlite), .class_init = xilinx_ethlite_class_init, diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index 553f8488f6..386fd30743 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -156,7 +156,7 @@ static int xilinx_intc_init(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, irq_handler, 32); sysbus_init_irq(dev, &p->parent_irq); - memory_region_init_io(&p->mmio, &pic_ops, p, "xilinx-pic", R_MAX * 4); + memory_region_init_io(&p->mmio, &pic_ops, p, "xlnx.xps-intc", R_MAX * 4); sysbus_init_mmio(dev, &p->mmio); return 0; } @@ -176,7 +176,7 @@ static void xilinx_intc_class_init(ObjectClass *klass, void *data) } static TypeInfo xilinx_intc_info = { - .name = "xilinx,intc", + .name = "xlnx.xps-intc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct xlx_pic), .class_init = xilinx_intc_class_init, diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index 3ab2f2bb03..0683ce1ecf 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -62,11 +62,16 @@ struct timerblock SysBusDevice busdev; MemoryRegion mmio; qemu_irq irq; - uint32_t nr_timers; + uint8_t one_timer_only; uint32_t freq_hz; struct xlx_timer *timers; }; +static inline unsigned int num_timers(struct timerblock *t) +{ + return 2 - t->one_timer_only; +} + static inline unsigned int timer_from_addr(target_phys_addr_t addr) { /* Timers get a 4x32bit control reg area each. */ @@ -78,7 +83,7 @@ static void timer_update_irq(struct timerblock *t) unsigned int i, irq = 0; uint32_t csr; - for (i = 0; i < t->nr_timers; i++) { + for (i = 0; i < num_timers(t); i++) { csr = t->timers[i].regs[R_TCSR]; irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT); } @@ -202,8 +207,8 @@ static int xilinx_timer_init(SysBusDevice *dev) sysbus_init_irq(dev, &t->irq); /* Init all the ptimers. */ - t->timers = g_malloc0(sizeof t->timers[0] * t->nr_timers); - for (i = 0; i < t->nr_timers; i++) { + t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t)); + for (i = 0; i < num_timers(t); i++) { struct xlx_timer *xt = &t->timers[i]; xt->parent = t; @@ -213,15 +218,15 @@ static int xilinx_timer_init(SysBusDevice *dev) ptimer_set_freq(xt->ptimer, t->freq_hz); } - memory_region_init_io(&t->mmio, &timer_ops, t, "xilinx-timer", - R_MAX * 4 * t->nr_timers); + memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx,xps-timer", + R_MAX * 4 * num_timers(t)); sysbus_init_mmio(dev, &t->mmio); return 0; } static Property xilinx_timer_properties[] = { - DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 0), - DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0), + DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 62 * 1000000), + DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -235,7 +240,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data) } static TypeInfo xilinx_timer_info = { - .name = "xilinx,timer", + .name = "xlnx,xps-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct timerblock), .class_init = xilinx_timer_class_init, diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index aa0170db49..d0f32db2c6 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -202,7 +202,8 @@ static int xilinx_uartlite_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); uart_update_status(s); - memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4); + memory_region_init_io(&s->mmio, &uart_ops, s, "xlnx.xps-uartlite", + R_MAX * 4); sysbus_init_mmio(dev, &s->mmio); s->chr = qemu_char_get_next_serial(); @@ -219,7 +220,7 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) } static TypeInfo xilinx_uartlite_info = { - .name = "xilinx,uartlite", + .name = "xlnx.xps-uartlite", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof (struct xlx_uartlite), .class_init = xilinx_uartlite_class_init, diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 7290c64a4c..7e6c27359e 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -50,7 +50,7 @@ static void zynq_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) { - CPUARMState *env = NULL; + ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ext_ram = g_new(MemoryRegion, 1); MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); @@ -66,12 +66,12 @@ static void zynq_init(ram_addr_t ram_size, const char *boot_device, cpu_model = "cortex-a9"; } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq = irqp[ARM_PIC_CPU_IRQ]; /* max 2GB ram */ @@ -137,7 +137,7 @@ static void zynq_init(ram_addr_t ram_size, const char *boot_device, zynq_binfo.nb_cpus = 1; zynq_binfo.board_id = 0xd32; zynq_binfo.loader_start = 0; - arm_load_kernel(first_cpu, &zynq_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &zynq_binfo); } static QEMUMachine zynq_machine = { diff --git a/hw/xtensa/Makefile.objs b/hw/xtensa/Makefile.objs new file mode 100644 index 0000000000..79698e903d --- /dev/null +++ b/hw/xtensa/Makefile.objs @@ -0,0 +1,5 @@ +obj-y += xtensa_pic.o +obj-y += xtensa_sim.o +obj-y += xtensa_lx60.o + +obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index afdef494b2..b153bfdddf 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -148,9 +148,9 @@ static uint64_t translate_phys_addr(void *env, uint64_t addr) static void lx60_reset(void *opaque) { - CPUXtensaState *env = opaque; + XtensaCPU *cpu = opaque; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); } static void lx_init(const LxBoardDesc *board, @@ -164,6 +164,7 @@ static void lx_init(const LxBoardDesc *board, int be = 0; #endif MemoryRegion *system_memory = get_system_memory(); + XtensaCPU *cpu = NULL; CPUXtensaState *env = NULL; MemoryRegion *ram, *rom, *system_io; DriveInfo *dinfo; @@ -175,17 +176,19 @@ static void lx_init(const LxBoardDesc *board, } for (n = 0; n < smp_cpus; n++) { - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_xtensa_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; + env->sregs[PRID] = n; - qemu_register_reset(lx60_reset, env); + qemu_register_reset(lx60_reset, cpu); /* Need MMU initialized prior to ELF loading, * so that ELF gets loaded into virtual addresses */ - cpu_state_reset(env); + cpu_reset(CPU(cpu)); } ram = g_malloc(sizeof(*ram)); diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c index c7e05dcf4e..1ce07fb899 100644 --- a/hw/xtensa_sim.c +++ b/hw/xtensa_sim.c @@ -37,9 +37,11 @@ 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) +static void sim_reset(void *opaque) { - cpu_state_reset(env); + XtensaCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); } static void sim_init(ram_addr_t ram_size, @@ -47,22 +49,25 @@ static void sim_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { + XtensaCPU *cpu = NULL; CPUXtensaState *env = NULL; MemoryRegion *ram, *rom; int n; for (n = 0; n < smp_cpus; n++) { - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_xtensa_init(cpu_model); + if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; + env->sregs[PRID] = n; - qemu_register_reset(sim_reset, env); + qemu_register_reset(sim_reset, cpu); /* Need MMU initialized prior to ELF loading, * so that ELF gets loaded into virtual addresses */ - sim_reset(env); + sim_reset(cpu); } ram = g_malloc(sizeof(*ram)); @@ -301,7 +301,7 @@ static void z2_init(ram_addr_t ram_size, { MemoryRegion *address_space_mem = get_system_memory(); uint32_t sector_len = 0x10000; - PXA2xxState *cpu; + PXA2xxState *mpu; DriveInfo *dinfo; int be; void *z2_lcd; @@ -313,7 +313,7 @@ static void z2_init(ram_addr_t ram_size, } /* Setup CPU & memory */ - cpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model); + mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model); #ifdef TARGET_WORDS_BIGENDIAN be = 1; @@ -337,25 +337,25 @@ static void z2_init(ram_addr_t ram_size, } /* setup keypad */ - pxa27x_register_keypad(cpu->kp, map, 0x100); + pxa27x_register_keypad(mpu->kp, map, 0x100); /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, + pxa2xx_mmci_handlers(mpu->mmc, NULL, - qdev_get_gpio_in(cpu->gpio, Z2_GPIO_SD_DETECT)); + qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT)); type_register_static(&zipit_lcd_info); type_register_static(&aer915_info); - z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd"); - bus = pxa2xx_i2c_bus(cpu->i2c[0]); + z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd"); + bus = pxa2xx_i2c_bus(mpu->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); + mpu->i2s->opaque = wm; + mpu->i2s->codec_out = wm8750_dac_dat; + mpu->i2s->codec_in = wm8750_adc_dat; + wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s); - qdev_connect_gpio_out(cpu->gpio, Z2_GPIO_LCD_CS, + qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS, qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]); if (kernel_filename) { @@ -363,7 +363,7 @@ static void z2_init(ram_addr_t ram_size, z2_binfo.kernel_cmdline = kernel_cmdline; z2_binfo.initrd_filename = initrd_filename; z2_binfo.board_id = 0x6dd; - arm_load_kernel(cpu->env, &z2_binfo); + arm_load_kernel(mpu->cpu, &z2_binfo); } } @@ -62,11 +62,6 @@ typedef struct KVMSlot typedef struct kvm_dirty_log KVMDirtyLog; -typedef struct KVMMSIRoute { - struct kvm_irq_routing_entry kroute; - QTAILQ_ENTRY(KVMMSIRoute) entry; -} KVMMSIRoute; - struct KVMState { KVMSlot slots[32]; @@ -867,6 +862,11 @@ int kvm_irqchip_set_irq(KVMState *s, int irq, int level) } #ifdef KVM_CAP_IRQ_ROUTING +typedef struct KVMMSIRoute { + struct kvm_irq_routing_entry kroute; + QTAILQ_ENTRY(KVMMSIRoute) entry; +} KVMMSIRoute; + static void set_gsi(KVMState *s, unsigned int gsi) { s->used_gsi_bitmap[gsi / 32] |= 1U << (gsi % 32); @@ -1129,6 +1129,10 @@ static void kvm_init_irq_routing(KVMState *s) { } +void kvm_irqchip_release_virq(KVMState *s, int virq) +{ +} + int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) { abort(); @@ -1286,7 +1290,9 @@ int kvm_init(void) s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2); #endif +#ifdef KVM_CAP_IRQ_ROUTING s->direct_msi = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0); +#endif ret = kvm_arch_init(s); if (ret < 0) { diff --git a/libcacard/Makefile b/libcacard/Makefile index c6a896a739..fdc287370d 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -2,29 +2,23 @@ -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)) +$(call set-vpath, $(SRC_PATH)) # objects linked into a shared library, built with libtool with -fPIC if required -QEMU_OBJS_LIB=$(addsuffix .lo,$(basename $(QEMU_OBJS))) +QEMU_OBJS=$(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) +QEMU_OBJS_LIB=$(patsubst %.o,%.lo,$(QEMU_OBJS)) QEMU_CFLAGS+=-I../ -libcacard.lib-y=$(addsuffix .lo,$(basename $(libcacard-y))) - -vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o - $(call quiet-command,$(CC) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@") +libcacard.lib-y=$(patsubst %.o,%.lo,$(libcacard-y)) clean: rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo .libs/* *.la *.pc rm -Rf .libs -all: vscclient +all: libcacard.la libcacard.pc # Dummy command so that make thinks it has done something @true @@ -41,6 +35,7 @@ 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_srcpath=$(SRC_PATH)/libcacard libcacard.pc: $(libcacard_srcpath)/libcacard.pc.in sed -e 's|@LIBDIR@|$(libdir)|' \ -e 's|@INCLUDEDIR@|$(libcacard_includedir)|' \ diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs new file mode 100644 index 0000000000..5899d72d3e --- /dev/null +++ b/linux-user/Makefile.objs @@ -0,0 +1,7 @@ +obj-y = main.o syscall.o strace.o mmap.o signal.o \ + elfload.o linuxload.o uaccess.o cpu-uname.o + +obj-$(TARGET_HAS_BFLT) += flatload.o +obj-$(TARGET_I386) += vm86.o +obj-$(TARGET_ARM) += arm/nwfpe/ +obj-$(TARGET_M68K) += m68k-sim.o diff --git a/linux-user/arm/nwfpe/Makefile.objs b/linux-user/arm/nwfpe/Makefile.objs new file mode 100644 index 0000000000..51b0c32c2a --- /dev/null +++ b/linux-user/arm/nwfpe/Makefile.objs @@ -0,0 +1,2 @@ +obj-y = fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o fpopcode.o +obj-y += single_cpdo.o double_cpdo.o extended_cpdo.o diff --git a/linux-user/main.c b/linux-user/main.c index 191b75060d..49108b81d3 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3405,7 +3405,7 @@ int main(int argc, char **argv, char **envp) exit(1); } #if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) - cpu_state_reset(env); + cpu_reset(ENV_GET_CPU(env)); #endif thread_env = env; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 20d2a74877..539af3f94b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4262,7 +4262,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, /* we create a new CPU instance. */ new_env = cpu_copy(env); #if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) - cpu_state_reset(new_env); + cpu_reset(ENV_GET_CPU(new_env)); #endif /* Init regs that differ from the parent. */ cpu_clone_regs(new_env, newsp); diff --git a/memory_mapping-stub.c b/memory_mapping-stub.c new file mode 100644 index 0000000000..76be34d89f --- /dev/null +++ b/memory_mapping-stub.c @@ -0,0 +1,33 @@ +/* + * QEMU memory mapping + * + * Copyright Fujitsu, Corp. 2011, 2012 + * + * Authors: + * Wen Congyang <wency@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "cpu.h" +#include "cpu-all.h" +#include "memory_mapping.h" + +int qemu_get_guest_memory_mapping(MemoryMappingList *list) +{ + return -2; +} + +int cpu_get_memory_mapping(MemoryMappingList *list, + CPUArchState *env) +{ + return -1; +} + +bool cpu_paging_enabled(CPUArchState *env) +{ + return true; +} + diff --git a/memory_mapping.c b/memory_mapping.c new file mode 100644 index 0000000000..6f5a2e3f71 --- /dev/null +++ b/memory_mapping.c @@ -0,0 +1,246 @@ +/* + * QEMU memory mapping + * + * Copyright Fujitsu, Corp. 2011, 2012 + * + * Authors: + * Wen Congyang <wency@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "cpu.h" +#include "cpu-all.h" +#include "memory_mapping.h" + +static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list, + MemoryMapping *mapping) +{ + MemoryMapping *p; + + QTAILQ_FOREACH(p, &list->head, next) { + if (p->phys_addr >= mapping->phys_addr) { + QTAILQ_INSERT_BEFORE(p, mapping, next); + return; + } + } + QTAILQ_INSERT_TAIL(&list->head, mapping, next); +} + +static void create_new_memory_mapping(MemoryMappingList *list, + target_phys_addr_t phys_addr, + target_phys_addr_t virt_addr, + ram_addr_t length) +{ + MemoryMapping *memory_mapping; + + memory_mapping = g_malloc(sizeof(MemoryMapping)); + memory_mapping->phys_addr = phys_addr; + memory_mapping->virt_addr = virt_addr; + memory_mapping->length = length; + list->last_mapping = memory_mapping; + list->num++; + memory_mapping_list_add_mapping_sorted(list, memory_mapping); +} + +static inline bool mapping_contiguous(MemoryMapping *map, + target_phys_addr_t phys_addr, + target_phys_addr_t virt_addr) +{ + return phys_addr == map->phys_addr + map->length && + virt_addr == map->virt_addr + map->length; +} + +/* + * [map->phys_addr, map->phys_addr + map->length) and + * [phys_addr, phys_addr + length) have intersection? + */ +static inline bool mapping_have_same_region(MemoryMapping *map, + target_phys_addr_t phys_addr, + ram_addr_t length) +{ + return !(phys_addr + length < map->phys_addr || + phys_addr >= map->phys_addr + map->length); +} + +/* + * [map->phys_addr, map->phys_addr + map->length) and + * [phys_addr, phys_addr + length) have intersection. The virtual address in the + * intersection are the same? + */ +static inline bool mapping_conflict(MemoryMapping *map, + target_phys_addr_t phys_addr, + target_phys_addr_t virt_addr) +{ + return virt_addr - map->virt_addr != phys_addr - map->phys_addr; +} + +/* + * [map->virt_addr, map->virt_addr + map->length) and + * [virt_addr, virt_addr + length) have intersection. And the physical address + * in the intersection are the same. + */ +static inline void mapping_merge(MemoryMapping *map, + target_phys_addr_t virt_addr, + ram_addr_t length) +{ + if (virt_addr < map->virt_addr) { + map->length += map->virt_addr - virt_addr; + map->virt_addr = virt_addr; + } + + if ((virt_addr + length) > + (map->virt_addr + map->length)) { + map->length = virt_addr + length - map->virt_addr; + } +} + +void memory_mapping_list_add_merge_sorted(MemoryMappingList *list, + target_phys_addr_t phys_addr, + target_phys_addr_t virt_addr, + ram_addr_t length) +{ + MemoryMapping *memory_mapping, *last_mapping; + + if (QTAILQ_EMPTY(&list->head)) { + create_new_memory_mapping(list, phys_addr, virt_addr, length); + return; + } + + last_mapping = list->last_mapping; + if (last_mapping) { + if (mapping_contiguous(last_mapping, phys_addr, virt_addr)) { + last_mapping->length += length; + return; + } + } + + QTAILQ_FOREACH(memory_mapping, &list->head, next) { + if (mapping_contiguous(memory_mapping, phys_addr, virt_addr)) { + memory_mapping->length += length; + list->last_mapping = memory_mapping; + return; + } + + if (phys_addr + length < memory_mapping->phys_addr) { + /* create a new region before memory_mapping */ + break; + } + + if (mapping_have_same_region(memory_mapping, phys_addr, length)) { + if (mapping_conflict(memory_mapping, phys_addr, virt_addr)) { + continue; + } + + /* merge this region into memory_mapping */ + mapping_merge(memory_mapping, virt_addr, length); + list->last_mapping = memory_mapping; + return; + } + } + + /* this region can not be merged into any existed memory mapping. */ + create_new_memory_mapping(list, phys_addr, virt_addr, length); +} + +void memory_mapping_list_free(MemoryMappingList *list) +{ + MemoryMapping *p, *q; + + QTAILQ_FOREACH_SAFE(p, &list->head, next, q) { + QTAILQ_REMOVE(&list->head, p, next); + g_free(p); + } + + list->num = 0; + list->last_mapping = NULL; +} + +void memory_mapping_list_init(MemoryMappingList *list) +{ + list->num = 0; + list->last_mapping = NULL; + QTAILQ_INIT(&list->head); +} + +static CPUArchState *find_paging_enabled_cpu(CPUArchState *start_cpu) +{ + CPUArchState *env; + + for (env = start_cpu; env != NULL; env = env->next_cpu) { + if (cpu_paging_enabled(env)) { + return env; + } + } + + return NULL; +} + +int qemu_get_guest_memory_mapping(MemoryMappingList *list) +{ + CPUArchState *env, *first_paging_enabled_cpu; + RAMBlock *block; + ram_addr_t offset, length; + int ret; + + first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu); + if (first_paging_enabled_cpu) { + for (env = first_paging_enabled_cpu; env != NULL; env = env->next_cpu) { + ret = cpu_get_memory_mapping(list, env); + if (ret < 0) { + return -1; + } + } + return 0; + } + + /* + * If the guest doesn't use paging, the virtual address is equal to physical + * address. + */ + QLIST_FOREACH(block, &ram_list.blocks, next) { + offset = block->offset; + length = block->length; + create_new_memory_mapping(list, offset, offset, length); + } + + return 0; +} + +void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list) +{ + RAMBlock *block; + + QLIST_FOREACH(block, &ram_list.blocks, next) { + create_new_memory_mapping(list, block->offset, 0, block->length); + } +} + +void memory_mapping_filter(MemoryMappingList *list, int64_t begin, + int64_t length) +{ + MemoryMapping *cur, *next; + + QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) { + if (cur->phys_addr >= begin + length || + cur->phys_addr + cur->length <= begin) { + QTAILQ_REMOVE(&list->head, cur, next); + list->num--; + continue; + } + + if (cur->phys_addr < begin) { + cur->length -= begin - cur->phys_addr; + if (cur->virt_addr) { + cur->virt_addr += begin - cur->phys_addr; + } + cur->phys_addr = begin; + } + + if (cur->phys_addr + cur->length > begin + length) { + cur->length -= cur->phys_addr + cur->length - begin - length; + } + } +} diff --git a/memory_mapping.h b/memory_mapping.h new file mode 100644 index 0000000000..ef72b0abad --- /dev/null +++ b/memory_mapping.h @@ -0,0 +1,64 @@ +/* + * QEMU memory mapping + * + * Copyright Fujitsu, Corp. 2011, 2012 + * + * Authors: + * Wen Congyang <wency@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef MEMORY_MAPPING_H +#define MEMORY_MAPPING_H + +#include "qemu-queue.h" + +/* The physical and virtual address in the memory mapping are contiguous. */ +typedef struct MemoryMapping { + target_phys_addr_t phys_addr; + target_ulong virt_addr; + ram_addr_t length; + QTAILQ_ENTRY(MemoryMapping) next; +} MemoryMapping; + +typedef struct MemoryMappingList { + unsigned int num; + MemoryMapping *last_mapping; + QTAILQ_HEAD(, MemoryMapping) head; +} MemoryMappingList; + +int cpu_get_memory_mapping(MemoryMappingList *list, CPUArchState *env); +bool cpu_paging_enabled(CPUArchState *env); + +/* + * add or merge the memory region [phys_addr, phys_addr + length) into the + * memory mapping's list. The region's virtual address starts with virt_addr, + * and is contiguous. The list is sorted by phys_addr. + */ +void memory_mapping_list_add_merge_sorted(MemoryMappingList *list, + target_phys_addr_t phys_addr, + target_phys_addr_t virt_addr, + ram_addr_t length); + +void memory_mapping_list_free(MemoryMappingList *list); + +void memory_mapping_list_init(MemoryMappingList *list); + +/* + * Return value: + * 0: success + * -1: failed + * -2: unsupported + */ +int qemu_get_guest_memory_mapping(MemoryMappingList *list); + +/* get guest's memory mapping without do paging(virtual address is 0). */ +void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list); + +void memory_mapping_filter(MemoryMappingList *list, int64_t begin, + int64_t length); + +#endif @@ -422,6 +422,30 @@ static void timestamp_put(QDict *qdict) qdict_put_obj(qdict, "timestamp", obj); } + +static const char *monitor_event_names[] = { + [QEVENT_SHUTDOWN] = "SHUTDOWN", + [QEVENT_RESET] = "RESET", + [QEVENT_POWERDOWN] = "POWERDOWN", + [QEVENT_STOP] = "STOP", + [QEVENT_RESUME] = "RESUME", + [QEVENT_VNC_CONNECTED] = "VNC_CONNECTED", + [QEVENT_VNC_INITIALIZED] = "VNC_INITIALIZED", + [QEVENT_VNC_DISCONNECTED] = "VNC_DISCONNECTED", + [QEVENT_BLOCK_IO_ERROR] = "BLOCK_IO_ERROR", + [QEVENT_RTC_CHANGE] = "RTC_CHANGE", + [QEVENT_WATCHDOG] = "WATCHDOG", + [QEVENT_SPICE_CONNECTED] = "SPICE_CONNECTED", + [QEVENT_SPICE_INITIALIZED] = "SPICE_INITIALIZED", + [QEVENT_SPICE_DISCONNECTED] = "SPICE_DISCONNECTED", + [QEVENT_BLOCK_JOB_COMPLETED] = "BLOCK_JOB_COMPLETED", + [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED", + [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED", + [QEVENT_SUSPEND] = "SUSPEND", + [QEVENT_WAKEUP] = "WAKEUP", +}; +QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) + /** * monitor_protocol_event(): Generate a Monitor event * @@ -435,68 +459,8 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) assert(event < QEVENT_MAX); - switch (event) { - case QEVENT_SHUTDOWN: - event_name = "SHUTDOWN"; - break; - case QEVENT_RESET: - event_name = "RESET"; - break; - case QEVENT_POWERDOWN: - event_name = "POWERDOWN"; - break; - case QEVENT_STOP: - event_name = "STOP"; - break; - case QEVENT_RESUME: - event_name = "RESUME"; - break; - case QEVENT_VNC_CONNECTED: - event_name = "VNC_CONNECTED"; - break; - case QEVENT_VNC_INITIALIZED: - event_name = "VNC_INITIALIZED"; - break; - case QEVENT_VNC_DISCONNECTED: - event_name = "VNC_DISCONNECTED"; - break; - case QEVENT_BLOCK_IO_ERROR: - event_name = "BLOCK_IO_ERROR"; - break; - case QEVENT_RTC_CHANGE: - event_name = "RTC_CHANGE"; - break; - case QEVENT_WATCHDOG: - event_name = "WATCHDOG"; - break; - case QEVENT_SPICE_CONNECTED: - event_name = "SPICE_CONNECTED"; - break; - case QEVENT_SPICE_INITIALIZED: - event_name = "SPICE_INITIALIZED"; - break; - case QEVENT_SPICE_DISCONNECTED: - event_name = "SPICE_DISCONNECTED"; - break; - case QEVENT_BLOCK_JOB_COMPLETED: - event_name = "BLOCK_JOB_COMPLETED"; - break; - case QEVENT_BLOCK_JOB_CANCELLED: - event_name = "BLOCK_JOB_CANCELLED"; - break; - case QEVENT_DEVICE_TRAY_MOVED: - event_name = "DEVICE_TRAY_MOVED"; - break; - case QEVENT_SUSPEND: - event_name = "SUSPEND"; - break; - case QEVENT_WAKEUP: - event_name = "WAKEUP"; - break; - default: - abort(); - break; - } + event_name = monitor_event_names[event]; + assert(event_name != NULL); qmp = qdict_new(); timestamp_put(qmp); @@ -738,6 +702,25 @@ CommandInfoList *qmp_query_commands(Error **errp) return cmd_list; } +EventInfoList *qmp_query_events(Error **errp) +{ + EventInfoList *info, *ev_list = NULL; + MonitorEvent e; + + for (e = 0 ; e < QEVENT_MAX ; e++) { + const char *event_name = monitor_event_names[e]; + assert(event_name != NULL); + info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + info->value->name = g_strdup(event_name); + + info->next = ev_list; + ev_list = info; + } + + return ev_list; +} + /* set the current CPU defined by the user */ int monitor_set_cpu(int cpu_index) { @@ -41,6 +41,10 @@ typedef enum MonitorEvent { QEVENT_DEVICE_TRAY_MOVED, QEVENT_SUSPEND, QEVENT_WAKEUP, + + /* Add to 'monitor_event_names' array in monitor.c when + * defining new events here */ + QEVENT_MAX, } MonitorEvent; @@ -745,10 +745,7 @@ int net_handle_fd_param(Monitor *mon, const char *param) return fd; } -static int net_init_nic(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan) +static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan) { int idx; NICInfo *nd; @@ -821,7 +818,6 @@ static int net_init_nic(QemuOpts *opts, } typedef int (*net_client_init_func)(QemuOpts *opts, - Monitor *mon, const char *name, VLANState *vlan); @@ -1085,7 +1081,7 @@ static const struct { #endif /* CONFIG_NET_BRIDGE */ }; -int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) +int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) { const char *name; const char *type; @@ -1093,7 +1089,7 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) type = qemu_opt_get(opts, "type"); if (!type) { - qerror_report(QERR_MISSING_PARAMETER, "type"); + error_set(errp, QERR_MISSING_PARAMETER, "type"); return -1; } @@ -1109,21 +1105,21 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) strcmp(type, "vde") != 0 && #endif strcmp(type, "socket") != 0) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "type", - "a netdev backend type"); + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type", + "a netdev backend type"); return -1; } if (qemu_opt_get(opts, "vlan")) { - qerror_report(QERR_INVALID_PARAMETER, "vlan"); + error_set(errp, QERR_INVALID_PARAMETER, "vlan"); return -1; } if (qemu_opt_get(opts, "name")) { - qerror_report(QERR_INVALID_PARAMETER, "name"); + error_set(errp, QERR_INVALID_PARAMETER, "name"); return -1; } if (!qemu_opts_id(opts)) { - qerror_report(QERR_MISSING_PARAMETER, "id"); + error_set(errp, QERR_MISSING_PARAMETER, "id"); return -1; } } @@ -1136,10 +1132,13 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) for (i = 0; i < NET_CLIENT_TYPE_MAX; i++) { if (net_client_types[i].type != NULL && !strcmp(net_client_types[i].type, type)) { + Error *local_err = NULL; VLANState *vlan = NULL; int ret; - if (qemu_opts_validate(opts, &net_client_types[i].desc[0]) == -1) { + qemu_opts_validate(opts, &net_client_types[i].desc[0], &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); return -1; } @@ -1152,10 +1151,10 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) ret = 0; if (net_client_types[i].init) { - ret = net_client_types[i].init(opts, mon, name, vlan); + ret = net_client_types[i].init(opts, name, vlan); if (ret < 0) { /* TODO push error reporting into init() methods */ - qerror_report(QERR_DEVICE_INIT_FAILED, type); + error_set(errp, QERR_DEVICE_INIT_FAILED, type); return -1; } } @@ -1163,8 +1162,8 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) } } - qerror_report(QERR_INVALID_PARAMETER_VALUE, "type", - "a network client type"); + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type", + "a network client type"); return -1; } @@ -1195,6 +1194,7 @@ void net_host_device_add(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); const char *opts_str = qdict_get_try_str(qdict, "opts"); + Error *local_err = NULL; QemuOpts *opts; if (!net_host_check_device(device)) { @@ -1209,7 +1209,10 @@ void net_host_device_add(Monitor *mon, const QDict *qdict) qemu_opt_set(opts, "type", device); - if (net_client_init(mon, opts, 0) < 0) { + net_client_init(opts, 0, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); monitor_printf(mon, "adding host network device %s failed\n", device); } } @@ -1231,37 +1234,53 @@ void net_host_device_remove(Monitor *mon, const QDict *qdict) qemu_del_vlan_client(vc); } -int do_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret_data) +void netdev_add(QemuOpts *opts, Error **errp) { + net_client_init(opts, 1, errp); +} + +int qmp_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret) +{ + Error *local_err = NULL; + QemuOptsList *opts_list; QemuOpts *opts; - int res; - opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict); - if (!opts) { - return -1; + opts_list = qemu_find_opts_err("netdev", &local_err); + if (error_is_set(&local_err)) { + goto exit_err; + } + + opts = qemu_opts_from_qdict(opts_list, qdict, &local_err); + if (error_is_set(&local_err)) { + goto exit_err; } - res = net_client_init(mon, opts, 1); - if (res < 0) { + netdev_add(opts, &local_err); + if (error_is_set(&local_err)) { qemu_opts_del(opts); + goto exit_err; } - return res; + return 0; + +exit_err: + qerror_report_err(local_err); + error_free(local_err); + return -1; } -int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data) +void qmp_netdev_del(const char *id, Error **errp) { - const char *id = qdict_get_str(qdict, "id"); VLANClientState *vc; vc = qemu_find_netdev(id); if (!vc) { - qerror_report(QERR_DEVICE_NOT_FOUND, id); - return -1; + error_set(errp, QERR_DEVICE_NOT_FOUND, id); + return; } + qemu_del_vlan_client(vc); - qemu_opts_del(qemu_opts_find(qemu_find_opts("netdev"), id)); - return 0; + qemu_opts_del(qemu_opts_find(qemu_find_opts_err("netdev", errp), id)); } static void print_net_client(Monitor *mon, VLANClientState *vc) @@ -1424,14 +1443,31 @@ void net_check_clients(void) static int net_init_client(QemuOpts *opts, void *dummy) { - if (net_client_init(NULL, opts, 0) < 0) + Error *local_err = NULL; + + net_client_init(opts, 0, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); return -1; + } + return 0; } static int net_init_netdev(QemuOpts *opts, void *dummy) { - return net_client_init(NULL, opts, 1); + Error *local_err = NULL; + int ret; + + ret = net_client_init(opts, 1, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + + return ret; } int net_init_clients(void) @@ -163,15 +163,15 @@ struct HCIInfo *qemu_next_hci(void); extern const char *legacy_tftp_prefix; extern const char *legacy_bootp_filename; -int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev); +int net_client_init(QemuOpts *opts, int is_netdev, Error **errp); int net_client_parse(QemuOptsList *opts_list, const char *str); int net_init_clients(void); void net_check_clients(void); void net_cleanup(void); void net_host_device_add(Monitor *mon, const QDict *qdict); void net_host_device_remove(Monitor *mon, const QDict *qdict); -int do_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret_data); -int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data); +void netdev_add(QemuOpts *opts, Error **errp); +int qmp_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret); #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" diff --git a/net/Makefile.objs b/net/Makefile.objs new file mode 100644 index 0000000000..72f50bc903 --- /dev/null +++ b/net/Makefile.objs @@ -0,0 +1,12 @@ +common-obj-y = queue.o checksum.o util.o +common-obj-y += socket.o +common-obj-y += dump.o +common-obj-$(CONFIG_POSIX) += tap.o +common-obj-$(CONFIG_LINUX) += tap-linux.o +common-obj-$(CONFIG_WIN32) += tap-win32.o +common-obj-$(CONFIG_BSD) += tap-bsd.o +common-obj-$(CONFIG_SOLARIS) += tap-solaris.o +common-obj-$(CONFIG_AIX) += tap-aix.o +common-obj-$(CONFIG_HAIKU) += tap-haiku.o +common-obj-$(CONFIG_SLIRP) += slirp.o +common-obj-$(CONFIG_VDE) += vde.o diff --git a/net/dump.c b/net/dump.c index 4b48d48408..f835c51187 100644 --- a/net/dump.c +++ b/net/dump.c @@ -144,7 +144,7 @@ static int net_dump_init(VLANState *vlan, const char *device, return 0; } -int net_init_dump(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) +int net_init_dump(QemuOpts *opts, const char *name, VLANState *vlan) { int len; const char *file; diff --git a/net/dump.h b/net/dump.h index fdc91ad6dc..2b5d9ba644 100644 --- a/net/dump.h +++ b/net/dump.h @@ -27,7 +27,6 @@ #include "net.h" #include "qemu-common.h" -int net_init_dump(QemuOpts *opts, Monitor *mon, - const char *name, VLANState *vlan); +int net_init_dump(QemuOpts *opts, const char *name, VLANState *vlan); #endif /* QEMU_NET_DUMP_H */ diff --git a/net/slirp.c b/net/slirp.c index 96f5032c4c..37b6ccfde9 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -676,10 +676,7 @@ static int net_init_slirp_configs(const char *name, const char *value, void *opa return 0; } -int net_init_slirp(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan) +int net_init_slirp(QemuOpts *opts, const char *name, VLANState *vlan) { struct slirp_config_str *config; const char *vhost; diff --git a/net/slirp.h b/net/slirp.h index c17de8ed47..53fe95dc12 100644 --- a/net/slirp.h +++ b/net/slirp.h @@ -30,10 +30,7 @@ #ifdef CONFIG_SLIRP -int net_init_slirp(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan); +int net_init_slirp(QemuOpts *opts, const char *name, VLANState *vlan); void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict); void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict); diff --git a/net/socket.c b/net/socket.c index 0bcf229c24..fcd0a3c162 100644 --- a/net/socket.c +++ b/net/socket.c @@ -26,6 +26,7 @@ #include "config-host.h" #include "net.h" +#include "monitor.h" #include "qemu-char.h" #include "qemu-common.h" #include "qemu-error.h" @@ -585,10 +586,7 @@ static int net_socket_udp_init(VLANState *vlan, return 0; } -int net_init_socket(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan) +int net_init_socket(QemuOpts *opts, const char *name, VLANState *vlan) { if (qemu_opt_get(opts, "fd")) { int fd; @@ -601,7 +599,7 @@ int net_init_socket(QemuOpts *opts, return -1; } - fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd")); + fd = net_handle_fd_param(cur_mon, qemu_opt_get(opts, "fd")); if (fd == -1) { return -1; } diff --git a/net/socket.h b/net/socket.h index ea46f02dd8..e1fe959412 100644 --- a/net/socket.h +++ b/net/socket.h @@ -27,7 +27,6 @@ #include "net.h" #include "qemu-common.h" -int net_init_socket(QemuOpts *opts, Monitor *mon, - const char *name, VLANState *vlan); +int net_init_socket(QemuOpts *opts, const char *name, VLANState *vlan); #endif /* QEMU_NET_SOCKET_H */ diff --git a/net/tap-bsd.c b/net/tap-bsd.c index 4b6b3a41a0..937a94b11f 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -33,12 +33,6 @@ #include <net/if_tap.h> #endif -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#include <libutil.h> -#else -#include <util.h> -#endif - int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) { int fd; diff --git a/net/tap-win32.c b/net/tap-win32.c index 596132e272..a801a553c4 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -699,7 +699,7 @@ static int tap_win32_init(VLANState *vlan, const char *model, return 0; } -int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) +int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) { const char *ifname; @@ -512,8 +512,7 @@ static int net_bridge_run_helper(const char *helper, const char *bridge) return -1; } -int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name, - VLANState *vlan) +int net_init_bridge(QemuOpts *opts, const char *name, VLANState *vlan) { TAPState *s; int fd, vnet_hdr; @@ -583,7 +582,7 @@ static int net_tap_init(QemuOpts *opts, int *vnet_hdr) return fd; } -int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) +int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) { TAPState *s; int fd, vnet_hdr = 0; @@ -600,7 +599,7 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan return -1; } - fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd")); + fd = net_handle_fd_param(cur_mon, qemu_opt_get(opts, "fd")); if (fd == -1) { return -1; } @@ -687,7 +686,7 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan int vhostfd, r; bool force = qemu_opt_get_bool(opts, "vhostforce", false); if (qemu_opt_get(opts, "vhostfd")) { - r = net_handle_fd_param(mon, qemu_opt_get(opts, "vhostfd")); + r = net_handle_fd_param(cur_mon, qemu_opt_get(opts, "vhostfd")); if (r == -1) { return -1; } @@ -32,7 +32,7 @@ #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" -int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan); +int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan); int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required); @@ -57,7 +57,6 @@ int tap_get_fd(VLANClientState *vc); struct vhost_net; struct vhost_net *tap_get_vhost_net(VLANClientState *vc); -int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name, - VLANState *vlan); +int net_init_bridge(QemuOpts *opts, const char *name, VLANState *vlan); #endif /* QEMU_NET_TAP_H */ @@ -110,7 +110,7 @@ static int net_vde_init(VLANState *vlan, const char *model, return 0; } -int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) +int net_init_vde(QemuOpts *opts, const char *name, VLANState *vlan) { const char *sock; const char *group; @@ -29,7 +29,7 @@ #ifdef CONFIG_VDE -int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan); +int net_init_vde(QemuOpts *opts, const char *name, VLANState *vlan); #endif /* CONFIG_VDE */ diff --git a/qapi-schema.json b/qapi-schema.json index 2ca7195d25..3b6e3468b4 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -228,6 +228,28 @@ { 'command': 'query-commands', 'returns': ['CommandInfo'] } ## +# @EventInfo: +# +# Information about a QMP event +# +# @name: The event name +# +# Since: 1.2.0 +## +{ 'type': 'EventInfo', 'data': {'name': 'str'} } + +## +# @query-events: +# +# Return a list of supported QMP events by this server +# +# Returns: A list of @EventInfo for all supported events +# +# Since: 1.2.0 +## +{ 'command': 'query-events', 'returns': ['EventInfo'] } + +## # @MigrationStats # # Detailed migration status. @@ -1755,3 +1777,88 @@ # Since: 0.14.0 ## { 'command': 'device_del', 'data': {'id': 'str'} } + +## +# @dump-guest-memory +# +# Dump guest's memory to vmcore. It is a synchronous operation that can take +# very long depending on the amount of guest memory. This command is only +# supported only on i386 and x86_64 +# +# @paging: if true, do paging to get guest's memory mapping. The @paging's +# default value of @paging is false, If you want to use gdb to process the +# core, please set @paging to true. The reason why the @paging's value is +# false: +# 1. guest machine in a catastrophic state can have corrupted memory, +# which we cannot trust. +# 2. The guest machine can be in read-mode even if paging is enabled. +# For example: the guest machine uses ACPI to sleep, and ACPI sleep +# state goes in real-mode +# @protocol: the filename or file descriptor of the vmcore. The supported +# protocol can be file or fd: +# 1. file: the protocol starts with "file:", and the following string is +# the file's path. +# 2. fd: the protocol starts with "fd:", and the following string is the +# fd's name. +# @begin: #optional if specified, the starting physical address. +# @length: #optional if specified, the memory size, in bytes. If you don't +# want to dump all guest's memory, please specify the start @begin and +# @length +# +# Returns: nothing on success +# If @begin contains an invalid address, InvalidParameter +# If only one of @begin and @length is specified, MissingParameter +# If @protocol stats with "fd:", and the fd cannot be found, FdNotFound +# If @protocol starts with "file:", and the file cannot be +# opened, OpenFileFailed +# If @protocol does not start with "fd:" or "file:", InvalidParameter +# If an I/O error occurs while writing the file, IOError +# If the target does not support this command, Unsupported +# +# Since: 1.2 +## +{ 'command': 'dump-guest-memory', + 'data': { 'paging': 'bool', 'protocol': 'str', '*begin': 'int', + '*length': 'int' } } +## +# @netdev_add: +# +# Add a network backend. +# +# @type: the type of network backend. Current valid values are 'user', 'tap', +# 'vde', 'socket', 'dump' and 'bridge' +# +# @id: the name of the new network backend +# +# @props: #optional a list of properties to be passed to the backend in +# the format 'name=value', like 'ifname=tap0,script=no' +# +# Notes: The semantics of @props is not well defined. Future commands will be +# introduced that provide stronger typing for backend creation. +# +# Since: 0.14.0 +# +# Returns: Nothing on success +# If @type is not a valid network backend, DeviceNotFound +# If @id is not a valid identifier, InvalidParameterValue +# if @id already exists, DuplicateId +# If @props contains an invalid parameter for this backend, +# InvalidParameter +## +{ 'command': 'netdev_add', + 'data': {'type': 'str', 'id': 'str', '*props': '**'}, + 'gen': 'no' } + +## +# @netdev_del: +# +# Remove a network backend. +# +# @id: the name of the network backend to remove +# +# Returns: Nothing on success +# If @id is not a valid network backend, DeviceNotFound +# +# Since: 0.14.0 +## +{ 'command': 'netdev_del', 'data': {'id': 'str'} } diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs new file mode 100644 index 0000000000..d0b0c16b90 --- /dev/null +++ b/qapi/Makefile.objs @@ -0,0 +1,3 @@ +qapi-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o +qapi-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o +qapi-obj-y += string-input-visitor.o string-output-visitor.o diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index a4e088c9fc..ffffbf79aa 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -97,6 +97,145 @@ void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) } } +void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_uint8) { + v->type_uint8(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT8_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint8_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_uint16) { + v->type_uint16(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT16_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint16_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_uint32) { + v->type_uint32(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT32_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint32_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_uint64) { + v->type_uint64(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + *obj = value; + } + } +} + +void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_int8) { + v->type_int8(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT8_MIN || value > INT8_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int8_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_int16) { + v->type_int16(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT16_MIN || value > INT16_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int16_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_int32) { + v->type_int32(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT32_MIN || value > INT32_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int32_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp) +{ + if (!error_is_set(errp)) { + if (v->type_int64) { + v->type_int64(v, obj, name, errp); + } else { + 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)) { diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h index e850746b75..a19d70c104 100644 --- a/qapi/qapi-visit-core.h +++ b/qapi/qapi-visit-core.h @@ -52,6 +52,14 @@ struct Visitor void (*start_handle)(Visitor *v, void **obj, const char *kind, const char *name, Error **errp); void (*end_handle)(Visitor *v, Error **errp); + void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp); + void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp); + void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error **errp); + void (*type_uint64)(Visitor *v, uint64_t *obj, const char *name, Error **errp); + void (*type_int8)(Visitor *v, int8_t *obj, const char *name, Error **errp); + void (*type_int16)(Visitor *v, int16_t *obj, const char *name, Error **errp); + void (*type_int32)(Visitor *v, int32_t *obj, const char *name, Error **errp); + void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp); }; void visit_start_handle(Visitor *v, void **obj, const char *kind, @@ -69,6 +77,14 @@ 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_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp); +void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp); +void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp); +void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp); +void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp); +void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp); +void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp); +void visit_type_int64(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); diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c index 92b0305212..34e525eadd 100644 --- a/qapi/string-output-visitor.c +++ b/qapi/string-output-visitor.c @@ -52,7 +52,7 @@ static void print_type_number(Visitor *v, double *obj, const char *name, Error **errp) { StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); - string_output_set(sov, g_strdup_printf("%g", *obj)); + string_output_set(sov, g_strdup_printf("%f", *obj)); } char *string_output_get_string(StringOutputVisitor *sov) diff --git a/qemu-char.c b/qemu-char.c index fe1126fe86..c2aaaeeb8f 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -56,19 +56,19 @@ #include <sys/select.h> #ifdef CONFIG_BSD #include <sys/stat.h> -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -#include <libutil.h> -#include <dev/ppbus/ppi.h> -#include <dev/ppbus/ppbconf.h> #if defined(__GLIBC__) #include <pty.h> +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#include <libutil.h> +#else +#include <util.h> #endif +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include <dev/ppbus/ppi.h> +#include <dev/ppbus/ppbconf.h> #elif defined(__DragonFly__) -#include <libutil.h> #include <dev/misc/ppi/ppi.h> #include <bus/ppbus/ppbconf.h> -#else -#include <util.h> #endif #else #ifdef __linux__ @@ -2584,10 +2584,14 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) int pos; const char *p; QemuOpts *opts; + Error *local_err = NULL; - opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1); - if (NULL == opts) + opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); return NULL; + } if (strstart(filename, "mon:", &p)) { filename = p; diff --git a/qemu-config.c b/qemu-config.c index be84a0347c..bb3bff426a 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -3,6 +3,7 @@ #include "qemu-option.h" #include "qemu-config.h" #include "hw/qdev.h" +#include "error.h" static QemuOptsList qemu_drive_opts = { .name = "drive", @@ -631,7 +632,8 @@ static QemuOptsList *vm_config_groups[32] = { NULL, }; -static QemuOptsList *find_list(QemuOptsList **lists, const char *group) +static QemuOptsList *find_list(QemuOptsList **lists, const char *group, + Error **errp) { int i; @@ -640,14 +642,28 @@ static QemuOptsList *find_list(QemuOptsList **lists, const char *group) break; } if (lists[i] == NULL) { - error_report("there is no option group \"%s\"", group); + error_set(errp, QERR_INVALID_OPTION_GROUP, group); } return lists[i]; } QemuOptsList *qemu_find_opts(const char *group) { - return find_list(vm_config_groups, group); + QemuOptsList *ret; + Error *local_err = NULL; + + ret = find_list(vm_config_groups, group, &local_err); + if (error_is_set(&local_err)) { + error_report("%s\n", error_get_pretty(local_err)); + error_free(local_err); + } + + return ret; +} + +QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) +{ + return find_list(vm_config_groups, group, errp); } void qemu_add_opts(QemuOptsList *list) @@ -709,7 +725,7 @@ int qemu_global_option(const char *str) return -1; } - opts = qemu_opts_create(&qemu_global_opts, NULL, 0); + opts = qemu_opts_create(&qemu_global_opts, NULL, 0, NULL); qemu_opt_set(opts, "driver", driver); qemu_opt_set(opts, "property", property); qemu_opt_set(opts, "value", str+offset+1); @@ -762,6 +778,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) char line[1024], group[64], id[64], arg[64], value[1024]; Location loc; QemuOptsList *list = NULL; + Error *local_err = NULL; QemuOpts *opts = NULL; int res = -1, lno = 0; @@ -778,18 +795,24 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) } if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) { /* group with id */ - list = find_list(lists, group); - if (list == NULL) + list = find_list(lists, group, &local_err); + if (error_is_set(&local_err)) { + error_report("%s\n", error_get_pretty(local_err)); + error_free(local_err); goto out; - opts = qemu_opts_create(list, id, 1); + } + opts = qemu_opts_create(list, id, 1, NULL); continue; } if (sscanf(line, "[%63[^]]]", group) == 1) { /* group without id */ - list = find_list(lists, group); - if (list == NULL) + list = find_list(lists, group, &local_err); + if (error_is_set(&local_err)) { + error_report("%s\n", error_get_pretty(local_err)); + error_free(local_err); goto out; - opts = qemu_opts_create(list, NULL, 0); + } + opts = qemu_opts_create(list, NULL, 0, NULL); continue; } if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) { diff --git a/qemu-config.h b/qemu-config.h index 6d7365d35b..e9f2ef4c7b 100644 --- a/qemu-config.h +++ b/qemu-config.h @@ -1,11 +1,14 @@ #ifndef QEMU_CONFIG_H #define QEMU_CONFIG_H +#include "error.h" + extern QemuOptsList qemu_fsdev_opts; extern QemuOptsList qemu_virtfs_opts; extern QemuOptsList qemu_spice_opts; QemuOptsList *qemu_find_opts(const char *group); +QemuOptsList *qemu_find_opts_err(const char *group, Error **errp); void qemu_add_opts(QemuOptsList *list); int qemu_set_option(const char *str); int qemu_global_option(const char *str); diff --git a/qemu-log.h b/qemu-log.h index fccfb1100e..a9b3ca4e0b 100644 --- a/qemu-log.h +++ b/qemu-log.h @@ -50,6 +50,7 @@ extern int loglevel; /* Special cases: */ +#ifdef NEED_CPU_H /* cpu_dump_state() logging functions: */ #define log_cpu_state(env, f) cpu_dump_state((env), logfile, fprintf, (f)); #define log_cpu_state_mask(b, env, f) do { \ @@ -64,6 +65,7 @@ extern int loglevel; /* page_dump() output to the log file: */ #define log_page_dump() page_dump(logfile) +#endif diff --git a/qemu-option.c b/qemu-option.c index 35cd609f75..bb3886c6b9 100644 --- a/qemu-option.c +++ b/qemu-option.c @@ -30,6 +30,7 @@ #include "qemu-error.h" #include "qemu-objects.h" #include "qemu-option.h" +#include "error.h" #include "qerror.h" /* @@ -168,7 +169,8 @@ QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list, return NULL; } -static int parse_option_bool(const char *name, const char *value, bool *ret) +static void parse_option_bool(const char *name, const char *value, bool *ret, + Error **errp) { if (value != NULL) { if (!strcmp(value, "on")) { @@ -176,16 +178,15 @@ static int parse_option_bool(const char *name, const char *value, bool *ret) } else if (!strcmp(value, "off")) { *ret = 0; } else { - qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'"); - return -1; + error_set(errp,QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'"); } } else { *ret = 1; } - return 0; } -static int parse_option_number(const char *name, const char *value, uint64_t *ret) +static void parse_option_number(const char *name, const char *value, + uint64_t *ret, Error **errp) { char *postfix; uint64_t number; @@ -193,18 +194,17 @@ static int parse_option_number(const char *name, const char *value, uint64_t *re if (value != NULL) { number = strtoull(value, &postfix, 0); if (*postfix != '\0') { - qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a number"); - return -1; + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number"); + return; } *ret = number; } else { - qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a number"); - return -1; + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number"); } - return 0; } -static int parse_option_size(const char *name, const char *value, uint64_t *ret) +static void parse_option_size(const char *name, const char *value, + uint64_t *ret, Error **errp) { char *postfix; double sizef; @@ -230,16 +230,14 @@ static int parse_option_size(const char *name, const char *value, uint64_t *ret) *ret = (uint64_t) sizef; break; default: - qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a size"); + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size"); error_printf_unless_qmp("You may use k, M, G or T suffixes for " "kilobytes, megabytes, gigabytes and terabytes.\n"); - return -1; + return; } } else { - qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a size"); - return -1; + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size"); } - return 0; } /* @@ -263,6 +261,7 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name, const char *value) { bool flag; + Error *local_err = NULL; // Find a matching parameter list = get_option_parameter(list, name); @@ -274,9 +273,10 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name, // Process parameter switch (list->type) { case OPT_FLAG: - if (parse_option_bool(name, value, &flag) == -1) - return -1; - list->value.n = flag; + parse_option_bool(name, value, &flag, &local_err); + if (!error_is_set(&local_err)) { + list->value.n = flag; + } break; case OPT_STRING: @@ -289,8 +289,7 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name, break; case OPT_SIZE: - if (parse_option_size(name, value, &list->value.n) == -1) - return -1; + parse_option_size(name, value, &list->value.n, &local_err); break; default: @@ -298,6 +297,12 @@ int set_option_parameter(QEMUOptionParameter *list, const char *name, return -1; } + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + return 0; } @@ -576,20 +581,24 @@ uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval) return opt->value.uint; } -static int qemu_opt_parse(QemuOpt *opt) +static void qemu_opt_parse(QemuOpt *opt, Error **errp) { if (opt->desc == NULL) - return 0; + return; + switch (opt->desc->type) { case QEMU_OPT_STRING: /* nothing */ - return 0; + return; case QEMU_OPT_BOOL: - return parse_option_bool(opt->name, opt->str, &opt->value.boolean); + parse_option_bool(opt->name, opt->str, &opt->value.boolean, errp); + break; case QEMU_OPT_NUMBER: - return parse_option_number(opt->name, opt->str, &opt->value.uint); + parse_option_number(opt->name, opt->str, &opt->value.uint, errp); + break; case QEMU_OPT_SIZE: - return parse_option_size(opt->name, opt->str, &opt->value.uint); + parse_option_size(opt->name, opt->str, &opt->value.uint, errp); + break; default: abort(); } @@ -603,11 +612,12 @@ static void qemu_opt_del(QemuOpt *opt) g_free(opt); } -static int opt_set(QemuOpts *opts, const char *name, const char *value, - bool prepend) +static void opt_set(QemuOpts *opts, const char *name, const char *value, + bool prepend, Error **errp) { QemuOpt *opt; const QemuOptDesc *desc = opts->list->desc; + Error *local_err = NULL; int i; for (i = 0; desc[i].name != NULL; i++) { @@ -619,8 +629,8 @@ static int opt_set(QemuOpts *opts, const char *name, const char *value, if (i == 0) { /* empty list -> allow any */; } else { - qerror_report(QERR_INVALID_PARAMETER, name); - return -1; + error_set(errp, QERR_INVALID_PARAMETER, name); + return; } } @@ -638,16 +648,31 @@ static int opt_set(QemuOpts *opts, const char *name, const char *value, if (value) { opt->str = g_strdup(value); } - if (qemu_opt_parse(opt) < 0) { + qemu_opt_parse(opt, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); qemu_opt_del(opt); + } +} + +int qemu_opt_set(QemuOpts *opts, const char *name, const char *value) +{ + Error *local_err = NULL; + + opt_set(opts, name, value, false, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); return -1; } + return 0; } -int qemu_opt_set(QemuOpts *opts, const char *name, const char *value) +void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, + Error **errp) { - return opt_set(opts, name, value, false); + opt_set(opts, name, value, false, errp); } int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val) @@ -729,20 +754,21 @@ static int id_wellformed(const char *id) return 1; } -QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists) +QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, + int fail_if_exists, Error **errp) { QemuOpts *opts = NULL; if (id) { if (!id_wellformed(id)) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "id", "an identifier"); + error_set(errp,QERR_INVALID_PARAMETER_VALUE, "id", "an identifier"); error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n"); return NULL; } opts = qemu_opts_find(list, id); if (opts != NULL) { if (fail_if_exists && !list->merge_lists) { - qerror_report(QERR_DUPLICATE_ID, id, list->name); + error_set(errp, QERR_DUPLICATE_ID, id, list->name); return NULL; } else { return opts; @@ -783,9 +809,12 @@ int qemu_opts_set(QemuOptsList *list, const char *id, const char *name, const char *value) { QemuOpts *opts; + Error *local_err = NULL; - opts = qemu_opts_create(list, id, 1); - if (opts == NULL) { + opts = qemu_opts_create(list, id, 1, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); return -1; } return qemu_opt_set(opts, name, value); @@ -829,6 +858,7 @@ static int opts_do_parse(QemuOpts *opts, const char *params, { char option[128], value[1024]; const char *p,*pe,*pc; + Error *local_err = NULL; for (p = params; *p != '\0'; p++) { pe = strchr(p, '='); @@ -860,7 +890,10 @@ static int opts_do_parse(QemuOpts *opts, const char *params, } if (strcmp(option, "id") != 0) { /* store and parse */ - if (opt_set(opts, option, value, prepend) == -1) { + opt_set(opts, option, value, prepend, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); return -1; } } @@ -883,6 +916,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, char value[1024], *id = NULL; const char *p; QemuOpts *opts; + Error *local_err = NULL; assert(!permit_abbrev || list->implied_opt_name); firstname = permit_abbrev ? list->implied_opt_name : NULL; @@ -898,13 +932,18 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, if (!id && !QTAILQ_EMPTY(&list->head)) { opts = qemu_opts_find(list, NULL); } else { - opts = qemu_opts_create(list, id, 0); + opts = qemu_opts_create(list, id, 0, &local_err); } } else { - opts = qemu_opts_create(list, id, 1); + opts = qemu_opts_create(list, id, 1, &local_err); } - if (opts == NULL) + if (opts == NULL) { + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + } return NULL; + } if (opts_do_parse(opts, params, firstname, defaults) != 0) { qemu_opts_del(opts); @@ -929,13 +968,19 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, assert(opts); } +typedef struct OptsFromQDictState { + QemuOpts *opts; + Error **errp; +} OptsFromQDictState; + static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) { + OptsFromQDictState *state = opaque; char buf[32]; const char *value; int n; - if (!strcmp(key, "id")) { + if (!strcmp(key, "id") || error_is_set(state->errp)) { return; } @@ -963,7 +1008,8 @@ static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) default: return; } - qemu_opt_set(opaque, key, value); + + qemu_opt_set_err(state->opts, key, value, state->errp); } /* @@ -972,15 +1018,31 @@ static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) * Only QStrings, QInts, QFloats and QBools are copied. Entries with * other types are silently ignored. */ -QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict) +QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, + Error **errp) { + OptsFromQDictState state; + Error *local_err = NULL; QemuOpts *opts; - opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1); - if (opts == NULL) + opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, + &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + return NULL; + } + + assert(opts != NULL); + + state.errp = &local_err; + state.opts = opts; + qdict_iter(qdict, qemu_opts_from_qdict_1, &state); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + qemu_opts_del(opts); return NULL; + } - qdict_iter(qdict, qemu_opts_from_qdict_1, opts); return opts; } @@ -1011,9 +1073,10 @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict) /* Validate parsed opts against descriptions where no * descriptions were provided in the QemuOptsList. */ -int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc) +void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) { QemuOpt *opt; + Error *local_err = NULL; assert(opts->list->desc[0].name == NULL); @@ -1026,18 +1089,18 @@ int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc) } } if (desc[i].name == NULL) { - qerror_report(QERR_INVALID_PARAMETER, opt->name); - return -1; + error_set(errp, QERR_INVALID_PARAMETER, opt->name); + return; } opt->desc = &desc[i]; - if (qemu_opt_parse(opt) < 0) { - return -1; + qemu_opt_parse(opt, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + return; } } - - return 0; } int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, diff --git a/qemu-option.h b/qemu-option.h index 3ca00c3cec..951dec3cc4 100644 --- a/qemu-option.h +++ b/qemu-option.h @@ -28,6 +28,7 @@ #include <stdint.h> #include "qemu-queue.h" +#include "error.h" #include "qdict.h" enum QEMUOptionParType { @@ -110,25 +111,29 @@ 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); +void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, + Error **errp); 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); QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id); -QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists); +QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, + int fail_if_exists, Error **errp); void qemu_opts_reset(QemuOptsList *list); void qemu_opts_loc_restore(QemuOpts *opts); int qemu_opts_set(QemuOptsList *list, const char *id, const char *name, const char *value); const char *qemu_opts_id(QemuOpts *opts); void qemu_opts_del(QemuOpts *opts); -int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc); +void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp); int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname); QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev); void qemu_opts_set_defaults(QemuOptsList *list, const char *params, int permit_abbrev); -QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict); +QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, + Error **errp); QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict); typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque); diff --git a/qemu-sockets.c b/qemu-sockets.c index 46c7619c7e..2ae715db76 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -461,7 +461,7 @@ int inet_listen(const char *str, char *ostr, int olen, char *optstr; int sock = -1; - opts = qemu_opts_create(&dummy_opts, NULL, 0); + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); if (inet_parse(opts, str) == 0) { sock = inet_listen_opts(opts, port_offset, errp); if (sock != -1 && ostr) { @@ -490,7 +490,7 @@ int inet_connect(const char *str, bool block, Error **errp) QemuOpts *opts; int sock = -1; - opts = qemu_opts_create(&dummy_opts, NULL, 0); + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); if (inet_parse(opts, str) == 0) { if (block) { qemu_opt_set(opts, "block", "on"); @@ -589,7 +589,7 @@ int unix_listen(const char *str, char *ostr, int olen) char *path, *optstr; int sock, len; - opts = qemu_opts_create(&dummy_opts, NULL, 0); + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); optstr = strchr(str, ','); if (optstr) { @@ -617,7 +617,7 @@ int unix_connect(const char *path) QemuOpts *opts; int sock; - opts = qemu_opts_create(&dummy_opts, NULL, 0); + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); qemu_opt_set(opts, "path", path); sock = unix_connect_opts(opts); qemu_opts_del(opts); @@ -156,6 +156,10 @@ static const QErrorStringTable qerror_table[] = { .desc = "Invalid block format '%(name)'", }, { + .error_fmt = QERR_INVALID_OPTION_GROUP, + .desc = "There is no option group '%(group)'", + }, + { .error_fmt = QERR_INVALID_PARAMETER, .desc = "Invalid parameter '%(name)'", }, @@ -139,6 +139,9 @@ QError *qobject_to_qerror(const QObject *obj); #define QERR_INVALID_BLOCK_FORMAT \ "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" +#define QERR_INVALID_OPTION_GROUP \ + "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }" + #define QERR_INVALID_PARAMETER \ "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" diff --git a/qga/Makefile.objs b/qga/Makefile.objs new file mode 100644 index 0000000000..6a4d843436 --- /dev/null +++ b/qga/Makefile.objs @@ -0,0 +1,3 @@ +qga-obj-y = commands.o guest-agent-command-state.o +qga-obj-$(CONFIG_POSIX) += commands-posix.o channel-posix.o +qga-obj-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o diff --git a/qmp-commands.hx b/qmp-commands.hx index db980fa811..2e1a38e695 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -604,12 +604,45 @@ Example: EQMP { + .name = "dump-guest-memory", + .args_type = "paging:b,protocol:s,begin:i?,end:i?", + .params = "-p protocol [begin] [length]", + .help = "dump guest memory to file", + .user_print = monitor_user_noop, + .mhandler.cmd_new = qmp_marshal_input_dump_guest_memory, + }, + +SQMP +dump + + +Dump guest memory to file. The file can be processed with crash or gdb. + +Arguments: + +- "paging": do paging to get guest's memory mapping (json-bool) +- "protocol": destination file(started with "file:") or destination file + descriptor (started with "fd:") (json-string) +- "begin": the starting physical address. It's optional, and should be specified + with length together (json-int) +- "length": the memory size, in bytes. It's optional, and should be specified + with begin together (json-int) + +Example: + +-> { "execute": "dump-guest-memory", "arguments": { "protocol": "fd:dump" } } +<- { "return": {} } + +Notes: + +(1) All boolean arguments default to false + +EQMP + + { .name = "netdev_add", .args_type = "netdev:O", - .params = "[user|tap|socket],id=str[,prop=value][,...]", - .help = "add host network device", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_netdev_add, + .mhandler.cmd_new = qmp_netdev_add, }, SQMP @@ -638,10 +671,7 @@ EQMP { .name = "netdev_del", .args_type = "id:s", - .params = "id", - .help = "remove host network device", - .user_print = monitor_user_noop, - .mhandler.cmd_new = do_netdev_del, + .mhandler.cmd_new = qmp_marshal_input_netdev_del, }, SQMP @@ -1179,6 +1209,43 @@ EQMP }, SQMP +query-events +-------------- + +List QMP available events. + +Each event is represented by a json-object, the returned value is a json-array +of all events. + +Each json-object contains: + +- "name": event's name (json-string) + +Example: + +-> { "execute": "query-events" } +<- { + "return":[ + { + "name":"SHUTDOWN" + }, + { + "name":"RESET" + } + ] + } + +Note: This example has been shortened as the real response is too long. + +EQMP + + { + .name = "query-events", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_events, + }, + +SQMP query-chardev ------------- diff --git a/qom/Makefile b/qom/Makefile deleted file mode 100644 index 34c6de558a..0000000000 --- a/qom/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -qom-y = object.o container.o qom-qobject.o -qom-twice-y = cpu.o diff --git a/qom/Makefile.objs b/qom/Makefile.objs new file mode 100644 index 0000000000..5ef060a401 --- /dev/null +++ b/qom/Makefile.objs @@ -0,0 +1,4 @@ +qom-obj-y = object.o container.o qom-qobject.o +qom-obj-twice-y = cpu.o +common-obj-y = $(qom-obj-twice-y) +user-obj-y = $(qom-obj-twice-y) diff --git a/readline.c b/readline.c index a6c0039ad2..540cd8a025 100644 --- a/readline.c +++ b/readline.c @@ -337,6 +337,9 @@ static void readline_completion(ReadLineState *rs) } readline_show_prompt(rs); } + for (i = 0; i < rs->nb_completions; i++) { + g_free(rs->completions[i]); + } } /* return true if command handled */ @@ -73,3 +73,43 @@ TRACETOOL=$(PYTHON) $(SRC_PATH)/scripts/tracetool.py # will delete the target of a rule if commands exit with a nonzero exit status .DELETE_ON_ERROR: + +# magic to descend into other directories + +obj := . +old-nested-dirs := + +define push-var +$(eval save-$2-$1 = $(value $1)) +$(eval $1 :=) +endef + +define pop-var +$(eval subdir-$2-$1 := $(if $(filter $2,$(save-$2-$1)),$(addprefix $2,$($1)))) +$(eval $1 = $(value save-$2-$1) $$(subdir-$2-$1)) +$(eval save-$2-$1 :=) +endef + +define unnest-dir +$(foreach var,$(nested-vars),$(call push-var,$(var),$1/)) +$(eval obj := $(obj)/$1) +$(eval include $(SRC_PATH)/$1/Makefile.objs) +$(eval obj := $(patsubst %/$1,%,$(obj))) +$(foreach var,$(nested-vars),$(call pop-var,$(var),$1/)) +endef + +define unnest-vars-1 +$(eval nested-dirs := $(filter-out \ + $(old-nested-dirs), \ + $(sort $(foreach var,$(nested-vars), $(filter %/, $($(var))))))) +$(if $(nested-dirs), + $(foreach dir,$(nested-dirs),$(call unnest-dir,$(patsubst %/,%,$(dir)))) + $(eval old-nested-dirs := $(old-nested-dirs) $(nested-dirs)) + $(call unnest-vars-1)) +endef + +define unnest-vars +$(call unnest-vars-1) +$(foreach var,$(nested-vars),$(eval $(var) := $(filter-out %/, $($(var))))) +$(shell mkdir -p $(sort $(foreach var,$(nested-vars),$(dir $($(var)))))) +endef diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs new file mode 100644 index 0000000000..bb43d3c08c --- /dev/null +++ b/slirp/Makefile.objs @@ -0,0 +1,3 @@ +common-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o +common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o +common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o diff --git a/target-alpha/Makefile.objs b/target-alpha/Makefile.objs new file mode 100644 index 0000000000..590304cc61 --- /dev/null +++ b/target-alpha/Makefile.objs @@ -0,0 +1,3 @@ +obj-$(CONFIG_SOFTMMU) += machine.o +obj-y += translate.o helper.o cpu.o +obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs new file mode 100644 index 0000000000..f447c4fdf2 --- /dev/null +++ b/target-arm/Makefile.objs @@ -0,0 +1,6 @@ +obj-y += arm-semi.o +obj-$(CONFIG_SOFTMMU) += machine.o +obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += neon_helper.o iwmmxt_helper.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/arm-semi.c b/target-arm/arm-semi.c index 88ca9bb1b7..88ca9bb1b7 100644 --- a/arm-semi.c +++ b/target-arm/arm-semi.c diff --git a/target-arm/helper.c b/target-arm/helper.c index 7e1c2c06bd..bbb1d05d10 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -4,11 +4,6 @@ #include "host-utils.h" #include "sysemu.h" -void cpu_state_reset(CPUARMState *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg) { int nregs; @@ -80,7 +75,7 @@ ARMCPU *cpu_arm_init(const char *cpu_model) arm_translate_init(); } - cpu_state_reset(env); + cpu_reset(CPU(cpu)); if (arm_feature(env, ARM_FEATURE_NEON)) { gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, 51, "arm-neon.xml", 0); diff --git a/target-cris/Makefile.objs b/target-cris/Makefile.objs new file mode 100644 index 0000000000..4b09e8c6b5 --- /dev/null +++ b/target-cris/Makefile.objs @@ -0,0 +1,4 @@ +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += mmu.o machine.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 5449cc48b6..4f4df6d9b5 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -64,17 +64,19 @@ #define PR_NRP 12 #define PR_CCS 13 #define PR_USP 14 +#define PRV10_BRP 14 #define PR_SPC 15 /* CPU flags. */ #define Q_FLAG 0x80000000 -#define M_FLAG 0x40000000 +#define M_FLAG_V32 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 +#define M_FLAG_V10 0x80 #define U_FLAG 0x40 #define I_FLAG 0x20 #define X_FLAG 0x10 @@ -171,7 +173,7 @@ typedef struct CPUCRISState { #include "cpu-qom.h" -CPUCRISState *cpu_cris_init(const char *cpu_model); +CRISCPU *cpu_cris_init(const char *cpu_model); int cpu_cris_exec(CPUCRISState *s); void cpu_cris_close(CPUCRISState *s); void do_interrupt(CPUCRISState *env); @@ -216,7 +218,15 @@ enum { #define TARGET_PHYS_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define cpu_init cpu_cris_init +static inline CPUCRISState *cpu_init(const char *cpu_model) +{ + CRISCPU *cpu = cpu_cris_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + #define cpu_exec cpu_cris_exec #define cpu_gen_code cpu_cris_gen_code #define cpu_signal_handler cpu_cris_signal_handler diff --git a/target-cris/helper.c b/target-cris/helper.c index 8680f436a0..bfbc29ec6a 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -121,14 +121,14 @@ static void do_interruptv10(CPUCRISState *env) /* These exceptions are genereated by the core itself. ERP should point to the insn following the brk. */ ex_vec = env->trap_vector; - env->pregs[PR_ERP] = env->pc; + env->pregs[PRV10_BRP] = env->pc; break; case EXCP_NMI: /* NMI is hardwired to vector zero. */ ex_vec = 0; - env->pregs[PR_CCS] &= ~M_FLAG; - env->pregs[PR_NRP] = env->pc; + env->pregs[PR_CCS] &= ~M_FLAG_V10; + env->pregs[PRV10_BRP] = env->pc; break; case EXCP_BUSFAULT: @@ -185,7 +185,7 @@ void do_interrupt(CPUCRISState *env) case EXCP_NMI: /* NMI is hardwired to vector zero. */ ex_vec = 0; - env->pregs[PR_CCS] &= ~M_FLAG; + env->pregs[PR_CCS] &= ~M_FLAG_V32; env->pregs[PR_NRP] = env->pc; break; diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index b92c106e10..ac7c98c8ed 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -247,8 +247,8 @@ void helper_rfn(void) if (!rflag) env->pregs[PR_CCS] |= P_FLAG; - /* Always set the M flag. */ - env->pregs[PR_CCS] |= M_FLAG; + /* Always set the M flag. */ + env->pregs[PR_CCS] |= M_FLAG_V32; } uint32_t helper_lz(uint32_t t0) diff --git a/target-cris/translate.c b/target-cris/translate.c index e353ea3fa8..1ad9ec788e 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3503,81 +3503,77 @@ static uint32_t vr_by_name(const char *name) return 32; } -CPUCRISState *cpu_cris_init (const char *cpu_model) +CRISCPU *cpu_cris_init(const char *cpu_model) { CRISCPU *cpu; - CPUCRISState *env; - static int tcg_initialized = 0; - int i; + CPUCRISState *env; + static int tcg_initialized = 0; + int i; cpu = CRIS_CPU(object_new(TYPE_CRIS_CPU)); env = &cpu->env; - env->pregs[PR_VR] = vr_by_name(cpu_model); + env->pregs[PR_VR] = vr_by_name(cpu_model); cpu_reset(CPU(cpu)); - qemu_init_vcpu(env); + qemu_init_vcpu(env); - if (tcg_initialized) - return env; + if (tcg_initialized) { + return cpu; + } - tcg_initialized = 1; + tcg_initialized = 1; #define GEN_HELPER 2 #include "helper.h" - if (env->pregs[PR_VR] < 32) { - cpu_crisv10_init(env); - return env; - } - + if (env->pregs[PR_VR] < 32) { + cpu_crisv10_init(env); + return cpu; + } - cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - cc_x = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, cc_x), "cc_x"); - cc_src = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, cc_src), "cc_src"); - cc_dest = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, cc_dest), - "cc_dest"); - cc_result = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, cc_result), - "cc_result"); - cc_op = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, cc_op), "cc_op"); - cc_size = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, cc_size), - "cc_size"); - cc_mask = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, cc_mask), - "cc_mask"); - - env_pc = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, pc), - "pc"); - env_btarget = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, btarget), - "btarget"); - env_btaken = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, btaken), - "btaken"); - for (i = 0; i < 16; i++) { - cpu_R[i] = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, regs[i]), - regnames[i]); - } - for (i = 0; i < 16; i++) { - cpu_PR[i] = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUCRISState, pregs[i]), - pregnames[i]); - } - return env; -} + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + cc_x = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, cc_x), "cc_x"); + cc_src = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, cc_src), "cc_src"); + cc_dest = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, cc_dest), + "cc_dest"); + cc_result = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, cc_result), + "cc_result"); + cc_op = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, cc_op), "cc_op"); + cc_size = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, cc_size), + "cc_size"); + cc_mask = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, cc_mask), + "cc_mask"); + + env_pc = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, pc), + "pc"); + env_btarget = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, btarget), + "btarget"); + env_btaken = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, btaken), + "btaken"); + for (i = 0; i < 16; i++) { + cpu_R[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, regs[i]), + regnames[i]); + } + for (i = 0; i < 16; i++) { + cpu_PR[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUCRISState, pregs[i]), + pregnames[i]); + } -void cpu_state_reset(CPUCRISState *env) -{ - cpu_reset(ENV_GET_CPU(env)); + return cpu; } void restore_state_to_opc(CPUCRISState *env, TranslationBlock *tb, int pc_pos) diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c index 4ada3ed09f..3629629d9d 100644 --- a/target-cris/translate_v10.c +++ b/target-cris/translate_v10.c @@ -1132,6 +1132,7 @@ static unsigned int dec10_ind(DisasContext *dc) LOG_DIS("break %d\n", dc->src); cris_evaluate_flags(dc); tcg_gen_movi_tl(env_pc, dc->pc + 2); + t_gen_mov_env_TN(trap_vector, tcg_const_tl(dc->src + 2)); t_gen_raise_exception(EXCP_BREAK); dc->is_jmp = DISAS_UPDATE; return insn_len; diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs new file mode 100644 index 0000000000..f91375578c --- /dev/null +++ b/target-i386/Makefile.objs @@ -0,0 +1,7 @@ +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o +obj-$(CONFIG_KVM) += kvm.o hyperv.o +obj-$(CONFIG_LINUX_USER) += ioport-user.o +obj-$(CONFIG_BSD_USER) += ioport-user.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c new file mode 100644 index 0000000000..4240278edd --- /dev/null +++ b/target-i386/arch_dump.c @@ -0,0 +1,449 @@ +/* + * i386 memory mapping + * + * Copyright Fujitsu, Corp. 2011, 2012 + * + * Authors: + * Wen Congyang <wency@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "cpu.h" +#include "cpu-all.h" +#include "dump.h" +#include "elf.h" + +#ifdef TARGET_X86_64 +typedef struct { + target_ulong r15, r14, r13, r12, rbp, rbx, r11, r10; + target_ulong r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax; + target_ulong rip, cs, eflags; + target_ulong rsp, ss; + target_ulong fs_base, gs_base; + target_ulong ds, es, fs, gs; +} x86_64_user_regs_struct; + +typedef struct { + char pad1[32]; + uint32_t pid; + char pad2[76]; + x86_64_user_regs_struct regs; + char pad3[8]; +} x86_64_elf_prstatus; + +static int x86_64_write_elf64_note(write_core_dump_function f, + CPUArchState *env, int id, + void *opaque) +{ + x86_64_user_regs_struct regs; + Elf64_Nhdr *note; + char *buf; + int descsz, note_size, name_size = 5; + const char *name = "CORE"; + int ret; + + regs.r15 = env->regs[15]; + regs.r14 = env->regs[14]; + regs.r13 = env->regs[13]; + regs.r12 = env->regs[12]; + regs.r11 = env->regs[11]; + regs.r10 = env->regs[10]; + regs.r9 = env->regs[9]; + regs.r8 = env->regs[8]; + regs.rbp = env->regs[R_EBP]; + regs.rsp = env->regs[R_ESP]; + regs.rdi = env->regs[R_EDI]; + regs.rsi = env->regs[R_ESI]; + regs.rdx = env->regs[R_EDX]; + regs.rcx = env->regs[R_ECX]; + regs.rbx = env->regs[R_EBX]; + regs.rax = env->regs[R_EAX]; + regs.rip = env->eip; + regs.eflags = env->eflags; + + regs.orig_rax = 0; /* FIXME */ + regs.cs = env->segs[R_CS].selector; + regs.ss = env->segs[R_SS].selector; + regs.fs_base = env->segs[R_FS].base; + regs.gs_base = env->segs[R_GS].base; + regs.ds = env->segs[R_DS].selector; + regs.es = env->segs[R_ES].selector; + regs.fs = env->segs[R_FS].selector; + regs.gs = env->segs[R_GS].selector; + + descsz = sizeof(x86_64_elf_prstatus); + note_size = ((sizeof(Elf64_Nhdr) + 3) / 4 + (name_size + 3) / 4 + + (descsz + 3) / 4) * 4; + note = g_malloc(note_size); + + memset(note, 0, note_size); + note->n_namesz = cpu_to_le32(name_size); + note->n_descsz = cpu_to_le32(descsz); + note->n_type = cpu_to_le32(NT_PRSTATUS); + buf = (char *)note; + buf += ((sizeof(Elf64_Nhdr) + 3) / 4) * 4; + memcpy(buf, name, name_size); + buf += ((name_size + 3) / 4) * 4; + memcpy(buf + 32, &id, 4); /* pr_pid */ + buf += descsz - sizeof(x86_64_user_regs_struct)-sizeof(target_ulong); + memcpy(buf, ®s, sizeof(x86_64_user_regs_struct)); + + ret = f(note, note_size, opaque); + g_free(note); + if (ret < 0) { + return -1; + } + + return 0; +} +#endif + +typedef struct { + uint32_t ebx, ecx, edx, esi, edi, ebp, eax; + unsigned short ds, __ds, es, __es; + unsigned short fs, __fs, gs, __gs; + uint32_t orig_eax, eip; + unsigned short cs, __cs; + uint32_t eflags, esp; + unsigned short ss, __ss; +} x86_user_regs_struct; + +typedef struct { + char pad1[24]; + uint32_t pid; + char pad2[44]; + x86_user_regs_struct regs; + char pad3[4]; +} x86_elf_prstatus; + +static void x86_fill_elf_prstatus(x86_elf_prstatus *prstatus, CPUArchState *env, + int id) +{ + memset(prstatus, 0, sizeof(x86_elf_prstatus)); + prstatus->regs.ebp = env->regs[R_EBP] & 0xffffffff; + prstatus->regs.esp = env->regs[R_ESP] & 0xffffffff; + prstatus->regs.edi = env->regs[R_EDI] & 0xffffffff; + prstatus->regs.esi = env->regs[R_ESI] & 0xffffffff; + prstatus->regs.edx = env->regs[R_EDX] & 0xffffffff; + prstatus->regs.ecx = env->regs[R_ECX] & 0xffffffff; + prstatus->regs.ebx = env->regs[R_EBX] & 0xffffffff; + prstatus->regs.eax = env->regs[R_EAX] & 0xffffffff; + prstatus->regs.eip = env->eip & 0xffffffff; + prstatus->regs.eflags = env->eflags & 0xffffffff; + + prstatus->regs.cs = env->segs[R_CS].selector; + prstatus->regs.ss = env->segs[R_SS].selector; + prstatus->regs.ds = env->segs[R_DS].selector; + prstatus->regs.es = env->segs[R_ES].selector; + prstatus->regs.fs = env->segs[R_FS].selector; + prstatus->regs.gs = env->segs[R_GS].selector; + + prstatus->pid = id; +} + +static int x86_write_elf64_note(write_core_dump_function f, CPUArchState *env, + int id, void *opaque) +{ + x86_elf_prstatus prstatus; + Elf64_Nhdr *note; + char *buf; + int descsz, note_size, name_size = 5; + const char *name = "CORE"; + int ret; + + x86_fill_elf_prstatus(&prstatus, env, id); + descsz = sizeof(x86_elf_prstatus); + note_size = ((sizeof(Elf64_Nhdr) + 3) / 4 + (name_size + 3) / 4 + + (descsz + 3) / 4) * 4; + note = g_malloc(note_size); + + memset(note, 0, note_size); + note->n_namesz = cpu_to_le32(name_size); + note->n_descsz = cpu_to_le32(descsz); + note->n_type = cpu_to_le32(NT_PRSTATUS); + buf = (char *)note; + buf += ((sizeof(Elf64_Nhdr) + 3) / 4) * 4; + memcpy(buf, name, name_size); + buf += ((name_size + 3) / 4) * 4; + memcpy(buf, &prstatus, sizeof(prstatus)); + + ret = f(note, note_size, opaque); + g_free(note); + if (ret < 0) { + return -1; + } + + return 0; +} + +int cpu_write_elf64_note(write_core_dump_function f, CPUArchState *env, + int cpuid, void *opaque) +{ + int ret; +#ifdef TARGET_X86_64 + bool lma = !!(first_cpu->hflags & HF_LMA_MASK); + + if (lma) { + ret = x86_64_write_elf64_note(f, env, cpuid, opaque); + } else { +#endif + ret = x86_write_elf64_note(f, env, cpuid, opaque); +#ifdef TARGET_X86_64 + } +#endif + + return ret; +} + +int cpu_write_elf32_note(write_core_dump_function f, CPUArchState *env, + int cpuid, void *opaque) +{ + x86_elf_prstatus prstatus; + Elf32_Nhdr *note; + char *buf; + int descsz, note_size, name_size = 5; + const char *name = "CORE"; + int ret; + + x86_fill_elf_prstatus(&prstatus, env, cpuid); + descsz = sizeof(x86_elf_prstatus); + note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 + + (descsz + 3) / 4) * 4; + note = g_malloc(note_size); + + memset(note, 0, note_size); + note->n_namesz = cpu_to_le32(name_size); + note->n_descsz = cpu_to_le32(descsz); + note->n_type = cpu_to_le32(NT_PRSTATUS); + buf = (char *)note; + buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4; + memcpy(buf, name, name_size); + buf += ((name_size + 3) / 4) * 4; + memcpy(buf, &prstatus, sizeof(prstatus)); + + ret = f(note, note_size, opaque); + g_free(note); + if (ret < 0) { + return -1; + } + + return 0; +} + +/* + * please count up QEMUCPUSTATE_VERSION if you have changed definition of + * QEMUCPUState, and modify the tools using this information accordingly. + */ +#define QEMUCPUSTATE_VERSION (1) + +struct QEMUCPUSegment { + uint32_t selector; + uint32_t limit; + uint32_t flags; + uint32_t pad; + uint64_t base; +}; + +typedef struct QEMUCPUSegment QEMUCPUSegment; + +struct QEMUCPUState { + uint32_t version; + uint32_t size; + uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp; + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; + uint64_t rip, rflags; + QEMUCPUSegment cs, ds, es, fs, gs, ss; + QEMUCPUSegment ldt, tr, gdt, idt; + uint64_t cr[5]; +}; + +typedef struct QEMUCPUState QEMUCPUState; + +static void copy_segment(QEMUCPUSegment *d, SegmentCache *s) +{ + d->pad = 0; + d->selector = s->selector; + d->limit = s->limit; + d->flags = s->flags; + d->base = s->base; +} + +static void qemu_get_cpustate(QEMUCPUState *s, CPUArchState *env) +{ + memset(s, 0, sizeof(QEMUCPUState)); + + s->version = QEMUCPUSTATE_VERSION; + s->size = sizeof(QEMUCPUState); + + s->rax = env->regs[R_EAX]; + s->rbx = env->regs[R_EBX]; + s->rcx = env->regs[R_ECX]; + s->rdx = env->regs[R_EDX]; + s->rsi = env->regs[R_ESI]; + s->rdi = env->regs[R_EDI]; + s->rsp = env->regs[R_ESP]; + s->rbp = env->regs[R_EBP]; +#ifdef TARGET_X86_64 + s->r8 = env->regs[8]; + s->r9 = env->regs[9]; + s->r10 = env->regs[10]; + s->r11 = env->regs[11]; + s->r12 = env->regs[12]; + s->r13 = env->regs[13]; + s->r14 = env->regs[14]; + s->r15 = env->regs[15]; +#endif + s->rip = env->eip; + s->rflags = env->eflags; + + copy_segment(&s->cs, &env->segs[R_CS]); + copy_segment(&s->ds, &env->segs[R_DS]); + copy_segment(&s->es, &env->segs[R_ES]); + copy_segment(&s->fs, &env->segs[R_FS]); + copy_segment(&s->gs, &env->segs[R_GS]); + copy_segment(&s->ss, &env->segs[R_SS]); + copy_segment(&s->ldt, &env->ldt); + copy_segment(&s->tr, &env->tr); + copy_segment(&s->gdt, &env->gdt); + copy_segment(&s->idt, &env->idt); + + s->cr[0] = env->cr[0]; + s->cr[1] = env->cr[1]; + s->cr[2] = env->cr[2]; + s->cr[3] = env->cr[3]; + s->cr[4] = env->cr[4]; +} + +static inline int cpu_write_qemu_note(write_core_dump_function f, + CPUArchState *env, + void *opaque, + int type) +{ + QEMUCPUState state; + Elf64_Nhdr *note64; + Elf32_Nhdr *note32; + void *note; + char *buf; + int descsz, note_size, name_size = 5, note_head_size; + const char *name = "QEMU"; + int ret; + + qemu_get_cpustate(&state, env); + + descsz = sizeof(state); + if (type == 0) { + note_head_size = sizeof(Elf32_Nhdr); + } else { + note_head_size = sizeof(Elf64_Nhdr); + } + note_size = ((note_head_size + 3) / 4 + (name_size + 3) / 4 + + (descsz + 3) / 4) * 4; + note = g_malloc(note_size); + + memset(note, 0, note_size); + if (type == 0) { + note32 = note; + note32->n_namesz = cpu_to_le32(name_size); + note32->n_descsz = cpu_to_le32(descsz); + note32->n_type = 0; + } else { + note64 = note; + note64->n_namesz = cpu_to_le32(name_size); + note64->n_descsz = cpu_to_le32(descsz); + note64->n_type = 0; + } + buf = note; + buf += ((note_head_size + 3) / 4) * 4; + memcpy(buf, name, name_size); + buf += ((name_size + 3) / 4) * 4; + memcpy(buf, &state, sizeof(state)); + + ret = f(note, note_size, opaque); + g_free(note); + if (ret < 0) { + return -1; + } + + return 0; +} + +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUArchState *env, + void *opaque) +{ + return cpu_write_qemu_note(f, env, opaque, 1); +} + +int cpu_write_elf32_qemunote(write_core_dump_function f, CPUArchState *env, + void *opaque) +{ + return cpu_write_qemu_note(f, env, opaque, 0); +} + +int cpu_get_dump_info(ArchDumpInfo *info) +{ + bool lma = false; + RAMBlock *block; + +#ifdef TARGET_X86_64 + lma = !!(first_cpu->hflags & HF_LMA_MASK); +#endif + + if (lma) { + info->d_machine = EM_X86_64; + } else { + info->d_machine = EM_386; + } + info->d_endian = ELFDATA2LSB; + + if (lma) { + info->d_class = ELFCLASS64; + } else { + info->d_class = ELFCLASS32; + + QLIST_FOREACH(block, &ram_list.blocks, next) { + if (block->offset + block->length > UINT_MAX) { + /* The memory size is greater than 4G */ + info->d_class = ELFCLASS64; + break; + } + } + } + + return 0; +} + +ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) +{ + int name_size = 5; /* "CORE" or "QEMU" */ + size_t elf_note_size = 0; + size_t qemu_note_size = 0; + int elf_desc_size = 0; + int qemu_desc_size = 0; + int note_head_size; + + if (class == ELFCLASS32) { + note_head_size = sizeof(Elf32_Nhdr); + } else { + note_head_size = sizeof(Elf64_Nhdr); + } + + if (machine == EM_386) { + elf_desc_size = sizeof(x86_elf_prstatus); + } +#ifdef TARGET_X86_64 + else { + elf_desc_size = sizeof(x86_64_elf_prstatus); + } +#endif + qemu_desc_size = sizeof(QEMUCPUState); + + elf_note_size = ((note_head_size + 3) / 4 + (name_size + 3) / 4 + + (elf_desc_size + 3) / 4) * 4; + qemu_note_size = ((note_head_size + 3) / 4 + (name_size + 3) / 4 + + (qemu_desc_size + 3) / 4) * 4; + + return (elf_note_size + qemu_note_size) * nr_cpus; +} diff --git a/target-i386/arch_memory_mapping.c b/target-i386/arch_memory_mapping.c new file mode 100644 index 0000000000..8e5a56a3a8 --- /dev/null +++ b/target-i386/arch_memory_mapping.c @@ -0,0 +1,272 @@ +/* + * i386 memory mapping + * + * Copyright Fujitsu, Corp. 2011, 2012 + * + * Authors: + * Wen Congyang <wency@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "cpu.h" +#include "cpu-all.h" +#include "memory_mapping.h" + +/* PAE Paging or IA-32e Paging */ +static void walk_pte(MemoryMappingList *list, target_phys_addr_t pte_start_addr, + int32_t a20_mask, target_ulong start_line_addr) +{ + target_phys_addr_t pte_addr, start_paddr; + uint64_t pte; + target_ulong start_vaddr; + int i; + + for (i = 0; i < 512; i++) { + pte_addr = (pte_start_addr + i * 8) & a20_mask; + pte = ldq_phys(pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + /* not present */ + continue; + } + + start_paddr = (pte & ~0xfff) & ~(0x1ULL << 63); + if (cpu_physical_memory_is_io(start_paddr)) { + /* I/O region */ + continue; + } + + start_vaddr = start_line_addr | ((i & 0x1fff) << 12); + memory_mapping_list_add_merge_sorted(list, start_paddr, + start_vaddr, 1 << 12); + } +} + +/* 32-bit Paging */ +static void walk_pte2(MemoryMappingList *list, + target_phys_addr_t pte_start_addr, int32_t a20_mask, + target_ulong start_line_addr) +{ + target_phys_addr_t pte_addr, start_paddr; + uint32_t pte; + target_ulong start_vaddr; + int i; + + for (i = 0; i < 1024; i++) { + pte_addr = (pte_start_addr + i * 4) & a20_mask; + pte = ldl_phys(pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + /* not present */ + continue; + } + + start_paddr = pte & ~0xfff; + if (cpu_physical_memory_is_io(start_paddr)) { + /* I/O region */ + continue; + } + + start_vaddr = start_line_addr | ((i & 0x3ff) << 12); + memory_mapping_list_add_merge_sorted(list, start_paddr, + start_vaddr, 1 << 12); + } +} + +/* PAE Paging or IA-32e Paging */ +static void walk_pde(MemoryMappingList *list, target_phys_addr_t pde_start_addr, + int32_t a20_mask, target_ulong start_line_addr) +{ + target_phys_addr_t pde_addr, pte_start_addr, start_paddr; + uint64_t pde; + target_ulong line_addr, start_vaddr; + int i; + + for (i = 0; i < 512; i++) { + pde_addr = (pde_start_addr + i * 8) & a20_mask; + pde = ldq_phys(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + /* not present */ + continue; + } + + line_addr = start_line_addr | ((i & 0x1ff) << 21); + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + start_paddr = (pde & ~0x1fffff) & ~(0x1ULL << 63); + if (cpu_physical_memory_is_io(start_paddr)) { + /* I/O region */ + continue; + } + start_vaddr = line_addr; + memory_mapping_list_add_merge_sorted(list, start_paddr, + start_vaddr, 1 << 21); + continue; + } + + pte_start_addr = (pde & ~0xfff) & a20_mask; + walk_pte(list, pte_start_addr, a20_mask, line_addr); + } +} + +/* 32-bit Paging */ +static void walk_pde2(MemoryMappingList *list, + target_phys_addr_t pde_start_addr, int32_t a20_mask, + bool pse) +{ + target_phys_addr_t pde_addr, pte_start_addr, start_paddr; + uint32_t pde; + target_ulong line_addr, start_vaddr; + int i; + + for (i = 0; i < 1024; i++) { + pde_addr = (pde_start_addr + i * 4) & a20_mask; + pde = ldl_phys(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + /* not present */ + continue; + } + + line_addr = (((unsigned int)i & 0x3ff) << 22); + if ((pde & PG_PSE_MASK) && pse) { + /* 4 MB page */ + start_paddr = (pde & ~0x3fffff) | ((pde & 0x1fe000) << 19); + if (cpu_physical_memory_is_io(start_paddr)) { + /* I/O region */ + continue; + } + start_vaddr = line_addr; + memory_mapping_list_add_merge_sorted(list, start_paddr, + start_vaddr, 1 << 22); + continue; + } + + pte_start_addr = (pde & ~0xfff) & a20_mask; + walk_pte2(list, pte_start_addr, a20_mask, line_addr); + } +} + +/* PAE Paging */ +static void walk_pdpe2(MemoryMappingList *list, + target_phys_addr_t pdpe_start_addr, int32_t a20_mask) +{ + target_phys_addr_t pdpe_addr, pde_start_addr; + uint64_t pdpe; + target_ulong line_addr; + int i; + + for (i = 0; i < 4; i++) { + pdpe_addr = (pdpe_start_addr + i * 8) & a20_mask; + pdpe = ldq_phys(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + /* not present */ + continue; + } + + line_addr = (((unsigned int)i & 0x3) << 30); + pde_start_addr = (pdpe & ~0xfff) & a20_mask; + walk_pde(list, pde_start_addr, a20_mask, line_addr); + } +} + +#ifdef TARGET_X86_64 +/* IA-32e Paging */ +static void walk_pdpe(MemoryMappingList *list, + target_phys_addr_t pdpe_start_addr, int32_t a20_mask, + target_ulong start_line_addr) +{ + target_phys_addr_t pdpe_addr, pde_start_addr, start_paddr; + uint64_t pdpe; + target_ulong line_addr, start_vaddr; + int i; + + for (i = 0; i < 512; i++) { + pdpe_addr = (pdpe_start_addr + i * 8) & a20_mask; + pdpe = ldq_phys(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + /* not present */ + continue; + } + + line_addr = start_line_addr | ((i & 0x1ffULL) << 30); + if (pdpe & PG_PSE_MASK) { + /* 1 GB page */ + start_paddr = (pdpe & ~0x3fffffff) & ~(0x1ULL << 63); + if (cpu_physical_memory_is_io(start_paddr)) { + /* I/O region */ + continue; + } + start_vaddr = line_addr; + memory_mapping_list_add_merge_sorted(list, start_paddr, + start_vaddr, 1 << 30); + continue; + } + + pde_start_addr = (pdpe & ~0xfff) & a20_mask; + walk_pde(list, pde_start_addr, a20_mask, line_addr); + } +} + +/* IA-32e Paging */ +static void walk_pml4e(MemoryMappingList *list, + target_phys_addr_t pml4e_start_addr, int32_t a20_mask) +{ + target_phys_addr_t pml4e_addr, pdpe_start_addr; + uint64_t pml4e; + target_ulong line_addr; + int i; + + for (i = 0; i < 512; i++) { + pml4e_addr = (pml4e_start_addr + i * 8) & a20_mask; + pml4e = ldq_phys(pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) { + /* not present */ + continue; + } + + line_addr = ((i & 0x1ffULL) << 39) | (0xffffULL << 48); + pdpe_start_addr = (pml4e & ~0xfff) & a20_mask; + walk_pdpe(list, pdpe_start_addr, a20_mask, line_addr); + } +} +#endif + +int cpu_get_memory_mapping(MemoryMappingList *list, CPUArchState *env) +{ + if (!cpu_paging_enabled(env)) { + /* paging is disabled */ + return 0; + } + + if (env->cr[4] & CR4_PAE_MASK) { +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + target_phys_addr_t pml4e_addr; + + pml4e_addr = (env->cr[3] & ~0xfff) & env->a20_mask; + walk_pml4e(list, pml4e_addr, env->a20_mask); + } else +#endif + { + target_phys_addr_t pdpe_addr; + + pdpe_addr = (env->cr[3] & ~0x1f) & env->a20_mask; + walk_pdpe2(list, pdpe_addr, env->a20_mask); + } + } else { + target_phys_addr_t pde_addr; + bool pse; + + pde_addr = (env->cr[3] & ~0xfff) & env->a20_mask; + pse = !!(env->cr[4] & CR4_PSE_MASK); + walk_pde2(list, pde_addr, env->a20_mask, pse); + } + + return 0; +} + +bool cpu_paging_enabled(CPUArchState *env) +{ + return env->cr[0] & CR0_PG_MASK; +} diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 388bc5c527..0b6116246f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -723,66 +723,32 @@ static void x86_cpuid_get_level(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - int64_t value; - value = cpu->env.cpuid_level; - /* TODO Use visit_type_uint32() once available */ - visit_type_int(v, &value, name, errp); + visit_type_uint32(v, &cpu->env.cpuid_level, name, errp); } static void x86_cpuid_set_level(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - const int64_t min = 0; - const int64_t max = UINT32_MAX; - int64_t value; - - /* TODO Use visit_type_uint32() once available */ - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { - return; - } - if (value < min || value > max) { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "", - name ? name : "null", value, min, max); - return; - } - cpu->env.cpuid_level = value; + visit_type_uint32(v, &cpu->env.cpuid_level, name, errp); } static void x86_cpuid_get_xlevel(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - int64_t value; - value = cpu->env.cpuid_xlevel; - /* TODO Use visit_type_uint32() once available */ - visit_type_int(v, &value, name, errp); + visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp); } static void x86_cpuid_set_xlevel(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - const int64_t min = 0; - const int64_t max = UINT32_MAX; - int64_t value; - - /* TODO Use visit_type_uint32() once available */ - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { - return; - } - if (value < min || value > max) { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "", - name ? name : "null", value, min, max); - return; - } - cpu->env.cpuid_xlevel = value; + visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp); } static char *x86_cpuid_get_vendor(Object *obj, Error **errp) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2460f6348b..bcf663eeb5 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -787,7 +787,7 @@ typedef struct CPUX86State { #include "cpu-qom.h" -CPUX86State *cpu_x86_init(const char *cpu_model); +X86CPU *cpu_x86_init(const char *cpu_model); int cpu_x86_exec(CPUX86State *s); void x86_cpu_list (FILE *f, fprintf_function cpu_fprintf, const char *optarg); void x86_cpudef_setup(void); @@ -960,7 +960,15 @@ uint64_t cpu_get_tsc(CPUX86State *env); #define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif -#define cpu_init cpu_x86_init +static inline CPUX86State *cpu_init(const char *cpu_model) +{ + X86CPU *cpu = cpu_x86_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + #define cpu_exec cpu_x86_exec #define cpu_gen_code cpu_x86_gen_code #define cpu_signal_handler cpu_x86_signal_handler @@ -1053,8 +1061,8 @@ static inline void cpu_get_tb_cpu_state(CPUX86State *env, target_ulong *pc, (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK)); } -void do_cpu_init(CPUX86State *env); -void do_cpu_sipi(CPUX86State *env); +void do_cpu_init(X86CPU *cpu); +void do_cpu_sipi(X86CPU *cpu); #define MCE_INJECT_BROADCAST 1 #define MCE_INJECT_UNCOND_AO 2 diff --git a/target-i386/helper.c b/target-i386/helper.c index 3421be2276..2cc80977e8 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -26,12 +26,6 @@ //#define DEBUG_MMU -/* NOTE: must be called outside the CPU execute loop */ -void cpu_state_reset(CPUX86State *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - static void cpu_x86_version(CPUX86State *env, int *family, int *model) { int cpuver = env->cpuid_version; @@ -1157,7 +1151,7 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector, return 1; } -CPUX86State *cpu_x86_init(const char *cpu_model) +X86CPU *cpu_x86_init(const char *cpu_model) { X86CPU *cpu; CPUX86State *env; @@ -1183,31 +1177,34 @@ CPUX86State *cpu_x86_init(const char *cpu_model) x86_cpu_realize(OBJECT(cpu), NULL); - return env; + return cpu; } #if !defined(CONFIG_USER_ONLY) -void do_cpu_init(CPUX86State *env) +void do_cpu_init(X86CPU *cpu) { + CPUX86State *env = &cpu->env; int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI; uint64_t pat = env->pat; - cpu_state_reset(env); + cpu_reset(CPU(cpu)); env->interrupt_request = sipi; env->pat = pat; apic_init_reset(env->apic_state); env->halted = !cpu_is_bsp(env); } -void do_cpu_sipi(CPUX86State *env) +void do_cpu_sipi(X86CPU *cpu) { + CPUX86State *env = &cpu->env; + apic_sipi(env->apic_state); } #else -void do_cpu_init(CPUX86State *env) +void do_cpu_init(X86CPU *cpu) { } -void do_cpu_sipi(CPUX86State *env) +void do_cpu_sipi(X86CPU *cpu) { } #endif diff --git a/ioport-user.c b/target-i386/ioport-user.c index 03fac22d22..03fac22d22 100644 --- a/ioport-user.c +++ b/target-i386/ioport-user.c diff --git a/target-i386/kvm.c b/target-i386/kvm.c index e74a9e4641..0d0d8f69d3 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1698,6 +1698,8 @@ void kvm_arch_post_run(CPUX86State *env, struct kvm_run *run) int kvm_arch_process_async_events(CPUX86State *env) { + X86CPU *cpu = x86_env_get_cpu(env); + if (env->interrupt_request & CPU_INTERRUPT_MCE) { /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */ assert(env->mcg_cap); @@ -1732,11 +1734,11 @@ int kvm_arch_process_async_events(CPUX86State *env) } if (env->interrupt_request & CPU_INTERRUPT_INIT) { kvm_cpu_synchronize_state(env); - do_cpu_init(env); + do_cpu_init(cpu); } if (env->interrupt_request & CPU_INTERRUPT_SIPI) { kvm_cpu_synchronize_state(env); - do_cpu_sipi(env); + do_cpu_sipi(cpu); } if (env->interrupt_request & CPU_INTERRUPT_TPR) { env->interrupt_request &= ~CPU_INTERRUPT_TPR; diff --git a/target-lm32/Makefile.objs b/target-lm32/Makefile.objs new file mode 100644 index 0000000000..2e0e093e1f --- /dev/null +++ b/target-lm32/Makefile.objs @@ -0,0 +1,4 @@ +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += machine.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index 48a5fe3f86..caa4834075 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -18,7 +18,7 @@ * <http://www.gnu.org/licenses/lgpl-2.1.html> */ -#include "cpu-qom.h" +#include "cpu.h" #include "qemu-common.h" diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index 422a55b063..da80469f51 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -186,7 +186,7 @@ struct CPULM32State { #include "cpu-qom.h" -CPULM32State *cpu_lm32_init(const char *cpu_model); +LM32CPU *cpu_lm32_init(const char *cpu_model); void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf); int cpu_lm32_exec(CPULM32State *s); void cpu_lm32_close(CPULM32State *s); @@ -199,8 +199,16 @@ int cpu_lm32_signal_handler(int host_signum, void *pinfo, void lm32_translate_init(void); void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value); +static inline CPULM32State *cpu_init(const char *cpu_model) +{ + LM32CPU *cpu = cpu_lm32_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + #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 diff --git a/target-lm32/helper.c b/target-lm32/helper.c index d0bc1931d8..1ea477fea3 100644 --- a/target-lm32/helper.c +++ b/target-lm32/helper.c @@ -192,7 +192,7 @@ static uint32_t cfg_by_def(const LM32Def *def) return cfg; } -CPULM32State *cpu_lm32_init(const char *cpu_model) +LM32CPU *cpu_lm32_init(const char *cpu_model) { LM32CPU *cpu; CPULM32State *env; @@ -219,7 +219,7 @@ CPULM32State *cpu_lm32_init(const char *cpu_model) lm32_translate_init(); } - return env; + return cpu; } /* Some soc ignores the MSB on the address bus. Thus creating a shadow memory @@ -233,9 +233,3 @@ void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value) env->flags &= ~LM32_FLAG_IGNORE_MSB; } } - -void cpu_state_reset(CPULM32State *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - diff --git a/target-m68k/Makefile.objs b/target-m68k/Makefile.objs new file mode 100644 index 0000000000..cda60157f5 --- /dev/null +++ b/target-m68k/Makefile.objs @@ -0,0 +1,5 @@ +obj-y += m68k-semi.o +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += machine.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index f428375d7d..eac0053c5d 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -98,11 +98,6 @@ static int fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) return 0; } -void cpu_state_reset(CPUM68KState *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - CPUM68KState *cpu_m68k_init(const char *cpu_model) { M68kCPU *cpu; diff --git a/m68k-semi.c b/target-m68k/m68k-semi.c index 3bb30cd1f7..3bb30cd1f7 100644 --- a/m68k-semi.c +++ b/target-m68k/m68k-semi.c diff --git a/target-microblaze/Makefile.objs b/target-microblaze/Makefile.objs new file mode 100644 index 0000000000..4b09e8c6b5 --- /dev/null +++ b/target-microblaze/Makefile.objs @@ -0,0 +1,4 @@ +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += mmu.o machine.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index b0ba9fe296..4968c244e8 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -272,7 +272,7 @@ struct CPUMBState { #include "cpu-qom.h" -CPUMBState *cpu_mb_init(const char *cpu_model); +MicroBlazeCPU *cpu_mb_init(const char *cpu_model); int cpu_mb_exec(CPUMBState *s); void cpu_mb_close(CPUMBState *s); void do_interrupt(CPUMBState *env); @@ -295,7 +295,15 @@ enum { #define TARGET_PHYS_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define cpu_init cpu_mb_init +static inline CPUMBState *cpu_init(const char *cpu_model) +{ + MicroBlazeCPU *cpu = cpu_mb_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + #define cpu_exec cpu_mb_exec #define cpu_gen_code cpu_mb_gen_code #define cpu_signal_handler cpu_mb_signal_handler diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index f0ebd596c0..c0a6bfd9c3 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1105,7 +1105,7 @@ static void gen_store(DisasContext *dc, TCGv addr, TCGv val, static void dec_store(DisasContext *dc) { - TCGv t, *addr, swx_addr, r_check = 0; + TCGv t, *addr, swx_addr, r_check; int swx_skip = 0; unsigned int size, rev = 0, ex = 0; @@ -1129,9 +1129,9 @@ static void dec_store(DisasContext *dc) sync_jmpstate(dc); addr = compute_ldst_addr(dc, &t); + r_check = tcg_temp_new(); + swx_addr = tcg_temp_local_new(); if (ex) { /* swx */ - r_check = tcg_temp_new(); - swx_addr = tcg_temp_local_new(); /* Force addr into the swx_addr. */ tcg_gen_mov_tl(swx_addr, *addr); @@ -1221,11 +1221,12 @@ static void dec_store(DisasContext *dc) gen_helper_memalign(*addr, tcg_const_tl(dc->rd), tcg_const_tl(1), tcg_const_tl(size - 1)); } + if (ex) { gen_set_label(swx_skip); - tcg_temp_free(r_check); - tcg_temp_free(swx_addr); } + tcg_temp_free(r_check); + tcg_temp_free(swx_addr); if (addr == &t) tcg_temp_free(t); @@ -1951,21 +1952,20 @@ void cpu_dump_state (CPUMBState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\n\n"); } -CPUMBState *cpu_mb_init (const char *cpu_model) +MicroBlazeCPU *cpu_mb_init(const char *cpu_model) { MicroBlazeCPU *cpu; - CPUMBState *env; static int tcg_initialized = 0; int i; cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); - env = &cpu->env; cpu_reset(CPU(cpu)); - qemu_init_vcpu(env); + qemu_init_vcpu(&cpu->env); - if (tcg_initialized) - return env; + if (tcg_initialized) { + return cpu; + } tcg_initialized = 1; @@ -1999,12 +1999,7 @@ CPUMBState *cpu_mb_init (const char *cpu_model) #define GEN_HELPER 2 #include "helper.h" - return env; -} - -void cpu_state_reset(CPUMBState *env) -{ - cpu_reset(ENV_GET_CPU(env)); + return cpu; } void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, int pc_pos) diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs new file mode 100644 index 0000000000..2e0e093e1f --- /dev/null +++ b/target-mips/Makefile.objs @@ -0,0 +1,4 @@ +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += machine.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 44c1152a3a..ce3467f140 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -496,7 +496,6 @@ void cpu_unassigned_access(CPUMIPSState *env, target_phys_addr_t addr, void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf); -#define cpu_init cpu_mips_init #define cpu_exec cpu_mips_exec #define cpu_gen_code cpu_mips_gen_code #define cpu_signal_handler cpu_mips_signal_handler @@ -626,9 +625,21 @@ enum { #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 int cpu_mips_exec(CPUMIPSState *s); -CPUMIPSState *cpu_mips_init(const char *cpu_model); +MIPSCPU *cpu_mips_init(const char *cpu_model); int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); +static inline CPUMIPSState *cpu_init(const char *cpu_model) +{ + MIPSCPU *cpu = cpu_mips_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + +/* TODO QOM'ify CPU reset and remove */ +void cpu_state_reset(CPUMIPSState *s); + /* mips_timer.c */ uint32_t cpu_mips_get_random (CPUMIPSState *env); uint32_t cpu_mips_get_count (CPUMIPSState *env); diff --git a/target-mips/helper.c b/target-mips/helper.c index ddf9cb72f4..4208bb20c8 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -399,6 +399,7 @@ static void set_hflags_for_handler (CPUMIPSState *env) void do_interrupt (CPUMIPSState *env) { #if !defined(CONFIG_USER_ONLY) + MIPSCPU *cpu = mips_env_get_cpu(env); target_ulong offset; int cause = -1; const char *name; @@ -452,7 +453,7 @@ void do_interrupt (CPUMIPSState *env) set_hflags_for_handler(env); break; case EXCP_RESET: - cpu_state_reset(env); + cpu_reset(CPU(cpu)); break; case EXCP_SRESET: env->CP0_Status |= (1 << CP0St_SR); diff --git a/target-mips/translate.c b/target-mips/translate.c index 0c563eedfa..4e15ee36b8 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12689,7 +12689,7 @@ static void mips_tcg_init(void) #include "translate_init.c" -CPUMIPSState *cpu_mips_init (const char *cpu_model) +MIPSCPU *cpu_mips_init(const char *cpu_model) { MIPSCPU *cpu; CPUMIPSState *env; @@ -12709,9 +12709,9 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model) fpu_init(env, def); mvp_init(env, def); mips_tcg_init(); - cpu_state_reset(env); + cpu_reset(CPU(cpu)); qemu_init_vcpu(env); - return env; + return cpu; } void cpu_state_reset(CPUMIPSState *env) diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs new file mode 100644 index 0000000000..f78161004e --- /dev/null +++ b/target-ppc/Makefile.objs @@ -0,0 +1,6 @@ +obj-y += translate.o op_helper.o helper.o +obj-$(CONFIG_SOFTMMU) += machine.o +obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o +obj-y += op_helper.o helper.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 84c9674157..77a28580af 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1099,7 +1099,7 @@ struct mmu_ctx_t { #include "cpu-qom.h" /*****************************************************************************/ -CPUPPCState *cpu_ppc_init (const char *cpu_model); +PowerPCCPU *cpu_ppc_init(const char *cpu_model); void ppc_translate_init(void); int cpu_ppc_exec (CPUPPCState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV @@ -1214,7 +1214,15 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn) int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp); int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val); -#define cpu_init cpu_ppc_init +static inline CPUPPCState *cpu_init(const char *cpu_model) +{ + PowerPCCPU *cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + #define cpu_exec cpu_ppc_exec #define cpu_gen_code cpu_ppc_gen_code #define cpu_signal_handler cpu_ppc_signal_handler diff --git a/target-ppc/helper.c b/target-ppc/helper.c index e97e49640d..f556f8567a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -3186,12 +3186,7 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr) TARGET_FMT_lx "\n", RA, msr); } -void cpu_state_reset(CPUPPCState *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - -CPUPPCState *cpu_ppc_init (const char *cpu_model) +PowerPCCPU *cpu_ppc_init(const char *cpu_model) { PowerPCCPU *cpu; CPUPPCState *env; @@ -3213,5 +3208,5 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) qemu_init_vcpu(env); - return env; + return cpu; } diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs new file mode 100644 index 0000000000..262747f8a6 --- /dev/null +++ b/target-s390x/Makefile.objs @@ -0,0 +1,5 @@ +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += machine.o +obj-$(CONFIG_KVM) += kvm.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index f183213eab..619b202b92 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -20,7 +20,7 @@ * <http://www.gnu.org/licenses/lgpl-2.1.html> */ -#include "cpu-qom.h" +#include "cpu.h" #include "qemu-common.h" #include "qemu-timer.h" diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 2f3f3942c0..c30ac3a0e1 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -105,6 +105,8 @@ typedef struct CPUS390XState { QEMUTimer *cpu_timer; } CPUS390XState; +#include "cpu-qom.h" + #if defined(CONFIG_USER_ONLY) static inline void cpu_clone_regs(CPUS390XState *env, target_ulong newsp) { @@ -271,7 +273,7 @@ static inline int get_ilc(uint8_t opc) #define ILC_LATER_INC_2 0x22 -CPUS390XState *cpu_s390x_init(const char *cpu_model); +S390CPU *cpu_s390x_init(const char *cpu_model); void s390x_translate_init(void); int cpu_s390x_exec(CPUS390XState *s); void cpu_s390x_close(CPUS390XState *s); @@ -314,7 +316,7 @@ static inline void kvm_s390_interrupt_internal(CPUS390XState *env, int type, { } #endif -CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr); +S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); void s390_add_running_cpu(CPUS390XState *env); unsigned s390_del_running_cpu(CPUS390XState *env); @@ -340,7 +342,7 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) env->aregs[1] = newtls & 0xffffffffULL; } -#define cpu_init cpu_s390x_init +#define cpu_init(model) (&cpu_s390x_init(model)->env) #define cpu_exec cpu_s390x_exec #define cpu_gen_code cpu_s390x_gen_code #define cpu_signal_handler cpu_s390x_signal_handler @@ -994,6 +996,4 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) env->psw.addr = tb->pc; } -#include "cpu-qom.h" - #endif diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 209a69603c..d0a1180a83 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -70,7 +70,7 @@ void s390x_cpu_timer(void *opaque) } #endif -CPUS390XState *cpu_s390x_init(const char *cpu_model) +S390CPU *cpu_s390x_init(const char *cpu_model) { S390CPU *cpu; CPUS390XState *env; @@ -86,7 +86,7 @@ CPUS390XState *cpu_s390x_init(const char *cpu_model) env->cpu_model_str = cpu_model; qemu_init_vcpu(env); - return env; + return cpu; } #if defined(CONFIG_USER_ONLY) @@ -106,14 +106,7 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw return 1; } -#endif /* CONFIG_USER_ONLY */ - -void cpu_state_reset(CPUS390XState *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - -#ifndef CONFIG_USER_ONLY +#else /* !CONFIG_USER_ONLY */ /* Ensure to exit the TB after this call! */ static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilc) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 90aad61eb0..5800fd612c 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -292,8 +292,10 @@ static int handle_diag(CPUS390XState *env, struct kvm_run *run, int ipb_code) return r; } -static int s390_cpu_restart(CPUS390XState *env) +static int s390_cpu_restart(S390CPU *cpu) { + CPUS390XState *env = &cpu->env; + kvm_s390_interrupt(env, KVM_S390_RESTART, 0); s390_add_running_cpu(env); qemu_cpu_kick(env); @@ -333,6 +335,7 @@ static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) uint16_t cpu_addr; uint8_t t; int r = -1; + S390CPU *target_cpu; CPUS390XState *target_env; cpu_synchronize_state(env); @@ -353,14 +356,15 @@ static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) parameter = env->regs[t] & 0x7ffffe00; cpu_addr = env->regs[ipa1 & 0x0f]; - target_env = s390_cpu_addr2state(cpu_addr); - if (!target_env) { + target_cpu = s390_cpu_addr2state(cpu_addr); + if (target_cpu == NULL) { goto out; } + target_env = &target_cpu->env; switch (order_code) { case SIGP_RESTART: - r = s390_cpu_restart(target_env); + r = s390_cpu_restart(target_cpu); break; case SIGP_STORE_STATUS_ADDR: r = s390_store_status(target_env, parameter); diff --git a/target-sh4/Makefile.objs b/target-sh4/Makefile.objs new file mode 100644 index 0000000000..2e0e093e1f --- /dev/null +++ b/target-sh4/Makefile.objs @@ -0,0 +1,4 @@ +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += machine.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index b6768f1648..bf592227ee 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -191,7 +191,7 @@ typedef struct CPUSH4State { #include "cpu-qom.h" -CPUSH4State *cpu_sh4_init(const char *cpu_model); +SuperHCPU *cpu_sh4_init(const char *cpu_model); int cpu_sh4_exec(CPUSH4State * s); int cpu_sh4_signal_handler(int host_signum, void *pinfo, void *puc); @@ -232,7 +232,15 @@ void cpu_load_tlb(CPUSH4State * env); #include "softfloat.h" -#define cpu_init cpu_sh4_init +static inline CPUSH4State *cpu_init(const char *cpu_model) +{ + SuperHCPU *cpu = cpu_sh4_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + #define cpu_exec cpu_sh4_exec #define cpu_gen_code cpu_sh4_gen_code #define cpu_signal_handler cpu_sh4_signal_handler diff --git a/target-sh4/translate.c b/target-sh4/translate.c index d25f0c5a29..6532ad2ade 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -178,11 +178,6 @@ void cpu_dump_state(CPUSH4State * env, FILE * f, } } -void cpu_state_reset(CPUSH4State *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - typedef struct { const char *name; int id; @@ -247,7 +242,7 @@ static void cpu_register(CPUSH4State *env, const sh4_def_t *def) env->id = def->id; } -CPUSH4State *cpu_sh4_init(const char *cpu_model) +SuperHCPU *cpu_sh4_init(const char *cpu_model) { SuperHCPU *cpu; CPUSH4State *env; @@ -264,7 +259,7 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model) cpu_reset(CPU(cpu)); cpu_register(env, def); qemu_init_vcpu(env); - return env; + return cpu; } static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) diff --git a/target-sparc/Makefile.objs b/target-sparc/Makefile.objs new file mode 100644 index 0000000000..a93e07deb1 --- /dev/null +++ b/target-sparc/Makefile.objs @@ -0,0 +1,8 @@ +obj-$(CONFIG_SOFTMMU) += machine.o +obj-y += translate.o helper.o cpu.o +obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o +obj-$(TARGET_SPARC) += int32_helper.o +obj-$(TARGET_SPARC64) += int64_helper.o +obj-$(TARGET_SPARC64) += vis_helper.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 7ac6bdb058..f7c004c7d8 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -23,11 +23,6 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model); -void cpu_state_reset(CPUSPARCState *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - /* CPUClass::reset() */ static void sparc_cpu_reset(CPUState *s) { @@ -111,7 +106,7 @@ static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model) return 0; } -CPUSPARCState *cpu_sparc_init(const char *cpu_model) +SPARCCPU *cpu_sparc_init(const char *cpu_model) { SPARCCPU *cpu; CPUSPARCState *env; @@ -129,7 +124,7 @@ CPUSPARCState *cpu_sparc_init(const char *cpu_model) } qemu_init_vcpu(env); - return env; + return cpu; } void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 29c63c711f..e16b7b3515 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -511,9 +511,11 @@ struct CPUSPARCState { uint32_t cache_control; }; +#include "cpu-qom.h" + #ifndef NO_CPU_IO_DEFS /* cpu_init.c */ -CPUSPARCState *cpu_sparc_init(const char *cpu_model); +SPARCCPU *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 */ @@ -590,7 +592,17 @@ target_phys_addr_t cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong ad #endif int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); -#define cpu_init cpu_sparc_init +#ifndef NO_CPU_IO_DEFS +static inline CPUSPARCState *cpu_init(const char *cpu_model) +{ + SPARCCPU *cpu = cpu_sparc_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} +#endif + #define cpu_exec cpu_sparc_exec #define cpu_gen_code cpu_sparc_gen_code #define cpu_signal_handler cpu_sparc_signal_handler @@ -691,7 +703,6 @@ static inline void cpu_clone_regs(CPUSPARCState *env, target_ulong newsp) #endif #include "cpu-all.h" -#include "cpu-qom.h" #ifdef TARGET_SPARC64 /* sun4u.c */ diff --git a/target-unicore32/Makefile.objs b/target-unicore32/Makefile.objs new file mode 100644 index 0000000000..2e0e093e1f --- /dev/null +++ b/target-unicore32/Makefile.objs @@ -0,0 +1,4 @@ +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += machine.o + +$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-xtensa/Makefile.objs b/target-xtensa/Makefile.objs new file mode 100644 index 0000000000..b30e5a8466 --- /dev/null +++ b/target-xtensa/Makefile.objs @@ -0,0 +1,6 @@ +obj-y += xtensa-semi.o +obj-y += core-dc232b.o +obj-y += core-dc233c.o +obj-y += core-fsf.o +obj-y += translate.o op_helper.o helper.o cpu.o +obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index 97deacb478..9d01983d44 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -28,7 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "cpu-qom.h" +#include "cpu.h" #include "qemu-common.h" diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index 6d0ea7c038..f7db116400 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -344,13 +344,24 @@ typedef struct CPUXtensaState { CPU_COMMON } CPUXtensaState; -#define cpu_init cpu_xtensa_init +#include "cpu-qom.h" + #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); +XtensaCPU *cpu_xtensa_init(const char *cpu_model); + +static inline CPUXtensaState *cpu_init(const char *cpu_model) +{ + XtensaCPU *cpu = cpu_xtensa_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + void xtensa_translate_init(void); int cpu_xtensa_exec(CPUXtensaState *s); void xtensa_register_core(XtensaConfigList *node); @@ -370,9 +381,12 @@ void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb, uint32_t *vpn, uint32_t wi, uint32_t *ei); int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb, uint32_t *pwi, uint32_t *pei, uint8_t *pring); +void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env, + xtensa_tlb_entry *entry, bool dtlb, + unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte); void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte); -int xtensa_get_physical_addr(CPUXtensaState *env, +int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, uint32_t vaddr, int is_write, int mmu_idx, uint32_t *paddr, uint32_t *page_size, unsigned *access); void reset_mmu(CPUXtensaState *env); @@ -471,7 +485,6 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, } #include "cpu-all.h" -#include "cpu-qom.h" #include "exec-all.h" static inline int cpu_has_work(CPUXtensaState *env) diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index 2094227843..044ce18364 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -33,11 +33,6 @@ #include "hw/loader.h" #endif -void cpu_state_reset(CPUXtensaState *env) -{ - cpu_reset(ENV_GET_CPU(env)); -} - static struct XtensaConfigList *xtensa_cores; void xtensa_register_core(XtensaConfigList *node) @@ -80,7 +75,7 @@ static void breakpoint_handler(CPUXtensaState *env) } } -CPUXtensaState *cpu_xtensa_init(const char *cpu_model) +XtensaCPU *cpu_xtensa_init(const char *cpu_model) { static int tcg_inited; static int debug_handler_inited; @@ -116,7 +111,7 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model) xtensa_irq_init(env); qemu_init_vcpu(env); - return env; + return cpu; } @@ -135,11 +130,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUXtensaState *env, target_ulong add uint32_t page_size; unsigned access; - if (xtensa_get_physical_addr(env, addr, 0, 0, + if (xtensa_get_physical_addr(env, false, addr, 0, 0, &paddr, &page_size, &access) == 0) { return paddr; } - if (xtensa_get_physical_addr(env, addr, 2, 0, + if (xtensa_get_physical_addr(env, false, addr, 2, 0, &paddr, &page_size, &access) == 0) { return paddr; } @@ -448,30 +443,48 @@ static bool is_access_granted(unsigned access, int is_write) } } -static int autorefill_mmu(CPUXtensaState *env, uint32_t vaddr, bool dtlb, - uint32_t *wi, uint32_t *ei, uint8_t *ring); +static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte); -static int get_physical_addr_mmu(CPUXtensaState *env, +static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb, uint32_t vaddr, int is_write, int mmu_idx, - uint32_t *paddr, uint32_t *page_size, unsigned *access) + uint32_t *paddr, uint32_t *page_size, unsigned *access, + bool may_lookup_pt) { bool dtlb = is_write != 2; uint32_t wi; uint32_t ei; uint8_t ring; + uint32_t vpn; + uint32_t pte; + const xtensa_tlb_entry *entry = NULL; + xtensa_tlb_entry tmp_entry; 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) { + may_lookup_pt && get_pte(env, vaddr, &pte) == 0) { + ring = (pte >> 4) & 0x3; + wi = 0; + split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei); + + if (update_tlb) { + wi = ++env->autorefill_idx & 0x3; + xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte); + env->sregs[EXCVADDR] = vaddr; + qemu_log("%s: autorefill(%08x): %08x -> %08x\n", + __func__, vaddr, vpn, pte); + } else { + xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte); + entry = &tmp_entry; + } ret = 0; } if (ret != 0) { return ret; } - const xtensa_tlb_entry *entry = - xtensa_tlb_get_entry(env, dtlb, wi, ei); + if (entry == NULL) { + entry = xtensa_tlb_get_entry(env, dtlb, wi, ei); + } if (ring < mmu_idx) { return dtlb ? @@ -494,30 +507,21 @@ static int get_physical_addr_mmu(CPUXtensaState *env, return 0; } -static int autorefill_mmu(CPUXtensaState *env, uint32_t vaddr, bool dtlb, - uint32_t *wi, uint32_t *ei, uint8_t *ring) +static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte) { 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); + int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0, + &paddr, &page_size, &access, false); 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); + *pte = ldl_phys(paddr); } return ret; } @@ -553,13 +557,13 @@ static int get_physical_addr_region(CPUXtensaState *env, * * \return 0 if ok, exception cause code otherwise */ -int xtensa_get_physical_addr(CPUXtensaState *env, +int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, 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); + return get_physical_addr_mmu(env, update_tlb, + vaddr, is_write, mmu_idx, paddr, page_size, access, true); } else if (xtensa_option_bits_enabled(env->config, XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) { diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h index 48a741e46d..152fec044d 100644 --- a/target-xtensa/helper.h +++ b/target-xtensa/helper.h @@ -1,39 +1,39 @@ #include "def-helper.h" -DEF_HELPER_1(exception, void, i32) -DEF_HELPER_2(exception_cause, void, i32, i32) -DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32) -DEF_HELPER_2(debug_exception, void, i32, i32) +DEF_HELPER_2(exception, noreturn, env, i32) +DEF_HELPER_3(exception_cause, noreturn, env, i32, i32) +DEF_HELPER_4(exception_cause_vaddr, noreturn, env, i32, i32, i32) +DEF_HELPER_3(debug_exception, noreturn, env, 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_FLAGS_1(nsa, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(nsau, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_2(wsr_windowbase, void, env, i32) +DEF_HELPER_4(entry, void, env, i32, i32, i32) +DEF_HELPER_2(retw, i32, env, i32) +DEF_HELPER_2(rotw, void, env, i32) +DEF_HELPER_3(window_check, void, env, i32, i32) +DEF_HELPER_1(restore_owb, void, env) +DEF_HELPER_2(movsp, void, env, i32) +DEF_HELPER_2(wsr_lbeg, void, env, i32) +DEF_HELPER_2(wsr_lend, void, env, i32) DEF_HELPER_1(simcall, void, env) -DEF_HELPER_0(dump_state, void) +DEF_HELPER_1(dump_state, void, env) -DEF_HELPER_2(waiti, void, i32, i32) -DEF_HELPER_2(timer_irq, void, i32, i32) -DEF_HELPER_1(advance_ccount, void, i32) +DEF_HELPER_3(waiti, void, env, i32, i32) +DEF_HELPER_3(timer_irq, void, env, i32, i32) +DEF_HELPER_2(advance_ccount, void, env, i32) DEF_HELPER_1(check_interrupts, void, env) -DEF_HELPER_1(wsr_rasid, void, i32) -DEF_HELPER_2(rtlb0, i32, i32, i32) -DEF_HELPER_2(rtlb1, i32, i32, i32) -DEF_HELPER_2(itlb, void, i32, i32) -DEF_HELPER_2(ptlb, i32, i32, i32) -DEF_HELPER_3(wtlb, void, i32, i32, i32) +DEF_HELPER_2(wsr_rasid, void, env, i32) +DEF_HELPER_FLAGS_3(rtlb0, TCG_CALL_CONST | TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(rtlb1, TCG_CALL_CONST | TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_3(itlb, void, env, i32, i32) +DEF_HELPER_3(ptlb, i32, env, i32, i32) +DEF_HELPER_4(wtlb, void, env, i32, i32, i32) -DEF_HELPER_1(wsr_ibreakenable, void, i32) -DEF_HELPER_2(wsr_ibreaka, void, i32, i32) -DEF_HELPER_2(wsr_dbreaka, void, i32, i32) -DEF_HELPER_2(wsr_dbreakc, void, i32, i32) +DEF_HELPER_2(wsr_ibreakenable, void, env, i32) +DEF_HELPER_3(wsr_ibreaka, void, env, i32, i32) +DEF_HELPER_3(wsr_dbreaka, void, env, i32, i32) +DEF_HELPER_3(wsr_dbreakc, void, env, i32, i32) #include "def-helper.h" diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index 364dc19bc0..2659c0e00f 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -26,12 +26,11 @@ */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" #include "host-utils.h" -static void do_unaligned_access(target_ulong addr, int is_write, int is_user, - uintptr_t retaddr); +static void do_unaligned_access(CPUXtensaState *env, + target_ulong addr, int is_write, int is_user, uintptr_t retaddr); #define ALIGNED_ONLY #define MMUSUFFIX _mmu @@ -48,7 +47,7 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user, #define SHIFT 3 #include "softmmu_template.h" -static void do_restore_state(uintptr_t pc) +static void do_restore_state(CPUXtensaState *env, uintptr_t pc) { TranslationBlock *tb; @@ -58,44 +57,38 @@ static void do_restore_state(uintptr_t pc) } } -static void do_unaligned_access(target_ulong addr, int is_write, int is_user, - uintptr_t retaddr) +static void do_unaligned_access(CPUXtensaState *env, + target_ulong addr, int is_write, int is_user, uintptr_t 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)( + do_restore_state(env, retaddr); + HELPER(exception_cause_vaddr)(env, env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr); } } -void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_idx, - uintptr_t retaddr) +void tlb_fill(CPUXtensaState *env, + target_ulong vaddr, int is_write, int mmu_idx, uintptr_t retaddr) { - CPUXtensaState *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); + uint32_t paddr; + uint32_t page_size; + unsigned access; + int ret = xtensa_get_physical_addr(env, true, 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); + 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); - } + if (ret == 0) { + tlb_set_page(env, + vaddr & TARGET_PAGE_MASK, + paddr & TARGET_PAGE_MASK, + access, mmu_idx, page_size); + } else { + do_restore_state(env, retaddr); + HELPER(exception_cause_vaddr)(env, env->pc, ret, vaddr); } - env = saved_env; } static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr) @@ -103,20 +96,20 @@ static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr) uint32_t paddr; uint32_t page_size; unsigned access; - int ret = xtensa_get_physical_addr(env, vaddr, 2, 0, + int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0, &paddr, &page_size, &access); if (ret == 0) { tb_invalidate_phys_addr(paddr); } } -void HELPER(exception)(uint32_t excp) +void HELPER(exception)(CPUXtensaState *env, uint32_t excp) { env->exception_index = excp; cpu_loop_exit(env); } -void HELPER(exception_cause)(uint32_t pc, uint32_t cause) +void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause) { uint32_t vector; @@ -136,24 +129,24 @@ void HELPER(exception_cause)(uint32_t pc, uint32_t cause) env->sregs[EXCCAUSE] = cause; env->sregs[PS] |= PS_EXCM; - HELPER(exception)(vector); + HELPER(exception)(env, vector); } -void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr) +void HELPER(exception_cause_vaddr)(CPUXtensaState *env, + uint32_t pc, uint32_t cause, uint32_t vaddr) { env->sregs[EXCVADDR] = vaddr; - HELPER(exception_cause)(pc, cause); + HELPER(exception_cause)(env, pc, cause); } -void debug_exception_env(CPUXtensaState *new_env, uint32_t cause) +void debug_exception_env(CPUXtensaState *env, uint32_t cause) { - if (xtensa_get_cintlevel(new_env) < new_env->config->debug_level) { - env = new_env; - HELPER(debug_exception)(env->pc, cause); + if (xtensa_get_cintlevel(env) < env->config->debug_level) { + HELPER(debug_exception)(env, env->pc, cause); } } -void HELPER(debug_exception)(uint32_t pc, uint32_t cause) +void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause) { unsigned level = env->config->debug_level; @@ -163,7 +156,7 @@ void HELPER(debug_exception)(uint32_t pc, uint32_t cause) env->sregs[EPS2 + level - 2] = env->sregs[PS]; env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | PS_EXCM | (level << PS_INTLEVEL_SHIFT); - HELPER(exception)(EXC_DEBUG); + HELPER(exception)(env, EXC_DEBUG); } uint32_t HELPER(nsa)(uint32_t v) @@ -232,39 +225,39 @@ void xtensa_sync_phys_from_window(CPUXtensaState *env) copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16); } -static void rotate_window_abs(uint32_t position) +static void rotate_window_abs(CPUXtensaState *env, 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) +static void rotate_window(CPUXtensaState *env, uint32_t delta) { - rotate_window_abs(env->sregs[WINDOW_BASE] + delta); + rotate_window_abs(env, env->sregs[WINDOW_BASE] + delta); } -void HELPER(wsr_windowbase)(uint32_t v) +void HELPER(wsr_windowbase)(CPUXtensaState *env, uint32_t v) { - rotate_window_abs(v); + rotate_window_abs(env, v); } -void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm) +void HELPER(entry)(CPUXtensaState *env, 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); + HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE); } else { env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3); - rotate_window(callinc); + rotate_window(env, callinc); env->sregs[WINDOW_START] |= windowstart_bit(env->sregs[WINDOW_BASE], env); } } -void HELPER(window_check)(uint32_t pc, uint32_t w) +void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w) { uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env); uint32_t windowstart = env->sregs[WINDOW_START]; @@ -284,21 +277,21 @@ void HELPER(window_check)(uint32_t pc, uint32_t w) } m = windowbase_bound(windowbase + n, env); - rotate_window(n); + rotate_window(env, 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); + HELPER(exception)(env, EXC_WINDOW_OVERFLOW4); } else if (windowstart & windowstart_bit(m + 2, env)) { - HELPER(exception)(EXC_WINDOW_OVERFLOW8); + HELPER(exception)(env, EXC_WINDOW_OVERFLOW8); } else { - HELPER(exception)(EXC_WINDOW_OVERFLOW12); + HELPER(exception)(env, EXC_WINDOW_OVERFLOW12); } } -uint32_t HELPER(retw)(uint32_t pc) +uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc) { int n = (env->regs[0] >> 30) & 0x3; int m = 0; @@ -319,13 +312,13 @@ uint32_t HELPER(retw)(uint32_t pc) 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); + HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE); } else { int owb = windowbase; ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff); - rotate_window(-n); + rotate_window(env, -n); if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) { env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env); } else { @@ -335,38 +328,38 @@ uint32_t HELPER(retw)(uint32_t pc) env->sregs[EPC1] = env->pc = pc; if (n == 1) { - HELPER(exception)(EXC_WINDOW_UNDERFLOW4); + HELPER(exception)(env, EXC_WINDOW_UNDERFLOW4); } else if (n == 2) { - HELPER(exception)(EXC_WINDOW_UNDERFLOW8); + HELPER(exception)(env, EXC_WINDOW_UNDERFLOW8); } else if (n == 3) { - HELPER(exception)(EXC_WINDOW_UNDERFLOW12); + HELPER(exception)(env, EXC_WINDOW_UNDERFLOW12); } } } return ret_pc; } -void HELPER(rotw)(uint32_t imm4) +void HELPER(rotw)(CPUXtensaState *env, uint32_t imm4) { - rotate_window(imm4); + rotate_window(env, imm4); } -void HELPER(restore_owb)(void) +void HELPER(restore_owb)(CPUXtensaState *env) { - rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT); + rotate_window_abs(env, (env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT); } -void HELPER(movsp)(uint32_t pc) +void HELPER(movsp)(CPUXtensaState *env, 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); + HELPER(exception_cause)(env, pc, ALLOCA_CAUSE); } } -void HELPER(wsr_lbeg)(uint32_t v) +void HELPER(wsr_lbeg)(CPUXtensaState *env, uint32_t v) { if (env->sregs[LBEG] != v) { tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1); @@ -374,7 +367,7 @@ void HELPER(wsr_lbeg)(uint32_t v) } } -void HELPER(wsr_lend)(uint32_t v) +void HELPER(wsr_lend)(CPUXtensaState *env, uint32_t v) { if (env->sregs[LEND] != v) { tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1); @@ -383,12 +376,12 @@ void HELPER(wsr_lend)(uint32_t v) } } -void HELPER(dump_state)(void) +void HELPER(dump_state)(CPUXtensaState *env) { cpu_dump_state(env, stderr, fprintf, 0); } -void HELPER(waiti)(uint32_t pc, uint32_t intlevel) +void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel) { env->pc = pc; env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | @@ -404,15 +397,15 @@ void HELPER(waiti)(uint32_t pc, uint32_t intlevel) if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { xtensa_rearm_ccompare_timer(env); } - HELPER(exception)(EXCP_HLT); + HELPER(exception)(env, EXCP_HLT); } -void HELPER(timer_irq)(uint32_t id, uint32_t active) +void HELPER(timer_irq)(CPUXtensaState *env, uint32_t id, uint32_t active) { xtensa_timer_irq(env, id, active); } -void HELPER(advance_ccount)(uint32_t d) +void HELPER(advance_ccount)(CPUXtensaState *env, uint32_t d) { xtensa_advance_ccount(env, d); } @@ -422,7 +415,7 @@ void HELPER(check_interrupts)(CPUXtensaState *env) check_interrupts(env); } -void HELPER(wsr_rasid)(uint32_t v) +void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v) { v = (v & 0xffffff00) | 0x1; if (v != env->sregs[RASID]) { @@ -574,7 +567,7 @@ void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb, * 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, +static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb, uint32_t *vpn, uint32_t *wi, uint32_t *ei) { if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { @@ -587,41 +580,42 @@ static void split_tlb_entry_spec(uint32_t v, bool dtlb, } } -static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi) +static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env, + 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); + split_tlb_entry_spec(env, 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) +uint32_t HELPER(rtlb0)(CPUXtensaState *env, 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); + const xtensa_tlb_entry *entry = get_tlb_entry(env, 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) +uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) { - const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, NULL); + const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL); return entry->paddr | entry->attr; } -void HELPER(itlb)(uint32_t v, uint32_t dtlb) +void HELPER(itlb)(CPUXtensaState *env, 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); + xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi); if (entry->variable && entry->asid) { tlb_flush_page(env, entry->vaddr); entry->asid = 0; @@ -629,7 +623,7 @@ void HELPER(itlb)(uint32_t v, uint32_t dtlb) } } -uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb) +uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) { if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { uint32_t wi; @@ -646,7 +640,7 @@ uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb) case INST_TLB_MULTI_HIT_CAUSE: case LOAD_STORE_TLB_MULTI_HIT_CAUSE: - HELPER(exception_cause_vaddr)(env->pc, res, v); + HELPER(exception_cause_vaddr)(env, env->pc, res, v); break; } return 0; @@ -655,6 +649,16 @@ uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb) } } +void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env, + xtensa_tlb_entry *entry, bool dtlb, + unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte) +{ + 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; +} + void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte) { @@ -665,10 +669,8 @@ void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, 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; + xtensa_tlb_set_entry_mmu(env, entry, dtlb, wi, ei, vpn, pte); + tlb_flush_page(env, entry->vaddr); } else { qemu_log("%s %d, %d, %d trying to set immutable entry\n", __func__, dtlb, wi, ei); @@ -683,17 +685,17 @@ void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, } } -void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb) +void HELPER(wtlb)(CPUXtensaState *env, 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); + split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei); xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p); } -void HELPER(wsr_ibreakenable)(uint32_t v) +void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v) { uint32_t change = v ^ env->sregs[IBREAKENABLE]; unsigned i; @@ -706,7 +708,7 @@ void HELPER(wsr_ibreakenable)(uint32_t v) env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1); } -void HELPER(wsr_ibreaka)(uint32_t i, uint32_t v) +void HELPER(wsr_ibreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) { if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) { tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]); @@ -715,7 +717,8 @@ void HELPER(wsr_ibreaka)(uint32_t i, uint32_t v) env->sregs[IBREAKA + i] = v; } -static void set_dbreak(unsigned i, uint32_t dbreaka, uint32_t dbreakc) +static void set_dbreak(CPUXtensaState *env, unsigned i, uint32_t dbreaka, + uint32_t dbreakc) { int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; uint32_t mask = dbreakc | ~DBREAKC_MASK; @@ -743,22 +746,22 @@ static void set_dbreak(unsigned i, uint32_t dbreaka, uint32_t dbreakc) } } -void HELPER(wsr_dbreaka)(uint32_t i, uint32_t v) +void HELPER(wsr_dbreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) { uint32_t dbreakc = env->sregs[DBREAKC + i]; if ((dbreakc & DBREAKC_SB_LB) && env->sregs[DBREAKA + i] != v) { - set_dbreak(i, v, dbreakc); + set_dbreak(env, i, v, dbreakc); } env->sregs[DBREAKA + i] = v; } -void HELPER(wsr_dbreakc)(uint32_t i, uint32_t v) +void HELPER(wsr_dbreakc)(CPUXtensaState *env, uint32_t i, uint32_t v) { if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) { if (v & DBREAKC_SB_LB) { - set_dbreak(i, env->sregs[DBREAKA + i], v); + set_dbreak(env, i, env->sregs[DBREAKA + i], v); } else { if (env->cpu_watchpoint[i]) { cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[i]); diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 521c0e6226..b883e6bb72 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -254,7 +254,7 @@ 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); + gen_helper_advance_ccount(cpu_env, tmp); tcg_temp_free(tmp); } } @@ -268,7 +268,7 @@ static void gen_exception(DisasContext *dc, int excp) { TCGv_i32 tmp = tcg_const_i32(excp); gen_advance_ccount(dc); - gen_helper_exception(tmp); + gen_helper_exception(cpu_env, tmp); tcg_temp_free(tmp); } @@ -277,7 +277,7 @@ 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); + gen_helper_exception_cause(cpu_env, tpc, tcause); tcg_temp_free(tpc); tcg_temp_free(tcause); if (cause == ILLEGAL_INSTRUCTION_CAUSE || @@ -292,7 +292,7 @@ static void gen_exception_cause_vaddr(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_vaddr(tpc, tcause, vaddr); + gen_helper_exception_cause_vaddr(cpu_env, tpc, tcause, vaddr); tcg_temp_free(tpc); tcg_temp_free(tcause); } @@ -302,7 +302,7 @@ static void gen_debug_exception(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_debug_exception(tpc, tcause); + gen_helper_debug_exception(cpu_env, tpc, tcause); tcg_temp_free(tpc); tcg_temp_free(tcause); if (cause & (DEBUGCAUSE_IB | DEBUGCAUSE_BI | DEBUGCAUSE_BN)) { @@ -388,6 +388,7 @@ static bool gen_check_loop_end(DisasContext *dc, int slot) dc->next_pc == dc->lend) { int label = gen_new_label(); + gen_advance_ccount(dc); 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); @@ -410,6 +411,7 @@ static void gen_brcond(DisasContext *dc, TCGCond cond, { int label = gen_new_label(); + gen_advance_ccount(dc); tcg_gen_brcond_i32(cond, t0, t1, label); gen_jumpi_check_loop_end(dc, 0); gen_set_label(label); @@ -458,13 +460,13 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s) { - gen_helper_wsr_lbeg(s); + gen_helper_wsr_lbeg(cpu_env, s); gen_jumpi_check_loop_end(dc, 0); } static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s) { - gen_helper_wsr_lend(s); + gen_helper_wsr_lend(cpu_env, s); gen_jumpi_check_loop_end(dc, 0); } @@ -497,7 +499,7 @@ static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s) static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v) { - gen_helper_wsr_windowbase(v); + gen_helper_wsr_windowbase(cpu_env, v); reset_used_window(dc); } @@ -514,7 +516,7 @@ static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v) static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v) { - gen_helper_wsr_rasid(v); + gen_helper_wsr_rasid(cpu_env, v); /* This can change tb->flags, so exit tb */ gen_jumpi_check_loop_end(dc, -1); } @@ -526,7 +528,7 @@ static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v) static void gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) { - gen_helper_wsr_ibreakenable(v); + gen_helper_wsr_ibreakenable(cpu_env, v); gen_jumpi_check_loop_end(dc, 0); } @@ -536,7 +538,7 @@ static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) if (id < dc->config->nibreak) { TCGv_i32 tmp = tcg_const_i32(id); - gen_helper_wsr_ibreaka(tmp, v); + gen_helper_wsr_ibreaka(cpu_env, tmp, v); tcg_temp_free(tmp); gen_jumpi_check_loop_end(dc, 0); } @@ -548,7 +550,7 @@ static void gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) if (id < dc->config->ndbreak) { TCGv_i32 tmp = tcg_const_i32(id); - gen_helper_wsr_dbreaka(tmp, v); + gen_helper_wsr_dbreaka(cpu_env, tmp, v); tcg_temp_free(tmp); } } @@ -559,7 +561,7 @@ static void gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v) if (id < dc->config->ndbreak) { TCGv_i32 tmp = tcg_const_i32(id); - gen_helper_wsr_dbreakc(tmp, v); + gen_helper_wsr_dbreakc(cpu_env, tmp, v); tcg_temp_free(tmp); } } @@ -712,7 +714,7 @@ 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); + gen_helper_waiti(cpu_env, pc, intlevel); tcg_temp_free(pc); tcg_temp_free(intlevel); } @@ -729,7 +731,7 @@ static void gen_window_check1(DisasContext *dc, unsigned r1) dc->used_window = r1 / 4; gen_advance_ccount(dc); - gen_helper_window_check(pc, w); + gen_helper_window_check(cpu_env, pc, w); tcg_temp_free(w); tcg_temp_free(pc); @@ -849,8 +851,8 @@ static void disas_xtensa_insn(DisasContext *dc) #define RSR_SR (b1) - uint8_t b0 = ldub_code(dc->pc); - uint8_t b1 = ldub_code(dc->pc + 1); + uint8_t b0 = cpu_ldub_code(cpu_single_env, dc->pc); + uint8_t b1 = cpu_ldub_code(cpu_single_env, dc->pc + 1); uint8_t b2 = 0; static const uint32_t B4CONST[] = { @@ -866,7 +868,7 @@ static void disas_xtensa_insn(DisasContext *dc) HAS_OPTION(XTENSA_OPTION_CODE_DENSITY); } else { dc->next_pc = dc->pc + 3; - b2 = ldub_code(dc->pc + 2); + b2 = cpu_ldub_code(cpu_single_env, dc->pc + 2); } switch (OP0) { @@ -903,7 +905,7 @@ static void disas_xtensa_insn(DisasContext *dc) { TCGv_i32 tmp = tcg_const_i32(dc->pc); gen_advance_ccount(dc); - gen_helper_retw(tmp, tmp); + gen_helper_retw(tmp, cpu_env, tmp); gen_jump(dc, tmp); tcg_temp_free(tmp); } @@ -951,7 +953,7 @@ static void disas_xtensa_insn(DisasContext *dc) { TCGv_i32 pc = tcg_const_i32(dc->pc); gen_advance_ccount(dc); - gen_helper_movsp(pc); + gen_helper_movsp(cpu_env, pc); tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]); tcg_temp_free(pc); } @@ -1031,7 +1033,7 @@ static void disas_xtensa_insn(DisasContext *dc) cpu_SR[WINDOW_START], tmp); } - gen_helper_restore_owb(); + gen_helper_restore_owb(cpu_env); gen_helper_check_interrupts(cpu_env); gen_jump(dc, cpu_SR[EPC1]); @@ -1219,7 +1221,7 @@ static void disas_xtensa_insn(DisasContext *dc) { TCGv_i32 tmp = tcg_const_i32( RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0)); - gen_helper_rotw(tmp); + gen_helper_rotw(cpu_env, tmp); tcg_temp_free(tmp); reset_used_window(dc); } @@ -1255,28 +1257,32 @@ static void disas_xtensa_insn(DisasContext *dc) switch (RRR_R & 7) { case 3: /*RITLB0*/ /*RDTLB0*/ - gen_helper_rtlb0(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); + gen_helper_rtlb0(cpu_R[RRR_T], + cpu_env, cpu_R[RRR_S], dtlb); break; case 4: /*IITLB*/ /*IDTLB*/ - gen_helper_itlb(cpu_R[RRR_S], dtlb); + gen_helper_itlb(cpu_env, 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); + gen_helper_ptlb(cpu_R[RRR_T], + cpu_env, cpu_R[RRR_S], dtlb); break; case 6: /*WITLB*/ /*WDTLB*/ - gen_helper_wtlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb); + gen_helper_wtlb( + cpu_env, 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); + gen_helper_rtlb1(cpu_R[RRR_T], + cpu_env, cpu_R[RRR_S], dtlb); break; default: @@ -2244,7 +2250,7 @@ static void disas_xtensa_insn(DisasContext *dc) 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); + gen_helper_entry(cpu_env, pc, s, imm); tcg_temp_free(imm); tcg_temp_free(s); tcg_temp_free(pc); @@ -2278,7 +2284,7 @@ static void disas_xtensa_insn(DisasContext *dc) tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1); tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc); - gen_helper_wsr_lend(tmp); + gen_helper_wsr_lend(cpu_env, tmp); tcg_temp_free(tmp); if (BRI8_R > 8) { @@ -2447,7 +2453,7 @@ static void disas_xtensa_insn(DisasContext *dc) { TCGv_i32 tmp = tcg_const_i32(dc->pc); gen_advance_ccount(dc); - gen_helper_retw(tmp, tmp); + gen_helper_retw(tmp, cpu_env, tmp); gen_jump(dc, tmp); tcg_temp_free(tmp); } diff --git a/xtensa-semi.c b/target-xtensa/xtensa-semi.c index b7c8c34564..1c8a19ed56 100644 --- a/xtensa-semi.c +++ b/target-xtensa/xtensa-semi.c @@ -30,7 +30,6 @@ #include <string.h> #include <stddef.h> #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" #include "qemu-log.h" diff --git a/tests/Makefile b/tests/Makefile index ab7f667009..d66ab196a7 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -13,6 +13,7 @@ check-unit-y += tests/test-qmp-commands$(EXESUF) check-unit-y += tests/test-string-input-visitor$(EXESUF) check-unit-y += tests/test-string-output-visitor$(EXESUF) check-unit-y += tests/test-coroutine$(EXESUF) +check-unit-y += tests/test-visitor-serialization$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -31,13 +32,12 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-coroutine.o tests/test-string-output-visitor.o \ tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ - tests/test-qmp-commands.o + tests/test-qmp-commands.o tests/test-visitor-serialization.o test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o test-qapi-obj-y += module.o -$(test-obj-y): $(GENERATED_HEADERS) $(test-obj-y): QEMU_INCLUDES += -Itests tests/check-qint$(EXESUF): tests/check-qint.o qint.o $(tools-obj-y) @@ -65,6 +65,7 @@ tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-q tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) +tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) diff --git a/tests/tcg/xtensa/test_mmu.S b/tests/tcg/xtensa/test_mmu.S index 52d5774212..5d87fbb703 100644 --- a/tests/tcg/xtensa/test_mmu.S +++ b/tests/tcg/xtensa/test_mmu.S @@ -293,26 +293,219 @@ test store_prohibited assert eq, a2, a3 test_end -test dtlb_autoload - set_vector kernel, 0 - - movi a2, 0xd4000000 +/* Set up page table entry vaddr->paddr, ring=pte_ring, attr=pte_attr + * and DTLB way 7 to cover this PTE, ring=pt_ring, attr=pt_attr + */ +.macro pt_setup pt_ring, pt_attr, pte_ring, vaddr, paddr, pte_attr + movi a2, 0x80000000 wsr a2, ptevaddr - movi a3, 0x00001013 - s32i a3, a2, 4 + + movi a3, 0x80000007 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */ + movi a4, 0x04000003 | ((\pt_ring) << 4) /* PADDR 64M */ + wdtlb a4, a3 + isync + + movi a3, ((\paddr) & 0xfffff000) | ((\pte_ring) << 4) | (\pte_attr) + movi a1, ((\vaddr) >> 12) << 2 + add a2, a1, a2 + s32i a3, a2, 0 + + movi a3, 0x80000007 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */ + movi a4, 0x04000000 | ((\pt_ring) << 4) | (\pt_attr) /* PADDR 64M */ + wdtlb a4, a3 + isync + + movi a3, (\vaddr) +.endm + +/* out: PS.RING=ring, PS.EXCM=excm, a3=vaddr */ +.macro go_ring ring, excm, vaddr + 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, 0 + wsr a2, excvaddr + + movi a3, \vaddr + movi a2, 0x4000f | ((\ring) << 6) | ((\excm) << 4) + jx a1 +10: + wsr a2, ps + isync +.endm + +/* in: a3 -- virtual address to test */ +.macro assert_auto_tlb + movi a2, 0x4000f + wsr a2, ps + isync + pdtlb a2, a3 + movi a1, 0xfffff01f + and a2, a2, a1 + movi a1, 0xfffff000 + and a1, a1, a3 + xor a1, a1, a2 + assert gei, a1, 0x10 + movi a2, 0x14 + assert lt, a1, a2 +.endm + +/* in: a3 -- virtual address to test */ +.macro assert_no_auto_tlb + movi a2, 0x4000f + wsr a2, ps + isync 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 +.endm + +.macro assert_sr sr, v + rsr a2, \sr + movi a1, (\v) + assert eq, a1, a2 +.endm + +.macro assert_epc1_1m vaddr + movi a2, (\vaddr) + movi a1, 0xfffff and a1, a1, a2 - assert lti, a1, 4 + rsr a2, epc1 + assert eq, a1, a2 +.endm + +test dtlb_autoload + set_vector kernel, 0 + + pt_setup 0, 3, 1, 0x1000, 0x1000, 3 + assert_no_auto_tlb + + l8ui a1, a3, 0 + + rsr a2, excvaddr + assert eq, a2, a3 + + assert_auto_tlb +test_end + +test autoload_load_store_privilege + set_vector kernel, 0 + set_vector double, 2f + + pt_setup 0, 3, 0, 0x2000, 0x2000, 3 + movi a3, 0x2004 + assert_no_auto_tlb + + movi a2, 0x4005f /* ring 1 + excm => cring == 0 */ + wsr a2, ps + isync +1: + l32e a2, a3, -4 /* ring used */ + test_fail +2: + rsr a2, excvaddr + addi a1, a3, -4 + assert eq, a1, a2 + + assert_auto_tlb + assert_sr depc, 1b + assert_sr exccause, 26 +test_end + +test autoload_pte_load_prohibited + set_vector kernel, 2f + + pt_setup 0, 3, 0, 0x3000, 0, 0xc + assert_no_auto_tlb +1: + l32i a2, a3, 0 + test_fail +2: + rsr a2, excvaddr + assert eq, a2, a3 + + assert_auto_tlb + assert_sr epc1, 1b + assert_sr exccause, 28 +test_end + +test autoload_pt_load_prohibited + set_vector kernel, 2f + + pt_setup 0, 0xc, 0, 0x4000, 0x4000, 3 + assert_no_auto_tlb +1: + l32i a2, a3, 0 + test_fail +2: + rsr a2, excvaddr + assert eq, a2, a3 + + assert_no_auto_tlb + assert_sr epc1, 1b + assert_sr exccause, 24 +test_end + +test autoload_pt_privilege + set_vector kernel, 2f + pt_setup 0, 3, 1, 0x5000, 0, 3 + go_ring 1, 0, 0x5001 + + l8ui a2, a3, 0 +1: + syscall +2: + rsr a2, excvaddr + assert eq, a2, a3 + + assert_auto_tlb + assert_epc1_1m 1b + assert_sr exccause, 1 +test_end + +test autoload_pte_privilege + set_vector kernel, 2f + pt_setup 0, 3, 0, 0x6000, 0, 3 + go_ring 1, 0, 0x6001 +1: + l8ui a2, a3, 0 + syscall +2: + rsr a2, excvaddr + assert eq, a2, a3 + + assert_auto_tlb + assert_epc1_1m 1b + assert_sr exccause, 26 +test_end + +test autoload_3_level_pt + set_vector kernel, 2f + pt_setup 1, 3, 1, 0x00400000, 0, 3 + pt_setup 1, 3, 1, 0x80001000, 0x2000000, 3 + go_ring 1, 0, 0x00400001 +1: + l8ui a2, a3, 0 + syscall +2: + rsr a2, excvaddr + assert eq, a2, a3 + + assert_no_auto_tlb + assert_epc1_1m 1b + assert_sr exccause, 24 test_end test_suite_end diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 22909b84ef..608f14a5de 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -84,7 +84,7 @@ static void test_visitor_out_number(TestOutputVisitorData *data, str = string_output_get_string(data->sov); g_assert(str != NULL); - g_assert_cmpstr(str, ==, "3.14"); + g_assert_cmpstr(str, ==, "3.140000"); g_free(str); } diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c new file mode 100644 index 0000000000..b8ad16fc9e --- /dev/null +++ b/tests/test-visitor-serialization.c @@ -0,0 +1,784 @@ +/* + * Unit-tests for visitor-based serialization + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Michael Roth <mdroth@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <stdlib.h> +#include <stdint.h> +#include <float.h> +#include "test-qapi-types.h" +#include "test-qapi-visit.h" +#include "qemu-objects.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/qmp-output-visitor.h" +#include "qapi/string-input-visitor.h" +#include "qapi/string-output-visitor.h" + +typedef struct PrimitiveType { + union { + const char *string; + bool boolean; + double number; + int64_t integer; + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + int8_t s8; + int16_t s16; + int32_t s32; + int64_t s64; + intmax_t max; + } value; + enum { + PTYPE_STRING = 0, + PTYPE_BOOLEAN, + PTYPE_NUMBER, + PTYPE_INTEGER, + PTYPE_U8, + PTYPE_U16, + PTYPE_U32, + PTYPE_U64, + PTYPE_S8, + PTYPE_S16, + PTYPE_S32, + PTYPE_S64, + PTYPE_EOL, + } type; + const char *description; +} PrimitiveType; + +/* test helpers */ + +static void visit_primitive_type(Visitor *v, void **native, Error **errp) +{ + PrimitiveType *pt = *native; + switch(pt->type) { + case PTYPE_STRING: + visit_type_str(v, (char **)&pt->value.string, NULL, errp); + break; + case PTYPE_BOOLEAN: + visit_type_bool(v, &pt->value.boolean, NULL, errp); + break; + case PTYPE_NUMBER: + visit_type_number(v, &pt->value.number, NULL, errp); + break; + case PTYPE_INTEGER: + visit_type_int(v, &pt->value.integer, NULL, errp); + break; + case PTYPE_U8: + visit_type_uint8(v, &pt->value.u8, NULL, errp); + break; + case PTYPE_U16: + visit_type_uint16(v, &pt->value.u16, NULL, errp); + break; + case PTYPE_U32: + visit_type_uint32(v, &pt->value.u32, NULL, errp); + break; + case PTYPE_U64: + visit_type_uint64(v, &pt->value.u64, NULL, errp); + break; + case PTYPE_S8: + visit_type_int8(v, &pt->value.s8, NULL, errp); + break; + case PTYPE_S16: + visit_type_int16(v, &pt->value.s16, NULL, errp); + break; + case PTYPE_S32: + visit_type_int32(v, &pt->value.s32, NULL, errp); + break; + case PTYPE_S64: + visit_type_int64(v, &pt->value.s64, NULL, errp); + break; + case PTYPE_EOL: + g_assert(false); + } +} + +typedef struct TestStruct +{ + int64_t integer; + bool boolean; + char *string; +} TestStruct; + +static void visit_type_TestStruct(Visitor *v, TestStruct **obj, + const char *name, Error **errp) +{ + visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), errp); + + visit_type_int(v, &(*obj)->integer, "integer", errp); + visit_type_bool(v, &(*obj)->boolean, "boolean", errp); + visit_type_str(v, &(*obj)->string, "string", errp); + + visit_end_struct(v, errp); +} + +static TestStruct *struct_create(void) +{ + TestStruct *ts = g_malloc0(sizeof(*ts)); + ts->integer = -42; + ts->boolean = true; + ts->string = strdup("test string"); + return ts; +} + +static void struct_compare(TestStruct *ts1, TestStruct *ts2) +{ + g_assert(ts1); + g_assert(ts2); + g_assert_cmpint(ts1->integer, ==, ts2->integer); + g_assert(ts1->boolean == ts2->boolean); + g_assert_cmpstr(ts1->string, ==, ts2->string); +} + +static void struct_cleanup(TestStruct *ts) +{ + g_free(ts->string); + g_free(ts); +} + +static void visit_struct(Visitor *v, void **native, Error **errp) +{ + visit_type_TestStruct(v, (TestStruct **)native, NULL, errp); +} + +static UserDefNested *nested_struct_create(void) +{ + UserDefNested *udnp = g_malloc0(sizeof(*udnp)); + udnp->string0 = strdup("test_string0"); + udnp->dict1.string1 = strdup("test_string1"); + udnp->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne)); + udnp->dict1.dict2.userdef1->integer = 42; + udnp->dict1.dict2.userdef1->string = strdup("test_string"); + udnp->dict1.dict2.string2 = strdup("test_string2"); + udnp->dict1.has_dict3 = true; + udnp->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne)); + udnp->dict1.dict3.userdef2->integer = 43; + udnp->dict1.dict3.userdef2->string = strdup("test_string"); + udnp->dict1.dict3.string3 = strdup("test_string3"); + return udnp; +} + +static void nested_struct_compare(UserDefNested *udnp1, UserDefNested *udnp2) +{ + g_assert(udnp1); + g_assert(udnp2); + g_assert_cmpstr(udnp1->string0, ==, udnp2->string0); + g_assert_cmpstr(udnp1->dict1.string1, ==, udnp2->dict1.string1); + g_assert_cmpint(udnp1->dict1.dict2.userdef1->integer, ==, + udnp2->dict1.dict2.userdef1->integer); + g_assert_cmpstr(udnp1->dict1.dict2.userdef1->string, ==, + udnp2->dict1.dict2.userdef1->string); + g_assert_cmpstr(udnp1->dict1.dict2.string2, ==, udnp2->dict1.dict2.string2); + g_assert(udnp1->dict1.has_dict3 == udnp2->dict1.has_dict3); + g_assert_cmpint(udnp1->dict1.dict3.userdef2->integer, ==, + udnp2->dict1.dict3.userdef2->integer); + g_assert_cmpstr(udnp1->dict1.dict3.userdef2->string, ==, + udnp2->dict1.dict3.userdef2->string); + g_assert_cmpstr(udnp1->dict1.dict3.string3, ==, udnp2->dict1.dict3.string3); +} + +static void nested_struct_cleanup(UserDefNested *udnp) +{ + qapi_free_UserDefNested(udnp); +} + +static void visit_nested_struct(Visitor *v, void **native, Error **errp) +{ + visit_type_UserDefNested(v, (UserDefNested **)native, NULL, errp); +} + +static void visit_nested_struct_list(Visitor *v, void **native, Error **errp) +{ + visit_type_UserDefNestedList(v, (UserDefNestedList **)native, NULL, errp); +} + +/* test cases */ + +typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp); + +typedef enum VisitorCapabilities { + VCAP_PRIMITIVES = 1, + VCAP_STRUCTURES = 2, + VCAP_LISTS = 4, +} VisitorCapabilities; + +typedef struct SerializeOps { + void (*serialize)(void *native_in, void **datap, + VisitorFunc visit, Error **errp); + void (*deserialize)(void **native_out, void *datap, + VisitorFunc visit, Error **errp); + void (*cleanup)(void *datap); + const char *type; + VisitorCapabilities caps; +} SerializeOps; + +typedef struct TestArgs { + const SerializeOps *ops; + void *test_data; +} TestArgs; + +#define FLOAT_STRING_PRECISION 6 /* corresponding to n in %.nf formatting */ +static gsize calc_float_string_storage(double value) +{ + int whole_value = value; + gsize i = 0; + do { + i++; + } while (whole_value /= 10); + return i + 2 + FLOAT_STRING_PRECISION; +} + +static void test_primitives(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + PrimitiveType *pt = args->test_data; + PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy)); + Error *err = NULL; + void *serialize_data; + char *double1, *double2; + + pt_copy->type = pt->type; + ops->serialize(pt, &serialize_data, visit_primitive_type, &err); + ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, &err); + + g_assert(err == NULL); + g_assert(pt_copy != NULL); + if (pt->type == PTYPE_STRING) { + g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string); + } else if (pt->type == PTYPE_NUMBER) { + /* we serialize with %f for our reference visitors, so rather than fuzzy + * floating math to test "equality", just compare the formatted values + */ + double1 = g_malloc0(calc_float_string_storage(pt->value.number)); + double2 = g_malloc0(calc_float_string_storage(pt_copy->value.number)); + g_assert_cmpstr(double1, ==, double2); + g_free(double1); + g_free(double2); + } else if (pt->type == PTYPE_BOOLEAN) { + g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max); + } else { + g_assert_cmpint(pt->value.max, ==, pt_copy->value.max); + } + + ops->cleanup(serialize_data); + g_free(args); +} + +static void test_struct(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + TestStruct *ts = struct_create(); + TestStruct *ts_copy = NULL; + Error *err = NULL; + void *serialize_data; + + ops->serialize(ts, &serialize_data, visit_struct, &err); + ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, &err); + + g_assert(err == NULL); + struct_compare(ts, ts_copy); + + struct_cleanup(ts); + struct_cleanup(ts_copy); + + ops->cleanup(serialize_data); + g_free(args); +} + +static void test_nested_struct(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + UserDefNested *udnp = nested_struct_create(); + UserDefNested *udnp_copy = NULL; + Error *err = NULL; + void *serialize_data; + + ops->serialize(udnp, &serialize_data, visit_nested_struct, &err); + ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct, &err); + + g_assert(err == NULL); + nested_struct_compare(udnp, udnp_copy); + + nested_struct_cleanup(udnp); + nested_struct_cleanup(udnp_copy); + + ops->cleanup(serialize_data); + g_free(args); +} + +static void test_nested_struct_list(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + UserDefNestedList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL; + Error *err = NULL; + void *serialize_data; + int i = 0; + + for (i = 0; i < 8; i++) { + tmp = g_malloc0(sizeof(UserDefNestedList)); + tmp->value = nested_struct_create(); + tmp->next = listp; + listp = tmp; + } + + ops->serialize(listp, &serialize_data, visit_nested_struct_list, &err); + ops->deserialize((void **)&listp_copy, serialize_data, + visit_nested_struct_list, &err); + + g_assert(err == NULL); + + tmp = listp; + tmp_copy = listp_copy; + while (listp_copy) { + g_assert(listp); + nested_struct_compare(listp->value, listp_copy->value); + listp = listp->next; + listp_copy = listp_copy->next; + } + + qapi_free_UserDefNestedList(tmp); + qapi_free_UserDefNestedList(tmp_copy); + + ops->cleanup(serialize_data); + g_free(args); +} + +PrimitiveType pt_values[] = { + /* string tests */ + { + .description = "string_empty", + .type = PTYPE_STRING, + .value.string = "", + }, + { + .description = "string_whitespace", + .type = PTYPE_STRING, + .value.string = "a b c\td", + }, + { + .description = "string_newlines", + .type = PTYPE_STRING, + .value.string = "a\nb\n", + }, + { + .description = "string_commas", + .type = PTYPE_STRING, + .value.string = "a,b, c,d", + }, + { + .description = "string_single_quoted", + .type = PTYPE_STRING, + .value.string = "'a b',cd", + }, + { + .description = "string_double_quoted", + .type = PTYPE_STRING, + .value.string = "\"a b\",cd", + }, + /* boolean tests */ + { + .description = "boolean_true1", + .type = PTYPE_BOOLEAN, + .value.boolean = true, + }, + { + .description = "boolean_true2", + .type = PTYPE_BOOLEAN, + .value.boolean = 8, + }, + { + .description = "boolean_true3", + .type = PTYPE_BOOLEAN, + .value.boolean = -1, + }, + { + .description = "boolean_false1", + .type = PTYPE_BOOLEAN, + .value.boolean = false, + }, + { + .description = "boolean_false2", + .type = PTYPE_BOOLEAN, + .value.boolean = 0, + }, + /* number tests (double) */ + /* note: we format these to %.6f before comparing, since that's how + * we serialize them and it doesn't make sense to check precision + * beyond that. + */ + { + .description = "number_sanity1", + .type = PTYPE_NUMBER, + .value.number = -1, + }, + { + .description = "number_sanity2", + .type = PTYPE_NUMBER, + .value.number = 3.14159265, + }, + { + .description = "number_min", + .type = PTYPE_NUMBER, + .value.number = DBL_MIN, + }, + { + .description = "number_max", + .type = PTYPE_NUMBER, + .value.number = DBL_MAX, + }, + /* integer tests (int64) */ + { + .description = "integer_sanity1", + .type = PTYPE_INTEGER, + .value.integer = -1, + }, + { + .description = "integer_sanity2", + .type = PTYPE_INTEGER, + .value.integer = INT64_MAX / 2 + 1, + }, + { + .description = "integer_min", + .type = PTYPE_INTEGER, + .value.integer = INT64_MIN, + }, + { + .description = "integer_max", + .type = PTYPE_INTEGER, + .value.integer = INT64_MAX, + }, + /* uint8 tests */ + { + .description = "uint8_sanity1", + .type = PTYPE_U8, + .value.u8 = 1, + }, + { + .description = "uint8_sanity2", + .type = PTYPE_U8, + .value.u8 = UINT8_MAX / 2 + 1, + }, + { + .description = "uint8_min", + .type = PTYPE_U8, + .value.u8 = 0, + }, + { + .description = "uint8_max", + .type = PTYPE_U8, + .value.u8 = UINT8_MAX, + }, + /* uint16 tests */ + { + .description = "uint16_sanity1", + .type = PTYPE_U16, + .value.u16 = 1, + }, + { + .description = "uint16_sanity2", + .type = PTYPE_U16, + .value.u16 = UINT16_MAX / 2 + 1, + }, + { + .description = "uint16_min", + .type = PTYPE_U16, + .value.u16 = 0, + }, + { + .description = "uint16_max", + .type = PTYPE_U16, + .value.u16 = UINT16_MAX, + }, + /* uint32 tests */ + { + .description = "uint32_sanity1", + .type = PTYPE_U32, + .value.u32 = 1, + }, + { + .description = "uint32_sanity2", + .type = PTYPE_U32, + .value.u32 = UINT32_MAX / 2 + 1, + }, + { + .description = "uint32_min", + .type = PTYPE_U32, + .value.u32 = 0, + }, + { + .description = "uint32_max", + .type = PTYPE_U32, + .value.u32 = UINT32_MAX, + }, + /* uint64 tests */ + { + .description = "uint64_sanity1", + .type = PTYPE_U64, + .value.u64 = 1, + }, + { + .description = "uint64_sanity2", + .type = PTYPE_U64, + .value.u64 = UINT64_MAX / 2 + 1, + }, + { + .description = "uint64_min", + .type = PTYPE_U64, + .value.u64 = 0, + }, + { + .description = "uint64_max", + .type = PTYPE_U64, + .value.u64 = UINT64_MAX, + }, + /* int8 tests */ + { + .description = "int8_sanity1", + .type = PTYPE_S8, + .value.s8 = -1, + }, + { + .description = "int8_sanity2", + .type = PTYPE_S8, + .value.s8 = INT8_MAX / 2 + 1, + }, + { + .description = "int8_min", + .type = PTYPE_S8, + .value.s8 = INT8_MIN, + }, + { + .description = "int8_max", + .type = PTYPE_S8, + .value.s8 = INT8_MAX, + }, + /* int16 tests */ + { + .description = "int16_sanity1", + .type = PTYPE_S16, + .value.s16 = -1, + }, + { + .description = "int16_sanity2", + .type = PTYPE_S16, + .value.s16 = INT16_MAX / 2 + 1, + }, + { + .description = "int16_min", + .type = PTYPE_S16, + .value.s16 = INT16_MIN, + }, + { + .description = "int16_max", + .type = PTYPE_S16, + .value.s16 = INT16_MAX, + }, + /* int32 tests */ + { + .description = "int32_sanity1", + .type = PTYPE_S32, + .value.s32 = -1, + }, + { + .description = "int32_sanity2", + .type = PTYPE_S32, + .value.s32 = INT32_MAX / 2 + 1, + }, + { + .description = "int32_min", + .type = PTYPE_S32, + .value.s32 = INT32_MIN, + }, + { + .description = "int32_max", + .type = PTYPE_S32, + .value.s32 = INT32_MAX, + }, + /* int64 tests */ + { + .description = "int64_sanity1", + .type = PTYPE_S64, + .value.s64 = -1, + }, + { + .description = "int64_sanity2", + .type = PTYPE_S64, + .value.s64 = INT64_MAX / 2 + 1, + }, + { + .description = "int64_min", + .type = PTYPE_S64, + .value.s64 = INT64_MIN, + }, + { + .description = "int64_max", + .type = PTYPE_S64, + .value.s64 = INT64_MAX, + }, + { .type = PTYPE_EOL } +}; + +/* visitor-specific op implementations */ + +typedef struct QmpSerializeData { + QmpOutputVisitor *qov; + QmpInputVisitor *qiv; +} QmpSerializeData; + +static void qmp_serialize(void *native_in, void **datap, + VisitorFunc visit, Error **errp) +{ + QmpSerializeData *d = g_malloc0(sizeof(*d)); + + d->qov = qmp_output_visitor_new(); + visit(qmp_output_get_visitor(d->qov), &native_in, errp); + *datap = d; +} + +static void qmp_deserialize(void **native_out, void *datap, + VisitorFunc visit, Error **errp) +{ + QmpSerializeData *d = datap; + QString *output_json = qobject_to_json(qmp_output_get_qobject(d->qov)); + QObject *obj = qobject_from_json(qstring_get_str(output_json)); + + QDECREF(output_json); + d->qiv = qmp_input_visitor_new(obj); + visit(qmp_input_get_visitor(d->qiv), native_out, errp); +} + +static void qmp_cleanup(void *datap) +{ + QmpSerializeData *d = datap; + qmp_output_visitor_cleanup(d->qov); + qmp_input_visitor_cleanup(d->qiv); +} + +typedef struct StringSerializeData { + StringOutputVisitor *sov; + StringInputVisitor *siv; +} StringSerializeData; + +static void string_serialize(void *native_in, void **datap, + VisitorFunc visit, Error **errp) +{ + StringSerializeData *d = g_malloc0(sizeof(*d)); + + d->sov = string_output_visitor_new(); + visit(string_output_get_visitor(d->sov), &native_in, errp); + *datap = d; +} + +static void string_deserialize(void **native_out, void *datap, + VisitorFunc visit, Error **errp) +{ + StringSerializeData *d = datap; + + d->siv = string_input_visitor_new(string_output_get_string(d->sov)); + visit(string_input_get_visitor(d->siv), native_out, errp); +} + +static void string_cleanup(void *datap) +{ + StringSerializeData *d = datap; + string_output_visitor_cleanup(d->sov); + string_input_visitor_cleanup(d->siv); +} + +/* visitor registration, test harness */ + +/* note: to function interchangeably as a serialization mechanism your + * visitor test implementation should pass the test cases for all visitor + * capabilities: primitives, structures, and lists + */ +static const SerializeOps visitors[] = { + { + .type = "QMP", + .serialize = qmp_serialize, + .deserialize = qmp_deserialize, + .cleanup = qmp_cleanup, + .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS + }, + { + .type = "String", + .serialize = string_serialize, + .deserialize = string_deserialize, + .cleanup = string_cleanup, + .caps = VCAP_PRIMITIVES + }, + { NULL } +}; + +static void add_visitor_type(const SerializeOps *ops) +{ + char testname_prefix[128]; + char testname[128]; + TestArgs *args; + int i = 0; + + sprintf(testname_prefix, "/visitor/serialization/%s", ops->type); + + if (ops->caps & VCAP_PRIMITIVES) { + while (pt_values[i].type != PTYPE_EOL) { + sprintf(testname, "%s/primitives/%s", testname_prefix, + pt_values[i].description); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = &pt_values[i]; + g_test_add_data_func(testname, args, test_primitives); + i++; + } + } + + if (ops->caps & VCAP_STRUCTURES) { + sprintf(testname, "%s/struct", testname_prefix); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = NULL; + g_test_add_data_func(testname, args, test_struct); + + sprintf(testname, "%s/nested_struct", testname_prefix); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = NULL; + g_test_add_data_func(testname, args, test_nested_struct); + } + + if (ops->caps & VCAP_LISTS) { + sprintf(testname, "%s/nested_struct_list", testname_prefix); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = NULL; + g_test_add_data_func(testname, args, test_nested_struct_list); + } +} + +int main(int argc, char **argv) +{ + int i = 0; + + g_test_init(&argc, &argv, NULL); + + while (visitors[i].type != NULL) { + add_visitor_type(&visitors[i]); + i++; + } + + g_test_run(); + + return 0; +} diff --git a/trace-events b/trace-events index 45c6bc1271..f70523c47e 100644 --- a/trace-events +++ b/trace-events @@ -257,19 +257,20 @@ usb_ehci_port_detach(uint32_t port) "detach port #%d" usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d" usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d" usb_ehci_queue_action(void *q, const char *action) "q %p: %s" +usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s" # hw/usb/hcd-uhci.c usb_uhci_reset(void) "=== RESET ===" usb_uhci_schedule_start(void) "" usb_uhci_schedule_stop(void) "" usb_uhci_frame_start(uint32_t num) "nr %d" +usb_uhci_frame_stop_bandwidth(void) "" usb_uhci_frame_loop_stop_idle(void) "" -usb_uhci_frame_loop_stop_bandwidth(void) "" usb_uhci_frame_loop_continue(void) "" -usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr %04x, ret 0x04%x" -usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr %04x, val 0x04%x" -usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr %04x, ret 0x08%x" -usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr %04x, val 0x08%x" +usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%04x" +usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%04x" +usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%08x" +usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%08x" usb_uhci_queue_add(uint32_t token) "token 0x%x" usb_uhci_queue_del(uint32_t token) "token 0x%x" usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" @@ -289,6 +290,41 @@ usb_uhci_td_nextqh(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" usb_uhci_td_async(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" +# hw/usb/hcd-xhci.c +usb_xhci_reset(void) "=== RESET ===" +usb_xhci_run(void) "" +usb_xhci_stop(void) "" +usb_xhci_cap_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" +usb_xhci_oper_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" +usb_xhci_port_read(uint32_t port, uint32_t off, uint32_t val) "port %d, off 0x%04x, ret 0x%08x" +usb_xhci_runtime_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" +usb_xhci_doorbell_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" +usb_xhci_oper_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" +usb_xhci_port_write(uint32_t port, uint32_t off, uint32_t val) "port %d, off 0x%04x, val 0x%08x" +usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" +usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" +usb_xhci_irq_intx(uint32_t level) "level %d" +usb_xhci_irq_msi(uint32_t nr) "nr %d" +usb_xhci_queue_event(uint32_t idx, const char *name, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, p %016" PRIx64 ", s %08x, c 0x%08x" +usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" +usb_xhci_slot_enable(uint32_t slotid) "slotid %d" +usb_xhci_slot_disable(uint32_t slotid) "slotid %d" +usb_xhci_slot_address(uint32_t slotid) "slotid %d" +usb_xhci_slot_configure(uint32_t slotid) "slotid %d" +usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d" +usb_xhci_slot_reset(uint32_t slotid) "slotid %d" +usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t length) "%p: slotid %d, epid %d, length %d" +usb_xhci_xfer_async(void *xfer) "%p" +usb_xhci_xfer_nak(void *xfer) "%p" +usb_xhci_xfer_retry(void *xfer) "%p" +usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d" +usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d" + # hw/usb/desc.c usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d" usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d" diff --git a/trace/simple.c b/trace/simple.c index 33ae48696d..b4a3c6e950 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -161,8 +161,11 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, } timestamp = get_clock(); - +#if GLIB_CHECK_VERSION(2, 30, 0) + idx = g_atomic_int_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN; +#else idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN; +#endif trace_buf[idx] = (TraceRecord){ .event = event, .timestamp_ns = timestamp, diff --git a/ui/Makefile.objs b/ui/Makefile.objs new file mode 100644 index 0000000000..3687c8a518 --- /dev/null +++ b/ui/Makefile.objs @@ -0,0 +1,18 @@ +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 +vnc-obj-y += vnc-jobs-async.o +else +vnc-obj-y += vnc-jobs-sync.o +endif + +common-obj-y += keymaps.o +common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o +common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o +common-obj-$(CONFIG_COCOA) += cocoa.o +common-obj-$(CONFIG_CURSES) += curses.o +common-obj-$(CONFIG_VNC) += $(vnc-obj-y) @@ -51,14 +51,12 @@ #ifdef CONFIG_BSD #include <sys/stat.h> #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#include <libutil.h> #include <sys/sysctl.h> #else #include <util.h> #endif #else #ifdef __linux__ -#include <pty.h> #include <malloc.h> #include <linux/ppdev.h> @@ -81,10 +79,6 @@ #endif #endif -#if defined(__OpenBSD__) -#include <util.h> -#endif - #if defined(CONFIG_VDE) #include <libvdeplug.h> #endif @@ -1786,7 +1780,7 @@ static int balloon_parse(const char *arg) return -1; } else { /* create empty opts */ - opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0); + opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, NULL); } qemu_opt_set(opts, "driver", "virtio-balloon"); return 0; @@ -1921,7 +1915,7 @@ static void monitor_parse(const char *optarg, const char *mode) } } - opts = qemu_opts_create(qemu_find_opts("mon"), label, 1); + opts = qemu_opts_create(qemu_find_opts("mon"), label, 1, NULL); if (!opts) { fprintf(stderr, "duplicate chardev: %s\n", label); exit(1); @@ -2035,14 +2029,14 @@ static int virtcon_parse(const char *devname) exit(1); } - bus_opts = qemu_opts_create(device, NULL, 0); + bus_opts = qemu_opts_create(device, NULL, 0, NULL); if (arch_type == QEMU_ARCH_S390X) { qemu_opt_set(bus_opts, "driver", "virtio-serial-s390"); } else { qemu_opt_set(bus_opts, "driver", "virtio-serial-pci"); } - dev_opts = qemu_opts_create(device, NULL, 0); + dev_opts = qemu_opts_create(device, NULL, 0, NULL); qemu_opt_set(dev_opts, "driver", "virtconsole"); snprintf(label, sizeof(label), "virtcon%d", index); @@ -2065,7 +2059,7 @@ static int debugcon_parse(const char *devname) if (!qemu_chr_new("debugcon", devname, NULL)) { exit(1); } - opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1); + opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL); if (!opts) { fprintf(stderr, "qemu: already have a debugcon device\n"); exit(1); @@ -2813,7 +2807,8 @@ int main(int argc, char **argv, char **envp) exit(1); } fsdev = qemu_opts_create(qemu_find_opts("fsdev"), - qemu_opt_get(opts, "mount_tag"), 1); + qemu_opt_get(opts, "mount_tag"), + 1, NULL); if (!fsdev) { fprintf(stderr, "duplicate fsdev id: %s\n", qemu_opt_get(opts, "mount_tag")); @@ -2845,7 +2840,8 @@ int main(int argc, char **argv, char **envp) qemu_opt_set_bool(fsdev, "readonly", qemu_opt_get_bool(opts, "readonly", 0)); - device = qemu_opts_create(qemu_find_opts("device"), NULL, 0); + device = qemu_opts_create(qemu_find_opts("device"), NULL, 0, + NULL); qemu_opt_set(device, "driver", "virtio-9p-pci"); qemu_opt_set(device, "fsdev", qemu_opt_get(opts, "mount_tag")); @@ -2857,14 +2853,16 @@ int main(int argc, char **argv, char **envp) QemuOpts *fsdev; QemuOpts *device; - fsdev = qemu_opts_create(qemu_find_opts("fsdev"), "v_synth", 1); + fsdev = qemu_opts_create(qemu_find_opts("fsdev"), "v_synth", + 1, NULL); if (!fsdev) { fprintf(stderr, "duplicate option: %s\n", "virtfs_synth"); exit(1); } qemu_opt_set(fsdev, "fsdriver", "synth"); - device = qemu_opts_create(qemu_find_opts("device"), NULL, 0); + device = qemu_opts_create(qemu_find_opts("device"), NULL, 0, + NULL); qemu_opt_set(device, "driver", "virtio-9p-pci"); qemu_opt_set(device, "fsdev", "v_synth"); qemu_opt_set(device, "mount_tag", "v_synth"); |