aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CODING_STYLE3
-rw-r--r--MAINTAINERS69
-rw-r--r--Makefile26
-rw-r--r--Makefile.objs4
-rw-r--r--Makefile.target15
-rw-r--r--arch_init.c35
-rw-r--r--arch_init.h1
-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.c46
-rw-r--r--audio/spiceaudio.c5
-rw-r--r--audio/winwaveaudio.c3
-rw-r--r--block-migration.c29
-rw-r--r--block.c20
-rw-r--r--block.h3
-rw-r--r--block/qcow2-cache.c314
-rw-r--r--block/qcow2-cluster.c292
-rw-r--r--block/qcow2-refcount.c265
-rw-r--r--block/qcow2.c56
-rw-r--r--block/qcow2.h34
-rw-r--r--block/qed.c30
-rw-r--r--block/raw-win32.c2
-rw-r--r--block/sheepdog.c17
-rw-r--r--block/vpc.c47
-rw-r--r--block/vvfat.c1
-rw-r--r--block_int.h5
-rw-r--r--blockdev.c254
-rw-r--r--blockdev.h19
-rw-r--r--bsd-user/elfload.c37
-rw-r--r--cache-utils.h2
-rw-r--r--cmd.h36
-rwxr-xr-xconfigure467
-rw-r--r--cutils.c36
-rw-r--r--dis-asm.h87
-rw-r--r--disas.c5
-rw-r--r--docs/qdev-device-use.txt13
-rw-r--r--docs/tracing.txt5
-rw-r--r--envlist.h14
-rw-r--r--exec-all.h2
-rw-r--r--exec.c7
-rw-r--r--fpu/softfloat-specialize.h58
-rw-r--r--fpu/softfloat.h5
-rw-r--r--fsdev/qemu-fsdev.h4
-rw-r--r--gdbstub.c6
-rw-r--r--gdbstub.h2
-rw-r--r--hmp-commands.hx19
-rw-r--r--hw/arm_sysctl.c17
-rw-r--r--hw/device-hotplug.c5
-rw-r--r--hw/ecc.c27
-rw-r--r--hw/escc.c8
-rw-r--r--hw/etraxfs_timer.c4
-rw-r--r--hw/file-op-9p.h2
-rw-r--r--hw/flash.h3
-rw-r--r--hw/grlib.h126
-rw-r--r--hw/grlib_apbuart.c187
-rw-r--r--hw/grlib_gptimer.c395
-rw-r--r--hw/grlib_irqmp.c376
-rw-r--r--hw/gt64xxx.c120
-rw-r--r--hw/gumstix.c4
-rw-r--r--hw/hw.h21
-rw-r--r--hw/ide.h2
-rw-r--r--hw/ide/ahci.c11
-rw-r--r--hw/ide/core.c119
-rw-r--r--hw/ide/internal.h4
-rw-r--r--hw/ide/pci.c13
-rw-r--r--hw/lan9118.c4
-rw-r--r--hw/leon3.c218
-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/mc146818rtc.c15
-rw-r--r--hw/mips.h4
-rw-r--r--hw/mips_fulong2e.c4
-rw-r--r--hw/mips_jazz.c24
-rw-r--r--hw/mips_malta.c27
-rw-r--r--hw/mips_timer.c44
-rw-r--r--hw/multiboot.c2
-rw-r--r--hw/onenand.c1
-rw-r--r--hw/pc.c17
-rw-r--r--hw/pc.h3
-rw-r--r--hw/pc_piix.c3
-rw-r--r--hw/pci-hotplug.c3
-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/pl181.c7
-rw-r--r--hw/pl190.c38
-rw-r--r--hw/ppc405_uc.c5
-rw-r--r--hw/ppc_prep.c5
-rw-r--r--hw/pxa.h10
-rw-r--r--hw/pxa2xx.c6
-rw-r--r--hw/pxa2xx_gpio.c150
-rw-r--r--hw/pxa2xx_lcd.c4
-rw-r--r--hw/qdev.c15
-rw-r--r--hw/qdev.h2
-rw-r--r--hw/r2d.c31
-rw-r--r--hw/s390-virtio-bus.h16
-rw-r--r--hw/scsi-bus.c8
-rw-r--r--hw/scsi-disk.c3
-rw-r--r--hw/scsi.h6
-rw-r--r--hw/sd.c7
-rw-r--r--hw/sh7750.c20
-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/sharpsl.h7
-rw-r--r--hw/sm501.c47
-rw-r--r--hw/smc91c111.c30
-rw-r--r--hw/spitz.c349
-rw-r--r--hw/ssi-sd.c7
-rw-r--r--hw/tosa.c35
-rw-r--r--hw/usb-bt.c525
-rw-r--r--hw/usb-bus.c129
-rw-r--r--hw/usb-desc.c406
-rw-r--r--hw/usb-desc.h92
-rw-r--r--hw/usb-hid.c491
-rw-r--r--hw/usb-hub.c250
-rw-r--r--hw/usb-msd.c274
-rw-r--r--hw/usb-musb.c44
-rw-r--r--hw/usb-net.c528
-rw-r--r--hw/usb-ohci.c88
-rw-r--r--hw/usb-serial.c236
-rw-r--r--hw/usb-uhci.c98
-rw-r--r--hw/usb-wacom.c214
-rw-r--r--hw/usb.c34
-rw-r--r--hw/usb.h50
-rw-r--r--hw/versatilepb.c24
-rw-r--r--hw/virtio-9p-xattr.h17
-rw-r--r--hw/virtio-9p.h4
-rw-r--r--hw/virtio-blk.c50
-rw-r--r--hw/virtio-net.c13
-rw-r--r--hw/watchdog.h8
-rw-r--r--hw/zaurus.c115
-rw-r--r--kvm-all.c8
-rw-r--r--linux-user/arm/nwfpe/fpa11.h6
-rw-r--r--linux-user/arm/nwfpe/fpopcode.h4
-rw-r--r--linux-user/ioctls.h2
-rw-r--r--linux-user/signal.c16
-rw-r--r--linux-user/syscall.c4
-rw-r--r--monitor.c9
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/keymaps/bepo333
-rw-r--r--pc-bios/openbios-ppcbin320328 -> 729876 bytes
-rw-r--r--pc-bios/openbios-sparc32bin217660 -> 377388 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1065864 -> 1598328 bytes
-rw-r--r--pc-bios/optionrom/Makefile2
-rw-r--r--qemu-common.h19
-rw-r--r--qemu-doc.texi2
-rw-r--r--qemu-img.c4
-rw-r--r--qemu-img.texi41
-rw-r--r--qemu-io.c6
-rw-r--r--qemu-timer.c15
-rw-r--r--qmp-commands.hx28
-rw-r--r--rules.mak8
-rw-r--r--savevm.c1
-rwxr-xr-xscripts/checkpatch.pl2910
-rwxr-xr-xscripts/create_config (renamed from create_config)0
-rw-r--r--scripts/feature_to_c.sh (renamed from feature_to_c.sh)3
-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)60
-rw-r--r--slirp/slirp.h2
-rw-r--r--slirp/tftp.c4
-rw-r--r--sysemu.h15
-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.c50
-rw-r--r--target-arm/translate.c281
-rw-r--r--target-cris/translate.c14
-rw-r--r--target-i386/translate.c34
-rw-r--r--target-microblaze/helper.h3
-rw-r--r--target-microblaze/op_helper.c45
-rw-r--r--target-microblaze/translate.c338
-rw-r--r--target-mips/translate.c20
-rw-r--r--target-ppc/op_helper.c192
-rw-r--r--target-ppc/translate.c2
-rw-r--r--target-s390x/cpu.h6
-rw-r--r--target-sh4/cpu.h65
-rw-r--r--target-sh4/helper.c150
-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/cpu.h38
-rw-r--r--target-sparc/helper.c8
-rw-r--r--target-sparc/helper.h1
-rw-r--r--target-sparc/op_helper.c212
-rw-r--r--target-sparc/translate.c24
-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/cris/sys.h4
-rw-r--r--tests/hello-i386.c4
-rw-r--r--trace-events35
-rw-r--r--ui/cocoa.m6
-rw-r--r--ui/d3des.h8
-rw-r--r--ui/sdl.c6
-rw-r--r--ui/vnc-auth-sasl.c14
-rw-r--r--ui/x_keymap.h4
-rw-r--r--vl.c108
228 files changed, 10960 insertions, 4081 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 59effc7143..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
@@ -329,8 +329,8 @@ F: hw/lsi53c895a.c
F: hw/scsi*
USB
-M: qemu-devel@nongnu.org
-S: Odd Fixes
+M: Gerd Hoffmann <kraxel@redhat.com>
+S: Maintained
F: hw/usb*
vhost
@@ -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.objs b/Makefile.objs
index c3e52c5674..93406ff392 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -19,7 +19,7 @@ block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
-block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
+block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-nested-y += qed-check.o
block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
@@ -88,7 +88,7 @@ common-obj-y += eeprom93xx.o
common-obj-y += scsi-disk.o cdrom.o
common-obj-y += scsi-generic.o scsi-bus.o
common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
-common-obj-y += usb-serial.o usb-net.o usb-bus.o
+common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
common-obj-$(CONFIG_SSI) += ssi.o
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
common-obj-$(CONFIG_SD) += sd.o
diff --git a/Makefile.target b/Makefile.target
index e15b1c4fb6..b0ba95f76e 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) \
@@ -286,7 +286,10 @@ obj-sparc-y += cirrus_vga.o
else
obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
-obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
+obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
+
+# GRLIB
+obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
endif
obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
@@ -344,14 +347,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/arch_init.c b/arch_init.c
index e32e289c8f..cc56f0f998 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -461,7 +461,18 @@ void qemu_service_io(void)
}
#ifdef HAS_AUDIO
-struct soundhw soundhw[] = {
+struct soundhw {
+ const char *name;
+ const char *descr;
+ int enabled;
+ int isa;
+ union {
+ int (*init_isa) (qemu_irq *pic);
+ int (*init_pci) (PCIBus *bus);
+ } init;
+};
+
+static struct soundhw soundhw[] = {
#ifdef HAS_AUDIO_CHOICE
#if defined(TARGET_I386) || defined(TARGET_MIPS)
{
@@ -610,10 +621,32 @@ void select_soundhw(const char *optarg)
}
}
}
+
+void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus)
+{
+ struct soundhw *c;
+
+ for (c = soundhw; c->name; ++c) {
+ if (c->enabled) {
+ if (c->isa) {
+ if (isa_pic) {
+ c->init.init_isa(isa_pic);
+ }
+ } else {
+ if (pci_bus) {
+ c->init.init_pci(pci_bus);
+ }
+ }
+ }
+ }
+}
#else
void select_soundhw(const char *optarg)
{
}
+void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus)
+{
+}
#endif
int qemu_uuid_parse(const char *str, uint8_t *uuid)
diff --git a/arch_init.h b/arch_init.h
index 682890c0ec..17c9164d39 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -27,6 +27,7 @@ void do_acpitable_option(const char *optarg);
void do_smbios_option(const char *optarg);
void cpudef_init(void);
int audio_available(void);
+void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus);
int kvm_available(void);
int xen_available(void);
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..fb4510e426 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -33,13 +33,11 @@ typedef struct {
static struct {
int samples;
- int divisor;
char *server;
char *sink;
char *source;
} conf = {
- .samples = 1024,
- .divisor = 2,
+ .samples = 4096,
};
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
@@ -57,9 +55,6 @@ static void *qpa_thread_out (void *arg)
{
PAVoiceOut *pa = arg;
HWVoiceOut *hw = &pa->hw;
- int threshold;
-
- threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return NULL;
@@ -73,7 +68,7 @@ static void *qpa_thread_out (void *arg)
goto exit;
}
- if (pa->live > threshold) {
+ if (pa->live > 0) {
break;
}
@@ -82,8 +77,8 @@ static void *qpa_thread_out (void *arg)
}
}
- decr = to_mix = pa->live;
- rpos = hw->rpos;
+ decr = to_mix = audio_MIN (pa->live, conf.samples >> 2);
+ rpos = pa->rpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
return NULL;
@@ -110,8 +105,8 @@ static void *qpa_thread_out (void *arg)
return NULL;
}
- pa->live = 0;
pa->rpos = rpos;
+ pa->live -= decr;
pa->decr += decr;
}
@@ -152,9 +147,6 @@ static void *qpa_thread_in (void *arg)
{
PAVoiceIn *pa = arg;
HWVoiceIn *hw = &pa->hw;
- int threshold;
-
- threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return NULL;
@@ -168,7 +160,7 @@ static void *qpa_thread_in (void *arg)
goto exit;
}
- if (pa->dead > threshold) {
+ if (pa->dead > 0) {
break;
}
@@ -177,8 +169,8 @@ static void *qpa_thread_in (void *arg)
}
}
- incr = to_grab = pa->dead;
- wpos = hw->wpos;
+ incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2);
+ wpos = pa->wpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
return NULL;
@@ -195,7 +187,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;
}
@@ -295,6 +287,7 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
{
int error;
static pa_sample_spec ss;
+ static pa_buffer_attr ba;
struct audsettings obt_as = *as;
PAVoiceOut *pa = (PAVoiceOut *) hw;
@@ -302,6 +295,15 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
ss.channels = as->nchannels;
ss.rate = as->freq;
+ /*
+ * qemu audio tick runs at 250 Hz (by default), so processing
+ * data chunks worth 4 ms of sound should be a good fit.
+ */
+ ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
+ ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
+ ba.maxlength = -1;
+ ba.prebuf = -1;
+
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
pa->s = pa_simple_new (
@@ -312,7 +314,7 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
"pcm.playback",
&ss,
NULL, /* channel map */
- NULL, /* buffering attributes */
+ &ba, /* buffering attributes */
&error
);
if (!pa->s) {
@@ -323,6 +325,7 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ pa->rpos = hw->rpos;
if (!pa->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
@@ -377,6 +380,7 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ pa->wpos = hw->wpos;
if (!pa->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
@@ -472,12 +476,6 @@ struct audio_option qpa_options[] = {
.descr = "buffer size in samples"
},
{
- .name = "DIVISOR",
- .tag = AUD_OPT_INT,
- .valp = &conf.divisor,
- .descr = "threshold divisor"
- },
- {
.name = "SERVER",
.tag = AUD_OPT_STR,
.valp = &conf.server,
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-migration.c b/block-migration.c
index 14753254d6..c9d3e81dbf 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -350,7 +350,12 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f)
}
}
- progress = completed_sector_sum * 100 / block_mig_state.total_sector_sum;
+ if (block_mig_state.total_sector_sum != 0) {
+ progress = completed_sector_sum * 100 /
+ block_mig_state.total_sector_sum;
+ } else {
+ progress = 100;
+ }
if (progress != block_mig_state.prev_progress) {
block_mig_state.prev_progress = progress;
qemu_put_be64(f, (progress << BDRV_SECTOR_BITS)
@@ -633,8 +638,10 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
int len, flags;
char device_name[256];
int64_t addr;
- BlockDriverState *bs;
+ BlockDriverState *bs, *bs_prev = NULL;
uint8_t *buf;
+ int64_t total_sectors = 0;
+ int nr_sectors;
do {
addr = qemu_get_be64(f);
@@ -656,10 +663,26 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
return -EINVAL;
}
+ if (bs != bs_prev) {
+ bs_prev = bs;
+ total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+ if (total_sectors <= 0) {
+ error_report("Error getting length of block device %s\n",
+ device_name);
+ return -EINVAL;
+ }
+ }
+
+ if (total_sectors - addr < BDRV_SECTORS_PER_DIRTY_CHUNK) {
+ nr_sectors = total_sectors - addr;
+ } else {
+ nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
+ }
+
buf = qemu_malloc(BLOCK_SIZE);
qemu_get_buffer(f, buf, BLOCK_SIZE);
- ret = bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK);
+ ret = bdrv_write(bs, addr, buf, nr_sectors);
qemu_free(buf);
if (ret < 0) {
diff --git a/block.c b/block.c
index ff2795b1e9..998df1b54b 100644
--- a/block.c
+++ b/block.c
@@ -645,7 +645,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
/* call the change callback */
bs->media_changed = 1;
if (bs->change_cb)
- bs->change_cb(bs->change_opaque);
+ bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
}
return 0;
@@ -684,7 +684,7 @@ void bdrv_close(BlockDriverState *bs)
/* call the change callback */
bs->media_changed = 1;
if (bs->change_cb)
- bs->change_cb(bs->change_opaque);
+ bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
}
}
@@ -1135,6 +1135,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
+ if (bs->change_cb) {
+ bs->change_cb(bs->change_opaque, CHANGE_SIZE);
+ }
}
return ret;
}
@@ -1366,7 +1369,8 @@ int bdrv_enable_write_cache(BlockDriverState *bs)
/* XXX: no longer used */
void bdrv_set_change_cb(BlockDriverState *bs,
- void (*change_cb)(void *opaque), void *opaque)
+ void (*change_cb)(void *opaque, int reason),
+ void *opaque)
{
bs->change_cb = change_cb;
bs->change_opaque = opaque;
@@ -1411,7 +1415,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
/* call the change callback now, we skipped it on open */
bs->media_changed = 1;
if (bs->change_cb)
- bs->change_cb(bs->change_opaque);
+ bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
}
return ret;
}
@@ -2778,6 +2782,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
QEMUOptionParameter *backing_fmt, *backing_file;
BlockDriverState *bs = NULL;
BlockDriver *drv, *proto_drv;
+ BlockDriver *backing_drv = NULL;
int ret = 0;
/* Find driver and parse its options */
@@ -2846,7 +2851,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
if (backing_fmt && backing_fmt->value.s) {
- if (!bdrv_find_format(backing_fmt->value.s)) {
+ backing_drv = bdrv_find_format(backing_fmt->value.s);
+ if (!backing_drv) {
error_report("Unknown backing file format '%s'",
backing_fmt->value.s);
ret = -EINVAL;
@@ -2863,9 +2869,9 @@ int bdrv_img_create(const char *filename, const char *fmt,
bs = bdrv_new("");
- ret = bdrv_open(bs, backing_file->value.s, flags, drv);
+ ret = bdrv_open(bs, backing_file->value.s, flags, backing_drv);
if (ret < 0) {
- error_report("Could not open '%s'", filename);
+ error_report("Could not open '%s'", backing_file->value.s);
goto out;
}
bdrv_get_geometry(bs, &size);
diff --git a/block.h b/block.h
index f923add60d..239f729580 100644
--- a/block.h
+++ b/block.h
@@ -182,7 +182,8 @@ int bdrv_is_locked(BlockDriverState *bs);
void bdrv_set_locked(BlockDriverState *bs, int locked);
int bdrv_eject(BlockDriverState *bs, int eject_flag);
void bdrv_set_change_cb(BlockDriverState *bs,
- void (*change_cb)(void *opaque), void *opaque);
+ void (*change_cb)(void *opaque, int reason),
+ void *opaque);
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
BlockDriverState *bdrv_find(const char *name);
BlockDriverState *bdrv_next(BlockDriverState *bs);
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
new file mode 100644
index 0000000000..382473933c
--- /dev/null
+++ b/block/qcow2-cache.c
@@ -0,0 +1,314 @@
+/*
+ * L2/refcount table cache for the QCOW2 format
+ *
+ * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "block_int.h"
+#include "qemu-common.h"
+#include "qcow2.h"
+
+typedef struct Qcow2CachedTable {
+ void* table;
+ int64_t offset;
+ bool dirty;
+ int cache_hits;
+ int ref;
+} Qcow2CachedTable;
+
+struct Qcow2Cache {
+ Qcow2CachedTable* entries;
+ struct Qcow2Cache* depends;
+ int size;
+ bool depends_on_flush;
+ bool writethrough;
+};
+
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
+ bool writethrough)
+{
+ BDRVQcowState *s = bs->opaque;
+ Qcow2Cache *c;
+ int i;
+
+ c = qemu_mallocz(sizeof(*c));
+ c->size = num_tables;
+ c->entries = qemu_mallocz(sizeof(*c->entries) * num_tables);
+ c->writethrough = writethrough;
+
+ for (i = 0; i < c->size; i++) {
+ c->entries[i].table = qemu_blockalign(bs, s->cluster_size);
+ }
+
+ return c;
+}
+
+int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
+{
+ int i;
+
+ for (i = 0; i < c->size; i++) {
+ assert(c->entries[i].ref == 0);
+ qemu_vfree(c->entries[i].table);
+ }
+
+ qemu_free(c->entries);
+ qemu_free(c);
+
+ return 0;
+}
+
+static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
+{
+ int ret;
+
+ ret = qcow2_cache_flush(bs, c->depends);
+ if (ret < 0) {
+ return ret;
+ }
+
+ c->depends = NULL;
+ c->depends_on_flush = false;
+
+ return 0;
+}
+
+static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
+{
+ BDRVQcowState *s = bs->opaque;
+ int ret = 0;
+
+ if (!c->entries[i].dirty || !c->entries[i].offset) {
+ return 0;
+ }
+
+ if (c->depends) {
+ ret = qcow2_cache_flush_dependency(bs, c);
+ } else if (c->depends_on_flush) {
+ ret = bdrv_flush(bs->file);
+ if (ret >= 0) {
+ c->depends_on_flush = false;
+ }
+ }
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (c == s->refcount_block_cache) {
+ BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
+ } else if (c == s->l2_table_cache) {
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
+ }
+
+ ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table,
+ s->cluster_size);
+ if (ret < 0) {
+ return ret;
+ }
+
+ c->entries[i].dirty = false;
+
+ return 0;
+}
+
+int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
+{
+ int result = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < c->size; i++) {
+ ret = qcow2_cache_entry_flush(bs, c, i);
+ if (ret < 0 && result != -ENOSPC) {
+ result = ret;
+ }
+ }
+
+ if (result == 0) {
+ ret = bdrv_flush(bs->file);
+ if (ret < 0) {
+ result = ret;
+ }
+ }
+
+ return result;
+}
+
+int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
+ Qcow2Cache *dependency)
+{
+ int ret;
+
+ if (dependency->depends) {
+ ret = qcow2_cache_flush_dependency(bs, dependency);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ if (c->depends && (c->depends != dependency)) {
+ ret = qcow2_cache_flush_dependency(bs, c);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ c->depends = dependency;
+ return 0;
+}
+
+void qcow2_cache_depends_on_flush(Qcow2Cache *c)
+{
+ c->depends_on_flush = true;
+}
+
+static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
+{
+ int i;
+ int min_count = INT_MAX;
+ int min_index = -1;
+
+
+ for (i = 0; i < c->size; i++) {
+ if (c->entries[i].ref) {
+ continue;
+ }
+
+ if (c->entries[i].cache_hits < min_count) {
+ min_index = i;
+ min_count = c->entries[i].cache_hits;
+ }
+
+ /* Give newer hits priority */
+ /* TODO Check how to optimize the replacement strategy */
+ c->entries[i].cache_hits /= 2;
+ }
+
+ if (min_index == -1) {
+ /* This can't happen in current synchronous code, but leave the check
+ * here as a reminder for whoever starts using AIO with the cache */
+ abort();
+ }
+ return min_index;
+}
+
+static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
+ uint64_t offset, void **table, bool read_from_disk)
+{
+ BDRVQcowState *s = bs->opaque;
+ int i;
+ int ret;
+
+ /* Check if the table is already cached */
+ for (i = 0; i < c->size; i++) {
+ if (c->entries[i].offset == offset) {
+ goto found;
+ }
+ }
+
+ /* If not, write a table back and replace it */
+ i = qcow2_cache_find_entry_to_replace(c);
+ if (i < 0) {
+ return i;
+ }
+
+ ret = qcow2_cache_entry_flush(bs, c, i);
+ if (ret < 0) {
+ return ret;
+ }
+
+ c->entries[i].offset = 0;
+ if (read_from_disk) {
+ if (c == s->l2_table_cache) {
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
+ }
+
+ ret = bdrv_pread(bs->file, offset, c->entries[i].table, s->cluster_size);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ /* Give the table some hits for the start so that it won't be replaced
+ * immediately. The number 32 is completely arbitrary. */
+ c->entries[i].cache_hits = 32;
+ c->entries[i].offset = offset;
+
+ /* And return the right table */
+found:
+ c->entries[i].cache_hits++;
+ c->entries[i].ref++;
+ *table = c->entries[i].table;
+ return 0;
+}
+
+int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+ void **table)
+{
+ return qcow2_cache_do_get(bs, c, offset, table, true);
+}
+
+int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+ void **table)
+{
+ return qcow2_cache_do_get(bs, c, offset, table, false);
+}
+
+int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
+{
+ int i;
+
+ for (i = 0; i < c->size; i++) {
+ if (c->entries[i].table == *table) {
+ goto found;
+ }
+ }
+ return -ENOENT;
+
+found:
+ c->entries[i].ref--;
+ *table = NULL;
+
+ assert(c->entries[i].ref >= 0);
+
+ if (c->writethrough) {
+ return qcow2_cache_entry_flush(bs, c, i);
+ } else {
+ return 0;
+ }
+}
+
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
+{
+ int i;
+
+ for (i = 0; i < c->size; i++) {
+ if (c->entries[i].table == table) {
+ goto found;
+ }
+ }
+ abort();
+
+found:
+ c->entries[i].dirty = true;
+}
+
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 6928c6341d..5fb8c6695a 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -67,7 +67,11 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
qemu_free(new_l1_table);
return new_l1_table_offset;
}
- bdrv_flush(bs->file);
+
+ ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+ if (ret < 0) {
+ return ret;
+ }
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
for(i = 0; i < s->l1_size; i++)
@@ -81,7 +85,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
/* set new table */
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
cpu_to_be32w((uint32_t*)data, new_l1_size);
- cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
+ cpu_to_be64wu((uint64_t*)(data + 4), new_l1_table_offset);
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data));
if (ret < 0) {
goto fail;
@@ -98,63 +102,6 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
return ret;
}
-void qcow2_l2_cache_reset(BlockDriverState *bs)
-{
- BDRVQcowState *s = bs->opaque;
-
- memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
- memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
- memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
-}
-
-static inline int l2_cache_new_entry(BlockDriverState *bs)
-{
- BDRVQcowState *s = bs->opaque;
- uint32_t min_count;
- int min_index, i;
-
- /* find a new entry in the least used one */
- min_index = 0;
- min_count = 0xffffffff;
- for(i = 0; i < L2_CACHE_SIZE; i++) {
- if (s->l2_cache_counts[i] < min_count) {
- min_count = s->l2_cache_counts[i];
- min_index = i;
- }
- }
- return min_index;
-}
-
-/*
- * seek_l2_table
- *
- * seek l2_offset in the l2_cache table
- * if not found, return NULL,
- * if found,
- * increments the l2 cache hit count of the entry,
- * if counter overflow, divide by two all counters
- * return the pointer to the l2 cache entry
- *
- */
-
-static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset)
-{
- int i, j;
-
- for(i = 0; i < L2_CACHE_SIZE; i++) {
- if (l2_offset == s->l2_cache_offsets[i]) {
- /* increment the hit count */
- if (++s->l2_cache_counts[i] == 0xffffffff) {
- for(j = 0; j < L2_CACHE_SIZE; j++) {
- s->l2_cache_counts[j] >>= 1;
- }
- }
- return s->l2_cache + (i << s->l2_bits);
- }
- }
- return NULL;
-}
-
/*
* l2_load
*
@@ -169,33 +116,11 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
uint64_t **l2_table)
{
BDRVQcowState *s = bs->opaque;
- int min_index;
int ret;
- /* seek if the table for the given offset is in the cache */
-
- *l2_table = seek_l2_table(s, l2_offset);
- if (*l2_table != NULL) {
- return 0;
- }
-
- /* not found: load a new entry in the least used one */
-
- min_index = l2_cache_new_entry(bs);
- *l2_table = s->l2_cache + (min_index << s->l2_bits);
-
- BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
- ret = bdrv_pread(bs->file, l2_offset, *l2_table,
- s->l2_size * sizeof(uint64_t));
- if (ret < 0) {
- qcow2_l2_cache_reset(bs);
- return ret;
- }
-
- s->l2_cache_offsets[min_index] = l2_offset;
- s->l2_cache_counts[min_index] = 1;
+ ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset, (void**) l2_table);
- return 0;
+ return ret;
}
/*
@@ -238,7 +163,6 @@ static int write_l1_entry(BlockDriverState *bs, int l1_index)
static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
{
BDRVQcowState *s = bs->opaque;
- int min_index;
uint64_t old_l2_offset;
uint64_t *l2_table;
int64_t l2_offset;
@@ -252,29 +176,48 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
if (l2_offset < 0) {
return l2_offset;
}
- bdrv_flush(bs->file);
+
+ ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+ if (ret < 0) {
+ goto fail;
+ }
/* allocate a new entry in the l2 cache */
- min_index = l2_cache_new_entry(bs);
- l2_table = s->l2_cache + (min_index << s->l2_bits);
+ ret = qcow2_cache_get_empty(bs, s->l2_table_cache, l2_offset, (void**) table);
+ if (ret < 0) {
+ return ret;
+ }
+
+ l2_table = *table;
if (old_l2_offset == 0) {
/* if there was no old l2 table, clear the new table */
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
} else {
+ uint64_t* old_table;
+
/* if there was an old l2 table, read it from the disk */
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
- ret = bdrv_pread(bs->file, old_l2_offset, l2_table,
- s->l2_size * sizeof(uint64_t));
+ ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_offset,
+ (void**) &old_table);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ memcpy(l2_table, old_table, s->cluster_size);
+
+ ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &old_table);
if (ret < 0) {
goto fail;
}
}
+
/* write the l2 table to the file */
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
- ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
- s->l2_size * sizeof(uint64_t));
+
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret < 0) {
goto fail;
}
@@ -286,17 +229,12 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
goto fail;
}
- /* update the l2 cache entry */
-
- s->l2_cache_offsets[min_index] = l2_offset;
- s->l2_cache_counts[min_index] = 1;
-
*table = l2_table;
return 0;
fail:
+ qcow2_cache_put(bs, s->l2_table_cache, (void**) table);
s->l1_table[l1_index] = old_l2_offset;
- qcow2_l2_cache_reset(bs);
return ret;
}
@@ -521,6 +459,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
&l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
}
+ qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+
nb_available = (c * s->cluster_sectors);
out:
if (nb_available > nb_needed)
@@ -575,6 +515,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
return ret;
}
} else {
+ /* FIXME Order */
if (l2_offset)
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
ret = l2_allocate(bs, l1_index, &l2_table);
@@ -632,6 +573,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
if (cluster_offset < 0) {
+ qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
return 0;
}
@@ -646,38 +588,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
/* compressed clusters never have the copied flag */
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
l2_table[l2_index] = cpu_to_be64(cluster_offset);
- if (bdrv_pwrite_sync(bs->file,
- l2_offset + l2_index * sizeof(uint64_t),
- l2_table + l2_index,
- sizeof(uint64_t)) < 0)
- return 0;
-
- return cluster_offset;
-}
-
-/*
- * Write L2 table updates to disk, writing whole sectors to avoid a
- * read-modify-write in bdrv_pwrite
- */
-#define L2_ENTRIES_PER_SECTOR (512 / 8)
-static int write_l2_entries(BlockDriverState *bs, uint64_t *l2_table,
- uint64_t l2_offset, int l2_index, int num)
-{
- int l2_start_index = l2_index & ~(L1_ENTRIES_PER_SECTOR - 1);
- int start_offset = (8 * l2_index) & ~511;
- int end_offset = (8 * (l2_index + num) + 511) & ~511;
- size_t len = end_offset - start_offset;
- int ret;
-
- BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
- ret = bdrv_pwrite(bs->file, l2_offset + start_offset,
- &l2_table[l2_start_index], len);
+ ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
if (ret < 0) {
- return ret;
+ return 0;
}
- return 0;
+ return cluster_offset;
}
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
@@ -686,6 +604,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
int i, j = 0, l2_index, ret;
uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
uint64_t cluster_offset = m->cluster_offset;
+ bool cow = false;
if (m->nb_clusters == 0)
return 0;
@@ -695,6 +614,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
/* copy content of unmodified sectors */
start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9;
if (m->n_start) {
+ cow = true;
ret = copy_sectors(bs, start_sect, cluster_offset, 0, m->n_start);
if (ret < 0)
goto err;
@@ -702,17 +622,30 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
if (m->nb_available & (s->cluster_sectors - 1)) {
uint64_t end = m->nb_available & ~(uint64_t)(s->cluster_sectors - 1);
+ cow = true;
ret = copy_sectors(bs, start_sect + end, cluster_offset + (end << 9),
m->nb_available - end, s->cluster_sectors);
if (ret < 0)
goto err;
}
- /* update L2 table */
+ /*
+ * Update L2 table.
+ *
+ * Before we update the L2 table to actually point to the new cluster, we
+ * need to be sure that the refcounts have been increased and COW was
+ * handled.
+ */
+ if (cow) {
+ qcow2_cache_depends_on_flush(s->l2_table_cache);
+ }
+
+ qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
ret = get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index);
if (ret < 0) {
goto err;
}
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
for (i = 0; i < m->nb_clusters; i++) {
/* if two concurrent writes happen to the same unallocated cluster
@@ -728,16 +661,9 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
}
- /*
- * Before we update the L2 table to actually point to the new cluster, we
- * need to be sure that the refcounts have been increased and COW was
- * handled.
- */
- bdrv_flush(bs->file);
- ret = write_l2_entries(bs, l2_table, l2_offset, l2_index, m->nb_clusters);
+ ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
if (ret < 0) {
- qcow2_l2_cache_reset(bs);
goto err;
}
@@ -746,7 +672,6 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
* Also flush bs->file to get the right order for L2 and refcount update.
*/
if (j != 0) {
- bdrv_flush(bs->file);
for (i = 0; i < j; i++) {
qcow2_free_any_clusters(bs,
be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
@@ -868,7 +793,8 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
m->depends_on = old_alloc;
m->nb_clusters = 0;
*num = 0;
- return 0;
+ ret = 0;
+ goto fail;
}
}
}
@@ -884,7 +810,8 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
if (cluster_offset < 0) {
QLIST_REMOVE(m, next_in_flight);
- return cluster_offset;
+ ret = cluster_offset;
+ goto fail;
}
/* save info needed for meta data update */
@@ -893,12 +820,21 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
m->nb_clusters = nb_clusters;
out:
+ ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ if (ret < 0) {
+ return ret;
+ }
+
m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
m->cluster_offset = cluster_offset;
*num = m->nb_available - n_start;
return 0;
+
+fail:
+ qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ return ret;
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
@@ -952,3 +888,85 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
}
return 0;
}
+
+/*
+ * This discards as many clusters of nb_clusters as possible at once (i.e.
+ * all clusters in the same L2 table) and returns the number of discarded
+ * clusters.
+ */
+static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
+ unsigned int nb_clusters)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t l2_offset, *l2_table;
+ int l2_index;
+ int ret;
+ int i;
+
+ ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Limit nb_clusters to one L2 table */
+ nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+
+ for (i = 0; i < nb_clusters; i++) {
+ uint64_t old_offset;
+
+ old_offset = be64_to_cpu(l2_table[l2_index + i]);
+ old_offset &= ~QCOW_OFLAG_COPIED;
+
+ if (old_offset == 0) {
+ continue;
+ }
+
+ /* First remove L2 entries */
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ l2_table[l2_index + i] = cpu_to_be64(0);
+
+ /* Then decrease the refcount */
+ qcow2_free_any_clusters(bs, old_offset, 1);
+ }
+
+ ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return nb_clusters;
+}
+
+int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
+ int nb_sectors)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t end_offset;
+ unsigned int nb_clusters;
+ int ret;
+
+ end_offset = offset + (nb_sectors << BDRV_SECTOR_BITS);
+
+ /* Round start up and end down */
+ offset = align_offset(offset, s->cluster_size);
+ end_offset &= ~(s->cluster_size - 1);
+
+ if (offset > end_offset) {
+ return 0;
+ }
+
+ nb_clusters = size_to_clusters(s, end_offset - offset);
+
+ /* Each L2 table is handled by its own loop iteration */
+ while (nb_clusters > 0) {
+ ret = discard_single_l2(bs, offset, nb_clusters);
+ if (ret < 0) {
+ return ret;
+ }
+
+ nb_clusters -= ret;
+ offset += (ret * s->cluster_size);
+ }
+
+ return 0;
+}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index a10453c875..915d85acbf 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -32,27 +32,6 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
int addend);
-static int cache_refcount_updates = 0;
-
-static int write_refcount_block(BlockDriverState *bs)
-{
- BDRVQcowState *s = bs->opaque;
- size_t size = s->cluster_size;
-
- if (s->refcount_block_cache_offset == 0) {
- return 0;
- }
-
- BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE);
- if (bdrv_pwrite_sync(bs->file, s->refcount_block_cache_offset,
- s->refcount_block_cache, size) < 0)
- {
- return -EIO;
- }
-
- return 0;
-}
-
/*********************************************************/
/* refcount handling */
@@ -61,7 +40,6 @@ int qcow2_refcount_init(BlockDriverState *bs)
BDRVQcowState *s = bs->opaque;
int ret, refcount_table_size2, i;
- s->refcount_block_cache = qemu_malloc(s->cluster_size);
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
s->refcount_table = qemu_malloc(refcount_table_size2);
if (s->refcount_table_size > 0) {
@@ -81,34 +59,22 @@ int qcow2_refcount_init(BlockDriverState *bs)
void qcow2_refcount_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
- qemu_free(s->refcount_block_cache);
qemu_free(s->refcount_table);
}
static int load_refcount_block(BlockDriverState *bs,
- int64_t refcount_block_offset)
+ int64_t refcount_block_offset,
+ void **refcount_block)
{
BDRVQcowState *s = bs->opaque;
int ret;
- if (cache_refcount_updates) {
- ret = write_refcount_block(bs);
- if (ret < 0) {
- return ret;
- }
- }
-
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_LOAD);
- ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache,
- s->cluster_size);
- if (ret < 0) {
- s->refcount_block_cache_offset = 0;
- return ret;
- }
+ ret = qcow2_cache_get(bs, s->refcount_block_cache, refcount_block_offset,
+ refcount_block);
- s->refcount_block_cache_offset = refcount_block_offset;
- return 0;
+ return ret;
}
/*
@@ -122,6 +88,8 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
int refcount_table_index, block_index;
int64_t refcount_block_offset;
int ret;
+ uint16_t *refcount_block;
+ uint16_t refcount;
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
if (refcount_table_index >= s->refcount_table_size)
@@ -129,16 +97,24 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
refcount_block_offset = s->refcount_table[refcount_table_index];
if (!refcount_block_offset)
return 0;
- if (refcount_block_offset != s->refcount_block_cache_offset) {
- /* better than nothing: return allocated if read error */
- ret = load_refcount_block(bs, refcount_block_offset);
- if (ret < 0) {
- return ret;
- }
+
+ ret = qcow2_cache_get(bs, s->refcount_block_cache, refcount_block_offset,
+ (void**) &refcount_block);
+ if (ret < 0) {
+ return ret;
}
+
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
- return be16_to_cpu(s->refcount_block_cache[block_index]);
+ refcount = be16_to_cpu(refcount_block[block_index]);
+
+ ret = qcow2_cache_put(bs, s->refcount_block_cache,
+ (void**) &refcount_block);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return refcount;
}
/*
@@ -174,9 +150,10 @@ static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a,
* Loads a refcount block. If it doesn't exist yet, it is allocated first
* (including growing the refcount table if needed).
*
- * Returns the offset of the refcount block on success or -errno in error case
+ * Returns 0 on success or -errno in error case
*/
-static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
+static int alloc_refcount_block(BlockDriverState *bs,
+ int64_t cluster_index, uint16_t **refcount_block)
{
BDRVQcowState *s = bs->opaque;
unsigned int refcount_table_index;
@@ -194,13 +171,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
/* If it's already there, we're done */
if (refcount_block_offset) {
- if (refcount_block_offset != s->refcount_block_cache_offset) {
- ret = load_refcount_block(bs, refcount_block_offset);
- if (ret < 0) {
- return ret;
- }
- }
- return refcount_block_offset;
+ return load_refcount_block(bs, refcount_block_offset,
+ (void**) refcount_block);
}
}
@@ -226,12 +198,10 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
* refcount block into the cache
*/
- if (cache_refcount_updates) {
- ret = write_refcount_block(bs);
- if (ret < 0) {
- return ret;
- }
- }
+ *refcount_block = NULL;
+
+ /* We write to the refcount table, so we might depend on L2 tables */
+ qcow2_cache_flush(bs, s->l2_table_cache);
/* Allocate the refcount block itself and mark it as used */
int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
@@ -247,13 +217,18 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
/* Zero the new refcount block before updating it */
- memset(s->refcount_block_cache, 0, s->cluster_size);
- s->refcount_block_cache_offset = new_block;
+ ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
+ (void**) refcount_block);
+ if (ret < 0) {
+ goto fail_block;
+ }
+
+ memset(*refcount_block, 0, s->cluster_size);
/* The block describes itself, need to update the cache */
int block_index = (new_block >> s->cluster_bits) &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
- s->refcount_block_cache[block_index] = cpu_to_be16(1);
+ (*refcount_block)[block_index] = cpu_to_be16(1);
} else {
/* Described somewhere else. This can recurse at most twice before we
* arrive at a block that describes itself. */
@@ -266,14 +241,19 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
/* Initialize the new refcount block only after updating its refcount,
* update_refcount uses the refcount cache itself */
- memset(s->refcount_block_cache, 0, s->cluster_size);
- s->refcount_block_cache_offset = new_block;
+ ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
+ (void**) refcount_block);
+ if (ret < 0) {
+ goto fail_block;
+ }
+
+ memset(*refcount_block, 0, s->cluster_size);
}
/* Now the new refcount block needs to be written to disk */
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
- ret = bdrv_pwrite_sync(bs->file, new_block, s->refcount_block_cache,
- s->cluster_size);
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
+ ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail_block;
}
@@ -290,7 +270,12 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
}
s->refcount_table[refcount_table_index] = new_block;
- return new_block;
+ return 0;
+ }
+
+ ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
+ if (ret < 0) {
+ goto fail_block;
}
/*
@@ -410,9 +395,9 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
s->free_cluster_index = old_free_cluster_index;
- ret = load_refcount_block(bs, new_block);
+ ret = load_refcount_block(bs, new_block, (void**) refcount_block);
if (ret < 0) {
- goto fail_block;
+ return ret;
}
return new_block;
@@ -420,41 +405,10 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
fail_table:
qemu_free(new_table);
fail_block:
- s->refcount_block_cache_offset = 0;
- return ret;
-}
-
-#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT)
-static int write_refcount_block_entries(BlockDriverState *bs,
- int64_t refcount_block_offset, int first_index, int last_index)
-{
- BDRVQcowState *s = bs->opaque;
- size_t size;
- int ret;
-
- if (cache_refcount_updates) {
- return 0;
+ if (*refcount_block != NULL) {
+ qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
}
-
- if (first_index < 0) {
- return 0;
- }
-
- first_index &= ~(REFCOUNTS_PER_SECTOR - 1);
- last_index = (last_index + REFCOUNTS_PER_SECTOR)
- & ~(REFCOUNTS_PER_SECTOR - 1);
-
- size = (last_index - first_index) << REFCOUNT_SHIFT;
-
- BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
- ret = bdrv_pwrite(bs->file,
- refcount_block_offset + (first_index << REFCOUNT_SHIFT),
- &s->refcount_block_cache[first_index], size);
- if (ret < 0) {
- return ret;
- }
-
- return 0;
+ return ret;
}
/* XXX: cache several refcount block clusters ? */
@@ -463,9 +417,8 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
{
BDRVQcowState *s = bs->opaque;
int64_t start, last, cluster_offset;
- int64_t refcount_block_offset = 0;
- int64_t table_index = -1, old_table_index;
- int first_index = -1, last_index = -1;
+ uint16_t *refcount_block = NULL;
+ int64_t old_table_index = -1;
int ret;
#ifdef DEBUG_ALLOC2
@@ -478,6 +431,11 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
return 0;
}
+ if (addend < 0) {
+ qcow2_cache_set_dependency(bs, s->refcount_block_cache,
+ s->l2_table_cache);
+ }
+
start = offset & ~(s->cluster_size - 1);
last = (offset + length - 1) & ~(s->cluster_size - 1);
for(cluster_offset = start; cluster_offset <= last;
@@ -485,42 +443,33 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
{
int block_index, refcount;
int64_t cluster_index = cluster_offset >> s->cluster_bits;
- int64_t new_block;
+ int64_t table_index =
+ cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
- /* Only write refcount block to disk when we are done with it */
- old_table_index = table_index;
- table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
- if ((old_table_index >= 0) && (table_index != old_table_index)) {
+ /* Load the refcount block and allocate it if needed */
+ if (table_index != old_table_index) {
+ if (refcount_block) {
+ ret = qcow2_cache_put(bs, s->refcount_block_cache,
+ (void**) &refcount_block);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
- ret = write_refcount_block_entries(bs, refcount_block_offset,
- first_index, last_index);
+ ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
if (ret < 0) {
- return ret;
+ goto fail;
}
-
- first_index = -1;
- last_index = -1;
}
+ old_table_index = table_index;
- /* Load the refcount block and allocate it if needed */
- new_block = alloc_refcount_block(bs, cluster_index);
- if (new_block < 0) {
- ret = new_block;
- goto fail;
- }
- refcount_block_offset = new_block;
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refcount_block);
/* we can update the count and save it */
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
- if (first_index == -1 || block_index < first_index) {
- first_index = block_index;
- }
- if (block_index > last_index) {
- last_index = block_index;
- }
- refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
+ refcount = be16_to_cpu(refcount_block[block_index]);
refcount += addend;
if (refcount < 0 || refcount > 0xffff) {
ret = -EINVAL;
@@ -529,17 +478,16 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
if (refcount == 0 && cluster_index < s->free_cluster_index) {
s->free_cluster_index = cluster_index;
}
- s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
+ refcount_block[block_index] = cpu_to_be16(refcount);
}
ret = 0;
fail:
-
/* Write last changed block to disk */
- if (refcount_block_offset != 0) {
+ if (refcount_block) {
int wret;
- wret = write_refcount_block_entries(bs, refcount_block_offset,
- first_index, last_index);
+ wret = qcow2_cache_put(bs, s->refcount_block_cache,
+ (void**) &refcount_block);
if (wret < 0) {
return ret < 0 ? ret : wret;
}
@@ -757,10 +705,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
int64_t old_offset, old_l2_offset;
- int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
-
- qcow2_l2_cache_reset(bs);
- cache_refcount_updates = 1;
+ int i, j, l1_modified, nb_csectors, refcount;
+ int ret;
l2_table = NULL;
l1_table = NULL;
@@ -783,17 +729,19 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
l1_allocated = 0;
}
- l2_size = s->l2_size * sizeof(uint64_t);
- l2_table = qemu_malloc(l2_size);
l1_modified = 0;
for(i = 0; i < l1_size; i++) {
l2_offset = l1_table[i];
if (l2_offset) {
old_l2_offset = l2_offset;
l2_offset &= ~QCOW_OFLAG_COPIED;
- l2_modified = 0;
- if (bdrv_pread(bs->file, l2_offset, l2_table, l2_size) != l2_size)
+
+ ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
+ (void**) &l2_table);
+ if (ret < 0) {
goto fail;
+ }
+
for(j = 0; j < s->l2_size; j++) {
offset = be64_to_cpu(l2_table[j]);
if (offset != 0) {
@@ -833,17 +781,22 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
offset |= QCOW_OFLAG_COPIED;
}
if (offset != old_offset) {
+ if (addend > 0) {
+ qcow2_cache_set_dependency(bs, s->l2_table_cache,
+ s->refcount_block_cache);
+ }
l2_table[j] = cpu_to_be64(offset);
- l2_modified = 1;
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
}
}
}
- if (l2_modified) {
- if (bdrv_pwrite_sync(bs->file,
- l2_offset, l2_table, l2_size) < 0)
- goto fail;
+
+ ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ if (ret < 0) {
+ goto fail;
}
+
if (addend != 0) {
refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);
} else {
@@ -871,16 +824,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
}
if (l1_allocated)
qemu_free(l1_table);
- qemu_free(l2_table);
- cache_refcount_updates = 0;
- write_refcount_block(bs);
return 0;
fail:
+ if (l2_table) {
+ qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ }
+
if (l1_allocated)
qemu_free(l1_table);
- qemu_free(l2_table);
- cache_refcount_updates = 0;
- write_refcount_block(bs);
return -EIO;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index b6b094c797..dbe4fdd44d 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -143,6 +143,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
int len, i, ret = 0;
QCowHeader header;
uint64_t ext_end;
+ bool writethrough;
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
if (ret < 0) {
@@ -217,8 +218,13 @@ static int qcow2_open(BlockDriverState *bs, int flags)
be64_to_cpus(&s->l1_table[i]);
}
}
- /* alloc L2 cache */
- s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+
+ /* alloc L2 table/refcount block cache */
+ writethrough = ((flags & BDRV_O_CACHE_MASK) == 0);
+ s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE, writethrough);
+ s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE,
+ writethrough);
+
s->cluster_cache = qemu_malloc(s->cluster_size);
/* one more sector for decompressed data alignment */
s->cluster_data = qemu_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
@@ -270,7 +276,9 @@ static int qcow2_open(BlockDriverState *bs, int flags)
qcow2_free_snapshots(bs);
qcow2_refcount_close(bs);
qemu_free(s->l1_table);
- qemu_free(s->l2_cache);
+ if (s->l2_table_cache) {
+ qcow2_cache_destroy(bs, s->l2_table_cache);
+ }
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
return ret;
@@ -719,7 +727,13 @@ static void qcow2_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
qemu_free(s->l1_table);
- qemu_free(s->l2_cache);
+
+ qcow2_cache_flush(bs, s->l2_table_cache);
+ qcow2_cache_flush(bs, s->refcount_block_cache);
+
+ qcow2_cache_destroy(bs, s->l2_table_cache);
+ qcow2_cache_destroy(bs, s->refcount_block_cache);
+
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
qcow2_refcount_close(bs);
@@ -1070,6 +1084,13 @@ static int qcow2_make_empty(BlockDriverState *bs)
return 0;
}
+static int qcow2_discard(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors)
+{
+ return qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
+ nb_sectors);
+}
+
static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
{
BDRVQcowState *s = bs->opaque;
@@ -1179,6 +1200,19 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
static int qcow2_flush(BlockDriverState *bs)
{
+ BDRVQcowState *s = bs->opaque;
+ int ret;
+
+ ret = qcow2_cache_flush(bs, s->l2_table_cache);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+ if (ret < 0) {
+ return ret;
+ }
+
return bdrv_flush(bs->file);
}
@@ -1186,6 +1220,19 @@ static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque)
{
+ BDRVQcowState *s = bs->opaque;
+ int ret;
+
+ ret = qcow2_cache_flush(bs, s->l2_table_cache);
+ if (ret < 0) {
+ return NULL;
+ }
+
+ ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+ if (ret < 0) {
+ return NULL;
+ }
+
return bdrv_aio_flush(bs->file, cb, opaque);
}
@@ -1309,6 +1356,7 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_aio_writev = qcow2_aio_writev,
.bdrv_aio_flush = qcow2_aio_flush,
+ .bdrv_discard = qcow2_discard,
.bdrv_truncate = qcow2_truncate,
.bdrv_write_compressed = qcow2_write_compressed,
diff --git a/block/qcow2.h b/block/qcow2.h
index 5217bea8a2..a019831838 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -51,6 +51,9 @@
#define L2_CACHE_SIZE 16
+/* Must be at least 4 to cover all cases of refcount table growth */
+#define REFCOUNT_CACHE_SIZE 4
+
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
@@ -78,6 +81,9 @@ typedef struct QCowSnapshot {
uint64_t vm_clock_nsec;
} QCowSnapshot;
+struct Qcow2Cache;
+typedef struct Qcow2Cache Qcow2Cache;
+
typedef struct BDRVQcowState {
int cluster_bits;
int cluster_size;
@@ -91,9 +97,10 @@ typedef struct BDRVQcowState {
uint64_t cluster_offset_mask;
uint64_t l1_table_offset;
uint64_t *l1_table;
- uint64_t *l2_cache;
- uint64_t l2_cache_offsets[L2_CACHE_SIZE];
- uint32_t l2_cache_counts[L2_CACHE_SIZE];
+
+ Qcow2Cache* l2_table_cache;
+ Qcow2Cache* refcount_block_cache;
+
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
@@ -102,8 +109,6 @@ typedef struct BDRVQcowState {
uint64_t *refcount_table;
uint64_t refcount_table_offset;
uint32_t refcount_table_size;
- uint64_t refcount_block_cache_offset;
- uint16_t *refcount_block_cache;
int64_t free_cluster_index;
int64_t free_byte_offset;
@@ -204,6 +209,8 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
int compressed_size);
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
+int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
+ int nb_sectors);
/* qcow2-snapshot.c functions */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
@@ -215,4 +222,21 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
void qcow2_free_snapshots(BlockDriverState *bs);
int qcow2_read_snapshots(BlockDriverState *bs);
+/* qcow2-cache.c functions */
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
+ bool writethrough);
+int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
+
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
+int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
+int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
+ Qcow2Cache *dependency);
+void qcow2_cache_depends_on_flush(Qcow2Cache *c);
+
+int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+ void **table);
+int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+ void **table);
+int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
+
#endif
diff --git a/block/qed.c b/block/qed.c
index 085c4f2210..32734486c5 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -469,6 +469,12 @@ static int qed_create(const char *filename, uint32_t cluster_size,
return ret;
}
+ /* File must start empty and grow, check truncate is supported */
+ ret = bdrv_truncate(bs, 0);
+ if (ret < 0) {
+ goto out;
+ }
+
if (backing_file) {
header.features |= QED_F_BACKING_FILE;
header.backing_filename_offset = sizeof(le_header);
@@ -971,6 +977,19 @@ static void qed_aio_write_prefill(void *opaque, int ret)
}
/**
+ * Check if the QED_F_NEED_CHECK bit should be set during allocating write
+ */
+static bool qed_should_set_need_check(BDRVQEDState *s)
+{
+ /* The flush before L2 update path ensures consistency */
+ if (s->bs->backing_hd) {
+ return false;
+ }
+
+ return !(s->header.features & QED_F_NEED_CHECK);
+}
+
+/**
* Write new data cluster
*
* @acb: Write request
@@ -995,15 +1014,12 @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
- /* Write new cluster if the image is already marked dirty */
- if (s->header.features & QED_F_NEED_CHECK) {
+ if (qed_should_set_need_check(s)) {
+ s->header.features |= QED_F_NEED_CHECK;
+ qed_write_header(s, qed_aio_write_prefill, acb);
+ } else {
qed_aio_write_prefill(acb, 0);
- return;
}
-
- /* Mark the image dirty before writing the new cluster */
- s->header.features |= QED_F_NEED_CHECK;
- qed_write_header(s, qed_aio_write_prefill, acb);
}
/**
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 06c97101bb..c204a80d79 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -153,7 +153,7 @@ static int raw_flush(BlockDriverState *bs)
int ret;
ret = FlushFileBuffers(s->hfile);
- if (ret != 0) {
+ if (ret == 0) {
return -EIO;
}
diff --git a/block/sheepdog.c b/block/sheepdog.c
index e62820a804..a54e0dee31 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1294,12 +1294,23 @@ static int do_sd_create(char *filename, int64_t vdi_size,
static int sd_create(const char *filename, QEMUOptionParameter *options)
{
int ret;
- uint32_t vid = 0;
+ uint32_t vid = 0, base_vid = 0;
int64_t vdi_size = 0;
char *backing_file = NULL;
+ BDRVSheepdogState s;
+ char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
+ uint32_t snapid;
strstart(filename, "sheepdog:", (const char **)&filename);
+ memset(&s, 0, sizeof(s));
+ memset(vdi, 0, sizeof(vdi));
+ memset(tag, 0, sizeof(tag));
+ if (parse_vdiname(&s, filename, vdi, &snapid, tag) < 0) {
+ error_report("invalid filename\n");
+ return -EINVAL;
+ }
+
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
vdi_size = options->value.n;
@@ -1338,11 +1349,11 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
return -EINVAL;
}
- vid = s->inode.vdi_id;
+ base_vid = s->inode.vdi_id;
bdrv_delete(bs);
}
- return do_sd_create((char *)filename, vdi_size, vid, NULL, 0, NULL, NULL);
+ return do_sd_create((char *)vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
}
static void sd_close(BlockDriverState *bs)
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/block_int.h b/block_int.h
index 12663e817d..6ebdc3eea2 100644
--- a/block_int.h
+++ b/block_int.h
@@ -153,7 +153,7 @@ struct BlockDriverState {
int valid_key; /* if true, a valid encryption key has been set */
int sg; /* if true, the device is a /dev/sg* */
/* event callback when inserting/removing */
- void (*change_cb)(void *opaque);
+ void (*change_cb)(void *opaque, int reason);
void *change_opaque;
BlockDriver *drv; /* NULL means no media */
@@ -203,6 +203,9 @@ struct BlockDriverState {
void *private;
};
+#define CHANGE_MEDIA 0x01
+#define CHANGE_SIZE 0x02
+
struct BlockDriverAIOCB {
AIOPool *pool;
BlockDriverState *bs;
diff --git a/blockdev.c b/blockdev.c
index d7add36929..1c56da0a16 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -19,6 +19,37 @@
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
+static const char *const if_name[IF_COUNT] = {
+ [IF_NONE] = "none",
+ [IF_IDE] = "ide",
+ [IF_SCSI] = "scsi",
+ [IF_FLOPPY] = "floppy",
+ [IF_PFLASH] = "pflash",
+ [IF_MTD] = "mtd",
+ [IF_SD] = "sd",
+ [IF_VIRTIO] = "virtio",
+ [IF_XEN] = "xen",
+};
+
+static const int if_max_devs[IF_COUNT] = {
+ /*
+ * Do not change these numbers! They govern how drive option
+ * index maps to unit and bus. That mapping is ABI.
+ *
+ * All controllers used to imlement if=T drives need to support
+ * if_max_devs[T] units, for any T with if_max_devs[T] != 0.
+ * Otherwise, some index values map to "impossible" bus, unit
+ * values.
+ *
+ * For instance, if you change [IF_SCSI] to 255, -drive
+ * if=scsi,index=12 no longer means bus=1,unit=5, but
+ * bus=0,unit=12. With an lsi53c895a controller (7 units max),
+ * the drive can't be set up. Regression.
+ */
+ [IF_IDE] = 2,
+ [IF_SCSI] = 7,
+};
+
/*
* We automatically delete the drive when a device using it gets
* unplugged. Questionable feature, but we can't just drop it.
@@ -44,20 +75,40 @@ void blockdev_auto_del(BlockDriverState *bs)
}
}
-QemuOpts *drive_add(const char *file, const char *fmt, ...)
+static int drive_index_to_bus_id(BlockInterfaceType type, int index)
{
- va_list ap;
- char optstr[1024];
- QemuOpts *opts;
+ int max_devs = if_max_devs[type];
+ return max_devs ? index / max_devs : 0;
+}
+
+static int drive_index_to_unit_id(BlockInterfaceType type, int index)
+{
+ int max_devs = if_max_devs[type];
+ return max_devs ? index % max_devs : index;
+}
- va_start(ap, fmt);
- vsnprintf(optstr, sizeof(optstr), fmt, ap);
- va_end(ap);
+QemuOpts *drive_def(const char *optstr)
+{
+ return qemu_opts_parse(qemu_find_opts("drive"), optstr, 0);
+}
- opts = qemu_opts_parse(qemu_find_opts("drive"), optstr, 0);
+QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
+ const char *optstr)
+{
+ QemuOpts *opts;
+ char buf[32];
+
+ opts = drive_def(optstr);
if (!opts) {
return NULL;
}
+ if (type != IF_DEFAULT) {
+ qemu_opt_set(opts, "if", if_name[type]);
+ }
+ if (index >= 0) {
+ snprintf(buf, sizeof(buf), "%d", index);
+ qemu_opt_set(opts, "index", buf);
+ }
if (file)
qemu_opt_set(opts, "file", file);
return opts;
@@ -79,6 +130,13 @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
return NULL;
}
+DriveInfo *drive_get_by_index(BlockInterfaceType type, int index)
+{
+ return drive_get(type,
+ drive_index_to_bus_id(type, index),
+ drive_index_to_unit_id(type, index));
+}
+
int drive_get_max_bus(BlockInterfaceType type)
{
int max_bus;
@@ -93,6 +151,16 @@ int drive_get_max_bus(BlockInterfaceType type)
return max_bus;
}
+/* Get a block device. This should only be used for single-drive devices
+ (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
+ appropriate bus. */
+DriveInfo *drive_get_next(BlockInterfaceType type)
+{
+ static int next_block_unit[IF_COUNT];
+
+ return drive_get(type, 0, next_block_unit[type]++);
+}
+
DriveInfo *drive_get_by_blockdev(BlockDriverState *bs)
{
DriveInfo *dinfo;
@@ -107,7 +175,7 @@ DriveInfo *drive_get_by_blockdev(BlockDriverState *bs)
static void bdrv_format_print(void *opaque, const char *name)
{
- fprintf(stderr, " %s", name);
+ error_printf(" %s", name);
}
void drive_uninit(DriveInfo *dinfo)
@@ -129,13 +197,13 @@ static int parse_block_error_action(const char *buf, int is_read)
} else if (!strcmp(buf, "report")) {
return BLOCK_ERR_REPORT;
} else {
- fprintf(stderr, "qemu: '%s' invalid %s error action\n",
- buf, is_read ? "read" : "write");
+ error_report("'%s' invalid %s error action",
+ buf, is_read ? "read" : "write");
return -1;
}
}
-DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
+DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
{
const char *buf;
const char *file = NULL;
@@ -157,17 +225,13 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
int snapshot = 0;
int ret;
- *fatal_error = 1;
-
translation = BIOS_ATA_TRANSLATION_AUTO;
if (default_to_scsi) {
type = IF_SCSI;
- max_devs = MAX_SCSI_DEVS;
pstrcpy(devname, sizeof(devname), "scsi");
} else {
type = IF_IDE;
- max_devs = MAX_IDE_DEVS;
pstrcpy(devname, sizeof(devname), "ide");
}
media = MEDIA_DISK;
@@ -189,59 +253,34 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
if ((buf = qemu_opt_get(opts, "if")) != NULL) {
pstrcpy(devname, sizeof(devname), buf);
- if (!strcmp(buf, "ide")) {
- type = IF_IDE;
- max_devs = MAX_IDE_DEVS;
- } else if (!strcmp(buf, "scsi")) {
- type = IF_SCSI;
- max_devs = MAX_SCSI_DEVS;
- } else if (!strcmp(buf, "floppy")) {
- type = IF_FLOPPY;
- max_devs = 0;
- } else if (!strcmp(buf, "pflash")) {
- type = IF_PFLASH;
- max_devs = 0;
- } else if (!strcmp(buf, "mtd")) {
- type = IF_MTD;
- max_devs = 0;
- } else if (!strcmp(buf, "sd")) {
- type = IF_SD;
- max_devs = 0;
- } else if (!strcmp(buf, "virtio")) {
- type = IF_VIRTIO;
- max_devs = 0;
- } else if (!strcmp(buf, "xen")) {
- type = IF_XEN;
- max_devs = 0;
- } else if (!strcmp(buf, "none")) {
- type = IF_NONE;
- max_devs = 0;
- } else {
- fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf);
+ for (type = 0; type < IF_COUNT && strcmp(buf, if_name[type]); type++)
+ ;
+ if (type == IF_COUNT) {
+ error_report("unsupported bus type '%s'", buf);
return NULL;
}
}
+ max_devs = if_max_devs[type];
if (cyls || heads || secs) {
if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
- fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf);
+ error_report("invalid physical cyls number");
return NULL;
}
if (heads < 1 || (type == IF_IDE && heads > 16)) {
- fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf);
+ error_report("invalid physical heads number");
return NULL;
}
if (secs < 1 || (type == IF_IDE && secs > 63)) {
- fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf);
+ error_report("invalid physical secs number");
return NULL;
}
}
if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
if (!cyls) {
- fprintf(stderr,
- "qemu: '%s' trans must be used with cyls,heads and secs\n",
- buf);
+ error_report("'%s' trans must be used with cyls,heads and secs",
+ buf);
return NULL;
}
if (!strcmp(buf, "none"))
@@ -251,7 +290,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
else if (!strcmp(buf, "auto"))
translation = BIOS_ATA_TRANSLATION_AUTO;
else {
- fprintf(stderr, "qemu: '%s' invalid translation type\n", buf);
+ error_report("'%s' invalid translation type", buf);
return NULL;
}
}
@@ -261,13 +300,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
media = MEDIA_DISK;
} else if (!strcmp(buf, "cdrom")) {
if (cyls || secs || heads) {
- fprintf(stderr,
- "qemu: '%s' invalid physical CHS format\n", buf);
+ error_report("'%s' invalid physical CHS format", buf);
return NULL;
}
media = MEDIA_CDROM;
} else {
- fprintf(stderr, "qemu: '%s' invalid media\n", buf);
+ error_report("'%s' invalid media", buf);
return NULL;
}
}
@@ -283,7 +321,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
} else if (!strcmp(buf, "writethrough")) {
/* this is the default */
} else {
- fprintf(stderr, "qemu: invalid cache option\n");
+ error_report("invalid cache option");
return NULL;
}
}
@@ -295,7 +333,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
} else if (!strcmp(buf, "threads")) {
/* this is the default */
} else {
- fprintf(stderr, "qemu: invalid aio option\n");
+ error_report("invalid aio option");
return NULL;
}
}
@@ -303,14 +341,14 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
if ((buf = qemu_opt_get(opts, "format")) != NULL) {
if (strcmp(buf, "?") == 0) {
- fprintf(stderr, "qemu: Supported formats:");
- bdrv_iterate_format(bdrv_format_print, NULL);
- fprintf(stderr, "\n");
- return NULL;
+ error_printf("Supported formats:");
+ bdrv_iterate_format(bdrv_format_print, NULL);
+ error_printf("\n");
+ return NULL;
}
drv = bdrv_find_whitelisted_format(buf);
if (!drv) {
- fprintf(stderr, "qemu: '%s' invalid format\n", buf);
+ error_report("'%s' invalid format", buf);
return NULL;
}
}
@@ -318,7 +356,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
on_write_error = BLOCK_ERR_STOP_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
- fprintf(stderr, "werror is not supported by this format\n");
+ error_report("werror is not supported by this bus type");
return NULL;
}
@@ -331,7 +369,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
on_read_error = BLOCK_ERR_REPORT;
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
- fprintf(stderr, "rerror is not supported by this format\n");
+ error_report("rerror is not supported by this bus type");
return NULL;
}
@@ -343,7 +381,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
if (type != IF_VIRTIO) {
- fprintf(stderr, "addr is not supported\n");
+ error_report("addr is not supported by this bus type");
return NULL;
}
}
@@ -352,18 +390,11 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
if (index != -1) {
if (bus_id != 0 || unit_id != -1) {
- fprintf(stderr,
- "qemu: index cannot be used with bus and unit\n");
+ error_report("index cannot be used with bus and unit");
return NULL;
}
- if (max_devs == 0)
- {
- unit_id = index;
- bus_id = 0;
- } else {
- unit_id = index % max_devs;
- bus_id = index / max_devs;
- }
+ bus_id = drive_index_to_bus_id(type, index);
+ unit_id = drive_index_to_unit_id(type, index);
}
/* if user doesn't specify a unit_id,
@@ -384,17 +415,18 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
/* check unit id */
if (max_devs && unit_id >= max_devs) {
- fprintf(stderr, "qemu: unit %d too big (max is %d)\n",
- unit_id, max_devs - 1);
+ error_report("unit %d too big (max is %d)",
+ unit_id, max_devs - 1);
return NULL;
}
/*
- * ignore multiple definitions
+ * catch multiple definitions
*/
if (drive_get(type, bus_id, unit_id) != NULL) {
- *fatal_error = 0;
+ error_report("drive with bus=%d, unit=%d (index=%d) exists",
+ bus_id, unit_id, index);
return NULL;
}
@@ -461,12 +493,11 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
if (devaddr)
qemu_opt_set(opts, "addr", devaddr);
break;
- case IF_COUNT:
+ default:
abort();
}
if (!file || !*file) {
- *fatal_error = 0;
- return NULL;
+ return dinfo;
}
if (snapshot) {
/* always use cache=unsafe with snapshot */
@@ -479,7 +510,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
ro = 1;
} else if (ro == 1) {
if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
- fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n");
+ error_report("readonly not supported by this bus type");
return NULL;
}
}
@@ -488,14 +519,13 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
if (ret < 0) {
- fprintf(stderr, "qemu: could not open disk image %s: %s\n",
- file, strerror(-ret));
+ error_report("could not open disk image %s: %s",
+ file, strerror(-ret));
return NULL;
}
if (bdrv_key_required(dinfo->bdrv))
autostart = 0;
- *fatal_error = 0;
return dinfo;
}
@@ -526,6 +556,12 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
int ret = 0;
int flags;
+ if (!filename) {
+ qerror_report(QERR_MISSING_PARAMETER, "snapshot_file");
+ ret = -1;
+ goto out;
+ }
+
bs = bdrv_find(device);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, device);
@@ -684,13 +720,15 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
/* clean up guest state from pointing to host resource by
* finding and removing DeviceState "drive" property */
- for (prop = bs->peer->info->props; prop && prop->name; prop++) {
- if (prop->info->type == PROP_TYPE_DRIVE) {
- ptr = qdev_get_prop_ptr(bs->peer, prop);
- if ((*ptr) == bs) {
- bdrv_detach(bs, bs->peer);
- *ptr = NULL;
- break;
+ if (bs->peer) {
+ for (prop = bs->peer->info->props; prop && prop->name; prop++) {
+ if (prop->info->type == PROP_TYPE_DRIVE) {
+ ptr = qdev_get_prop_ptr(bs->peer, prop);
+ if (*ptr == bs) {
+ bdrv_detach(bs, bs->peer);
+ *ptr = NULL;
+ break;
+ }
}
}
}
@@ -700,3 +738,33 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
return 0;
}
+
+/*
+ * XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the
+ * existing QERR_ macro mess is cleaned up. A good example for better
+ * error reports can be found in the qemu-img resize code.
+ */
+int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *device = qdict_get_str(qdict, "device");
+ int64_t size = qdict_get_int(qdict, "size");
+ BlockDriverState *bs;
+
+ bs = bdrv_find(device);
+ if (!bs) {
+ qerror_report(QERR_DEVICE_NOT_FOUND, device);
+ return -1;
+ }
+
+ if (size < 0) {
+ qerror_report(QERR_UNDEFINED_ERROR);
+ return -1;
+ }
+
+ if (bdrv_truncate(bs, size)) {
+ qerror_report(QERR_UNDEFINED_ERROR);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/blockdev.h b/blockdev.h
index 4536b5cab1..84e462ab3f 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -18,6 +18,13 @@ void blockdev_auto_del(BlockDriverState *bs);
#define BLOCK_SERIAL_STRLEN 20
+typedef enum {
+ IF_DEFAULT = -1, /* for use with drive_add() only */
+ IF_NONE,
+ IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
+ IF_COUNT
+} BlockInterfaceType;
+
struct DriveInfo {
BlockDriverState *bdrv;
char *id;
@@ -31,16 +38,17 @@ struct DriveInfo {
QTAILQ_ENTRY(DriveInfo) next;
};
-#define MAX_IDE_DEVS 2
-#define MAX_SCSI_DEVS 255
-
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
+DriveInfo *drive_get_by_index(BlockInterfaceType type, int index);
int drive_get_max_bus(BlockInterfaceType type);
+DriveInfo *drive_get_next(BlockInterfaceType type);
void drive_uninit(DriveInfo *dinfo);
DriveInfo *drive_get_by_blockdev(BlockDriverState *bs);
-QemuOpts *drive_add(const char *file, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
-DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi, int *fatal_error);
+QemuOpts *drive_def(const char *optstr);
+QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
+ const char *optstr);
+DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi);
/* device-hotplug */
@@ -53,5 +61,6 @@ int do_change_block(Monitor *mon, const char *device,
const char *filename, const char *fmt);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data);
#endif
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/cache-utils.h b/cache-utils.h
index b45fde44e8..0b65907e97 100644
--- a/cache-utils.h
+++ b/cache-utils.h
@@ -9,7 +9,7 @@ struct qemu_cache_conf {
extern struct qemu_cache_conf qemu_cache_conf;
-extern void qemu_cache_utils_init(char **envp);
+void qemu_cache_utils_init(char **envp);
/* mildly adjusted code from tcg-dyngen.c */
static inline void flush_icache_range(unsigned long start, unsigned long stop)
diff --git a/cmd.h b/cmd.h
index cbe9549572..b763b198c4 100644
--- a/cmd.h
+++ b/cmd.h
@@ -38,33 +38,33 @@ typedef struct cmdinfo {
extern cmdinfo_t *cmdtab;
extern int ncmds;
-extern void help_init(void);
-extern void quit_init(void);
+void help_init(void);
+void quit_init(void);
typedef int (*argsfunc_t)(int index);
typedef int (*checkfunc_t)(const cmdinfo_t *ci);
-extern void add_command(const cmdinfo_t *ci);
-extern void add_user_command(char *optarg);
-extern void add_args_command(argsfunc_t af);
-extern void add_check_command(checkfunc_t cf);
+void add_command(const cmdinfo_t *ci);
+void add_user_command(char *optarg);
+void add_args_command(argsfunc_t af);
+void add_check_command(checkfunc_t cf);
-extern const cmdinfo_t *find_command(const char *cmd);
+const cmdinfo_t *find_command(const char *cmd);
-extern void command_loop(void);
-extern int command_usage(const cmdinfo_t *ci);
-extern int command(const cmdinfo_t *ci, int argc, char **argv);
+void command_loop(void);
+int command_usage(const cmdinfo_t *ci);
+int command(const cmdinfo_t *ci, int argc, char **argv);
/* from input.h */
-extern char **breakline(char *input, int *count);
-extern void doneline(char *input, char **vec);
-extern char *fetchline(void);
+char **breakline(char *input, int *count);
+void doneline(char *input, char **vec);
+char *fetchline(void);
-extern long long cvtnum(char *s);
-extern void cvtstr(double value, char *str, size_t sz);
+long long cvtnum(char *s);
+void cvtstr(double value, char *str, size_t sz);
-extern struct timeval tsub(struct timeval t1, struct timeval t2);
-extern double tdiv(double value, struct timeval tv);
+struct timeval tsub(struct timeval t1, struct timeval t2);
+double tdiv(double value, struct timeval tv);
enum {
DEFAULT_TIME = 0x0,
@@ -72,7 +72,7 @@ enum {
VERBOSE_FIXED_TIME = 0x2
};
-extern void timestr(struct timeval *tv, char *str, size_t sz, int flags);
+void timestr(struct timeval *tv, char *str, size_t sz, int flags);
extern char *progname;
diff --git a/configure b/configure
index 831a741c74..fcc5a71b3d 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,9 @@ 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 Set trace backend"
+echo " Available backends:" $("$source_path"/scripts/tracetool --list-backends)
+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 +919,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 +1087,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 +1162,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 +1185,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 +1203,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 +1275,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 +1590,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 +1623,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 +1642,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 +1687,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 +2088,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 +2267,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 +2548,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 +2646,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 +2778,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 +2812,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 +2876,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 +3062,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 +3087,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 +3225,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 +3255,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 +3262,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/cutils.c b/cutils.c
index 7984bc1ca4..8d562b28ab 100644
--- a/cutils.c
+++ b/cutils.c
@@ -291,10 +291,11 @@ int fcntl_setfl(int fd, int flag)
* value must be terminated by whitespace, ',' or '\0'. Return -1 on
* error.
*/
-ssize_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
+int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
{
- ssize_t retval = -1;
- char *endptr, c, d;
+ int64_t retval = -1;
+ char *endptr;
+ unsigned char c, d;
int mul_required = 0;
double val, mul, integral, fraction;
@@ -303,8 +304,8 @@ ssize_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
if (isnan(val) || endptr == nptr || errno != 0) {
goto fail;
}
- integral = modf(val, &fraction);
- if (integral != 0) {
+ fraction = modf(val, &integral);
+ if (fraction != 0) {
mul_required = 1;
}
/*
@@ -314,7 +315,7 @@ ssize_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
*/
c = *endptr;
d = c;
- if (isspace(c) || c == '\0' || c == ',') {
+ if (qemu_isspace(c) || c == '\0' || c == ',') {
c = 0;
if (default_suffix) {
d = default_suffix;
@@ -322,32 +323,27 @@ ssize_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
d = c;
}
}
- switch (d) {
- case 'B':
- case 'b':
+ switch (qemu_toupper(d)) {
+ case STRTOSZ_DEFSUFFIX_B:
mul = 1;
if (mul_required) {
goto fail;
}
break;
- case 'K':
- case 'k':
+ case STRTOSZ_DEFSUFFIX_KB:
mul = 1 << 10;
break;
case 0:
if (mul_required) {
goto fail;
}
- case 'M':
- case 'm':
+ case STRTOSZ_DEFSUFFIX_MB:
mul = 1ULL << 20;
break;
- case 'G':
- case 'g':
+ case STRTOSZ_DEFSUFFIX_GB:
mul = 1ULL << 30;
break;
- case 'T':
- case 't':
+ case STRTOSZ_DEFSUFFIX_TB:
mul = 1ULL << 40;
break;
default:
@@ -361,11 +357,11 @@ ssize_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
*/
if (c != 0) {
endptr++;
- if (!isspace(*endptr) && *endptr != ',' && *endptr != 0) {
+ if (!qemu_isspace(*endptr) && *endptr != ',' && *endptr != 0) {
goto fail;
}
}
- if ((val * mul >= ~(size_t)0) || val < 0) {
+ if ((val * mul >= INT64_MAX) || val < 0) {
goto fail;
}
retval = val * mul;
@@ -378,7 +374,7 @@ fail:
return retval;
}
-ssize_t strtosz(const char *nptr, char **end)
+int64_t strtosz(const char *nptr, char **end)
{
return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB);
}
diff --git a/dis-asm.h b/dis-asm.h
index 356459c5fd..296537ad3a 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -362,48 +362,48 @@ typedef struct disassemble_info {
target address. Return number of bytes processed. */
typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
-extern int print_insn_big_mips (bfd_vma, disassemble_info*);
-extern int print_insn_little_mips (bfd_vma, disassemble_info*);
-extern int print_insn_i386 (bfd_vma, disassemble_info*);
-extern int print_insn_m68k (bfd_vma, disassemble_info*);
-extern int print_insn_z8001 (bfd_vma, disassemble_info*);
-extern int print_insn_z8002 (bfd_vma, disassemble_info*);
-extern int print_insn_h8300 (bfd_vma, disassemble_info*);
-extern int print_insn_h8300h (bfd_vma, disassemble_info*);
-extern int print_insn_h8300s (bfd_vma, disassemble_info*);
-extern int print_insn_h8500 (bfd_vma, disassemble_info*);
-extern int print_insn_alpha (bfd_vma, disassemble_info*);
-extern disassembler_ftype arc_get_disassembler (int, int);
-extern int print_insn_arm (bfd_vma, disassemble_info*);
-extern int print_insn_sparc (bfd_vma, disassemble_info*);
-extern int print_insn_big_a29k (bfd_vma, disassemble_info*);
-extern int print_insn_little_a29k (bfd_vma, disassemble_info*);
-extern int print_insn_i960 (bfd_vma, disassemble_info*);
-extern int print_insn_sh (bfd_vma, disassemble_info*);
-extern int print_insn_shl (bfd_vma, disassemble_info*);
-extern int print_insn_hppa (bfd_vma, disassemble_info*);
-extern int print_insn_m32r (bfd_vma, disassemble_info*);
-extern int print_insn_m88k (bfd_vma, disassemble_info*);
-extern int print_insn_mn10200 (bfd_vma, disassemble_info*);
-extern int print_insn_mn10300 (bfd_vma, disassemble_info*);
-extern int print_insn_ns32k (bfd_vma, disassemble_info*);
-extern int print_insn_big_powerpc (bfd_vma, disassemble_info*);
-extern int print_insn_little_powerpc (bfd_vma, disassemble_info*);
-extern int print_insn_rs6000 (bfd_vma, disassemble_info*);
-extern int print_insn_w65 (bfd_vma, disassemble_info*);
-extern int print_insn_d10v (bfd_vma, disassemble_info*);
-extern int print_insn_v850 (bfd_vma, disassemble_info*);
-extern int print_insn_tic30 (bfd_vma, disassemble_info*);
-extern int print_insn_ppc (bfd_vma, disassemble_info*);
-extern int print_insn_s390 (bfd_vma, disassemble_info*);
-extern int print_insn_crisv32 (bfd_vma, disassemble_info*);
-extern int print_insn_crisv10 (bfd_vma, disassemble_info*);
-extern int print_insn_microblaze (bfd_vma, disassemble_info*);
-extern int print_insn_ia64 (bfd_vma, disassemble_info*);
+int print_insn_big_mips (bfd_vma, disassemble_info*);
+int print_insn_little_mips (bfd_vma, disassemble_info*);
+int print_insn_i386 (bfd_vma, disassemble_info*);
+int print_insn_m68k (bfd_vma, disassemble_info*);
+int print_insn_z8001 (bfd_vma, disassemble_info*);
+int print_insn_z8002 (bfd_vma, disassemble_info*);
+int print_insn_h8300 (bfd_vma, disassemble_info*);
+int print_insn_h8300h (bfd_vma, disassemble_info*);
+int print_insn_h8300s (bfd_vma, disassemble_info*);
+int print_insn_h8500 (bfd_vma, disassemble_info*);
+int print_insn_alpha (bfd_vma, disassemble_info*);
+disassembler_ftype arc_get_disassembler (int, int);
+int print_insn_arm (bfd_vma, disassemble_info*);
+int print_insn_sparc (bfd_vma, disassemble_info*);
+int print_insn_big_a29k (bfd_vma, disassemble_info*);
+int print_insn_little_a29k (bfd_vma, disassemble_info*);
+int print_insn_i960 (bfd_vma, disassemble_info*);
+int print_insn_sh (bfd_vma, disassemble_info*);
+int print_insn_shl (bfd_vma, disassemble_info*);
+int print_insn_hppa (bfd_vma, disassemble_info*);
+int print_insn_m32r (bfd_vma, disassemble_info*);
+int print_insn_m88k (bfd_vma, disassemble_info*);
+int print_insn_mn10200 (bfd_vma, disassemble_info*);
+int print_insn_mn10300 (bfd_vma, disassemble_info*);
+int print_insn_ns32k (bfd_vma, disassemble_info*);
+int print_insn_big_powerpc (bfd_vma, disassemble_info*);
+int print_insn_little_powerpc (bfd_vma, disassemble_info*);
+int print_insn_rs6000 (bfd_vma, disassemble_info*);
+int print_insn_w65 (bfd_vma, disassemble_info*);
+int print_insn_d10v (bfd_vma, disassemble_info*);
+int print_insn_v850 (bfd_vma, disassemble_info*);
+int print_insn_tic30 (bfd_vma, disassemble_info*);
+int print_insn_ppc (bfd_vma, disassemble_info*);
+int print_insn_s390 (bfd_vma, disassemble_info*);
+int print_insn_crisv32 (bfd_vma, disassemble_info*);
+int print_insn_crisv10 (bfd_vma, disassemble_info*);
+int print_insn_microblaze (bfd_vma, disassemble_info*);
+int print_insn_ia64 (bfd_vma, disassemble_info*);
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
-extern disassembler_ftype disassembler (bfd *);
+disassembler_ftype disassembler(bfd *);
#endif
@@ -412,21 +412,20 @@ extern disassembler_ftype disassembler (bfd *);
/* Here is a function which callers may wish to use for read_memory_func.
It gets bytes from a buffer. */
-extern int buffer_read_memory
- (bfd_vma, bfd_byte *, int, struct disassemble_info *);
+int buffer_read_memory(bfd_vma, bfd_byte *, int, struct disassemble_info *);
/* This function goes with buffer_read_memory.
It prints a message using info->fprintf_func and info->stream. */
-extern void perror_memory (int, bfd_vma, struct disassemble_info *);
+void perror_memory(int, bfd_vma, struct disassemble_info *);
/* Just print the address in hex. This is included for completeness even
though both GDB and objdump provide their own (to print symbolic
addresses). */
-extern void generic_print_address (bfd_vma, struct disassemble_info *);
+void generic_print_address(bfd_vma, struct disassemble_info *);
/* Always true. */
-extern int generic_symbol_at_address (bfd_vma, struct disassemble_info *);
+int generic_symbol_at_address(bfd_vma, struct disassemble_info *);
/* Macro to initialize a disassemble_info struct. This should be called
by all applications creating such a struct. */
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 f2f9b757a5..4bb2be8850 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -80,7 +80,11 @@ The -device argument differs in detail for each kind of drive:
This SCSI controller a single SCSI bus, named ID.0. Put a disk on
it:
- -device scsi-disk,drive=DRIVE-ID,bus=ID.0,scsi-id=SCSI-ID
+ -device scsi-disk,drive=DRIVE-ID,bus=ID.0,scsi-id=SCSI-ID,removable=RMB
+
+ The (optional) removable parameter lets you override the SCSI INQUIRY
+ removable (RMB) bit for non CD-ROM devices. It is ignored for CD-ROM devices
+ which are always removable. RMB is "on" or "off".
* if=floppy
@@ -116,7 +120,12 @@ For USB devices, the old way is actually different:
Provides much less control than -drive's HOST-OPTS... The new way
fixes that:
- -device usb-storage,drive=DRIVE-ID
+ -device usb-storage,drive=DRIVE-ID,removable=RMB
+
+The removable parameter gives control over the SCSI INQUIRY removable (RMB)
+bit. USB thumbdrives usually set removable=on, while USB hard disks set
+removable=off. See the if=scsi description above for details on the removable
+parameter, which applies only to scsi-disk devices and not to scsi-generic.
=== Character Devices ===
diff --git a/docs/tracing.txt b/docs/tracing.txt
index 963c5047fe..21183f9a68 100644
--- a/docs/tracing.txt
+++ b/docs/tracing.txt
@@ -133,6 +133,11 @@ source tree. It may not be as powerful as platform-specific or third-party
trace backends but it is portable. This is the recommended trace backend
unless you have specific needs for more advanced backends.
+=== Stderr ===
+
+The "stderr" backend sends trace events directly to standard error output
+during emulation.
+
==== Monitor commands ====
* info trace
diff --git a/envlist.h b/envlist.h
index e76d4a101b..b9addcc11f 100644
--- a/envlist.h
+++ b/envlist.h
@@ -7,13 +7,13 @@ extern "C" {
typedef struct envlist envlist_t;
-extern envlist_t *envlist_create(void);
-extern void envlist_free(envlist_t *);
-extern int envlist_setenv(envlist_t *, const char *);
-extern int envlist_unsetenv(envlist_t *, const char *);
-extern int envlist_parse_set(envlist_t *, const char *);
-extern int envlist_parse_unset(envlist_t *, const char *);
-extern char **envlist_to_environ(const envlist_t *, size_t *);
+envlist_t *envlist_create(void);
+void envlist_free(envlist_t *);
+int envlist_setenv(envlist_t *, const char *);
+int envlist_unsetenv(envlist_t *, const char *);
+int envlist_parse_set(envlist_t *, const char *);
+int envlist_parse_unset(envlist_t *, const char *);
+char **envlist_to_environ(const envlist_t *, size_t *);
#ifdef __cplusplus
}
diff --git a/exec-all.h b/exec-all.h
index a4b75bdbcb..e3a82bc997 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -192,7 +192,7 @@ extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
#if defined(USE_DIRECT_JUMP)
#if defined(_ARCH_PPC)
-extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr);
+void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr);
#define tb_set_jmp_target1 ppc_tb_set_jmp_target
#elif defined(__i386__) || defined(__x86_64__)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
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/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index 6c2788147f..a704043beb 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -49,7 +49,7 @@ typedef struct FsTypeListEntry {
QTAILQ_ENTRY(FsTypeListEntry) next;
} FsTypeListEntry;
-extern int qemu_fsdev_add(QemuOpts *opts);
-extern FsTypeEntry *get_fsdev_fsentry(char *id);
+int qemu_fsdev_add(QemuOpts *opts);
+FsTypeEntry *get_fsdev_fsentry(char *id);
extern FileOperations local_ops;
#endif
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/hmp-commands.hx b/hmp-commands.hx
index 1cea572b15..8df4adf831 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -53,6 +53,25 @@ Quit the emulator.
ETEXI
{
+ .name = "block_resize",
+ .args_type = "device:B,size:o",
+ .params = "device size",
+ .help = "resize a block image",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_block_resize,
+ },
+
+STEXI
+@item block_resize
+@findex block_resize
+Resize a block image while a guest is running. Usually requires guest
+action to see the updated size. Resize to a lower size is supported,
+but should be used with extreme caution. Note that this command only
+resizes image files, it can not resize block devices like LVM volumes.
+ETEXI
+
+
+ {
.name = "eject",
.args_type = "force:-f,device:B",
.params = "[-f] device",
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/device-hotplug.c b/hw/device-hotplug.c
index 9704e2feb2..8b2ed7a492 100644
--- a/hw/device-hotplug.c
+++ b/hw/device-hotplug.c
@@ -29,15 +29,14 @@
DriveInfo *add_init_drive(const char *optstr)
{
- int fatal_error;
DriveInfo *dinfo;
QemuOpts *opts;
- opts = drive_add(NULL, "%s", optstr);
+ opts = drive_def(optstr);
if (!opts)
return NULL;
- dinfo = drive_init(opts, current_machine->use_scsi, &fatal_error);
+ dinfo = drive_init(opts, current_machine->use_scsi);
if (!dinfo) {
qemu_opts_del(opts);
return NULL;
diff --git a/hw/ecc.c b/hw/ecc.c
index 2fbf167943..a75408b9ae 100644
--- a/hw/ecc.c
+++ b/hw/ecc.c
@@ -74,18 +74,15 @@ void ecc_reset(ECCState *s)
}
/* Save/restore */
-void ecc_put(QEMUFile *f, ECCState *s)
-{
- qemu_put_8s(f, &s->cp);
- qemu_put_be16s(f, &s->lp[0]);
- qemu_put_be16s(f, &s->lp[1]);
- qemu_put_be16s(f, &s->count);
-}
-
-void ecc_get(QEMUFile *f, ECCState *s)
-{
- qemu_get_8s(f, &s->cp);
- qemu_get_be16s(f, &s->lp[0]);
- qemu_get_be16s(f, &s->lp[1]);
- qemu_get_be16s(f, &s->count);
-}
+VMStateDescription vmstate_ecc_state = {
+ .name = "ecc-state",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(cp, ECCState),
+ VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
+ VMSTATE_UINT16(count, ECCState),
+ VMSTATE_END_OF_LIST(),
+ },
+};
diff --git a/hw/escc.c b/hw/escc.c
index ba6063608d..f6fd9192ea 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -369,14 +369,18 @@ static inline void set_txint(ChannelState *s)
if (!s->rxint_under_svc) {
s->txint_under_svc = 1;
if (s->chn == chn_a) {
- s->rregs[R_INTR] |= INTR_TXINTA;
+ if (s->wregs[W_INTR] & INTR_TXINT) {
+ s->rregs[R_INTR] |= INTR_TXINTA;
+ }
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
else
s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
} else {
s->rregs[R_IVEC] = IVEC_TXINTB;
- s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
+ if (s->wregs[W_INTR] & INTR_TXINT) {
+ s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
+ }
}
escc_update_irq(s);
}
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index ba1adbe3c0..133741b4f5 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -100,7 +100,6 @@ static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
return r;
}
-#define TIMER_SLOWDOWN 1
static void update_ctrl(struct etrax_timer *t, int tnum)
{
unsigned int op;
@@ -142,9 +141,6 @@ static void update_ctrl(struct etrax_timer *t, int tnum)
}
D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
- div = div * TIMER_SLOWDOWN;
- div /= 1000;
- freq_hz /= 1000;
ptimer_set_freq(timer, freq_hz);
ptimer_set_limit(timer, div, 0);
diff --git a/hw/file-op-9p.h b/hw/file-op-9p.h
index c7731c2993..126e60e276 100644
--- a/hw/file-op-9p.h
+++ b/hw/file-op-9p.h
@@ -57,7 +57,7 @@ typedef struct FsContext
struct xattr_operations **xops;
} FsContext;
-extern void cred_init(FsCred *);
+void cred_init(FsCred *);
typedef struct FileOperations
{
diff --git a/hw/flash.h b/hw/flash.h
index a80205c4e0..d7d103e66f 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -51,5 +51,4 @@ typedef struct {
uint8_t ecc_digest(ECCState *s, uint8_t sample);
void ecc_reset(ECCState *s);
-void ecc_put(QEMUFile *f, ECCState *s);
-void ecc_get(QEMUFile *f, ECCState *s);
+extern VMStateDescription vmstate_ecc_state;
diff --git a/hw/grlib.h b/hw/grlib.h
new file mode 100644
index 0000000000..fdf4b1190a
--- /dev/null
+++ b/hw/grlib.h
@@ -0,0 +1,126 @@
+/*
+ * QEMU GRLIB Components
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef _GRLIB_H_
+#define _GRLIB_H_
+
+#include "qdev.h"
+#include "sysbus.h"
+
+/* Emulation of GrLib device is base on the GRLIB IP Core User's Manual:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ */
+
+/* IRQMP */
+
+typedef void (*set_pil_in_fn) (void *opaque, uint32_t pil_in);
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level);
+
+void grlib_irqmp_ack(DeviceState *dev, int intno);
+
+static inline
+DeviceState *grlib_irqmp_create(target_phys_addr_t base,
+ CPUState *env,
+ qemu_irq **cpu_irqs,
+ uint32_t nr_irqs,
+ set_pil_in_fn set_pil_in)
+{
+ DeviceState *dev;
+
+ assert(cpu_irqs != NULL);
+
+ dev = qdev_create(NULL, "grlib,irqmp");
+ qdev_prop_set_ptr(dev, "set_pil_in", set_pil_in);
+ qdev_prop_set_ptr(dev, "set_pil_in_opaque", env);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ env->irq_manager = dev;
+
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+ *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq,
+ dev,
+ nr_irqs);
+
+ return dev;
+}
+
+/* GPTimer */
+
+static inline
+DeviceState *grlib_gptimer_create(target_phys_addr_t base,
+ uint32_t nr_timers,
+ uint32_t freq,
+ qemu_irq *cpu_irqs,
+ int base_irq)
+{
+ DeviceState *dev;
+ int i;
+
+ dev = qdev_create(NULL, "grlib,gptimer");
+ qdev_prop_set_uint32(dev, "nr-timers", nr_timers);
+ qdev_prop_set_uint32(dev, "frequency", freq);
+ qdev_prop_set_uint32(dev, "irq-line", base_irq);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+ for (i = 0; i < nr_timers; i++) {
+ sysbus_connect_irq(sysbus_from_qdev(dev), i, cpu_irqs[base_irq + i]);
+ }
+
+ return dev;
+}
+
+/* APB UART */
+
+static inline
+DeviceState *grlib_apbuart_create(target_phys_addr_t base,
+ CharDriverState *serial,
+ qemu_irq irq)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "grlib,apbuart");
+ qdev_prop_set_chr(dev, "chrdev", serial);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+ return dev;
+}
+
+#endif /* ! _GRLIB_H_ */
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
new file mode 100644
index 0000000000..101b150aa5
--- /dev/null
+++ b/hw/grlib_apbuart.c
@@ -0,0 +1,187 @@
+/*
+ * QEMU GRLIB APB UART Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-char.h"
+
+#include "trace.h"
+
+#define UART_REG_SIZE 20 /* Size of memory mapped registers */
+
+/* UART status register fields */
+#define UART_DATA_READY (1 << 0)
+#define UART_TRANSMIT_SHIFT_EMPTY (1 << 1)
+#define UART_TRANSMIT_FIFO_EMPTY (1 << 2)
+#define UART_BREAK_RECEIVED (1 << 3)
+#define UART_OVERRUN (1 << 4)
+#define UART_PARITY_ERROR (1 << 5)
+#define UART_FRAMING_ERROR (1 << 6)
+#define UART_TRANSMIT_FIFO_HALF (1 << 7)
+#define UART_RECEIVE_FIFO_HALF (1 << 8)
+#define UART_TRANSMIT_FIFO_FULL (1 << 9)
+#define UART_RECEIVE_FIFO_FULL (1 << 10)
+
+/* UART control register fields */
+#define UART_RECEIVE_ENABLE (1 << 0)
+#define UART_TRANSMIT_ENABLE (1 << 1)
+#define UART_RECEIVE_INTERRUPT (1 << 2)
+#define UART_TRANSMIT_INTERRUPT (1 << 3)
+#define UART_PARITY_SELECT (1 << 4)
+#define UART_PARITY_ENABLE (1 << 5)
+#define UART_FLOW_CONTROL (1 << 6)
+#define UART_LOOPBACK (1 << 7)
+#define UART_EXTERNAL_CLOCK (1 << 8)
+#define UART_RECEIVE_FIFO_INTERRUPT (1 << 9)
+#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
+#define UART_FIFO_DEBUG_MODE (1 << 11)
+#define UART_OUTPUT_ENABLE (1 << 12)
+#define UART_FIFO_AVAILABLE (1 << 31)
+
+/* Memory mapped register offsets */
+#define DATA_OFFSET 0x00
+#define STATUS_OFFSET 0x04
+#define CONTROL_OFFSET 0x08
+#define SCALER_OFFSET 0x0C /* not supported */
+#define FIFO_DEBUG_OFFSET 0x10 /* not supported */
+
+typedef struct UART {
+ SysBusDevice busdev;
+
+ qemu_irq irq;
+
+ CharDriverState *chr;
+
+ /* registers */
+ uint32_t receive;
+ uint32_t status;
+ uint32_t control;
+} UART;
+
+static int grlib_apbuart_can_receive(void *opaque)
+{
+ UART *uart = opaque;
+
+ return !!(uart->status & UART_DATA_READY);
+}
+
+static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ UART *uart = opaque;
+
+ uart->receive = *buf;
+ uart->status |= UART_DATA_READY;
+
+ if (uart->control & UART_RECEIVE_INTERRUPT) {
+ qemu_irq_pulse(uart->irq);
+ }
+}
+
+static void grlib_apbuart_event(void *opaque, int event)
+{
+ trace_grlib_apbuart_event(event);
+}
+
+static void
+grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ UART *uart = opaque;
+ unsigned char c = 0;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case DATA_OFFSET:
+ c = value & 0xFF;
+ qemu_chr_write(uart->chr, &c, 1);
+ return;
+
+ case STATUS_OFFSET:
+ /* Read Only */
+ return;
+
+ case CONTROL_OFFSET:
+ /* Not supported */
+ return;
+
+ case SCALER_OFFSET:
+ /* Not supported */
+ return;
+
+ default:
+ break;
+ }
+
+ trace_grlib_apbuart_unknown_register("write", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_apbuart_read[] = {
+ NULL, NULL, NULL,
+};
+
+static CPUWriteMemoryFunc * const grlib_apbuart_write[] = {
+ NULL, NULL, grlib_apbuart_writel,
+};
+
+static int grlib_apbuart_init(SysBusDevice *dev)
+{
+ UART *uart = FROM_SYSBUS(typeof(*uart), dev);
+ int uart_regs = 0;
+
+ qemu_chr_add_handlers(uart->chr,
+ grlib_apbuart_can_receive,
+ grlib_apbuart_receive,
+ grlib_apbuart_event,
+ uart);
+
+ sysbus_init_irq(dev, &uart->irq);
+
+ uart_regs = cpu_register_io_memory(grlib_apbuart_read,
+ grlib_apbuart_write,
+ uart, DEVICE_NATIVE_ENDIAN);
+ if (uart_regs < 0) {
+ return -1;
+ }
+
+ sysbus_init_mmio(dev, UART_REG_SIZE, uart_regs);
+
+ return 0;
+}
+
+static SysBusDeviceInfo grlib_gptimer_info = {
+ .init = grlib_apbuart_init,
+ .qdev.name = "grlib,apbuart",
+ .qdev.size = sizeof(UART),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_CHR("chrdev", UART, chr),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
+
+static void grlib_gptimer_register(void)
+{
+ sysbus_register_withprop(&grlib_gptimer_info);
+}
+
+device_init(grlib_gptimer_register)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
new file mode 100644
index 0000000000..596a9000a1
--- /dev/null
+++ b/hw/grlib_gptimer.c
@@ -0,0 +1,395 @@
+/*
+ * QEMU GRLIB GPTimer Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+#include "trace.h"
+
+#define UNIT_REG_SIZE 16 /* Size of memory mapped regs for the unit */
+#define GPTIMER_REG_SIZE 16 /* Size of memory mapped regs for a GPTimer */
+
+#define GPTIMER_MAX_TIMERS 8
+
+/* GPTimer Config register fields */
+#define GPTIMER_ENABLE (1 << 0)
+#define GPTIMER_RESTART (1 << 1)
+#define GPTIMER_LOAD (1 << 2)
+#define GPTIMER_INT_ENABLE (1 << 3)
+#define GPTIMER_INT_PENDING (1 << 4)
+#define GPTIMER_CHAIN (1 << 5) /* Not supported */
+#define GPTIMER_DEBUG_HALT (1 << 6) /* Not supported */
+
+/* Memory mapped register offsets */
+#define SCALER_OFFSET 0x00
+#define SCALER_RELOAD_OFFSET 0x04
+#define CONFIG_OFFSET 0x08
+#define COUNTER_OFFSET 0x00
+#define COUNTER_RELOAD_OFFSET 0x04
+#define TIMER_BASE 0x10
+
+typedef struct GPTimer GPTimer;
+typedef struct GPTimerUnit GPTimerUnit;
+
+struct GPTimer {
+ QEMUBH *bh;
+ struct ptimer_state *ptimer;
+
+ qemu_irq irq;
+ int id;
+ GPTimerUnit *unit;
+
+ /* registers */
+ uint32_t counter;
+ uint32_t reload;
+ uint32_t config;
+};
+
+struct GPTimerUnit {
+ SysBusDevice busdev;
+
+ uint32_t nr_timers; /* Number of timers available */
+ uint32_t freq_hz; /* System frequency */
+ uint32_t irq_line; /* Base irq line */
+
+ GPTimer *timers;
+
+ /* registers */
+ uint32_t scaler;
+ uint32_t reload;
+ uint32_t config;
+};
+
+static void grlib_gptimer_enable(GPTimer *timer)
+{
+ assert(timer != NULL);
+
+
+ ptimer_stop(timer->ptimer);
+
+ if (!(timer->config & GPTIMER_ENABLE)) {
+ /* Timer disabled */
+ trace_grlib_gptimer_disabled(timer->id, timer->config);
+ return;
+ }
+
+ /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
+ underflow. Set count + 1 to simulate the GPTimer behavior. */
+
+ trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
+
+ ptimer_set_count(timer->ptimer, timer->counter + 1);
+ ptimer_run(timer->ptimer, 1);
+}
+
+static void grlib_gptimer_restart(GPTimer *timer)
+{
+ assert(timer != NULL);
+
+ trace_grlib_gptimer_restart(timer->id, timer->reload);
+
+ timer->counter = timer->reload;
+ grlib_gptimer_enable(timer);
+}
+
+static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
+{
+ int i = 0;
+ uint32_t value = 0;
+
+ assert(unit != NULL);
+
+ if (scaler > 0) {
+ value = unit->freq_hz / (scaler + 1);
+ } else {
+ value = unit->freq_hz;
+ }
+
+ trace_grlib_gptimer_set_scaler(scaler, value);
+
+ for (i = 0; i < unit->nr_timers; i++) {
+ ptimer_set_freq(unit->timers[i].ptimer, value);
+ }
+}
+
+static void grlib_gptimer_hit(void *opaque)
+{
+ GPTimer *timer = opaque;
+ assert(timer != NULL);
+
+ trace_grlib_gptimer_hit(timer->id);
+
+ /* Timer expired */
+
+ if (timer->config & GPTIMER_INT_ENABLE) {
+ /* Set the pending bit (only unset by write in the config register) */
+ timer->config |= GPTIMER_INT_PENDING;
+ qemu_irq_pulse(timer->irq);
+ }
+
+ if (timer->config & GPTIMER_RESTART) {
+ grlib_gptimer_restart(timer);
+ }
+}
+
+static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
+{
+ GPTimerUnit *unit = opaque;
+ target_phys_addr_t timer_addr;
+ int id;
+ uint32_t value = 0;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case SCALER_OFFSET:
+ trace_grlib_gptimer_readl(-1, "scaler:", unit->scaler);
+ return unit->scaler;
+
+ case SCALER_RELOAD_OFFSET:
+ trace_grlib_gptimer_readl(-1, "reload:", unit->reload);
+ return unit->reload;
+
+ case CONFIG_OFFSET:
+ trace_grlib_gptimer_readl(-1, "config:", unit->config);
+ return unit->config;
+
+ default:
+ break;
+ }
+
+ timer_addr = (addr % TIMER_BASE);
+ id = (addr - TIMER_BASE) / TIMER_BASE;
+
+ if (id >= 0 && id < unit->nr_timers) {
+
+ /* GPTimer registers */
+ switch (timer_addr) {
+ case COUNTER_OFFSET:
+ value = ptimer_get_count(unit->timers[id].ptimer);
+ trace_grlib_gptimer_readl(id, "counter value:", value);
+ return value;
+
+ case COUNTER_RELOAD_OFFSET:
+ value = unit->timers[id].reload;
+ trace_grlib_gptimer_readl(id, "reload value:", value);
+ return value;
+
+ case CONFIG_OFFSET:
+ trace_grlib_gptimer_readl(id, "scaler value:",
+ unit->timers[id].config);
+ return unit->timers[id].config;
+
+ default:
+ break;
+ }
+
+ }
+
+ trace_grlib_gptimer_unknown_register("read", addr);
+ return 0;
+}
+
+static void
+grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ GPTimerUnit *unit = opaque;
+ target_phys_addr_t timer_addr;
+ int id;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case SCALER_OFFSET:
+ value &= 0xFFFF; /* clean up the value */
+ unit->scaler = value;
+ trace_grlib_gptimer_writel(-1, "scaler:", unit->scaler);
+ return;
+
+ case SCALER_RELOAD_OFFSET:
+ value &= 0xFFFF; /* clean up the value */
+ unit->reload = value;
+ trace_grlib_gptimer_writel(-1, "reload:", unit->reload);
+ grlib_gptimer_set_scaler(unit, value);
+ return;
+
+ case CONFIG_OFFSET:
+ /* Read Only (disable timer freeze not supported) */
+ trace_grlib_gptimer_writel(-1, "config (Read Only):", 0);
+ return;
+
+ default:
+ break;
+ }
+
+ timer_addr = (addr % TIMER_BASE);
+ id = (addr - TIMER_BASE) / TIMER_BASE;
+
+ if (id >= 0 && id < unit->nr_timers) {
+
+ /* GPTimer registers */
+ switch (timer_addr) {
+ case COUNTER_OFFSET:
+ trace_grlib_gptimer_writel(id, "counter:", value);
+ unit->timers[id].counter = value;
+ grlib_gptimer_enable(&unit->timers[id]);
+ return;
+
+ case COUNTER_RELOAD_OFFSET:
+ trace_grlib_gptimer_writel(id, "reload:", value);
+ unit->timers[id].reload = value;
+ return;
+
+ case CONFIG_OFFSET:
+ trace_grlib_gptimer_writel(id, "config:", value);
+
+ if (value & GPTIMER_INT_PENDING) {
+ /* clear pending bit */
+ value &= ~GPTIMER_INT_PENDING;
+ } else {
+ /* keep pending bit */
+ value |= unit->timers[id].config & GPTIMER_INT_PENDING;
+ }
+
+ unit->timers[id].config = value;
+
+ /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
+ bits are present, we just have to call restart. */
+
+ if (value & GPTIMER_LOAD) {
+ grlib_gptimer_restart(&unit->timers[id]);
+ } else if (value & GPTIMER_ENABLE) {
+ grlib_gptimer_enable(&unit->timers[id]);
+ }
+
+ /* These fields must always be read as 0 */
+ value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
+
+ unit->timers[id].config = value;
+ return;
+
+ default:
+ break;
+ }
+
+ }
+
+ trace_grlib_gptimer_unknown_register("write", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
+ NULL, NULL, grlib_gptimer_readl,
+};
+
+static CPUWriteMemoryFunc * const grlib_gptimer_write[] = {
+ NULL, NULL, grlib_gptimer_writel,
+};
+
+static void grlib_gptimer_reset(DeviceState *d)
+{
+ GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
+ int i = 0;
+
+ assert(unit != NULL);
+
+ unit->scaler = 0;
+ unit->reload = 0;
+ unit->config = 0;
+
+ unit->config = unit->nr_timers;
+ unit->config |= unit->irq_line << 3;
+ unit->config |= 1 << 8; /* separate interrupt */
+ unit->config |= 1 << 9; /* Disable timer freeze */
+
+
+ for (i = 0; i < unit->nr_timers; i++) {
+ GPTimer *timer = &unit->timers[i];
+
+ timer->counter = 0;
+ timer->reload = 0;
+ timer->config = 0;
+ ptimer_stop(timer->ptimer);
+ ptimer_set_count(timer->ptimer, 0);
+ ptimer_set_freq(timer->ptimer, unit->freq_hz);
+ }
+}
+
+static int grlib_gptimer_init(SysBusDevice *dev)
+{
+ GPTimerUnit *unit = FROM_SYSBUS(typeof(*unit), dev);
+ unsigned int i;
+ int timer_regs;
+
+ assert(unit->nr_timers > 0);
+ assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
+
+ unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
+
+ for (i = 0; i < unit->nr_timers; i++) {
+ GPTimer *timer = &unit->timers[i];
+
+ timer->unit = unit;
+ timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
+ timer->ptimer = ptimer_init(timer->bh);
+ timer->id = i;
+
+ /* One IRQ line for each timer */
+ sysbus_init_irq(dev, &timer->irq);
+
+ ptimer_set_freq(timer->ptimer, unit->freq_hz);
+ }
+
+ timer_regs = cpu_register_io_memory(grlib_gptimer_read,
+ grlib_gptimer_write,
+ unit, DEVICE_NATIVE_ENDIAN);
+ if (timer_regs < 0) {
+ return -1;
+ }
+
+ sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers,
+ timer_regs);
+ return 0;
+}
+
+static SysBusDeviceInfo grlib_gptimer_info = {
+ .init = grlib_gptimer_init,
+ .qdev.name = "grlib,gptimer",
+ .qdev.reset = grlib_gptimer_reset,
+ .qdev.size = sizeof(GPTimerUnit),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
+ DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
+ DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
+
+static void grlib_gptimer_register(void)
+{
+ sysbus_register_withprop(&grlib_gptimer_info);
+}
+
+device_init(grlib_gptimer_register)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
new file mode 100644
index 0000000000..f47c491a48
--- /dev/null
+++ b/hw/grlib_irqmp.c
@@ -0,0 +1,376 @@
+/*
+ * QEMU GRLIB IRQMP Emulator
+ *
+ * (Multiprocessor and extended interrupt not supported)
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "cpu.h"
+
+#include "grlib.h"
+
+#include "trace.h"
+
+#define IRQMP_MAX_CPU 16
+#define IRQMP_REG_SIZE 256 /* Size of memory mapped registers */
+
+/* Memory mapped register offsets */
+#define LEVEL_OFFSET 0x00
+#define PENDING_OFFSET 0x04
+#define FORCE0_OFFSET 0x08
+#define CLEAR_OFFSET 0x0C
+#define MP_STATUS_OFFSET 0x10
+#define BROADCAST_OFFSET 0x14
+#define MASK_OFFSET 0x40
+#define FORCE_OFFSET 0x80
+#define EXTENDED_OFFSET 0xC0
+
+typedef struct IRQMPState IRQMPState;
+
+typedef struct IRQMP {
+ SysBusDevice busdev;
+
+ void *set_pil_in;
+ void *set_pil_in_opaque;
+
+ IRQMPState *state;
+} IRQMP;
+
+struct IRQMPState {
+ uint32_t level;
+ uint32_t pending;
+ uint32_t clear;
+ uint32_t broadcast;
+
+ uint32_t mask[IRQMP_MAX_CPU];
+ uint32_t force[IRQMP_MAX_CPU];
+ uint32_t extended[IRQMP_MAX_CPU];
+
+ IRQMP *parent;
+};
+
+static void grlib_irqmp_check_irqs(IRQMPState *state)
+{
+ uint32_t pend = 0;
+ uint32_t level0 = 0;
+ uint32_t level1 = 0;
+ set_pil_in_fn set_pil_in;
+
+ assert(state != NULL);
+ assert(state->parent != NULL);
+
+ /* IRQ for CPU 0 (no SMP support) */
+ pend = (state->pending | state->force[0])
+ & state->mask[0];
+
+ level0 = pend & ~state->level;
+ level1 = pend & state->level;
+
+ trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
+ state->mask[0], level1, level0);
+
+ set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
+
+ /* Trigger level1 interrupt first and level0 if there is no level1 */
+ if (level1 != 0) {
+ set_pil_in(state->parent->set_pil_in_opaque, level1);
+ } else {
+ set_pil_in(state->parent->set_pil_in_opaque, level0);
+ }
+}
+
+void grlib_irqmp_ack(DeviceState *dev, int intno)
+{
+ SysBusDevice *sdev;
+ IRQMP *irqmp;
+ IRQMPState *state;
+ uint32_t mask;
+
+ assert(dev != NULL);
+
+ sdev = sysbus_from_qdev(dev);
+ assert(sdev != NULL);
+
+ irqmp = FROM_SYSBUS(typeof(*irqmp), sdev);
+ assert(irqmp != NULL);
+
+ state = irqmp->state;
+ assert(state != NULL);
+
+ intno &= 15;
+ mask = 1 << intno;
+
+ trace_grlib_irqmp_ack(intno);
+
+ /* Clear registers */
+ state->pending &= ~mask;
+ state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
+
+ grlib_irqmp_check_irqs(state);
+}
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level)
+{
+ IRQMP *irqmp;
+ IRQMPState *s;
+ int i = 0;
+
+ assert(opaque != NULL);
+
+ irqmp = FROM_SYSBUS(typeof(*irqmp), sysbus_from_qdev(opaque));
+ assert(irqmp != NULL);
+
+ s = irqmp->state;
+ assert(s != NULL);
+ assert(s->parent != NULL);
+
+
+ if (level) {
+ trace_grlib_irqmp_set_irq(irq);
+
+ if (s->broadcast & 1 << irq) {
+ /* Broadcasted IRQ */
+ for (i = 0; i < IRQMP_MAX_CPU; i++) {
+ s->force[i] |= 1 << irq;
+ }
+ } else {
+ s->pending |= 1 << irq;
+ }
+ grlib_irqmp_check_irqs(s);
+
+ }
+}
+
+static uint32_t grlib_irqmp_readl(void *opaque, target_phys_addr_t addr)
+{
+ IRQMP *irqmp = opaque;
+ IRQMPState *state;
+
+ assert(irqmp != NULL);
+ state = irqmp->state;
+ assert(state != NULL);
+
+ addr &= 0xff;
+
+ /* global registers */
+ switch (addr) {
+ case LEVEL_OFFSET:
+ return state->level;
+
+ case PENDING_OFFSET:
+ return state->pending;
+
+ case FORCE0_OFFSET:
+ /* This register is an "alias" for the force register of CPU 0 */
+ return state->force[0];
+
+ case CLEAR_OFFSET:
+ case MP_STATUS_OFFSET:
+ /* Always read as 0 */
+ return 0;
+
+ case BROADCAST_OFFSET:
+ return state->broadcast;
+
+ default:
+ break;
+ }
+
+ /* mask registers */
+ if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+ int cpu = (addr - MASK_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ return state->mask[cpu];
+ }
+
+ /* force registers */
+ if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+ int cpu = (addr - FORCE_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ return state->force[cpu];
+ }
+
+ /* extended (not supported) */
+ if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+ int cpu = (addr - EXTENDED_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ return state->extended[cpu];
+ }
+
+ trace_grlib_irqmp_unknown_register("read", addr);
+ return 0;
+}
+
+static void
+grlib_irqmp_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ IRQMP *irqmp = opaque;
+ IRQMPState *state;
+
+ assert(irqmp != NULL);
+ state = irqmp->state;
+ assert(state != NULL);
+
+ addr &= 0xff;
+
+ /* global registers */
+ switch (addr) {
+ case LEVEL_OFFSET:
+ value &= 0xFFFF << 1; /* clean up the value */
+ state->level = value;
+ return;
+
+ case PENDING_OFFSET:
+ /* Read Only */
+ return;
+
+ case FORCE0_OFFSET:
+ /* This register is an "alias" for the force register of CPU 0 */
+
+ value &= 0xFFFE; /* clean up the value */
+ state->force[0] = value;
+ grlib_irqmp_check_irqs(irqmp->state);
+ return;
+
+ case CLEAR_OFFSET:
+ value &= ~1; /* clean up the value */
+ state->pending &= ~value;
+ return;
+
+ case MP_STATUS_OFFSET:
+ /* Read Only (no SMP support) */
+ return;
+
+ case BROADCAST_OFFSET:
+ value &= 0xFFFE; /* clean up the value */
+ state->broadcast = value;
+ return;
+
+ default:
+ break;
+ }
+
+ /* mask registers */
+ if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+ int cpu = (addr - MASK_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ value &= ~1; /* clean up the value */
+ state->mask[cpu] = value;
+ grlib_irqmp_check_irqs(irqmp->state);
+ return;
+ }
+
+ /* force registers */
+ if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+ int cpu = (addr - FORCE_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ uint32_t force = value & 0xFFFE;
+ uint32_t clear = (value >> 16) & 0xFFFE;
+ uint32_t old = state->force[cpu];
+
+ state->force[cpu] = (old | force) & ~clear;
+ grlib_irqmp_check_irqs(irqmp->state);
+ return;
+ }
+
+ /* extended (not supported) */
+ if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+ int cpu = (addr - EXTENDED_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ value &= 0xF; /* clean up the value */
+ state->extended[cpu] = value;
+ return;
+ }
+
+ trace_grlib_irqmp_unknown_register("write", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_irqmp_read[] = {
+ NULL, NULL, &grlib_irqmp_readl,
+};
+
+static CPUWriteMemoryFunc * const grlib_irqmp_write[] = {
+ NULL, NULL, &grlib_irqmp_writel,
+};
+
+static void grlib_irqmp_reset(DeviceState *d)
+{
+ IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev);
+ assert(irqmp != NULL);
+ assert(irqmp->state != NULL);
+
+ memset(irqmp->state, 0, sizeof *irqmp->state);
+ irqmp->state->parent = irqmp;
+}
+
+static int grlib_irqmp_init(SysBusDevice *dev)
+{
+ IRQMP *irqmp = FROM_SYSBUS(typeof(*irqmp), dev);
+ int irqmp_regs;
+
+ assert(irqmp != NULL);
+
+ /* Check parameters */
+ if (irqmp->set_pil_in == NULL) {
+ return -1;
+ }
+
+ irqmp_regs = cpu_register_io_memory(grlib_irqmp_read,
+ grlib_irqmp_write,
+ irqmp, DEVICE_NATIVE_ENDIAN);
+
+ irqmp->state = qemu_mallocz(sizeof *irqmp->state);
+
+ if (irqmp_regs < 0) {
+ return -1;
+ }
+
+ sysbus_init_mmio(dev, IRQMP_REG_SIZE, irqmp_regs);
+
+ return 0;
+}
+
+static SysBusDeviceInfo grlib_irqmp_info = {
+ .init = grlib_irqmp_init,
+ .qdev.name = "grlib,irqmp",
+ .qdev.reset = grlib_irqmp_reset,
+ .qdev.size = sizeof(IRQMP),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
+ DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void grlib_irqmp_register(void)
+{
+ sysbus_register_withprop(&grlib_irqmp_info);
+}
+
+device_init(grlib_irqmp_register)
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/gumstix.c b/hw/gumstix.c
index af8b464b88..ee63f634cc 100644
--- a/hw/gumstix.c
+++ b/hw/gumstix.c
@@ -78,7 +78,7 @@ static void connex_init(ram_addr_t ram_size,
/* Interrupt line of NIC is connected to GPIO line 36 */
smc91c111_init(&nd_table[0], 0x04000300,
- pxa2xx_gpio_in_get(cpu->gpio)[36]);
+ qdev_get_gpio_in(cpu->gpio, 36));
}
static void verdex_init(ram_addr_t ram_size,
@@ -117,7 +117,7 @@ static void verdex_init(ram_addr_t ram_size,
/* Interrupt line of NIC is connected to GPIO line 99 */
smc91c111_init(&nd_table[0], 0x04000300,
- pxa2xx_gpio_in_get(cpu->gpio)[99]);
+ qdev_get_gpio_in(cpu->gpio, 99));
}
static QEMUMachine connex_machine = {
diff --git a/hw/hw.h b/hw/hw.h
index 163a68327e..dd993de10c 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -799,17 +799,16 @@ extern const VMStateDescription vmstate_i2c_slave;
#define VMSTATE_END_OF_LIST() \
{}
-extern int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, int version_id);
-extern void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque);
-extern int vmstate_register(DeviceState *dev, int instance_id,
- const VMStateDescription *vmsd, void *base);
-extern int vmstate_register_with_alias_id(DeviceState *dev,
- int instance_id,
- const VMStateDescription *vmsd,
- void *base, int alias_id,
- int required_for_version);
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, int version_id);
+void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque);
+int vmstate_register(DeviceState *dev, int instance_id,
+ const VMStateDescription *vmsd, void *base);
+int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+ const VMStateDescription *vmsd,
+ void *base, int alias_id,
+ int required_for_version);
void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
void *opaque);
#endif
diff --git a/hw/ide.h b/hw/ide.h
index 2b5ae7c39e..73fb550574 100644
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -4,6 +4,8 @@
#include "isa.h"
#include "pci.h"
+#define MAX_IDE_DEVS 2
+
/* ide-isa.c */
ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
DriveInfo *hd0, DriveInfo *hd1);
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 968fdcecaf..671b4df7f6 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -70,7 +70,6 @@
#include "monitor.h"
#include "dma.h"
#include "cpu-common.h"
-#include "blockdev.h"
#include "internal.h"
#include <hw/ide/pci.h>
@@ -513,12 +512,12 @@ static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted)
target_phys_addr_t len = wanted;
if (*ptr) {
- cpu_physical_memory_unmap(*ptr, 1, len, len);
+ cpu_physical_memory_unmap(*ptr, len, 1, len);
}
*ptr = cpu_physical_memory_map(addr, &len, 1);
if (len < wanted) {
- cpu_physical_memory_unmap(*ptr, 1, len, len);
+ cpu_physical_memory_unmap(*ptr, len, 1, len);
*ptr = NULL;
}
}
@@ -956,7 +955,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
if (cmd_mapped) {
- cpu_physical_memory_unmap(cmd_fis, 0, cmd_len, cmd_len);
+ cpu_physical_memory_unmap(cmd_fis, cmd_len, 0, cmd_len);
}
}
@@ -1002,7 +1001,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
}
out:
- cpu_physical_memory_unmap(prdt, 0, prdt_len, prdt_len);
+ cpu_physical_memory_unmap(prdt, prdt_len, 0, prdt_len);
return r;
}
@@ -1228,7 +1227,7 @@ static int handle_cmd(AHCIState *s, int port, int slot)
}
out:
- cpu_physical_memory_unmap(cmd_fis, 1, cmd_len, cmd_len);
+ cpu_physical_memory_unmap(cmd_fis, cmd_len, 1, cmd_len);
if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
/* async command, complete later */
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9496e990b9..dd63664c0d 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -321,14 +321,6 @@ static inline void ide_abort_command(IDEState *s)
s->error = ABRT_ERR;
}
-static inline void ide_dma_submit_check(IDEState *s,
- BlockDriverCompletionFunc *dma_cb)
-{
- if (s->bus->dma->aiocb)
- return;
- dma_cb(s, -1);
-}
-
/* prepare data transfer and tell what to do after */
static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func)
@@ -487,16 +479,19 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
return 1;
}
-void ide_read_dma_cb(void *opaque, int ret)
+void ide_dma_cb(void *opaque, int ret)
{
IDEState *s = opaque;
int n;
int64_t sector_num;
+handle_rw_error:
if (ret < 0) {
- if (ide_handle_rw_error(s, -ret,
- BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ))
- {
+ int op = BM_STATUS_DMA_RETRY;
+
+ if (s->is_read)
+ op |= BM_STATUS_RETRY_READ;
+ if (ide_handle_rw_error(s, -ret, op)) {
return;
}
}
@@ -504,7 +499,7 @@ void ide_read_dma_cb(void *opaque, int ret)
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
- dma_buf_commit(s, 1);
+ dma_buf_commit(s, s->is_read);
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
@@ -514,32 +509,47 @@ void ide_read_dma_cb(void *opaque, int ret)
if (s->nsector == 0) {
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s->bus);
- eot:
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
- ide_set_inactive(s);
- return;
+ goto eot;
}
/* launch next transfer */
n = s->nsector;
s->io_buffer_index = 0;
s->io_buffer_size = n * 512;
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, 1) == 0)
+ if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->is_read) == 0)
goto eot;
+
#ifdef DEBUG_AIO
- printf("aio_read: sector_num=%" PRId64 " n=%d\n", sector_num, n);
+ printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, is_read=%d\n",
+ sector_num, n, s->is_read);
#endif
- s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, ide_read_dma_cb, s);
- ide_dma_submit_check(s, ide_read_dma_cb);
+
+ if (s->is_read) {
+ s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
+ ide_dma_cb, s);
+ } else {
+ s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
+ ide_dma_cb, s);
+ }
+
+ if (!s->bus->dma->aiocb) {
+ ret = -1;
+ goto handle_rw_error;
+ }
+ return;
+
+eot:
+ s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
+ ide_set_inactive(s);
}
-static void ide_sector_read_dma(IDEState *s)
+static void ide_sector_start_dma(IDEState *s, int is_read)
{
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
s->io_buffer_index = 0;
s->io_buffer_size = 0;
- s->is_read = 1;
- s->bus->dma->ops->start_dma(s->bus->dma, s, ide_read_dma_cb);
+ s->is_read = is_read;
+ s->bus->dma->ops->start_dma(s->bus->dma, s, ide_dma_cb);
}
static void ide_sector_write_timer_cb(void *opaque)
@@ -594,57 +604,6 @@ void ide_sector_write(IDEState *s)
}
}
-void ide_write_dma_cb(void *opaque, int ret)
-{
- IDEState *s = opaque;
- int n;
- int64_t sector_num;
-
- if (ret < 0) {
- if (ide_handle_rw_error(s, -ret, BM_STATUS_DMA_RETRY))
- return;
- }
-
- n = s->io_buffer_size >> 9;
- sector_num = ide_get_sector(s);
- if (n > 0) {
- dma_buf_commit(s, 0);
- sector_num += n;
- ide_set_sector(s, sector_num);
- s->nsector -= n;
- }
-
- /* end of transfer ? */
- if (s->nsector == 0) {
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s->bus);
- eot:
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
- ide_set_inactive(s);
- return;
- }
-
- n = s->nsector;
- s->io_buffer_size = n * 512;
- /* launch next transfer */
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, 0) == 0)
- goto eot;
-#ifdef DEBUG_AIO
- printf("aio_write: sector_num=%" PRId64 " n=%d\n", sector_num, n);
-#endif
- s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, ide_write_dma_cb, s);
- ide_dma_submit_check(s, ide_write_dma_cb);
-}
-
-static void ide_sector_write_dma(IDEState *s)
-{
- s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
- s->io_buffer_index = 0;
- s->io_buffer_size = 0;
- s->is_read = 0;
- s->bus->dma->ops->start_dma(s->bus->dma, s, ide_write_dma_cb);
-}
-
void ide_atapi_cmd_ok(IDEState *s)
{
s->error = 0;
@@ -1625,11 +1584,15 @@ static void ide_cfata_metadata_write(IDEState *s)
}
/* called when the inserted state of the media has changed */
-static void cdrom_change_cb(void *opaque)
+static void cdrom_change_cb(void *opaque, int reason)
{
IDEState *s = opaque;
uint64_t nb_sectors;
+ if (!(reason & CHANGE_MEDIA)) {
+ return;
+ }
+
bdrv_get_geometry(s->bs, &nb_sectors);
s->nb_sectors = nb_sectors;
@@ -1858,7 +1821,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
- ide_sector_read_dma(s);
+ ide_sector_start_dma(s, 1);
break;
case WIN_WRITEDMA_EXT:
lba48 = 1;
@@ -1867,7 +1830,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
- ide_sector_write_dma(s);
+ ide_sector_start_dma(s, 0);
s->media_changed = 1;
break;
case WIN_READ_NATIVE_MAX_EXT:
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 697c3b4dc1..d533fb63b3 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -439,7 +439,6 @@ struct IDEState {
uint32_t mdata_size;
uint8_t *mdata_storage;
int media_changed;
- /* for pmac */
int is_read;
/* SMART */
uint8_t smart_enabled;
@@ -560,8 +559,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
void ide_exec_cmd(IDEBus *bus, uint32_t val);
-void ide_read_dma_cb(void *opaque, int ret);
-void ide_write_dma_cb(void *opaque, int ret);
+void ide_dma_cb(void *opaque, int ret);
void ide_sector_write(IDEState *s);
void ide_sector_read(IDEState *s);
void ide_flush_cache(IDEState *s);
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 510b2de597..35168cb469 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -178,14 +178,9 @@ static void bmdma_restart_dma(BMDMAState *bm, int is_read)
s->io_buffer_index = 0;
s->io_buffer_size = 0;
s->nsector = bm->nsector;
+ s->is_read = is_read;
bm->cur_addr = bm->addr;
-
- if (is_read) {
- bm->dma_cb = ide_read_dma_cb;
- } else {
- bm->dma_cb = ide_write_dma_cb;
- }
-
+ bm->dma_cb = ide_dma_cb;
bmdma_start_dma(&bm->dma, s, bm->dma_cb);
}
@@ -272,9 +267,7 @@ static void bmdma_irq(void *opaque, int n, int level)
return;
}
- if (bm) {
- bm->status |= BM_STATUS_INT;
- }
+ bm->status |= BM_STATUS_INT;
/* trigger the real irq */
qemu_set_irq(bm->irq, level);
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/leon3.c b/hw/leon3.c
new file mode 100644
index 0000000000..69d8f3b655
--- /dev/null
+++ b/hw/leon3.c
@@ -0,0 +1,218 @@
+/*
+ * QEMU Leon3 System Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "trace.h"
+
+#include "grlib.h"
+
+/* Default system clock. */
+#define CPU_CLK (40 * 1000 * 1000)
+
+#define PROM_FILENAME "u-boot.bin"
+
+#define MAX_PILS 16
+
+typedef struct ResetData {
+ CPUState *env;
+ uint32_t entry; /* save kernel entry in case of reset */
+} ResetData;
+
+static void main_cpu_reset(void *opaque)
+{
+ ResetData *s = (ResetData *)opaque;
+ CPUState *env = s->env;
+
+ cpu_reset(env);
+
+ env->halted = 0;
+ env->pc = s->entry;
+ env->npc = s->entry + 4;
+}
+
+static void leon3_irq_ack(void *irq_manager, int intno)
+{
+ grlib_irqmp_ack((DeviceState *)irq_manager, intno);
+ leon3_cache_control_int();
+}
+
+static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
+{
+ CPUState *env = (CPUState *)opaque;
+
+ assert(env != NULL);
+
+ env->pil_in = pil_in;
+
+ if (env->pil_in && (env->interrupt_index == 0 ||
+ (env->interrupt_index & ~15) == TT_EXTINT)) {
+ unsigned int i;
+
+ for (i = 15; i > 0; i--) {
+ if (env->pil_in & (1 << i)) {
+ int old_interrupt = env->interrupt_index;
+
+ env->interrupt_index = TT_EXTINT | i;
+ if (old_interrupt != env->interrupt_index) {
+ trace_leon3_set_irq(i);
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+ break;
+ }
+ }
+ } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+ trace_leon3_reset_irq(env->interrupt_index & 15);
+ env->interrupt_index = 0;
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void leon3_generic_hw_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ CPUState *env;
+ ram_addr_t ram_offset, prom_offset;
+ int ret;
+ char *filename;
+ qemu_irq *cpu_irqs = NULL;
+ int bios_size;
+ int prom_size;
+ ResetData *reset_info;
+
+ /* Init CPU */
+ if (!cpu_model) {
+ cpu_model = "LEON3";
+ }
+
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+ exit(1);
+ }
+
+ cpu_sparc_set_id(env, 0);
+
+ /* Reset data */
+ reset_info = qemu_mallocz(sizeof(ResetData));
+ reset_info->env = env;
+ qemu_register_reset(main_cpu_reset, reset_info);
+
+ /* Allocate IRQ manager */
+ grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
+
+ env->qemu_irq_ack = leon3_irq_ack;
+
+ /* Allocate RAM */
+ if ((uint64_t)ram_size > (1UL << 30)) {
+ fprintf(stderr,
+ "qemu: Too much memory for this machine: %d, maximum 1G\n",
+ (unsigned int)(ram_size / (1024 * 1024)));
+ exit(1);
+ }
+
+ ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
+ cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
+
+ /* Allocate BIOS */
+ prom_size = 8 * 1024 * 1024; /* 8Mb */
+ prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
+ cpu_register_physical_memory(0x00000000, prom_size,
+ prom_offset | IO_MEM_ROM);
+
+ /* Load boot prom */
+ if (bios_name == NULL) {
+ bios_name = PROM_FILENAME;
+ }
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+ bios_size = get_image_size(filename);
+
+ if (bios_size > prom_size) {
+ fprintf(stderr, "qemu: could not load prom '%s': file too big\n",
+ filename);
+ exit(1);
+ }
+
+ if (bios_size > 0) {
+ ret = load_image_targphys(filename, 0x00000000, bios_size);
+ if (ret < 0 || ret > prom_size) {
+ fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
+ exit(1);
+ }
+ } else if (kernel_filename == NULL) {
+ fprintf(stderr, "Can't read bios image %s\n", filename);
+ exit(1);
+ }
+
+ /* Can directly load an application. */
+ if (kernel_filename != NULL) {
+ long kernel_size;
+ uint64_t entry;
+
+ kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+ 1 /* big endian */, ELF_MACHINE, 0);
+ if (kernel_size < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ kernel_filename);
+ exit(1);
+ }
+ if (bios_size <= 0) {
+ /* If there is no bios/monitor, start the application. */
+ env->pc = entry;
+ env->npc = entry + 4;
+ reset_info->entry = entry;
+ }
+ }
+
+ /* Allocate timers */
+ grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
+
+ /* Allocate uart */
+ if (serial_hds[0]) {
+ grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
+ }
+}
+
+QEMUMachine leon3_generic_machine = {
+ .name = "leon3_generic",
+ .desc = "Leon-3 generic",
+ .init = leon3_generic_hw_init,
+ .use_scsi = 0,
+};
+
+static void leon3_machine_init(void)
+{
+ qemu_register_machine(&leon3_generic_machine);
+}
+
+machine_init(leon3_machine_init);
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/mc146818rtc.c b/hw/mc146818rtc.c
index 6466aff316..a1b0e31ee5 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -72,6 +72,7 @@
#define REG_B_UIE 0x10
#define REG_B_SQWE 0x08
#define REG_B_DM 0x04
+#define REG_B_24H 0x02
#define REG_C_UF 0x10
#define REG_C_IRQF 0x80
@@ -246,7 +247,15 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
rtc_set_time(s);
}
}
- s->cmos_data[RTC_REG_B] = data;
+ if (((s->cmos_data[RTC_REG_B] ^ data) & (REG_B_DM | REG_B_24H)) &&
+ !(data & REG_B_SET)) {
+ /* If the time format has changed and not in set mode,
+ update the registers immediately. */
+ s->cmos_data[RTC_REG_B] = data;
+ rtc_copy_date(s);
+ } else {
+ s->cmos_data[RTC_REG_B] = data;
+ }
rtc_timer_update(s, qemu_get_clock(rtc_clock));
break;
case RTC_REG_C:
@@ -285,7 +294,7 @@ static void rtc_set_time(RTCState *s)
tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
- if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
+ if (!(s->cmos_data[RTC_REG_B] & REG_B_24H) &&
(s->cmos_data[RTC_HOURS] & 0x80)) {
tm->tm_hour += 12;
}
@@ -304,7 +313,7 @@ static void rtc_copy_date(RTCState *s)
s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
- if (s->cmos_data[RTC_REG_B] & 0x02) {
+ if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
/* 24 hour format */
s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
} else {
diff --git a/hw/mips.h b/hw/mips.h
index 617ea103c0..73aa8f8b0e 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);
@@ -21,7 +21,7 @@ int g364fb_mm_init(target_phys_addr_t vram_base,
void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
/* jazz_led.c */
-extern void jazz_led_init(target_phys_addr_t base);
+void jazz_led_init(target_phys_addr_t base);
/* rc4030.c */
typedef struct rc4030DMAState *rc4030_dma;
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index 07eb9eeba1..2783ed5837 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -218,13 +218,11 @@ uint8_t eeprom_spd[0x80] = {
};
/* Audio support */
-#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus)
{
vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
}
-#endif
/* Network support */
static void network_init (void)
@@ -391,9 +389,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
}
/* Sound card */
-#ifdef HAS_AUDIO
audio_init(pci_bus);
-#endif
/* Network card */
network_init();
}
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index a7caa3f171..85eba5a69a 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -29,7 +29,7 @@
#include "isa.h"
#include "fdc.h"
#include "sysemu.h"
-#include "audio/audio.h"
+#include "arch_init.h"
#include "boards.h"
#include "net.h"
#include "esp.h"
@@ -90,26 +90,6 @@ static CPUWriteMemoryFunc * const dma_dummy_write[3] = {
dma_dummy_writeb,
};
-static void audio_init(qemu_irq *pic)
-{
- struct soundhw *c;
- int audio_enabled = 0;
-
- for (c = soundhw; !audio_enabled && c->name; ++c) {
- audio_enabled = c->enabled;
- }
-
- if (audio_enabled) {
- for (c = soundhw; c->name; ++c) {
- if (c->enabled) {
- if (c->isa) {
- c->init.init_isa(pic);
- }
- }
- }
- }
-}
-
#define MAGNUM_BIOS_SIZE_MAX 0x7e000
#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
@@ -284,7 +264,7 @@ void mips_jazz_init (ram_addr_t ram_size,
/* Sound card */
/* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
- audio_init(i8259);
+ audio_init(i8259, NULL);
/* NVRAM: Unprotected at 0x9000, Protected at 0xa000, Read only at 0xb000 */
ds1225y_init(0x80009000, "nvram");
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 5ef3fcbea9..2d3f242cc8 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -37,7 +37,7 @@
#include "vmware_vga.h"
#include "qemu-char.h"
#include "sysemu.h"
-#include "audio/audio.h"
+#include "arch_init.h"
#include "boards.h"
#include "qemu-log.h"
#include "mips-bios.h"
@@ -457,25 +457,6 @@ static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_ir
return s;
}
-/* Audio support */
-static void audio_init (PCIBus *pci_bus)
-{
- struct soundhw *c;
- int audio_enabled = 0;
-
- for (c = soundhw; !audio_enabled && c->name; ++c) {
- audio_enabled = c->enabled;
- }
-
- if (audio_enabled) {
- for (c = soundhw; c->name; ++c) {
- if (c->enabled) {
- c->init.init_pci(pci_bus);
- }
- }
- }
-}
-
/* Network support */
static void network_init(void)
{
@@ -910,7 +891,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 +902,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 */
@@ -967,7 +948,7 @@ void mips_malta_init (ram_addr_t ram_size,
fdctrl_init_isa(fd);
/* Sound card */
- audio_init(pci_bus);
+ audio_init(NULL, pci_bus);
/* Network card */
network_init();
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/multiboot.c b/hw/multiboot.c
index 7cc3055359..0d2bfb4973 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -306,7 +306,7 @@ int load_multiboot(void *fw_cfg,
| MULTIBOOT_FLAGS_MODULES
| MULTIBOOT_FLAGS_MMAP);
stl_p(bootinfo + MBI_MEM_LOWER, 640);
- stl_p(bootinfo + MBI_MEM_UPPER, ram_size / 1024);
+ stl_p(bootinfo + MBI_MEM_UPPER, (ram_size / 1024) - 1024);
stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
diff --git a/hw/onenand.c b/hw/onenand.c
index d9cdcf2944..71c1ab40b4 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -19,6 +19,7 @@
*/
#include "qemu-common.h"
+#include "hw.h"
#include "flash.h"
#include "irq.h"
#include "blockdev.h"
diff --git a/hw/pc.c b/hw/pc.c
index fface7dec9..4dfdc0be53 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -829,23 +829,6 @@ static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
-void pc_audio_init (PCIBus *pci_bus, qemu_irq *pic)
-{
- struct soundhw *c;
-
- for (c = soundhw; c->name; ++c) {
- if (c->enabled) {
- if (c->isa) {
- c->init.init_isa(pic);
- } else {
- if (pci_bus) {
- c->init.init_pci(pci_bus);
- }
- }
- }
- }
-}
-
void pc_init_ne2k_isa(NICInfo *nd)
{
static int nb_ne2k = 0;
diff --git a/hw/pc.h b/hw/pc.h
index 68527902a5..a048768d21 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -100,9 +100,6 @@ void pc_basic_device_init(qemu_irq *isa_irq,
FDCtrl **floppy_controller,
ISADevice **rtc_state);
void pc_init_ne2k_isa(NICInfo *nd);
-#ifdef HAS_AUDIO
-void pc_audio_init (PCIBus *pci_bus, qemu_irq *pic);
-#endif
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
const char *boot_device,
BusState *ide0, BusState *ide1,
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index f82508d92f..7b744730f7 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,6 +34,7 @@
#include "kvm.h"
#include "sysemu.h"
#include "sysbus.h"
+#include "arch_init.h"
#include "blockdev.h"
#define MAX_IDE_BUS 2
@@ -148,7 +149,7 @@ static void pc_init1(ram_addr_t ram_size,
}
}
- pc_audio_init(pci_enabled ? pci_bus : NULL, isa_irq);
+ audio_init(isa_irq, pci_enabled ? pci_bus : NULL);
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
idebus[0], idebus[1], floppy_controller, rtc_state);
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 716133c376..b6dcbda0ce 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -90,7 +90,8 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
* specified).
*/
dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
- scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit);
+ dinfo->bus = scsibus->busnr;
+ scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, false);
if (!scsidev) {
return -1;
}
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/pl181.c b/hw/pl181.c
index 3e5f92f0e7..36d9d02d6a 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -7,6 +7,7 @@
* This code is licenced under the GPL.
*/
+#include "blockdev.h"
#include "sysbus.h"
#include "sd.h"
@@ -449,15 +450,15 @@ static int pl181_init(SysBusDevice *dev)
{
int iomemtype;
pl181_state *s = FROM_SYSBUS(pl181_state, dev);
- BlockDriverState *bd;
+ DriveInfo *dinfo;
iomemtype = cpu_register_io_memory(pl181_readfn, pl181_writefn, s,
DEVICE_NATIVE_ENDIAN);
sysbus_init_mmio(dev, 0x1000, iomemtype);
sysbus_init_irq(dev, &s->irq[0]);
sysbus_init_irq(dev, &s->irq[1]);
- bd = qdev_init_bdrv(&dev->qdev, IF_SD);
- s->card = sd_init(bd, 0);
+ dinfo = drive_get_next(IF_SD);
+ s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
qemu_register_reset(pl181_reset, s);
pl181_reset(s);
/* ??? Save/restore. */
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/ppc_prep.c b/hw/ppc_prep.c
index 1492266267..6c1499a780 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -600,9 +600,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
if (filename) {
qemu_free(filename);
}
- if (env->nip < 0xFFF80000 && bios_size < 0x00100000) {
- hw_error("PowerPC 601 / 620 / 970 need a 1MB BIOS\n");
- }
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
@@ -693,7 +690,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
}
- for(i = 0; i < MAX_IDE_BUS; i++) {
+ for(i = 0; i < 1/*MAX_IDE_BUS*/; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
hd[2 * i],
hd[2 * i + 1]);
diff --git a/hw/pxa.h b/hw/pxa.h
index 8d6a8c3348..f73d33b1a8 100644
--- a/hw/pxa.h
+++ b/hw/pxa.h
@@ -70,13 +70,9 @@ void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs);
void pxa27x_timer_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq irq4);
/* pxa2xx_gpio.c */
-typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo;
-PXA2xxGPIOInfo *pxa2xx_gpio_init(target_phys_addr_t base,
+DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
CPUState *env, qemu_irq *pic, int lines);
-qemu_irq *pxa2xx_gpio_in_get(PXA2xxGPIOInfo *s);
-void pxa2xx_gpio_out_set(PXA2xxGPIOInfo *s,
- int line, qemu_irq handler);
-void pxa2xx_gpio_read_notifier(PXA2xxGPIOInfo *s, qemu_irq handler);
+void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler);
/* pxa2xx_dma.c */
typedef struct PXA2xxDMAState PXA2xxDMAState;
@@ -132,7 +128,7 @@ typedef struct {
qemu_irq *pic;
qemu_irq reset;
PXA2xxDMAState *dma;
- PXA2xxGPIOInfo *gpio;
+ DeviceState *gpio;
PXA2xxLCDState *lcd;
SSIBus **ssp;
PXA2xxI2CState *i2c[2];
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index ab524a779a..d966846f94 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()
}
};
@@ -2158,7 +2158,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
/* GPIO1 resets the processor */
/* The handler can be overridden by board-specific code */
- pxa2xx_gpio_out_set(s->gpio, 1, s->reset);
+ qdev_connect_gpio_out(s->gpio, 1, s->reset);
return s;
}
@@ -2279,7 +2279,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
/* GPIO1 resets the processor */
/* The handler can be overridden by board-specific code */
- pxa2xx_gpio_out_set(s->gpio, 1, s->reset);
+ qdev_connect_gpio_out(s->gpio, 1, s->reset);
return s;
}
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index 0d034462d2..789965d88b 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -8,15 +8,18 @@
*/
#include "hw.h"
+#include "sysbus.h"
#include "pxa.h"
#define PXA2XX_GPIO_BANKS 4
+typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo;
struct PXA2xxGPIOInfo {
- qemu_irq *pic;
+ SysBusDevice busdev;
+ qemu_irq irq0, irq1, irqX;
int lines;
+ int ncpu;
CPUState *cpu_env;
- qemu_irq *in;
/* XXX: GNU C vectors are more suitable */
uint32_t ilevel[PXA2XX_GPIO_BANKS];
@@ -66,19 +69,19 @@ static struct {
static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s)
{
if (s->status[0] & (1 << 0))
- qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_0]);
+ qemu_irq_raise(s->irq0);
else
- qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_0]);
+ qemu_irq_lower(s->irq0);
if (s->status[0] & (1 << 1))
- qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_1]);
+ qemu_irq_raise(s->irq1);
else
- qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_1]);
+ qemu_irq_lower(s->irq1);
if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
- qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_X]);
+ qemu_irq_raise(s->irqX);
else
- qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_X]);
+ qemu_irq_lower(s->irqX);
}
/* Bitmap of pins used as standby and sleep wake-up sources. */
@@ -249,96 +252,89 @@ static CPUWriteMemoryFunc * const pxa2xx_gpio_writefn[] = {
pxa2xx_gpio_write
};
-static void pxa2xx_gpio_save(QEMUFile *f, void *opaque)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- int i;
-
- qemu_put_be32(f, s->lines);
-
- for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
- qemu_put_be32s(f, &s->ilevel[i]);
- qemu_put_be32s(f, &s->olevel[i]);
- qemu_put_be32s(f, &s->dir[i]);
- qemu_put_be32s(f, &s->rising[i]);
- qemu_put_be32s(f, &s->falling[i]);
- qemu_put_be32s(f, &s->status[i]);
- qemu_put_be32s(f, &s->gafr[i * 2 + 0]);
- qemu_put_be32s(f, &s->gafr[i * 2 + 1]);
-
- qemu_put_be32s(f, &s->prev_level[i]);
- }
-}
-
-static int pxa2xx_gpio_load(QEMUFile *f, void *opaque, int version_id)
+DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
+ CPUState *env, qemu_irq *pic, int lines)
{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- int i;
+ DeviceState *dev;
- if (qemu_get_be32(f) != s->lines)
- return -EINVAL;
+ dev = qdev_create(NULL, "pxa2xx-gpio");
+ qdev_prop_set_int32(dev, "lines", lines);
+ qdev_prop_set_int32(dev, "ncpu", env->cpu_index);
+ qdev_init_nofail(dev);
- for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
- qemu_get_be32s(f, &s->ilevel[i]);
- qemu_get_be32s(f, &s->olevel[i]);
- qemu_get_be32s(f, &s->dir[i]);
- qemu_get_be32s(f, &s->rising[i]);
- qemu_get_be32s(f, &s->falling[i]);
- qemu_get_be32s(f, &s->status[i]);
- qemu_get_be32s(f, &s->gafr[i * 2 + 0]);
- qemu_get_be32s(f, &s->gafr[i * 2 + 1]);
-
- qemu_get_be32s(f, &s->prev_level[i]);
- }
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[PXA2XX_PIC_GPIO_0]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[PXA2XX_PIC_GPIO_1]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[PXA2XX_PIC_GPIO_X]);
- return 0;
+ return dev;
}
-PXA2xxGPIOInfo *pxa2xx_gpio_init(target_phys_addr_t base,
- CPUState *env, qemu_irq *pic, int lines)
+static int pxa2xx_gpio_initfn(SysBusDevice *dev)
{
int iomemtype;
PXA2xxGPIOInfo *s;
- s = (PXA2xxGPIOInfo *)
- qemu_mallocz(sizeof(PXA2xxGPIOInfo));
- memset(s, 0, sizeof(PXA2xxGPIOInfo));
- s->pic = pic;
- s->lines = lines;
- s->cpu_env = env;
- s->in = qemu_allocate_irqs(pxa2xx_gpio_set, s, lines);
+ s = FROM_SYSBUS(PXA2xxGPIOInfo, dev);
- iomemtype = cpu_register_io_memory(pxa2xx_gpio_readfn,
- pxa2xx_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(base, 0x00001000, iomemtype);
+ s->cpu_env = qemu_get_cpu(s->ncpu);
- register_savevm(NULL, "pxa2xx_gpio", 0, 0,
- pxa2xx_gpio_save, pxa2xx_gpio_load, s);
-
- return s;
-}
+ qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines);
+ qdev_init_gpio_out(&dev->qdev, s->handler, s->lines);
-qemu_irq *pxa2xx_gpio_in_get(PXA2xxGPIOInfo *s)
-{
- return s->in;
-}
+ iomemtype = cpu_register_io_memory(pxa2xx_gpio_readfn,
+ pxa2xx_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
-void pxa2xx_gpio_out_set(PXA2xxGPIOInfo *s,
- int line, qemu_irq handler)
-{
- if (line >= s->lines) {
- printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
- return;
- }
+ sysbus_init_mmio(dev, 0x1000, iomemtype);
+ sysbus_init_irq(dev, &s->irq0);
+ sysbus_init_irq(dev, &s->irq1);
+ sysbus_init_irq(dev, &s->irqX);
- s->handler[line] = handler;
+ return 0;
}
/*
* Registers a callback to notify on GPLR reads. This normally
* shouldn't be needed but it is used for the hack on Spitz machines.
*/
-void pxa2xx_gpio_read_notifier(PXA2xxGPIOInfo *s, qemu_irq handler)
+void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler)
{
+ PXA2xxGPIOInfo *s = FROM_SYSBUS(PXA2xxGPIOInfo, sysbus_from_qdev(dev));
s->read_notify = handler;
}
+
+static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
+ .name = "pxa2xx-gpio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(lines, PXA2xxGPIOInfo),
+ VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static SysBusDeviceInfo pxa2xx_gpio_info = {
+ .init = pxa2xx_gpio_initfn,
+ .qdev.name = "pxa2xx-gpio",
+ .qdev.desc = "PXA2xx GPIO controller",
+ .qdev.size = sizeof(PXA2xxGPIOInfo),
+ .qdev.props = (Property []) {
+ DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
+ DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void pxa2xx_gpio_register(void)
+{
+ sysbus_register_withprop(&pxa2xx_gpio_info);
+}
+device_init(pxa2xx_gpio_register);
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 5b8d3742ec..c7fec44a83 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -29,7 +29,6 @@
#include "qdev.h"
#include "sysemu.h"
#include "monitor.h"
-#include "blockdev.h"
static int qdev_hotplug = 0;
static bool qdev_hot_added = false;
@@ -458,20 +457,6 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
}
}
-static int next_block_unit[IF_COUNT];
-
-/* Get a block device. This should only be used for single-drive devices
- (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
- appropriate bus. */
-BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
-{
- int unit = next_block_unit[type]++;
- DriveInfo *dinfo;
-
- dinfo = drive_get(type, 0, unit);
- return dinfo ? dinfo->bdrv : NULL;
-}
-
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
{
BusState *bus;
diff --git a/hw/qdev.h b/hw/qdev.h
index e520aaa786..9808f85119 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -137,8 +137,6 @@ 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);
-BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type);
-
BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
/*** Device API. ***/
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/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index 669b610a14..33379a3ba4 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -58,14 +58,12 @@ typedef struct VirtIOS390Bus {
} VirtIOS390Bus;
-extern void s390_virtio_device_update_status(VirtIOS390Device *dev);
+void s390_virtio_device_update_status(VirtIOS390Device *dev);
-extern VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus);
-extern VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size);
+VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus);
+VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size);
-extern VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
- ram_addr_t mem,
- int *vq_num);
-extern VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus,
- ram_addr_t mem);
-extern void s390_virtio_device_sync(VirtIOS390Device *dev);
+VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
+ ram_addr_t mem, int *vq_num);
+VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem);
+void s390_virtio_device_sync(VirtIOS390Device *dev);
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 7febb86e77..ceeb4ecb91 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -87,7 +87,8 @@ void scsi_qdev_register(SCSIDeviceInfo *info)
}
/* handle legacy '-drive if=scsi,...' cmd line args */
-SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit)
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
+ int unit, bool removable)
{
const char *driver;
DeviceState *dev;
@@ -95,6 +96,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int
driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
dev = qdev_create(&bus->qbus, driver);
qdev_prop_set_uint32(dev, "scsi-id", unit);
+ if (qdev_prop_exists(dev, "removable")) {
+ qdev_prop_set_bit(dev, "removable", removable);
+ }
if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
qdev_free(dev);
return NULL;
@@ -117,7 +121,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
continue;
}
qemu_opts_loc_restore(dinfo->opts);
- if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit)) {
+ if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false)) {
res = -1;
break;
}
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 6cb317c8f9..488eedd2cd 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -72,6 +72,7 @@ struct SCSIDiskState
/* The qemu block layer uses a fixed 512 byte sector size.
This is the number of 512 byte blocks in a single scsi sector. */
int cluster_size;
+ uint32_t removable;
uint64_t max_lba;
QEMUBH *bh;
char *version;
@@ -552,6 +553,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
memcpy(&outbuf[16], "QEMU CD-ROM ", 16);
} else {
outbuf[0] = 0;
+ outbuf[1] = s->removable ? 0x80 : 0;
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
}
memcpy(&outbuf[8], "QEMU ", 8);
@@ -1295,6 +1297,7 @@ static SCSIDeviceInfo scsi_disk_info = {
DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),
DEFINE_PROP_STRING("ver", SCSIDiskState, version),
DEFINE_PROP_STRING("serial", SCSIDiskState, serial),
+ DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
DEFINE_PROP_END_OF_LIST(),
},
};
diff --git a/hw/scsi.h b/hw/scsi.h
index bf02adfbe2..d3b5d56cd6 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,9 +3,10 @@
#include "qdev.h"
#include "block.h"
-#include "blockdev.h"
#include "block_int.h"
+#define MAX_SCSI_DEVS 255
+
#define SCSI_CMD_BUF_SIZE 16
/* scsi-disk.c */
@@ -94,7 +95,8 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
}
-SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit);
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
+ int unit, bool removable);
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
diff --git a/hw/sd.c b/hw/sd.c
index 601545b2d9..789ca84785 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -422,9 +422,14 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
sd->pwd_len = 0;
}
-static void sd_cardchange(void *opaque)
+static void sd_cardchange(void *opaque, int reason)
{
SDState *sd = opaque;
+
+ if (!(reason & CHANGE_MEDIA)) {
+ return;
+ }
+
qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
if (bdrv_is_inserted(sd->bdrv)) {
sd_reset(sd, sd->bdrv);
diff --git a/hw/sh7750.c b/hw/sh7750.c
index 36b702f628..19d5bf8537 100644
--- a/hw/sh7750.c
+++ b/hw/sh7750.c
@@ -625,6 +625,7 @@ static uint32_t invalid_read(void *opaque, target_phys_addr_t addr)
static uint32_t sh7750_mmct_readl(void *opaque, target_phys_addr_t addr)
{
+ SH7750State *s = opaque;
uint32_t ret = 0;
switch (MM_REGION_TYPE(addr)) {
@@ -633,19 +634,21 @@ static uint32_t sh7750_mmct_readl(void *opaque, target_phys_addr_t addr)
/* do nothing */
break;
case MM_ITLB_ADDR:
+ ret = cpu_sh4_read_mmaped_itlb_addr(s->cpu, addr);
+ break;
case MM_ITLB_DATA:
- /* XXXXX */
- abort();
- break;
+ ret = cpu_sh4_read_mmaped_itlb_data(s->cpu, addr);
+ break;
case MM_OCACHE_ADDR:
case MM_OCACHE_DATA:
/* do nothing */
break;
case MM_UTLB_ADDR:
+ ret = cpu_sh4_read_mmaped_utlb_addr(s->cpu, addr);
+ break;
case MM_UTLB_DATA:
- /* XXXXX */
- abort();
- break;
+ ret = cpu_sh4_read_mmaped_utlb_data(s->cpu, addr);
+ break;
default:
abort();
}
@@ -673,7 +676,7 @@ static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr,
cpu_sh4_write_mmaped_itlb_addr(s->cpu, addr, mem_value);
break;
case MM_ITLB_DATA:
- /* XXXXX */
+ cpu_sh4_write_mmaped_itlb_data(s->cpu, addr, mem_value);
abort();
break;
case MM_OCACHE_ADDR:
@@ -684,8 +687,7 @@ static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr,
cpu_sh4_write_mmaped_utlb_addr(s->cpu, addr, mem_value);
break;
case MM_UTLB_DATA:
- /* XXXXX */
- abort();
+ cpu_sh4_write_mmaped_utlb_data(s->cpu, addr, mem_value);
break;
default:
abort();
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/sharpsl.h b/hw/sharpsl.h
index c5ccf791f6..0b3a774f2f 100644
--- a/hw/sharpsl.h
+++ b/hw/sharpsl.h
@@ -10,13 +10,6 @@
fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
/* zaurus.c */
-typedef struct ScoopInfo ScoopInfo;
-ScoopInfo *scoop_init(PXA2xxState *cpu,
- int instance, target_phys_addr_t target_base);
-void scoop_gpio_set(void *opaque, int line, int level);
-qemu_irq *scoop_gpio_in_get(ScoopInfo *s);
-void scoop_gpio_out_set(ScoopInfo *s, int line,
- qemu_irq handler);
#define SL_PXA_PARAM_BASE 0xa0000a00
void sl_bootparam_write(target_phys_addr_t ptr);
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/spitz.c b/hw/spitz.c
index 092bb64eac..5b1e42dff3 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -23,6 +23,7 @@
#include "audio/audio.h"
#include "boards.h"
#include "blockdev.h"
+#include "sysbus.h"
#undef REG_FMT
#define REG_FMT "0x%02lx"
@@ -46,8 +47,11 @@
#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)
typedef struct {
+ SysBusDevice busdev;
NANDFlashState *nand;
uint8_t ctl;
+ uint8_t manf_id;
+ uint8_t chip_id;
ECCState ecc;
} SLNANDState;
@@ -130,56 +134,53 @@ static void sl_writeb(void *opaque, target_phys_addr_t addr,
}
}
-static void sl_save(QEMUFile *f, void *opaque)
-{
- SLNANDState *s = (SLNANDState *) opaque;
-
- qemu_put_8s(f, &s->ctl);
- ecc_put(f, &s->ecc);
-}
-
-static int sl_load(QEMUFile *f, void *opaque, int version_id)
-{
- SLNANDState *s = (SLNANDState *) opaque;
-
- qemu_get_8s(f, &s->ctl);
- ecc_get(f, &s->ecc);
-
- return 0;
-}
-
enum {
FLASH_128M,
FLASH_1024M,
};
+static CPUReadMemoryFunc * const sl_readfn[] = {
+ sl_readb,
+ sl_readb,
+ sl_readl,
+};
+static CPUWriteMemoryFunc * const sl_writefn[] = {
+ sl_writeb,
+ sl_writeb,
+ sl_writeb,
+};
+
static void sl_flash_register(PXA2xxState *cpu, int size)
{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "sl-nand");
+
+ qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG);
+ if (size == FLASH_128M)
+ qdev_prop_set_uint8(dev, "chip_id", 0x73);
+ else if (size == FLASH_1024M)
+ qdev_prop_set_uint8(dev, "chip_id", 0xf1);
+
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, FLASH_BASE);
+}
+
+static int sl_nand_init(SysBusDevice *dev) {
int iomemtype;
SLNANDState *s;
- CPUReadMemoryFunc * const sl_readfn[] = {
- sl_readb,
- sl_readb,
- sl_readl,
- };
- CPUWriteMemoryFunc * const sl_writefn[] = {
- sl_writeb,
- sl_writeb,
- sl_writeb,
- };
-
- s = (SLNANDState *) qemu_mallocz(sizeof(SLNANDState));
+
+ s = FROM_SYSBUS(SLNANDState, dev);
+
s->ctl = 0;
- if (size == FLASH_128M)
- s->nand = nand_init(NAND_MFR_SAMSUNG, 0x73);
- else if (size == FLASH_1024M)
- s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1);
+ s->nand = nand_init(s->manf_id, s->chip_id);
iomemtype = cpu_register_io_memory(sl_readfn,
sl_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(FLASH_BASE, 0x40, iomemtype);
- register_savevm(NULL, "sl_flash", 0, 0, sl_save, sl_load, s);
+ sysbus_init_mmio(dev, 0x40, iomemtype);
+
+ return 0;
}
/* Spitz Keyboard */
@@ -218,11 +219,10 @@ static const int spitz_gpiomap[5] = {
SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
};
-static int spitz_gpio_invert[5] = { 0, 0, 0, 0, 0, };
typedef struct {
+ SysBusDevice busdev;
qemu_irq sense[SPITZ_KEY_SENSE_NUM];
- qemu_irq *strobe;
qemu_irq gpiomap[5];
int keymap[0x80];
uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
@@ -273,8 +273,7 @@ static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
/* Handle the additional keys */
if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
- qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80) ^
- spitz_gpio_invert[spitz_keycode & 0xf]);
+ qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80));
return;
}
@@ -292,8 +291,9 @@ static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
-static void spitz_keyboard_handler(SpitzKeyboardState *s, int keycode)
+static void spitz_keyboard_handler(void *opaque, int keycode)
{
+ SpitzKeyboardState *s = opaque;
uint16_t code;
int mapcode;
switch (keycode) {
@@ -439,34 +439,15 @@ static void spitz_keyboard_pre_map(SpitzKeyboardState *s)
s->imodifiers = 0;
s->fifopos = 0;
s->fifolen = 0;
- s->kbdtimer = qemu_new_timer(vm_clock, spitz_keyboard_tick, s);
- spitz_keyboard_tick(s);
}
#undef SHIFT
#undef CTRL
#undef FN
-static void spitz_keyboard_save(QEMUFile *f, void *opaque)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
- int i;
-
- qemu_put_be16s(f, &s->sense_state);
- qemu_put_be16s(f, &s->strobe_state);
- for (i = 0; i < 5; i ++)
- qemu_put_byte(f, spitz_gpio_invert[i]);
-}
-
-static int spitz_keyboard_load(QEMUFile *f, void *opaque, int version_id)
+static int spitz_keyboard_post_load(void *opaque, int version_id)
{
SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
- int i;
-
- qemu_get_be16s(f, &s->sense_state);
- qemu_get_be16s(f, &s->strobe_state);
- for (i = 0; i < 5; i ++)
- spitz_gpio_invert[i] = qemu_get_byte(f);
/* Release all pressed keys */
memset(s->keyrow, 0, sizeof(s->keyrow));
@@ -481,12 +462,40 @@ static int spitz_keyboard_load(QEMUFile *f, void *opaque, int version_id)
static void spitz_keyboard_register(PXA2xxState *cpu)
{
- int i, j;
+ int i;
+ DeviceState *dev;
SpitzKeyboardState *s;
- s = (SpitzKeyboardState *)
- qemu_mallocz(sizeof(SpitzKeyboardState));
- memset(s, 0, sizeof(SpitzKeyboardState));
+ dev = sysbus_create_simple("spitz-keyboard", -1, NULL);
+ s = FROM_SYSBUS(SpitzKeyboardState, sysbus_from_qdev(dev));
+
+ for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
+ qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i]));
+
+ for (i = 0; i < 5; i ++)
+ s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]);
+
+ if (!graphic_rotate)
+ s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]);
+
+ for (i = 0; i < 5; i++)
+ qemu_set_irq(s->gpiomap[i], 0);
+
+ for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
+ qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
+ qdev_get_gpio_in(dev, i));
+
+ qemu_mod_timer(s->kbdtimer, qemu_get_clock(vm_clock));
+
+ qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
+}
+
+static int spitz_keyboard_init(SysBusDevice *dev)
+{
+ SpitzKeyboardState *s;
+ int i, j;
+
+ s = FROM_SYSBUS(SpitzKeyboardState, dev);
for (i = 0; i < 0x80; i ++)
s->keymap[i] = -1;
@@ -495,22 +504,13 @@ static void spitz_keyboard_register(PXA2xxState *cpu)
if (spitz_keymap[i][j] != -1)
s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
- s->sense[i] = pxa2xx_gpio_in_get(cpu->gpio)[spitz_gpio_key_sense[i]];
-
- for (i = 0; i < 5; i ++)
- s->gpiomap[i] = pxa2xx_gpio_in_get(cpu->gpio)[spitz_gpiomap[i]];
-
- s->strobe = qemu_allocate_irqs(spitz_keyboard_strobe, s,
- SPITZ_KEY_STROBE_NUM);
- for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
- pxa2xx_gpio_out_set(cpu->gpio, spitz_gpio_key_strobe[i], s->strobe[i]);
-
spitz_keyboard_pre_map(s);
- qemu_add_kbd_event_handler((QEMUPutKBDEvent *) spitz_keyboard_handler, s);
- register_savevm(NULL, "spitz_keyboard", 0, 0,
- spitz_keyboard_save, spitz_keyboard_load, s);
+ s->kbdtimer = qemu_new_timer(vm_clock, spitz_keyboard_tick, s);
+ qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
+ qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM);
+
+ return 0;
}
/* LCD backlight controller */
@@ -526,8 +526,8 @@ static void spitz_keyboard_register(PXA2xxState *cpu)
typedef struct {
SSISlave ssidev;
- int bl_intensity;
- int bl_power;
+ uint32_t bl_intensity;
+ uint32_t bl_power;
} SpitzLCDTG;
static void spitz_bl_update(SpitzLCDTG *s)
@@ -591,21 +591,6 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
return 0;
}
-static void spitz_lcdtg_save(QEMUFile *f, void *opaque)
-{
- SpitzLCDTG *s = (SpitzLCDTG *)opaque;
- qemu_put_be32(f, s->bl_intensity);
- qemu_put_be32(f, s->bl_power);
-}
-
-static int spitz_lcdtg_load(QEMUFile *f, void *opaque, int version_id)
-{
- SpitzLCDTG *s = (SpitzLCDTG *)opaque;
- s->bl_intensity = qemu_get_be32(f);
- s->bl_power = qemu_get_be32(f);
- return 0;
-}
-
static int spitz_lcdtg_init(SSISlave *dev)
{
SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
@@ -614,8 +599,6 @@ static int spitz_lcdtg_init(SSISlave *dev)
s->bl_power = 0;
s->bl_intensity = 0x20;
- register_savevm(&dev->qdev, "spitz-lcdtg", -1, 1,
- spitz_lcdtg_save, spitz_lcdtg_load, s);
return 0;
}
@@ -634,7 +617,7 @@ static DeviceState *max1111;
typedef struct {
SSISlave ssidev;
SSIBus *bus[3];
- int enable[3];
+ uint32_t enable[3];
} CorgiSSPState;
static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value)
@@ -676,30 +659,6 @@ static void spitz_adc_temp_on(void *opaque, int line, int level)
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
}
-static void spitz_ssp_save(QEMUFile *f, void *opaque)
-{
- CorgiSSPState *s = (CorgiSSPState *)opaque;
- int i;
-
- for (i = 0; i < 3; i++) {
- qemu_put_be32(f, s->enable[i]);
- }
-}
-
-static int spitz_ssp_load(QEMUFile *f, void *opaque, int version_id)
-{
- CorgiSSPState *s = (CorgiSSPState *)opaque;
- int i;
-
- if (version_id != 1) {
- return -EINVAL;
- }
- for (i = 0; i < 3; i++) {
- s->enable[i] = qemu_get_be32(f);
- }
- return 0;
-}
-
static int corgi_ssp_init(SSISlave *dev)
{
CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
@@ -709,8 +668,6 @@ static int corgi_ssp_init(SSISlave *dev)
s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2");
- register_savevm(&dev->qdev, "spitz_ssp", -1, 1,
- spitz_ssp_save, spitz_ssp_load, s);
return 0;
}
@@ -728,7 +685,7 @@ static void spitz_ssp_attach(PXA2xxState *cpu)
bus = qdev_get_child_bus(mux, "ssi1");
dev = ssi_create_slave(bus, "ads7846");
qdev_connect_gpio_out(dev, 0,
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_TP_INT]);
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT));
bus = qdev_get_child_bus(mux, "ssi2");
max1111 = ssi_create_slave(bus, "max1111");
@@ -736,11 +693,11 @@ static void spitz_ssp_attach(PXA2xxState *cpu)
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
qdev_get_gpio_in(mux, 0));
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
qdev_get_gpio_in(mux, 1));
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
qdev_get_gpio_in(mux, 2));
}
@@ -790,7 +747,7 @@ static void spitz_i2c_setup(PXA2xxState *cpu)
wm = i2c_create_slave(bus, "wm8750", 0);
spitz_wm8750_addr(wm, 0, 0);
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_WM,
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM,
qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]);
/* .. and to the sound interface. */
cpu->i2s->opaque = wm;
@@ -851,21 +808,21 @@ static void spitz_out_switch(void *opaque, int line, int level)
#define SPITZ_SCP2_MIC_BIAS 9
static void spitz_scoop_gpio_setup(PXA2xxState *cpu,
- ScoopInfo *scp0, ScoopInfo *scp1)
+ DeviceState *scp0, DeviceState *scp1)
{
qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8);
- scoop_gpio_out_set(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
- scoop_gpio_out_set(scp0, SPITZ_SCP_JK_B, outsignals[1]);
- scoop_gpio_out_set(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
- scoop_gpio_out_set(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
if (scp1) {
- scoop_gpio_out_set(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
- scoop_gpio_out_set(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
+ qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
+ qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
}
- scoop_gpio_out_set(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
}
#define SPITZ_GPIO_HSYNC 22
@@ -883,7 +840,7 @@ static int spitz_hsync;
static void spitz_lcd_hsync_handler(void *opaque, int line, int level)
{
PXA2xxState *cpu = (PXA2xxState *) opaque;
- qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_HSYNC], spitz_hsync);
+ qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync);
spitz_hsync ^= 1;
}
@@ -903,36 +860,24 @@ static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
/* MMC/SD host */
pxa2xx_mmci_handlers(cpu->mmc,
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_WP],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_DETECT]);
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP),
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT));
/* Battery lock always closed */
- qemu_irq_raise(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_BAT_COVER]);
+ qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER));
/* Handle reset */
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset);
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset);
/* PCMCIA signals: card's IRQ and Card-Detect */
if (slots >= 1)
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF1_IRQ],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF1_CD]);
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ),
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD));
if (slots >= 2)
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF2_IRQ],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF2_CD]);
-
- /* Initialise the screen rotation related signals */
- spitz_gpio_invert[3] = 0; /* Always open */
- if (graphic_rotate) { /* Tablet mode */
- spitz_gpio_invert[4] = 0;
- } else { /* Portrait mode */
- spitz_gpio_invert[4] = 1;
- }
- qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SWA],
- spitz_gpio_invert[3]);
- qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SWB],
- spitz_gpio_invert[4]);
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ),
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD));
}
/* Board init. */
@@ -952,7 +897,7 @@ static void spitz_common_init(ram_addr_t ram_size,
const char *cpu_model, enum spitz_model_e model, int arm_id)
{
PXA2xxState *cpu;
- ScoopInfo *scp0, *scp1 = NULL;
+ DeviceState *scp0, *scp1 = NULL;
if (!cpu_model)
cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
@@ -970,9 +915,9 @@ static void spitz_common_init(ram_addr_t ram_size,
spitz_ssp_attach(cpu);
- scp0 = scoop_init(cpu, 0, 0x10800000);
+ scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
if (model != akita) {
- scp1 = scoop_init(cpu, 1, 0x08800040);
+ scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
}
spitz_scoop_gpio_setup(cpu, scp0, scp1);
@@ -1069,16 +1014,94 @@ static void spitz_machine_init(void)
machine_init(spitz_machine_init);
+static bool is_version_0(void *opaque, int version_id)
+{
+ return version_id == 0;
+}
+
+static VMStateDescription vmstate_sl_nand_info = {
+ .name = "sl-nand",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(ctl, SLNANDState),
+ VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static SysBusDeviceInfo sl_nand_info = {
+ .init = sl_nand_init,
+ .qdev.name = "sl-nand",
+ .qdev.size = sizeof(SLNANDState),
+ .qdev.vmsd = &vmstate_sl_nand_info,
+ .qdev.props = (Property []) {
+ DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
+ DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static VMStateDescription vmstate_spitz_kbd = {
+ .name = "spitz-keyboard",
+ .version_id = 1,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .post_load = spitz_keyboard_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT16(sense_state, SpitzKeyboardState),
+ VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
+ VMSTATE_UNUSED_TEST(is_version_0, 5),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static SysBusDeviceInfo spitz_keyboard_info = {
+ .init = spitz_keyboard_init,
+ .qdev.name = "spitz-keyboard",
+ .qdev.size = sizeof(SpitzKeyboardState),
+ .qdev.vmsd = &vmstate_spitz_kbd,
+ .qdev.props = (Property []) {
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static const VMStateDescription vmstate_corgi_ssp_regs = {
+ .name = "corgi-ssp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
static SSISlaveInfo corgi_ssp_info = {
.qdev.name = "corgi-ssp",
.qdev.size = sizeof(CorgiSSPState),
+ .qdev.vmsd = &vmstate_corgi_ssp_regs,
.init = corgi_ssp_init,
.transfer = corgi_ssp_transfer
};
+static const VMStateDescription vmstate_spitz_lcdtg_regs = {
+ .name = "spitz-lcdtg",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
+ VMSTATE_UINT32(bl_power, SpitzLCDTG),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
static SSISlaveInfo spitz_lcdtg_info = {
.qdev.name = "spitz-lcdtg",
.qdev.size = sizeof(SpitzLCDTG),
+ .qdev.vmsd = &vmstate_spitz_lcdtg_regs,
.init = spitz_lcdtg_init,
.transfer = spitz_lcdtg_transfer
};
@@ -1087,6 +1110,8 @@ static void spitz_register_devices(void)
{
ssi_register_slave(&corgi_ssp_info);
ssi_register_slave(&spitz_lcdtg_info);
+ sysbus_register_withprop(&spitz_keyboard_info);
+ sysbus_register_withprop(&sl_nand_info);
}
device_init(spitz_register_devices)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index a1a63b23e2..fb4b649279 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -7,6 +7,7 @@
* This code is licenced under the GNU GPL v2.
*/
+#include "blockdev.h"
#include "ssi.h"
#include "sd.h"
@@ -231,11 +232,11 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
static int ssi_sd_init(SSISlave *dev)
{
ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
- BlockDriverState *bs;
+ DriveInfo *dinfo;
s->mode = SSI_SD_CMD;
- bs = qdev_init_bdrv(&dev->qdev, IF_SD);
- s->sd = sd_init(bs, 1);
+ dinfo = drive_get_next(IF_SD);
+ s->sd = sd_init(dinfo ? dinfo->bdrv : NULL, 1);
register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
return 0;
}
diff --git a/hw/tosa.c b/hw/tosa.c
index cc8ce6d641..0bfab1634a 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -20,6 +20,7 @@
#include "i2c.h"
#include "ssi.h"
#include "blockdev.h"
+#include "sysbus.h"
#define TOSA_RAM 0x04000000
#define TOSA_ROM 0x00800000
@@ -86,34 +87,34 @@ static void tosa_out_switch(void *opaque, int line, int level)
static void tosa_gpio_setup(PXA2xxState *cpu,
- ScoopInfo *scp0,
- ScoopInfo *scp1,
+ DeviceState *scp0,
+ DeviceState *scp1,
TC6393xbState *tmio)
{
qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4);
/* MMC/SD host */
pxa2xx_mmci_handlers(cpu->mmc,
- scoop_gpio_in_get(scp0)[TOSA_GPIO_SD_WP],
- qemu_irq_invert(pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_nSD_DETECT]));
+ qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
+ qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
/* Handle reset */
- pxa2xx_gpio_out_set(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset);
+ qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset);
/* PCMCIA signals: card's IRQ and Card-Detect */
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_CF_IRQ],
- pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_CF_CD]);
+ qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
+ qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_JC_CF_IRQ],
+ qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
NULL);
- scoop_gpio_out_set(scp1, TOSA_GPIO_BT_LED, outsignals[0]);
- scoop_gpio_out_set(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]);
- scoop_gpio_out_set(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]);
- scoop_gpio_out_set(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]);
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]);
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]);
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
- scoop_gpio_out_set(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
}
static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
@@ -208,7 +209,7 @@ static void tosa_init(ram_addr_t ram_size,
{
PXA2xxState *cpu;
TC6393xbState *tmio;
- ScoopInfo *scp0, *scp1;
+ DeviceState *scp0, *scp1;
if (!cpu_model)
cpu_model = "pxa255";
@@ -219,10 +220,10 @@ static void tosa_init(ram_addr_t ram_size,
qemu_ram_alloc(NULL, "tosa.rom", TOSA_ROM) | IO_MEM_ROM);
tmio = tc6393xb_init(0x10000000,
- pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_TC6393XB_INT]);
+ qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_TC6393XB_INT));
- scp0 = scoop_init(cpu, 0, 0x08800000);
- scp1 = scoop_init(cpu, 1, 0x14800040);
+ scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
+ scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
tosa_gpio_setup(cpu, scp0, scp1, tmio);
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 56d1a6ce4a..22e6845049 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -20,6 +20,7 @@
#include "qemu-common.h"
#include "usb.h"
+#include "usb-desc.h"
#include "net.h"
#include "bt.h"
@@ -51,251 +52,202 @@ struct USBBtState {
#define USB_ACL_EP 2
#define USB_SCO_EP 3
-static const uint8_t qemu_bt_dev_descriptor[] = {
- 0x12, /* u8 bLength; */
- USB_DT_DEVICE, /* u8 bDescriptorType; Device */
- 0x10, 0x01, /* u16 bcdUSB; v1.10 */
+enum {
+ STR_MANUFACTURER = 1,
+ STR_SERIALNUMBER,
+};
- 0xe0, /* u8 bDeviceClass; Wireless */
- 0x01, /* u8 bDeviceSubClass; Radio Frequency */
- 0x01, /* u8 bDeviceProtocol; Bluetooth */
- 0x40, /* u8 bMaxPacketSize0; 64 Bytes */
+static const USBDescStrings desc_strings = {
+ [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+ [STR_SERIALNUMBER] = "1",
+};
- 0x12, 0x0a, /* u16 idVendor; */
- 0x01, 0x00, /* u16 idProduct; Bluetooth Dongle (HCI mode) */
- 0x58, 0x19, /* u16 bcdDevice; (some devices have 0x48, 0x02) */
+static const USBDescIface desc_iface_bluetooth[] = {
+ {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = 0xe0, /* Wireless */
+ .bInterfaceSubClass = 0x01, /* Radio Frequency */
+ .bInterfaceProtocol = 0x01, /* Bluetooth */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | USB_EVT_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x10,
+ .bInterval = 0x02,
+ },
+ {
+ .bEndpointAddress = USB_DIR_OUT | USB_ACL_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 0x40,
+ .bInterval = 0x0a,
+ },
+ {
+ .bEndpointAddress = USB_DIR_IN | USB_ACL_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 0x40,
+ .bInterval = 0x0a,
+ },
+ },
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xe0, /* Wireless */
+ .bInterfaceSubClass = 0x01, /* Radio Frequency */
+ .bInterfaceProtocol = 0x01, /* Bluetooth */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0,
+ .bInterval = 0x01,
+ },
+ {
+ .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0,
+ .bInterval = 0x01,
+ },
+ },
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xe0, /* Wireless */
+ .bInterfaceSubClass = 0x01, /* Radio Frequency */
+ .bInterfaceProtocol = 0x01, /* Bluetooth */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x09,
+ .bInterval = 0x01,
+ },
+ {
+ .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x09,
+ .bInterval = 0x01,
+ },
+ },
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 2,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xe0, /* Wireless */
+ .bInterfaceSubClass = 0x01, /* Radio Frequency */
+ .bInterfaceProtocol = 0x01, /* Bluetooth */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x11,
+ .bInterval = 0x01,
+ },
+ {
+ .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x11,
+ .bInterval = 0x01,
+ },
+ },
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 3,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xe0, /* Wireless */
+ .bInterfaceSubClass = 0x01, /* Radio Frequency */
+ .bInterfaceProtocol = 0x01, /* Bluetooth */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x19,
+ .bInterval = 0x01,
+ },
+ {
+ .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x19,
+ .bInterval = 0x01,
+ },
+ },
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 4,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xe0, /* Wireless */
+ .bInterfaceSubClass = 0x01, /* Radio Frequency */
+ .bInterfaceProtocol = 0x01, /* Bluetooth */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x21,
+ .bInterval = 0x01,
+ },
+ {
+ .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x21,
+ .bInterval = 0x01,
+ },
+ },
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 5,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xe0, /* Wireless */
+ .bInterfaceSubClass = 0x01, /* Radio Frequency */
+ .bInterfaceProtocol = 0x01, /* Bluetooth */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x31,
+ .bInterval = 0x01,
+ },
+ {
+ .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 0x31,
+ .bInterval = 0x01,
+ },
+ },
+ }
+};
- 0x00, /* u8 iManufacturer; */
- 0x00, /* u8 iProduct; */
- 0x00, /* u8 iSerialNumber; */
- 0x01, /* u8 bNumConfigurations; */
+static const USBDescDevice desc_device_bluetooth = {
+ .bcdUSB = 0x0110,
+ .bDeviceClass = 0xe0, /* Wireless */
+ .bDeviceSubClass = 0x01, /* Radio Frequency */
+ .bDeviceProtocol = 0x01, /* Bluetooth */
+ .bMaxPacketSize0 = 64,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 2,
+ .bConfigurationValue = 1,
+ .bmAttributes = 0xc0,
+ .bMaxPower = 0,
+ .nif = ARRAY_SIZE(desc_iface_bluetooth),
+ .ifs = desc_iface_bluetooth,
+ },
+ },
};
-static const uint8_t qemu_bt_config_descriptor[] = {
- /* one configuration */
- 0x09, /* u8 bLength; */
- USB_DT_CONFIG, /* u8 bDescriptorType; */
- 0xb1, 0x00, /* u16 wTotalLength; */
- 0x02, /* u8 bNumInterfaces; (2) */
- 0x01, /* u8 bConfigurationValue; */
- 0x00, /* u8 iConfiguration; */
- 0xc0, /* u8 bmAttributes;
- Bit 7: must be set,
- 6: Self-powered,
- 5: Remote wakeup,
- 4..0: resvd */
- 0x00, /* u8 MaxPower; */
-
- /* USB 1.1:
- * USB 2.0, single TT organization (mandatory):
- * one interface, protocol 0
- *
- * USB 2.0, multiple TT organization (optional):
- * two interfaces, protocols 1 (like single TT)
- * and 2 (multiple TT mode) ... config is
- * sometimes settable
- * NOT IMPLEMENTED
- */
-
- /* interface one */
- 0x09, /* u8 if_bLength; */
- USB_DT_INTERFACE, /* u8 if_bDescriptorType; */
- 0x00, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x03, /* u8 if_bNumEndpoints; */
- 0xe0, /* u8 if_bInterfaceClass; Wireless */
- 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */
- 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */
- 0x00, /* u8 if_iInterface; */
-
- /* endpoint one */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_IN | USB_EVT_EP, /* u8 ep_bEndpointAddress; */
- 0x03, /* u8 ep_bmAttributes; Interrupt */
- 0x10, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x02, /* u8 ep_bInterval; */
-
- /* endpoint two */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_OUT | USB_ACL_EP, /* u8 ep_bEndpointAddress; */
- 0x02, /* u8 ep_bmAttributes; Bulk */
- 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* endpoint three */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_IN | USB_ACL_EP, /* u8 ep_bEndpointAddress; */
- 0x02, /* u8 ep_bmAttributes; Bulk */
- 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* interface two setting one */
- 0x09, /* u8 if_bLength; */
- USB_DT_INTERFACE, /* u8 if_bDescriptorType; */
- 0x01, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x02, /* u8 if_bNumEndpoints; */
- 0xe0, /* u8 if_bInterfaceClass; Wireless */
- 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */
- 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */
- 0x00, /* u8 if_iInterface; */
-
- /* endpoint one */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x00, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* endpoint two */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x00, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* interface two setting two */
- 0x09, /* u8 if_bLength; */
- USB_DT_INTERFACE, /* u8 if_bDescriptorType; */
- 0x01, /* u8 if_bInterfaceNumber; */
- 0x01, /* u8 if_bAlternateSetting; */
- 0x02, /* u8 if_bNumEndpoints; */
- 0xe0, /* u8 if_bInterfaceClass; Wireless */
- 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */
- 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */
- 0x00, /* u8 if_iInterface; */
-
- /* endpoint one */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x09, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* endpoint two */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x09, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* interface two setting three */
- 0x09, /* u8 if_bLength; */
- USB_DT_INTERFACE, /* u8 if_bDescriptorType; */
- 0x01, /* u8 if_bInterfaceNumber; */
- 0x02, /* u8 if_bAlternateSetting; */
- 0x02, /* u8 if_bNumEndpoints; */
- 0xe0, /* u8 if_bInterfaceClass; Wireless */
- 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */
- 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */
- 0x00, /* u8 if_iInterface; */
-
- /* endpoint one */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x11, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* endpoint two */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x11, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* interface two setting four */
- 0x09, /* u8 if_bLength; */
- USB_DT_INTERFACE, /* u8 if_bDescriptorType; */
- 0x01, /* u8 if_bInterfaceNumber; */
- 0x03, /* u8 if_bAlternateSetting; */
- 0x02, /* u8 if_bNumEndpoints; */
- 0xe0, /* u8 if_bInterfaceClass; Wireless */
- 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */
- 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */
- 0x00, /* u8 if_iInterface; */
-
- /* endpoint one */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x19, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* endpoint two */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x19, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* interface two setting five */
- 0x09, /* u8 if_bLength; */
- USB_DT_INTERFACE, /* u8 if_bDescriptorType; */
- 0x01, /* u8 if_bInterfaceNumber; */
- 0x04, /* u8 if_bAlternateSetting; */
- 0x02, /* u8 if_bNumEndpoints; */
- 0xe0, /* u8 if_bInterfaceClass; Wireless */
- 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */
- 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */
- 0x00, /* u8 if_iInterface; */
-
- /* endpoint one */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x21, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* endpoint two */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x21, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* interface two setting six */
- 0x09, /* u8 if_bLength; */
- USB_DT_INTERFACE, /* u8 if_bDescriptorType; */
- 0x01, /* u8 if_bInterfaceNumber; */
- 0x05, /* u8 if_bAlternateSetting; */
- 0x02, /* u8 if_bNumEndpoints; */
- 0xe0, /* u8 if_bInterfaceClass; Wireless */
- 0x01, /* u8 if_bInterfaceSubClass; Radio Frequency */
- 0x01, /* u8 if_bInterfaceProtocol; Bluetooth */
- 0x00, /* u8 if_iInterface; */
-
- /* endpoint one */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_OUT | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x31, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* endpoint two */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; */
- USB_DIR_IN | USB_SCO_EP, /* u8 ep_bEndpointAddress; */
- 0x01, /* u8 ep_bmAttributes; Isochronous */
- 0x31, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x01, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-
- /* If implemented, the DFU interface descriptor goes here with no
- * endpoints or alternative settings. */
+static const USBDesc desc_bluetooth = {
+ .id = {
+ .idVendor = 0x0a12,
+ .idProduct = 0x0001,
+ .bcdDevice = 0x1958,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = 0,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_bluetooth,
+ .str = desc_strings,
};
static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo)
@@ -424,85 +376,38 @@ static int usb_bt_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
struct USBBtState *s = (struct USBBtState *) dev->opaque;
- int ret = 0;
+ int ret;
+ ret = usb_desc_handle_control(dev, request, value, index, length, data);
+ if (ret >= 0) {
+ switch (request) {
+ case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+ s->config = 0;
+ break;
+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+ s->config = 1;
+ usb_bt_fifo_reset(&s->evt);
+ usb_bt_fifo_reset(&s->acl);
+ usb_bt_fifo_reset(&s->sco);
+ break;
+ }
+ return ret;
+ }
+
+ ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_STATUS:
case InterfaceRequest | USB_REQ_GET_STATUS:
case EndpointRequest | USB_REQ_GET_STATUS:
- data[0] = (1 << USB_DEVICE_SELF_POWERED) |
- (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
+ data[0] = 0x00;
data[1] = 0x00;
ret = 2;
break;
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE:
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
+ goto fail;
case InterfaceOutRequest | USB_REQ_SET_FEATURE:
case EndpointOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- ret = 0;
- break;
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- switch (value >> 8) {
- case USB_DT_DEVICE:
- ret = sizeof(qemu_bt_dev_descriptor);
- memcpy(data, qemu_bt_dev_descriptor, ret);
- break;
- case USB_DT_CONFIG:
- ret = sizeof(qemu_bt_config_descriptor);
- memcpy(data, qemu_bt_config_descriptor, ret);
- break;
- case USB_DT_STRING:
- switch(value & 0xff) {
- case 0:
- /* language ids */
- data[0] = 4;
- data[1] = 3;
- data[2] = 0x09;
- data[3] = 0x04;
- ret = 4;
- break;
- default:
- goto fail;
- }
- break;
- default:
- goto fail;
- }
- break;
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- data[0] = qemu_bt_config_descriptor[0x5];
- ret = 1;
- s->config = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- ret = 0;
- if (value != qemu_bt_config_descriptor[0x5] && value != 0) {
- printf("%s: Wrong SET_CONFIGURATION request (%i)\n",
- __FUNCTION__, value);
- goto fail;
- }
- s->config = 1;
- usb_bt_fifo_reset(&s->evt);
- usb_bt_fifo_reset(&s->acl);
- usb_bt_fifo_reset(&s->sco);
+ goto fail;
break;
case InterfaceRequest | USB_REQ_GET_INTERFACE:
if (value != 0 || (index & ~1) || length != 1)
@@ -618,8 +523,7 @@ static void usb_bt_handle_destroy(USBDevice *dev)
static int usb_bt_initfn(USBDevice *dev)
{
- struct USBBtState *s = DO_UPCAST(struct USBBtState, dev, dev);
- s->dev.speed = USB_SPEED_HIGH;
+ usb_desc_init(dev);
return 0;
}
@@ -648,6 +552,7 @@ static struct USBDeviceInfo bt_info = {
.product_desc = "QEMU BT dongle",
.qdev.name = "usb-bt-dongle",
.qdev.size = sizeof(struct USBBtState),
+ .usb_desc = &desc_bluetooth,
.init = usb_bt_initfn,
.handle_packet = usb_generic_handle_packet,
.handle_reset = usb_bt_handle_reset,
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 8b4583c1e6..6e2e5fd17a 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -5,13 +5,20 @@
#include "monitor.h"
static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
-static char *usbbus_get_fw_dev_path(DeviceState *dev);
+
+static char *usb_get_dev_path(DeviceState *dev);
+static char *usb_get_fw_dev_path(DeviceState *qdev);
static struct BusInfo usb_bus_info = {
.name = "USB",
.size = sizeof(USBBus),
.print_dev = usb_bus_dev_print,
- .get_fw_dev_path = usbbus_get_fw_dev_path,
+ .get_dev_path = usb_get_dev_path,
+ .get_fw_dev_path = usb_get_fw_dev_path,
+ .props = (Property[]) {
+ DEFINE_PROP_STRING("port", USBDevice, port_path),
+ DEFINE_PROP_END_OF_LIST()
+ },
};
static int next_usb_bus = 0;
static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
@@ -48,6 +55,7 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
dev->info = info;
dev->auto_attach = 1;
+ QLIST_INIT(&dev->strings);
rc = dev->info->init(dev);
if (rc == 0 && dev->auto_attach)
usb_device_attach(dev);
@@ -112,16 +120,28 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name)
}
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
- USBDevice *pdev, usb_attachfn attach)
+ USBPortOps *ops, int speedmask)
{
port->opaque = opaque;
port->index = index;
- port->attach = attach;
- port->pdev = pdev;
+ port->opaque = opaque;
+ port->index = index;
+ port->ops = ops;
+ port->speedmask = speedmask;
QTAILQ_INSERT_TAIL(&bus->free, port, next);
bus->nfree++;
}
+void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
+{
+ if (upstream) {
+ snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
+ upstream->path, portnr);
+ } else {
+ snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
+ }
+}
+
void usb_unregister_port(USBBus *bus, USBPort *port)
{
if (port->dev)
@@ -140,9 +160,22 @@ static void do_attach(USBDevice *dev)
dev->product_desc);
return;
}
- dev->attached++;
+ if (dev->port_path) {
+ QTAILQ_FOREACH(port, &bus->free, next) {
+ if (strcmp(port->path, dev->port_path) == 0) {
+ break;
+ }
+ }
+ if (port == NULL) {
+ fprintf(stderr, "Warning: usb port %s (bus %s) not found\n",
+ dev->port_path, bus->qbus.name);
+ return;
+ }
+ } else {
+ port = QTAILQ_FIRST(&bus->free);
+ }
- port = QTAILQ_FIRST(&bus->free);
+ dev->attached++;
QTAILQ_REMOVE(&bus->free, port, next);
bus->nfree--;
@@ -156,8 +189,9 @@ int usb_device_attach(USBDevice *dev)
{
USBBus *bus = usb_bus_from_device(dev);
- if (bus->nfree == 1) {
- /* Create a new hub and chain it on. */
+ if (bus->nfree == 1 && dev->port_path == NULL) {
+ /* Create a new hub and chain it on
+ (unless a physical port location is specified). */
usb_create_simple(bus, "usb-hub");
}
do_attach(dev);
@@ -231,12 +265,43 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
USBBus *bus = usb_bus_from_device(dev);
- monitor_printf(mon, "%*saddr %d.%d, speed %s, name %s%s\n",
+ monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
indent, "", bus->busnr, dev->addr,
+ dev->port ? dev->port->path : "-",
usb_speed(dev->speed), dev->product_desc,
dev->attached ? ", attached" : "");
}
+static char *usb_get_dev_path(DeviceState *qdev)
+{
+ USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ return qemu_strdup(dev->port->path);
+}
+
+static char *usb_get_fw_dev_path(DeviceState *qdev)
+{
+ USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ char *fw_path, *in;
+ int pos = 0;
+ long nr;
+
+ fw_path = qemu_malloc(32 + strlen(dev->port->path) * 6);
+ in = dev->port->path;
+ while (true) {
+ nr = strtol(in, &in, 10);
+ if (in[0] == '.') {
+ /* some hub between root port and device */
+ pos += sprintf(fw_path + pos, "hub@%ld/", nr);
+ in++;
+ } else {
+ /* the device itself */
+ pos += sprintf(fw_path + pos, "%s@%ld", qdev_fw_name(qdev), nr);
+ break;
+ }
+ }
+ return fw_path;
+}
+
void usb_info(Monitor *mon)
{
USBBus *bus;
@@ -253,8 +318,8 @@ void usb_info(Monitor *mon)
dev = port->dev;
if (!dev)
continue;
- monitor_printf(mon, " Device %d.%d, Speed %s Mb/s, Product %s\n",
- bus->busnr, dev->addr, usb_speed(dev->speed),
+ monitor_printf(mon, " Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
+ bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
dev->product_desc);
}
}
@@ -309,43 +374,3 @@ USBDevice *usbdevice_create(const char *cmdline)
}
return usb->usbdevice_init(params);
}
-
-static int usbbus_get_fw_dev_path_helper(USBDevice *d, USBBus *bus, char *p,
- int len)
-{
- int l = 0;
- USBPort *port;
-
- QTAILQ_FOREACH(port, &bus->used, next) {
- if (port->dev == d) {
- if (port->pdev) {
- l = usbbus_get_fw_dev_path_helper(port->pdev, bus, p, len);
- }
- l += snprintf(p + l, len - l, "%s@%x/", qdev_fw_name(&d->qdev),
- port->index);
- break;
- }
- }
-
- return l;
-}
-
-static char *usbbus_get_fw_dev_path(DeviceState *dev)
-{
- USBDevice *d = (USBDevice*)dev;
- USBBus *bus = usb_bus_from_device(d);
- char path[100];
- int l;
-
- assert(d->attached != 0);
-
- l = usbbus_get_fw_dev_path_helper(d, bus, path, sizeof(path));
-
- if (l == 0) {
- abort();
- }
-
- path[l-1] = '\0';
-
- return strdup(path);
-}
diff --git a/hw/usb-desc.c b/hw/usb-desc.c
new file mode 100644
index 0000000000..62591f20aa
--- /dev/null
+++ b/hw/usb-desc.c
@@ -0,0 +1,406 @@
+#include "usb.h"
+#include "usb-desc.h"
+#include "trace.h"
+
+/* ------------------------------------------------------------------ */
+
+static uint8_t usb_lo(uint16_t val)
+{
+ return val & 0xff;
+}
+
+static uint8_t usb_hi(uint16_t val)
+{
+ return (val >> 8) & 0xff;
+}
+
+int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
+ uint8_t *dest, size_t len)
+{
+ uint8_t bLength = 0x12;
+
+ if (len < bLength) {
+ return -1;
+ }
+
+ dest[0x00] = bLength;
+ dest[0x01] = USB_DT_DEVICE;
+
+ dest[0x02] = usb_lo(dev->bcdUSB);
+ dest[0x03] = usb_hi(dev->bcdUSB);
+ dest[0x04] = dev->bDeviceClass;
+ dest[0x05] = dev->bDeviceSubClass;
+ dest[0x06] = dev->bDeviceProtocol;
+ dest[0x07] = dev->bMaxPacketSize0;
+
+ dest[0x08] = usb_lo(id->idVendor);
+ dest[0x09] = usb_hi(id->idVendor);
+ dest[0x0a] = usb_lo(id->idProduct);
+ dest[0x0b] = usb_hi(id->idProduct);
+ dest[0x0c] = usb_lo(id->bcdDevice);
+ dest[0x0d] = usb_hi(id->bcdDevice);
+ dest[0x0e] = id->iManufacturer;
+ dest[0x0f] = id->iProduct;
+ dest[0x10] = id->iSerialNumber;
+
+ dest[0x11] = dev->bNumConfigurations;
+
+ return bLength;
+}
+
+int usb_desc_device_qualifier(const USBDescDevice *dev,
+ uint8_t *dest, size_t len)
+{
+ uint8_t bLength = 0x0a;
+
+ if (len < bLength) {
+ return -1;
+ }
+
+ dest[0x00] = bLength;
+ dest[0x01] = USB_DT_DEVICE_QUALIFIER;
+
+ dest[0x02] = usb_lo(dev->bcdUSB);
+ dest[0x03] = usb_hi(dev->bcdUSB);
+ dest[0x04] = dev->bDeviceClass;
+ dest[0x05] = dev->bDeviceSubClass;
+ dest[0x06] = dev->bDeviceProtocol;
+ dest[0x07] = dev->bMaxPacketSize0;
+ dest[0x08] = dev->bNumConfigurations;
+ dest[0x09] = 0; /* reserved */
+
+ return bLength;
+}
+
+int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
+{
+ uint8_t bLength = 0x09;
+ uint16_t wTotalLength = 0;
+ int i, rc, count;
+
+ if (len < bLength) {
+ return -1;
+ }
+
+ dest[0x00] = bLength;
+ dest[0x01] = USB_DT_CONFIG;
+ dest[0x04] = conf->bNumInterfaces;
+ dest[0x05] = conf->bConfigurationValue;
+ dest[0x06] = conf->iConfiguration;
+ dest[0x07] = conf->bmAttributes;
+ dest[0x08] = conf->bMaxPower;
+ wTotalLength += bLength;
+
+ count = conf->nif ? conf->nif : conf->bNumInterfaces;
+ for (i = 0; i < count; i++) {
+ rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength);
+ if (rc < 0) {
+ return rc;
+ }
+ wTotalLength += rc;
+ }
+
+ dest[0x02] = usb_lo(wTotalLength);
+ dest[0x03] = usb_hi(wTotalLength);
+ return wTotalLength;
+}
+
+int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
+{
+ uint8_t bLength = 0x09;
+ int i, rc, pos = 0;
+
+ if (len < bLength) {
+ return -1;
+ }
+
+ dest[0x00] = bLength;
+ dest[0x01] = USB_DT_INTERFACE;
+ dest[0x02] = iface->bInterfaceNumber;
+ dest[0x03] = iface->bAlternateSetting;
+ dest[0x04] = iface->bNumEndpoints;
+ dest[0x05] = iface->bInterfaceClass;
+ dest[0x06] = iface->bInterfaceSubClass;
+ dest[0x07] = iface->bInterfaceProtocol;
+ dest[0x08] = iface->iInterface;
+ pos += bLength;
+
+ for (i = 0; i < iface->ndesc; i++) {
+ rc = usb_desc_other(iface->descs + i, dest + pos, len - pos);
+ if (rc < 0) {
+ return rc;
+ }
+ pos += rc;
+ }
+
+ for (i = 0; i < iface->bNumEndpoints; i++) {
+ rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos);
+ if (rc < 0) {
+ return rc;
+ }
+ pos += rc;
+ }
+
+ return pos;
+}
+
+int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
+{
+ uint8_t bLength = 0x07;
+
+ if (len < bLength) {
+ return -1;
+ }
+
+ dest[0x00] = bLength;
+ dest[0x01] = USB_DT_ENDPOINT;
+ dest[0x02] = ep->bEndpointAddress;
+ dest[0x03] = ep->bmAttributes;
+ dest[0x04] = usb_lo(ep->wMaxPacketSize);
+ dest[0x05] = usb_hi(ep->wMaxPacketSize);
+ dest[0x06] = ep->bInterval;
+
+ return bLength;
+}
+
+int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
+{
+ int bLength = desc->length ? desc->length : desc->data[0];
+
+ if (len < bLength) {
+ return -1;
+ }
+
+ memcpy(dest, desc->data, bLength);
+ return bLength;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void usb_desc_setdefaults(USBDevice *dev)
+{
+ const USBDesc *desc = dev->info->usb_desc;
+
+ assert(desc != NULL);
+ switch (dev->speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ dev->device = desc->full;
+ break;
+ case USB_SPEED_HIGH:
+ dev->device = desc->high;
+ break;
+ }
+ dev->config = dev->device->confs;
+}
+
+void usb_desc_init(USBDevice *dev)
+{
+ dev->speed = USB_SPEED_FULL;
+ usb_desc_setdefaults(dev);
+}
+
+void usb_desc_attach(USBDevice *dev)
+{
+ const USBDesc *desc = dev->info->usb_desc;
+
+ assert(desc != NULL);
+ if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
+ dev->speed = USB_SPEED_HIGH;
+ } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
+ dev->speed = USB_SPEED_FULL;
+ } else {
+ fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n",
+ dev->info->product_desc);
+ return;
+ }
+ usb_desc_setdefaults(dev);
+}
+
+void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str)
+{
+ USBDescString *s;
+
+ QLIST_FOREACH(s, &dev->strings, next) {
+ if (s->index == index) {
+ break;
+ }
+ }
+ if (s == NULL) {
+ s = qemu_mallocz(sizeof(*s));
+ s->index = index;
+ QLIST_INSERT_HEAD(&dev->strings, s, next);
+ }
+ qemu_free(s->str);
+ s->str = qemu_strdup(str);
+}
+
+const char *usb_desc_get_string(USBDevice *dev, uint8_t index)
+{
+ USBDescString *s;
+
+ QLIST_FOREACH(s, &dev->strings, next) {
+ if (s->index == index) {
+ return s->str;
+ }
+ }
+ return NULL;
+}
+
+int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
+{
+ uint8_t bLength, pos, i;
+ const char *str;
+
+ if (len < 4) {
+ return -1;
+ }
+
+ if (index == 0) {
+ /* language ids */
+ dest[0] = 4;
+ dest[1] = USB_DT_STRING;
+ dest[2] = 0x09;
+ dest[3] = 0x04;
+ return 4;
+ }
+
+ str = usb_desc_get_string(dev, index);
+ if (str == NULL) {
+ str = dev->info->usb_desc->str[index];
+ if (str == NULL) {
+ return 0;
+ }
+ }
+
+ bLength = strlen(str) * 2 + 2;
+ dest[0] = bLength;
+ dest[1] = USB_DT_STRING;
+ i = 0; pos = 2;
+ while (pos+1 < bLength && pos+1 < len) {
+ dest[pos++] = str[i++];
+ dest[pos++] = 0;
+ }
+ return pos;
+}
+
+int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
+{
+ const USBDesc *desc = dev->info->usb_desc;
+ const USBDescDevice *other_dev;
+ uint8_t buf[256];
+ uint8_t type = value >> 8;
+ uint8_t index = value & 0xff;
+ int ret = -1;
+
+ if (dev->speed == USB_SPEED_HIGH) {
+ other_dev = dev->info->usb_desc->full;
+ } else {
+ other_dev = dev->info->usb_desc->high;
+ }
+
+ switch(type) {
+ case USB_DT_DEVICE:
+ ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
+ trace_usb_desc_device(dev->addr, len, ret);
+ break;
+ case USB_DT_CONFIG:
+ if (index < dev->device->bNumConfigurations) {
+ ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf));
+ }
+ trace_usb_desc_config(dev->addr, index, len, ret);
+ break;
+ case USB_DT_STRING:
+ ret = usb_desc_string(dev, index, buf, sizeof(buf));
+ trace_usb_desc_string(dev->addr, index, len, ret);
+ break;
+
+ case USB_DT_DEVICE_QUALIFIER:
+ if (other_dev != NULL) {
+ ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
+ }
+ trace_usb_desc_device_qualifier(dev->addr, len, ret);
+ break;
+ case USB_DT_OTHER_SPEED_CONFIG:
+ if (other_dev != NULL && index < other_dev->bNumConfigurations) {
+ ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf));
+ buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
+ }
+ trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
+ break;
+
+ default:
+ fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__,
+ dev->addr, type, len);
+ break;
+ }
+
+ if (ret > 0) {
+ if (ret > len) {
+ ret = len;
+ }
+ memcpy(dest, buf, ret);
+ }
+ return ret;
+}
+
+int usb_desc_handle_control(USBDevice *dev, int request, int value,
+ int index, int length, uint8_t *data)
+{
+ const USBDesc *desc = dev->info->usb_desc;
+ int i, ret = -1;
+
+ assert(desc != NULL);
+ switch(request) {
+ case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+ dev->addr = value;
+ trace_usb_set_addr(dev->addr);
+ ret = 0;
+ break;
+
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ ret = usb_desc_get_descriptor(dev, value, data, length);
+ break;
+
+ case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+ data[0] = dev->config->bConfigurationValue;
+ ret = 1;
+ break;
+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+ for (i = 0; i < dev->device->bNumConfigurations; i++) {
+ if (dev->device->confs[i].bConfigurationValue == value) {
+ dev->config = dev->device->confs + i;
+ ret = 0;
+ }
+ }
+ trace_usb_set_config(dev->addr, value, ret);
+ break;
+
+ case DeviceRequest | USB_REQ_GET_STATUS:
+ data[0] = 0;
+ if (dev->config->bmAttributes & 0x40) {
+ data[0] |= 1 << USB_DEVICE_SELF_POWERED;
+ }
+ if (dev->remote_wakeup) {
+ data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+ }
+ data[1] = 0x00;
+ ret = 2;
+ break;
+ case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+ if (value == USB_DEVICE_REMOTE_WAKEUP) {
+ dev->remote_wakeup = 0;
+ ret = 0;
+ }
+ trace_usb_clear_device_feature(dev->addr, value, ret);
+ break;
+ case DeviceOutRequest | USB_REQ_SET_FEATURE:
+ if (value == USB_DEVICE_REMOTE_WAKEUP) {
+ dev->remote_wakeup = 1;
+ ret = 0;
+ }
+ trace_usb_set_device_feature(dev->addr, value, ret);
+ break;
+ }
+ return ret;
+}
diff --git a/hw/usb-desc.h b/hw/usb-desc.h
new file mode 100644
index 0000000000..ac734ab088
--- /dev/null
+++ b/hw/usb-desc.h
@@ -0,0 +1,92 @@
+#ifndef QEMU_HW_USB_DESC_H
+#define QEMU_HW_USB_DESC_H
+
+#include <inttypes.h>
+
+struct USBDescID {
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+};
+
+struct USBDescDevice {
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint8_t bNumConfigurations;
+
+ const USBDescConfig *confs;
+};
+
+struct USBDescConfig {
+ uint8_t bNumInterfaces;
+ uint8_t bConfigurationValue;
+ uint8_t iConfiguration;
+ uint8_t bmAttributes;
+ uint8_t bMaxPower;
+
+ uint8_t nif;
+ const USBDescIface *ifs;
+};
+
+struct USBDescIface {
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+
+ uint8_t ndesc;
+ USBDescOther *descs;
+ USBDescEndpoint *eps;
+};
+
+struct USBDescEndpoint {
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+};
+
+struct USBDescOther {
+ uint8_t length;
+ uint8_t *data;
+};
+
+typedef const char *USBDescStrings[256];
+
+struct USBDesc {
+ USBDescID id;
+ const USBDescDevice *full;
+ const USBDescDevice *high;
+ const char* const *str;
+};
+
+/* generate usb packages from structs */
+int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
+ uint8_t *dest, size_t len);
+int usb_desc_device_qualifier(const USBDescDevice *dev,
+ uint8_t *dest, size_t len);
+int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len);
+int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len);
+int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
+int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
+
+/* control message emulation helpers */
+void usb_desc_init(USBDevice *dev);
+void usb_desc_attach(USBDevice *dev);
+void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
+const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
+int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
+int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len);
+int usb_desc_handle_control(USBDevice *dev, int request, int value,
+ int index, int length, uint8_t *data);
+
+#endif /* QEMU_HW_USB_DESC_H */
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 882d933466..90a2b49e1d 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -25,6 +25,7 @@
#include "hw.h"
#include "console.h"
#include "usb.h"
+#include "usb-desc.h"
#include "sysemu.h"
/* HID interface requests */
@@ -73,190 +74,206 @@ typedef struct USBHIDState {
void (*datain)(void *);
} USBHIDState;
-/* mostly the same values as the Bochs USB Mouse device */
-static const uint8_t qemu_mouse_dev_descriptor[] = {
- 0x12, /* u8 bLength; */
- 0x01, /* u8 bDescriptorType; Device */
- 0x00, 0x01, /* u16 bcdUSB; v1.0 */
-
- 0x00, /* u8 bDeviceClass; */
- 0x00, /* u8 bDeviceSubClass; */
- 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
- 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
-
- 0x27, 0x06, /* u16 idVendor; */
- 0x01, 0x00, /* u16 idProduct; */
- 0x00, 0x00, /* u16 bcdDevice */
-
- 0x03, /* u8 iManufacturer; */
- 0x02, /* u8 iProduct; */
- 0x01, /* u8 iSerialNumber; */
- 0x01 /* u8 bNumConfigurations; */
+enum {
+ STR_MANUFACTURER = 1,
+ STR_PRODUCT_MOUSE,
+ STR_PRODUCT_TABLET,
+ STR_PRODUCT_KEYBOARD,
+ STR_SERIALNUMBER,
+ STR_CONFIG_MOUSE,
+ STR_CONFIG_TABLET,
+ STR_CONFIG_KEYBOARD,
};
-static const uint8_t qemu_mouse_config_descriptor[] = {
- /* one configuration */
- 0x09, /* u8 bLength; */
- 0x02, /* u8 bDescriptorType; Configuration */
- 0x22, 0x00, /* u16 wTotalLength; */
- 0x01, /* u8 bNumInterfaces; (1) */
- 0x01, /* u8 bConfigurationValue; */
- 0x04, /* u8 iConfiguration; */
- 0xe0, /* u8 bmAttributes;
- Bit 7: must be set,
- 6: Self-powered,
- 5: Remote wakeup,
- 4..0: resvd */
- 50, /* u8 MaxPower; */
-
- /* USB 1.1:
- * USB 2.0, single TT organization (mandatory):
- * one interface, protocol 0
- *
- * USB 2.0, multiple TT organization (optional):
- * two interfaces, protocols 1 (like single TT)
- * and 2 (multiple TT mode) ... config is
- * sometimes settable
- * NOT IMPLEMENTED
- */
-
- /* one interface */
- 0x09, /* u8 if_bLength; */
- 0x04, /* u8 if_bDescriptorType; Interface */
- 0x00, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x01, /* u8 if_bNumEndpoints; */
- 0x03, /* u8 if_bInterfaceClass; */
- 0x01, /* u8 if_bInterfaceSubClass; */
- 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
- 0x07, /* u8 if_iInterface; */
-
- /* HID descriptor */
- 0x09, /* u8 bLength; */
- 0x21, /* u8 bDescriptorType; */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- 0x22, /* u8 type; Report */
- 52, 0, /* u16 len */
-
- /* one endpoint (status change endpoint) */
- 0x07, /* u8 ep_bLength; */
- 0x05, /* u8 ep_bDescriptorType; Endpoint */
- 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* u8 ep_bmAttributes; Interrupt */
- 0x04, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+static const USBDescStrings desc_strings = {
+ [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+ [STR_PRODUCT_MOUSE] = "QEMU USB Mouse",
+ [STR_PRODUCT_TABLET] = "QEMU USB Tablet",
+ [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
+ [STR_SERIALNUMBER] = "42", /* == remote wakeup works */
+ [STR_CONFIG_MOUSE] = "HID Mouse",
+ [STR_CONFIG_TABLET] = "HID Tablet",
+ [STR_CONFIG_KEYBOARD] = "HID Keyboard",
};
-static const uint8_t qemu_tablet_config_descriptor[] = {
- /* one configuration */
- 0x09, /* u8 bLength; */
- 0x02, /* u8 bDescriptorType; Configuration */
- 0x22, 0x00, /* u16 wTotalLength; */
- 0x01, /* u8 bNumInterfaces; (1) */
- 0x01, /* u8 bConfigurationValue; */
- 0x05, /* u8 iConfiguration; */
- 0xa0, /* u8 bmAttributes;
- Bit 7: must be set,
- 6: Self-powered,
- 5: Remote wakeup,
- 4..0: resvd */
- 50, /* u8 MaxPower; */
-
- /* USB 1.1:
- * USB 2.0, single TT organization (mandatory):
- * one interface, protocol 0
- *
- * USB 2.0, multiple TT organization (optional):
- * two interfaces, protocols 1 (like single TT)
- * and 2 (multiple TT mode) ... config is
- * sometimes settable
- * NOT IMPLEMENTED
- */
-
- /* one interface */
- 0x09, /* u8 if_bLength; */
- 0x04, /* u8 if_bDescriptorType; Interface */
- 0x00, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x01, /* u8 if_bNumEndpoints; */
- 0x03, /* u8 if_bInterfaceClass; */
- 0x01, /* u8 if_bInterfaceSubClass; */
- 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
- 0x07, /* u8 if_iInterface; */
-
- /* HID descriptor */
- 0x09, /* u8 bLength; */
- 0x21, /* u8 bDescriptorType; */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- 0x22, /* u8 type; Report */
- 74, 0, /* u16 len */
-
- /* one endpoint (status change endpoint) */
- 0x07, /* u8 ep_bLength; */
- 0x05, /* u8 ep_bDescriptorType; Endpoint */
- 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* u8 ep_bmAttributes; Interrupt */
- 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+static const USBDescIface desc_iface_mouse = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = 0x01, /* boot */
+ .bInterfaceProtocol = 0x02,
+ .ndesc = 1,
+ .descs = (USBDescOther[]) {
+ {
+ /* HID descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ USB_DT_HID, /* u8 bDescriptorType */
+ 0x01, 0x00, /* u16 HID_class */
+ 0x00, /* u8 country_code */
+ 0x01, /* u8 num_descriptors */
+ USB_DT_REPORT, /* u8 type: Report */
+ 52, 0, /* u16 len */
+ },
+ },
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 4,
+ .bInterval = 0x0a,
+ },
+ },
};
-static const uint8_t qemu_keyboard_config_descriptor[] = {
- /* one configuration */
- 0x09, /* u8 bLength; */
- USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */
- 0x22, 0x00, /* u16 wTotalLength; */
- 0x01, /* u8 bNumInterfaces; (1) */
- 0x01, /* u8 bConfigurationValue; */
- 0x06, /* u8 iConfiguration; */
- 0xa0, /* u8 bmAttributes;
- Bit 7: must be set,
- 6: Self-powered,
- 5: Remote wakeup,
- 4..0: resvd */
- 0x32, /* u8 MaxPower; */
-
- /* USB 1.1:
- * USB 2.0, single TT organization (mandatory):
- * one interface, protocol 0
- *
- * USB 2.0, multiple TT organization (optional):
- * two interfaces, protocols 1 (like single TT)
- * and 2 (multiple TT mode) ... config is
- * sometimes settable
- * NOT IMPLEMENTED
- */
-
- /* one interface */
- 0x09, /* u8 if_bLength; */
- USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */
- 0x00, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x01, /* u8 if_bNumEndpoints; */
- 0x03, /* u8 if_bInterfaceClass; HID */
- 0x01, /* u8 if_bInterfaceSubClass; Boot */
- 0x01, /* u8 if_bInterfaceProtocol; Keyboard */
- 0x07, /* u8 if_iInterface; */
-
- /* HID descriptor */
- 0x09, /* u8 bLength; */
- USB_DT_HID, /* u8 bDescriptorType; */
- 0x11, 0x01, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type; Report */
- 0x3f, 0x00, /* u16 len */
-
- /* one endpoint (status change endpoint) */
- 0x07, /* u8 ep_bLength; */
- USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */
- USB_DIR_IN | 0x01, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* u8 ep_bmAttributes; Interrupt */
- 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+static const USBDescIface desc_iface_tablet = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = 0x01, /* boot */
+ .bInterfaceProtocol = 0x02,
+ .ndesc = 1,
+ .descs = (USBDescOther[]) {
+ {
+ /* HID descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ USB_DT_HID, /* u8 bDescriptorType */
+ 0x01, 0x00, /* u16 HID_class */
+ 0x00, /* u8 country_code */
+ 0x01, /* u8 num_descriptors */
+ USB_DT_REPORT, /* u8 type: Report */
+ 74, 0, /* u16 len */
+ },
+ },
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 8,
+ .bInterval = 0x0a,
+ },
+ },
+};
+
+static const USBDescIface desc_iface_keyboard = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = 0x01, /* boot */
+ .bInterfaceProtocol = 0x01, /* keyboard */
+ .ndesc = 1,
+ .descs = (USBDescOther[]) {
+ {
+ /* HID descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ USB_DT_HID, /* u8 bDescriptorType */
+ 0x11, 0x01, /* u16 HID_class */
+ 0x00, /* u8 country_code */
+ 0x01, /* u8 num_descriptors */
+ USB_DT_REPORT, /* u8 type: Report */
+ 0x3f, 0, /* u16 len */
+ },
+ },
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 8,
+ .bInterval = 0x0a,
+ },
+ },
+};
+
+static const USBDescDevice desc_device_mouse = {
+ .bcdUSB = 0x0100,
+ .bMaxPacketSize0 = 8,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG_MOUSE,
+ .bmAttributes = 0xa0,
+ .bMaxPower = 50,
+ .ifs = &desc_iface_mouse,
+ },
+ },
+};
+
+static const USBDescDevice desc_device_tablet = {
+ .bcdUSB = 0x0100,
+ .bMaxPacketSize0 = 8,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG_TABLET,
+ .bmAttributes = 0xa0,
+ .bMaxPower = 50,
+ .ifs = &desc_iface_tablet,
+ },
+ },
+};
+
+static const USBDescDevice desc_device_keyboard = {
+ .bcdUSB = 0x0100,
+ .bMaxPacketSize0 = 8,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG_KEYBOARD,
+ .bmAttributes = 0xa0,
+ .bMaxPower = 50,
+ .ifs = &desc_iface_keyboard,
+ },
+ },
+};
+
+static const USBDesc desc_mouse = {
+ .id = {
+ .idVendor = 0x0627,
+ .idProduct = 0x0001,
+ .bcdDevice = 0,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT_MOUSE,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_mouse,
+ .str = desc_strings,
+};
+
+static const USBDesc desc_tablet = {
+ .id = {
+ .idVendor = 0x0627,
+ .idProduct = 0x0001,
+ .bcdDevice = 0,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT_TABLET,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_tablet,
+ .str = desc_strings,
+};
+
+static const USBDesc desc_keyboard = {
+ .id = {
+ .idVendor = 0x0627,
+ .idProduct = 0x0001,
+ .bcdDevice = 0,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT_KEYBOARD,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_keyboard,
+ .str = desc_strings,
};
static const uint8_t qemu_mouse_hid_report_descriptor[] = {
@@ -399,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,
@@ -412,6 +429,8 @@ static void usb_hid_changed(USBHIDState *hs)
if (hs->datain)
hs->datain(hs->datain_opaque);
+
+ usb_wakeup(&hs->dev);
}
static void usb_mouse_event(void *opaque,
@@ -460,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;
}
@@ -647,106 +669,15 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
USBHIDState *s = (USBHIDState *)dev;
- int ret = 0;
+ int ret;
+
+ ret = usb_desc_handle_control(dev, request, value, index, length, data);
+ if (ret >= 0) {
+ return ret;
+ }
+ ret = 0;
switch(request) {
- case DeviceRequest | USB_REQ_GET_STATUS:
- data[0] = (1 << USB_DEVICE_SELF_POWERED) |
- (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
- data[1] = 0x00;
- ret = 2;
- break;
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- ret = 0;
- break;
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- switch(value >> 8) {
- case USB_DT_DEVICE:
- memcpy(data, qemu_mouse_dev_descriptor,
- sizeof(qemu_mouse_dev_descriptor));
- ret = sizeof(qemu_mouse_dev_descriptor);
- break;
- case USB_DT_CONFIG:
- if (s->kind == USB_MOUSE) {
- memcpy(data, qemu_mouse_config_descriptor,
- sizeof(qemu_mouse_config_descriptor));
- ret = sizeof(qemu_mouse_config_descriptor);
- } else if (s->kind == USB_TABLET) {
- memcpy(data, qemu_tablet_config_descriptor,
- sizeof(qemu_tablet_config_descriptor));
- ret = sizeof(qemu_tablet_config_descriptor);
- } else if (s->kind == USB_KEYBOARD) {
- memcpy(data, qemu_keyboard_config_descriptor,
- sizeof(qemu_keyboard_config_descriptor));
- ret = sizeof(qemu_keyboard_config_descriptor);
- }
- break;
- case USB_DT_STRING:
- switch(value & 0xff) {
- case 0:
- /* language ids */
- data[0] = 4;
- data[1] = 3;
- data[2] = 0x09;
- data[3] = 0x04;
- ret = 4;
- break;
- case 1:
- /* serial number */
- ret = set_usb_string(data, "1");
- break;
- case 2:
- /* product description */
- ret = set_usb_string(data, s->dev.product_desc);
- break;
- case 3:
- /* vendor description */
- ret = set_usb_string(data, "QEMU " QEMU_VERSION);
- break;
- case 4:
- ret = set_usb_string(data, "HID Mouse");
- break;
- case 5:
- ret = set_usb_string(data, "HID Tablet");
- break;
- case 6:
- ret = set_usb_string(data, "HID Keyboard");
- break;
- case 7:
- ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
- break;
- default:
- goto fail;
- }
- break;
- default:
- goto fail;
- }
- break;
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- data[0] = 1;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- ret = 0;
- break;
case DeviceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
ret = 1;
@@ -867,7 +798,8 @@ static void usb_hid_handle_destroy(USBDevice *dev)
static int usb_hid_initfn(USBDevice *dev, int kind)
{
USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
- s->dev.speed = USB_SPEED_FULL;
+
+ usb_desc_init(dev);
s->kind = kind;
if (s->kind == USB_MOUSE) {
@@ -912,6 +844,7 @@ static struct USBDeviceInfo hid_info[] = {
.qdev.name = "usb-tablet",
.usbdevice_name = "tablet",
.qdev.size = sizeof(USBHIDState),
+ .usb_desc = &desc_tablet,
.init = usb_tablet_initfn,
.handle_packet = usb_generic_handle_packet,
.handle_reset = usb_mouse_handle_reset,
@@ -923,6 +856,7 @@ static struct USBDeviceInfo hid_info[] = {
.qdev.name = "usb-mouse",
.usbdevice_name = "mouse",
.qdev.size = sizeof(USBHIDState),
+ .usb_desc = &desc_mouse,
.init = usb_mouse_initfn,
.handle_packet = usb_generic_handle_packet,
.handle_reset = usb_mouse_handle_reset,
@@ -934,6 +868,7 @@ static struct USBDeviceInfo hid_info[] = {
.qdev.name = "usb-kbd",
.usbdevice_name = "keyboard",
.qdev.size = sizeof(USBHIDState),
+ .usb_desc = &desc_keyboard,
.init = usb_keyboard_initfn,
.handle_packet = usb_generic_handle_packet,
.handle_reset = usb_keyboard_handle_reset,
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 8a3f829c96..78698caf67 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -23,10 +23,11 @@
*/
#include "qemu-common.h"
#include "usb.h"
+#include "usb-desc.h"
//#define DEBUG
-#define MAX_PORTS 8
+#define NUM_PORTS 8
typedef struct USBHubPort {
USBPort port;
@@ -36,8 +37,7 @@ typedef struct USBHubPort {
typedef struct USBHubState {
USBDevice dev;
- int nb_ports;
- USBHubPort ports[MAX_PORTS];
+ USBHubPort ports[NUM_PORTS];
} USBHubState;
#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
@@ -83,6 +83,60 @@ typedef struct USBHubState {
/* same as Linux kernel root hubs */
+enum {
+ STR_MANUFACTURER = 1,
+ STR_PRODUCT,
+ STR_SERIALNUMBER,
+};
+
+static const USBDescStrings desc_strings = {
+ [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+ [STR_PRODUCT] = "QEMU USB Hub",
+ [STR_SERIALNUMBER] = "314159",
+};
+
+static const USBDescIface desc_iface_hub = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HUB,
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 1 + (NUM_PORTS + 7) / 8,
+ .bInterval = 0xff,
+ },
+ }
+};
+
+static const USBDescDevice desc_device_hub = {
+ .bcdUSB = 0x0110,
+ .bDeviceClass = USB_CLASS_HUB,
+ .bMaxPacketSize0 = 8,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .bmAttributes = 0xe0,
+ .ifs = &desc_iface_hub,
+ },
+ },
+};
+
+static const USBDesc desc_hub = {
+ .id = {
+ .idVendor = 0,
+ .idProduct = 0,
+ .bcdDevice = 0x0101,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_hub,
+ .str = desc_strings,
+};
+
static const uint8_t qemu_hub_dev_descriptor[] = {
0x12, /* u8 bLength; */
0x01, /* u8 bDescriptorType; Device */
@@ -164,37 +218,51 @@ static const uint8_t qemu_hub_hub_descriptor[] =
/* DeviceRemovable and PortPwrCtrlMask patched in later */
};
-static void usb_hub_attach(USBPort *port1, USBDevice *dev)
+static void usb_hub_attach(USBPort *port1)
{
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
- if (dev) {
- if (port->port.dev)
- usb_attach(port1, NULL);
-
- port->wPortStatus |= PORT_STAT_CONNECTION;
- port->wPortChange |= PORT_STAT_C_CONNECTION;
- if (dev->speed == USB_SPEED_LOW)
- port->wPortStatus |= PORT_STAT_LOW_SPEED;
- else
- port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
- port->port.dev = dev;
- /* send the attach message */
- usb_send_msg(dev, USB_MSG_ATTACH);
+ port->wPortStatus |= PORT_STAT_CONNECTION;
+ port->wPortChange |= PORT_STAT_C_CONNECTION;
+ if (port->port.dev->speed == USB_SPEED_LOW) {
+ port->wPortStatus |= PORT_STAT_LOW_SPEED;
} else {
- dev = port->port.dev;
- if (dev) {
- port->wPortStatus &= ~PORT_STAT_CONNECTION;
- port->wPortChange |= PORT_STAT_C_CONNECTION;
- if (port->wPortStatus & PORT_STAT_ENABLE) {
- port->wPortStatus &= ~PORT_STAT_ENABLE;
- port->wPortChange |= PORT_STAT_C_ENABLE;
- }
- /* send the detach message */
- usb_send_msg(dev, USB_MSG_DETACH);
- port->port.dev = NULL;
- }
+ port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
+ }
+}
+
+static void usb_hub_detach(USBPort *port1)
+{
+ USBHubState *s = port1->opaque;
+ USBHubPort *port = &s->ports[port1->index];
+
+ port->wPortStatus &= ~PORT_STAT_CONNECTION;
+ port->wPortChange |= PORT_STAT_C_CONNECTION;
+ if (port->wPortStatus & PORT_STAT_ENABLE) {
+ port->wPortStatus &= ~PORT_STAT_ENABLE;
+ port->wPortChange |= PORT_STAT_C_ENABLE;
+ }
+}
+
+static void usb_hub_wakeup(USBDevice *dev)
+{
+ USBHubState *s = dev->port->opaque;
+ USBHubPort *port = &s->ports[dev->port->index];
+
+ if (port->wPortStatus & PORT_STAT_SUSPEND) {
+ port->wPortChange |= PORT_STAT_C_SUSPEND;
+ usb_wakeup(&s->dev);
+ }
+}
+
+static void usb_hub_handle_attach(USBDevice *dev)
+{
+ USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+ int i;
+
+ for (i = 0; i < NUM_PORTS; i++) {
+ usb_port_location(&s->ports[i].port, dev->port, i+1);
}
}
@@ -209,93 +277,18 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
USBHubState *s = (USBHubState *)dev;
int ret;
+ ret = usb_desc_handle_control(dev, request, value, index, length, data);
+ if (ret >= 0) {
+ return ret;
+ }
+
switch(request) {
- case DeviceRequest | USB_REQ_GET_STATUS:
- data[0] = (1 << USB_DEVICE_SELF_POWERED) |
- (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
- data[1] = 0x00;
- ret = 2;
- break;
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- } else {
- goto fail;
- }
- ret = 0;
- break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == 0 && index != 0x81) { /* clear ep halt */
goto fail;
}
ret = 0;
break;
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- ret = 0;
- break;
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- switch(value >> 8) {
- case USB_DT_DEVICE:
- memcpy(data, qemu_hub_dev_descriptor,
- sizeof(qemu_hub_dev_descriptor));
- ret = sizeof(qemu_hub_dev_descriptor);
- break;
- case USB_DT_CONFIG:
- memcpy(data, qemu_hub_config_descriptor,
- sizeof(qemu_hub_config_descriptor));
-
- /* status change endpoint size based on number
- * of ports */
- data[22] = (s->nb_ports + 1 + 7) / 8;
-
- ret = sizeof(qemu_hub_config_descriptor);
- break;
- case USB_DT_STRING:
- switch(value & 0xff) {
- case 0:
- /* language ids */
- data[0] = 4;
- data[1] = 3;
- data[2] = 0x09;
- data[3] = 0x04;
- ret = 4;
- break;
- case 1:
- /* serial number */
- ret = set_usb_string(data, "314159");
- break;
- case 2:
- /* product description */
- ret = set_usb_string(data, "QEMU USB Hub");
- break;
- case 3:
- /* vendor description */
- ret = set_usb_string(data, "QEMU " QEMU_VERSION);
- break;
- default:
- goto fail;
- }
- break;
- default:
- goto fail;
- }
- break;
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- data[0] = 1;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- ret = 0;
- break;
case DeviceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
ret = 1;
@@ -315,8 +308,9 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
{
unsigned int n = index - 1;
USBHubPort *port;
- if (n >= s->nb_ports)
+ if (n >= NUM_PORTS) {
goto fail;
+ }
port = &s->ports[n];
data[0] = port->wPortStatus;
data[1] = port->wPortStatus >> 8;
@@ -338,8 +332,9 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
unsigned int n = index - 1;
USBHubPort *port;
USBDevice *dev;
- if (n >= s->nb_ports)
+ if (n >= NUM_PORTS) {
goto fail;
+ }
port = &s->ports[n];
dev = port->port.dev;
switch(value) {
@@ -367,8 +362,9 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
unsigned int n = index - 1;
USBHubPort *port;
- if (n >= s->nb_ports)
+ if (n >= NUM_PORTS) {
goto fail;
+ }
port = &s->ports[n];
switch(value) {
case PORT_ENABLE:
@@ -403,17 +399,17 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
unsigned int n, limit, var_hub_size = 0;
memcpy(data, qemu_hub_hub_descriptor,
sizeof(qemu_hub_hub_descriptor));
- data[2] = s->nb_ports;
+ data[2] = NUM_PORTS;
/* fill DeviceRemovable bits */
- limit = ((s->nb_ports + 1 + 7) / 8) + 7;
+ limit = ((NUM_PORTS + 1 + 7) / 8) + 7;
for (n = 7; n < limit; n++) {
data[n] = 0x00;
var_hub_size++;
}
/* fill PortPwrCtrlMask bits */
- limit = limit + ((s->nb_ports + 7) / 8);
+ limit = limit + ((NUM_PORTS + 7) / 8);
for (;n < limit; n++) {
data[n] = 0xff;
var_hub_size++;
@@ -442,14 +438,14 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
USBHubPort *port;
unsigned int status;
int i, n;
- n = (s->nb_ports + 1 + 7) / 8;
+ n = (NUM_PORTS + 1 + 7) / 8;
if (p->len == 1) { /* FreeBSD workaround */
n = 1;
} else if (n > p->len) {
return USB_RET_BABBLE;
}
status = 0;
- for(i = 0; i < s->nb_ports; i++) {
+ for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
if (port->wPortChange)
status |= (1 << (i + 1));
@@ -481,7 +477,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
USBDevice *dev;
int i, ret;
- for(i = 0; i < s->nb_ports; i++) {
+ for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
dev = port->port.dev;
if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
@@ -518,24 +514,30 @@ static void usb_hub_handle_destroy(USBDevice *dev)
USBHubState *s = (USBHubState *)dev;
int i;
- for (i = 0; i < s->nb_ports; i++) {
+ for (i = 0; i < NUM_PORTS; i++) {
usb_unregister_port(usb_bus_from_device(dev),
&s->ports[i].port);
}
}
+static USBPortOps usb_hub_port_ops = {
+ .attach = usb_hub_attach,
+ .detach = usb_hub_detach,
+ .wakeup = usb_hub_wakeup,
+};
+
static int usb_hub_initfn(USBDevice *dev)
{
USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
USBHubPort *port;
int i;
- s->dev.speed = USB_SPEED_FULL,
- s->nb_ports = MAX_PORTS; /* FIXME: make configurable */
- for (i = 0; i < s->nb_ports; i++) {
+ usb_desc_init(dev);
+ for (i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
usb_register_port(usb_bus_from_device(dev),
- &port->port, s, i, &s->dev, usb_hub_attach);
+ &port->port, s, i, &usb_hub_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
port->wPortStatus = PORT_STAT_POWER;
port->wPortChange = 0;
}
@@ -547,8 +549,10 @@ static struct USBDeviceInfo hub_info = {
.qdev.name = "usb-hub",
.qdev.fw_name = "hub",
.qdev.size = sizeof(USBHubState),
+ .usb_desc = &desc_hub,
.init = usb_hub_initfn,
.handle_packet = usb_hub_handle_packet,
+ .handle_attach = usb_hub_handle_attach,
.handle_reset = usb_hub_handle_reset,
.handle_control = usb_hub_handle_control,
.handle_data = usb_hub_handle_data,
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 0a95d8d506..97d1e4af13 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -11,6 +11,7 @@
#include "qemu-option.h"
#include "qemu-config.h"
#include "usb.h"
+#include "usb-desc.h"
#include "scsi.h"
#include "console.h"
#include "monitor.h"
@@ -50,6 +51,7 @@ typedef struct {
SCSIBus bus;
BlockConf conf;
SCSIDevice *scsi_dev;
+ uint32_t removable;
int result;
/* For async completion. */
USBPacket *packet;
@@ -72,69 +74,102 @@ struct usb_msd_csw {
uint8_t status;
};
-static const uint8_t qemu_msd_dev_descriptor[] = {
- 0x12, /* u8 bLength; */
- 0x01, /* u8 bDescriptorType; Device */
- 0x00, 0x01, /* u16 bcdUSB; v1.0 */
-
- 0x00, /* u8 bDeviceClass; */
- 0x00, /* u8 bDeviceSubClass; */
- 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
- 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
-
- /* Vendor and product id are arbitrary. */
- 0x00, 0x00, /* u16 idVendor; */
- 0x00, 0x00, /* u16 idProduct; */
- 0x00, 0x00, /* u16 bcdDevice */
-
- 0x01, /* u8 iManufacturer; */
- 0x02, /* u8 iProduct; */
- 0x03, /* u8 iSerialNumber; */
- 0x01 /* u8 bNumConfigurations; */
+enum {
+ STR_MANUFACTURER = 1,
+ STR_PRODUCT,
+ STR_SERIALNUMBER,
+ STR_CONFIG_FULL,
+ STR_CONFIG_HIGH,
};
-static const uint8_t qemu_msd_config_descriptor[] = {
-
- /* one configuration */
- 0x09, /* u8 bLength; */
- 0x02, /* u8 bDescriptorType; Configuration */
- 0x20, 0x00, /* u16 wTotalLength; */
- 0x01, /* u8 bNumInterfaces; (1) */
- 0x01, /* u8 bConfigurationValue; */
- 0x00, /* u8 iConfiguration; */
- 0xc0, /* u8 bmAttributes;
- Bit 7: must be set,
- 6: Self-powered,
- 5: Remote wakeup,
- 4..0: resvd */
- 0x00, /* u8 MaxPower; */
-
- /* one interface */
- 0x09, /* u8 if_bLength; */
- 0x04, /* u8 if_bDescriptorType; Interface */
- 0x00, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x02, /* u8 if_bNumEndpoints; */
- 0x08, /* u8 if_bInterfaceClass; MASS STORAGE */
- 0x06, /* u8 if_bInterfaceSubClass; SCSI */
- 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */
- 0x00, /* u8 if_iInterface; */
-
- /* Bulk-In endpoint */
- 0x07, /* u8 ep_bLength; */
- 0x05, /* u8 ep_bDescriptorType; Endpoint */
- 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x02, /* u8 ep_bmAttributes; Bulk */
- 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x00, /* u8 ep_bInterval; */
-
- /* Bulk-Out endpoint */
- 0x07, /* u8 ep_bLength; */
- 0x05, /* u8 ep_bDescriptorType; Endpoint */
- 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */
- 0x02, /* u8 ep_bmAttributes; Bulk */
- 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x00 /* u8 ep_bInterval; */
+static const USBDescStrings desc_strings = {
+ [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+ [STR_PRODUCT] = "QEMU USB HARDDRIVE",
+ [STR_SERIALNUMBER] = "1",
+ [STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
+ [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
+};
+
+static const USBDescIface desc_iface_full = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = 0x06, /* SCSI */
+ .bInterfaceProtocol = 0x50, /* Bulk */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 64,
+ },{
+ .bEndpointAddress = USB_DIR_OUT | 0x02,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 64,
+ },
+ }
+};
+
+static const USBDescDevice desc_device_full = {
+ .bcdUSB = 0x0200,
+ .bMaxPacketSize0 = 8,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG_FULL,
+ .bmAttributes = 0xc0,
+ .ifs = &desc_iface_full,
+ },
+ },
+};
+
+static const USBDescIface desc_iface_high = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,
+ .bInterfaceSubClass = 0x06, /* SCSI */
+ .bInterfaceProtocol = 0x50, /* Bulk */
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 512,
+ },{
+ .bEndpointAddress = USB_DIR_OUT | 0x02,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 512,
+ },
+ }
+};
+
+static const USBDescDevice desc_device_high = {
+ .bcdUSB = 0x0200,
+ .bMaxPacketSize0 = 64,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG_HIGH,
+ .bmAttributes = 0xc0,
+ .ifs = &desc_iface_high,
+ },
+ },
+};
+
+static const USBDesc desc = {
+ .id = {
+ .idVendor = 0,
+ .idProduct = 0,
+ .bcdDevice = 0,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_full,
+ .high = &desc_device_high,
+ .str = desc_strings,
};
static void usb_msd_copy_data(MSDState *s)
@@ -153,7 +188,7 @@ static void usb_msd_copy_data(MSDState *s)
s->usb_buf += len;
s->scsi_buf += len;
s->data_len -= len;
- if (s->scsi_len == 0) {
+ if (s->scsi_len == 0 || s->data_len == 0) {
if (s->mode == USB_MSDM_DATAIN) {
s->scsi_dev->info->read_data(s->scsi_dev, s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) {
@@ -162,15 +197,18 @@ static void usb_msd_copy_data(MSDState *s)
}
}
-static void usb_msd_send_status(MSDState *s)
+static void usb_msd_send_status(MSDState *s, USBPacket *p)
{
struct usb_msd_csw csw;
+ int len;
csw.sig = cpu_to_le32(0x53425355);
csw.tag = cpu_to_le32(s->tag);
csw.residue = s->residue;
csw.status = s->result;
- memcpy(s->usb_buf, &csw, 13);
+
+ len = MIN(sizeof(csw), p->len);
+ memcpy(p->data, &csw, len);
}
static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
@@ -190,7 +228,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
/* A deferred packet with no write data remaining must be
the status read packet. */
- usb_msd_send_status(s);
+ usb_msd_send_status(s, p);
s->mode = USB_MSDM_CBW;
} else {
if (s->data_len) {
@@ -236,84 +274,15 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
MSDState *s = (MSDState *)dev;
- int ret = 0;
+ int ret;
+ ret = usb_desc_handle_control(dev, request, value, index, length, data);
+ if (ret >= 0) {
+ return ret;
+ }
+
+ ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_STATUS:
- data[0] = (1 << USB_DEVICE_SELF_POWERED) |
- (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
- data[1] = 0x00;
- ret = 2;
- break;
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- ret = 0;
- break;
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- switch(value >> 8) {
- case USB_DT_DEVICE:
- memcpy(data, qemu_msd_dev_descriptor,
- sizeof(qemu_msd_dev_descriptor));
- ret = sizeof(qemu_msd_dev_descriptor);
- break;
- case USB_DT_CONFIG:
- memcpy(data, qemu_msd_config_descriptor,
- sizeof(qemu_msd_config_descriptor));
- ret = sizeof(qemu_msd_config_descriptor);
- break;
- case USB_DT_STRING:
- switch(value & 0xff) {
- case 0:
- /* language ids */
- data[0] = 4;
- data[1] = 3;
- data[2] = 0x09;
- data[3] = 0x04;
- ret = 4;
- break;
- case 1:
- /* vendor description */
- ret = set_usb_string(data, "QEMU " QEMU_VERSION);
- break;
- case 2:
- /* product description */
- ret = set_usb_string(data, "QEMU USB HARDDRIVE");
- break;
- case 3:
- /* serial number */
- ret = set_usb_string(data, "1");
- break;
- default:
- goto fail;
- }
- break;
- default:
- goto fail;
- }
- break;
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- data[0] = 1;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- ret = 0;
- break;
case DeviceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
ret = 1;
@@ -338,7 +307,6 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
ret = 1;
break;
default:
- fail:
ret = USB_RET_STALL;
break;
}
@@ -461,15 +429,13 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
if (len < 13)
goto fail;
- s->usb_len = len;
- s->usb_buf = data;
- usb_msd_send_status(s);
+ usb_msd_send_status(s, p);
s->mode = USB_MSDM_CBW;
ret = 13;
break;
case USB_MSDM_DATAIN:
- DPRINTF("Data in %d/%d\n", len, s->data_len);
+ DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len);
if (len > s->data_len)
len = s->data_len;
s->usb_buf = data;
@@ -524,6 +490,7 @@ static int usb_msd_initfn(USBDevice *dev)
{
MSDState *s = DO_UPCAST(MSDState, dev, dev);
BlockDriverState *bs = s->conf.bs;
+ DriveInfo *dinfo;
if (!bs) {
error_report("usb-msd: drive property not set");
@@ -542,9 +509,14 @@ static int usb_msd_initfn(USBDevice *dev)
bdrv_detach(bs, &s->dev.qdev);
s->conf.bs = NULL;
- s->dev.speed = USB_SPEED_FULL;
+ dinfo = drive_get_by_blockdev(bs);
+ if (dinfo && dinfo->serial) {
+ usb_desc_set_string(dev, STR_SERIALNUMBER, dinfo->serial);
+ }
+
+ usb_desc_init(dev);
scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete);
- s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0);
+ s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
if (!s->scsi_dev) {
return -1;
}
@@ -570,7 +542,6 @@ static USBDevice *usb_msd_init(const char *filename)
QemuOpts *opts;
DriveInfo *dinfo;
USBDevice *dev;
- int fatal_error;
const char *p1;
char fmt[32];
@@ -600,7 +571,7 @@ static USBDevice *usb_msd_init(const char *filename)
qemu_opt_set(opts, "if", "none");
/* create host drive */
- dinfo = drive_init(opts, 0, &fatal_error);
+ dinfo = drive_init(opts, 0);
if (!dinfo) {
qemu_opts_del(opts);
return NULL;
@@ -625,8 +596,10 @@ static struct USBDeviceInfo msd_info = {
.product_desc = "QEMU USB MSD",
.qdev.name = "usb-storage",
.qdev.size = sizeof(MSDState),
+ .usb_desc = &desc,
.init = usb_msd_initfn,
.handle_packet = usb_generic_handle_packet,
+ .handle_attach = usb_desc_attach,
.handle_reset = usb_msd_handle_reset,
.handle_control = usb_msd_handle_control,
.handle_data = usb_msd_handle_data,
@@ -634,6 +607,7 @@ static struct USBDeviceInfo msd_info = {
.usbdevice_init = usb_msd_init,
.qdev.props = (Property[]) {
DEFINE_BLOCK_PROPERTIES(MSDState, conf),
+ DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
DEFINE_PROP_END_OF_LIST(),
},
};
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 9efe7a6344..782cfa2282 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -259,7 +259,13 @@
#endif
-static void musb_attach(USBPort *port, USBDevice *dev);
+static void musb_attach(USBPort *port);
+static void musb_detach(USBPort *port);
+
+static USBPortOps musb_port_ops = {
+ .attach = musb_attach,
+ .detach = musb_detach,
+};
typedef struct {
uint16_t faddr[2];
@@ -343,7 +349,9 @@ struct MUSBState {
}
usb_bus_new(&s->bus, NULL /* FIXME */);
- usb_register_port(&s->bus, &s->port, s, 0, NULL, musb_attach);
+ usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+ usb_port_location(&s->port, NULL, 1);
return s;
}
@@ -460,34 +468,20 @@ static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
}
/* Attach or detach a device on our only port. */
-static void musb_attach(USBPort *port, USBDevice *dev)
+static void musb_attach(USBPort *port)
{
MUSBState *s = (MUSBState *) port->opaque;
- USBDevice *curr;
-
- port = &s->port;
- curr = port->dev;
-
- if (dev) {
- if (curr) {
- usb_attach(port, NULL);
- /* TODO: signal some interrupts */
- }
-
- musb_intr_set(s, musb_irq_vbus_request, 1);
- /* Send the attach message to device */
- usb_send_msg(dev, USB_MSG_ATTACH);
- } else if (curr) {
- /* Send the detach message */
- usb_send_msg(curr, USB_MSG_DETACH);
-
- musb_intr_set(s, musb_irq_disconnect, 1);
- }
+ musb_intr_set(s, musb_irq_vbus_request, 1);
+ musb_session_update(s, 0, s->session);
+}
- port->dev = dev;
+static void musb_detach(USBPort *port)
+{
+ MUSBState *s = (MUSBState *) port->opaque;
- musb_session_update(s, !!curr, s->session);
+ musb_intr_set(s, musb_irq_disconnect, 1);
+ musb_session_update(s, 1, s->session);
}
static inline void musb_cb_tick0(void *opaque)
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 84924550fd..bf51bb3890 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -25,6 +25,7 @@
#include "qemu-common.h"
#include "usb.h"
+#include "usb-desc.h"
#include "net.h"
#include "qemu-queue.h"
#include "sysemu.h"
@@ -89,182 +90,209 @@ enum usbstring_idx {
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
-/*
- * mostly the same descriptor as the linux gadget rndis driver
- */
-static const uint8_t qemu_net_dev_descriptor[] = {
- 0x12, /* u8 bLength; */
- USB_DT_DEVICE, /* u8 bDescriptorType; Device */
- 0x00, 0x02, /* u16 bcdUSB; v2.0 */
- USB_CLASS_COMM, /* u8 bDeviceClass; */
- 0x00, /* u8 bDeviceSubClass; */
- 0x00, /* u8 bDeviceProtocol; [ low/full only ] */
- 0x40, /* u8 bMaxPacketSize0 */
- RNDIS_VENDOR_NUM & 0xff, RNDIS_VENDOR_NUM >> 8, /* u16 idVendor; */
- RNDIS_PRODUCT_NUM & 0xff, RNDIS_PRODUCT_NUM >> 8, /* u16 idProduct; */
- 0x00, 0x00, /* u16 bcdDevice */
- STRING_MANUFACTURER, /* u8 iManufacturer; */
- STRING_PRODUCT, /* u8 iProduct; */
- STRING_SERIALNUMBER, /* u8 iSerialNumber; */
- 0x02, /* u8 bNumConfigurations; */
+static const USBDescStrings usb_net_stringtable = {
+ [STRING_MANUFACTURER] = "QEMU",
+ [STRING_PRODUCT] = "RNDIS/QEMU USB Network Device",
+ [STRING_ETHADDR] = "400102030405",
+ [STRING_DATA] = "QEMU USB Net Data Interface",
+ [STRING_CONTROL] = "QEMU USB Net Control Interface",
+ [STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface",
+ [STRING_CDC] = "QEMU USB Net CDC",
+ [STRING_SUBSET] = "QEMU USB Net Subset",
+ [STRING_RNDIS] = "QEMU USB Net RNDIS",
+ [STRING_SERIALNUMBER] = "1",
+};
+
+static const USBDescIface desc_iface_rndis[] = {
+ {
+ /* RNDIS Control Interface */
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
+ .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
+ .iInterface = STRING_RNDIS_CONTROL,
+ .ndesc = 4,
+ .descs = (USBDescOther[]) {
+ {
+ /* Header Descriptor */
+ .data = (uint8_t[]) {
+ 0x05, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
+ 0x10, 0x01, /* le16 bcdCDC */
+ },
+ },{
+ /* Call Management Descriptor */
+ .data = (uint8_t[]) {
+ 0x05, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */
+ 0x00, /* u8 bmCapabilities */
+ 0x01, /* u8 bDataInterface */
+ },
+ },{
+ /* ACM Descriptor */
+ .data = (uint8_t[]) {
+ 0x04, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */
+ 0x00, /* u8 bmCapabilities */
+ },
+ },{
+ /* Union Descriptor */
+ .data = (uint8_t[]) {
+ 0x05, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
+ 0x00, /* u8 bMasterInterface0 */
+ 0x01, /* u8 bSlaveInterface0 */
+ },
+ },
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = STATUS_BYTECOUNT,
+ .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
+ },
+ }
+ },{
+ /* RNDIS Data Interface */
+ .bInterfaceNumber = 1,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .iInterface = STRING_DATA,
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x02,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 0x40,
+ },{
+ .bEndpointAddress = USB_DIR_OUT | 0x02,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 0x40,
+ }
+ }
+ }
+};
+
+static const USBDescIface desc_iface_cdc[] = {
+ {
+ /* CDC Control Interface */
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .iInterface = STRING_CONTROL,
+ .ndesc = 3,
+ .descs = (USBDescOther[]) {
+ {
+ /* Header Descriptor */
+ .data = (uint8_t[]) {
+ 0x05, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
+ 0x10, 0x01, /* le16 bcdCDC */
+ },
+ },{
+ /* Union Descriptor */
+ .data = (uint8_t[]) {
+ 0x05, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
+ 0x00, /* u8 bMasterInterface0 */
+ 0x01, /* u8 bSlaveInterface0 */
+ },
+ },{
+ /* Ethernet Descriptor */
+ .data = (uint8_t[]) {
+ 0x0d, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */
+ STRING_ETHADDR, /* u8 iMACAddress */
+ 0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */
+ ETH_FRAME_LEN & 0xff,
+ ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */
+ 0x00, 0x00, /* le16 wNumberMCFilters */
+ 0x00, /* u8 bNumberPowerFilters */
+ },
+ },
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = STATUS_BYTECOUNT,
+ .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
+ },
+ }
+ },{
+ /* CDC Data Interface (off) */
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ },{
+ /* CDC Data Interface */
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .iInterface = STRING_DATA,
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x02,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 0x40,
+ },{
+ .bEndpointAddress = USB_DIR_OUT | 0x02,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 0x40,
+ }
+ }
+ }
};
-static const uint8_t qemu_net_rndis_config_descriptor[] = {
- /* Configuration Descriptor */
- 0x09, /* u8 bLength */
- USB_DT_CONFIG, /* u8 bDescriptorType */
- 0x43, 0x00, /* le16 wTotalLength */
- 0x02, /* u8 bNumInterfaces */
- DEV_RNDIS_CONFIG_VALUE, /* u8 bConfigurationValue */
- STRING_RNDIS, /* u8 iConfiguration */
- 0xc0, /* u8 bmAttributes */
- 0x32, /* u8 bMaxPower */
- /* RNDIS Control Interface */
- 0x09, /* u8 bLength */
- USB_DT_INTERFACE, /* u8 bDescriptorType */
- 0x00, /* u8 bInterfaceNumber */
- 0x00, /* u8 bAlternateSetting */
- 0x01, /* u8 bNumEndpoints */
- USB_CLASS_COMM, /* u8 bInterfaceClass */
- USB_CDC_SUBCLASS_ACM, /* u8 bInterfaceSubClass */
- USB_CDC_ACM_PROTO_VENDOR, /* u8 bInterfaceProtocol */
- STRING_RNDIS_CONTROL, /* u8 iInterface */
- /* Header Descriptor */
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
- 0x10, 0x01, /* le16 bcdCDC */
- /* Call Management Descriptor */
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bmCapabilities */
- 0x01, /* u8 bDataInterface */
- /* ACM Descriptor */
- 0x04, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bmCapabilities */
- /* Union Descriptor */
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bMasterInterface0 */
- 0x01, /* u8 bSlaveInterface0 */
- /* Status Descriptor */
- 0x07, /* u8 bLength */
- USB_DT_ENDPOINT, /* u8 bDescriptorType */
- USB_DIR_IN | 1, /* u8 bEndpointAddress */
- USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */
- STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */
- 1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */
- /* RNDIS Data Interface */
- 0x09, /* u8 bLength */
- USB_DT_INTERFACE, /* u8 bDescriptorType */
- 0x01, /* u8 bInterfaceNumber */
- 0x00, /* u8 bAlternateSetting */
- 0x02, /* u8 bNumEndpoints */
- USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */
- 0x00, /* u8 bInterfaceSubClass */
- 0x00, /* u8 bInterfaceProtocol */
- STRING_DATA, /* u8 iInterface */
- /* Source Endpoint */
- 0x07, /* u8 bLength */
- USB_DT_ENDPOINT, /* u8 bDescriptorType */
- USB_DIR_IN | 2, /* u8 bEndpointAddress */
- USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */
- 0x40, 0x00, /* le16 wMaxPacketSize */
- 0x00, /* u8 bInterval */
- /* Sink Endpoint */
- 0x07, /* u8 bLength */
- USB_DT_ENDPOINT, /* u8 bDescriptorType */
- USB_DIR_OUT | 2, /* u8 bEndpointAddress */
- USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */
- 0x40, 0x00, /* le16 wMaxPacketSize */
- 0x00 /* u8 bInterval */
+static const USBDescDevice desc_device_net = {
+ .bcdUSB = 0x0200,
+ .bDeviceClass = USB_CLASS_COMM,
+ .bMaxPacketSize0 = 0x40,
+ .bNumConfigurations = 2,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 2,
+ .bConfigurationValue = DEV_RNDIS_CONFIG_VALUE,
+ .iConfiguration = STRING_RNDIS,
+ .bmAttributes = 0xc0,
+ .bMaxPower = 0x32,
+ .nif = ARRAY_SIZE(desc_iface_rndis),
+ .ifs = desc_iface_rndis,
+ },{
+ .bNumInterfaces = 2,
+ .bConfigurationValue = DEV_CONFIG_VALUE,
+ .iConfiguration = STRING_CDC,
+ .bmAttributes = 0xc0,
+ .bMaxPower = 0x32,
+ .nif = ARRAY_SIZE(desc_iface_cdc),
+ .ifs = desc_iface_cdc,
+ }
+ },
};
-static const uint8_t qemu_net_cdc_config_descriptor[] = {
- /* Configuration Descriptor */
- 0x09, /* u8 bLength */
- USB_DT_CONFIG, /* u8 bDescriptorType */
- 0x50, 0x00, /* le16 wTotalLength */
- 0x02, /* u8 bNumInterfaces */
- DEV_CONFIG_VALUE, /* u8 bConfigurationValue */
- STRING_CDC, /* u8 iConfiguration */
- 0xc0, /* u8 bmAttributes */
- 0x32, /* u8 bMaxPower */
- /* CDC Control Interface */
- 0x09, /* u8 bLength */
- USB_DT_INTERFACE, /* u8 bDescriptorType */
- 0x00, /* u8 bInterfaceNumber */
- 0x00, /* u8 bAlternateSetting */
- 0x01, /* u8 bNumEndpoints */
- USB_CLASS_COMM, /* u8 bInterfaceClass */
- USB_CDC_SUBCLASS_ETHERNET, /* u8 bInterfaceSubClass */
- USB_CDC_PROTO_NONE, /* u8 bInterfaceProtocol */
- STRING_CONTROL, /* u8 iInterface */
- /* Header Descriptor */
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
- 0x10, 0x01, /* le16 bcdCDC */
- /* Union Descriptor */
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bMasterInterface0 */
- 0x01, /* u8 bSlaveInterface0 */
- /* Ethernet Descriptor */
- 0x0d, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */
- STRING_ETHADDR, /* u8 iMACAddress */
- 0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */
- ETH_FRAME_LEN & 0xff, ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */
- 0x00, 0x00, /* le16 wNumberMCFilters */
- 0x00, /* u8 bNumberPowerFilters */
- /* Status Descriptor */
- 0x07, /* u8 bLength */
- USB_DT_ENDPOINT, /* u8 bDescriptorType */
- USB_DIR_IN | 1, /* u8 bEndpointAddress */
- USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */
- STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */
- 1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */
- /* CDC Data (nop) Interface */
- 0x09, /* u8 bLength */
- USB_DT_INTERFACE, /* u8 bDescriptorType */
- 0x01, /* u8 bInterfaceNumber */
- 0x00, /* u8 bAlternateSetting */
- 0x00, /* u8 bNumEndpoints */
- USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */
- 0x00, /* u8 bInterfaceSubClass */
- 0x00, /* u8 bInterfaceProtocol */
- 0x00, /* u8 iInterface */
- /* CDC Data Interface */
- 0x09, /* u8 bLength */
- USB_DT_INTERFACE, /* u8 bDescriptorType */
- 0x01, /* u8 bInterfaceNumber */
- 0x01, /* u8 bAlternateSetting */
- 0x02, /* u8 bNumEndpoints */
- USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */
- 0x00, /* u8 bInterfaceSubClass */
- 0x00, /* u8 bInterfaceProtocol */
- STRING_DATA, /* u8 iInterface */
- /* Source Endpoint */
- 0x07, /* u8 bLength */
- USB_DT_ENDPOINT, /* u8 bDescriptorType */
- USB_DIR_IN | 2, /* u8 bEndpointAddress */
- USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */
- 0x40, 0x00, /* le16 wMaxPacketSize */
- 0x00, /* u8 bInterval */
- /* Sink Endpoint */
- 0x07, /* u8 bLength */
- USB_DT_ENDPOINT, /* u8 bDescriptorType */
- USB_DIR_OUT | 2, /* u8 bEndpointAddress */
- USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */
- 0x40, 0x00, /* le16 wMaxPacketSize */
- 0x00 /* u8 bInterval */
+static const USBDesc desc_net = {
+ .id = {
+ .idVendor = RNDIS_VENDOR_NUM,
+ .idProduct = RNDIS_PRODUCT_NUM,
+ .bcdDevice = 0,
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .iSerialNumber = STRING_SERIALNUMBER,
+ },
+ .full = &desc_device_net,
+ .str = usb_net_stringtable,
};
/*
@@ -599,7 +627,6 @@ struct rndis_response {
typedef struct USBNetState {
USBDevice dev;
- unsigned int rndis;
enum rndis_state rndis_state;
uint32_t medium;
uint32_t speed;
@@ -620,6 +647,11 @@ typedef struct USBNetState {
QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp;
} USBNetState;
+static int is_rndis(USBNetState *s)
+{
+ return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE;
+}
+
static int ndis_query(USBNetState *s, uint32_t oid,
uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf,
size_t outlen)
@@ -1010,59 +1042,23 @@ static void usb_net_handle_reset(USBDevice *dev)
{
}
-static const char * const usb_net_stringtable[] = {
- [STRING_MANUFACTURER] = "QEMU",
- [STRING_PRODUCT] = "RNDIS/QEMU USB Network Device",
- [STRING_ETHADDR] = "400102030405",
- [STRING_DATA] = "QEMU USB Net Data Interface",
- [STRING_CONTROL] = "QEMU USB Net Control Interface",
- [STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface",
- [STRING_CDC] = "QEMU USB Net CDC",
- [STRING_SUBSET] = "QEMU USB Net Subset",
- [STRING_RNDIS] = "QEMU USB Net RNDIS",
- [STRING_SERIALNUMBER] = "1",
-};
-
static int usb_net_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
USBNetState *s = (USBNetState *) dev;
- int ret = 0;
-
- switch(request) {
- case DeviceRequest | USB_REQ_GET_STATUS:
- data[0] = (1 << USB_DEVICE_SELF_POWERED) |
- (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
- data[1] = 0x00;
- ret = 2;
- break;
-
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- } else {
- goto fail;
- }
- ret = 0;
- break;
-
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- } else {
- goto fail;
- }
- ret = 0;
- break;
+ int ret;
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- ret = 0;
- break;
+ ret = usb_desc_handle_control(dev, request, value, index, length, data);
+ if (ret >= 0) {
+ return ret;
+ }
+ ret = 0;
+ switch(request) {
case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
- if (!s->rndis || value || index != 0)
+ if (!is_rndis(s) || value || index != 0) {
goto fail;
+ }
#ifdef TRAFFIC_DEBUG
{
unsigned int i;
@@ -1079,8 +1075,9 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
break;
case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE:
- if (!s->rndis || value || index != 0)
+ if (!is_rndis(s) || value || index != 0) {
goto fail;
+ }
ret = rndis_get_response(s, data);
if (!ret) {
data[0] = 0;
@@ -1100,85 +1097,6 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
#endif
break;
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- switch(value >> 8) {
- case USB_DT_DEVICE:
- ret = sizeof(qemu_net_dev_descriptor);
- memcpy(data, qemu_net_dev_descriptor, ret);
- break;
-
- case USB_DT_CONFIG:
- switch (value & 0xff) {
- case 0:
- ret = sizeof(qemu_net_rndis_config_descriptor);
- memcpy(data, qemu_net_rndis_config_descriptor, ret);
- break;
-
- case 1:
- ret = sizeof(qemu_net_cdc_config_descriptor);
- memcpy(data, qemu_net_cdc_config_descriptor, ret);
- break;
-
- default:
- goto fail;
- }
-
- data[2] = ret & 0xff;
- data[3] = ret >> 8;
- break;
-
- case USB_DT_STRING:
- switch (value & 0xff) {
- case 0:
- /* language ids */
- data[0] = 4;
- data[1] = 3;
- data[2] = 0x09;
- data[3] = 0x04;
- ret = 4;
- break;
-
- case STRING_ETHADDR:
- ret = set_usb_string(data, s->usbstring_mac);
- break;
-
- default:
- if (ARRAY_SIZE(usb_net_stringtable) > (value & 0xff)) {
- ret = set_usb_string(data,
- usb_net_stringtable[value & 0xff]);
- break;
- }
-
- goto fail;
- }
- break;
-
- default:
- goto fail;
- }
- break;
-
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- data[0] = s->rndis ? DEV_RNDIS_CONFIG_VALUE : DEV_CONFIG_VALUE;
- ret = 1;
- break;
-
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- switch (value & 0xff) {
- case DEV_CONFIG_VALUE:
- s->rndis = 0;
- break;
-
- case DEV_RNDIS_CONFIG_VALUE:
- s->rndis = 1;
- break;
-
- default:
- goto fail;
- }
- ret = 0;
- break;
-
case DeviceRequest | USB_REQ_GET_INTERFACE:
case InterfaceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
@@ -1249,7 +1167,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
memcpy(p->data, &s->in_buf[s->in_ptr], ret);
s->in_ptr += ret;
if (s->in_ptr >= s->in_len &&
- (s->rndis || (s->in_len & (64 - 1)) || !ret)) {
+ (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
/* no short packet necessary */
s->in_ptr = s->in_len = 0;
}
@@ -1298,7 +1216,7 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
memcpy(&s->out_buf[s->out_ptr], p->data, sz);
s->out_ptr += sz;
- if (!s->rndis) {
+ if (!is_rndis(s)) {
if (ret < 64) {
qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr);
s->out_ptr = 0;
@@ -1369,7 +1287,7 @@ static ssize_t usbnet_receive(VLANClientState *nc, const uint8_t *buf, size_t si
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
struct rndis_packet_msg_type *msg;
- if (s->rndis) {
+ if (is_rndis(s)) {
msg = (struct rndis_packet_msg_type *) s->in_buf;
if (!s->rndis_state == RNDIS_DATA_INITIALIZED)
return -1;
@@ -1405,8 +1323,9 @@ static int usbnet_can_receive(VLANClientState *nc)
{
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
- if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED)
+ if (is_rndis(s) && !s->rndis_state == RNDIS_DATA_INITIALIZED) {
return 1;
+ }
return !s->in_len;
}
@@ -1439,9 +1358,8 @@ static int usb_net_initfn(USBDevice *dev)
{
USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
- s->dev.speed = USB_SPEED_FULL;
+ usb_desc_init(dev);
- s->rndis = 1;
s->rndis_state = RNDIS_UNINITIALIZED;
QTAILQ_INIT(&s->rndis_resp);
@@ -1463,6 +1381,7 @@ static int usb_net_initfn(USBDevice *dev)
s->conf.macaddr.a[3],
s->conf.macaddr.a[4],
s->conf.macaddr.a[5]);
+ usb_desc_set_string(dev, STRING_ETHADDR, s->usbstring_mac);
add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet@0");
return 0;
@@ -1500,6 +1419,7 @@ static struct USBDeviceInfo net_info = {
.qdev.name = "usb-net",
.qdev.fw_name = "network",
.qdev.size = sizeof(USBNetState),
+ .usb_desc = &desc_net,
.init = usb_net_initfn,
.handle_packet = usb_generic_handle_packet,
.handle_reset = usb_net_handle_reset,
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 240e8409af..09ea0b6260 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -322,52 +322,46 @@ static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
}
/* Attach or detach a device on a root hub port. */
-static void ohci_attach(USBPort *port1, USBDevice *dev)
+static void ohci_attach(USBPort *port1)
{
OHCIState *s = port1->opaque;
OHCIPort *port = &s->rhport[port1->index];
- uint32_t old_state = port->ctrl;
- if (dev) {
- if (port->port.dev) {
- usb_attach(port1, NULL);
- }
- /* set connect status */
- port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
-
- /* update speed */
- if (dev->speed == USB_SPEED_LOW)
- port->ctrl |= OHCI_PORT_LSDA;
- else
- port->ctrl &= ~OHCI_PORT_LSDA;
- port->port.dev = dev;
-
- /* notify of remote-wakeup */
- if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND)
- ohci_set_interrupt(s, OHCI_INTR_RD);
-
- /* send the attach message */
- usb_send_msg(dev, USB_MSG_ATTACH);
- DPRINTF("usb-ohci: Attached port %d\n", port1->index);
+ /* set connect status */
+ port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
+
+ /* update speed */
+ if (port->port.dev->speed == USB_SPEED_LOW) {
+ port->ctrl |= OHCI_PORT_LSDA;
} else {
- /* set connect status */
- if (port->ctrl & OHCI_PORT_CCS) {
- port->ctrl &= ~OHCI_PORT_CCS;
- port->ctrl |= OHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & OHCI_PORT_PES) {
- port->ctrl &= ~OHCI_PORT_PES;
- port->ctrl |= OHCI_PORT_PESC;
- }
- dev = port->port.dev;
- if (dev) {
- /* send the detach message */
- usb_send_msg(dev, USB_MSG_DETACH);
- }
- port->port.dev = NULL;
- DPRINTF("usb-ohci: Detached port %d\n", port1->index);
+ port->ctrl &= ~OHCI_PORT_LSDA;
+ }
+
+ /* notify of remote-wakeup */
+ if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
+ ohci_set_interrupt(s, OHCI_INTR_RD);
+ }
+
+ DPRINTF("usb-ohci: Attached port %d\n", port1->index);
+}
+
+static void ohci_detach(USBPort *port1)
+{
+ OHCIState *s = port1->opaque;
+ OHCIPort *port = &s->rhport[port1->index];
+ uint32_t old_state = port->ctrl;
+
+ /* set connect status */
+ if (port->ctrl & OHCI_PORT_CCS) {
+ port->ctrl &= ~OHCI_PORT_CCS;
+ port->ctrl |= OHCI_PORT_CSC;
}
+ /* disable port */
+ if (port->ctrl & OHCI_PORT_PES) {
+ port->ctrl &= ~OHCI_PORT_PES;
+ port->ctrl |= OHCI_PORT_PESC;
+ }
+ DPRINTF("usb-ohci: Detached port %d\n", port1->index);
if (old_state != port->ctrl)
ohci_set_interrupt(s, OHCI_INTR_RHSC);
@@ -413,8 +407,9 @@ static void ohci_reset(void *opaque)
{
port = &ohci->rhport[i];
port->ctrl = 0;
- if (port->port.dev)
- ohci_attach(&port->port, port->port.dev);
+ if (port->port.dev) {
+ usb_attach(&port->port, port->port.dev);
+ }
}
if (ohci->async_td) {
usb_cancel_packet(&ohci->usb_packet);
@@ -1669,6 +1664,11 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
ohci_mem_write
};
+static USBPortOps ohci_port_ops = {
+ .attach = ohci_attach,
+ .detach = ohci_detach,
+};
+
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
int num_ports, uint32_t localmem_base)
{
@@ -1699,7 +1699,9 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
usb_bus_new(&ohci->bus, dev);
ohci->num_ports = num_ports;
for (i = 0; i < num_ports; i++) {
- usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, NULL, ohci_attach);
+ usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+ usb_port_location(&ohci->rhport[i].port, NULL, i+1);
}
ohci->async_td = 0;
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index c19580f305..6763d52040 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -11,6 +11,7 @@
#include "qemu-common.h"
#include "qemu-error.h"
#include "usb.h"
+#include "usb-desc.h"
#include "qemu-char.h"
//#define DEBUG_Serial
@@ -91,8 +92,6 @@ do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0)
typedef struct {
USBDevice dev;
- uint32_t vendorid;
- uint32_t productid;
uint8_t recv_buf[RECV_BUF];
uint16_t recv_ptr;
uint16_t recv_used;
@@ -104,69 +103,78 @@ typedef struct {
CharDriverState *cs;
} USBSerialState;
-static const uint8_t qemu_serial_dev_descriptor[] = {
- 0x12, /* u8 bLength; */
- 0x01, /* u8 bDescriptorType; Device */
- 0x00, 0x02, /* u16 bcdUSB; v2.0 */
-
- 0x00, /* u8 bDeviceClass; */
- 0x00, /* u8 bDeviceSubClass; */
- 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
- 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
-
- /* Vendor and product id are arbitrary. */
- 0x03, 0x04, /* u16 idVendor; */
- 0x00, 0xFF, /* u16 idProduct; */
- 0x00, 0x04, /* u16 bcdDevice */
-
- 0x01, /* u8 iManufacturer; */
- 0x02, /* u8 iProduct; */
- 0x03, /* u8 iSerialNumber; */
- 0x01 /* u8 bNumConfigurations; */
+enum {
+ STR_MANUFACTURER = 1,
+ STR_PRODUCT_SERIAL,
+ STR_PRODUCT_BRAILLE,
+ STR_SERIALNUMBER,
};
-static const uint8_t qemu_serial_config_descriptor[] = {
-
- /* one configuration */
- 0x09, /* u8 bLength; */
- 0x02, /* u8 bDescriptorType; Configuration */
- 0x20, 0x00, /* u16 wTotalLength; */
- 0x01, /* u8 bNumInterfaces; (1) */
- 0x01, /* u8 bConfigurationValue; */
- 0x00, /* u8 iConfiguration; */
- 0x80, /* u8 bmAttributes;
- Bit 7: must be set,
- 6: Self-powered,
- 5: Remote wakeup,
- 4..0: resvd */
- 100/2, /* u8 MaxPower; */
-
- /* one interface */
- 0x09, /* u8 if_bLength; */
- 0x04, /* u8 if_bDescriptorType; Interface */
- 0x00, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x02, /* u8 if_bNumEndpoints; */
- 0xff, /* u8 if_bInterfaceClass; Vendor Specific */
- 0xff, /* u8 if_bInterfaceSubClass; Vendor Specific */
- 0xff, /* u8 if_bInterfaceProtocol; Vendor Specific */
- 0x02, /* u8 if_iInterface; */
-
- /* Bulk-In endpoint */
- 0x07, /* u8 ep_bLength; */
- 0x05, /* u8 ep_bDescriptorType; Endpoint */
- 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x02, /* u8 ep_bmAttributes; Bulk */
- 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x00, /* u8 ep_bInterval; */
-
- /* Bulk-Out endpoint */
- 0x07, /* u8 ep_bLength; */
- 0x05, /* u8 ep_bDescriptorType; Endpoint */
- 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */
- 0x02, /* u8 ep_bmAttributes; Bulk */
- 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x00 /* u8 ep_bInterval; */
+static const USBDescStrings desc_strings = {
+ [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+ [STR_PRODUCT_SERIAL] = "QEMU USB SERIAL",
+ [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE",
+ [STR_SERIALNUMBER] = "1",
+};
+
+static const USBDescIface desc_iface0 = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0xff,
+ .bInterfaceProtocol = 0xff,
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 64,
+ },{
+ .bEndpointAddress = USB_DIR_OUT | 0x02,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = 64,
+ },
+ }
+};
+
+static const USBDescDevice desc_device = {
+ .bcdUSB = 0x0200,
+ .bMaxPacketSize0 = 8,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .bmAttributes = 0x80,
+ .bMaxPower = 50,
+ .ifs = &desc_iface0,
+ },
+ },
+};
+
+static const USBDesc desc_serial = {
+ .id = {
+ .idVendor = 0x0403,
+ .idProduct = 0x6001,
+ .bcdDevice = 0x0400,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT_SERIAL,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device,
+ .str = desc_strings,
+};
+
+static const USBDesc desc_braille = {
+ .id = {
+ .idVendor = 0x0403,
+ .idProduct = 0xfe72,
+ .bcdDevice = 0x0400,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT_BRAILLE,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device,
+ .str = desc_strings,
};
static void usb_serial_reset(USBSerialState *s)
@@ -214,89 +222,16 @@ static int usb_serial_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
USBSerialState *s = (USBSerialState *)dev;
- int ret = 0;
+ int ret;
- //DPRINTF("got control %x, value %x\n",request, value);
+ DPRINTF("got control %x, value %x\n",request, value);
+ ret = usb_desc_handle_control(dev, request, value, index, length, data);
+ if (ret >= 0) {
+ return ret;
+ }
+
+ ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_STATUS:
- data[0] = (0 << USB_DEVICE_SELF_POWERED) |
- (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
- data[1] = 0x00;
- ret = 2;
- break;
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- ret = 0;
- break;
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- switch(value >> 8) {
- case USB_DT_DEVICE:
- memcpy(data, qemu_serial_dev_descriptor,
- sizeof(qemu_serial_dev_descriptor));
- data[8] = s->vendorid & 0xff;
- data[9] = ((s->vendorid) >> 8) & 0xff;
- data[10] = s->productid & 0xff;
- data[11] = ((s->productid) >> 8) & 0xff;
- ret = sizeof(qemu_serial_dev_descriptor);
- break;
- case USB_DT_CONFIG:
- memcpy(data, qemu_serial_config_descriptor,
- sizeof(qemu_serial_config_descriptor));
- ret = sizeof(qemu_serial_config_descriptor);
- break;
- case USB_DT_STRING:
- switch(value & 0xff) {
- case 0:
- /* language ids */
- data[0] = 4;
- data[1] = 3;
- data[2] = 0x09;
- data[3] = 0x04;
- ret = 4;
- break;
- case 1:
- /* vendor description */
- ret = set_usb_string(data, "QEMU " QEMU_VERSION);
- break;
- case 2:
- /* product description */
- ret = set_usb_string(data, "QEMU USB SERIAL");
- break;
- case 3:
- /* serial number */
- ret = set_usb_string(data, "1");
- break;
- default:
- goto fail;
- }
- break;
- default:
- goto fail;
- }
- break;
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- data[0] = 1;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- ret = 0;
- break;
case DeviceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
ret = 1;
@@ -543,7 +478,8 @@ static void usb_serial_event(void *opaque, int event)
static int usb_serial_initfn(USBDevice *dev)
{
USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
- s->dev.speed = USB_SPEED_FULL;
+
+ usb_desc_init(dev);
if (!s->cs) {
error_report("Property chardev is required");
@@ -633,6 +569,7 @@ static struct USBDeviceInfo serial_info = {
.product_desc = "QEMU USB Serial",
.qdev.name = "usb-serial",
.qdev.size = sizeof(USBSerialState),
+ .usb_desc = &desc_serial,
.init = usb_serial_initfn,
.handle_packet = usb_generic_handle_packet,
.handle_reset = usb_serial_handle_reset,
@@ -642,9 +579,7 @@ static struct USBDeviceInfo serial_info = {
.usbdevice_name = "serial",
.usbdevice_init = usb_serial_init,
.qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_HEX32("vendorid", USBSerialState, vendorid, 0x0403),
- DEFINE_PROP_HEX32("productid", USBSerialState, productid, 0x6001),
+ DEFINE_PROP_CHR("chardev", USBSerialState, cs),
DEFINE_PROP_END_OF_LIST(),
},
};
@@ -653,6 +588,7 @@ static struct USBDeviceInfo braille_info = {
.product_desc = "QEMU USB Braille",
.qdev.name = "usb-braille",
.qdev.size = sizeof(USBSerialState),
+ .usb_desc = &desc_braille,
.init = usb_serial_initfn,
.handle_packet = usb_generic_handle_packet,
.handle_reset = usb_serial_handle_reset,
@@ -662,9 +598,7 @@ static struct USBDeviceInfo braille_info = {
.usbdevice_name = "braille",
.usbdevice_init = usb_braille_init,
.qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_HEX32("vendorid", USBSerialState, vendorid, 0x0403),
- DEFINE_PROP_HEX32("productid", USBSerialState, productid, 0xfe72),
+ DEFINE_PROP_CHR("chardev", USBSerialState, cs),
DEFINE_PROP_END_OF_LIST(),
},
};
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index b9b822fcb1..b384e1ddec 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -57,13 +57,18 @@
#define TD_CTRL_NAK (1 << 19)
#define TD_CTRL_TIMEOUT (1 << 18)
+#define UHCI_PORT_SUSPEND (1 << 12)
#define UHCI_PORT_RESET (1 << 9)
#define UHCI_PORT_LSDA (1 << 8)
+#define UHCI_PORT_RD (1 << 6)
#define UHCI_PORT_ENC (1 << 3)
#define UHCI_PORT_EN (1 << 2)
#define UHCI_PORT_CSC (1 << 1)
#define UHCI_PORT_CCS (1 << 0)
+#define UHCI_PORT_READ_ONLY (0x1bb)
+#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC)
+
#define FRAME_TIMER_FREQ 1000
#define FRAME_MAX_LOOPS 100
@@ -307,8 +312,6 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
return match;
}
-static void uhci_attach(USBPort *port1, USBDevice *dev);
-
static void uhci_update_irq(UHCIState *s)
{
int level;
@@ -348,8 +351,9 @@ static void uhci_reset(void *opaque)
for(i = 0; i < NB_PORTS; i++) {
port = &s->ports[i];
port->ctrl = 0x0080;
- if (port->port.dev)
- uhci_attach(&port->port, port->port.dev);
+ if (port->port.dev) {
+ usb_attach(&port->port, port->port.dev);
+ }
}
uhci_async_cancel_all(s);
@@ -498,9 +502,10 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
usb_send_msg(dev, USB_MSG_RESET);
}
}
- port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);
+ port->ctrl &= UHCI_PORT_READ_ONLY;
+ port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
/* some bits are reset when a '1' is written to them */
- port->ctrl &= ~(val & 0x000a);
+ port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
}
break;
}
@@ -593,49 +598,52 @@ static void uhci_resume (void *opaque)
}
}
-static void uhci_attach(USBPort *port1, USBDevice *dev)
+static void uhci_attach(USBPort *port1)
{
UHCIState *s = port1->opaque;
UHCIPort *port = &s->ports[port1->index];
- if (dev) {
- if (port->port.dev) {
- usb_attach(port1, NULL);
- }
- /* set connect status */
- port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+ /* set connect status */
+ port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
- /* update speed */
- if (dev->speed == USB_SPEED_LOW)
- port->ctrl |= UHCI_PORT_LSDA;
- else
- port->ctrl &= ~UHCI_PORT_LSDA;
+ /* update speed */
+ if (port->port.dev->speed == USB_SPEED_LOW) {
+ port->ctrl |= UHCI_PORT_LSDA;
+ } else {
+ port->ctrl &= ~UHCI_PORT_LSDA;
+ }
- uhci_resume(s);
+ uhci_resume(s);
+}
- port->port.dev = dev;
- /* send the attach message */
- usb_send_msg(dev, USB_MSG_ATTACH);
- } else {
- /* set connect status */
- if (port->ctrl & UHCI_PORT_CCS) {
- port->ctrl &= ~UHCI_PORT_CCS;
- port->ctrl |= UHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & UHCI_PORT_EN) {
- port->ctrl &= ~UHCI_PORT_EN;
- port->ctrl |= UHCI_PORT_ENC;
- }
+static void uhci_detach(USBPort *port1)
+{
+ UHCIState *s = port1->opaque;
+ UHCIPort *port = &s->ports[port1->index];
- uhci_resume(s);
+ /* set connect status */
+ if (port->ctrl & UHCI_PORT_CCS) {
+ port->ctrl &= ~UHCI_PORT_CCS;
+ port->ctrl |= UHCI_PORT_CSC;
+ }
+ /* disable port */
+ if (port->ctrl & UHCI_PORT_EN) {
+ port->ctrl &= ~UHCI_PORT_EN;
+ port->ctrl |= UHCI_PORT_ENC;
+ }
- dev = port->port.dev;
- if (dev) {
- /* send the detach message */
- usb_send_msg(dev, USB_MSG_DETACH);
- }
- port->port.dev = NULL;
+ uhci_resume(s);
+}
+
+static void uhci_wakeup(USBDevice *dev)
+{
+ USBBus *bus = usb_bus_from_device(dev);
+ UHCIState *s = container_of(bus, UHCIState, bus);
+ UHCIPort *port = s->ports + dev->port->index;
+
+ if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
+ port->ctrl |= UHCI_PORT_RD;
+ uhci_resume(s);
}
}
@@ -1101,6 +1109,12 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
+static USBPortOps uhci_port_ops = {
+ .attach = uhci_attach,
+ .detach = uhci_detach,
+ .wakeup = uhci_wakeup,
+};
+
static int usb_uhci_common_initfn(UHCIState *s)
{
uint8_t *pci_conf = s->dev.config;
@@ -1115,7 +1129,9 @@ static int usb_uhci_common_initfn(UHCIState *s)
usb_bus_new(&s->bus, &s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
- usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, uhci_attach);
+ usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+ usb_port_location(&s->ports[i].port, NULL, i+1);
}
s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
s->expire_time = qemu_get_clock(vm_clock) +
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 47f26cd0a3..16be7a20cf 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -28,6 +28,7 @@
#include "hw.h"
#include "console.h"
#include "usb.h"
+#include "usb-desc.h"
/* Interface requests */
#define WACOM_GET_REPORT 0x2101
@@ -54,68 +55,75 @@ typedef struct USBWacomState {
int changed;
} USBWacomState;
-static const uint8_t qemu_wacom_dev_descriptor[] = {
- 0x12, /* u8 bLength; */
- 0x01, /* u8 bDescriptorType; Device */
- 0x10, 0x10, /* u16 bcdUSB; v1.10 */
+enum {
+ STR_MANUFACTURER = 1,
+ STR_PRODUCT,
+ STR_SERIALNUMBER,
+};
- 0x00, /* u8 bDeviceClass; */
- 0x00, /* u8 bDeviceSubClass; */
- 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
- 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
+static const USBDescStrings desc_strings = {
+ [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+ [STR_PRODUCT] = "Wacom PenPartner",
+ [STR_SERIALNUMBER] = "1",
+};
- 0x6a, 0x05, /* u16 idVendor; */
- 0x00, 0x00, /* u16 idProduct; */
- 0x10, 0x42, /* u16 bcdDevice */
+static const USBDescIface desc_iface_wacom = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = 0x01, /* boot */
+ .bInterfaceProtocol = 0x02,
+ .ndesc = 1,
+ .descs = (USBDescOther[]) {
+ {
+ /* HID descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ 0x21, /* u8 bDescriptorType */
+ 0x01, 0x10, /* u16 HID_class */
+ 0x00, /* u8 country_code */
+ 0x01, /* u8 num_descriptors */
+ 0x22, /* u8 type: Report */
+ 0x6e, 0, /* u16 len */
+ },
+ },
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 8,
+ .bInterval = 0x0a,
+ },
+ },
+};
- 0x01, /* u8 iManufacturer; */
- 0x02, /* u8 iProduct; */
- 0x00, /* u8 iSerialNumber; */
- 0x01, /* u8 bNumConfigurations; */
+static const USBDescDevice desc_device_wacom = {
+ .bcdUSB = 0x0110,
+ .bMaxPacketSize0 = 8,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .bmAttributes = 0x80,
+ .bMaxPower = 40,
+ .ifs = &desc_iface_wacom,
+ },
+ },
};
-static const uint8_t qemu_wacom_config_descriptor[] = {
- /* one configuration */
- 0x09, /* u8 bLength; */
- 0x02, /* u8 bDescriptorType; Configuration */
- 0x22, 0x00, /* u16 wTotalLength; */
- 0x01, /* u8 bNumInterfaces; (1) */
- 0x01, /* u8 bConfigurationValue; */
- 0x00, /* u8 iConfiguration; */
- 0x80, /* u8 bmAttributes;
- Bit 7: must be set,
- 6: Self-powered,
- 5: Remote wakeup,
- 4..0: resvd */
- 40, /* u8 MaxPower; */
-
- /* one interface */
- 0x09, /* u8 if_bLength; */
- 0x04, /* u8 if_bDescriptorType; Interface */
- 0x00, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x01, /* u8 if_bNumEndpoints; */
- 0x03, /* u8 if_bInterfaceClass; HID */
- 0x01, /* u8 if_bInterfaceSubClass; Boot */
- 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
- 0x00, /* u8 if_iInterface; */
-
- /* HID descriptor */
- 0x09, /* u8 bLength; */
- 0x21, /* u8 bDescriptorType; */
- 0x01, 0x10, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- 0x22, /* u8 type; Report */
- 0x6e, 0x00, /* u16 len */
-
- /* one endpoint (status change endpoint) */
- 0x07, /* u8 ep_bLength; */
- 0x05, /* u8 ep_bDescriptorType; Endpoint */
- 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* u8 ep_bmAttributes; Interrupt */
- 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x0a, /* u8 ep_bInterval; */
+static const USBDesc desc_wacom = {
+ .id = {
+ .idVendor = 0x056a,
+ .idProduct = 0x0000,
+ .bcdDevice = 0x4210,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_wacom,
+ .str = desc_strings,
};
static void usb_mouse_event(void *opaque,
@@ -245,89 +253,15 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
USBWacomState *s = (USBWacomState *) dev;
- int ret = 0;
+ int ret;
+ ret = usb_desc_handle_control(dev, request, value, index, length, data);
+ if (ret >= 0) {
+ return ret;
+ }
+
+ ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_STATUS:
- data[0] = (1 << USB_DEVICE_SELF_POWERED) |
- (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
- data[1] = 0x00;
- ret = 2;
- break;
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- } else {
- goto fail;
- }
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- ret = 0;
- break;
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- switch (value >> 8) {
- case USB_DT_DEVICE:
- memcpy(data, qemu_wacom_dev_descriptor,
- sizeof(qemu_wacom_dev_descriptor));
- ret = sizeof(qemu_wacom_dev_descriptor);
- break;
- case USB_DT_CONFIG:
- memcpy(data, qemu_wacom_config_descriptor,
- sizeof(qemu_wacom_config_descriptor));
- ret = sizeof(qemu_wacom_config_descriptor);
- break;
- case USB_DT_STRING:
- switch (value & 0xff) {
- case 0:
- /* language ids */
- data[0] = 4;
- data[1] = 3;
- data[2] = 0x09;
- data[3] = 0x04;
- ret = 4;
- break;
- case 1:
- /* serial number */
- ret = set_usb_string(data, "1");
- break;
- case 2:
- ret = set_usb_string(data, "Wacom PenPartner");
- break;
- case 3:
- /* vendor description */
- ret = set_usb_string(data, "QEMU " QEMU_VERSION);
- break;
- case 4:
- ret = set_usb_string(data, "Wacom Tablet");
- break;
- case 5:
- ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
- break;
- default:
- goto fail;
- }
- break;
- default:
- goto fail;
- }
- break;
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- data[0] = 1;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- ret = 0;
- break;
case DeviceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
ret = 1;
@@ -364,7 +298,6 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
ret = 0;
break;
default:
- fail:
ret = USB_RET_STALL;
break;
}
@@ -410,7 +343,7 @@ static void usb_wacom_handle_destroy(USBDevice *dev)
static int usb_wacom_initfn(USBDevice *dev)
{
USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
- s->dev.speed = USB_SPEED_FULL;
+ usb_desc_init(dev);
s->changed = 1;
return 0;
}
@@ -420,6 +353,7 @@ static struct USBDeviceInfo wacom_info = {
.qdev.name = "usb-wacom-tablet",
.qdev.desc = "QEMU PenPartner Tablet",
.usbdevice_name = "wacom-tablet",
+ .usb_desc = &desc_wacom,
.qdev.size = sizeof(USBWacomState),
.init = usb_wacom_initfn,
.handle_packet = usb_generic_handle_packet,
diff --git a/hw/usb.c b/hw/usb.c
index a326bcfffe..82a6217a0b 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -28,7 +28,32 @@
void usb_attach(USBPort *port, USBDevice *dev)
{
- port->attach(port, dev);
+ if (dev != NULL) {
+ /* attach */
+ if (port->dev) {
+ usb_attach(port, NULL);
+ }
+ dev->port = port;
+ port->dev = dev;
+ port->ops->attach(port);
+ usb_send_msg(dev, USB_MSG_ATTACH);
+ } else {
+ /* detach */
+ dev = port->dev;
+ port->ops->detach(port);
+ if (dev) {
+ usb_send_msg(dev, USB_MSG_DETACH);
+ dev->port = NULL;
+ port->dev = NULL;
+ }
+ }
+}
+
+void usb_wakeup(USBDevice *dev)
+{
+ if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
+ dev->port->ops->wakeup(dev);
+ }
}
/**********************/
@@ -169,6 +194,9 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
switch(p->pid) {
case USB_MSG_ATTACH:
s->state = USB_STATE_ATTACHED;
+ if (s->info->handle_attach) {
+ s->info->handle_attach(s);
+ }
return 0;
case USB_MSG_DETACH:
@@ -179,7 +207,9 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
s->remote_wakeup = 0;
s->addr = 0;
s->state = USB_STATE_DEFAULT;
- s->info->handle_reset(s);
+ if (s->info->handle_reset) {
+ s->info->handle_reset(s);
+ }
return 0;
}
diff --git a/hw/usb.h b/hw/usb.h
index 0b32d77e6f..5c1da3ed25 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -44,6 +44,12 @@
#define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1
#define USB_SPEED_HIGH 2
+#define USB_SPEED_SUPER 3
+
+#define USB_SPEED_MASK_LOW (1 << USB_SPEED_LOW)
+#define USB_SPEED_MASK_FULL (1 << USB_SPEED_FULL)
+#define USB_SPEED_MASK_HIGH (1 << USB_SPEED_HIGH)
+#define USB_SPEED_MASK_SUPER (1 << USB_SPEED_SUPER)
#define USB_STATE_NOTATTACHED 0
#define USB_STATE_ATTACHED 1
@@ -116,6 +122,8 @@
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
+#define USB_DT_DEVICE_QUALIFIER 0x06
+#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
@@ -128,10 +136,27 @@ typedef struct USBDevice USBDevice;
typedef struct USBDeviceInfo USBDeviceInfo;
typedef struct USBPacket USBPacket;
+typedef struct USBDesc USBDesc;
+typedef struct USBDescID USBDescID;
+typedef struct USBDescDevice USBDescDevice;
+typedef struct USBDescConfig USBDescConfig;
+typedef struct USBDescIface USBDescIface;
+typedef struct USBDescEndpoint USBDescEndpoint;
+typedef struct USBDescOther USBDescOther;
+typedef struct USBDescString USBDescString;
+
+struct USBDescString {
+ uint8_t index;
+ char *str;
+ QLIST_ENTRY(USBDescString) next;
+};
+
/* definition of a USB device */
struct USBDevice {
DeviceState qdev;
USBDeviceInfo *info;
+ USBPort *port;
+ char *port_path;
void *opaque;
int speed;
@@ -147,6 +172,10 @@ struct USBDevice {
int setup_state;
int setup_len;
int setup_index;
+
+ QLIST_HEAD(, USBDescString) strings;
+ const USBDescDevice *device;
+ const USBDescConfig *config;
};
struct USBDeviceInfo {
@@ -168,6 +197,11 @@ struct USBDeviceInfo {
void (*handle_destroy)(USBDevice *dev);
/*
+ * Attach the device
+ */
+ void (*handle_attach)(USBDevice *dev);
+
+ /*
* Reset the device
*/
void (*handle_reset)(USBDevice *dev);
@@ -190,20 +224,26 @@ struct USBDeviceInfo {
int (*handle_data)(USBDevice *dev, USBPacket *p);
const char *product_desc;
+ const USBDesc *usb_desc;
/* handle legacy -usbdevice command line options */
const char *usbdevice_name;
USBDevice *(*usbdevice_init)(const char *params);
};
-typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev);
+typedef struct USBPortOps {
+ void (*attach)(USBPort *port);
+ void (*detach)(USBPort *port);
+ void (*wakeup)(USBDevice *dev);
+} USBPortOps;
/* USB port on which a device can be connected */
struct USBPort {
USBDevice *dev;
- usb_attachfn attach;
+ int speedmask;
+ char path[16];
+ USBPortOps *ops;
void *opaque;
- USBDevice *pdev;
int index; /* internal port index, may be used with the opaque */
QTAILQ_ENTRY(USBPort) next;
};
@@ -251,6 +291,7 @@ static inline void usb_cancel_packet(USBPacket * p)
}
void usb_attach(USBPort *port, USBDevice *dev);
+void usb_wakeup(USBDevice *dev);
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
int set_usb_string(uint8_t *buf, const char *str);
void usb_send_msg(USBDevice *dev, int msg);
@@ -313,7 +354,8 @@ USBDevice *usb_create(USBBus *bus, const char *name);
USBDevice *usb_create_simple(USBBus *bus, const char *name);
USBDevice *usbdevice_create(const char *cmdline);
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
- USBDevice *pdev, usb_attachfn attach);
+ USBPortOps *ops, int speedmask);
+void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
void usb_unregister_port(USBBus *bus, USBPort *port);
int usb_device_attach(USBDevice *dev);
int usb_device_detach(USBDevice *dev);
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/virtio-9p-xattr.h b/hw/virtio-9p-xattr.h
index a6e31a152f..2bbae2dcb5 100644
--- a/hw/virtio-9p-xattr.h
+++ b/hw/virtio-9p-xattr.h
@@ -41,16 +41,15 @@ extern XattrOperations *mapped_xattr_ops[];
extern XattrOperations *passthrough_xattr_ops[];
extern XattrOperations *none_xattr_ops[];
-extern ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
- const char *name, void *value, size_t size);
-extern ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
- void *value, size_t vsize);
-extern int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, const char *name,
+ void *value, size_t size);
+ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value,
+ size_t vsize);
+int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags);
-extern int v9fs_remove_xattr(FsContext *ctx,
- const char *path, const char *name);
-extern ssize_t pt_listxattr(FsContext *ctx, const char *path,
- char *name, void *value, size_t size);
+int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
+ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
+ size_t size);
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
diff --git a/hw/virtio-9p.h b/hw/virtio-9p.h
index 6c233192e3..2ae4ce7189 100644
--- a/hw/virtio-9p.h
+++ b/hw/virtio-9p.h
@@ -495,8 +495,8 @@ typedef struct V9fsReadLinkState
V9fsString target;
} V9fsReadLinkState;
-extern size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
- size_t offset, size_t size, int pack);
+size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
+ size_t offset, size_t size, int pack);
static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
size_t offset, size_t size)
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index f62ccd1fe8..ffac5a4d8f 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -55,7 +55,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
trace_virtio_blk_req_complete(req, status);
- req->in->status = status;
+ stb_p(&req->in->status, status);
virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
virtio_notify(&s->vdev, s->vq);
@@ -94,7 +94,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
trace_virtio_blk_rw_complete(req, ret);
if (ret) {
- int is_read = !(req->out->type & VIRTIO_BLK_T_OUT);
+ int is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT);
if (virtio_blk_handle_rw_error(req, -ret, is_read))
return;
}
@@ -223,10 +223,10 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
status = VIRTIO_BLK_S_OK;
}
- req->scsi->errors = hdr.status;
- req->scsi->residual = hdr.resid;
- req->scsi->sense_len = hdr.sb_len_wr;
- req->scsi->data_len = hdr.dxfer_len;
+ stl_p(&req->scsi->errors, hdr.status);
+ stl_p(&req->scsi->residual, hdr.resid);
+ stl_p(&req->scsi->sense_len, hdr.sb_len_wr);
+ stl_p(&req->scsi->data_len, hdr.dxfer_len);
virtio_blk_req_complete(req, status);
}
@@ -280,10 +280,13 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
{
BlockRequest *blkreq;
+ uint64_t sector;
- trace_virtio_blk_handle_write(req, req->out->sector, req->qiov.size / 512);
+ sector = ldq_p(&req->out->sector);
- if (req->out->sector & req->dev->sector_mask) {
+ trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);
+
+ if (sector & req->dev->sector_mask) {
virtio_blk_rw_complete(req, -EIO);
return;
}
@@ -293,7 +296,7 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
}
blkreq = &mrb->blkreq[mrb->num_writes];
- blkreq->sector = req->out->sector;
+ blkreq->sector = sector;
blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE;
blkreq->qiov = &req->qiov;
blkreq->cb = virtio_blk_rw_complete;
@@ -306,13 +309,16 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
static void virtio_blk_handle_read(VirtIOBlockReq *req)
{
BlockDriverAIOCB *acb;
+ uint64_t sector;
+
+ sector = ldq_p(&req->out->sector);
- if (req->out->sector & req->dev->sector_mask) {
+ if (sector & req->dev->sector_mask) {
virtio_blk_rw_complete(req, -EIO);
return;
}
- acb = bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
+ acb = bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
req->qiov.size / BDRV_SECTOR_SIZE,
virtio_blk_rw_complete, req);
if (!acb) {
@@ -323,6 +329,8 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
static void virtio_blk_handle_request(VirtIOBlockReq *req,
MultiReqBuffer *mrb)
{
+ uint32_t type;
+
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
error_report("virtio-blk missing headers");
exit(1);
@@ -337,17 +345,19 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
req->out = (void *)req->elem.out_sg[0].iov_base;
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
- if (req->out->type & VIRTIO_BLK_T_FLUSH) {
+ type = ldl_p(&req->out->type);
+
+ if (type & VIRTIO_BLK_T_FLUSH) {
virtio_blk_handle_flush(req, mrb);
- } else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
+ } else if (type & VIRTIO_BLK_T_SCSI_CMD) {
virtio_blk_handle_scsi(req);
- } else if (req->out->type & VIRTIO_BLK_T_GET_ID) {
+ } else if (type & VIRTIO_BLK_T_GET_ID) {
VirtIOBlock *s = req->dev;
memcpy(req->elem.in_sg[0].iov_base, s->sn,
MIN(req->elem.in_sg[0].iov_len, sizeof(s->sn)));
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
- } else if (req->out->type & VIRTIO_BLK_T_OUT) {
+ } else if (type & VIRTIO_BLK_T_OUT) {
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
req->elem.out_num - 1);
virtio_blk_handle_write(req, mrb);
@@ -504,6 +514,15 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+static void virtio_blk_change_cb(void *opaque, int reason)
+{
+ VirtIOBlock *s = opaque;
+
+ if (reason & CHANGE_SIZE) {
+ virtio_notify_config(&s->vdev);
+ }
+}
+
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
{
VirtIOBlock *s;
@@ -546,6 +565,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
virtio_blk_save, virtio_blk_load, s);
bdrv_set_removable(s->bs, 0);
+ bdrv_set_change_cb(s->bs, virtio_blk_change_cb, s);
s->bs->buffer_alignment = conf->logical_block_size;
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index ccb3e632a4..161f11445f 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -79,7 +79,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
VirtIONet *n = to_virtio_net(vdev);
struct virtio_net_config netcfg;
- netcfg.status = n->status;
+ netcfg.status = lduw_p(&n->status);
memcpy(netcfg.mac, n->mac, ETH_ALEN);
memcpy(config, &netcfg, sizeof(netcfg));
}
@@ -338,7 +338,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
n->mac_table.multi_overflow = 0;
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
- mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base);
+ mac_data.entries = ldl_p(elem->out_sg[1].iov_base);
if (sizeof(mac_data.entries) +
(mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len)
@@ -354,7 +354,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
n->mac_table.first_multi = n->mac_table.in_use;
- mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
+ mac_data.entries = ldl_p(elem->out_sg[2].iov_base);
if (sizeof(mac_data.entries) +
(mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len)
@@ -384,7 +384,7 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_ERR;
}
- vid = lduw_le_p(elem->out_sg[1].iov_base);
+ vid = lduw_p(elem->out_sg[1].iov_base);
if (vid >= MAX_VLAN)
return VIRTIO_NET_ERR;
@@ -673,8 +673,9 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
virtqueue_fill(n->rx_vq, &elem, total, i++);
}
- if (mhdr)
- mhdr->num_buffers = i;
+ if (mhdr) {
+ mhdr->num_buffers = lduw_p(&i);
+ }
virtqueue_flush(n->rx_vq, i);
virtio_notify(&n->vdev, n->rx_vq);
diff --git a/hw/watchdog.h b/hw/watchdog.h
index 8fd32c34da..c12a29311a 100644
--- a/hw/watchdog.h
+++ b/hw/watchdog.h
@@ -35,9 +35,9 @@ struct WatchdogTimerModel {
typedef struct WatchdogTimerModel WatchdogTimerModel;
/* in hw/watchdog.c */
-extern int select_watchdog(const char *p);
-extern int select_watchdog_action(const char *action);
-extern void watchdog_add_model(WatchdogTimerModel *model);
-extern void watchdog_perform_action(void);
+int select_watchdog(const char *p);
+int select_watchdog_action(const char *action);
+void watchdog_add_model(WatchdogTimerModel *model);
+void watchdog_perform_action(void);
#endif /* QEMU_WATCHDOG_H */
diff --git a/hw/zaurus.c b/hw/zaurus.c
index 54ec3f00d5..fca11a5333 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -18,15 +18,17 @@
#include "hw.h"
#include "pxa.h"
#include "sharpsl.h"
+#include "sysbus.h"
#undef REG_FMT
#define REG_FMT "0x%02lx"
/* SCOOP devices */
+typedef struct ScoopInfo ScoopInfo;
struct ScoopInfo {
+ SysBusDevice busdev;
qemu_irq handler[16];
- qemu_irq *in;
uint16_t status;
uint16_t power;
uint32_t gpio_level;
@@ -70,7 +72,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 +106,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;
@@ -153,7 +155,7 @@ static CPUWriteMemoryFunc * const scoop_writefn[] = {
scoop_writeb,
};
-void scoop_gpio_set(void *opaque, int line, int level)
+static void scoop_gpio_set(void *opaque, int line, int level)
{
ScoopInfo *s = (ScoopInfo *) opaque;
@@ -163,77 +165,66 @@ void scoop_gpio_set(void *opaque, int line, int level)
s->gpio_level &= ~(1 << line);
}
-qemu_irq *scoop_gpio_in_get(ScoopInfo *s)
+static int scoop_init(SysBusDevice *dev)
{
- return s->in;
-}
+ ScoopInfo *s = FROM_SYSBUS(ScoopInfo, dev);
+ int iomemtype;
-void scoop_gpio_out_set(ScoopInfo *s, int line,
- qemu_irq handler) {
- if (line >= 16) {
- fprintf(stderr, "No GPIO pin %i\n", line);
- exit(-1);
- }
+ s->status = 0x02;
+ qdev_init_gpio_out(&s->busdev.qdev, s->handler, 16);
+ qdev_init_gpio_in(&s->busdev.qdev, scoop_gpio_set, 16);
+ iomemtype = cpu_register_io_memory(scoop_readfn,
+ scoop_writefn, s, DEVICE_NATIVE_ENDIAN);
- s->handler[line] = handler;
-}
+ sysbus_init_mmio(dev, 0x1000, iomemtype);
-static void scoop_save(QEMUFile *f, void *opaque)
-{
- ScoopInfo *s = (ScoopInfo *) opaque;
- qemu_put_be16s(f, &s->status);
- qemu_put_be16s(f, &s->power);
- qemu_put_be32s(f, &s->gpio_level);
- qemu_put_be32s(f, &s->gpio_dir);
- qemu_put_be32s(f, &s->prev_level);
- qemu_put_be16s(f, &s->mcr);
- qemu_put_be16s(f, &s->cdr);
- qemu_put_be16s(f, &s->ccr);
- qemu_put_be16s(f, &s->irr);
- qemu_put_be16s(f, &s->imr);
- qemu_put_be16s(f, &s->isr);
+ return 0;
}
-static int scoop_load(QEMUFile *f, void *opaque, int version_id)
+static bool is_version_0 (void *opaque, int version_id)
{
- uint16_t dummy;
- ScoopInfo *s = (ScoopInfo *) opaque;
- qemu_get_be16s(f, &s->status);
- qemu_get_be16s(f, &s->power);
- qemu_get_be32s(f, &s->gpio_level);
- qemu_get_be32s(f, &s->gpio_dir);
- qemu_get_be32s(f, &s->prev_level);
- qemu_get_be16s(f, &s->mcr);
- qemu_get_be16s(f, &s->cdr);
- qemu_get_be16s(f, &s->ccr);
- qemu_get_be16s(f, &s->irr);
- qemu_get_be16s(f, &s->imr);
- qemu_get_be16s(f, &s->isr);
- if (version_id < 1)
- qemu_get_be16s(f, &dummy);
-
- return 0;
+ return version_id == 0;
}
-ScoopInfo *scoop_init(PXA2xxState *cpu,
- int instance,
- target_phys_addr_t target_base) {
- int iomemtype;
- ScoopInfo *s;
- s = (ScoopInfo *)
- qemu_mallocz(sizeof(ScoopInfo));
- memset(s, 0, sizeof(ScoopInfo));
+static const VMStateDescription vmstate_scoop_regs = {
+ .name = "scoop",
+ .version_id = 1,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT16(status, ScoopInfo),
+ VMSTATE_UINT16(power, ScoopInfo),
+ VMSTATE_UINT32(gpio_level, ScoopInfo),
+ VMSTATE_UINT32(gpio_dir, ScoopInfo),
+ VMSTATE_UINT32(prev_level, ScoopInfo),
+ VMSTATE_UINT16(mcr, ScoopInfo),
+ VMSTATE_UINT16(cdr, ScoopInfo),
+ VMSTATE_UINT16(ccr, ScoopInfo),
+ VMSTATE_UINT16(irr, ScoopInfo),
+ VMSTATE_UINT16(imr, ScoopInfo),
+ VMSTATE_UINT16(isr, ScoopInfo),
+ VMSTATE_UNUSED_TEST(is_version_0, 2),
+ VMSTATE_END_OF_LIST(),
+ },
+};
- s->status = 0x02;
- s->in = qemu_allocate_irqs(scoop_gpio_set, s, 16);
- iomemtype = cpu_register_io_memory(scoop_readfn,
- scoop_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(target_base, 0x1000, iomemtype);
- register_savevm(NULL, "scoop", instance, 1, scoop_save, scoop_load, s);
+static SysBusDeviceInfo scoop_sysbus_info = {
+ .init = scoop_init,
+ .qdev.name = "scoop",
+ .qdev.desc = "Scoop2 Sharp custom ASIC",
+ .qdev.size = sizeof(ScoopInfo),
+ .qdev.vmsd = &vmstate_scoop_regs,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
- return s;
+static void scoop_register(void)
+{
+ sysbus_register_withprop(&scoop_sysbus_info);
}
+device_init(scoop_register);
/* Write the bootloader parameters memory area. */
diff --git a/kvm-all.c b/kvm-all.c
index 255b6fad9c..8f0e17cbf3 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -449,10 +449,14 @@ int kvm_check_extension(KVMState *s, unsigned int extension)
static int kvm_check_many_ioeventfds(void)
{
- /* Older kernels have a 6 device limit on the KVM io bus. Find out so we
+ /* Userspace can use ioeventfd for io notification. This requires a host
+ * that supports eventfd(2) and an I/O thread; since eventfd does not
+ * support SIGIO it cannot interrupt the vcpu.
+ *
+ * Older kernels have a 6 device limit on the KVM io bus. Find out so we
* can avoid creating too many ioeventfds.
*/
-#ifdef CONFIG_EVENTFD
+#if defined(CONFIG_EVENTFD) && defined(CONFIG_IOTHREAD)
int ioeventfds[7];
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(ioeventfds); i++) {
diff --git a/linux-user/arm/nwfpe/fpa11.h b/linux-user/arm/nwfpe/fpa11.h
index 07419e266b..f17647bdb9 100644
--- a/linux-user/arm/nwfpe/fpa11.h
+++ b/linux-user/arm/nwfpe/fpa11.h
@@ -89,9 +89,9 @@ typedef struct tagFPA11 {
extern FPA11* qemufpa;
-extern void resetFPA11(void);
-extern void SetRoundingMode(const unsigned int);
-extern void SetRoundingPrecision(const unsigned int);
+void resetFPA11(void);
+void SetRoundingMode(const unsigned int);
+void SetRoundingPrecision(const unsigned int);
static inline unsigned int readRegister(unsigned int reg)
{
diff --git a/linux-user/arm/nwfpe/fpopcode.h b/linux-user/arm/nwfpe/fpopcode.h
index 16fa34afbf..e7d100941c 100644
--- a/linux-user/arm/nwfpe/fpopcode.h
+++ b/linux-user/arm/nwfpe/fpopcode.h
@@ -384,7 +384,7 @@ static inline float32 getSingleConstant(const unsigned int nIndex)
return float32Constant[nIndex];
}
-extern unsigned int getRegisterCount(const unsigned int opcode);
-extern unsigned int getDestinationSize(const unsigned int opcode);
+unsigned int getRegisterCount(const unsigned int opcode);
+unsigned int getDestinationSize(const unsigned int opcode);
#endif
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/monitor.c b/monitor.c
index f2580007f2..c5f54f46c7 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;
@@ -2509,8 +2509,9 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
nchannels = has_channels ? nchannels : 2;
if (wav_start_capture (s, path, freq, bits, nchannels)) {
- monitor_printf(mon, "Faied to add wave capture\n");
+ monitor_printf(mon, "Failed to add wave capture\n");
qemu_free (s);
+ return;
}
QLIST_INSERT_HEAD (&capture_head, s, entries);
}
@@ -4162,7 +4163,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
break;
case 'o':
{
- ssize_t val;
+ int64_t val;
char *end;
while (qemu_isspace(*p)) {
diff --git a/pc-bios/README b/pc-bios/README
index 4b019e08a1..3fc09449fa 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -11,7 +11,7 @@
firmware implementation. The goal is to implement a 100% IEEE
1275-1994 (referred to as Open Firmware) compliant firmware.
The included image for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32
- and Sparc64 are built from OpenBIOS SVN revision 859.
+ and Sparc64 are built from OpenBIOS SVN revision 1018.
- The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0
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/openbios-ppc b/pc-bios/openbios-ppc
index cb0af05575..ee6f5ae3b9 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index aaff1f00c9..b2dc5c5e7b 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index a1b692e7e5..70a223d573 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
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-common.h b/qemu-common.h
index 63d9943609..c7ff280b95 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -90,7 +90,7 @@ typedef int (*fprintf_function)(FILE *f, const char *fmt, ...)
#ifdef _WIN32
#define fsync _commit
#define lseek _lseeki64
-extern int qemu_ftruncate64(int, int64_t);
+int qemu_ftruncate64(int, int64_t);
#define ftruncate qemu_ftruncate64
static inline char *realpath(const char *path, char *resolved_path)
@@ -153,13 +153,20 @@ int qemu_fls(int i);
int qemu_fdatasync(int fd);
int fcntl_setfl(int fd, int flag);
+/*
+ * strtosz() suffixes used to specify the default treatment of an
+ * argument passed to strtosz() without an explicit suffix.
+ * These should be defined using upper case characters in the range
+ * A-Z, as strtosz() will use qemu_toupper() on the given argument
+ * prior to comparison.
+ */
#define STRTOSZ_DEFSUFFIX_TB 'T'
#define STRTOSZ_DEFSUFFIX_GB 'G'
#define STRTOSZ_DEFSUFFIX_MB 'M'
#define STRTOSZ_DEFSUFFIX_KB 'K'
#define STRTOSZ_DEFSUFFIX_B 'B'
-ssize_t strtosz(const char *nptr, char **end);
-ssize_t strtosz_suffix(const char *nptr, char **end, const char default_suffix);
+int64_t strtosz(const char *nptr, char **end);
+int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix);
/* path.c */
void init_paths(const char *prefix);
@@ -267,12 +274,6 @@ typedef struct VirtIODevice VirtIODevice;
typedef uint64_t pcibus_t;
-typedef enum {
- IF_NONE,
- IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
- IF_COUNT
-} BlockInterfaceType;
-
void cpu_exec_init_all(unsigned long tb_size);
/* CPU save/load. */
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-img.c b/qemu-img.c
index afd9ed2e0e..4a3735811c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -320,7 +320,7 @@ static int img_create(int argc, char **argv)
/* Get image size, if specified */
if (optind < argc) {
- ssize_t sval;
+ int64_t sval;
sval = strtosz_suffix(argv[optind++], NULL, STRTOSZ_DEFSUFFIX_B);
if (sval < 0) {
error_report("Invalid image size specified! You may use k, M, G or "
@@ -1068,7 +1068,7 @@ static int img_snapshot(int argc, char **argv)
int action = 0;
qemu_timeval tv;
- bdrv_oflags = BDRV_O_RDWR;
+ bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
/* Parse commandline parameters */
for(;;) {
c = getopt(argc, argv, "la:c:d:h");
diff --git a/qemu-img.texi b/qemu-img.texi
index 1b90ddbcfc..ced64a40ed 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -59,6 +59,13 @@ lists all snapshots in the given image
Command description:
@table @option
+@item check [-f @var{fmt}] @var{filename}
+
+Perform a consistency check on the disk image @var{filename}.
+
+Only the formats @code{qcow2}, @code{qed} and @code{vdi} support
+consistency checks.
+
@item create [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
Create the new disk image @var{filename} of size @var{size} and format
@@ -107,6 +114,40 @@ they are displayed too.
List, apply, create or delete snapshots in image @var{filename}.
+@item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
+
+Changes the backing file of an image. Only the formats @code{qcow2} and
+@code{qed} support changing the backing file.
+
+The backing file is changed to @var{backing_file} and (if the image format of
+@var{filename} supports this) the backing file format is changed to
+@var{backing_fmt}.
+
+There are two different modes in which @code{rebase} can operate:
+@table @option
+@item Safe mode
+This is the default mode and performs a real rebase operation. The new backing
+file may differ from the old one and qemu-img rebase will take care of keeping
+the guest-visible content of @var{filename} unchanged.
+
+In order to achieve this, any clusters that differ between @var{backing_file}
+and the old backing file of @var{filename} are merged into @var{filename}
+before actually changing the backing file.
+
+Note that the safe mode is an expensive operation, comparable to converting
+an image. It only works if the old backing file still exists.
+
+@item Unsafe mode
+qemu-img uses the unsafe mode if @code{-u} is specified. In this mode, only the
+backing file name and format of @var{filename} is changed without any checks
+on the file contents. The user must take care of specifying the correct new
+backing file, or the guest-visible content of the image will be corrupted.
+
+This mode is useful for renaming or moving the backing file to somewhere else.
+It can be used without an accessible old backing file, i.e. you can use it to
+fix an image whose backing file has already been moved/renamed.
+@end table
+
@item resize @var{filename} [+ | -]@var{size}
Change the disk image as if it had been created with @var{size}.
diff --git a/qemu-io.c b/qemu-io.c
index 65dee13731..4470e49bc8 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;
@@ -1463,7 +1465,7 @@ discard_f(int argc, char **argv)
}
gettimeofday(&t1, NULL);
- ret = bdrv_discard(bs, offset, count);
+ ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, count >> BDRV_SECTOR_BITS);
gettimeofday(&t2, NULL);
if (ret < 0) {
diff --git a/qemu-timer.c b/qemu-timer.c
index 95814af798..db1ec49b3f 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -110,7 +110,6 @@ static int64_t cpu_get_clock(void)
}
}
-#ifndef CONFIG_IOTHREAD
static int64_t qemu_icount_delta(void)
{
if (!use_icount) {
@@ -124,7 +123,6 @@ static int64_t qemu_icount_delta(void)
return cpu_get_icount() - cpu_get_clock();
}
}
-#endif
/* enable cpu_get_ticks() */
void cpu_enable_ticks(void)
@@ -1077,9 +1075,17 @@ void quit_timers(void)
int qemu_calculate_timeout(void)
{
-#ifndef CONFIG_IOTHREAD
int timeout;
+#ifdef CONFIG_IOTHREAD
+ /* When using icount, making forward progress with qemu_icount when the
+ guest CPU is idle is critical. We only use the static io-thread timeout
+ for non icount runs. */
+ if (!use_icount) {
+ return 1000;
+ }
+#endif
+
if (!vm_running)
timeout = 5000;
else {
@@ -1110,8 +1116,5 @@ int qemu_calculate_timeout(void)
}
return timeout;
-#else /* CONFIG_IOTHREAD */
- return 1000;
-#endif
}
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 56c4d8bc47..9f79f5fdf2 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -601,6 +601,34 @@ Example:
-> { "execute": "netdev_del", "arguments": { "id": "netdev1" } }
<- { "return": {} }
+
+EQMP
+
+ {
+ .name = "block_resize",
+ .args_type = "device:B,size:o",
+ .params = "device size",
+ .help = "resize a block image",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_block_resize,
+ },
+
+SQMP
+block_resize
+------------
+
+Resize a block image while a guest is running.
+
+Arguments:
+
+- "device": the device's ID, must be unique (json-string)
+- "size": new size
+
+Example:
+
+-> { "execute": "block_resize", "arguments": { "device": "scratch", "size": 1073741824 } }
+<- { "return": {} }
+
EQMP
{
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 fcd8db4f85..4453217205 100644
--- a/savevm.c
+++ b/savevm.c
@@ -78,7 +78,6 @@
#include "sysemu.h"
#include "qemu-timer.h"
#include "qemu-char.h"
-#include "blockdev.h"
#include "audio/audio.h"
#include "migration.h"
#include "qemu_socket.h"
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
new file mode 100755
index 0000000000..4fa06c002e
--- /dev/null
+++ b/scripts/checkpatch.pl
@@ -0,0 +1,2910 @@
+#!/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/ &&
+ $line !~ /\#\s*else/) {
+ 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..b62da8a0bd 100644
--- a/feature_to_c.sh
+++ b/scripts/feature_to_c.sh
@@ -36,6 +36,9 @@ for input; do
arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'`
${AWK:-awk} 'BEGIN { n = 0
+ printf "#include \"config.h\"\n"
+ printf "#include \"qemu-common.h\"\n"
+ printf "#include \"gdbstub.h\"\n"
print "static const char '$arrayname'[] = {"
for (i = 0; i < 255; i++)
_ord_[sprintf("%c", i)] = i
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..e04668322d 100755
--- a/tracetool
+++ b/scripts/tracetool
@@ -13,12 +13,13 @@ set -f
usage()
{
cat >&2 <<EOF
-usage: $0 [--nop | --simple | --ust] [-h | -c]
+usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
Generate tracing code for a file on stdin.
Backends:
--nop Tracing disabled
--simple Simple built-in backend
+ --stderr Stderr built-in backend
--ust LTTng User Space Tracing backend
--dtrace DTrace/SystemTAP backend
@@ -236,6 +237,56 @@ linetoc_end_simple()
EOF
}
+#STDERR
+linetoh_begin_stderr()
+{
+ cat <<EOF
+#include <stdio.h>
+EOF
+}
+
+linetoh_stderr()
+{
+ local name args argnames argc fmt
+ name=$(get_name "$1")
+ args=$(get_args "$1")
+ argnames=$(get_argnames "$1" ",")
+ argc=$(get_argc "$1")
+ fmt=$(get_fmt "$1")
+
+ if [ "$argc" -gt 0 ]; then
+ argnames=", $argnames"
+ fi
+
+ cat <<EOF
+static inline void trace_$name($args)
+{
+ fprintf(stderr, "$name $fmt\n" $argnames);
+}
+EOF
+}
+
+linetoh_end_stderr()
+{
+return
+}
+
+linetoc_begin_stderr()
+{
+return
+}
+
+linetoc_stderr()
+{
+return
+}
+
+linetoc_end_stderr()
+{
+return
+}
+#END OF STDERR
+
# Clean up after UST headers which pollute the namespace
ust_clean_namespace() {
cat <<EOF
@@ -546,7 +597,7 @@ targetarch=
until [ -z "$1" ]
do
case "$1" in
- "--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
+ "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
"--binary") shift ; binary="$1" ;;
"--target-arch") shift ; targetarch="$1" ;;
@@ -557,6 +608,11 @@ do
"--check-backend") exit 0 ;; # used by ./configure to test for backend
+ "--list-backends") # used by ./configure to list available backends
+ echo "nop simple stderr ust dtrace"
+ exit 0
+ ;;
+
*)
usage;;
esac
diff --git a/slirp/slirp.h b/slirp/slirp.h
index dfd977aa0c..954289a8c8 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -238,7 +238,7 @@ void if_start(struct ttys *);
#endif
#ifndef HAVE_STRERROR
- extern char *strerror(int error);
+ char *strerror(int error);
#endif
#ifndef HAVE_INDEX
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 0c969f22b9..23ae17e2e9 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -178,21 +178,6 @@ extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
-#ifdef HAS_AUDIO
-struct soundhw {
- const char *name;
- const char *descr;
- int enabled;
- int isa;
- union {
- int (*init_isa) (qemu_irq *pic);
- int (*init_pci) (PCIBus *bus);
- } init;
-};
-
-extern struct soundhw soundhw[];
-#endif
-
void do_usb_add(Monitor *mon, const QDict *qdict);
void do_usb_del(Monitor *mon, const QDict *qdict);
void usb_info(Monitor *mon);
diff --git a/target-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..fead1525c4 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 { \
@@ -833,8 +880,9 @@ uint32_t HELPER(neon_cnt_u8)(uint32_t x)
if ((tmp ^ (tmp << 1)) & SIGNBIT) { \
SET_QC(); \
tmp = (tmp >> 31) ^ ~SIGNBIT; \
+ } else { \
+ tmp <<= 1; \
} \
- tmp <<= 1; \
if (round) { \
int32_t old = tmp; \
tmp += 1 << 15; \
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 2ce82f3bbb..d95133f725 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) {
@@ -3601,14 +3608,14 @@ static inline TCGv neon_get_scalar(int size, int reg)
{
TCGv tmp;
if (size == 1) {
- tmp = neon_load_reg(reg >> 1, reg & 1);
- } else {
- tmp = neon_load_reg(reg >> 2, (reg >> 1) & 1);
- if (reg & 1) {
- gen_neon_dup_low16(tmp);
- } else {
+ tmp = neon_load_reg(reg & 7, reg >> 4);
+ if (reg & 8) {
gen_neon_dup_high16(tmp);
+ } else {
+ gen_neon_dup_low16(tmp);
}
+ } else {
+ tmp = neon_load_reg(reg & 15, reg >> 4);
}
return tmp;
}
@@ -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;
@@ -4176,6 +4183,13 @@ static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
break;
default: abort();
}
+
+ /* gen_helper_neon_mull_[su]{8|16} do not free their parameters.
+ Don't forget to clean them now. */
+ if (size < 2) {
+ dead_tmp(a);
+ dead_tmp(b);
+ }
}
/* Translate a NEON data processing instruction. Return nonzero if the
@@ -4199,7 +4213,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 +4666,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 +4720,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);
@@ -4819,7 +4854,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (size == 3) {
tcg_temp_free_i64(tmp64);
} else {
- dead_tmp(tmp2);
+ tcg_temp_free_i32(tmp2);
}
} else if (op == 10) {
/* VSHLL */
@@ -5055,8 +5090,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 8: case 9: case 10: case 11: case 12: case 13:
/* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
- dead_tmp(tmp2);
- dead_tmp(tmp);
break;
case 14: /* Polynomial VMULL */
cpu_abort(env, "Polynomial VMULL not implemented");
@@ -5207,6 +5240,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
return 1;
tmp2 = neon_get_scalar(size, rm);
+ /* We need a copy of tmp2 because gen_neon_mull
+ * deletes it during pass 0. */
+ tmp4 = new_tmp();
+ tcg_gen_mov_i32(tmp4, tmp2);
tmp3 = neon_load_reg(rn, 1);
for (pass = 0; pass < 2; pass++) {
@@ -5214,9 +5251,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
tmp = neon_load_reg(rn, 0);
} else {
tmp = tmp3;
+ tmp2 = tmp4;
}
gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
- dead_tmp(tmp);
if (op == 6 || op == 7) {
gen_neon_negl(cpu_V0, size);
}
@@ -5243,7 +5280,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
neon_store_reg64(cpu_V0, rd + pass);
}
- dead_tmp(tmp2);
break;
default: /* 14 and 15 are RESERVED */
@@ -5958,10 +5994,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 +6134,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 +6164,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 +6391,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:
@@ -6874,27 +6896,23 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
tcg_gen_shli_i32(tmp, tmp, shift);
}
sh = (insn >> 16) & 0x1f;
- if (sh != 0) {
- tmp2 = tcg_const_i32(sh);
- if (insn & (1 << 22))
- gen_helper_usat(tmp, tmp, tmp2);
- else
- gen_helper_ssat(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
+ tmp2 = tcg_const_i32(sh);
+ if (insn & (1 << 22))
+ gen_helper_usat(tmp, tmp, tmp2);
+ else
+ gen_helper_ssat(tmp, tmp, tmp2);
+ tcg_temp_free_i32(tmp2);
store_reg(s, rd, tmp);
} else if ((insn & 0x00300fe0) == 0x00200f20) {
/* [us]sat16 */
tmp = load_reg(s, rm);
sh = (insn >> 16) & 0x1f;
- if (sh != 0) {
- tmp2 = tcg_const_i32(sh);
- if (insn & (1 << 22))
- gen_helper_usat16(tmp, tmp, tmp2);
- else
- gen_helper_ssat16(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
+ tmp2 = tcg_const_i32(sh);
+ if (insn & (1 << 22))
+ gen_helper_usat16(tmp, tmp, tmp2);
+ else
+ gen_helper_ssat16(tmp, tmp, tmp2);
+ tcg_temp_free_i32(tmp2);
store_reg(s, rd, tmp);
} else if ((insn & 0x00700fe0) == 0x00000fa0) {
/* Select bytes. */
@@ -7268,10 +7286,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 +7569,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 +7588,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 +8932,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 +9018,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 +9054,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 +9090,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 +9115,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 +9178,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 +9195,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 +9203,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 +9321,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 +9407,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..b4648a01de 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -947,15 +947,8 @@ static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
case CC_EQ:
if ((arith_opt || move_opt)
&& dc->cc_x_uptodate != (2 | X_FLAG)) {
- /* If cc_result is zero, T0 should be
- non-zero otherwise T0 should be zero. */
- int l1;
- l1 = gen_new_label();
- tcg_gen_movi_tl(cc, 0);
- tcg_gen_brcondi_tl(TCG_COND_NE, cc_result,
- 0, l1);
- tcg_gen_movi_tl(cc, 1);
- gen_set_label(l1);
+ tcg_gen_setcond_tl(TCG_COND_EQ, cc,
+ cc_result, tcg_const_tl(0));
}
else {
cris_evaluate_flags(dc);
@@ -1129,6 +1122,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/helper.h b/target-microblaze/helper.h
index 11ad1b6dcb..1696b885b6 100644
--- a/target-microblaze/helper.h
+++ b/target-microblaze/helper.h
@@ -2,8 +2,7 @@
DEF_HELPER_1(raise_exception, void, i32)
DEF_HELPER_0(debug, void)
-DEF_HELPER_4(addkc, i32, i32, i32, i32, i32)
-DEF_HELPER_4(subkc, i32, i32, i32, i32, i32)
+DEF_HELPER_FLAGS_3(carry, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32, i32)
DEF_HELPER_2(cmp, i32, i32, i32)
DEF_HELPER_2(cmpu, i32, i32, i32)
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index 97461aed6e..d75a53cc54 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -128,48 +128,11 @@ uint32_t helper_cmpu(uint32_t a, uint32_t b)
return t;
}
-uint32_t helper_addkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c)
+uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf)
{
- uint32_t d, cf = 0, ncf;
-
- if (c)
- cf = env->sregs[SR_MSR] >> 31;
- assert(cf == 0 || cf == 1);
- d = a + b + cf;
-
- if (!k) {
- ncf = compute_carry(a, b, cf);
- assert(ncf == 0 || ncf == 1);
- if (ncf)
- env->sregs[SR_MSR] |= MSR_C | MSR_CC;
- else
- env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC);
- }
- D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n",
- d, a, b, cf, ncf, k, c));
- return d;
-}
-
-uint32_t helper_subkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c)
-{
- uint32_t d, cf = 1, ncf;
-
- if (c)
- cf = env->sregs[SR_MSR] >> 31;
- assert(cf == 0 || cf == 1);
- d = b + ~a + cf;
-
- if (!k) {
- ncf = compute_carry(b, ~a, cf);
- assert(ncf == 0 || ncf == 1);
- if (ncf)
- env->sregs[SR_MSR] |= MSR_C | MSR_CC;
- else
- env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC);
- }
- D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n",
- d, a, b, cf, ncf, k, c));
- return d;
+ uint32_t ncf;
+ ncf = compute_carry(a, b, cf);
+ return ncf;
}
static inline int div_prepare(uint32_t a, uint32_t b)
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index c018c99826..220743195c 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;
@@ -152,6 +153,23 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
}
}
+static void read_carry(DisasContext *dc, TCGv d)
+{
+ tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
+}
+
+static void write_carry(DisasContext *dc, TCGv v)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_shli_tl(t0, v, 31);
+ tcg_gen_sari_tl(t0, t0, 31);
+ tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
+ tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
+ ~(MSR_C | MSR_CC));
+ tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
+ tcg_temp_free(t0);
+}
+
/* True if ALU operand b is a small immediate that may deserve
faster treatment. */
static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
@@ -175,6 +193,7 @@ static inline TCGv *dec_alu_op_b(DisasContext *dc)
static void dec_add(DisasContext *dc)
{
unsigned int k, c;
+ TCGv cf;
k = dc->opcode & 4;
c = dc->opcode & 2;
@@ -183,22 +202,52 @@ static void dec_add(DisasContext *dc)
dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "",
dc->rd, dc->ra, dc->rb);
- if (k && !c && dc->rd)
+ /* Take care of the easy cases first. */
+ if (k) {
+ /* k - keep carry, no need to update MSR. */
+ /* If rd == r0, it's a nop. */
+ if (dc->rd) {
+ tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+
+ if (c) {
+ /* c - Add carry into the result. */
+ cf = tcg_temp_new();
+
+ read_carry(dc, cf);
+ tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ tcg_temp_free(cf);
+ }
+ }
+ return;
+ }
+
+ /* From now on, we can assume k is zero. So we need to update MSR. */
+ /* Extract carry. */
+ cf = tcg_temp_new();
+ if (c) {
+ read_carry(dc, cf);
+ } else {
+ tcg_gen_movi_tl(cf, 0);
+ }
+
+ if (dc->rd) {
+ TCGv ncf = tcg_temp_new();
+ gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
- else if (dc->rd)
- gen_helper_addkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)),
- tcg_const_tl(k), tcg_const_tl(c));
- else {
- TCGv d = tcg_temp_new();
- gen_helper_addkc(d, cpu_R[dc->ra], *(dec_alu_op_b(dc)),
- tcg_const_tl(k), tcg_const_tl(c));
- tcg_temp_free(d);
+ tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ write_carry(dc, ncf);
+ tcg_temp_free(ncf);
+ } else {
+ gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
+ write_carry(dc, cf);
}
+ tcg_temp_free(cf);
}
static void dec_sub(DisasContext *dc)
{
unsigned int u, cmp, k, c;
+ TCGv cf, na;
u = dc->imm & 2;
k = dc->opcode & 4;
@@ -213,24 +262,57 @@ static void dec_sub(DisasContext *dc)
else
gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
}
- } else {
- LOG_DIS("sub%s%s r%d, r%d r%d\n",
- k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb);
+ return;
+ }
- if (!k || c) {
- TCGv t;
- t = tcg_temp_new();
- if (dc->rd)
- gen_helper_subkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)),
- tcg_const_tl(k), tcg_const_tl(c));
- else
- gen_helper_subkc(t, cpu_R[dc->ra], *(dec_alu_op_b(dc)),
- tcg_const_tl(k), tcg_const_tl(c));
- tcg_temp_free(t);
- }
- else if (dc->rd)
+ LOG_DIS("sub%s%s r%d, r%d r%d\n",
+ k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb);
+
+ /* Take care of the easy cases first. */
+ if (k) {
+ /* k - keep carry, no need to update MSR. */
+ /* If rd == r0, it's a nop. */
+ if (dc->rd) {
tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+
+ if (c) {
+ /* c - Add carry into the result. */
+ cf = tcg_temp_new();
+
+ read_carry(dc, cf);
+ tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ tcg_temp_free(cf);
+ }
+ }
+ return;
+ }
+
+ /* From now on, we can assume k is zero. So we need to update MSR. */
+ /* Extract carry. And complement a into na. */
+ cf = tcg_temp_new();
+ na = tcg_temp_new();
+ if (c) {
+ read_carry(dc, cf);
+ } else {
+ tcg_gen_movi_tl(cf, 1);
}
+
+ /* d = b + ~a + c. carry defaults to 1. */
+ tcg_gen_not_tl(na, cpu_R[dc->ra]);
+
+ if (dc->rd) {
+ TCGv ncf = tcg_temp_new();
+ gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
+ tcg_gen_add_tl(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
+ tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ write_carry(dc, ncf);
+ tcg_temp_free(ncf);
+ } else {
+ gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
+ write_carry(dc, cf);
+ }
+ tcg_temp_free(cf);
+ tcg_temp_free(na);
}
static void dec_pattern(DisasContext *dc)
@@ -336,25 +418,6 @@ static void dec_xor(DisasContext *dc)
tcg_gen_xor_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
}
-static void read_carry(DisasContext *dc, TCGv d)
-{
- tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
-}
-
-static void write_carry(DisasContext *dc, TCGv v)
-{
- TCGv t0 = tcg_temp_new();
- tcg_gen_shli_tl(t0, v, 31);
- tcg_gen_sari_tl(t0, t0, 31);
- tcg_gen_mov_tl(env_debug, t0);
- tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
- tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
- ~(MSR_C | MSR_CC));
- tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
- tcg_temp_free(t0);
-}
-
-
static inline void msr_read(DisasContext *dc, TCGv d)
{
tcg_gen_mov_tl(d, cpu_SR[SR_MSR]);
@@ -751,7 +814,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 +850,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 +879,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 +915,62 @@ 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_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 +989,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 +1031,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 +1045,83 @@ 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_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 +1192,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 +1246,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 +1667,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 +1695,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..0f93e2abb1 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1066,7 +1066,7 @@ static void gen_ld (CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "ld";
break;
case OPC_LLD:
- save_cpu_state(ctx, 0);
+ save_cpu_state(ctx, 1);
op_ld_lld(t0, t0, ctx);
gen_store_gpr(t0, rt);
opn = "lld";
@@ -1086,7 +1086,7 @@ static void gen_ld (CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "ldr";
break;
case OPC_LDPC:
- save_cpu_state(ctx, 1);
+ save_cpu_state(ctx, 0);
tcg_gen_movi_tl(t1, pc_relative_pc(ctx));
gen_op_addr_add(ctx, t0, t0, t1);
op_ld_ld(t0, t0, ctx);
@@ -1095,7 +1095,7 @@ static void gen_ld (CPUState *env, DisasContext *ctx, uint32_t opc,
break;
#endif
case OPC_LWPC:
- save_cpu_state(ctx, 1);
+ save_cpu_state(ctx, 0);
tcg_gen_movi_tl(t1, pc_relative_pc(ctx));
gen_op_addr_add(ctx, t0, t0, t1);
op_ld_lw(t0, t0, ctx);
@@ -1238,7 +1238,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
switch (opc) {
#if defined(TARGET_MIPS64)
case OPC_SCD:
- save_cpu_state(ctx, 0);
+ save_cpu_state(ctx, 1);
op_st_scd(t1, t0, rt, ctx);
opn = "scd";
break;
@@ -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 */
@@ -9967,7 +9971,7 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
opn = "lwp";
break;
case SWP:
- save_cpu_state(ctx, 1);
+ save_cpu_state(ctx, 0);
gen_load_gpr(t1, rd);
op_st_sw(t1, t0, ctx);
tcg_gen_movi_tl(t1, 4);
@@ -9988,7 +9992,7 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
opn = "ldp";
break;
case SDP:
- save_cpu_state(ctx, 1);
+ save_cpu_state(ctx, 0);
gen_load_gpr(t1, rd);
op_st_sd(t1, t0, ctx);
tcg_gen_movi_tl(t1, 8);
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-ppc/translate.c b/target-ppc/translate.c
index 74e06d733d..89413c5395 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -5874,7 +5874,7 @@ static void gen_tlbre_440(DisasContext *ctx)
case 2:
{
TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
- gen_helper_440_tlbwe(t0, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+ gen_helper_440_tlbre(cpu_gpr[rD(ctx->opcode)], t0, cpu_gpr[rA(ctx->opcode)]);
tcg_temp_free_i32(t0);
}
break;
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 8d73fad360..e47c372fbd 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -105,9 +105,9 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw
#define TARGET_VIRT_ADDR_SPACE_BITS 32
#ifndef CONFIG_USER_ONLY
-extern int s390_virtio_hypercall(CPUState *env);
-extern void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token);
-extern CPUState *s390_cpu_addr2state(uint16_t cpu_addr);
+int s390_virtio_hypercall(CPUState *env);
+void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token);
+CPUState *s390_cpu_addr2state(uint16_t cpu_addr);
#endif
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index 8ccf25cafb..789d1880b7 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;
@@ -172,10 +201,22 @@ void do_interrupt(CPUSH4State * env);
void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf);
#if !defined(CONFIG_USER_ONLY)
void cpu_sh4_invalidate_tlb(CPUSH4State *s);
+uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
+ target_phys_addr_t addr);
void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
- uint32_t mem_value);
+ uint32_t mem_value);
+uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s,
+ target_phys_addr_t addr);
+void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, target_phys_addr_t addr,
+ uint32_t mem_value);
+uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s,
+ target_phys_addr_t addr);
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
- uint32_t mem_value);
+ uint32_t mem_value);
+uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s,
+ target_phys_addr_t addr);
+void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, target_phys_addr_t addr,
+ uint32_t mem_value);
#endif
int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr);
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index 2343366762..d2038bd842 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;
@@ -453,6 +453,10 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
if (ret != MMU_OK) {
env->tea = address;
+ if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) {
+ env->pteh = (env->pteh & PTEH_ASID_MASK) |
+ (address & PTEH_VPN_MASK);
+ }
switch (ret) {
case MMU_ITLB_MISS:
case MMU_DTLB_MISS_READ:
@@ -479,7 +483,7 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
break;
case MMU_IADDR_ERROR:
case MMU_DADDR_ERROR_READ:
- env->exception_index = 0x0c0;
+ env->exception_index = 0x0e0;
break;
case MMU_DADDR_ERROR_WRITE:
env->exception_index = 0x100;
@@ -559,14 +563,25 @@ void cpu_load_tlb(CPUSH4State * env)
entry->v = 0;
}
/* ITLB */
- for (i = 0; i < UTLB_SIZE; i++) {
- tlb_t * entry = &s->utlb[i];
+ for (i = 0; i < ITLB_SIZE; i++) {
+ tlb_t * entry = &s->itlb[i];
entry->v = 0;
}
tlb_flush(s, 1);
}
+uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
+ target_phys_addr_t addr)
+{
+ int index = (addr & 0x00000300) >> 8;
+ tlb_t * entry = &s->itlb[index];
+
+ return (entry->vpn << 10) |
+ (entry->v << 8) |
+ (entry->asid);
+}
+
void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
uint32_t mem_value)
{
@@ -574,7 +589,7 @@ void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
- int index = (addr & 0x00003f00) >> 8;
+ int index = (addr & 0x00000300) >> 8;
tlb_t * entry = &s->itlb[index];
if (entry->v) {
/* Overwriting valid entry in itlb. */
@@ -586,6 +601,70 @@ void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
entry->v = v;
}
+uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s,
+ target_phys_addr_t addr)
+{
+ int array = (addr & 0x00800000) >> 23;
+ int index = (addr & 0x00000300) >> 8;
+ tlb_t * entry = &s->itlb[index];
+
+ if (array == 0) {
+ /* ITLB Data Array 1 */
+ return (entry->ppn << 10) |
+ (entry->v << 8) |
+ (entry->pr << 5) |
+ ((entry->sz & 1) << 6) |
+ ((entry->sz & 2) << 4) |
+ (entry->c << 3) |
+ (entry->sh << 1);
+ } else {
+ /* ITLB Data Array 2 */
+ return (entry->tc << 1) |
+ (entry->sa);
+ }
+}
+
+void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, target_phys_addr_t addr,
+ uint32_t mem_value)
+{
+ int array = (addr & 0x00800000) >> 23;
+ int index = (addr & 0x00000300) >> 8;
+ tlb_t * entry = &s->itlb[index];
+
+ if (array == 0) {
+ /* ITLB Data Array 1 */
+ if (entry->v) {
+ /* Overwriting valid entry in utlb. */
+ target_ulong address = entry->vpn << 10;
+ tlb_flush_page(s, address);
+ }
+ entry->ppn = (mem_value & 0x1ffffc00) >> 10;
+ entry->v = (mem_value & 0x00000100) >> 8;
+ entry->sz = (mem_value & 0x00000080) >> 6 |
+ (mem_value & 0x00000010) >> 4;
+ entry->pr = (mem_value & 0x00000040) >> 5;
+ entry->c = (mem_value & 0x00000008) >> 3;
+ entry->sh = (mem_value & 0x00000002) >> 1;
+ } else {
+ /* ITLB Data Array 2 */
+ entry->tc = (mem_value & 0x00000008) >> 3;
+ entry->sa = (mem_value & 0x00000007);
+ }
+}
+
+uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s,
+ target_phys_addr_t addr)
+{
+ int index = (addr & 0x00003f00) >> 8;
+ tlb_t * entry = &s->utlb[index];
+
+ increment_urc(s); /* per utlb access */
+
+ return (entry->vpn << 10) |
+ (entry->v << 8) |
+ (entry->asid);
+}
+
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
uint32_t mem_value)
{
@@ -658,6 +737,65 @@ void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
}
}
+uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s,
+ target_phys_addr_t addr)
+{
+ int array = (addr & 0x00800000) >> 23;
+ int index = (addr & 0x00003f00) >> 8;
+ tlb_t * entry = &s->utlb[index];
+
+ increment_urc(s); /* per utlb access */
+
+ if (array == 0) {
+ /* ITLB Data Array 1 */
+ return (entry->ppn << 10) |
+ (entry->v << 8) |
+ (entry->pr << 5) |
+ ((entry->sz & 1) << 6) |
+ ((entry->sz & 2) << 4) |
+ (entry->c << 3) |
+ (entry->d << 2) |
+ (entry->sh << 1) |
+ (entry->wt);
+ } else {
+ /* ITLB Data Array 2 */
+ return (entry->tc << 1) |
+ (entry->sa);
+ }
+}
+
+void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, target_phys_addr_t addr,
+ uint32_t mem_value)
+{
+ int array = (addr & 0x00800000) >> 23;
+ int index = (addr & 0x00003f00) >> 8;
+ tlb_t * entry = &s->utlb[index];
+
+ increment_urc(s); /* per utlb access */
+
+ if (array == 0) {
+ /* UTLB Data Array 1 */
+ if (entry->v) {
+ /* Overwriting valid entry in utlb. */
+ target_ulong address = entry->vpn << 10;
+ tlb_flush_page(s, address);
+ }
+ entry->ppn = (mem_value & 0x1ffffc00) >> 10;
+ entry->v = (mem_value & 0x00000100) >> 8;
+ entry->sz = (mem_value & 0x00000080) >> 6 |
+ (mem_value & 0x00000010) >> 4;
+ entry->pr = (mem_value & 0x00000060) >> 5;
+ entry->c = (mem_value & 0x00000008) >> 3;
+ entry->d = (mem_value & 0x00000004) >> 2;
+ entry->sh = (mem_value & 0x00000002) >> 1;
+ entry->wt = (mem_value & 0x00000001);
+ } else {
+ /* UTLB Data Array 2 */
+ entry->tc = (mem_value & 0x00000008) >> 3;
+ entry->sa = (mem_value & 0x00000007);
+ }
+}
+
int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
{
int n;
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/cpu.h b/target-sparc/cpu.h
index 7225b2ed3c..6f5990b130 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -252,20 +252,22 @@ typedef struct sparc_def_t {
uint32_t maxtl;
} sparc_def_t;
-#define CPU_FEATURE_FLOAT (1 << 0)
-#define CPU_FEATURE_FLOAT128 (1 << 1)
-#define CPU_FEATURE_SWAP (1 << 2)
-#define CPU_FEATURE_MUL (1 << 3)
-#define CPU_FEATURE_DIV (1 << 4)
-#define CPU_FEATURE_FLUSH (1 << 5)
-#define CPU_FEATURE_FSQRT (1 << 6)
-#define CPU_FEATURE_FMUL (1 << 7)
-#define CPU_FEATURE_VIS1 (1 << 8)
-#define CPU_FEATURE_VIS2 (1 << 9)
-#define CPU_FEATURE_FSMULD (1 << 10)
-#define CPU_FEATURE_HYPV (1 << 11)
-#define CPU_FEATURE_CMT (1 << 12)
-#define CPU_FEATURE_GL (1 << 13)
+#define CPU_FEATURE_FLOAT (1 << 0)
+#define CPU_FEATURE_FLOAT128 (1 << 1)
+#define CPU_FEATURE_SWAP (1 << 2)
+#define CPU_FEATURE_MUL (1 << 3)
+#define CPU_FEATURE_DIV (1 << 4)
+#define CPU_FEATURE_FLUSH (1 << 5)
+#define CPU_FEATURE_FSQRT (1 << 6)
+#define CPU_FEATURE_FMUL (1 << 7)
+#define CPU_FEATURE_VIS1 (1 << 8)
+#define CPU_FEATURE_VIS2 (1 << 9)
+#define CPU_FEATURE_FSMULD (1 << 10)
+#define CPU_FEATURE_HYPV (1 << 11)
+#define CPU_FEATURE_CMT (1 << 12)
+#define CPU_FEATURE_GL (1 << 13)
+#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
+#define CPU_FEATURE_ASR17 (1 << 15)
#ifndef TARGET_SPARC64
#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \
CPU_FEATURE_MUL | CPU_FEATURE_DIV | \
@@ -437,6 +439,12 @@ typedef struct CPUSPARCState {
#define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
#endif
sparc_def_t *def;
+
+ void *irq_manager;
+ void (*qemu_irq_ack) (void *irq_manager, int intno);
+
+ /* Leon3 cache control */
+ uint32_t cache_control;
} CPUSPARCState;
#ifndef NO_CPU_IO_DEFS
@@ -469,6 +477,8 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
int cpu_cwp_dec(CPUState *env1, int cwp);
void cpu_set_cwp(CPUState *env1, int new_cwp);
+void leon3_cache_control_int(void);
+
/* sun4m.c, sun4u.c */
void cpu_check_irqs(CPUSPARCState *env);
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 6b337ca091..2f3d1e61f3 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -770,6 +770,7 @@ void cpu_reset(CPUSPARCState *env)
env->pc = 0;
env->npc = env->pc + 4;
#endif
+ env->cache_control = 0;
}
static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
@@ -1274,20 +1275,21 @@ static const sparc_def_t sparc_defs[] = {
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
},
{
.name = "LEON3",
.iu_version = 0xf3000000,
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
.mmu_version = 0xf3000000,
- .mmu_bm = 0x00004000,
+ .mmu_bm = 0x00000000,
.mmu_ctpr_mask = 0x007ffff0,
.mmu_cxr_mask = 0x0000003f,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
+ CPU_FEATURE_ASR17,
},
#endif
};
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index e6d82f9eab..12e8557133 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -85,6 +85,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
DEF_HELPER_0(fcmpeq_fcc3, void)
#endif
DEF_HELPER_1(raise_exception, void, int)
+DEF_HELPER_0(shutdown, void)
#define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
#define F_HELPER_DQ_0_0(name) \
F_HELPER_0_0(name ## d); \
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 58f9f82f52..d3e1b63539 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,6 +1,7 @@
#include "exec.h"
#include "host-utils.h"
#include "helper.h"
+#include "sysemu.h"
//#define DEBUG_MMU
//#define DEBUG_MXCC
@@ -9,6 +10,7 @@
//#define DEBUG_ASI
//#define DEBUG_PCALL
//#define DEBUG_PSTATE
+//#define DEBUG_CACHE_CONTROL
#ifdef DEBUG_MMU
#define DPRINTF_MMU(fmt, ...) \
@@ -36,6 +38,13 @@
#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
#endif
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...) \
+ do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
#ifdef TARGET_SPARC64
#ifndef TARGET_ABI32
#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
@@ -49,6 +58,27 @@
#define QT0 (env->qt0)
#define QT1 (env->qt1)
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+ any effect on the emulated */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED 0x0
+#define CACHE_FROZEN 0x1
+#define CACHE_ENABLED 0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */
+
#if defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
int is_asi, int size);
@@ -294,6 +324,13 @@ void HELPER(raise_exception)(int tt)
raise_exception(tt);
}
+void helper_shutdown(void)
+{
+#if !defined(CONFIG_USER_ONLY)
+ qemu_system_shutdown_request();
+#endif
+}
+
void helper_check_align(target_ulong addr, uint32_t align)
{
if (addr & align) {
@@ -857,65 +894,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);
@@ -1600,6 +1649,103 @@ static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
#ifndef TARGET_SPARC64
#ifndef CONFIG_USER_ONLY
+
+
+/* Leon3 cache control */
+
+void leon3_cache_control_int(void)
+{
+ uint32_t state = 0;
+
+ if (env->cache_control & CACHE_CTRL_IF) {
+ /* Instruction cache state */
+ state = env->cache_control & CACHE_STATE_MASK;
+ if (state == CACHE_ENABLED) {
+ state = CACHE_FROZEN;
+ DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
+ }
+
+ env->cache_control &= ~CACHE_STATE_MASK;
+ env->cache_control |= state;
+ }
+
+ if (env->cache_control & CACHE_CTRL_DF) {
+ /* Data cache state */
+ state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+ if (state == CACHE_ENABLED) {
+ state = CACHE_FROZEN;
+ DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
+ }
+
+ env->cache_control &= ~(CACHE_STATE_MASK << 2);
+ env->cache_control |= (state << 2);
+ }
+}
+
+static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+ DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+ addr, val, size);
+
+ if (size != 4) {
+ DPRINTF_CACHE_CONTROL("32bits only\n");
+ return;
+ }
+
+ switch (addr) {
+ case 0x00: /* Cache control */
+
+ /* These values must always be read as zeros */
+ val &= ~CACHE_CTRL_FD;
+ val &= ~CACHE_CTRL_FI;
+ val &= ~CACHE_CTRL_IB;
+ val &= ~CACHE_CTRL_IP;
+ val &= ~CACHE_CTRL_DP;
+
+ env->cache_control = val;
+ break;
+ case 0x04: /* Instruction cache configuration */
+ case 0x08: /* Data cache configuration */
+ /* Read Only */
+ break;
+ default:
+ DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+ break;
+ };
+}
+
+static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+ uint64_t ret = 0;
+
+ if (size != 4) {
+ DPRINTF_CACHE_CONTROL("32bits only\n");
+ return 0;
+ }
+
+ switch (addr) {
+ case 0x00: /* Cache control */
+ ret = env->cache_control;
+ break;
+
+ /* Configuration registers are read and only always keep those
+ predefined values */
+
+ case 0x04: /* Instruction cache configuration */
+ ret = 0x10220000;
+ break;
+ case 0x08: /* Data cache configuration */
+ ret = 0x18220000;
+ break;
+ default:
+ DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+ break;
+ };
+ DPRINTF_CACHE_CONTROL("st addr:%08x, ret:%" PRIx64 ", size:%d\n",
+ addr, ret, size);
+ return ret;
+}
+
uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
uint64_t ret = 0;
@@ -1609,8 +1755,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
helper_check_align(addr, size - 1);
switch (asi) {
- case 2: /* SuperSparc MXCC registers */
+ case 2: /* SuperSparc MXCC registers and Leon3 cache control */
switch (addr) {
+ case 0x00: /* Leon3 Cache Control */
+ case 0x08: /* Leon3 Instruction Cache config */
+ case 0x0C: /* Leon3 Date Cache config */
+ ret = leon3_cache_control_ld(addr, size);
+ break;
case 0x01c00a00: /* MXCC control register */
if (size == 8)
ret = env->mxccregs[3];
@@ -1838,8 +1989,14 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
{
helper_check_align(addr, size - 1);
switch(asi) {
- case 2: /* SuperSparc MXCC registers */
+ case 2: /* SuperSparc MXCC registers and Leon3 cache control */
switch (addr) {
+ case 0x00: /* Leon3 Cache Control */
+ case 0x08: /* Leon3 Instruction Cache config */
+ case 0x0C: /* Leon3 Date Cache config */
+ leon3_cache_control_st(addr, val, size);
+ break;
+
case 0x01c00000: /* MXCC stream data register 0 */
if (size == 8)
env->mxccdata[0] = val;
@@ -4165,6 +4322,13 @@ void do_interrupt(CPUState *env)
env->pc = env->tbr;
env->npc = env->pc + 4;
env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+ /* IRQ acknowledgment */
+ if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+ env->qemu_irq_ack(env->irq_manager, intno);
+ }
+#endif
}
#endif
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 21c567562e..e26462eef5 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1997,8 +1997,9 @@ static void disas_sparc_insn(DisasContext * dc)
} else
tcg_gen_mov_tl(cpu_dst, cpu_src1);
}
+
cond = GET_FIELD(insn, 3, 6);
- if (cond == 0x8) {
+ if (cond == 0x8) { /* Trap Always */
save_state(dc, cpu_cond);
if ((dc->def->features & CPU_FEATURE_HYPV) &&
supervisor(dc))
@@ -2007,7 +2008,15 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
- gen_helper_raise_exception(cpu_tmp32);
+
+ if (rs2 == 0 &&
+ dc->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
+
+ gen_helper_shutdown();
+
+ } else {
+ gen_helper_raise_exception(cpu_tmp32);
+ }
} else if (cond != 0) {
TCGv r_cond = tcg_temp_new();
int l1;
@@ -2058,6 +2067,17 @@ static void disas_sparc_insn(DisasContext * dc)
case 0x10 ... 0x1f: /* implementation-dependent in the
SPARCv8 manual, rdy on the
microSPARC II */
+ /* Read Asr17 */
+ if (rs1 == 0x11 && dc->def->features & CPU_FEATURE_ASR17) {
+ TCGv r_const;
+
+ /* Read Asr17 for a Leon3 monoprocessor */
+ r_const = tcg_const_tl((1 << 8)
+ | (dc->def->nwindows - 1));
+ gen_movl_TN_reg(rd, r_const);
+ tcg_temp_free(r_const);
+ break;
+ }
#endif
gen_movl_TN_reg(rd, cpu_y);
break;
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/cris/sys.h b/tests/cris/sys.h
index d2ed4ce753..c5f88e1a29 100644
--- a/tests/cris/sys.h
+++ b/tests/cris/sys.h
@@ -12,5 +12,5 @@
#define mb() asm volatile ("" : : : "memory")
-extern void pass(void);
-extern void _fail(char *reason);
+void pass(void);
+void _fail(char *reason);
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/trace-events b/trace-events
index e8fed0f424..c75a7a9824 100644
--- a/trace-events
+++ b/trace-events
@@ -190,6 +190,17 @@ disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "g
disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+# hw/usb-desc.c
+disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
+disable usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
+disable usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
+disable usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
+disable usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
+disable usb_set_addr(int addr) "dev %d"
+disable usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
+disable usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
+disable usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
+
# vl.c
disable vm_state_notify(int running, int reason) "running %d reason %d"
@@ -213,3 +224,27 @@ disable qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t
disable qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
disable qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
disable qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+
+# hw/grlib_gptimer.c
+disable grlib_gptimer_enable(int id, uint32_t count) "timer:%d set count 0x%x and run"
+disable grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable config 0x%x"
+disable grlib_gptimer_restart(int id, uint32_t reload) "timer:%d reload val: 0x%x"
+disable grlib_gptimer_set_scaler(uint32_t scaler, uint32_t freq) "scaler:0x%x freq: 0x%x"
+disable grlib_gptimer_hit(int id) "timer:%d HIT"
+disable grlib_gptimer_readl(int id, const char *s, uint32_t val) "timer:%d %s 0x%x"
+disable grlib_gptimer_writel(int id, const char *s, uint32_t val) "timer:%d %s 0x%x"
+disable grlib_gptimer_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64""
+
+# hw/grlib_irqmp.c
+disable grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x\n"
+disable grlib_irqmp_ack(int intno) "interrupt:%d"
+disable grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
+disable grlib_irqmp_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64""
+
+# hw/grlib_apbuart.c
+disable grlib_apbuart_event(int event) "event:%d"
+disable grlib_apbuart_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64""
+
+# hw/leon3.c
+disable leon3_set_irq(int intno) "Set CPU IRQ %d"
+disable leon3_reset_irq(int intno) "Reset CPU IRQ %d"
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 56c789a98c..20f91bc642 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -852,9 +852,9 @@ typedef struct CPSProcessSerNum
UInt32 hi;
} CPSProcessSerNum;
-extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
-extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
-extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
+OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
+OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
int main (int argc, const char * argv[]) {
diff --git a/ui/d3des.h b/ui/d3des.h
index ea3da44ce9..78d546f7d8 100644
--- a/ui/d3des.h
+++ b/ui/d3des.h
@@ -22,25 +22,25 @@
#define EN0 0 /* MODE == encrypt */
#define DE1 1 /* MODE == decrypt */
-extern void deskey(unsigned char *, int);
+void deskey(unsigned char *, int);
/* hexkey[8] MODE
* Sets the internal key register according to the hexadecimal
* key contained in the 8 bytes of hexkey, according to the DES,
* for encryption or decryption according to MODE.
*/
-extern void usekey(unsigned long *);
+void usekey(unsigned long *);
/* cookedkey[32]
* Loads the internal key register with the data in cookedkey.
*/
-extern void cpkey(unsigned long *);
+void cpkey(unsigned long *);
/* cookedkey[32]
* Copies the contents of the internal key register into the storage
* located at &cookedkey[0].
*/
-extern void des(unsigned char *, unsigned char *);
+void des(unsigned char *, unsigned char *);
/* from[8] to[8]
* Encrypts/Decrypts (according to the key currently loaded in the
* internal key register) one block of eight bytes at address 'from'
diff --git a/ui/sdl.c b/ui/sdl.c
index f599d42425..a1458ce04d 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -87,12 +87,6 @@ static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
static void sdl_setdata(DisplayState *ds)
{
- SDL_Rect rec;
- rec.x = 0;
- rec.y = 0;
- rec.w = real_screen->w;
- rec.h = real_screen->h;
-
if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
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)
diff --git a/ui/x_keymap.h b/ui/x_keymap.h
index 2042ce0ed2..afde2e94bf 100644
--- a/ui/x_keymap.h
+++ b/ui/x_keymap.h
@@ -25,8 +25,8 @@
#ifndef QEMU_X_KEYMAP_H
#define QEMU_X_KEYMAP_H
-extern uint8_t translate_xfree86_keycode(const int key);
+uint8_t translate_xfree86_keycode(const int key);
-extern uint8_t translate_evdev_keycode(const int key);
+uint8_t translate_evdev_keycode(const int key);
#endif
diff --git a/vl.c b/vl.c
index 0292184273..ce5708bbbd 100644
--- a/vl.c
+++ b/vl.c
@@ -621,23 +621,18 @@ static int bt_parse(const char *opt)
/***********************************************************/
/* QEMU Block devices */
-#define HD_ALIAS "index=%d,media=disk"
-#define CDROM_ALIAS "index=2,media=cdrom"
-#define FD_ALIAS "index=%d,if=floppy"
-#define PFLASH_ALIAS "if=pflash"
-#define MTD_ALIAS "if=mtd"
-#define SD_ALIAS "index=0,if=sd"
+#define HD_OPTS "media=disk"
+#define CDROM_OPTS "media=cdrom"
+#define FD_OPTS ""
+#define PFLASH_OPTS ""
+#define MTD_OPTS ""
+#define SD_OPTS ""
static int drive_init_func(QemuOpts *opts, void *opaque)
{
int *use_scsi = opaque;
- int fatal_error = 0;
- if (drive_init(opts, *use_scsi, &fatal_error) == NULL) {
- if (fatal_error)
- return 1;
- }
- return 0;
+ return drive_init(opts, *use_scsi) == NULL;
}
static int drive_enable_snapshot(QemuOpts *opts, void *opaque)
@@ -648,6 +643,29 @@ static int drive_enable_snapshot(QemuOpts *opts, void *opaque)
return 0;
}
+static void default_drive(int enable, int snapshot, int use_scsi,
+ BlockInterfaceType type, int index,
+ const char *optstr)
+{
+ QemuOpts *opts;
+
+ if (type == IF_DEFAULT) {
+ type = use_scsi ? IF_SCSI : IF_IDE;
+ }
+
+ if (!enable || drive_get_by_index(type, index)) {
+ return;
+ }
+
+ opts = drive_add(type, index, NULL, optstr);
+ if (snapshot) {
+ drive_enable_snapshot(opts, NULL);
+ }
+ if (!drive_init(opts, use_scsi)) {
+ exit(1);
+ }
+}
+
void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
{
boot_set_handler = func;
@@ -804,7 +822,7 @@ static void numa_add(const char *optarg)
if (get_param_value(option, 128, "mem", optarg) == 0) {
node_mem[nodenr] = 0;
} else {
- ssize_t sval;
+ int64_t sval;
sval = strtosz(option, NULL);
if (sval < 0) {
fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg);
@@ -1987,7 +2005,7 @@ int main(int argc, char **argv, char **envp)
if (optind >= argc)
break;
if (argv[optind][0] != '-') {
- hda_opts = drive_add(argv[optind++], HD_ALIAS, 0);
+ hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
} else {
const QEMUOption *popt;
@@ -2026,24 +2044,29 @@ int main(int argc, char **argv, char **envp)
initrd_filename = optarg;
break;
case QEMU_OPTION_hda:
- if (cyls == 0)
- hda_opts = drive_add(optarg, HD_ALIAS, 0);
- else
- hda_opts = drive_add(optarg, HD_ALIAS
- ",cyls=%d,heads=%d,secs=%d%s",
- 0, cyls, heads, secs,
- translation == BIOS_ATA_TRANSLATION_LBA ?
+ {
+ char buf[256];
+ if (cyls == 0)
+ snprintf(buf, sizeof(buf), "%s", HD_OPTS);
+ else
+ snprintf(buf, sizeof(buf),
+ "%s,cyls=%d,heads=%d,secs=%d%s",
+ HD_OPTS , cyls, heads, secs,
+ translation == BIOS_ATA_TRANSLATION_LBA ?
",trans=lba" :
- translation == BIOS_ATA_TRANSLATION_NONE ?
+ translation == BIOS_ATA_TRANSLATION_NONE ?
",trans=none" : "");
- break;
+ drive_add(IF_DEFAULT, 0, optarg, buf);
+ break;
+ }
case QEMU_OPTION_hdb:
case QEMU_OPTION_hdc:
case QEMU_OPTION_hdd:
- drive_add(optarg, HD_ALIAS, popt->index - QEMU_OPTION_hda);
+ drive_add(IF_DEFAULT, popt->index - QEMU_OPTION_hda, optarg,
+ HD_OPTS);
break;
case QEMU_OPTION_drive:
- drive_add(NULL, "%s", optarg);
+ drive_def(optarg);
break;
case QEMU_OPTION_set:
if (qemu_set_option(optarg) != 0)
@@ -2054,13 +2077,13 @@ int main(int argc, char **argv, char **envp)
exit(1);
break;
case QEMU_OPTION_mtdblock:
- drive_add(optarg, MTD_ALIAS);
+ drive_add(IF_MTD, -1, optarg, MTD_OPTS);
break;
case QEMU_OPTION_sd:
- drive_add(optarg, SD_ALIAS);
+ drive_add(IF_SD, 0, optarg, SD_OPTS);
break;
case QEMU_OPTION_pflash:
- drive_add(optarg, PFLASH_ALIAS);
+ drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
break;
case QEMU_OPTION_snapshot:
snapshot = 1;
@@ -2139,7 +2162,7 @@ int main(int argc, char **argv, char **envp)
kernel_cmdline = optarg;
break;
case QEMU_OPTION_cdrom:
- drive_add(optarg, CDROM_ALIAS);
+ drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
break;
case QEMU_OPTION_boot:
{
@@ -2192,7 +2215,8 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_fda:
case QEMU_OPTION_fdb:
- drive_add(optarg, FD_ALIAS, popt->index - QEMU_OPTION_fda);
+ drive_add(IF_FLOPPY, popt->index - QEMU_OPTION_fda,
+ optarg, FD_OPTS);
break;
case QEMU_OPTION_no_fd_bootchk:
fd_bootchk = 0;
@@ -2245,7 +2269,7 @@ int main(int argc, char **argv, char **envp)
exit(0);
break;
case QEMU_OPTION_m: {
- ssize_t value;
+ int64_t value;
value = strtosz(optarg, NULL);
if (value < 0) {
@@ -2890,27 +2914,19 @@ int main(int argc, char **argv, char **envp)
blk_mig_init();
- if (default_cdrom) {
- /* we always create the cdrom drive, even if no disk is there */
- drive_add(NULL, CDROM_ALIAS);
- }
-
- if (default_floppy) {
- /* we always create at least one floppy */
- drive_add(NULL, FD_ALIAS, 0);
- }
-
- if (default_sdcard) {
- /* we always create one sd slot, even if no card is in it */
- drive_add(NULL, SD_ALIAS);
- }
-
/* open the virtual block devices */
if (snapshot)
qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0);
if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, &machine->use_scsi, 1) != 0)
exit(1);
+ default_drive(default_cdrom, snapshot, machine->use_scsi,
+ IF_DEFAULT, 2, CDROM_OPTS);
+ default_drive(default_floppy, snapshot, machine->use_scsi,
+ IF_FLOPPY, 0, FD_OPTS);
+ default_drive(default_sdcard, snapshot, machine->use_scsi,
+ IF_SD, 0, SD_OPTS);
+
register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL,
ram_load, NULL);