aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CODING_STYLE3
-rw-r--r--MAINTAINERS65
-rw-r--r--Makefile26
-rw-r--r--Makefile.target10
-rw-r--r--arm-dis.c24
-rw-r--r--audio/alsaaudio.c2
-rw-r--r--audio/audio.c11
-rw-r--r--audio/audio_int.h2
-rw-r--r--audio/dsoundaudio.c4
-rw-r--r--audio/esdaudio.c3
-rw-r--r--audio/fmodaudio.c4
-rw-r--r--audio/mixeng.c25
-rw-r--r--audio/mixeng.h4
-rw-r--r--audio/mixeng_template.h39
-rw-r--r--audio/ossaudio.c3
-rw-r--r--audio/paaudio.c2
-rw-r--r--audio/spiceaudio.c5
-rw-r--r--audio/winwaveaudio.c3
-rw-r--r--block/vpc.c47
-rw-r--r--block/vvfat.c1
-rw-r--r--bsd-user/elfload.c37
-rwxr-xr-xconfigure466
-rw-r--r--disas.c5
-rw-r--r--docs/qdev-device-use.txt8
-rw-r--r--docs/specs/acpi_pci_hotplug.txt37
-rw-r--r--exec.c7
-rw-r--r--fpu/softfloat-specialize.h58
-rw-r--r--fpu/softfloat.h5
-rw-r--r--gdbstub.c6
-rw-r--r--gdbstub.h2
-rw-r--r--hw/acpi_piix4.c39
-rw-r--r--hw/arm_sysctl.c17
-rw-r--r--hw/cirrus_vga.c1
-rw-r--r--hw/gt64xxx.c120
-rw-r--r--hw/ide/piix.c2
-rw-r--r--hw/lan9118.c4
-rw-r--r--hw/loader.c5
-rw-r--r--hw/lsi53c895a.c4
-rw-r--r--hw/m48t59.c11
-rw-r--r--hw/mainstone.c3
-rw-r--r--hw/mips.h2
-rw-r--r--hw/mips_malta.c4
-rw-r--r--hw/mips_timer.c44
-rw-r--r--hw/msi.c5
-rw-r--r--hw/msix.c5
-rw-r--r--hw/pci.c37
-rw-r--r--hw/pci.h5
-rw-r--r--hw/piix4.c1
-rw-r--r--hw/piix_pci.c2
-rw-r--r--hw/pl031.c25
-rw-r--r--hw/pl050.c35
-rw-r--r--hw/pl080.c58
-rw-r--r--hw/pl110.c44
-rw-r--r--hw/pl190.c38
-rw-r--r--hw/ppc405_uc.c5
-rw-r--r--hw/pxa2xx.c2
-rw-r--r--hw/pxa2xx_lcd.c4
-rw-r--r--hw/qdev.c10
-rw-r--r--hw/qdev.h1
-rw-r--r--hw/qxl.c1
-rw-r--r--hw/r2d.c31
-rw-r--r--hw/rtl8139.c28
-rw-r--r--hw/sh_pci.c105
-rw-r--r--hw/sh_pci.h9
-rw-r--r--hw/sh_serial.c59
-rw-r--r--hw/sm501.c47
-rw-r--r--hw/smc91c111.c30
-rw-r--r--hw/usb-hid.c5
-rw-r--r--hw/versatilepb.c24
-rw-r--r--hw/vga-pci.c1
-rw-r--r--hw/virtio-net.c28
-rw-r--r--hw/virtio-pci.c213
-rw-r--r--hw/virtio-serial-bus.c10
-rw-r--r--hw/virtio.c36
-rw-r--r--hw/virtio.h4
-rw-r--r--hw/vmware_vga.c1
-rw-r--r--hw/zaurus.c4
-rw-r--r--kvm-all.c49
-rw-r--r--kvm-stub.c5
-rw-r--r--kvm.h1
-rw-r--r--linux-user/ioctls.h2
-rw-r--r--linux-user/signal.c16
-rw-r--r--linux-user/syscall.c4
-rw-r--r--migration.c4
-rw-r--r--monitor.c4
-rw-r--r--pc-bios/keymaps/bepo333
-rw-r--r--pc-bios/optionrom/Makefile2
-rw-r--r--qemu-doc.texi2
-rw-r--r--qemu-io.c4
-rw-r--r--qerror.c4
-rw-r--r--qerror.h3
-rw-r--r--rules.mak8
-rw-r--r--savevm.c40
-rwxr-xr-xscripts/checkpatch.pl2909
-rwxr-xr-xscripts/create_config (renamed from create_config)0
-rw-r--r--scripts/feature_to_c.sh (renamed from feature_to_c.sh)0
-rw-r--r--scripts/hxtool (renamed from hxtool)0
-rw-r--r--scripts/make_device_config.sh (renamed from make_device_config.sh)2
-rw-r--r--scripts/qemu-binfmt-conf.sh (renamed from qemu-binfmt-conf.sh)0
-rwxr-xr-xscripts/signrom.sh (renamed from pc-bios/optionrom/signrom.sh)0
-rwxr-xr-xscripts/simpletrace.py (renamed from simpletrace.py)0
-rwxr-xr-xscripts/texi2pod.pl (renamed from texi2pod.pl)0
-rwxr-xr-xscripts/tracetool (renamed from tracetool)0
-rw-r--r--slirp/tftp.c4
-rw-r--r--sysemu.h1
-rw-r--r--target-arm/cpu.h64
-rw-r--r--target-arm/helper.c29
-rw-r--r--target-arm/helpers.h4
-rw-r--r--target-arm/neon_helper.c47
-rw-r--r--target-arm/translate.c223
-rw-r--r--target-cris/translate.c3
-rw-r--r--target-i386/translate.c34
-rw-r--r--target-microblaze/translate.c192
-rw-r--r--target-mips/translate.c8
-rw-r--r--target-ppc/op_helper.c192
-rw-r--r--target-sh4/cpu.h49
-rw-r--r--target-sh4/helper.c4
-rw-r--r--target-sh4/helper.h3
-rw-r--r--target-sh4/op_helper.c249
-rw-r--r--target-sh4/translate.c162
-rw-r--r--target-sparc/op_helper.c56
-rw-r--r--tcg/README14
-rw-r--r--tcg/arm/tcg-target.c3
-rw-r--r--tcg/ia64/tcg-target.c3
-rw-r--r--tcg/mips/tcg-target.c4
-rw-r--r--tcg/tcg-op.h64
-rw-r--r--tcg/tcg-opc.h6
-rw-r--r--tests/Makefile3
-rw-r--r--tests/cris/check_abs.c5
-rw-r--r--tests/cris/check_addc.c3
-rw-r--r--tests/cris/check_addcm.c6
-rw-r--r--tests/cris/check_bound.c9
-rw-r--r--tests/cris/check_ftag.c12
-rw-r--r--tests/cris/check_int64.c6
-rw-r--r--tests/cris/check_lz.c2
-rw-r--r--tests/cris/check_swap.c2
-rw-r--r--tests/cris/crisutils.h20
-rw-r--r--tests/hello-i386.c4
-rw-r--r--ui/vnc-auth-sasl.c14
139 files changed, 5883 insertions, 1096 deletions
diff --git a/CODING_STYLE b/CODING_STYLE
index 2c8268ddc2..5ecfa22161 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -1,6 +1,9 @@
Qemu Coding Style
=================
+Please use the script checkpatch.pl in the scripts directory to check
+patches before submitting.
+
1. Whitespace
Of course, the most important aspect in any coding style is whitespace.
diff --git a/MAINTAINERS b/MAINTAINERS
index 4b07192d4e..f20d390d0c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -81,8 +81,8 @@ S: Maintained
F: target-microblaze/
MIPS
-M: qemu-devel@nongnu.org
-S: Orphan
+M: Aurelien Jarno <aurelien@aurel32.net>
+S: Maintained
F: target-mips/
PowerPC
@@ -96,8 +96,8 @@ S: Maintained
F: target-s390x/
SH4
-M: qemu-devel@nongnu.org
-S: Orphan
+M: Aurelien Jarno <aurelien@aurel32.net>
+S: Maintained
F: target-sh4/
SPARC
@@ -202,7 +202,7 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: hw/etraxfs.c
-M86K Machines
+M68K Machines
-------------
an5206
M: Paul Brook <paul@codesourcery.com>
@@ -279,7 +279,7 @@ F: hw/r2d.c
Shix
M: Magnus Damm <magnus.damm@gmail.com>
-S: Oprhan
+S: Orphan
F: hw/shix.c
SPARC Machines
@@ -426,3 +426,56 @@ Linux user
M: Riku Voipio <riku.voipio@iki.fi>
S: Maintained
F: linux-user/
+
+Tiny Code Generator (TCG)
+-------------------------
+Common code
+M: qemu-devel@nongnu.org
+S: Maintained
+F: tcg/
+
+ARM target
+M: Andrzej Zaborowski <balrogg@gmail.com>
+S: Maintained
+F: tcg/arm/
+
+HPPA target
+M: Richard Henderson <rth@twiddle.net>
+S: Maintained
+F: tcg/hppa/
+
+i386 target
+M: qemu-devel@nongnu.org
+S: Maintained
+F: tcg/i386/
+
+IA64 target
+M: Aurelien Jarno <aurelien@aurel32.net>
+S: Maintained
+F: tcg/ia64/
+
+MIPS target
+M: Aurelien Jarno <aurelien@aurel32.ne>
+S: Maintained
+F: tcg/mips/
+
+PPC
+M: Vassili Karpov (malc) <av1474@comtv.ru>
+S: Maintained
+F: tcg/ppc/
+
+PPC64 target
+M: Vassili Karpov (malc) <av1474@comtv.ru>
+S: Maintained
+F: tcg/ppc64/
+
+S390 target
+M: Alexander Graf <agraf@suse.de>
+M: Richard Henderson <rth@twiddle.net>
+S: Maintained
+F: tcg/s390/
+
+SPARC target
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: tcg/sparc/
diff --git a/Makefile b/Makefile
index 6d601eef6e..eca4c7651e 100644
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
-include $(SUBDIR_DEVICES_MAK_DEP)
%/config-devices.mak: default-configs/%.mak
- $(call quiet-command,$(SHELL) $(SRC_PATH)/make_device_config.sh $@ $<, " GEN $@")
+ $(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $@ $<, " GEN $@")
@if test -f $@; then \
if cmp -s $@.old $@; then \
mv $@.tmp $@; \
@@ -76,7 +76,7 @@ build-all: $(DOCS) $(TOOLS) recurse-all
config-host.h: config-host.h-timestamp
config-host.h-timestamp: config-host.mak
qemu-options.def: $(SRC_PATH)/qemu-options.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
@@ -118,12 +118,12 @@ else
trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
@@ -136,7 +136,7 @@ trace-dtrace.h: trace-dtrace.dtrace
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
@@ -160,7 +160,7 @@ qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-ob
qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
@@ -282,32 +282,32 @@ TEXIFLAG=$(if $(V),,--quiet)
$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<," GEN $@")
qemu-options.texi: $(SRC_PATH)/qemu-options.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -q < $< > $@," GEN $@")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@," GEN $@")
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
$(call quiet-command, \
- perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod && \
+ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
" GEN $@")
qemu-img.1: qemu-img.texi qemu-img-cmds.texi
$(call quiet-command, \
- perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod && \
+ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
" GEN $@")
qemu-nbd.8: qemu-nbd.texi
$(call quiet-command, \
- perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod && \
+ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
" GEN $@")
diff --git a/Makefile.target b/Makefile.target
index e15b1c4fb6..cd2abde394 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -52,7 +52,7 @@ TARGET_TYPE=system
endif
$(QEMU_PROG).stp:
- $(call quiet-command,sh $(SRC_PATH)/tracetool \
+ $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \
--$(TRACE_BACKEND) \
--binary $(bindir)/$(QEMU_PROG) \
--target-arch $(TARGET_ARCH) \
@@ -344,14 +344,14 @@ $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
$(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y))
-gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/feature_to_c.sh
- $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
+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)$@")
hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
- $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
+ $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
diff --git a/arm-dis.c b/arm-dis.c
index af217397d4..3ece02c1b3 100644
--- a/arm-dis.c
+++ b/arm-dis.c
@@ -4101,6 +4101,30 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
addresses, since the addend is not currently pc-relative. */
pc = 0;
+ /* We include the hexdump of the instruction. The format here
+ matches that used by objdump and the ARM ARM (in particular,
+ 32 bit Thumb instructions are displayed as pairs of halfwords,
+ not as a single word.) */
+ if (is_thumb)
+ {
+ if (size == 2)
+ {
+ info->fprintf_func(info->stream, "%04lx ",
+ ((unsigned long)given) & 0xffff);
+ }
+ else
+ {
+ info->fprintf_func(info->stream, "%04lx %04lx ",
+ (((unsigned long)given) >> 16) & 0xffff,
+ ((unsigned long)given) & 0xffff);
+ }
+ }
+ else
+ {
+ info->fprintf_func(info->stream, "%08lx ",
+ ((unsigned long)given) & 0xffffffff);
+ }
+
printer (pc, info, given);
if (is_thumb)
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 727b9f84c3..4d720146df 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -1097,7 +1097,7 @@ static int alsa_run_in (HWVoiceIn *hw)
}
}
- hw->conv (dst, src, nread, &nominal_volume);
+ hw->conv (dst, src, nread);
src = advance (src, nread << hwshift);
dst += nread;
diff --git a/audio/audio.c b/audio/audio.c
index 17074469b2..1729c0be2c 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -104,7 +104,7 @@ static struct {
static AudioState glob_audio_state;
-struct mixeng_volume nominal_volume = {
+const struct mixeng_volume nominal_volume = {
.mute = 0,
#ifdef FLOAT_MIXENG
.r = 1.0,
@@ -702,13 +702,11 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
/*
* Capture
*/
-static void noop_conv (struct st_sample *dst, const void *src,
- int samples, struct mixeng_volume *vol)
+static void noop_conv (struct st_sample *dst, const void *src, int samples)
{
(void) src;
(void) dst;
(void) samples;
- (void) vol;
}
static CaptureVoiceOut *audio_pcm_capture_find_specific (
@@ -956,6 +954,8 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
total += isamp;
}
+ mixeng_volume (sw->buf, ret, &sw->vol);
+
sw->clip (buf, sw->buf, ret);
sw->total_hw_samples_acquired += total;
return ret << sw->info.shift;
@@ -1037,7 +1037,8 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
swlim = ((int64_t) dead << 32) / sw->ratio;
swlim = audio_MIN (swlim, samples);
if (swlim) {
- sw->conv (sw->buf, buf, swlim, &sw->vol);
+ sw->conv (sw->buf, buf, swlim);
+ mixeng_volume (sw->buf, swlim, &sw->vol);
}
while (swlim) {
diff --git a/audio/audio_int.h b/audio/audio_int.h
index d66f2c3bf6..2003f8bf20 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -211,7 +211,7 @@ extern struct audio_driver esd_audio_driver;
extern struct audio_driver pa_audio_driver;
extern struct audio_driver spice_audio_driver;
extern struct audio_driver winwave_audio_driver;
-extern struct mixeng_volume nominal_volume;
+extern const struct mixeng_volume nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index e5479555fa..e2d89fd5d5 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -831,11 +831,11 @@ static int dsound_run_in (HWVoiceIn *hw)
decr = len1 + len2;
if (p1 && len1) {
- hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
+ hw->conv (hw->conv_buf + hw->wpos, p1, len1);
}
if (p2 && len2) {
- hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
+ hw->conv (hw->conv_buf, p2, len2);
}
dsound_unlock_in (dscb, p1, p2, blen1, blen2);
diff --git a/audio/esdaudio.c b/audio/esdaudio.c
index 9a1f2f8617..ff97b397d2 100644
--- a/audio/esdaudio.c
+++ b/audio/esdaudio.c
@@ -346,8 +346,7 @@ static void *qesd_thread_in (void *arg)
break;
}
- hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
- &nominal_volume);
+ hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift);
wpos = (wpos + chunk) % hw->samples;
to_grab -= chunk;
}
diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c
index 7f08e14718..c34cf53567 100644
--- a/audio/fmodaudio.c
+++ b/audio/fmodaudio.c
@@ -488,10 +488,10 @@ static int fmod_run_in (HWVoiceIn *hw)
decr = len1 + len2;
if (p1 && blen1) {
- hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
+ hw->conv (hw->conv_buf + hw->wpos, p1, len1);
}
if (p2 && len2) {
- hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
+ hw->conv (hw->conv_buf, p2, len2);
}
fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 9f1d93fcfc..4a9e8ebe2a 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -333,3 +333,28 @@ void mixeng_clear (struct st_sample *buf, int len)
{
memset (buf, 0, len * sizeof (struct st_sample));
}
+
+void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol)
+{
+#ifdef CONFIG_MIXEMU
+ if (vol->mute) {
+ mixeng_clear (buf, len);
+ return;
+ }
+
+ while (len--) {
+#ifdef FLOAT_MIXENG
+ buf->l = buf->l * vol->l;
+ buf->r = buf->r * vol->r;
+#else
+ buf->l = (buf->l * vol->l) >> 32;
+ buf->r = (buf->r * vol->r) >> 32;
+#endif
+ buf += 1;
+ }
+#else
+ (void) buf;
+ (void) len;
+ (void) vol;
+#endif
+}
diff --git a/audio/mixeng.h b/audio/mixeng.h
index 4af1dd9891..9de443b01d 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -33,8 +33,7 @@ struct mixeng_volume { int mute; int64_t r; int64_t l; };
struct st_sample { int64_t l; int64_t r; };
#endif
-typedef void (t_sample) (struct st_sample *dst, const void *src,
- int samples, struct mixeng_volume *vol);
+typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
extern t_sample *mixeng_conv[2][2][2][3];
@@ -47,5 +46,6 @@ void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *o
int *isamp, int *osamp);
void st_rate_stop (void *opaque);
void mixeng_clear (struct st_sample *buf, int len);
+void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
#endif /* mixeng.h */
diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h
index 56177056ce..a2d0ef84fd 100644
--- a/audio/mixeng_template.h
+++ b/audio/mixeng_template.h
@@ -31,16 +31,6 @@
#define HALF (IN_MAX >> 1)
#endif
-#ifdef CONFIG_MIXEMU
-#ifdef FLOAT_MIXENG
-#define VOL(a, b) ((a) * (b))
-#else
-#define VOL(a, b) ((a) * (b)) >> 32
-#endif
-#else
-#define VOL(a, b) a
-#endif
-
#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
#ifdef FLOAT_MIXENG
@@ -109,40 +99,26 @@ static inline IN_T glue (clip_, ET) (int64_t v)
#endif
static void glue (glue (conv_, ET), _to_stereo)
- (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
+ (struct st_sample *dst, const void *src, int samples)
{
struct st_sample *out = dst;
IN_T *in = (IN_T *) src;
-#ifdef CONFIG_MIXEMU
- if (vol->mute) {
- mixeng_clear (dst, samples);
- return;
- }
-#else
- (void) vol;
-#endif
+
while (samples--) {
- out->l = VOL (glue (conv_, ET) (*in++), vol->l);
- out->r = VOL (glue (conv_, ET) (*in++), vol->r);
+ out->l = glue (conv_, ET) (*in++);
+ out->r = glue (conv_, ET) (*in++);
out += 1;
}
}
static void glue (glue (conv_, ET), _to_mono)
- (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
+ (struct st_sample *dst, const void *src, int samples)
{
struct st_sample *out = dst;
IN_T *in = (IN_T *) src;
-#ifdef CONFIG_MIXEMU
- if (vol->mute) {
- mixeng_clear (dst, samples);
- return;
- }
-#else
- (void) vol;
-#endif
+
while (samples--) {
- out->l = VOL (glue (conv_, ET) (in[0]), vol->l);
+ out->l = glue (conv_, ET) (in[0]);
out->r = out->l;
out += 1;
in += 1;
@@ -174,4 +150,3 @@ static void glue (glue (clip_, ET), _from_mono)
#undef ET
#undef HALF
-#undef VOL
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index d7a55e5441..b49e102747 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -788,8 +788,7 @@ static int oss_run_in (HWVoiceIn *hw)
hw->info.align + 1);
}
read_samples += nread >> hwshift;
- hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
- &nominal_volume);
+ hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
}
if (bufs[i].len - nread) {
diff --git a/audio/paaudio.c b/audio/paaudio.c
index ff71dac2a5..9cf685d30f 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -195,7 +195,7 @@ static void *qpa_thread_in (void *arg)
return NULL;
}
- hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
+ hw->conv (hw->conv_buf + wpos, buf, chunk);
wpos = (wpos + chunk) % hw->samples;
to_grab -= chunk;
}
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 373e4c43ed..a5c0d6bc66 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -268,11 +268,10 @@ static int line_in_run (HWVoiceIn *hw)
len[1] = 0;
}
- hw->conv (hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume);
+ hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
if (len[1]) {
- hw->conv (hw->conv_buf, samples + len[0], len[1],
- &nominal_volume);
+ hw->conv (hw->conv_buf, samples + len[0], len[1]);
}
hw->wpos = (hw->wpos + num_samples) % hw->samples;
diff --git a/audio/winwaveaudio.c b/audio/winwaveaudio.c
index cdf483b89a..e5ad3c6604 100644
--- a/audio/winwaveaudio.c
+++ b/audio/winwaveaudio.c
@@ -581,8 +581,7 @@ static int winwave_run_in (HWVoiceIn *hw)
int conv = audio_MIN (left, decr);
hw->conv (hw->conv_buf + hw->wpos,
advance (wave->pcm_buf, wave->rpos << hw->info.shift),
- conv,
- &nominal_volume);
+ conv);
wave->rpos = (wave->rpos + conv) % hw->samples;
hw->wpos = (hw->wpos + conv) % hw->samples;
diff --git a/block/vpc.c b/block/vpc.c
index 21e2a6870c..7b025be01d 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -502,6 +502,7 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
uint8_t secs_per_cyl = 0;
size_t block_size, num_bat_entries;
int64_t total_sectors = 0;
+ int ret = -EIO;
// Read out options
while (options && options->name) {
@@ -521,7 +522,8 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
if (calculate_geometry(total_sectors + i,
&cyls, &heads, &secs_per_cyl)) {
- return -EFBIG;
+ ret = -EFBIG;
+ goto fail;
}
}
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
@@ -560,22 +562,28 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
block_size = 0x200000;
num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
- if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
- return -EIO;
+ if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+ goto fail;
+ }
- if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0)
- return -EIO;
- if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
- return -EIO;
+ if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0) {
+ goto fail;
+ }
+ if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+ goto fail;
+ }
// Write the initial BAT
- if (lseek(fd, 3 * 512, SEEK_SET) < 0)
- return -EIO;
+ if (lseek(fd, 3 * 512, SEEK_SET) < 0) {
+ goto fail;
+ }
memset(buf, 0xFF, 512);
- for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++)
- if (write(fd, buf, 512) != 512)
- return -EIO;
+ for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++) {
+ if (write(fd, buf, 512) != 512) {
+ goto fail;
+ }
+ }
// Prepare the Dynamic Disk Header
@@ -592,13 +600,18 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
// Write the header
- if (lseek(fd, 512, SEEK_SET) < 0)
- return -EIO;
- if (write(fd, buf, 1024) != 1024)
- return -EIO;
+ if (lseek(fd, 512, SEEK_SET) < 0) {
+ goto fail;
+ }
+ if (write(fd, buf, 1024) != 1024) {
+ goto fail;
+ }
+ ret = 0;
+
+ fail:
close(fd);
- return 0;
+ return ret;
}
static void vpc_close(BlockDriverState *bs)
diff --git a/block/vvfat.c b/block/vvfat.c
index 26dd474bb5..fe568fe2c7 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -756,6 +756,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
if (st.st_size > 0x7fffffff) {
fprintf(stderr, "File %s is larger than 2GB\n", buffer);
free(buffer);
+ closedir(dir);
return -2;
}
direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 7374912b19..1ef1f972fc 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -1044,7 +1044,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
struct elf_shdr sechdr, symtab, strtab;
char *strings;
struct syminfo *s;
- struct elf_sym *syms;
+ struct elf_sym *syms, *new_syms;
lseek(fd, hdr->e_shoff, SEEK_SET);
for (i = 0; i < hdr->e_shnum; i++) {
@@ -1072,15 +1072,24 @@ static void load_symbols(struct elfhdr *hdr, int fd)
/* Now know where the strtab and symtab are. Snarf them. */
s = malloc(sizeof(*s));
syms = malloc(symtab.sh_size);
- if (!syms)
+ if (!syms) {
+ free(s);
return;
+ }
s->disas_strtab = strings = malloc(strtab.sh_size);
- if (!s->disas_strtab)
+ if (!s->disas_strtab) {
+ free(s);
+ free(syms);
return;
+ }
lseek(fd, symtab.sh_offset, SEEK_SET);
- if (read(fd, syms, symtab.sh_size) != symtab.sh_size)
+ if (read(fd, syms, symtab.sh_size) != symtab.sh_size) {
+ free(s);
+ free(syms);
+ free(strings);
return;
+ }
nsyms = symtab.sh_size / sizeof(struct elf_sym);
@@ -1105,13 +1114,29 @@ static void load_symbols(struct elfhdr *hdr, int fd)
#endif
i++;
}
- syms = realloc(syms, nsyms * sizeof(*syms));
+
+ /* Attempt to free the storage associated with the local symbols
+ that we threw away. Whether or not this has any effect on the
+ memory allocation depends on the malloc implementation and how
+ many symbols we managed to discard. */
+ new_syms = realloc(syms, nsyms * sizeof(*syms));
+ if (new_syms == NULL) {
+ free(s);
+ free(syms);
+ free(strings);
+ return;
+ }
+ syms = new_syms;
qsort(syms, nsyms, sizeof(*syms), symcmp);
lseek(fd, strtab.sh_offset, SEEK_SET);
- if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
+ if (read(fd, strings, strtab.sh_size) != strtab.sh_size) {
+ free(s);
+ free(syms);
+ free(strings);
return;
+ }
s->disas_num_syms = nsyms;
#if ELF_CLASS == ELFCLASS32
s->disas_symtab.elf32 = syms;
diff --git a/configure b/configure
index 831a741c74..210670c16f 100755
--- a/configure
+++ b/configure
@@ -32,6 +32,12 @@ compile_prog() {
$cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1
}
+# symbolically link $1 to $2. Portable version of "ln -sf".
+symlink() {
+ rm -f $2
+ ln -s $1 $2
+}
+
# check whether a command is available to this shell (may be either an
# executable or a builtin)
has() {
@@ -69,24 +75,17 @@ path_of() {
}
# default parameters
+source_path=`dirname "$0"`
cpu=""
interp_prefix="/usr/gnemul/qemu-%M"
static="no"
sparc_cpu=""
cross_prefix=""
-cc="gcc"
audio_drv_list=""
audio_card_list="ac97 es1370 sb16 hda"
audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda"
block_drv_whitelist=""
host_cc="gcc"
-ar="ar"
-make="make"
-install="install"
-objcopy="objcopy"
-ld="ld"
-strip="strip"
-windres="windres"
helper_cflags=""
libs_softmmu=""
libs_tools=""
@@ -94,13 +93,97 @@ audio_pt_int=""
audio_win_int=""
cc_i386=i386-pc-linux-gnu-gcc
+target_list=""
+
+# Default value for a variable defining feature "foo".
+# * foo="no" feature will only be used if --enable-foo arg is given
+# * foo="" feature will be searched for, and if found, will be used
+# unless --disable-foo is given
+# * foo="yes" this value will only be set by --enable-foo flag.
+# feature will searched for,
+# if not found, configure exits with error
+#
+# Always add --enable-foo and --disable-foo command line args.
+# Distributions want to ensure that several features are compiled in, and it
+# is impossible without a --enable-foo that exits if a feature is not found.
+
+bluez=""
+brlapi=""
+curl=""
+curses=""
+docs=""
+fdt=""
+kvm=""
+kvm_para=""
+nptl=""
+sdl=""
+sparse="no"
+uuid=""
+vde=""
+vnc_tls=""
+vnc_sasl=""
+vnc_jpeg=""
+vnc_png=""
+vnc_thread="no"
+xen=""
+linux_aio=""
+attr=""
+vhost_net=""
+xfs=""
+
+gprof="no"
+debug_tcg="no"
+debug_mon="no"
+debug="no"
+strip_opt="yes"
+bigendian="no"
+mingw32="no"
+EXESUF=""
+prefix="/usr/local"
+mandir="\${prefix}/share/man"
+datadir="\${prefix}/share/qemu"
+docdir="\${prefix}/share/doc/qemu"
+bindir="\${prefix}/bin"
+sysconfdir="\${prefix}/etc"
+confsuffix="/qemu"
+slirp="yes"
+fmod_lib=""
+fmod_inc=""
+oss_lib=""
+bsd="no"
+linux="no"
+solaris="no"
+profiler="no"
+cocoa="no"
+softmmu="yes"
+linux_user="no"
+darwin_user="no"
+bsd_user="no"
+guest_base=""
+uname_release=""
+io_thread="no"
+mixemu="no"
+kerneldir=""
+aix="no"
+blobs="yes"
+pkgversion=""
+check_utests="no"
+user_pie="no"
+zero_malloc=""
+trace_backend="nop"
+trace_file="trace"
+spice=""
+rbd=""
+
# parse CC options first
for opt do
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
case "$opt" in
--cross-prefix=*) cross_prefix="$optarg"
;;
- --cc=*) cc="$optarg"
+ --cc=*) CC="$optarg"
+ ;;
+ --source-path=*) source_path="$optarg"
;;
--cpu=*) cpu="$optarg"
;;
@@ -129,12 +212,14 @@ done
# Using uname is really, really broken. Once we have the right set of checks
# we can eliminate it's usage altogether
-cc="${cross_prefix}${cc}"
-ar="${cross_prefix}${ar}"
-objcopy="${cross_prefix}${objcopy}"
-ld="${cross_prefix}${ld}"
-strip="${cross_prefix}${strip}"
-windres="${cross_prefix}${windres}"
+cc="${cross_prefix}${CC-gcc}"
+ar="${cross_prefix}${AR-ar}"
+objcopy="${cross_prefix}${OBJCOPY-objcopy}"
+ld="${cross_prefix}${LD-ld}"
+strip="${cross_prefix}${STRIP-strip}"
+windres="${cross_prefix}${WINDRES-windres}"
+pkg_config="${cross_prefix}${PKG_CONFIG-pkg-config}"
+sdl_config="${cross_prefix}${SDL_CONFIG-sdl-config}"
# default flags for all hosts
QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
@@ -143,33 +228,11 @@ QEMU_CFLAGS="-Wall -Wundef -Wendif-labels -Wwrite-strings -Wmissing-prototypes $
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
QEMU_CFLAGS="-D_FORTIFY_SOURCE=2 $QEMU_CFLAGS"
-QEMU_CFLAGS="-I. -I\$(SRC_PATH) $QEMU_CFLAGS"
+QEMU_INCLUDES="-I. -I\$(SRC_PATH)"
LDFLAGS="-g $LDFLAGS"
-gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
-gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
-gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
-gcc_flags="-fstack-protector-all $gcc_flags"
-cat > $TMPC << EOF
-int main(void) { return 0; }
-EOF
-for flag in $gcc_flags; do
- if compile_prog "-Werror $QEMU_CFLAGS" "-Werror $flag" ; then
- QEMU_CFLAGS="$QEMU_CFLAGS $flag"
- fi
-done
-
-# check that the C compiler works.
-cat > $TMPC <<EOF
-int main(void) {}
-EOF
-
-if compile_object ; then
- : C compiler works ok
-else
- echo "ERROR: \"$cc\" either does not exist or does not work"
- exit 1
-fi
+# make source path absolute
+source_path=`cd "$source_path"; pwd`
check_define() {
cat > $TMPC <<EOF
@@ -216,7 +279,6 @@ else
cpu=`uname -m`
fi
-target_list=""
case "$cpu" in
alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64)
cpu="$cpu"
@@ -254,87 +316,6 @@ case "$cpu" in
;;
esac
-# Default value for a variable defining feature "foo".
-# * foo="no" feature will only be used if --enable-foo arg is given
-# * foo="" feature will be searched for, and if found, will be used
-# unless --disable-foo is given
-# * foo="yes" this value will only be set by --enable-foo flag.
-# feature will searched for,
-# if not found, configure exits with error
-#
-# Always add --enable-foo and --disable-foo command line args.
-# Distributions want to ensure that several features are compiled in, and it
-# is impossible without a --enable-foo that exits if a feature is not found.
-
-bluez=""
-brlapi=""
-curl=""
-curses=""
-docs=""
-fdt=""
-kvm=""
-kvm_para=""
-nptl=""
-sdl=""
-sparse="no"
-uuid=""
-vde=""
-vnc_tls=""
-vnc_sasl=""
-vnc_jpeg=""
-vnc_png=""
-vnc_thread="no"
-xen=""
-linux_aio=""
-attr=""
-vhost_net=""
-xfs=""
-
-gprof="no"
-debug_tcg="no"
-debug_mon="no"
-debug="no"
-strip_opt="yes"
-bigendian="no"
-mingw32="no"
-EXESUF=""
-prefix="/usr/local"
-mandir="\${prefix}/share/man"
-datadir="\${prefix}/share/qemu"
-docdir="\${prefix}/share/doc/qemu"
-bindir="\${prefix}/bin"
-sysconfdir="\${prefix}/etc"
-confsuffix="/qemu"
-slirp="yes"
-fmod_lib=""
-fmod_inc=""
-oss_lib=""
-bsd="no"
-linux="no"
-solaris="no"
-profiler="no"
-cocoa="no"
-softmmu="yes"
-linux_user="no"
-darwin_user="no"
-bsd_user="no"
-guest_base=""
-uname_release=""
-io_thread="no"
-mixemu="no"
-kerneldir=""
-aix="no"
-haiku="no"
-blobs="yes"
-pkgversion=""
-check_utests="no"
-user_pie="no"
-zero_malloc=""
-trace_backend="nop"
-trace_file="trace"
-spice=""
-rbd=""
-
# OS specific
if check_define __linux__ ; then
targetos="Linux"
@@ -369,7 +350,7 @@ GNU/kFreeBSD)
;;
FreeBSD)
bsd="yes"
- make="gmake"
+ make="${MAKE-gmake}"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd pa"
# needed for kinfo_getvmmap(3) in libutil.h
@@ -377,20 +358,20 @@ FreeBSD)
;;
DragonFly)
bsd="yes"
- make="gmake"
+ make="${MAKE-gmake}"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd pa"
;;
NetBSD)
bsd="yes"
- make="gmake"
+ make="${MAKE-gmake}"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd"
oss_lib="-lossaudio"
;;
OpenBSD)
bsd="yes"
- make="gmake"
+ make="${MAKE-gmake}"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd"
oss_lib="-lossaudio"
@@ -419,8 +400,8 @@ Darwin)
;;
SunOS)
solaris="yes"
- make="gmake"
- install="ginstall"
+ make="${MAKE-gmake}"
+ install="${INSTALL-ginstall}"
ld="gld"
needs_libsunmath="no"
solarisrev=`uname -r | cut -f2 -d.`
@@ -459,7 +440,7 @@ SunOS)
;;
AIX)
aix="yes"
- make="gmake"
+ make="${MAKE-gmake}"
;;
Haiku)
haiku="yes"
@@ -485,6 +466,9 @@ if [ "$bsd" = "yes" ] ; then
bsd_user="yes"
fi
+: ${make=${MAKE-make}}
+: ${install=${INSTALL-install}}
+
if test "$mingw32" = "yes" ; then
EXESUF=".exe"
QEMU_CFLAGS="-DWIN32_LEAN_AND_MEAN -DWINVER=0x501 $QEMU_CFLAGS"
@@ -500,17 +484,6 @@ if test "$mingw32" = "yes" ; then
confsuffix=""
fi
-# find source path
-source_path=`dirname "$0"`
-source_path_used="no"
-workdir=`pwd`
-if [ -z "$source_path" ]; then
- source_path=$workdir
-else
- source_path=`cd "$source_path"; pwd`
-fi
-[ -f "$workdir/vl.c" ] || source_path_used="yes"
-
werror=""
for opt do
@@ -522,8 +495,7 @@ for opt do
;;
--interp-prefix=*) interp_prefix="$optarg"
;;
- --source-path=*) source_path="$optarg"
- source_path_used="yes"
+ --source-path=*)
;;
--cross-prefix=*)
;;
@@ -543,9 +515,9 @@ for opt do
;;
--target-list=*) target_list="$optarg"
;;
- --trace-backend=*) trace_backend="$optarg"
+ --enable-trace-backend=*) trace_backend="$optarg"
;;
- --trace-file=*) trace_file="$optarg"
+ --with-trace-file=*) trace_file="$optarg"
;;
--enable-gprof) gprof="yes"
;;
@@ -935,8 +907,8 @@ echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable vhost-net acceleration support"
-echo " --trace-backend=B Trace backend nop simple ust dtrace"
-echo " --trace-file=NAME Full PATH,NAME of file to store traces"
+echo " --enable-trace-backend=B Trace backend nop simple ust dtrace"
+echo " --with-trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
echo " --enable-spice enable spice"
@@ -946,6 +918,31 @@ echo "NOTE: The object files are built at the place where configure is launched"
exit 1
fi
+# check that the C compiler works.
+cat > $TMPC <<EOF
+int main(void) {}
+EOF
+
+if compile_object ; then
+ : C compiler works ok
+else
+ echo "ERROR: \"$cc\" either does not exist or does not work"
+ exit 1
+fi
+
+gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
+gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
+gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
+gcc_flags="-fstack-protector-all $gcc_flags"
+cat > $TMPC << EOF
+int main(void) { return 0; }
+EOF
+for flag in $gcc_flags; do
+ if compile_prog "-Werror $QEMU_CFLAGS" "-Werror $flag" ; then
+ QEMU_CFLAGS="$QEMU_CFLAGS $flag"
+ fi
+done
+
#
# Solaris specific configure tool chain decisions
#
@@ -1089,13 +1086,15 @@ esac
fi
-# host long bits test
-hostlongbits="32"
-case "$cpu" in
- x86_64|alpha|ia64|sparc64|ppc64|s390x)
- hostlongbits=64
- ;;
-esac
+# host long bits test, actually a pointer size test
+cat > $TMPC << EOF
+int sizeof_pointer_is_8[sizeof(void *) == 8 ? 1 : -1];
+EOF
+if compile_object; then
+hostlongbits=64
+else
+hostlongbits=32
+fi
##########################################
@@ -1162,12 +1161,11 @@ EOF
fi
##########################################
-# pkgconfig probe
+# pkg-config probe
-pkgconfig="${cross_prefix}pkg-config"
-if ! has $pkgconfig; then
- # likely not cross compiling, or hope for the best
- pkgconfig=pkg-config
+if ! has $pkg_config; then
+ echo warning: proceeding without "$pkg_config" >&2
+ pkg_config=/bin/false
fi
##########################################
@@ -1186,21 +1184,17 @@ fi
##########################################
# SDL probe
-# Look for sdl configuration program (pkg-config or sdl-config).
-# Prefer variant with cross prefix if cross compiling,
-# and favour pkg-config with sdl over sdl-config.
-if test -n "$cross_prefix" -a $pkgconfig != pkg-config && \
- $pkgconfig sdl --modversion >/dev/null 2>&1; then
- sdlconfig="$pkgconfig sdl"
- _sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
-elif test -n "$cross_prefix" && has ${cross_prefix}sdl-config; then
- sdlconfig="${cross_prefix}sdl-config"
- _sdlversion=`$sdlconfig --version | sed 's/[^0-9]//g'`
-elif $pkgconfig sdl --modversion >/dev/null 2>&1; then
- sdlconfig="$pkgconfig sdl"
+# Look for sdl configuration program (pkg-config or sdl-config). Try
+# sdl-config even without cross prefix, and favour pkg-config over sdl-config.
+if test "`basename $sdl_config`" != sdl-config && ! has ${sdl_config}; then
+ sdl_config=sdl-config
+fi
+
+if $pkg_config sdl --modversion >/dev/null 2>&1; then
+ sdlconfig="$pkg_config sdl"
_sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
-elif has sdl-config; then
- sdlconfig='sdl-config'
+elif has ${sdl_config}; then
+ sdlconfig="$sdl_config"
_sdlversion=`$sdlconfig --version | sed 's/[^0-9]//g'`
else
if test "$sdl" = "yes" ; then
@@ -1208,6 +1202,9 @@ else
fi
sdl=no
fi
+if test -n "$cross_prefix" && test "`basename $sdlconfig`" = sdl-config; then
+ echo warning: using "\"$sdlconfig\"" to detect cross-compiled sdl >&2
+fi
sdl_too_old=no
if test "$sdl" != "no" ; then
@@ -1277,8 +1274,8 @@ if test "$vnc_tls" != "no" ; then
#include <gnutls/gnutls.h>
int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
EOF
- vnc_tls_cflags=`$pkgconfig --cflags gnutls 2> /dev/null`
- vnc_tls_libs=`$pkgconfig --libs gnutls 2> /dev/null`
+ vnc_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null`
+ vnc_tls_libs=`$pkg_config --libs gnutls 2> /dev/null`
if compile_prog "$vnc_tls_cflags" "$vnc_tls_libs" ; then
vnc_tls=yes
libs_softmmu="$vnc_tls_libs $libs_softmmu"
@@ -1592,8 +1589,8 @@ fi
##########################################
# curl probe
-if $pkgconfig libcurl --modversion >/dev/null 2>&1; then
- curlconfig="$pkgconfig libcurl"
+if $pkg_config libcurl --modversion >/dev/null 2>&1; then
+ curlconfig="$pkg_config libcurl"
else
curlconfig=curl-config
fi
@@ -1625,7 +1622,7 @@ if test "$check_utests" != "no" ; then
#include <check.h>
int main(void) { suite_create("qemu test"); return 0; }
EOF
- check_libs=`$pkgconfig --libs check`
+ check_libs=`$pkg_config --libs check`
if compile_prog "" $check_libs ; then
check_utests=yes
libs_tools="$check_libs $libs_tools"
@@ -1644,8 +1641,8 @@ if test "$bluez" != "no" ; then
#include <bluetooth/bluetooth.h>
int main(void) { return bt_error(0); }
EOF
- bluez_cflags=`$pkgconfig --cflags bluez 2> /dev/null`
- bluez_libs=`$pkgconfig --libs bluez 2> /dev/null`
+ bluez_cflags=`$pkg_config --cflags bluez 2> /dev/null`
+ bluez_libs=`$pkg_config --libs bluez 2> /dev/null`
if compile_prog "$bluez_cflags" "$bluez_libs" ; then
bluez=yes
libs_softmmu="$bluez_libs $libs_softmmu"
@@ -1689,7 +1686,7 @@ EOF
kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include"
fi
else
- kvm_cflags=`$pkgconfig --cflags kvm-kmod 2>/dev/null`
+ kvm_cflags=`$pkg_config --cflags kvm-kmod 2>/dev/null`
fi
if compile_prog "$kvm_cflags" "" ; then
kvm=yes
@@ -2090,6 +2087,23 @@ if compile_prog "$ARCH_CFLAGS" "" ; then
sync_file_range=yes
fi
+# check for linux/fiemap.h and FS_IOC_FIEMAP
+fiemap=no
+cat > $TMPC << EOF
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+
+int main(void)
+{
+ ioctl(0, FS_IOC_FIEMAP, 0);
+ return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+ fiemap=yes
+fi
+
# check for dup3
dup3=no
cat > $TMPC << EOF
@@ -2252,7 +2266,7 @@ fi
##########################################
# check if trace backend exists
-sh "$source_path/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
+sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
if test "$?" -ne 0 ; then
echo
echo "Error: invalid trace backend"
@@ -2533,7 +2547,7 @@ if test $profiler = "yes" ; then
fi
if test "$slirp" = "yes" ; then
echo "CONFIG_SLIRP=y" >> $config_host_mak
- QEMU_CFLAGS="-I\$(SRC_PATH)/slirp $QEMU_CFLAGS"
+ QEMU_INCLUDES="-I\$(SRC_PATH)/slirp $QEMU_INCLUDES"
fi
if test "$vde" = "yes" ; then
echo "CONFIG_VDE=y" >> $config_host_mak
@@ -2631,6 +2645,9 @@ fi
if test "$sync_file_range" = "yes" ; then
echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
fi
+if test "$fiemap" = "yes" ; then
+ echo "CONFIG_FIEMAP=y" >> $config_host_mak
+fi
if test "$dup3" = "yes" ; then
echo "CONFIG_DUP3=y" >> $config_host_mak
fi
@@ -2760,17 +2777,18 @@ echo "INSTALL_PROG=$install -m0755 -p" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
echo "CC_I386=$cc_i386" >> $config_host_mak
echo "HOST_CC=$host_cc" >> $config_host_mak
-if test "$sparse" = "yes" ; then
- echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak
- echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak
- echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
-fi
echo "AR=$ar" >> $config_host_mak
echo "OBJCOPY=$objcopy" >> $config_host_mak
echo "LD=$ld" >> $config_host_mak
echo "WINDRES=$windres" >> $config_host_mak
echo "CFLAGS=$CFLAGS" >> $config_host_mak
echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
+echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
+if test "$sparse" = "yes" ; then
+ echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak
+ echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak
+ echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
+fi
echo "HELPER_CFLAGS=$helper_cflags" >> $config_host_mak
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak
@@ -2793,8 +2811,7 @@ fi
for d in libdis libdis-user; do
mkdir -p $d
- rm -f $d/Makefile
- ln -s $source_path/Makefile.dis $d/Makefile
+ symlink $source_path/Makefile.dis $d/Makefile
echo > $d/config.mak
done
if test "$static" = "no" -a "$user_pie" = "yes" ; then
@@ -2858,12 +2875,7 @@ mkdir -p $target_dir/ide
if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
mkdir -p $target_dir/nwfpe
fi
-
-#
-# don't use ln -sf as not all "ln -sf" over write the file/link
-#
-rm -f $target_dir/Makefile
-ln -s $source_path/Makefile.target $target_dir/Makefile
+symlink $source_path/Makefile.target $target_dir/Makefile
echo "# Automatically generated by configure - do not modify" > $config_target_mak
@@ -3049,11 +3061,11 @@ if test ! -z "$gdb_xml_files" ; then
fi
case "$target_arch2" in
- alpha|arm|armeb|m68k|microblaze|mips|mipsel|mipsn32|mipsn32el|mips64|mips64el|ppc|ppc64|ppc64abi32|ppcemb|s390x|sparc|sparc64|sparc32plus)
- echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak
+ i386|x86_64)
+ echo "CONFIG_NOSOFTFLOAT=y" >> $config_target_mak
;;
*)
- echo "CONFIG_NOSOFTFLOAT=y" >> $config_target_mak
+ echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak
;;
esac
@@ -3074,19 +3086,20 @@ fi
# generate QEMU_CFLAGS/LDFLAGS for targets
cflags=""
+includes=""
ldflags=""
if test "$ARCH" = "sparc64" ; then
- cflags="-I\$(SRC_PATH)/tcg/sparc $cflags"
+ includes="-I\$(SRC_PATH)/tcg/sparc $includes"
elif test "$ARCH" = "s390x" ; then
- cflags="-I\$(SRC_PATH)/tcg/s390 $cflags"
+ includes="-I\$(SRC_PATH)/tcg/s390 $includes"
elif test "$ARCH" = "x86_64" ; then
- cflags="-I\$(SRC_PATH)/tcg/i386 $cflags"
+ includes="-I\$(SRC_PATH)/tcg/i386 $includes"
else
- cflags="-I\$(SRC_PATH)/tcg/\$(ARCH) $cflags"
+ includes="-I\$(SRC_PATH)/tcg/\$(ARCH) $includes"
fi
-cflags="-I\$(SRC_PATH)/tcg $cflags"
-cflags="-I\$(SRC_PATH)/fpu $cflags"
+includes="-I\$(SRC_PATH)/tcg $includes"
+includes="-I\$(SRC_PATH)/fpu $includes"
if test "$target_user_only" = "yes" ; then
libdis_config_mak=libdis-user/config.mak
@@ -3211,31 +3224,25 @@ fi
echo "LDFLAGS+=$ldflags" >> $config_target_mak
echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak
+echo "QEMU_INCLUDES+=$includes" >> $config_target_mak
done # for target in $targets
-# build tree in object directory if source path is different from current one
-if test "$source_path_used" = "yes" ; then
- DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
- DIRS="$DIRS roms/seabios roms/vgabios"
- DIRS="$DIRS fsdev ui"
- FILES="Makefile tests/Makefile"
- FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
- FILES="$FILES tests/test-mmap.c"
- FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
- FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
- for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
- FILES="$FILES pc-bios/`basename $bios_file`"
- done
- for dir in $DIRS ; do
- mkdir -p $dir
- done
- # remove the link and recreate it, as not all "ln -sf" overwrite the link
- for f in $FILES ; do
- rm -f $f
- ln -s $source_path/$f $f
- done
-fi
+# build tree in object directory in case the source is not in the current directory
+DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
+DIRS="$DIRS roms/seabios roms/vgabios"
+DIRS="$DIRS fsdev ui"
+FILES="Makefile tests/Makefile"
+FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
+FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
+FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
+for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
+ FILES="$FILES pc-bios/`basename $bios_file`"
+done
+mkdir -p $DIRS
+for f in $FILES ; do
+ test -e $f || symlink $source_path/$f $f
+done
# temporary config to build submodules
for rom in seabios vgabios ; do
@@ -3247,7 +3254,6 @@ for rom in seabios vgabios ; do
echo "CPP=${cross_prefix}cpp" >> $config_mak
echo "OBJCOPY=objcopy" >> $config_mak
echo "IASL=iasl" >> $config_mak
- echo "HOST_CC=$host_cc" >> $config_mak
echo "LD=$ld" >> $config_mak
done
@@ -3255,15 +3261,13 @@ for hwlib in 32 64; do
d=libhw$hwlib
mkdir -p $d
mkdir -p $d/ide
- rm -f $d/Makefile
- ln -s $source_path/Makefile.hw $d/Makefile
+ symlink $source_path/Makefile.hw $d/Makefile
echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak
done
d=libuser
mkdir -p $d
-rm -f $d/Makefile
-ln -s $source_path/Makefile.user $d/Makefile
+symlink $source_path/Makefile.user $d/Makefile
if test "$static" = "no" -a "$user_pie" = "yes" ; then
echo "QEMU_CFLAGS+=-fpie" > $d/config.mak
fi
diff --git a/disas.c b/disas.c
index dd2db142d7..c76f36f590 100644
--- a/disas.c
+++ b/disas.c
@@ -307,11 +307,6 @@ void disas(FILE *out, void *code, unsigned long size)
#endif
for (pc = (unsigned long)code; size > 0; pc += count, size -= count) {
fprintf(out, "0x%08lx: ", pc);
-#ifdef __arm__
- /* since data is included in the code, it is better to
- display code data too */
- fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
-#endif
count = print_insn(pc, &disasm_info);
fprintf(out, "\n");
if (count < 0)
diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt
index f252c8e3bc..f2f9b757a5 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -97,10 +97,13 @@ The -device argument differs in detail for each kind of drive:
* if=virtio
- -device virtio-blk-pci,drive=DRIVE-ID,class=C,vectors=V
+ -device virtio-blk-pci,drive=DRIVE-ID,class=C,vectors=V,ioeventfd=IOEVENTFD
This lets you control PCI device class and MSI-X vectors.
+ IOEVENTFD controls whether or not ioeventfd is used for virtqueue notify. It
+ can be set to on (default) or off.
+
As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
control the PCI device address.
@@ -240,6 +243,9 @@ For PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control the PCI
device address, as usual. The old -net nic provides parameter addr
for that, it is silently ignored when the NIC is not a PCI device.
+For virtio-net-pci, you can control whether or not ioeventfd is used for
+virtqueue notify by setting ioeventfd= to on or off (default).
+
-net nic accepts vectors=V for all models, but it's silently ignored
except for virtio-net-pci (model=virtio). With -device, only devices
that support it accept it.
diff --git a/docs/specs/acpi_pci_hotplug.txt b/docs/specs/acpi_pci_hotplug.txt
new file mode 100644
index 0000000000..f0f74a7c7c
--- /dev/null
+++ b/docs/specs/acpi_pci_hotplug.txt
@@ -0,0 +1,37 @@
+QEMU<->ACPI BIOS PCI hotplug interface
+--------------------------------------
+
+QEMU supports PCI hotplug via ACPI, for PCI bus 0. This document
+describes the interface between QEMU and the ACPI BIOS.
+
+ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
+-----------------------------------------
+
+Generic ACPI GPE block. Bit 1 (GPE.1) used to notify PCI hotplug/eject
+event to ACPI BIOS, via SCI interrupt.
+
+PCI slot injection notification pending (IO port 0xae00-0xae03, 4-byte access):
+---------------------------------------------------------------
+Slot injection notification pending. One bit per slot.
+
+Read by ACPI BIOS GPE.1 handler to notify OS of injection
+events.
+
+PCI slot removal notification (IO port 0xae04-0xae07, 4-byte access):
+-----------------------------------------------------
+Slot removal notification pending. One bit per slot.
+
+Read by ACPI BIOS GPE.1 handler to notify OS of removal
+events.
+
+PCI device eject (IO port 0xae08-0xae0b, 4-byte access):
+----------------------------------------
+
+Used by ACPI BIOS _EJ0 method to request device removal. One bit per slot.
+Reads return 0.
+
+PCI removability status (IO port 0xae0c-0xae0f, 4-byte access):
+-----------------------------------------------
+
+Used by ACPI BIOS _RMV method to indicate removability status to OS. One
+bit per slot.
diff --git a/exec.c b/exec.c
index 49c28b160e..e950df25c3 100644
--- a/exec.c
+++ b/exec.c
@@ -531,6 +531,13 @@ static void code_gen_alloc(unsigned long tb_size)
/* Cannot map more than that */
if (code_gen_buffer_size > (800 * 1024 * 1024))
code_gen_buffer_size = (800 * 1024 * 1024);
+#elif defined(__sparc_v9__)
+ // Map the buffer below 2G, so we can use direct calls and branches
+ flags |= MAP_FIXED;
+ addr = (void *) 0x60000000UL;
+ if (code_gen_buffer_size > (512 * 1024 * 1024)) {
+ code_gen_buffer_size = (512 * 1024 * 1024);
+ }
#endif
code_gen_buffer = mmap(addr, code_gen_buffer_size,
PROT_WRITE | PROT_READ | PROT_EXEC,
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index f293f24356..eb644b2273 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -30,7 +30,7 @@ these four paragraphs for those parts of this code that are retained.
=============================================================================*/
-#if defined(TARGET_MIPS)
+#if defined(TARGET_MIPS) || defined(TARGET_SH4)
#define SNAN_BIT_IS_ONE 1
#else
#define SNAN_BIT_IS_ONE 0
@@ -108,7 +108,7 @@ float32 float32_maybe_silence_nan( float32 a_ )
{
if (float32_is_signaling_nan(a_)) {
#if SNAN_BIT_IS_ONE
-# if defined(TARGET_MIPS)
+# if defined(TARGET_MIPS) || defined(TARGET_SH4)
return float32_default_nan;
# else
# error Rules for silencing a signaling NaN are target-specific
@@ -278,9 +278,6 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
flag aIsLargerSignificand;
bits32 av, bv;
- if ( STATUS(default_nan_mode) )
- return float32_default_nan;
-
aIsQuietNaN = float32_is_quiet_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
bIsQuietNaN = float32_is_quiet_nan( b );
@@ -290,6 +287,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+ if ( STATUS(default_nan_mode) )
+ return float32_default_nan;
+
if ((bits32)(av<<1) < (bits32)(bv<<1)) {
aIsLargerSignificand = 0;
} else if ((bits32)(bv<<1) < (bits32)(av<<1)) {
@@ -362,7 +362,7 @@ float64 float64_maybe_silence_nan( float64 a_ )
{
if (float64_is_signaling_nan(a_)) {
#if SNAN_BIT_IS_ONE
-# if defined(TARGET_MIPS)
+# if defined(TARGET_MIPS) || defined(TARGET_SH4)
return float64_default_nan;
# else
# error Rules for silencing a signaling NaN are target-specific
@@ -423,9 +423,6 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
flag aIsLargerSignificand;
bits64 av, bv;
- if ( STATUS(default_nan_mode) )
- return float64_default_nan;
-
aIsQuietNaN = float64_is_quiet_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsQuietNaN = float64_is_quiet_nan( b );
@@ -435,6 +432,9 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+ if ( STATUS(default_nan_mode) )
+ return float64_default_nan;
+
if ((bits64)(av<<1) < (bits64)(bv<<1)) {
aIsLargerSignificand = 0;
} else if ((bits64)(bv<<1) < (bits64)(av<<1)) {
@@ -468,7 +468,8 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
-| quiet NaN; otherwise returns 0.
+| quiet NaN; otherwise returns 0. This slightly differs from the same
+| function for other types as floatx80 has an explicit bit.
*----------------------------------------------------------------------------*/
int floatx80_is_quiet_nan( floatx80 a )
@@ -482,19 +483,22 @@ int floatx80_is_quiet_nan( floatx80 a )
&& (bits64) ( aLow<<1 )
&& ( a.low == aLow );
#else
- return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
+ return ( ( a.high & 0x7FFF ) == 0x7FFF )
+ && (LIT64( 0x8000000000000000 ) <= ((bits64) ( a.low<<1 )));
#endif
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
-| signaling NaN; otherwise returns 0.
+| signaling NaN; otherwise returns 0. This slightly differs from the same
+| function for other types as floatx80 has an explicit bit.
*----------------------------------------------------------------------------*/
int floatx80_is_signaling_nan( floatx80 a )
{
#if SNAN_BIT_IS_ONE
- return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
+ return ( ( a.high & 0x7FFF ) == 0x7FFF )
+ && (LIT64( 0x8000000000000000 ) <= ((bits64) ( a.low<<1 )));
#else
bits64 aLow;
@@ -515,7 +519,7 @@ floatx80 floatx80_maybe_silence_nan( floatx80 a )
{
if (floatx80_is_signaling_nan(a)) {
#if SNAN_BIT_IS_ONE
-# if defined(TARGET_MIPS)
+# if defined(TARGET_MIPS) || defined(TARGET_SH4)
a.low = floatx80_default_nan_low;
a.high = floatx80_default_nan_high;
# else
@@ -574,12 +578,6 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
- if ( STATUS(default_nan_mode) ) {
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
- }
-
aIsQuietNaN = floatx80_is_quiet_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsQuietNaN = floatx80_is_quiet_nan( b );
@@ -587,6 +585,12 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+ if ( STATUS(default_nan_mode) ) {
+ a.low = floatx80_default_nan_low;
+ a.high = floatx80_default_nan_high;
+ return a;
+ }
+
if (a.low < b.low) {
aIsLargerSignificand = 0;
} else if (b.low < a.low) {
@@ -664,7 +668,7 @@ float128 float128_maybe_silence_nan( float128 a )
{
if (float128_is_signaling_nan(a)) {
#if SNAN_BIT_IS_ONE
-# if defined(TARGET_MIPS)
+# if defined(TARGET_MIPS) || defined(TARGET_SH4)
a.low = float128_default_nan_low;
a.high = float128_default_nan_high;
# else
@@ -719,12 +723,6 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
- if ( STATUS(default_nan_mode) ) {
- a.low = float128_default_nan_low;
- a.high = float128_default_nan_high;
- return a;
- }
-
aIsQuietNaN = float128_is_quiet_nan( a );
aIsSignalingNaN = float128_is_signaling_nan( a );
bIsQuietNaN = float128_is_quiet_nan( b );
@@ -732,6 +730,12 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+ if ( STATUS(default_nan_mode) ) {
+ a.low = float128_default_nan_low;
+ a.high = float128_default_nan_high;
+ return a;
+ }
+
if (lt128(a.high<<1, a.low, b.high<<1, b.low)) {
aIsLargerSignificand = 0;
} else if (lt128(b.high<<1, b.low, a.high<<1, a.low)) {
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index a6d0f16b42..4a5345ceca 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -336,6 +336,11 @@ INLINE int float32_is_any_nan(float32 a)
return ((float32_val(a) & ~(1 << 31)) > 0x7f800000UL);
}
+INLINE int float32_is_zero_or_denormal(float32 a)
+{
+ return (float32_val(a) & 0x7f800000) == 0;
+}
+
#define float32_zero make_float32(0)
#define float32_one make_float32(0x3f800000)
#define float32_ln2 make_float32(0x3f317218)
diff --git a/gdbstub.c b/gdbstub.c
index 0aa081b13b..d6556c9a2f 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2391,6 +2391,12 @@ void gdb_exit(CPUState *env, int code)
snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
put_packet(s, buf);
+
+#ifndef CONFIG_USER_ONLY
+ if (s->chr) {
+ qemu_chr_close(s->chr);
+ }
+#endif
}
#ifdef CONFIG_USER_ONLY
diff --git a/gdbstub.h b/gdbstub.h
index ce5fdcc223..d82334fc7b 100644
--- a/gdbstub.h
+++ b/gdbstub.h
@@ -38,7 +38,7 @@ int gdbserver_start(int);
int gdbserver_start(const char *port);
#endif
-/* in gdbstub-xml.c, generated by feature_to_c.sh */
+/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
extern const char *const xml_builtin[][2];
#endif
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 173d78148d..5bbc2b5a26 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -37,6 +37,7 @@
#define GPE_BASE 0xafe0
#define PCI_BASE 0xae00
#define PCI_EJ_BASE 0xae08
+#define PCI_RMV_BASE 0xae0c
#define PIIX4_PCI_HOTPLUG_STATUS 2
@@ -73,6 +74,7 @@ typedef struct PIIX4PMState {
/* for pci hotplug */
struct gpe_regs gpe;
struct pci_status pci0_status;
+ uint32_t pci0_hotplug_enable;
} PIIX4PMState;
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
@@ -322,6 +324,25 @@ static const VMStateDescription vmstate_acpi = {
}
};
+static void piix4_update_hotplug(PIIX4PMState *s)
+{
+ PCIDevice *dev = &s->dev;
+ BusState *bus = qdev_get_parent_bus(&dev->qdev);
+ DeviceState *qdev, *next;
+
+ s->pci0_hotplug_enable = ~0;
+
+ QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+ PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+ PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+ int slot = PCI_SLOT(pdev->devfn);
+
+ if (info->no_hotplug) {
+ s->pci0_hotplug_enable &= ~(1 << slot);
+ }
+ }
+}
+
static void piix4_reset(void *opaque)
{
PIIX4PMState *s = opaque;
@@ -336,6 +357,7 @@ static void piix4_reset(void *opaque)
/* Mark SMM as already inited (until KVM supports SMM). */
pci_conf[0x5B] = 0x02;
}
+ piix4_update_hotplug(s);
}
static void piix4_powerdown(void *opaque, int irq, int power_failing)
@@ -428,6 +450,8 @@ static PCIDeviceInfo piix4_pm_info = {
.qdev.desc = "PM",
.qdev.size = sizeof(PIIX4PMState),
.qdev.vmsd = &vmstate_acpi,
+ .qdev.no_user = 1,
+ .no_hotplug = 1,
.init = piix4_pm_initfn,
.config_write = pm_write_config,
.qdev.props = (Property[]) {
@@ -574,6 +598,18 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val);
}
+static uint32_t pcirmv_read(void *opaque, uint32_t addr)
+{
+ PIIX4PMState *s = opaque;
+
+ return s->pci0_hotplug_enable;
+}
+
+static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ return;
+}
+
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
@@ -590,6 +626,9 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
+ register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s);
+ register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s);
+
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
}
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index bd0664fe7a..d8b062c1bf 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -28,6 +28,22 @@ typedef struct {
uint32_t proc_id;
} arm_sysctl_state;
+static const VMStateDescription vmstate_arm_sysctl = {
+ .name = "realview_sysctl",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(leds, arm_sysctl_state),
+ VMSTATE_UINT16(lockval, arm_sysctl_state),
+ VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
+ VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
+ VMSTATE_UINT32(flags, arm_sysctl_state),
+ VMSTATE_UINT32(nvflags, arm_sysctl_state),
+ VMSTATE_UINT32(resetlevel, arm_sysctl_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void arm_sysctl_reset(DeviceState *d)
{
arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sysbus_from_qdev(d));
@@ -231,6 +247,7 @@ static SysBusDeviceInfo arm_sysctl_info = {
.init = arm_sysctl_init1,
.qdev.name = "realview_sysctl",
.qdev.size = sizeof(arm_sysctl_state),
+ .qdev.vmsd = &vmstate_arm_sysctl,
.qdev.reset = arm_sysctl_reset,
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 75d1cc6f57..5f45b5dee7 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -3140,6 +3140,7 @@ static PCIDeviceInfo cirrus_vga_info = {
.qdev.desc = "Cirrus CLGD 54xx VGA",
.qdev.size = sizeof(PCICirrusVGAState),
.qdev.vmsd = &vmstate_pci_cirrus_vga,
+ .no_hotplug = 1,
.init = pci_cirrus_vga_initfn,
.romfile = VGABIOS_CIRRUS_FILENAME,
.config_write = pci_cirrus_write_config,
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 14c6ad364c..923073be94 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -223,16 +223,14 @@
#define GT_PCI0_HICMASK (0xca4 >> 2)
#define GT_PCI1_SERR1MASK (0xca8 >> 2)
-
-typedef PCIHostState GT64120PCIState;
-
#define PCI_MAPPING_ENTRY(regname) \
target_phys_addr_t regname ##_start; \
target_phys_addr_t regname ##_length; \
int regname ##_handle
typedef struct GT64120State {
- GT64120PCIState *pci;
+ SysBusDevice busdev;
+ PCIHostState pci;
uint32_t regs[GT_REGS];
PCI_MAPPING_ENTRY(PCI0IO);
PCI_MAPPING_ENTRY(ISD);
@@ -525,13 +523,13 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
/* not implemented */
break;
case GT_PCI0_CFGADDR:
- s->pci->config_reg = val & 0x80fffffc;
+ s->pci.config_reg = val & 0x80fffffc;
break;
case GT_PCI0_CFGDATA:
- if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci->config_reg & 0x00fff800))
+ if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
val = bswap32(val);
- if (s->pci->config_reg & (1u << 31))
- pci_data_write(s->pci->bus, s->pci->config_reg, val, 4);
+ if (s->pci.config_reg & (1u << 31))
+ pci_data_write(s->pci.bus, s->pci.config_reg, val, 4);
break;
/* Interrupts */
@@ -765,14 +763,14 @@ static uint32_t gt64120_readl (void *opaque,
/* PCI Internal */
case GT_PCI0_CFGADDR:
- val = s->pci->config_reg;
+ val = s->pci.config_reg;
break;
case GT_PCI0_CFGDATA:
- if (!(s->pci->config_reg & (1 << 31)))
+ if (!(s->pci.config_reg & (1 << 31)))
val = 0xffffffff;
else
- val = pci_data_read(s->pci->bus, s->pci->config_reg, 4);
- if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci->config_reg & 0x00fff800))
+ val = pci_data_read(s->pci.bus, s->pci.config_reg, 4);
+ if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
val = bswap32(val);
break;
@@ -864,7 +862,7 @@ static CPUReadMemoryFunc * const gt64120_read[] = {
&gt64120_readl,
};
-static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num)
+static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num)
{
int slot;
@@ -891,7 +889,7 @@ static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num)
static int pci_irq_levels[4];
-static void pci_gt64120_set_irq(void *opaque, int irq_num, int level)
+static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
{
int i, pic_irq, pic_level;
qemu_irq *pic = opaque;
@@ -1101,50 +1099,76 @@ static int gt64120_load(QEMUFile* f, void *opaque, int version_id)
return 0;
}
-PCIBus *pci_gt64120_init(qemu_irq *pic)
+PCIBus *gt64120_register(qemu_irq *pic)
+{
+ SysBusDevice *s;
+ GT64120State *d;
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "gt64120");
+ qdev_init_nofail(dev);
+ s = sysbus_from_qdev(dev);
+ d = FROM_SYSBUS(GT64120State, s);
+ d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
+ gt64120_pci_set_irq, gt64120_pci_map_irq,
+ pic, PCI_DEVFN(18, 0), 4);
+ d->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, d,
+ DEVICE_NATIVE_ENDIAN);
+
+ pci_create_simple(d->pci.bus, PCI_DEVFN(0, 0), "gt64120_pci");
+ return d->pci.bus;
+}
+
+static int gt64120_init(SysBusDevice *dev)
{
GT64120State *s;
- PCIDevice *d;
- s = qemu_mallocz(sizeof(GT64120State));
- s->pci = qemu_mallocz(sizeof(GT64120PCIState));
+ s = FROM_SYSBUS(GT64120State, dev);
- s->pci->bus = pci_register_bus(NULL, "pci",
- pci_gt64120_set_irq, pci_gt64120_map_irq,
- pic, PCI_DEVFN(18, 0), 4);
- s->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, s,
- DEVICE_NATIVE_ENDIAN);
- d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
- 0, NULL, NULL);
+ /* FIXME: This value is computed from registers during reset, but some
+ devices (e.g. VGA card) need to know it when they are registered.
+ This also mean that changing the register to change the mapping
+ does not fully work. */
+ isa_mem_base = 0x10000000;
+ qemu_register_reset(gt64120_reset, s);
+ register_savevm(&dev->qdev, "GT64120 PCI Bus", 0, 1,
+ gt64120_save, gt64120_load, &s->pci);
+ return 0;
+}
+static int gt64120_pci_init(PCIDevice *d)
+{
/* FIXME: Malta specific hw assumptions ahead */
-
pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MARVELL);
pci_config_set_device_id(d->config, PCI_DEVICE_ID_MARVELL_GT6412X);
-
- d->config[0x04] = 0x00;
- d->config[0x05] = 0x00;
- d->config[0x06] = 0x80;
- d->config[0x07] = 0x02;
-
- d->config[0x08] = 0x10;
- d->config[0x09] = 0x00;
+ pci_set_word(d->config + PCI_COMMAND, 0);
+ pci_set_word(d->config + PCI_STATUS,
+ PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+ pci_set_byte(d->config + PCI_CLASS_REVISION, 0x10);
+ pci_config_set_prog_interface(d->config, 0);
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+ pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
+ pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
+ pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
+ pci_set_long(d->config + PCI_BASE_ADDRESS_3, 0x1f000000);
+ pci_set_long(d->config + PCI_BASE_ADDRESS_4, 0x14000000);
+ pci_set_long(d->config + PCI_BASE_ADDRESS_5, 0x14000001);
+ pci_set_byte(d->config + 0x3d, 0x01);
- d->config[0x10] = 0x08;
- d->config[0x14] = 0x08;
- d->config[0x17] = 0x01;
- d->config[0x1B] = 0x1c;
- d->config[0x1F] = 0x1f;
- d->config[0x23] = 0x14;
- d->config[0x24] = 0x01;
- d->config[0x27] = 0x14;
- d->config[0x3D] = 0x01;
-
- gt64120_reset(s);
+ return 0;
+}
- register_savevm(&d->qdev, "GT64120 PCI Bus", 0, 1,
- gt64120_save, gt64120_load, d);
+static PCIDeviceInfo gt64120_pci_info = {
+ .qdev.name = "gt64120_pci",
+ .qdev.size = sizeof(PCIDevice),
+ .init = gt64120_pci_init,
+};
- return s->pci->bus;
+static void gt64120_pci_register_devices(void)
+{
+ sysbus_register_dev("gt64120", sizeof(GT64120State),
+ gt64120_init);
+ pci_qdev_register(&gt64120_pci_info);
}
+
+device_init(gt64120_pci_register_devices)
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 1cad9066a0..d4289af9c4 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -194,11 +194,13 @@ static PCIDeviceInfo piix_ide_info[] = {
.qdev.name = "piix3-ide",
.qdev.size = sizeof(PCIIDEState),
.qdev.no_user = 1,
+ .no_hotplug = 1,
.init = pci_piix3_ide_initfn,
},{
.qdev.name = "piix4-ide",
.qdev.size = sizeof(PCIIDEState),
.qdev.no_user = 1,
+ .no_hotplug = 1,
.init = pci_piix4_ide_initfn,
},{
/* end of list */
diff --git a/hw/lan9118.c b/hw/lan9118.c
index a98866479b..9cc7952b2a 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -187,7 +187,7 @@ typedef struct {
uint32_t phy_int_mask;
int eeprom_writable;
- uint8_t eeprom[8];
+ uint8_t eeprom[128];
int tx_fifo_size;
LAN9118Packet *txp;
@@ -1003,7 +1003,7 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
s->afc_cfg = val & 0x00ffffff;
break;
case CSR_E2P_CMD:
- lan9118_eeprom_cmd(s, (val >> 28) & 7, val & 0xff);
+ lan9118_eeprom_cmd(s, (val >> 28) & 7, val & 0x7f);
break;
case CSR_E2P_DATA:
s->e2p_data = val & 0xff;
diff --git a/hw/loader.c b/hw/loader.c
index eb198f6723..35d792e647 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -307,8 +307,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
target_data_order = ELFDATA2LSB;
}
- if (target_data_order != e_ident[EI_DATA])
- return -1;
+ if (target_data_order != e_ident[EI_DATA]) {
+ goto fail;
+ }
lseek(fd, 0, SEEK_SET);
if (e_ident[EI_CLASS] == ELFCLASS64) {
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 0129ae3cc0..9c761cdb66 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -1930,7 +1930,7 @@ static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr)
val = s->script_ram[addr >> 2];
if (addr & 2)
val >>= 16;
- return le16_to_cpu(val);
+ return val;
}
static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr)
@@ -1938,7 +1938,7 @@ static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr)
LSIState *s = opaque;
addr &= 0x1fff;
- return le32_to_cpu(s->script_ram[addr >> 2]);
+ return s->script_ram[addr >> 2];
}
static CPUReadMemoryFunc * const lsi_ram_readfn[3] = {
diff --git a/hw/m48t59.c b/hw/m48t59.c
index 6991e2e8e1..2020487bbe 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -642,6 +642,7 @@ M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
DeviceState *dev;
SysBusDevice *s;
M48t59SysBusState *d;
+ M48t59State *state;
dev = qdev_create(NULL, "m48t59");
qdev_prop_set_uint32(dev, "type", type);
@@ -649,18 +650,18 @@ M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
qdev_prop_set_uint32(dev, "io_base", io_base);
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
+ d = FROM_SYSBUS(M48t59SysBusState, s);
+ state = &d->state;
sysbus_connect_irq(s, 0, IRQ);
if (io_base != 0) {
- register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
- register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
+ register_ioport_read(io_base, 0x04, 1, NVRAM_readb, state);
+ register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, state);
}
if (mem_base != 0) {
sysbus_mmio_map(s, 0, mem_base);
}
- d = FROM_SYSBUS(M48t59SysBusState, s);
-
- return &d->state;
+ return state;
}
M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type)
diff --git a/hw/mainstone.c b/hw/mainstone.c
index efa2959c72..58e3f8670d 100644
--- a/hw/mainstone.c
+++ b/hw/mainstone.c
@@ -106,7 +106,8 @@ static void mainstone_common_init(ram_addr_t ram_size,
}
if (!pflash_cfi01_register(mainstone_flash_base[i],
- qemu_ram_alloc(NULL, "mainstone.flash",
+ qemu_ram_alloc(NULL, i ? "mainstone.flash1" :
+ "mainstone.flash0",
MAINSTONE_FLASH),
dinfo->bdrv, sector_len,
MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0,
diff --git a/hw/mips.h b/hw/mips.h
index 617ea103c0..757e8f931c 100644
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -3,7 +3,7 @@
/* Definitions for mips board emulation. */
/* gt64xxx.c */
-PCIBus *pci_gt64120_init(qemu_irq *pic);
+PCIBus *gt64120_register(qemu_irq *pic);
/* bonito.c */
PCIBus *bonito_init(qemu_irq *pic);
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 5ef3fcbea9..87554169c5 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -910,7 +910,7 @@ void mips_malta_init (ram_addr_t ram_size,
/* Board ID = 0x420 (Malta Board with CoreLV)
XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
map to the board ID. */
- stl_phys(0x1fc00010LL, 0x00000420);
+ stl_p(qemu_get_ram_ptr(bios_offset) + 0x10, 0x00000420);
/* Init internal devices */
cpu_mips_irq_init_cpu(env);
@@ -921,7 +921,7 @@ void mips_malta_init (ram_addr_t ram_size,
i8259 = i8259_init(env->irq[2]);
/* Northbridge */
- pci_bus = pci_gt64120_init(i8259);
+ pci_bus = gt64120_register(i8259);
/* Southbridge */
diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index e3beee8281..9c95f282a2 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -42,16 +42,6 @@ uint32_t cpu_mips_get_random (CPUState *env)
}
/* MIPS R4K timer */
-uint32_t cpu_mips_get_count (CPUState *env)
-{
- if (env->CP0_Cause & (1 << CP0Ca_DC))
- return env->CP0_Count;
- else
- return env->CP0_Count +
- (uint32_t)muldiv64(qemu_get_clock(vm_clock),
- TIMER_FREQ, get_ticks_per_sec());
-}
-
static void cpu_mips_timer_update(CPUState *env)
{
uint64_t now, next;
@@ -64,6 +54,35 @@ static void cpu_mips_timer_update(CPUState *env)
qemu_mod_timer(env->timer, next);
}
+/* Expire the timer. */
+static void cpu_mips_timer_expire(CPUState *env)
+{
+ cpu_mips_timer_update(env);
+ if (env->insn_flags & ISA_MIPS32R2) {
+ env->CP0_Cause |= 1 << CP0Ca_TI;
+ }
+ qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+uint32_t cpu_mips_get_count (CPUState *env)
+{
+ if (env->CP0_Cause & (1 << CP0Ca_DC)) {
+ return env->CP0_Count;
+ } else {
+ uint64_t now;
+
+ now = qemu_get_clock(vm_clock);
+ if (qemu_timer_pending(env->timer)
+ && qemu_timer_expired(env->timer, now)) {
+ /* The timer has already expired. */
+ cpu_mips_timer_expire(env);
+ }
+
+ return env->CP0_Count +
+ (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
+ }
+}
+
void cpu_mips_store_count (CPUState *env, uint32_t count)
{
if (env->CP0_Cause & (1 << CP0Ca_DC))
@@ -116,11 +135,8 @@ static void mips_timer_cb (void *opaque)
the comparator value. Offset the count by one to avoid immediately
retriggering the callback before any virtual time has passed. */
env->CP0_Count++;
- cpu_mips_timer_update(env);
+ cpu_mips_timer_expire(env);
env->CP0_Count--;
- if (env->insn_flags & ISA_MIPS32R2)
- env->CP0_Cause |= 1 << CP0Ca_TI;
- qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
}
void cpu_mips_clock_init (CPUState *env)
diff --git a/hw/msi.c b/hw/msi.c
index f03f519a2e..3dc3a24b77 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -255,7 +255,6 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
uint8_t log_max_vecs;
unsigned int vector;
uint32_t pending;
- int i;
if (!ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
return;
@@ -296,9 +295,7 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
* from using its INTx# pin (if implemented) to request
* service (MSI, MSI-X, and INTx# are mutually exclusive).
*/
- for (i = 0; i < PCI_NUM_PINS; ++i) {
- qemu_set_irq(dev->irq[i], 0);
- }
+ pci_device_deassert_intx(dev);
/*
* nr_vectors might be set bigger than capable. So clamp it.
diff --git a/hw/msix.c b/hw/msix.c
index e1230824b2..daaf9b7878 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -159,7 +159,6 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
{
unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
int vector;
- int i;
if (!range_covers_byte(addr, len, enable_pos)) {
return;
@@ -169,9 +168,7 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
return;
}
- for (i = 0; i < PCI_NUM_PINS; ++i) {
- qemu_set_irq(dev->irq[i], 0);
- }
+ pci_device_deassert_intx(dev);
if (msix_function_masked(dev)) {
return;
diff --git a/hw/pci.c b/hw/pci.c
index d0b51b80bd..b8f5385170 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -137,6 +137,14 @@ static void pci_update_irq_status(PCIDevice *dev)
}
}
+void pci_device_deassert_intx(PCIDevice *dev)
+{
+ int i;
+ for (i = 0; i < PCI_NUM_PINS; ++i) {
+ qemu_set_irq(dev->irq[i], 0);
+ }
+}
+
/*
* This function is called on #RST and FLR.
* FLR if PCI_EXP_DEVCTL_BCR_FLR is set
@@ -152,6 +160,7 @@ void pci_device_reset(PCIDevice *dev)
dev->irq_state = 0;
pci_update_irq_status(dev);
+ pci_device_deassert_intx(dev);
/* Clear all writeable bits */
pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
pci_get_word(dev->wmask + PCI_COMMAND) |
@@ -1624,6 +1633,11 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
info->is_bridge);
if (pci_dev == NULL)
return -1;
+ if (qdev->hotplugged && info->no_hotplug) {
+ qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+ do_pci_unregister_device(pci_dev);
+ return -1;
+ }
rc = info->init(pci_dev);
if (rc != 0) {
do_pci_unregister_device(pci_dev);
@@ -1656,7 +1670,12 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
static int pci_unplug_device(DeviceState *qdev)
{
PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+ if (info->no_hotplug) {
+ qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+ return -1;
+ }
return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
PCI_HOTPLUG_DISABLED);
}
@@ -2022,10 +2041,13 @@ static char *pcibus_get_dev_path(DeviceState *dev)
* domain:Bus:Slot.Func for systems without nested PCI bridges.
* Slot.Function list specifies the slot and function numbers for all
* devices on the path from root to the specific device. */
- int domain_len = strlen("DDDD:00");
- int slot_len = strlen(":SS.F");
+ char domain[] = "DDDD:00";
+ char slot[] = ":SS.F";
+ int domain_len = sizeof domain - 1 /* For '\0' */;
+ int slot_len = sizeof slot - 1 /* For '\0' */;
int path_len;
char *path, *p;
+ int s;
/* Calculate # of slots on path between device and root. */;
slot_depth = 0;
@@ -2036,18 +2058,23 @@ static char *pcibus_get_dev_path(DeviceState *dev)
path_len = domain_len + slot_len * slot_depth;
/* Allocate memory, fill in the terminating null byte. */
- path = malloc(path_len + 1 /* For '\0' */);
+ path = qemu_malloc(path_len + 1 /* For '\0' */);
path[path_len] = '\0';
/* First field is the domain. */
- snprintf(path, domain_len, "%04x:00", pci_find_domain(d->bus));
+ s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus));
+ assert(s == domain_len);
+ memcpy(path, domain, domain_len);
/* Fill in slot numbers. We walk up from device to root, so need to print
* them in the reverse order, last to first. */
p = path + path_len;
for (t = d; t; t = t->bus->parent_dev) {
p -= slot_len;
- snprintf(p, slot_len, ":%02x.%x", PCI_SLOT(t->devfn), PCI_FUNC(d->devfn));
+ s = snprintf(slot, sizeof slot, ":%02x.%x",
+ PCI_SLOT(t->devfn), PCI_FUNC(d->devfn));
+ assert(s == slot_len);
+ memcpy(p, slot, slot_len);
}
return path;
diff --git a/hw/pci.h b/hw/pci.h
index 052960e3ea..0d2753f27e 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -264,6 +264,8 @@ void do_pci_info_print(Monitor *mon, const QObject *data);
void do_pci_info(Monitor *mon, QObject **ret_data);
void pci_bridge_update_mappings(PCIBus *b);
+void pci_device_deassert_intx(PCIDevice *dev);
+
static inline void
pci_set_byte(uint8_t *config, uint8_t val)
{
@@ -436,6 +438,9 @@ typedef struct {
/* pcie stuff */
int is_express; /* is this device pci express? */
+ /* device isn't hot-pluggable */
+ int no_hotplug;
+
/* rom bar */
const char *romfile;
} PCIDeviceInfo;
diff --git a/hw/piix4.c b/hw/piix4.c
index 5489386d68..72073cd0a0 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -113,6 +113,7 @@ static PCIDeviceInfo piix4_info[] = {
.qdev.desc = "ISA bridge",
.qdev.size = sizeof(PCIDevice),
.qdev.no_user = 1,
+ .no_hotplug = 1,
.init = piix4_initfn,
},{
/* end of list */
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 38f9d9eea4..358da58a80 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -348,6 +348,7 @@ static PCIDeviceInfo i440fx_info[] = {
.qdev.size = sizeof(PCII440FXState),
.qdev.vmsd = &vmstate_i440fx,
.qdev.no_user = 1,
+ .no_hotplug = 1,
.init = i440fx_initfn,
.config_write = i440fx_write_config,
},{
@@ -356,6 +357,7 @@ static PCIDeviceInfo i440fx_info[] = {
.qdev.size = sizeof(PIIX3State),
.qdev.vmsd = &vmstate_piix3,
.qdev.no_user = 1,
+ .no_hotplug = 1,
.init = piix3_initfn,
},{
/* end of list */
diff --git a/hw/pl031.c b/hw/pl031.c
index e3700c169c..c488f69511 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -44,6 +44,21 @@ typedef struct {
uint32_t is;
} pl031_state;
+static const VMStateDescription vmstate_pl031 = {
+ .name = "pl031",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(tick_offset, pl031_state),
+ VMSTATE_UINT32(mr, pl031_state),
+ VMSTATE_UINT32(lr, pl031_state),
+ VMSTATE_UINT32(cr, pl031_state),
+ VMSTATE_UINT32(im, pl031_state),
+ VMSTATE_UINT32(is, pl031_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const unsigned char pl031_id[] = {
0x31, 0x10, 0x14, 0x00, /* Device ID */
0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */
@@ -206,9 +221,17 @@ static int pl031_init(SysBusDevice *dev)
return 0;
}
+static SysBusDeviceInfo pl031_info = {
+ .init = pl031_init,
+ .qdev.name = "pl031",
+ .qdev.size = sizeof(pl031_state),
+ .qdev.vmsd = &vmstate_pl031,
+ .qdev.no_user = 1,
+};
+
static void pl031_register_devices(void)
{
- sysbus_register_dev("pl031", sizeof(pl031_state), pl031_init);
+ sysbus_register_withprop(&pl031_info);
}
device_init(pl031_register_devices)
diff --git a/hw/pl050.c b/hw/pl050.c
index 057383985e..b155cc07b6 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -21,6 +21,20 @@ typedef struct {
int is_mouse;
} pl050_state;
+static const VMStateDescription vmstate_pl050 = {
+ .name = "pl050",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(cr, pl050_state),
+ VMSTATE_UINT32(clk, pl050_state),
+ VMSTATE_UINT32(last, pl050_state),
+ VMSTATE_INT32(pending, pl050_state),
+ VMSTATE_INT32(is_mouse, pl050_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
#define PL050_TXEMPTY (1 << 6)
#define PL050_TXBUSY (1 << 5)
#define PL050_RXFULL (1 << 4)
@@ -137,7 +151,6 @@ static int pl050_init(SysBusDevice *dev, int is_mouse)
s->dev = ps2_mouse_init(pl050_update, s);
else
s->dev = ps2_kbd_init(pl050_update, s);
- /* ??? Save/restore. */
return 0;
}
@@ -151,12 +164,24 @@ static int pl050_init_mouse(SysBusDevice *dev)
return pl050_init(dev, 1);
}
+static SysBusDeviceInfo pl050_kbd_info = {
+ .init = pl050_init_keyboard,
+ .qdev.name = "pl050_keyboard",
+ .qdev.size = sizeof(pl050_state),
+ .qdev.vmsd = &vmstate_pl050,
+};
+
+static SysBusDeviceInfo pl050_mouse_info = {
+ .init = pl050_init_mouse,
+ .qdev.name = "pl050_mouse",
+ .qdev.size = sizeof(pl050_state),
+ .qdev.vmsd = &vmstate_pl050,
+};
+
static void pl050_register_devices(void)
{
- sysbus_register_dev("pl050_keyboard", sizeof(pl050_state),
- pl050_init_keyboard);
- sysbus_register_dev("pl050_mouse", sizeof(pl050_state),
- pl050_init_mouse);
+ sysbus_register_withprop(&pl050_kbd_info);
+ sysbus_register_withprop(&pl050_mouse_info);
}
device_init(pl050_register_devices)
diff --git a/hw/pl080.c b/hw/pl080.c
index 1a3e06c920..901f04a844 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -52,6 +52,43 @@ typedef struct {
qemu_irq irq;
} pl080_state;
+static const VMStateDescription vmstate_pl080_channel = {
+ .name = "pl080_channel",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(src, pl080_channel),
+ VMSTATE_UINT32(dest, pl080_channel),
+ VMSTATE_UINT32(lli, pl080_channel),
+ VMSTATE_UINT32(ctrl, pl080_channel),
+ VMSTATE_UINT32(conf, pl080_channel),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_pl080 = {
+ .name = "pl080",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(tc_int, pl080_state),
+ VMSTATE_UINT8(tc_mask, pl080_state),
+ VMSTATE_UINT8(err_int, pl080_state),
+ VMSTATE_UINT8(err_mask, pl080_state),
+ VMSTATE_UINT32(conf, pl080_state),
+ VMSTATE_UINT32(sync, pl080_state),
+ VMSTATE_UINT32(req_single, pl080_state),
+ VMSTATE_UINT32(req_burst, pl080_state),
+ VMSTATE_UINT8(tc_int, pl080_state),
+ VMSTATE_UINT8(tc_int, pl080_state),
+ VMSTATE_UINT8(tc_int, pl080_state),
+ VMSTATE_STRUCT_ARRAY(chan, pl080_state, PL080_MAX_CHANNELS,
+ 1, vmstate_pl080_channel, pl080_channel),
+ VMSTATE_INT32(running, pl080_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const unsigned char pl080_id[] =
{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
@@ -330,7 +367,6 @@ static int pl08x_init(SysBusDevice *dev, int nchannels)
sysbus_init_mmio(dev, 0x1000, iomemtype);
sysbus_init_irq(dev, &s->irq);
s->nchannels = nchannels;
- /* ??? Save/restore. */
return 0;
}
@@ -344,12 +380,28 @@ static int pl081_init(SysBusDevice *dev)
return pl08x_init(dev, 2);
}
+static SysBusDeviceInfo pl080_info = {
+ .init = pl080_init,
+ .qdev.name = "pl080",
+ .qdev.size = sizeof(pl080_state),
+ .qdev.vmsd = &vmstate_pl080,
+ .qdev.no_user = 1,
+};
+
+static SysBusDeviceInfo pl081_info = {
+ .init = pl081_init,
+ .qdev.name = "pl081",
+ .qdev.size = sizeof(pl080_state),
+ .qdev.vmsd = &vmstate_pl080,
+ .qdev.no_user = 1,
+};
+
/* The PL080 and PL081 are the same except for the number of channels
they implement (8 and 2 respectively). */
static void pl080_register_devices(void)
{
- sysbus_register_dev("pl080", sizeof(pl080_state), pl080_init);
- sysbus_register_dev("pl081", sizeof(pl080_state), pl081_init);
+ sysbus_register_withprop(&pl080_info);
+ sysbus_register_withprop(&pl081_info);
}
device_init(pl080_register_devices)
diff --git a/hw/pl110.c b/hw/pl110.c
index a4adb630b0..06d2dfada6 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -48,6 +48,28 @@ typedef struct {
qemu_irq irq;
} pl110_state;
+static const VMStateDescription vmstate_pl110 = {
+ .name = "pl110",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(versatile, pl110_state),
+ VMSTATE_UINT32_ARRAY(timing, pl110_state, 4),
+ VMSTATE_UINT32(cr, pl110_state),
+ VMSTATE_UINT32(upbase, pl110_state),
+ VMSTATE_UINT32(lpbase, pl110_state),
+ VMSTATE_UINT32(int_status, pl110_state),
+ VMSTATE_UINT32(int_mask, pl110_state),
+ VMSTATE_INT32(cols, pl110_state),
+ VMSTATE_INT32(rows, pl110_state),
+ VMSTATE_UINT32(bpp, pl110_state),
+ VMSTATE_INT32(invalidate, pl110_state),
+ VMSTATE_UINT32_ARRAY(pallette, pl110_state, 256),
+ VMSTATE_UINT32_ARRAY(raw_pallette, pl110_state, 128),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const unsigned char pl110_id[] =
{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
@@ -365,7 +387,6 @@ static int pl110_init(SysBusDevice *dev)
s->ds = graphic_console_init(pl110_update_display,
pl110_invalidate_display,
NULL, NULL, s);
- /* ??? Save/restore. */
return 0;
}
@@ -376,11 +397,26 @@ static int pl110_versatile_init(SysBusDevice *dev)
return pl110_init(dev);
}
+static SysBusDeviceInfo pl110_info = {
+ .init = pl110_init,
+ .qdev.name = "pl110",
+ .qdev.size = sizeof(pl110_state),
+ .qdev.vmsd = &vmstate_pl110,
+ .qdev.no_user = 1,
+};
+
+static SysBusDeviceInfo pl110_versatile_info = {
+ .init = pl110_versatile_init,
+ .qdev.name = "pl110_versatile",
+ .qdev.size = sizeof(pl110_state),
+ .qdev.vmsd = &vmstate_pl110,
+ .qdev.no_user = 1,
+};
+
static void pl110_register_devices(void)
{
- sysbus_register_dev("pl110", sizeof(pl110_state), pl110_init);
- sysbus_register_dev("pl110_versatile", sizeof(pl110_state),
- pl110_versatile_init);
+ sysbus_register_withprop(&pl110_info);
+ sysbus_register_withprop(&pl110_versatile_info);
}
device_init(pl110_register_devices)
diff --git a/hw/pl190.c b/hw/pl190.c
index e04e6c17fb..75f2ba1966 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -21,7 +21,6 @@ typedef struct {
uint32_t soft_level;
uint32_t irq_enable;
uint32_t fiq_select;
- uint32_t default_addr;
uint8_t vect_control[16];
uint32_t vect_addr[PL190_NUM_PRIO];
/* Mask containing interrupts with higher priority than this one. */
@@ -186,7 +185,7 @@ static void pl190_write(void *opaque, target_phys_addr_t offset, uint32_t val)
s->priority = s->prev_prio[s->priority];
break;
case 13: /* DEFVECTADDR */
- s->default_addr = val;
+ s->vect_addr[16] = val;
break;
case 0xc0: /* ITCR */
if (val) {
@@ -212,8 +211,9 @@ static CPUWriteMemoryFunc * const pl190_writefn[] = {
pl190_write
};
-static void pl190_reset(pl190_state *s)
+static void pl190_reset(DeviceState *d)
{
+ pl190_state *s = DO_UPCAST(pl190_state, busdev.qdev, d);
int i;
for (i = 0; i < 16; i++)
@@ -239,14 +239,40 @@ static int pl190_init(SysBusDevice *dev)
qdev_init_gpio_in(&dev->qdev, pl190_set_irq, 32);
sysbus_init_irq(dev, &s->irq);
sysbus_init_irq(dev, &s->fiq);
- pl190_reset(s);
- /* ??? Save/restore. */
return 0;
}
+static const VMStateDescription vmstate_pl190 = {
+ .name = "pl190",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(level, pl190_state),
+ VMSTATE_UINT32(soft_level, pl190_state),
+ VMSTATE_UINT32(irq_enable, pl190_state),
+ VMSTATE_UINT32(fiq_select, pl190_state),
+ VMSTATE_UINT8_ARRAY(vect_control, pl190_state, 16),
+ VMSTATE_UINT32_ARRAY(vect_addr, pl190_state, PL190_NUM_PRIO),
+ VMSTATE_UINT32_ARRAY(prio_mask, pl190_state, PL190_NUM_PRIO+1),
+ VMSTATE_INT32(protected, pl190_state),
+ VMSTATE_INT32(priority, pl190_state),
+ VMSTATE_INT32_ARRAY(prev_prio, pl190_state, PL190_NUM_PRIO),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static SysBusDeviceInfo pl190_info = {
+ .init = pl190_init,
+ .qdev.name = "pl190",
+ .qdev.size = sizeof(pl190_state),
+ .qdev.vmsd = &vmstate_pl190,
+ .qdev.reset = pl190_reset,
+ .qdev.no_user = 1,
+};
+
static void pl190_register_devices(void)
{
- sysbus_register_dev("pl190", sizeof(pl190_state), pl190_init);
+ sysbus_register_withprop(&pl190_info);
}
device_init(pl190_register_devices)
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 8136cb962b..334187e53b 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -68,8 +68,9 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
stl_phys(bdloc + 0x34, bd->bi_baudrate);
for (i = 0; i < 4; i++)
stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]);
- for (i = 0; i < 32; i++)
- stb_phys(bdloc + 0x3C + i, bd->bi_s_version[i]);
+ for (i = 0; i < 32; i++) {
+ stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]);
+ }
stl_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
stl_phys(bdloc + 0x60, bd->bi_pci_busfreq);
for (i = 0; i < 6; i++)
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index ab524a779a..6e72a5c753 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1476,7 +1476,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c = {
VMSTATE_UINT8(ibmr, PXA2xxI2CState),
VMSTATE_UINT8(data, PXA2xxI2CState),
VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
- vmstate_pxa2xx_i2c, PXA2xxI2CSlaveState *),
+ vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState *),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 1f2211a2f0..5b2b07e02c 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -796,9 +796,9 @@ static void pxa2xx_update_display(void *opaque)
if (miny >= 0) {
if (s->orientation)
- dpy_update(s->ds, miny, 0, maxy, s->xres);
+ dpy_update(s->ds, miny, 0, maxy - miny, s->xres);
else
- dpy_update(s->ds, 0, miny, s->xres, maxy);
+ dpy_update(s->ds, 0, miny, s->xres, maxy - miny);
}
pxa2xx_lcdc_int_update(s);
diff --git a/hw/qdev.c b/hw/qdev.c
index 31eb464f23..5b8d3742ec 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -32,6 +32,8 @@
#include "blockdev.h"
static int qdev_hotplug = 0;
+static bool qdev_hot_added = false;
+static bool qdev_hot_removed = false;
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
static BusState *main_system_bus;
@@ -93,6 +95,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
if (qdev_hotplug) {
assert(bus->allow_hotplug);
dev->hotplugged = 1;
+ qdev_hot_added = true;
}
dev->instance_id_alias = -1;
dev->state = DEV_STATE_CREATED;
@@ -294,6 +297,8 @@ int qdev_unplug(DeviceState *dev)
}
assert(dev->info->unplug != NULL);
+ qdev_hot_removed = true;
+
return dev->info->unplug(dev);
}
@@ -395,6 +400,11 @@ void qdev_machine_creation_done(void)
qdev_hotplug = 1;
}
+bool qdev_machine_modified(void)
+{
+ return qdev_hot_added || qdev_hot_removed;
+}
+
/* Get a character (serial) device interface. */
CharDriverState *qdev_init_chardev(DeviceState *dev)
{
diff --git a/hw/qdev.h b/hw/qdev.h
index 2be775f9e8..e520aaa786 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -132,6 +132,7 @@ int qdev_unplug(DeviceState *dev);
void qdev_free(DeviceState *dev);
int qdev_simple_unplug_cb(DeviceState *dev);
void qdev_machine_creation_done(void);
+bool qdev_machine_modified(void);
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
diff --git a/hw/qxl.c b/hw/qxl.c
index 207aa63f90..bd71e5810f 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1546,6 +1546,7 @@ static PCIDeviceInfo qxl_info_primary = {
.qdev.size = sizeof(PCIQXLDevice),
.qdev.reset = qxl_reset_handler,
.qdev.vmsd = &qxl_vmstate,
+ .no_hotplug = 1,
.init = qxl_init_primary,
.config_write = qxl_write_config,
.romfile = "vgabios-qxl.bin",
diff --git a/hw/r2d.c b/hw/r2d.c
index c4f32ef49d..a0f8c1f201 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -23,13 +23,13 @@
* THE SOFTWARE.
*/
+#include "sysbus.h"
#include "hw.h"
#include "sh.h"
#include "devices.h"
#include "sysemu.h"
#include "boards.h"
#include "pci.h"
-#include "sh_pci.h"
#include "net.h"
#include "sh7750_regs.h"
#include "ide.h"
@@ -195,17 +195,18 @@ static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl)
return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
}
-static void r2d_pci_set_irq(void *opaque, int n, int l)
-{
- qemu_irq *p = opaque;
-
- qemu_set_irq(p[n], l);
-}
+typedef struct ResetData {
+ CPUState *env;
+ uint32_t vector;
+} ResetData;
-static int r2d_pci_map_irq(PCIDevice *d, int irq_num)
+static void main_cpu_reset(void *opaque)
{
- const int intx[] = { PCI_INTA, PCI_INTB, PCI_INTC, PCI_INTD };
- return intx[d->devfn >> 3];
+ ResetData *s = (ResetData *)opaque;
+ CPUState *env = s->env;
+
+ cpu_reset(env);
+ env->pc = s->vector;
}
static struct __attribute__((__packed__))
@@ -228,6 +229,7 @@ static void r2d_init(ram_addr_t ram_size,
const char *initrd_filename, const char *cpu_model)
{
CPUState *env;
+ ResetData *reset_info;
struct SH7750State *s;
ram_addr_t sdram_addr;
qemu_irq *irq;
@@ -242,6 +244,10 @@ static void r2d_init(ram_addr_t ram_size,
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+ reset_info = qemu_mallocz(sizeof(ResetData));
+ reset_info->env = env;
+ reset_info->vector = env->pc;
+ qemu_register_reset(main_cpu_reset, reset_info);
/* Allocate memory space */
sdram_addr = qemu_ram_alloc(NULL, "r2d.sdram", SDRAM_SIZE);
@@ -249,7 +255,8 @@ static void r2d_init(ram_addr_t ram_size,
/* Register peripherals */
s = sh7750_init(env);
irq = r2d_fpga_init(0x04000000, sh7750_irl(s));
- sh_pci_register_bus(r2d_pci_set_irq, r2d_pci_map_irq, irq, 0, 4);
+ sysbus_create_varargs("sh_pci", 0x1e200000, irq[PCI_INTA], irq[PCI_INTB],
+ irq[PCI_INTC], irq[PCI_INTD], NULL);
sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]);
@@ -290,7 +297,7 @@ static void r2d_init(ram_addr_t ram_size,
/* initialization which should be done by firmware */
stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */
stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */
- env->pc = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */
+ reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */
}
if (initrd_filename) {
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index a8aed89074..a22530cf89 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -495,6 +495,8 @@ typedef struct RTL8139State {
QEMUTimer *timer;
int64_t TimerExpire;
+ /* Support migration to/from old versions */
+ int rtl8139_mmio_io_addr_dummy;
} RTL8139State;
static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time);
@@ -3162,6 +3164,21 @@ static int rtl8139_post_load(void *opaque, int version_id)
return 0;
}
+static bool rtl8139_hotplug_ready_needed(void *opaque)
+{
+ return qdev_machine_modified();
+}
+
+static const VMStateDescription vmstate_rtl8139_hotplug_ready ={
+ .name = "rtl8139/hotplug_ready",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void rtl8139_pre_save(void *opaque)
{
RTL8139State* s = opaque;
@@ -3171,6 +3188,7 @@ static void rtl8139_pre_save(void *opaque)
rtl8139_set_next_tctr_time(s, current_time);
s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
get_ticks_per_sec());
+ s->rtl8139_mmio_io_addr_dummy = s->rtl8139_mmio_io_addr;
}
static const VMStateDescription vmstate_rtl8139 = {
@@ -3223,7 +3241,7 @@ static const VMStateDescription vmstate_rtl8139 = {
VMSTATE_UNUSED(4),
VMSTATE_MACADDR(conf.macaddr, RTL8139State),
- VMSTATE_INT32(rtl8139_mmio_io_addr, RTL8139State),
+ VMSTATE_INT32(rtl8139_mmio_io_addr_dummy, RTL8139State),
VMSTATE_UINT32(currTxDesc, RTL8139State),
VMSTATE_UINT32(currCPlusRxDesc, RTL8139State),
@@ -3252,6 +3270,14 @@ static const VMStateDescription vmstate_rtl8139 = {
VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_rtl8139_hotplug_ready,
+ .needed = rtl8139_hotplug_ready_needed,
+ }, {
+ /* empty */
+ }
}
};
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 072078be51..e99d8dbfb5 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -21,24 +21,26 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "hw.h"
+#include "sysbus.h"
#include "sh.h"
#include "pci.h"
#include "pci_host.h"
-#include "sh_pci.h"
#include "bswap.h"
-typedef struct {
+typedef struct SHPCIState {
+ SysBusDevice busdev;
PCIBus *bus;
PCIDevice *dev;
+ qemu_irq irq[4];
+ int memconfig;
uint32_t par;
uint32_t mbr;
uint32_t iobr;
-} SHPCIC;
+} SHPCIState;
static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
{
- SHPCIC *pcic = p;
+ SHPCIState *pcic = p;
switch(addr) {
case 0 ... 0xfc:
cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val);
@@ -65,7 +67,7 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr)
{
- SHPCIC *pcic = p;
+ SHPCIState *pcic = p;
switch(addr) {
case 0 ... 0xfc:
return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
@@ -91,32 +93,69 @@ static MemOp sh_pci_reg = {
{ NULL, NULL, sh_pci_reg_write },
};
-PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
- void *opaque, int devfn_min, int nirq)
+static int sh_pci_map_irq(PCIDevice *d, int irq_num)
+{
+ return (d->devfn >> 3);
+}
+
+static void sh_pci_set_irq(void *opaque, int irq_num, int level)
+{
+ qemu_irq *pic = opaque;
+
+ qemu_set_irq(pic[irq_num], level);
+}
+
+static void sh_pci_map(SysBusDevice *dev, target_phys_addr_t base)
+{
+ SHPCIState *s = FROM_SYSBUS(SHPCIState, dev);
+
+ cpu_register_physical_memory(P4ADDR(base), 0x224, s->memconfig);
+ cpu_register_physical_memory(A7ADDR(base), 0x224, s->memconfig);
+
+ s->iobr = 0xfe240000;
+ isa_mmio_init(s->iobr, 0x40000);
+}
+
+static int sh_pci_init_device(SysBusDevice *dev)
+{
+ SHPCIState *s;
+ int i;
+
+ s = FROM_SYSBUS(SHPCIState, dev);
+ for (i = 0; i < 4; i++) {
+ sysbus_init_irq(dev, &s->irq[i]);
+ }
+ s->bus = pci_register_bus(&s->busdev.qdev, "pci",
+ sh_pci_set_irq, sh_pci_map_irq,
+ s->irq, PCI_DEVFN(0, 0), 4);
+ s->memconfig = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w,
+ s, DEVICE_NATIVE_ENDIAN);
+ sysbus_init_mmio_cb(dev, 0x224, sh_pci_map);
+ s->dev = pci_create_simple(s->bus, PCI_DEVFN(0, 0), "sh_pci_host");
+ return 0;
+}
+
+static int sh_pci_host_init(PCIDevice *d)
+{
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_HITACHI);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_HITACHI_SH7751R);
+ pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
+ pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
+ PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+ return 0;
+}
+
+static PCIDeviceInfo sh_pci_host_info = {
+ .qdev.name = "sh_pci_host",
+ .qdev.size = sizeof(PCIDevice),
+ .init = sh_pci_host_init,
+};
+
+static void sh_pci_register_devices(void)
{
- SHPCIC *p;
- int reg;
-
- p = qemu_mallocz(sizeof(SHPCIC));
- p->bus = pci_register_bus(NULL, "pci",
- set_irq, map_irq, opaque, devfn_min, nirq);
-
- p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
- -1, NULL, NULL);
- reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p,
- DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(0x1e200000, 0x224, reg);
- cpu_register_physical_memory(0xfe200000, 0x224, reg);
-
- p->iobr = 0xfe240000;
- isa_mmio_init(p->iobr, 0x40000);
-
- pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI);
- pci_config_set_device_id(p->dev->config, PCI_DEVICE_ID_HITACHI_SH7751R);
- p->dev->config[0x04] = 0x80;
- p->dev->config[0x05] = 0x00;
- p->dev->config[0x06] = 0x90;
- p->dev->config[0x07] = 0x02;
-
- return p->bus;
+ sysbus_register_dev("sh_pci", sizeof(SHPCIState),
+ sh_pci_init_device);
+ pci_qdev_register(&sh_pci_host_info);
}
+
+device_init(sh_pci_register_devices)
diff --git a/hw/sh_pci.h b/hw/sh_pci.h
deleted file mode 100644
index b1a5ec37c3..0000000000
--- a/hw/sh_pci.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef QEMU_SH_PCI_H
-#define QEMU_SH_PCI_H
-
-#include "qemu-common.h"
-
-PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
- void *pic, int devfn_min, int nirq);
-
-#endif
diff --git a/hw/sh_serial.c b/hw/sh_serial.c
index 1bdc0a5ab2..191f4a60c6 100644
--- a/hw/sh_serial.c
+++ b/hw/sh_serial.c
@@ -74,7 +74,7 @@ static void sh_serial_clear_fifo(sh_serial_state * s)
s->rx_tail = 0;
}
-static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
+static void sh_serial_write(void *opaque, uint32_t offs, uint32_t val)
{
sh_serial_state *s = opaque;
unsigned char ch;
@@ -185,7 +185,7 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
abort();
}
-static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
+static uint32_t sh_serial_read(void *opaque, uint32_t offs)
{
sh_serial_state *s = opaque;
uint32_t ret = ~0;
@@ -293,26 +293,6 @@ static int sh_serial_can_receive(sh_serial_state *s)
return s->scr & (1 << 4);
}
-static void sh_serial_receive_byte(sh_serial_state *s, int ch)
-{
- if (s->feat & SH_SERIAL_FEAT_SCIF) {
- if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
- s->rx_fifo[s->rx_head++] = ch;
- if (s->rx_head == SH_RX_FIFO_LENGTH)
- s->rx_head = 0;
- s->rx_cnt++;
- if (s->rx_cnt >= s->rtrg) {
- s->flags |= SH_SERIAL_FLAG_RDF;
- if (s->scr & (1 << 6) && s->rxi) {
- qemu_set_irq(s->rxi, 1);
- }
- }
- }
- } else {
- s->rx_fifo[0] = ch;
- }
-}
-
static void sh_serial_receive_break(sh_serial_state *s)
{
if (s->feat & SH_SERIAL_FEAT_SCIF)
@@ -328,7 +308,27 @@ static int sh_serial_can_receive1(void *opaque)
static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
{
sh_serial_state *s = opaque;
- sh_serial_receive_byte(s, buf[0]);
+
+ if (s->feat & SH_SERIAL_FEAT_SCIF) {
+ int i;
+ for (i = 0; i < size; i++) {
+ if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
+ s->rx_fifo[s->rx_head++] = buf[i];
+ if (s->rx_head == SH_RX_FIFO_LENGTH) {
+ s->rx_head = 0;
+ }
+ s->rx_cnt++;
+ if (s->rx_cnt >= s->rtrg) {
+ s->flags |= SH_SERIAL_FLAG_RDF;
+ if (s->scr & (1 << 6) && s->rxi) {
+ qemu_set_irq(s->rxi, 1);
+ }
+ }
+ }
+ }
+ } else {
+ s->rx_fifo[0] = buf[0];
+ }
}
static void sh_serial_event(void *opaque, int event)
@@ -338,19 +338,6 @@ static void sh_serial_event(void *opaque, int event)
sh_serial_receive_break(s);
}
-static uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr)
-{
- sh_serial_state *s = opaque;
- return sh_serial_ioport_read(s, addr);
-}
-
-static void sh_serial_write (void *opaque,
- target_phys_addr_t addr, uint32_t value)
-{
- sh_serial_state *s = opaque;
- sh_serial_ioport_write(s, addr, value);
-}
-
static CPUReadMemoryFunc * const sh_serial_readfn[] = {
&sh_serial_read,
&sh_serial_read,
diff --git a/hw/sm501.c b/hw/sm501.c
index f16e6e4e65..0f0bf96609 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -511,6 +511,7 @@ typedef struct SM501State {
uint32_t dc_crt_hwc_color_1_2;
uint32_t dc_crt_hwc_color_3;
+ uint32_t twoD_source;
uint32_t twoD_destination;
uint32_t twoD_dimension;
uint32_t twoD_control;
@@ -636,6 +637,9 @@ static void sm501_2d_operation(SM501State * s)
{
/* obtain operation parameters */
int operation = (s->twoD_control >> 16) & 0x1f;
+ int rtl = s->twoD_control & 0x8000000;
+ int src_x = (s->twoD_source >> 16) & 0x01FFF;
+ int src_y = s->twoD_source & 0xFFFF;
int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
int dst_y = s->twoD_destination & 0xFFFF;
int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
@@ -645,10 +649,9 @@ static void sm501_2d_operation(SM501State * s)
int addressing = (s->twoD_stretch >> 16) & 0xF;
/* get frame buffer info */
-#if 0 /* for future use */
uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
-#endif
uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
+ int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
if (addressing != 0x0) {
@@ -663,8 +666,36 @@ static void sm501_2d_operation(SM501State * s)
}
switch (operation) {
- case 0x01: /* fill rectangle */
+ case 0x00: /* copy area */
+#define COPY_AREA(_bpp, _pixel_type, rtl) { \
+ int y, x, index_d, index_s; \
+ for (y = 0; y < operation_height; y++) { \
+ for (x = 0; x < operation_width; x++) { \
+ if (rtl) { \
+ index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
+ index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
+ } else { \
+ index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
+ index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+ } \
+ *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
+ } \
+ } \
+ }
+ switch (format_flags) {
+ case 0:
+ COPY_AREA(1, uint8_t, rtl);
+ break;
+ case 1:
+ COPY_AREA(2, uint16_t, rtl);
+ break;
+ case 2:
+ COPY_AREA(4, uint32_t, rtl);
+ break;
+ }
+ break;
+ case 0x01: /* fill rectangle */
#define FILL_RECT(_bpp, _pixel_type) { \
int y, x; \
for (y = 0; y < operation_height; y++) { \
@@ -1072,6 +1103,9 @@ static void sm501_2d_engine_write(void *opaque,
addr, value);
switch(addr) {
+ case SM501_2D_SOURCE:
+ s->twoD_source = value;
+ break;
case SM501_2D_DESTINATION:
s->twoD_destination = value;
break;
@@ -1240,8 +1274,8 @@ static void sm501_draw_crt(SM501State * s)
draw_hwc_line_func * draw_hwc_line = NULL;
int full_update = 0;
int y_start = -1;
- int page_min = 0x7fffffff;
- int page_max = -1;
+ ram_addr_t page_min = ~0l;
+ ram_addr_t page_max = 0l;
ram_addr_t offset = s->local_mem_offset;
/* choose draw_line function */
@@ -1337,9 +1371,10 @@ static void sm501_draw_crt(SM501State * s)
dpy_update(s->ds, 0, y_start, width, y - y_start);
/* clear dirty flags */
- if (page_max != -1)
+ if (page_min != ~0l) {
cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
+ }
}
static void sm501_update_display(void *opaque)
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index fc714d7f28..dafea5cc6e 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -46,6 +46,35 @@ typedef struct {
int mmio_index;
} smc91c111_state;
+static const VMStateDescription vmstate_smc91c111 = {
+ .name = "smc91c111",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT16(tcr, smc91c111_state),
+ VMSTATE_UINT16(rcr, smc91c111_state),
+ VMSTATE_UINT16(cr, smc91c111_state),
+ VMSTATE_UINT16(ctr, smc91c111_state),
+ VMSTATE_UINT16(gpr, smc91c111_state),
+ VMSTATE_UINT16(ptr, smc91c111_state),
+ VMSTATE_UINT16(ercv, smc91c111_state),
+ VMSTATE_INT32(bank, smc91c111_state),
+ VMSTATE_INT32(packet_num, smc91c111_state),
+ VMSTATE_INT32(tx_alloc, smc91c111_state),
+ VMSTATE_INT32(allocated, smc91c111_state),
+ VMSTATE_INT32(tx_fifo_len, smc91c111_state),
+ VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
+ VMSTATE_INT32(rx_fifo_len, smc91c111_state),
+ VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
+ VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
+ VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
+ VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
+ VMSTATE_UINT8(int_level, smc91c111_state),
+ VMSTATE_UINT8(int_mask, smc91c111_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
#define RCR_SOFT_RST 0x8000
#define RCR_STRIP_CRC 0x0200
#define RCR_RXEN 0x0100
@@ -738,6 +767,7 @@ static SysBusDeviceInfo smc91c111_info = {
.init = smc91c111_init1,
.qdev.name = "smc91c111",
.qdev.size = sizeof(smc91c111_state),
+ .qdev.vmsd = &vmstate_smc91c111,
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 1fec163d05..90a2b49e1d 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -416,7 +416,7 @@ static const uint8_t usb_hid_usage_keys[0x100] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -479,15 +479,18 @@ static void usb_keyboard_event(void *opaque, int keycode)
case 0xe0:
if (s->modifiers & (1 << 9)) {
s->modifiers ^= 3 << 8;
+ usb_hid_changed(hs);
return;
}
case 0xe1 ... 0xe7:
if (keycode & (1 << 7)) {
s->modifiers &= ~(1 << (hid_code & 0x0f));
+ usb_hid_changed(hs);
return;
}
case 0xe8 ... 0xef:
s->modifiers |= 1 << (hid_code & 0x0f);
+ usb_hid_changed(hs);
return;
}
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index be758e447f..9f1bfcf941 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -30,6 +30,18 @@ typedef struct vpb_sic_state
int irq;
} vpb_sic_state;
+static const VMStateDescription vmstate_vpb_sic = {
+ .name = "versatilepb_sic",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(level, vpb_sic_state),
+ VMSTATE_UINT32(mask, vpb_sic_state),
+ VMSTATE_UINT32(pic_enable, vpb_sic_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void vpb_sic_update(vpb_sic_state *s)
{
uint32_t flags;
@@ -146,7 +158,6 @@ static int vpb_sic_init(SysBusDevice *dev)
vpb_sic_writefn, s,
DEVICE_NATIVE_ENDIAN);
sysbus_init_mmio(dev, 0x1000, iomemtype);
- /* ??? Save/restore. */
return 0;
}
@@ -335,10 +346,17 @@ static void versatile_machine_init(void)
machine_init(versatile_machine_init);
+static SysBusDeviceInfo vpb_sic_info = {
+ .init = vpb_sic_init,
+ .qdev.name = "versatilepb_sic",
+ .qdev.size = sizeof(vpb_sic_state),
+ .qdev.vmsd = &vmstate_vpb_sic,
+ .qdev.no_user = 1,
+};
+
static void versatilepb_register_devices(void)
{
- sysbus_register_dev("versatilepb_sic", sizeof(vpb_sic_state),
- vpb_sic_init);
+ sysbus_register_withprop(&vpb_sic_info);
}
device_init(versatilepb_register_devices)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 791ca22763..ce9ec45777 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -110,6 +110,7 @@ static PCIDeviceInfo vga_info = {
.qdev.name = "VGA",
.qdev.size = sizeof(PCIVGAState),
.qdev.vmsd = &vmstate_vga_pci,
+ .no_hotplug = 1,
.init = pci_vga_initfn,
.config_write = pci_vga_write_config,
.romfile = "vgabios-stdvga.bin",
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index ec1bf8dda7..ccb3e632a4 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -54,8 +54,6 @@ typedef struct VirtIONet
uint8_t nouni;
uint8_t nobcast;
uint8_t vhost_started;
- bool vm_running;
- VMChangeStateEntry *vmstate;
struct {
int in_use;
int first_multi;
@@ -102,7 +100,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
static bool virtio_net_started(VirtIONet *n, uint8_t status)
{
return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
- (n->status & VIRTIO_NET_S_LINK_UP) && n->vm_running;
+ (n->status & VIRTIO_NET_S_LINK_UP) && n->vdev.vm_running;
}
static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
@@ -453,7 +451,7 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
static int virtio_net_can_receive(VLANClientState *nc)
{
VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
- if (!n->vm_running) {
+ if (!n->vdev.vm_running) {
return 0;
}
@@ -708,7 +706,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
return num_packets;
}
- assert(n->vm_running);
+ assert(n->vdev.vm_running);
if (n->async_tx.elem.out_num) {
virtio_queue_set_notification(n->tx_vq, 0);
@@ -769,7 +767,7 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
VirtIONet *n = to_virtio_net(vdev);
/* This happens when device was stopped but VCPU wasn't. */
- if (!n->vm_running) {
+ if (!n->vdev.vm_running) {
n->tx_waiting = 1;
return;
}
@@ -796,7 +794,7 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
}
n->tx_waiting = 1;
/* This happens when device was stopped but VCPU wasn't. */
- if (!n->vm_running) {
+ if (!n->vdev.vm_running) {
return;
}
virtio_queue_set_notification(vq, 0);
@@ -806,7 +804,7 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
static void virtio_net_tx_timer(void *opaque)
{
VirtIONet *n = opaque;
- assert(n->vm_running);
+ assert(n->vdev.vm_running);
n->tx_waiting = 0;
@@ -823,7 +821,7 @@ static void virtio_net_tx_bh(void *opaque)
VirtIONet *n = opaque;
int32_t ret;
- assert(n->vm_running);
+ assert(n->vdev.vm_running);
n->tx_waiting = 0;
@@ -988,16 +986,6 @@ static NetClientInfo net_virtio_info = {
.link_status_changed = virtio_net_set_link_status,
};
-static void virtio_net_vmstate_change(void *opaque, int running, int reason)
-{
- VirtIONet *n = opaque;
- n->vm_running = running;
- /* This is called when vm is started/stopped,
- * it will start/stop vhost backend if appropriate
- * e.g. after migration. */
- virtio_net_set_status(&n->vdev, n->vdev.status);
-}
-
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
virtio_net_conf *net)
{
@@ -1052,7 +1040,6 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
n->qdev = dev;
register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
virtio_net_save, virtio_net_load, n);
- n->vmstate = qemu_add_vm_change_state_handler(virtio_net_vmstate_change, n);
add_boot_device_path(conf->bootindex, dev, "/ethernet-phy@0");
@@ -1062,7 +1049,6 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
void virtio_net_exit(VirtIODevice *vdev)
{
VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
- qemu_del_vm_change_state_handler(n->vmstate);
/* This will stop vhost backend if appropriate. */
virtio_net_set_status(vdev, 0);
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 6186142b2b..d07ff976be 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -80,9 +80,13 @@
* 12 is historical, and due to x86 page size. */
#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
-/* We can catch some guest bugs inside here so we continue supporting older
- guests. */
-#define VIRTIO_PCI_BUG_BUS_MASTER (1 << 0)
+/* Flags track per-device state like workarounds for quirks in older guests. */
+#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0)
+
+/* Performance improves when virtqueue kick processing is decoupled from the
+ * vcpu thread using ioeventfd for some devices. */
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
/* QEMU doesn't strictly need write barriers since everything runs in
* lock-step. We'll leave the calls to wmb() in though to make it obvious for
@@ -95,7 +99,7 @@
typedef struct {
PCIDevice pci_dev;
VirtIODevice *vdev;
- uint32_t bugs;
+ uint32_t flags;
uint32_t addr;
uint32_t class_code;
uint32_t nvectors;
@@ -108,6 +112,8 @@ typedef struct {
/* Max. number of ports we can have for a the virtio-serial device */
uint32_t max_virtserial_ports;
virtio_net_conf net;
+ bool ioeventfd_disabled;
+ bool ioeventfd_started;
} VirtIOPCIProxy;
/* virtio device */
@@ -159,7 +165,7 @@ static int virtio_pci_load_config(void * opaque, QEMUFile *f)
in ready state. Then we have a buggy guest OS. */
if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
- proxy->bugs |= VIRTIO_PCI_BUG_BUS_MASTER;
+ proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
}
return 0;
}
@@ -180,12 +186,139 @@ static int virtio_pci_load_queue(void * opaque, int n, QEMUFile *f)
return 0;
}
+static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
+ int n, bool assign)
+{
+ VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+ EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+ int r;
+ if (assign) {
+ r = event_notifier_init(notifier, 1);
+ if (r < 0) {
+ error_report("%s: unable to init event notifier: %d",
+ __func__, r);
+ return r;
+ }
+ r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
+ proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
+ n, assign);
+ if (r < 0) {
+ error_report("%s: unable to map ioeventfd: %d",
+ __func__, r);
+ event_notifier_cleanup(notifier);
+ }
+ } else {
+ r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
+ proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
+ n, assign);
+ if (r < 0) {
+ error_report("%s: unable to unmap ioeventfd: %d",
+ __func__, r);
+ return r;
+ }
+
+ /* Handle the race condition where the guest kicked and we deassigned
+ * before we got around to handling the kick.
+ */
+ if (event_notifier_test_and_clear(notifier)) {
+ virtio_queue_notify_vq(vq);
+ }
+
+ event_notifier_cleanup(notifier);
+ }
+ return r;
+}
+
+static void virtio_pci_host_notifier_read(void *opaque)
+{
+ VirtQueue *vq = opaque;
+ EventNotifier *n = virtio_queue_get_host_notifier(vq);
+ if (event_notifier_test_and_clear(n)) {
+ virtio_queue_notify_vq(vq);
+ }
+}
+
+static void virtio_pci_set_host_notifier_fd_handler(VirtIOPCIProxy *proxy,
+ int n, bool assign)
+{
+ VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+ EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+ if (assign) {
+ qemu_set_fd_handler(event_notifier_get_fd(notifier),
+ virtio_pci_host_notifier_read, NULL, vq);
+ } else {
+ qemu_set_fd_handler(event_notifier_get_fd(notifier),
+ NULL, NULL, NULL);
+ }
+}
+
+static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
+{
+ int n, r;
+
+ if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
+ proxy->ioeventfd_disabled ||
+ proxy->ioeventfd_started) {
+ return;
+ }
+
+ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(proxy->vdev, n)) {
+ continue;
+ }
+
+ r = virtio_pci_set_host_notifier_internal(proxy, n, true);
+ if (r < 0) {
+ goto assign_error;
+ }
+
+ virtio_pci_set_host_notifier_fd_handler(proxy, n, true);
+ }
+ proxy->ioeventfd_started = true;
+ return;
+
+assign_error:
+ while (--n >= 0) {
+ if (!virtio_queue_get_num(proxy->vdev, n)) {
+ continue;
+ }
+
+ virtio_pci_set_host_notifier_fd_handler(proxy, n, false);
+ r = virtio_pci_set_host_notifier_internal(proxy, n, false);
+ assert(r >= 0);
+ }
+ proxy->ioeventfd_started = false;
+ error_report("%s: failed. Fallback to a userspace (slower).", __func__);
+}
+
+static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
+{
+ int r;
+ int n;
+
+ if (!proxy->ioeventfd_started) {
+ return;
+ }
+
+ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(proxy->vdev, n)) {
+ continue;
+ }
+
+ virtio_pci_set_host_notifier_fd_handler(proxy, n, false);
+ r = virtio_pci_set_host_notifier_internal(proxy, n, false);
+ assert(r >= 0);
+ }
+ proxy->ioeventfd_started = false;
+}
+
static void virtio_pci_reset(DeviceState *d)
{
VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
+ virtio_pci_stop_ioeventfd(proxy);
virtio_reset(proxy->vdev);
msix_reset(&proxy->pci_dev);
- proxy->bugs = 0;
+ proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
}
static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@@ -210,6 +343,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case VIRTIO_PCI_QUEUE_PFN:
pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
if (pa == 0) {
+ virtio_pci_stop_ioeventfd(proxy);
virtio_reset(proxy->vdev);
msix_unuse_all_vectors(&proxy->pci_dev);
}
@@ -224,7 +358,16 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
virtio_queue_notify(vdev, val);
break;
case VIRTIO_PCI_STATUS:
+ if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ virtio_pci_stop_ioeventfd(proxy);
+ }
+
virtio_set_status(vdev, val & 0xFF);
+
+ if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
+ virtio_pci_start_ioeventfd(proxy);
+ }
+
if (vdev->status == 0) {
virtio_reset(proxy->vdev);
msix_unuse_all_vectors(&proxy->pci_dev);
@@ -235,7 +378,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
some safety checks. */
if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
- proxy->bugs |= VIRTIO_PCI_BUG_BUS_MASTER;
+ proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
}
break;
case VIRTIO_MSI_CONFIG_VECTOR:
@@ -403,7 +546,8 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
if (PCI_COMMAND == address) {
if (!(val & PCI_COMMAND_MASTER)) {
- if (!(proxy->bugs & VIRTIO_PCI_BUG_BUS_MASTER)) {
+ if (!(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
+ virtio_pci_stop_ioeventfd(proxy);
virtio_set_status(proxy->vdev,
proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
}
@@ -481,30 +625,30 @@ assign_error:
static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign)
{
VirtIOPCIProxy *proxy = opaque;
- VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
- EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
- int r;
+
+ /* Stop using ioeventfd for virtqueue kick if the device starts using host
+ * notifiers. This makes it easy to avoid stepping on each others' toes.
+ */
+ proxy->ioeventfd_disabled = assign;
if (assign) {
- r = event_notifier_init(notifier, 1);
- if (r < 0) {
- return r;
- }
- r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
- proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
- n, assign);
- if (r < 0) {
- event_notifier_cleanup(notifier);
- }
+ virtio_pci_stop_ioeventfd(proxy);
+ }
+ /* We don't need to start here: it's not needed because backend
+ * currently only stops on status change away from ok,
+ * reset, vmstop and such. If we do add code to start here,
+ * need to check vmstate, device state etc. */
+ return virtio_pci_set_host_notifier_internal(proxy, n, assign);
+}
+
+static void virtio_pci_vmstate_change(void *opaque, bool running)
+{
+ VirtIOPCIProxy *proxy = opaque;
+
+ if (running) {
+ virtio_pci_start_ioeventfd(proxy);
} else {
- r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
- proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
- n, assign);
- if (r < 0) {
- return r;
- }
- event_notifier_cleanup(notifier);
+ virtio_pci_stop_ioeventfd(proxy);
}
- return r;
}
static const VirtIOBindings virtio_pci_bindings = {
@@ -516,6 +660,7 @@ static const VirtIOBindings virtio_pci_bindings = {
.get_features = virtio_pci_get_features,
.set_host_notifier = virtio_pci_set_host_notifier,
.set_guest_notifiers = virtio_pci_set_guest_notifiers,
+ .vmstate_change = virtio_pci_vmstate_change,
};
static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
@@ -560,6 +705,10 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO,
virtio_map);
+ if (!kvm_has_many_ioeventfds()) {
+ proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
+ }
+
virtio_bind_device(vdev, &virtio_pci_bindings, proxy);
proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
@@ -598,6 +747,7 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ virtio_pci_stop_ioeventfd(proxy);
virtio_blk_exit(proxy->vdev);
blockdev_mark_auto_del(proxy->block.bs);
return virtio_exit_pci(pci_dev);
@@ -659,6 +809,7 @@ static int virtio_net_exit_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ virtio_pci_stop_ioeventfd(proxy);
virtio_net_exit(proxy->vdev);
return virtio_exit_pci(pci_dev);
}
@@ -706,6 +857,8 @@ static PCIDeviceInfo virtio_info[] = {
.qdev.props = (Property[]) {
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_END_OF_LIST(),
@@ -718,6 +871,8 @@ static PCIDeviceInfo virtio_info[] = {
.exit = virtio_net_exit_pci,
.romfile = "pxe-virtio.bin",
.qdev.props = (Property[]) {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 74ba5ec3d3..b728040f3a 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -769,10 +769,16 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
/* Add a queue for guest to host transfers for port 0 (backward compat) */
vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
+ /* TODO: host to guest notifications can get dropped
+ * if the queue fills up. Implement queueing in host,
+ * this might also make it possible to reduce the control
+ * queue size: as guest preposts buffers there,
+ * this will save 4Kbyte of guest memory per entry. */
+
/* control queue: host to guest */
- vser->c_ivq = virtio_add_queue(vdev, 16, control_in);
+ vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
/* control queue: guest to host */
- vser->c_ovq = virtio_add_queue(vdev, 16, control_out);
+ vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
for (i = 1; i < vser->bus->max_nr_ports; i++) {
/* Add a per-port queue for host to guest transfers */
diff --git a/hw/virtio.c b/hw/virtio.c
index 07dbf868fd..31bd9e32dc 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -575,11 +575,19 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n)
return vdev->vq[n].vring.num;
}
+void virtio_queue_notify_vq(VirtQueue *vq)
+{
+ if (vq->vring.desc) {
+ VirtIODevice *vdev = vq->vdev;
+ trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
+ vq->handle_output(vdev, vq);
+ }
+}
+
void virtio_queue_notify(VirtIODevice *vdev, int n)
{
- if (n < VIRTIO_PCI_QUEUE_MAX && vdev->vq[n].vring.desc) {
- trace_virtio_queue_notify(vdev, n, &vdev->vq[n]);
- vdev->vq[n].handle_output(vdev, &vdev->vq[n]);
+ if (n < VIRTIO_PCI_QUEUE_MAX) {
+ virtio_queue_notify_vq(&vdev->vq[n]);
}
}
@@ -743,11 +751,31 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
void virtio_cleanup(VirtIODevice *vdev)
{
+ qemu_del_vm_change_state_handler(vdev->vmstate);
if (vdev->config)
qemu_free(vdev->config);
qemu_free(vdev->vq);
}
+static void virtio_vmstate_change(void *opaque, int running, int reason)
+{
+ VirtIODevice *vdev = opaque;
+ bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
+ vdev->vm_running = running;
+
+ if (backend_run) {
+ virtio_set_status(vdev, vdev->status);
+ }
+
+ if (vdev->binding->vmstate_change) {
+ vdev->binding->vmstate_change(vdev->binding_opaque, backend_run);
+ }
+
+ if (!backend_run) {
+ virtio_set_status(vdev, vdev->status);
+ }
+}
+
VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
size_t config_size, size_t struct_size)
{
@@ -774,6 +802,8 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
else
vdev->config = NULL;
+ vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, vdev);
+
return vdev;
}
diff --git a/hw/virtio.h b/hw/virtio.h
index 02fa312d3e..d8546d5b30 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -95,6 +95,7 @@ typedef struct {
unsigned (*get_features)(void * opaque);
int (*set_guest_notifiers)(void * opaque, bool assigned);
int (*set_host_notifier)(void * opaque, int n, bool assigned);
+ void (*vmstate_change)(void * opaque, bool running);
} VirtIOBindings;
#define VIRTIO_PCI_QUEUE_MAX 64
@@ -123,6 +124,8 @@ struct VirtIODevice
const VirtIOBindings *binding;
void *binding_opaque;
uint16_t device_id;
+ bool vm_running;
+ VMChangeStateEntry *vmstate;
};
static inline void virtio_set_status(VirtIODevice *vdev, uint8_t val)
@@ -219,5 +222,6 @@ void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
+void virtio_queue_notify_vq(VirtQueue *vq);
void virtio_irq(VirtQueue *vq);
#endif
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index d9dd52fc60..6c59053308 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1318,6 +1318,7 @@ static PCIDeviceInfo vmsvga_info = {
.qdev.name = "vmware-svga",
.qdev.size = sizeof(struct pci_vmsvga_state_s),
.qdev.vmsd = &vmstate_vmware_vga,
+ .no_hotplug = 1,
.init = pci_vmsvga_initfn,
.romfile = "vgabios-vmware.bin",
};
diff --git a/hw/zaurus.c b/hw/zaurus.c
index 54ec3f00d5..36be94a179 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -70,7 +70,7 @@ static uint32_t scoop_readb(void *opaque, target_phys_addr_t addr)
{
ScoopInfo *s = (ScoopInfo *) opaque;
- switch (addr) {
+ switch (addr & 0x3f) {
case SCOOP_MCR:
return s->mcr;
case SCOOP_CDR:
@@ -104,7 +104,7 @@ static void scoop_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
ScoopInfo *s = (ScoopInfo *) opaque;
value &= 0xffff;
- switch (addr) {
+ switch (addr & 0x3f) {
case SCOOP_MCR:
s->mcr = value;
break;
diff --git a/kvm-all.c b/kvm-all.c
index cae24bb87c..255b6fad9c 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -28,6 +28,11 @@
#include "kvm.h"
#include "bswap.h"
+/* This check must be after config-host.h is included */
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
/* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */
#define PAGE_SIZE TARGET_PAGE_SIZE
@@ -72,6 +77,7 @@ struct KVMState
int irqchip_in_kernel;
int pit_in_kernel;
int xsave, xcrs;
+ int many_ioeventfds;
};
static KVMState *kvm_state;
@@ -441,6 +447,39 @@ int kvm_check_extension(KVMState *s, unsigned int extension)
return ret;
}
+static int kvm_check_many_ioeventfds(void)
+{
+ /* Older kernels have a 6 device limit on the KVM io bus. Find out so we
+ * can avoid creating too many ioeventfds.
+ */
+#ifdef CONFIG_EVENTFD
+ int ioeventfds[7];
+ int i, ret = 0;
+ for (i = 0; i < ARRAY_SIZE(ioeventfds); i++) {
+ ioeventfds[i] = eventfd(0, EFD_CLOEXEC);
+ if (ioeventfds[i] < 0) {
+ break;
+ }
+ ret = kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, true);
+ if (ret < 0) {
+ close(ioeventfds[i]);
+ break;
+ }
+ }
+
+ /* Decide whether many devices are supported or not */
+ ret = i == ARRAY_SIZE(ioeventfds);
+
+ while (i-- > 0) {
+ kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, false);
+ close(ioeventfds[i]);
+ }
+ return ret;
+#else
+ return 0;
+#endif
+}
+
static void kvm_set_phys_mem(target_phys_addr_t start_addr,
ram_addr_t size,
ram_addr_t phys_offset)
@@ -717,6 +756,8 @@ int kvm_init(int smp_cpus)
kvm_state = s;
cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client);
+ s->many_ioeventfds = kvm_check_many_ioeventfds();
+
return 0;
err:
@@ -1046,6 +1087,14 @@ int kvm_has_xcrs(void)
return kvm_state->xcrs;
}
+int kvm_has_many_ioeventfds(void)
+{
+ if (!kvm_enabled()) {
+ return 0;
+ }
+ return kvm_state->many_ioeventfds;
+}
+
void kvm_setup_guest_memory(void *start, size_t size)
{
if (!kvm_has_sync_mmu()) {
diff --git a/kvm-stub.c b/kvm-stub.c
index 5384a4b9a4..33d4476fa3 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -99,6 +99,11 @@ int kvm_has_robust_singlestep(void)
return 0;
}
+int kvm_has_many_ioeventfds(void)
+{
+ return 0;
+}
+
void kvm_setup_guest_memory(void *start, size_t size)
{
}
diff --git a/kvm.h b/kvm.h
index 60a9b425c8..ce08d42756 100644
--- a/kvm.h
+++ b/kvm.h
@@ -42,6 +42,7 @@ int kvm_has_robust_singlestep(void);
int kvm_has_debugregs(void);
int kvm_has_xsave(void);
int kvm_has_xcrs(void);
+int kvm_has_many_ioeventfds(void);
#ifdef NEED_CPU_H
int kvm_init_vcpu(CPUState *env);
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 538e2572bb..acff781081 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -76,7 +76,7 @@
#ifdef FIGETBSZ
IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
#endif
-#ifdef FS_IOC_FIEMAP
+#ifdef CONFIG_FIEMAP
IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap,
MK_PTR(MK_STRUCT(STRUCT_fiemap)))
#endif
diff --git a/linux-user/signal.c b/linux-user/signal.c
index c846b8c7d4..0664770c94 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1256,6 +1256,14 @@ setup_return(CPUState *env, struct target_sigaction *ka,
abi_ulong handler = ka->_sa_handler;
abi_ulong retcode;
int thumb = handler & 1;
+ uint32_t cpsr = cpsr_read(env);
+
+ cpsr &= ~CPSR_IT;
+ if (thumb) {
+ cpsr |= CPSR_T;
+ } else {
+ cpsr &= ~CPSR_T;
+ }
if (ka->sa_flags & TARGET_SA_RESTORER) {
retcode = ka->sa_restorer;
@@ -1278,13 +1286,7 @@ setup_return(CPUState *env, struct target_sigaction *ka,
env->regs[13] = frame_addr;
env->regs[14] = retcode;
env->regs[15] = handler & (thumb ? ~1 : ~3);
- env->thumb = thumb;
-
-#if 0
-#ifdef TARGET_CONFIG_CPU_32
- env->cpsr = cpsr;
-#endif
-#endif
+ cpsr_write(env, cpsr, 0xffffffff);
return 0;
}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f10e17ae23..499c4d7d62 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -83,7 +83,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <linux/kd.h>
#include <linux/mtio.h>
#include <linux/fs.h>
+#if defined(CONFIG_FIEMAP)
#include <linux/fiemap.h>
+#endif
#include <linux/fb.h>
#include <linux/vt.h>
#include "linux_loop.h"
@@ -2986,6 +2988,7 @@ struct IOCTLEntry {
#define MAX_STRUCT_SIZE 4096
+#ifdef CONFIG_FIEMAP
/* So fiemap access checks don't overflow on 32 bit systems.
* This is very slightly smaller than the limit imposed by
* the underlying kernel.
@@ -3072,6 +3075,7 @@ static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
}
return ret;
}
+#endif
static IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \
diff --git a/migration.c b/migration.c
index e5ba51c314..d593b1df5d 100644
--- a/migration.c
+++ b/migration.c
@@ -88,6 +88,10 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
return -1;
}
+ if (qemu_savevm_state_blocked(mon)) {
+ return -1;
+ }
+
if (strstart(uri, "tcp:", &p)) {
s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
blk, inc);
diff --git a/monitor.c b/monitor.c
index f2580007f2..d291158c2f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2275,8 +2275,8 @@ static void mem_info_64(Monitor *mon, CPUState *env)
end = (l1 << 39) + (l2 << 30);
if (pdpe & PG_PRESENT_MASK) {
if (pdpe & PG_PSE_MASK) {
- prot = pde & (PG_USER_MASK | PG_RW_MASK |
- PG_PRESENT_MASK);
+ prot = pdpe & (PG_USER_MASK | PG_RW_MASK |
+ PG_PRESENT_MASK);
mem_print(mon, &start, &last_prot, end, prot);
} else {
pd_addr = pdpe & 0x3fffffffff000ULL;
diff --git a/pc-bios/keymaps/bepo b/pc-bios/keymaps/bepo
new file mode 100644
index 0000000000..d40041a4cb
--- /dev/null
+++ b/pc-bios/keymaps/bepo
@@ -0,0 +1,333 @@
+include common
+
+# Bépo : Improved ergonomic french keymap using Dvorak method.
+# Built by community on 'Dvorak Fr / Bépo' :
+# see http://www.clavier-dvorak.org/wiki/ to join and help.
+#
+# Bépo layout (1.0rc2 version) for a pc105 keyboard (french) :
+# ┌────┐
+# │ S A│ S = Shift, A = AltGr + Shift
+# │ s a│ s = normal, a = AltGr
+# └────┘
+#
+# ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┲━━━━━━━━━┓
+# │ # ¶ │ 1 „ │ 2 “ │ 3 ” │ 4 ≤ │ 5 ≥ │ 6 │ 7 ¬ │ 8 ¼ │ 9 ½ │ 0 ¾ │ ° ′ │ ` ″ ┃ ⌫ Retour┃
+# │ $ – │ " — │ « < │ » > │ ( [ │ ) ] │ @ ^ │ + ± │ - − │ / ÷ │ * × │ = ≠ │ % ‰ ┃ arrière┃
+# ┢━━━━━┷━┱───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┺━┳━━━━━━━┫
+# ┃ ┃ B ¦ │ É ˝ │ P § │ O Œ │ È ` │ ! │ V │ D Ð │ L │ J IJ │ Z Ə │ W ┃Entrée ┃
+# ┃Tab ↹ ┃ b | │ é ˊ │ p & │ o œ │ è ` │ ˆ ¡ │ v ˇ │ d ð │ l / │ j ij │ z ə │ w ̆ ┃ ⏎ ┃
+# ┣━━━━━━━┻┱────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┺┓ ┃
+# ┃ ┃ A Æ │ U Ù │ I ˙ │ E ¤ │ ; ̛ │ C ſ │ T Þ │ S ẞ │ R ™ │ N │ M º │ Ç , ┃ ┃
+# ┃Maj ⇬ ┃ a æ │ u ù │ i ̈ │ e € │ , ’ │ c © │ t þ │ s ß │ r ® │ n ˜ │ m ¯ │ ç ¸ ┃ ┃
+# ┣━━━━━━━┳┹────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┲┷━━━━━┻━━━━━━┫
+# ┃ ┃ Ê │ À │ Y ‘ │ X ’ │ : · │ K │ ? ̉ │ Q ̣ │ G │ H ‡ │ F ª ┃ ┃
+# ┃Shift ⇧┃ ê / │ à \ │ y { │ x } │ . … │ k ~ │ ' ¿ │ q ˚ │ g µ │ h † │ f ˛ ┃Shift ⇧ ┃
+# ┣━━━━━━━╋━━━━━┷━┳━━━┷━━━┱─┴─────┴─────┴─────┴─────┴─────┴───┲━┷━━━━━╈━━━━━┻━┳━━━━━━━┳━━━┛
+# ┃ ┃ ┃ ┃ Espace inséc. Espace inséc. fin ┃ ┃ ┃ ┃
+# ┃Ctrl ┃Meta ┃Alt ┃ ␣ (Espace) _ ␣ ┃AltGr ⇮┃Menu ┃Ctrl ┃
+# ┗━━━━━━━┻━━━━━━━┻━━━━━━━┹───────────────────────────────────┺━━━━━━━┻━━━━━━━┻━━━━━━━┛
+
+
+# First row
+## keycode 41 = dollar numbersign U+2013 U+00b6
+dollar 0x29
+numbersign 0x29 shift
+U2013 0x29 altgr
+U00b6 0x29 shift altgr
+
+## keycode 2 = +quotedbl +one U+2014 U+201e
+quotedbl 0x2
+one 0x2 shift
+U2014 0x2 altgr
+U201e 0x2 shift altgr
+
+## keycode 3 = +guillemotleft +two less U+201c
+guillemotleft 0x3
+two 0x3 shift
+less 0x3 altgr
+U201c 0x3 shift altgr
+
+## keycode 4 = +guillemotright +three greater U+201d
+guillemotright 0x4
+three 0x4 shift
+greater 0x4 altgr
+U201d 0x4 shift altgr
+
+## keycode 5 = +parenleft +four bracketleft U+2264
+parenleft 0x5
+four 0x5 shift
+bracketleft 0x5 altgr
+U2264 0x5 shift altgr
+
+## keycode 6 = +parenright +five bracketright U+2265
+parenright 0x6
+five 0x6 shift
+bracketright 0x6 altgr
+U2265 0x6 shift altgr
+
+## keycode 7 = +at +six asciicircum
+at 0x7
+six 0x7 shift
+asciicircum 0x7 altgr
+
+## keycode 8 = +plus +seven U+00b1 U+00ac
+plus 0x8
+seven 0x8 shift
+U00b1 0x8 altgr
+U00ac 0x8 shift altgr
+
+## keycode 9 = +minus +eight U+2212 U+00bc
+minus 0x9
+eight 0x9 shift
+U2212 0x9 altgr
+U00bc 0x9 shift altgr
+
+## keycode 10 = +slash +nine U+00f7 U+00bd
+slash 0xa
+nine 0xa shift
+U00f7 0xa altgr
+U00bd 0xa shift altgr
+
+## keycode 11 = +asterisk +zero U+00d7 U+00be
+asterisk 0xb
+zero 0xb shift
+U00d7 0xb altgr
+U00be 0xb shift altgr
+
+## keycode 12 = equal U+00b0 U+2260 U+2032
+equal 0xc
+U00b0 0xc shift
+U2260 0xc altgr
+U2032 0xc shift altgr
+
+## keycode 13 = percent grave U+2030 U+2033
+percent 0xd
+grave 0xd shift
+U2030 0xd altgr
+U2033 0xd shift altgr
+
+
+# Second row
+
+# simplified letter definitions notation :
+## keycode 16 = b
+b 0x10 addupper
+## keycode 18 = p
+p 0x12 addupper
+## keycode 19 = o
+o 0x13 addupper
+## keycode 22 = v
+v 0x16 addupper
+## keycode 23 = d
+d 0x17 addupper
+## keycode 24 = l
+l 0x18 addupper
+## keycode 25 = j
+j 0x19 addupper
+## keycode 26 = z
+z 0x1a addupper
+## keycode 27 = w
+w 0x1b addupper
+
+# then, add specific definitions
+## AltGr keycode 16 = bar
+bar 0x10 altgr
+## Shift AltGr keycode 16 = brokenbar
+brokenbar 0x10 shift altgr
+
+## keycode 17 = +eacute +Eacute dead_acute
+eacute 0x11
+Eacute 0x11 shift
+dead_acute 0x11 altgr
+
+## AltGr keycode 18 = ampersand
+ampersand 0x12 altgr
+## Shift AltGr keycode 18 = U+00a7
+U00a7 0x12 shift altgr
+
+## AltGr keycode 19 = +U+0153
+U+0153 0x13 altgr
+## Shift AltGr keycode 19 = +U+0152
+U+0152 0x13 shift altgr
+
+## keycode 20 = +egrave +Egrave dead_grave grave # no Meta !
+egrave 0x14
+Egrave 0x14 shift
+dead_grave 0x14 altgr
+
+## keycode 21 = dead_circumflex exclam exclamdown
+dead_circumflex 0x15
+exclam 0x15 shift
+exclamdown 0x15 altgr
+
+## AltGr keycode 22 = dead_caron
+dead_caron 0x16 altgr
+
+## AltGr keycode 23 = eth
+eth 0x17 altgr
+## Shift AltGr keycode 23 = ETH
+ETH 0x17 shift altgr
+
+## AltGr keycode 25 = +U+0133
+U+0133 0x19 altgr
+## Shift AltGr keycode 25 = +U+0132
+U+0132 0x19 shift altgr
+
+## AltGr keycode 26 = +U+0259
+U+0259 0x1a altgr
+## Shift AltGr keycode 26 = +U+018f
+U+018f 0x1a shift altgr
+
+
+
+# Third row
+
+# simplified letter definitions notation :
+## keycode 30 = a
+a 0x1e addupper
+## keycode 31 = u
+u 0x1f addupper
+## keycode 32 = i
+i 0x20 addupper
+## keycode 33 = e
+e 0x21 addupper
+## keycode 35 = c
+c 0x23 addupper
+## keycode 36 = t
+t 0x24 addupper
+## keycode 37 = s
+s 0x25 addupper
+## keycode 38 = r
+r 0x26 addupper
+## keycode 39 = n
+n 0x27 addupper
+## keycode 40 = m
+m 0x28 addupper
+
+# then, add specific definitions
+## AltGr keycode 30 = +ae
+ae 0x1e altgr
+## Shift AltGr keycode 30 = +AE
+AE 0x1e shift altgr
+
+## AltGr keycode 31 = +ugrave
+ugrave 0x1f altgr
+## Shift AltGr keycode 31 = +Ugrave
+Ugrave 0x1f shift altgr
+
+## AltGr keycode 32 = dead_diaeresis
+dead_diaeresis 0x20 altgr
+
+
+## AltGr keycode 33 = U+20ac
+U20ac 0x21 altgr
+
+## keycode 34 = comma semicolon U+2019 +U+031b
+comma 0x22
+semicolon 0x22 shift
+U2019 0x22 altgr
+U+031b 0x22 shift altgr
+
+## AltGr keycode 35 = copyright
+copyright 0x23 altgr
+## Shift AltGr keycode 35 = U+017f
+U017f 0x23 shift altgr
+
+## AltGr keycode 36 = +thorn
+thorn 0x24 altgr
+## Shift AltGr keycode 36 = +THORN
+THORN 0x24 shift altgr
+
+## AltGr keycode 37 = +ssharp
+ssharp 0x25 altgr
+## Shift AltGr keycode 37 = U+1e9e
+U1e9e 0x25 shift altgr
+
+## AltGr keycode 38 = registered
+registered 0x26 altgr
+## Shift AltGr keycode 38 = U+2122
+U2122 0x26 shift altgr
+
+## AltGr keycode 39 = dead_tilde
+dead_tilde 0x27 altgr
+
+## Shift AltGr keycode 40 = masculine
+masculine 0x28 shift altgr
+
+## keycode 43 = +ccedilla +Ccedilla dead_cedilla
+ccedilla 0x2b
+Ccedilla 0x2b shift
+dead_cedilla 0x2b altgr
+
+
+# Fourth row
+
+# simplified letter definitions notation :
+## keycode 45 = y
+y 0x2d addupper
+## keycode 46 = x
+x 0x2e addupper
+## keycode 48 = k
+k 0x30 addupper
+## keycode 50 = q
+q 0x32 addupper
+## keycode 51 = g
+g 0x33 addupper
+## keycode 52 = h
+h 0x34 addupper
+## keycode 53 = f
+f 0x35 addupper
+
+# then, add specific definitions
+## keycode 86 = +ecircumflex +Ecircumflex slash slash
+ecircumflex 0x56
+Ecircumflex 0x56 shift
+
+## keycode 44 = +agrave +Agrave backslash
+agrave 0x2c
+Agrave 0x2c shift
+backslash 0x2c altgr
+
+## AltGr keycode 45 = braceleft
+braceleft 0x2d altgr
+## Shift AltGr keycode 45 = U+2018
+U2018 0x2d shift altgr
+
+## AltGr keycode 46 = braceright
+braceright 0x2e altgr
+
+## keycode 47 = period colon U+2026 periodcentered
+period 0x2f
+colon 0x2f shift
+U2026 0x2f altgr
+periodcentered 0x2f shift altgr
+
+## AltGr keycode 48 = asciitilde
+asciitilde 0x30 altgr
+## Shift AltGr keycode 48 = U+2328
+U2328 0x30 shift altgr
+
+## keycode 49 = apostrophe question questiondown +U+0309
+apostrophe 0x31
+question 0x31 shift
+questiondown 0x31 altgr
+U+0309 0x31 shift altgr
+
+## AltGr keycode 51 = mu
+mu 0x33 altgr
+
+## AltGr keycode 52 = U+2020
+U2020 0x34 altgr
+## Shift AltGr keycode 52 = U+2021
+U2021 0x34 shift altgr
+
+## Shift AltGr keycode 53 = ordfeminine
+ordfeminine 0x35 shift altgr
+
+
+
+## keycode 57 = space nobreakspace underscore U+202f
+space 0x39
+nobreakspace 0x39 shift
+underscore 0x39 altgr
+U202f 0x39 shift altgr
diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
index b4be31ec8f..51da288e32 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -23,7 +23,7 @@ build-all: multiboot.bin linuxboot.bin
$(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@," Building $(TARGET_DIR)$@")
%.bin: %.raw
- $(call quiet-command,$(SHELL) $(SRC_PATH)/pc-bios/optionrom/signrom.sh $< $@," Signing $(TARGET_DIR)$@")
+ $(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/signrom.sh $< $@," Signing $(TARGET_DIR)$@")
clean:
rm -f *.o *.d *.raw *.img *.bin *~
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 45190f6d3b..22a8663f6b 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2132,7 +2132,7 @@ Then you can launch the precompiled @file{ls} x86 executable:
@example
qemu-i386 tests/i386/ls
@end example
-You can look at @file{qemu-binfmt-conf.sh} so that
+You can look at @file{scripts/qemu-binfmt-conf.sh} so that
QEMU is automatically launched by the Linux kernel when you try to
launch x86 executables. It requires the @code{binfmt_misc} module in the
Linux kernel.
diff --git a/qemu-io.c b/qemu-io.c
index 65dee13731..5b24c5eec2 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1131,8 +1131,10 @@ aio_read_f(int argc, char **argv)
case 'P':
ctx->Pflag = 1;
ctx->pattern = parse_pattern(optarg);
- if (ctx->pattern < 0)
+ if (ctx->pattern < 0) {
+ free(ctx);
return 0;
+ }
break;
case 'q':
ctx->qflag = 1;
diff --git a/qerror.c b/qerror.c
index ac2cdafa65..9d0cdeb45c 100644
--- a/qerror.c
+++ b/qerror.c
@@ -101,6 +101,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' has no child bus",
},
{
+ .error_fmt = QERR_DEVICE_NO_HOTPLUG,
+ .desc = "Device '%(device)' does not support hotplugging",
+ },
+ {
.error_fmt = QERR_DUPLICATE_ID,
.desc = "Duplicate ID '%(id)' for %(object)",
},
diff --git a/qerror.h b/qerror.h
index 943a24b4e5..b0f69dabe5 100644
--- a/qerror.h
+++ b/qerror.h
@@ -90,6 +90,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_NO_BUS \
"{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+#define QERR_DEVICE_NO_HOTPLUG \
+ "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+
#define QERR_DUPLICATE_ID \
"{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
diff --git a/rules.mak b/rules.mak
index 6dac7773d5..ed59c9e82b 100644
--- a/rules.mak
+++ b/rules.mak
@@ -15,13 +15,13 @@ MAKEFLAGS += -rR
QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d
%.o: %.c
- $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CC $(TARGET_DIR)$@")
+ $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CC $(TARGET_DIR)$@")
%.o: %.S
- $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@")
+ $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@")
%.o: %.m
- $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@")
+ $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@")
LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(1) $(LIBS)," LINK $(TARGET_DIR)$@")
@@ -57,7 +57,7 @@ find-in-path = $(if $(find-string /, $1), \
@test -f $@ || cp $< $@
%.h-timestamp: %.mak
- $(call quiet-command, sh $(SRC_PATH)/create_config < $< > $@, " GEN $*.h")
+ $(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, " GEN $*.h")
@cmp $@ $*.h >/dev/null 2>&1 || cp $@ $*.h
# will delete the target of a rule if commands exit with a nonzero exit status
diff --git a/savevm.c b/savevm.c
index 90aa237c9c..fcd8db4f85 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1401,19 +1401,13 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
}
-static int vmstate_save(QEMUFile *f, SaveStateEntry *se)
+static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
{
- if (se->no_migrate) {
- return -1;
- }
-
if (!se->vmsd) { /* Old style */
se->save_state(f, se->opaque);
- return 0;
+ return;
}
vmstate_save_state(f,se->vmsd, se->opaque);
-
- return 0;
}
#define QEMU_VM_FILE_MAGIC 0x5145564d
@@ -1427,6 +1421,20 @@ static int vmstate_save(QEMUFile *f, SaveStateEntry *se)
#define QEMU_VM_SECTION_FULL 0x04
#define QEMU_VM_SUBSECTION 0x05
+bool qemu_savevm_state_blocked(Monitor *mon)
+{
+ SaveStateEntry *se;
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (se->no_migrate) {
+ monitor_printf(mon, "state blocked by non-migratable device '%s'\n",
+ se->idstr);
+ return true;
+ }
+ }
+ return false;
+}
+
int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
int shared)
{
@@ -1508,7 +1516,6 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
{
SaveStateEntry *se;
- int r;
cpu_synchronize_all_states();
@@ -1541,11 +1548,7 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
- r = vmstate_save(f, se);
- if (r < 0) {
- monitor_printf(mon, "cannot migrate with device '%s'\n", se->idstr);
- return r;
- }
+ vmstate_save(f, se);
}
qemu_put_byte(f, QEMU_VM_EOF);
@@ -1575,6 +1578,11 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
saved_vm_running = vm_running;
vm_stop(0);
+ if (qemu_savevm_state_blocked(mon)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
ret = qemu_savevm_state_begin(mon, f, 0, 0);
if (ret < 0)
goto out;
@@ -1692,6 +1700,10 @@ int qemu_loadvm_state(QEMUFile *f)
unsigned int v;
int ret;
+ if (qemu_savevm_state_blocked(default_mon)) {
+ return -EINVAL;
+ }
+
v = qemu_get_be32(f);
if (v != QEMU_VM_FILE_MAGIC)
return -EINVAL;
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
new file mode 100755
index 0000000000..55ef439865
--- /dev/null
+++ b/scripts/checkpatch.pl
@@ -0,0 +1,2909 @@
+#!/usr/bin/perl -w
+# (c) 2001, Dave Jones. (the file handling bit)
+# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
+# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
+# (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+$P =~ s@.*/@@g;
+
+my $V = '0.31';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $quiet = 0;
+my $tree = 1;
+my $chk_signoff = 1;
+my $chk_patch = 1;
+my $tst_only;
+my $emacs = 0;
+my $terse = 0;
+my $file = 0;
+my $check = 0;
+my $summary = 1;
+my $mailback = 0;
+my $summary_file = 0;
+my $root;
+my %debug;
+my $help = 0;
+
+sub help {
+ my ($exitcode) = @_;
+
+ print << "EOM";
+Usage: $P [OPTION]... [FILE]...
+Version: $V
+
+Options:
+ -q, --quiet quiet
+ --no-tree run without a kernel tree
+ --no-signoff do not check for 'Signed-off-by' line
+ --patch treat FILE as patchfile (default)
+ --emacs emacs compile window format
+ --terse one line per report
+ -f, --file treat FILE as regular source file
+ --subjective, --strict enable more subjective tests
+ --root=PATH PATH to the kernel tree root
+ --no-summary suppress the per-file summary
+ --mailback only produce a report in case of warnings/errors
+ --summary-file include the filename in summary
+ --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of
+ 'values', 'possible', 'type', and 'attr' (default
+ is all off)
+ --test-only=WORD report only warnings/errors containing WORD
+ literally
+ -h, --help, --version display this help and exit
+
+When FILE is - read standard input.
+EOM
+
+ exit($exitcode);
+}
+
+GetOptions(
+ 'q|quiet+' => \$quiet,
+ 'tree!' => \$tree,
+ 'signoff!' => \$chk_signoff,
+ 'patch!' => \$chk_patch,
+ 'emacs!' => \$emacs,
+ 'terse!' => \$terse,
+ 'f|file!' => \$file,
+ 'subjective!' => \$check,
+ 'strict!' => \$check,
+ 'root=s' => \$root,
+ 'summary!' => \$summary,
+ 'mailback!' => \$mailback,
+ 'summary-file!' => \$summary_file,
+
+ 'debug=s' => \%debug,
+ 'test-only=s' => \$tst_only,
+ 'h|help' => \$help,
+ 'version' => \$help
+) or help(1);
+
+help(0) if ($help);
+
+my $exit = 0;
+
+if ($#ARGV < 0) {
+ print "$P: no input files\n";
+ exit(1);
+}
+
+my $dbg_values = 0;
+my $dbg_possible = 0;
+my $dbg_type = 0;
+my $dbg_attr = 0;
+for my $key (keys %debug) {
+ ## no critic
+ eval "\${dbg_$key} = '$debug{$key}';";
+ die "$@" if ($@);
+}
+
+my $rpt_cleaners = 0;
+
+if ($terse) {
+ $emacs = 1;
+ $quiet++;
+}
+
+if ($tree) {
+ if (defined $root) {
+ if (!top_of_kernel_tree($root)) {
+ die "$P: $root: --root does not point at a valid tree\n";
+ }
+ } else {
+ if (top_of_kernel_tree('.')) {
+ $root = '.';
+ } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
+ top_of_kernel_tree($1)) {
+ $root = $1;
+ }
+ }
+
+ if (!defined $root) {
+ print "Must be run from the top-level dir. of a kernel tree\n";
+ exit(2);
+ }
+}
+
+my $emitted_corrupt = 0;
+
+our $Ident = qr{
+ [A-Za-z_][A-Za-z\d_]*
+ (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
+ }x;
+our $Storage = qr{extern|static|asmlinkage};
+our $Sparse = qr{
+ __user|
+ __kernel|
+ __force|
+ __iomem|
+ __must_check|
+ __init_refok|
+ __kprobes|
+ __ref
+ }x;
+
+# Notes to $Attribute:
+# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
+our $Attribute = qr{
+ const|
+ __percpu|
+ __nocast|
+ __safe|
+ __bitwise__|
+ __packed__|
+ __packed2__|
+ __naked|
+ __maybe_unused|
+ __always_unused|
+ __noreturn|
+ __used|
+ __cold|
+ __noclone|
+ __deprecated|
+ __read_mostly|
+ __kprobes|
+ __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
+ ____cacheline_aligned|
+ ____cacheline_aligned_in_smp|
+ ____cacheline_internodealigned_in_smp|
+ __weak
+ }x;
+our $Modifier;
+our $Inline = qr{inline|__always_inline|noinline};
+our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]};
+our $Lval = qr{$Ident(?:$Member)*};
+
+our $Constant = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*};
+our $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};
+our $Compare = qr{<=|>=|==|!=|<|>};
+our $Operators = qr{
+ <=|>=|==|!=|
+ =>|->|<<|>>|<|>|!|~|
+ &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+ }x;
+
+our $NonptrType;
+our $Type;
+our $Declare;
+
+our $UTF8 = qr {
+ [\x09\x0A\x0D\x20-\x7E] # ASCII
+ | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
+ | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
+ | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
+ | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
+ | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
+ | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
+ | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
+}x;
+
+our $typeTypedefs = qr{(?x:
+ (?:__)?(?:u|s|be|le)(?:8|16|32|64)|
+ atomic_t
+)};
+
+our $logFunctions = qr{(?x:
+ printk|
+ pr_(debug|dbg|vdbg|devel|info|warning|err|notice|alert|crit|emerg|cont)|
+ (dev|netdev|netif)_(printk|dbg|vdbg|info|warn|err|notice|alert|crit|emerg|WARN)|
+ WARN|
+ panic
+)};
+
+our @typeList = (
+ qr{void},
+ qr{(?:unsigned\s+)?char},
+ qr{(?:unsigned\s+)?short},
+ qr{(?:unsigned\s+)?int},
+ qr{(?:unsigned\s+)?long},
+ qr{(?:unsigned\s+)?long\s+int},
+ qr{(?:unsigned\s+)?long\s+long},
+ qr{(?:unsigned\s+)?long\s+long\s+int},
+ qr{unsigned},
+ qr{float},
+ qr{double},
+ qr{bool},
+ qr{struct\s+$Ident},
+ qr{union\s+$Ident},
+ qr{enum\s+$Ident},
+ qr{${Ident}_t},
+ qr{${Ident}_handler},
+ qr{${Ident}_handler_fn},
+);
+our @modifierList = (
+ qr{fastcall},
+);
+
+our $allowed_asm_includes = qr{(?x:
+ irq|
+ memory
+)};
+# memory.h: ARM has a custom one
+
+sub build_types {
+ my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)";
+ my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)";
+ $Modifier = qr{(?:$Attribute|$Sparse|$mods)};
+ $NonptrType = qr{
+ (?:$Modifier\s+|const\s+)*
+ (?:
+ (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+ (?:$typeTypedefs\b)|
+ (?:${all}\b)
+ )
+ (?:\s+$Modifier|\s+const)*
+ }x;
+ $Type = qr{
+ $NonptrType
+ (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)?
+ (?:\s+$Inline|\s+$Modifier)*
+ }x;
+ $Declare = qr{(?:$Storage\s+)?$Type};
+}
+build_types();
+
+$chk_signoff = 0 if ($file);
+
+my @dep_includes = ();
+my @dep_functions = ();
+my $removal = "Documentation/feature-removal-schedule.txt";
+if ($tree && -f "$root/$removal") {
+ open(my $REMOVE, '<', "$root/$removal") ||
+ die "$P: $removal: open failed - $!\n";
+ while (<$REMOVE>) {
+ if (/^Check:\s+(.*\S)/) {
+ for my $entry (split(/[, ]+/, $1)) {
+ if ($entry =~ m@include/(.*)@) {
+ push(@dep_includes, $1);
+
+ } elsif ($entry !~ m@/@) {
+ push(@dep_functions, $entry);
+ }
+ }
+ }
+ }
+ close($REMOVE);
+}
+
+my @rawlines = ();
+my @lines = ();
+my $vname;
+for my $filename (@ARGV) {
+ my $FILE;
+ if ($file) {
+ open($FILE, '-|', "diff -u /dev/null $filename") ||
+ die "$P: $filename: diff failed - $!\n";
+ } elsif ($filename eq '-') {
+ open($FILE, '<&STDIN');
+ } else {
+ open($FILE, '<', "$filename") ||
+ die "$P: $filename: open failed - $!\n";
+ }
+ if ($filename eq '-') {
+ $vname = 'Your patch';
+ } else {
+ $vname = $filename;
+ }
+ while (<$FILE>) {
+ chomp;
+ push(@rawlines, $_);
+ }
+ close($FILE);
+ if (!process($filename)) {
+ $exit = 1;
+ }
+ @rawlines = ();
+ @lines = ();
+}
+
+exit($exit);
+
+sub top_of_kernel_tree {
+ my ($root) = @_;
+
+ my @tree_check = (
+ "COPYING", "MAINTAINERS", "Makefile",
+ "README", "docs", "VERSION",
+ "vl.c"
+ );
+
+ foreach my $check (@tree_check) {
+ if (! -e $root . '/' . $check) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+sub expand_tabs {
+ my ($str) = @_;
+
+ my $res = '';
+ my $n = 0;
+ for my $c (split(//, $str)) {
+ if ($c eq "\t") {
+ $res .= ' ';
+ $n++;
+ for (; ($n % 8) != 0; $n++) {
+ $res .= ' ';
+ }
+ next;
+ }
+ $res .= $c;
+ $n++;
+ }
+
+ return $res;
+}
+sub copy_spacing {
+ (my $res = shift) =~ tr/\t/ /c;
+ return $res;
+}
+
+sub line_stats {
+ my ($line) = @_;
+
+ # Drop the diff line leader and expand tabs
+ $line =~ s/^.//;
+ $line = expand_tabs($line);
+
+ # Pick the indent from the front of the line.
+ my ($white) = ($line =~ /^(\s*)/);
+
+ return (length($line), length($white));
+}
+
+my $sanitise_quote = '';
+
+sub sanitise_line_reset {
+ my ($in_comment) = @_;
+
+ if ($in_comment) {
+ $sanitise_quote = '*/';
+ } else {
+ $sanitise_quote = '';
+ }
+}
+sub sanitise_line {
+ my ($line) = @_;
+
+ my $res = '';
+ my $l = '';
+
+ my $qlen = 0;
+ my $off = 0;
+ my $c;
+
+ # Always copy over the diff marker.
+ $res = substr($line, 0, 1);
+
+ for ($off = 1; $off < length($line); $off++) {
+ $c = substr($line, $off, 1);
+
+ # Comments we are wacking completly including the begin
+ # and end, all to $;.
+ if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
+ $sanitise_quote = '*/';
+
+ substr($res, $off, 2, "$;$;");
+ $off++;
+ next;
+ }
+ if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
+ $sanitise_quote = '';
+ substr($res, $off, 2, "$;$;");
+ $off++;
+ next;
+ }
+ if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') {
+ $sanitise_quote = '//';
+
+ substr($res, $off, 2, $sanitise_quote);
+ $off++;
+ next;
+ }
+
+ # A \ in a string means ignore the next character.
+ if (($sanitise_quote eq "'" || $sanitise_quote eq '"') &&
+ $c eq "\\") {
+ substr($res, $off, 2, 'XX');
+ $off++;
+ next;
+ }
+ # Regular quotes.
+ if ($c eq "'" || $c eq '"') {
+ if ($sanitise_quote eq '') {
+ $sanitise_quote = $c;
+
+ substr($res, $off, 1, $c);
+ next;
+ } elsif ($sanitise_quote eq $c) {
+ $sanitise_quote = '';
+ }
+ }
+
+ #print "c<$c> SQ<$sanitise_quote>\n";
+ if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") {
+ substr($res, $off, 1, $;);
+ } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") {
+ substr($res, $off, 1, $;);
+ } elsif ($off != 0 && $sanitise_quote && $c ne "\t") {
+ substr($res, $off, 1, 'X');
+ } else {
+ substr($res, $off, 1, $c);
+ }
+ }
+
+ if ($sanitise_quote eq '//') {
+ $sanitise_quote = '';
+ }
+
+ # The pathname on a #include may be surrounded by '<' and '>'.
+ if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) {
+ my $clean = 'X' x length($1);
+ $res =~ s@\<.*\>@<$clean>@;
+
+ # The whole of a #error is a string.
+ } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
+ my $clean = 'X' x length($1);
+ $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
+ }
+
+ return $res;
+}
+
+sub ctx_statement_block {
+ my ($linenr, $remain, $off) = @_;
+ my $line = $linenr - 1;
+ my $blk = '';
+ my $soff = $off;
+ my $coff = $off - 1;
+ my $coff_set = 0;
+
+ my $loff = 0;
+
+ my $type = '';
+ my $level = 0;
+ my @stack = ();
+ my $p;
+ my $c;
+ my $len = 0;
+
+ my $remainder;
+ while (1) {
+ @stack = (['', 0]) if ($#stack == -1);
+
+ #warn "CSB: blk<$blk> remain<$remain>\n";
+ # If we are about to drop off the end, pull in more
+ # context.
+ if ($off >= $len) {
+ for (; $remain > 0; $line++) {
+ last if (!defined $lines[$line]);
+ next if ($lines[$line] =~ /^-/);
+ $remain--;
+ $loff = $len;
+ $blk .= $lines[$line] . "\n";
+ $len = length($blk);
+ $line++;
+ last;
+ }
+ # Bail if there is no further context.
+ #warn "CSB: blk<$blk> off<$off> len<$len>\n";
+ if ($off >= $len) {
+ last;
+ }
+ }
+ $p = $c;
+ $c = substr($blk, $off, 1);
+ $remainder = substr($blk, $off);
+
+ #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
+
+ # Handle nested #if/#else.
+ if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) {
+ push(@stack, [ $type, $level ]);
+ } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) {
+ ($type, $level) = @{$stack[$#stack - 1]};
+ } elsif ($remainder =~ /^#\s*endif\b/) {
+ ($type, $level) = @{pop(@stack)};
+ }
+
+ # Statement ends at the ';' or a close '}' at the
+ # outermost level.
+ if ($level == 0 && $c eq ';') {
+ last;
+ }
+
+ # An else is really a conditional as long as its not else if
+ if ($level == 0 && $coff_set == 0 &&
+ (!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
+ $remainder =~ /^(else)(?:\s|{)/ &&
+ $remainder !~ /^else\s+if\b/) {
+ $coff = $off + length($1) - 1;
+ $coff_set = 1;
+ #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
+ #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
+ }
+
+ if (($type eq '' || $type eq '(') && $c eq '(') {
+ $level++;
+ $type = '(';
+ }
+ if ($type eq '(' && $c eq ')') {
+ $level--;
+ $type = ($level != 0)? '(' : '';
+
+ if ($level == 0 && $coff < $soff) {
+ $coff = $off;
+ $coff_set = 1;
+ #warn "CSB: mark coff<$coff>\n";
+ }
+ }
+ if (($type eq '' || $type eq '{') && $c eq '{') {
+ $level++;
+ $type = '{';
+ }
+ if ($type eq '{' && $c eq '}') {
+ $level--;
+ $type = ($level != 0)? '{' : '';
+
+ if ($level == 0) {
+ if (substr($blk, $off + 1, 1) eq ';') {
+ $off++;
+ }
+ last;
+ }
+ }
+ $off++;
+ }
+ # We are truly at the end, so shuffle to the next line.
+ if ($off == $len) {
+ $loff = $len + 1;
+ $line++;
+ $remain--;
+ }
+
+ my $statement = substr($blk, $soff, $off - $soff + 1);
+ my $condition = substr($blk, $soff, $coff - $soff + 1);
+
+ #warn "STATEMENT<$statement>\n";
+ #warn "CONDITION<$condition>\n";
+
+ #print "coff<$coff> soff<$off> loff<$loff>\n";
+
+ return ($statement, $condition,
+ $line, $remain + 1, $off - $loff + 1, $level);
+}
+
+sub statement_lines {
+ my ($stmt) = @_;
+
+ # Strip the diff line prefixes and rip blank lines at start and end.
+ $stmt =~ s/(^|\n)./$1/g;
+ $stmt =~ s/^\s*//;
+ $stmt =~ s/\s*$//;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+
+ return $#stmt_lines + 2;
+}
+
+sub statement_rawlines {
+ my ($stmt) = @_;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+
+ return $#stmt_lines + 2;
+}
+
+sub statement_block_size {
+ my ($stmt) = @_;
+
+ $stmt =~ s/(^|\n)./$1/g;
+ $stmt =~ s/^\s*{//;
+ $stmt =~ s/}\s*$//;
+ $stmt =~ s/^\s*//;
+ $stmt =~ s/\s*$//;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+ my @stmt_statements = ($stmt =~ /;/g);
+
+ my $stmt_lines = $#stmt_lines + 2;
+ my $stmt_statements = $#stmt_statements + 1;
+
+ if ($stmt_lines > $stmt_statements) {
+ return $stmt_lines;
+ } else {
+ return $stmt_statements;
+ }
+}
+
+sub ctx_statement_full {
+ my ($linenr, $remain, $off) = @_;
+ my ($statement, $condition, $level);
+
+ my (@chunks);
+
+ # Grab the first conditional/block pair.
+ ($statement, $condition, $linenr, $remain, $off, $level) =
+ ctx_statement_block($linenr, $remain, $off);
+ #print "F: c<$condition> s<$statement> remain<$remain>\n";
+ push(@chunks, [ $condition, $statement ]);
+ if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
+ return ($level, $linenr, @chunks);
+ }
+
+ # Pull in the following conditional/block pairs and see if they
+ # could continue the statement.
+ for (;;) {
+ ($statement, $condition, $linenr, $remain, $off, $level) =
+ ctx_statement_block($linenr, $remain, $off);
+ #print "C: c<$condition> s<$statement> remain<$remain>\n";
+ last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
+ #print "C: push\n";
+ push(@chunks, [ $condition, $statement ]);
+ }
+
+ return ($level, $linenr, @chunks);
+}
+
+sub ctx_block_get {
+ my ($linenr, $remain, $outer, $open, $close, $off) = @_;
+ my $line;
+ my $start = $linenr - 1;
+ my $blk = '';
+ my @o;
+ my @c;
+ my @res = ();
+
+ my $level = 0;
+ my @stack = ($level);
+ for ($line = $start; $remain > 0; $line++) {
+ next if ($rawlines[$line] =~ /^-/);
+ $remain--;
+
+ $blk .= $rawlines[$line];
+
+ # Handle nested #if/#else.
+ if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
+ push(@stack, $level);
+ } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
+ $level = $stack[$#stack - 1];
+ } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
+ $level = pop(@stack);
+ }
+
+ foreach my $c (split(//, $lines[$line])) {
+ ##print "C<$c>L<$level><$open$close>O<$off>\n";
+ if ($off > 0) {
+ $off--;
+ next;
+ }
+
+ if ($c eq $close && $level > 0) {
+ $level--;
+ last if ($level == 0);
+ } elsif ($c eq $open) {
+ $level++;
+ }
+ }
+
+ if (!$outer || $level <= 1) {
+ push(@res, $rawlines[$line]);
+ }
+
+ last if ($level == 0);
+ }
+
+ return ($level, @res);
+}
+sub ctx_block_outer {
+ my ($linenr, $remain) = @_;
+
+ my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
+ return @r;
+}
+sub ctx_block {
+ my ($linenr, $remain) = @_;
+
+ my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+ return @r;
+}
+sub ctx_statement {
+ my ($linenr, $remain, $off) = @_;
+
+ my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+ return @r;
+}
+sub ctx_block_level {
+ my ($linenr, $remain) = @_;
+
+ return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+}
+sub ctx_statement_level {
+ my ($linenr, $remain, $off) = @_;
+
+ return ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+}
+
+sub ctx_locate_comment {
+ my ($first_line, $end_line) = @_;
+
+ # Catch a comment on the end of the line itself.
+ my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@);
+ return $current_comment if (defined $current_comment);
+
+ # Look through the context and try and figure out if there is a
+ # comment.
+ my $in_comment = 0;
+ $current_comment = '';
+ for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {
+ my $line = $rawlines[$linenr - 1];
+ #warn " $line\n";
+ if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
+ $in_comment = 1;
+ }
+ if ($line =~ m@/\*@) {
+ $in_comment = 1;
+ }
+ if (!$in_comment && $current_comment ne '') {
+ $current_comment = '';
+ }
+ $current_comment .= $line . "\n" if ($in_comment);
+ if ($line =~ m@\*/@) {
+ $in_comment = 0;
+ }
+ }
+
+ chomp($current_comment);
+ return($current_comment);
+}
+sub ctx_has_comment {
+ my ($first_line, $end_line) = @_;
+ my $cmt = ctx_locate_comment($first_line, $end_line);
+
+ ##print "LINE: $rawlines[$end_line - 1 ]\n";
+ ##print "CMMT: $cmt\n";
+
+ return ($cmt ne '');
+}
+
+sub raw_line {
+ my ($linenr, $cnt) = @_;
+
+ my $offset = $linenr - 1;
+ $cnt++;
+
+ my $line;
+ while ($cnt) {
+ $line = $rawlines[$offset++];
+ next if (defined($line) && $line =~ /^-/);
+ $cnt--;
+ }
+
+ return $line;
+}
+
+sub cat_vet {
+ my ($vet) = @_;
+ my ($res, $coded);
+
+ $res = '';
+ while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {
+ $res .= $1;
+ if ($2 ne '') {
+ $coded = sprintf("^%c", unpack('C', $2) + 64);
+ $res .= $coded;
+ }
+ }
+ $res =~ s/$/\$/;
+
+ return $res;
+}
+
+my $av_preprocessor = 0;
+my $av_pending;
+my @av_paren_type;
+my $av_pend_colon;
+
+sub annotate_reset {
+ $av_preprocessor = 0;
+ $av_pending = '_';
+ @av_paren_type = ('E');
+ $av_pend_colon = 'O';
+}
+
+sub annotate_values {
+ my ($stream, $type) = @_;
+
+ my $res;
+ my $var = '_' x length($stream);
+ my $cur = $stream;
+
+ print "$stream\n" if ($dbg_values > 1);
+
+ while (length($cur)) {
+ @av_paren_type = ('E') if ($#av_paren_type < 0);
+ print " <" . join('', @av_paren_type) .
+ "> <$type> <$av_pending>" if ($dbg_values > 1);
+ if ($cur =~ /^(\s+)/o) {
+ print "WS($1)\n" if ($dbg_values > 1);
+ if ($1 =~ /\n/ && $av_preprocessor) {
+ $type = pop(@av_paren_type);
+ $av_preprocessor = 0;
+ }
+
+ } elsif ($cur =~ /^(\(\s*$Type\s*)\)/) {
+ print "CAST($1)\n" if ($dbg_values > 1);
+ push(@av_paren_type, $type);
+ $type = 'C';
+
+ } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
+ print "DECLARE($1)\n" if ($dbg_values > 1);
+ $type = 'T';
+
+ } elsif ($cur =~ /^($Modifier)\s*/) {
+ print "MODIFIER($1)\n" if ($dbg_values > 1);
+ $type = 'T';
+
+ } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
+ print "DEFINE($1,$2)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+ push(@av_paren_type, $type);
+ if ($2 ne '') {
+ $av_pending = 'N';
+ }
+ $type = 'E';
+
+ } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
+ print "UNDEF($1)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+ push(@av_paren_type, $type);
+
+ } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
+ print "PRE_START($1)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+
+ push(@av_paren_type, $type);
+ push(@av_paren_type, $type);
+ $type = 'E';
+
+ } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
+ print "PRE_RESTART($1)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+
+ push(@av_paren_type, $av_paren_type[$#av_paren_type]);
+
+ $type = 'E';
+
+ } elsif ($cur =~ /^(\#\s*(?:endif))/o) {
+ print "PRE_END($1)\n" if ($dbg_values > 1);
+
+ $av_preprocessor = 1;
+
+ # Assume all arms of the conditional end as this
+ # one does, and continue as if the #endif was not here.
+ pop(@av_paren_type);
+ push(@av_paren_type, $type);
+ $type = 'E';
+
+ } elsif ($cur =~ /^(\\\n)/o) {
+ print "PRECONT($1)\n" if ($dbg_values > 1);
+
+ } elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
+ print "ATTR($1)\n" if ($dbg_values > 1);
+ $av_pending = $type;
+ $type = 'N';
+
+ } elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
+ print "SIZEOF($1)\n" if ($dbg_values > 1);
+ if (defined $2) {
+ $av_pending = 'V';
+ }
+ $type = 'N';
+
+ } elsif ($cur =~ /^(if|while|for)\b/o) {
+ print "COND($1)\n" if ($dbg_values > 1);
+ $av_pending = 'E';
+ $type = 'N';
+
+ } elsif ($cur =~/^(case)/o) {
+ print "CASE($1)\n" if ($dbg_values > 1);
+ $av_pend_colon = 'C';
+ $type = 'N';
+
+ } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
+ print "KEYWORD($1)\n" if ($dbg_values > 1);
+ $type = 'N';
+
+ } elsif ($cur =~ /^(\()/o) {
+ print "PAREN('$1')\n" if ($dbg_values > 1);
+ push(@av_paren_type, $av_pending);
+ $av_pending = '_';
+ $type = 'N';
+
+ } elsif ($cur =~ /^(\))/o) {
+ my $new_type = pop(@av_paren_type);
+ if ($new_type ne '_') {
+ $type = $new_type;
+ print "PAREN('$1') -> $type\n"
+ if ($dbg_values > 1);
+ } else {
+ print "PAREN('$1')\n" if ($dbg_values > 1);
+ }
+
+ } elsif ($cur =~ /^($Ident)\s*\(/o) {
+ print "FUNC($1)\n" if ($dbg_values > 1);
+ $type = 'V';
+ $av_pending = 'V';
+
+ } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) {
+ if (defined $2 && $type eq 'C' || $type eq 'T') {
+ $av_pend_colon = 'B';
+ } elsif ($type eq 'E') {
+ $av_pend_colon = 'L';
+ }
+ print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1);
+ $type = 'V';
+
+ } elsif ($cur =~ /^($Ident|$Constant)/o) {
+ print "IDENT($1)\n" if ($dbg_values > 1);
+ $type = 'V';
+
+ } elsif ($cur =~ /^($Assignment)/o) {
+ print "ASSIGN($1)\n" if ($dbg_values > 1);
+ $type = 'N';
+
+ } elsif ($cur =~/^(;|{|})/) {
+ print "END($1)\n" if ($dbg_values > 1);
+ $type = 'E';
+ $av_pend_colon = 'O';
+
+ } elsif ($cur =~/^(,)/) {
+ print "COMMA($1)\n" if ($dbg_values > 1);
+ $type = 'C';
+
+ } elsif ($cur =~ /^(\?)/o) {
+ print "QUESTION($1)\n" if ($dbg_values > 1);
+ $type = 'N';
+
+ } elsif ($cur =~ /^(:)/o) {
+ print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1);
+
+ substr($var, length($res), 1, $av_pend_colon);
+ if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {
+ $type = 'E';
+ } else {
+ $type = 'N';
+ }
+ $av_pend_colon = 'O';
+
+ } elsif ($cur =~ /^(\[)/o) {
+ print "CLOSE($1)\n" if ($dbg_values > 1);
+ $type = 'N';
+
+ } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
+ my $variant;
+
+ print "OPV($1)\n" if ($dbg_values > 1);
+ if ($type eq 'V') {
+ $variant = 'B';
+ } else {
+ $variant = 'U';
+ }
+
+ substr($var, length($res), 1, $variant);
+ $type = 'N';
+
+ } elsif ($cur =~ /^($Operators)/o) {
+ print "OP($1)\n" if ($dbg_values > 1);
+ if ($1 ne '++' && $1 ne '--') {
+ $type = 'N';
+ }
+
+ } elsif ($cur =~ /(^.)/o) {
+ print "C($1)\n" if ($dbg_values > 1);
+ }
+ if (defined $1) {
+ $cur = substr($cur, length($1));
+ $res .= $type x length($1);
+ }
+ }
+
+ return ($res, $var);
+}
+
+sub possible {
+ my ($possible, $line) = @_;
+ my $notPermitted = qr{(?:
+ ^(?:
+ $Modifier|
+ $Storage|
+ $Type|
+ DEFINE_\S+
+ )$|
+ ^(?:
+ goto|
+ return|
+ case|
+ else|
+ asm|__asm__|
+ do
+ )(?:\s|$)|
+ ^(?:typedef|struct|enum)\b
+ )}x;
+ warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+ if ($possible !~ $notPermitted) {
+ # Check for modifiers.
+ $possible =~ s/\s*$Storage\s*//g;
+ $possible =~ s/\s*$Sparse\s*//g;
+ if ($possible =~ /^\s*$/) {
+
+ } elsif ($possible =~ /\s/) {
+ $possible =~ s/\s*$Type\s*//g;
+ for my $modifier (split(' ', $possible)) {
+ if ($modifier !~ $notPermitted) {
+ warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible);
+ push(@modifierList, $modifier);
+ }
+ }
+
+ } else {
+ warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
+ push(@typeList, $possible);
+ }
+ build_types();
+ } else {
+ warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
+ }
+}
+
+my $prefix = '';
+
+sub report {
+ if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) {
+ return 0;
+ }
+ my $line = $prefix . $_[0];
+
+ $line = (split('\n', $line))[0] . "\n" if ($terse);
+
+ push(our @report, $line);
+
+ return 1;
+}
+sub report_dump {
+ our @report;
+}
+sub ERROR {
+ if (report("ERROR: $_[0]\n")) {
+ our $clean = 0;
+ our $cnt_error++;
+ }
+}
+sub WARN {
+ if (report("WARNING: $_[0]\n")) {
+ our $clean = 0;
+ our $cnt_warn++;
+ }
+}
+sub CHK {
+ if ($check && report("CHECK: $_[0]\n")) {
+ our $clean = 0;
+ our $cnt_chk++;
+ }
+}
+
+sub check_absolute_file {
+ my ($absolute, $herecurr) = @_;
+ my $file = $absolute;
+
+ ##print "absolute<$absolute>\n";
+
+ # See if any suffix of this path is a path within the tree.
+ while ($file =~ s@^[^/]*/@@) {
+ if (-f "$root/$file") {
+ ##print "file<$file>\n";
+ last;
+ }
+ }
+ if (! -f _) {
+ return 0;
+ }
+
+ # It is, so see if the prefix is acceptable.
+ my $prefix = $absolute;
+ substr($prefix, -length($file)) = '';
+
+ ##print "prefix<$prefix>\n";
+ if ($prefix ne ".../") {
+ WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr);
+ }
+}
+
+sub process {
+ my $filename = shift;
+
+ my $linenr=0;
+ my $prevline="";
+ my $prevrawline="";
+ my $stashline="";
+ my $stashrawline="";
+
+ my $length;
+ my $indent;
+ my $previndent=0;
+ my $stashindent=0;
+
+ our $clean = 1;
+ my $signoff = 0;
+ my $is_patch = 0;
+
+ our @report = ();
+ our $cnt_lines = 0;
+ our $cnt_error = 0;
+ our $cnt_warn = 0;
+ our $cnt_chk = 0;
+
+ # Trace the real file/line as we go.
+ my $realfile = '';
+ my $realline = 0;
+ my $realcnt = 0;
+ my $here = '';
+ my $in_comment = 0;
+ my $comment_edge = 0;
+ my $first_line = 0;
+ my $p1_prefix = '';
+
+ my $prev_values = 'E';
+
+ # suppression flags
+ my %suppress_ifbraces;
+ my %suppress_whiletrailers;
+ my %suppress_export;
+
+ # Pre-scan the patch sanitizing the lines.
+ # Pre-scan the patch looking for any __setup documentation.
+ #
+ my @setup_docs = ();
+ my $setup_docs = 0;
+
+ sanitise_line_reset();
+ my $line;
+ foreach my $rawline (@rawlines) {
+ $linenr++;
+ $line = $rawline;
+
+ if ($rawline=~/^\+\+\+\s+(\S+)/) {
+ $setup_docs = 0;
+ if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
+ $setup_docs = 1;
+ }
+ #next;
+ }
+ if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+ $realline=$1-1;
+ if (defined $2) {
+ $realcnt=$3+1;
+ } else {
+ $realcnt=1+1;
+ }
+ $in_comment = 0;
+
+ # Guestimate if this is a continuing comment. Run
+ # the context looking for a comment "edge". If this
+ # edge is a close comment then we must be in a comment
+ # at context start.
+ my $edge;
+ my $cnt = $realcnt;
+ for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+ next if (defined $rawlines[$ln - 1] &&
+ $rawlines[$ln - 1] =~ /^-/);
+ $cnt--;
+ #print "RAW<$rawlines[$ln - 1]>\n";
+ last if (!defined $rawlines[$ln - 1]);
+ if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
+ $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
+ ($edge) = $1;
+ last;
+ }
+ }
+ if (defined $edge && $edge eq '*/') {
+ $in_comment = 1;
+ }
+
+ # Guestimate if this is a continuing comment. If this
+ # is the start of a diff block and this line starts
+ # ' *' then it is very likely a comment.
+ if (!defined $edge &&
+ $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
+ {
+ $in_comment = 1;
+ }
+
+ ##print "COMMENT:$in_comment edge<$edge> $rawline\n";
+ sanitise_line_reset($in_comment);
+
+ } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
+ # Standardise the strings and chars within the input to
+ # simplify matching -- only bother with positive lines.
+ $line = sanitise_line($rawline);
+ }
+ push(@lines, $line);
+
+ if ($realcnt > 1) {
+ $realcnt-- if ($line =~ /^(?:\+| |$)/);
+ } else {
+ $realcnt = 0;
+ }
+
+ #print "==>$rawline\n";
+ #print "-->$line\n";
+
+ if ($setup_docs && $line =~ /^\+/) {
+ push(@setup_docs, $line);
+ }
+ }
+
+ $prefix = '';
+
+ $realcnt = 0;
+ $linenr = 0;
+ foreach my $line (@lines) {
+ $linenr++;
+
+ my $rawline = $rawlines[$linenr - 1];
+
+#extract the line range in the file after the patch is applied
+ if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+ $is_patch = 1;
+ $first_line = $linenr + 1;
+ $realline=$1-1;
+ if (defined $2) {
+ $realcnt=$3+1;
+ } else {
+ $realcnt=1+1;
+ }
+ annotate_reset();
+ $prev_values = 'E';
+
+ %suppress_ifbraces = ();
+ %suppress_whiletrailers = ();
+ %suppress_export = ();
+ next;
+
+# track the line number as we move through the hunk, note that
+# new versions of GNU diff omit the leading space on completely
+# blank context lines so we need to count that too.
+ } elsif ($line =~ /^( |\+|$)/) {
+ $realline++;
+ $realcnt-- if ($realcnt != 0);
+
+ # Measure the line length and indent.
+ ($length, $indent) = line_stats($rawline);
+
+ # Track the previous line.
+ ($prevline, $stashline) = ($stashline, $line);
+ ($previndent, $stashindent) = ($stashindent, $indent);
+ ($prevrawline, $stashrawline) = ($stashrawline, $rawline);
+
+ #warn "line<$line>\n";
+
+ } elsif ($realcnt == 1) {
+ $realcnt--;
+ }
+
+ my $hunk_line = ($realcnt != 0);
+
+#make up the handle for any error we report on this line
+ $prefix = "$filename:$realline: " if ($emacs && $file);
+ $prefix = "$filename:$linenr: " if ($emacs && !$file);
+
+ $here = "#$linenr: " if (!$file);
+ $here = "#$realline: " if ($file);
+
+ # extract the filename as it passes
+ if ($line =~ /^diff --git.*?(\S+)$/) {
+ $realfile = $1;
+ $realfile =~ s@^([^/]*)/@@;
+
+ } elsif ($line =~ /^\+\+\+\s+(\S+)/) {
+ $realfile = $1;
+ $realfile =~ s@^([^/]*)/@@;
+
+ $p1_prefix = $1;
+ if (!$file && $tree && $p1_prefix ne '' &&
+ -e "$root/$p1_prefix") {
+ WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
+ }
+
+ if ($realfile =~ m@^include/asm/@) {
+ ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
+ }
+ next;
+ }
+
+ $here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
+
+ my $hereline = "$here\n$rawline\n";
+ my $herecurr = "$here\n$rawline\n";
+ my $hereprev = "$here\n$prevrawline\n$rawline\n";
+
+ $cnt_lines++ if ($realcnt != 0);
+
+# Check for incorrect file permissions
+ if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
+ my $permhere = $here . "FILE: $realfile\n";
+ if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) {
+ ERROR("do not set execute permissions for source files\n" . $permhere);
+ }
+ }
+
+#check the patch for a signoff:
+ if ($line =~ /^\s*signed-off-by:/i) {
+ # This is a signoff, if ugly, so do not double report.
+ $signoff++;
+ if (!($line =~ /^\s*Signed-off-by:/)) {
+ WARN("Signed-off-by: is the preferred form\n" .
+ $herecurr);
+ }
+ if ($line =~ /^\s*signed-off-by:\S/i) {
+ WARN("space required after Signed-off-by:\n" .
+ $herecurr);
+ }
+ }
+
+# Check for wrappage within a valid hunk of the file
+ if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
+ ERROR("patch seems to be corrupt (line wrapped?)\n" .
+ $herecurr) if (!$emitted_corrupt++);
+ }
+
+# Check for absolute kernel paths.
+ if ($tree) {
+ while ($line =~ m{(?:^|\s)(/\S*)}g) {
+ my $file = $1;
+
+ if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+ check_absolute_file($1, $herecurr)) {
+ #
+ } else {
+ check_absolute_file($file, $herecurr);
+ }
+ }
+ }
+
+# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
+ if (($realfile =~ /^$/ || $line =~ /^\+/) &&
+ $rawline !~ m/^$UTF8*$/) {
+ my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/);
+
+ my $blank = copy_spacing($rawline);
+ my $ptr = substr($blank, 0, length($utf8_prefix)) . "^";
+ my $hereptr = "$hereline$ptr\n";
+
+ ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
+ }
+
+# ignore non-hunk lines and lines being removed
+ next if (!$hunk_line || $line =~ /^-/);
+
+#trailing whitespace
+ if ($line =~ /^\+.*\015/) {
+ my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+ ERROR("DOS line endings\n" . $herevet);
+
+ } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
+ my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+ ERROR("trailing whitespace\n" . $herevet);
+ $rpt_cleaners = 1;
+ }
+
+# check for Kconfig help text having a real description
+# Only applies when adding the entry originally, after that we do not have
+# sufficient context to determine whether it is indeed long enough.
+ if ($realfile =~ /Kconfig/ &&
+ $line =~ /\+\s*(?:---)?help(?:---)?$/) {
+ my $length = 0;
+ my $cnt = $realcnt;
+ my $ln = $linenr + 1;
+ my $f;
+ my $is_end = 0;
+ while ($cnt > 0 && defined $lines[$ln - 1]) {
+ $f = $lines[$ln - 1];
+ $cnt-- if ($lines[$ln - 1] !~ /^-/);
+ $is_end = $lines[$ln - 1] =~ /^\+/;
+ $ln++;
+
+ next if ($f =~ /^-/);
+ $f =~ s/^.//;
+ $f =~ s/#.*//;
+ $f =~ s/^\s+//;
+ next if ($f =~ /^$/);
+ if ($f =~ /^\s*config\s/) {
+ $is_end = 1;
+ last;
+ }
+ $length++;
+ }
+ WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_end && $length < 4);
+ #print "is_end<$is_end> length<$length>\n";
+ }
+
+# check we are in a valid source file if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
+#80 column limit
+ if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
+ $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
+ !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ ||
+ $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) &&
+ $length > 80)
+ {
+ WARN("line over 80 characters\n" . $herecurr);
+ }
+
+# check for spaces before a quoted newline
+ if ($rawline =~ /^.*\".*\s\\n/) {
+ WARN("unnecessary whitespace before a quoted newline\n" . $herecurr);
+ }
+
+# check for adding lines without a newline.
+ if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) {
+ WARN("adding a line without newline at end of file\n" . $herecurr);
+ }
+
+# Blackfin: use hi/lo macros
+ if ($realfile =~ m@arch/blackfin/.*\.S$@) {
+ if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("use the LO() macro, not (... & 0xFFFF)\n" . $herevet);
+ }
+ if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("use the HI() macro, not (... >> 16)\n" . $herevet);
+ }
+ }
+
+# check we are in a valid source file C or perl if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c|pl)$/);
+
+# in QEMU, no tabs are allowed
+ if ($rawline =~ /\t/) {
+ my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+ ERROR("code indent should never use tabs\n" . $herevet);
+ $rpt_cleaners = 1;
+ }
+
+# check we are in a valid C source file if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c)$/);
+
+# check for RCS/CVS revision markers
+ if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
+ WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
+ }
+
+# Blackfin: don't use __builtin_bfin_[cs]sync
+ if ($line =~ /__builtin_bfin_csync/) {
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("use the CSYNC() macro in asm/blackfin.h\n" . $herevet);
+ }
+ if ($line =~ /__builtin_bfin_ssync/) {
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
+ }
+
+# Check for potential 'bare' types
+ my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
+ $realline_next);
+ if ($realcnt && $line =~ /.\s*\S/) {
+ ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+ ctx_statement_block($linenr, $realcnt, 0);
+ $stat =~ s/\n./\n /g;
+ $cond =~ s/\n./\n /g;
+
+ # Find the real next line.
+ $realline_next = $line_nr_next;
+ if (defined $realline_next &&
+ (!defined $lines[$realline_next - 1] ||
+ substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) {
+ $realline_next++;
+ }
+
+ my $s = $stat;
+ $s =~ s/{.*$//s;
+
+ # Ignore goto labels.
+ if ($s =~ /$Ident:\*$/s) {
+
+ # Ignore functions being called
+ } elsif ($s =~ /^.\s*$Ident\s*\(/s) {
+
+ } elsif ($s =~ /^.\s*else\b/s) {
+
+ # declarations always start with types
+ } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) {
+ my $type = $1;
+ $type =~ s/\s+/ /g;
+ possible($type, "A:" . $s);
+
+ # definitions in global scope can only start with types
+ } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
+ possible($1, "B:" . $s);
+ }
+
+ # any (foo ... *) is a pointer cast, and foo is a type
+ while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) {
+ possible($1, "C:" . $s);
+ }
+
+ # Check for any sort of function declaration.
+ # int foo(something bar, other baz);
+ # void (*store_gdt)(x86_descr_ptr *);
+ if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) {
+ my ($name_len) = length($1);
+
+ my $ctx = $s;
+ substr($ctx, 0, $name_len + 1, '');
+ $ctx =~ s/\)[^\)]*$//;
+
+ for my $arg (split(/\s*,\s*/, $ctx)) {
+ if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) {
+
+ possible($1, "D:" . $s);
+ }
+ }
+ }
+
+ }
+
+#
+# Checks which may be anchored in the context.
+#
+
+# Check for switch () and associated case and default
+# statements should be at the same indent.
+ if ($line=~/\bswitch\s*\(.*\)/) {
+ my $err = '';
+ my $sep = '';
+ my @ctx = ctx_block_outer($linenr, $realcnt);
+ shift(@ctx);
+ for my $ctx (@ctx) {
+ my ($clen, $cindent) = line_stats($ctx);
+ if ($ctx =~ /^\+\s*(case\s+|default:)/ &&
+ $indent != $cindent) {
+ $err .= "$sep$ctx\n";
+ $sep = '';
+ } else {
+ $sep = "[...]\n";
+ }
+ }
+ if ($err ne '') {
+ ERROR("switch and case should be at the same indent\n$hereline$err");
+ }
+ }
+
+# if/while/etc brace do not go on next line, unless defining a do while loop,
+# or if that brace on the next line is for something else
+ if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
+ my $pre_ctx = "$1$2";
+
+ my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
+ my $ctx_cnt = $realcnt - $#ctx - 1;
+ my $ctx = join("\n", @ctx);
+
+ my $ctx_ln = $linenr;
+ my $ctx_skip = $realcnt;
+
+ while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt &&
+ defined $lines[$ctx_ln - 1] &&
+ $lines[$ctx_ln - 1] =~ /^-/)) {
+ ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n";
+ $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/);
+ $ctx_ln++;
+ }
+
+ #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+ #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
+
+ if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+ ERROR("that open brace { should be on the previous line\n" .
+ "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
+ }
+ if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
+ $ctx =~ /\)\s*\;\s*$/ &&
+ defined $lines[$ctx_ln - 1])
+ {
+ my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
+ if ($nindent > $indent) {
+ WARN("trailing semicolon indicates no statements, indent implies otherwise\n" .
+ "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
+ }
+ }
+ }
+
+# Check relative indent for conditionals and blocks.
+ if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+ my ($s, $c) = ($stat, $cond);
+
+ substr($s, 0, length($c), '');
+
+ # Make sure we remove the line prefixes as we have
+ # none on the first line, and are going to readd them
+ # where necessary.
+ $s =~ s/\n./\n/gs;
+
+ # Find out how long the conditional actually is.
+ my @newlines = ($c =~ /\n/gs);
+ my $cond_lines = 1 + $#newlines;
+
+ # We want to check the first line inside the block
+ # starting at the end of the conditional, so remove:
+ # 1) any blank line termination
+ # 2) any opening brace { on end of the line
+ # 3) any do (...) {
+ my $continuation = 0;
+ my $check = 0;
+ $s =~ s/^.*\bdo\b//;
+ $s =~ s/^\s*{//;
+ if ($s =~ s/^\s*\\//) {
+ $continuation = 1;
+ }
+ if ($s =~ s/^\s*?\n//) {
+ $check = 1;
+ $cond_lines++;
+ }
+
+ # Also ignore a loop construct at the end of a
+ # preprocessor statement.
+ if (($prevline =~ /^.\s*#\s*define\s/ ||
+ $prevline =~ /\\\s*$/) && $continuation == 0) {
+ $check = 0;
+ }
+
+ my $cond_ptr = -1;
+ $continuation = 0;
+ while ($cond_ptr != $cond_lines) {
+ $cond_ptr = $cond_lines;
+
+ # If we see an #else/#elif then the code
+ # is not linear.
+ if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+ $check = 0;
+ }
+
+ # Ignore:
+ # 1) blank lines, they should be at 0,
+ # 2) preprocessor lines, and
+ # 3) labels.
+ if ($continuation ||
+ $s =~ /^\s*?\n/ ||
+ $s =~ /^\s*#\s*?/ ||
+ $s =~ /^\s*$Ident\s*:/) {
+ $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+ if ($s =~ s/^.*?\n//) {
+ $cond_lines++;
+ }
+ }
+ }
+
+ my (undef, $sindent) = line_stats("+" . $s);
+ my $stat_real = raw_line($linenr, $cond_lines);
+
+ # Check if either of these lines are modified, else
+ # this is not this patch's fault.
+ if (!defined($stat_real) ||
+ $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+ $check = 0;
+ }
+ if (defined($stat_real) && $cond_lines > 1) {
+ $stat_real = "[...]\n$stat_real";
+ }
+
+ #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+ if ($check && (($sindent % 4) != 0 ||
+ ($sindent <= $indent && $s ne ''))) {
+ WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+ }
+ }
+
+ # Track the 'values' across context and added lines.
+ my $opline = $line; $opline =~ s/^./ /;
+ my ($curr_values, $curr_vars) =
+ annotate_values($opline . "\n", $prev_values);
+ $curr_values = $prev_values . $curr_values;
+ if ($dbg_values) {
+ my $outline = $opline; $outline =~ s/\t/ /g;
+ print "$linenr > .$outline\n";
+ print "$linenr > $curr_values\n";
+ print "$linenr > $curr_vars\n";
+ }
+ $prev_values = substr($curr_values, -1);
+
+#ignore lines not being added
+ if ($line=~/^[^\+]/) {next;}
+
+# TEST: allow direct testing of the type matcher.
+ if ($dbg_type) {
+ if ($line =~ /^.\s*$Declare\s*$/) {
+ ERROR("TEST: is type\n" . $herecurr);
+ } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
+ ERROR("TEST: is not type ($1 is)\n". $herecurr);
+ }
+ next;
+ }
+# TEST: allow direct testing of the attribute matcher.
+ if ($dbg_attr) {
+ if ($line =~ /^.\s*$Modifier\s*$/) {
+ ERROR("TEST: is attr\n" . $herecurr);
+ } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
+ ERROR("TEST: is not attr ($1 is)\n". $herecurr);
+ }
+ next;
+ }
+
+# check for initialisation to aggregates open brace on the next line
+ if ($line =~ /^.\s*{/ &&
+ $prevline =~ /(?:^|[^=])=\s*$/) {
+ ERROR("that open brace { should be on the previous line\n" . $hereprev);
+ }
+
+#
+# Checks which are anchored on the added line.
+#
+
+# check for malformed paths in #include statements (uses RAW line)
+ if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
+ my $path = $1;
+ if ($path =~ m{//}) {
+ ERROR("malformed #include filename\n" .
+ $herecurr);
+ }
+ }
+
+# no C99 // comments
+ if ($line =~ m{//}) {
+ ERROR("do not use C99 // comments\n" . $herecurr);
+ }
+ # Remove C99 comments.
+ $line =~ s@//.*@@;
+ $opline =~ s@//.*@@;
+
+# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
+# the whole statement.
+#print "APW <$lines[$realline_next - 1]>\n";
+ if (defined $realline_next &&
+ exists $lines[$realline_next - 1] &&
+ !defined $suppress_export{$realline_next} &&
+ ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+ $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+ # Handle definitions which produce identifiers with
+ # a prefix:
+ # XXX(foo);
+ # EXPORT_SYMBOL(something_foo);
+ my $name = $1;
+ if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ &&
+ $name =~ /^${Ident}_$2/) {
+#print "FOO C name<$name>\n";
+ $suppress_export{$realline_next} = 1;
+
+ } elsif ($stat !~ /(?:
+ \n.}\s*$|
+ ^.DEFINE_$Ident\(\Q$name\E\)|
+ ^.DECLARE_$Ident\(\Q$name\E\)|
+ ^.LIST_HEAD\(\Q$name\E\)|
+ ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+ \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\()
+ )/x) {
+#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n";
+ $suppress_export{$realline_next} = 2;
+ } else {
+ $suppress_export{$realline_next} = 1;
+ }
+ }
+ if (!defined $suppress_export{$linenr} &&
+ $prevline =~ /^.\s*$/ &&
+ ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+ $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+#print "FOO B <$lines[$linenr - 1]>\n";
+ $suppress_export{$linenr} = 2;
+ }
+ if (defined $suppress_export{$linenr} &&
+ $suppress_export{$linenr} == 2) {
+ WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
+ }
+
+# check for global initialisers.
+ if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
+ ERROR("do not initialise globals to 0 or NULL\n" .
+ $herecurr);
+ }
+# check for static initialisers.
+ if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
+ ERROR("do not initialise statics to 0 or NULL\n" .
+ $herecurr);
+ }
+
+# * goes on variable not on type
+ # (char*[ const])
+ if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) {
+ my ($from, $to) = ($1, $1);
+
+ # Should start with a space.
+ $to =~ s/^(\S)/ $1/;
+ # Should not end with a space.
+ $to =~ s/\s+$//;
+ # '*'s should not have spaces between.
+ while ($to =~ s/\*\s+\*/\*\*/) {
+ }
+
+ #print "from<$from> to<$to>\n";
+ if ($from ne $to) {
+ ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr);
+ }
+ } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) {
+ my ($from, $to, $ident) = ($1, $1, $2);
+
+ # Should start with a space.
+ $to =~ s/^(\S)/ $1/;
+ # Should not end with a space.
+ $to =~ s/\s+$//;
+ # '*'s should not have spaces between.
+ while ($to =~ s/\*\s+\*/\*\*/) {
+ }
+ # Modifiers should have spaces.
+ $to =~ s/(\b$Modifier$)/$1 /;
+
+ #print "from<$from> to<$to> ident<$ident>\n";
+ if ($from ne $to && $ident !~ /^$Modifier$/) {
+ ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr);
+ }
+ }
+
+# # no BUG() or BUG_ON()
+# if ($line =~ /\b(BUG|BUG_ON)\b/) {
+# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n";
+# print "$herecurr";
+# $clean = 0;
+# }
+
+ if ($line =~ /\bLINUX_VERSION_CODE\b/) {
+ WARN("LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
+ }
+
+# printk should use KERN_* levels. Note that follow on printk's on the
+# same line do not need a level, so we use the current block context
+# to try and find and validate the current printk. In summary the current
+# printk includes all preceeding printk's which have no newline on the end.
+# we assume the first bad printk is the one to report.
+ if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
+ my $ok = 0;
+ for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
+ #print "CHECK<$lines[$ln - 1]\n";
+ # we have a preceeding printk if it ends
+ # with "\n" ignore it, else it is to blame
+ if ($lines[$ln - 1] =~ m{\bprintk\(}) {
+ if ($rawlines[$ln - 1] !~ m{\\n"}) {
+ $ok = 1;
+ }
+ last;
+ }
+ }
+ if ($ok == 0) {
+ WARN("printk() should include KERN_ facility level\n" . $herecurr);
+ }
+ }
+
+# function brace can't be on same line, except for #defines of do while,
+# or if closed on same line
+ if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and
+ !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) {
+ ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr);
+ }
+
+# open braces for enum, union and struct go on the same line.
+ if ($line =~ /^.\s*{/ &&
+ $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
+ ERROR("open brace '{' following $1 go on the same line\n" . $hereprev);
+ }
+
+# missing space after union, struct or enum definition
+ if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
+ WARN("missing space after $1 definition\n" . $herecurr);
+ }
+
+# check for spacing round square brackets; allowed:
+# 1. with a type on the left -- int [] a;
+# 2. at the beginning of a line for slice initialisers -- [0...10] = 5,
+# 3. inside a curly brace -- = { [0...10] = 5 }
+ while ($line =~ /(.*?\s)\[/g) {
+ my ($where, $prefix) = ($-[1], $1);
+ if ($prefix !~ /$Type\s+$/ &&
+ ($where != 0 || $prefix !~ /^.\s+$/) &&
+ $prefix !~ /{\s+$/) {
+ ERROR("space prohibited before open square bracket '['\n" . $herecurr);
+ }
+ }
+
+# check for spaces between functions and their parentheses.
+ while ($line =~ /($Ident)\s+\(/g) {
+ my $name = $1;
+ my $ctx_before = substr($line, 0, $-[1]);
+ my $ctx = "$ctx_before$name";
+
+ # Ignore those directives where spaces _are_ permitted.
+ if ($name =~ /^(?:
+ if|for|while|switch|return|case|
+ volatile|__volatile__|
+ __attribute__|format|__extension__|
+ asm|__asm__)$/x)
+ {
+
+ # cpp #define statements have non-optional spaces, ie
+ # if there is a space between the name and the open
+ # parenthesis it is simply not a parameter group.
+ } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) {
+
+ # cpp #elif statement condition may start with a (
+ } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) {
+
+ # If this whole things ends with a type its most
+ # likely a typedef for a function.
+ } elsif ($ctx =~ /$Type$/) {
+
+ } else {
+ WARN("space prohibited between function name and open parenthesis '('\n" . $herecurr);
+ }
+ }
+# Check operator spacing.
+ if (!($line=~/\#\s*include/)) {
+ my $ops = qr{
+ <<=|>>=|<=|>=|==|!=|
+ \+=|-=|\*=|\/=|%=|\^=|\|=|&=|
+ =>|->|<<|>>|<|>|=|!|~|
+ &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%|
+ \?|:
+ }x;
+ my @elements = split(/($ops|;)/, $opline);
+ my $off = 0;
+
+ my $blank = copy_spacing($opline);
+
+ for (my $n = 0; $n < $#elements; $n += 2) {
+ $off += length($elements[$n]);
+
+ # Pick up the preceeding and succeeding characters.
+ my $ca = substr($opline, 0, $off);
+ my $cc = '';
+ if (length($opline) >= ($off + length($elements[$n + 1]))) {
+ $cc = substr($opline, $off + length($elements[$n + 1]));
+ }
+ my $cb = "$ca$;$cc";
+
+ my $a = '';
+ $a = 'V' if ($elements[$n] ne '');
+ $a = 'W' if ($elements[$n] =~ /\s$/);
+ $a = 'C' if ($elements[$n] =~ /$;$/);
+ $a = 'B' if ($elements[$n] =~ /(\[|\()$/);
+ $a = 'O' if ($elements[$n] eq '');
+ $a = 'E' if ($ca =~ /^\s*$/);
+
+ my $op = $elements[$n + 1];
+
+ my $c = '';
+ if (defined $elements[$n + 2]) {
+ $c = 'V' if ($elements[$n + 2] ne '');
+ $c = 'W' if ($elements[$n + 2] =~ /^\s/);
+ $c = 'C' if ($elements[$n + 2] =~ /^$;/);
+ $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
+ $c = 'O' if ($elements[$n + 2] eq '');
+ $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/);
+ } else {
+ $c = 'E';
+ }
+
+ my $ctx = "${a}x${c}";
+
+ my $at = "(ctx:$ctx)";
+
+ my $ptr = substr($blank, 0, $off) . "^";
+ my $hereptr = "$hereline$ptr\n";
+
+ # Pull out the value of this operator.
+ my $op_type = substr($curr_values, $off + 1, 1);
+
+ # Get the full operator variant.
+ my $opv = $op . substr($curr_vars, $off, 1);
+
+ # Ignore operators passed as parameters.
+ if ($op_type ne 'V' &&
+ $ca =~ /\s$/ && $cc =~ /^\s*,/) {
+
+# # Ignore comments
+# } elsif ($op =~ /^$;+$/) {
+
+ # ; should have either the end of line or a space or \ after it
+ } elsif ($op eq ';') {
+ if ($ctx !~ /.x[WEBC]/ &&
+ $cc !~ /^\\/ && $cc !~ /^;/) {
+ ERROR("space required after that '$op' $at\n" . $hereptr);
+ }
+
+ # // is a comment
+ } elsif ($op eq '//') {
+
+ # No spaces for:
+ # ->
+ # : when part of a bitfield
+ } elsif ($op eq '->' || $opv eq ':B') {
+ if ($ctx =~ /Wx.|.xW/) {
+ ERROR("spaces prohibited around that '$op' $at\n" . $hereptr);
+ }
+
+ # , must have a space on the right.
+ } elsif ($op eq ',') {
+ if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
+ ERROR("space required after that '$op' $at\n" . $hereptr);
+ }
+
+ # '*' as part of a type definition -- reported already.
+ } elsif ($opv eq '*_') {
+ #warn "'*' is part of type\n";
+
+ # unary operators should have a space before and
+ # none after. May be left adjacent to another
+ # unary operator, or a cast
+ } elsif ($op eq '!' || $op eq '~' ||
+ $opv eq '*U' || $opv eq '-U' ||
+ $opv eq '&U' || $opv eq '&&U') {
+ if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
+ ERROR("space required before that '$op' $at\n" . $hereptr);
+ }
+ if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
+ # A unary '*' may be const
+
+ } elsif ($ctx =~ /.xW/) {
+ ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+ }
+
+ # unary ++ and unary -- are allowed no space on one side.
+ } elsif ($op eq '++' or $op eq '--') {
+ if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
+ ERROR("space required one side of that '$op' $at\n" . $hereptr);
+ }
+ if ($ctx =~ /Wx[BE]/ ||
+ ($ctx =~ /Wx./ && $cc =~ /^;/)) {
+ ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+ }
+ if ($ctx =~ /ExW/) {
+ ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+ }
+
+
+ # << and >> may either have or not have spaces both sides
+ } elsif ($op eq '<<' or $op eq '>>' or
+ $op eq '&' or $op eq '^' or $op eq '|' or
+ $op eq '+' or $op eq '-' or
+ $op eq '*' or $op eq '/' or
+ $op eq '%')
+ {
+ if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
+ ERROR("need consistent spacing around '$op' $at\n" .
+ $hereptr);
+ }
+
+ # A colon needs no spaces before when it is
+ # terminating a case value or a label.
+ } elsif ($opv eq ':C' || $opv eq ':L') {
+ if ($ctx =~ /Wx./) {
+ ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+ }
+
+ # All the others need spaces both sides.
+ } elsif ($ctx !~ /[EWC]x[CWE]/) {
+ my $ok = 0;
+
+ # Ignore email addresses <foo@bar>
+ if (($op eq '<' &&
+ $cc =~ /^\S+\@\S+>/) ||
+ ($op eq '>' &&
+ $ca =~ /<\S+\@\S+$/))
+ {
+ $ok = 1;
+ }
+
+ # Ignore ?:
+ if (($opv eq ':O' && $ca =~ /\?$/) ||
+ ($op eq '?' && $cc =~ /^:/)) {
+ $ok = 1;
+ }
+
+ if ($ok == 0) {
+ ERROR("spaces required around that '$op' $at\n" . $hereptr);
+ }
+ }
+ $off += length($elements[$n + 1]);
+ }
+ }
+
+# check for multiple assignments
+ if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
+ CHK("multiple assignments should be avoided\n" . $herecurr);
+ }
+
+## # check for multiple declarations, allowing for a function declaration
+## # continuation.
+## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
+## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
+##
+## # Remove any bracketed sections to ensure we do not
+## # falsly report the parameters of functions.
+## my $ln = $line;
+## while ($ln =~ s/\([^\(\)]*\)//g) {
+## }
+## if ($ln =~ /,/) {
+## WARN("declaring multiple variables together should be avoided\n" . $herecurr);
+## }
+## }
+
+#need space before brace following if, while, etc
+ if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) ||
+ $line =~ /do{/) {
+ ERROR("space required before the open brace '{'\n" . $herecurr);
+ }
+
+# closing brace should have a space following it when it has anything
+# on the line
+ if ($line =~ /}(?!(?:,|;|\)))\S/) {
+ ERROR("space required after that close brace '}'\n" . $herecurr);
+ }
+
+# check spacing on square brackets
+ if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
+ ERROR("space prohibited after that open square bracket '['\n" . $herecurr);
+ }
+ if ($line =~ /\s\]/) {
+ ERROR("space prohibited before that close square bracket ']'\n" . $herecurr);
+ }
+
+# check spacing on parentheses
+ if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
+ $line !~ /for\s*\(\s+;/) {
+ ERROR("space prohibited after that open parenthesis '('\n" . $herecurr);
+ }
+ if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
+ $line !~ /for\s*\(.*;\s+\)/ &&
+ $line !~ /:\s+\)/) {
+ ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr);
+ }
+
+#goto labels aren't indented, allow a single space however
+ if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
+ !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
+ WARN("labels should not be indented\n" . $herecurr);
+ }
+
+# Return is not a function.
+ if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
+ my $spacing = $1;
+ my $value = $2;
+
+ # Flatten any parentheses
+ $value =~ s/\(/ \(/g;
+ $value =~ s/\)/\) /g;
+ while ($value =~ s/\[[^\{\}]*\]/1/ ||
+ $value !~ /(?:$Ident|-?$Constant)\s*
+ $Compare\s*
+ (?:$Ident|-?$Constant)/x &&
+ $value =~ s/\([^\(\)]*\)/1/) {
+ }
+#print "value<$value>\n";
+ if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) {
+ ERROR("return is not a function, parentheses are not required\n" . $herecurr);
+
+ } elsif ($spacing !~ /\s+/) {
+ ERROR("space required before the open parenthesis '('\n" . $herecurr);
+ }
+ }
+# Return of what appears to be an errno should normally be -'ve
+ if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) {
+ my $name = $1;
+ if ($name ne 'EOF' && $name ne 'ERROR') {
+ CHK("return of an errno should typically be -ve (return -$1)\n" . $herecurr);
+ }
+ }
+
+# Need a space before open parenthesis after if, while etc
+ if ($line=~/\b(if|while|for|switch)\(/) {
+ ERROR("space required before the open parenthesis '('\n" . $herecurr);
+ }
+
+# Check for illegal assignment in if conditional -- and check for trailing
+# statements after the conditional.
+ if ($line =~ /do\s*(?!{)/) {
+ my ($stat_next) = ctx_statement_block($line_nr_next,
+ $remain_next, $off_next);
+ $stat_next =~ s/\n./\n /g;
+ ##print "stat<$stat> stat_next<$stat_next>\n";
+
+ if ($stat_next =~ /^\s*while\b/) {
+ # If the statement carries leading newlines,
+ # then count those as offsets.
+ my ($whitespace) =
+ ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+ my $offset =
+ statement_rawlines($whitespace) - 1;
+
+ $suppress_whiletrailers{$line_nr_next +
+ $offset} = 1;
+ }
+ }
+ if (!defined $suppress_whiletrailers{$linenr} &&
+ $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
+ my ($s, $c) = ($stat, $cond);
+
+ if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
+ ERROR("do not use assignment in if condition\n" . $herecurr);
+ }
+
+ # Find out what is on the end of the line after the
+ # conditional.
+ substr($s, 0, length($c), '');
+ $s =~ s/\n.*//g;
+ $s =~ s/$;//g; # Remove any comments
+ if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
+ $c !~ /}\s*while\s*/)
+ {
+ # Find out how long the conditional actually is.
+ my @newlines = ($c =~ /\n/gs);
+ my $cond_lines = 1 + $#newlines;
+ my $stat_real = '';
+
+ $stat_real = raw_line($linenr, $cond_lines)
+ . "\n" if ($cond_lines);
+ if (defined($stat_real) && $cond_lines > 1) {
+ $stat_real = "[...]\n$stat_real";
+ }
+
+ ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real);
+ }
+ }
+
+# Check for bitwise tests written as boolean
+ if ($line =~ /
+ (?:
+ (?:\[|\(|\&\&|\|\|)
+ \s*0[xX][0-9]+\s*
+ (?:\&\&|\|\|)
+ |
+ (?:\&\&|\|\|)
+ \s*0[xX][0-9]+\s*
+ (?:\&\&|\|\||\)|\])
+ )/x)
+ {
+ WARN("boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
+ }
+
+# if and else should not have general statements after it
+ if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
+ my $s = $1;
+ $s =~ s/$;//g; # Remove any comments
+ if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
+ ERROR("trailing statements should be on next line\n" . $herecurr);
+ }
+ }
+# if should not continue a brace
+ if ($line =~ /}\s*if\b/) {
+ ERROR("trailing statements should be on next line\n" .
+ $herecurr);
+ }
+# case and default should not have general statements after them
+ if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+ $line !~ /\G(?:
+ (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+ \s*return\s+
+ )/xg)
+ {
+ ERROR("trailing statements should be on next line\n" . $herecurr);
+ }
+
+ # Check for }<nl>else {, these must be at the same
+ # indent level to be relevant to each other.
+ if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
+ $previndent == $indent) {
+ ERROR("else should follow close brace '}'\n" . $hereprev);
+ }
+
+ if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and
+ $previndent == $indent) {
+ my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
+
+ # Find out what is on the end of the line after the
+ # conditional.
+ substr($s, 0, length($c), '');
+ $s =~ s/\n.*//g;
+
+ if ($s =~ /^\s*;/) {
+ ERROR("while should follow close brace '}'\n" . $hereprev);
+ }
+ }
+
+#studly caps, commented out until figure out how to distinguish between use of existing and adding new
+# if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) {
+# print "No studly caps, use _\n";
+# print "$herecurr";
+# $clean = 0;
+# }
+
+#no spaces allowed after \ in define
+ if ($line=~/\#\s*define.*\\\s$/) {
+ WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr);
+ }
+
+#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
+ if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
+ my $file = "$1.h";
+ my $checkfile = "include/linux/$file";
+ if (-f "$root/$checkfile" &&
+ $realfile ne $checkfile &&
+ $1 !~ /$allowed_asm_includes/)
+ {
+ if ($realfile =~ m{^arch/}) {
+ CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+ } else {
+ WARN("Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+ }
+ }
+ }
+
+# multi-statement macros should be enclosed in a do while loop, grab the
+# first statement and ensure its the whole macro if its not enclosed
+# in a known good container
+ if ($realfile !~ m@/vmlinux.lds.h$@ &&
+ $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
+ my $ln = $linenr;
+ my $cnt = $realcnt;
+ my ($off, $dstat, $dcond, $rest);
+ my $ctx = '';
+
+ my $args = defined($1);
+
+ # Find the end of the macro and limit our statement
+ # search to that.
+ while ($cnt > 0 && defined $lines[$ln - 1] &&
+ $lines[$ln - 1] =~ /^(?:-|..*\\$)/)
+ {
+ $ctx .= $rawlines[$ln - 1] . "\n";
+ $cnt-- if ($lines[$ln - 1] !~ /^-/);
+ $ln++;
+ }
+ $ctx .= $rawlines[$ln - 1];
+
+ ($dstat, $dcond, $ln, $cnt, $off) =
+ ctx_statement_block($linenr, $ln - $linenr + 1, 0);
+ #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
+ #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
+
+ # Extract the remainder of the define (if any) and
+ # rip off surrounding spaces, and trailing \'s.
+ $rest = '';
+ while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) {
+ #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n";
+ if ($off != 0 || $lines[$ln - 1] !~ /^-/) {
+ $rest .= substr($lines[$ln - 1], $off) . "\n";
+ $cnt--;
+ }
+ $ln++;
+ $off = 0;
+ }
+ $rest =~ s/\\\n.//g;
+ $rest =~ s/^\s*//s;
+ $rest =~ s/\s*$//s;
+
+ # Clean up the original statement.
+ if ($args) {
+ substr($dstat, 0, length($dcond), '');
+ } else {
+ $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//;
+ }
+ $dstat =~ s/$;//g;
+ $dstat =~ s/\\\n.//g;
+ $dstat =~ s/^\s*//s;
+ $dstat =~ s/\s*$//s;
+
+ # Flatten any parentheses and braces
+ while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+ $dstat =~ s/\{[^\{\}]*\}/1/ ||
+ $dstat =~ s/\[[^\{\}]*\]/1/)
+ {
+ }
+
+ my $exceptions = qr{
+ $Declare|
+ module_param_named|
+ MODULE_PARAM_DESC|
+ DECLARE_PER_CPU|
+ DEFINE_PER_CPU|
+ __typeof__\(|
+ union|
+ struct|
+ \.$Ident\s*=\s*|
+ ^\"|\"$
+ }x;
+ #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
+ if ($rest ne '' && $rest ne ',') {
+ if ($rest !~ /while\s*\(/ &&
+ $dstat !~ /$exceptions/)
+ {
+ ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
+ }
+
+ } elsif ($ctx !~ /;/) {
+ if ($dstat ne '' &&
+ $dstat !~ /^(?:$Ident|-?$Constant)$/ &&
+ $dstat !~ /$exceptions/ &&
+ $dstat !~ /^\.$Ident\s*=/ &&
+ $dstat =~ /$Operators/)
+ {
+ ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
+ }
+ }
+ }
+
+# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
+# all assignments may have only one of the following with an assignment:
+# .
+# ALIGN(...)
+# VMLINUX_SYMBOL(...)
+ if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
+ WARN("vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
+ }
+
+# check for missing bracing round if etc
+ if ($line =~ /(^.*)\bif\b/ && $line !~ /\#\s*if/) {
+ my ($level, $endln, @chunks) =
+ ctx_statement_full($linenr, $realcnt, 1);
+ #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
+ #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+ if ($#chunks >= 0 && $level == 0) {
+ my $allowed = 0;
+ my $seen = 0;
+ my $herectx = $here . "\n";
+ my $ln = $linenr - 1;
+ for my $chunk (@chunks) {
+ my ($cond, $block) = @{$chunk};
+
+ # If the condition carries leading newlines, then count those as offsets.
+ my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
+ my $offset = statement_rawlines($whitespace) - 1;
+
+ #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
+
+ # We have looked at and allowed this specific line.
+ $suppress_ifbraces{$ln + $offset} = 1;
+
+ $herectx .= "$rawlines[$ln + $offset]\n[...]\n";
+ $ln += statement_rawlines($block) - 1;
+
+ substr($block, 0, length($cond), '');
+
+ $seen++ if ($block =~ /^\s*{/);
+
+ #print "cond<$cond> block<$block> allowed<$allowed>\n";
+ if (statement_lines($cond) > 1) {
+ #print "APW: ALLOWED: cond<$cond>\n";
+ $allowed = 1;
+ }
+ if ($block =~/\b(?:if|for|while)\b/) {
+ #print "APW: ALLOWED: block<$block>\n";
+ $allowed = 1;
+ }
+ if (statement_block_size($block) > 1) {
+ #print "APW: ALLOWED: lines block<$block>\n";
+ $allowed = 1;
+ }
+ }
+ if (!$seen) {
+ WARN("braces {} are necessary for all arms of this statement\n" . $herectx);
+ }
+ }
+ }
+ if (!defined $suppress_ifbraces{$linenr - 1} &&
+ $line =~ /\b(if|while|for|else)\b/) {
+ my $allowed = 0;
+
+ # Check the pre-context.
+ if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+ #print "APW: ALLOWED: pre<$1>\n";
+ $allowed = 1;
+ }
+
+ my ($level, $endln, @chunks) =
+ ctx_statement_full($linenr, $realcnt, $-[0]);
+
+ # Check the condition.
+ my ($cond, $block) = @{$chunks[0]};
+ #print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+ if (defined $cond) {
+ substr($block, 0, length($cond), '');
+ }
+ if (statement_lines($cond) > 1) {
+ #print "APW: ALLOWED: cond<$cond>\n";
+ $allowed = 1;
+ }
+ if ($block =~/\b(?:if|for|while)\b/) {
+ #print "APW: ALLOWED: block<$block>\n";
+ $allowed = 1;
+ }
+ if (statement_block_size($block) > 1) {
+ #print "APW: ALLOWED: lines block<$block>\n";
+ $allowed = 1;
+ }
+ # Check the post-context.
+ if (defined $chunks[1]) {
+ my ($cond, $block) = @{$chunks[1]};
+ if (defined $cond) {
+ substr($block, 0, length($cond), '');
+ }
+ if ($block =~ /^\s*\{/) {
+ #print "APW: ALLOWED: chunk-1 block<$block>\n";
+ $allowed = 1;
+ }
+ }
+ if ($level == 0 && $block !~ /^\s*\{/ && !$allowed) {
+ my $herectx = $here . "\n";;
+ my $cnt = statement_rawlines($block);
+
+ for (my $n = 0; $n < $cnt; $n++) {
+ $herectx .= raw_line($linenr, $n) . "\n";;
+ }
+
+ WARN("braces {} are necessary even for single statement blocks\n" . $herectx);
+ }
+ }
+
+# don't include deprecated include files (uses RAW line)
+ for my $inc (@dep_includes) {
+ if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) {
+ ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr);
+ }
+ }
+
+# don't use deprecated functions
+ for my $func (@dep_functions) {
+ if ($line =~ /\b$func\b/) {
+ ERROR("Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr);
+ }
+ }
+
+# no volatiles please
+ my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
+ if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
+ WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
+ }
+
+# SPIN_LOCK_UNLOCKED & RW_LOCK_UNLOCKED are deprecated
+ if ($line =~ /\b(SPIN_LOCK_UNLOCKED|RW_LOCK_UNLOCKED)/) {
+ ERROR("Use of $1 is deprecated: see Documentation/spinlocks.txt\n" . $herecurr);
+ }
+
+# warn about #if 0
+ if ($line =~ /^.\s*\#\s*if\s+0\b/) {
+ CHK("if this code is redundant consider removing it\n" .
+ $herecurr);
+ }
+
+# check for needless kfree() checks
+ if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+ my $expr = $1;
+ if ($line =~ /\bkfree\(\Q$expr\E\);/) {
+ WARN("kfree(NULL) is safe this check is probably not required\n" . $hereprev);
+ }
+ }
+# check for needless usb_free_urb() checks
+ if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+ my $expr = $1;
+ if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) {
+ WARN("usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev);
+ }
+ }
+
+# prefer usleep_range over udelay
+ if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) {
+ # ignore udelay's < 10, however
+ if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) {
+ CHK("usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line);
+ }
+ }
+
+# warn about unexpectedly long msleep's
+ if ($line =~ /\bmsleep\s*\((\d+)\);/) {
+ if ($1 < 20) {
+ WARN("msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line);
+ }
+ }
+
+# warn about #ifdefs in C files
+# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
+# print "#ifdef in C files should be avoided\n";
+# print "$herecurr";
+# $clean = 0;
+# }
+
+# warn about spacing in #ifdefs
+ if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
+ ERROR("exactly one space required after that #$1\n" . $herecurr);
+ }
+
+# check for spinlock_t definitions without a comment.
+ if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
+ $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
+ my $which = $1;
+ if (!ctx_has_comment($first_line, $linenr)) {
+ CHK("$1 definition without comment\n" . $herecurr);
+ }
+ }
+# check for memory barriers without a comment.
+ if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+ if (!ctx_has_comment($first_line, $linenr)) {
+ CHK("memory barrier without comment\n" . $herecurr);
+ }
+ }
+# check of hardware specific defines
+ if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
+ CHK("architecture specific defines should be avoided\n" . $herecurr);
+ }
+
+# Check that the storage class is at the beginning of a declaration
+ if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
+ WARN("storage class should be at the beginning of the declaration\n" . $herecurr)
+ }
+
+# check the location of the inline attribute, that it is between
+# storage class and type.
+ if ($line =~ /\b$Type\s+$Inline\b/ ||
+ $line =~ /\b$Inline\s+$Storage\b/) {
+ ERROR("inline keyword should sit between storage class and type\n" . $herecurr);
+ }
+
+# Check for __inline__ and __inline, prefer inline
+ if ($line =~ /\b(__inline__|__inline)\b/) {
+ WARN("plain inline is preferred over $1\n" . $herecurr);
+ }
+
+# check for sizeof(&)
+ if ($line =~ /\bsizeof\s*\(\s*\&/) {
+ WARN("sizeof(& should be avoided\n" . $herecurr);
+ }
+
+# check for new externs in .c files.
+ if ($realfile =~ /\.c$/ && defined $stat &&
+ $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
+ {
+ my $function_name = $1;
+ my $paren_space = $2;
+
+ my $s = $stat;
+ if (defined $cond) {
+ substr($s, 0, length($cond), '');
+ }
+ if ($s =~ /^\s*;/ &&
+ $function_name ne 'uninitialized_var')
+ {
+ WARN("externs should be avoided in .c files\n" . $herecurr);
+ }
+
+ if ($paren_space =~ /\n/) {
+ WARN("arguments for function declarations should follow identifier\n" . $herecurr);
+ }
+
+ } elsif ($realfile =~ /\.c$/ && defined $stat &&
+ $stat =~ /^.\s*extern\s+/)
+ {
+ WARN("externs should be avoided in .c files\n" . $herecurr);
+ }
+
+# checks for new __setup's
+ if ($rawline =~ /\b__setup\("([^"]*)"/) {
+ my $name = $1;
+
+ if (!grep(/$name/, @setup_docs)) {
+ CHK("__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
+ }
+ }
+
+# check for pointless casting of kmalloc return
+ if ($line =~ /\*\s*\)\s*k[czm]alloc\b/) {
+ WARN("unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
+ }
+
+# check for gcc specific __FUNCTION__
+ if ($line =~ /__FUNCTION__/) {
+ WARN("__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr);
+ }
+
+# check for semaphores used as mutexes
+ if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
+ WARN("mutexes are preferred for single holder semaphores\n" . $herecurr);
+ }
+# check for semaphores used as mutexes
+ if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) {
+ WARN("consider using a completion\n" . $herecurr);
+
+ }
+# recommend strict_strto* over simple_strto*
+ if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
+ WARN("consider using strict_$1 in preference to simple_$1\n" . $herecurr);
+ }
+# check for __initcall(), use device_initcall() explicitly please
+ if ($line =~ /^.\s*__initcall\s*\(/) {
+ WARN("please use device_initcall() instead of __initcall()\n" . $herecurr);
+ }
+# check for various ops structs, ensure they are const.
+ my $struct_ops = qr{acpi_dock_ops|
+ address_space_operations|
+ backlight_ops|
+ block_device_operations|
+ dentry_operations|
+ dev_pm_ops|
+ dma_map_ops|
+ extent_io_ops|
+ file_lock_operations|
+ file_operations|
+ hv_ops|
+ ide_dma_ops|
+ intel_dvo_dev_ops|
+ item_operations|
+ iwl_ops|
+ kgdb_arch|
+ kgdb_io|
+ kset_uevent_ops|
+ lock_manager_operations|
+ microcode_ops|
+ mtrr_ops|
+ neigh_ops|
+ nlmsvc_binding|
+ pci_raw_ops|
+ pipe_buf_operations|
+ platform_hibernation_ops|
+ platform_suspend_ops|
+ proto_ops|
+ rpc_pipe_ops|
+ seq_operations|
+ snd_ac97_build_ops|
+ soc_pcmcia_socket_ops|
+ stacktrace_ops|
+ sysfs_ops|
+ tty_operations|
+ usb_mon_operations|
+ wd_ops}x;
+ if ($line !~ /\bconst\b/ &&
+ $line =~ /\bstruct\s+($struct_ops)\b/) {
+ WARN("struct $1 should normally be const\n" .
+ $herecurr);
+ }
+
+# use of NR_CPUS is usually wrong
+# ignore definitions of NR_CPUS and usage to define arrays as likely right
+ if ($line =~ /\bNR_CPUS\b/ &&
+ $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
+ $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
+ $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
+ $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
+ $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
+ {
+ WARN("usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
+ }
+
+# check for %L{u,d,i} in strings
+ my $string;
+ while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
+ $string = substr($rawline, $-[1], $+[1] - $-[1]);
+ $string =~ s/%%/__/g;
+ if ($string =~ /(?<!%)%L[udi]/) {
+ WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
+ last;
+ }
+ }
+
+# whine mightly about in_atomic
+ if ($line =~ /\bin_atomic\s*\(/) {
+ if ($realfile =~ m@^drivers/@) {
+ ERROR("do not use in_atomic in drivers\n" . $herecurr);
+ } elsif ($realfile !~ m@^kernel/@) {
+ WARN("use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
+ }
+ }
+
+# check for lockdep_set_novalidate_class
+ if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
+ $line =~ /__lockdep_no_validate__\s*\)/ ) {
+ if ($realfile !~ m@^kernel/lockdep@ &&
+ $realfile !~ m@^include/linux/lockdep@ &&
+ $realfile !~ m@^drivers/base/core@) {
+ ERROR("lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr);
+ }
+ }
+ }
+
+ # If we have no input at all, then there is nothing to report on
+ # so just keep quiet.
+ if ($#rawlines == -1) {
+ exit(0);
+ }
+
+ # In mailback mode only produce a report in the negative, for
+ # things that appear to be patches.
+ if ($mailback && ($clean == 1 || !$is_patch)) {
+ exit(0);
+ }
+
+ # This is not a patch, and we are are in 'no-patch' mode so
+ # just keep quiet.
+ if (!$chk_patch && !$is_patch) {
+ exit(0);
+ }
+
+ if (!$is_patch) {
+ ERROR("Does not appear to be a unified-diff format patch\n");
+ }
+ if ($is_patch && $chk_signoff && $signoff == 0) {
+ ERROR("Missing Signed-off-by: line(s)\n");
+ }
+
+ print report_dump();
+ if ($summary && !($clean == 1 && $quiet == 1)) {
+ print "$filename " if ($summary_file);
+ print "total: $cnt_error errors, $cnt_warn warnings, " .
+ (($check)? "$cnt_chk checks, " : "") .
+ "$cnt_lines lines checked\n";
+ print "\n" if ($quiet == 0);
+ }
+
+ if ($quiet == 0) {
+ # If there were whitespace errors which cleanpatch can fix
+ # then suggest that.
+# if ($rpt_cleaners) {
+# print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n";
+# print " scripts/cleanfile\n\n";
+# }
+ }
+
+ if ($clean == 1 && $quiet == 0) {
+ print "$vname has no obvious style problems and is ready for submission.\n"
+ }
+ if ($clean == 0 && $quiet == 0) {
+ print "$vname has style problems, please review. If any of these errors\n";
+ print "are false positives report them to the maintainer, see\n";
+ print "CHECKPATCH in MAINTAINERS.\n";
+ }
+
+ return $clean;
+}
diff --git a/create_config b/scripts/create_config
index 0098e683e2..0098e683e2 100755
--- a/create_config
+++ b/scripts/create_config
diff --git a/feature_to_c.sh b/scripts/feature_to_c.sh
index 0994d9546e..0994d9546e 100644
--- a/feature_to_c.sh
+++ b/scripts/feature_to_c.sh
diff --git a/hxtool b/scripts/hxtool
index 7ca83ed1ff..7ca83ed1ff 100644
--- a/hxtool
+++ b/scripts/hxtool
diff --git a/make_device_config.sh b/scripts/make_device_config.sh
index 596fc5bf69..5d14885dfc 100644
--- a/make_device_config.sh
+++ b/scripts/make_device_config.sh
@@ -18,7 +18,7 @@ process_includes () {
f=$src
while [ -n "$f" ] ; do
- f=`tr -d '\r' < $f | awk '/^include / {ORS=" "; print "'$src_dir'/" $2}'`
+ f=`tr -d '\r' < $f | awk '/^include / {printf "'$src_dir'/%s", $2}'`
[ $? = 0 ] || exit 1
all_includes="$all_includes $f"
done
diff --git a/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh
index c50beb7337..c50beb7337 100644
--- a/qemu-binfmt-conf.sh
+++ b/scripts/qemu-binfmt-conf.sh
diff --git a/pc-bios/optionrom/signrom.sh b/scripts/signrom.sh
index 9dc5c63dde..9dc5c63dde 100755
--- a/pc-bios/optionrom/signrom.sh
+++ b/scripts/signrom.sh
diff --git a/simpletrace.py b/scripts/simpletrace.py
index 553a72709f..553a72709f 100755
--- a/simpletrace.py
+++ b/scripts/simpletrace.py
diff --git a/texi2pod.pl b/scripts/texi2pod.pl
index 9ed056ad1c..9ed056ad1c 100755
--- a/texi2pod.pl
+++ b/scripts/texi2pod.pl
diff --git a/tracetool b/scripts/tracetool
index fce491c505..fce491c505 100755
--- a/tracetool
+++ b/scripts/tracetool
diff --git a/slirp/tftp.c b/slirp/tftp.c
index 55e4692acc..1821648251 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -311,7 +311,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
return;
}
- if (memcmp(&tp->x.tp_buf[k], "octet\0", 6) != 0) {
+ if (strcasecmp((const char *)&tp->x.tp_buf[k], "octet") != 0) {
tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
return;
}
@@ -351,7 +351,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
value = (const char *)&tp->x.tp_buf[k];
k += strlen(value) + 1;
- if (strcmp(key, "tsize") == 0) {
+ if (strcasecmp(key, "tsize") == 0) {
int tsize = atoi(value);
struct stat stat_p;
diff --git a/sysemu.h b/sysemu.h
index d8fceec806..0c969f22b9 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -75,6 +75,7 @@ void qemu_announce_self(void);
void main_loop_wait(int nonblocking);
+bool qemu_savevm_state_blocked(Monitor *mon);
int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
int shared);
int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 340933ef50..5bcd53ac73 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -173,7 +173,20 @@ typedef struct CPUARMState {
/* scratch space when Tn are not sufficient. */
uint32_t scratch[8];
+ /* fp_status is the "normal" fp status. standard_fp_status retains
+ * values corresponding to the ARM "Standard FPSCR Value", ie
+ * default-NaN, flush-to-zero, round-to-nearest and is used by
+ * any operations (generally Neon) which the architecture defines
+ * as controlled by the standard FPSCR value rather than the FPSCR.
+ *
+ * To avoid having to transfer exception bits around, we simply
+ * say that the FPSCR cumulative exception flags are the logical
+ * OR of the flags in the two fp statuses. This relies on the
+ * only thing which needs to read the exception flags being
+ * an explicit FPSCR read.
+ */
float_status fp_status;
+ float_status standard_fp_status;
} vfp;
uint32_t exclusive_addr;
uint32_t exclusive_val;
@@ -440,17 +453,56 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
#include "cpu-all.h"
+/* Bit usage in the TB flags field: */
+#define ARM_TBFLAG_THUMB_SHIFT 0
+#define ARM_TBFLAG_THUMB_MASK (1 << ARM_TBFLAG_THUMB_SHIFT)
+#define ARM_TBFLAG_VECLEN_SHIFT 1
+#define ARM_TBFLAG_VECLEN_MASK (0x7 << ARM_TBFLAG_VECLEN_SHIFT)
+#define ARM_TBFLAG_VECSTRIDE_SHIFT 4
+#define ARM_TBFLAG_VECSTRIDE_MASK (0x3 << ARM_TBFLAG_VECSTRIDE_SHIFT)
+#define ARM_TBFLAG_PRIV_SHIFT 6
+#define ARM_TBFLAG_PRIV_MASK (1 << ARM_TBFLAG_PRIV_SHIFT)
+#define ARM_TBFLAG_VFPEN_SHIFT 7
+#define ARM_TBFLAG_VFPEN_MASK (1 << ARM_TBFLAG_VFPEN_SHIFT)
+#define ARM_TBFLAG_CONDEXEC_SHIFT 8
+#define ARM_TBFLAG_CONDEXEC_MASK (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
+/* Bits 31..16 are currently unused. */
+
+/* some convenience accessor macros */
+#define ARM_TBFLAG_THUMB(F) \
+ (((F) & ARM_TBFLAG_THUMB_MASK) >> ARM_TBFLAG_THUMB_SHIFT)
+#define ARM_TBFLAG_VECLEN(F) \
+ (((F) & ARM_TBFLAG_VECLEN_MASK) >> ARM_TBFLAG_VECLEN_SHIFT)
+#define ARM_TBFLAG_VECSTRIDE(F) \
+ (((F) & ARM_TBFLAG_VECSTRIDE_MASK) >> ARM_TBFLAG_VECSTRIDE_SHIFT)
+#define ARM_TBFLAG_PRIV(F) \
+ (((F) & ARM_TBFLAG_PRIV_MASK) >> ARM_TBFLAG_PRIV_SHIFT)
+#define ARM_TBFLAG_VFPEN(F) \
+ (((F) & ARM_TBFLAG_VFPEN_MASK) >> ARM_TBFLAG_VFPEN_SHIFT)
+#define ARM_TBFLAG_CONDEXEC(F) \
+ (((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
+
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
+ int privmode;
*pc = env->regs[15];
*cs_base = 0;
- *flags = env->thumb | (env->vfp.vec_len << 1)
- | (env->vfp.vec_stride << 4) | (env->condexec_bits << 8);
- if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
- *flags |= (1 << 6);
- if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
- *flags |= (1 << 7);
+ *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
+ | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
+ | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
+ | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT);
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
+ } else {
+ privmode = (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR;
+ }
+ if (privmode) {
+ *flags |= ARM_TBFLAG_PRIV_MASK;
+ }
+ if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
+ *flags |= ARM_TBFLAG_VFPEN_MASK;
+ }
}
#endif
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 705b99f9cb..b562767279 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -237,6 +237,9 @@ void cpu_reset(CPUARMState *env)
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
env->cp15.c2_base_mask = 0xffffc000u;
#endif
+ set_flush_to_zero(1, &env->vfp.standard_fp_status);
+ set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
+ set_default_nan_mode(1, &env->vfp.standard_fp_status);
tlb_flush(env, 1);
}
@@ -1846,12 +1849,20 @@ bad_reg:
void HELPER(set_r13_banked)(CPUState *env, uint32_t mode, uint32_t val)
{
- env->banked_r13[bank_number(mode)] = val;
+ if ((env->uncached_cpsr & CPSR_M) == mode) {
+ env->regs[13] = val;
+ } else {
+ env->banked_r13[bank_number(mode)] = val;
+ }
}
uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode)
{
- return env->banked_r13[bank_number(mode)];
+ if ((env->uncached_cpsr & CPSR_M) == mode) {
+ return env->regs[13];
+ } else {
+ return env->banked_r13[bank_number(mode)];
+ }
}
uint32_t HELPER(v7m_mrs)(CPUState *env, uint32_t reg)
@@ -2256,6 +2267,7 @@ uint32_t HELPER(vfp_get_fpscr)(CPUState *env)
| (env->vfp.vec_len << 16)
| (env->vfp.vec_stride << 20);
i = get_float_exception_flags(&env->vfp.fp_status);
+ i |= get_float_exception_flags(&env->vfp.standard_fp_status);
fpscr |= vfp_exceptbits_from_host(i);
return fpscr;
}
@@ -2323,6 +2335,7 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
i = vfp_exceptbits_to_host(val);
set_float_exception_flags(i, &env->vfp.fp_status);
+ set_float_exception_flags(0, &env->vfp.standard_fp_status);
}
void vfp_set_fpscr(CPUState *env, uint32_t val)
@@ -2611,9 +2624,17 @@ float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env)
float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env)
{
- float_status *s = &env->vfp.fp_status;
+ float_status *s = &env->vfp.standard_fp_status;
+ float32 two = int32_to_float32(2, s);
float32 three = int32_to_float32(3, s);
- return float32_sub(three, float32_mul(a, b, s), s);
+ float32 product;
+ if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) ||
+ (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) {
+ product = float32_zero;
+ } else {
+ product = float32_mul(a, b, s);
+ }
+ return float32_div(float32_sub(three, product, s), two, s);
}
/* NEON helpers. */
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index 0d1bc47d00..b88ebaecc6 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -249,6 +249,10 @@ DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32)
DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32)
DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64)
DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qshlu_s8, i32, env, i32, i32);
+DEF_HELPER_3(neon_qshlu_s16, i32, env, i32, i32);
+DEF_HELPER_3(neon_qshlu_s32, i32, env, i32, i32);
+DEF_HELPER_3(neon_qshlu_s64, i64, env, i64, i64);
DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32)
DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32)
DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32)
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index dae063ea1a..20f3c162cd 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -632,6 +632,53 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
return val;
}
+#define NEON_FN(dest, src1, src2) do { \
+ if (src1 & (1 << (sizeof(src1) * 8 - 1))) { \
+ SET_QC(); \
+ dest = 0; \
+ } else { \
+ int8_t tmp; \
+ tmp = (int8_t)src2; \
+ if (tmp >= (ssize_t)sizeof(src1) * 8) { \
+ if (src1) { \
+ SET_QC(); \
+ dest = ~0; \
+ } else { \
+ dest = 0; \
+ } \
+ } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
+ dest = 0; \
+ } else if (tmp < 0) { \
+ dest = src1 >> -tmp; \
+ } else { \
+ dest = src1 << tmp; \
+ if ((dest >> tmp) != src1) { \
+ SET_QC(); \
+ dest = ~0; \
+ } \
+ } \
+ }} while (0)
+NEON_VOP_ENV(qshlu_s8, neon_u8, 4)
+NEON_VOP_ENV(qshlu_s16, neon_u16, 2)
+#undef NEON_FN
+
+uint32_t HELPER(neon_qshlu_s32)(CPUState *env, uint32_t valop, uint32_t shiftop)
+{
+ if ((int32_t)valop < 0) {
+ SET_QC();
+ return 0;
+ }
+ return helper_neon_qshl_u32(env, valop, shiftop);
+}
+
+uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
+{
+ if ((int64_t)valop < 0) {
+ SET_QC();
+ return 0;
+ }
+ return helper_neon_qshl_u64(env, valop, shiftop);
+}
/* FIXME: This is wrong. */
#define NEON_FN(dest, src1, src2) do { \
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 2ce82f3bbb..c60cd18e1e 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -59,8 +59,13 @@ typedef struct DisasContext {
#if !defined(CONFIG_USER_ONLY)
int user;
#endif
+ int vfp_enabled;
+ int vec_len;
+ int vec_stride;
} DisasContext;
+static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
+
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#else
@@ -2603,12 +2608,6 @@ static void gen_vfp_msr(TCGv tmp)
dead_tmp(tmp);
}
-static inline int
-vfp_enabled(CPUState * env)
-{
- return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0);
-}
-
static void gen_neon_dup_u8(TCGv var, int shift)
{
TCGv tmp = new_tmp();
@@ -2653,7 +2652,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (!arm_feature(env, ARM_FEATURE_VFP))
return 1;
- if (!vfp_enabled(env)) {
+ if (!s->vfp_enabled) {
/* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */
if ((insn & 0x0fe00fff) != 0x0ee00a10)
return 1;
@@ -2900,7 +2899,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
rm = VFP_SREG_M(insn);
}
- veclen = env->vfp.vec_len;
+ veclen = s->vec_len;
if (op == 15 && rn > 3)
veclen = 0;
@@ -2921,9 +2920,9 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
veclen = 0;
} else {
if (dp)
- delta_d = (env->vfp.vec_stride >> 1) + 1;
+ delta_d = (s->vec_stride >> 1) + 1;
else
- delta_d = env->vfp.vec_stride + 1;
+ delta_d = s->vec_stride + 1;
if ((rm & bank_mask) == 0) {
/* mixed scalar/vector */
@@ -3488,6 +3487,14 @@ gen_set_condexec (DisasContext *s)
}
}
+static void gen_exception_insn(DisasContext *s, int offset, int excp)
+{
+ gen_set_condexec(s);
+ gen_set_pc_im(s->pc - offset);
+ gen_exception(excp);
+ s->is_jmp = DISAS_JUMP;
+}
+
static void gen_nop_hint(DisasContext *s, int val)
{
switch (val) {
@@ -3804,7 +3811,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
TCGv tmp2;
TCGv_i64 tmp64;
- if (!vfp_enabled(env))
+ if (!s->vfp_enabled)
return 1;
VFP_DREG_D(rd, insn);
rn = (insn >> 16) & 0xf;
@@ -4199,7 +4206,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
TCGv tmp, tmp2, tmp3, tmp4, tmp5;
TCGv_i64 tmp64;
- if (!vfp_enabled(env))
+ if (!s->vfp_enabled)
return 1;
q = (insn & (1 << 6)) != 0;
u = (insn >> 24) & 1;
@@ -4652,14 +4659,22 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 5: /* VSHL, VSLI */
gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
break;
- case 6: /* VQSHL */
- if (u)
- gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
- else
- gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
+ case 6: /* VQSHLU */
+ if (u) {
+ gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
+ cpu_V0, cpu_V1);
+ } else {
+ return 1;
+ }
break;
- case 7: /* VQSHLU */
- gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
+ case 7: /* VQSHL */
+ if (u) {
+ gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
+ cpu_V0, cpu_V1);
+ } else {
+ gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
+ cpu_V0, cpu_V1);
+ }
break;
}
if (op == 1 || op == 3) {
@@ -4698,17 +4713,30 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
default: return 1;
}
break;
- case 6: /* VQSHL */
- GEN_NEON_INTEGER_OP_ENV(qshl);
- break;
- case 7: /* VQSHLU */
+ case 6: /* VQSHLU */
+ if (!u) {
+ return 1;
+ }
switch (size) {
- case 0: gen_helper_neon_qshl_u8(tmp, cpu_env, tmp, tmp2); break;
- case 1: gen_helper_neon_qshl_u16(tmp, cpu_env, tmp, tmp2); break;
- case 2: gen_helper_neon_qshl_u32(tmp, cpu_env, tmp, tmp2); break;
- default: return 1;
+ case 0:
+ gen_helper_neon_qshlu_s8(tmp, cpu_env,
+ tmp, tmp2);
+ break;
+ case 1:
+ gen_helper_neon_qshlu_s16(tmp, cpu_env,
+ tmp, tmp2);
+ break;
+ case 2:
+ gen_helper_neon_qshlu_s32(tmp, cpu_env,
+ tmp, tmp2);
+ break;
+ default:
+ return 1;
}
break;
+ case 7: /* VQSHL */
+ GEN_NEON_INTEGER_OP_ENV(qshl);
+ break;
}
dead_tmp(tmp2);
@@ -5958,10 +5986,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
tcg_gen_mov_i32(cpu_exclusive_test, addr);
tcg_gen_movi_i32(cpu_exclusive_info,
size | (rd << 4) | (rt << 8) | (rt2 << 12));
- gen_set_condexec(s);
- gen_set_pc_im(s->pc - 4);
- gen_exception(EXCP_STREX);
- s->is_jmp = DISAS_JUMP;
+ gen_exception_insn(s, 4, EXCP_STREX);
}
#else
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
@@ -6101,14 +6126,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
goto illegal_op;
ARCH(6);
op1 = (insn & 0x1f);
- if (op1 == (env->uncached_cpsr & CPSR_M)) {
- addr = load_reg(s, 13);
- } else {
- addr = new_tmp();
- tmp = tcg_const_i32(op1);
- gen_helper_get_r13_banked(addr, cpu_env, tmp);
- tcg_temp_free_i32(tmp);
- }
+ addr = new_tmp();
+ tmp = tcg_const_i32(op1);
+ gen_helper_get_r13_banked(addr, cpu_env, tmp);
+ tcg_temp_free_i32(tmp);
i = (insn >> 23) & 3;
switch (i) {
case 0: offset = -4; break; /* DA */
@@ -6135,14 +6156,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
}
if (offset)
tcg_gen_addi_i32(addr, addr, offset);
- if (op1 == (env->uncached_cpsr & CPSR_M)) {
- store_reg(s, 13, addr);
- } else {
- tmp = tcg_const_i32(op1);
- gen_helper_set_r13_banked(cpu_env, tmp, addr);
- tcg_temp_free_i32(tmp);
- dead_tmp(addr);
- }
+ tmp = tcg_const_i32(op1);
+ gen_helper_set_r13_banked(cpu_env, tmp, addr);
+ tcg_temp_free_i32(tmp);
+ dead_tmp(addr);
} else {
dead_tmp(addr);
}
@@ -6366,10 +6383,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
goto illegal_op;
}
/* bkpt */
- gen_set_condexec(s);
- gen_set_pc_im(s->pc - 4);
- gen_exception(EXCP_BKPT);
- s->is_jmp = DISAS_JUMP;
+ gen_exception_insn(s, 4, EXCP_BKPT);
break;
case 0x8: /* signed multiply */
case 0xa:
@@ -7268,10 +7282,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
break;
default:
illegal_op:
- gen_set_condexec(s);
- gen_set_pc_im(s->pc - 4);
- gen_exception(EXCP_UDEF);
- s->is_jmp = DISAS_JUMP;
+ gen_exception_insn(s, 4, EXCP_UDEF);
break;
}
}
@@ -7554,14 +7565,10 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
} else {
/* srs */
op = (insn & 0x1f);
- if (op == (env->uncached_cpsr & CPSR_M)) {
- addr = load_reg(s, 13);
- } else {
- addr = new_tmp();
- tmp = tcg_const_i32(op);
- gen_helper_get_r13_banked(addr, cpu_env, tmp);
- tcg_temp_free_i32(tmp);
- }
+ addr = new_tmp();
+ tmp = tcg_const_i32(op);
+ gen_helper_get_r13_banked(addr, cpu_env, tmp);
+ tcg_temp_free_i32(tmp);
if ((insn & (1 << 24)) == 0) {
tcg_gen_addi_i32(addr, addr, -8);
}
@@ -7577,13 +7584,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
} else {
tcg_gen_addi_i32(addr, addr, 4);
}
- if (op == (env->uncached_cpsr & CPSR_M)) {
- store_reg(s, 13, addr);
- } else {
- tmp = tcg_const_i32(op);
- gen_helper_set_r13_banked(cpu_env, tmp, addr);
- tcg_temp_free_i32(tmp);
- }
+ tmp = tcg_const_i32(op);
+ gen_helper_set_r13_banked(cpu_env, tmp, addr);
+ tcg_temp_free_i32(tmp);
} else {
dead_tmp(addr);
}
@@ -8925,10 +8928,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
break;
case 0xe: /* bkpt */
- gen_set_condexec(s);
- gen_set_pc_im(s->pc - 2);
- gen_exception(EXCP_BKPT);
- s->is_jmp = DISAS_JUMP;
+ gen_exception_insn(s, 2, EXCP_BKPT);
break;
case 0xa: /* rev */
@@ -9014,7 +9014,6 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
if (cond == 0xf) {
/* swi */
- gen_set_condexec(s);
gen_set_pc_im(s->pc);
s->is_jmp = DISAS_SWI;
break;
@@ -9051,17 +9050,11 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
}
return;
undef32:
- gen_set_condexec(s);
- gen_set_pc_im(s->pc - 4);
- gen_exception(EXCP_UDEF);
- s->is_jmp = DISAS_JUMP;
+ gen_exception_insn(s, 4, EXCP_UDEF);
return;
illegal_op:
undef:
- gen_set_condexec(s);
- gen_set_pc_im(s->pc - 2);
- gen_exception(EXCP_UDEF);
- s->is_jmp = DISAS_JUMP;
+ gen_exception_insn(s, 2, EXCP_UDEF);
}
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
@@ -9093,16 +9086,15 @@ static inline void gen_intermediate_code_internal(CPUState *env,
dc->pc = pc_start;
dc->singlestep_enabled = env->singlestep_enabled;
dc->condjmp = 0;
- dc->thumb = env->thumb;
- dc->condexec_mask = (env->condexec_bits & 0xf) << 1;
- dc->condexec_cond = env->condexec_bits >> 4;
+ dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
+ dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
+ dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
#if !defined(CONFIG_USER_ONLY)
- if (IS_M(env)) {
- dc->user = ((env->v7m.exception == 0) && (env->v7m.control & 1));
- } else {
- dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
- }
+ dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
#endif
+ dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
+ dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
+ dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
cpu_F0s = tcg_temp_new_i32();
cpu_F1s = tcg_temp_new_i32();
cpu_F0d = tcg_temp_new_i64();
@@ -9119,9 +9111,41 @@ static inline void gen_intermediate_code_internal(CPUState *env,
max_insns = CF_COUNT_MASK;
gen_icount_start();
+
+ /* A note on handling of the condexec (IT) bits:
+ *
+ * We want to avoid the overhead of having to write the updated condexec
+ * bits back to the CPUState for every instruction in an IT block. So:
+ * (1) if the condexec bits are not already zero then we write
+ * zero back into the CPUState now. This avoids complications trying
+ * to do it at the end of the block. (For example if we don't do this
+ * it's hard to identify whether we can safely skip writing condexec
+ * at the end of the TB, which we definitely want to do for the case
+ * where a TB doesn't do anything with the IT state at all.)
+ * (2) if we are going to leave the TB then we call gen_set_condexec()
+ * which will write the correct value into CPUState if zero is wrong.
+ * This is done both for leaving the TB at the end, and for leaving
+ * it because of an exception we know will happen, which is done in
+ * gen_exception_insn(). The latter is necessary because we need to
+ * leave the TB with the PC/IT state just prior to execution of the
+ * instruction which caused the exception.
+ * (3) if we leave the TB unexpectedly (eg a data abort on a load)
+ * then the CPUState will be wrong and we need to reset it.
+ * This is handled in the same way as restoration of the
+ * PC in these situations: we will be called again with search_pc=1
+ * and generate a mapping of the condexec bits for each PC in
+ * gen_opc_condexec_bits[]. gen_pc_load[] then uses this to restore
+ * the condexec bits.
+ *
+ * Note that there are no instructions which can read the condexec
+ * bits, and none which can write non-static values to them, so
+ * we don't need to care about whether CPUState is correct in the
+ * middle of a TB.
+ */
+
/* Reset the conditional execution bits immediately. This avoids
complications trying to do it at the end of the block. */
- if (env->condexec_bits)
+ if (dc->condexec_mask || dc->condexec_cond)
{
TCGv tmp = new_tmp();
tcg_gen_movi_i32(tmp, 0);
@@ -9150,10 +9174,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == dc->pc) {
- gen_set_condexec(dc);
- gen_set_pc_im(dc->pc);
- gen_exception(EXCP_DEBUG);
- dc->is_jmp = DISAS_JUMP;
+ gen_exception_insn(dc, 0, EXCP_DEBUG);
/* Advance PC so that clearing the breakpoint will
invalidate this TB. */
dc->pc += 2;
@@ -9170,6 +9191,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
gen_opc_instr_start[lj++] = 0;
}
gen_opc_pc[lj] = dc->pc;
+ gen_opc_condexec_bits[lj] = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
gen_opc_instr_start[lj] = 1;
gen_opc_icount[lj] = num_insns;
}
@@ -9177,7 +9199,11 @@ static inline void gen_intermediate_code_internal(CPUState *env,
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
- if (env->thumb) {
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+ tcg_gen_debug_insn_start(dc->pc);
+ }
+
+ if (dc->thumb) {
disas_thumb_insn(env, dc);
if (dc->condexec_mask) {
dc->condexec_cond = (dc->condexec_cond & 0xe)
@@ -9291,7 +9317,7 @@ done_generating:
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("----------------\n");
qemu_log("IN: %s\n", lookup_symbol(pc_start));
- log_target_disas(pc_start, dc->pc - pc_start, env->thumb);
+ log_target_disas(pc_start, dc->pc - pc_start, dc->thumb);
qemu_log("\n");
}
#endif
@@ -9377,4 +9403,5 @@ void gen_pc_load(CPUState *env, TranslationBlock *tb,
unsigned long searched_pc, int pc_pos, void *puc)
{
env->regs[15] = gen_opc_pc[pc_pos];
+ env->condexec_bits = gen_opc_condexec_bits[pc_pos];
}
diff --git a/target-cris/translate.c b/target-cris/translate.c
index e09aaa9e9d..f4cc1252a5 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -1129,6 +1129,9 @@ static void cris_store_direct_jmp(DisasContext *dc)
{
/* Store the direct jmp state into the cpu-state. */
if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
+ if (dc->jmp == JMP_DIRECT) {
+ tcg_gen_movi_tl(env_btaken, 1);
+ }
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
dc->jmp = JMP_INDIRECT;
}
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 7b6e3c2eae..c00845038a 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -274,28 +274,16 @@ static inline void gen_op_andl_A0_ffff(void)
static inline void gen_op_mov_reg_v(int ot, int reg, TCGv t0)
{
- TCGv tmp;
-
switch(ot) {
case OT_BYTE:
- tmp = tcg_temp_new();
- tcg_gen_ext8u_tl(tmp, t0);
if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) {
- tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xff);
- tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
+ tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 8);
} else {
- tcg_gen_shli_tl(tmp, tmp, 8);
- tcg_gen_andi_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], ~0xff00);
- tcg_gen_or_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], tmp);
+ tcg_gen_deposit_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], t0, 8, 8);
}
- tcg_temp_free(tmp);
break;
case OT_WORD:
- tmp = tcg_temp_new();
- tcg_gen_ext16u_tl(tmp, t0);
- tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
- tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
- tcg_temp_free(tmp);
+ tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 16);
break;
default: /* XXX this shouldn't be reached; abort? */
case OT_LONG:
@@ -323,15 +311,9 @@ static inline void gen_op_mov_reg_T1(int ot, int reg)
static inline void gen_op_mov_reg_A0(int size, int reg)
{
- TCGv tmp;
-
switch(size) {
case 0:
- tmp = tcg_temp_new();
- tcg_gen_ext16u_tl(tmp, cpu_A0);
- tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
- tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
- tcg_temp_free(tmp);
+ tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_A0, 0, 16);
break;
default: /* XXX this shouldn't be reached; abort? */
case 1:
@@ -415,9 +397,7 @@ static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
switch(size) {
case 0:
tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
- tcg_gen_ext16u_tl(cpu_tmp0, cpu_tmp0);
- tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
- tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0);
+ tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16);
break;
case 1:
tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
@@ -439,9 +419,7 @@ static inline void gen_op_add_reg_T0(int size, int reg)
switch(size) {
case 0:
tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
- tcg_gen_ext16u_tl(cpu_tmp0, cpu_tmp0);
- tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
- tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0);
+ tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16);
break;
case 1:
tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index c018c99826..4b6ae068ce 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -78,9 +78,10 @@ typedef struct DisasContext {
unsigned int clear_imm;
int is_jmp;
-#define JMP_NOJMP 0
-#define JMP_DIRECT 1
-#define JMP_INDIRECT 2
+#define JMP_NOJMP 0
+#define JMP_DIRECT 1
+#define JMP_DIRECT_CC 2
+#define JMP_INDIRECT 3
unsigned int jmp;
uint32_t jmp_pc;
@@ -751,7 +752,10 @@ static void dec_bit(DisasContext *dc)
static inline void sync_jmpstate(DisasContext *dc)
{
- if (dc->jmp == JMP_DIRECT) {
+ if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
+ if (dc->jmp == JMP_DIRECT) {
+ tcg_gen_movi_tl(env_btaken, 1);
+ }
dc->jmp = JMP_INDIRECT;
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
}
@@ -784,7 +788,7 @@ static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
{
unsigned int extimm = dc->tb_flags & IMM_FLAG;
- /* Treat the fast cases first. */
+ /* Treat the common cases first. */
if (!dc->type_b) {
/* If any of the regs is r0, return a ptr to the other. */
if (dc->ra == 0) {
@@ -813,12 +817,35 @@ static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
return t;
}
+static inline void dec_byteswap(DisasContext *dc, TCGv dst, TCGv src, int size)
+{
+ if (size == 4) {
+ tcg_gen_bswap32_tl(dst, src);
+ } else if (size == 2) {
+ TCGv t = tcg_temp_new();
+
+ /* bswap16 assumes the high bits are zero. */
+ tcg_gen_andi_tl(t, src, 0xffff);
+ tcg_gen_bswap16_tl(dst, t);
+ tcg_temp_free(t);
+ } else {
+ /* Ignore.
+ cpu_abort(dc->env, "Invalid ldst byteswap size %d\n", size);
+ */
+ }
+}
+
static void dec_load(DisasContext *dc)
{
TCGv t, *addr;
- unsigned int size;
+ unsigned int size, rev = 0;
size = 1 << (dc->opcode & 3);
+
+ if (!dc->type_b) {
+ rev = (dc->ir >> 9) & 1;
+ }
+
if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
&& (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
@@ -826,10 +853,63 @@ static void dec_load(DisasContext *dc)
return;
}
- LOG_DIS("l %x %d\n", dc->opcode, size);
+ LOG_DIS("l%d%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "");
+
t_sync_flags(dc);
addr = compute_ldst_addr(dc, &t);
+ /*
+ * When doing reverse accesses we need to do two things.
+ *
+ * 1. Reverse the address wrt endianess.
+ * 2. Byteswap the data lanes on the way back into the CPU core.
+ */
+ if (rev && size != 4) {
+ /* Endian reverse the address. t is addr. */
+ switch (size) {
+ case 1:
+ {
+ /* 00 -> 11
+ 01 -> 10
+ 10 -> 10
+ 11 -> 00 */
+ TCGv low = tcg_temp_new();
+
+ /* Force addr into the temp. */
+ if (addr != &t) {
+ t = tcg_temp_new();
+ tcg_gen_mov_tl(t, *addr);
+ addr = &t;
+ }
+
+ tcg_gen_andi_tl(low, t, 3);
+ tcg_gen_sub_tl(low, tcg_const_tl(3), low);
+ tcg_gen_andi_tl(t, t, ~3);
+ tcg_gen_or_tl(t, t, low);
+ tcg_gen_mov_tl(env_debug, low);
+ tcg_gen_mov_tl(env_imm, t);
+ tcg_temp_free(low);
+ break;
+ }
+
+ case 2:
+ /* 00 -> 10
+ 10 -> 00. */
+ /* Force addr into the temp. */
+ if (addr != &t) {
+ t = tcg_temp_new();
+ tcg_gen_xori_tl(t, *addr, 2);
+ addr = &t;
+ } else {
+ tcg_gen_xori_tl(t, t, 2);
+ }
+ break;
+ default:
+ cpu_abort(dc->env, "Invalid reverse size\n");
+ break;
+ }
+ }
+
/* If we get a fault on a dslot, the jmpstate better be in sync. */
sync_jmpstate(dc);
@@ -848,13 +928,22 @@ static void dec_load(DisasContext *dc)
tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
tcg_const_tl(0), tcg_const_tl(size - 1));
- if (dc->rd)
- tcg_gen_mov_tl(cpu_R[dc->rd], v);
+ if (dc->rd) {
+ if (rev) {
+ dec_byteswap(dc, cpu_R[dc->rd], v, size);
+ } else {
+ tcg_gen_mov_tl(cpu_R[dc->rd], v);
+ }
+ }
tcg_temp_free(v);
} else {
if (dc->rd) {
gen_load(dc, cpu_R[dc->rd], *addr, size);
+ if (rev) {
+ dec_byteswap(dc, cpu_R[dc->rd], cpu_R[dc->rd], size);
+ }
} else {
+ /* We are loading into r0, no need to reverse. */
gen_load(dc, env_imm, *addr, size);
}
}
@@ -881,9 +970,12 @@ static void gen_store(DisasContext *dc, TCGv addr, TCGv val,
static void dec_store(DisasContext *dc)
{
TCGv t, *addr;
- unsigned int size;
+ unsigned int size, rev = 0;
size = 1 << (dc->opcode & 3);
+ if (!dc->type_b) {
+ rev = (dc->ir >> 9) & 1;
+ }
if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
&& (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
@@ -892,19 +984,84 @@ static void dec_store(DisasContext *dc)
return;
}
- LOG_DIS("s%d%s\n", size, dc->type_b ? "i" : "");
+ LOG_DIS("s%d%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "");
t_sync_flags(dc);
/* If we get a fault on a dslot, the jmpstate better be in sync. */
sync_jmpstate(dc);
addr = compute_ldst_addr(dc, &t);
- gen_store(dc, *addr, cpu_R[dc->rd], size);
+ if (rev && size != 4) {
+ /* Endian reverse the address. t is addr. */
+ switch (size) {
+ case 1:
+ {
+ /* 00 -> 11
+ 01 -> 10
+ 10 -> 10
+ 11 -> 00 */
+ TCGv low = tcg_temp_new();
+
+ /* Force addr into the temp. */
+ if (addr != &t) {
+ t = tcg_temp_new();
+ tcg_gen_mov_tl(t, *addr);
+ addr = &t;
+ }
+
+ tcg_gen_andi_tl(low, t, 3);
+ tcg_gen_sub_tl(low, tcg_const_tl(3), low);
+ tcg_gen_andi_tl(t, t, ~3);
+ tcg_gen_or_tl(t, t, low);
+ tcg_gen_mov_tl(env_debug, low);
+ tcg_gen_mov_tl(env_imm, t);
+ tcg_temp_free(low);
+ break;
+ }
+
+ case 2:
+ /* 00 -> 10
+ 10 -> 00. */
+ /* Force addr into the temp. */
+ if (addr != &t) {
+ t = tcg_temp_new();
+ tcg_gen_xori_tl(t, *addr, 2);
+ addr = &t;
+ } else {
+ tcg_gen_xori_tl(t, t, 2);
+ }
+ break;
+ default:
+ cpu_abort(dc->env, "Invalid reverse size\n");
+ break;
+ }
+
+ if (size != 1) {
+ TCGv bs_data = tcg_temp_new();
+ dec_byteswap(dc, bs_data, cpu_R[dc->rd], size);
+ gen_store(dc, *addr, bs_data, size);
+ tcg_temp_free(bs_data);
+ } else {
+ gen_store(dc, *addr, cpu_R[dc->rd], size);
+ }
+ } else {
+ if (rev) {
+ TCGv bs_data = tcg_temp_new();
+ dec_byteswap(dc, bs_data, cpu_R[dc->rd], size);
+ gen_store(dc, *addr, bs_data, size);
+ tcg_temp_free(bs_data);
+ } else {
+ gen_store(dc, *addr, cpu_R[dc->rd], size);
+ }
+ }
/* Verify alignment if needed. */
if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
/* FIXME: if the alignment is wrong, we should restore the value
- * in memory.
+ * in memory. One possible way to acheive this is to probe
+ * the MMU prior to the memaccess, thay way we could put
+ * the alignment checks in between the probe and the mem
+ * access.
*/
gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
tcg_const_tl(1), tcg_const_tl(size - 1));
@@ -975,7 +1132,7 @@ static void dec_bcc(DisasContext *dc)
int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */
tcg_gen_movi_tl(env_btarget, dc->pc + offset);
- dc->jmp = JMP_DIRECT;
+ dc->jmp = JMP_DIRECT_CC;
dc->jmp_pc = dc->pc + offset;
} else {
dc->jmp = JMP_INDIRECT;
@@ -1029,7 +1186,6 @@ static void dec_br(DisasContext *dc)
if (dec_alu_op_b_is_small_imm(dc)) {
dc->jmp = JMP_DIRECT;
dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
- tcg_gen_movi_tl(env_btaken, 1);
} else {
tcg_gen_movi_tl(env_btaken, 1);
tcg_gen_movi_tl(env_btarget, dc->pc);
@@ -1451,6 +1607,10 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
dc->is_jmp = DISAS_JUMP;
} else if (dc->jmp == JMP_DIRECT) {
+ t_sync_flags(dc);
+ gen_goto_tb(dc, 0, dc->jmp_pc);
+ dc->is_jmp = DISAS_TB_JUMP;
+ } else if (dc->jmp == JMP_DIRECT_CC) {
int l1;
t_sync_flags(dc);
@@ -1475,7 +1635,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
&& num_insns < max_insns);
npc = dc->pc;
- if (dc->jmp == JMP_DIRECT) {
+ if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
if (dc->tb_flags & D_FLAG) {
dc->is_jmp = DISAS_UPDATE;
tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
diff --git a/target-mips/translate.c b/target-mips/translate.c
index cce77be0d1..187930e3d2 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -3410,8 +3410,10 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
gen_helper_mfc0_count(arg);
if (use_icount) {
gen_io_end();
- ctx->bstate = BS_STOP;
}
+ /* Break the TB to be able to take timer interrupts immediately
+ after reading count. */
+ ctx->bstate = BS_STOP;
rn = "Count";
break;
/* 6,7 are implementation dependent */
@@ -4581,8 +4583,10 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
gen_helper_mfc0_count(arg);
if (use_icount) {
gen_io_end();
- ctx->bstate = BS_STOP;
}
+ /* Break the TB to be able to take timer interrupts immediately
+ after reading count. */
+ ctx->bstate = BS_STOP;
rn = "Count";
break;
/* 6,7 are implementation dependent */
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 279f345593..17e070ae75 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -546,7 +546,7 @@ uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
int ret;
farg.ll = arg;
isneg = float64_is_neg(farg.d);
- if (unlikely(float64_is_quiet_nan(farg.d))) {
+ if (unlikely(float64_is_any_nan(farg.d))) {
if (float64_is_signaling_nan(farg.d)) {
/* Signaling NaN: flags are undefined */
ret = 0x00;
@@ -975,15 +975,16 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
farg1.ll = arg1;
farg2.ll = arg2;
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN addition */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
- float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
+ if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+ float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
} else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN addition */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
}
@@ -998,15 +999,16 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
farg1.ll = arg1;
farg2.ll = arg2;
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN subtraction */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
- float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
+ if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+ float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
} else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN subtraction */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
}
@@ -1021,15 +1023,16 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
farg1.ll = arg1;
farg2.ll = arg2;
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN multiplication */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN multiplication */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
}
@@ -1044,17 +1047,18 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
farg1.ll = arg1;
farg2.ll = arg2;
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN division */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
+ if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
/* Division of zero by zero */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
} else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN division */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
}
@@ -1232,16 +1236,17 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
farg2.ll = arg2;
farg3.ll = arg3;
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
#ifdef FLOAT128
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -1276,16 +1281,17 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
farg2.ll = arg2;
farg3.ll = arg3;
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
#ifdef FLOAT128
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -1319,16 +1325,17 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
farg2.ll = arg2;
farg3.ll = arg3;
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
#ifdef FLOAT128
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -1349,8 +1356,9 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) + farg3.d;
#endif
- if (likely(!float64_is_quiet_nan(farg1.d)))
+ if (likely(!float64_is_any_nan(farg1.d))) {
farg1.d = float64_chs(farg1.d);
+ }
}
return farg1.ll;
}
@@ -1364,16 +1372,17 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
farg2.ll = arg2;
farg3.ll = arg3;
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
#ifdef FLOAT128
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -1394,8 +1403,9 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) - farg3.d;
#endif
- if (likely(!float64_is_quiet_nan(farg1.d)))
+ if (likely(!float64_is_any_nan(farg1.d))) {
farg1.d = float64_chs(farg1.d);
+ }
}
return farg1.ll;
}
@@ -1409,11 +1419,11 @@ uint64_t helper_frsp (uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else {
- f32 = float64_to_float32(farg.d, &env->fp_status);
- farg.d = float32_to_float64(f32, &env->fp_status);
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
}
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
+
return farg.ll;
}
@@ -1423,13 +1433,14 @@ uint64_t helper_fsqrt (uint64_t arg)
CPU_DoubleU farg;
farg.ll = arg;
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN square root */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
+ if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Square root of a negative nonzero number */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
} else {
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN square root */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
farg.d = float64_sqrt(farg.d, &env->fp_status);
}
return farg.ll;
@@ -1443,10 +1454,9 @@ uint64_t helper_fre (uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else {
- farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
}
+ farg.d = float64_div(float64_one, farg.d, &env->fp_status);
return farg.d;
}
@@ -1459,12 +1469,12 @@ uint64_t helper_fres (uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else {
- farg.d = float64_div(float64_one, farg.d, &env->fp_status);
- f32 = float64_to_float32(farg.d, &env->fp_status);
- farg.d = float32_to_float64(f32, &env->fp_status);
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
}
+ farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
+
return farg.ll;
}
@@ -1475,13 +1485,14 @@ uint64_t helper_frsqrte (uint64_t arg)
float32 f32;
farg.ll = arg;
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN reciprocal square root */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
+ if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Reciprocal square root of a negative nonzero number */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
} else {
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN reciprocal square root */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
farg.d = float64_sqrt(farg.d, &env->fp_status);
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
f32 = float64_to_float32(farg.d, &env->fp_status);
@@ -1497,10 +1508,11 @@ uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
farg1.ll = arg1;
- if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_quiet_nan(farg1.d))
+ if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
return arg2;
- else
+ } else {
return arg3;
+ }
}
void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
@@ -1510,8 +1522,8 @@ void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
farg1.ll = arg1;
farg2.ll = arg2;
- if (unlikely(float64_is_quiet_nan(farg1.d) ||
- float64_is_quiet_nan(farg2.d))) {
+ if (unlikely(float64_is_any_nan(farg1.d) ||
+ float64_is_any_nan(farg2.d))) {
ret = 0x01UL;
} else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
ret = 0x08UL;
@@ -1539,8 +1551,8 @@ void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
farg1.ll = arg1;
farg2.ll = arg2;
- if (unlikely(float64_is_quiet_nan(farg1.d) ||
- float64_is_quiet_nan(farg2.d))) {
+ if (unlikely(float64_is_any_nan(farg1.d) ||
+ float64_is_any_nan(farg2.d))) {
ret = 0x01UL;
} else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
ret = 0x08UL;
@@ -3437,8 +3449,9 @@ uint32_t helper_efdctsi (uint64_t val)
u.ll = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_quiet_nan(u.d)))
+ if (unlikely(float64_is_any_nan(u.d))) {
return 0;
+ }
return float64_to_int32(u.d, &env->vec_status);
}
@@ -3449,8 +3462,9 @@ uint32_t helper_efdctui (uint64_t val)
u.ll = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_quiet_nan(u.d)))
+ if (unlikely(float64_is_any_nan(u.d))) {
return 0;
+ }
return float64_to_uint32(u.d, &env->vec_status);
}
@@ -3461,8 +3475,9 @@ uint32_t helper_efdctsiz (uint64_t val)
u.ll = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_quiet_nan(u.d)))
+ if (unlikely(float64_is_any_nan(u.d))) {
return 0;
+ }
return float64_to_int32_round_to_zero(u.d, &env->vec_status);
}
@@ -3473,8 +3488,9 @@ uint64_t helper_efdctsidz (uint64_t val)
u.ll = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_quiet_nan(u.d)))
+ if (unlikely(float64_is_any_nan(u.d))) {
return 0;
+ }
return float64_to_int64_round_to_zero(u.d, &env->vec_status);
}
@@ -3485,8 +3501,9 @@ uint32_t helper_efdctuiz (uint64_t val)
u.ll = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_quiet_nan(u.d)))
+ if (unlikely(float64_is_any_nan(u.d))) {
return 0;
+ }
return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
}
@@ -3497,8 +3514,9 @@ uint64_t helper_efdctuidz (uint64_t val)
u.ll = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_quiet_nan(u.d)))
+ if (unlikely(float64_is_any_nan(u.d))) {
return 0;
+ }
return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
}
@@ -3534,8 +3552,9 @@ uint32_t helper_efdctsf (uint64_t val)
u.ll = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_quiet_nan(u.d)))
+ if (unlikely(float64_is_any_nan(u.d))) {
return 0;
+ }
tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
u.d = float64_mul(u.d, tmp, &env->vec_status);
@@ -3549,8 +3568,9 @@ uint32_t helper_efdctuf (uint64_t val)
u.ll = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_quiet_nan(u.d)))
+ if (unlikely(float64_is_any_nan(u.d))) {
return 0;
+ }
tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
u.d = float64_mul(u.d, tmp, &env->vec_status);
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index 8ccf25cafb..95df6d2a75 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -61,10 +61,37 @@
#define SR_S (1 << 1)
#define SR_T (1 << 0)
-#define FPSCR_FR (1 << 21)
-#define FPSCR_SZ (1 << 20)
-#define FPSCR_PR (1 << 19)
-#define FPSCR_DN (1 << 18)
+#define FPSCR_MASK (0x003fffff)
+#define FPSCR_FR (1 << 21)
+#define FPSCR_SZ (1 << 20)
+#define FPSCR_PR (1 << 19)
+#define FPSCR_DN (1 << 18)
+#define FPSCR_CAUSE_MASK (0x3f << 12)
+#define FPSCR_CAUSE_SHIFT (12)
+#define FPSCR_CAUSE_E (1 << 17)
+#define FPSCR_CAUSE_V (1 << 16)
+#define FPSCR_CAUSE_Z (1 << 15)
+#define FPSCR_CAUSE_O (1 << 14)
+#define FPSCR_CAUSE_U (1 << 13)
+#define FPSCR_CAUSE_I (1 << 12)
+#define FPSCR_ENABLE_MASK (0x1f << 7)
+#define FPSCR_ENABLE_SHIFT (7)
+#define FPSCR_ENABLE_V (1 << 11)
+#define FPSCR_ENABLE_Z (1 << 10)
+#define FPSCR_ENABLE_O (1 << 9)
+#define FPSCR_ENABLE_U (1 << 8)
+#define FPSCR_ENABLE_I (1 << 7)
+#define FPSCR_FLAG_MASK (0x1f << 2)
+#define FPSCR_FLAG_SHIFT (2)
+#define FPSCR_FLAG_V (1 << 6)
+#define FPSCR_FLAG_Z (1 << 5)
+#define FPSCR_FLAG_O (1 << 4)
+#define FPSCR_FLAG_U (1 << 3)
+#define FPSCR_FLAG_I (1 << 2)
+#define FPSCR_RM_MASK (0x03 << 0)
+#define FPSCR_RM_NEAREST (0 << 0)
+#define FPSCR_RM_ZERO (1 << 0)
+
#define DELAY_SLOT (1 << 0)
#define DELAY_SLOT_CONDITIONAL (1 << 1)
#define DELAY_SLOT_TRUE (1 << 2)
@@ -109,8 +136,6 @@ typedef struct memory_content {
} memory_content;
typedef struct CPUSH4State {
- int id; /* CPU model */
-
uint32_t flags; /* general execution flags */
uint32_t gregs[24]; /* general registers */
float32 fregs[32]; /* floating point registers */
@@ -146,14 +171,18 @@ typedef struct CPUSH4State {
uint32_t expevt; /* exception event register */
uint32_t intevt; /* interrupt event register */
+ tlb_t itlb[ITLB_SIZE]; /* instruction translation table */
+ tlb_t utlb[UTLB_SIZE]; /* unified translation table */
+
+ uint32_t ldst;
+
+ CPU_COMMON
+
+ int id; /* CPU model */
uint32_t pvr; /* Processor Version Register */
uint32_t prr; /* Processor Revision Register */
uint32_t cvr; /* Cache Version Register */
- uint32_t ldst;
-
- CPU_COMMON tlb_t utlb[UTLB_SIZE]; /* unified translation table */
- tlb_t itlb[ITLB_SIZE]; /* instruction translation table */
void *intc_handle;
int intr_at_halt; /* SR_BL ignored during sleep */
memory_content *movcal_backup;
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index 2343366762..45449ea64e 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -380,7 +380,7 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
MMU_DTLB_VIOLATION_READ;
} else if ((rw == 1) && !(matching->pr & 1)) {
n = MMU_DTLB_VIOLATION_WRITE;
- } else if ((rw == 1) & !matching->d) {
+ } else if ((rw == 1) && !matching->d) {
n = MMU_DTLB_INITIAL_WRITE;
} else {
*prot = PAGE_READ;
@@ -430,7 +430,7 @@ static int get_physical_address(CPUState * env, target_ulong * physical,
}
/* If MMU is disabled, return the corresponding physical page */
- if (!env->mmucr & MMUCR_AT) {
+ if (!(env->mmucr & MMUCR_AT)) {
*physical = address & 0x1FFFFFFF;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
return MMU_OK;
diff --git a/target-sh4/helper.h b/target-sh4/helper.h
index 4b2fcdd536..2e52768414 100644
--- a/target-sh4/helper.h
+++ b/target-sh4/helper.h
@@ -17,7 +17,6 @@ DEF_HELPER_2(addv, i32, i32, i32)
DEF_HELPER_2(addc, i32, i32, i32)
DEF_HELPER_2(subv, i32, i32, i32)
DEF_HELPER_2(subc, i32, i32, i32)
-DEF_HELPER_1(negc, i32, i32)
DEF_HELPER_2(div1, i32, i32, i32)
DEF_HELPER_2(macl, void, i32, i32)
DEF_HELPER_2(macw, void, i32, i32)
@@ -49,5 +48,7 @@ DEF_HELPER_1(fsqrt_FT, i32, i32)
DEF_HELPER_1(fsqrt_DT, i64, i64)
DEF_HELPER_1(ftrc_FT, i32, i32)
DEF_HELPER_1(ftrc_DT, i32, i64)
+DEF_HELPER_2(fipr, void, i32, i32)
+DEF_HELPER_1(ftrv, void, i32)
#include "def-helper.h"
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index 2e5f5552a2..30f9842295 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -21,6 +21,22 @@
#include "exec.h"
#include "helper.h"
+static void cpu_restore_state_from_retaddr(void *retaddr)
+{
+ TranslationBlock *tb;
+ unsigned long pc;
+
+ if (retaddr) {
+ pc = (unsigned long) retaddr;
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, NULL);
+ }
+ }
+}
+
#ifndef CONFIG_USER_ONLY
#define MMUSUFFIX _mmu
@@ -39,9 +55,7 @@
void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
{
- TranslationBlock *tb;
CPUState *saved_env;
- unsigned long pc;
int ret;
/* XXX: hack to restore env in all cases, even if not called from
@@ -50,16 +64,8 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
env = cpu_single_env;
ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
if (ret) {
- if (retaddr) {
- /* now we have a real cpu fault */
- pc = (unsigned long) retaddr;
- tb = tb_find_pc(pc);
- if (tb) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, pc, NULL);
- }
- }
+ /* now we have a real cpu fault */
+ cpu_restore_state_from_retaddr(retaddr);
cpu_loop_exit();
}
env = saved_env;
@@ -77,28 +83,31 @@ void helper_ldtlb(void)
#endif
}
-void helper_raise_illegal_instruction(void)
+static inline void raise_exception(int index, void *retaddr)
{
- env->exception_index = 0x180;
+ env->exception_index = index;
+ cpu_restore_state_from_retaddr(retaddr);
cpu_loop_exit();
}
+void helper_raise_illegal_instruction(void)
+{
+ raise_exception(0x180, GETPC());
+}
+
void helper_raise_slot_illegal_instruction(void)
{
- env->exception_index = 0x1a0;
- cpu_loop_exit();
+ raise_exception(0x1a0, GETPC());
}
void helper_raise_fpu_disable(void)
{
- env->exception_index = 0x800;
- cpu_loop_exit();
+ raise_exception(0x800, GETPC());
}
void helper_raise_slot_fpu_disable(void)
{
- env->exception_index = 0x820;
- cpu_loop_exit();
+ raise_exception(0x820, GETPC());
}
void helper_debug(void)
@@ -118,8 +127,7 @@ void helper_sleep(uint32_t next_pc)
void helper_trapa(uint32_t tra)
{
env->tra = tra << 2;
- env->exception_index = 0x160;
- cpu_loop_exit();
+ raise_exception(0x160, GETPC());
}
void helper_movcal(uint32_t address, uint32_t value)
@@ -371,21 +379,6 @@ void helper_macw(uint32_t arg0, uint32_t arg1)
}
}
-uint32_t helper_negc(uint32_t arg)
-{
- uint32_t temp;
-
- temp = -arg;
- arg = temp - (env->sr & SR_T);
- if (0 < temp)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- if (temp < arg)
- env->sr |= SR_T;
- return arg;
-}
-
uint32_t helper_subc(uint32_t arg0, uint32_t arg1)
{
uint32_t tmp0, tmp1;
@@ -443,11 +436,54 @@ static inline void clr_t(void)
void helper_ld_fpscr(uint32_t val)
{
- env->fpscr = val & 0x003fffff;
- if (val & 0x01)
+ env->fpscr = val & FPSCR_MASK;
+ if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- else
+ } else {
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+ }
+ set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
+}
+
+static void update_fpscr(void *retaddr)
+{
+ int xcpt, cause, enable;
+
+ xcpt = get_float_exception_flags(&env->fp_status);
+
+ /* Clear the flag entries */
+ env->fpscr &= ~FPSCR_FLAG_MASK;
+
+ if (unlikely(xcpt)) {
+ if (xcpt & float_flag_invalid) {
+ env->fpscr |= FPSCR_FLAG_V;
+ }
+ if (xcpt & float_flag_divbyzero) {
+ env->fpscr |= FPSCR_FLAG_Z;
+ }
+ if (xcpt & float_flag_overflow) {
+ env->fpscr |= FPSCR_FLAG_O;
+ }
+ if (xcpt & float_flag_underflow) {
+ env->fpscr |= FPSCR_FLAG_U;
+ }
+ if (xcpt & float_flag_inexact) {
+ env->fpscr |= FPSCR_FLAG_I;
+ }
+
+ /* Accumulate in cause entries */
+ env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
+ << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
+
+ /* Generate an exception if enabled */
+ cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
+ enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
+ if (cause & enable) {
+ cpu_restore_state_from_retaddr(retaddr);
+ env->exception_index = 0x120;
+ cpu_loop_exit();
+ }
+ }
}
uint32_t helper_fabs_FT(uint32_t t0)
@@ -471,7 +507,9 @@ uint32_t helper_fadd_FT(uint32_t t0, uint32_t t1)
CPU_FloatU f0, f1;
f0.l = t0;
f1.l = t1;
+ set_float_exception_flags(0, &env->fp_status);
f0.f = float32_add(f0.f, f1.f, &env->fp_status);
+ update_fpscr(GETPC());
return f0.l;
}
@@ -480,56 +518,82 @@ uint64_t helper_fadd_DT(uint64_t t0, uint64_t t1)
CPU_DoubleU d0, d1;
d0.ll = t0;
d1.ll = t1;
+ set_float_exception_flags(0, &env->fp_status);
d0.d = float64_add(d0.d, d1.d, &env->fp_status);
+ update_fpscr(GETPC());
return d0.ll;
}
void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1)
{
CPU_FloatU f0, f1;
+ int relation;
f0.l = t0;
f1.l = t1;
- if (float32_compare(f0.f, f1.f, &env->fp_status) == 0)
+ set_float_exception_flags(0, &env->fp_status);
+ relation = float32_compare(f0.f, f1.f, &env->fp_status);
+ if (unlikely(relation == float_relation_unordered)) {
+ update_fpscr(GETPC());
+ } else if (relation == float_relation_equal) {
set_t();
- else
+ } else {
clr_t();
+ }
}
void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1)
{
CPU_DoubleU d0, d1;
+ int relation;
d0.ll = t0;
d1.ll = t1;
- if (float64_compare(d0.d, d1.d, &env->fp_status) == 0)
+ set_float_exception_flags(0, &env->fp_status);
+ relation = float64_compare(d0.d, d1.d, &env->fp_status);
+ if (unlikely(relation == float_relation_unordered)) {
+ update_fpscr(GETPC());
+ } else if (relation == float_relation_equal) {
set_t();
- else
+ } else {
clr_t();
+ }
}
void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1)
{
CPU_FloatU f0, f1;
+ int relation;
f0.l = t0;
f1.l = t1;
- if (float32_compare(f0.f, f1.f, &env->fp_status) == 1)
+ set_float_exception_flags(0, &env->fp_status);
+ relation = float32_compare(f0.f, f1.f, &env->fp_status);
+ if (unlikely(relation == float_relation_unordered)) {
+ update_fpscr(GETPC());
+ } else if (relation == float_relation_greater) {
set_t();
- else
+ } else {
clr_t();
+ }
}
void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1)
{
CPU_DoubleU d0, d1;
+ int relation;
d0.ll = t0;
d1.ll = t1;
- if (float64_compare(d0.d, d1.d, &env->fp_status) == 1)
+ set_float_exception_flags(0, &env->fp_status);
+ relation = float64_compare(d0.d, d1.d, &env->fp_status);
+ if (unlikely(relation == float_relation_unordered)) {
+ update_fpscr(GETPC());
+ } else if (relation == float_relation_greater) {
set_t();
- else
+ } else {
clr_t();
+ }
}
uint64_t helper_fcnvsd_FT_DT(uint32_t t0)
@@ -537,7 +601,9 @@ uint64_t helper_fcnvsd_FT_DT(uint32_t t0)
CPU_DoubleU d;
CPU_FloatU f;
f.l = t0;
+ set_float_exception_flags(0, &env->fp_status);
d.d = float32_to_float64(f.f, &env->fp_status);
+ update_fpscr(GETPC());
return d.ll;
}
@@ -546,7 +612,9 @@ uint32_t helper_fcnvds_DT_FT(uint64_t t0)
CPU_DoubleU d;
CPU_FloatU f;
d.ll = t0;
+ set_float_exception_flags(0, &env->fp_status);
f.f = float64_to_float32(d.d, &env->fp_status);
+ update_fpscr(GETPC());
return f.l;
}
@@ -555,7 +623,9 @@ uint32_t helper_fdiv_FT(uint32_t t0, uint32_t t1)
CPU_FloatU f0, f1;
f0.l = t0;
f1.l = t1;
+ set_float_exception_flags(0, &env->fp_status);
f0.f = float32_div(f0.f, f1.f, &env->fp_status);
+ update_fpscr(GETPC());
return f0.l;
}
@@ -564,21 +634,29 @@ uint64_t helper_fdiv_DT(uint64_t t0, uint64_t t1)
CPU_DoubleU d0, d1;
d0.ll = t0;
d1.ll = t1;
+ set_float_exception_flags(0, &env->fp_status);
d0.d = float64_div(d0.d, d1.d, &env->fp_status);
+ update_fpscr(GETPC());
return d0.ll;
}
uint32_t helper_float_FT(uint32_t t0)
{
CPU_FloatU f;
+
+ set_float_exception_flags(0, &env->fp_status);
f.f = int32_to_float32(t0, &env->fp_status);
+ update_fpscr(GETPC());
+
return f.l;
}
uint64_t helper_float_DT(uint32_t t0)
{
CPU_DoubleU d;
+ set_float_exception_flags(0, &env->fp_status);
d.d = int32_to_float64(t0, &env->fp_status);
+ update_fpscr(GETPC());
return d.ll;
}
@@ -588,8 +666,11 @@ uint32_t helper_fmac_FT(uint32_t t0, uint32_t t1, uint32_t t2)
f0.l = t0;
f1.l = t1;
f2.l = t2;
+ set_float_exception_flags(0, &env->fp_status);
f0.f = float32_mul(f0.f, f1.f, &env->fp_status);
f0.f = float32_add(f0.f, f2.f, &env->fp_status);
+ update_fpscr(GETPC());
+
return f0.l;
}
@@ -598,7 +679,9 @@ uint32_t helper_fmul_FT(uint32_t t0, uint32_t t1)
CPU_FloatU f0, f1;
f0.l = t0;
f1.l = t1;
+ set_float_exception_flags(0, &env->fp_status);
f0.f = float32_mul(f0.f, f1.f, &env->fp_status);
+ update_fpscr(GETPC());
return f0.l;
}
@@ -607,7 +690,10 @@ uint64_t helper_fmul_DT(uint64_t t0, uint64_t t1)
CPU_DoubleU d0, d1;
d0.ll = t0;
d1.ll = t1;
+ set_float_exception_flags(0, &env->fp_status);
d0.d = float64_mul(d0.d, d1.d, &env->fp_status);
+ update_fpscr(GETPC());
+
return d0.ll;
}
@@ -623,7 +709,9 @@ uint32_t helper_fsqrt_FT(uint32_t t0)
{
CPU_FloatU f;
f.l = t0;
+ set_float_exception_flags(0, &env->fp_status);
f.f = float32_sqrt(f.f, &env->fp_status);
+ update_fpscr(GETPC());
return f.l;
}
@@ -631,7 +719,9 @@ uint64_t helper_fsqrt_DT(uint64_t t0)
{
CPU_DoubleU d;
d.ll = t0;
+ set_float_exception_flags(0, &env->fp_status);
d.d = float64_sqrt(d.d, &env->fp_status);
+ update_fpscr(GETPC());
return d.ll;
}
@@ -640,29 +730,88 @@ uint32_t helper_fsub_FT(uint32_t t0, uint32_t t1)
CPU_FloatU f0, f1;
f0.l = t0;
f1.l = t1;
+ set_float_exception_flags(0, &env->fp_status);
f0.f = float32_sub(f0.f, f1.f, &env->fp_status);
+ update_fpscr(GETPC());
return f0.l;
}
uint64_t helper_fsub_DT(uint64_t t0, uint64_t t1)
{
CPU_DoubleU d0, d1;
+
d0.ll = t0;
d1.ll = t1;
+ set_float_exception_flags(0, &env->fp_status);
d0.d = float64_sub(d0.d, d1.d, &env->fp_status);
+ update_fpscr(GETPC());
return d0.ll;
}
uint32_t helper_ftrc_FT(uint32_t t0)
{
CPU_FloatU f;
+ uint32_t ret;
f.l = t0;
- return float32_to_int32_round_to_zero(f.f, &env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
+ ret = float32_to_int32_round_to_zero(f.f, &env->fp_status);
+ update_fpscr(GETPC());
+ return ret;
}
uint32_t helper_ftrc_DT(uint64_t t0)
{
CPU_DoubleU d;
+ uint32_t ret;
d.ll = t0;
- return float64_to_int32_round_to_zero(d.d, &env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
+ ret = float64_to_int32_round_to_zero(d.d, &env->fp_status);
+ update_fpscr(GETPC());
+ return ret;
+}
+
+void helper_fipr(uint32_t m, uint32_t n)
+{
+ int bank, i;
+ float32 r, p;
+
+ bank = (env->sr & FPSCR_FR) ? 16 : 0;
+ r = float32_zero;
+ set_float_exception_flags(0, &env->fp_status);
+
+ for (i = 0 ; i < 4 ; i++) {
+ p = float32_mul(env->fregs[bank + m + i],
+ env->fregs[bank + n + i],
+ &env->fp_status);
+ r = float32_add(r, p, &env->fp_status);
+ }
+ update_fpscr(GETPC());
+
+ env->fregs[bank + n + 3] = r;
+}
+
+void helper_ftrv(uint32_t n)
+{
+ int bank_matrix, bank_vector;
+ int i, j;
+ float32 r[4];
+ float32 p;
+
+ bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
+ bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
+ set_float_exception_flags(0, &env->fp_status);
+ for (i = 0 ; i < 4 ; i++) {
+ r[i] = float32_zero;
+ for (j = 0 ; j < 4 ; j++) {
+ p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
+ env->fregs[bank_vector + j],
+ &env->fp_status);
+ r[i] = float32_add(r[i], p, &env->fp_status);
+ }
+ }
+ update_fpscr(GETPC());
+
+ for (i = 0 ; i < 4 ; i++) {
+ env->fregs[bank_vector + i] = r[i];
+ }
}
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index f418139931..35573be5ff 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -185,28 +185,27 @@ void cpu_dump_state(CPUState * env, FILE * f,
}
}
-static void cpu_sh4_reset(CPUSH4State * env)
+void cpu_reset(CPUSH4State * env)
{
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
log_cpu_state(env, 0);
}
-#if defined(CONFIG_USER_ONLY)
- env->sr = 0;
-#else
- env->sr = SR_MD | SR_RB | SR_BL | SR_I3 | SR_I2 | SR_I1 | SR_I0;
-#endif
- env->vbr = 0;
+ memset(env, 0, offsetof(CPUSH4State, breakpoints));
+ tlb_flush(env, 1);
+
env->pc = 0xA0000000;
#if defined(CONFIG_USER_ONLY)
env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */
set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */
#else
- env->fpscr = 0x00040001; /* CPU reset value according to SH4 manual */
+ env->sr = SR_MD | SR_RB | SR_BL | SR_I3 | SR_I2 | SR_I1 | SR_I0;
+ env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
+ set_flush_to_zero(1, &env->fp_status);
#endif
- env->mmucr = 0;
+ set_default_nan_mode(1, &env->fp_status);
}
typedef struct {
@@ -265,7 +264,7 @@ void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf)
(*cpu_fprintf)(f, "%s\n", sh4_defs[i].name);
}
-static void cpu_sh4_register(CPUSH4State *env, const sh4_def_t *def)
+static void cpu_register(CPUSH4State *env, const sh4_def_t *def)
{
env->pvr = def->pvr;
env->prr = def->prr;
@@ -287,9 +286,8 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model)
env->movcal_backup_tail = &(env->movcal_backup);
sh4_translate_init();
env->cpu_model_str = cpu_model;
- cpu_sh4_reset(env);
- cpu_sh4_register(env, def);
- tlb_flush(env, 1);
+ cpu_reset(env);
+ cpu_register(env, def);
qemu_init_vcpu(env);
return env;
}
@@ -334,7 +332,7 @@ static inline void gen_branch_slot(uint32_t delayed_pc, int t)
tcg_gen_movi_i32(cpu_delayed_pc, delayed_pc);
sr = tcg_temp_new();
tcg_gen_andi_i32(sr, cpu_sr, SR_T);
- tcg_gen_brcondi_i32(TCG_COND_NE, sr, t ? SR_T : 0, label);
+ tcg_gen_brcondi_i32(t ? TCG_COND_EQ:TCG_COND_NE, sr, 0, label);
tcg_gen_ori_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE);
gen_set_label(label);
}
@@ -349,7 +347,7 @@ static void gen_conditional_jump(DisasContext * ctx,
l1 = gen_new_label();
sr = tcg_temp_new();
tcg_gen_andi_i32(sr, cpu_sr, SR_T);
- tcg_gen_brcondi_i32(TCG_COND_EQ, sr, SR_T, l1);
+ tcg_gen_brcondi_i32(TCG_COND_NE, sr, 0, l1);
gen_goto_tb(ctx, 0, ifnott);
gen_set_label(l1);
gen_goto_tb(ctx, 1, ift);
@@ -364,7 +362,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
l1 = gen_new_label();
ds = tcg_temp_new();
tcg_gen_andi_i32(ds, cpu_flags, DELAY_SLOT_TRUE);
- tcg_gen_brcondi_i32(TCG_COND_EQ, ds, DELAY_SLOT_TRUE, l1);
+ tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1);
gen_goto_tb(ctx, 1, ctx->pc + 2);
gen_set_label(l1);
tcg_gen_andi_i32(cpu_flags, cpu_flags, ~DELAY_SLOT_TRUE);
@@ -383,26 +381,26 @@ static inline void gen_clr_t(void)
static inline void gen_cmp(int cond, TCGv t0, TCGv t1)
{
- int label1 = gen_new_label();
- int label2 = gen_new_label();
- tcg_gen_brcond_i32(cond, t1, t0, label1);
- gen_clr_t();
- tcg_gen_br(label2);
- gen_set_label(label1);
- gen_set_t();
- gen_set_label(label2);
+ TCGv t;
+
+ t = tcg_temp_new();
+ tcg_gen_setcond_i32(cond, t, t1, t0);
+ tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, t);
+
+ tcg_temp_free(t);
}
static inline void gen_cmp_imm(int cond, TCGv t0, int32_t imm)
{
- int label1 = gen_new_label();
- int label2 = gen_new_label();
- tcg_gen_brcondi_i32(cond, t0, imm, label1);
- gen_clr_t();
- tcg_gen_br(label2);
- gen_set_label(label1);
- gen_set_t();
- gen_set_label(label2);
+ TCGv t;
+
+ t = tcg_temp_new();
+ tcg_gen_setcondi_i32(cond, t, t0, imm);
+ tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, t);
+
+ tcg_temp_free(t);
}
static inline void gen_store_flags(uint32_t flags)
@@ -469,27 +467,27 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg)
#define CHECK_NOT_DELAY_SLOT \
if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
{ \
- tcg_gen_movi_i32(cpu_pc, ctx->pc-2); \
gen_helper_raise_slot_illegal_instruction(); \
ctx->bstate = BS_EXCP; \
return; \
}
-#define CHECK_PRIVILEGED \
- if (IS_USER(ctx)) { \
- tcg_gen_movi_i32(cpu_pc, ctx->pc); \
- gen_helper_raise_illegal_instruction(); \
- ctx->bstate = BS_EXCP; \
- return; \
+#define CHECK_PRIVILEGED \
+ if (IS_USER(ctx)) { \
+ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \
+ gen_helper_raise_slot_illegal_instruction(); \
+ } else { \
+ gen_helper_raise_illegal_instruction(); \
+ } \
+ ctx->bstate = BS_EXCP; \
+ return; \
}
#define CHECK_FPU_ENABLED \
if (ctx->flags & SR_FD) { \
if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \
- tcg_gen_movi_i32(cpu_pc, ctx->pc-2); \
gen_helper_raise_slot_fpu_disable(); \
} else { \
- tcg_gen_movi_i32(cpu_pc, ctx->pc); \
gen_helper_raise_fpu_disable(); \
} \
ctx->bstate = BS_EXCP; \
@@ -818,24 +816,22 @@ static void _decode_opc(DisasContext * ctx)
return;
case 0x200c: /* cmp/str Rm,Rn */
{
- int label1 = gen_new_label();
- int label2 = gen_new_label();
- TCGv cmp1 = tcg_temp_local_new();
- TCGv cmp2 = tcg_temp_local_new();
+ TCGv cmp1 = tcg_temp_new();
+ TCGv cmp2 = tcg_temp_new();
+ tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
tcg_gen_xor_i32(cmp1, REG(B7_4), REG(B11_8));
tcg_gen_andi_i32(cmp2, cmp1, 0xff000000);
- tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1);
+ tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
tcg_gen_andi_i32(cmp2, cmp1, 0x00ff0000);
- tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1);
+ tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
tcg_gen_andi_i32(cmp2, cmp1, 0x0000ff00);
- tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1);
+ tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
tcg_gen_andi_i32(cmp2, cmp1, 0x000000ff);
- tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1);
- tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
- tcg_gen_br(label2);
- gen_set_label(label1);
- tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_T);
- gen_set_label(label2);
+ tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2);
tcg_temp_free(cmp2);
tcg_temp_free(cmp1);
}
@@ -956,7 +952,21 @@ static void _decode_opc(DisasContext * ctx)
tcg_gen_neg_i32(REG(B11_8), REG(B7_4));
return;
case 0x600a: /* negc Rm,Rn */
- gen_helper_negc(REG(B11_8), REG(B7_4));
+ {
+ TCGv t0, t1;
+ t0 = tcg_temp_new();
+ tcg_gen_neg_i32(t0, REG(B7_4));
+ t1 = tcg_temp_new();
+ tcg_gen_andi_i32(t1, cpu_sr, SR_T);
+ tcg_gen_sub_i32(REG(B11_8), t0, t1);
+ tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+ tcg_gen_setcond_i32(TCG_COND_GE, t1, REG(B11_8), t0);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
+ tcg_gen_setcondi_i32(TCG_COND_GE, t1, t0, 0);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ }
return;
case 0x6007: /* not Rm,Rn */
tcg_gen_not_i32(REG(B11_8), REG(B7_4));
@@ -1375,7 +1385,6 @@ static void _decode_opc(DisasContext * ctx)
{
TCGv imm;
CHECK_NOT_DELAY_SLOT
- tcg_gen_movi_i32(cpu_pc, ctx->pc);
imm = tcg_const_i32(B7_0);
gen_helper_trapa(imm);
tcg_temp_free(imm);
@@ -1695,14 +1704,12 @@ static void _decode_opc(DisasContext * ctx)
}
return;
case 0x4004: /* rotl Rn */
- gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31);
- tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1);
- gen_copy_bit_i32(REG(B11_8), 0, cpu_sr, 0);
+ tcg_gen_rotli_i32(REG(B11_8), REG(B11_8), 1);
+ gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
return;
case 0x4005: /* rotr Rn */
gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0);
- tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1);
- gen_copy_bit_i32(REG(B11_8), 31, cpu_sr, 0);
+ tcg_gen_rotri_i32(REG(B11_8), REG(B11_8), 1);
return;
case 0x4000: /* shll Rn */
case 0x4020: /* shal Rn */
@@ -1854,13 +1861,40 @@ static void _decode_opc(DisasContext * ctx)
tcg_temp_free_i64(fp);
}
return;
+ case 0xf0ed: /* fipr FVm,FVn */
+ CHECK_FPU_ENABLED
+ if ((ctx->fpscr & FPSCR_PR) == 0) {
+ TCGv m, n;
+ m = tcg_const_i32((ctx->opcode >> 16) & 3);
+ n = tcg_const_i32((ctx->opcode >> 18) & 3);
+ gen_helper_fipr(m, n);
+ tcg_temp_free(m);
+ tcg_temp_free(n);
+ return;
+ }
+ break;
+ case 0xf0fd: /* ftrv XMTRX,FVn */
+ CHECK_FPU_ENABLED
+ if ((ctx->opcode & 0x0300) == 0x0100 &&
+ (ctx->fpscr & FPSCR_PR) == 0) {
+ TCGv n;
+ n = tcg_const_i32((ctx->opcode >> 18) & 3);
+ gen_helper_ftrv(n);
+ tcg_temp_free(n);
+ return;
+ }
+ break;
}
#if 0
fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
ctx->opcode, ctx->pc);
fflush(stderr);
#endif
- gen_helper_raise_illegal_instruction();
+ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
+ gen_helper_raise_slot_illegal_instruction();
+ } else {
+ gen_helper_raise_illegal_instruction();
+ }
ctx->bstate = BS_EXCP;
}
@@ -1868,6 +1902,10 @@ static void decode_opc(DisasContext * ctx)
{
uint32_t old_flags = ctx->flags;
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+ tcg_gen_debug_insn_start(ctx->pc);
+ }
+
_decode_opc(ctx);
if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 58f9f82f52..b70970ac2a 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -857,65 +857,77 @@ void helper_fsqrtq(void)
QT0 = float128_sqrt(QT1, &env->fp_status);
}
-#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \
+#define GEN_FCMP(name, size, reg1, reg2, FS, E) \
void glue(helper_, name) (void) \
{ \
- target_ulong new_fsr; \
- \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr &= FSR_FTT_NMASK; \
+ if (E && (glue(size, _is_any_nan)(reg1) || \
+ glue(size, _is_any_nan)(reg2)) && \
+ (env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ raise_exception(TT_FP_EXCP); \
+ } \
switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
case float_relation_unordered: \
- new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \
- if ((env->fsr & FSR_NVM) || TRAP) { \
- env->fsr |= new_fsr; \
+ if ((env->fsr & FSR_NVM)) { \
env->fsr |= FSR_NVC; \
env->fsr |= FSR_FTT_IEEE_EXCP; \
raise_exception(TT_FP_EXCP); \
} else { \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
env->fsr |= FSR_NVA; \
} \
break; \
case float_relation_less: \
- new_fsr = FSR_FCC0 << FS; \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC0 << FS; \
break; \
case float_relation_greater: \
- new_fsr = FSR_FCC1 << FS; \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC1 << FS; \
break; \
default: \
- new_fsr = 0; \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
break; \
} \
- env->fsr |= new_fsr; \
}
-#define GEN_FCMPS(name, size, FS, TRAP) \
+#define GEN_FCMPS(name, size, FS, E) \
void glue(helper_, name)(float32 src1, float32 src2) \
{ \
- target_ulong new_fsr; \
- \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr &= FSR_FTT_NMASK; \
+ if (E && (glue(size, _is_any_nan)(src1) || \
+ glue(size, _is_any_nan)(src2)) && \
+ (env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ raise_exception(TT_FP_EXCP); \
+ } \
switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \
case float_relation_unordered: \
- new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \
- if ((env->fsr & FSR_NVM) || TRAP) { \
- env->fsr |= new_fsr; \
+ if ((env->fsr & FSR_NVM)) { \
env->fsr |= FSR_NVC; \
env->fsr |= FSR_FTT_IEEE_EXCP; \
raise_exception(TT_FP_EXCP); \
} else { \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
env->fsr |= FSR_NVA; \
} \
break; \
case float_relation_less: \
- new_fsr = FSR_FCC0 << FS; \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC0 << FS; \
break; \
case float_relation_greater: \
- new_fsr = FSR_FCC1 << FS; \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC1 << FS; \
break; \
default: \
- new_fsr = 0; \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
break; \
} \
- env->fsr |= new_fsr; \
}
GEN_FCMPS(fcmps, float32, 0, 0);
diff --git a/tcg/README b/tcg/README
index a18a87ffcd..660012281f 100644
--- a/tcg/README
+++ b/tcg/README
@@ -285,6 +285,20 @@ the four high order bytes are set to zero.
Indicate that the value of t0 won't be used later. It is useful to
force dead code elimination.
+* deposit_i32/i64 dest, t1, t2, pos, len
+
+Deposit T2 as a bitfield into T1, placing the result in DEST.
+The bitfield is described by POS/LEN, which are immediate values:
+
+ LEN - the length of the bitfield
+ POS - the position of the first bit, counting from the LSB
+
+For example, pos=8, len=4 indicates a 4-bit field at bit 8.
+This operation would be equivalent to
+
+ dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00)
+
+
********* Conditional moves
* setcond_i32/i64 cond, dest, t1, t2
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 1eb5605f8c..918e2f73cb 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -352,6 +352,9 @@ static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset)
static inline void tcg_out_b_noaddr(TCGContext *s, int cond)
{
+ /* We pay attention here to not modify the branch target by skipping
+ the corresponding bytes. This ensure that caches and memory are
+ kept coherent during retranslation. */
#ifdef HOST_WORDS_BIGENDIAN
tcg_out8(s, (cond << 4) | 0x0a);
s->code_ptr += 3;
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index e2e44f7d76..8dac7f72fd 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -871,6 +871,9 @@ static void tcg_out_br(TCGContext *s, int label_index)
{
TCGLabel *l = &s->labels[label_index];
+ /* We pay attention here to not modify the branch target by reading
+ the existing value and using it again. This ensure that caches and
+ memory are kept coherent during retranslation. */
tcg_out_bundle(s, mmB,
tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 4e92a50e6f..e04b0dc32f 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -351,7 +351,9 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int i
*/
static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs)
{
- /* We need to keep the offset unchanged for retranslation */
+ /* We pay attention here to not modify the branch target by reading
+ the existing value and using it again. This ensure that caches and
+ memory are kept coherent during retranslation. */
uint16_t offset = (uint16_t)(*(uint32_t *) s->code_ptr);
tcg_out_opc_imm(s, opc, rt, rs, offset);
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 3ee0a58ed1..207a89fd97 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -254,6 +254,30 @@ static inline void tcg_gen_op5i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2,
*gen_opparam_ptr++ = arg5;
}
+static inline void tcg_gen_op5ii_i32(TCGOpcode opc, TCGv_i32 arg1,
+ TCGv_i32 arg2, TCGv_i32 arg3,
+ TCGArg arg4, TCGArg arg5)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+ *gen_opparam_ptr++ = arg4;
+ *gen_opparam_ptr++ = arg5;
+}
+
+static inline void tcg_gen_op5ii_i64(TCGOpcode opc, TCGv_i64 arg1,
+ TCGv_i64 arg2, TCGv_i64 arg3,
+ TCGArg arg4, TCGArg arg5)
+{
+ *gen_opc_ptr++ = opc;
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+ *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+ *gen_opparam_ptr++ = arg4;
+ *gen_opparam_ptr++ = arg5;
+}
+
static inline void tcg_gen_op6_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2,
TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5,
TCGv_i32 arg6)
@@ -2071,6 +2095,44 @@ static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
}
}
+static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1,
+ TCGv_i32 arg2, unsigned int ofs,
+ unsigned int len)
+{
+#ifdef TCG_TARGET_HAS_deposit_i32
+ tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
+#else
+ uint32_t mask = (1u << len) - 1;
+ TCGv_i32 t1 = tcg_temp_new_i32 ();
+
+ tcg_gen_andi_i32(t1, arg2, mask);
+ tcg_gen_shli_i32(t1, t1, ofs);
+ tcg_gen_andi_i32(ret, arg1, ~(mask << ofs));
+ tcg_gen_or_i32(ret, ret, t1);
+
+ tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
+ TCGv_i64 arg2, unsigned int ofs,
+ unsigned int len)
+{
+#ifdef TCG_TARGET_HAS_deposit_i64
+ tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
+#else
+ uint64_t mask = (1ull << len) - 1;
+ TCGv_i64 t1 = tcg_temp_new_i64 ();
+
+ tcg_gen_andi_i64(t1, arg2, mask);
+ tcg_gen_shli_i64(t1, t1, ofs);
+ tcg_gen_andi_i64(ret, arg1, ~(mask << ofs));
+ tcg_gen_or_i64(ret, ret, t1);
+
+ tcg_temp_free_i64(t1);
+#endif
+}
+
/***************************************/
/* QEMU specific operations. Their type depend on the QEMU CPU
type. */
@@ -2384,6 +2446,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#define tcg_gen_rotli_tl tcg_gen_rotli_i64
#define tcg_gen_rotr_tl tcg_gen_rotr_i64
#define tcg_gen_rotri_tl tcg_gen_rotri_i64
+#define tcg_gen_deposit_tl tcg_gen_deposit_i64
#define tcg_const_tl tcg_const_i64
#define tcg_const_local_tl tcg_const_local_i64
#else
@@ -2454,6 +2517,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#define tcg_gen_rotli_tl tcg_gen_rotli_i32
#define tcg_gen_rotr_tl tcg_gen_rotr_i32
#define tcg_gen_rotri_tl tcg_gen_rotri_i32
+#define tcg_gen_deposit_tl tcg_gen_deposit_i32
#define tcg_const_tl tcg_const_i32
#define tcg_const_local_tl tcg_const_local_i32
#endif
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 2a98fed909..2c7ca1a450 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -78,6 +78,9 @@ DEF(sar_i32, 1, 2, 0, 0)
DEF(rotl_i32, 1, 2, 0, 0)
DEF(rotr_i32, 1, 2, 0, 0)
#endif
+#ifdef TCG_TARGET_HAS_deposit_i32
+DEF(deposit_i32, 1, 2, 2, 0)
+#endif
DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
#if TCG_TARGET_REG_BITS == 32
@@ -168,6 +171,9 @@ DEF(sar_i64, 1, 2, 0, 0)
DEF(rotl_i64, 1, 2, 0, 0)
DEF(rotr_i64, 1, 2, 0, 0)
#endif
+#ifdef TCG_TARGET_HAS_deposit_i64
+DEF(deposit_i64, 1, 2, 2, 0)
+#endif
DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
#ifdef TCG_TARGET_HAS_ext8s_i64
diff --git a/tests/Makefile b/tests/Makefile
index e43ec70b6d..9ded4b7349 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -7,7 +7,8 @@ QEMU=../i386-linux-user/qemu-i386
QEMU_X86_64=../x86_64-linux-user/qemu-x86_64
CC_X86_64=$(CC_I386) -m64
-CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I..
+QEMU_INCLUDES += -I..
+CFLAGS=-Wall -O2 -g -fno-strict-aliasing
#CFLAGS+=-msse2
LDFLAGS=
diff --git a/tests/cris/check_abs.c b/tests/cris/check_abs.c
index 3966c87c78..9770a8d9ef 100644
--- a/tests/cris/check_abs.c
+++ b/tests/cris/check_abs.c
@@ -4,13 +4,14 @@
#include "sys.h"
#include "crisutils.h"
-extern inline int cris_abs(int n) {
+static inline int cris_abs(int n)
+{
int r;
asm ("abs\t%1, %0\n" : "=r" (r) : "r" (n));
return r;
}
-extern inline void
+static inline void
verify_abs(int val, int res,
const int n, const int z, const int v, const int c)
{
diff --git a/tests/cris/check_addc.c b/tests/cris/check_addc.c
index e4078555f8..facd1bea2d 100644
--- a/tests/cris/check_addc.c
+++ b/tests/cris/check_addc.c
@@ -4,7 +4,8 @@
#include "sys.h"
#include "crisutils.h"
-extern inline int cris_addc(int a, const int b) {
+static inline int cris_addc(int a, const int b)
+{
asm ("addc\t%1, %0\n" : "+r" (a) : "r" (b));
return a;
}
diff --git a/tests/cris/check_addcm.c b/tests/cris/check_addcm.c
index 9ffea29bd9..7928bc9999 100644
--- a/tests/cris/check_addcm.c
+++ b/tests/cris/check_addcm.c
@@ -5,13 +5,15 @@
#include "crisutils.h"
/* need to avoid acr as source here. */
-extern inline int cris_addc_m(int a, const int *b) {
+static inline int cris_addc_m(int a, const int *b)
+{
asm volatile ("addc [%1], %0\n" : "+r" (a) : "r" (b));
return a;
}
/* 'b' is a crisv32 constrain to avoid postinc with $acr. */
-extern inline int cris_addc_pi_m(int a, int **b) {
+static inline int cris_addc_pi_m(int a, int **b)
+{
asm volatile ("addc [%1+], %0\n" : "+r" (a), "+b" (*b));
return a;
}
diff --git a/tests/cris/check_bound.c b/tests/cris/check_bound.c
index 411d2ad56e..e8831754ec 100644
--- a/tests/cris/check_bound.c
+++ b/tests/cris/check_bound.c
@@ -4,19 +4,22 @@
#include "sys.h"
#include "crisutils.h"
-extern inline int cris_bound_b(int v, int b) {
+static inline int cris_bound_b(int v, int b)
+{
int r = v;
asm ("bound.b\t%1, %0\n" : "+r" (r) : "ri" (b));
return r;
}
-extern inline int cris_bound_w(int v, int b) {
+static inline int cris_bound_w(int v, int b)
+{
int r = v;
asm ("bound.w\t%1, %0\n" : "+r" (r) : "ri" (b));
return r;
}
-extern inline int cris_bound_d(int v, int b) {
+static inline int cris_bound_d(int v, int b)
+{
int r = v;
asm ("bound.d\t%1, %0\n" : "+r" (r) : "ri" (b));
return r;
diff --git a/tests/cris/check_ftag.c b/tests/cris/check_ftag.c
index 40d1507a87..908773a38a 100644
--- a/tests/cris/check_ftag.c
+++ b/tests/cris/check_ftag.c
@@ -4,19 +4,23 @@
#include "sys.h"
#include "crisutils.h"
-extern inline void cris_ftag_i(unsigned int x) {
+static inline void cris_ftag_i(unsigned int x)
+{
register unsigned int v asm("$r10") = x;
asm ("ftagi\t[%0]\n" : : "r" (v) );
}
-extern inline void cris_ftag_d(unsigned int x) {
+static inline void cris_ftag_d(unsigned int x)
+{
register unsigned int v asm("$r10") = x;
asm ("ftagd\t[%0]\n" : : "r" (v) );
}
-extern inline void cris_fidx_i(unsigned int x) {
+static inline void cris_fidx_i(unsigned int x)
+{
register unsigned int v asm("$r10") = x;
asm ("fidxi\t[%0]\n" : : "r" (v) );
}
-extern inline void cris_fidx_d(unsigned int x) {
+static inline void cris_fidx_d(unsigned int x)
+{
register unsigned int v asm("$r10") = x;
asm ("fidxd\t[%0]\n" : : "r" (v) );
}
diff --git a/tests/cris/check_int64.c b/tests/cris/check_int64.c
index 99ca6f1158..fc600176e2 100644
--- a/tests/cris/check_int64.c
+++ b/tests/cris/check_int64.c
@@ -5,11 +5,13 @@
#include "crisutils.h"
-extern inline int64_t add64(const int64_t a, const int64_t b) {
+static inline int64_t add64(const int64_t a, const int64_t b)
+{
return a + b;
}
-extern inline int64_t sub64(const int64_t a, const int64_t b) {
+static inline int64_t sub64(const int64_t a, const int64_t b)
+{
return a - b;
}
diff --git a/tests/cris/check_lz.c b/tests/cris/check_lz.c
index 7b30a265ad..69c2e6d4ec 100644
--- a/tests/cris/check_lz.c
+++ b/tests/cris/check_lz.c
@@ -3,7 +3,7 @@
#include <stdint.h>
#include "sys.h"
-extern inline int cris_lz(int x)
+static inline int cris_lz(int x)
{
int r;
asm ("lz\t%1, %0\n" : "=r" (r) : "r" (x));
diff --git a/tests/cris/check_swap.c b/tests/cris/check_swap.c
index 824a685517..f851cbcef1 100644
--- a/tests/cris/check_swap.c
+++ b/tests/cris/check_swap.c
@@ -9,7 +9,7 @@
#define B 2
#define R 1
-extern inline int cris_swap(const int mode, int x)
+static inline int cris_swap(const int mode, int x)
{
switch (mode)
{
diff --git a/tests/cris/crisutils.h b/tests/cris/crisutils.h
index 7d1ea86f73..29b71cd7b9 100644
--- a/tests/cris/crisutils.h
+++ b/tests/cris/crisutils.h
@@ -10,57 +10,57 @@ void _err(void) {
_fail(tst_cc_loc);
}
-extern inline void cris_tst_cc_n1(void)
+static inline void cris_tst_cc_n1(void)
{
asm volatile ("bpl _err\n"
"nop\n");
}
-extern inline void cris_tst_cc_n0(void)
+static inline void cris_tst_cc_n0(void)
{
asm volatile ("bmi _err\n"
"nop\n");
}
-extern inline void cris_tst_cc_z1(void)
+static inline void cris_tst_cc_z1(void)
{
asm volatile ("bne _err\n"
"nop\n");
}
-extern inline void cris_tst_cc_z0(void)
+static inline void cris_tst_cc_z0(void)
{
asm volatile ("beq _err\n"
"nop\n");
}
-extern inline void cris_tst_cc_v1(void)
+static inline void cris_tst_cc_v1(void)
{
asm volatile ("bvc _err\n"
"nop\n");
}
-extern inline void cris_tst_cc_v0(void)
+static inline void cris_tst_cc_v0(void)
{
asm volatile ("bvs _err\n"
"nop\n");
}
-extern inline void cris_tst_cc_c1(void)
+static inline void cris_tst_cc_c1(void)
{
asm volatile ("bcc _err\n"
"nop\n");
}
-extern inline void cris_tst_cc_c0(void)
+static inline void cris_tst_cc_c0(void)
{
asm volatile ("bcs _err\n"
"nop\n");
}
-extern inline void cris_tst_mov_cc(int n, int z)
+static inline void cris_tst_mov_cc(int n, int z)
{
if (n) cris_tst_cc_n1(); else cris_tst_cc_n0();
if (z) cris_tst_cc_z1(); else cris_tst_cc_z0();
asm volatile ("" : : "g" (_err));
}
-extern inline void cris_tst_cc(const int n, const int z,
+static inline void cris_tst_cc(const int n, const int z,
const int v, const int c)
{
if (n) cris_tst_cc_n1(); else cris_tst_cc_n0();
diff --git a/tests/hello-i386.c b/tests/hello-i386.c
index e00245d3fe..86afc34fb1 100644
--- a/tests/hello-i386.c
+++ b/tests/hello-i386.c
@@ -1,6 +1,6 @@
#include <asm/unistd.h>
-extern inline volatile void exit(int status)
+static inline volatile void exit(int status)
{
int __res;
__asm__ volatile ("movl %%ecx,%%ebx\n"\
@@ -8,7 +8,7 @@ extern inline volatile void exit(int status)
: "=a" (__res) : "0" (__NR_exit),"c" ((long)(status)));
}
-extern inline int write(int fd, const char * buf, int len)
+static inline int write(int fd, const char * buf, int len)
{
int status;
__asm__ volatile ("pushl %%ebx\n"\
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index a51ddc8a18..17a621a2ba 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -444,22 +444,19 @@ static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_
if (vs->sasl.mechlist[len] != '\0' &&
vs->sasl.mechlist[len] != ',') {
VNC_DEBUG("One %d", vs->sasl.mechlist[len]);
- vnc_client_error(vs);
- return -1;
+ goto fail;
}
} else {
char *offset = strstr(vs->sasl.mechlist, mechname);
VNC_DEBUG("Two %p\n", offset);
if (!offset) {
- vnc_client_error(vs);
- return -1;
+ goto fail;
}
VNC_DEBUG("Two '%s'\n", offset);
if (offset[-1] != ',' ||
(offset[len] != '\0'&&
offset[len] != ',')) {
- vnc_client_error(vs);
- return -1;
+ goto fail;
}
}
@@ -469,6 +466,11 @@ static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_
VNC_DEBUG("Validated mechname '%s'\n", mechname);
vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4);
return 0;
+
+ fail:
+ vnc_client_error(vs);
+ free(mechname);
+ return -1;
}
static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len)