diff options
107 files changed, 1848 insertions, 1259 deletions
@@ -39,9 +39,7 @@ /qmp-introspect.[ch] /qmp-marshal.c /qemu-doc.html -/qemu-tech.html /qemu-doc.info -/qemu-tech.info /qemu-img /qemu-nbd /qemu-options.def diff --git a/.travis.yml b/.travis.yml index f30b10e..9916178 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ cache: ccache addons: apt: packages: + # Build dependencies - libaio-dev - libattr1-dev - libbrlapi-dev @@ -89,6 +90,7 @@ matrix: - env: CONFIG="" os: osx compiler: clang + # Plain Trusty Build - env: CONFIG="" sudo: required addons: @@ -99,3 +101,46 @@ matrix: - sudo apt-get build-dep -qq qemu - wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ - git submodule update --init --recursive + # Using newer GCC with sanitizers + - addons: + apt: + sources: + # PPAs for newer toolchains + - ubuntu-toolchain-r-test + packages: + # Extra toolchains + - gcc-5 + - g++-5 + # Build dependencies + - libaio-dev + - libattr1-dev + - libbrlapi-dev + - libcap-ng-dev + - libgnutls-dev + - libgtk-3-dev + - libiscsi-dev + - liblttng-ust-dev + - libnfs-dev + - libncurses5-dev + - libnss3-dev + - libpixman-1-dev + - libpng12-dev + - librados-dev + - libsdl1.2-dev + - libseccomp-dev + - libspice-protocol-dev + - libspice-server-dev + - libssh2-1-dev + - liburcu-dev + - libusb-1.0-0-dev + - libvte-2.90-dev + - sparse + - uuid-dev + language: generic + compiler: none + env: + - COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5 + - CONFIG="--cc=gcc-5 --cxx=g++-5 --disable-pie --disable-linux-user --with-coroutine=gthread" + - TEST_CMD="" + before_script: + - ./configure ${CONFIG} --extra-cflags="-g3 -O0 -fsanitize=thread -fuse-ld=gold" || cat config.log diff --git a/MAINTAINERS b/MAINTAINERS index 5355a5e..a4d2dd4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -620,6 +620,7 @@ S: Maintained F: hw/ppc/mac_oldworld.c F: hw/pci-host/grackle.c F: hw/misc/macio/ +F: hw/intc/heathrow_pic.c PReP L: qemu-devel@nongnu.org @@ -628,6 +629,7 @@ S: Odd Fixes F: hw/ppc/prep.c F: hw/pci-host/prep.[hc] F: hw/isa/pc87312.[hc] +F: pc-bios/ppc_rom.bin sPAPR M: David Gibson <david@gibson.dropbear.id.au> @@ -93,7 +93,7 @@ LIBS+=-lz $(LIBS_TOOLS) HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF) ifdef BUILD_DOCS -DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 +DOCS=qemu-doc.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 ifdef CONFIG_VIRTFS DOCS+=fsdev/virtfs-proxy-helper.1 endif @@ -107,20 +107,20 @@ SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS)) ifeq ($(SUBDIR_DEVICES_MAK),) config-all-devices.mak: - $(call quiet-command,echo '# no devices' > $@," GEN $@") + $(call quiet-command,echo '# no devices' > $@,"GEN","$@") else config-all-devices.mak: $(SUBDIR_DEVICES_MAK) $(call quiet-command, sed -n \ 's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \ $(SUBDIR_DEVICES_MAK) | sort -u > $@, \ - " GEN $@") + "GEN","$@") endif -include $(SUBDIR_DEVICES_MAK_DEP) %/config-devices.mak: default-configs/%.mak $(SRC_PATH)/scripts/make_device_config.sh $(call quiet-command, \ - $(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp, " GEN $@.tmp") + $(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp,"GEN","$@.tmp") $(call quiet-command, if test -f $@; then \ if cmp -s $@.old $@; then \ mv $@.tmp $@; \ @@ -137,7 +137,7 @@ endif else \ mv $@.tmp $@; \ cp -p $@ $@.old; \ - fi, " GEN $@"); + fi,"GEN","$@"); defconfig: rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK) @@ -191,7 +191,7 @@ qemu-version.h: FORCE config-host.h: config-host.h-timestamp config-host.h-timestamp: config-host.mak qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@") SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES)) @@ -235,9 +235,9 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS)) recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) $(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h | $(BUILD_DIR)/version.lo - $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o") + $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o") $(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc config-host.h - $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.lo") + $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.lo") Makefile: $(version-obj-y) $(version-lobj-y) @@ -261,7 +261,7 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@") qemu-ga$(EXESUF): LIBS = $(LIBS_QGA) qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated @@ -274,17 +274,17 @@ qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ - " GEN $@") + "GEN","$@") qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ - " GEN $@") + "GEN","$@") qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ - " GEN $@") + "GEN","$@") qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \ @@ -296,27 +296,27 @@ qapi-types.c qapi-types.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o "." -b $<, \ - " GEN $@") + "GEN","$@") qapi-visit.c qapi-visit.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ $(gen-out-type) -o "." -b $<, \ - " GEN $@") + "GEN","$@") qapi-event.c qapi-event.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ $(gen-out-type) -o "." $<, \ - " GEN $@") + "GEN","$@") qmp-commands.h qmp-marshal.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ $(gen-out-type) -o "." $<, \ - " GEN $@") + "GEN","$@") qmp-introspect.h qmp-introspect.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \ $(gen-out-type) -o "." $<, \ - " GEN $@") + "GEN","$@") QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) @@ -335,7 +335,7 @@ $(QEMU_GA_MSI): config-host.mak $(QEMU_GA_MSI): $(SRC_PATH)/qga/installer/qemu-ga.wxs $(call quiet-command,QEMU_GA_VERSION="$(QEMU_GA_VERSION)" QEMU_GA_MANUFACTURER="$(QEMU_GA_MANUFACTURER)" QEMU_GA_DISTRO="$(QEMU_GA_DISTRO)" BUILD_DIR="$(BUILD_DIR)" \ - wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<, " WIXL $@") + wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<,"WIXL","$@") else msi: @echo "MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)" @@ -354,7 +354,7 @@ ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak $(call quiet-command,$(PYTHON) $< $@ \ $(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \ - " GEN $@") + "GEN","$@") clean: # avoid old build problems by removing potentially incorrect old files @@ -398,7 +398,6 @@ distclean: clean rm -f qemu-doc.vr rm -f config.log rm -f linux-headers/asm - rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ done @@ -434,7 +433,7 @@ endif install-doc: $(DOCS) $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)" - $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)" + $(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)" ifdef CONFIG_POSIX $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" @@ -521,13 +520,13 @@ ui/shader/%-vert.h: $(SRC_PATH)/ui/shader/%.vert $(SRC_PATH)/scripts/shaderinclu @mkdir -p $(dir $@) $(call quiet-command,\ perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\ - " VERT $@") + "VERT","$@") ui/shader/%-frag.h: $(SRC_PATH)/ui/shader/%.frag $(SRC_PATH)/scripts/shaderinclude.pl @mkdir -p $(dir $@) $(call quiet-command,\ perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\ - " FRAG $@") + "FRAG","$@") ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \ ui/shader/texture-blit-vert.h ui/shader/texture-blit-frag.h @@ -537,65 +536,65 @@ MAKEINFO=makeinfo MAKEINFOFLAGS=--no-headers --no-split --number-sections TEXIFLAG=$(if $(V),,--quiet) %.dvi: %.texi - $(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<," GEN $@") + $(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<,"GEN","$@") %.html: %.texi $(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \ - " GEN $@") + "GEN","$@") %.info: %.texi - $(call quiet-command,$(MAKEINFO) $< -o $@," GEN $@") + $(call quiet-command,$(MAKEINFO) $< -o $@,"GEN","$@") %.pdf: %.texi - $(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<," GEN $@") + $(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<,"GEN","$@") qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \ $(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \ - " GEN $@") + "GEN","$@") qemu.1: qemu-option-trace.texi qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \ $(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \ - " GEN $@") + "GEN","$@") fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \ $(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \ - " GEN $@") + "GEN","$@") qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \ $(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \ - " GEN $@") + "GEN","$@") qemu-ga.8: qemu-ga.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-ga.pod && \ $(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \ - " GEN $@") + "GEN","$@") -dvi: qemu-doc.dvi qemu-tech.dvi -html: qemu-doc.html qemu-tech.html -info: qemu-doc.info qemu-tech.info -pdf: qemu-doc.pdf qemu-tech.pdf +dvi: qemu-doc.dvi +html: qemu-doc.html +info: qemu-doc.info +pdf: qemu-doc.pdf qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \ qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \ diff --git a/Makefile.target b/Makefile.target index 19cc49c..9968871 100644 --- a/Makefile.target +++ b/Makefile.target @@ -26,7 +26,7 @@ ifneq (,$(findstring -mwindows,$(libs_softmmu))) # Terminate program name with a 'w' because the linker builds a windows executable. QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF) $(QEMU_PROG): $(QEMU_PROGW) - $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)") + $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG),"GEN","$(TARGET_DIR)$(QEMU_PROG)") QEMU_PROG_BUILD = $(QEMU_PROGW) else QEMU_PROG_BUILD = $(QEMU_PROG) @@ -55,7 +55,7 @@ $(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all --binary=$(bindir)/$(QEMU_PROG) \ --target-name=$(TARGET_NAME) \ --target-type=$(TARGET_TYPE) \ - < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp-installed") + < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp-installed") $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ @@ -64,14 +64,14 @@ $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all --binary=$(realpath .)/$(QEMU_PROG) \ --target-name=$(TARGET_NAME) \ --target-type=$(TARGET_TYPE) \ - < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp") + < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp") $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ --format=simpletrace-stap \ --backends=$(TRACE_BACKENDS) \ --probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \ - < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp") + < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp") else stap: @@ -196,18 +196,18 @@ $(QEMU_PROG_BUILD): config-devices.mak $(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a $(call LINK, $(filter-out %.mak, $^)) ifdef CONFIG_DARWIN - $(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@," REZ $(TARGET_DIR)$@") - $(call quiet-command,SetFile -a C $@," SETFILE $(TARGET_DIR)$@") + $(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@") + $(call quiet-command,SetFile -a C $@,"SETFILE","$(TARGET_DIR)$@") endif gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh - $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") + $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"GEN","$(TARGET_DIR)$@") hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@") hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@") clean: clean-target rm -f *.a *~ $(PROGS) @@ -42,8 +42,6 @@ of other UNIX targets. The simple steps to build QEMU are: ../configure make -Complete details of the process for building and configuring QEMU for -all supported host platforms can be found in the qemu-tech.html file. Additional information can also be found online via the QEMU website: http://qemu-project.org/Hosts/Linux diff --git a/bsd-user/main.c b/bsd-user/main.c index d803d3e..d8367bd 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -695,6 +695,16 @@ static void usage(void) THREAD CPUState *thread_cpu; +bool qemu_cpu_is_self(CPUState *cpu) +{ + return thread_cpu == cpu; +} + +void qemu_cpu_kick(CPUState *cpu) +{ + cpu_exit(cpu); +} + /* Assumes contents are already zeroed. */ void init_task_state(TaskState *ts) { @@ -192,7 +192,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) /* We were asked to stop executing TBs (probably a pending * interrupt. We've now stopped, so clear the flag. */ - cpu->tcg_exit_req = 0; + atomic_set(&cpu->tcg_exit_req, 0); } return ret; } @@ -490,8 +490,8 @@ static inline void cpu_handle_interrupt(CPUState *cpu, *last_tb = NULL; } } - if (unlikely(cpu->exit_request || replay_has_interrupt())) { - cpu->exit_request = 0; + if (unlikely(atomic_read(&cpu->exit_request) || replay_has_interrupt())) { + atomic_set(&cpu->exit_request, 0); cpu->exception_index = EXCP_INTERRUPT; cpu_loop_exit(cpu); } @@ -503,7 +503,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, { uintptr_t ret; - if (unlikely(cpu->exit_request)) { + if (unlikely(atomic_read(&cpu->exit_request))) { return; } diff --git a/docs/specs/edu.txt b/docs/specs/edu.txt index 7f81467..0876310 100644 --- a/docs/specs/edu.txt +++ b/docs/specs/edu.txt @@ -52,7 +52,7 @@ size == 8 for the rest. 0x20 (RW) : status register, bitwise OR 0x01 -- computing factorial (RO) - 0x80 -- raise interrupt 0x01 after finishing factorial computation + 0x80 -- raise interrupt after finishing factorial computation 0x24 (RO) : interrupt status register It contains values which raised the interrupt (see interrupt raise @@ -87,6 +87,11 @@ An IRQ is generated when written to the interrupt raise register. The value appears in interrupt status register when the interrupt is raised and has to be written to the interrupt acknowledge register to lower it. +The device supports both INTx and MSI interrupt. By default, INTx is +used. Even if the driver disabled INTx and only uses MSI, it still +needs to update the acknowledge register at the end of the IRQ handler +routine. + DMA controller -------------- One has to specify, source, destination, size, and start the transfer. One diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 19729e5..55d50c4 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -172,20 +172,12 @@ STEXI Show the command line history. ETEXI -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_MIPS) || \ - defined(TARGET_LM32) || (defined(TARGET_SPARC) && !defined(TARGET_SPARC64)) { .name = "irq", .args_type = "", .params = "", .help = "show the interrupts statistics (if available)", -#ifdef TARGET_SPARC - .cmd = sun4m_hmp_info_irq, -#elif defined(TARGET_LM32) - .cmd = lm32_hmp_info_irq, -#else .cmd = hmp_info_irq, -#endif }, STEXI @@ -198,16 +190,9 @@ ETEXI .name = "pic", .args_type = "", .params = "", - .help = "show i8259 (PIC) state", -#ifdef TARGET_SPARC - .cmd = sun4m_hmp_info_pic, -#elif defined(TARGET_LM32) - .cmd = lm32_hmp_info_pic, -#else + .help = "show PIC state", .cmd = hmp_info_pic, -#endif }, -#endif STEXI @item info pic @@ -36,6 +36,7 @@ #include "qemu-io.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "hw/intc/intc.h" #ifdef CONFIG_SPICE #include <spice/enums.h> @@ -787,6 +788,70 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) } } +static int hmp_info_irq_foreach(Object *obj, void *opaque) +{ + InterruptStatsProvider *intc; + InterruptStatsProviderClass *k; + Monitor *mon = opaque; + + if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { + intc = INTERRUPT_STATS_PROVIDER(obj); + k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); + uint64_t *irq_counts; + unsigned int nb_irqs, i; + if (k->get_statistics && + k->get_statistics(intc, &irq_counts, &nb_irqs)) { + if (nb_irqs > 0) { + monitor_printf(mon, "IRQ statistics for %s:\n", + object_get_typename(obj)); + for (i = 0; i < nb_irqs; i++) { + if (irq_counts[i] > 0) { + monitor_printf(mon, "%2d: %" PRId64 "\n", i, + irq_counts[i]); + } + } + } + } else { + monitor_printf(mon, "IRQ statistics not available for %s.\n", + object_get_typename(obj)); + } + } + + return 0; +} + +void hmp_info_irq(Monitor *mon, const QDict *qdict) +{ + object_child_foreach_recursive(object_get_root(), + hmp_info_irq_foreach, mon); +} + +static int hmp_info_pic_foreach(Object *obj, void *opaque) +{ + InterruptStatsProvider *intc; + InterruptStatsProviderClass *k; + Monitor *mon = opaque; + + if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { + intc = INTERRUPT_STATS_PROVIDER(obj); + k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); + if (k->print_info) { + k->print_info(intc, mon); + } else { + monitor_printf(mon, "Interrupt controller information not available for %s.\n", + object_get_typename(obj)); + } + } + + return 0; +} + +void hmp_info_pic(Monitor *mon, const QDict *qdict) +{ + object_child_foreach_recursive(object_get_root(), + hmp_info_pic_foreach, mon); +} + void hmp_info_pci(Monitor *mon, const QDict *qdict) { PciInfoList *info_list, *info; @@ -36,6 +36,8 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict); void hmp_info_vnc(Monitor *mon, const QDict *qdict); void hmp_info_spice(Monitor *mon, const QDict *qdict); void hmp_info_balloon(Monitor *mon, const QDict *qdict); +void hmp_info_irq(Monitor *mon, const QDict *qdict); +void hmp_info_pic(Monitor *mon, const QDict *qdict); void hmp_info_pci(Monitor *mon, const QDict *qdict); void hmp_info_block_jobs(Monitor *mon, const QDict *qdict); void hmp_info_tpm(Monitor *mon, const QDict *qdict); diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 023de52..47b79d9 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -143,10 +143,10 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val) static void amdvi_generate_msi_interrupt(AMDVIState *s) { - MSIMessage msg; - MemTxAttrs attrs; - - attrs.requester_id = pci_requester_id(&s->pci.dev); + MSIMessage msg = {}; + MemTxAttrs attrs = { + .requester_id = pci_requester_id(&s->pci.dev) + }; if (msi_enabled(&s->pci.dev)) { msg = msi_get_message(&s->pci.dev, 0); @@ -185,7 +185,7 @@ static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start, int length) { int index = start / 64, bitpos = start % 64; - uint64_t mask = ((1 << length) - 1) << bitpos; + uint64_t mask = MAKE_64BIT_MASK(start, length); buffer[index] &= ~mask; buffer[index] |= (value << bitpos) & mask; } @@ -333,8 +333,8 @@ static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid, uint64_t gpa, IOMMUTLBEntry to_cache, uint16_t domid) { - AMDVIIOTLBEntry *entry = g_malloc(sizeof(*entry)); - uint64_t *key = g_malloc(sizeof(key)); + AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1); + uint64_t *key = g_new(uint64_t, 1); uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K; /* don't cache erroneous translations */ @@ -1135,6 +1135,7 @@ static void amdvi_reset(DeviceState *dev) static void amdvi_realize(DeviceState *dev, Error **err) { + int ret = 0; AMDVIState *s = AMD_IOMMU_DEVICE(dev); X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus; @@ -1147,8 +1148,11 @@ static void amdvi_realize(DeviceState *dev, Error **err) object_property_set_bool(OBJECT(&s->pci), true, "realized", err); s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, AMDVI_CAPAB_SIZE); - pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE); - pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE); + assert(s->capab_offset > 0); + ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE); + assert(ret > 0); + ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE); + assert(ret > 0); /* set up MMIO */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio", diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 9cca280..2f44a2d 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -18,6 +18,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_its_common.o common-obj-$(CONFIG_OPENPIC) += openpic.o +common-obj-y += intc.o obj-$(CONFIG_APIC) += apic.o apic_common.o obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index c2607a5..fe9ecd6 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -29,6 +29,7 @@ #include "qemu/timer.h" #include "qemu/log.h" #include "hw/isa/i8259_internal.h" +#include "hw/intc/intc.h" /* debug PIC */ //#define DEBUG_PIC @@ -251,6 +252,35 @@ static void pic_reset(DeviceState *dev) pic_init_reset(s); } +static bool pic_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, unsigned int *nb_irqs) +{ + PICCommonState *s = PIC_COMMON(obj); + + if (s->master) { +#ifdef DEBUG_IRQ_COUNT + *irq_counts = irq_count; + *nb_irqs = ARRAY_SIZE(irq_count); +#else + return false; +#endif + } else { + *irq_counts = NULL; + *nb_irqs = 0; + } + return true; +} + +static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon) +{ + PICCommonState *s = PIC_COMMON(obj); + monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d " + "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", + s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add, + s->irq_base, s->read_reg_select, s->elcr, + s->special_fully_nested_mode); +} + static void pic_ioport_write(void *opaque, hwaddr addr64, uint64_t val64, unsigned size) { @@ -431,42 +461,6 @@ static void pic_realize(DeviceState *dev, Error **errp) pc->parent_realize(dev, errp); } -void hmp_info_pic(Monitor *mon, const QDict *qdict) -{ - int i; - PICCommonState *s; - - if (!isa_pic) { - return; - } - for (i = 0; i < 2; i++) { - s = i == 0 ? PIC_COMMON(isa_pic) : slave_pic; - monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d " - "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", - i, s->irr, s->imr, s->isr, s->priority_add, - s->irq_base, s->read_reg_select, s->elcr, - s->special_fully_nested_mode); - } -} - -void hmp_info_irq(Monitor *mon, const QDict *qdict) -{ -#ifndef DEBUG_IRQ_COUNT - monitor_printf(mon, "irq statistic code not compiled.\n"); -#else - int i; - int64_t count; - - monitor_printf(mon, "IRQ statistics:\n"); - for (i = 0; i < 16; i++) { - count = irq_count[i]; - if (count > 0) { - monitor_printf(mon, "%2d: %" PRId64 "\n", i, count); - } - } -#endif -} - qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq) { qemu_irq *irq_set; @@ -503,10 +497,13 @@ static void i8259_class_init(ObjectClass *klass, void *data) { PICClass *k = PIC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); k->parent_realize = dc->realize; dc->realize = pic_realize; dc->reset = pic_reset; + ic->get_statistics = pic_get_statistics; + ic->print_info = pic_print_info; } static const TypeInfo i8259_info = { @@ -515,6 +512,10 @@ static const TypeInfo i8259_info = { .parent = TYPE_PIC_COMMON, .class_init = i8259_class_init, .class_size = sizeof(PICClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; static void pic_register_types(void) diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c index 3a850b0..d9a5e8b 100644 --- a/hw/intc/i8259_common.c +++ b/hw/intc/i8259_common.c @@ -70,10 +70,11 @@ static int pic_dispatch_post_load(void *opaque, int version_id) static void pic_common_realize(DeviceState *dev, Error **errp) { PICCommonState *s = PIC_COMMON(dev); + ISADevice *isa = ISA_DEVICE(dev); - isa_register_ioport(NULL, &s->base_io, s->iobase); + isa_register_ioport(isa, &s->base_io, s->iobase); if (s->elcr_addr != -1) { - isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr); + isa_register_ioport(isa, &s->elcr_io, s->elcr_addr); } qdev_set_legacy_instance_id(dev, s->iobase, 1); diff --git a/hw/intc/intc.c b/hw/intc/intc.c new file mode 100644 index 0000000..2e1e29e --- /dev/null +++ b/hw/intc/intc.c @@ -0,0 +1,41 @@ +/* + * QEMU Generic Interrupt Controller + * + * Copyright (c) 2016 Hervé Poussineau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/intc/intc.h" +#include "qemu/module.h" + +static const TypeInfo intctrl_info = { + .name = TYPE_INTERRUPT_STATS_PROVIDER, + .parent = TYPE_INTERFACE, + .class_size = sizeof(InterruptStatsProviderClass), +}; + +static void intc_register_types(void) +{ + type_register_static(&intctrl_info); +} + +type_init(intc_register_types) + diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c index 3dad01c..09e1511 100644 --- a/hw/intc/lm32_pic.c +++ b/hw/intc/lm32_pic.c @@ -25,6 +25,7 @@ #include "hw/sysbus.h" #include "trace.h" #include "hw/lm32/lm32_pic.h" +#include "hw/intc/intc.h" #define TYPE_LM32_PIC "lm32-pic" #define LM32_PIC(obj) OBJECT_CHECK(LM32PicState, (obj), TYPE_LM32_PIC) @@ -38,39 +39,10 @@ struct LM32PicState { uint32_t irq_state; /* statistics */ - uint32_t stats_irq_count[32]; + uint64_t stats_irq_count[32]; }; typedef struct LM32PicState LM32PicState; -static LM32PicState *pic; -void lm32_hmp_info_pic(Monitor *mon, const QDict *qdict) -{ - if (pic == NULL) { - return; - } - - monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n", - pic->im, pic->ip, pic->irq_state); -} - -void lm32_hmp_info_irq(Monitor *mon, const QDict *qdict) -{ - int i; - uint32_t count; - - if (pic == NULL) { - return; - } - - monitor_printf(mon, "IRQ statistics:\n"); - for (i = 0; i < 32; i++) { - count = pic->stats_irq_count[i]; - if (count > 0) { - monitor_printf(mon, "%2d: %u\n", i, count); - } - } -} - static void update_irq(LM32PicState *s) { s->ip |= s->irq_state; @@ -152,6 +124,22 @@ static void pic_reset(DeviceState *d) } } +static bool lm32_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, unsigned int *nb_irqs) +{ + LM32PicState *s = LM32_PIC(obj); + *irq_counts = s->stats_irq_count; + *nb_irqs = ARRAY_SIZE(s->stats_irq_count); + return true; +} + +static void lm32_print_info(InterruptStatsProvider *obj, Monitor *mon) +{ + LM32PicState *s = LM32_PIC(obj); + monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n", + s->im, s->ip, s->irq_state); +} + static void lm32_pic_init(Object *obj) { DeviceState *dev = DEVICE(obj); @@ -160,19 +148,17 @@ static void lm32_pic_init(Object *obj) qdev_init_gpio_in(dev, irq_handler, 32); sysbus_init_irq(sbd, &s->parent_irq); - - pic = s; } static const VMStateDescription vmstate_lm32_pic = { .name = "lm32-pic", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINT32(im, LM32PicState), VMSTATE_UINT32(ip, LM32PicState), VMSTATE_UINT32(irq_state, LM32PicState), - VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32), + VMSTATE_UINT64_ARRAY(stats_irq_count, LM32PicState, 32), VMSTATE_END_OF_LIST() } }; @@ -180,9 +166,12 @@ static const VMStateDescription vmstate_lm32_pic = { static void lm32_pic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); dc->reset = pic_reset; dc->vmsd = &vmstate_lm32_pic; + ic->get_statistics = lm32_get_statistics; + ic->print_info = lm32_print_info; } static const TypeInfo lm32_pic_info = { @@ -191,6 +180,10 @@ static const TypeInfo lm32_pic_info = { .instance_size = sizeof(LM32PicState), .instance_init = lm32_pic_init, .class_init = lm32_pic_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; static void lm32_pic_register_types(void) diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index e82e893..84e0bee 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -26,6 +26,7 @@ #include "hw/sparc/sun4m.h" #include "monitor/monitor.h" #include "hw/sysbus.h" +#include "hw/intc/intc.h" #include "trace.h" //#define DEBUG_IRQ_COUNT @@ -210,38 +211,6 @@ static const MemoryRegionOps slavio_intctlm_mem_ops = { }, }; -void slavio_pic_info(Monitor *mon, DeviceState *dev) -{ - SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); - int i; - - for (i = 0; i < MAX_CPUS; i++) { - monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, - s->slaves[i].intreg_pending); - } - monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", - s->intregm_pending, s->intregm_disabled); -} - -void slavio_irq_info(Monitor *mon, DeviceState *dev) -{ -#ifndef DEBUG_IRQ_COUNT - monitor_printf(mon, "irq statistic code not compiled.\n"); -#else - SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); - int i; - int64_t count; - - s = SLAVIO_INTCTL(dev); - monitor_printf(mon, "IRQ statistics:\n"); - for (i = 0; i < 32; i++) { - count = s->irq_count[i]; - if (count > 0) - monitor_printf(mon, "%2d: %" PRId64 "\n", i, count); - } -#endif -} - static const uint32_t intbit_to_level[] = { 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12, 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0, @@ -418,6 +387,31 @@ static void slavio_intctl_reset(DeviceState *d) slavio_check_interrupts(s, 0); } +#ifdef DEBUG_IRQ_COUNT +static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, + unsigned int *nb_irqs) +{ + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); + *irq_counts = s->irq_count; + *nb_irqs = ARRAY_SIZE(s->irq_count); + return true; +} +#endif + +static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon) +{ + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); + int i; + + for (i = 0; i < MAX_CPUS; i++) { + monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, + s->slaves[i].intreg_pending); + } + monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", + s->intregm_pending, s->intregm_disabled); +} + static void slavio_intctl_init(Object *obj) { DeviceState *dev = DEVICE(obj); @@ -449,9 +443,14 @@ static void slavio_intctl_init(Object *obj) static void slavio_intctl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); dc->reset = slavio_intctl_reset; dc->vmsd = &vmstate_intctl; +#ifdef DEBUG_IRQ_COUNT + ic->get_statistics = slavio_intctl_get_statistics; +#endif + ic->print_info = slavio_intctl_print_info; } static const TypeInfo slavio_intctl_info = { @@ -460,6 +459,10 @@ static const TypeInfo slavio_intctl_info = { .instance_size = sizeof(SLAVIO_INTCTLState), .instance_init = slavio_intctl_init, .class_init = slavio_intctl_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; static void slavio_intctl_register_types(void) diff --git a/hw/misc/edu.c b/hw/misc/edu.c index 888ba49..401039c 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "hw/pci/pci.h" +#include "hw/pci/msi.h" #include "qemu/timer.h" #include "qemu/main-loop.h" /* iothread mutex */ #include "qapi/visitor.h" @@ -69,11 +70,20 @@ typedef struct { uint64_t dma_mask; } EduState; +static bool edu_msi_enabled(EduState *edu) +{ + return msi_enabled(&edu->pdev); +} + static void edu_raise_irq(EduState *edu, uint32_t val) { edu->irq_status |= val; if (edu->irq_status) { - pci_set_irq(&edu->pdev, 1); + if (edu_msi_enabled(edu)) { + msi_notify(&edu->pdev, 0); + } else { + pci_set_irq(&edu->pdev, 1); + } } } @@ -81,7 +91,7 @@ static void edu_lower_irq(EduState *edu, uint32_t val) { edu->irq_status &= ~val; - if (!edu->irq_status) { + if (!edu->irq_status && !edu_msi_enabled(edu)) { pci_set_irq(&edu->pdev, 0); } } @@ -342,6 +352,10 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp) pci_config_set_interrupt_pin(pci_conf, 1); + if (msi_init(pdev, 0, 1, true, false, errp)) { + return; + } + memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu, "edu-mmio", 1 << 20); pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 14b6821..03e3803 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -546,6 +546,51 @@ static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt) return 0; } +/* Populate the "ibm,pa-features" property */ +static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) +{ + uint8_t pa_features_206[] = { 6, 0, + 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; + uint8_t pa_features_207[] = { 24, 0, + 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00 }; + uint8_t *pa_features; + size_t pa_size; + + switch (env->mmu_model) { + case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06a: + pa_features = pa_features_206; + pa_size = sizeof(pa_features_206); + break; + case POWERPC_MMU_2_07: + case POWERPC_MMU_2_07a: + pa_features = pa_features_207; + pa_size = sizeof(pa_features_207); + break; + default: + return; + } + + if (env->ci_large_pages) { + /* + * Note: we keep CI large pages off by default because a 64K capable + * guest provisioned with large pages might otherwise try to map a qemu + * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages + * even if that qemu runs on a 4k host. + * We dd this bit back here if we are confident this is not an issue + */ + pa_features[3] |= 0x20; + } + if (kvmppc_has_cap_htm() && pa_size > 24) { + pa_features[24] |= 0x80; /* Transactional memory support */ + } + + _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); +} + static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, sPAPRMachineState *spapr) { @@ -573,24 +618,6 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index))); } - /* Note: we keep CI large pages off for now because a 64K capable guest - * provisioned with large pages might otherwise try to map a qemu - * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages - * even if that qemu runs on a 4k host. - * - * We can later add this bit back when we are confident this is not - * an issue (!HV KVM or 64K host) - */ - uint8_t pa_features_206[] = { 6, 0, - 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; - uint8_t pa_features_207[] = { 24, 0, - 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; - uint8_t *pa_features; - size_t pa_size; - _FDT((fdt_setprop_cell(fdt, offset, "reg", index))); _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); @@ -657,18 +684,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, page_sizes_prop, page_sizes_prop_size))); } - /* Do the ibm,pa-features property, adjust it for ci-large-pages */ - if (env->mmu_model == POWERPC_MMU_2_06) { - pa_features = pa_features_206; - pa_size = sizeof(pa_features_206); - } else /* env->mmu_model == POWERPC_MMU_2_07 */ { - pa_features = pa_features_207; - pa_size = sizeof(pa_features_207); - } - if (env->ci_large_pages) { - pa_features[3] |= 0x20; - } - _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); + spapr_populate_pa_features(env, fdt, offset); _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", cs->cpu_index / vcpus_per_socket))); @@ -1759,7 +1775,7 @@ static void ppc_spapr_init(MachineState *machine) /* init CPUs */ if (machine->cpu_model == NULL) { - machine->cpu_model = kvm_enabled() ? "host" : "POWER7"; + machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu; } ppc_cpu_parse_features(machine->cpu_model); @@ -2386,6 +2402,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id; smc->dr_lmb_enabled = true; + smc->tcg_default_cpu = "POWER8"; mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; @@ -2437,18 +2454,39 @@ static const TypeInfo spapr_machine_info = { type_init(spapr_machine_register_##suffix) /* + * pseries-2.8 + */ +static void spapr_machine_2_8_instance_options(MachineState *machine) +{ +} + +static void spapr_machine_2_8_class_options(MachineClass *mc) +{ + /* Defaults for the latest behaviour inherited from the base class */ +} + +DEFINE_SPAPR_MACHINE(2_8, "2.8", true); + +/* * pseries-2.7 */ +#define SPAPR_COMPAT_2_7 \ + HW_COMPAT_2_7 \ + static void spapr_machine_2_7_instance_options(MachineState *machine) { } static void spapr_machine_2_7_class_options(MachineClass *mc) { - /* Defaults for the latest behaviour inherited from the base class */ + sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + + spapr_machine_2_8_class_options(mc); + smc->tcg_default_cpu = "POWER7"; + SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7); } -DEFINE_SPAPR_MACHINE(2_7, "2.7", true); +DEFINE_SPAPR_MACHINE(2_7, "2.7", false); /* * pseries-2.6 diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 6f0533c..35d1873 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -92,20 +92,20 @@ char *spapr_get_cpu_core_type(const char *model) gchar **model_pieces = g_strsplit(model, ",", 2); core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE); - g_strfreev(model_pieces); /* Check whether it exists or whether we have to look up an alias name */ if (!object_class_by_name(core_type)) { const char *realmodel; g_free(core_type); - realmodel = ppc_cpu_lookup_alias(model); + core_type = NULL; + realmodel = ppc_cpu_lookup_alias(model_pieces[0]); if (realmodel) { - return spapr_get_cpu_core_type(realmodel); + core_type = spapr_get_cpu_core_type(realmodel); } - return NULL; } + g_strfreev(model_pieces); return core_type; } diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index d8a2296..6090a20 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -658,7 +658,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req) struct srp_login_rsp *rsp = &iu->srp.login_rsp; uint64_t tag = iu->srp.rsp.tag; - trace_spapr_vscsi__process_login(); + trace_spapr_vscsi_process_login(); /* TODO handle case that requested size is wrong and * buffer format is wrong diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index d1995b8..4a2e5d6 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -225,7 +225,7 @@ spapr_vscsi_command_complete_sense_data2(unsigned s8, unsigned s9, unsigned s10, spapr_vscsi_command_complete_status(uint32_t status) "Command complete err=%"PRIu32 spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x" spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x" -spapr_vscsi__process_login(void) "Got login, sending response !" +spapr_vscsi_process_login(void) "Got login, sending response !" spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun %08" PRIx64 " with no drive" spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d" spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..." diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 478fda8..b3915e4 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -159,20 +159,6 @@ static void nvram_init(Nvram *nvram, uint8_t *macaddr, } } -static DeviceState *slavio_intctl; - -void sun4m_hmp_info_pic(Monitor *mon, const QDict *qdict) -{ - if (slavio_intctl) - slavio_pic_info(mon, slavio_intctl); -} - -void sun4m_hmp_info_irq(Monitor *mon, const QDict *qdict) -{ - if (slavio_intctl) - slavio_irq_info(mon, slavio_intctl); -} - void cpu_check_irqs(CPUSPARCState *env) { CPUState *cs; @@ -873,6 +859,7 @@ static void dummy_fdc_tc(void *opaque, int irq, int level) static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, MachineState *machine) { + DeviceState *slavio_intctl; const char *cpu_model = machine->cpu_model; unsigned int i; void *iommu, *espdma, *ledma, *nvram; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index ea625f2..da209d0 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -717,11 +717,18 @@ static void rtc_set_date_from_host(ISADevice *dev) rtc_set_cmos(s, &tm); } +static void rtc_pre_save(void *opaque) +{ + RTCState *s = opaque; + + rtc_update_time(s); +} + static int rtc_post_load(void *opaque, int version_id) { RTCState *s = opaque; - if (version_id <= 2) { + if (version_id <= 2 || rtc_clock == QEMU_CLOCK_REALTIME) { rtc_set_time(s); s->offset = 0; check_update_timer(s); @@ -764,6 +771,7 @@ static const VMStateDescription vmstate_rtc = { .name = "mc146818rtc", .version_id = 3, .minimum_version_id = 1, + .pre_save = rtc_pre_save, .post_load = rtc_post_load, .fields = (VMStateField[]) { VMSTATE_BUFFER(cmos_data, RTCState), diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index cb2df83..b16c448 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -181,8 +181,6 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq); qemu_irq *kvm_i8259_init(ISABus *bus); int pic_read_irq(DeviceState *d); int pic_get_output(DeviceState *d); -void hmp_info_pic(Monitor *mon, const QDict *qdict); -void hmp_info_irq(Monitor *mon, const QDict *qdict); /* ioapic.c */ diff --git a/include/hw/intc/intc.h b/include/hw/intc/intc.h new file mode 100644 index 0000000..27d9828 --- /dev/null +++ b/include/hw/intc/intc.h @@ -0,0 +1,33 @@ +#ifndef INTC_H +#define INTC_H + +#include "qom/object.h" + +#define TYPE_INTERRUPT_STATS_PROVIDER "intctrl" + +#define INTERRUPT_STATS_PROVIDER_CLASS(klass) \ + OBJECT_CLASS_CHECK(InterruptStatsProviderClass, (klass), \ + TYPE_INTERRUPT_STATS_PROVIDER) +#define INTERRUPT_STATS_PROVIDER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(InterruptStatsProviderClass, (obj), \ + TYPE_INTERRUPT_STATS_PROVIDER) +#define INTERRUPT_STATS_PROVIDER(obj) \ + INTERFACE_CHECK(InterruptStatsProvider, (obj), \ + TYPE_INTERRUPT_STATS_PROVIDER) + +typedef struct InterruptStatsProvider { + Object parent; +} InterruptStatsProvider; + +typedef struct InterruptStatsProviderClass { + InterfaceClass parent; + + /* The returned pointer and statistics must remain valid until + * the BQL is next dropped. + */ + bool (*get_statistics)(InterruptStatsProvider *obj, uint64_t **irq_counts, + unsigned int *nb_irqs); + void (*print_info)(InterruptStatsProvider *obj, Monitor *mon); +} InterruptStatsProviderClass; + +#endif diff --git a/include/hw/lm32/lm32_pic.h b/include/hw/lm32/lm32_pic.h index 189fa38..e6479b8 100644 --- a/include/hw/lm32/lm32_pic.h +++ b/include/hw/lm32/lm32_pic.h @@ -8,7 +8,4 @@ uint32_t lm32_pic_get_im(DeviceState *d); void lm32_pic_set_ip(DeviceState *d, uint32_t ip); void lm32_pic_set_im(DeviceState *d, uint32_t im); -void lm32_hmp_info_pic(Monitor *mon, const QDict *qdict); -void lm32_hmp_info_irq(Monitor *mon, const QDict *qdict); - #endif /* QEMU_HW_LM32_PIC_H */ diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 6289d50..39dadaa 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -39,6 +39,7 @@ struct sPAPRMachineClass { /*< public >*/ bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ + const char *tcg_default_cpu; /* which (TCG) CPU to simulate by default */ }; /** diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h index 9c17425..580d87b 100644 --- a/include/hw/sparc/sun4m.h +++ b/include/hw/sparc/sun4m.h @@ -24,14 +24,6 @@ static inline void sparc_iommu_memory_write(void *opaque, sparc_iommu_memory_rw(opaque, addr, buf, len, 1); } -/* slavio_intctl.c */ -void slavio_pic_info(Monitor *mon, DeviceState *dev); -void slavio_irq_info(Monitor *mon, DeviceState *dev); - -/* sun4m.c */ -void sun4m_hmp_info_pic(Monitor *mon, const QDict *qdict); -void sun4m_hmp_info_irq(Monitor *mon, const QDict *qdict); - /* sparc32_dma.c */ #include "hw/sparc/sparc32_dma.h" diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 0cce246..c4f6950 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -82,7 +82,7 @@ */ #if defined(__SANITIZE_THREAD__) #define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); }) -#elsif defined(__alpha__) +#elif defined(__alpha__) #define smp_read_barrier_depends() asm volatile("mb":::"memory") #else #define smp_read_barrier_depends() barrier() @@ -92,6 +92,12 @@ /* Weak atomic operations prevent the compiler moving other * loads/stores past the atomic operation load/store. However there is * no explicit memory barrier for the processor. + * + * The C11 memory model says that variables that are accessed from + * different threads should at least be done with __ATOMIC_RELAXED + * primitives or the result is undefined. Generally this has little to + * no effect on the generated code but not using the atomic primitives + * will get flagged by sanitizers as a violation. */ #define atomic_read(ptr) \ ({ \ diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 9e9fa61..384bfe2 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -388,6 +388,16 @@ void os_mem_prealloc(int fd, char *area, size_t sz, Error **errp); int qemu_read_password(char *buf, int buf_size); /** + * qemu_get_pid_name: + * @pid: pid of a process + * + * For given @pid fetch its name. Caller is responsible for + * freeing the string when no longer needed. + * Returns allocated string on success, NULL on failure. + */ +char *qemu_get_pid_name(pid_t pid); + +/** * qemu_fork: * * A version of fork that avoids signal handler race diff --git a/include/qemu/seqlock.h b/include/qemu/seqlock.h index 2e2be4c..8dee11d 100644 --- a/include/qemu/seqlock.h +++ b/include/qemu/seqlock.h @@ -31,7 +31,7 @@ static inline void seqlock_init(QemuSeqLock *sl) /* Lock out other writers and update the count. */ static inline void seqlock_write_begin(QemuSeqLock *sl) { - ++sl->sequence; + atomic_set(&sl->sequence, sl->sequence + 1); /* Write sequence before updating other fields. */ smp_wmb(); @@ -42,7 +42,7 @@ static inline void seqlock_write_end(QemuSeqLock *sl) /* Write other fields before finalizing sequence. */ smp_wmb(); - ++sl->sequence; + atomic_set(&sl->sequence, sl->sequence + 1); } static inline unsigned seqlock_read_begin(QemuSeqLock *sl) diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 0d0465a..4593576 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -92,6 +92,7 @@ struct CharDriverState { int explicit_be_open; int avail_connections; int is_mux; + int mux_idx; guint fd_in_tag; QemuOpts *opts; bool replay; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0815f30..fa559be 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7476,13 +7476,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; } + cpu_list_lock(); + if (CPU_NEXT(first_cpu)) { TaskState *ts; - cpu_list_lock(); /* Remove the CPU from the list. */ QTAILQ_REMOVE(&cpus, cpu, node); + cpu_list_unlock(); + ts = cpu->opaque; if (ts->child_tidptr) { put_user_u32(0, ts->child_tidptr); @@ -7495,6 +7498,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, rcu_unregister_thread(); pthread_exit(NULL); } + + cpu_list_unlock(); #ifdef TARGET_GPROF _mcleanup(); #endif @@ -81,12 +81,6 @@ #include "qemu/cutils.h" #include "qapi/qmp/dispatch.h" -/* for hmp_info_irq/pic */ -#if defined(TARGET_SPARC) -#include "hw/sparc/sun4m.h" -#endif -#include "hw/lm32/lm32_pic.h" - #if defined(TARGET_S390X) #include "hw/s390x/storage-keys.h" #endif diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index afa48f1..fa53d9e 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -43,16 +43,16 @@ build-all: multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin %.o: %.S - $(call quiet-command,$(CPP) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) -c -o - $< | $(AS) $(ASFLAGS) -o $@," AS $(TARGET_DIR)$@") + $(call quiet-command,$(CPP) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) -c -o - $< | $(AS) $(ASFLAGS) -o $@,"AS","$(TARGET_DIR)$@") %.img: %.o - $(call quiet-command,$(LD) $(LDFLAGS_NOPIE) -m $(LD_I386_EMULATION) -T $(SRC_PATH)/pc-bios/optionrom/flat.lds -s -o $@ $<," Building $(TARGET_DIR)$@") + $(call quiet-command,$(LD) $(LDFLAGS_NOPIE) -m $(LD_I386_EMULATION) -T $(SRC_PATH)/pc-bios/optionrom/flat.lds -s -o $@ $<,"BUILD","$(TARGET_DIR)$@") %.raw: %.img - $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@," Building $(TARGET_DIR)$@") + $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"BUILD","$(TARGET_DIR)$@") %.bin: %.raw - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/signrom.py $< $@," Signing $(TARGET_DIR)$@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/signrom.py $< $@,"SIGN","$(TARGET_DIR)$@") clean: rm -f *.o *.d *.raw *.img *.bin *~ diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 0ab2538..0339c24 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -19,10 +19,10 @@ LDFLAGS += -Wl,-pie -nostdlib build-all: s390-ccw.img s390-ccw.elf: $(OBJECTS) - $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS)," Building $(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_DIR)$@") s390-ccw.img: s390-ccw.elf - $(call quiet-command,strip --strip-unneeded $< -o $@," Stripping $(TARGET_DIR)$@") + $(call quiet-command,strip --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") $(OBJECTS): Makefile diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile index dc8b23e..f26dd42 100644 --- a/pc-bios/spapr-rtas/Makefile +++ b/pc-bios/spapr-rtas/Makefile @@ -15,10 +15,10 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas) build-all: spapr-rtas.bin %.img: %.o - $(call quiet-command,$(CC) -nostdlib -o $@ $<," Building $(TARGET_DIR)$@") + $(call quiet-command,$(CC) -nostdlib -o $@ $<,"Building","$(TARGET_DIR)$@") %.bin: %.img - $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@," Building $(TARGET_DIR)$@") + $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"Building","$(TARGET_DIR)$@") clean: rm -f *.o *.d *.img *.bin *~ diff --git a/po/Makefile b/po/Makefile index 7bab09d..cc63036 100644 --- a/po/Makefile +++ b/po/Makefile @@ -10,7 +10,7 @@ all: .PHONY: all build clean install update %.mo: %.po - $(call quiet-command, msgfmt -o $@ $<, " GEN $@") + $(call quiet-command, msgfmt -o $@ $<,"GEN","$@") -include ../config-host.mak include $(SRC_PATH)/rules.mak @@ -46,7 +46,7 @@ $(PO_PATH)/messages.po: $(SRC_PATH)/ui/gtk.c xgettext -o - --from-code=UTF-8 --foreign-user \ --package-name=QEMU --package-version=$(VERSION) \ --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C ui/gtk.c | \ - sed -e s/CHARSET/UTF-8/) >$@, " GEN $@") + sed -e s/CHARSET/UTF-8/) >$@,"GEN","$@") $(PO_PATH)/%.po: $(PO_PATH)/messages.po - $(call quiet-command, msgmerge -q $@ $< > $@.bak && mv $@.bak $@, " GEN $@") + $(call quiet-command, msgmerge -q $@ $< > $@.bak && mv $@.bak $@,"GEN","$@") diff --git a/qemu-char.c b/qemu-char.c index fb456ce..4b330ea 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -165,6 +165,7 @@ CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp) CharDriverState *chr = g_malloc0(sizeof(CharDriverState)); qemu_mutex_init(&chr->chr_write_lock); + chr->mux_idx = -1; if (backend->has_logfile) { int flags = O_WRONLY | O_CREAT; if (backend->has_logappend && @@ -468,7 +469,7 @@ void qemu_chr_add_handlers_full(CharDriverState *s, s->chr_read = fd_read; s->chr_event = fd_event; s->handler_opaque = opaque; - if (fe_open && s->chr_update_read_handler) { + if (s->chr_update_read_handler) { s->chr_update_read_handler(s, context); } @@ -738,17 +739,25 @@ static void mux_chr_update_read_handler(CharDriverState *chr, GMainContext *context) { MuxDriver *d = chr->opaque; + int idx; if (d->mux_cnt >= MAX_MUX) { fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); return; } - d->ext_opaque[d->mux_cnt] = chr->handler_opaque; - d->chr_can_read[d->mux_cnt] = chr->chr_can_read; - d->chr_read[d->mux_cnt] = chr->chr_read; - d->chr_event[d->mux_cnt] = chr->chr_event; + + if (chr->mux_idx == -1) { + chr->mux_idx = d->mux_cnt++; + } + + idx = chr->mux_idx; + d->ext_opaque[idx] = chr->handler_opaque; + d->chr_can_read[idx] = chr->chr_can_read; + d->chr_read[idx] = chr->chr_read; + d->chr_event[idx] = chr->chr_event; + /* Fix up the real driver with mux routines */ - if (d->mux_cnt == 0) { + if (d->mux_cnt == 1) { qemu_chr_add_handlers_full(d->drv, mux_chr_can_read, mux_chr_read, mux_chr_event, @@ -757,8 +766,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr, if (d->focus != -1) { mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); } - d->focus = d->mux_cnt; - d->mux_cnt++; + d->focus = idx; mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN); } diff --git a/qemu-doc.texi b/qemu-doc.texi index f37fd31..023c140 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -32,11 +32,10 @@ @menu * Introduction:: -* Installation:: * QEMU PC System emulator:: * QEMU System emulator for non PC targets:: * QEMU User space emulator:: -* compilation:: Compilation from the sources +* Implementation notes:: * License:: * Index:: @end menu @@ -57,98 +56,69 @@ QEMU is a FAST! processor emulator using dynamic translation to achieve good emulation speed. +@cindex operating modes QEMU has two operating modes: @itemize -@cindex operating modes - -@item @cindex system emulation -Full system emulation. In this mode, QEMU emulates a full system (for +@item Full system emulation. In this mode, QEMU emulates a full system (for example a PC), including one or several processors and various peripherals. It can be used to launch different Operating Systems without rebooting the PC or to debug system code. -@item @cindex user mode emulation -User mode emulation. In this mode, QEMU can launch +@item User mode emulation. In this mode, QEMU can launch processes compiled for one CPU on another CPU. It can be used to launch the Wine Windows API emulator (@url{http://www.winehq.org}) or to ease cross-compilation and cross-debugging. @end itemize -QEMU can run without a host kernel driver and yet gives acceptable -performance. +QEMU has the following features: -For system emulation, the following hardware targets are supported: @itemize -@cindex emulated target systems -@cindex supported target systems -@item PC (x86 or x86_64 processor) -@item ISA PC (old style PC without PCI bus) -@item PREP (PowerPC processor) -@item G3 Beige PowerMac (PowerPC processor) -@item Mac99 PowerMac (PowerPC processor, in progress) -@item Sun4m/Sun4c/Sun4d (32-bit Sparc processor) -@item Sun4u/Sun4v (64-bit Sparc processor, in progress) -@item Malta board (32-bit and 64-bit MIPS processors) -@item MIPS Magnum (64-bit MIPS processor) -@item ARM Integrator/CP (ARM) -@item ARM Versatile baseboard (ARM) -@item ARM RealView Emulation/Platform baseboard (ARM) -@item Spitz, Akita, Borzoi, Terrier and Tosa PDAs (PXA270 processor) -@item Luminary Micro LM3S811EVB (ARM Cortex-M3) -@item Luminary Micro LM3S6965EVB (ARM Cortex-M3) -@item Freescale MCF5208EVB (ColdFire V2). -@item Arnewsh MCF5206 evaluation board (ColdFire V2). -@item Palm Tungsten|E PDA (OMAP310 processor) -@item N800 and N810 tablets (OMAP2420 processor) -@item MusicPal (MV88W8618 ARM processor) -@item Gumstix "Connex" and "Verdex" motherboards (PXA255/270). -@item Siemens SX1 smartphone (OMAP310 processor) -@item AXIS-Devboard88 (CRISv32 ETRAX-FS). -@item Petalogix Spartan 3aDSP1800 MMU ref design (MicroBlaze). -@item Avnet LX60/LX110/LX200 boards (Xtensa) -@end itemize +@item QEMU can run without a host kernel driver and yet gives acceptable +performance. It uses dynamic translation to native code for reasonable speed, +with support for self-modifying code and precise exceptions. -@cindex supported user mode targets -For user emulation, x86 (32 and 64 bit), PowerPC (32 and 64 bit), -ARM, MIPS (32 bit only), Sparc (32 and 64 bit), -Alpha, ColdFire(m68k), CRISv32 and MicroBlaze CPUs are supported. +@item It is portable to several operating systems (GNU/Linux, *BSD, Mac OS X, +Windows) and architectures. -@node Installation -@chapter Installation +@item It performs accurate software emulation of the FPU. +@end itemize -If you want to compile QEMU yourself, see @ref{compilation}. +QEMU user mode emulation has the following features: +@itemize +@item Generic Linux system call converter, including most ioctls. -@menu -* install_linux:: Linux -* install_windows:: Windows -* install_mac:: Macintosh -@end menu +@item clone() emulation using native CPU clone() to use Linux scheduler for threads. -@node install_linux -@section Linux -@cindex installation (Linux) +@item Accurate signal handling by remapping host signals to target signals. +@end itemize + +QEMU full system emulation has the following features: +@itemize +@item +QEMU uses a full software MMU for maximum portability. -If a precompiled package is available for your distribution - you just -have to install it. Otherwise, see @ref{compilation}. +@item +QEMU can optionally use an in-kernel accelerator, like kvm. The accelerators +execute most of the guest code natively, while +continuing to emulate the rest of the machine. -@node install_windows -@section Windows -@cindex installation (Windows) +@item +Various hardware devices can be emulated and in some cases, host +devices (e.g. serial and parallel ports, USB, drives) can be used +transparently by the guest Operating System. Host device passthrough +can be used for talking to external physical peripherals (e.g. a +webcam, modem or tape drive). -Download the experimental binary installer at -@url{http://www.free.oszoo.org/@/download.html}. -TODO (no longer available) +@item +Symmetric multiprocessing (SMP) support. Currently, an in-kernel +accelerator is required to use more than one host CPU for emulation. -@node install_mac -@section Mac OS X +@end itemize -Download the experimental binary installer at -@url{http://www.free.oszoo.org/@/download.html}. -TODO (no longer available) @node QEMU PC System emulator @chapter QEMU PC System emulator @@ -2660,6 +2630,7 @@ so should only be used with trusted guest OS. @menu * Supported Operating Systems :: +* Features:: * Linux User space emulator:: * BSD User space emulator :: @end menu @@ -2676,6 +2647,39 @@ Linux (referred as qemu-linux-user) BSD (referred as qemu-bsd-user) @end itemize +@node Features +@section Features + +QEMU user space emulation has the following notable features: + +@table @strong +@item System call translation: +QEMU includes a generic system call translator. This means that +the parameters of the system calls can be converted to fix +endianness and 32/64-bit mismatches between hosts and targets. +IOCTLs can be converted too. + +@item POSIX signal handling: +QEMU can redirect to the running program all signals coming from +the host (such as @code{SIGALRM}), as well as synthesize signals from +virtual CPU exceptions (for example @code{SIGFPE} when the program +executes a division by zero). + +QEMU relies on the host kernel to emulate most signal system +calls, for example to emulate the signal mask. On Linux, QEMU +supports both normal and real-time signals. + +@item Threading: +On Linux, QEMU can emulate the @code{clone} syscall and create a real +host thread (with a separate virtual CPU) for each emulated thread. +Note that not all targets currently emulate atomic operations correctly. +x86 and ARM use a global lock in order to preserve their semantics. +@end table + +QEMU was conceived so that ultimately it can emulate itself. Although +it is not very useful, it is an important test to show the power of the +emulator. + @node Linux User space emulator @section Linux User space emulator @@ -2945,220 +2949,8 @@ Act as if the host page size was 'pagesize' bytes Run the emulation in single step mode. @end table -@node compilation -@chapter Compilation from the sources - -@menu -* Linux/Unix:: -* Windows:: -* Cross compilation for Windows with Linux:: -* Mac OS X:: -* Make targets:: -@end menu - -@node Linux/Unix -@section Linux/Unix - -@subsection Compilation - -First you must decompress the sources: -@example -cd /tmp -tar zxvf qemu-x.y.z.tar.gz -cd qemu-x.y.z -@end example - -Then you configure QEMU and build it (usually no options are needed): -@example -./configure -make -@end example - -Then type as root user: -@example -make install -@end example -to install QEMU in @file{/usr/local}. - -@node Windows -@section Windows - -@itemize -@item Install the current versions of MSYS and MinGW from -@url{http://www.mingw.org/}. You can find detailed installation -instructions in the download section and the FAQ. - -@item Download -the MinGW development library of SDL 1.2.x -(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from -@url{http://www.libsdl.org}. Unpack it in a temporary place and -edit the @file{sdl-config} script so that it gives the -correct SDL directory when invoked. - -@item Install the MinGW version of zlib and make sure -@file{zlib.h} and @file{libz.dll.a} are in -MinGW's default header and linker search paths. - -@item Extract the current version of QEMU. - -@item Start the MSYS shell (file @file{msys.bat}). - -@item Change to the QEMU directory. Launch @file{./configure} and -@file{make}. If you have problems using SDL, verify that -@file{sdl-config} can be launched from the MSYS command line. - -@item You can install QEMU in @file{Program Files/QEMU} by typing -@file{make install}. Don't forget to copy @file{SDL.dll} in -@file{Program Files/QEMU}. - -@end itemize - -@node Cross compilation for Windows with Linux -@section Cross compilation for Windows with Linux - -@itemize -@item -Install the MinGW cross compilation tools available at -@url{http://www.mingw.org/}. - -@item Download -the MinGW development library of SDL 1.2.x -(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from -@url{http://www.libsdl.org}. Unpack it in a temporary place and -edit the @file{sdl-config} script so that it gives the -correct SDL directory when invoked. Set up the @code{PATH} environment -variable so that @file{sdl-config} can be launched by -the QEMU configuration script. - -@item Install the MinGW version of zlib and make sure -@file{zlib.h} and @file{libz.dll.a} are in -MinGW's default header and linker search paths. - -@item -Configure QEMU for Windows cross compilation: -@example -PATH=/usr/i686-pc-mingw32/sys-root/mingw/bin:$PATH ./configure --cross-prefix='i686-pc-mingw32-' -@end example -The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-mingw32/sys-root/mingw/bin} and -MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}. -We set the @code{PATH} environment variable to ensure the MinGW version of @file{sdl-config} is used and -use --cross-prefix to specify the name of the cross compiler. -You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/QEMU}. - -Under Fedora Linux, you can run: -@example -yum -y install mingw32-gcc mingw32-SDL mingw32-zlib -@end example -to get a suitable cross compilation environment. - -@item You can install QEMU in the installation directory by typing -@code{make install}. Don't forget to copy @file{SDL.dll} and @file{zlib1.dll} into the -installation directory. - -@end itemize - -Wine can be used to launch the resulting qemu-system-i386.exe -and all other qemu-system-@var{target}.exe compiled for Win32. - -@node Mac OS X -@section Mac OS X - -System Requirements: -@itemize -@item Mac OS 10.5 or higher -@item The clang compiler shipped with Xcode 4.2 or higher, -or GCC 4.3 or higher -@end itemize - -Additional Requirements (install in order): -@enumerate -@item libffi: @uref{https://sourceware.org/libffi/} -@item gettext: @uref{http://www.gnu.org/software/gettext/} -@item glib: @uref{http://ftp.gnome.org/pub/GNOME/sources/glib/} -@item pkg-config: @uref{http://www.freedesktop.org/wiki/Software/pkg-config/} -@item autoconf: @uref{http://www.gnu.org/software/autoconf/autoconf.html} -@item automake: @uref{http://www.gnu.org/software/automake/} -@item pixman: @uref{http://www.pixman.org/} -@end enumerate - -* You may find it easiest to get these from a third-party packager -such as Homebrew, Macports, or Fink. - -After downloading the QEMU source code, double-click it to expand it. - -Then configure and make QEMU: -@example -./configure -make -@end example - -If you have a recent version of Mac OS X (OSX 10.7 or better -with Xcode 4.2 or better) we recommend building QEMU with the -default compiler provided by Apple, for your version of Mac OS X -(which will be 'clang'). The configure script will -automatically pick this. -Note: If after the configure step you see a message like this: -@example -ERROR: Your compiler does not support the __thread specifier for - Thread-Local Storage (TLS). Please upgrade to a version that does. -@end example -you may have to build your own version of gcc from source. Expect that to take -several hours. More information can be found here: -@uref{https://gcc.gnu.org/install/} @* - -These are some of the third party binaries of gcc available for download: -@itemize -@item Homebrew: @uref{http://brew.sh/} -@item @uref{https://www.litebeam.net/gcc/gcc_472.pkg} -@item @uref{http://www.macports.org/ports.php?by=name&substr=gcc} -@end itemize - -You can have several versions of GCC on your system. To specify a certain version, -use the --cc and --cxx options. -@example -./configure --cxx=<path of your c++ compiler> --cc=<path of your c compiler> <other options> -@end example - -@node Make targets -@section Make targets - -@table @code - -@item make -@item make all -Make everything which is typically needed. - -@item install -TODO - -@item install-doc -TODO - -@item make clean -Remove most files which were built during make. - -@item make distclean -Remove everything which was built during make. - -@item make dvi -@item make html -@item make info -@item make pdf -Create documentation in dvi, html, info or pdf format. - -@item make cscope -TODO - -@item make defconfig -(Re-)create some build configuration files. -User made changes will be overwritten. - -@item tar -@item tarbin -TODO - -@end table +@include qemu-tech.texi @node License @appendix License @@ -901,6 +901,14 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (dev_offset >= fd_size) { + error_report("Offset (%lld) has to be smaller than the image size " + "(%lld)", + (long long int)dev_offset, (long long int)fd_size); + exit(EXIT_FAILURE); + } + fd_size -= dev_offset; + if (partition != -1) { ret = find_partition(blk, partition, &dev_offset, &fd_size); if (ret < 0) { diff --git a/qemu-tech.texi b/qemu-tech.texi index 1b048cb..52a56ae 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -1,146 +1,27 @@ -\input texinfo @c -*- texinfo -*- -@c %**start of header -@setfilename qemu-tech.info - -@documentlanguage en -@documentencoding UTF-8 - -@settitle QEMU Internals -@exampleindent 0 -@paragraphindent 0 -@c %**end of header - -@ifinfo -@direntry -* QEMU Internals: (qemu-tech). The QEMU Emulator Internals. -@end direntry -@end ifinfo - -@iftex -@titlepage -@sp 7 -@center @titlefont{QEMU Internals} -@sp 3 -@end titlepage -@end iftex - -@ifnottex -@node Top -@top +@node Implementation notes +@appendix Implementation notes @menu -* Introduction:: -* QEMU Internals:: -* Regression Tests:: -* Index:: +* CPU emulation:: +* Translator Internals:: +* QEMU compared to other emulators:: +* Bibliography:: @end menu -@end ifnottex - -@contents -@node Introduction -@chapter Introduction +@node CPU emulation +@section CPU emulation @menu -* intro_features:: Features -* intro_x86_emulation:: x86 and x86-64 emulation -* intro_arm_emulation:: ARM emulation -* intro_mips_emulation:: MIPS emulation -* intro_ppc_emulation:: PowerPC emulation -* intro_sparc_emulation:: Sparc32 and Sparc64 emulation -* intro_xtensa_emulation:: Xtensa emulation -* intro_other_emulation:: Other CPU emulation +* x86:: x86 and x86-64 emulation +* ARM:: ARM emulation +* MIPS:: MIPS emulation +* PPC:: PowerPC emulation +* SPARC:: Sparc32 and Sparc64 emulation +* Xtensa:: Xtensa emulation @end menu -@node intro_features -@section Features - -QEMU is a FAST! processor emulator using a portable dynamic -translator. - -QEMU has two operating modes: - -@itemize @minus - -@item -Full system emulation. In this mode (full platform virtualization), -QEMU emulates a full system (usually a PC), including a processor and -various peripherals. It can be used to launch several different -Operating Systems at once without rebooting the host machine or to -debug system code. - -@item -User mode emulation. In this mode (application level virtualization), -QEMU can launch processes compiled for one CPU on another CPU, however -the Operating Systems must match. This can be used for example to ease -cross-compilation and cross-debugging. -@end itemize - -As QEMU requires no host kernel driver to run, it is very safe and -easy to use. - -QEMU generic features: - -@itemize - -@item User space only or full system emulation. - -@item Using dynamic translation to native code for reasonable speed. - -@item -Working on x86, x86_64 and PowerPC32/64 hosts. Being tested on ARM, -S390x, Sparc32 and Sparc64. - -@item Self-modifying code support. - -@item Precise exceptions support. - -@item -Floating point library supporting both full software emulation and -native host FPU instructions. - -@end itemize - -QEMU user mode emulation features: -@itemize -@item Generic Linux system call converter, including most ioctls. - -@item clone() emulation using native CPU clone() to use Linux scheduler for threads. - -@item Accurate signal handling by remapping host signals to target signals. -@end itemize - -Linux user emulator (Linux host only) can be used to launch the Wine -Windows API emulator (@url{http://www.winehq.org}). A BSD user emulator for BSD -hosts is under development. It would also be possible to develop a -similar user emulator for Solaris. - -QEMU full system emulation features: -@itemize -@item -QEMU uses a full software MMU for maximum portability. - -@item -QEMU can optionally use an in-kernel accelerator, like kvm. The accelerators -execute some of the guest code natively, while -continuing to emulate the rest of the machine. - -@item -Various hardware devices can be emulated and in some cases, host -devices (e.g. serial and parallel ports, USB, drives) can be used -transparently by the guest Operating System. Host device passthrough -can be used for talking to external physical peripherals (e.g. a -webcam, modem or tape drive). - -@item -Symmetric multiprocessing (SMP) even on a host with a single CPU. On a -SMP host system, QEMU can use only one CPU fully due to difficulty in -implementing atomic memory accesses efficiently. - -@end itemize - -@node intro_x86_emulation -@section x86 and x86-64 emulation +@node x86 +@subsection x86 and x86-64 emulation QEMU x86 target features: @@ -174,8 +55,8 @@ normal use. @end itemize -@node intro_arm_emulation -@section ARM emulation +@node ARM +@subsection ARM emulation @itemize @@ -187,8 +68,8 @@ normal use. @end itemize -@node intro_mips_emulation -@section MIPS emulation +@node MIPS +@subsection MIPS emulation @itemize @@ -214,8 +95,8 @@ Current QEMU limitations: @end itemize -@node intro_ppc_emulation -@section PowerPC emulation +@node PPC +@subsection PowerPC emulation @itemize @@ -226,8 +107,8 @@ FPU and MMU. @end itemize -@node intro_sparc_emulation -@section Sparc32 and Sparc64 emulation +@node SPARC +@subsection Sparc32 and Sparc64 emulation @itemize @@ -254,8 +135,8 @@ Current QEMU limitations: @end itemize -@node intro_xtensa_emulation -@section Xtensa emulation +@node Xtensa +@subsection Xtensa emulation @itemize @@ -279,96 +160,8 @@ may be created from overlay with minimal amount of hand-written code. @end itemize -@node intro_other_emulation -@section Other CPU emulation - -In addition to the above, QEMU supports emulation of other CPUs with -varying levels of success. These are: - -@itemize - -@item -Alpha -@item -CRIS -@item -M68k -@item -SH4 -@end itemize - -@node QEMU Internals -@chapter QEMU Internals - -@menu -* QEMU compared to other emulators:: -* Portable dynamic translation:: -* Condition code optimisations:: -* CPU state optimisations:: -* Translation cache:: -* Direct block chaining:: -* Self-modifying code and translated code invalidation:: -* Exception support:: -* MMU emulation:: -* Device emulation:: -* Hardware interrupts:: -* User emulation specific details:: -* Bibliography:: -@end menu - -@node QEMU compared to other emulators -@section QEMU compared to other emulators - -Like bochs [1], QEMU emulates an x86 CPU. But QEMU is much faster than -bochs as it uses dynamic compilation. Bochs is closely tied to x86 PC -emulation while QEMU can emulate several processors. - -Like Valgrind [2], QEMU does user space emulation and dynamic -translation. Valgrind is mainly a memory debugger while QEMU has no -support for it (QEMU could be used to detect out of bound memory -accesses as Valgrind, but it has no support to track uninitialised data -as Valgrind does). The Valgrind dynamic translator generates better code -than QEMU (in particular it does register allocation) but it is closely -tied to an x86 host and target and has no support for precise exceptions -and system emulation. - -EM86 [3] is the closest project to user space QEMU (and QEMU still uses -some of its code, in particular the ELF file loader). EM86 was limited -to an alpha host and used a proprietary and slow interpreter (the -interpreter part of the FX!32 Digital Win32 code translator [4]). - -TWIN from Willows Software was a Windows API emulator like Wine. It is less -accurate than Wine but includes a protected mode x86 interpreter to launch -x86 Windows executables. Such an approach has greater potential because most -of the Windows API is executed natively but it is far more difficult to -develop because all the data structures and function parameters exchanged -between the API and the x86 code must be converted. - -User mode Linux [5] was the only solution before QEMU to launch a -Linux kernel as a process while not needing any host kernel -patches. However, user mode Linux requires heavy kernel patches while -QEMU accepts unpatched Linux kernels. The price to pay is that QEMU is -slower. - -The Plex86 [6] PC virtualizer is done in the same spirit as the now -obsolete qemu-fast system emulator. It requires a patched Linux kernel -to work (you cannot launch the same kernel on your PC), but the -patches are really small. As it is a PC virtualizer (no emulation is -done except for some privileged instructions), it has the potential of -being faster than QEMU. The downside is that a complicated (and -potentially unsafe) host kernel patch is needed. - -The commercial PC Virtualizers (VMWare [7], VirtualPC [8]) are faster -than QEMU (without virtualization), but they all need specific, proprietary -and potentially unsafe host drivers. Moreover, they are unable to -provide cycle exact simulation as an emulator can. - -VirtualBox [9], Xen [10] and KVM [11] are based on QEMU. QEMU-SystemC -[12] uses QEMU to simulate a system where some hardware devices are -developed in SystemC. - -@node Portable dynamic translation -@section Portable dynamic translation +@node Translator Internals +@section Translator Internals QEMU is a dynamic translator. When it first encounters a piece of code, it converts it to the host instruction set. Usually dynamic translators @@ -376,68 +169,26 @@ are very complicated and highly CPU dependent. QEMU uses some tricks which make it relatively easily portable and simple while achieving good performances. -After the release of version 0.9.1, QEMU switched to a new method of -generating code, Tiny Code Generator or TCG. TCG relaxes the -dependency on the exact version of the compiler used. The basic idea -is to split every target instruction into a couple of RISC-like TCG -ops (see @code{target-i386/translate.c}). Some optimizations can be -performed at this stage, including liveness analysis and trivial -constant expression evaluation. TCG ops are then implemented in the -host CPU back end, also known as TCG target (see -@code{tcg/i386/tcg-target.inc.c}). For more information, please take a -look at @code{tcg/README}. - -@node Condition code optimisations -@section Condition code optimisations - -Lazy evaluation of CPU condition codes (@code{EFLAGS} register on x86) -is important for CPUs where every instruction sets the condition -codes. It tends to be less important on conventional RISC systems -where condition codes are only updated when explicitly requested. On -Sparc64, costly update of both 32 and 64 bit condition codes can be -avoided with lazy evaluation. - -Instead of computing the condition codes after each x86 instruction, -QEMU just stores one operand (called @code{CC_SRC}), the result -(called @code{CC_DST}) and the type of operation (called -@code{CC_OP}). When the condition codes are needed, the condition -codes can be calculated using this information. In addition, an -optimized calculation can be performed for some instruction types like -conditional branches. - -@code{CC_OP} is almost never explicitly set in the generated code -because it is known at translation time. - -The lazy condition code evaluation is used on x86, m68k, cris and -Sparc. ARM uses a simplified variant for the N and Z flags. - -@node CPU state optimisations -@section CPU state optimisations +QEMU's dynamic translation backend is called TCG, for "Tiny Code +Generator". For more information, please take a look at @code{tcg/README}. + +Some notable features of QEMU's dynamic translator are: + +@table @strong +@item CPU state optimisations: The target CPUs have many internal states which change the way it evaluates instructions. In order to achieve a good speed, the translation phase considers that some state information of the virtual CPU cannot change in it. The state is recorded in the Translation Block (TB). If the state changes (e.g. privilege level), a new TB will be generated and the previous TB won't be used anymore until the state -matches the state recorded in the previous TB. For example, if the SS, +matches the state recorded in the previous TB. The same idea can be applied +to other aspects of the CPU state. For example, on x86, if the SS, DS and ES segments have a zero base, then the translator does not even generate an addition for the segment base. -[The FPU stack pointer register is not handled that way yet]. - -@node Translation cache -@section Translation cache - -A 32 MByte cache holds the most recently used translations. For -simplicity, it is completely flushed when it is full. A translation unit -contains just a single basic block (a block of x86 instructions -terminated by a jump or by a virtual CPU state change which the -translator cannot deduce statically). - -@node Direct block chaining -@section Direct block chaining - +@item Direct block chaining: After each translated basic block is executed, QEMU uses the simulated Program Counter (PC) and other cpu state information (such as the CS segment base value) to find the next basic block. @@ -451,18 +202,17 @@ it easier to make the jump target modification atomic. On some host architectures (such as x86 or PowerPC), the @code{JUMP} opcode is directly patched so that the block chaining has no overhead. -@node Self-modifying code and translated code invalidation -@section Self-modifying code and translated code invalidation - +@item Self-modifying code and translated code invalidation: Self-modifying code is a special challenge in x86 emulation because no instruction cache invalidation is signaled by the application when code is modified. -When translated code is generated for a basic block, the corresponding -host page is write protected if it is not already read-only. Then, if -a write access is done to the page, Linux raises a SEGV signal. QEMU -then invalidates all the translated code in the page and enables write -accesses to the page. +User-mode emulation marks a host page as write-protected (if it is +not already read-only) every time translated code is generated for a +basic block. Then, if a write access is done to the page, Linux raises +a SEGV signal. QEMU then invalidates all the translated code in the page +and enables write accesses to the page. For system emulation, write +protection is achieved through the software MMU. Correct translated code invalidation is done efficiently by maintaining a linked list of every translated block contained in a given page. Other @@ -474,132 +224,95 @@ necessary. However, QEMU still requires that the generated code always matches the target instructions in memory in order to handle exceptions correctly. -@node Exception support -@section Exception support - +@item Exception support: longjmp() is used when an exception such as division by zero is encountered. The host SIGSEGV and SIGBUS signal handlers are used to get invalid -memory accesses. The simulated program counter is found by -retranslating the corresponding basic block and by looking where the -host program counter was at the exception point. - -The virtual CPU cannot retrieve the exact @code{EFLAGS} register because -in some cases it is not computed because of condition code -optimisations. It is not a big concern because the emulated code can -still be restarted in any cases. - -@node MMU emulation -@section MMU emulation - -For system emulation QEMU supports a soft MMU. In that mode, the MMU +memory accesses. QEMU keeps a map from host program counter to +target program counter, and looks up where the exception happened +based on the host program counter at the exception point. + +On some targets, some bits of the virtual CPU's state are not flushed to the +memory until the end of the translation block. This is done for internal +emulation state that is rarely accessed directly by the program and/or changes +very often throughout the execution of a translation block---this includes +condition codes on x86, delay slots on SPARC, conditional execution on +ARM, and so on. This state is stored for each target instruction, and +looked up on exceptions. + +@item MMU emulation: +For system emulation QEMU uses a software MMU. In that mode, the MMU virtual to physical address translation is done at every memory -access. QEMU uses an address translation cache to speed up the -translation. +access. +QEMU uses an address translation cache (TLB) to speed up the translation. In order to avoid flushing the translated code each time the MMU -mappings change, QEMU uses a physically indexed translation cache. It +mappings change, all caches in QEMU are physically indexed. This means that each basic block is indexed with its physical address. -When MMU mappings change, only the chaining of the basic blocks is -reset (i.e. a basic block can no longer jump directly to another one). - -@node Device emulation -@section Device emulation - -Systems emulated by QEMU are organized by boards. At initialization -phase, each board instantiates a number of CPUs, devices, RAM and -ROM. Each device in turn can assign I/O ports or memory areas (for -MMIO) to its handlers. When the emulation starts, an access to the -ports or MMIO memory areas assigned to the device causes the -corresponding handler to be called. - -RAM and ROM are handled more optimally, only the offset to the host -memory needs to be added to the guest address. - -The video RAM of VGA and other display cards is special: it can be -read or written directly like RAM, but write accesses cause the memory -to be marked with VGA_DIRTY flag as well. +In order to avoid invalidating the basic block chain when MMU mappings +change, chaining is only performed when the destination of the jump +shares a page with the basic block that is performing the jump. -QEMU supports some device classes like serial and parallel ports, USB, -drives and network devices, by providing APIs for easier connection to -the generic, higher level implementations. The API hides the -implementation details from the devices, like native device use or -advanced block device formats like QCOW. - -Usually the devices implement a reset method and register support for -saving and loading of the device state. The devices can also use -timers, especially together with the use of bottom halves (BHs). - -@node Hardware interrupts -@section Hardware interrupts - -In order to be faster, QEMU does not check at every basic block if a -hardware interrupt is pending. Instead, the user must asynchronously -call a specific function to tell that an interrupt is pending. This -function resets the chaining of the currently executing basic -block. It ensures that the execution will return soon in the main loop -of the CPU emulator. Then the main loop can test if the interrupt is -pending and handle it. - -@node User emulation specific details -@section User emulation specific details - -@subsection Linux system call translation - -QEMU includes a generic system call translator for Linux. It means that -the parameters of the system calls can be converted to fix the -endianness and 32/64 bit issues. The IOCTLs are converted with a generic -type description system (see @file{ioctls.h} and @file{thunk.c}). - -QEMU supports host CPUs which have pages bigger than 4KB. It records all -the mappings the process does and try to emulated the @code{mmap()} -system calls in cases where the host @code{mmap()} call would fail -because of bad page alignment. - -@subsection Linux signals - -Normal and real-time signals are queued along with their information -(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt -request is done to the virtual CPU. When it is interrupted, one queued -signal is handled by generating a stack frame in the virtual CPU as the -Linux kernel does. The @code{sigreturn()} system call is emulated to return -from the virtual signal handler. +The MMU can also distinguish RAM and ROM memory areas from MMIO memory +areas. Access is faster for RAM and ROM because the translation cache also +hosts the offset between guest address and host memory. Accessing MMIO +memory areas instead calls out to C code for device emulation. +Finally, the MMU helps tracking dirty pages and pages pointed to by +translation blocks. +@end table -Some signals (such as SIGALRM) directly come from the host. Other -signals are synthesized from the virtual CPU exceptions such as SIGFPE -when a division by zero is done (see @code{main.c:cpu_loop()}). +@node QEMU compared to other emulators +@section QEMU compared to other emulators -The blocked signal mask is still handled by the host Linux kernel so -that most signal system calls can be redirected directly to the host -Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system -calls need to be fully emulated (see @file{signal.c}). +Like bochs [1], QEMU emulates an x86 CPU. But QEMU is much faster than +bochs as it uses dynamic compilation. Bochs is closely tied to x86 PC +emulation while QEMU can emulate several processors. -@subsection clone() system call and threads +Like Valgrind [2], QEMU does user space emulation and dynamic +translation. Valgrind is mainly a memory debugger while QEMU has no +support for it (QEMU could be used to detect out of bound memory +accesses as Valgrind, but it has no support to track uninitialised data +as Valgrind does). The Valgrind dynamic translator generates better code +than QEMU (in particular it does register allocation) but it is closely +tied to an x86 host and target and has no support for precise exceptions +and system emulation. -The Linux clone() system call is usually used to create a thread. QEMU -uses the host clone() system call so that real host threads are created -for each emulated thread. One virtual CPU instance is created for each -thread. +EM86 [3] is the closest project to user space QEMU (and QEMU still uses +some of its code, in particular the ELF file loader). EM86 was limited +to an alpha host and used a proprietary and slow interpreter (the +interpreter part of the FX!32 Digital Win32 code translator [4]). -The virtual x86 CPU atomic operations are emulated with a global lock so -that their semantic is preserved. +TWIN from Willows Software was a Windows API emulator like Wine. It is less +accurate than Wine but includes a protected mode x86 interpreter to launch +x86 Windows executables. Such an approach has greater potential because most +of the Windows API is executed natively but it is far more difficult to +develop because all the data structures and function parameters exchanged +between the API and the x86 code must be converted. -Note that currently there are still some locking issues in QEMU. In -particular, the translated cache flush is not protected yet against -reentrancy. +User mode Linux [5] was the only solution before QEMU to launch a +Linux kernel as a process while not needing any host kernel +patches. However, user mode Linux requires heavy kernel patches while +QEMU accepts unpatched Linux kernels. The price to pay is that QEMU is +slower. -@subsection Self-virtualization +The Plex86 [6] PC virtualizer is done in the same spirit as the now +obsolete qemu-fast system emulator. It requires a patched Linux kernel +to work (you cannot launch the same kernel on your PC), but the +patches are really small. As it is a PC virtualizer (no emulation is +done except for some privileged instructions), it has the potential of +being faster than QEMU. The downside is that a complicated (and +potentially unsafe) host kernel patch is needed. -QEMU was conceived so that ultimately it can emulate itself. Although -it is not very useful, it is an important test to show the power of the -emulator. +The commercial PC Virtualizers (VMWare [7], VirtualPC [8]) are faster +than QEMU (without virtualization), but they all need specific, proprietary +and potentially unsafe host drivers. Moreover, they are unable to +provide cycle exact simulation as an emulator can. -Achieving self-virtualization is not easy because there may be address -space conflicts. QEMU user emulators solve this problem by being an -executable ELF shared object as the ld-linux.so ELF interpreter. That -way, it can be relocated at load time. +VirtualBox [9], Xen [10] and KVM [11] are based on QEMU. QEMU-SystemC +[12] uses QEMU to simulate a system where some hardware devices are +developed in SystemC. @node Bibliography @section Bibliography @@ -656,43 +369,3 @@ Kernel Based Virtual Machine (KVM). QEMU-SystemC, a hardware co-simulator. @end table - -@node Regression Tests -@chapter Regression Tests - -In the directory @file{tests/}, various interesting testing programs -are available. They are used for regression testing. - -@menu -* test-i386:: -* linux-test:: -@end menu - -@node test-i386 -@section @file{test-i386} - -This program executes most of the 16 bit and 32 bit x86 instructions and -generates a text output. It can be compared with the output obtained with -a real CPU or another emulator. The target @code{make test} runs this -program and a @code{diff} on the generated output. - -The Linux system call @code{modify_ldt()} is used to create x86 selectors -to test some 16 bit addressing and 32 bit with segmentation cases. - -The Linux system call @code{vm86()} is used to test vm86 emulation. - -Various exceptions are raised to test most of the x86 user space -exception reporting. - -@node linux-test -@section @file{linux-test} - -This program tests various Linux system calls. It is used to verify -that the system call parameters are correctly converted between target -and host CPUs. - -@node Index -@chapter Index -@printindex cp - -@bye @@ -171,10 +171,8 @@ SectionEnd Section "Documentation" SectionDoc SetOutPath "$INSTDIR" File "${BINDIR}\qemu-doc.html" - File "${BINDIR}\qemu-tech.html" CreateDirectory "$SMPROGRAMS\${PRODUCT}" CreateShortCut "$SMPROGRAMS\${PRODUCT}\User Documentation.lnk" "$INSTDIR\qemu-doc.html" "" "$INSTDIR\qemu-doc.html" 0 - CreateShortCut "$SMPROGRAMS\${PRODUCT}\Technical Documentation.lnk" "$INSTDIR\qemu-tech.html" "" "$INSTDIR\qemu-tech.html" 0 SectionEnd !endif @@ -219,7 +217,6 @@ Section "Uninstall" Delete "$INSTDIR\qemu.exe" Delete "$INSTDIR\qemu-system-*.exe" Delete "$INSTDIR\qemu-doc.html" - Delete "$INSTDIR\qemu-tech.html" RMDir /r "$INSTDIR\keymaps" RMDir /r "$INSTDIR\share" ; Remove generated files diff --git a/qga/commands.c b/qga/commands.c index 50fd26a..edd3e83 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -16,6 +16,7 @@ #include "qapi/qmp/qerror.h" #include "qemu/base64.h" #include "qemu/cutils.h" +#include "qemu/atomic.h" /* Maximum captured guest-exec out_data/err_data - 16MB */ #define GUEST_EXEC_MAX_OUTPUT (16*1024*1024) @@ -82,7 +83,7 @@ struct GuestExecIOData { guchar *data; gsize size; gsize length; - gint closed; + bool closed; bool truncated; const char *name; }; @@ -93,7 +94,7 @@ struct GuestExecInfo { int64_t pid_numeric; gint status; bool has_output; - gint finished; + bool finished; GuestExecIOData in; GuestExecIOData out; GuestExecIOData err; @@ -156,13 +157,13 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **err) ges = g_new0(GuestExecStatus, 1); - bool finished = g_atomic_int_get(&gei->finished); + bool finished = atomic_mb_read(&gei->finished); /* need to wait till output channels are closed * to be sure we captured all output at this point */ if (gei->has_output) { - finished = finished && g_atomic_int_get(&gei->out.closed); - finished = finished && g_atomic_int_get(&gei->err.closed); + finished = finished && atomic_mb_read(&gei->out.closed); + finished = finished && atomic_mb_read(&gei->err.closed); } ges->exited = finished; @@ -264,7 +265,7 @@ static void guest_exec_child_watch(GPid pid, gint status, gpointer data) (int32_t)gpid_to_int64(pid), (uint32_t)status); gei->status = status; - gei->finished = true; + atomic_mb_set(&gei->finished, true); g_spawn_close_pid(pid); } @@ -320,7 +321,7 @@ static gboolean guest_exec_input_watch(GIOChannel *ch, done: g_io_channel_shutdown(ch, true, NULL); g_io_channel_unref(ch); - g_atomic_int_set(&p->closed, 1); + atomic_mb_set(&p->closed, true); g_free(p->data); return false; @@ -374,7 +375,7 @@ static gboolean guest_exec_output_watch(GIOChannel *ch, close: g_io_channel_shutdown(ch, true, NULL); g_io_channel_unref(ch); - g_atomic_int_set(&p->closed, 1); + atomic_mb_set(&p->closed, true); return false; } diff --git a/qga/vss-win32/Makefile.objs b/qga/vss-win32/Makefile.objs index 7c96c6b..23d08da 100644 --- a/qga/vss-win32/Makefile.objs +++ b/qga/vss-win32/Makefile.objs @@ -7,7 +7,7 @@ $(obj-qga-vss-dll-obj-y): QEMU_CXXFLAGS = $(filter-out -Wstrict-prototypes -Wmis $(obj)/qga-vss.dll: LDFLAGS = -shared -Wl,--add-stdcall-alias,--enable-stdcall-fixup -lole32 -loleaut32 -lshlwapi -luuid -static $(obj)/qga-vss.dll: $(obj-qga-vss-dll-obj-y) $(SRC_PATH)/$(obj)/qga-vss.def - $(call quiet-command,$(CXX) -o $@ $(qga-vss-dll-obj-y) $(SRC_PATH)/qga/vss-win32/qga-vss.def $(CXXFLAGS) $(LDFLAGS)," LINK $(TARGET_DIR)$@") + $(call quiet-command,$(CXX) -o $@ $(qga-vss-dll-obj-y) $(SRC_PATH)/qga/vss-win32/qga-vss.def $(CXXFLAGS) $(LDFLAGS),"LINK","$(TARGET_DIR)$@") # rules to build qga-provider.tlb @@ -17,7 +17,7 @@ MIDL=$(WIN_SDK)/Bin/midl $(obj)/qga-vss.tlb: $(SRC_PATH)/$(obj)/qga-vss.idl ifeq ($(WIN_SDK),"") - $(call quiet-command,cp $(dir $<)qga-vss.tlb $@, " COPY $(TARGET_DIR)$@") + $(call quiet-command,cp $(dir $<)qga-vss.tlb $@,"COPY","$(TARGET_DIR)$@") else - $(call quiet-command,$(MIDL) -tlb $@ -I $(WIN_SDK)/Include $<," MIDL $(TARGET_DIR)$@") + $(call quiet-command,$(MIDL) -tlb $@ -I $(WIN_SDK)/Include $<,"MIDL","$(TARGET_DIR)$@") endif @@ -120,10 +120,10 @@ void cpu_reset_interrupt(CPUState *cpu, int mask) void cpu_exit(CPUState *cpu) { - cpu->exit_request = 1; + atomic_set(&cpu->exit_request, 1); /* Ensure cpu_exec will see the exit request after TCG has exited. */ smp_wmb(); - cpu->tcg_exit_req = 1; + atomic_set(&cpu->tcg_exit_req, 1); } int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, @@ -253,6 +253,7 @@ void cpu_reset(CPUState *cpu) static void cpu_common_reset(CPUState *cpu) { CPUClass *cc = CPU_GET_CLASS(cpu); + int i; if (qemu_loglevel_mask(CPU_LOG_RESET)) { qemu_log("CPU Reset (CPU %d)\n", cpu->cpu_index); @@ -268,7 +269,10 @@ static void cpu_common_reset(CPUState *cpu) cpu->can_do_io = 1; cpu->exception_index = -1; cpu->crash_occurred = false; - memset(cpu->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *)); + + for (i = 0; i < TB_JMP_CACHE_SIZE; ++i) { + atomic_set(&cpu->tb_jmp_cache[i], NULL); + } } static bool cpu_common_has_work(CPUState *cs) diff --git a/qom/object.c b/qom/object.c index 8166b7d..7a05e35 100644 --- a/qom/object.c +++ b/qom/object.c @@ -614,7 +614,7 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename, Object *inst; for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { - if (obj->class->object_cast_cache[i] == typename) { + if (atomic_read(&obj->class->object_cast_cache[i]) == typename) { goto out; } } @@ -631,10 +631,10 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename, if (obj && obj == inst) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { - obj->class->object_cast_cache[i - 1] = - obj->class->object_cast_cache[i]; + atomic_set(&obj->class->object_cast_cache[i - 1], + atomic_read(&obj->class->object_cast_cache[i])); } - obj->class->object_cast_cache[i - 1] = typename; + atomic_set(&obj->class->object_cast_cache[i - 1], typename); } out: @@ -704,7 +704,7 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, int i; for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { - if (class->class_cast_cache[i] == typename) { + if (atomic_read(&class->class_cast_cache[i]) == typename) { ret = class; goto out; } @@ -725,9 +725,10 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, #ifdef CONFIG_QOM_CAST_DEBUG if (class && ret == class) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { - class->class_cast_cache[i - 1] = class->class_cast_cache[i]; + atomic_set(&class->class_cast_cache[i - 1], + atomic_read(&class->class_cast_cache[i])); } - class->class_cast_cache[i - 1] = typename; + atomic_set(&class->class_cast_cache[i - 1], typename); } out: #endif @@ -57,9 +57,9 @@ expand-objs = $(strip $(sort $(filter %.o,$1)) \ $(filter-out %.o %.mo,$1)) %.o: %.c - $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," CC $(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<,"CC","$(TARGET_DIR)$@") %.o: %.rc - $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") + $(call quiet-command,$(WINDRES) -I. -o $@ $<,"RC","$(TARGET_DIR)$@") # If we have a CXX we might have some C++ objects, in which case we # must link with the C++ compiler, not the plain C compiler. @@ -67,22 +67,22 @@ LINKPROG = $(or $(CXX),$(CC)) LINK = $(call quiet-command, $(LINKPROG) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ $(call process-archive-undefs, $1) \ - $(version-obj-y) $(call extract-libs,$1) $(LIBS)," LINK $(TARGET_DIR)$@") + $(version-obj-y) $(call extract-libs,$1) $(LIBS),"LINK","$(TARGET_DIR)$@") %.o: %.S - $(call quiet-command,$(CCAS) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CCAS $(TARGET_DIR)$@") + $(call quiet-command,$(CCAS) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"CCAS","$(TARGET_DIR)$@") %.o: %.cc - $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," CXX $(TARGET_DIR)$@") + $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<,"CXX","$(TARGET_DIR)$@") %.o: %.cpp - $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," CXX $(TARGET_DIR)$@") + $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<,"CXX","$(TARGET_DIR)$@") %.o: %.m - $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," OBJC $(TARGET_DIR)$@") + $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<,"OBJC","$(TARGET_DIR)$@") %.o: %.dtrace - $(call quiet-command,dtrace -o $@ -G -s $<, " GEN $(TARGET_DIR)$@") + $(call quiet-command,dtrace -o $@ -G -s $<,"GEN","$(TARGET_DIR)$@") DSO_OBJ_CFLAGS := -fPIC -DBUILD_DSO module-common.o: CFLAGS += $(DSO_OBJ_CFLAGS) @@ -90,13 +90,13 @@ module-common.o: CFLAGS += $(DSO_OBJ_CFLAGS) %$(DSOSUF): %.mo $(call LINK,$^) @# Copy to build root so modules can be loaded when program started without install - $(if $(findstring /,$@),$(call quiet-command,cp $@ $(subst /,-,$@), " CP $(subst /,-,$@)")) + $(if $(findstring /,$@),$(call quiet-command,cp $@ $(subst /,-,$@),"CP","$(subst /,-,$@)")) LD_REL := $(CC) -nostdlib -Wl,-r $(LD_REL_FLAGS) %.mo: - $(call quiet-command,$(LD_REL) -o $@ $^," LD -r $(TARGET_DIR)$@") + $(call quiet-command,$(LD_REL) -o $@ $^,"LD","$(TARGET_DIR)$@") .PHONY: modules modules: @@ -105,9 +105,15 @@ modules: $(call LINK,$(filter %.o %.a %.mo, $^)) %.a: - $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^," AR $(TARGET_DIR)$@") + $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,"AR","$(TARGET_DIR)$@") -quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1)) +# Usage: $(call quiet-command,command and args,"NAME","args to print") +# This will run "command and args", and either: +# if V=1 just print the whole command and args +# otherwise print the 'quiet' output in the format " NAME args to print" +# NAME should be a short name of the command, 7 letters or fewer. +# If called with only a single argument, will print nothing in quiet mode. +quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) # cc-option # Usage: CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0) @@ -173,7 +179,7 @@ config-%.h: config-%.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ config-%.h-timestamp: config-%.mak $(SRC_PATH)/scripts/create_config - $(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, " GEN $(TARGET_DIR)config-$*.h") + $(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@,"GEN","$(TARGET_DIR)config-$*.h") .PHONY: clean-timestamp clean-timestamp: diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 7d7fe6e..43d5f9d 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -223,6 +223,13 @@ int cpu_cris_signal_handler(int host_signum, void *pinfo, void cris_initialize_tcg(void); void cris_initialize_crisv10_tcg(void); +/* Instead of computing the condition codes after each CRIS instruction, + * QEMU just stores one operand (called CC_SRC), the result + * (called CC_DEST) and the type of operation (called CC_OP). When the + * condition codes are needed, the condition codes can be calculated + * using this information. Condition codes are not generated if they + * are only needed for conditional branches. + */ enum { CC_OP_DYNAMIC, /* Use env->cc_op */ CC_OP_FLAGS, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1cb32ae..e645698 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -698,6 +698,13 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; /* Use a clearer name for this. */ #define CPU_INTERRUPT_INIT CPU_INTERRUPT_RESET +/* Instead of computing the condition codes after each x86 instruction, + * QEMU just stores one operand (called CC_SRC), the result + * (called CC_DST) and the type of operation (called CC_OP). When the + * condition codes are needed, the condition codes can be calculated + * using this information. Condition codes are not generated if they + * are only needed for conditional branches. + */ typedef enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitly computed, CC_SRC = flags */ diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index c2d40cb..471f490 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -154,6 +154,14 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); void cpu_m68k_flush_flags(CPUM68KState *, int); + +/* Instead of computing the condition codes after each m68k instruction, + * QEMU just stores one operand (called CC_SRC), the result + * (called CC_DEST) and the type of operation (called CC_OP). When the + * condition codes are needed, the condition codes can be calculated + * using this information. Condition codes are not generated if they + * are only needed for conditional branches. + */ enum { CC_OP_DYNAMIC, /* Use env->cc_op */ CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */ diff --git a/target-ppc/helper.h b/target-ppc/helper.h index a1c2962..796ad45 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -147,6 +147,9 @@ DEF_HELPER_4(vcmpequb, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequh, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequw, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequd, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneb, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneh, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnew, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezb, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezh, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezw, void, env, avr, avr, avr) @@ -166,6 +169,9 @@ DEF_HELPER_4(vcmpequb_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequh_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequw_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequd_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneb_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneh_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnew_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezb_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezh_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezw_dot, void, env, avr, avr, avr) @@ -337,6 +343,8 @@ DEF_HELPER_2(vpopcntb, void, avr, avr) DEF_HELPER_2(vpopcnth, void, avr, avr) DEF_HELPER_2(vpopcntw, void, avr, avr) DEF_HELPER_2(vpopcntd, void, avr, avr) +DEF_HELPER_1(vclzlsbb, tl, avr) +DEF_HELPER_1(vctzlsbb, tl, avr) DEF_HELPER_3(vbpermd, void, avr, avr, avr) DEF_HELPER_3(vbpermq, void, avr, avr, avr) DEF_HELPER_2(vgbbd, void, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 51a9ac5..202854f 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -735,20 +735,24 @@ VCMP(gtsd, >, s64) #undef VCMP_DO #undef VCMP -#define VCMPNEZ_DO(suffix, element, etype, record) \ -void helper_vcmpnez##suffix(CPUPPCState *env, ppc_avr_t *r, \ +#define VCMPNE_DO(suffix, element, etype, cmpzero, record) \ +void helper_vcmpne##suffix(CPUPPCState *env, ppc_avr_t *r, \ ppc_avr_t *a, ppc_avr_t *b) \ { \ etype ones = (etype)-1; \ etype all = ones; \ - etype none = 0; \ + etype result, none = 0; \ int i; \ \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - etype result = ((a->element[i] == 0) \ + if (cmpzero) { \ + result = ((a->element[i] == 0) \ || (b->element[i] == 0) \ || (a->element[i] != b->element[i]) ? \ ones : 0x0); \ + } else { \ + result = (a->element[i] != b->element[i]) ? ones : 0x0; \ + } \ r->element[i] = result; \ all &= result; \ none |= result; \ @@ -762,14 +766,17 @@ void helper_vcmpnez##suffix(CPUPPCState *env, ppc_avr_t *r, \ * suffix - instruction mnemonic suffix (b: byte, h: halfword, w: word) * element - element type to access from vector */ -#define VCMPNEZ(suffix, element, etype) \ - VCMPNEZ_DO(suffix, element, etype, 0) \ - VCMPNEZ_DO(suffix##_dot, element, etype, 1) -VCMPNEZ(b, u8, uint8_t) -VCMPNEZ(h, u16, uint16_t) -VCMPNEZ(w, u32, uint32_t) -#undef VCMPNEZ_DO -#undef VCMPNEZ +#define VCMPNE(suffix, element, etype, cmpzero) \ + VCMPNE_DO(suffix, element, etype, cmpzero, 0) \ + VCMPNE_DO(suffix##_dot, element, etype, cmpzero, 1) +VCMPNE(zb, u8, uint8_t, 1) +VCMPNE(zh, u16, uint16_t, 1) +VCMPNE(zw, u32, uint32_t, 1) +VCMPNE(b, u8, uint8_t, 0) +VCMPNE(h, u16, uint16_t, 0) +VCMPNE(w, u32, uint32_t, 0) +#undef VCMPNE_DO +#undef VCMPNE #define VCMPFP_DO(suffix, compare, order, record) \ void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \ @@ -874,6 +881,36 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT +target_ulong helper_vclzlsbb(ppc_avr_t *r) +{ + target_ulong count = 0; + int i; + VECTOR_FOR_INORDER_I(i, u8) { + if (r->u8[i] & 0x01) { + break; + } + count++; + } + return count; +} + +target_ulong helper_vctzlsbb(ppc_avr_t *r) +{ + target_ulong count = 0; + int i; +#if defined(HOST_WORDS_BIGENDIAN) + for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) { +#else + for (i = 0; i < ARRAY_SIZE(r->u8); i++) { +#endif + if (r->u8[i] & 0x01) { + break; + } + count++; + } + return count; +} + void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index a18d4d5..9c4834c 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -80,6 +80,7 @@ static int cap_ppc_watchdog; static int cap_papr; static int cap_htab_fd; static int cap_fixup_hcalls; +static int cap_htm; /* Hardware transactional memory support */ static uint32_t debug_inst_opcode; @@ -101,6 +102,16 @@ static void kvm_kick_cpu(void *opaque) qemu_cpu_kick(CPU(cpu)); } +/* Check whether we are running with KVM-PR (instead of KVM-HV). This + * should only be used for fallback tests - generally we should use + * explicit capabilities for the features we want, rather than + * assuming what is/isn't available depending on the KVM variant. */ +static bool kvmppc_is_pr(KVMState *ks) +{ + /* Assume KVM-PR if the GET_PVINFO capability is available */ + return kvm_check_extension(ks, KVM_CAP_PPC_GET_PVINFO) != 0; +} + static int kvm_ppc_register_host_cpu_type(void); int kvm_arch_init(MachineState *ms, KVMState *s) @@ -122,6 +133,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) * only activated after this by kvmppc_set_papr() */ cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); + cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -221,10 +233,9 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu, * * For that to work we make a few assumptions: * - * - If KVM_CAP_PPC_GET_PVINFO is supported we are running "PR" - * KVM which only supports 4K and 16M pages, but supports them - * regardless of the backing store characteritics. We also don't - * support 1T segments. + * - Check whether we are running "PR" KVM which only supports 4K + * and 16M pages, but supports them regardless of the backing + * store characteritics. We also don't support 1T segments. * * This is safe as if HV KVM ever supports that capability or PR * KVM grows supports for more page/segment sizes, those versions @@ -239,7 +250,7 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu, * implements KVM_CAP_PPC_GET_SMMU_INFO and thus doesn't hit * this fallback. */ - if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + if (kvmppc_is_pr(cs->kvm_state)) { /* No flags */ info->flags = 0; info->slb_size = 64; @@ -559,11 +570,18 @@ int kvm_arch_init_vcpu(CPUState *cs) idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, kvm_kick_cpu, cpu); - /* Some targets support access to KVM's guest TLB. */ switch (cenv->mmu_model) { case POWERPC_MMU_BOOKE206: + /* This target supports access to KVM's guest TLB */ ret = kvm_booke206_tlb_init(cpu); break; + case POWERPC_MMU_2_07: + if (!cap_htm && !kvmppc_is_pr(cs->kvm_state)) { + /* KVM-HV has transactional memory on POWER8 also without the + * KVM_CAP_PPC_HTM extension, so enable it here instead. */ + cap_htm = true; + } + break; default: break; } @@ -2268,11 +2286,8 @@ int kvmppc_reset_htab(int shift_hint) /* We have a kernel that predates the htab reset calls. For PR * KVM, we need to allocate the htab ourselves, for an HV KVM of - * this era, it has allocated a 16MB fixed size hash table - * already. Kernels of this era have the GET_PVINFO capability - * only on PR, so we use this hack to determine the right - * answer */ - if (kvm_check_extension(kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + * this era, it has allocated a 16MB fixed size hash table already. */ + if (kvmppc_is_pr(kvm_state)) { /* PR - tell caller to allocate htab */ return 0; } else { @@ -2353,6 +2368,11 @@ bool kvmppc_has_cap_fixup_hcalls(void) return cap_fixup_hcalls; } +bool kvmppc_has_cap_htm(void) +{ + return cap_htm; +} + static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc) { ObjectClass *oc = OBJECT_CLASS(pcc); diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index a778184..bd1d78b 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -55,6 +55,7 @@ void kvmppc_hash64_free_pteg(uint64_t token); void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, target_ulong pte0, target_ulong pte1); bool kvmppc_has_cap_fixup_hcalls(void); +bool kvmppc_has_cap_htm(void); int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); @@ -249,6 +250,11 @@ static inline bool kvmppc_has_cap_fixup_hcalls(void) abort(); } +static inline bool kvmppc_has_cap_htm(void) +{ + return false; +} + static inline int kvmppc_enable_hwrng(void) { return -1; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 8eefd82..dab8f19 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6203,7 +6203,7 @@ static opcode_t opcodes[] = { GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), -GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER), +GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400001, PPC_INTEGER), GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), #if defined(TARGET_PPC64) GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x00600000, PPC_NONE, PPC2_ISA300), @@ -6297,7 +6297,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW), GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW), GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW), GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW), -GEN_HANDLER_E(bctar, 0x13, 0x10, 0x11, 0, PPC_NONE, PPC2_BCTAR_ISA207), +GEN_HANDLER_E(bctar, 0x13, 0x10, 0x11, 0x0000E000, PPC_NONE, PPC2_BCTAR_ISA207), GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER), GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW), #if defined(TARGET_PPC64) diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index 3ce374d..25cd073 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -510,7 +510,16 @@ GEN_VXRFORM(vcmpeqfp, 3, 3) GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM(vcmpgtfp, 3, 11) GEN_VXRFORM(vcmpbfp, 3, 15) - +GEN_VXRFORM(vcmpneb, 3, 0) +GEN_VXRFORM(vcmpneh, 3, 1) +GEN_VXRFORM(vcmpnew, 3, 2) + +GEN_VXRFORM_DUAL(vcmpequb, PPC_ALTIVEC, PPC_NONE, \ + vcmpneb, PPC_NONE, PPC2_ISA300) +GEN_VXRFORM_DUAL(vcmpequh, PPC_ALTIVEC, PPC_NONE, \ + vcmpneh, PPC_NONE, PPC2_ISA300) +GEN_VXRFORM_DUAL(vcmpequw, PPC_ALTIVEC, PPC_NONE, \ + vcmpnew, PPC_NONE, PPC2_ISA300) GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \ vcmpequd, PPC_NONE, PPC2_ALTIVEC_207) GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \ @@ -584,6 +593,18 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_NOA_3(name, opc2, opc3, opc4) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], rb); \ + tcg_temp_free_ptr(rb); \ + } GEN_VXFORM_NOA(vupkhsb, 7, 8); GEN_VXFORM_NOA(vupkhsh, 7, 9); GEN_VXFORM_NOA(vupkhsw, 7, 25); @@ -691,18 +712,18 @@ GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); -GEN_VXFORM_DUAL(vspltb, PPC_NONE, PPC2_ALTIVEC_207, - vextractub, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vsplth, PPC_NONE, PPC2_ALTIVEC_207, - vextractuh, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltw, PPC_NONE, PPC2_ALTIVEC_207, - vextractuw, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltisb, PPC_NONE, PPC2_ALTIVEC_207, - vinsertb, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltish, PPC_NONE, PPC2_ALTIVEC_207, - vinserth, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltisw, PPC_NONE, PPC2_ALTIVEC_207, - vinsertw, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltb, PPC_ALTIVEC, PPC_NONE, + vextractub, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vsplth, PPC_ALTIVEC, PPC_NONE, + vextractuh, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltw, PPC_ALTIVEC, PPC_NONE, + vextractuw, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisb, PPC_ALTIVEC, PPC_NONE, + vinsertb, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltish, PPC_ALTIVEC, PPC_NONE, + vinserth, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisw, PPC_ALTIVEC, PPC_NONE, + vinsertw, PPC_NONE, PPC2_ISA300); static void gen_vsldoi(DisasContext *ctx) { @@ -798,6 +819,8 @@ GEN_VXFORM_NOA_2(vctzb, 1, 24, 28) GEN_VXFORM_NOA_2(vctzh, 1, 24, 29) GEN_VXFORM_NOA_2(vctzw, 1, 24, 30) GEN_VXFORM_NOA_2(vctzd, 1, 24, 31) +GEN_VXFORM_NOA_3(vclzlsbb, 1, 24, 0) +GEN_VXFORM_NOA_3(vctzlsbb, 1, 24, 1) GEN_VXFORM_NOA(vpopcntb, 1, 28) GEN_VXFORM_NOA(vpopcnth, 1, 29) GEN_VXFORM_NOA(vpopcntw, 1, 30) diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index a7022a0..ac1dc9b 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -181,9 +181,6 @@ GEN_HANDLER2_E(name, str, 0x4, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_VXRFORM1_300(name, name, #name, opc2, opc3) \ GEN_VXRFORM1_300(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) -GEN_VXRFORM(vcmpequb, 3, 0) -GEN_VXRFORM(vcmpequh, 3, 1) -GEN_VXRFORM(vcmpequw, 3, 2) GEN_VXRFORM_300(vcmpnezb, 3, 4) GEN_VXRFORM_300(vcmpnezh, 3, 5) GEN_VXRFORM_300(vcmpnezw, 3, 6) @@ -197,28 +194,33 @@ GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequb, vcmpneb, 3, 0, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequh, vcmpneh, 3, 1, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequw, vcmpnew, 3, 2, PPC_ALTIVEC, PPC_NONE) #define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \ GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \ PPC_NONE) GEN_VXFORM_DUAL_INV(vspltb, vextractub, 6, 8, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vsplth, vextractuh, 6, 9, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltw, vextractuw, 6, 10, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_300_EXT(vextractd, 6, 11, 0x100000), GEN_VXFORM_DUAL_INV(vspltisb, vinsertb, 6, 12, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000), GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), GEN_VXFORM_300_EO(vctzd, 0x01, 0x18, 0x1F), +GEN_VXFORM_300_EO(vclzlsbb, 0x01, 0x18, 0x0), +GEN_VXFORM_300_EO(vctzlsbb, 0x01, 0x18, 0x1), GEN_VXFORM_300(vpermr, 0x1D, 0xFF), #define GEN_VXFORM_NOA(name, opc2, opc3) \ diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index eee6052..23ec1e1 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -75,7 +75,6 @@ static void gen_lxvdsx(DisasContext *ctx) static void gen_lxvw4x(DisasContext *ctx) { TCGv EA; - TCGv_i64 tmp; TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); if (unlikely(!ctx->vsx_enabled)) { @@ -84,22 +83,95 @@ static void gen_lxvw4x(DisasContext *ctx) } gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); - tmp = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld32u_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, xth, EA); - tcg_gen_deposit_i64(xth, xth, tmp, 32, 32); + if (ctx->le_mode) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_shri_i64(t1, t0, 32); + tcg_gen_deposit_i64(xth, t1, t0, 32, 32); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_shri_i64(t1, t0, 32); + tcg_gen_deposit_i64(xtl, t1, t0, 32, 32); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } else { + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + } + tcg_temp_free(EA); +} + +static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl, + TCGv_i64 inh, TCGv_i64 inl) +{ + TCGv_i64 mask = tcg_const_i64(0x00FF00FF00FF00FF); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + /* outh = ((inh & mask) << 8) | ((inh >> 8) & mask) */ + tcg_gen_and_i64(t0, inh, mask); + tcg_gen_shli_i64(t0, t0, 8); + tcg_gen_shri_i64(t1, inh, 8); + tcg_gen_and_i64(t1, t1, mask); + tcg_gen_or_i64(outh, t0, t1); + + /* outl = ((inl & mask) << 8) | ((inl >> 8) & mask) */ + tcg_gen_and_i64(t0, inl, mask); + tcg_gen_shli_i64(t0, t0, 8); + tcg_gen_shri_i64(t1, inl, 8); + tcg_gen_and_i64(t1, t1, mask); + tcg_gen_or_i64(outl, t0, t1); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(mask); +} + +static void gen_lxvh8x(DisasContext *ctx) +{ + TCGv EA; + TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + if (ctx->le_mode) { + gen_bswap16x8(xth, xtl, xth, xtl); + } + tcg_temp_free(EA); +} - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, xtl, EA); - tcg_gen_deposit_i64(xtl, xtl, tmp, 32, 32); +static void gen_lxvb16x(DisasContext *ctx) +{ + TCGv EA; + TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); tcg_temp_free(EA); - tcg_temp_free_i64(tmp); } #define VSX_STORE_SCALAR(name, operation) \ @@ -142,7 +214,8 @@ static void gen_stxvd2x(DisasContext *ctx) static void gen_stxvw4x(DisasContext *ctx) { - TCGv_i64 tmp; + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); TCGv EA; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); @@ -151,21 +224,75 @@ static void gen_stxvw4x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - tmp = tcg_temp_new_i64(); + if (ctx->le_mode) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_shri_i64(t0, xsh, 32); + tcg_gen_deposit_i64(t1, t0, xsh, 32, 32); + tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_shri_i64(t0, xsl, 32); + tcg_gen_deposit_i64(t1, t0, xsl, 32, 32); + tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } else { + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + } + tcg_temp_free(EA); +} - tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32); - gen_qemu_st32_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); +static void gen_stxvh8x(DisasContext *ctx) +{ + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); + TCGv EA; - tcg_gen_shri_i64(tmp, cpu_vsrl(xS(ctx->opcode)), 32); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + if (ctx->le_mode) { + TCGv_i64 outh = tcg_temp_new_i64(); + TCGv_i64 outl = tcg_temp_new_i64(); + + gen_bswap16x8(outh, outl, xsh, xsl); + tcg_gen_qemu_st_i64(outh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(outl, EA, ctx->mem_idx, MO_BEQ); + tcg_temp_free_i64(outh); + tcg_temp_free_i64(outl); + } else { + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + } + tcg_temp_free(EA); +} +static void gen_stxvb16x(DisasContext *ctx) +{ + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); + TCGv EA; + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); tcg_temp_free(EA); - tcg_temp_free_i64(tmp); } #define MV_VSRW(name, tcgop1, tcgop2, target, source) \ @@ -217,6 +344,65 @@ static void gen_##name(DisasContext *ctx) \ MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode))) MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]) +static void gen_mfvsrld(DisasContext *ctx) +{ + if (xS(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], cpu_vsrl(xS(ctx->opcode))); +} + +static void gen_mtvsrdd(DisasContext *ctx) +{ + if (xT(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + if (!rA(ctx->opcode)) { + tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), 0); + } else { + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]); + } + + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rB(ctx->opcode)]); +} + +static void gen_mtvsrws(DisasContext *ctx) +{ + if (xT(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], 32, 32); + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xT(ctx->opcode))); +} + #endif static void gen_xxpermdi(DisasContext *ctx) diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 414b73b..10eb4b9 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -7,6 +7,8 @@ GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(lxvb16x, 0x1F, 0x0C, 0x1B, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300), @@ -15,6 +17,8 @@ GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxvh8x, 0x1F, 0x0C, 0x1D, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(stxvb16x, 0x1F, 0x0C, 0x1F, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207), @@ -22,6 +26,9 @@ GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207), #if defined(TARGET_PPC64) GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(mfvsrld, 0X1F, 0x13, 0x09, 0x0000F800, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(mtvsrdd, 0X1F, 0x13, 0x0D, 0x0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(mtvsrws, 0x1F, 0x13, 0x0C, 0x0000F800, PPC_NONE, PPC2_ISA300), #endif #define GEN_XX1FORM(name, opc2, opc3, fl2) \ diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 4329d39..6b02b17 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -14,10 +14,10 @@ endif $(feat-dst)gen-features.h: $(feat-dst)gen-features.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ $(feat-dst)gen-features.h-timestamp: $(feat-dst)gen-features - $(call quiet-command,$< >$@," GEN $(TARGET_DIR)gen-features.h") + $(call quiet-command,$< >$@,"GEN","$(TARGET_DIR)gen-features.h") $(feat-dst)gen-features: $(feat-src)gen-features.c - $(call quiet-command,$(HOST_CC) $(QEMU_INCLUDES) -o $@ $<," CC $(TARGET_DIR)gen-features") + $(call quiet-command,$(HOST_CC) $(QEMU_INCLUDES) -o $@ $<,"CC","$(TARGET_DIR)gen-features") clean-target: rm -f gen-features.h-timestamp diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 4fb34b5..4e58cde 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -671,6 +671,13 @@ ObjectClass *s390_cpu_class_by_name(const char *name); /* CC optimization */ +/* Instead of computing the condition codes after each x86 instruction, + * QEMU just stores the result (called CC_DST), the type of operation + * (called CC_OP) and whatever operands are needed (CC_SRC and possibly + * CC_VR). When the condition codes are needed, the condition codes can + * be calculated using this information. Condition codes are not generated + * if they are only needed for conditional branches. + */ enum cc_op { CC_OP_CONST0 = 0, /* CC is 0 */ CC_OP_CONST1, /* CC is 1 */ diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index a3d64a4..646a103 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -102,6 +102,11 @@ #define CC_DST (env->cc_dst) #define CC_OP (env->cc_op) +/* Even though lazy evaluation of CPU condition codes tends to be less + * important on RISC systems where condition codes are only updated + * when explicitly requested, SPARC uses it to update 32-bit and 64-bit + * condition codes. + */ enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_FLAGS, /* all cc are back in status register */ @@ -8,6 +8,11 @@ in the QOP code generator written by Paul Brook. 2) Definitions +TCG receives RISC-like "TCG ops" and performs some optimizations on them, +including liveness analysis and trivial constant expression +evaluation. TCG ops are then implemented in the host CPU back end, +also known as the TCG "target". + The TCG "target" is the architecture for which we generate the code. It is of course not the same as the "target" of QEMU which is the emulated architecture. As TCG started as a generic C backend used diff --git a/tcg/optimize.c b/tcg/optimize.c index 9998ac7..0f13490 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -468,9 +468,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, default: return 2; } - } else { - return 2; } + return 2; } /* Return 2 if the condition can't be simplified, and the result diff --git a/tests/Makefile.include b/tests/Makefile.include index 8162f6f..a77777c 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -271,6 +271,13 @@ check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF) check-qtest-ppc64-y += tests/rtas-test$(EXESUF) +check-qtest-ppc64-y += tests/pxe-test$(EXESUF) +check-qtest-ppc64-y += tests/usb-hcd-ohci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-ohci.c +check-qtest-ppc64-y += tests/usb-hcd-uhci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-uhci.c +check-qtest-ppc64-y += tests/usb-hcd-xhci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-xhci.c check-qtest-sh4-y = tests/endianness-test$(EXESUF) @@ -517,27 +524,27 @@ tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-qapi-event.c tests/test-qapi-event.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-qmp-introspect.c tests/test-qmp-introspect.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) @@ -590,12 +597,13 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o libqos-spapr-obj-y += tests/libqos/libqos-spapr.o libqos-spapr-obj-y += tests/libqos/rtas.o +libqos-spapr-obj-y += tests/libqos/pci-spapr.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o -libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o +libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o @@ -671,7 +679,7 @@ tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/cor tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/migration/stress$(EXESUF): tests/migration/stress.o - $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ," LINK $(TARGET_DIR)$@") + $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@") INITRD_WORK_DIR=tests/migration/initrd @@ -734,7 +742,7 @@ $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ QTEST_QEMU_IMG=qemu-img$(EXESUF) \ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ - gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER $@") + gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER","$@") $(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y) $(gcov-files-generic-y); do \ echo Gcov report for $$f:;\ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ @@ -745,7 +753,7 @@ $(patsubst %, check-%, $(check-unit-y)): check-%: % $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,) $(call quiet-command, \ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ - gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*") + gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER","$*") $(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y) $(gcov-files-generic-y); do \ echo Gcov report for $$f:;\ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ @@ -756,18 +764,18 @@ $(patsubst %, check-%, $(check-unit-y)): check-%: % $(patsubst %, check-report-qtest-%.xml, $(QTEST_TARGETS)): check-report-qtest-%.xml: $(check-qtest-y) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ QTEST_QEMU_IMG=qemu-img$(EXESUF) \ - gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER $@") + gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER","$@") check-report-unit.xml: $(check-unit-y) - $(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^, "GTESTER $@") + $(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^,"GTESTER","$@") # Reports and overall runs check-report.xml: $(patsubst %,check-report-qtest-%.xml, $(QTEST_TARGETS)) check-report-unit.xml - $(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, " GEN $@") + $(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@,"GEN","$@") check-report.html: check-report.xml - $(call quiet-command,gtester-report $< > $@, " GEN $@") + $(call quiet-command,gtester-report $< > $@,"GEN","$@") # Other tests @@ -787,7 +795,7 @@ $(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \ $^ >$*.test.out 2>$*.test.err; \ echo $$? >$*.test.exit, \ - " TEST $*.out") + "TEST","$*.out") @diff -q $(SRC_PATH)/$*.out $*.test.out @# Sanitize error messages (make them independent of build directory) @perl -p -e 's|\Q$(SRC_PATH)\E/||g' $*.test.err | diff -q $(SRC_PATH)/$*.err - diff --git a/tests/boot-sector.c b/tests/boot-sector.c index 3ffe298..e3193c0 100644 --- a/tests/boot-sector.c +++ b/tests/boot-sector.c @@ -77,6 +77,15 @@ int boot_sector_init(const char *fname) fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno)); return 1; } + + /* For Open Firmware based system, we can use a Forth script instead */ + if (strcmp(qtest_get_arch(), "ppc64") == 0) { + memset(boot_sector, ' ', sizeof boot_sector); + sprintf((char *)boot_sector, "\\ Bootscript\n%x %x c! %x %x c!\n", + LOW(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET, + HIGH(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); + } + fwrite(boot_sector, 1, sizeof boot_sector, f); fclose(f); return 0; diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 2fcc3c6..b44daab 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -25,7 +25,7 @@ make-archive-maybe = $(if $(wildcard $1/*), \ else \ git archive -1 $$(git stash create) --format=tar.gz; \ fi) > $2, \ - " ARCHIVE $(notdir $2)")) + "ARCHIVE","$(notdir $2)")) CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$) DOCKER_SRC_COPY := docker-src.$(CUR_TIME) @@ -36,7 +36,7 @@ $(DOCKER_SRC_COPY): $(call make-archive-maybe, $(SRC_PATH)/dtc, $@/dtc.tgz) $(call make-archive-maybe, $(SRC_PATH)/pixman, $@/pixman.tgz) $(call quiet-command, cp $(SRC_PATH)/tests/docker/run $@/run, \ - " COPY RUNNER") + "COPY","RUNNER") docker-qemu-src: $(DOCKER_SRC_COPY) @@ -51,7 +51,7 @@ docker-image-%: $(DOCKER_FILES_DIR)/%.docker $(SRC_PATH)/tests/docker/docker.py build qemu:$* $< \ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ $(if $(EXECUTABLE),--include-executable=$(EXECUTABLE)),\ - " BUILD $*") + "BUILD","$*") # Expand all the pre-requistes for each docker image and test combination $(foreach i,$(DOCKER_IMAGES), \ @@ -125,7 +125,7 @@ docker-run-%: docker-qemu-src /var/tmp/qemu/run \ $(CMD); \ fi \ - , " RUN $(CMD) in $(IMAGE)"))) + ,"RUN","$(CMD) in $(IMAGE)"))) docker-clean: $(call quiet-command, $(SRC_PATH)/tests/docker/docker.py clean) diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c index d497b08..3979b20 100644 --- a/tests/e1000e-test.c +++ b/tests/e1000e-test.c @@ -390,7 +390,7 @@ static void data_test_init(e1000e_device *d) qtest_start(cmdline); g_free(cmdline); - test_bus = qpci_init_pc(); + test_bus = qpci_init_pc(NULL); g_assert_nonnull(test_bus); test_alloc = pc_alloc_init(); diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c index 3542ad1..da2d5a5 100644 --- a/tests/i440fx-test.c +++ b/tests/i440fx-test.c @@ -38,7 +38,7 @@ static QPCIBus *test_start_get_bus(const TestData *s) cmdline = g_strdup_printf("-smp %d", s->num_cpus); qtest_start(cmdline); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void test_i440fx_defaults(gconstpointer opaque) diff --git a/tests/ide-test.c b/tests/ide-test.c index 1e51af2..a8a4081 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -143,7 +143,7 @@ static QPCIDevice *get_pci_device(uint16_t *bmdma_base) uint16_t vendor_id, device_id; if (!pcibus) { - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); } /* Find PCI device and verify it's the right one */ diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c index 0957ee7..f36bfe7 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c @@ -105,7 +105,7 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix) uint64_t barsize; s->qtest = qtest_start(cmd); - s->pcibus = qpci_init_pc(); + s->pcibus = qpci_init_pc(NULL); s->dev = get_device(s->pcibus); s->reg_base = qpci_iomap(s->dev, 0, &barsize); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index f3be550..716ab79 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -128,7 +128,7 @@ QPCIDevice *get_ahci_device(uint32_t *fingerprint) uint32_t ahci_fingerprint; QPCIBus *pcibus; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); /* Find the AHCI PCI device and verify it's the right one. */ ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index df34092..b554758 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -1,10 +1,14 @@ #include "qemu/osdep.h" #include "libqos/libqos-pc.h" #include "libqos/malloc-pc.h" +#include "libqos/pci-pc.h" static QOSOps qos_ops = { .init_allocator = pc_alloc_init_flags, - .uninit_allocator = pc_alloc_uninit + .uninit_allocator = pc_alloc_uninit, + .qpci_init = qpci_init_pc, + .qpci_free = qpci_free_pc, + .shutdown = qtest_pc_shutdown, }; QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) @@ -28,5 +32,5 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) void qtest_pc_shutdown(QOSState *qs) { - return qtest_shutdown(qs); + return qtest_common_shutdown(qs); } diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c index f19408b..a37791e 100644 --- a/tests/libqos/libqos-spapr.c +++ b/tests/libqos/libqos-spapr.c @@ -1,10 +1,14 @@ #include "qemu/osdep.h" #include "libqos/libqos-spapr.h" #include "libqos/malloc-spapr.h" +#include "libqos/pci-spapr.h" static QOSOps qos_ops = { .init_allocator = spapr_alloc_init_flags, - .uninit_allocator = spapr_alloc_uninit + .uninit_allocator = spapr_alloc_uninit, + .qpci_init = qpci_init_spapr, + .qpci_free = qpci_free_spapr, + .shutdown = qtest_spapr_shutdown, }; QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) @@ -26,5 +30,5 @@ QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...) void qtest_spapr_shutdown(QOSState *qs) { - return qtest_shutdown(qs); + return qtest_common_shutdown(qs); } diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index a852dc5..7abb482 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -20,8 +20,13 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); qs->ops = ops; - if (ops && ops->init_allocator) { - qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + if (ops) { + if (ops->init_allocator) { + qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + } + if (ops->qpci_init && qs->alloc) { + qs->pcibus = ops->qpci_init(qs->alloc); + } } g_free(cmdline); @@ -47,16 +52,31 @@ QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) /** * Tear down the QEMU instance. */ -void qtest_shutdown(QOSState *qs) +void qtest_common_shutdown(QOSState *qs) { - if (qs->alloc && qs->ops && qs->ops->uninit_allocator) { - qs->ops->uninit_allocator(qs->alloc); - qs->alloc = NULL; + if (qs->ops) { + if (qs->pcibus && qs->ops->qpci_free) { + qs->ops->qpci_free(qs->pcibus); + qs->pcibus = NULL; + } + if (qs->alloc && qs->ops->uninit_allocator) { + qs->ops->uninit_allocator(qs->alloc); + qs->alloc = NULL; + } } qtest_quit(qs->qts); g_free(qs); } +void qtest_shutdown(QOSState *qs) +{ + if (qs->ops && qs->ops->shutdown) { + qs->ops->shutdown(qs); + } else { + qtest_common_shutdown(qs); + } +} + void set_context(QOSState *s) { global_qtest = s->qts; diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index 604980d..2319697 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -5,19 +5,26 @@ #include "libqos/pci.h" #include "libqos/malloc-pc.h" +typedef struct QOSState QOSState; + typedef struct QOSOps { QGuestAllocator *(*init_allocator)(QAllocOpts); void (*uninit_allocator)(QGuestAllocator *); + QPCIBus *(*qpci_init)(QGuestAllocator *alloc); + void (*qpci_free)(QPCIBus *bus); + void (*shutdown)(QOSState *); } QOSOps; -typedef struct QOSState { +struct QOSState { QTestState *qts; QGuestAllocator *alloc; + QPCIBus *pcibus; QOSOps *ops; -} QOSState; +}; QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); +void qtest_common_shutdown(QOSState *qs); void qtest_shutdown(QOSState *qs); bool have_qemu_img(void); void mkimg(const char *file, const char *fmt, unsigned size_mb); diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 1ae2d37..9600ed6 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -212,7 +212,7 @@ static void qpci_pc_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -QPCIBus *qpci_init_pc(void) +QPCIBus *qpci_init_pc(QGuestAllocator *alloc) { QPCIBusPC *ret; @@ -255,28 +255,6 @@ void qpci_free_pc(QPCIBus *bus) g_free(s); } -void qpci_plug_device_test(const char *driver, const char *id, - uint8_t slot, const char *opts) -{ - QDict *response; - char *cmd; - - cmd = g_strdup_printf("{'execute': 'device_add'," - " 'arguments': {" - " 'driver': '%s'," - " 'addr': '%d'," - " %s%s" - " 'id': '%s'" - "}}", driver, slot, - opts ? opts : "", opts ? "," : "", - id); - response = qmp(cmd); - g_free(cmd); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - QDECREF(response); -} - void qpci_unplug_acpi_device_test(const char *id, uint8_t slot) { QDict *response; diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h index 2621179..9479b51 100644 --- a/tests/libqos/pci-pc.h +++ b/tests/libqos/pci-pc.h @@ -14,8 +14,9 @@ #define LIBQOS_PCI_PC_H #include "libqos/pci.h" +#include "libqos/malloc.h" -QPCIBus *qpci_init_pc(void); +QPCIBus *qpci_init_pc(QGuestAllocator *alloc); void qpci_free_pc(QPCIBus *bus); #endif diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c new file mode 100644 index 0000000..2f73bad --- /dev/null +++ b/tests/libqos/pci-spapr.c @@ -0,0 +1,288 @@ +/* + * libqos PCI bindings for SPAPR + * + * 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/osdep.h" +#include "libqtest.h" +#include "libqos/pci-spapr.h" +#include "libqos/rtas.h" + +#include "hw/pci/pci_regs.h" + +#include "qemu-common.h" +#include "qemu/host-utils.h" + + +/* From include/hw/pci-host/spapr.h */ + +#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL + +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL + +#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL +#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL +#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ + SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 + +/* index is the phb index */ + +#define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index)) +#define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \ + (index) * SPAPR_PCI_WINDOW_SPACING) +#define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF) +#define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF) + +typedef struct QPCIBusSPAPR { + QPCIBus bus; + QGuestAllocator *alloc; + + uint64_t pci_hole_start; + uint64_t pci_hole_size; + uint64_t pci_hole_alloc; + + uint32_t pci_iohole_start; + uint32_t pci_iohole_size; + uint32_t pci_iohole_alloc; +} QPCIBusSPAPR; + +/* + * PCI devices are always little-endian + * SPAPR by default is big-endian + * so PCI accessors need to swap data endianness + */ + +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint8_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readb(IOBASE(0) + port); + } else { + v = readb(MMIOBASE(0) + port); + } + return v; +} + +static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint16_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readw(IOBASE(0) + port); + } else { + v = readw(MMIOBASE(0) + port); + } + return bswap16(v); +} + +static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint32_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readl(IOBASE(0) + port); + } else { + v = readl(MMIOBASE(0) + port); + } + return bswap32(v); +} + +static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) +{ + uint64_t port = (uintptr_t)addr; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writeb(IOBASE(0) + port, value); + } else { + writeb(MMIOBASE(0) + port, value); + } +} + +static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) +{ + uint64_t port = (uintptr_t)addr; + value = bswap16(value); + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writew(IOBASE(0) + port, value); + } else { + writew(MMIOBASE(0) + port, value); + } +} + +static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) +{ + uint64_t port = (uintptr_t)addr; + value = bswap32(value); + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writel(IOBASE(0) + port, value); + } else { + writel(MMIOBASE(0) + port, value); + } +} + +static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 1); +} + +static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 2); +} + +static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 4); +} + +static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, + uint8_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 1, value); +} + +static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, + uint16_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 2, value); +} + +static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, + uint32_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 4, value); +} + +static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, + uint64_t *sizeptr) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + static const int bar_reg_map[] = { + PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, + }; + int bar_reg; + uint32_t addr; + uint64_t size; + uint32_t io_type; + + g_assert(barno >= 0 && barno <= 5); + bar_reg = bar_reg_map[barno]; + + qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); + addr = qpci_config_readl(dev, bar_reg); + + io_type = addr & PCI_BASE_ADDRESS_SPACE; + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + addr &= PCI_BASE_ADDRESS_IO_MASK; + } else { + addr &= PCI_BASE_ADDRESS_MEM_MASK; + } + + size = (1ULL << ctzl(addr)); + if (size == 0) { + return NULL; + } + if (sizeptr) { + *sizeptr = size; + } + + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + uint16_t loc; + + g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size + <= s->pci_iohole_size); + s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size); + loc = s->pci_iohole_start + s->pci_iohole_alloc; + s->pci_iohole_alloc += size; + + qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); + + return (void *)(unsigned long)loc; + } else { + uint64_t loc; + + g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size + <= s->pci_hole_size); + s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size); + loc = s->pci_hole_start + s->pci_hole_alloc; + s->pci_hole_alloc += size; + + qpci_config_writel(dev, bar_reg, loc); + + return (void *)(unsigned long)loc; + } +} + +static void qpci_spapr_iounmap(QPCIBus *bus, void *data) +{ + /* FIXME */ +} + +QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) +{ + QPCIBusSPAPR *ret; + + ret = g_malloc(sizeof(*ret)); + + ret->alloc = alloc; + + ret->bus.io_readb = qpci_spapr_io_readb; + ret->bus.io_readw = qpci_spapr_io_readw; + ret->bus.io_readl = qpci_spapr_io_readl; + + ret->bus.io_writeb = qpci_spapr_io_writeb; + ret->bus.io_writew = qpci_spapr_io_writew; + ret->bus.io_writel = qpci_spapr_io_writel; + + ret->bus.config_readb = qpci_spapr_config_readb; + ret->bus.config_readw = qpci_spapr_config_readw; + ret->bus.config_readl = qpci_spapr_config_readl; + + ret->bus.config_writeb = qpci_spapr_config_writeb; + ret->bus.config_writew = qpci_spapr_config_writew; + ret->bus.config_writel = qpci_spapr_config_writel; + + ret->bus.iomap = qpci_spapr_iomap; + ret->bus.iounmap = qpci_spapr_iounmap; + + ret->pci_hole_start = 0xC0000000; + ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; + ret->pci_hole_alloc = 0; + + ret->pci_iohole_start = 0xc000; + ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE; + ret->pci_iohole_alloc = 0; + + return &ret->bus; +} + +void qpci_free_spapr(QPCIBus *bus) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + + g_free(s); +} diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h new file mode 100644 index 0000000..4192126 --- /dev/null +++ b/tests/libqos/pci-spapr.h @@ -0,0 +1,17 @@ +/* + * libqos PCI bindings for SPAPR + * + * 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 LIBQOS_PCI_SPAPR_H +#define LIBQOS_PCI_SPAPR_H + +#include "libqos/malloc.h" +#include "libqos/pci.h" + +QPCIBus *qpci_init_spapr(QGuestAllocator *alloc); +void qpci_free_spapr(QPCIBus *bus); + +#endif diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index ed78d91..c3f3382 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -263,4 +263,24 @@ void qpci_iounmap(QPCIDevice *dev, void *data) dev->bus->iounmap(dev->bus, data); } - +void qpci_plug_device_test(const char *driver, const char *id, + uint8_t slot, const char *opts) +{ + QDict *response; + char *cmd; + + cmd = g_strdup_printf("{'execute': 'device_add'," + " 'arguments': {" + " 'driver': '%s'," + " 'addr': '%d'," + " %s%s" + " 'id': '%s'" + "}}", driver, slot, + opts ? opts : "", opts ? "," : "", + id); + response = qmp(cmd); + g_free(cmd); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); +} diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c index 820321a..0269803 100644 --- a/tests/libqos/rtas.c +++ b/tests/libqos/rtas.c @@ -69,3 +69,48 @@ int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns) return res; } + +uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size) +{ + int res; + uint32_t args[4], ret[2]; + + args[0] = addr; + args[1] = buid >> 32; + args[2] = buid & 0xffffffff; + args[3] = size; + res = qrtas_call(alloc, "ibm,read-pci-config", 4, args, 2, ret); + if (res != 0) { + return -1; + } + + if (ret[0] != 0) { + return -1; + } + + return ret[1]; +} + +int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size, uint32_t val) +{ + int res; + uint32_t args[5], ret[1]; + + args[0] = addr; + args[1] = buid >> 32; + args[2] = buid & 0xffffffff; + args[3] = size; + args[4] = val; + res = qrtas_call(alloc, "ibm,write-pci-config", 5, args, 1, ret); + if (res != 0) { + return -1; + } + + if (ret[0] != 0) { + return -1; + } + + return 0; +} diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h index a1b60a8..498eb19 100644 --- a/tests/libqos/rtas.h +++ b/tests/libqos/rtas.h @@ -8,4 +8,8 @@ #include "libqos/malloc.h" int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns); +uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size); +int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size, uint32_t val); #endif /* LIBQOS_RTAS_H */ diff --git a/tests/pxe-test.c b/tests/pxe-test.c index b2cc355..5d3ddbe 100644 --- a/tests/pxe-test.c +++ b/tests/pxe-test.c @@ -21,14 +21,14 @@ static const char *disk = "tests/pxe-test-disk.raw"; -static void test_pxe_one(const char *params) +static void test_pxe_one(const char *params, bool ipv6) { char *args; - args = g_strdup_printf("-machine accel=tcg " - "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s " - "%s ", - disk, params); + args = g_strdup_printf("-machine accel=tcg -nodefaults -boot order=n " + "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s," + "ipv4=%s,ipv6=%s %s", disk, ipv6 ? "off" : "on", + ipv6 ? "on" : "off", params); qtest_start(args); boot_sector_test(); @@ -38,12 +38,17 @@ static void test_pxe_one(const char *params) static void test_pxe_e1000(void) { - test_pxe_one("-device e1000,netdev=" NETNAME); + test_pxe_one("-device e1000,netdev=" NETNAME, false); } static void test_pxe_virtio_pci(void) { - test_pxe_one("-device virtio-net-pci,netdev=" NETNAME); + test_pxe_one("-device virtio-net-pci,netdev=" NETNAME, false); +} + +static void test_pxe_spapr_vlan(void) +{ + test_pxe_one("-device spapr-vlan,netdev=" NETNAME, true); } int main(int argc, char *argv[]) @@ -60,6 +65,9 @@ int main(int argc, char *argv[]) if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { qtest_add_func("pxe/e1000", test_pxe_e1000); qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + } else if (strcmp(arch, "ppc64") == 0) { + qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + qtest_add_func("pxe/spapr-vlan", test_pxe_spapr_vlan); } ret = g_test_run(); boot_sector_cleanup(disk); diff --git a/tests/q35-test.c b/tests/q35-test.c index 71538fc..763fe3d 100644 --- a/tests/q35-test.c +++ b/tests/q35-test.c @@ -42,7 +42,7 @@ static void test_smram_lock(void) QPCIDevice *pcidev; QDict *response; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); g_assert(pcibus != NULL); pcidev = qpci_device_find(pcibus, 0); diff --git a/tests/rtas-test.c b/tests/rtas-test.c index 73c7803..ba0867a 100644 --- a/tests/rtas-test.c +++ b/tests/rtas-test.c @@ -22,7 +22,7 @@ static void test_rtas_get_time_of_day(void) t2 = mktimegm(&tm); g_assert(t2 - t1 < 5); /* 5 sec max to run the test */ - qtest_spapr_shutdown(qs); + qtest_shutdown(qs); } int main(int argc, char *argv[]) diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c index 13de7ee..c2f601a 100644 --- a/tests/rtl8139-test.c +++ b/tests/rtl8139-test.c @@ -35,7 +35,7 @@ static QPCIDevice *get_device(void) { QPCIDevice *dev; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev); g_assert(dev != NULL); diff --git a/tests/tcg/README b/tests/tcg/README new file mode 100644 index 0000000..5dcfb48 --- /dev/null +++ b/tests/tcg/README @@ -0,0 +1,76 @@ +This directory contains various interesting programs for +regression testing. + +The target "make test" runs the programs and, if applicable, +runs "diff" to detect mismatches between output on the host and +output on QEMU. + +i386 +==== + +test-i386 +--------- + +This program executes most of the 16 bit and 32 bit x86 instructions and +generates a text output, for comparison with the output obtained with +a real CPU or another emulator. + +The Linux system call modify_ldt() is used to create x86 selectors +to test some 16 bit addressing and 32 bit with segmentation cases. + +The Linux system call vm86() is used to test vm86 emulation. + +Various exceptions are raised to test most of the x86 user space +exception reporting. + +linux-test +---------- + +This program tests various Linux system calls. It is used to verify +that the system call parameters are correctly converted between target +and host CPUs. + +test-i386-fprem +--------------- + +runcom +------ + +test-mmap +--------- + +sha1 +---- + +hello-i386 +---------- + + +ARM +=== + +hello-arm +--------- + +test-arm-iwmmxt +--------------- + +MIPS +==== + +hello-mips +---------- + +hello-mipsel +------------ + +CRIS +==== +The testsuite for CRIS is in tests/tcg/cris. You can run it +with "make test-cris". + +LM32 +==== +The testsuite for LM32 is in tests/tcg/cris. You can run it +with "make test-lm32". + diff --git a/tests/tco-test.c b/tests/tco-test.c index 0d13aa8..0d201b1 100644 --- a/tests/tco-test.c +++ b/tests/tco-test.c @@ -57,7 +57,7 @@ static void test_init(TestData *d) qtest_irq_intercept_in(qs, "ioapic"); g_free(s); - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); d->dev = qpci_device_find(bus, QPCI_DEVFN(0x1f, 0x00)); g_assert(d->dev != NULL); diff --git a/tests/test-qht.c b/tests/test-qht.c index 46a64b6..9b7423a 100644 --- a/tests/test-qht.c +++ b/tests/test-qht.c @@ -6,6 +6,7 @@ */ #include "qemu/osdep.h" #include "qemu/qht.h" +#include "qemu/rcu.h" #define N 5000 @@ -51,6 +52,7 @@ static void check(int a, int b, bool expected) struct qht_stats stats; int i; + rcu_read_lock(); for (i = a; i < b; i++) { void *p; uint32_t hash; @@ -61,6 +63,8 @@ static void check(int a, int b, bool expected) p = qht_lookup(&ht, is_equal, &val, hash); g_assert_true(!!p == expected); } + rcu_read_unlock(); + qht_statistics_init(&ht, &stats); if (stats.used_head_buckets) { g_assert_cmpfloat(qdist_avg(&stats.chain), >=, 1.0); diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c index eb247ad..a4ceeaa 100644 --- a/tests/usb-hcd-ehci-test.c +++ b/tests/usb-hcd-ehci-test.c @@ -56,7 +56,7 @@ static void pci_init(void) if (pcibus) { return; } - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); g_assert(pcibus != NULL); qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4); diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c index 5cd59ad..4b951ce 100644 --- a/tests/usb-hcd-uhci-test.c +++ b/tests/usb-hcd-uhci-test.c @@ -9,9 +9,13 @@ #include "qemu/osdep.h" #include "libqtest.h" +#include "libqos/libqos.h" #include "libqos/usb.h" +#include "libqos/libqos-pc.h" +#include "libqos/libqos-spapr.h" #include "hw/usb/uhci-regs.h" +static QOSState *qs; static void test_uhci_init(void) { @@ -19,13 +23,10 @@ static void test_uhci_init(void) static void test_port(int port) { - QPCIBus *pcibus; struct qhc uhci; g_assert(port > 0); - pcibus = qpci_init_pc(); - g_assert(pcibus != NULL); - qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4); + qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4); uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS); } @@ -75,6 +76,7 @@ static void test_usb_storage_hotplug(void) int main(int argc, char **argv) { + const char *arch = qtest_get_arch(); int ret; g_test_init(&argc, &argv, NULL); @@ -84,11 +86,17 @@ int main(int argc, char **argv) qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug); qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug); - qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0" - " -drive id=drive0,if=none,file=/dev/null,format=raw" - " -device usb-tablet,bus=uhci.0,port=1"); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qs = qtest_pc_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0" + " -drive id=drive0,if=none,file=/dev/null,format=raw" + " -device usb-tablet,bus=uhci.0,port=1"); + } else if (strcmp(arch, "ppc64") == 0) { + qs = qtest_spapr_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0" + " -drive id=drive0,if=none,file=/dev/null,format=raw" + " -device usb-tablet,bus=uhci.0,port=1"); + } ret = g_test_run(); - qtest_end(); + qtest_shutdown(qs); return ret; } diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index a39846e..d7c48c5 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -163,7 +163,7 @@ static void init_virtio_dev(TestServer *s) QVirtioPCIDevice *dev; uint32_t features; - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); g_assert_nonnull(bus); dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET); @@ -884,7 +884,7 @@ static void test_multiqueue(void) qtest_start(cmd); g_free(cmd); - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); dev = virtio_net_pci_init(bus, PCI_SLOT); alloc = pc_alloc_init(); diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index b8fb6cd..e8b2196 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -63,7 +63,7 @@ static QVirtIO9P *qvirtio_9p_pci_init(void) v9p = g_new0(QVirtIO9P, 1); v9p->alloc = pc_alloc_init(); - v9p->bus = qpci_init_pc(); + v9p->bus = qpci_init_pc(NULL); dev = qvirtio_pci_device_find(v9p->bus, VIRTIO_ID_9P); g_assert_nonnull(dev); diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 811cf75..3c4fecc 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -75,7 +75,7 @@ static QPCIBus *pci_test_start(void) g_free(tmp_path); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void arm_test_start(void) diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c index 361506f..a343a6b 100644 --- a/tests/virtio-net-test.c +++ b/tests/virtio-net-test.c @@ -62,7 +62,7 @@ static QPCIBus *pci_test_start(int socket) qtest_start(cmdline); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev) diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index f1489e6..79088bb 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -146,7 +146,7 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot) vs = g_new0(QVirtIOSCSI, 1); vs->alloc = pc_alloc_init(); - vs->bus = qpci_init_pc(); + vs->bus = qpci_init_pc(NULL); dev = qvirtio_pci_device_find(vs->bus, VIRTIO_ID_SCSI); vs->dev = (QVirtioDevice *)dev; diff --git a/trace/Makefile.objs b/trace/Makefile.objs index 4d91b3b..24d3b37 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -22,7 +22,7 @@ $(obj)/generated-ust-provider.h-timestamp: $(BUILD_DIR)/trace-events-all $(trace $(call quiet-command,$(TRACETOOL) \ --format=ust-events-h \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-ust.c: $(obj)/generated-ust.c-timestamp $(BUILD_DIR)/config-host.mak @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -30,7 +30,7 @@ $(obj)/generated-ust.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) $(call quiet-command,$(TRACETOOL) \ --format=ust-events-c \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-events.h: $(obj)/generated-ust-provider.h $(obj)/generated-events.c: $(obj)/generated-ust.c @@ -46,7 +46,7 @@ $(obj)/generated-events.h-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y $(call quiet-command,$(TRACETOOL) \ --format=events-h \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-events.c: $(obj)/generated-events.c-timestamp $(BUILD_DIR)/config-host.mak @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -54,7 +54,7 @@ $(obj)/generated-events.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y $(call quiet-command,$(TRACETOOL) \ --format=events-c \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") util-obj-y += generated-events.o @@ -71,7 +71,7 @@ $(obj)/generated-tracers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=h \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") ############################## # non-DTrace @@ -82,7 +82,7 @@ $(obj)/generated-tracers.c-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=c \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h @@ -100,10 +100,10 @@ $(obj)/generated-tracers-dtrace.dtrace-timestamp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ --format=d \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers-dtrace.dtrace - $(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@") + $(call quiet-command,dtrace -o $@ -h -s $<,"GEN","$@") $(obj)/generated-tracers-dtrace.o: $(obj)/generated-tracers-dtrace.dtrace @@ -119,7 +119,7 @@ $(obj)/generated-helpers-wrappers.h-timestamp: $(BUILD_DIR)/trace-events-all $(B $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-wrapper-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.h: $(obj)/generated-helpers.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -127,7 +127,7 @@ $(obj)/generated-helpers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.c: $(obj)/generated-helpers.c-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -135,7 +135,7 @@ $(obj)/generated-helpers.c-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-c \ --backend=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.o: $(obj)/generated-helpers.c @@ -148,7 +148,7 @@ $(obj)/generated-tcg-tracers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_ $(call quiet-command,$(TRACETOOL) \ --format=tcg-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") ###################################################################### @@ -814,7 +814,6 @@ QemuCocoaView *cocoaView; - (void)doToggleFullScreen:(id)sender; - (void)toggleFullScreen:(id)sender; - (void)showQEMUDoc:(id)sender; -- (void)showQEMUTec:(id)sender; - (void)zoomToFit:(id) sender; - (void)displayConsole:(id)sender; - (void)pauseQEMU:(id)sender; @@ -998,13 +997,6 @@ QemuCocoaView *cocoaView; [self openDocumentation: @"qemu-doc.html"]; } -- (void)showQEMUTec:(id)sender -{ - COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n"); - - [self openDocumentation: @"qemu-tech.html"]; -} - /* Stretches video to fit host monitor size */ - (void)zoomToFit:(id) sender { @@ -1335,7 +1327,6 @@ int main (int argc, const char * argv[]) { // Help menu menu = [[NSMenu alloc] initWithTitle:@"Help"]; [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help - [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease]; [menuItem setSubmenu:menu]; [[NSApp mainMenu] addItem:menuItem]; diff --git a/util/oslib-posix.c b/util/oslib-posix.c index aaec189..8ec99cc 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -46,6 +46,7 @@ #ifdef __FreeBSD__ #include <sys/sysctl.h> +#include <libutil.h> #endif #include "qemu/mmap-alloc.h" @@ -434,6 +435,32 @@ int qemu_read_password(char *buf, int buf_size) } +char *qemu_get_pid_name(pid_t pid) +{ + char *name = NULL; + +#if defined(__FreeBSD__) + /* BSDs don't have /proc, but they provide a nice substitute */ + struct kinfo_proc *proc = kinfo_getproc(pid); + + if (proc) { + name = g_strdup(proc->ki_comm); + free(proc); + } +#else + /* Assume a system with reasonable procfs */ + char *pid_path; + size_t len; + + pid_path = g_strdup_printf("/proc/%d/cmdline", pid); + g_file_get_contents(pid_path, &name, &len, NULL); + g_free(pid_path); +#endif + + return name; +} + + pid_t qemu_fork(Error **errp) { sigset_t oldmask, newmask; diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 4c1dcf1..d09863c 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -575,6 +575,13 @@ int qemu_read_password(char *buf, int buf_size) } +char *qemu_get_pid_name(pid_t pid) +{ + /* XXX Implement me */ + abort(); +} + + pid_t qemu_fork(Error **errp) { errno = ENOSYS; @@ -133,7 +133,8 @@ struct qht_map { /* trigger a resize when n_added_buckets > n_buckets / div */ #define QHT_NR_ADDED_BUCKETS_THRESHOLD_DIV 8 -static void qht_do_resize(struct qht *ht, struct qht_map *new); +static void qht_do_resize_reset(struct qht *ht, struct qht_map *new, + bool reset); static void qht_grow_maybe(struct qht *ht); #ifdef QHT_DEBUG @@ -379,7 +380,7 @@ static void qht_bucket_reset__locked(struct qht_bucket *head) if (b->pointers[i] == NULL) { goto done; } - b->hashes[i] = 0; + atomic_set(&b->hashes[i], 0); atomic_set(&b->pointers[i], NULL); } b = b->next; @@ -408,12 +409,21 @@ void qht_reset(struct qht *ht) qht_map_unlock_buckets(map); } +static inline void qht_do_resize(struct qht *ht, struct qht_map *new) +{ + qht_do_resize_reset(ht, new, false); +} + +static inline void qht_do_resize_and_reset(struct qht *ht, struct qht_map *new) +{ + qht_do_resize_reset(ht, new, true); +} + bool qht_reset_size(struct qht *ht, size_t n_elems) { - struct qht_map *new; + struct qht_map *new = NULL; struct qht_map *map; size_t n_buckets; - bool resize = false; n_buckets = qht_elems_to_buckets(n_elems); @@ -421,18 +431,11 @@ bool qht_reset_size(struct qht *ht, size_t n_elems) map = ht->map; if (n_buckets != map->n_buckets) { new = qht_map_create(n_buckets); - resize = true; - } - - qht_map_lock_buckets(map); - qht_map_reset__all_locked(map); - if (resize) { - qht_do_resize(ht, new); } - qht_map_unlock_buckets(map); + qht_do_resize_and_reset(ht, new); qemu_mutex_unlock(&ht->lock); - return resize; + return !!new; } static inline @@ -444,7 +447,7 @@ void *qht_do_lookup(struct qht_bucket *head, qht_lookup_func_t func, do { for (i = 0; i < QHT_BUCKET_ENTRIES; i++) { - if (b->hashes[i] == hash) { + if (atomic_read(&b->hashes[i]) == hash) { /* The pointer is dereferenced before seqlock_read_retry, * so (unlike qht_insert__locked) we need to use * atomic_rcu_read here. @@ -538,8 +541,8 @@ static bool qht_insert__locked(struct qht *ht, struct qht_map *map, if (new) { atomic_rcu_set(&prev->next, b); } - b->hashes[i] = hash; /* smp_wmb() implicit in seqlock_write_begin. */ + atomic_set(&b->hashes[i], hash); atomic_set(&b->pointers[i], p); seqlock_write_end(&head->sequence); return true; @@ -561,9 +564,7 @@ static __attribute__((noinline)) void qht_grow_maybe(struct qht *ht) if (qht_map_needs_resize(map)) { struct qht_map *new = qht_map_create(map->n_buckets * 2); - qht_map_lock_buckets(map); qht_do_resize(ht, new); - qht_map_unlock_buckets(map); } qemu_mutex_unlock(&ht->lock); } @@ -607,10 +608,10 @@ qht_entry_move(struct qht_bucket *to, int i, struct qht_bucket *from, int j) qht_debug_assert(to->pointers[i]); qht_debug_assert(from->pointers[j]); - to->hashes[i] = from->hashes[j]; + atomic_set(&to->hashes[i], from->hashes[j]); atomic_set(&to->pointers[i], from->pointers[j]); - from->hashes[j] = 0; + atomic_set(&from->hashes[j], 0); atomic_set(&from->pointers[j], NULL); } @@ -739,24 +740,31 @@ static void qht_map_copy(struct qht *ht, void *p, uint32_t hash, void *userp) } /* - * Call with ht->lock and all bucket locks held. - * - * Creating the @new map here would add unnecessary delay while all the locks - * are held--holding up the bucket locks is particularly bad, since no writes - * can occur while these are held. Thus, we let callers create the new map, - * hopefully without the bucket locks held. + * Atomically perform a resize and/or reset. + * Call with ht->lock held. */ -static void qht_do_resize(struct qht *ht, struct qht_map *new) +static void qht_do_resize_reset(struct qht *ht, struct qht_map *new, bool reset) { struct qht_map *old; old = ht->map; - g_assert_cmpuint(new->n_buckets, !=, old->n_buckets); + qht_map_lock_buckets(old); + if (reset) { + qht_map_reset__all_locked(old); + } + + if (new == NULL) { + qht_map_unlock_buckets(old); + return; + } + + g_assert_cmpuint(new->n_buckets, !=, old->n_buckets); qht_map_iter__all_locked(ht, old, qht_map_copy, new); qht_map_debug__all_locked(new); atomic_rcu_set(&ht->map, new); + qht_map_unlock_buckets(old); call_rcu(old, qht_map_destroy, rcu); } @@ -768,12 +776,9 @@ bool qht_resize(struct qht *ht, size_t n_elems) qemu_mutex_lock(&ht->lock); if (n_buckets != ht->map->n_buckets) { struct qht_map *new; - struct qht_map *old = ht->map; new = qht_map_create(n_buckets); - qht_map_lock_buckets(old); qht_do_resize(ht, new); - qht_map_unlock_buckets(old); ret = true; } qemu_mutex_unlock(&ht->lock); @@ -1675,8 +1675,12 @@ static void qemu_kill_report(void) */ error_report("terminating on signal %d", shutdown_signal); } else { - error_report("terminating on signal %d from pid " FMT_pid, - shutdown_signal, shutdown_pid); + char *shutdown_cmd = qemu_get_pid_name(shutdown_pid); + + error_report("terminating on signal %d from pid " FMT_pid " (%s)", + shutdown_signal, shutdown_pid, + shutdown_cmd ? shutdown_cmd : "<unknown process>"); + g_free(shutdown_cmd); } shutdown_signal = -1; } |