Merge remote branch 'spice/config.2' into staging
authorAnthony Liguori <aliguori@us.ibm.com>
Mon, 1 Nov 2010 18:02:56 +0000 (13:02 -0500)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 1 Nov 2010 18:02:56 +0000 (13:02 -0500)
190 files changed:
.gitignore
Makefile
Makefile.objs
Makefile.target
QMP/qmp-events.txt
arch_init.c
audio/alsaaudio.c
block.c
block.h
block/blkverify.c
block/qcow2-cluster.c
block/qcow2-refcount.c
block/qcow2-snapshot.c
block/qcow2.c
block/qcow2.h
block/raw-posix.c
block_int.h
cache-utils.c
check-qjson.c
compatfd.c [new file with mode: 0644]
compatfd.h [new file with mode: 0644]
configure
cpu-all.h
cpu-common.h
cpus.c
cpus.h
cris-dis.c
disas.h
docs/tracing.txt
dyngen-exec.h
exec-all.h
exec.c
fsdev/qemu-fsdev.c
hw/acpi.c
hw/acpi_piix4.c
hw/apb_pci.c
hw/apic.c
hw/audiodev.h
hw/bt-sdp.c
hw/cirrus_vga.c
hw/cirrus_vga_rop.h
hw/cirrus_vga_rop2.h
hw/cs4231.c
hw/dec_pci.c
hw/eccmemctl.c
hw/eepro100.c
hw/file-op-9p.h
hw/hda-audio.c [new file with mode: 0644]
hw/hw.h
hw/ide/core.c
hw/ide/internal.h
hw/intel-hda-defs.h [new file with mode: 0644]
hw/intel-hda.c [new file with mode: 0644]
hw/intel-hda.h [new file with mode: 0644]
hw/ioh3420.c [new file with mode: 0644]
hw/ioh3420.h [new file with mode: 0644]
hw/lance.c
hw/lsi53c895a.c
hw/mips_fulong2e.c
hw/mips_malta.c
hw/mips_r4k.c
hw/msi.c [new file with mode: 0644]
hw/msi.h [new file with mode: 0644]
hw/msix.c
hw/pci.c
hw/pci.h
hw/pci_bridge.c [new file with mode: 0644]
hw/pci_bridge.h [new file with mode: 0644]
hw/pci_ids.h
hw/pci_internals.h [new file with mode: 0644]
hw/pcie.c [new file with mode: 0644]
hw/pcie.h [new file with mode: 0644]
hw/pcie_port.c [new file with mode: 0644]
hw/pcie_port.h [new file with mode: 0644]
hw/pcie_regs.h [new file with mode: 0644]
hw/ppc405_boards.c
hw/ppc405_uc.c
hw/ppc_mac.h
hw/ppc_newworld.c
hw/ppc_oldworld.c
hw/ppc_prep.c
hw/ppce500_mpc8544ds.c
hw/slavio_intctl.c
hw/slavio_misc.c
hw/slavio_timer.c
hw/sparc32_dma.c
hw/sun4m.c
hw/sun4m_iommu.c
hw/tc6393xb_template.h
hw/usb-wacom.c
hw/vhost.c
hw/virtex_ml507.c
hw/virtio-9p-debug.c
hw/virtio-9p-local.c
hw/virtio-9p-posix-acl.c [new file with mode: 0644]
hw/virtio-9p-xattr-user.c [new file with mode: 0644]
hw/virtio-9p-xattr.c [new file with mode: 0644]
hw/virtio-9p-xattr.h [new file with mode: 0644]
hw/virtio-9p.c
hw/virtio-9p.h
hw/virtio-blk.c
hw/virtio-net.c
hw/virtio-pci.c
hw/virtio.c
hw/virtio.h
hw/vmmouse.c
hw/wm8750.c
hw/xio3130_downstream.c [new file with mode: 0644]
hw/xio3130_downstream.h [new file with mode: 0644]
hw/xio3130_upstream.c [new file with mode: 0644]
hw/xio3130_upstream.h [new file with mode: 0644]
kvm-all.c
kvm-stub.c
kvm.h
m68k-semi.c
monitor.c
net.c
net.h
net/tap-win32.c
os-posix.c
os-win32.c
osdep.c
osdep.h
oslib-posix.c [new file with mode: 0644]
oslib-win32.c [new file with mode: 0644]
pc-bios/README
pc-bios/bios.bin
pc-bios/video.x [deleted file]
posix-aio-compat.c
qemu-common.h
qemu-img-cmds.hx
qemu-img.c
qemu-img.texi
qemu-io.c
qemu-malloc.c
qemu-os-posix.h
qemu-os-win32.h
qemu-timer-common.c [new file with mode: 0644]
qemu-timer.c
qemu-timer.h
qemu-tool.c
roms/seabios
rules.mak
savevm.c
simpletrace.c
simpletrace.h
simpletrace.py
target-alpha/helper.c
target-arm/cpu.h
target-arm/helper.c
target-arm/translate.c
target-cris/cpu.h
target-cris/op_helper.c
target-cris/translate.c
target-cris/translate_v10.c
target-i386/cpu.h
target-i386/cpuid.c
target-i386/helper.c
target-i386/kvm.c
target-i386/kvm_x86.h [new file with mode: 0644]
target-i386/op_helper.c
target-m68k/cpu.h
target-m68k/helper.c
target-m68k/translate.c
target-microblaze/translate.c
target-mips/cpu.h
target-mips/translate.c
target-mips/translate_init.c
target-ppc/cpu.h
target-ppc/helper.c
target-ppc/op_helper.c
target-ppc/translate.c
target-ppc/translate_init.c
target-s390x/translate.c
target-sh4/cpu.h
target-sh4/translate.c
target-sparc/helper.c
tcg/tcg.c
tcg/tcg.h
tests/Makefile
tests/runcom.c
tests/test-i386.c
tests/test_path.c
trace-events
tracetool
ui/curses.c
ui/curses_keys.h
ui/spice-display.c
ui/vnc.c
vl.c

index 72bff98740ef07fcd79360f7e822c8ab411cc3df..a43e4d1d98f9ab16903cfba5c9b742fe3c5b3499 100644 (file)
@@ -4,6 +4,7 @@ config-host.*
 config-target.*
 trace.h
 trace.c
+*-timestamp
 *-softmmu
 *-darwin-user
 *-linux-user
index 92c041eaf392682ca53e34f33652489323a60384..ec8a6bce009a2be94dfa1c2262ce50d780b3e84b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 # Makefile for QEMU.
 
-GENERATED_HEADERS = config-host.h trace.h
+GENERATED_HEADERS = config-host.h trace.h qemu-options.def
 
 ifneq ($(wildcard config-host.mak),)
 # Put the all: rule here so that config-host.mak can contain dependencies.
@@ -71,6 +71,8 @@ build-all: $(DOCS) $(TOOLS) recurse-all
 
 config-host.h: config-host.h-timestamp
 config-host.h-timestamp: config-host.mak
+qemu-options.def: qemu-options.hx
+       $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 
 SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
 
@@ -129,39 +131,40 @@ version-obj-$(CONFIG_WIN32) += version.o
 qemu-img.o: qemu-img-cmds.h
 qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
 
-qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y)
+qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
-qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y)
+qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
-qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y)
+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   $@")
 
 check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
 
-check-qint: check-qint.o qint.o qemu-malloc.o
-check-qstring: check-qstring.o qstring.o qemu-malloc.o
-check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o
-check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
-check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o
-check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o
+check-qint: check-qint.o qint.o qemu-malloc.o $(trace-obj-y)
+check-qstring: check-qstring.o qstring.o qemu-malloc.o $(trace-obj-y)
+check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o $(trace-obj-y)
+check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o $(trace-obj-y)
+check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o $(trace-obj-y)
+check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o $(trace-obj-y)
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
        rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
+       rm -f qemu-options.def
        rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
        rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
        rm -f qemu-img-cmds.h
-       rm -f trace.c trace.h
+       rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
        $(MAKE) -C tests clean
        for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
        if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
+       rm -f $$d/qemu-options.def; \
         done
 
 distclean: clean
        rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
-       rm -f qemu-options.def
        rm -f config-all-devices.mak
        rm -f roms/seabios/config.mak roms/vgabios/config.mak
        rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr
@@ -176,7 +179,7 @@ common  de-ch  es     fo  fr-ca  hu     ja  mk  nl-be      pt  sl     tr
 
 ifdef INSTALL_BLOBS
 BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
-video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
+openbios-sparc32 openbios-sparc64 openbios-ppc \
 gpxe-eepro100-80861209.rom \
 gpxe-eepro100-80861229.rom \
 pxe-e1000.bin \
@@ -323,7 +326,6 @@ tarbin:
        $(datadir)/vgabios.bin \
        $(datadir)/vgabios-cirrus.bin \
        $(datadir)/ppc_rom.bin \
-       $(datadir)/video.x \
        $(datadir)/openbios-sparc32 \
        $(datadir)/openbios-sparc64 \
        $(datadir)/openbios-ppc \
index 816194a3d65eab9900b75c3354a570ec1636a752..faf485ed1bcae3b16fa49c2f3d658057e50560c5 100644 (file)
@@ -4,11 +4,17 @@ qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
 qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
 qobject-obj-y += qerror.o
 
+#######################################################################
+# oslib-obj-y is code depending on the OS (win32 vs posix)
+oslib-obj-y = osdep.o
+oslib-obj-$(CONFIG_WIN32) += oslib-win32.o
+oslib-obj-$(CONFIG_POSIX) += oslib-posix.o
+
 #######################################################################
 # block-obj-y is code used by both qemu system emulation and qemu-img
 
 block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
-block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o
+block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
@@ -50,6 +56,7 @@ common-obj-y += $(net-obj-y)
 common-obj-y += $(qobject-obj-y)
 common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
 common-obj-y += readline.o console.o cursor.o async.o qemu-error.o
+common-obj-y += $(oslib-obj-y)
 common-obj-$(CONFIG_WIN32) += os-win32.o
 common-obj-$(CONFIG_POSIX) += os-posix.o
 
@@ -125,8 +132,9 @@ common-obj-y += $(addprefix ui/, $(ui-obj-y))
 
 common-obj-y += iov.o acl.o
 common-obj-$(CONFIG_THREAD) += qemu-thread.o
+common-obj-$(CONFIG_IOTHREAD) += compatfd.o
 common-obj-y += notify.o event_notifier.o
-common-obj-y += qemu-timer.o
+common-obj-y += qemu-timer.o qemu-timer-common.o
 
 slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
 slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
@@ -151,7 +159,8 @@ user-obj-y += cutils.o cache-utils.o
 hw-obj-y =
 hw-obj-y += vl.o loader.o
 hw-obj-y += virtio.o virtio-console.o
-hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o
+hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
+hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
 hw-obj-y += watchdog.o
 hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 hw-obj-$(CONFIG_ECC) += ecc.o
@@ -198,7 +207,8 @@ hw-obj-$(CONFIG_PIIX4) += piix4.o
 # PCI watchdog devices
 hw-obj-y += wdt_i6300esb.o
 
-hw-obj-y += msix.o
+hw-obj-y += pcie.o pcie_port.o
+hw-obj-y += msix.o msi.o
 
 # PCI network cards
 hw-obj-y += ne2000.o
@@ -245,11 +255,13 @@ sound-obj-$(CONFIG_AC97) += ac97.o
 sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
 sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
 sound-obj-$(CONFIG_CS4231A) += cs4231a.o
+sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
 
 adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 
-hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o
+hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o virtio-9p-xattr.o
+hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 
 ######################################################################
 # libdis
@@ -276,16 +288,10 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
 trace-obj-y = trace.o
 ifeq ($(TRACE_BACKEND),simple)
 trace-obj-y += simpletrace.o
+user-obj-y += qemu-timer-common.o
 endif
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 
-vl.o: qemu-options.def
-os-posix.o: qemu-options.def
-os-win32.o: qemu-options.def
-
-qemu-options.def: $(SRC_PATH)/qemu-options.hx
-       $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
-
index c48cbcc7f3dde25df1692c69c43f1821ca70e7ff..91e6e7439985d8bbd147c865cba853236539aee2 100644 (file)
@@ -88,7 +88,7 @@ $(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR
 QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
 obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
       elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \
-      qemu-malloc.o
+      qemu-malloc.o $(oslib-obj-y)
 
 obj-$(TARGET_HAS_BFLT) += flatload.o
 
index 01ec85fbb92349cf0efd1052d171eef8efef14c4..aa2021082f500d922aa36b5421d4b4c99988f516 100644 (file)
@@ -89,7 +89,7 @@ Data: None.
 
 Example:
 
-{ "event": "SHUTDOWN",
+{ "event": "STOP",
     "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
 
 VNC_CONNECTED
index a910033c8c07f2469efc13aa78c439c309153c38..44869255efbbdab0b550ee1ec646c051caf56044 100644 (file)
@@ -390,6 +390,9 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
                 host = qemu_get_ram_ptr(addr);
             else
                 host = host_from_stream_offset(f, addr, flags);
+            if (!host) {
+                return -EINVAL;
+            }
 
             ch = qemu_get_byte(f);
             memset(host, ch, TARGET_PAGE_SIZE);
@@ -499,6 +502,16 @@ struct soundhw soundhw[] = {
     },
 #endif
 
+#ifdef CONFIG_HDA
+    {
+        "hda",
+        "Intel HD Audio",
+        0,
+        0,
+        { .init_pci = intel_hda_and_codec_init }
+    },
+#endif
+
 #endif /* HAS_AUDIO_CHOICE */
 
     { NULL, NULL, 0, 0, { NULL } }
index f0171f9842a4476c3cb3aa78fb9c7695b8e5ba5f..07412030c21870a1bc834ffdcdb810a970290182 100644 (file)
@@ -843,11 +843,15 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
     return 0;
 }
 
-static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
+#define VOICE_CTL_PAUSE 0
+#define VOICE_CTL_PREPARE 1
+#define VOICE_CTL_START 2
+
+static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
 {
     int err;
 
-    if (pause) {
+    if (ctl == VOICE_CTL_PAUSE) {
         err = snd_pcm_drop (handle);
         if (err < 0) {
             alsa_logerr (err, "Could not stop %s\n", typ);
@@ -860,6 +864,13 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
             alsa_logerr (err, "Could not prepare handle for %s\n", typ);
             return -1;
         }
+        if (ctl == VOICE_CTL_START) {
+            err = snd_pcm_start(handle);
+            if (err < 0) {
+                alsa_logerr (err, "Could not start handle for %s\n", typ);
+                return -1;
+            }
+        }
     }
 
     return 0;
@@ -884,12 +895,16 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
                 poll_mode = 0;
             }
             hw->poll_mode = poll_mode;
-            return alsa_voice_ctl (alsa->handle, "playback", 0);
+            return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE);
         }
 
     case VOICE_DISABLE:
         ldebug ("disabling voice\n");
-        return alsa_voice_ctl (alsa->handle, "playback", 1);
+        if (hw->poll_mode) {
+            hw->poll_mode = 0;
+            alsa_fini_poll (&alsa->pollhlp);
+        }
+        return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
     }
 
     return -1;
@@ -1102,7 +1117,7 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
             }
             hw->poll_mode = poll_mode;
 
-            return alsa_voice_ctl (alsa->handle, "capture", 0);
+            return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START);
         }
 
     case VOICE_DISABLE:
@@ -1111,7 +1126,7 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
             hw->poll_mode = 0;
             alsa_fini_poll (&alsa->pollhlp);
         }
-        return alsa_voice_ctl (alsa->handle, "capture", 1);
+        return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE);
     }
 
     return -1;
diff --git a/block.c b/block.c
index ebbc376b0c7cc8e4452a9947e65538e4c2d4eefe..985d0b7e39e2c398d5b310ce1f1de9f4d1436d24 100644 (file)
--- a/block.c
+++ b/block.c
@@ -1899,6 +1899,22 @@ int bdrv_snapshot_list(BlockDriverState *bs,
     return -ENOTSUP;
 }
 
+int bdrv_snapshot_load_tmp(BlockDriverState *bs,
+        const char *snapshot_name)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv) {
+        return -ENOMEDIUM;
+    }
+    if (!bs->read_only) {
+        return -EINVAL;
+    }
+    if (drv->bdrv_snapshot_load_tmp) {
+        return drv->bdrv_snapshot_load_tmp(bs, snapshot_name);
+    }
+    return -ENOTSUP;
+}
+
 #define NB_SUFFIXES 4
 
 char *get_human_readable_size(char *buf, int buf_size, int64_t size)
@@ -1983,6 +1999,8 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
     BlockDriver *drv = bs->drv;
     BlockDriverAIOCB *ret;
 
+    trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
+
     if (!drv)
         return NULL;
     if (bdrv_check_request(bs, sector_num, nb_sectors))
@@ -2007,6 +2025,8 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
     BlockDriver *drv = bs->drv;
     BlockDriverAIOCB *ret;
 
+    trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
+
     if (!drv)
         return NULL;
     if (bs->read_only)
diff --git a/block.h b/block.h
index 5f6438010f84c925cbf18f277cd91870f42c78b5..a4facf2fa6ffe86e731cdf34d29f91c1ad134ce6 100644 (file)
--- a/block.h
+++ b/block.h
@@ -211,6 +211,8 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
 int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
 int bdrv_snapshot_list(BlockDriverState *bs,
                        QEMUSnapshotInfo **psn_info);
+int bdrv_snapshot_load_tmp(BlockDriverState *bs,
+                           const char *snapshot_name);
 char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
 
 char *get_human_readable_size(char *buf, int buf_size, int64_t size);
index 8083464751ef7784a17916d678142707970791c1..b2a12fe7f56dacfeae4256a887b7d843f088b7f6 100644 (file)
@@ -53,7 +53,8 @@ static AIOPool blkverify_aio_pool = {
     .cancel             = blkverify_aio_cancel,
 };
 
-static void blkverify_err(BlkverifyAIOCB *acb, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
+                                             const char *fmt, ...)
 {
     va_list ap;
 
@@ -299,7 +300,7 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb)
 {
     ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
     if (offset != -1) {
-        blkverify_err(acb, "contents mismatch in sector %ld",
+        blkverify_err(acb, "contents mismatch in sector %lld",
                       acb->sector_num + (offset / BDRV_SECTOR_SIZE));
     }
 }
index fb4224a669ebeeff8e8b6545008aaf93fd6e2f0f..4f7dc59b7636f63e2ee5565e581e51af541122c9 100644 (file)
@@ -28,7 +28,7 @@
 #include "block_int.h"
 #include "block/qcow2.h"
 
-int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
+int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
 {
     BDRVQcowState *s = bs->opaque;
     int new_l1_size, new_l1_size2, ret, i;
@@ -36,15 +36,22 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
     int64_t new_l1_table_offset;
     uint8_t data[12];
 
-    new_l1_size = s->l1_size;
-    if (min_size <= new_l1_size)
+    if (min_size <= s->l1_size)
         return 0;
-    if (new_l1_size == 0) {
-        new_l1_size = 1;
-    }
-    while (min_size > new_l1_size) {
-        new_l1_size = (new_l1_size * 3 + 1) / 2;
+
+    if (exact_size) {
+        new_l1_size = min_size;
+    } else {
+        /* Bump size up to reduce the number of times we have to grow */
+        new_l1_size = s->l1_size;
+        if (new_l1_size == 0) {
+            new_l1_size = 1;
+        }
+        while (min_size > new_l1_size) {
+            new_l1_size = (new_l1_size * 3 + 1) / 2;
+        }
     }
+
 #ifdef DEBUG_ALLOC2
     printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
 #endif
@@ -550,7 +557,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
 
     l1_index = offset >> (s->l2_bits + s->cluster_bits);
     if (l1_index >= s->l1_size) {
-        ret = qcow2_grow_l1_table(bs, l1_index + 1);
+        ret = qcow2_grow_l1_table(bs, l1_index + 1, false);
         if (ret < 0) {
             return ret;
         }
index 7082601f598981ff55b90f70fd6a84f16f0f7aec..0efb6760cbb9698522e6ade2d9eff578b4e56331 100644 (file)
@@ -551,6 +551,7 @@ fail:
     if (ret < 0) {
         int dummy;
         dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);
+        (void)dummy;
     }
 
     return ret;
index bbfcaaae22a0db1094d93874e05565466ecf5155..aacf3578219ab713b694712bd37914de6e219cc1 100644 (file)
@@ -327,7 +327,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
         goto fail;
 
-    if (qcow2_grow_l1_table(bs, sn->l1_size) < 0)
+    if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0)
         goto fail;
 
     s->l1_size = sn->l1_size;
@@ -418,3 +418,34 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
     return s->nb_snapshots;
 }
 
+int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
+{
+    int i, snapshot_index, l1_size2;
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+
+    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name);
+    if (snapshot_index < 0) {
+        return -ENOENT;
+    }
+
+    sn = &s->snapshots[snapshot_index];
+    s->l1_size = sn->l1_size;
+    l1_size2 = s->l1_size * sizeof(uint64_t);
+    if (s->l1_table != NULL) {
+        qemu_free(s->l1_table);
+    }
+
+    s->l1_table_offset = sn->l1_table_offset;
+    s->l1_table = qemu_mallocz(align_offset(l1_size2, 512));
+
+    if (bdrv_pread(bs->file, sn->l1_table_offset,
+                   s->l1_table, l1_size2) != l1_size2) {
+        return -1;
+    }
+
+    for(i = 0;i < s->l1_size; i++) {
+        be64_to_cpus(&s->l1_table[i]);
+    }
+    return 0;
+}
index ee3481b786f0e05bbf5c8c52d90d2ed61917ee22..b816d8733f124aba8743b09d1d77280e29596a2a 100644 (file)
@@ -27,6 +27,7 @@
 #include <zlib.h>
 #include "aes.h"
 #include "block/qcow2.h"
+#include "qemu-error.h"
 
 /*
   Differences with QCOW:
@@ -794,28 +795,6 @@ static int qcow2_change_backing_file(BlockDriverState *bs,
     return qcow2_update_ext_header(bs, backing_file, backing_fmt);
 }
 
-static int get_bits_from_size(size_t size)
-{
-    int res = 0;
-
-    if (size == 0) {
-        return -1;
-    }
-
-    while (size != 1) {
-        /* Not a power of two */
-        if (size & 1) {
-            return -1;
-        }
-
-        size >>= 1;
-        res++;
-    }
-
-    return res;
-}
-
-
 static int preallocate(BlockDriverState *bs)
 {
     uint64_t nb_sectors;
@@ -871,199 +850,127 @@ static int preallocate(BlockDriverState *bs)
 
 static int qcow_create2(const char *filename, int64_t total_size,
                         const char *backing_file, const char *backing_format,
-                        int flags, size_t cluster_size, int prealloc)
+                        int flags, size_t cluster_size, int prealloc,
+                        QEMUOptionParameter *options)
 {
+    /* Calulate cluster_bits */
+    int cluster_bits;
+    cluster_bits = ffs(cluster_size) - 1;
+    if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS ||
+        (1 << cluster_bits) != cluster_size)
+    {
+        error_report(
+            "Cluster size must be a power of two between %d and %dk\n",
+            1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10));
+        return -EINVAL;
+    }
 
-    int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
-    int ref_clusters, reftable_clusters, backing_format_len = 0;
-    int rounded_ext_bf_len = 0;
+    /*
+     * Open the image file and write a minimal qcow2 header.
+     *
+     * We keep things simple and start with a zero-sized image. We also
+     * do without refcount blocks or a L1 table for now. We'll fix the
+     * inconsistency later.
+     *
+     * We do need a refcount table because growing the refcount table means
+     * allocating two new refcount blocks - the seconds of which would be at
+     * 2 GB for 64k clusters, and we don't want to have a 2 GB initial file
+     * size for any qcow2 image.
+     */
+    BlockDriverState* bs;
     QCowHeader header;
-    uint64_t tmp, offset;
-    uint64_t old_ref_clusters;
-    QCowCreateState s1, *s = &s1;
-    QCowExtension ext_bf = {0, 0};
+    uint8_t* refcount_table;
     int ret;
 
-    memset(s, 0, sizeof(*s));
+    ret = bdrv_create_file(filename, options);
+    if (ret < 0) {
+        return ret;
+    }
 
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-    if (fd < 0)
-        return -errno;
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* Write the header */
     memset(&header, 0, sizeof(header));
     header.magic = cpu_to_be32(QCOW_MAGIC);
     header.version = cpu_to_be32(QCOW_VERSION);
-    header.size = cpu_to_be64(total_size * 512);
-    header_size = sizeof(header);
-    backing_filename_len = 0;
-    if (backing_file) {
-        if (backing_format) {
-            ext_bf.magic = QCOW_EXT_MAGIC_BACKING_FORMAT;
-            backing_format_len = strlen(backing_format);
-            ext_bf.len = backing_format_len;
-            rounded_ext_bf_len = (sizeof(ext_bf) + ext_bf.len + 7) & ~7;
-            header_size += rounded_ext_bf_len;
-        }
-        header.backing_file_offset = cpu_to_be64(header_size);
-        backing_filename_len = strlen(backing_file);
-        header.backing_file_size = cpu_to_be32(backing_filename_len);
-        header_size += backing_filename_len;
-    }
-
-    /* Cluster size */
-    s->cluster_bits = get_bits_from_size(cluster_size);
-    if (s->cluster_bits < MIN_CLUSTER_BITS ||
-        s->cluster_bits > MAX_CLUSTER_BITS)
-    {
-        fprintf(stderr, "Cluster size must be a power of two between "
-            "%d and %dk\n",
-            1 << MIN_CLUSTER_BITS,
-            1 << (MAX_CLUSTER_BITS - 10));
-        return -EINVAL;
-    }
-    s->cluster_size = 1 << s->cluster_bits;
+    header.cluster_bits = cpu_to_be32(cluster_bits);
+    header.size = cpu_to_be64(0);
+    header.l1_table_offset = cpu_to_be64(0);
+    header.l1_size = cpu_to_be32(0);
+    header.refcount_table_offset = cpu_to_be64(cluster_size);
+    header.refcount_table_clusters = cpu_to_be32(1);
 
-    header.cluster_bits = cpu_to_be32(s->cluster_bits);
-    header_size = (header_size + 7) & ~7;
     if (flags & BLOCK_FLAG_ENCRYPT) {
         header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
     } else {
         header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
     }
-    l2_bits = s->cluster_bits - 3;
-    shift = s->cluster_bits + l2_bits;
-    l1_size = (((total_size * 512) + (1LL << shift) - 1) >> shift);
-    offset = align_offset(header_size, s->cluster_size);
-    s->l1_table_offset = offset;
-    header.l1_table_offset = cpu_to_be64(s->l1_table_offset);
-    header.l1_size = cpu_to_be32(l1_size);
-    offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
-
-    /* count how many refcount blocks needed */
-
-#define NUM_CLUSTERS(bytes) \
-    (((bytes) + (s->cluster_size) - 1) / (s->cluster_size))
 
-    ref_clusters = NUM_CLUSTERS(NUM_CLUSTERS(offset) * sizeof(uint16_t));
-
-    do {
-        uint64_t image_clusters;
-        old_ref_clusters = ref_clusters;
-
-        /* Number of clusters used for the refcount table */
-        reftable_clusters = NUM_CLUSTERS(ref_clusters * sizeof(uint64_t));
+    ret = bdrv_pwrite(bs, 0, &header, sizeof(header));
+    if (ret < 0) {
+        goto out;
+    }
 
-        /* Number of clusters that the whole image will have */
-        image_clusters = NUM_CLUSTERS(offset) + ref_clusters
-            + reftable_clusters;
+    /* Write an empty refcount table */
+    refcount_table = qemu_mallocz(cluster_size);
+    ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size);
+    qemu_free(refcount_table);
 
-        /* Number of refcount blocks needed for the image */
-        ref_clusters = NUM_CLUSTERS(image_clusters * sizeof(uint16_t));
+    if (ret < 0) {
+        goto out;
+    }
 
-    } while (ref_clusters != old_ref_clusters);
+    bdrv_close(bs);
 
-    s->refcount_table = qemu_mallocz(reftable_clusters * s->cluster_size);
+    /*
+     * And now open the image and make it consistent first (i.e. increase the
+     * refcount of the cluster that is occupied by the header and the refcount
+     * table)
+     */
+    BlockDriver* drv = bdrv_find_format("qcow2");
+    assert(drv != NULL);
+    ret = bdrv_open(bs, filename, BDRV_O_RDWR | BDRV_O_NO_FLUSH, drv);
+    if (ret < 0) {
+        goto out;
+    }
 
-    s->refcount_table_offset = offset;
-    header.refcount_table_offset = cpu_to_be64(offset);
-    header.refcount_table_clusters = cpu_to_be32(reftable_clusters);
-    offset += (reftable_clusters * s->cluster_size);
-    s->refcount_block_offset = offset;
+    ret = qcow2_alloc_clusters(bs, 2 * cluster_size);
+    if (ret < 0) {
+        goto out;
 
-    for (i=0; i < ref_clusters; i++) {
-        s->refcount_table[i] = cpu_to_be64(offset);
-        offset += s->cluster_size;
+    } else if (ret != 0) {
+        error_report("Huh, first cluster in empty image is already in use?");
+        abort();
     }
 
-    s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size);
-
-    /* update refcounts */
-    qcow2_create_refcount_update(s, 0, header_size);
-    qcow2_create_refcount_update(s, s->l1_table_offset,
-        l1_size * sizeof(uint64_t));
-    qcow2_create_refcount_update(s, s->refcount_table_offset,
-        reftable_clusters * s->cluster_size);
-    qcow2_create_refcount_update(s, s->refcount_block_offset,
-        ref_clusters * s->cluster_size);
-
-    /* write all the data */
-    ret = qemu_write_full(fd, &header, sizeof(header));
-    if (ret != sizeof(header)) {
-        ret = -errno;
-        goto exit;
+    /* Okay, now that we have a valid image, let's give it the right size */
+    ret = bdrv_truncate(bs, total_size * BDRV_SECTOR_SIZE);
+    if (ret < 0) {
+        goto out;
     }
+
+    /* Want a backing file? There you go.*/
     if (backing_file) {
-        if (backing_format_len) {
-            char zero[16];
-            int padding = rounded_ext_bf_len - (ext_bf.len + sizeof(ext_bf));
-
-            memset(zero, 0, sizeof(zero));
-            cpu_to_be32s(&ext_bf.magic);
-            cpu_to_be32s(&ext_bf.len);
-            ret = qemu_write_full(fd, &ext_bf, sizeof(ext_bf));
-            if (ret != sizeof(ext_bf)) {
-                ret = -errno;
-                goto exit;
-            }
-            ret = qemu_write_full(fd, backing_format, backing_format_len);
-            if (ret != backing_format_len) {
-                ret = -errno;
-                goto exit;
-            }
-            if (padding > 0) {
-                ret = qemu_write_full(fd, zero, padding);
-                if (ret != padding) {
-                    ret = -errno;
-                    goto exit;
-                }
-            }
-        }
-        ret = qemu_write_full(fd, backing_file, backing_filename_len);
-        if (ret != backing_filename_len) {
-            ret = -errno;
-            goto exit;
-        }
-    }
-    lseek(fd, s->l1_table_offset, SEEK_SET);
-    tmp = 0;
-    for(i = 0;i < l1_size; i++) {
-        ret = qemu_write_full(fd, &tmp, sizeof(tmp));
-        if (ret != sizeof(tmp)) {
-            ret = -errno;
-            goto exit;
+        ret = bdrv_change_backing_file(bs, backing_file, backing_format);
+        if (ret < 0) {
+            goto out;
         }
     }
-    lseek(fd, s->refcount_table_offset, SEEK_SET);
-    ret = qemu_write_full(fd, s->refcount_table,
-        reftable_clusters * s->cluster_size);
-    if (ret != reftable_clusters * s->cluster_size) {
-        ret = -errno;
-        goto exit;
-    }
-
-    lseek(fd, s->refcount_block_offset, SEEK_SET);
-    ret = qemu_write_full(fd, s->refcount_block,
-                   ref_clusters * s->cluster_size);
-    if (ret != ref_clusters * s->cluster_size) {
-        ret = -errno;
-        goto exit;
-    }
 
-    ret = 0;
-exit:
-    qemu_free(s->refcount_table);
-    qemu_free(s->refcount_block);
-    close(fd);
-
-    /* Preallocate metadata */
-    if (ret == 0 && prealloc) {
-        BlockDriverState *bs;
-        BlockDriver *drv = bdrv_find_format("qcow2");
-        bs = bdrv_new("");
-        bdrv_open(bs, filename, BDRV_O_CACHE_WB | BDRV_O_RDWR, drv);
+    /* And if we're supposed to preallocate metadata, do that now */
+    if (prealloc) {
         ret = preallocate(bs);
-        bdrv_close(bs);
+        if (ret < 0) {
+            goto out;
+        }
     }
 
+    ret = 0;
+out:
+    bdrv_delete(bs);
     return ret;
 }
 
@@ -1111,7 +1018,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
     }
 
     return qcow_create2(filename, sectors, backing_file, backing_fmt, flags,
-        cluster_size, prealloc);
+        cluster_size, prealloc, options);
 }
 
 static int qcow_make_empty(BlockDriverState *bs)
@@ -1154,7 +1061,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
     }
 
     new_l1_size = size_to_l1(s, offset);
-    ret = qcow2_grow_l1_table(bs, new_l1_size);
+    ret = qcow2_grow_l1_table(bs, new_l1_size, true);
     if (ret < 0) {
         return ret;
     }
@@ -1379,6 +1286,7 @@ static BlockDriver bdrv_qcow2 = {
     .bdrv_snapshot_goto     = qcow2_snapshot_goto,
     .bdrv_snapshot_delete   = qcow2_snapshot_delete,
     .bdrv_snapshot_list     = qcow2_snapshot_list,
+    .bdrv_snapshot_load_tmp     = qcow2_snapshot_load_tmp,
     .bdrv_get_info     = qcow_get_info,
 
     .bdrv_save_vmstate    = qcow_save_vmstate,
index 356a34af434a73d2800a3444a00f61936240093f..2d22e5ec4767d018fc1749e5c977ba46b2157af8 100644 (file)
@@ -188,7 +188,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
 int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res);
 
 /* qcow2-cluster.c functions */
-int qcow2_grow_l1_table(BlockDriverState *bs, int min_size);
+int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size);
 void qcow2_l2_cache_reset(BlockDriverState *bs);
 int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
 void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
@@ -211,6 +211,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
 int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
 int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
 int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
+int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
 
 void qcow2_free_snapshots(BlockDriverState *bs);
 int qcow2_read_snapshots(BlockDriverState *bs);
index a5cbb7e92947eb437dcaf3a5ef4510c263bfbcb5..d0393e0c447931ea001b4c86b668c50e512817c9 100644 (file)
@@ -97,9 +97,9 @@
 #define FTYPE_CD     1
 #define FTYPE_FD     2
 
-/* if the FD is not accessed during that time (in ms), we try to
+/* if the FD is not accessed during that time (in ns), we try to
    reopen it to see if the disk has been changed */
-#define FD_OPEN_TIMEOUT 1000
+#define FD_OPEN_TIMEOUT (1000000000)
 
 #define MAX_BLOCKSIZE  4096
 
@@ -908,7 +908,7 @@ static int fd_open(BlockDriverState *bs)
         return 0;
     last_media_present = (s->fd >= 0);
     if (s->fd >= 0 &&
-        (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
+        (get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
         close(s->fd);
         s->fd = -1;
 #ifdef DEBUG_FLOPPY
@@ -917,7 +917,7 @@ static int fd_open(BlockDriverState *bs)
     }
     if (s->fd < 0) {
         if (s->fd_got_error &&
-            (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
+            (get_clock() - s->fd_error_time) < FD_OPEN_TIMEOUT) {
 #ifdef DEBUG_FLOPPY
             printf("No floppy (open delayed)\n");
 #endif
@@ -925,7 +925,7 @@ static int fd_open(BlockDriverState *bs)
         }
         s->fd = open(bs->filename, s->open_flags & ~O_NONBLOCK);
         if (s->fd < 0) {
-            s->fd_error_time = qemu_get_clock(rt_clock);
+            s->fd_error_time = get_clock();
             s->fd_got_error = 1;
             if (last_media_present)
                 s->fd_media_changed = 1;
@@ -940,7 +940,7 @@ static int fd_open(BlockDriverState *bs)
     }
     if (!last_media_present)
         s->fd_media_changed = 1;
-    s->fd_open_time = qemu_get_clock(rt_clock);
+    s->fd_open_time = get_clock();
     s->fd_got_error = 0;
     return 0;
 }
index e8e7156c92e6e78362dd9e97e36587f6a339b995..87e60b8597a746a5f2a43b254da3f604bc6407d7 100644 (file)
@@ -93,6 +93,8 @@ struct BlockDriver {
     int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
     int (*bdrv_snapshot_list)(BlockDriverState *bs,
                               QEMUSnapshotInfo **psn_info);
+    int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
+                                  const char *snapshot_name);
     int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
 
     int (*bdrv_save_vmstate)(BlockDriverState *bs, const uint8_t *buf,
index b1f20978ca6a9ee6fa89a759ce8052a69dc0f59c..2db5af2db14d025a5b24c606191c020028480a36 100644 (file)
@@ -79,7 +79,7 @@ static void ppc_init_cacheline_sizes(void)
     qemu_cache_conf.dcache_bsize = cacheline;
     qemu_cache_conf.icache_bsize = cacheline;
 }
-#endif    
+#endif
 
 #ifdef __linux__
 void qemu_cache_utils_init(char **envp)
index 0b60e45fa64ac70d8a24dc54f8053d15a9b94b70..64fcdcb4ad0ac5c113d8ddd343375b0c46bf20ce 100644 (file)
@@ -639,7 +639,9 @@ END_TEST
 
 START_TEST(empty_input)
 {
-    QObject *obj = qobject_from_json("");
+    const char *empty = "";
+
+    QObject *obj = qobject_from_json(empty);
     fail_unless(obj == NULL);
 }
 END_TEST
diff --git a/compatfd.c b/compatfd.c
new file mode 100644 (file)
index 0000000..a7cebc4
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * signalfd/eventfd compatibility
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "compatfd.h"
+
+#include <sys/syscall.h>
+#include <pthread.h>
+
+struct sigfd_compat_info
+{
+    sigset_t mask;
+    int fd;
+};
+
+static void *sigwait_compat(void *opaque)
+{
+    struct sigfd_compat_info *info = opaque;
+    int err;
+    sigset_t all;
+
+    sigfillset(&all);
+    sigprocmask(SIG_BLOCK, &all, NULL);
+
+    do {
+        siginfo_t siginfo;
+
+        err = sigwaitinfo(&info->mask, &siginfo);
+        if (err == -1 && errno == EINTR) {
+            err = 0;
+            continue;
+        }
+
+        if (err > 0) {
+            char buffer[128];
+            size_t offset = 0;
+
+            memcpy(buffer, &err, sizeof(err));
+            while (offset < sizeof(buffer)) {
+                ssize_t len;
+
+                len = write(info->fd, buffer + offset,
+                            sizeof(buffer) - offset);
+                if (len == -1 && errno == EINTR)
+                    continue;
+
+                if (len <= 0) {
+                    err = -1;
+                    break;
+                }
+
+                offset += len;
+            }
+        }
+    } while (err >= 0);
+
+    return NULL;
+}
+
+static int qemu_signalfd_compat(const sigset_t *mask)
+{
+    pthread_attr_t attr;
+    pthread_t tid;
+    struct sigfd_compat_info *info;
+    int fds[2];
+
+    info = malloc(sizeof(*info));
+    if (info == NULL) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    if (pipe(fds) == -1) {
+        free(info);
+        return -1;
+    }
+
+    qemu_set_cloexec(fds[0]);
+    qemu_set_cloexec(fds[1]);
+
+    memcpy(&info->mask, mask, sizeof(*mask));
+    info->fd = fds[1];
+
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    pthread_create(&tid, &attr, sigwait_compat, info);
+
+    pthread_attr_destroy(&attr);
+
+    return fds[0];
+}
+
+int qemu_signalfd(const sigset_t *mask)
+{
+#if defined(CONFIG_SIGNALFD)
+    int ret;
+
+    ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
+    if (ret != -1) {
+        qemu_set_cloexec(ret);
+        return ret;
+    }
+#endif
+
+    return qemu_signalfd_compat(mask);
+}
diff --git a/compatfd.h b/compatfd.h
new file mode 100644 (file)
index 0000000..fc37915
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * signalfd/eventfd compatibility
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_COMPATFD_H
+#define QEMU_COMPATFD_H
+
+#include <signal.h>
+
+struct qemu_signalfd_siginfo {
+    uint32_t ssi_signo;   /* Signal number */
+    int32_t  ssi_errno;   /* Error number (unused) */
+    int32_t  ssi_code;    /* Signal code */
+    uint32_t ssi_pid;     /* PID of sender */
+    uint32_t ssi_uid;     /* Real UID of sender */
+    int32_t  ssi_fd;      /* File descriptor (SIGIO) */
+    uint32_t ssi_tid;     /* Kernel timer ID (POSIX timers) */
+    uint32_t ssi_band;    /* Band event (SIGIO) */
+    uint32_t ssi_overrun; /* POSIX timer overrun count */
+    uint32_t ssi_trapno;  /* Trap number that caused signal */
+    int32_t  ssi_status;  /* Exit status or signal (SIGCHLD) */
+    int32_t  ssi_int;     /* Integer sent by sigqueue(2) */
+    uint64_t ssi_ptr;     /* Pointer sent by sigqueue(2) */
+    uint64_t ssi_utime;   /* User CPU time consumed (SIGCHLD) */
+    uint64_t ssi_stime;   /* System CPU time consumed (SIGCHLD) */
+    uint64_t ssi_addr;    /* Address that generated signal
+                             (for hardware-generated signals) */
+    uint8_t  pad[48];     /* Pad size to 128 bytes (allow for
+                             additional fields in the future) */
+};
+
+int qemu_signalfd(const sigset_t *mask);
+
+#endif
index 9e65de05af115d8ae8ba55e29fbf34aa5f3f1a42..7025d2bf0d9f8c04024ac68855f0be205fe1ca18 100755 (executable)
--- a/configure
+++ b/configure
@@ -76,8 +76,8 @@ sparc_cpu=""
 cross_prefix=""
 cc="gcc"
 audio_drv_list=""
-audio_card_list="ac97 es1370 sb16"
-audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus"
+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"
@@ -92,6 +92,7 @@ libs_softmmu=""
 libs_tools=""
 audio_pt_int=""
 audio_win_int=""
+cc_i386=i386-pc-linux-gnu-gcc
 
 # parse CC options first
 for opt do
@@ -154,7 +155,7 @@ int main(void) { return 0; }
 EOF
 for flag in $gcc_flags; do
     if compile_prog "-Werror $QEMU_CFLAGS" "-Werror $flag" ; then
-       QEMU_CFLAGS="$flag $QEMU_CFLAGS"
+       QEMU_CFLAGS="$QEMU_CFLAGS $flag"
     fi
 done
 
@@ -789,12 +790,14 @@ case "$cpu" in
     i386)
            QEMU_CFLAGS="-m32 $QEMU_CFLAGS"
            LDFLAGS="-m32 $LDFLAGS"
+           cc_i386='$(CC) -m32'
            helper_cflags="-fomit-frame-pointer"
            host_guest_base="yes"
            ;;
     x86_64)
            QEMU_CFLAGS="-m64 $QEMU_CFLAGS"
            LDFLAGS="-m64 $LDFLAGS"
+           cc_i386='$(CC) -m32'
            host_guest_base="yes"
            ;;
     arm*)
@@ -1329,6 +1332,7 @@ if test "$vnc_png" != "no" ; then
 cat > $TMPC <<EOF
 //#include <stdio.h>
 #include <png.h>
+#include <stddef.h>
 int main(void) {
     png_structp png_ptr;
     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
@@ -1513,6 +1517,7 @@ if test "$brlapi" != "no" ; then
   brlapi_libs="-lbrlapi"
   cat > $TMPC << EOF
 #include <brlapi.h>
+#include <stddef.h>
 int main( void ) { return brlapi__openConnection (NULL, NULL, NULL); }
 EOF
   if compile_prog "" "$brlapi_libs" ; then
@@ -1747,6 +1752,7 @@ if test "$linux_aio" != "no" ; then
   cat > $TMPC <<EOF
 #include <libaio.h>
 #include <sys/eventfd.h>
+#include <stddef.h>
 int main(void) { io_setup(0, NULL); io_set_eventfd(NULL, 0); eventfd(0, 0); return 0; }
 EOF
   if compile_prog "" "-laio" ; then
@@ -1888,7 +1894,6 @@ fi
 utimens=no
 cat > $TMPC << EOF
 #define _ATFILE_SOURCE
-#define _GNU_SOURCE
 #include <stddef.h>
 #include <fcntl.h>
 
@@ -1906,7 +1911,6 @@ fi
 # check if pipe2 is there
 pipe2=no
 cat > $TMPC << EOF
-#define _GNU_SOURCE
 #include <unistd.h>
 #include <fcntl.h>
 
@@ -1924,7 +1928,6 @@ fi
 # check if accept4 is there
 accept4=no
 cat > $TMPC << EOF
-#define _GNU_SOURCE
 #include <sys/socket.h>
 #include <stddef.h>
 
@@ -1941,7 +1944,6 @@ fi
 # check if tee/splice is there. vmsplice was added same time.
 splice=no
 cat > $TMPC << EOF
-#define _GNU_SOURCE
 #include <unistd.h>
 #include <fcntl.h>
 #include <limits.h>
@@ -1958,6 +1960,21 @@ if compile_prog "" "" ; then
   splice=yes
 fi
 
+##########################################
+# signalfd probe
+signalfd="no"
+cat > $TMPC << EOF
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <signal.h>
+int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }
+EOF
+
+if compile_prog "" "" ; then
+  signalfd=yes
+fi
+
 # check if eventfd is supported
 eventfd=no
 cat > $TMPC << EOF
@@ -2093,7 +2110,7 @@ int main(void) { spice_server_new(); return 0; }
 EOF
   spice_cflags=$($pkgconfig --cflags spice-protocol spice-server 2>/dev/null)
   spice_libs=$($pkgconfig --libs spice-protocol spice-server 2>/dev/null)
-  if $pkgconfig --atleast-version=0.5.3 spice-server &&\
+  if $pkgconfig --atleast-version=0.5.3 spice-server >/dev/null 2>&1 && \
      compile_prog "$spice_cflags" "$spice_libs" ; then
     spice="yes"
     libs_softmmu="$libs_softmmu $spice_libs"
@@ -2127,6 +2144,7 @@ madvise=no
 cat > $TMPC << EOF
 #include <sys/types.h>
 #include <sys/mman.h>
+#include <stddef.h>
 int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }
 EOF
 if compile_prog "" "" ; then
@@ -2139,6 +2157,7 @@ fi
 posix_madvise=no
 cat > $TMPC << EOF
 #include <sys/mman.h>
+#include <stddef.h>
 int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }
 EOF
 if compile_prog "" "" ; then
@@ -2332,6 +2351,7 @@ printf "# Configured with:" >> $config_host_mak
 printf " '%s'" "$0" "$@" >> $config_host_mak
 echo >> $config_host_mak
 
+echo all: >> $config_host_mak
 echo "prefix=$prefix" >> $config_host_mak
 echo "bindir=$bindir" >> $config_host_mak
 echo "mandir=$mandir" >> $config_host_mak
@@ -2558,6 +2578,9 @@ fi
 if test "$fdt" = "yes" ; then
   echo "CONFIG_FDT=y" >> $config_host_mak
 fi
+if test "$signalfd" = "yes" ; then
+  echo "CONFIG_SIGNALFD=y" >> $config_host_mak
+fi
 if test "$need_offsetof" = "yes" ; then
   echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
 fi
@@ -2620,6 +2643,7 @@ echo "INSTALL_DIR=$install -d -m0755 -p" >> $config_host_mak
 echo "INSTALL_DATA=$install -m0644 -p" >> $config_host_mak
 echo "INSTALL_PROG=$install -m0755 -p" >> $config_host_mak
 echo "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
@@ -3083,7 +3107,7 @@ if test "$source_path_used" = "yes" ; then
     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 pc-bios/video.x"
+    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`"
index 67a32664d52e514196179f82f4d47fe18969003c..30ae17d41df261c09e0f0463842b77925c05fedb 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -765,15 +765,13 @@ int page_check_range(target_ulong start, target_ulong len, int flags);
 CPUState *cpu_copy(CPUState *env);
 CPUState *qemu_get_cpu(int cpu);
 
-void cpu_dump_state(CPUState *env, FILE *f,
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     int flags);
-void cpu_dump_statistics (CPUState *env, FILE *f,
-                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
-                          int flags);
+void cpu_dump_statistics(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+                         int flags);
 
 void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...)
-    __attribute__ ((__format__ (__printf__, 2, 3)));
+    GCC_FMT_ATTR(2, 3);
 extern CPUState *first_cpu;
 extern CPUState *cpu_single_env;
 
@@ -959,8 +957,7 @@ int cpu_physical_memory_get_dirty_tracking(void);
 int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
                                    target_phys_addr_t end_addr);
 
-void dump_exec_info(FILE *f,
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);
 #endif /* !CONFIG_USER_ONLY */
 
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
index 0426bc8e27fa940707185004ea63c8011671973a..a543b5d7cfcb14a432603a97681416ee91752e39 100644 (file)
@@ -47,7 +47,8 @@ void qemu_ram_free(ram_addr_t addr);
 /* This should only be used for ram local to a device.  */
 void *qemu_get_ram_ptr(ram_addr_t addr);
 /* This should not be used by devices.  */
-ram_addr_t qemu_ram_addr_from_host(void *ptr);
+int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
+ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
 
 int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
diff --git a/cpus.c b/cpus.c
index b09f5e3b508d2300f69a1c220eb495a06726c463..91a0fb1146aa2c9cfbc0a09066cb7b3a39d7e7cb 100644 (file)
--- a/cpus.c
+++ b/cpus.c
 #include "exec-all.h"
 
 #include "cpus.h"
+#include "compatfd.h"
+#ifdef CONFIG_LINUX
+#include <sys/prctl.h>
+#endif
 
 #ifdef SIGRTMIN
 #define SIG_IPI (SIGRTMIN+4)
 #define SIG_IPI SIGUSR1
 #endif
 
+#ifndef PR_MCE_KILL
+#define PR_MCE_KILL 33
+#endif
+
 static CPUState *next_cpu;
 
 /***********************************************************/
@@ -329,14 +337,75 @@ static QemuCond qemu_work_cond;
 
 static void tcg_init_ipi(void);
 static void kvm_init_ipi(CPUState *env);
-static void unblock_io_signals(void);
+static sigset_t block_io_signals(void);
+
+/* If we have signalfd, we mask out the signals we want to handle and then
+ * use signalfd to listen for them.  We rely on whatever the current signal
+ * handler is to dispatch the signals when we receive them.
+ */
+static void sigfd_handler(void *opaque)
+{
+    int fd = (unsigned long) opaque;
+    struct qemu_signalfd_siginfo info;
+    struct sigaction action;
+    ssize_t len;
+
+    while (1) {
+        do {
+            len = read(fd, &info, sizeof(info));
+        } while (len == -1 && errno == EINTR);
+
+        if (len == -1 && errno == EAGAIN) {
+            break;
+        }
+
+        if (len != sizeof(info)) {
+            printf("read from sigfd returned %zd: %m\n", len);
+            return;
+        }
+
+        sigaction(info.ssi_signo, NULL, &action);
+        if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
+            action.sa_sigaction(info.ssi_signo,
+                                (siginfo_t *)&info, NULL);
+        } else if (action.sa_handler) {
+            action.sa_handler(info.ssi_signo);
+        }
+    }
+}
+
+static int qemu_signalfd_init(sigset_t mask)
+{
+    int sigfd;
+
+    sigfd = qemu_signalfd(&mask);
+    if (sigfd == -1) {
+        fprintf(stderr, "failed to create signalfd\n");
+        return -errno;
+    }
+
+    fcntl_setfl(sigfd, O_NONBLOCK);
+
+    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+                         (void *)(unsigned long) sigfd);
+
+    return 0;
+}
 
 int qemu_init_main_loop(void)
 {
     int ret;
+    sigset_t blocked_signals;
 
     cpu_set_debug_excp_handler(cpu_debug_handler);
 
+    blocked_signals = block_io_signals();
+
+    ret = qemu_signalfd_init(blocked_signals);
+    if (ret)
+        return ret;
+
+    /* Note eventfd must be drained before signalfd handlers run */
     ret = qemu_event_init();
     if (ret)
         return ret;
@@ -347,7 +416,6 @@ int qemu_init_main_loop(void)
     qemu_mutex_init(&qemu_global_mutex);
     qemu_mutex_lock(&qemu_global_mutex);
 
-    unblock_io_signals();
     qemu_thread_self(&io_thread);
 
     return 0;
@@ -437,28 +505,77 @@ static void qemu_tcg_wait_io_event(void)
     }
 }
 
+static void sigbus_reraise(void)
+{
+    sigset_t set;
+    struct sigaction action;
+
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = SIG_DFL;
+    if (!sigaction(SIGBUS, &action, NULL)) {
+        raise(SIGBUS);
+        sigemptyset(&set);
+        sigaddset(&set, SIGBUS);
+        sigprocmask(SIG_UNBLOCK, &set, NULL);
+    }
+    perror("Failed to re-raise SIGBUS!\n");
+    abort();
+}
+
+static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
+                           void *ctx)
+{
+#if defined(TARGET_I386)
+    if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr))
+#endif
+        sigbus_reraise();
+}
+
 static void qemu_kvm_eat_signal(CPUState *env, int timeout)
 {
     struct timespec ts;
     int r, e;
     siginfo_t siginfo;
     sigset_t waitset;
+    sigset_t chkset;
 
     ts.tv_sec = timeout / 1000;
     ts.tv_nsec = (timeout % 1000) * 1000000;
 
     sigemptyset(&waitset);
     sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
 
-    qemu_mutex_unlock(&qemu_global_mutex);
-    r = sigtimedwait(&waitset, &siginfo, &ts);
-    e = errno;
-    qemu_mutex_lock(&qemu_global_mutex);
+    do {
+        qemu_mutex_unlock(&qemu_global_mutex);
 
-    if (r == -1 && !(e == EAGAIN || e == EINTR)) {
-        fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
-        exit(1);
-    }
+        r = sigtimedwait(&waitset, &siginfo, &ts);
+        e = errno;
+
+        qemu_mutex_lock(&qemu_global_mutex);
+
+        if (r == -1 && !(e == EAGAIN || e == EINTR)) {
+            fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+#ifdef TARGET_I386
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr))
+#endif
+                sigbus_reraise();
+            break;
+        default:
+            break;
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            fprintf(stderr, "sigpending: %s\n", strerror(e));
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
 }
 
 static void qemu_kvm_wait_io_event(CPUState *env)
@@ -579,6 +696,7 @@ static void kvm_init_ipi(CPUState *env)
 
     pthread_sigmask(SIG_BLOCK, NULL, &set);
     sigdelset(&set, SIG_IPI);
+    sigdelset(&set, SIGBUS);
     r = kvm_set_signal_mask(env, &set);
     if (r) {
         fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
@@ -586,19 +704,30 @@ static void kvm_init_ipi(CPUState *env)
     }
 }
 
-static void unblock_io_signals(void)
+static sigset_t block_io_signals(void)
 {
     sigset_t set;
+    struct sigaction action;
 
+    /* SIGUSR2 used by posix-aio-compat.c */
     sigemptyset(&set);
     sigaddset(&set, SIGUSR2);
-    sigaddset(&set, SIGIO);
-    sigaddset(&set, SIGALRM);
     pthread_sigmask(SIG_UNBLOCK, &set, NULL);
 
     sigemptyset(&set);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
     sigaddset(&set, SIG_IPI);
+    sigaddset(&set, SIGBUS);
     pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    memset(&action, 0, sizeof(action));
+    action.sa_flags = SA_SIGINFO;
+    action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
+    sigaction(SIGBUS, &action, NULL);
+    prctl(PR_MCE_KILL, 1, 1, 0, 0);
+
+    return set;
 }
 
 void qemu_mutex_lock_iothread(void)
@@ -849,8 +978,7 @@ int64_t cpu_get_icount(void)
     return qemu_icount_bias + (icount << icount_time_shift);
 }
 
-void list_cpus(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
-               const char *optarg)
+void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
 {
     /* XXX: implement xxx_cpu_list for targets that still miss it */
 #if defined(cpu_list_id)
diff --git a/cpus.h b/cpus.h
index af267ea07f10566a80658727e3b8791fe3cc6f85..bf4d9bb87a75f521aed366a50d6257708aeab702 100644 (file)
--- a/cpus.h
+++ b/cpus.h
@@ -16,7 +16,6 @@ void vm_state_notify(int running, int reason);
 bool cpu_exec_all(void);
 void set_numa_modes(void);
 void set_cpu_log(const char *optarg);
-void list_cpus(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
-               const char *optarg);
+void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg);
 
 #endif
index 455ba8af3f035ded982a84bfd193d4b3f3d1f208..afd775c29b23fe25aedb5a717c08eccb87368ea1 100644 (file)
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>. */
 
+#include "qemu-common.h"
 #include "dis-asm.h"
 //#include "sysdep.h"
 #include "target-cris/opcode-cris.h"
 //#include "libiberty.h"
-\f
-
-void *qemu_malloc(size_t len); /* can't include qemu-common.h here */
 
 #define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0)
 
diff --git a/disas.h b/disas.h
index 6a9332d6ccbd2a33700dc62a56137d595a46aa2e..f9287f73e107a6fd85f223cd78ddee2753657da7 100644 (file)
--- a/disas.h
+++ b/disas.h
@@ -8,11 +8,8 @@
 void disas(FILE *out, void *code, unsigned long size);
 void target_disas(FILE *out, target_ulong code, target_ulong size, int flags);
 
-/* The usual mess... FIXME: Remove this condition once dyngen-exec.h is gone */
-#ifndef __DYNGEN_EXEC_H__
 void monitor_disas(Monitor *mon, CPUState *env,
                    target_ulong pc, int nb_insn, int is_physical, int flags);
-#endif
 
 /* Look up symbol for debugging purpose.  Returns "" if unknown. */
 const char *lookup_symbol(target_ulong orig_addr);
index ae01ff1378816cb6801ee8c5e1cf2134632b257c..963c5047fe48d019e1d01c729e8cd09eb6c69ea2 100644 (file)
@@ -72,6 +72,13 @@ Trace events should use types as follows:
  * For everything else, use primitive scalar types (char, int, long) with the
    appropriate signedness.
 
+Format strings should reflect the types defined in the trace event.  Take
+special care to use PRId64 and PRIu64 for int64_t and uint64_t types,
+respectively.  This ensures portability between 32- and 64-bit platforms.  Note
+that format strings must begin and end with double quotes.  When using
+portability macros, ensure they are preceded and followed by double quotes:
+"value %"PRIx64"".
+
 === Hints for adding new trace events ===
 
 1. Trace state changes in the code.  Interesting points in the code usually
index 5bfef3f6fe1b7ea494e89a3c4ebfe544de26babe..db00fbae04e20eec0c9bdd84700d5eff336dd2cc 100644 (file)
 #if !defined(__DYNGEN_EXEC_H__)
 #define __DYNGEN_EXEC_H__
 
-/* prevent Solaris from trying to typedef FILE in gcc's
-   include/floatingpoint.h which will conflict with the
-   definition down below */
-#ifdef __sun__
-#define _FILEDEFED
-#endif
-
-/* NOTE: standard headers should be used with special care at this
-   point because host CPU registers are used as global variables. Some
-   host headers do not allow that. */
-#include <stddef.h>
-#include <stdint.h>
-#include <stdbool.h>
+#include "qemu-common.h"
 
 #ifdef __OpenBSD__
 #include <sys/types.h>
 /* XXX: This may be wrong for 64-bit ILP32 hosts.  */
 typedef void * host_reg_t;
 
-#ifdef CONFIG_BSD
-typedef struct __sFILE FILE;
-#else
-typedef struct FILE FILE;
-#endif
-extern int fprintf(FILE *, const char *, ...);
-extern int fputs(const char *, FILE *);
-extern int printf(const char *, ...);
-
 #if defined(__i386__)
 #define AREG0 "ebp"
 #elif defined(__x86_64__)
index 3a53fe64c2e72fa867ddbf0da34582c28a680b72..c4570587d736d5cc2d0220ac852ea761ca690a24 100644 (file)
@@ -334,7 +334,7 @@ static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add
     }
     p = (void *)(unsigned long)addr
         + env1->tlb_table[mmu_idx][page_index].addend;
-    return qemu_ram_addr_from_host(p);
+    return qemu_ram_addr_from_host_nofail(p);
 }
 #endif
 
diff --git a/exec.c b/exec.c
index 1fbe91cf40a49f29b270173ed8cc8263051fa87c..db9ff5515a266e4f0933e6d19404705cb8e2fc09 100644 (file)
--- a/exec.c
+++ b/exec.c
 #include <sys/types.h>
 #include <sys/mman.h>
 #endif
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <inttypes.h>
 
+#include "qemu-common.h"
 #include "cpu.h"
 #include "exec-all.h"
-#include "qemu-common.h"
 #include "tcg.h"
 #include "hw/hw.h"
 #include "hw/qdev.h"
@@ -2085,7 +2078,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
     if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
         p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
             + tlb_entry->addend);
-        ram_addr = qemu_ram_addr_from_host(p);
+        ram_addr = qemu_ram_addr_from_host_nofail(p);
         if (!cpu_physical_memory_is_dirty(ram_addr)) {
             tlb_entry->addr_write |= TLB_NOTDIRTY;
         }
@@ -2938,23 +2931,31 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
     return NULL;
 }
 
-/* Some of the softmmu routines need to translate from a host pointer
-   (typically a TLB entry) back to a ram offset.  */
-ram_addr_t qemu_ram_addr_from_host(void *ptr)
+int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
 {
     RAMBlock *block;
     uint8_t *host = ptr;
 
     QLIST_FOREACH(block, &ram_list.blocks, next) {
         if (host - block->host < block->length) {
-            return block->offset + (host - block->host);
+            *ram_addr = block->offset + (host - block->host);
+            return 0;
         }
     }
+    return -1;
+}
 
-    fprintf(stderr, "Bad ram pointer %p\n", ptr);
-    abort();
+/* Some of the softmmu routines need to translate from a host pointer
+   (typically a TLB entry) back to a ram offset.  */
+ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
+{
+    ram_addr_t ram_addr;
 
-    return 0;
+    if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
+        fprintf(stderr, "Bad ram pointer %p\n", ptr);
+        abort();
+    }
+    return ram_addr;
 }
 
 static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -3703,7 +3704,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
 {
     if (buffer != bounce.buffer) {
         if (is_write) {
-            ram_addr_t addr1 = qemu_ram_addr_from_host(buffer);
+            ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
             while (access_len) {
                 unsigned l;
                 l = TARGET_PAGE_SIZE;
@@ -4088,8 +4089,7 @@ void cpu_io_recompile(CPUState *env, void *retaddr)
 
 #if !defined(CONFIG_USER_ONLY)
 
-void dump_exec_info(FILE *f,
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
 {
     int i, target_code_size, max_target_code_size;
     int direct_jmp_count, direct_jmp2_count, cross_page;
@@ -4116,14 +4116,14 @@ void dump_exec_info(FILE *f,
     }
     /* XXX: avoid using doubles ? */
     cpu_fprintf(f, "Translation buffer state:\n");
-    cpu_fprintf(f, "gen code size       %ld/%ld\n",
+    cpu_fprintf(f, "gen code size       %td/%ld\n",
                 code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
     cpu_fprintf(f, "TB count            %d/%d\n", 
                 nb_tbs, code_gen_max_blocks);
     cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n",
                 nb_tbs ? target_code_size / nb_tbs : 0,
                 max_target_code_size);
-    cpu_fprintf(f, "TB avg host size    %d bytes (expansion ratio: %0.1f)\n",
+    cpu_fprintf(f, "TB avg host size    %td bytes (expansion ratio: %0.1f)\n",
                 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
                 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
     cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
index 280b8f57b9dce28063d745b8ab9e5c15ce88577e..0b332907bdad073c1f22dd533bdd6dced8dc4f8b 100644 (file)
@@ -29,35 +29,47 @@ int qemu_fsdev_add(QemuOpts *opts)
 {
     struct FsTypeListEntry *fsle;
     int i;
+    const char *fsdev_id = qemu_opts_id(opts);
+    const char *fstype = qemu_opt_get(opts, "fstype");
+    const char *path = qemu_opt_get(opts, "path");
+    const char *sec_model = qemu_opt_get(opts, "security_model");
 
-    if (qemu_opts_id(opts) == NULL) {
+    if (!fsdev_id) {
         fprintf(stderr, "fsdev: No id specified\n");
         return -1;
     }
 
-    for (i = 0; i < ARRAY_SIZE(FsTypes); i++) {
-        if (strcmp(FsTypes[i].name, qemu_opt_get(opts, "fstype")) == 0) {
-            break;
+    if (fstype) {
+        for (i = 0; i < ARRAY_SIZE(FsTypes); i++) {
+            if (strcmp(FsTypes[i].name, fstype) == 0) {
+                break;
+            }
         }
-    }
 
-    if (i == ARRAY_SIZE(FsTypes)) {
-        fprintf(stderr, "fsdev: fstype %s not found\n",
-                    qemu_opt_get(opts, "fstype"));
+        if (i == ARRAY_SIZE(FsTypes)) {
+            fprintf(stderr, "fsdev: fstype %s not found\n", fstype);
+            return -1;
+        }
+    } else {
+        fprintf(stderr, "fsdev: No fstype specified\n");
         return -1;
     }
 
-    if (qemu_opt_get(opts, "security_model") == NULL) {
+    if (!sec_model) {
         fprintf(stderr, "fsdev: No security_model specified.\n");
         return -1;
     }
 
+    if (!path) {
+        fprintf(stderr, "fsdev: No path specified.\n");
+        return -1;
+    }
+
     fsle = qemu_malloc(sizeof(*fsle));
 
-    fsle->fse.fsdev_id = qemu_strdup(qemu_opts_id(opts));
-    fsle->fse.path = qemu_strdup(qemu_opt_get(opts, "path"));
-    fsle->fse.security_model = qemu_strdup(qemu_opt_get(opts,
-                "security_model"));
+    fsle->fse.fsdev_id = qemu_strdup(fsdev_id);
+    fsle->fse.path = qemu_strdup(path);
+    fsle->fse.security_model = qemu_strdup(sec_model);
     fsle->fse.ops = FsTypes[i].ops;
 
     QTAILQ_INSERT_TAIL(&fstype_entries, fsle, next);
@@ -67,11 +79,13 @@ int qemu_fsdev_add(QemuOpts *opts)
 
 FsTypeEntry *get_fsdev_fsentry(char *id)
 {
-    struct FsTypeListEntry *fsle;
+    if (id) {
+        struct FsTypeListEntry *fsle;
 
-    QTAILQ_FOREACH(fsle, &fstype_entries, next) {
-        if (strcmp(fsle->fse.fsdev_id, id) == 0) {
-            return &fsle->fse;
+        QTAILQ_FOREACH(fsle, &fstype_entries, next) {
+            if (strcmp(fsle->fse.fsdev_id, id) == 0) {
+                return &fsle->fse;
+            }
         }
     }
     return NULL;
index 069e05fc7a8274120e5d432daa55135b9725e308..8071e7bebaf67cb312fe05b88231f8e9a02f97b3 100644 (file)
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -161,7 +161,7 @@ int acpi_table_add(const char *t)
 
         /* off < length is necessary because file size can be changed
            under our foot */
-        while(s.st_size && off < length); {
+        while(s.st_size && off < length) {
             int r;
             r = read(fd, p + off, s.st_size);
             if (r > 0) {
index c8733e5fada4f56ae98a3d42eb261a8dd971116f..66c7885d62648cfd70bd95658d4b171e9ce504ab 100644 (file)
@@ -38,6 +38,8 @@
 #define PCI_BASE 0xae00
 #define PCI_EJ_BASE 0xae08
 
+#define PIIX4_PCI_HOTPLUG_STATUS 2
+
 struct gpe_regs {
     uint16_t sts; /* status */
     uint16_t en;  /* enabled */
@@ -105,7 +107,9 @@ static void pm_update_sci(PIIX4PMState *s)
                   (ACPI_BITMASK_RT_CLOCK_ENABLE |
                    ACPI_BITMASK_POWER_BUTTON_ENABLE |
                    ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
-                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
+                   ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
+        (((s->gpe.sts & s->gpe.en) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
+
     qemu_set_irq(s->irq, sci_level);
     /* schedule a timer interruption if needed */
     if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
@@ -460,7 +464,9 @@ static uint32_t gpe_read_val(uint16_t val, uint32_t addr)
 static uint32_t gpe_readb(void *opaque, uint32_t addr)
 {
     uint32_t val = 0;
-    struct gpe_regs *g = opaque;
+    PIIX4PMState *s = opaque;
+    struct gpe_regs *g = &s->gpe;
+
     switch (addr) {
         case GPE_BASE:
         case GPE_BASE + 1:
@@ -500,7 +506,9 @@ static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val)
 
 static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
-    struct gpe_regs *g = opaque;
+    PIIX4PMState *s = opaque;
+    struct gpe_regs *g = &s->gpe;
+
     switch (addr) {
         case GPE_BASE:
         case GPE_BASE + 1:
@@ -512,7 +520,9 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
             break;
         default:
             break;
-   }
+    }
+
+    pm_update_sci(s);
 
     PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
 }
@@ -579,11 +589,10 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state);
 
 static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
 {
-    struct gpe_regs *gpe = &s->gpe;
     struct pci_status *pci0_status = &s->pci0_status;
 
-    register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, gpe);
-    register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, gpe);
+    register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, s);
+    register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, s);
 
     register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
     register_ioport_read(PCI_BASE, 8, 4,  pcihotplug_read, pci0_status);
@@ -596,13 +605,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
 
 static void enable_device(PIIX4PMState *s, int slot)
 {
-    s->gpe.sts |= 2;
+    s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
     s->pci0_status.up |= (1 << slot);
 }
 
 static void disable_device(PIIX4PMState *s, int slot)
 {
-    s->gpe.sts |= 2;
+    s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
     s->pci0_status.down |= (1 << slot);
 }
 
@@ -612,6 +621,9 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state)
     PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
                                 DO_UPCAST(PCIDevice, qdev, qdev));
 
+    if (!dev->qdev.hotplugged)
+        return 0;
+
     s->pci0_status.up = 0;
     s->pci0_status.down = 0;
     if (state) {
@@ -619,9 +631,8 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state)
     } else {
         disable_device(s, slot);
     }
-    if (s->gpe.en & 2) {
-        qemu_set_irq(s->irq, 1);
-        qemu_set_irq(s->irq, 0);
-    }
+
+    pm_update_sci(s);
+
     return 0;
 }
index 0ecac55792d9c296d911d08d44434f2f7706d9b4..c619112b1260403a4befee47c9c3696e20c140fb 100644 (file)
@@ -29,6 +29,8 @@
 #include "sysbus.h"
 #include "pci.h"
 #include "pci_host.h"
+#include "pci_bridge.h"
+#include "pci_internals.h"
 #include "rwhandler.h"
 #include "apb_pci.h"
 #include "sysemu.h"
@@ -293,9 +295,17 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
     }
 }
 
-static void apb_pci_bridge_init(PCIBus *b)
+static int apb_pci_bridge_initfn(PCIDevice *dev)
 {
-    PCIDevice *dev = pci_bridge_get_device(b);
+    int rc;
+
+    rc = pci_bridge_initfn(dev);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_SUN);
+    pci_config_set_device_id(dev->config, PCI_DEVICE_ID_SUN_SIMBA);
 
     /*
      * command register:
@@ -312,6 +322,7 @@ static void apb_pci_bridge_init(PCIBus *b)
                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
                  PCI_STATUS_DEVSEL_MEDIUM);
     pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
+    return 0;
 }
 
 PCIBus *pci_apb_init(target_phys_addr_t special_base,
@@ -322,6 +333,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
     SysBusDevice *s;
     APBState *d;
     unsigned int i;
+    PCIDevice *pci_dev;
+    PCIBridge *br;
 
     /* Ultrasparc PBM main bus */
     dev = qdev_create(NULL, "pbm");
@@ -347,17 +360,21 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
     pci_create_simple(d->bus, 0, "pbm");
 
     /* APB secondary busses */
-    *bus2 = pci_bridge_init(d->bus, PCI_DEVFN(1, 0), true,
-                            PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
-                            pci_apb_map_irq,
-                            "Advanced PCI Bus secondary bridge 1");
-    apb_pci_bridge_init(*bus2);
-
-    *bus3 = pci_bridge_init(d->bus, PCI_DEVFN(1, 1), true,
-                            PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
-                            pci_apb_map_irq,
-                            "Advanced PCI Bus secondary bridge 2");
-    apb_pci_bridge_init(*bus3);
+    pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
+                                   "pbm-bridge");
+    br = DO_UPCAST(PCIBridge, dev, pci_dev);
+    pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
+                       pci_apb_map_irq);
+    qdev_init_nofail(&pci_dev->qdev);
+    *bus2 = pci_bridge_get_sec_bus(br);
+
+    pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
+                                   "pbm-bridge");
+    br = DO_UPCAST(PCIBridge, dev, pci_dev);
+    pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
+                       pci_apb_map_irq);
+    qdev_init_nofail(&pci_dev->qdev);
+    *bus3 = pci_bridge_get_sec_bus(br);
 
     return d->bus;
 }
@@ -440,10 +457,23 @@ static SysBusDeviceInfo pbm_host_info = {
     .qdev.reset = pci_pbm_reset,
     .init = pci_pbm_init_device,
 };
+
+static PCIDeviceInfo pbm_pci_bridge_info = {
+    .qdev.name = "pbm-bridge",
+    .qdev.size = sizeof(PCIBridge),
+    .qdev.vmsd = &vmstate_pci_device,
+    .qdev.reset = pci_bridge_reset,
+    .init = apb_pci_bridge_initfn,
+    .exit = pci_bridge_exitfn,
+    .config_write = pci_bridge_write_config,
+    .is_bridge = 1,
+};
+
 static void pbm_register_devices(void)
 {
     sysbus_register_withprop(&pbm_host_info);
     pci_qdev_register(&pbm_pci_host_info);
+    pci_qdev_register(&pbm_pci_bridge_info);
 }
 
 device_init(pbm_register_devices)
index d686b510b05bc55daa780ac4ac642ba253ee123c..63d62c75531757c5fe914fc6e024dc07799411df 100644 (file)
--- a/hw/apic.c
+++ b/hw/apic.c
 #include "qemu-timer.h"
 #include "host-utils.h"
 #include "sysbus.h"
-
-//#define DEBUG_APIC
-//#define DEBUG_COALESCING
-
-#ifdef DEBUG_APIC
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("apic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#ifdef DEBUG_COALESCING
-#define DPRINTF_C(fmt, ...)                                     \
-    do { printf("apic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_C(fmt, ...)
-#endif
+#include "trace.h"
 
 /* APIC Local Vector Table */
 #define APIC_LVT_TIMER   0
@@ -168,8 +152,8 @@ static void apic_local_deliver(APICState *s, int vector)
     uint32_t lvt = s->lvt[vector];
     int trigger_mode;
 
-    DPRINTF("%s: vector %d delivery mode %d\n", __func__, vector,
-            (lvt >> 8) & 7);
+    trace_apic_local_deliver(vector, (lvt >> 8) & 7);
+
     if (lvt & APIC_LVT_MASKED)
         return;
 
@@ -300,9 +284,9 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
 {
     uint32_t deliver_bitmask[MAX_APIC_WORDS];
 
-    DPRINTF("%s: dest %d dest_mode %d delivery_mode %d vector %d"
-            " polarity %d trigger_mode %d\n", __func__, dest, dest_mode,
-            delivery_mode, vector_num, polarity, trigger_mode);
+    trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
+                           polarity, trigger_mode);
+
     apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
                      trigger_mode);
@@ -312,7 +296,8 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
 {
     APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
 
-    DPRINTF("cpu_set_apic_base: %016" PRIx64 "\n", val);
+    trace_cpu_set_apic_base(val);
+
     if (!s)
         return;
     s->apicbase = (val & 0xfffff000) |
@@ -329,8 +314,8 @@ uint64_t cpu_get_apic_base(DeviceState *d)
 {
     APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
 
-    DPRINTF("cpu_get_apic_base: %016" PRIx64 "\n",
-            s ? (uint64_t)s->apicbase: 0);
+    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
+
     return s ? s->apicbase : 0;
 }
 
@@ -402,20 +387,23 @@ static void apic_update_irq(APICState *s)
 
 void apic_reset_irq_delivered(void)
 {
-    DPRINTF_C("%s: old coalescing %d\n", __func__, apic_irq_delivered);
+    trace_apic_reset_irq_delivered(apic_irq_delivered);
+
     apic_irq_delivered = 0;
 }
 
 int apic_get_irq_delivered(void)
 {
-    DPRINTF_C("%s: returning coalescing %d\n", __func__, apic_irq_delivered);
+    trace_apic_get_irq_delivered(apic_irq_delivered);
+
     return apic_irq_delivered;
 }
 
 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
 {
     apic_irq_delivered += !get_bit(s->irr, vector_num);
-    DPRINTF_C("%s: coalescing %d\n", __func__, apic_irq_delivered);
+
+    trace_apic_set_irq(apic_irq_delivered);
 
     set_bit(s->irr, vector_num);
     if (trigger_mode)
@@ -769,7 +757,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
         val = 0;
         break;
     }
-    DPRINTF("read: " TARGET_FMT_plx " = %08x\n", addr, val);
+    trace_apic_mem_readl(addr, val);
     return val;
 }
 
@@ -805,7 +793,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
     s = DO_UPCAST(APICState, busdev.qdev, d);
 
-    DPRINTF("write: " TARGET_FMT_plx " = %08x\n", addr, val);
+    trace_apic_mem_writel(addr, val);
 
     switch(index) {
     case 0x02:
index 39a729b8a4161872578a298e592150ddec874fb2..8e930b21aefe1094da5c72f5a54f40787a6e8099 100644 (file)
@@ -15,3 +15,6 @@ int ac97_init(PCIBus *buf);
 
 /* cs4231a.c */
 int cs4231a_init(qemu_irq *pic);
+
+/* intel-hda.c + hda-audio.c */
+int intel_hda_and_codec_init(PCIBus *bus);
index cc0bf2f9b3bfc3c7ea0b399f909070df8e99e89b..cdf2d95d52e52fe280a560ad7dd52ac6416222b6 100644 (file)
@@ -786,11 +786,11 @@ static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
         .type       = SDP_DTYPE_UUID | SDP_DSIZE_16,   \
         .value.uint = val,                             \
     },
-#define TRUE   {                               \
+#define SDP_TRUE       {                               \
         .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,    \
         .value.uint = 1,                               \
     },
-#define FALSE  {                               \
+#define SDP_FALSE      {                               \
         .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,    \
         .value.uint = 0,                               \
     },
@@ -842,8 +842,8 @@ SERVICE(hid,
     /* TODO: extract from l2cap_device->device.class[0] */
     ATTRIBUTE(DEVICE_SUBCLASS,         UINT8(0x40))
     ATTRIBUTE(COUNTRY_CODE,            UINT8(0x15))
-    ATTRIBUTE(VIRTUAL_CABLE,           TRUE)
-    ATTRIBUTE(RECONNECT_INITIATE,      FALSE)
+    ATTRIBUTE(VIRTUAL_CABLE,           SDP_TRUE)
+    ATTRIBUTE(RECONNECT_INITIATE,      SDP_FALSE)
     /* TODO: extract from hid->usbdev->report_desc */
     ATTRIBUTE(DESCRIPTOR_LIST,         LIST(
         LIST(UINT8(0x22) ARRAY(
@@ -883,12 +883,12 @@ SERVICE(hid,
     ATTRIBUTE(LANG_ID_BASE_LIST,       LIST(
         LIST(UINT16(0x0409) UINT16(0x0100))
     ))
-    ATTRIBUTE(SDP_DISABLE,             FALSE)
-    ATTRIBUTE(BATTERY_POWER,           TRUE)
-    ATTRIBUTE(REMOTE_WAKEUP,           TRUE)
-    ATTRIBUTE(BOOT_DEVICE,             TRUE)   /* XXX: untested */
+    ATTRIBUTE(SDP_DISABLE,             SDP_FALSE)
+    ATTRIBUTE(BATTERY_POWER,           SDP_TRUE)
+    ATTRIBUTE(REMOTE_WAKEUP,           SDP_TRUE)
+    ATTRIBUTE(BOOT_DEVICE,             SDP_TRUE)       /* XXX: untested */
     ATTRIBUTE(SUPERVISION_TIMEOUT,     UINT16(0x0c80))
-    ATTRIBUTE(NORMALLY_CONNECTABLE,    TRUE)
+    ATTRIBUTE(NORMALLY_CONNECTABLE,    SDP_TRUE)
     ATTRIBUTE(PROFILE_VERSION,         UINT16(0x0100))
 )
 
@@ -936,7 +936,7 @@ SERVICE(pnp,
     /* Profile specific */
     ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
     ATTRIBUTE(VERSION,         UINT16(0x0100))
-    ATTRIBUTE(PRIMARY_RECORD,  TRUE)
+    ATTRIBUTE(PRIMARY_RECORD,  SDP_TRUE)
 )
 
 static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
index bbd4b082d2718b13728c642980071353b758baa7..aadc56f692de44154de0f45ccd337b3c826472ae 100644 (file)
@@ -280,63 +280,63 @@ static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
 }
 
 #define ROP_NAME 0
-#define ROP_OP(d, s) d = 0
+#define ROP_FN(d, s) 0
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_and_dst
-#define ROP_OP(d, s) d = (s) & (d)
+#define ROP_FN(d, s) (s) & (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_and_notdst
-#define ROP_OP(d, s) d = (s) & (~(d))
+#define ROP_FN(d, s) (s) & (~(d))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notdst
-#define ROP_OP(d, s) d = ~(d)
+#define ROP_FN(d, s) ~(d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src
-#define ROP_OP(d, s) d = s
+#define ROP_FN(d, s) s
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME 1
-#define ROP_OP(d, s) d = ~0
+#define ROP_FN(d, s) ~0
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc_and_dst
-#define ROP_OP(d, s) d = (~(s)) & (d)
+#define ROP_FN(d, s) (~(s)) & (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_xor_dst
-#define ROP_OP(d, s) d = (s) ^ (d)
+#define ROP_FN(d, s) (s) ^ (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_or_dst
-#define ROP_OP(d, s) d = (s) | (d)
+#define ROP_FN(d, s) (s) | (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc_or_notdst
-#define ROP_OP(d, s) d = (~(s)) | (~(d))
+#define ROP_FN(d, s) (~(s)) | (~(d))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_notxor_dst
-#define ROP_OP(d, s) d = ~((s) ^ (d))
+#define ROP_FN(d, s) ~((s) ^ (d))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_or_notdst
-#define ROP_OP(d, s) d = (s) | (~(d))
+#define ROP_FN(d, s) (s) | (~(d))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc
-#define ROP_OP(d, s) d = (~(s))
+#define ROP_FN(d, s) (~(s))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc_or_dst
-#define ROP_OP(d, s) d = (~(s)) | (d)
+#define ROP_FN(d, s) (~(s)) | (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc_and_notdst
-#define ROP_OP(d, s) d = (~(s)) & (~(d))
+#define ROP_FN(d, s) (~(s)) & (~(d))
 #include "cirrus_vga_rop.h"
 
 static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
index 39a7b7285bef14797f5ea0252223f49846f5a8e4..9c7bb092862cc5f9a49b9a3d22f82a0336af1387 100644 (file)
  * THE SOFTWARE.
  */
 
+static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
+#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
+#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
+#undef ROP_FN
+
 static void
 glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
                              uint8_t *dst,const uint8_t *src,
@@ -39,7 +59,7 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
 
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
-            ROP_OP(*dst, *src);
+            ROP_OP(dst, *src);
             dst++;
             src++;
         }
@@ -59,7 +79,7 @@ glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
     srcpitch += bltwidth;
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
-            ROP_OP(*dst, *src);
+            ROP_OP(dst, *src);
             dst--;
             src--;
         }
@@ -81,7 +101,7 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
            p = *dst;
-            ROP_OP(p, *src);
+            ROP_OP(&p, *src);
            if (p != s->vga.gr[0x34]) *dst = p;
             dst++;
             src++;
@@ -104,7 +124,7 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
            p = *dst;
-            ROP_OP(p, *src);
+            ROP_OP(&p, *src);
            if (p != s->vga.gr[0x34]) *dst = p;
             dst--;
             src--;
@@ -128,8 +148,8 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
         for (x = 0; x < bltwidth; x+=2) {
            p1 = *dst;
            p2 = *(dst+1);
-            ROP_OP(p1, *src);
-            ROP_OP(p2, *(src+1));
+            ROP_OP(&p1, *src);
+            ROP_OP(&p2, *(src + 1));
            if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
                *dst = p1;
                *(dst+1) = p2;
@@ -156,8 +176,8 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
         for (x = 0; x < bltwidth; x+=2) {
            p1 = *(dst-1);
            p2 = *dst;
-            ROP_OP(p1, *(src-1));
-            ROP_OP(p2, *src);
+            ROP_OP(&p1, *(src - 1));
+            ROP_OP(&p2, *src);
            if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
                *(dst-1) = p1;
                *dst = p2;
@@ -184,3 +204,5 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
 
 #undef ROP_NAME
 #undef ROP_OP
+#undef ROP_OP_16
+#undef ROP_OP_32
index 81a5b398e090309dd74db232d17dbc61309fc8f3..d28bcc6f2580513cd2c3d1891fa15393b133bc08 100644 (file)
  */
 
 #if DEPTH == 8
-#define PUTPIXEL()    ROP_OP(d[0], col)
+#define PUTPIXEL()    ROP_OP(&d[0], col)
 #elif DEPTH == 16
-#define PUTPIXEL()    ROP_OP(((uint16_t *)d)[0], col);
+#define PUTPIXEL()    ROP_OP_16((uint16_t *)&d[0], col)
 #elif DEPTH == 24
-#define PUTPIXEL()    ROP_OP(d[0], col); \
-                      ROP_OP(d[1], (col >> 8)); \
-                      ROP_OP(d[2], (col >> 16))
+#define PUTPIXEL()    ROP_OP(&d[0], col);        \
+                      ROP_OP(&d[1], (col >> 8)); \
+                      ROP_OP(&d[2], (col >> 16))
 #elif DEPTH == 32
-#define PUTPIXEL()    ROP_OP(((uint32_t *)d)[0], col)
+#define PUTPIXEL()    ROP_OP_32(((uint32_t *)&d[0]), col)
 #else
 #error unsupported DEPTH
 #endif
index f7ce0af3f92be4c4c583bdccde9123cbe17d95e8..2977101e39ce838da49f43f0b098a5b51322060c 100644 (file)
@@ -23,9 +23,7 @@
  */
 
 #include "sysbus.h"
-
-/* debug CS4231 */
-//#define DEBUG_CS
+#include "trace.h"
 
 /*
  * In addition to Crystal CS4231 there is a DMA controller on Sparc.
@@ -46,13 +44,6 @@ typedef struct CSState {
 #define CS_VER 0xa0
 #define CS_CDC_VER 0x8a
 
-#ifdef DEBUG_CS
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("CS: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
 static void cs_reset(DeviceState *d)
 {
     CSState *s = container_of(d, CSState, busdev.qdev);
@@ -79,11 +70,11 @@ static uint32_t cs_mem_readl(void *opaque, target_phys_addr_t addr)
             ret = s->dregs[CS_RAP(s)];
             break;
         }
-        DPRINTF("read dreg[%d]: 0x%8.8x\n", CS_RAP(s), ret);
+        trace_cs4231_mem_readl_dreg(CS_RAP(s), ret);
         break;
     default:
         ret = s->regs[saddr];
-        DPRINTF("read reg[%d]: 0x%8.8x\n", saddr, ret);
+        trace_cs4231_mem_readl_reg(saddr, ret);
         break;
     }
     return ret;
@@ -95,11 +86,10 @@ static void cs_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     uint32_t saddr;
 
     saddr = addr >> 2;
-    DPRINTF("write reg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->regs[saddr], val);
+    trace_cs4231_mem_writel_reg(saddr, s->regs[saddr], val);
     switch (saddr) {
     case 1:
-        DPRINTF("write dreg[%d]: 0x%2.2x -> 0x%2.2x\n", CS_RAP(s),
-                s->dregs[CS_RAP(s)], val);
+        trace_cs4231_mem_writel_dreg(CS_RAP(s), s->dregs[CS_RAP(s)], val);
         switch(CS_RAP(s)) {
         case 11:
         case 25: // Read only
index ee49d5adf0d1ac7c85f1f8e76c7d6c05abc69a9a..aa07ab7d84d5675e563ede1e61ba6df1ac56c9a5 100644 (file)
@@ -27,6 +27,8 @@
 #include "sysbus.h"
 #include "pci.h"
 #include "pci_host.h"
+#include "pci_bridge.h"
+#include "pci_internals.h"
 
 /* debug DEC */
 //#define DEBUG_DEC
@@ -48,18 +50,43 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
     return irq_num;
 }
 
-PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
+static int dec_21154_initfn(PCIDevice *dev)
 {
-    DeviceState *dev;
-    PCIBus *ret;
+    int rc;
+
+    rc = pci_bridge_initfn(dev);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_DEC);
+    pci_config_set_device_id(dev->config, PCI_DEVICE_ID_DEC_21154);
+    return 0;
+}
 
-    dev = qdev_create(NULL, "dec-21154");
-    qdev_init_nofail(dev);
-    ret = pci_bridge_init(parent_bus, devfn, false,
-                          PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21154,
-                          dec_map_irq, "DEC 21154 PCI-PCI bridge");
+static PCIDeviceInfo dec_21154_pci_bridge_info = {
+    .qdev.name = "dec-21154-p2p-bridge",
+    .qdev.desc = "DEC 21154 PCI-PCI bridge",
+    .qdev.size = sizeof(PCIBridge),
+    .qdev.vmsd = &vmstate_pci_device,
+    .qdev.reset = pci_bridge_reset,
+    .init = dec_21154_initfn,
+    .exit = pci_bridge_exitfn,
+    .config_write = pci_bridge_write_config,
+    .is_bridge = 1,
+};
+
+PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
+{
+    PCIDevice *dev;
+    PCIBridge *br;
 
-    return ret;
+    dev = pci_create_multifunction(parent_bus, devfn, false,
+                                   "dec-21154-p2p-bridge");
+    br = DO_UPCAST(PCIBridge, dev, dev);
+    pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq);
+    qdev_init_nofail(&dev->qdev);
+    return pci_bridge_get_sec_bus(br);
 }
 
 static int pci_dec_21154_init_device(SysBusDevice *dev)
@@ -98,6 +125,7 @@ static void dec_register_devices(void)
     sysbus_register_dev("dec-21154", sizeof(DECState),
                         pci_dec_21154_init_device);
     pci_qdev_register(&dec_21154_pci_host_info);
+    pci_qdev_register(&dec_21154_pci_bridge_info);
 }
 
 device_init(dec_register_devices)
index 498c61a89c7b0d1d842a82aeaab7513b39609bad..a8042e94bc55bf1d9f408408c95d91b7b3d49dd6 100644 (file)
  */
 
 #include "sysbus.h"
-
-//#define DEBUG_ECC
-
-#ifdef DEBUG_ECC
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("ECC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
+#include "trace.h"
 
 /* There are 3 versions of this chip used in SMP sun4m systems:
  * MCC (version 0, implementation 0) SS-600MP
@@ -148,32 +140,32 @@ static void ecc_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
             s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1);
         else if (s->version == ECC_SMC)
             s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2);
-        DPRINTF("Write memory enable %08x\n", val);
+        trace_ecc_mem_writel_mer(val);
         break;
     case ECC_MDR:
         s->regs[ECC_MDR] =  val & ECC_MDR_MASK;
-        DPRINTF("Write memory delay %08x\n", val);
+        trace_ecc_mem_writel_mdr(val);
         break;
     case ECC_MFSR:
         s->regs[ECC_MFSR] =  val;
         qemu_irq_lower(s->irq);
-        DPRINTF("Write memory fault status %08x\n", val);
+        trace_ecc_mem_writel_mfsr(val);
         break;
     case ECC_VCR:
         s->regs[ECC_VCR] =  val;
-        DPRINTF("Write slot configuration %08x\n", val);
+        trace_ecc_mem_writel_vcr(val);
         break;
     case ECC_DR:
         s->regs[ECC_DR] =  val;
-        DPRINTF("Write diagnostic %08x\n", val);
+        trace_ecc_mem_writel_dr(val);
         break;
     case ECC_ECR0:
         s->regs[ECC_ECR0] =  val;
-        DPRINTF("Write event count 1 %08x\n", val);
+        trace_ecc_mem_writel_ecr0(val);
         break;
     case ECC_ECR1:
         s->regs[ECC_ECR0] =  val;
-        DPRINTF("Write event count 2 %08x\n", val);
+        trace_ecc_mem_writel_ecr1(val);
         break;
     }
 }
@@ -186,39 +178,39 @@ static uint32_t ecc_mem_readl(void *opaque, target_phys_addr_t addr)
     switch (addr >> 2) {
     case ECC_MER:
         ret = s->regs[ECC_MER];
-        DPRINTF("Read memory enable %08x\n", ret);
+        trace_ecc_mem_readl_mer(ret);
         break;
     case ECC_MDR:
         ret = s->regs[ECC_MDR];
-        DPRINTF("Read memory delay %08x\n", ret);
+        trace_ecc_mem_readl_mdr(ret);
         break;
     case ECC_MFSR:
         ret = s->regs[ECC_MFSR];
-        DPRINTF("Read memory fault status %08x\n", ret);
+        trace_ecc_mem_readl_mfsr(ret);
         break;
     case ECC_VCR:
         ret = s->regs[ECC_VCR];
-        DPRINTF("Read slot configuration %08x\n", ret);
+        trace_ecc_mem_readl_vcr(ret);
         break;
     case ECC_MFAR0:
         ret = s->regs[ECC_MFAR0];
-        DPRINTF("Read memory fault address 0 %08x\n", ret);
+        trace_ecc_mem_readl_mfar0(ret);
         break;
     case ECC_MFAR1:
         ret = s->regs[ECC_MFAR1];
-        DPRINTF("Read memory fault address 1 %08x\n", ret);
+        trace_ecc_mem_readl_mfar1(ret);
         break;
     case ECC_DR:
         ret = s->regs[ECC_DR];
-        DPRINTF("Read diagnostic %08x\n", ret);
+        trace_ecc_mem_readl_dr(ret);
         break;
     case ECC_ECR0:
         ret = s->regs[ECC_ECR0];
-        DPRINTF("Read event count 1 %08x\n", ret);
+        trace_ecc_mem_readl_ecr0(ret);
         break;
     case ECC_ECR1:
         ret = s->regs[ECC_ECR0];
-        DPRINTF("Read event count 2 %08x\n", ret);
+        trace_ecc_mem_readl_ecr1(ret);
         break;
     }
     return ret;
@@ -241,7 +233,7 @@ static void ecc_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
 {
     ECCState *s = opaque;
 
-    DPRINTF("Write diagnostic[%d] = %02x\n", (int)addr, val);
+    trace_ecc_diag_mem_writeb(addr, val);
     s->diag[addr & ECC_DIAG_MASK] = val;
 }
 
@@ -250,7 +242,7 @@ static uint32_t ecc_diag_mem_readb(void *opaque, target_phys_addr_t addr)
     ECCState *s = opaque;
     uint32_t ret = s->diag[(int)addr];
 
-    DPRINTF("Read diagnostic[%d] = %02x\n", (int)addr, ret);
+    trace_ecc_diag_mem_readb(addr, ret);
     return ret;
 }
 
index 2b75c8f495d059f97285503bb7cb8015ca16e9ed..41d792ad24e31994a21bf2e6eb3cd1bcb8a53fe0 100644 (file)
@@ -219,7 +219,8 @@ typedef enum {
 
 typedef struct {
     PCIDevice dev;
-    uint8_t mult[8];            /* multicast mask array */
+    /* Hash register (multicast mask array, multiple individual addresses). */
+    uint8_t mult[8];
     int mmio_index;
     NICState *nic;
     NICConf conf;
@@ -539,8 +540,8 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
     if (e100_device->power_management) {
         /* Power Management Capabilities */
         int cfg_offset = 0xdc;
-        int r = pci_add_capability_at_offset(&s->dev, PCI_CAP_ID_PM,
-                                             cfg_offset, PCI_PM_SIZEOF);
+        int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
+                                   cfg_offset, PCI_PM_SIZEOF);
         assert(r >= 0);
         pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
 #if 0 /* TODO: replace dummy code for power management emulation. */
@@ -599,7 +600,7 @@ static void nic_reset(void *opaque)
 {
     EEPRO100State *s = opaque;
     TRACE(OTHER, logout("%p\n", s));
-    /* TODO: Clearing of multicast table for selective reset, too? */
+    /* TODO: Clearing of hash register for selective reset, too? */
     memset(&s->mult[0], 0, sizeof(s->mult));
     nic_selective_reset(s);
 }
@@ -851,7 +852,14 @@ static void action_command(EEPRO100State *s)
         case CmdConfigure:
             cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
                                      sizeof(s->configuration));
-            TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16)));
+            TRACE(OTHER, logout("configuration: %s\n",
+                                nic_dump(&s->configuration[0], 16)));
+            TRACE(OTHER, logout("configuration: %s\n",
+                                nic_dump(&s->configuration[16],
+                                ARRAY_SIZE(s->configuration) - 16)));
+            if (s->configuration[20] & BIT(6)) {
+                TRACE(OTHER, logout("Multiple IA bit\n"));
+            }
             break;
         case CmdMulticastList:
             set_multicast_list(s);
@@ -1282,7 +1290,7 @@ static void eepro100_write_port(EEPRO100State * s, uint32_t val)
 
 static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
 {
-    uint8_t val;
+    uint8_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&val, &s->mem[addr], sizeof(val));
     }
@@ -1325,7 +1333,7 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
 
 static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
 {
-    uint16_t val;
+    uint16_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&val, &s->mem[addr], sizeof(val));
     }
@@ -1348,7 +1356,7 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
 
 static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
 {
-    uint32_t val;
+    uint32_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&val, &s->mem[addr], sizeof(val));
     }
@@ -1647,12 +1655,6 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
     static const uint8_t broadcast_macaddr[6] =
         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-    /* TODO: check multiple IA bit. */
-    if (s->configuration[20] & BIT(6)) {
-        missing("Multiple IA bit");
-        return -1;
-    }
-
     if (s->configuration[8] & 0x80) {
         /* CSMA is disabled. */
         logout("%p received while CSMA is disabled\n", s);
@@ -1702,6 +1704,16 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
         /* Promiscuous: receive all. */
         TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
         rfd_status |= 0x0004;
+    } else if (s->configuration[20] & BIT(6)) {
+        /* Multiple IA bit set. */
+        unsigned mcast_idx = compute_mcast_idx(buf);
+        assert(mcast_idx < 64);
+        if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+            TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
+        } else {
+            TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
+            return -1;
+        }
     } else {
         TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
               nic_dump(buf, size)));
index d91b7e79963a2ecd05654a28f6e1c67b1cf1233d..21d60b58556639e53eb00720da59ab03fdd87abc 100644 (file)
@@ -47,11 +47,14 @@ typedef struct FsCred
     dev_t   fc_rdev;
 } FsCred;
 
+struct xattr_operations;
+
 typedef struct FsContext
 {
     char *fs_root;
     SecModel fs_sm;
     uid_t uid;
+    struct xattr_operations **xops;
 } FsContext;
 
 extern void cred_init(FsCred *);
@@ -77,9 +80,8 @@ typedef struct FileOperations
     off_t (*telldir)(FsContext *, DIR *);
     struct dirent *(*readdir)(FsContext *, DIR *);
     void (*seekdir)(FsContext *, DIR *, off_t);
-    ssize_t (*readv)(FsContext *, int, const struct iovec *, int);
-    ssize_t (*writev)(FsContext *, int, const struct iovec *, int);
-    off_t (*lseek)(FsContext *, int, off_t, int);
+    ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
+    ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
     int (*mkdir)(FsContext *, const char *, FsCred *);
     int (*fstat)(FsContext *, int, struct stat *);
     int (*rename)(FsContext *, const char *, const char *);
@@ -94,4 +96,12 @@ typedef struct FileOperations
     int (*lremovexattr)(FsContext *, const char *, const char *);
     void *opaque;
 } FileOperations;
+
+static inline const char *rpath(FsContext *ctx, const char *path)
+{
+    /* FIXME: so wrong... */
+    static char buffer[4096];
+    snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
+    return buffer;
+}
 #endif
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
new file mode 100644 (file)
index 0000000..1035774
--- /dev/null
@@ -0,0 +1,902 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "pci.h"
+#include "intel-hda.h"
+#include "intel-hda-defs.h"
+#include "audio/audio.h"
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct desc_param {
+    uint32_t id;
+    uint32_t val;
+} desc_param;
+
+typedef struct desc_node {
+    uint32_t nid;
+    const char *name;
+    const desc_param *params;
+    uint32_t nparams;
+    uint32_t config;
+    uint32_t pinctl;
+    uint32_t *conn;
+    uint32_t stindex;
+} desc_node;
+
+typedef struct desc_codec {
+    const char *name;
+    uint32_t iid;
+    const desc_node *nodes;
+    uint32_t nnodes;
+} desc_codec;
+
+static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id)
+{
+    int i;
+
+    for (i = 0; i < node->nparams; i++) {
+        if (node->params[i].id == id) {
+            return &node->params[i];
+        }
+    }
+    return NULL;
+}
+
+static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid)
+{
+    int i;
+
+    for (i = 0; i < codec->nnodes; i++) {
+        if (codec->nodes[i].nid == nid) {
+            return &codec->nodes[i];
+        }
+    }
+    return NULL;
+}
+
+static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
+{
+    if (format & AC_FMT_TYPE_NON_PCM) {
+        return;
+    }
+
+    as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000;
+
+    switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) {
+    case 1: as->freq *= 2; break;
+    case 2: as->freq *= 3; break;
+    case 3: as->freq *= 4; break;
+    }
+
+    switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) {
+    case 1: as->freq /= 2; break;
+    case 2: as->freq /= 3; break;
+    case 3: as->freq /= 4; break;
+    case 4: as->freq /= 5; break;
+    case 5: as->freq /= 6; break;
+    case 6: as->freq /= 7; break;
+    case 7: as->freq /= 8; break;
+    }
+
+    switch (format & AC_FMT_BITS_MASK) {
+    case AC_FMT_BITS_8:  as->fmt = AUD_FMT_S8;  break;
+    case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break;
+    case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break;
+    }
+
+    as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1;
+}
+
+/* -------------------------------------------------------------------------- */
+/*
+ * HDA codec descriptions
+ */
+
+/* some defines */
+
+#define QEMU_HDA_ID_VENDOR  0x1af4
+#define QEMU_HDA_ID_OUTPUT  ((QEMU_HDA_ID_VENDOR << 16) | 0x10)
+#define QEMU_HDA_ID_DUPLEX  ((QEMU_HDA_ID_VENDOR << 16) | 0x20)
+
+#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 |       \
+                              0x1fc /* 16 -> 96 kHz */)
+#define QEMU_HDA_AMP_NONE    (0)
+#define QEMU_HDA_AMP_STEPS   0x4a
+
+#ifdef CONFIG_MIXEMU
+#define QEMU_HDA_AMP_CAPS                                               \
+    (AC_AMPCAP_MUTE |                                                   \
+     (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)    |                \
+     (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |                \
+     (3                  << AC_AMPCAP_STEP_SIZE_SHIFT))
+#else
+#define QEMU_HDA_AMP_CAPS    QEMU_HDA_AMP_NONE
+#endif
+
+/* common: audio output widget */
+static const desc_param common_params_audio_dac[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_FORMAT_OVRD |
+                AC_WCAP_AMP_OVRD |
+                AC_WCAP_OUT_AMP |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_CAPS,
+    },
+};
+
+/* common: pin widget (line-out) */
+static const desc_param common_params_audio_lineout[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_CONN_LIST |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PIN_CAP,
+        .val = AC_PINCAP_OUT,
+    },{
+        .id  = AC_PAR_CONNLIST_LEN,
+        .val = 1,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* output: root node */
+static const desc_param output_params_root[] = {
+    {
+        .id  = AC_PAR_VENDOR_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_REV_ID,
+        .val = 0x00100101,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00010001,
+    },
+};
+
+/* output: audio function */
+static const desc_param output_params_audio_func[] = {
+    {
+        .id  = AC_PAR_FUNCTION_TYPE,
+        .val = AC_GRP_AUDIO_FUNCTION,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00020002,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_GPIO_CAP,
+        .val = 0,
+    },{
+        .id  = AC_PAR_AUDIO_FG_CAP,
+        .val = 0x00000808,
+    },{
+        .id  = AC_PAR_POWER_STATE,
+        .val = 0,
+    },
+};
+
+/* output: nodes */
+static const desc_node output_nodes[] = {
+    {
+        .nid     = AC_NODE_ROOT,
+        .name    = "root",
+        .params  = output_params_root,
+        .nparams = ARRAY_SIZE(output_params_root),
+    },{
+        .nid     = 1,
+        .name    = "func",
+        .params  = output_params_audio_func,
+        .nparams = ARRAY_SIZE(output_params_audio_func),
+    },{
+        .nid     = 2,
+        .name    = "dac",
+        .params  = common_params_audio_dac,
+        .nparams = ARRAY_SIZE(common_params_audio_dac),
+        .stindex = 0,
+    },{
+        .nid     = 3,
+        .name    = "out",
+        .params  = common_params_audio_lineout,
+        .nparams = ARRAY_SIZE(common_params_audio_lineout),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_OUT     << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x10),
+        .pinctl  = AC_PINCTL_OUT_EN,
+        .conn    = (uint32_t[]) { 2 },
+    }
+};
+
+/* output: codec */
+static const desc_codec output = {
+    .name   = "output",
+    .iid    = QEMU_HDA_ID_OUTPUT,
+    .nodes  = output_nodes,
+    .nnodes = ARRAY_SIZE(output_nodes),
+};
+
+/* duplex: root node */
+static const desc_param duplex_params_root[] = {
+    {
+        .id  = AC_PAR_VENDOR_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_REV_ID,
+        .val = 0x00100101,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00010001,
+    },
+};
+
+/* duplex: audio input widget */
+static const desc_param duplex_params_audio_adc[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_CONN_LIST |
+                AC_WCAP_FORMAT_OVRD |
+                AC_WCAP_AMP_OVRD |
+                AC_WCAP_IN_AMP |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_CONNLIST_LEN,
+        .val = 1,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_CAPS,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* duplex: pin widget (line-in) */
+static const desc_param duplex_params_audio_linein[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PIN_CAP,
+        .val = AC_PINCAP_IN,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* duplex: audio function */
+static const desc_param duplex_params_audio_func[] = {
+    {
+        .id  = AC_PAR_FUNCTION_TYPE,
+        .val = AC_GRP_AUDIO_FUNCTION,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00020004,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_GPIO_CAP,
+        .val = 0,
+    },{
+        .id  = AC_PAR_AUDIO_FG_CAP,
+        .val = 0x00000808,
+    },{
+        .id  = AC_PAR_POWER_STATE,
+        .val = 0,
+    },
+};
+
+/* duplex: nodes */
+static const desc_node duplex_nodes[] = {
+    {
+        .nid     = AC_NODE_ROOT,
+        .name    = "root",
+        .params  = duplex_params_root,
+        .nparams = ARRAY_SIZE(duplex_params_root),
+    },{
+        .nid     = 1,
+        .name    = "func",
+        .params  = duplex_params_audio_func,
+        .nparams = ARRAY_SIZE(duplex_params_audio_func),
+    },{
+        .nid     = 2,
+        .name    = "dac",
+        .params  = common_params_audio_dac,
+        .nparams = ARRAY_SIZE(common_params_audio_dac),
+        .stindex = 0,
+    },{
+        .nid     = 3,
+        .name    = "out",
+        .params  = common_params_audio_lineout,
+        .nparams = ARRAY_SIZE(common_params_audio_lineout),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_OUT     << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x10),
+        .pinctl  = AC_PINCTL_OUT_EN,
+        .conn    = (uint32_t[]) { 2 },
+    },{
+        .nid     = 4,
+        .name    = "adc",
+        .params  = duplex_params_audio_adc,
+        .nparams = ARRAY_SIZE(duplex_params_audio_adc),
+        .stindex = 1,
+        .conn    = (uint32_t[]) { 5 },
+    },{
+        .nid     = 5,
+        .name    = "in",
+        .params  = duplex_params_audio_linein,
+        .nparams = ARRAY_SIZE(duplex_params_audio_linein),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_IN      << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_RED    << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x20),
+        .pinctl  = AC_PINCTL_IN_EN,
+    }
+};
+
+/* duplex: codec */
+static const desc_codec duplex = {
+    .name   = "duplex",
+    .iid    = QEMU_HDA_ID_DUPLEX,
+    .nodes  = duplex_nodes,
+    .nnodes = ARRAY_SIZE(duplex_nodes),
+};
+
+/* -------------------------------------------------------------------------- */
+
+static const char *fmt2name[] = {
+    [ AUD_FMT_U8  ] = "PCM-U8",
+    [ AUD_FMT_S8  ] = "PCM-S8",
+    [ AUD_FMT_U16 ] = "PCM-U16",
+    [ AUD_FMT_S16 ] = "PCM-S16",
+    [ AUD_FMT_U32 ] = "PCM-U32",
+    [ AUD_FMT_S32 ] = "PCM-S32",
+};
+
+typedef struct HDAAudioState HDAAudioState;
+typedef struct HDAAudioStream HDAAudioStream;
+
+struct HDAAudioStream {
+    HDAAudioState *state;
+    const desc_node *node;
+    bool output, running;
+    uint32_t stream;
+    uint32_t channel;
+    uint32_t format;
+    uint32_t gain_left, gain_right;
+    bool mute_left, mute_right;
+    struct audsettings as;
+    union {
+        SWVoiceIn *in;
+        SWVoiceOut *out;
+    } voice;
+    uint8_t buf[HDA_BUFFER_SIZE];
+    uint32_t bpos;
+};
+
+struct HDAAudioState {
+    HDACodecDevice hda;
+    const char *name;
+
+    QEMUSoundCard card;
+    const desc_codec *desc;
+    HDAAudioStream st[4];
+    bool running[16];
+
+    /* properties */
+    uint32_t debug;
+};
+
+static void hda_audio_input_cb(void *opaque, int avail)
+{
+    HDAAudioStream *st = opaque;
+    int recv = 0;
+    int len;
+    bool rc;
+
+    while (avail - recv >= sizeof(st->buf)) {
+        if (st->bpos != sizeof(st->buf)) {
+            len = AUD_read(st->voice.in, st->buf + st->bpos,
+                           sizeof(st->buf) - st->bpos);
+            st->bpos += len;
+            recv += len;
+            if (st->bpos != sizeof(st->buf)) {
+                break;
+            }
+        }
+        rc = hda_codec_xfer(&st->state->hda, st->stream, false,
+                            st->buf, sizeof(st->buf));
+        if (!rc) {
+            break;
+        }
+        st->bpos = 0;
+    }
+}
+
+static void hda_audio_output_cb(void *opaque, int avail)
+{
+    HDAAudioStream *st = opaque;
+    int sent = 0;
+    int len;
+    bool rc;
+
+    while (avail - sent >= sizeof(st->buf)) {
+        if (st->bpos == sizeof(st->buf)) {
+            rc = hda_codec_xfer(&st->state->hda, st->stream, true,
+                                st->buf, sizeof(st->buf));
+            if (!rc) {
+                break;
+            }
+            st->bpos = 0;
+        }
+        len = AUD_write(st->voice.out, st->buf + st->bpos,
+                        sizeof(st->buf) - st->bpos);
+        st->bpos += len;
+        sent += len;
+        if (st->bpos != sizeof(st->buf)) {
+            break;
+        }
+    }
+}
+
+static void hda_audio_set_running(HDAAudioStream *st, bool running)
+{
+    if (st->node == NULL) {
+        return;
+    }
+    if (st->running == running) {
+        return;
+    }
+    st->running = running;
+    dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name,
+           st->running ? "on" : "off", st->stream);
+    if (st->output) {
+        AUD_set_active_out(st->voice.out, st->running);
+    } else {
+        AUD_set_active_in(st->voice.in, st->running);
+    }
+}
+
+static void hda_audio_set_amp(HDAAudioStream *st)
+{
+    bool muted;
+    uint32_t left, right;
+
+    if (st->node == NULL) {
+        return;
+    }
+
+    muted = st->mute_left && st->mute_right;
+    left  = st->mute_left  ? 0 : st->gain_left;
+    right = st->mute_right ? 0 : st->gain_right;
+
+    left = left * 255 / QEMU_HDA_AMP_STEPS;
+    right = right * 255 / QEMU_HDA_AMP_STEPS;
+
+    if (st->output) {
+        AUD_set_volume_out(st->voice.out, muted, left, right);
+    } else {
+        AUD_set_volume_in(st->voice.in, muted, left, right);
+    }
+}
+
+static void hda_audio_setup(HDAAudioStream *st)
+{
+    if (st->node == NULL) {
+        return;
+    }
+
+    dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n",
+           st->node->name, st->as.nchannels,
+           fmt2name[st->as.fmt], st->as.freq);
+
+    if (st->output) {
+        st->voice.out = AUD_open_out(&st->state->card, st->voice.out,
+                                     st->node->name, st,
+                                     hda_audio_output_cb, &st->as);
+    } else {
+        st->voice.in = AUD_open_in(&st->state->card, st->voice.in,
+                                   st->node->name, st,
+                                   hda_audio_input_cb, &st->as);
+    }
+}
+
+static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    const desc_node *node = NULL;
+    const desc_param *param;
+    uint32_t verb, payload, response, count, shift;
+
+    if ((data & 0x70000) == 0x70000) {
+        /* 12/8 id/payload */
+        verb = (data >> 8) & 0xfff;
+        payload = data & 0x00ff;
+    } else {
+        /* 4/16 id/payload */
+        verb = (data >> 8) & 0xf00;
+        payload = data & 0xffff;
+    }
+
+    node = hda_codec_find_node(a->desc, nid);
+    if (node == NULL) {
+        goto fail;
+    }
+    dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n",
+           __FUNCTION__, nid, node->name, verb, payload);
+
+    switch (verb) {
+    /* all nodes */
+    case AC_VERB_PARAMETERS:
+        param = hda_codec_find_param(node, payload);
+        if (param == NULL) {
+            goto fail;
+        }
+        hda_codec_response(hda, true, param->val);
+        break;
+    case AC_VERB_GET_SUBSYSTEM_ID:
+        hda_codec_response(hda, true, a->desc->iid);
+        break;
+
+    /* all functions */
+    case AC_VERB_GET_CONNECT_LIST:
+        param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN);
+        count = param ? param->val : 0;
+        response = 0;
+        shift = 0;
+        while (payload < count && shift < 32) {
+            response |= node->conn[payload] << shift;
+            payload++;
+            shift += 8;
+        }
+        hda_codec_response(hda, true, response);
+        break;
+
+    /* pin widget */
+    case AC_VERB_GET_CONFIG_DEFAULT:
+        hda_codec_response(hda, true, node->config);
+        break;
+    case AC_VERB_GET_PIN_WIDGET_CONTROL:
+        hda_codec_response(hda, true, node->pinctl);
+        break;
+    case AC_VERB_SET_PIN_WIDGET_CONTROL:
+        if (node->pinctl != payload) {
+            dprint(a, 1, "unhandled pin control bit\n");
+        }
+        hda_codec_response(hda, true, 0);
+        break;
+
+    /* audio in/out widget */
+    case AC_VERB_SET_CHANNEL_STREAMID:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        hda_audio_set_running(st, false);
+        st->stream = (payload >> 4) & 0x0f;
+        st->channel = payload & 0x0f;
+        dprint(a, 2, "%s: stream %d, channel %d\n",
+               st->node->name, st->stream, st->channel);
+        hda_audio_set_running(st, a->running[st->stream]);
+        hda_codec_response(hda, true, 0);
+        break;
+    case AC_VERB_GET_CONV:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        response = st->stream << 4 | st->channel;
+        hda_codec_response(hda, true, response);
+        break;
+    case AC_VERB_SET_STREAM_FORMAT:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        st->format = payload;
+        hda_codec_parse_fmt(st->format, &st->as);
+        hda_audio_setup(st);
+        hda_codec_response(hda, true, 0);
+        break;
+    case AC_VERB_GET_STREAM_FORMAT:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        hda_codec_response(hda, true, st->format);
+        break;
+    case AC_VERB_GET_AMP_GAIN_MUTE:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        if (payload & AC_AMP_GET_LEFT) {
+            response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0);
+        } else {
+            response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0);
+        }
+        hda_codec_response(hda, true, response);
+        break;
+    case AC_VERB_SET_AMP_GAIN_MUTE:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        dprint(a, 1, "amp (%s): %s%s%s%s index %d  gain %3d %s\n",
+               st->node->name,
+               (payload & AC_AMP_SET_OUTPUT) ? "o" : "-",
+               (payload & AC_AMP_SET_INPUT)  ? "i" : "-",
+               (payload & AC_AMP_SET_LEFT)   ? "l" : "-",
+               (payload & AC_AMP_SET_RIGHT)  ? "r" : "-",
+               (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT,
+               (payload & AC_AMP_GAIN),
+               (payload & AC_AMP_MUTE) ? "muted" : "");
+        if (payload & AC_AMP_SET_LEFT) {
+            st->gain_left = payload & AC_AMP_GAIN;
+            st->mute_left = payload & AC_AMP_MUTE;
+        }
+        if (payload & AC_AMP_SET_RIGHT) {
+            st->gain_right = payload & AC_AMP_GAIN;
+            st->mute_right = payload & AC_AMP_MUTE;
+        }
+        hda_audio_set_amp(st);
+        hda_codec_response(hda, true, 0);
+        break;
+
+    /* not supported */
+    case AC_VERB_SET_POWER_STATE:
+    case AC_VERB_GET_POWER_STATE:
+    case AC_VERB_GET_SDI_SELECT:
+        hda_codec_response(hda, true, 0);
+        break;
+    default:
+        goto fail;
+    }
+    return;
+
+fail:
+    dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n",
+           __FUNCTION__, nid, node ? node->name : "?", verb, payload);
+    hda_codec_response(hda, true, 0);
+}
+
+static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    int s;
+
+    a->running[stnr] = running;
+    for (s = 0; s < ARRAY_SIZE(a->st); s++) {
+        if (a->st[s].node == NULL) {
+            continue;
+        }
+        if (a->st[s].stream != stnr) {
+            continue;
+        }
+        hda_audio_set_running(&a->st[s], running);
+    }
+}
+
+static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    const desc_node *node;
+    const desc_param *param;
+    uint32_t i, type;
+
+    a->desc = desc;
+    a->name = a->hda.qdev.info->name;
+    dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
+
+    AUD_register_card("hda", &a->card);
+    for (i = 0; i < a->desc->nnodes; i++) {
+        node = a->desc->nodes + i;
+        param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP);
+        if (NULL == param)
+            continue;
+        type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+        switch (type) {
+        case AC_WID_AUD_OUT:
+        case AC_WID_AUD_IN:
+            assert(node->stindex < ARRAY_SIZE(a->st));
+            st = a->st + node->stindex;
+            st->state = a;
+            st->node = node;
+            if (type == AC_WID_AUD_OUT) {
+                /* unmute output by default */
+                st->gain_left = QEMU_HDA_AMP_STEPS;
+                st->gain_right = QEMU_HDA_AMP_STEPS;
+                st->bpos = sizeof(st->buf);
+                st->output = true;
+            } else {
+                st->output = false;
+            }
+            st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 |
+                (1 << AC_FMT_CHAN_SHIFT);
+            hda_codec_parse_fmt(st->format, &st->as);
+            hda_audio_setup(st);
+            break;
+        }
+    }
+    return 0;
+}
+
+static int hda_audio_post_load(void *opaque, int version)
+{
+    HDAAudioState *a = opaque;
+    HDAAudioStream *st;
+    int i;
+
+    dprint(a, 1, "%s\n", __FUNCTION__);
+    for (i = 0; i < ARRAY_SIZE(a->st); i++) {
+        st = a->st + i;
+        if (st->node == NULL)
+            continue;
+        hda_codec_parse_fmt(st->format, &st->as);
+        hda_audio_setup(st);
+        hda_audio_set_amp(st);
+        hda_audio_set_running(st, a->running[st->stream]);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_hda_audio_stream = {
+    .name = "hda-audio-stream",
+    .version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32(stream, HDAAudioStream),
+        VMSTATE_UINT32(channel, HDAAudioStream),
+        VMSTATE_UINT32(format, HDAAudioStream),
+        VMSTATE_UINT32(gain_left, HDAAudioStream),
+        VMSTATE_UINT32(gain_right, HDAAudioStream),
+        VMSTATE_BOOL(mute_left, HDAAudioStream),
+        VMSTATE_BOOL(mute_right, HDAAudioStream),
+        VMSTATE_UINT32(bpos, HDAAudioStream),
+        VMSTATE_BUFFER(buf, HDAAudioStream),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_hda_audio = {
+    .name = "hda-audio",
+    .version_id = 1,
+    .post_load = hda_audio_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
+                             vmstate_hda_audio_stream,
+                             HDAAudioStream),
+        VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property hda_audio_properties[] = {
+    DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int hda_audio_init_output(HDACodecDevice *hda)
+{
+    return hda_audio_init(hda, &output);
+}
+
+static int hda_audio_init_duplex(HDACodecDevice *hda)
+{
+    return hda_audio_init(hda, &duplex);
+}
+
+static HDACodecDeviceInfo hda_audio_info_output = {
+    .qdev.name    = "hda-output",
+    .qdev.desc    = "HDA Audio Codec, output-only",
+    .qdev.size    = sizeof(HDAAudioState),
+    .qdev.vmsd    = &vmstate_hda_audio,
+    .qdev.props   = hda_audio_properties,
+    .init         = hda_audio_init_output,
+    .command      = hda_audio_command,
+    .stream       = hda_audio_stream,
+};
+
+static HDACodecDeviceInfo hda_audio_info_duplex = {
+    .qdev.name    = "hda-duplex",
+    .qdev.desc    = "HDA Audio Codec, duplex",
+    .qdev.size    = sizeof(HDAAudioState),
+    .qdev.vmsd    = &vmstate_hda_audio,
+    .qdev.props   = hda_audio_properties,
+    .init         = hda_audio_init_duplex,
+    .command      = hda_audio_command,
+    .stream       = hda_audio_stream,
+};
+
+static void hda_audio_register(void)
+{
+    hda_codec_register(&hda_audio_info_output);
+    hda_codec_register(&hda_audio_info_duplex);
+}
+device_init(hda_audio_register);
diff --git a/hw/hw.h b/hw/hw.h
index 4405092b54a2d681cb0f5570eba9d6bad2b6d8eb..9d2cfc219cc7774c367a35cc56bf6817792294f1 100644 (file)
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -333,6 +333,8 @@ struct VMStateDescription {
     const VMStateSubsection *subsections;
 };
 
+extern const VMStateInfo vmstate_info_bool;
+
 extern const VMStateInfo vmstate_info_int8;
 extern const VMStateInfo vmstate_info_int16;
 extern const VMStateInfo vmstate_info_int32;
@@ -602,6 +604,9 @@ extern const VMStateDescription vmstate_i2c_slave;
 #define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type)          \
     VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type)
 
+#define VMSTATE_BOOL_V(_f, _s, _v)                                    \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)
+
 #define VMSTATE_INT8_V(_f, _s, _v)                                    \
     VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t)
 #define VMSTATE_INT16_V(_f, _s, _v)                                   \
@@ -620,6 +625,9 @@ extern const VMStateDescription vmstate_i2c_slave;
 #define VMSTATE_UINT64_V(_f, _s, _v)                                  \
     VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t)
 
+#define VMSTATE_BOOL(_f, _s)                                          \
+    VMSTATE_BOOL_V(_f, _s, 0)
+
 #define VMSTATE_INT8(_f, _s)                                          \
     VMSTATE_INT8_V(_f, _s, 0)
 #define VMSTATE_INT16(_f, _s)                                         \
@@ -674,6 +682,12 @@ extern const VMStateDescription vmstate_i2c_slave;
 #define VMSTATE_PTIMER(_f, _s)                                        \
     VMSTATE_PTIMER_V(_f, _s, 0)
 
+#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_BOOL_ARRAY(_f, _s, _n)                               \
+    VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
+
 #define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v)                         \
     VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
 
index 06b6e14e56850788c046c04a57ee58477a226e40..bc3e91658ab46cbfcbf4761aec24cb2f7c8c68ce 100644 (file)
@@ -65,6 +65,7 @@ static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);
 static void ide_dma_restart(IDEState *s, int is_read);
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
 static int ide_handle_rw_error(IDEState *s, int error, int op);
+static void ide_flush_cache(IDEState *s);
 
 static void padstr(char *str, const char *src, int len)
 {
@@ -146,8 +147,8 @@ static void ide_identify(IDEState *s)
     put_le16(p + 68, 120);
     put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
     put_le16(p + 81, 0x16); /* conforms to ata5 */
-    /* 14=NOP supported, 0=SMART supported */
-    put_le16(p + 82, (1 << 14) | 1);
+    /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */
+    put_le16(p + 82, (1 << 14) | (1 << 5) | 1);
     /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
     put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
     /* 14=set to 1, 1=SMART self test, 0=SMART error logging */
@@ -688,6 +689,8 @@ static void ide_dma_restart_bh(void *opaque)
         } else {
             ide_sector_write(bmdma_active_if(bm));
         }
+    } else if (bm->status & BM_STATUS_RETRY_FLUSH) {
+        ide_flush_cache(bmdma_active_if(bm));
     }
 }
 
@@ -795,12 +798,26 @@ static void ide_flush_cb(void *opaque, int ret)
 {
     IDEState *s = opaque;
 
-    /* XXX: how do we signal I/O errors here? */
+    if (ret < 0) {
+        /* XXX: What sector number to set here? */
+        if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) {
+            return;
+        }
+    }
 
     s->status = READY_STAT | SEEK_STAT;
     ide_set_irq(s->bus);
 }
 
+static void ide_flush_cache(IDEState *s)
+{
+    if (s->bs) {
+        bdrv_aio_flush(s->bs, ide_flush_cb, s);
+    } else {
+        ide_flush_cb(s, 0);
+    }
+}
+
 static inline void cpu_to_ube16(uint8_t *buf, int val)
 {
     buf[0] = val >> 8;
@@ -2031,10 +2048,7 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             break;
         case WIN_FLUSH_CACHE:
         case WIN_FLUSH_CACHE_EXT:
-            if (s->bs)
-                bdrv_aio_flush(s->bs, ide_flush_cb, s);
-            else
-                ide_flush_cb(s, 0);
+            ide_flush_cache(s);
             break;
         case WIN_STANDBY:
         case WIN_STANDBY2:
index 416554324c618844d21319c849b6341963b56aa2..d652e06c45c548ce4edabe5ea16e441c139268f9 100644 (file)
@@ -472,7 +472,8 @@ struct IDEDeviceInfo {
 #define BM_STATUS_INT    0x04
 #define BM_STATUS_DMA_RETRY  0x08
 #define BM_STATUS_PIO_RETRY  0x10
-#define BM_STATUS_RETRY_READ 0x20
+#define BM_STATUS_RETRY_READ  0x20
+#define BM_STATUS_RETRY_FLUSH 0x40
 
 #define BM_CMD_START     0x01
 #define BM_CMD_READ      0x08
diff --git a/hw/intel-hda-defs.h b/hw/intel-hda-defs.h
new file mode 100644 (file)
index 0000000..2e37e5b
--- /dev/null
@@ -0,0 +1,717 @@
+#ifndef HW_INTEL_HDA_DEFS_H
+#define HW_INTEL_HDA_DEFS_H
+
+/* qemu */
+#define HDA_BUFFER_SIZE 256
+
+/* --------------------------------------------------------------------- */
+/* from linux/sound/pci/hda/hda_intel.c                                  */
+
+/*
+ * registers
+ */
+#define ICH6_REG_GCAP                  0x00
+#define   ICH6_GCAP_64OK       (1 << 0)   /* 64bit address support */
+#define   ICH6_GCAP_NSDO       (3 << 1)   /* # of serial data out signals */
+#define   ICH6_GCAP_BSS                (31 << 3)  /* # of bidirectional streams */
+#define   ICH6_GCAP_ISS                (15 << 8)  /* # of input streams */
+#define   ICH6_GCAP_OSS                (15 << 12) /* # of output streams */
+#define ICH6_REG_VMIN                  0x02
+#define ICH6_REG_VMAJ                  0x03
+#define ICH6_REG_OUTPAY                        0x04
+#define ICH6_REG_INPAY                 0x06
+#define ICH6_REG_GCTL                  0x08
+#define   ICH6_GCTL_RESET      (1 << 0)   /* controller reset */
+#define   ICH6_GCTL_FCNTRL     (1 << 1)   /* flush control */
+#define   ICH6_GCTL_UNSOL      (1 << 8)   /* accept unsol. response enable */
+#define ICH6_REG_WAKEEN                        0x0c
+#define ICH6_REG_STATESTS              0x0e
+#define ICH6_REG_GSTS                  0x10
+#define   ICH6_GSTS_FSTS       (1 << 1)   /* flush status */
+#define ICH6_REG_INTCTL                        0x20
+#define ICH6_REG_INTSTS                        0x24
+#define ICH6_REG_WALLCLK               0x30    /* 24Mhz source */
+#define ICH6_REG_SYNC                  0x34
+#define ICH6_REG_CORBLBASE             0x40
+#define ICH6_REG_CORBUBASE             0x44
+#define ICH6_REG_CORBWP                        0x48
+#define ICH6_REG_CORBRP                        0x4a
+#define   ICH6_CORBRP_RST      (1 << 15)  /* read pointer reset */
+#define ICH6_REG_CORBCTL               0x4c
+#define   ICH6_CORBCTL_RUN     (1 << 1)   /* enable DMA */
+#define   ICH6_CORBCTL_CMEIE   (1 << 0)   /* enable memory error irq */
+#define ICH6_REG_CORBSTS               0x4d
+#define   ICH6_CORBSTS_CMEI    (1 << 0)   /* memory error indication */
+#define ICH6_REG_CORBSIZE              0x4e
+
+#define ICH6_REG_RIRBLBASE             0x50
+#define ICH6_REG_RIRBUBASE             0x54
+#define ICH6_REG_RIRBWP                        0x58
+#define   ICH6_RIRBWP_RST      (1 << 15)  /* write pointer reset */
+#define ICH6_REG_RINTCNT               0x5a
+#define ICH6_REG_RIRBCTL               0x5c
+#define   ICH6_RBCTL_IRQ_EN    (1 << 0)   /* enable IRQ */
+#define   ICH6_RBCTL_DMA_EN    (1 << 1)   /* enable DMA */
+#define   ICH6_RBCTL_OVERRUN_EN        (1 << 2)   /* enable overrun irq */
+#define ICH6_REG_RIRBSTS               0x5d
+#define   ICH6_RBSTS_IRQ       (1 << 0)   /* response irq */
+#define   ICH6_RBSTS_OVERRUN   (1 << 2)   /* overrun irq */
+#define ICH6_REG_RIRBSIZE              0x5e
+
+#define ICH6_REG_IC                    0x60
+#define ICH6_REG_IR                    0x64
+#define ICH6_REG_IRS                   0x68
+#define   ICH6_IRS_VALID       (1<<1)
+#define   ICH6_IRS_BUSY                (1<<0)
+
+#define ICH6_REG_DPLBASE               0x70
+#define ICH6_REG_DPUBASE               0x74
+#define   ICH6_DPLBASE_ENABLE  0x1     /* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define ICH6_REG_SD_CTL                        0x00
+#define ICH6_REG_SD_STS                        0x03
+#define ICH6_REG_SD_LPIB               0x04
+#define ICH6_REG_SD_CBL                        0x08
+#define ICH6_REG_SD_LVI                        0x0c
+#define ICH6_REG_SD_FIFOW              0x0e
+#define ICH6_REG_SD_FIFOSIZE           0x10
+#define ICH6_REG_SD_FORMAT             0x12
+#define ICH6_REG_SD_BDLPL              0x18
+#define ICH6_REG_SD_BDLPU              0x1c
+
+/* PCI space */
+#define ICH6_PCIREG_TCSEL      0x44
+
+/*
+ * other constants
+ */
+
+/* max number of SDs */
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_NUM_CAPTURE       4
+#define ICH6_NUM_PLAYBACK      4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_NUM_CAPTURE                5
+#define ULI_NUM_PLAYBACK       6
+
+/* ATI HDMI has 1 playback and 0 capture */
+#define ATIHDMI_NUM_CAPTURE    0
+#define ATIHDMI_NUM_PLAYBACK   1
+
+/* TERA has 4 playback and 3 capture */
+#define TERA_NUM_CAPTURE       3
+#define TERA_NUM_PLAYBACK      4
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV            16
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE               4096
+#define AZX_MAX_BDL_ENTRIES    (BDL_SIZE / 16)
+#define AZX_MAX_FRAG           32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE       (1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE      0x01
+#define RIRB_INT_OVERRUN       0x04
+#define RIRB_INT_MASK          0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS         8
+#define AZX_DEFAULT_CODECS     4
+#define STATESTS_INT_MASK      ((1 << AZX_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
+#define SD_CTL_DMA_START       0x02    /* stream DMA start bit */
+#define SD_CTL_STRIPE          (3 << 16)       /* stripe control */
+#define SD_CTL_TRAFFIC_PRIO    (1 << 18)       /* traffic priority */
+#define SD_CTL_DIR             (1 << 19)       /* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT        20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR                0x10    /* descriptor error interrupt */
+#define SD_INT_FIFO_ERR                0x08    /* FIFO error interrupt */
+#define SD_INT_COMPLETE                0x04    /* completion interrupt */
+#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+                                SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY      0x20    /* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define ICH6_INT_ALL_STREAM    0xff       /* all stream interrupts */
+#define ICH6_INT_CTRL_EN       0x40000000 /* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN     0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define ICH6_MAX_CORB_ENTRIES  256
+#define ICH6_MAX_RIRB_ENTRIES  256
+
+/* position fix mode */
+enum {
+       POS_FIX_AUTO,
+       POS_FIX_LPIB,
+       POS_FIX_POSBUF,
+};
+
+/* Defines for ATI HD Audio support in SB450 south bridge */
+#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
+#define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
+
+/* Defines for Nvidia HDA support */
+#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
+#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
+#define NVIDIA_HDA_ISTRM_COH          0x4d
+#define NVIDIA_HDA_OSTRM_COH          0x4c
+#define NVIDIA_HDA_ENABLE_COHBIT      0x01
+
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC      0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
+
+/* Define IN stream 0 FIFO size offset in VIA controller */
+#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET        0x90
+/* Define VIA HD Audio Device ID*/
+#define VIA_HDAC_DEVICE_ID             0x3288
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
+
+/* --------------------------------------------------------------------- */
+/* from linux/sound/pci/hda/hda_codec.h                                  */
+
+/*
+ * nodes
+ */
+#define        AC_NODE_ROOT            0x00
+
+/*
+ * function group types
+ */
+enum {
+       AC_GRP_AUDIO_FUNCTION = 0x01,
+       AC_GRP_MODEM_FUNCTION = 0x02,
+};
+       
+/*
+ * widget types
+ */
+enum {
+       AC_WID_AUD_OUT,         /* Audio Out */
+       AC_WID_AUD_IN,          /* Audio In */
+       AC_WID_AUD_MIX,         /* Audio Mixer */
+       AC_WID_AUD_SEL,         /* Audio Selector */
+       AC_WID_PIN,             /* Pin Complex */
+       AC_WID_POWER,           /* Power */
+       AC_WID_VOL_KNB,         /* Volume Knob */
+       AC_WID_BEEP,            /* Beep Generator */
+       AC_WID_VENDOR = 0x0f    /* Vendor specific */
+};
+
+/*
+ * GET verbs
+ */
+#define AC_VERB_GET_STREAM_FORMAT              0x0a00
+#define AC_VERB_GET_AMP_GAIN_MUTE              0x0b00
+#define AC_VERB_GET_PROC_COEF                  0x0c00
+#define AC_VERB_GET_COEF_INDEX                 0x0d00
+#define AC_VERB_PARAMETERS                     0x0f00
+#define AC_VERB_GET_CONNECT_SEL                        0x0f01
+#define AC_VERB_GET_CONNECT_LIST               0x0f02
+#define AC_VERB_GET_PROC_STATE                 0x0f03
+#define AC_VERB_GET_SDI_SELECT                 0x0f04
+#define AC_VERB_GET_POWER_STATE                        0x0f05
+#define AC_VERB_GET_CONV                       0x0f06
+#define AC_VERB_GET_PIN_WIDGET_CONTROL         0x0f07
+#define AC_VERB_GET_UNSOLICITED_RESPONSE       0x0f08
+#define AC_VERB_GET_PIN_SENSE                  0x0f09
+#define AC_VERB_GET_BEEP_CONTROL               0x0f0a
+#define AC_VERB_GET_EAPD_BTLENABLE             0x0f0c
+#define AC_VERB_GET_DIGI_CONVERT_1             0x0f0d
+#define AC_VERB_GET_DIGI_CONVERT_2             0x0f0e /* unused */
+#define AC_VERB_GET_VOLUME_KNOB_CONTROL                0x0f0f
+/* f10-f1a: GPIO */
+#define AC_VERB_GET_GPIO_DATA                  0x0f15
+#define AC_VERB_GET_GPIO_MASK                  0x0f16
+#define AC_VERB_GET_GPIO_DIRECTION             0x0f17
+#define AC_VERB_GET_GPIO_WAKE_MASK             0x0f18
+#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK  0x0f19
+#define AC_VERB_GET_GPIO_STICKY_MASK           0x0f1a
+#define AC_VERB_GET_CONFIG_DEFAULT             0x0f1c
+/* f20: AFG/MFG */
+#define AC_VERB_GET_SUBSYSTEM_ID               0x0f20
+#define AC_VERB_GET_CVT_CHAN_COUNT             0x0f2d
+#define AC_VERB_GET_HDMI_DIP_SIZE              0x0f2e
+#define AC_VERB_GET_HDMI_ELDD                  0x0f2f
+#define AC_VERB_GET_HDMI_DIP_INDEX             0x0f30
+#define AC_VERB_GET_HDMI_DIP_DATA              0x0f31
+#define AC_VERB_GET_HDMI_DIP_XMIT              0x0f32
+#define AC_VERB_GET_HDMI_CP_CTRL               0x0f33
+#define AC_VERB_GET_HDMI_CHAN_SLOT             0x0f34
+
+/*
+ * SET verbs
+ */
+#define AC_VERB_SET_STREAM_FORMAT              0x200
+#define AC_VERB_SET_AMP_GAIN_MUTE              0x300
+#define AC_VERB_SET_PROC_COEF                  0x400
+#define AC_VERB_SET_COEF_INDEX                 0x500
+#define AC_VERB_SET_CONNECT_SEL                        0x701
+#define AC_VERB_SET_PROC_STATE                 0x703
+#define AC_VERB_SET_SDI_SELECT                 0x704
+#define AC_VERB_SET_POWER_STATE                        0x705
+#define AC_VERB_SET_CHANNEL_STREAMID           0x706
+#define AC_VERB_SET_PIN_WIDGET_CONTROL         0x707
+#define AC_VERB_SET_UNSOLICITED_ENABLE         0x708
+#define AC_VERB_SET_PIN_SENSE                  0x709
+#define AC_VERB_SET_BEEP_CONTROL               0x70a
+#define AC_VERB_SET_EAPD_BTLENABLE             0x70c
+#define AC_VERB_SET_DIGI_CONVERT_1             0x70d
+#define AC_VERB_SET_DIGI_CONVERT_2             0x70e
+#define AC_VERB_SET_VOLUME_KNOB_CONTROL                0x70f
+#define AC_VERB_SET_GPIO_DATA                  0x715
+#define AC_VERB_SET_GPIO_MASK                  0x716
+#define AC_VERB_SET_GPIO_DIRECTION             0x717
+#define AC_VERB_SET_GPIO_WAKE_MASK             0x718
+#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK  0x719
+#define AC_VERB_SET_GPIO_STICKY_MASK           0x71a
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0     0x71c
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1     0x71d
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2     0x71e
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3     0x71f
+#define AC_VERB_SET_EAPD                               0x788
+#define AC_VERB_SET_CODEC_RESET                        0x7ff
+#define AC_VERB_SET_CVT_CHAN_COUNT             0x72d
+#define AC_VERB_SET_HDMI_DIP_INDEX             0x730
+#define AC_VERB_SET_HDMI_DIP_DATA              0x731
+#define AC_VERB_SET_HDMI_DIP_XMIT              0x732
+#define AC_VERB_SET_HDMI_CP_CTRL               0x733
+#define AC_VERB_SET_HDMI_CHAN_SLOT             0x734
+
+/*
+ * Parameter IDs
+ */
+#define AC_PAR_VENDOR_ID               0x00
+#define AC_PAR_SUBSYSTEM_ID            0x01
+#define AC_PAR_REV_ID                  0x02
+#define AC_PAR_NODE_COUNT              0x04
+#define AC_PAR_FUNCTION_TYPE           0x05
+#define AC_PAR_AUDIO_FG_CAP            0x08
+#define AC_PAR_AUDIO_WIDGET_CAP                0x09
+#define AC_PAR_PCM                     0x0a
+#define AC_PAR_STREAM                  0x0b
+#define AC_PAR_PIN_CAP                 0x0c
+#define AC_PAR_AMP_IN_CAP              0x0d
+#define AC_PAR_CONNLIST_LEN            0x0e
+#define AC_PAR_POWER_STATE             0x0f
+#define AC_PAR_PROC_CAP                        0x10
+#define AC_PAR_GPIO_CAP                        0x11
+#define AC_PAR_AMP_OUT_CAP             0x12
+#define AC_PAR_VOL_KNB_CAP             0x13
+#define AC_PAR_HDMI_LPCM_CAP           0x20
+
+/*
+ * AC_VERB_PARAMETERS results (32bit)
+ */
+
+/* Function Group Type */
+#define AC_FGT_TYPE                    (0xff<<0)
+#define AC_FGT_TYPE_SHIFT              0
+#define AC_FGT_UNSOL_CAP               (1<<8)
+
+/* Audio Function Group Capabilities */
+#define AC_AFG_OUT_DELAY               (0xf<<0)
+#define AC_AFG_IN_DELAY                        (0xf<<8)
+#define AC_AFG_BEEP_GEN                        (1<<16)
+
+/* Audio Widget Capabilities */
+#define AC_WCAP_STEREO                 (1<<0)  /* stereo I/O */
+#define AC_WCAP_IN_AMP                 (1<<1)  /* AMP-in present */
+#define AC_WCAP_OUT_AMP                        (1<<2)  /* AMP-out present */
+#define AC_WCAP_AMP_OVRD               (1<<3)  /* AMP-parameter override */
+#define AC_WCAP_FORMAT_OVRD            (1<<4)  /* format override */
+#define AC_WCAP_STRIPE                 (1<<5)  /* stripe */
+#define AC_WCAP_PROC_WID               (1<<6)  /* Proc Widget */
+#define AC_WCAP_UNSOL_CAP              (1<<7)  /* Unsol capable */
+#define AC_WCAP_CONN_LIST              (1<<8)  /* connection list */
+#define AC_WCAP_DIGITAL                        (1<<9)  /* digital I/O */
+#define AC_WCAP_POWER                  (1<<10) /* power control */
+#define AC_WCAP_LR_SWAP                        (1<<11) /* L/R swap */
+#define AC_WCAP_CP_CAPS                        (1<<12) /* content protection */
+#define AC_WCAP_CHAN_CNT_EXT           (7<<13) /* channel count ext */
+#define AC_WCAP_DELAY                  (0xf<<16)
+#define AC_WCAP_DELAY_SHIFT            16
+#define AC_WCAP_TYPE                   (0xf<<20)
+#define AC_WCAP_TYPE_SHIFT             20
+
+/* supported PCM rates and bits */
+#define AC_SUPPCM_RATES                        (0xfff << 0)
+#define AC_SUPPCM_BITS_8               (1<<16)
+#define AC_SUPPCM_BITS_16              (1<<17)
+#define AC_SUPPCM_BITS_20              (1<<18)
+#define AC_SUPPCM_BITS_24              (1<<19)
+#define AC_SUPPCM_BITS_32              (1<<20)
+
+/* supported PCM stream format */
+#define AC_SUPFMT_PCM                  (1<<0)
+#define AC_SUPFMT_FLOAT32              (1<<1)
+#define AC_SUPFMT_AC3                  (1<<2)
+
+/* GP I/O count */
+#define AC_GPIO_IO_COUNT               (0xff<<0)
+#define AC_GPIO_O_COUNT                        (0xff<<8)
+#define AC_GPIO_O_COUNT_SHIFT          8
+#define AC_GPIO_I_COUNT                        (0xff<<16)
+#define AC_GPIO_I_COUNT_SHIFT          16
+#define AC_GPIO_UNSOLICITED            (1<<30)
+#define AC_GPIO_WAKE                   (1<<31)
+
+/* Converter stream, channel */
+#define AC_CONV_CHANNEL                        (0xf<<0)
+#define AC_CONV_STREAM                 (0xf<<4)
+#define AC_CONV_STREAM_SHIFT           4
+
+/* Input converter SDI select */
+#define AC_SDI_SELECT                  (0xf<<0)
+
+/* stream format id */
+#define AC_FMT_CHAN_SHIFT              0
+#define AC_FMT_CHAN_MASK               (0x0f << 0)
+#define AC_FMT_BITS_SHIFT              4
+#define AC_FMT_BITS_MASK               (7 << 4)
+#define AC_FMT_BITS_8                  (0 << 4)
+#define AC_FMT_BITS_16                 (1 << 4)
+#define AC_FMT_BITS_20                 (2 << 4)
+#define AC_FMT_BITS_24                 (3 << 4)
+#define AC_FMT_BITS_32                 (4 << 4)
+#define AC_FMT_DIV_SHIFT               8
+#define AC_FMT_DIV_MASK                        (7 << 8)
+#define AC_FMT_MULT_SHIFT              11
+#define AC_FMT_MULT_MASK               (7 << 11)
+#define AC_FMT_BASE_SHIFT              14
+#define AC_FMT_BASE_48K                        (0 << 14)
+#define AC_FMT_BASE_44K                        (1 << 14)
+#define AC_FMT_TYPE_SHIFT              15
+#define AC_FMT_TYPE_PCM                        (0 << 15)
+#define AC_FMT_TYPE_NON_PCM            (1 << 15)
+
+/* Unsolicited response control */
+#define AC_UNSOL_TAG                   (0x3f<<0)
+#define AC_UNSOL_ENABLED               (1<<7)
+#define AC_USRSP_EN                    AC_UNSOL_ENABLED
+
+/* Unsolicited responses */
+#define AC_UNSOL_RES_TAG               (0x3f<<26)
+#define AC_UNSOL_RES_TAG_SHIFT         26
+#define AC_UNSOL_RES_SUBTAG            (0x1f<<21)
+#define AC_UNSOL_RES_SUBTAG_SHIFT      21
+#define AC_UNSOL_RES_ELDV              (1<<1)  /* ELD Data valid (for HDMI) */
+#define AC_UNSOL_RES_PD                        (1<<0)  /* pinsense detect */
+#define AC_UNSOL_RES_CP_STATE          (1<<1)  /* content protection */
+#define AC_UNSOL_RES_CP_READY          (1<<0)  /* content protection */
+
+/* Pin widget capabilies */
+#define AC_PINCAP_IMP_SENSE            (1<<0)  /* impedance sense capable */
+#define AC_PINCAP_TRIG_REQ             (1<<1)  /* trigger required */
+#define AC_PINCAP_PRES_DETECT          (1<<2)  /* presence detect capable */
+#define AC_PINCAP_HP_DRV               (1<<3)  /* headphone drive capable */
+#define AC_PINCAP_OUT                  (1<<4)  /* output capable */
+#define AC_PINCAP_IN                   (1<<5)  /* input capable */
+#define AC_PINCAP_BALANCE              (1<<6)  /* balanced I/O capable */
+/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
+ *       but is marked reserved in the Intel HDA specification.
+ */
+#define AC_PINCAP_LR_SWAP              (1<<7)  /* L/R swap */
+/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
+ *       in HD-audio specification
+ */
+#define AC_PINCAP_HDMI                 (1<<7)  /* HDMI pin */
+#define AC_PINCAP_DP                   (1<<24) /* DisplayPort pin, can
+                                                * coexist with AC_PINCAP_HDMI
+                                                */
+#define AC_PINCAP_VREF                 (0x37<<8)
+#define AC_PINCAP_VREF_SHIFT           8
+#define AC_PINCAP_EAPD                 (1<<16) /* EAPD capable */
+#define AC_PINCAP_HBR                  (1<<27) /* High Bit Rate */
+/* Vref status (used in pin cap) */
+#define AC_PINCAP_VREF_HIZ             (1<<0)  /* Hi-Z */
+#define AC_PINCAP_VREF_50              (1<<1)  /* 50% */
+#define AC_PINCAP_VREF_GRD             (1<<2)  /* ground */
+#define AC_PINCAP_VREF_80              (1<<4)  /* 80% */
+#define AC_PINCAP_VREF_100             (1<<5)  /* 100% */
+
+/* Amplifier capabilities */
+#define AC_AMPCAP_OFFSET               (0x7f<<0)  /* 0dB offset */
+#define AC_AMPCAP_OFFSET_SHIFT         0
+#define AC_AMPCAP_NUM_STEPS            (0x7f<<8)  /* number of steps */
+#define AC_AMPCAP_NUM_STEPS_SHIFT      8
+#define AC_AMPCAP_STEP_SIZE            (0x7f<<16) /* step size 0-32dB
+                                                   * in 0.25dB
+                                                   */
+#define AC_AMPCAP_STEP_SIZE_SHIFT      16
+#define AC_AMPCAP_MUTE                 (1<<31)    /* mute capable */
+#define AC_AMPCAP_MUTE_SHIFT           31
+
+/* Connection list */
+#define AC_CLIST_LENGTH                        (0x7f<<0)
+#define AC_CLIST_LONG                  (1<<7)
+
+/* Supported power status */
+#define AC_PWRST_D0SUP                 (1<<0)
+#define AC_PWRST_D1SUP                 (1<<1)
+#define AC_PWRST_D2SUP                 (1<<2)
+#define AC_PWRST_D3SUP                 (1<<3)
+#define AC_PWRST_D3COLDSUP             (1<<4)
+#define AC_PWRST_S3D3COLDSUP           (1<<29)
+#define AC_PWRST_CLKSTOP               (1<<30)
+#define AC_PWRST_EPSS                  (1U<<31)
+
+/* Power state values */
+#define AC_PWRST_SETTING               (0xf<<0)
+#define AC_PWRST_ACTUAL                        (0xf<<4)
+#define AC_PWRST_ACTUAL_SHIFT          4
+#define AC_PWRST_D0                    0x00
+#define AC_PWRST_D1                    0x01
+#define AC_PWRST_D2                    0x02
+#define AC_PWRST_D3                    0x03
+
+/* Processing capabilies */
+#define AC_PCAP_BENIGN                 (1<<0)
+#define AC_PCAP_NUM_COEF               (0xff<<8)
+#define AC_PCAP_NUM_COEF_SHIFT         8
+
+/* Volume knobs capabilities */
+#define AC_KNBCAP_NUM_STEPS            (0x7f<<0)
+#define AC_KNBCAP_DELTA                        (1<<7)
+
+/* HDMI LPCM capabilities */
+#define AC_LPCMCAP_48K_CP_CHNS         (0x0f<<0) /* max channels w/ CP-on */   
+#define AC_LPCMCAP_48K_NO_CHNS         (0x0f<<4) /* max channels w/o CP-on */
+#define AC_LPCMCAP_48K_20BIT           (1<<8)  /* 20b bitrate supported */
+#define AC_LPCMCAP_48K_24BIT           (1<<9)  /* 24b bitrate supported */
+#define AC_LPCMCAP_96K_CP_CHNS         (0x0f<<10) /* max channels w/ CP-on */  
+#define AC_LPCMCAP_96K_NO_CHNS         (0x0f<<14) /* max channels w/o CP-on */
+#define AC_LPCMCAP_96K_20BIT           (1<<18) /* 20b bitrate supported */
+#define AC_LPCMCAP_96K_24BIT           (1<<19) /* 24b bitrate supported */
+#define AC_LPCMCAP_192K_CP_CHNS                (0x0f<<20) /* max channels w/ CP-on */  
+#define AC_LPCMCAP_192K_NO_CHNS                (0x0f<<24) /* max channels w/o CP-on */
+#define AC_LPCMCAP_192K_20BIT          (1<<28) /* 20b bitrate supported */
+#define AC_LPCMCAP_192K_24BIT          (1<<29) /* 24b bitrate supported */
+#define AC_LPCMCAP_44K                 (1<<30) /* 44.1kHz support */
+#define AC_LPCMCAP_44K_MS              (1<<31) /* 44.1kHz-multiplies support */
+
+/*
+ * Control Parameters
+ */
+
+/* Amp gain/mute */
+#define AC_AMP_MUTE                    (1<<7)
+#define AC_AMP_GAIN                    (0x7f)
+#define AC_AMP_GET_INDEX               (0xf<<0)
+
+#define AC_AMP_GET_LEFT                        (1<<13)
+#define AC_AMP_GET_RIGHT               (0<<13)
+#define AC_AMP_GET_OUTPUT              (1<<15)
+#define AC_AMP_GET_INPUT               (0<<15)
+
+#define AC_AMP_SET_INDEX               (0xf<<8)
+#define AC_AMP_SET_INDEX_SHIFT         8
+#define AC_AMP_SET_RIGHT               (1<<12)
+#define AC_AMP_SET_LEFT                        (1<<13)
+#define AC_AMP_SET_INPUT               (1<<14)
+#define AC_AMP_SET_OUTPUT              (1<<15)
+
+/* DIGITAL1 bits */
+#define AC_DIG1_ENABLE                 (1<<0)
+#define AC_DIG1_V                      (1<<1)
+#define AC_DIG1_VCFG                   (1<<2)
+#define AC_DIG1_EMPHASIS               (1<<3)
+#define AC_DIG1_COPYRIGHT              (1<<4)
+#define AC_DIG1_NONAUDIO               (1<<5)
+#define AC_DIG1_PROFESSIONAL           (1<<6)
+#define AC_DIG1_LEVEL                  (1<<7)
+
+/* DIGITAL2 bits */
+#define AC_DIG2_CC                     (0x7f<<0)
+
+/* Pin widget control - 8bit */
+#define AC_PINCTL_EPT                  (0x3<<0)
+#define AC_PINCTL_EPT_NATIVE           0
+#define AC_PINCTL_EPT_HBR              3
+#define AC_PINCTL_VREFEN               (0x7<<0)
+#define AC_PINCTL_VREF_HIZ             0       /* Hi-Z */
+#define AC_PINCTL_VREF_50              1       /* 50% */
+#define AC_PINCTL_VREF_GRD             2       /* ground */
+#define AC_PINCTL_VREF_80              4       /* 80% */
+#define AC_PINCTL_VREF_100             5       /* 100% */
+#define AC_PINCTL_IN_EN                        (1<<5)
+#define AC_PINCTL_OUT_EN               (1<<6)
+#define AC_PINCTL_HP_EN                        (1<<7)
+
+/* Pin sense - 32bit */
+#define AC_PINSENSE_IMPEDANCE_MASK     (0x7fffffff)
+#define AC_PINSENSE_PRESENCE           (1<<31)
+#define AC_PINSENSE_ELDV               (1<<30) /* ELD valid (HDMI) */
+
+/* EAPD/BTL enable - 32bit */
+#define AC_EAPDBTL_BALANCED            (1<<0)
+#define AC_EAPDBTL_EAPD                        (1<<1)
+#define AC_EAPDBTL_LR_SWAP             (1<<2)
+
+/* HDMI ELD data */
+#define AC_ELDD_ELD_VALID              (1<<31)
+#define AC_ELDD_ELD_DATA               0xff
+
+/* HDMI DIP size */
+#define AC_DIPSIZE_ELD_BUF             (1<<3) /* ELD buf size of packet size */
+#define AC_DIPSIZE_PACK_IDX            (0x07<<0) /* packet index */
+
+/* HDMI DIP index */
+#define AC_DIPIDX_PACK_IDX             (0x07<<5) /* packet idnex */
+#define AC_DIPIDX_BYTE_IDX             (0x1f<<0) /* byte index */
+
+/* HDMI DIP xmit (transmit) control */
+#define AC_DIPXMIT_MASK                        (0x3<<6)
+#define AC_DIPXMIT_DISABLE             (0x0<<6) /* disable xmit */
+#define AC_DIPXMIT_ONCE                        (0x2<<6) /* xmit once then disable */
+#define AC_DIPXMIT_BEST                        (0x3<<6) /* best effort */
+
+/* HDMI content protection (CP) control */
+#define AC_CPCTRL_CES                  (1<<9) /* current encryption state */
+#define AC_CPCTRL_READY                        (1<<8) /* ready bit */
+#define AC_CPCTRL_SUBTAG               (0x1f<<3) /* subtag for unsol-resp */
+#define AC_CPCTRL_STATE                        (3<<0) /* current CP request state */
+
+/* Converter channel <-> HDMI slot mapping */
+#define AC_CVTMAP_HDMI_SLOT            (0xf<<0) /* HDMI slot number */
+#define AC_CVTMAP_CHAN                 (0xf<<4) /* converter channel number */
+
+/* configuration default - 32bit */
+#define AC_DEFCFG_SEQUENCE             (0xf<<0)
+#define AC_DEFCFG_DEF_ASSOC            (0xf<<4)
+#define AC_DEFCFG_ASSOC_SHIFT          4
+#define AC_DEFCFG_MISC                 (0xf<<8)
+#define AC_DEFCFG_MISC_SHIFT           8
+#define AC_DEFCFG_MISC_NO_PRESENCE     (1<<0)
+#define AC_DEFCFG_COLOR                        (0xf<<12)
+#define AC_DEFCFG_COLOR_SHIFT          12
+#define AC_DEFCFG_CONN_TYPE            (0xf<<16)
+#define AC_DEFCFG_CONN_TYPE_SHIFT      16
+#define AC_DEFCFG_DEVICE               (0xf<<20)
+#define AC_DEFCFG_DEVICE_SHIFT         20
+#define AC_DEFCFG_LOCATION             (0x3f<<24)
+#define AC_DEFCFG_LOCATION_SHIFT       24
+#define AC_DEFCFG_PORT_CONN            (0x3<<30)
+#define AC_DEFCFG_PORT_CONN_SHIFT      30
+
+/* device device types (0x0-0xf) */
+enum {
+       AC_JACK_LINE_OUT,
+       AC_JACK_SPEAKER,
+       AC_JACK_HP_OUT,
+       AC_JACK_CD,
+       AC_JACK_SPDIF_OUT,
+       AC_JACK_DIG_OTHER_OUT,
+       AC_JACK_MODEM_LINE_SIDE,
+       AC_JACK_MODEM_HAND_SIDE,
+       AC_JACK_LINE_IN,
+       AC_JACK_AUX,
+       AC_JACK_MIC_IN,
+       AC_JACK_TELEPHONY,
+       AC_JACK_SPDIF_IN,
+       AC_JACK_DIG_OTHER_IN,
+       AC_JACK_OTHER = 0xf,
+};
+
+/* jack connection types (0x0-0xf) */
+enum {
+       AC_JACK_CONN_UNKNOWN,
+       AC_JACK_CONN_1_8,
+       AC_JACK_CONN_1_4,
+       AC_JACK_CONN_ATAPI,
+       AC_JACK_CONN_RCA,
+       AC_JACK_CONN_OPTICAL,
+       AC_JACK_CONN_OTHER_DIGITAL,
+       AC_JACK_CONN_OTHER_ANALOG,
+       AC_JACK_CONN_DIN,
+       AC_JACK_CONN_XLR,
+       AC_JACK_CONN_RJ11,
+       AC_JACK_CONN_COMB,
+       AC_JACK_CONN_OTHER = 0xf,
+};
+
+/* jack colors (0x0-0xf) */
+enum {
+       AC_JACK_COLOR_UNKNOWN,
+       AC_JACK_COLOR_BLACK,
+       AC_JACK_COLOR_GREY,
+       AC_JACK_COLOR_BLUE,
+       AC_JACK_COLOR_GREEN,
+       AC_JACK_COLOR_RED,
+       AC_JACK_COLOR_ORANGE,
+       AC_JACK_COLOR_YELLOW,
+       AC_JACK_COLOR_PURPLE,
+       AC_JACK_COLOR_PINK,
+       AC_JACK_COLOR_WHITE = 0xe,
+       AC_JACK_COLOR_OTHER,
+};
+
+/* Jack location (0x0-0x3f) */
+/* common case */
+enum {
+       AC_JACK_LOC_NONE,
+       AC_JACK_LOC_REAR,
+       AC_JACK_LOC_FRONT,
+       AC_JACK_LOC_LEFT,
+       AC_JACK_LOC_RIGHT,
+       AC_JACK_LOC_TOP,
+       AC_JACK_LOC_BOTTOM,
+};
+/* bits 4-5 */
+enum {
+       AC_JACK_LOC_EXTERNAL = 0x00,
+       AC_JACK_LOC_INTERNAL = 0x10,
+       AC_JACK_LOC_SEPARATE = 0x20,
+       AC_JACK_LOC_OTHER    = 0x30,
+};
+enum {
+       /* external on primary chasis */
+       AC_JACK_LOC_REAR_PANEL = 0x07,
+       AC_JACK_LOC_DRIVE_BAY,
+       /* internal */
+       AC_JACK_LOC_RISER = 0x17,
+       AC_JACK_LOC_HDMI,
+       AC_JACK_LOC_ATAPI,
+       /* others */
+       AC_JACK_LOC_MOBILE_IN = 0x37,
+       AC_JACK_LOC_MOBILE_OUT,
+};
+
+/* Port connectivity (0-3) */
+enum {
+       AC_JACK_PORT_COMPLEX,
+       AC_JACK_PORT_NONE,
+       AC_JACK_PORT_FIXED,
+       AC_JACK_PORT_BOTH,
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS    32
+
+/* max. codec address */
+#define HDA_MAX_CODEC_ADDRESS  0x0f
+
+/* max number of PCM devics per card */
+#define HDA_MAX_PCMS           10
+
+/* --------------------------------------------------------------------- */
+
+#endif
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
new file mode 100644 (file)
index 0000000..ccb059d
--- /dev/null
@@ -0,0 +1,1250 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "pci.h"
+#include "qemu-timer.h"
+#include "audiodev.h"
+#include "intel-hda.h"
+#include "intel-hda-defs.h"
+
+/* --------------------------------------------------------------------- */
+/* hda bus                                                               */
+
+static struct BusInfo hda_codec_bus_info = {
+    .name      = "HDA",
+    .size      = sizeof(HDACodecBus),
+    .props     = (Property[]) {
+        DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
+                        hda_codec_response_func response,
+                        hda_codec_xfer_func xfer)
+{
+    qbus_create_inplace(&bus->qbus, &hda_codec_bus_info, dev, NULL);
+    bus->response = response;
+    bus->xfer = xfer;
+}
+
+static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
+    HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+    HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base);
+
+    dev->info = info;
+    if (dev->cad == -1) {
+        dev->cad = bus->next_cad;
+    }
+    if (dev->cad > 15)
+        return -1;
+    bus->next_cad = dev->cad + 1;
+    return info->init(dev);
+}
+
+void hda_codec_register(HDACodecDeviceInfo *info)
+{
+    info->qdev.init = hda_codec_dev_init;
+    info->qdev.bus_info = &hda_codec_bus_info;
+    qdev_register(&info->qdev);
+}
+
+HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
+{
+    DeviceState *qdev;
+    HDACodecDevice *cdev;
+
+    QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        if (cdev->cad == cad) {
+            return cdev;
+        }
+    }
+    return NULL;
+}
+
+void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    bus->response(dev, solicited, response);
+}
+
+bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                    uint8_t *buf, uint32_t len)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    return bus->xfer(dev, stnr, output, buf, len);
+}
+
+/* --------------------------------------------------------------------- */
+/* intel hda emulation                                                   */
+
+typedef struct IntelHDAStream IntelHDAStream;
+typedef struct IntelHDAState IntelHDAState;
+typedef struct IntelHDAReg IntelHDAReg;
+
+typedef struct bpl {
+    uint64_t addr;
+    uint32_t len;
+    uint32_t flags;
+} bpl;
+
+struct IntelHDAStream {
+    /* registers */
+    uint32_t ctl;
+    uint32_t lpib;
+    uint32_t cbl;
+    uint32_t lvi;
+    uint32_t fmt;
+    uint32_t bdlp_lbase;
+    uint32_t bdlp_ubase;
+
+    /* state */
+    bpl      *bpl;
+    uint32_t bentries;
+    uint32_t bsize, be, bp;
+};
+
+struct IntelHDAState {
+    PCIDevice pci;
+    const char *name;
+    HDACodecBus codecs;
+
+    /* registers */
+    uint32_t g_ctl;
+    uint32_t wake_en;
+    uint32_t state_sts;
+    uint32_t int_ctl;
+    uint32_t int_sts;
+    uint32_t wall_clk;
+
+    uint32_t corb_lbase;
+    uint32_t corb_ubase;
+    uint32_t corb_rp;
+    uint32_t corb_wp;
+    uint32_t corb_ctl;
+    uint32_t corb_sts;
+    uint32_t corb_size;
+
+    uint32_t rirb_lbase;
+    uint32_t rirb_ubase;
+    uint32_t rirb_wp;
+    uint32_t rirb_cnt;
+    uint32_t rirb_ctl;
+    uint32_t rirb_sts;
+    uint32_t rirb_size;
+
+    uint32_t dp_lbase;
+    uint32_t dp_ubase;
+
+    uint32_t icw;
+    uint32_t irr;
+    uint32_t ics;
+
+    /* streams */
+    IntelHDAStream st[8];
+
+    /* state */
+    int mmio_addr;
+    uint32_t rirb_count;
+    int64_t wall_base_ns;
+
+    /* debug logging */
+    const IntelHDAReg *last_reg;
+    uint32_t last_val;
+    uint32_t last_write;
+    uint32_t last_sec;
+    uint32_t repeat_count;
+
+    /* properties */
+    uint32_t debug;
+};
+
+struct IntelHDAReg {
+    const char *name;      /* register name */
+    uint32_t   size;       /* size in bytes */
+    uint32_t   reset;      /* reset value */
+    uint32_t   wmask;      /* write mask */
+    uint32_t   wclear;     /* write 1 to clear bits */
+    uint32_t   offset;     /* location in IntelHDAState */
+    uint32_t   shift;      /* byte access entries for dwords */
+    uint32_t   stream;
+    void       (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old);
+    void       (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg);
+};
+
+static void intel_hda_reset(DeviceState *dev);
+
+/* --------------------------------------------------------------------- */
+
+static target_phys_addr_t intel_hda_addr(uint32_t lbase, uint32_t ubase)
+{
+    target_phys_addr_t addr;
+
+#if TARGET_PHYS_ADDR_BITS == 32
+    addr = lbase;
+#else
+    addr = ubase;
+    addr <<= 32;
+    addr |= lbase;
+#endif
+    return addr;
+}
+
+static void stl_phys_le(target_phys_addr_t addr, uint32_t value)
+{
+    uint32_t value_le = cpu_to_le32(value);
+    cpu_physical_memory_write(addr, (uint8_t*)(&value_le), sizeof(value_le));
+}
+
+static uint32_t ldl_phys_le(target_phys_addr_t addr)
+{
+    uint32_t value_le;
+    cpu_physical_memory_read(addr, (uint8_t*)(&value_le), sizeof(value_le));
+    return le32_to_cpu(value_le);
+}
+
+static void intel_hda_update_int_sts(IntelHDAState *d)
+{
+    uint32_t sts = 0;
+    uint32_t i;
+
+    /* update controller status */
+    if (d->rirb_sts & ICH6_RBSTS_IRQ) {
+        sts |= (1 << 30);
+    }
+    if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
+        sts |= (1 << 30);
+    }
+    if (d->state_sts) {
+        sts |= (1 << 30);
+    }
+
+    /* update stream status */
+    for (i = 0; i < 8; i++) {
+        /* buffer completion interrupt */
+        if (d->st[i].ctl & (1 << 26)) {
+            sts |= (1 << i);
+        }
+    }
+
+    /* update global status */
+    if (sts & d->int_ctl) {
+        sts |= (1 << 31);
+    }
+
+    d->int_sts = sts;
+}
+
+static void intel_hda_update_irq(IntelHDAState *d)
+{
+    int level;
+
+    intel_hda_update_int_sts(d);
+    if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
+        level = 1;
+    } else {
+        level = 0;
+    }
+    dprint(d, 2, "%s: level %d\n", __FUNCTION__, level);
+    qemu_set_irq(d->pci.irq[0], level);
+}
+
+static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
+{
+    uint32_t cad, nid, data;
+    HDACodecDevice *codec;
+
+    cad = (verb >> 28) & 0x0f;
+    if (verb & (1 << 27)) {
+        /* indirect node addressing, not specified in HDA 1.0 */
+        dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__);
+        return -1;
+    }
+    nid = (verb >> 20) & 0x7f;
+    data = verb & 0xfffff;
+
+    codec = hda_codec_find(&d->codecs, cad);
+    if (codec == NULL) {
+        dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
+        return -1;
+    }
+    codec->info->command(codec, nid, data);
+    return 0;
+}
+
+static void intel_hda_corb_run(IntelHDAState *d)
+{
+    target_phys_addr_t addr;
+    uint32_t rp, verb;
+
+    if (d->ics & ICH6_IRS_BUSY) {
+        dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw);
+        intel_hda_send_command(d, d->icw);
+        return;
+    }
+
+    for (;;) {
+        if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) {
+            dprint(d, 2, "%s: !run\n", __FUNCTION__);
+            return;
+        }
+        if ((d->corb_rp & 0xff) == d->corb_wp) {
+            dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__);
+            return;
+        }
+        if (d->rirb_count == d->rirb_cnt) {
+            dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__);
+            return;
+        }
+
+        rp = (d->corb_rp + 1) & 0xff;
+        addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
+        verb = ldl_phys_le(addr + 4*rp);
+        d->corb_rp = rp;
+
+        dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
+        intel_hda_send_command(d, verb);
+    }
+}
+
+static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
+    target_phys_addr_t addr;
+    uint32_t wp, ex;
+
+    if (d->ics & ICH6_IRS_BUSY) {
+        dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n",
+               __FUNCTION__, response, dev->cad);
+        d->irr = response;
+        d->ics &= ~(ICH6_IRS_BUSY | 0xf0);
+        d->ics |= (ICH6_IRS_VALID | (dev->cad << 4));
+        return;
+    }
+
+    if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) {
+        dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__);
+        return;
+    }
+
+    ex = (solicited ? 0 : (1 << 4)) | dev->cad;
+    wp = (d->rirb_wp + 1) & 0xff;
+    addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
+    stl_phys_le(addr + 8*wp, response);
+    stl_phys_le(addr + 8*wp + 4, ex);
+    d->rirb_wp = wp;
+
+    dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
+           __FUNCTION__, wp, response, ex);
+
+    d->rirb_count++;
+    if (d->rirb_count == d->rirb_cnt) {
+        dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count);
+        if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
+            d->rirb_sts |= ICH6_RBSTS_IRQ;
+            intel_hda_update_irq(d);
+        }
+    } else if ((d->corb_rp & 0xff) == d->corb_wp) {
+        dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__,
+               d->rirb_count, d->rirb_cnt);
+        if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
+            d->rirb_sts |= ICH6_RBSTS_IRQ;
+            intel_hda_update_irq(d);
+        }
+    }
+}
+
+static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                           uint8_t *buf, uint32_t len)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
+    IntelHDAStream *st = NULL;
+    target_phys_addr_t addr;
+    uint32_t s, copy, left;
+    bool irq = false;
+
+    for (s = 0; s < ARRAY_SIZE(d->st); s++) {
+        if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) {
+            st = d->st + s;
+            break;
+        }
+    }
+    if (st == NULL) {
+        return false;
+    }
+    if (st->bpl == NULL) {
+        return false;
+    }
+    if (st->ctl & (1 << 26)) {
+        /*
+         * Wait with the next DMA xfer until the guest
+         * has acked the buffer completion interrupt
+         */
+        return false;
+    }
+
+    left = len;
+    while (left > 0) {
+        copy = left;
+        if (copy > st->bsize - st->lpib)
+            copy = st->bsize - st->lpib;
+        if (copy > st->bpl[st->be].len - st->bp)
+            copy = st->bpl[st->be].len - st->bp;
+
+        dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
+               st->be, st->bp, st->bpl[st->be].len, copy);
+
+        cpu_physical_memory_rw(st->bpl[st->be].addr + st->bp,
+                               buf, copy, !output);
+        st->lpib += copy;
+        st->bp += copy;
+        buf += copy;
+        left -= copy;
+
+        if (st->bpl[st->be].len == st->bp) {
+            /* bpl entry filled */
+            if (st->bpl[st->be].flags & 0x01) {
+                irq = true;
+            }
+            st->bp = 0;
+            st->be++;
+            if (st->be == st->bentries) {
+                /* bpl wrap around */
+                st->be = 0;
+                st->lpib = 0;
+            }
+        }
+    }
+    if (d->dp_lbase & 0x01) {
+        addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
+        stl_phys_le(addr + 8*s, st->lpib);
+    }
+    dprint(d, 3, "dma: --\n");
+
+    if (irq) {
+        st->ctl |= (1 << 26); /* buffer completion interrupt */
+        intel_hda_update_irq(d);
+    }
+    return true;
+}
+
+static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
+{
+    target_phys_addr_t addr;
+    uint8_t buf[16];
+    uint32_t i;
+
+    addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
+    st->bentries = st->lvi +1;
+    qemu_free(st->bpl);
+    st->bpl = qemu_malloc(sizeof(bpl) * st->bentries);
+    for (i = 0; i < st->bentries; i++, addr += 16) {
+        cpu_physical_memory_read(addr, buf, 16);
+        st->bpl[i].addr  = le64_to_cpu(*(uint64_t *)buf);
+        st->bpl[i].len   = le32_to_cpu(*(uint32_t *)(buf + 8));
+        st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
+        dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n",
+               i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags);
+    }
+
+    st->bsize = st->cbl;
+    st->lpib  = 0;
+    st->be    = 0;
+    st->bp    = 0;
+}
+
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
+{
+    DeviceState *qdev;
+    HDACodecDevice *cdev;
+
+    QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        if (cdev->info->stream) {
+            cdev->info->stream(cdev, stream, running);
+        }
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if ((d->g_ctl & ICH6_GCTL_RESET) == 0) {
+        intel_hda_reset(&d->pci.qdev);
+    }
+}
+
+static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
+static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
+static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg)
+{
+    int64_t ns;
+
+    ns = qemu_get_clock_ns(vm_clock) - d->wall_base_ns;
+    d->wall_clk = (uint32_t)(ns * 24 / 1000);  /* 24 MHz */
+}
+
+static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_corb_run(d);
+}
+
+static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_corb_run(d);
+}
+
+static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if (d->rirb_wp & ICH6_RIRBWP_RST) {
+        d->rirb_wp = 0;
+    }
+}
+
+static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+
+    if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) {
+        /* cleared ICH6_RBSTS_IRQ */
+        d->rirb_count = 0;
+        intel_hda_corb_run(d);
+    }
+}
+
+static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if (d->ics & ICH6_IRS_BUSY) {
+        intel_hda_corb_run(d);
+    }
+}
+
+static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    IntelHDAStream *st = d->st + reg->stream;
+
+    if (st->ctl & 0x01) {
+        /* reset */
+        dprint(d, 1, "st #%d: reset\n", reg->stream);
+        st->ctl = 0;
+    }
+    if ((st->ctl & 0x02) != (old & 0x02)) {
+        uint32_t stnr = (st->ctl >> 20) & 0x0f;
+        /* run bit flipped */
+        if (st->ctl & 0x02) {
+            /* start */
+            dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
+                   reg->stream, stnr, st->cbl);
+            intel_hda_parse_bdl(d, st);
+            intel_hda_notify_codecs(d, stnr, true);
+        } else {
+            /* stop */
+            dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
+            intel_hda_notify_codecs(d, stnr, false);
+        }
+    }
+    intel_hda_update_irq(d);
+}
+
+/* --------------------------------------------------------------------- */
+
+#define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o))
+
+static const struct IntelHDAReg regtab[] = {
+    /* global */
+    [ ICH6_REG_GCAP ] = {
+        .name     = "GCAP",
+        .size     = 2,
+        .reset    = 0x4401,
+    },
+    [ ICH6_REG_VMIN ] = {
+        .name     = "VMIN",
+        .size     = 1,
+    },
+    [ ICH6_REG_VMAJ ] = {
+        .name     = "VMAJ",
+        .size     = 1,
+        .reset    = 1,
+    },
+    [ ICH6_REG_OUTPAY ] = {
+        .name     = "OUTPAY",
+        .size     = 2,
+        .reset    = 0x3c,
+    },
+    [ ICH6_REG_INPAY ] = {
+        .name     = "INPAY",
+        .size     = 2,
+        .reset    = 0x1d,
+    },
+    [ ICH6_REG_GCTL ] = {
+        .name     = "GCTL",
+        .size     = 4,
+        .wmask    = 0x0103,
+        .offset   = offsetof(IntelHDAState, g_ctl),
+        .whandler = intel_hda_set_g_ctl,
+    },
+    [ ICH6_REG_WAKEEN ] = {
+        .name     = "WAKEEN",
+        .size     = 2,
+        .offset   = offsetof(IntelHDAState, wake_en),
+    },
+    [ ICH6_REG_STATESTS ] = {
+        .name     = "STATESTS",
+        .size     = 2,
+        .wmask    = 0x3fff,
+        .wclear   = 0x3fff,
+        .offset   = offsetof(IntelHDAState, state_sts),
+        .whandler = intel_hda_set_state_sts,
+    },
+
+    /* interrupts */
+    [ ICH6_REG_INTCTL ] = {
+        .name     = "INTCTL",
+        .size     = 4,
+        .wmask    = 0xc00000ff,
+        .offset   = offsetof(IntelHDAState, int_ctl),
+        .whandler = intel_hda_set_int_ctl,
+    },
+    [ ICH6_REG_INTSTS ] = {
+        .name     = "INTSTS",
+        .size     = 4,
+        .wmask    = 0xc00000ff,
+        .wclear   = 0xc00000ff,
+        .offset   = offsetof(IntelHDAState, int_sts),
+    },
+
+    /* misc */
+    [ ICH6_REG_WALLCLK ] = {
+        .name     = "WALLCLK",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, wall_clk),
+        .rhandler = intel_hda_get_wall_clk,
+    },
+    [ ICH6_REG_WALLCLK + 0x2000 ] = {
+        .name     = "WALLCLK(alias)",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, wall_clk),
+        .rhandler = intel_hda_get_wall_clk,
+    },
+
+    /* dma engine */
+    [ ICH6_REG_CORBLBASE ] = {
+        .name     = "CORBLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff80,
+        .offset   = offsetof(IntelHDAState, corb_lbase),
+    },
+    [ ICH6_REG_CORBUBASE ] = {
+        .name     = "CORBUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, corb_ubase),
+    },
+    [ ICH6_REG_CORBWP ] = {
+        .name     = "CORBWP",
+        .size     = 2,
+        .wmask    = 0xff,
+        .offset   = offsetof(IntelHDAState, corb_wp),
+        .whandler = intel_hda_set_corb_wp,
+    },
+    [ ICH6_REG_CORBRP ] = {
+        .name     = "CORBRP",
+        .size     = 2,
+        .wmask    = 0x80ff,
+        .offset   = offsetof(IntelHDAState, corb_rp),
+    },
+    [ ICH6_REG_CORBCTL ] = {
+        .name     = "CORBCTL",
+        .size     = 1,
+        .wmask    = 0x03,
+        .offset   = offsetof(IntelHDAState, corb_ctl),
+        .whandler = intel_hda_set_corb_ctl,
+    },
+    [ ICH6_REG_CORBSTS ] = {
+        .name     = "CORBSTS",
+        .size     = 1,
+        .wmask    = 0x01,
+        .wclear   = 0x01,
+        .offset   = offsetof(IntelHDAState, corb_sts),
+    },
+    [ ICH6_REG_CORBSIZE ] = {
+        .name     = "CORBSIZE",
+        .size     = 1,
+        .reset    = 0x42,
+        .offset   = offsetof(IntelHDAState, corb_size),
+    },
+    [ ICH6_REG_RIRBLBASE ] = {
+        .name     = "RIRBLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff80,
+        .offset   = offsetof(IntelHDAState, rirb_lbase),
+    },
+    [ ICH6_REG_RIRBUBASE ] = {
+        .name     = "RIRBUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, rirb_ubase),
+    },
+    [ ICH6_REG_RIRBWP ] = {
+        .name     = "RIRBWP",
+        .size     = 2,
+        .wmask    = 0x8000,
+        .offset   = offsetof(IntelHDAState, rirb_wp),
+        .whandler = intel_hda_set_rirb_wp,
+    },
+    [ ICH6_REG_RINTCNT ] = {
+        .name     = "RINTCNT",
+        .size     = 2,
+        .wmask    = 0xff,
+        .offset   = offsetof(IntelHDAState, rirb_cnt),
+    },
+    [ ICH6_REG_RIRBCTL ] = {
+        .name     = "RIRBCTL",
+        .size     = 1,
+        .wmask    = 0x07,
+        .offset   = offsetof(IntelHDAState, rirb_ctl),
+    },
+    [ ICH6_REG_RIRBSTS ] = {
+        .name     = "RIRBSTS",
+        .size     = 1,
+        .wmask    = 0x05,
+        .wclear   = 0x05,
+        .offset   = offsetof(IntelHDAState, rirb_sts),
+        .whandler = intel_hda_set_rirb_sts,
+    },
+    [ ICH6_REG_RIRBSIZE ] = {
+        .name     = "RIRBSIZE",
+        .size     = 1,
+        .reset    = 0x42,
+        .offset   = offsetof(IntelHDAState, rirb_size),
+    },
+
+    [ ICH6_REG_DPLBASE ] = {
+        .name     = "DPLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff81,
+        .offset   = offsetof(IntelHDAState, dp_lbase),
+    },
+    [ ICH6_REG_DPUBASE ] = {
+        .name     = "DPUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, dp_ubase),
+    },
+
+    [ ICH6_REG_IC ] = {
+        .name     = "ICW",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, icw),
+    },
+    [ ICH6_REG_IR ] = {
+        .name     = "IRR",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, irr),
+    },
+    [ ICH6_REG_IRS ] = {
+        .name     = "ICS",
+        .size     = 2,
+        .wmask    = 0x0003,
+        .wclear   = 0x0002,
+        .offset   = offsetof(IntelHDAState, ics),
+        .whandler = intel_hda_set_ics,
+    },
+
+#define HDA_STREAM(_t, _i)                                            \
+    [ ST_REG(_i, ICH6_REG_SD_CTL) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL",                          \
+        .size     = 4,                                                \
+        .wmask    = 0x1cff001f,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = {                            \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL(stnr)",                    \
+        .size     = 1,                                                \
+        .shift    = 16,                                               \
+        .wmask    = 0x00ff0000,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_STS)] = {                                \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL(sts)",                     \
+        .size     = 1,                                                \
+        .shift    = 24,                                               \
+        .wmask    = 0x1c000000,                                       \
+        .wclear   = 0x1c000000,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = {                              \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LPIB",                         \
+        .size     = 4,                                                \
+        .offset   = offsetof(IntelHDAState, st[_i].lpib),             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = {                     \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LPIB(alias)",                  \
+        .size     = 4,                                                \
+        .offset   = offsetof(IntelHDAState, st[_i].lpib),             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_CBL) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CBL",                          \
+        .size     = 4,                                                \
+        .wmask    = 0xffffffff,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].cbl),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LVI) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LVI",                          \
+        .size     = 2,                                                \
+        .wmask    = 0x00ff,                                           \
+        .offset   = offsetof(IntelHDAState, st[_i].lvi),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = {                          \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " FIFOS",                        \
+        .size     = 2,                                                \
+        .reset    = HDA_BUFFER_SIZE,                                  \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = {                            \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " FMT",                          \
+        .size     = 2,                                                \
+        .wmask    = 0x7f7f,                                           \
+        .offset   = offsetof(IntelHDAState, st[_i].fmt),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = {                             \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " BDLPL",                        \
+        .size     = 4,                                                \
+        .wmask    = 0xffffff80,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].bdlp_lbase),       \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = {                             \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " BDLPU",                        \
+        .size     = 4,                                                \
+        .wmask    = 0xffffffff,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].bdlp_ubase),       \
+    },                                                                \
+
+    HDA_STREAM("IN", 0)
+    HDA_STREAM("IN", 1)
+    HDA_STREAM("IN", 2)
+    HDA_STREAM("IN", 3)
+
+    HDA_STREAM("OUT", 4)
+    HDA_STREAM("OUT", 5)
+    HDA_STREAM("OUT", 6)
+    HDA_STREAM("OUT", 7)
+
+};
+
+static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, target_phys_addr_t addr)
+{
+    const IntelHDAReg *reg;
+
+    if (addr >= sizeof(regtab)/sizeof(regtab[0])) {
+        goto noreg;
+    }
+    reg = regtab+addr;
+    if (reg->name == NULL) {
+        goto noreg;
+    }
+    return reg;
+
+noreg:
+    dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr);
+    return NULL;
+}
+
+static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg)
+{
+    uint8_t *addr = (void*)d;
+
+    addr += reg->offset;
+    return (uint32_t*)addr;
+}
+
+static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val,
+                                uint32_t wmask)
+{
+    uint32_t *addr;
+    uint32_t old;
+
+    if (!reg) {
+        return;
+    }
+
+    if (d->debug) {
+        time_t now = time(NULL);
+        if (d->last_write && d->last_reg == reg && d->last_val == val) {
+            d->repeat_count++;
+            if (d->last_sec != now) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+                d->last_sec = now;
+                d->repeat_count = 0;
+            }
+        } else {
+            if (d->repeat_count) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+            }
+            dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask);
+            d->last_write = 1;
+            d->last_reg   = reg;
+            d->last_val   = val;
+            d->last_sec   = now;
+            d->repeat_count = 0;
+        }
+    }
+    assert(reg->offset != 0);
+
+    addr = intel_hda_reg_addr(d, reg);
+    old = *addr;
+
+    if (reg->shift) {
+        val <<= reg->shift;
+        wmask <<= reg->shift;
+    }
+    wmask &= reg->wmask;
+    *addr &= ~wmask;
+    *addr |= wmask & val;
+    *addr &= ~(val & reg->wclear);
+
+    if (reg->whandler) {
+        reg->whandler(d, reg, old);
+    }
+}
+
+static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg,
+                                   uint32_t rmask)
+{
+    uint32_t *addr, ret;
+
+    if (!reg) {
+        return 0;
+    }
+
+    if (reg->rhandler) {
+        reg->rhandler(d, reg);
+    }
+
+    if (reg->offset == 0) {
+        /* constant read-only register */
+        ret = reg->reset;
+    } else {
+        addr = intel_hda_reg_addr(d, reg);
+        ret = *addr;
+        if (reg->shift) {
+            ret >>= reg->shift;
+        }
+        ret &= rmask;
+    }
+    if (d->debug) {
+        time_t now = time(NULL);
+        if (!d->last_write && d->last_reg == reg && d->last_val == ret) {
+            d->repeat_count++;
+            if (d->last_sec != now) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+                d->last_sec = now;
+                d->repeat_count = 0;
+            }
+        } else {
+            if (d->repeat_count) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+            }
+            dprint(d, 2, "read  %-16s: 0x%x (%x)\n", reg->name, ret, rmask);
+            d->last_write = 0;
+            d->last_reg   = reg;
+            d->last_val   = ret;
+            d->last_sec   = now;
+            d->repeat_count = 0;
+        }
+    }
+    return ret;
+}
+
+static void intel_hda_regs_reset(IntelHDAState *d)
+{
+    uint32_t *addr;
+    int i;
+
+    for (i = 0; i < sizeof(regtab)/sizeof(regtab[0]); i++) {
+        if (regtab[i].name == NULL) {
+            continue;
+        }
+        if (regtab[i].offset == 0) {
+            continue;
+        }
+        addr = intel_hda_reg_addr(d, regtab + i);
+        *addr = regtab[i].reset;
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xff);
+}
+
+static void intel_hda_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xffff);
+}
+
+static void intel_hda_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xffffffff);
+}
+
+static uint32_t intel_hda_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xff);
+}
+
+static uint32_t intel_hda_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xffff);
+}
+
+static uint32_t intel_hda_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xffffffff);
+}
+
+static CPUReadMemoryFunc * const intel_hda_mmio_read[3] = {
+    intel_hda_mmio_readb,
+    intel_hda_mmio_readw,
+    intel_hda_mmio_readl,
+};
+
+static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
+    intel_hda_mmio_writeb,
+    intel_hda_mmio_writew,
+    intel_hda_mmio_writel,
+};
+
+static void intel_hda_map(PCIDevice *pci, int region_num,
+                          pcibus_t addr, pcibus_t size, int type)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+    cpu_register_physical_memory(addr, 0x4000, d->mmio_addr);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_reset(DeviceState *dev)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
+    DeviceState *qdev;
+    HDACodecDevice *cdev;
+
+    intel_hda_regs_reset(d);
+    d->wall_base_ns = qemu_get_clock(vm_clock);
+
+    /* reset codecs */
+    QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        if (qdev->info->reset) {
+            qdev->info->reset(qdev);
+        }
+        d->state_sts |= (1 << cdev->cad);
+    }
+    intel_hda_update_irq(d);
+}
+
+static int intel_hda_init(PCIDevice *pci)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+    uint8_t *conf = d->pci.config;
+
+    d->name = d->pci.qdev.info->name;
+
+    pci_config_set_vendor_id(conf, PCI_VENDOR_ID_INTEL);
+    pci_config_set_device_id(conf, 0x2668);
+    pci_config_set_revision(conf, 1);
+    pci_config_set_class(conf, PCI_CLASS_MULTIMEDIA_HD_AUDIO);
+    pci_config_set_interrupt_pin(conf, 1);
+
+    /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
+    conf[0x40] = 0x01;
+
+    d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
+                                          intel_hda_mmio_write, d);
+    pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     intel_hda_map);
+
+    hda_codec_bus_init(&d->pci.qdev, &d->codecs,
+                       intel_hda_response, intel_hda_xfer);
+
+    return 0;
+}
+
+static int intel_hda_post_load(void *opaque, int version)
+{
+    IntelHDAState* d = opaque;
+    int i;
+
+    dprint(d, 1, "%s\n", __FUNCTION__);
+    for (i = 0; i < ARRAY_SIZE(d->st); i++) {
+        if (d->st[i].ctl & 0x02) {
+            intel_hda_parse_bdl(d, &d->st[i]);
+        }
+    }
+    intel_hda_update_irq(d);
+    return 0;
+}
+
+static const VMStateDescription vmstate_intel_hda_stream = {
+    .name = "intel-hda-stream",
+    .version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32(ctl, IntelHDAStream),
+        VMSTATE_UINT32(lpib, IntelHDAStream),
+        VMSTATE_UINT32(cbl, IntelHDAStream),
+        VMSTATE_UINT32(lvi, IntelHDAStream),
+        VMSTATE_UINT32(fmt, IntelHDAStream),
+        VMSTATE_UINT32(bdlp_lbase, IntelHDAStream),
+        VMSTATE_UINT32(bdlp_ubase, IntelHDAStream),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_intel_hda = {
+    .name = "intel-hda",
+    .version_id = 1,
+    .post_load = intel_hda_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci, IntelHDAState),
+
+        /* registers */
+        VMSTATE_UINT32(g_ctl, IntelHDAState),
+        VMSTATE_UINT32(wake_en, IntelHDAState),
+        VMSTATE_UINT32(state_sts, IntelHDAState),
+        VMSTATE_UINT32(int_ctl, IntelHDAState),
+        VMSTATE_UINT32(int_sts, IntelHDAState),
+        VMSTATE_UINT32(wall_clk, IntelHDAState),
+        VMSTATE_UINT32(corb_lbase, IntelHDAState),
+        VMSTATE_UINT32(corb_ubase, IntelHDAState),
+        VMSTATE_UINT32(corb_rp, IntelHDAState),
+        VMSTATE_UINT32(corb_wp, IntelHDAState),
+        VMSTATE_UINT32(corb_ctl, IntelHDAState),
+        VMSTATE_UINT32(corb_sts, IntelHDAState),
+        VMSTATE_UINT32(corb_size, IntelHDAState),
+        VMSTATE_UINT32(rirb_lbase, IntelHDAState),
+        VMSTATE_UINT32(rirb_ubase, IntelHDAState),
+        VMSTATE_UINT32(rirb_wp, IntelHDAState),
+        VMSTATE_UINT32(rirb_cnt, IntelHDAState),
+        VMSTATE_UINT32(rirb_ctl, IntelHDAState),
+        VMSTATE_UINT32(rirb_sts, IntelHDAState),
+        VMSTATE_UINT32(rirb_size, IntelHDAState),
+        VMSTATE_UINT32(dp_lbase, IntelHDAState),
+        VMSTATE_UINT32(dp_ubase, IntelHDAState),
+        VMSTATE_UINT32(icw, IntelHDAState),
+        VMSTATE_UINT32(irr, IntelHDAState),
+        VMSTATE_UINT32(ics, IntelHDAState),
+        VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0,
+                             vmstate_intel_hda_stream,
+                             IntelHDAStream),
+
+        /* additional state info */
+        VMSTATE_UINT32(rirb_count, IntelHDAState),
+        VMSTATE_INT64(wall_base_ns, IntelHDAState),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PCIDeviceInfo intel_hda_info = {
+    .qdev.name    = "intel-hda",
+    .qdev.desc    = "Intel HD Audio Controller",
+    .qdev.size    = sizeof(IntelHDAState),
+    .qdev.vmsd    = &vmstate_intel_hda,
+    .qdev.reset   = intel_hda_reset,
+    .init         = intel_hda_init,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void intel_hda_register(void)
+{
+    pci_qdev_register(&intel_hda_info);
+}
+device_init(intel_hda_register);
+
+/*
+ * create intel hda controller with codec attached to it,
+ * so '-soundhw hda' works.
+ */
+int intel_hda_and_codec_init(PCIBus *bus)
+{
+    PCIDevice *controller;
+    BusState *hdabus;
+    DeviceState *codec;
+
+    controller = pci_create_simple(bus, -1, "intel-hda");
+    hdabus = QLIST_FIRST(&controller->qdev.child_bus);
+    codec = qdev_create(hdabus, "hda-duplex");
+    qdev_init_nofail(codec);
+    return 0;
+}
+
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
new file mode 100644 (file)
index 0000000..ba290ec
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef HW_INTEL_HDA_H
+#define HW_INTEL_HDA_H
+
+#include "qdev.h"
+
+/* --------------------------------------------------------------------- */
+/* hda bus                                                               */
+
+typedef struct HDACodecBus HDACodecBus;
+typedef struct HDACodecDevice HDACodecDevice;
+typedef struct HDACodecDeviceInfo HDACodecDeviceInfo;
+
+typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
+                                        bool solicited, uint32_t response);
+typedef bool (*hda_codec_xfer_func)(HDACodecDevice *dev,
+                                    uint32_t stnr, bool output,
+                                    uint8_t *buf, uint32_t len);
+
+struct HDACodecBus {
+    BusState qbus;
+    uint32_t next_cad;
+    hda_codec_response_func response;
+    hda_codec_xfer_func xfer;
+};
+
+struct HDACodecDevice {
+    DeviceState         qdev;
+    HDACodecDeviceInfo  *info;
+    uint32_t            cad;    /* codec address */
+};
+
+struct HDACodecDeviceInfo {
+    DeviceInfo qdev;
+    int (*init)(HDACodecDevice *dev);
+    void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
+    void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
+};
+
+void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
+                        hda_codec_response_func response,
+                        hda_codec_xfer_func xfer);
+void hda_codec_register(HDACodecDeviceInfo *info);
+HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
+
+void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
+bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                    uint8_t *buf, uint32_t len);
+
+/* --------------------------------------------------------------------- */
+
+#define dprint(_dev, _level, _fmt, ...)                                 \
+    do {                                                                \
+        if (_dev->debug >= _level) {                                    \
+            fprintf(stderr, "%s: ", _dev->name);                        \
+            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
+        }                                                               \
+    } while (0)
+
+/* --------------------------------------------------------------------- */
+
+#endif
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
new file mode 100644 (file)
index 0000000..3cc129f
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * ioh3420.c
+ * Intel X58 north bridge IOH
+ * PCI Express root port device id 3420
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "ioh3420.h"
+
+#define PCI_DEVICE_ID_IOH_EPORT         0x3420  /* D0:F0 express mode */
+#define PCI_DEVICE_ID_IOH_REV           0x2
+#define IOH_EP_SSVID_OFFSET             0x40
+#define IOH_EP_SSVID_SVID               PCI_VENDOR_ID_INTEL
+#define IOH_EP_SSVID_SSID               0
+#define IOH_EP_MSI_OFFSET               0x60
+#define IOH_EP_MSI_SUPPORTED_FLAGS      PCI_MSI_FLAGS_MASKBIT
+#define IOH_EP_MSI_NR_VECTOR            2
+#define IOH_EP_EXP_OFFSET               0x90
+#define IOH_EP_AER_OFFSET               0x100
+
+static void ioh3420_write_config(PCIDevice *d,
+                                   uint32_t address, uint32_t val, int len)
+{
+    pci_bridge_write_config(d, address, val, len);
+    msi_write_config(d, address, val, len);
+    pcie_cap_slot_write_config(d, address, val, len);
+    /* TODO: AER */
+}
+
+static void ioh3420_reset(DeviceState *qdev)
+{
+    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    msi_reset(d);
+    pcie_cap_root_reset(d);
+    pcie_cap_deverr_reset(d);
+    pcie_cap_slot_reset(d);
+    pci_bridge_reset(qdev);
+    pci_bridge_disable_base_limit(d);
+    /* TODO: AER */
+}
+
+static int ioh3420_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+    int rc;
+
+    rc = pci_bridge_initfn(d);
+    if (rc < 0) {
+        return rc;
+    }
+
+    d->config[PCI_REVISION_ID] = PCI_DEVICE_ID_IOH_REV;
+    pcie_port_init_reg(d);
+
+    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
+    pci_config_set_device_id(d->config, PCI_DEVICE_ID_IOH_EPORT);
+
+    rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
+                               IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
+    if (rc < 0) {
+        return rc;
+    }
+    rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
+                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        return rc;
+    }
+    rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
+    if (rc < 0) {
+        return rc;
+    }
+    pcie_cap_deverr_init(d);
+    pcie_cap_slot_init(d, s->slot);
+    pcie_chassis_create(s->chassis);
+    rc = pcie_chassis_add_slot(s);
+    if (rc < 0) {
+        return rc;
+    }
+    pcie_cap_root_init(d);
+    /* TODO: AER */
+    return 0;
+}
+
+static int ioh3420_exitfn(PCIDevice *d)
+{
+    /* TODO: AER */
+    msi_uninit(d);
+    pcie_cap_exit(d);
+    return pci_bridge_exitfn(d);
+}
+
+PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
+                         const char *bus_name, pci_map_irq_fn map_irq,
+                         uint8_t port, uint8_t chassis, uint16_t slot)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_prop_set_uint8(qdev, "chassis", chassis);
+    qdev_prop_set_uint16(qdev, "slot", slot);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
+}
+
+static const VMStateDescription vmstate_ioh3420 = {
+    .name = "ioh-3240-express-root-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pcie_cap_slot_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
+        /* TODO: AER */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PCIDeviceInfo ioh3420_info = {
+    .qdev.name = "ioh3420",
+    .qdev.desc = "Intel IOH device id 3420 PCIE Root Port",
+    .qdev.size = sizeof(PCIESlot),
+    .qdev.reset = ioh3420_reset,
+    .qdev.vmsd = &vmstate_ioh3420,
+
+    .is_express = 1,
+    .is_bridge = 1,
+    .config_write = ioh3420_write_config,
+    .init = ioh3420_initfn,
+    .exit = ioh3420_exitfn,
+
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+        DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+        DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+        /* TODO: AER */
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void ioh3420_register(void)
+{
+    pci_qdev_register(&ioh3420_info);
+}
+
+device_init(ioh3420_register);
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/ioh3420.h b/hw/ioh3420.h
new file mode 100644 (file)
index 0000000..68c523a
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef QEMU_IOH3420_H
+#define QEMU_IOH3420_H
+
+#include "pcie_port.h"
+
+PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
+                       const char *bus_name, pci_map_irq_fn map_irq,
+                       uint8_t port, uint8_t chassis, uint16_t slot);
+
+#endif /* QEMU_IOH3420_H */
index b6b04ddb9c153c428fa736c2d00d1674445d15d3..dc12144deda7762970b03c8cbe95ddc48cf674c7 100644 (file)
@@ -40,8 +40,8 @@
 #include "qemu-timer.h"
 #include "qemu_socket.h"
 #include "sun4m.h"
-
 #include "pcnet.h"
+#include "trace.h"
 
 typedef struct {
     SysBusDevice busdev;
@@ -59,10 +59,8 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
                              uint32_t val)
 {
     SysBusPCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("lance_mem_writew addr=" TARGET_FMT_plx " val=0x%04x\n", addr,
-           val & 0xffff);
-#endif
+
+    trace_lance_mem_writew(addr, val & 0xffff);
     pcnet_ioport_writew(&d->state, addr, val & 0xffff);
 }
 
@@ -72,11 +70,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
     uint32_t val;
 
     val = pcnet_ioport_readw(&d->state, addr);
-#ifdef PCNET_DEBUG_IO
-    printf("lance_mem_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr,
-           val & 0xffff);
-#endif
-
+    trace_lance_mem_readw(addr, val & 0xffff);
     return val & 0xffff;
 }
 
index 5eaf69ed3f54d852184c9c1cbdf579959e74813e..f97335eaa985ccf4012a055dd153f95d12dc2a24 100644 (file)
@@ -864,6 +864,7 @@ static void lsi_do_msgout(LSIState *s)
         case 0x01:
             len = lsi_get_msgbyte(s);
             msg = lsi_get_msgbyte(s);
+            (void)len; /* avoid a warning about unused variable*/
             DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
             switch (msg) {
             case 1:
index df80ef6c2b499184893e45db55a34074f88e5524..07eb9eeba19974c28ceec574959c41756db36718 100644 (file)
@@ -265,13 +265,11 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     qemu_irq *cpu_exit_irq;
     int via_devfn;
     PCIBus *pci_bus;
-    ISADevice *isa_dev;
     uint8_t *eeprom_buf;
     i2c_bus *smbus;
     int i;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     DeviceState *eeprom;
-    ISADevice *rtc_state;
     CPUState *env;
 
     /* init CPUs */
@@ -297,7 +295,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     ram_offset = qemu_ram_alloc(NULL, "fulong2e.ram", ram_size);
     bios_offset = qemu_ram_alloc(NULL, "fulong2e.bios", bios_size);
 
-    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
     cpu_register_physical_memory(0x1fc00000LL,
                                           bios_size, bios_offset | IO_MEM_ROM);
 
@@ -378,9 +376,9 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     DMA_init(0, cpu_exit_irq);
 
     /* Super I/O */
-    isa_dev = isa_create_simple("i8042");
+    isa_create_simple("i8042");
 
-    rtc_state = rtc_init(2000, NULL);
+    rtc_init(2000, NULL);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
index 096908943508ec4084f00edae9ddfb93e8fc4c65..80260714ec80d5c1bedeb932afc729cf09e9b03e 100644 (file)
@@ -784,11 +784,7 @@ void mips_malta_init (ram_addr_t ram_size,
     target_long bios_size;
     int64_t kernel_entry;
     PCIBus *pci_bus;
-    ISADevice *isa_dev;
     CPUState *env;
-    ISADevice *rtc_state;
-    FDCtrl *floppy_controller;
-    MaltaFPGAState *malta_fpga;
     qemu_irq *i8259;
     qemu_irq *cpu_exit_irq;
     int piix4_devfn;
@@ -851,7 +847,7 @@ void mips_malta_init (ram_addr_t ram_size,
     be = 0;
 #endif
     /* FPGA */
-    malta_fpga = malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
+    malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
 
     /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
     if (kernel_filename) {
@@ -957,9 +953,9 @@ void mips_malta_init (ram_addr_t ram_size,
     DMA_init(0, cpu_exit_irq);
 
     /* Super I/O */
-    isa_dev = isa_create_simple("i8042");
-    rtc_state = rtc_init(2000, NULL);
+    isa_create_simple("i8042");
+
+    rtc_init(2000, NULL);
     serial_isa_init(0, serial_hds[0]);
     serial_isa_init(1, serial_hds[1]);
     if (parallel_hds[0])
@@ -967,7 +963,7 @@ void mips_malta_init (ram_addr_t ram_size,
     for(i = 0; i < MAX_FD; i++) {
         fd[i] = drive_get(IF_FLOPPY, 0, i);
     }
-    floppy_controller = fdctrl_init_isa(fd);
+    fdctrl_init_isa(fd);
 
     /* Sound card */
     audio_init(pci_bus);
index ca61431eefcfe537bb2ee244c616c8f04a41af16..aa348904adda61f4c956cb43374039551204d178 100644 (file)
@@ -167,7 +167,6 @@ void mips_r4k_init (ram_addr_t ram_size,
     int bios_size;
     CPUState *env;
     ResetData *reset_info;
-    ISADevice *rtc_state;
     int i;
     qemu_irq *i8259;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@@ -268,7 +267,7 @@ void mips_r4k_init (ram_addr_t ram_size,
     isa_bus_new(NULL);
     isa_bus_irqs(i8259);
 
-    rtc_state = rtc_init(2000, NULL);
+    rtc_init(2000, NULL);
 
     /* Register 64 KB of ISA IO space at 0x14000000 */
 #ifdef TARGET_WORDS_BIGENDIAN
diff --git a/hw/msi.c b/hw/msi.c
new file mode 100644 (file)
index 0000000..f03f519
--- /dev/null
+++ b/hw/msi.c
@@ -0,0 +1,347 @@
+/*
+ * msi.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msi.h"
+#include "range.h"
+
+/* Eventually those constants should go to Linux pci_regs.h */
+#define PCI_MSI_PENDING_32      0x10
+#define PCI_MSI_PENDING_64      0x14
+
+/* PCI_MSI_ADDRESS_LO */
+#define PCI_MSI_ADDRESS_LO_MASK         (~0x3)
+
+/* If we get rid of cap allocator, we won't need those. */
+#define PCI_MSI_32_SIZEOF       0x0a
+#define PCI_MSI_64_SIZEOF       0x0e
+#define PCI_MSI_32M_SIZEOF      0x14
+#define PCI_MSI_64M_SIZEOF      0x18
+
+#define PCI_MSI_VECTORS_MAX     32
+
+/* If we get rid of cap allocator, we won't need this. */
+static inline uint8_t msi_cap_sizeof(uint16_t flags)
+{
+    switch (flags & (PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT)) {
+    case PCI_MSI_FLAGS_MASKBIT | PCI_MSI_FLAGS_64BIT:
+        return PCI_MSI_64M_SIZEOF;
+    case PCI_MSI_FLAGS_64BIT:
+        return PCI_MSI_64_SIZEOF;
+    case PCI_MSI_FLAGS_MASKBIT:
+        return PCI_MSI_32M_SIZEOF;
+    case 0:
+        return PCI_MSI_32_SIZEOF;
+    default:
+        abort();
+        break;
+    }
+    return 0;
+}
+
+//#define MSI_DEBUG
+
+#ifdef MSI_DEBUG
+# define MSI_DPRINTF(fmt, ...)                                          \
+    fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
+#else
+# define MSI_DPRINTF(fmt, ...)  do { } while (0)
+#endif
+#define MSI_DEV_PRINTF(dev, fmt, ...)                                   \
+    MSI_DPRINTF("%s:%x " fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
+
+static inline unsigned int msi_nr_vectors(uint16_t flags)
+{
+    return 1U <<
+        ((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1));
+}
+
+static inline uint8_t msi_flags_off(const PCIDevice* dev)
+{
+    return dev->msi_cap + PCI_MSI_FLAGS;
+}
+
+static inline uint8_t msi_address_lo_off(const PCIDevice* dev)
+{
+    return dev->msi_cap + PCI_MSI_ADDRESS_LO;
+}
+
+static inline uint8_t msi_address_hi_off(const PCIDevice* dev)
+{
+    return dev->msi_cap + PCI_MSI_ADDRESS_HI;
+}
+
+static inline uint8_t msi_data_off(const PCIDevice* dev, bool msi64bit)
+{
+    return dev->msi_cap + (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32);
+}
+
+static inline uint8_t msi_mask_off(const PCIDevice* dev, bool msi64bit)
+{
+    return dev->msi_cap + (msi64bit ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32);
+}
+
+static inline uint8_t msi_pending_off(const PCIDevice* dev, bool msi64bit)
+{
+    return dev->msi_cap + (msi64bit ? PCI_MSI_PENDING_64 : PCI_MSI_PENDING_32);
+}
+
+bool msi_enabled(const PCIDevice *dev)
+{
+    return msi_present(dev) &&
+        (pci_get_word(dev->config + msi_flags_off(dev)) &
+         PCI_MSI_FLAGS_ENABLE);
+}
+
+int msi_init(struct PCIDevice *dev, uint8_t offset,
+             unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask)
+{
+    unsigned int vectors_order;
+    uint16_t flags;
+    uint8_t cap_size;
+    int config_offset;
+    MSI_DEV_PRINTF(dev,
+                   "init offset: 0x%"PRIx8" vector: %"PRId8
+                   " 64bit %d mask %d\n",
+                   offset, nr_vectors, msi64bit, msi_per_vector_mask);
+
+    assert(!(nr_vectors & (nr_vectors - 1)));   /* power of 2 */
+    assert(nr_vectors > 0);
+    assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
+    /* the nr of MSI vectors is up to 32 */
+    vectors_order = ffs(nr_vectors) - 1;
+
+    flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1);
+    if (msi64bit) {
+        flags |= PCI_MSI_FLAGS_64BIT;
+    }
+    if (msi_per_vector_mask) {
+        flags |= PCI_MSI_FLAGS_MASKBIT;
+    }
+
+    cap_size = msi_cap_sizeof(flags);
+    config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size);
+    if (config_offset < 0) {
+        return config_offset;
+    }
+
+    dev->msi_cap = config_offset;
+    dev->cap_present |= QEMU_PCI_CAP_MSI;
+
+    pci_set_word(dev->config + msi_flags_off(dev), flags);
+    pci_set_word(dev->wmask + msi_flags_off(dev),
+                 PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
+    pci_set_long(dev->wmask + msi_address_lo_off(dev),
+                 PCI_MSI_ADDRESS_LO_MASK);
+    if (msi64bit) {
+        pci_set_long(dev->wmask + msi_address_hi_off(dev), 0xffffffff);
+    }
+    pci_set_word(dev->wmask + msi_data_off(dev, msi64bit), 0xffff);
+
+    if (msi_per_vector_mask) {
+        /* Make mask bits 0 to nr_vectors - 1 writeable. */
+        pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
+                     0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
+    }
+    return config_offset;
+}
+
+void msi_uninit(struct PCIDevice *dev)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    uint8_t cap_size = msi_cap_sizeof(flags);
+    pci_del_capability(dev, PCI_CAP_ID_MSIX, cap_size);
+    MSI_DEV_PRINTF(dev, "uninit\n");
+}
+
+void msi_reset(PCIDevice *dev)
+{
+    uint16_t flags;
+    bool msi64bit;
+
+    flags = pci_get_word(dev->config + msi_flags_off(dev));
+    flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
+    msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+
+    pci_set_word(dev->config + msi_flags_off(dev), flags);
+    pci_set_long(dev->config + msi_address_lo_off(dev), 0);
+    if (msi64bit) {
+        pci_set_long(dev->config + msi_address_hi_off(dev), 0);
+    }
+    pci_set_word(dev->config + msi_data_off(dev, msi64bit), 0);
+    if (flags & PCI_MSI_FLAGS_MASKBIT) {
+        pci_set_long(dev->config + msi_mask_off(dev, msi64bit), 0);
+        pci_set_long(dev->config + msi_pending_off(dev, msi64bit), 0);
+    }
+    MSI_DEV_PRINTF(dev, "reset\n");
+}
+
+static bool msi_is_masked(const PCIDevice *dev, unsigned int vector)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    uint32_t mask;
+    assert(vector < PCI_MSI_VECTORS_MAX);
+
+    if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
+        return false;
+    }
+
+    mask = pci_get_long(dev->config +
+                        msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT));
+    return mask & (1U << vector);
+}
+
+void msi_notify(PCIDevice *dev, unsigned int vector)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+    unsigned int nr_vectors = msi_nr_vectors(flags);
+    uint64_t address;
+    uint32_t data;
+
+    assert(vector < nr_vectors);
+    if (msi_is_masked(dev, vector)) {
+        assert(flags & PCI_MSI_FLAGS_MASKBIT);
+        pci_long_test_and_set_mask(
+            dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
+        MSI_DEV_PRINTF(dev, "pending vector 0x%x\n", vector);
+        return;
+    }
+
+    if (msi64bit) {
+        address = pci_get_quad(dev->config + msi_address_lo_off(dev));
+    } else {
+        address = pci_get_long(dev->config + msi_address_lo_off(dev));
+    }
+
+    /* upper bit 31:16 is zero */
+    data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
+    if (nr_vectors > 1) {
+        data &= ~(nr_vectors - 1);
+        data |= vector;
+    }
+
+    MSI_DEV_PRINTF(dev,
+                   "notify vector 0x%x"
+                   " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
+                   vector, address, data);
+    stl_phys(address, data);
+}
+
+/* call this function after updating configs by pci_default_write_config(). */
+void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
+    bool msi_per_vector_mask = flags & PCI_MSI_FLAGS_MASKBIT;
+    unsigned int nr_vectors;
+    uint8_t log_num_vecs;
+    uint8_t log_max_vecs;
+    unsigned int vector;
+    uint32_t pending;
+    int i;
+
+    if (!ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
+        return;
+    }
+
+#ifdef MSI_DEBUG
+    MSI_DEV_PRINTF(dev, "addr 0x%"PRIx32" val 0x%"PRIx32" len %d\n",
+                   addr, val, len);
+    MSI_DEV_PRINTF(dev, "ctrl: 0x%"PRIx16" address: 0x%"PRIx32,
+                   flags,
+                   pci_get_long(dev->config + msi_address_lo_off(dev)));
+    if (msi64bit) {
+        fprintf(stderr, " address-hi: 0x%"PRIx32,
+                pci_get_long(dev->config + msi_address_hi_off(dev)));
+    }
+    fprintf(stderr, " data: 0x%"PRIx16,
+            pci_get_word(dev->config + msi_data_off(dev, msi64bit)));
+    if (flags & PCI_MSI_FLAGS_MASKBIT) {
+        fprintf(stderr, " mask 0x%"PRIx32" pending 0x%"PRIx32,
+                pci_get_long(dev->config + msi_mask_off(dev, msi64bit)),
+                pci_get_long(dev->config + msi_pending_off(dev, msi64bit)));
+    }
+    fprintf(stderr, "\n");
+#endif
+
+    if (!(flags & PCI_MSI_FLAGS_ENABLE)) {
+        return;
+    }
+
+    /*
+     * Now MSI is enabled, clear INTx# interrupts.
+     * the driver is prohibited from writing enable bit to mask
+     * a service request. But the guest OS could do this.
+     * So we just discard the interrupts as moderate fallback.
+     *
+     * 6.8.3.3. Enabling Operation
+     *   While enabled for MSI or MSI-X operation, a function is prohibited
+     *   from using its INTx# pin (if implemented) to request
+     *   service (MSI, MSI-X, and INTx# are mutually exclusive).
+     */
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        qemu_set_irq(dev->irq[i], 0);
+    }
+
+    /*
+     * nr_vectors might be set bigger than capable. So clamp it.
+     * This is not legal by spec, so we can do anything we like,
+     * just don't crash the host
+     */
+    log_num_vecs =
+        (flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
+    log_max_vecs =
+        (flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1);
+    if (log_num_vecs > log_max_vecs) {
+        flags &= ~PCI_MSI_FLAGS_QSIZE;
+        flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
+        pci_set_word(dev->config + msi_flags_off(dev), flags);
+    }
+
+    if (!msi_per_vector_mask) {
+        /* if per vector masking isn't supported,
+           there is no pending interrupt. */
+        return;
+    }
+
+    nr_vectors = msi_nr_vectors(flags);
+
+    /* This will discard pending interrupts, if any. */
+    pending = pci_get_long(dev->config + msi_pending_off(dev, msi64bit));
+    pending &= 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors);
+    pci_set_long(dev->config + msi_pending_off(dev, msi64bit), pending);
+
+    /* deliver pending interrupts which are unmasked */
+    for (vector = 0; vector < nr_vectors; ++vector) {
+        if (msi_is_masked(dev, vector) || !(pending & (1U << vector))) {
+            continue;
+        }
+
+        pci_long_test_and_clear_mask(
+            dev->config + msi_pending_off(dev, msi64bit), 1U << vector);
+        msi_notify(dev, vector);
+    }
+}
+
+unsigned int msi_nr_vectors_allocated(const PCIDevice *dev)
+{
+    uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
+    return msi_nr_vectors(flags);
+}
diff --git a/hw/msi.h b/hw/msi.h
new file mode 100644 (file)
index 0000000..5766018
--- /dev/null
+++ b/hw/msi.h
@@ -0,0 +1,41 @@
+/*
+ * msi.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_MSI_H
+#define QEMU_MSI_H
+
+#include "qemu-common.h"
+#include "pci.h"
+
+bool msi_enabled(const PCIDevice *dev);
+int msi_init(struct PCIDevice *dev, uint8_t offset,
+             unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
+void msi_uninit(struct PCIDevice *dev);
+void msi_reset(PCIDevice *dev);
+void msi_notify(PCIDevice *dev, unsigned int vector);
+void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
+unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
+
+static inline bool msi_present(const PCIDevice *dev)
+{
+    return dev->cap_present & QEMU_PCI_CAP_MSI;
+}
+
+#endif /* QEMU_MSI_H */
index b3bb92d755a44380592937e0f19acdcddcbc76c5..f66d2550a7e9d22ba8bf552dcda5b1768c3a0ed6 100644 (file)
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -74,7 +74,8 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
     }
 
     pdev->msix_bar_size = new_size;
-    config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
+    config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX,
+                                       0, MSIX_CAP_LENGTH);
     if (config_offset < 0)
         return config_offset;
     config = pdev->config + config_offset;
@@ -158,6 +159,7 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
 {
     unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
     int vector;
+    int i;
 
     if (!range_covers_byte(addr, len, enable_pos)) {
         return;
@@ -167,7 +169,9 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
         return;
     }
 
-    qemu_set_irq(dev->irq[0], 0);
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        qemu_set_irq(dev->irq[i], 0);
+    }
 
     if (msix_function_masked(dev)) {
         return;
index 1280d4d78525d5e36a13eda6ef73a367ea7b8e34..962886e767921d6bfe9a7f4318af72b6340c2749 100644 (file)
--- a/hw/pci.c
+++ b/hw/pci.c
  */
 #include "hw.h"
 #include "pci.h"
+#include "pci_bridge.h"
+#include "pci_internals.h"
+#include "msix.h"
+#include "msi.h"
 #include "monitor.h"
 #include "net.h"
 #include "sysemu.h"
 # define PCI_DPRINTF(format, ...)       do { } while (0)
 #endif
 
-struct PCIBus {
-    BusState qbus;
-    int devfn_min;
-    pci_set_irq_fn set_irq;
-    pci_map_irq_fn map_irq;
-    pci_hotplug_fn hotplug;
-    DeviceState *hotplug_qdev;
-    void *irq_opaque;
-    PCIDevice *devices[256];
-    PCIDevice *parent_dev;
-    target_phys_addr_t mem_base;
-
-    QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
-    QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
-
-    /* The bus IRQ state is the logical OR of the connected devices.
-       Keep a count of the number of devices with raised IRQs.  */
-    int nirq;
-    int *irq_count;
-};
-
 static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
 static char *pcibus_get_dev_path(DeviceState *dev);
 
-static struct BusInfo pci_bus_info = {
+struct BusInfo pci_bus_info = {
     .name       = "PCI",
     .size       = sizeof(PCIBus),
     .print_dev  = pcibus_dev_print,
@@ -157,9 +140,9 @@ static void pci_device_reset(PCIDevice *dev)
     dev->irq_state = 0;
     pci_update_irq_status(dev);
     /* Clear all writeable bits */
-    pci_set_word(dev->config + PCI_COMMAND,
-                 pci_get_word(dev->config + PCI_COMMAND) &
-                 ~pci_get_word(dev->wmask + PCI_COMMAND));
+    pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
+                                 pci_get_word(dev->wmask + PCI_COMMAND) |
+                                 pci_get_word(dev->w1cmask + PCI_COMMAND));
     dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
     dev->config[PCI_INTERRUPT_LINE] = 0x0;
     for (r = 0; r < PCI_NUM_REGIONS; ++r) {
@@ -293,26 +276,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
     return bus;
 }
 
-static void pci_register_secondary_bus(PCIBus *parent,
-                                       PCIBus *bus,
-                                       PCIDevice *dev,
-                                       pci_map_irq_fn map_irq,
-                                       const char *name)
-{
-    qbus_create_inplace(&bus->qbus, &pci_bus_info, &dev->qdev, name);
-    bus->map_irq = map_irq;
-    bus->parent_dev = dev;
-
-    QLIST_INIT(&bus->child);
-    QLIST_INSERT_HEAD(&parent->child, bus, sibling);
-}
-
-static void pci_unregister_secondary_bus(PCIBus *bus)
-{
-    assert(QLIST_EMPTY(&bus->child));
-    QLIST_REMOVE(bus, sibling);
-}
-
 int pci_bus_num(PCIBus *s)
 {
     if (!s->parent_dev)
@@ -331,7 +294,8 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
 
     qemu_get_buffer(f, config, size);
     for (i = 0; i < size; ++i) {
-        if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i]) {
+        if ((config[i] ^ s->config[i]) &
+            s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {
             qemu_free(config);
             return -EINVAL;
         }
@@ -464,15 +428,18 @@ static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
 }
 
 /*
- * Parse [[<domain>:]<bus>:]<slot>, return -1 on error
+ * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
+ *       [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
  */
-static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
+int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+                      unsigned int *slotp, unsigned int *funcp)
 {
     const char *p;
     char *e;
     unsigned long val;
     unsigned long dom = 0, bus = 0;
-    unsigned slot = 0;
+    unsigned int slot = 0;
+    unsigned int func = 0;
 
     p = addr;
     val = strtoul(p, &e, 16);
@@ -494,11 +461,24 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s
        }
     }
 
-    if (dom > 0xffff || bus > 0xff || val > 0x1f)
-       return -1;
-
     slot = val;
 
+    if (funcp != NULL) {
+        if (*e != '.')
+            return -1;
+
+        p = e + 1;
+        val = strtoul(p, &e, 16);
+        if (e == p)
+            return -1;
+
+        func = val;
+    }
+
+    /* if funcp == NULL func is 0 */
+    if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
+       return -1;
+
     if (*e)
        return -1;
 
@@ -509,6 +489,8 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s
     *domp = dom;
     *busp = bus;
     *slotp = slot;
+    if (funcp != NULL)
+        *funcp = func;
     return 0;
 }
 
@@ -519,7 +501,7 @@ int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
     if (!strncmp(addr, "pci_addr=", 9)) {
         addr += 9;
     }
-    if (pci_parse_devaddr(addr, domp, busp, slotp)) {
+    if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) {
         monitor_printf(mon, "Invalid pci address\n");
         return -1;
     }
@@ -536,7 +518,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
         return pci_find_bus(pci_find_root_bus(0), 0);
     }
 
-    if (pci_parse_devaddr(devaddr, &dom, &bus, &slot) < 0) {
+    if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
         return NULL;
     }
 
@@ -649,6 +631,7 @@ static void pci_config_alloc(PCIDevice *pci_dev)
     pci_dev->config = qemu_mallocz(config_size);
     pci_dev->cmask = qemu_mallocz(config_size);
     pci_dev->wmask = qemu_mallocz(config_size);
+    pci_dev->w1cmask = qemu_mallocz(config_size);
     pci_dev->used = qemu_mallocz(config_size);
 }
 
@@ -657,6 +640,7 @@ static void pci_config_free(PCIDevice *pci_dev)
     qemu_free(pci_dev->config);
     qemu_free(pci_dev->cmask);
     qemu_free(pci_dev->wmask);
+    qemu_free(pci_dev->w1cmask);
     qemu_free(pci_dev->used);
 }
 
@@ -780,16 +764,15 @@ static int pci_unregister_device(DeviceState *dev)
 }
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, int type,
+                            pcibus_t size, uint8_t type,
                             PCIMapIORegionFunc *map_func)
 {
     PCIIORegion *r;
     uint32_t addr;
-    pcibus_t wmask;
-
-    if ((unsigned int)region_num >= PCI_NUM_REGIONS)
-        return;
+    uint64_t wmask;
 
+    assert(region_num >= 0);
+    assert(region_num < PCI_NUM_REGIONS);
     if (size & (size-1)) {
         fprintf(stderr, "ERROR: PCI region size must be pow2 "
                     "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);
@@ -820,75 +803,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
     }
 }
 
-static uint32_t pci_config_get_io_base(PCIDevice *d,
-                                       uint32_t base, uint32_t base_upper16)
-{
-    uint32_t val;
-
-    val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
-    if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
-        val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
-    }
-    return val;
-}
-
-static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base)
-{
-    return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
-        << 16;
-}
-
-static pcibus_t pci_config_get_pref_base(PCIDevice *d,
-                                         uint32_t base, uint32_t upper)
-{
-    pcibus_t tmp;
-    pcibus_t val;
-
-    tmp = (pcibus_t)pci_get_word(d->config + base);
-    val = (tmp & PCI_PREF_RANGE_MASK) << 16;
-    if (tmp & PCI_PREF_RANGE_TYPE_64) {
-        val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
-    }
-    return val;
-}
-
-static pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
-{
-    pcibus_t base;
-    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
-        base = pci_config_get_io_base(bridge,
-                                      PCI_IO_BASE, PCI_IO_BASE_UPPER16);
-    } else {
-        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
-            base = pci_config_get_pref_base(
-                bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
-        } else {
-            base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
-        }
-    }
-
-    return base;
-}
-
-static pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
-{
-    pcibus_t limit;
-    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
-        limit = pci_config_get_io_base(bridge,
-                                      PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
-        limit |= 0xfff;         /* PCI bridge spec 3.2.5.6. */
-    } else {
-        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
-            limit = pci_config_get_pref_base(
-                bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
-        } else {
-            limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
-        }
-        limit |= 0xfffff;       /* PCI bridge spec 3.2.5.{1, 8}. */
-    }
-    return limit;
-}
-
 static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
                               uint8_t type)
 {
@@ -1089,7 +1003,10 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 
     for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
         uint8_t wmask = d->wmask[addr + i];
+        uint8_t w1cmask = d->w1cmask[addr + i];
+        assert(!(wmask & w1cmask));
         d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
+        d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
     }
     if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
         ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
@@ -1121,6 +1038,23 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
     pci_change_irq_level(pci_dev, irq_num, change);
 }
 
+bool pci_msi_enabled(PCIDevice *dev)
+{
+    return msix_enabled(dev) || msi_enabled(dev);
+}
+
+void pci_msi_notify(PCIDevice *dev, unsigned int vector)
+{
+    if (msix_enabled(dev)) {
+        msix_notify(dev, vector);
+    } else if (msi_enabled(dev)) {
+        msi_notify(dev, vector);
+    } else {
+        /* MSI/MSI-X must be enabled */
+        abort();
+    }
+}
+
 /***********************************************************/
 /* monitor info on PCI */
 
@@ -1534,20 +1468,12 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
     return res;
 }
 
-typedef struct {
-    PCIDevice dev;
-    PCIBus bus;
-    uint32_t vid;
-    uint32_t did;
-} PCIBridge;
-
-
 static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)
 {
     pci_update_mappings(d);
 }
 
-static void pci_bridge_update_mappings(PCIBus *b)
+void pci_bridge_update_mappings(PCIBus *b)
 {
     PCIBus *child;
 
@@ -1558,23 +1484,6 @@ static void pci_bridge_update_mappings(PCIBus *b)
     }
 }
 
-static void pci_bridge_write_config(PCIDevice *d,
-                             uint32_t address, uint32_t val, int len)
-{
-    pci_default_write_config(d, address, val, len);
-
-    if (/* io base/limit */
-        ranges_overlap(address, len, PCI_IO_BASE, 2) ||
-
-        /* memory base/limit, prefetchable base/limit and
-           io base/limit upper 16 */
-        ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
-        PCIBridge *s = container_of(d, PCIBridge, dev);
-        PCIBus *secondary_bus = &s->bus;
-        pci_bridge_update_mappings(secondary_bus);
-    }
-}
-
 PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
 {
     PCIBus *sec;
@@ -1618,54 +1527,6 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function)
     return bus->devices[PCI_DEVFN(slot, function)];
 }
 
-static int pci_bridge_initfn(PCIDevice *dev)
-{
-    PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
-
-    pci_config_set_vendor_id(s->dev.config, s->vid);
-    pci_config_set_device_id(s->dev.config, s->did);
-
-    pci_set_word(dev->config + PCI_STATUS,
-                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
-    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
-    dev->config[PCI_HEADER_TYPE] =
-        (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
-        PCI_HEADER_TYPE_BRIDGE;
-    pci_set_word(dev->config + PCI_SEC_STATUS,
-                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
-    return 0;
-}
-
-static int pci_bridge_exitfn(PCIDevice *pci_dev)
-{
-    PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
-    PCIBus *bus = &s->bus;
-    pci_unregister_secondary_bus(bus);
-    return 0;
-}
-
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
-                        uint16_t vid, uint16_t did,
-                        pci_map_irq_fn map_irq, const char *name)
-{
-    PCIDevice *dev;
-    PCIBridge *s;
-
-    dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge");
-    qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
-    qdev_prop_set_uint32(&dev->qdev, "deviceid", did);
-    qdev_init_nofail(&dev->qdev);
-
-    s = DO_UPCAST(PCIBridge, dev, dev);
-    pci_register_secondary_bus(bus, &s->bus, &s->dev, map_irq, name);
-    return &s->bus;
-}
-
-PCIDevice *pci_bridge_get_device(PCIBus *bus)
-{
-    return bus->parent_dev;
-}
-
 static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     PCIDevice *pci_dev = (PCIDevice *)qdev;
@@ -1696,7 +1557,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
         pci_dev->romfile = qemu_strdup(info->romfile);
     pci_add_option_rom(pci_dev);
 
-    if (qdev->hotplugged) {
+    if (bus->hotplug) {
+        /* lower layer must check qdev->hotplugged */
         rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
         if (rc != 0) {
             int r = pci_unregister_device(&pci_dev->qdev);
@@ -1864,11 +1726,25 @@ static void pci_del_option_rom(PCIDevice *pdev)
     pdev->rom_offset = 0;
 }
 
-/* Reserve space and add capability to the linked list in pci config space */
-int pci_add_capability_at_offset(PCIDevice *pdev, uint8_t cap_id,
-                                 uint8_t offset, uint8_t size)
+/*
+ * if !offset
+ * Reserve space and add capability to the linked list in pci config space
+ *
+ * if offset = 0,
+ * Find and reserve space and add capability to the linked list
+ * in pci config space */
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+                       uint8_t offset, uint8_t size)
 {
-    uint8_t *config = pdev->config + offset;
+    uint8_t *config;
+    if (!offset) {
+        offset = pci_find_space(pdev, size);
+        if (!offset) {
+            return -ENOSPC;
+        }
+    }
+
+    config = pdev->config + offset;
     config[PCI_CAP_LIST_ID] = cap_id;
     config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
     pdev->config[PCI_CAPABILITY_LIST] = offset;
@@ -1881,17 +1757,6 @@ int pci_add_capability_at_offset(PCIDevice *pdev, uint8_t cap_id,
     return offset;
 }
 
-/* Find and reserve space and add capability to the linked list
- * in pci config space */
-int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
-{
-    uint8_t offset = pci_find_space(pdev, size);
-    if (!offset) {
-        return -ENOSPC;
-    }
-    return pci_add_capability_at_offset(pdev, cap_id, offset, size);
-}
-
 /* Unlink capability from the pci config space. */
 void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
 {
@@ -1901,6 +1766,7 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
     pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
     /* Make capability writeable again */
     memset(pdev->wmask + offset, 0xff, size);
+    memset(pdev->w1cmask + offset, 0, size);
     /* Clear cmask as device-specific registers can't be checked */
     memset(pdev->cmask + offset, 0, size);
     memset(pdev->used + offset, 0, size);
@@ -1971,23 +1837,3 @@ static char *pcibus_get_dev_path(DeviceState *dev)
     return strdup(path);
 }
 
-static PCIDeviceInfo bridge_info = {
-    .qdev.name    = "pci-bridge",
-    .qdev.size    = sizeof(PCIBridge),
-    .init         = pci_bridge_initfn,
-    .exit         = pci_bridge_exitfn,
-    .config_write = pci_bridge_write_config,
-    .is_bridge    = 1,
-    .qdev.props   = (Property[]) {
-        DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
-        DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
-};
-
-static void pci_register_devices(void)
-{
-    pci_qdev_register(&bridge_info);
-}
-
-device_init(pci_register_devices)
index 3d23f031f1925cc9fdc480133d6b8ca6840262e2..7100804e7c0b1e28072d887644d97eed348cc35c 100644 (file)
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -9,6 +9,8 @@
 /* PCI includes legacy ISA access.  */
 #include "isa.h"
 
+#include "pcie.h"
+
 /* PCI bus */
 
 #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
@@ -109,11 +111,12 @@ typedef struct PCIIORegion {
 
 /* Bits in cap_present field. */
 enum {
-    QEMU_PCI_CAP_MSIX = 0x1,
-    QEMU_PCI_CAP_EXPRESS = 0x2,
+    QEMU_PCI_CAP_MSI = 0x1,
+    QEMU_PCI_CAP_MSIX = 0x2,
+    QEMU_PCI_CAP_EXPRESS = 0x4,
 
     /* multifunction capable device */
-#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR        2
+#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR        3
     QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
 };
 
@@ -129,6 +132,9 @@ struct PCIDevice {
     /* Used to implement R/W bytes */
     uint8_t *wmask;
 
+    /* Used to implement RW1C(Write 1 to Clear) bytes */
+    uint8_t *w1cmask;
+
     /* Used to allocate config space for capabilities. */
     uint8_t *used;
 
@@ -168,6 +174,12 @@ struct PCIDevice {
     /* Version id needed for VMState */
     int32_t version_id;
 
+    /* Offset of MSI capability in config space */
+    uint8_t msi_cap;
+
+    /* PCI Express */
+    PCIExpressDevice exp;
+
     /* Location of option rom */
     char *romfile;
     ram_addr_t rom_offset;
@@ -180,12 +192,11 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                PCIConfigWriteFunc *config_write);
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, int type,
+                            pcibus_t size, uint8_t type,
                             PCIMapIORegionFunc *map_func);
 
-int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
-int pci_add_capability_at_offset(PCIDevice *pci_dev, uint8_t cap_id,
-                                 uint8_t cap_offset, uint8_t cap_size);
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+                       uint8_t offset, uint8_t size);
 
 void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
 
@@ -228,15 +239,17 @@ PCIBus *pci_find_bus(PCIBus *bus, int bus_num);
 PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function);
 PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
 
+int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+                      unsigned int *slotp, unsigned int *funcp);
 int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
                      unsigned *slotp);
 
 void do_pci_info_print(Monitor *mon, const QObject *data);
 void do_pci_info(Monitor *mon, QObject **ret_data);
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
-                        uint16_t vid, uint16_t did,
-                        pci_map_irq_fn map_irq, const char *name);
-PCIDevice *pci_bridge_get_device(PCIBus *bus);
+void pci_bridge_update_mappings(PCIBus *b);
+
+bool pci_msi_enabled(PCIDevice *dev);
+void pci_msi_notify(PCIDevice *dev, unsigned int vector);
 
 static inline void
 pci_set_byte(uint8_t *config, uint8_t val)
@@ -322,6 +335,76 @@ pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val)
     pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val);
 }
 
+/*
+ * helper functions to do bit mask operation on configuration space.
+ * Just to set bit, use test-and-set and discard returned value.
+ * Just to clear bit, use test-and-clear and discard returned value.
+ * NOTE: They aren't atomic.
+ */
+static inline uint8_t
+pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask)
+{
+    uint8_t val = pci_get_byte(config);
+    pci_set_byte(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint8_t
+pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask)
+{
+    uint8_t val = pci_get_byte(config);
+    pci_set_byte(config, val | mask);
+    return val & mask;
+}
+
+static inline uint16_t
+pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask)
+{
+    uint16_t val = pci_get_word(config);
+    pci_set_word(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint16_t
+pci_word_test_and_set_mask(uint8_t *config, uint16_t mask)
+{
+    uint16_t val = pci_get_word(config);
+    pci_set_word(config, val | mask);
+    return val & mask;
+}
+
+static inline uint32_t
+pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask)
+{
+    uint32_t val = pci_get_long(config);
+    pci_set_long(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint32_t
+pci_long_test_and_set_mask(uint8_t *config, uint32_t mask)
+{
+    uint32_t val = pci_get_long(config);
+    pci_set_long(config, val | mask);
+    return val & mask;
+}
+
+static inline uint64_t
+pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask)
+{
+    uint64_t val = pci_get_quad(config);
+    pci_set_quad(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint64_t
+pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
+{
+    uint64_t val = pci_get_quad(config);
+    pci_set_quad(config, val | mask);
+    return val & mask;
+}
+
 typedef int (*pci_qdev_initfn)(PCIDevice *dev);
 typedef struct {
     DeviceInfo qdev;
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
new file mode 100644 (file)
index 0000000..58cc2e4
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * QEMU PCI bus manager
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to dea
+
+ * 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.
+ */
+/*
+ * split out from pci.c
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ */
+
+#include "pci_bridge.h"
+#include "pci_internals.h"
+#include "range.h"
+
+/* PCI bridge subsystem vendor ID helper functions */
+#define PCI_SSVID_SIZEOF        8
+#define PCI_SSVID_SVID          4
+#define PCI_SSVID_SSID          6
+
+int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+                          uint16_t svid, uint16_t ssid)
+{
+    int pos;
+    pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF);
+    if (pos < 0) {
+        return pos;
+    }
+
+    pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid);
+    pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid);
+    return pos;
+}
+
+/* Accessor function to get parent bridge device from pci bus. */
+PCIDevice *pci_bridge_get_device(PCIBus *bus)
+{
+    return bus->parent_dev;
+}
+
+/* Accessor function to get secondary bus from pci-to-pci bridge device */
+PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
+{
+    return &br->sec_bus;
+}
+
+static uint32_t pci_config_get_io_base(const PCIDevice *d,
+                                       uint32_t base, uint32_t base_upper16)
+{
+    uint32_t val;
+
+    val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
+    if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
+        val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;
+    }
+    return val;
+}
+
+static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base)
+{
+    return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
+        << 16;
+}
+
+static pcibus_t pci_config_get_pref_base(const PCIDevice *d,
+                                         uint32_t base, uint32_t upper)
+{
+    pcibus_t tmp;
+    pcibus_t val;
+
+    tmp = (pcibus_t)pci_get_word(d->config + base);
+    val = (tmp & PCI_PREF_RANGE_MASK) << 16;
+    if (tmp & PCI_PREF_RANGE_TYPE_64) {
+        val |= (pcibus_t)pci_get_long(d->config + upper) << 32;
+    }
+    return val;
+}
+
+/* accessor function to get bridge filtering base address */
+pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type)
+{
+    pcibus_t base;
+    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+        base = pci_config_get_io_base(bridge,
+                                      PCI_IO_BASE, PCI_IO_BASE_UPPER16);
+    } else {
+        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+            base = pci_config_get_pref_base(
+                bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
+        } else {
+            base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
+        }
+    }
+
+    return base;
+}
+
+/* accessor funciton to get bridge filtering limit */
+pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
+{
+    pcibus_t limit;
+    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+        limit = pci_config_get_io_base(bridge,
+                                      PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
+        limit |= 0xfff;         /* PCI bridge spec 3.2.5.6. */
+    } else {
+        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+            limit = pci_config_get_pref_base(
+                bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
+        } else {
+            limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
+        }
+        limit |= 0xfffff;       /* PCI bridge spec 3.2.5.{1, 8}. */
+    }
+    return limit;
+}
+
+/* default write_config function for PCI-to-PCI bridge */
+void pci_bridge_write_config(PCIDevice *d,
+                             uint32_t address, uint32_t val, int len)
+{
+    pci_default_write_config(d, address, val, len);
+
+    if (/* io base/limit */
+        ranges_overlap(address, len, PCI_IO_BASE, 2) ||
+
+        /* memory base/limit, prefetchable base/limit and
+           io base/limit upper 16 */
+        ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
+        PCIBridge *s = container_of(d, PCIBridge, dev);
+        pci_bridge_update_mappings(&s->sec_bus);
+    }
+}
+
+void pci_bridge_disable_base_limit(PCIDevice *dev)
+{
+    uint8_t *conf = dev->config;
+
+    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
+                               PCI_IO_RANGE_MASK & 0xff);
+    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
+                                 PCI_IO_RANGE_MASK & 0xff);
+    pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE,
+                               PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
+                                 PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE,
+                               PCI_PREF_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
+                                 PCI_PREF_RANGE_MASK & 0xffff);
+    pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
+    pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
+}
+
+/* reset bridge specific configuration registers */
+void pci_bridge_reset_reg(PCIDevice *dev)
+{
+    uint8_t *conf = dev->config;
+
+    conf[PCI_PRIMARY_BUS] = 0;
+    conf[PCI_SECONDARY_BUS] = 0;
+    conf[PCI_SUBORDINATE_BUS] = 0;
+    conf[PCI_SEC_LATENCY_TIMER] = 0;
+
+    /*
+     * the default values for base/limit registers aren't specified
+     * in the PCI-to-PCI-bridge spec. So we don't thouch them here.
+     * Each implementation can override it.
+     * typical implementation does
+     * zero base/limit registers or
+     * disable forwarding: pci_bridge_disable_base_limit()
+     * If disable forwarding is wanted, call pci_bridge_disable_base_limit()
+     * after this function.
+     */
+    pci_byte_test_and_clear_mask(conf + PCI_IO_BASE,
+                                 PCI_IO_RANGE_MASK & 0xff);
+    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
+                                 PCI_IO_RANGE_MASK & 0xff);
+    pci_word_test_and_clear_mask(conf + PCI_MEMORY_BASE,
+                                 PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
+                                 PCI_MEMORY_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_BASE,
+                                 PCI_PREF_RANGE_MASK & 0xffff);
+    pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
+                                 PCI_PREF_RANGE_MASK & 0xffff);
+    pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
+    pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
+
+    pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
+}
+
+/* default reset function for PCI-to-PCI bridge */
+void pci_bridge_reset(DeviceState *qdev)
+{
+    PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+    pci_bridge_reset_reg(dev);
+}
+
+/* default qdev initialization function for PCI-to-PCI bridge */
+int pci_bridge_initfn(PCIDevice *dev)
+{
+    PCIBus *parent = dev->bus;
+    PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
+    PCIBus *sec_bus = &br->sec_bus;
+
+    pci_set_word(dev->config + PCI_STATUS,
+                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
+    dev->config[PCI_HEADER_TYPE] =
+        (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
+        PCI_HEADER_TYPE_BRIDGE;
+    pci_set_word(dev->config + PCI_SEC_STATUS,
+                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+
+    qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev,
+                        br->bus_name);
+    sec_bus->parent_dev = dev;
+    sec_bus->map_irq = br->map_irq;
+
+    QLIST_INIT(&sec_bus->child);
+    QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
+    return 0;
+}
+
+/* default qdev clean up function for PCI-to-PCI bridge */
+int pci_bridge_exitfn(PCIDevice *pci_dev)
+{
+    PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
+    assert(QLIST_EMPTY(&s->sec_bus.child));
+    QLIST_REMOVE(&s->sec_bus, sibling);
+    /* qbus_free() is called automatically by qdev_free() */
+    return 0;
+}
+
+/*
+ * before qdev initialization(qdev_init()), this function sets bus_name and
+ * map_irq callback which are necessry for pci_bridge_initfn() to
+ * initialize bus.
+ */
+void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
+                        pci_map_irq_fn map_irq)
+{
+    br->map_irq = map_irq;
+    br->bus_name = bus_name;
+}
diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h
new file mode 100644 (file)
index 0000000..84411a6
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * QEMU PCI bridge
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc]
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ */
+
+#ifndef QEMU_PCI_BRIDGE_H
+#define QEMU_PCI_BRIDGE_H
+
+#include "pci.h"
+
+int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+                          uint16_t svid, uint16_t ssid);
+
+PCIDevice *pci_bridge_get_device(PCIBus *bus);
+PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
+
+pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
+pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
+
+void pci_bridge_write_config(PCIDevice *d,
+                             uint32_t address, uint32_t val, int len);
+void pci_bridge_disable_base_limit(PCIDevice *dev);
+void pci_bridge_reset_reg(PCIDevice *dev);
+void pci_bridge_reset(DeviceState *qdev);
+
+int pci_bridge_initfn(PCIDevice *pci_dev);
+int pci_bridge_exitfn(PCIDevice *pci_dev);
+
+
+/*
+ * before qdev initialization(qdev_init()), this function sets bus_name and
+ * map_irq callback which are necessry for pci_bridge_initfn() to
+ * initialize bus.
+ */
+void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
+                        pci_map_irq_fn map_irq);
+
+#endif  /* QEMU_PCI_BRIDGE_H */
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
index 39e9f1d89d406409580d1e5c1737bbfb0f6bd17c..82cba7eeb37ba6805e7c9258556c3f8707653a2b 100644 (file)
@@ -57,6 +57,8 @@
 #define PCI_VENDOR_ID_AMD                0x1022
 #define PCI_DEVICE_ID_AMD_LANCE          0x2000
 
+#define PCI_VENDOR_ID_TI                 0x104c
+
 #define PCI_VENDOR_ID_MOTOROLA           0x1057
 #define PCI_DEVICE_ID_MOTOROLA_MPC106    0x0002
 #define PCI_DEVICE_ID_MOTOROLA_RAVEN     0x4801
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
new file mode 100644 (file)
index 0000000..e3c93a3
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef QEMU_PCI_INTERNALS_H
+#define QEMU_PCI_INTERNALS_H
+
+/*
+ * This header files is private to pci.c and pci_bridge.c
+ * So following structures are opaque to others and shouldn't be
+ * accessed.
+ *
+ * For pci-to-pci bridge needs to include this header file to embed
+ * PCIBridge in its structure or to get sizeof(PCIBridge),
+ * However, they shouldn't access those following members directly.
+ * Use accessor function in pci.h, pci_bridge.h
+ */
+
+extern struct BusInfo pci_bus_info;
+
+struct PCIBus {
+    BusState qbus;
+    int devfn_min;
+    pci_set_irq_fn set_irq;
+    pci_map_irq_fn map_irq;
+    pci_hotplug_fn hotplug;
+    DeviceState *hotplug_qdev;
+    void *irq_opaque;
+    PCIDevice *devices[256];
+    PCIDevice *parent_dev;
+    target_phys_addr_t mem_base;
+
+    QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
+    QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
+
+    /* The bus IRQ state is the logical OR of the connected devices.
+       Keep a count of the number of devices with raised IRQs.  */
+    int nirq;
+    int *irq_count;
+};
+
+struct PCIBridge {
+    PCIDevice dev;
+
+    /* private member */
+    PCIBus sec_bus;
+    pci_map_irq_fn map_irq;
+    const char *bus_name;
+};
+
+#endif /* QEMU_PCI_INTERNALS_H */
diff --git a/hw/pcie.c b/hw/pcie.c
new file mode 100644 (file)
index 0000000..35918f7
--- /dev/null
+++ b/hw/pcie.c
@@ -0,0 +1,541 @@
+/*
+ * pcie.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysemu.h"
+#include "range.h"
+#include "pci_bridge.h"
+#include "pcie.h"
+#include "msix.h"
+#include "msi.h"
+#include "pci_internals.h"
+#include "pcie_regs.h"
+#include "range.h"
+
+//#define DEBUG_PCIE
+#ifdef DEBUG_PCIE
+# define PCIE_DPRINTF(fmt, ...)                                         \
+    fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__)
+#else
+# define PCIE_DPRINTF(fmt, ...) do {} while (0)
+#endif
+#define PCIE_DEV_PRINTF(dev, fmt, ...)                                  \
+    PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
+
+
+/***************************************************************************
+ * pci express capability helper functions
+ */
+int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
+{
+    int pos;
+    uint8_t *exp_cap;
+
+    assert(pci_is_express(dev));
+
+    pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
+                                 PCI_EXP_VER2_SIZEOF);
+    if (pos < 0) {
+        return pos;
+    }
+    dev->exp.exp_cap = pos;
+    exp_cap = dev->config + pos;
+
+    /* capability register
+       interrupt message number defaults to 0 */
+    pci_set_word(exp_cap + PCI_EXP_FLAGS,
+                 ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) |
+                 PCI_EXP_FLAGS_VER2);
+
+    /* device capability register
+     * table 7-12:
+     * roll based error reporting bit must be set by all
+     * Functions conforming to the ECN, PCI Express Base
+     * Specification, Revision 1.1., or subsequent PCI Express Base
+     * Specification revisions.
+     */
+    pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);
+
+    pci_set_long(exp_cap + PCI_EXP_LNKCAP,
+                 (port << PCI_EXP_LNKCAP_PN_SHIFT) |
+                 PCI_EXP_LNKCAP_ASPMS_0S |
+                 PCI_EXP_LNK_MLW_1 |
+                 PCI_EXP_LNK_LS_25);
+
+    pci_set_word(exp_cap + PCI_EXP_LNKSTA,
+                 PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
+
+    pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
+                 PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
+
+    pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB);
+    return pos;
+}
+
+void pcie_cap_exit(PCIDevice *dev)
+{
+    pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
+}
+
+uint8_t pcie_cap_get_type(const PCIDevice *dev)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    assert(pos > 0);
+    return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) &
+            PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT;
+}
+
+/* MSI/MSI-X */
+/* pci express interrupt message number */
+/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */
+void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector)
+{
+    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+    assert(vector < 32);
+    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ);
+    pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
+                               vector << PCI_EXP_FLAGS_IRQ_SHIFT);
+}
+
+uint8_t pcie_cap_flags_get_vector(PCIDevice *dev)
+{
+    return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) &
+            PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT;
+}
+
+void pcie_cap_deverr_init(PCIDevice *dev)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP,
+                               PCI_EXP_DEVCAP_RBER);
+    pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL,
+                               PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
+                               PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
+    pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA,
+                               PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
+                               PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD);
+}
+
+void pcie_cap_deverr_reset(PCIDevice *dev)
+{
+    uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
+    pci_long_test_and_clear_mask(devctl,
+                                 PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE |
+                                 PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
+}
+
+static void hotplug_event_update_event_status(PCIDevice *dev)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    uint8_t *exp_cap = dev->config + pos;
+    uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
+    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+    dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) &&
+        (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED);
+}
+
+static void hotplug_event_notify(PCIDevice *dev)
+{
+    bool prev = dev->exp.hpev_notified;
+
+    hotplug_event_update_event_status(dev);
+
+    if (prev == dev->exp.hpev_notified) {
+        return;
+    }
+
+    /* Note: the logic above does not take into account whether interrupts
+     * are masked. The result is that interrupt will be sent when it is
+     * subsequently unmasked. This appears to be legal: Section 6.7.3.4:
+     * The Port may optionally send an MSI when there are hot-plug events that
+     * occur while interrupt generation is disabled, and interrupt generation is
+     * subsequently enabled. */
+    if (!pci_msi_enabled(dev)) {
+        qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
+    } else if (dev->exp.hpev_notified) {
+        pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
+    }
+}
+
+/*
+ * A PCI Express Hot-Plug Event has occured, so update slot status register
+ * and notify OS of the event if necessary.
+ *
+ * 6.7.3 PCI Express Hot-Plug Events
+ * 6.7.3.4 Software Notification of Hot-Plug Events
+ */
+static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
+{
+    /* Minor optimization: if nothing changed - no event is needed. */
+    if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
+                                   PCI_EXP_SLTSTA, event)) {
+        return;
+    }
+    hotplug_event_notify(dev);
+}
+
+static int pcie_cap_slot_hotplug(DeviceState *qdev,
+                                 PCIDevice *pci_dev, int state)
+{
+    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    uint8_t *exp_cap = d->config + d->exp.exp_cap;
+    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+    if (!pci_dev->qdev.hotplugged) {
+        assert(state); /* this case only happens at machine creation. */
+        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
+                                   PCI_EXP_SLTSTA_PDS);
+        return 0;
+    }
+
+    PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
+    if (sltsta & PCI_EXP_SLTSTA_EIS) {
+        /* the slot is electromechanically locked.
+         * This error is propagated up to qdev and then to HMP/QMP.
+         */
+        return -EBUSY;
+    }
+
+    /* TODO: multifunction hot-plug.
+     * Right now, only a device of function = 0 is allowed to be
+     * hot plugged/unplugged.
+     */
+    assert(PCI_FUNC(pci_dev->devfn) == 0);
+
+    if (state) {
+        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
+                                   PCI_EXP_SLTSTA_PDS);
+        pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
+    } else {
+        qdev_free(&pci_dev->qdev);
+        pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
+                                     PCI_EXP_SLTSTA_PDS);
+        pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
+    }
+    return 0;
+}
+
+/* pci express slot for pci express root/downstream port
+   PCI express capability slot registers */
+void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
+{
+    uint32_t pos = dev->exp.exp_cap;
+
+    pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS,
+                               PCI_EXP_FLAGS_SLOT);
+
+    pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP,
+                                 ~PCI_EXP_SLTCAP_PSN);
+    pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
+                               (slot << PCI_EXP_SLTCAP_PSN_SHIFT) |
+                               PCI_EXP_SLTCAP_EIP |
+                               PCI_EXP_SLTCAP_HPS |
+                               PCI_EXP_SLTCAP_HPC |
+                               PCI_EXP_SLTCAP_PIP |
+                               PCI_EXP_SLTCAP_AIP |
+                               PCI_EXP_SLTCAP_ABP);
+
+    pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
+                                 PCI_EXP_SLTCTL_PIC |
+                                 PCI_EXP_SLTCTL_AIC);
+    pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL,
+                               PCI_EXP_SLTCTL_PIC_OFF |
+                               PCI_EXP_SLTCTL_AIC_OFF);
+    pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
+                               PCI_EXP_SLTCTL_PIC |
+                               PCI_EXP_SLTCTL_AIC |
+                               PCI_EXP_SLTCTL_HPIE |
+                               PCI_EXP_SLTCTL_CCIE |
+                               PCI_EXP_SLTCTL_PDCE |
+                               PCI_EXP_SLTCTL_ABPE);
+    /* Although reading PCI_EXP_SLTCTL_EIC returns always 0,
+     * make the bit writable here in order to detect 1b is written.
+     * pcie_cap_slot_write_config() test-and-clear the bit, so
+     * this bit always returns 0 to the guest.
+     */
+    pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
+                               PCI_EXP_SLTCTL_EIC);
+
+    pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
+                               PCI_EXP_HP_EV_SUPPORTED);
+
+    dev->exp.hpev_notified = false;
+
+    pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)),
+                    pcie_cap_slot_hotplug, &dev->qdev);
+}
+
+void pcie_cap_slot_reset(PCIDevice *dev)
+{
+    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+
+    PCIE_DEV_PRINTF(dev, "reset\n");
+
+    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
+                                 PCI_EXP_SLTCTL_EIC |
+                                 PCI_EXP_SLTCTL_PIC |
+                                 PCI_EXP_SLTCTL_AIC |
+                                 PCI_EXP_SLTCTL_HPIE |
+                                 PCI_EXP_SLTCTL_CCIE |
+                                 PCI_EXP_SLTCTL_PDCE |
+                                 PCI_EXP_SLTCTL_ABPE);
+    pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
+                               PCI_EXP_SLTCTL_PIC_OFF |
+                               PCI_EXP_SLTCTL_AIC_OFF);
+
+    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
+                                 PCI_EXP_SLTSTA_EIS |/* on reset,
+                                                        the lock is released */
+                                 PCI_EXP_SLTSTA_CC |
+                                 PCI_EXP_SLTSTA_PDC |
+                                 PCI_EXP_SLTSTA_ABP);
+
+    hotplug_event_update_event_status(dev);
+}
+
+void pcie_cap_slot_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    uint8_t *exp_cap = dev->config + pos;
+    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+
+    if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
+        return;
+    }
+
+    if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
+                                     PCI_EXP_SLTCTL_EIC)) {
+        sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
+        pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
+        PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
+                        "sltsta -> 0x%02"PRIx16"\n",
+                        sltsta);
+    }
+
+    hotplug_event_notify(dev);
+
+    /* 
+     * 6.7.3.2 Command Completed Events
+     *
+     * Software issues a command to a hot-plug capable Downstream Port by
+     * issuing a write transaction that targets any portion of the Port’s Slot
+     * Control register. A single write to the Slot Control register is
+     * considered to be a single command, even if the write affects more than
+     * one field in the Slot Control register. In response to this transaction,
+     * the Port must carry out the requested actions and then set the
+     * associated status field for the command completed event. */
+
+    /* Real hardware might take a while to complete requested command because
+     * physical movement would be involved like locking the electromechanical
+     * lock.  However in our case, command is completed instantaneously above,
+     * so send a command completion event right now.
+     */
+    pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
+}
+
+int pcie_cap_slot_post_load(void *opaque, int version_id)
+{
+    PCIDevice *dev = opaque;
+    hotplug_event_update_event_status(dev);
+    return 0;
+}
+
+void pcie_cap_slot_push_attention_button(PCIDevice *dev)
+{
+    pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
+}
+
+/* root control/capabilities/status. PME isn't emulated for now */
+void pcie_cap_root_init(PCIDevice *dev)
+{
+    pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL,
+                 PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
+                 PCI_EXP_RTCTL_SEFEE);
+}
+
+void pcie_cap_root_reset(PCIDevice *dev)
+{
+    pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0);
+}
+
+/*
+ * TODO: implement FLR:
+ * Right now sets the bit which indicates FLR is supported.
+ */
+/* function level reset(FLR) */
+void pcie_cap_flr_init(PCIDevice *dev)
+{
+    pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP,
+                               PCI_EXP_DEVCAP_FLR);
+
+    /* Although reading BCR_FLR returns always 0,
+     * the bit is made writable here in order to detect the 1b is written
+     * pcie_cap_flr_write_config() test-and-clear the bit, so
+     * this bit always returns 0 to the guest.
+     */
+    pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL,
+                               PCI_EXP_DEVCTL_BCR_FLR);
+}
+
+void pcie_cap_flr_write_config(PCIDevice *dev,
+                               uint32_t addr, uint32_t val, int len)
+{
+    uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
+    if (pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR)) {
+        /* TODO: implement FLR */
+    }
+}
+
+/* Alternative Routing-ID Interpretation (ARI) */
+/* ari forwarding support for down stream port */
+void pcie_cap_ari_init(PCIDevice *dev)
+{
+    uint32_t pos = dev->exp.exp_cap;
+    pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2,
+                               PCI_EXP_DEVCAP2_ARI);
+    pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2,
+                               PCI_EXP_DEVCTL2_ARI);
+}
+
+void pcie_cap_ari_reset(PCIDevice *dev)
+{
+    uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2;
+    pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI);
+}
+
+bool pcie_cap_is_ari_enabled(const PCIDevice *dev)
+{
+    if (!pci_is_express(dev)) {
+        return false;
+    }
+    if (!dev->exp.exp_cap) {
+        return false;
+    }
+
+    return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
+        PCI_EXP_DEVCTL2_ARI;
+}
+
+/**************************************************************************
+ * pci express extended capability allocation functions
+ * uint16_t ext_cap_id (16 bit)
+ * uint8_t cap_ver (4 bit)
+ * uint16_t cap_offset (12 bit)
+ * uint16_t ext_cap_size
+ */
+
+static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id,
+                                          uint16_t *prev_p)
+{
+    uint16_t prev = 0;
+    uint16_t next;
+    uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE);
+
+    if (!header) {
+        /* no extended capability */
+        next = 0;
+        goto out;
+    }
+    for (next = PCI_CONFIG_SPACE_SIZE; next;
+         prev = next, next = PCI_EXT_CAP_NEXT(header)) {
+
+        assert(next >= PCI_CONFIG_SPACE_SIZE);
+        assert(next <= PCIE_CONFIG_SPACE_SIZE - 8);
+
+        header = pci_get_long(dev->config + next);
+        if (PCI_EXT_CAP_ID(header) == cap_id) {
+            break;
+        }
+    }
+
+out:
+    if (prev_p) {
+        *prev_p = prev;
+    }
+    return next;
+}
+
+uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id)
+{
+    return pcie_find_capability_list(dev, cap_id, NULL);
+}
+
+static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next)
+{
+    uint16_t header = pci_get_long(dev->config + pos);
+    assert(!(next & (PCI_EXT_CAP_ALIGN - 1)));
+    header = (header & ~PCI_EXT_CAP_NEXT_MASK) |
+        ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK);
+    pci_set_long(dev->config + pos, header);
+}
+
+/*
+ * caller must supply valid (offset, size) * such that the range shouldn't
+ * overlap with other capability or other registers.
+ * This function doesn't check it.
+ */
+void pcie_add_capability(PCIDevice *dev,
+                         uint16_t cap_id, uint8_t cap_ver,
+                         uint16_t offset, uint16_t size)
+{
+    uint32_t header;
+    uint16_t next;
+
+    assert(offset >= PCI_CONFIG_SPACE_SIZE);
+    assert(offset < offset + size);
+    assert(offset + size < PCIE_CONFIG_SPACE_SIZE);
+    assert(size >= 8);
+    assert(pci_is_express(dev));
+
+    if (offset == PCI_CONFIG_SPACE_SIZE) {
+        header = pci_get_long(dev->config + offset);
+        next = PCI_EXT_CAP_NEXT(header);
+    } else {
+        uint16_t prev;
+
+        /* 0 is reserved cap id. use internally to find the last capability
+           in the linked list */
+        next = pcie_find_capability_list(dev, 0, &prev);
+
+        assert(prev >= PCI_CONFIG_SPACE_SIZE);
+        assert(next == 0);
+        pcie_ext_cap_set_next(dev, prev, offset);
+    }
+    pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next));
+
+    /* Make capability read-only by default */
+    memset(dev->wmask + offset, 0, size);
+    memset(dev->w1cmask + offset, 0, size);
+    /* Check capability by default */
+    memset(dev->cmask + offset, 0xFF, size);
+}
+
+/**************************************************************************
+ * pci express extended capability helper functions
+ */
+
+/* ARI */
+void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn)
+{
+    pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER,
+                        offset, PCI_ARI_SIZEOF);
+    pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn));
+}
diff --git a/hw/pcie.h b/hw/pcie.h
new file mode 100644 (file)
index 0000000..8708504
--- /dev/null
+++ b/hw/pcie.h
@@ -0,0 +1,120 @@
+/*
+ * pcie.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_PCIE_H
+#define QEMU_PCIE_H
+
+#include "hw.h"
+#include "pci_regs.h"
+#include "pcie_regs.h"
+
+typedef enum {
+    /* for attention and power indicator */
+    PCI_EXP_HP_IND_RESERVED     = PCI_EXP_SLTCTL_IND_RESERVED,
+    PCI_EXP_HP_IND_ON           = PCI_EXP_SLTCTL_IND_ON,
+    PCI_EXP_HP_IND_BLINK        = PCI_EXP_SLTCTL_IND_BLINK,
+    PCI_EXP_HP_IND_OFF          = PCI_EXP_SLTCTL_IND_OFF,
+} PCIExpressIndicator;
+
+typedef enum {
+    /* these bits must match the bits in Slot Control/Status registers.
+     * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx
+     *
+     * Not all the bits of slot control register match with the ones of
+     * slot status. Not some bits of slot status register is used to
+     * show status, not to report event occurence.
+     * So such bits must be masked out when checking the software
+     * notification condition.
+     */
+    PCI_EXP_HP_EV_ABP           = PCI_EXP_SLTCTL_ABPE,
+                                        /* attention button pressed */
+    PCI_EXP_HP_EV_PDC           = PCI_EXP_SLTCTL_PDCE,
+                                        /* presence detect changed */
+    PCI_EXP_HP_EV_CCI           = PCI_EXP_SLTCTL_CCIE,
+                                        /* command completed */
+
+    PCI_EXP_HP_EV_SUPPORTED     = PCI_EXP_HP_EV_ABP |
+                                  PCI_EXP_HP_EV_PDC |
+                                  PCI_EXP_HP_EV_CCI,
+                                                /* supported event mask  */
+
+    /* events not listed aren't supported */
+} PCIExpressHotPlugEvent;
+
+struct PCIExpressDevice {
+    /* Offset of express capability in config space */
+    uint8_t exp_cap;
+
+    /* TODO FLR */
+
+    /* SLOT */
+    unsigned int hpev_intx;     /* INTx for hot plug event (0-3:INT[A-D]#)
+                                 * default is 0 = INTA#
+                                 * If the chip wants to use other interrupt
+                                 * line, initialize this member with the
+                                 * desired number.
+                                 * If the chip dynamically changes this member,
+                                 * also initialize it when loaded as
+                                 * appropreately.
+                                 */
+    bool hpev_notified; /* Logical AND of conditions for hot plug event.
+                         Following 6.7.3.4:
+                         Software Notification of Hot-Plug Events, an interrupt
+                         is sent whenever the logical and of these conditions
+                         transitions from false to true. */
+};
+
+/* PCI express capability helper functions */
+int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
+void pcie_cap_exit(PCIDevice *dev);
+uint8_t pcie_cap_get_type(const PCIDevice *dev);
+void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
+uint8_t pcie_cap_flags_get_vector(PCIDevice *dev);
+
+void pcie_cap_deverr_init(PCIDevice *dev);
+void pcie_cap_deverr_reset(PCIDevice *dev);
+
+void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
+void pcie_cap_slot_reset(PCIDevice *dev);
+void pcie_cap_slot_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len);
+int pcie_cap_slot_post_load(void *opaque, int version_id);
+void pcie_cap_slot_push_attention_button(PCIDevice *dev);
+
+void pcie_cap_root_init(PCIDevice *dev);
+void pcie_cap_root_reset(PCIDevice *dev);
+
+void pcie_cap_flr_init(PCIDevice *dev);
+void pcie_cap_flr_write_config(PCIDevice *dev,
+                           uint32_t addr, uint32_t val, int len);
+
+void pcie_cap_ari_init(PCIDevice *dev);
+void pcie_cap_ari_reset(PCIDevice *dev);
+bool pcie_cap_is_ari_enabled(const PCIDevice *dev);
+
+/* PCI express extended capability helper functions */
+uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
+void pcie_add_capability(PCIDevice *dev,
+                         uint16_t cap_id, uint8_t cap_ver,
+                         uint16_t offset, uint16_t size);
+
+void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
+
+#endif /* QEMU_PCIE_H */
diff --git a/hw/pcie_port.c b/hw/pcie_port.c
new file mode 100644 (file)
index 0000000..117de61
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * pcie_port.c
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pcie_port.h"
+
+void pcie_port_init_reg(PCIDevice *d)
+{
+    /* Unlike pci bridge,
+       66MHz and fast back to back don't apply to pci express port. */
+    pci_set_word(d->config + PCI_STATUS, 0);
+    pci_set_word(d->config + PCI_SEC_STATUS, 0);
+
+    /* 7.5.3.5 Prefetchable Memory Base Limit
+     * The Prefetchable Memory Base and Prefetchable Memory Limit registers
+     * must indicate that 64-bit addresses are supported, as defined in
+     * PCI-to-PCI Bridge Architecture Specification, Revision 1.2.
+     */
+    pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
+                               PCI_PREF_RANGE_TYPE_64);
+    pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
+                               PCI_PREF_RANGE_TYPE_64);
+}
+
+/**************************************************************************
+ * (chassis number, pcie physical slot number) -> pcie slot conversion
+ */
+struct PCIEChassis {
+    uint8_t     number;
+
+    QLIST_HEAD(, PCIESlot) slots;
+    QLIST_ENTRY(PCIEChassis) next;
+};
+
+static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
+
+static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
+{
+    struct PCIEChassis *c;
+    QLIST_FOREACH(c, &chassis, next) {
+        if (c->number == chassis_number) {
+            break;
+        }
+    }
+    return c;
+}
+
+void pcie_chassis_create(uint8_t chassis_number)
+{
+    struct PCIEChassis *c;
+    c = pcie_chassis_find(chassis_number);
+    if (c) {
+        return;
+    }
+    c = qemu_mallocz(sizeof(*c));
+    c->number = chassis_number;
+    QLIST_INIT(&c->slots);
+    QLIST_INSERT_HEAD(&chassis, c, next);
+}
+
+static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
+                                                     uint8_t slot)
+{
+    PCIESlot *s;
+    QLIST_FOREACH(s, &c->slots, next) {
+        if (s->slot == slot) {
+            break;
+        }
+    }
+    return s;
+}
+
+PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
+{
+    struct PCIEChassis *c;
+    c = pcie_chassis_find(chassis_number);
+    if (!c) {
+        return NULL;
+    }
+    return pcie_chassis_find_slot_with_chassis(c, slot);
+}
+
+int pcie_chassis_add_slot(struct PCIESlot *slot)
+{
+    struct PCIEChassis *c;
+    c = pcie_chassis_find(slot->chassis);
+    if (!c) {
+        return -ENODEV;
+    }
+    if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
+        return -EBUSY;
+    }
+    QLIST_INSERT_HEAD(&c->slots, slot, next);
+    return 0;
+}
+
+void pcie_chassis_del_slot(PCIESlot *s)
+{
+    QLIST_REMOVE(s, next);
+}
diff --git a/hw/pcie_port.h b/hw/pcie_port.h
new file mode 100644 (file)
index 0000000..3709583
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * pcie_port.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_PCIE_PORT_H
+#define QEMU_PCIE_PORT_H
+
+#include "pci_bridge.h"
+#include "pci_internals.h"
+
+struct PCIEPort {
+    PCIBridge   br;
+
+    /* pci express switch port */
+    uint8_t     port;
+};
+
+void pcie_port_init_reg(PCIDevice *d);
+
+struct PCIESlot {
+    PCIEPort    port;
+
+    /* pci express switch port with slot */
+    uint8_t     chassis;
+    uint16_t    slot;
+    QLIST_ENTRY(PCIESlot) next;
+};
+
+void pcie_chassis_create(uint8_t chassis_number);
+void pcie_main_chassis_create(void);
+PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
+int pcie_chassis_add_slot(struct PCIESlot *slot);
+void pcie_chassis_del_slot(PCIESlot *s);
+
+#endif /* QEMU_PCIE_PORT_H */
diff --git a/hw/pcie_regs.h b/hw/pcie_regs.h
new file mode 100644 (file)
index 0000000..3461a1b
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * constants for pcie configurations space from pci express spec.
+ *
+ * TODO:
+ * Those constants and macros should go to Linux pci_regs.h
+ * Once they're merged, they will go away.
+ */
+#ifndef QEMU_PCIE_REGS_H
+#define QEMU_PCIE_REGS_H
+
+
+/* express capability */
+
+#define PCI_EXP_VER2_SIZEOF             0x3c /* express capability of ver. 2 */
+#define PCI_EXT_CAP_VER_SHIFT           16
+#define PCI_EXT_CAP_NEXT_SHIFT          20
+#define PCI_EXT_CAP_NEXT_MASK           (0xffc << PCI_EXT_CAP_NEXT_SHIFT)
+
+#define PCI_EXT_CAP(id, ver, next)                                      \
+    ((id) |                                                             \
+     ((ver) << PCI_EXT_CAP_VER_SHIFT) |                                 \
+     ((next) << PCI_EXT_CAP_NEXT_SHIFT))
+
+#define PCI_EXT_CAP_ALIGN               4
+#define PCI_EXT_CAP_ALIGNUP(x)                                  \
+    (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1))
+
+/* PCI_EXP_FLAGS */
+#define PCI_EXP_FLAGS_VER2              2 /* for now, supports only ver. 2 */
+#define PCI_EXP_FLAGS_IRQ_SHIFT         (ffs(PCI_EXP_FLAGS_IRQ) - 1)
+#define PCI_EXP_FLAGS_TYPE_SHIFT        (ffs(PCI_EXP_FLAGS_TYPE) - 1)
+
+
+/* PCI_EXP_LINK{CAP, STA} */
+/* link speed */
+#define PCI_EXP_LNK_LS_25               1
+
+#define PCI_EXP_LNK_MLW_SHIFT           (ffs(PCI_EXP_LNKCAP_MLW) - 1)
+#define PCI_EXP_LNK_MLW_1               (1 << PCI_EXP_LNK_MLW_SHIFT)
+
+/* PCI_EXP_LINKCAP */
+#define PCI_EXP_LNKCAP_ASPMS_SHIFT      (ffs(PCI_EXP_LNKCAP_ASPMS) - 1)
+#define PCI_EXP_LNKCAP_ASPMS_0S         (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
+
+#define PCI_EXP_LNKCAP_PN_SHIFT         (ffs(PCI_EXP_LNKCAP_PN) - 1)
+
+#define PCI_EXP_SLTCAP_PSN_SHIFT        (ffs(PCI_EXP_SLTCAP_PSN) - 1)
+
+#define PCI_EXP_SLTCTL_IND_RESERVED     0x0
+#define PCI_EXP_SLTCTL_IND_ON           0x1
+#define PCI_EXP_SLTCTL_IND_BLINK        0x2
+#define PCI_EXP_SLTCTL_IND_OFF          0x3
+#define PCI_EXP_SLTCTL_AIC_SHIFT        (ffs(PCI_EXP_SLTCTL_AIC) - 1)
+#define PCI_EXP_SLTCTL_AIC_OFF                          \
+    (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT)
+
+#define PCI_EXP_SLTCTL_PIC_SHIFT        (ffs(PCI_EXP_SLTCTL_PIC) - 1)
+#define PCI_EXP_SLTCTL_PIC_OFF                          \
+    (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT)
+
+#define PCI_EXP_SLTCTL_SUPPORTED        \
+            (PCI_EXP_SLTCTL_ABPE |      \
+             PCI_EXP_SLTCTL_PDCE |      \
+             PCI_EXP_SLTCTL_CCIE |      \
+             PCI_EXP_SLTCTL_HPIE |      \
+             PCI_EXP_SLTCTL_AIC |       \
+             PCI_EXP_SLTCTL_PCC |       \
+             PCI_EXP_SLTCTL_EIC)
+
+#define PCI_EXP_DEVCAP2_EFF             0x100000
+#define PCI_EXP_DEVCAP2_EETLPP          0x200000
+
+#define PCI_EXP_DEVCTL2_EETLPPB         0x80
+
+/* ARI */
+#define PCI_ARI_VER                     1
+#define PCI_ARI_SIZEOF                  8
+
+/* AER */
+#define PCI_ERR_VER                     2
+#define PCI_ERR_SIZEOF                  0x48
+
+#define PCI_ERR_UNC_SDN                 0x00000020      /* surprise down */
+#define PCI_ERR_UNC_ACSV                0x00200000      /* ACS Violation */
+#define PCI_ERR_UNC_INTN                0x00400000      /* Internal Error */
+#define PCI_ERR_UNC_MCBTLP              0x00800000      /* MC Blcoked TLP */
+#define PCI_ERR_UNC_ATOP_EBLOCKED       0x01000000      /* atomic op egress blocked */
+#define PCI_ERR_UNC_TLP_PRF_BLOCKED     0x02000000      /* TLP Prefix Blocked */
+#define PCI_ERR_COR_ADV_NONFATAL        0x00002000      /* Advisory Non-Fatal */
+#define PCI_ERR_COR_INTERNAL            0x00004000      /* Corrected Internal */
+#define PCI_ERR_COR_HL_OVERFLOW         0x00008000      /* Header Long Overflow */
+#define PCI_ERR_CAP_FEP_MASK            0x0000001f
+#define PCI_ERR_CAP_MHRC                0x00000200
+#define PCI_ERR_CAP_MHRE                0x00000400
+#define PCI_ERR_CAP_TLP                 0x00000800
+
+#define PCI_ERR_TLP_PREFIX_LOG          0x38
+
+#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR         0x4000
+
+/* aer root error command/status */
+#define PCI_ERR_ROOT_CMD_EN_MASK        (PCI_ERR_ROOT_CMD_COR_EN |      \
+                                         PCI_ERR_ROOT_CMD_NONFATAL_EN | \
+                                         PCI_ERR_ROOT_CMD_FATAL_EN)
+
+#define PCI_ERR_ROOT_IRQ_MAX            32
+#define PCI_ERR_ROOT_IRQ                0xf8000000
+#define PCI_ERR_ROOT_IRQ_SHIFT          (ffs(PCI_ERR_ROOT_IRQ) - 1)
+#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV |         \
+                                         PCI_ERR_ROOT_MULTI_COR_RCV |   \
+                                         PCI_ERR_ROOT_UNCOR_RCV |       \
+                                         PCI_ERR_ROOT_MULTI_UNCOR_RCV | \
+                                         PCI_ERR_ROOT_FIRST_FATAL |     \
+                                         PCI_ERR_ROOT_NONFATAL_RCV |    \
+                                         PCI_ERR_ROOT_FATAL_RCV)
+
+#define PCI_ERR_UNC_SUPPORTED           (PCI_ERR_UNC_DLP |              \
+                                         PCI_ERR_UNC_SDN |              \
+                                         PCI_ERR_UNC_POISON_TLP |       \
+                                         PCI_ERR_UNC_FCP |              \
+                                         PCI_ERR_UNC_COMP_TIME |        \
+                                         PCI_ERR_UNC_COMP_ABORT |       \
+                                         PCI_ERR_UNC_UNX_COMP |         \
+                                         PCI_ERR_UNC_RX_OVER |          \
+                                         PCI_ERR_UNC_MALF_TLP |         \
+                                         PCI_ERR_UNC_ECRC |             \
+                                         PCI_ERR_UNC_UNSUP |            \
+                                         PCI_ERR_UNC_ACSV |             \
+                                         PCI_ERR_UNC_INTN |             \
+                                         PCI_ERR_UNC_MCBTLP |           \
+                                         PCI_ERR_UNC_ATOP_EBLOCKED |    \
+                                         PCI_ERR_UNC_TLP_PRF_BLOCKED)
+
+#define PCI_ERR_UNC_SEVERITY_DEFAULT    (PCI_ERR_UNC_DLP |              \
+                                         PCI_ERR_UNC_SDN |              \
+                                         PCI_ERR_UNC_FCP |              \
+                                         PCI_ERR_UNC_RX_OVER |          \
+                                         PCI_ERR_UNC_MALF_TLP |         \
+                                         PCI_ERR_UNC_INTN)
+
+#define PCI_ERR_COR_SUPPORTED           (PCI_ERR_COR_RCVR |             \
+                                         PCI_ERR_COR_BAD_TLP |          \
+                                         PCI_ERR_COR_BAD_DLLP |         \
+                                         PCI_ERR_COR_REP_ROLL |         \
+                                         PCI_ERR_COR_REP_TIMER |        \
+                                         PCI_ERR_COR_ADV_NONFATAL |     \
+                                         PCI_ERR_COR_INTERNAL |         \
+                                         PCI_ERR_COR_HL_OVERFLOW)
+
+#define PCI_ERR_COR_MASK_DEFAULT        (PCI_ERR_COR_ADV_NONFATAL |     \
+                                         PCI_ERR_COR_INTERNAL |         \
+                                         PCI_ERR_COR_HL_OVERFLOW)
+
+#endif /* QEMU_PCIE_REGS_H */
index db8e5ecb74c4f6168c04bc9c8eaf78aedd686a9a..c5897a9d4da905260b7d74f1efb48929383cd74c 100644 (file)
@@ -501,7 +501,6 @@ static void taihu_405ep_init(ram_addr_t ram_size,
                              const char *cpu_model)
 {
     char *filename;
-    CPUPPCState *env;
     qemu_irq *pic;
     ram_addr_t bios_offset;
     target_phys_addr_t ram_bases[2], ram_sizes[2];
@@ -521,8 +520,8 @@ static void taihu_405ep_init(ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register cpu\n", __func__);
 #endif
-    env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
-                        kernel_filename == NULL ? 0 : 1);
+    ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
+                  kernel_filename == NULL ? 0 : 1);
     /* allocate and load BIOS */
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register BIOS\n", __func__);
index b884ea5fbd02a4d6baf744e6eccc91ced0746222..360073741268cfc5d41c64142662dc0f63cd14f5 100644 (file)
@@ -630,18 +630,11 @@ struct ppc405_dma_t {
 
 static uint32_t dcr_read_dma (void *opaque, int dcrn)
 {
-    ppc405_dma_t *dma;
-
-    dma = opaque;
-
     return 0;
 }
 
 static void dcr_write_dma (void *opaque, int dcrn, uint32_t val)
 {
-    ppc405_dma_t *dma;
-
-    dma = opaque;
 }
 
 static void ppc405_dma_reset (void *opaque)
@@ -739,9 +732,6 @@ struct ppc405_gpio_t {
 
 static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 #endif
@@ -752,9 +742,6 @@ static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
 static void ppc405_gpio_writeb (void *opaque,
                                 target_phys_addr_t addr, uint32_t value)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
            value);
@@ -763,9 +750,6 @@ static void ppc405_gpio_writeb (void *opaque,
 
 static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 #endif
@@ -776,9 +760,6 @@ static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
 static void ppc405_gpio_writew (void *opaque,
                                 target_phys_addr_t addr, uint32_t value)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
            value);
@@ -787,9 +768,6 @@ static void ppc405_gpio_writew (void *opaque,
 
 static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 #endif
@@ -800,9 +778,6 @@ static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
 static void ppc405_gpio_writel (void *opaque,
                                 target_phys_addr_t addr, uint32_t value)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
            value);
@@ -823,9 +798,6 @@ static CPUWriteMemoryFunc * const ppc405_gpio_write[] = {
 
 static void ppc405_gpio_reset (void *opaque)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 }
 
 static void ppc405_gpio_init(target_phys_addr_t base)
index 89f96bbc347b32491d4d64ad8a26d3bf03638724..ea8759324cd6510f3c34d75a5d36af691c23220f 100644 (file)
@@ -30,7 +30,6 @@
 
 #define BIOS_SIZE     (1024 * 1024)
 #define BIOS_FILENAME "ppc_rom.bin"
-#define VGABIOS_FILENAME "video.x"
 #define NVRAM_SIZE        0x2000
 #define PROM_FILENAME    "openbios-ppc"
 #define PROM_ADDR         0xfff00000
index fb07c8316f69486278949e88a2dc74bec3a93e7b..4369337b2133a2701906d6d38b64b24b1c85aeeb 100644 (file)
@@ -69,7 +69,6 @@
 #include "blockdev.h"
 
 #define MAX_IDE_BUS 2
-#define VGA_BIOS_SIZE 65536
 #define CFG_ADDR 0xf0000510
 
 /* debug UniNorth */
@@ -129,25 +128,24 @@ static void ppc_core99_init (ram_addr_t ram_size,
                              const char *initrd_filename,
                              const char *cpu_model)
 {
-    CPUState *env = NULL, *envs[MAX_CPUS];
+    CPUState *env = NULL;
     char *filename;
     qemu_irq *pic, **openpic_irqs;
     int unin_memory;
     int linux_boot, i;
-    ram_addr_t ram_offset, bios_offset, vga_bios_offset;
+    ram_addr_t ram_offset, bios_offset;
     uint32_t kernel_base, initrd_base;
     long kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
     int nvram_mem_index;
-    int vga_bios_size, bios_size;
+    int bios_size;
     int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index;
     int ide_mem_index[3];
     int ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
     void *dbdma;
-    uint8_t *vga_bios_ptr;
     int machine_arch;
 
     linux_boot = (kernel_filename != NULL);
@@ -167,11 +165,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
         }
         /* Set time-base frequency to 100 Mhz */
         cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
-#if 0
-        env->osi_call = vga_osi_call;
-#endif
         qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
-        envs[i] = env;
     }
 
     /* allocate RAM */
@@ -199,36 +193,6 @@ static void ppc_core99_init (ram_addr_t ram_size,
         exit(1);
     }
 
-    /* allocate and load VGA BIOS */
-    vga_bios_offset = qemu_ram_alloc(NULL, "ppc_core99.vbios", VGA_BIOS_SIZE);
-    vga_bios_ptr = qemu_get_ram_ptr(vga_bios_offset);
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, VGABIOS_FILENAME);
-    if (filename) {
-        vga_bios_size = load_image(filename, vga_bios_ptr + 8);
-        qemu_free(filename);
-    } else {
-        vga_bios_size = -1;
-    }
-    if (vga_bios_size < 0) {
-        /* if no bios is present, we can still work */
-        fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n",
-                VGABIOS_FILENAME);
-        vga_bios_size = 0;
-    } else {
-        /* set a specific header (XXX: find real Apple format for NDRV
-           drivers) */
-        vga_bios_ptr[0] = 'N';
-        vga_bios_ptr[1] = 'D';
-        vga_bios_ptr[2] = 'R';
-        vga_bios_ptr[3] = 'V';
-        cpu_to_be32w((uint32_t *)(vga_bios_ptr + 4), vga_bios_size);
-        vga_bios_size += 8;
-
-        /* Round to page boundary */
-        vga_bios_size = (vga_bios_size + TARGET_PAGE_SIZE - 1) &
-            TARGET_PAGE_MASK;
-    }
-
     if (linux_boot) {
         uint64_t lowaddr = 0;
         int bswap_needed;
@@ -352,7 +316,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
         machine_arch = ARCH_MAC99;
     }
     /* init basic PC hardware */
-    pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size);
+    pci_vga_init(pci_bus, 0, 0);
 
     escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
                                serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
index a12a812970766d7e271192b5b5dacd3bcad4874a..a2f9ddf738ade250acfa8c7256a5221e6728ce4e 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * QEMU OldWorld PowerMac (currently ~G3 Beige) hardware System Emulator
  *
 #include "blockdev.h"
 
 #define MAX_IDE_BUS 2
-#define VGA_BIOS_SIZE 65536
 #define CFG_ADDR 0xf0000510
 
-/* temporary frame buffer OSI calls for the video.x driver. The right
-   solution is to modify the driver to use VGA PCI I/Os */
-/* XXX: to be removed. This is no way related to emulation */
-static int vga_osi_call (CPUState *env)
-{
-    static int vga_vbl_enabled;
-    int linesize;
-
-#if 0
-    printf("osi_call R5=%016" PRIx64 "\n", ppc_dump_gpr(env, 5));
-#endif
-
-    /* same handler as PearPC, coming from the original MOL video
-       driver. */
-    switch(env->gpr[5]) {
-    case 4:
-        break;
-    case 28: /* set_vmode */
-        if (env->gpr[6] != 1 || env->gpr[7] != 0)
-            env->gpr[3] = 1;
-        else
-            env->gpr[3] = 0;
-        break;
-    case 29: /* get_vmode_info */
-        if (env->gpr[6] != 0) {
-            if (env->gpr[6] != 1 || env->gpr[7] != 0) {
-                env->gpr[3] = 1;
-                break;
-            }
-        }
-        env->gpr[3] = 0;
-        env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
-        env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
-        env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
-        env->gpr[7] = 85 << 16; /* refresh rate */
-        env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
-        linesize = ((graphic_depth + 7) >> 3) * graphic_width;
-        linesize = (linesize + 3) & ~3;
-        env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
-        break;
-    case 31: /* set_video power */
-        env->gpr[3] = 0;
-        break;
-    case 39: /* video_ctrl */
-        if (env->gpr[6] == 0 || env->gpr[6] == 1)
-            vga_vbl_enabled = env->gpr[6];
-        env->gpr[3] = 0;
-        break;
-    case 47:
-        break;
-    case 59: /* set_color */
-        /* R6 = index, R7 = RGB */
-        env->gpr[3] = 0;
-        break;
-    case 64: /* get color */
-        /* R6 = index */
-        env->gpr[3] = 0;
-        break;
-    case 116: /* set hwcursor */
-        /* R6 = x, R7 = y, R8 = visible, R9 = data */
-        break;
-    default:
-        fprintf(stderr, "unsupported OSI call R5=%016" PRIx64 "\n",
-                ppc_dump_gpr(env, 5));
-        break;
-    }
-
-    return 1; /* osi_call handled */
-}
-
 static int fw_cfg_boot_set(void *opaque, const char *boot_device)
 {
     fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
@@ -136,23 +66,22 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
                                const char *initrd_filename,
                                const char *cpu_model)
 {
-    CPUState *env = NULL, *envs[MAX_CPUS];
+    CPUState *env = NULL;
     char *filename;
     qemu_irq *pic, **heathrow_irqs;
     int linux_boot, i;
-    ram_addr_t ram_offset, bios_offset, vga_bios_offset;
+    ram_addr_t ram_offset, bios_offset;
     uint32_t kernel_base, initrd_base;
     int32_t kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
-    int vga_bios_size, bios_size;
+    int bios_size;
     int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
     int escc_mem_index, ide_mem_index[2];
     uint16_t ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
     void *dbdma;
-    uint8_t *vga_bios_ptr;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -167,9 +96,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         }
         /* Set time-base frequency to 16.6 Mhz */
         cpu_ppc_tb_init(env,  16600000UL);
-        env->osi_call = vga_osi_call;
         qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
-        envs[i] = env;
     }
 
     /* allocate RAM */
@@ -203,36 +130,6 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         exit(1);
     }
 
-    /* allocate and load VGA BIOS */
-    vga_bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.vbios", VGA_BIOS_SIZE);
-    vga_bios_ptr = qemu_get_ram_ptr(vga_bios_offset);
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, VGABIOS_FILENAME);
-    if (filename) {
-        vga_bios_size = load_image(filename, vga_bios_ptr + 8);
-        qemu_free(filename);
-    } else {
-        vga_bios_size = -1;
-    }
-    if (vga_bios_size < 0) {
-        /* if no bios is present, we can still work */
-        fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n",
-                VGABIOS_FILENAME);
-        vga_bios_size = 0;
-    } else {
-        /* set a specific header (XXX: find real Apple format for NDRV
-           drivers) */
-        vga_bios_ptr[0] = 'N';
-        vga_bios_ptr[1] = 'D';
-        vga_bios_ptr[2] = 'R';
-        vga_bios_ptr[3] = 'V';
-        cpu_to_be32w((uint32_t *)(vga_bios_ptr + 4), vga_bios_size);
-        vga_bios_size += 8;
-
-        /* Round to page boundary */
-        vga_bios_size = (vga_bios_size + TARGET_PAGE_SIZE - 1) &
-            TARGET_PAGE_MASK;
-    }
-
     if (linux_boot) {
         uint64_t lowaddr = 0;
         int bswap_needed;
@@ -330,7 +227,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     }
     pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
     pci_bus = pci_grackle_init(0xfec00000, pic);
-    pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size);
+    pci_vga_init(pci_bus, 0, 0);
 
     escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
                                serial_hds[1], ESCC_CLOCK, 4);
index 0e5b88ce759bea07b1813851ca9ebb5df037a98d..a6915f7e68af233d5047635be32df952dbfd1aea 100644 (file)
@@ -565,7 +565,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
                            const char *initrd_filename,
                            const char *cpu_model)
 {
-    CPUState *env = NULL, *envs[MAX_CPUS];
+    CPUState *env = NULL;
     char *filename;
     nvram_t nvram;
     M48t59State *m48t59;
@@ -602,7 +602,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
             cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
         }
         qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
-        envs[i] = env;
     }
 
     /* allocate RAM */
index 1422fad07273332f247a7f1ae952e14498470ede..59d20d30aed898df5a576057ded484ee5cfc2622 100644 (file)
@@ -176,7 +176,6 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     int i=0;
     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
     qemu_irq *irqs, *mpic, *pci_irqs;
-    SerialState * serial[2];
 
     /* Setup CPU */
     env = cpu_ppc_init("e500v2_v30");
@@ -200,15 +199,15 @@ static void mpc8544ds_init(ram_addr_t ram_size,
 
     /* Serial */
     if (serial_hds[0]) {
-        serial[0] = serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
-                                   0, mpic[12+26], 399193,
-                                   serial_hds[0], 1, 1);
+        serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
+                       0, mpic[12+26], 399193,
+                       serial_hds[0], 1, 1);
     }
 
     if (serial_hds[1]) {
-        serial[0] = serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
-                                   0, mpic[12+26], 399193,
-                                   serial_hds[0], 1, 1);
+        serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
+                       0, mpic[12+26], 399193,
+                       serial_hds[0], 1, 1);
     }
 
     /* PCI */
index 10362a36550243b7038746f320155ed647134665..9d5ad86d98509145f979c2cdc8fb08a04a87bb40 100644 (file)
 #include "sun4m.h"
 #include "monitor.h"
 #include "sysbus.h"
+#include "trace.h"
 
 //#define DEBUG_IRQ_COUNT
-//#define DEBUG_IRQ
-
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
 
 /*
  * Registers of interrupt controller in sun4m.
@@ -97,7 +90,7 @@ static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
         ret = 0;
         break;
     }
-    DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, ret);
+    trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
 
     return ret;
 }
@@ -109,21 +102,19 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr,
     uint32_t saddr;
 
     saddr = addr >> 2;
-    DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, val);
+    trace_slavio_intctl_mem_writel(s->cpu, addr, val);
     switch (saddr) {
     case 1: // clear pending softints
         val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
         s->intreg_pending &= ~val;
         slavio_check_interrupts(s->master, 1);
-        DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", s->cpu, val,
-                s->intreg_pending);
+        trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
         break;
     case 2: // set softint
         val &= CPU_SOFTIRQ_MASK;
         s->intreg_pending |= val;
         slavio_check_interrupts(s->master, 1);
-        DPRINTF("Set cpu %d irq mask %x, curmask %x\n", s->cpu, val,
-                s->intreg_pending);
+        trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
         break;
     default:
         break;
@@ -163,7 +154,7 @@ static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
         ret = 0;
         break;
     }
-    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+    trace_slavio_intctlm_mem_readl(addr, ret);
 
     return ret;
 }
@@ -175,14 +166,13 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr,
     uint32_t saddr;
 
     saddr = addr >> 2;
-    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
+    trace_slavio_intctlm_mem_writel(addr, val);
     switch (saddr) {
     case 2: // clear (enable)
         // Force clear unused bits
         val &= MASTER_IRQ_MASK;
         s->intregm_disabled &= ~val;
-        DPRINTF("Enabled master irq mask %x, curmask %x\n", val,
-                s->intregm_disabled);
+        trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
         slavio_check_interrupts(s, 1);
         break;
     case 3: // set (disable; doesn't affect pending)
@@ -190,13 +180,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr,
         val &= MASTER_IRQ_MASK;
         s->intregm_disabled |= val;
         slavio_check_interrupts(s, 1);
-        DPRINTF("Disabled master irq mask %x, curmask %x\n", val,
-                s->intregm_disabled);
+        trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
         break;
     case 4:
         s->target_cpu = val & (MAX_CPUS - 1);
         slavio_check_interrupts(s, 1);
-        DPRINTF("Set master irq cpu %d\n", s->target_cpu);
+        trace_slavio_intctlm_mem_writel_target(s->target_cpu);
         break;
     default:
         break;
@@ -264,7 +253,7 @@ static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
 
     pending &= ~s->intregm_disabled;
 
-    DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
+    trace_slavio_check_interrupts(pending, s->intregm_disabled);
     for (i = 0; i < MAX_CPUS; i++) {
         pil_pending = 0;
 
@@ -327,8 +316,7 @@ static void slavio_set_irq(void *opaque, int irq, int level)
     uint32_t pil = intbit_to_level[irq];
     unsigned int i;
 
-    DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
-            level);
+    trace_slavio_set_irq(s->target_cpu, irq, pil, level);
     if (pil > 0) {
         if (level) {
 #ifdef DEBUG_IRQ_COUNT
@@ -356,7 +344,7 @@ static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
 {
     SLAVIO_INTCTLState *s = opaque;
 
-    DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
+    trace_slavio_set_timer_irq_cpu(cpu, level);
 
     if (level) {
         s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
index 5ae628df8ed7435520a5874a6b57a482cb739ff1..1d81a633c7d40ece46ec32445c4573c0d6843e2d 100644 (file)
@@ -24,9 +24,7 @@
 
 #include "sysemu.h"
 #include "sysbus.h"
-
-/* debug misc */
-//#define DEBUG_MISC
+#include "trace.h"
 
 /*
  * This is the auxio port, chip control and system control part of
  * This also includes the PMC CPU idle controller.
  */
 
-#ifdef DEBUG_MISC
-#define MISC_DPRINTF(fmt, ...)                                  \
-    do { printf("MISC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define MISC_DPRINTF(fmt, ...)
-#endif
-
 typedef struct MiscState {
     SysBusDevice busdev;
     qemu_irq irq;
@@ -79,10 +70,10 @@ static void slavio_misc_update_irq(void *opaque)
     MiscState *s = opaque;
 
     if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
-        MISC_DPRINTF("Raise IRQ\n");
+        trace_slavio_misc_update_irq_raise();
         qemu_irq_raise(s->irq);
     } else {
-        MISC_DPRINTF("Lower IRQ\n");
+        trace_slavio_misc_update_irq_lower();
         qemu_irq_lower(s->irq);
     }
 }
@@ -99,7 +90,7 @@ static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
 {
     MiscState *s = opaque;
 
-    MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
+    trace_slavio_set_power_fail(power_failing, s->config);
     if (power_failing && (s->config & CFG_PWRINTEN)) {
         s->aux2 |= AUX2_PWRFAIL;
     } else {
@@ -113,7 +104,7 @@ static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
 {
     MiscState *s = opaque;
 
-    MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
+    trace_slavio_cfg_mem_writeb(val & 0xff);
     s->config = val & 0xff;
     slavio_misc_update_irq(s);
 }
@@ -124,7 +115,7 @@ static uint32_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t ret = 0;
 
     ret = s->config;
-    MISC_DPRINTF("Read config %2.2x\n", ret);
+    trace_slavio_cfg_mem_readb(ret);
     return ret;
 }
 
@@ -145,7 +136,7 @@ static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
 {
     MiscState *s = opaque;
 
-    MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
+    trace_slavio_diag_mem_writeb(val & 0xff);
     s->diag = val & 0xff;
 }
 
@@ -155,7 +146,7 @@ static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t ret = 0;
 
     ret = s->diag;
-    MISC_DPRINTF("Read diag %2.2x\n", ret);
+    trace_slavio_diag_mem_readb(ret);
     return ret;
 }
 
@@ -176,7 +167,7 @@ static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
 {
     MiscState *s = opaque;
 
-    MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
+    trace_slavio_mdm_mem_writeb(val & 0xff);
     s->mctrl = val & 0xff;
 }
 
@@ -186,7 +177,7 @@ static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t ret = 0;
 
     ret = s->mctrl;
-    MISC_DPRINTF("Read modem control %2.2x\n", ret);
+    trace_slavio_mdm_mem_readb(ret);
     return ret;
 }
 
@@ -207,7 +198,7 @@ static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
 {
     MiscState *s = opaque;
 
-    MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
+    trace_slavio_aux1_mem_writeb(val & 0xff);
     if (val & AUX1_TC) {
         // Send a pulse to floppy terminal count line
         if (s->fdc_tc) {
@@ -225,8 +216,7 @@ static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t ret = 0;
 
     ret = s->aux1;
-    MISC_DPRINTF("Read aux1 %2.2x\n", ret);
-
+    trace_slavio_aux1_mem_readb(ret);
     return ret;
 }
 
@@ -248,7 +238,7 @@ static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
     MiscState *s = opaque;
 
     val &= AUX2_PWRINTCLR | AUX2_PWROFF;
-    MISC_DPRINTF("Write aux2 %2.2x\n", val);
+    trace_slavio_aux2_mem_writeb(val & 0xff);
     val |= s->aux2 & AUX2_PWRFAIL;
     if (val & AUX2_PWRINTCLR) // Clear Power Fail int
         val &= AUX2_PWROFF;
@@ -264,8 +254,7 @@ static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t ret = 0;
 
     ret = s->aux2;
-    MISC_DPRINTF("Read aux2 %2.2x\n", ret);
-
+    trace_slavio_aux2_mem_readb(ret);
     return ret;
 }
 
@@ -285,7 +274,7 @@ static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     APCState *s = opaque;
 
-    MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
+    trace_apc_mem_writeb(val & 0xff);
     qemu_irq_raise(s->cpu_halt);
 }
 
@@ -293,7 +282,7 @@ static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
 {
     uint32_t ret = 0;
 
-    MISC_DPRINTF("Read power management %2.2x\n", ret);
+    trace_apc_mem_readb(ret);
     return ret;
 }
 
@@ -321,7 +310,7 @@ static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
     default:
         break;
     }
-    MISC_DPRINTF("Read system control %08x\n", ret);
+    trace_slavio_sysctrl_mem_readl(ret);
     return ret;
 }
 
@@ -330,7 +319,7 @@ static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
 {
     MiscState *s = opaque;
 
-    MISC_DPRINTF("Write system control %08x\n", val);
+    trace_slavio_sysctrl_mem_writel(val);
     switch (addr) {
     case 0:
         if (val & SYS_RESET) {
@@ -367,7 +356,7 @@ static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
     default:
         break;
     }
-    MISC_DPRINTF("Read diagnostic LED %04x\n", ret);
+    trace_slavio_led_mem_readw(ret);
     return ret;
 }
 
@@ -376,7 +365,7 @@ static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
 {
     MiscState *s = opaque;
 
-    MISC_DPRINTF("Write diagnostic LED %04x\n", val & 0xffff);
+    trace_slavio_led_mem_readw(val & 0xffff);
     switch (addr) {
     case 0:
         s->leds = val;
index c125de4b62dbc625f7065bb22107feaf1272d2d8..13f1e62ad8ee406188870108cb7a629dc14c83d2 100644 (file)
 #include "sun4m.h"
 #include "qemu-timer.h"
 #include "sysbus.h"
-
-//#define DEBUG_TIMER
-
-#ifdef DEBUG_TIMER
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
+#include "trace.h"
 
 /*
  * Registers of hardware timer in sun4m.
@@ -112,8 +104,7 @@ static void slavio_timer_get_out(CPUTimerState *t)
     }
     count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
 
-    DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", t->limit, t->counthigh,
-            t->count);
+    trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
     t->count = count & TIMER_COUNT_MASK32;
     t->counthigh = count >> 32;
 }
@@ -126,7 +117,7 @@ static void slavio_timer_irq(void *opaque)
     CPUTimerState *t = &s->cputimer[tc->timer_index];
 
     slavio_timer_get_out(t);
-    DPRINTF("callback: count %x%08x\n", t->counthigh, t->count);
+    trace_slavio_timer_irq(t->counthigh, t->count);
     /* if limit is 0 (free-run), there will be no match */
     if (t->limit != 0) {
         t->reached = TIMER_REACHED;
@@ -188,12 +179,11 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
         ret = s->cputimer_mode;
         break;
     default:
-        DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr);
+        trace_slavio_timer_mem_readl_invalid(addr);
         ret = 0;
         break;
     }
-    DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
-
+    trace_slavio_timer_mem_readl(addr, ret);
     return ret;
 }
 
@@ -206,7 +196,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
     unsigned int timer_index = tc->timer_index;
     CPUTimerState *t = &s->cputimer[timer_index];
 
-    DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
+    trace_slavio_timer_mem_writel(addr, val);
     saddr = addr >> 2;
     switch (saddr) {
     case TIMER_LIMIT:
@@ -218,8 +208,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
             t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
             t->reached = 0;
             count = ((uint64_t)t->counthigh << 32) | t->count;
-            DPRINTF("processor %d user timer set to %016" PRIx64 "\n",
-                    timer_index, count);
+            trace_slavio_timer_mem_writel_limit(timer_index, count);
             ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
         } else {
             // set limit, reset counter
@@ -244,11 +233,11 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
             t->count = val & TIMER_MAX_COUNT64;
             t->reached = 0;
             count = ((uint64_t)t->counthigh) << 32 | t->count;
-            DPRINTF("processor %d user timer set to %016" PRIx64 "\n",
-                    timer_index, count);
+            trace_slavio_timer_mem_writel_limit(timer_index, count);
             ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
-        } else
-            DPRINTF("not user timer\n");
+        } else {
+            trace_slavio_timer_mem_writel_counter_invalid();
+        }
         break;
     case TIMER_COUNTER_NORST:
         // set limit without resetting counter
@@ -263,13 +252,11 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
         if (slavio_timer_is_user(tc)) {
             // start/stop user counter
             if ((val & 1) && !t->running) {
-                DPRINTF("processor %d user timer started\n",
-                        timer_index);
+                trace_slavio_timer_mem_writel_status_start(timer_index);
                 ptimer_run(t->timer, 0);
                 t->running = 1;
             } else if (!(val & 1) && t->running) {
-                DPRINTF("processor %d user timer stopped\n",
-                        timer_index);
+                trace_slavio_timer_mem_writel_status_stop(timer_index);
                 ptimer_stop(t->timer);
                 t->running = 0;
             }
@@ -298,8 +285,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
                         // set this processors user timer bit in config
                         // register
                         s->cputimer_mode |= processor;
-                        DPRINTF("processor %d changed from counter to user "
-                                "timer\n", timer_index);
+                        trace_slavio_timer_mem_writel_mode_user(timer_index);
                     } else { // user timer -> counter
                         // stop the user timer if it is running
                         if (curr_timer->running) {
@@ -311,17 +297,16 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
                         // clear this processors user timer bit in config
                         // register
                         s->cputimer_mode &= ~processor;
-                        DPRINTF("processor %d changed from user timer to "
-                                "counter\n", timer_index);
+                        trace_slavio_timer_mem_writel_mode_counter(timer_index);
                     }
                 }
             }
         } else {
-            DPRINTF("not system timer\n");
+            trace_slavio_timer_mem_writel_mode_invalid();
         }
         break;
     default:
-        DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr);
+        trace_slavio_timer_mem_writel_invalid(addr);
         break;
     }
 }
index 984ffc3e531da72f847e15f4d064d0d470257f5b..0904188c95034e93fe5fb55beb700bc8fb5ad889 100644 (file)
@@ -29,9 +29,7 @@
 #include "sparc32_dma.h"
 #include "sun4m.h"
 #include "sysbus.h"
-
-/* debug DMA */
-//#define DEBUG_DMA
+#include "trace.h"
 
 /*
  * This is the DMA controller part of chip STP2000 (Master I/O), also
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt
  */
 
-#ifdef DEBUG_DMA
-#define DPRINTF(fmt, ...)                               \
-    do { printf("DMA: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
 #define DMA_REGS 4
 #define DMA_SIZE (4 * sizeof(uint32_t))
 /* We need the mask, because one instance of the device is not page
@@ -88,9 +79,8 @@ void ledma_memory_read(void *opaque, target_phys_addr_t addr,
     DMAState *s = opaque;
     int i;
 
-    DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
-            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
     addr |= s->dmaregs[3];
+    trace_ledma_memory_read(addr);
     if (do_bswap) {
         sparc_iommu_memory_read(s->iommu, addr, buf, len);
     } else {
@@ -110,9 +100,8 @@ void ledma_memory_write(void *opaque, target_phys_addr_t addr,
     int l, i;
     uint16_t tmp_buf[32];
 
-    DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
-            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
     addr |= s->dmaregs[3];
+    trace_ledma_memory_write(addr);
     if (do_bswap) {
         sparc_iommu_memory_write(s->iommu, addr, buf, len);
     } else {
@@ -139,14 +128,14 @@ static void dma_set_irq(void *opaque, int irq, int level)
     if (level) {
         s->dmaregs[0] |= DMA_INTR;
         if (s->dmaregs[0] & DMA_INTREN) {
-            DPRINTF("Raise IRQ\n");
+            trace_sparc32_dma_set_irq_raise();
             qemu_irq_raise(s->irq);
         }
     } else {
         if (s->dmaregs[0] & DMA_INTR) {
             s->dmaregs[0] &= ~DMA_INTR;
             if (s->dmaregs[0] & DMA_INTREN) {
-                DPRINTF("Lower IRQ\n");
+                trace_sparc32_dma_set_irq_lower();
                 qemu_irq_lower(s->irq);
             }
         }
@@ -157,8 +146,7 @@ void espdma_memory_read(void *opaque, uint8_t *buf, int len)
 {
     DMAState *s = opaque;
 
-    DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
-            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
+    trace_espdma_memory_read(s->dmaregs[1]);
     sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len);
     s->dmaregs[1] += len;
 }
@@ -167,8 +155,7 @@ void espdma_memory_write(void *opaque, uint8_t *buf, int len)
 {
     DMAState *s = opaque;
 
-    DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
-            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
+    trace_espdma_memory_write(s->dmaregs[1]);
     sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len);
     s->dmaregs[1] += len;
 }
@@ -179,9 +166,7 @@ static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
     uint32_t saddr;
 
     saddr = (addr & DMA_MASK) >> 2;
-    DPRINTF("read dmareg " TARGET_FMT_plx ": 0x%8.8x\n", addr,
-            s->dmaregs[saddr]);
-
+    trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]);
     return s->dmaregs[saddr];
 }
 
@@ -191,18 +176,17 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     uint32_t saddr;
 
     saddr = (addr & DMA_MASK) >> 2;
-    DPRINTF("write dmareg " TARGET_FMT_plx ": 0x%8.8x -> 0x%8.8x\n", addr,
-            s->dmaregs[saddr], val);
+    trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val);
     switch (saddr) {
     case 0:
         if (val & DMA_INTREN) {
             if (s->dmaregs[0] & DMA_INTR) {
-                DPRINTF("Raise IRQ\n");
+                trace_sparc32_dma_set_irq_raise();
                 qemu_irq_raise(s->irq);
             }
         } else {
             if (s->dmaregs[0] & (DMA_INTR | DMA_INTREN)) {
-                DPRINTF("Lower IRQ\n");
+                trace_sparc32_dma_set_irq_lower();
                 qemu_irq_lower(s->irq);
             }
         }
@@ -215,10 +199,10 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
             val = DMA_DRAIN_FIFO;
 
         if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) {
-            DPRINTF("Raise DMA enable\n");
+            trace_sparc32_dma_enable_raise();
             qemu_irq_raise(s->gpio[GPIO_DMA]);
         } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) {
-            DPRINTF("Lower DMA enable\n");
+            trace_sparc32_dma_enable_lower();
             qemu_irq_lower(s->gpio[GPIO_DMA]);
         }
 
index 03921092307817d9be42d30121ac62cd77f1af70..4795b3f45ebc14155b72831347ecf2850b77706a 100644 (file)
@@ -41,8 +41,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "blockdev.h"
-
-//#define DEBUG_IRQ
+#include "trace.h"
 
 /*
  * Sun4m architecture was used in the following machines:
  * See for example: http://www.sunhelp.org/faq/sunref1.html
  */
 
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
 #define KERNEL_LOAD_ADDR     0x00004000
 #define CMDLINE_ADDR         0x007ff000
 #define INITRD_LOAD_ADDR     0x00800000
@@ -248,14 +240,14 @@ void cpu_check_irqs(CPUState *env)
 
                 env->interrupt_index = TT_EXTINT | i;
                 if (old_interrupt != env->interrupt_index) {
-                    DPRINTF("Set CPU IRQ %d\n", i);
+                    trace_sun4m_cpu_interrupt(i);
                     cpu_interrupt(env, CPU_INTERRUPT_HARD);
                 }
                 break;
             }
         }
     } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
-        DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15);
+        trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15);
         env->interrupt_index = 0;
         cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
     }
@@ -266,12 +258,12 @@ static void cpu_set_irq(void *opaque, int irq, int level)
     CPUState *env = opaque;
 
     if (level) {
-        DPRINTF("Raise CPU IRQ %d\n", irq);
+        trace_sun4m_cpu_set_irq_raise(irq);
         env->halted = 0;
         env->pil_in |= 1 << irq;
         cpu_check_irqs(env);
     } else {
-        DPRINTF("Lower CPU IRQ %d\n", irq);
+        trace_sun4m_cpu_set_irq_lower(irq);
         env->pil_in &= ~(1 << irq);
         cpu_check_irqs(env);
     }
index 1dbe0774661e5b6cedd43b2b155a596cae5427cc..720ee3f0bd7e74fcce4ed12f5720a7c12d2c9110 100644 (file)
 
 #include "sun4m.h"
 #include "sysbus.h"
-
-/* debug iommu */
-//#define DEBUG_IOMMU
-
-#ifdef DEBUG_IOMMU
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
+#include "trace.h"
 
 /*
  * I/O MMU used by Sun4m systems
@@ -160,7 +151,7 @@ static uint32_t iommu_mem_readl(void *opaque, target_phys_addr_t addr)
         qemu_irq_lower(s->irq);
         break;
     }
-    DPRINTF("read reg[%d] = %x\n", (int)saddr, ret);
+    trace_sun4m_iommu_mem_readl(saddr, ret);
     return ret;
 }
 
@@ -171,7 +162,7 @@ static void iommu_mem_writel(void *opaque, target_phys_addr_t addr,
     target_phys_addr_t saddr;
 
     saddr = addr >> 2;
-    DPRINTF("write reg[%d] = %x\n", (int)saddr, val);
+    trace_sun4m_iommu_mem_writel(saddr, val);
     switch (saddr) {
     case IOMMU_CTRL:
         switch (val & IOMMU_CTRL_RNGE) {
@@ -201,18 +192,18 @@ static void iommu_mem_writel(void *opaque, target_phys_addr_t addr,
             s->iostart = 0xffffffff80000000ULL;
             break;
         }
-        DPRINTF("iostart = " TARGET_FMT_plx "\n", s->iostart);
+        trace_sun4m_iommu_mem_writel_ctrl(s->iostart);
         s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version);
         break;
     case IOMMU_BASE:
         s->regs[saddr] = val & IOMMU_BASE_MASK;
         break;
     case IOMMU_TLBFLUSH:
-        DPRINTF("tlb flush %x\n", val);
+        trace_sun4m_iommu_mem_writel_tlbflush(val);
         s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK;
         break;
     case IOMMU_PGFLUSH:
-        DPRINTF("page flush %x\n", val);
+        trace_sun4m_iommu_mem_writel_pgflush(val);
         s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
         break;
     case IOMMU_AFAR:
@@ -262,18 +253,14 @@ static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr)
 {
     uint32_t ret;
     target_phys_addr_t iopte;
-#ifdef DEBUG_IOMMU
     target_phys_addr_t pa = addr;
-#endif
 
     iopte = s->regs[IOMMU_BASE] << 4;
     addr &= ~s->iostart;
     iopte += (addr >> (IOMMU_PAGE_SHIFT - 2)) & ~3;
     cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4);
     tswap32s(&ret);
-    DPRINTF("get flags addr " TARGET_FMT_plx " => pte " TARGET_FMT_plx
-            ", *pte = %x\n", pa, iopte, ret);
-
+    trace_sun4m_iommu_page_get_flags(pa, iopte, ret);
     return ret;
 }
 
@@ -283,16 +270,14 @@ static target_phys_addr_t iommu_translate_pa(target_phys_addr_t addr,
     target_phys_addr_t pa;
 
     pa = ((pte & IOPTE_PAGE) << 4) + (addr & ~IOMMU_PAGE_MASK);
-    DPRINTF("xlate dva " TARGET_FMT_plx " => pa " TARGET_FMT_plx
-            " (iopte = %x)\n", addr, pa, pte);
-
+    trace_sun4m_iommu_translate_pa(addr, pa, pte);
     return pa;
 }
 
 static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr,
                            int is_write)
 {
-    DPRINTF("bad addr " TARGET_FMT_plx "\n", addr);
+    trace_sun4m_iommu_bad_addr(addr);
     s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV |
         IOMMU_AFSR_FAV;
     if (!is_write)
index 37bf8336becc360a2d724299200c114071194881..1ccf6e8dfe95958573a9f25987e9343a41107a5f 100644 (file)
 static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s)
 {
     int i;
-    int w_display;
     uint16_t *data_buffer;
     uint8_t *data_display;
 
     data_buffer = s->vram_ptr;
-    w_display = s->scr_width * BITS / 8;
     data_display = ds_get_data(s->ds);
     for(i = 0; i < s->scr_height; i++) {
 #if (BITS == 16)
index fe052eb756a4375be6fc0c26155f36b80a0e7950..47f26cd0a3333d8723ca9fbc5a3aae0062117175 100644 (file)
@@ -160,6 +160,7 @@ static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
     if (!s->mouse_grabbed) {
         s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
                         "QEMU PenPartner tablet");
+        qemu_activate_mouse_event_handler(s->eh_entry);
         s->mouse_grabbed = 1;
     }
 
@@ -197,6 +198,7 @@ static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
     if (!s->mouse_grabbed) {
         s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
                         "QEMU PenPartner tablet");
+        qemu_activate_mouse_event_handler(s->eh_entry);
         s->mouse_grabbed = 1;
     }
 
@@ -334,8 +336,10 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
         ret = 0;
         break;
     case WACOM_SET_REPORT:
-        qemu_remove_mouse_event_handler(s->eh_entry);
-        s->mouse_grabbed = 0;
+        if (s->mouse_grabbed) {
+            qemu_remove_mouse_event_handler(s->eh_entry);
+            s->mouse_grabbed = 0;
+        }
         s->mode = data[0];
         ret = 0;
         break;
@@ -397,7 +401,10 @@ static void usb_wacom_handle_destroy(USBDevice *dev)
 {
     USBWacomState *s = (USBWacomState *) dev;
 
-    qemu_remove_mouse_event_handler(s->eh_entry);
+    if (s->mouse_grabbed) {
+        qemu_remove_mouse_event_handler(s->eh_entry);
+        s->mouse_grabbed = 0;
+    }
 }
 
 static int usb_wacom_initfn(USBDevice *dev)
index 1b8624d9812b3390fbb0716559971f858f3d91a3..8586f66baccb80dbc4f6153ac111e32e0f2f0de4 100644 (file)
@@ -454,11 +454,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
     };
     struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
 
-    if (!vdev->binding->set_guest_notifier) {
-        fprintf(stderr, "binding does not support guest notifiers\n");
-        return -ENOSYS;
-    }
-
     if (!vdev->binding->set_host_notifier) {
         fprintf(stderr, "binding does not support host notifiers\n");
         return -ENOSYS;
@@ -511,12 +506,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
         r = -errno;
         goto fail_alloc;
     }
-    r = vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, true);
-    if (r < 0) {
-        fprintf(stderr, "Error binding guest notifier: %d\n", -r);
-        goto fail_guest_notifier;
-    }
-
     r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, true);
     if (r < 0) {
         fprintf(stderr, "Error binding host notifier: %d\n", -r);
@@ -526,12 +515,14 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
     file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
     r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
     if (r) {
+        r = -errno;
         goto fail_kick;
     }
 
     file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
     r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
     if (r) {
+        r = -errno;
         goto fail_call;
     }
 
@@ -541,8 +532,6 @@ fail_call:
 fail_kick:
     vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
 fail_host_notifier:
-    vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, false);
-fail_guest_notifier:
 fail_alloc:
     cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
                               0, 0);
@@ -568,13 +557,6 @@ static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
         .index = idx,
     };
     int r;
-    r = vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, false);
-    if (r < 0) {
-        fprintf(stderr, "vhost VQ %d guest cleanup failed: %d\n", idx, r);
-        fflush(stderr);
-    }
-    assert (r >= 0);
-
     r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
     if (r < 0) {
         fprintf(stderr, "vhost VQ %d host cleanup failed: %d\n", idx, r);
@@ -647,15 +629,26 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
 int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
     int i, r;
+    if (!vdev->binding->set_guest_notifiers) {
+        fprintf(stderr, "binding does not support guest notifiers\n");
+        r = -ENOSYS;
+        goto fail;
+    }
+
+    r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, true);
+    if (r < 0) {
+        fprintf(stderr, "Error binding guest notifier: %d\n", -r);
+        goto fail_notifiers;
+    }
 
     r = vhost_dev_set_features(hdev, hdev->log_enabled);
     if (r < 0) {
-        goto fail;
+        goto fail_features;
     }
     r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
     if (r < 0) {
         r = -errno;
-        goto fail;
+        goto fail_mem;
     }
     for (i = 0; i < hdev->nvqs; ++i) {
         r = vhost_virtqueue_init(hdev,
@@ -675,13 +668,14 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
                   (uint64_t)(unsigned long)hdev->log);
         if (r < 0) {
             r = -errno;
-            goto fail_vq;
+            goto fail_log;
         }
     }
 
     hdev->started = true;
 
     return 0;
+fail_log:
 fail_vq:
     while (--i >= 0) {
         vhost_virtqueue_cleanup(hdev,
@@ -689,13 +683,18 @@ fail_vq:
                                 hdev->vqs + i,
                                 i);
     }
+fail_mem:
+fail_features:
+    vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
+fail_notifiers:
 fail:
     return r;
 }
 
 void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
-    int i;
+    int i, r;
+
     for (i = 0; i < hdev->nvqs; ++i) {
         vhost_virtqueue_cleanup(hdev,
                                 vdev,
@@ -704,6 +703,13 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
     }
     vhost_client_sync_dirty_bitmap(&hdev->client, 0,
                                    (target_phys_addr_t)~0x0ull);
+    r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
+    if (r < 0) {
+        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
+        fflush(stderr);
+    }
+    assert (r >= 0);
+
     hdev->started = false;
     qemu_free(hdev->log);
     hdev->log_size = 0;
index c5bbedac7d2aab2b93c1c0b3e431cd244fce4162..fa605158e7564cd5b9be3b7a27b3a90e9c4705c7 100644 (file)
@@ -85,7 +85,6 @@ static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
                                     uint32_t sysclk)
 {
     CPUState *env;
-    qemu_irq *pic;
     qemu_irq *irqs;
 
     env = cpu_init(cpu_model);
@@ -106,7 +105,7 @@ static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
     irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
     irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
     irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    ppcuic_init(env, irqs, 0x0C0, 0, 1);
     return env;
 }
 
@@ -236,13 +235,11 @@ static void virtex_init(ram_addr_t ram_size,
 
     if (kernel_filename) {
         uint64_t entry, low, high;
-        uint32_t base32;
         target_phys_addr_t boot_offset;
 
         /* Boots a kernel elf binary.  */
         kernel_size = load_elf(kernel_filename, NULL, NULL,
                                &entry, &low, &high, 1, ELF_MACHINE, 0);
-        base32 = entry;
         boot_info.bootstrap_pc = entry & 0x00ffffff;
 
         if (kernel_size < 0) {
index 6f6a0ec13bb5f8f4df68e474b8dc87093b8eb778..cff5b07297108774740a493af232131ead7b645a 100644 (file)
@@ -502,6 +502,14 @@ void pprint_pdu(V9fsPDU *pdu)
         fprintf(llogfile, "RMKNOD: )");
         pprint_qid(pdu, 0, &offset, "qid");
         break;
+    case P9_TREADLINK:
+       fprintf(llogfile, "TREADLINK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RREADLINK:
+       fprintf(llogfile, "RREADLINK: (");
+        pprint_str(pdu, 0, &offset, "target");
+        break;
     case P9_TREAD:
         fprintf(llogfile, "TREAD: (");
         pprint_int32(pdu, 0, &offset, "fid");
@@ -535,6 +543,13 @@ void pprint_pdu(V9fsPDU *pdu)
     case P9_RCLUNK:
         fprintf(llogfile, "RCLUNK: (");
         break;
+    case P9_TFSYNC:
+        fprintf(llogfile, "TFSYNC: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RFSYNC:
+        fprintf(llogfile, "RFSYNC: (");
+        break;
     case P9_TLINK:
         fprintf(llogfile, "TLINK: (");
         pprint_int32(pdu, 0, &offset, "fid");
@@ -588,6 +603,37 @@ void pprint_pdu(V9fsPDU *pdu)
     case P9_RXATTRCREATE:
         fprintf(llogfile, "RXATTRCREATE: (");
         break;
+    case P9_TLOCK:
+        fprintf(llogfile, "TLOCK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", type");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    case P9_RLOCK:
+        fprintf(llogfile, "RLOCK: (");
+        pprint_int8(pdu, 0, &offset, "status");
+        break;
+    case P9_TGETLOCK:
+        fprintf(llogfile, "TGETLOCK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", type");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    case P9_RGETLOCK:
+        fprintf(llogfile, "RGETLOCK: (");
+        pprint_int8(pdu, 0, &offset, "type");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
     default:
         fprintf(llogfile, "unknown(%d): (", pdu->id);
         break;
index 57f92433d3b259fa09c883a17b70c9ce6edd8127..0d520201b4dfd322fb3529b2721a5e62c471f3ec 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include "virtio.h"
 #include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
 #include <arpa/inet.h>
 #include <pwd.h>
 #include <grp.h>
 #include <sys/un.h>
 #include <attr/xattr.h>
 
-static const char *rpath(FsContext *ctx, const char *path)
-{
-    /* FIXME: so wrong... */
-    static char buffer[4096];
-    snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
-    return buffer;
-}
-
 
 static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
 {
@@ -175,21 +168,34 @@ static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
     return seekdir(dir, off);
 }
 
-static ssize_t local_readv(FsContext *ctx, int fd, const struct iovec *iov,
-                            int iovcnt)
+static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+                            int iovcnt, off_t offset)
 {
-    return readv(fd, iov, iovcnt);
-}
-
-static off_t local_lseek(FsContext *ctx, int fd, off_t offset, int whence)
-{
-    return lseek(fd, offset, whence);
+#ifdef CONFIG_PREADV
+    return preadv(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return readv(fd, iov, iovcnt);
+    }
+#endif
 }
 
-static ssize_t local_writev(FsContext *ctx, int fd, const struct iovec *iov,
-                            int iovcnt)
+static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+                            int iovcnt, off_t offset)
 {
-    return writev(fd, iov, iovcnt);
+#ifdef CONFIG_PREADV
+    return pwritev(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return writev(fd, iov, iovcnt);
+    }
+#endif
 }
 
 static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
@@ -497,103 +503,25 @@ static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
 static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
                                const char *name, void *value, size_t size)
 {
-    if ((ctx->fs_sm == SM_MAPPED) &&
-        (strncmp(name, "user.virtfs.", 12) == 0)) {
-        /*
-         * Don't allow fetch of user.virtfs namesapce
-         * in case of mapped security
-         */
-        errno = ENOATTR;
-        return -1;
-    }
-
-    return lgetxattr(rpath(ctx, path), name, value, size);
+    return v9fs_get_xattr(ctx, path, name, value, size);
 }
 
 static ssize_t local_llistxattr(FsContext *ctx, const char *path,
                                 void *value, size_t size)
 {
-    ssize_t retval;
-    ssize_t actual_len = 0;
-    char *orig_value, *orig_value_start;
-    char *temp_value, *temp_value_start;
-    ssize_t xattr_len, parsed_len = 0, attr_len;
-
-    if (ctx->fs_sm != SM_MAPPED) {
-        return llistxattr(rpath(ctx, path), value, size);
-    }
-
-    /* Get the actual len */
-    xattr_len = llistxattr(rpath(ctx, path), value, 0);
-
-    /* Now fetch the xattr and find the actual size */
-    orig_value = qemu_malloc(xattr_len);
-    xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
-
-    /*
-     * For mapped security model drop user.virtfs namespace
-     * from the list
-     */
-    temp_value = qemu_mallocz(xattr_len);
-    temp_value_start = temp_value;
-    orig_value_start = orig_value;
-    while (xattr_len > parsed_len) {
-        attr_len = strlen(orig_value) + 1;
-        if (strncmp(orig_value, "user.virtfs.", 12) != 0) {
-            /* Copy this entry */
-            strcat(temp_value, orig_value);
-            temp_value  += attr_len;
-            actual_len += attr_len;
-        }
-        parsed_len += attr_len;
-        orig_value += attr_len;
-    }
-    if (!size) {
-        retval = actual_len;
-        goto out;
-    } else if (size >= actual_len) {
-        /* now copy the parsed attribute list back */
-        memset(value, 0, size);
-        memcpy(value, temp_value_start, actual_len);
-        retval = actual_len;
-        goto out;
-    }
-    errno = ERANGE;
-    retval = -1;
-out:
-    qemu_free(orig_value_start);
-    qemu_free(temp_value_start);
-    return retval;
+    return v9fs_list_xattr(ctx, path, value, size);
 }
 
 static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
                            void *value, size_t size, int flags)
 {
-    if ((ctx->fs_sm == SM_MAPPED) &&
-        (strncmp(name, "user.virtfs.", 12) == 0)) {
-        /*
-         * Don't allow fetch of user.virtfs namesapce
-         * in case of mapped security
-         */
-        errno = EACCES;
-        return -1;
-    }
-    return lsetxattr(rpath(ctx, path), name, value, size, flags);
+    return v9fs_set_xattr(ctx, path, name, value, size, flags);
 }
 
 static int local_lremovexattr(FsContext *ctx,
                               const char *path, const char *name)
 {
-    if ((ctx->fs_sm == SM_MAPPED) &&
-        (strncmp(name, "user.virtfs.", 12) == 0)) {
-        /*
-         * Don't allow fetch of user.virtfs namesapce
-         * in case of mapped security
-         */
-        errno = EACCES;
-        return -1;
-    }
-    return lremovexattr(rpath(ctx, path), name);
+    return v9fs_remove_xattr(ctx, path, name);
 }
 
 
@@ -608,9 +536,8 @@ FileOperations local_ops = {
     .telldir = local_telldir,
     .readdir = local_readdir,
     .seekdir = local_seekdir,
-    .readv = local_readv,
-    .lseek = local_lseek,
-    .writev = local_writev,
+    .preadv = local_preadv,
+    .pwritev = local_pwritev,
     .chmod = local_chmod,
     .mknod = local_mknod,
     .mkdir = local_mkdir,
diff --git a/hw/virtio-9p-posix-acl.c b/hw/virtio-9p-posix-acl.c
new file mode 100644 (file)
index 0000000..3978d0c
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Virtio 9p system.posix* xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <attr/xattr.h>
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+#define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access"
+#define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default"
+#define ACL_ACCESS "system.posix_acl_access"
+#define ACL_DEFAULT "system.posix_acl_default"
+
+static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size);
+}
+
+static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t osize)
+{
+    ssize_t len = sizeof(ACL_ACCESS);
+
+    if (!value) {
+        return len;
+    }
+
+    if (osize < len) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, ACL_ACCESS, len);
+    return 0;
+}
+
+static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size, flags);
+}
+
+static int mp_pacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    int ret;
+    ret  = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS);
+    if (ret == -1 && errno == ENODATA) {
+        /*
+         * We don't get ENODATA error when trying to remote a
+         * posix acl that is not present. So don't throw the error
+         * even in case of mapped security model
+         */
+        errno = 0;
+        ret = 0;
+    }
+    return ret;
+}
+
+static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size);
+}
+
+static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t osize)
+{
+    ssize_t len = sizeof(ACL_DEFAULT);
+
+    if (!value) {
+        return len;
+    }
+
+    if (osize < len) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, ACL_DEFAULT, len);
+    return 0;
+}
+
+static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size, flags);
+}
+
+static int mp_dacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    return lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
+}
+
+
+XattrOperations mapped_pacl_xattr = {
+    .name = "system.posix_acl_access",
+    .getxattr = mp_pacl_getxattr,
+    .setxattr = mp_pacl_setxattr,
+    .listxattr = mp_pacl_listxattr,
+    .removexattr = mp_pacl_removexattr,
+};
+
+XattrOperations mapped_dacl_xattr = {
+    .name = "system.posix_acl_default",
+    .getxattr = mp_dacl_getxattr,
+    .setxattr = mp_dacl_setxattr,
+    .listxattr = mp_dacl_listxattr,
+    .removexattr = mp_dacl_removexattr,
+};
+
+XattrOperations passthrough_acl_xattr = {
+    .name = "system.posix_acl_",
+    .getxattr = pt_getxattr,
+    .setxattr = pt_setxattr,
+    .listxattr = pt_listxattr,
+    .removexattr = pt_removexattr,
+};
+
+XattrOperations none_acl_xattr = {
+    .name = "system.posix_acl_",
+    .getxattr = notsup_getxattr,
+    .setxattr = notsup_setxattr,
+    .listxattr = notsup_listxattr,
+    .removexattr = notsup_removexattr,
+};
diff --git a/hw/virtio-9p-xattr-user.c b/hw/virtio-9p-xattr-user.c
new file mode 100644 (file)
index 0000000..faa02a1
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Virtio 9p user. xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = ENOATTR;
+        return -1;
+    }
+    return lgetxattr(rpath(ctx, path), name, value, size);
+}
+
+static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t size)
+{
+    int name_size = strlen(name) + 1;
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+
+        /*  check if it is a mapped posix acl */
+        if (strncmp(name, "user.virtfs.system.posix_acl_", 29) == 0) {
+            /* adjust the name and size */
+            name += 12;
+            name_size -= 12;
+        } else {
+            /*
+             * Don't allow fetch of user.virtfs namesapce
+             * in case of mapped security
+             */
+            return 0;
+        }
+    }
+    if (!value) {
+        return name_size;
+    }
+
+    if (size < name_size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, name, name_size);
+    return name_size;
+}
+
+static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = EACCES;
+        return -1;
+    }
+    return lsetxattr(rpath(ctx, path), name, value, size, flags);
+}
+
+static int mp_user_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = EACCES;
+        return -1;
+    }
+    return lremovexattr(rpath(ctx, path), name);
+}
+
+XattrOperations mapped_user_xattr = {
+    .name = "user.",
+    .getxattr = mp_user_getxattr,
+    .setxattr = mp_user_setxattr,
+    .listxattr = mp_user_listxattr,
+    .removexattr = mp_user_removexattr,
+};
+
+XattrOperations passthrough_user_xattr = {
+    .name = "user.",
+    .getxattr = pt_getxattr,
+    .setxattr = pt_setxattr,
+    .listxattr = pt_listxattr,
+    .removexattr = pt_removexattr,
+};
diff --git a/hw/virtio-9p-xattr.c b/hw/virtio-9p-xattr.c
new file mode 100644 (file)
index 0000000..175f372
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Virtio 9p  xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static XattrOperations *get_xattr_operations(XattrOperations **h,
+                                             const char *name)
+{
+    XattrOperations *xops;
+    for (xops = *(h)++; xops != NULL; xops = *(h)++) {
+        if (!strncmp(name, xops->name, strlen(xops->name))) {
+            return xops;
+        }
+    }
+    return NULL;
+}
+
+ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
+                       const char *name, void *value, size_t size)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->getxattr(ctx, path, name, value, size);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+}
+
+ssize_t pt_listxattr(FsContext *ctx, const char *path,
+                     char *name, void *value, size_t size)
+{
+    int name_size = strlen(name) + 1;
+    if (!value) {
+        return name_size;
+    }
+
+    if (size < name_size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, name, name_size);
+    return name_size;
+}
+
+
+/*
+ * Get the list and pass to each layer to find out whether
+ * to send the data or not
+ */
+ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
+                        void *value, size_t vsize)
+{
+    ssize_t size = 0;
+    void *ovalue = value;
+    XattrOperations *xops;
+    char *orig_value, *orig_value_start;
+    ssize_t xattr_len, parsed_len = 0, attr_len;
+
+    /* Get the actual len */
+    xattr_len = llistxattr(rpath(ctx, path), value, 0);
+
+    /* Now fetch the xattr and find the actual size */
+    orig_value = qemu_malloc(xattr_len);
+    xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
+
+    /* store the orig pointer */
+    orig_value_start = orig_value;
+    while (xattr_len > parsed_len) {
+        xops = get_xattr_operations(ctx->xops, orig_value);
+        if (!xops) {
+            goto next_entry;
+        }
+
+        if (!value) {
+            size += xops->listxattr(ctx, path, orig_value, value, vsize);
+        } else {
+            size = xops->listxattr(ctx, path, orig_value, value, vsize);
+            if (size < 0) {
+                goto err_out;
+            }
+            value += size;
+            vsize -= size;
+        }
+next_entry:
+        /* Got the next entry */
+        attr_len = strlen(orig_value) + 1;
+        parsed_len += attr_len;
+        orig_value += attr_len;
+    }
+    if (value) {
+        size = value - ovalue;
+    }
+
+err_out:
+    qemu_free(orig_value_start);
+    return size;
+}
+
+int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+                   void *value, size_t size, int flags)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->setxattr(ctx, path, name, value, size, flags);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+
+}
+
+int v9fs_remove_xattr(FsContext *ctx,
+                      const char *path, const char *name)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->removexattr(ctx, path, name);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+
+}
+
+XattrOperations *mapped_xattr_ops[] = {
+    &mapped_user_xattr,
+    &mapped_pacl_xattr,
+    &mapped_dacl_xattr,
+    NULL,
+};
+
+XattrOperations *passthrough_xattr_ops[] = {
+    &passthrough_user_xattr,
+    &passthrough_acl_xattr,
+    NULL,
+};
+
+/* for .user none model should be same as passthrough */
+XattrOperations *none_xattr_ops[] = {
+    &passthrough_user_xattr,
+    &none_acl_xattr,
+    NULL,
+};
diff --git a/hw/virtio-9p-xattr.h b/hw/virtio-9p-xattr.h
new file mode 100644 (file)
index 0000000..a6e31a1
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef _QEMU_VIRTIO_9P_XATTR_H
+#define _QEMU_VIRTIO_9P_XATTR_H
+
+#include <attr/xattr.h>
+
+typedef struct xattr_operations
+{
+    const char *name;
+    ssize_t (*getxattr)(FsContext *ctx, const char *path,
+                        const char *name, void *value, size_t size);
+    ssize_t (*listxattr)(FsContext *ctx, const char *path,
+                         char *name, void *value, size_t size);
+    int (*setxattr)(FsContext *ctx, const char *path, const char *name,
+                    void *value, size_t size, int flags);
+    int (*removexattr)(FsContext *ctx,
+                       const char *path, const char *name);
+} XattrOperations;
+
+
+extern XattrOperations mapped_user_xattr;
+extern XattrOperations passthrough_user_xattr;
+
+extern XattrOperations mapped_pacl_xattr;
+extern XattrOperations mapped_dacl_xattr;
+extern XattrOperations passthrough_acl_xattr;
+extern XattrOperations none_acl_xattr;
+
+extern XattrOperations *mapped_xattr_ops[];
+extern XattrOperations *passthrough_xattr_ops[];
+extern XattrOperations *none_xattr_ops[];
+
+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,
+                          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);
+
+static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
+                                  const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), name, value, size);
+}
+
+static inline int pt_setxattr(FsContext *ctx, const char *path,
+                              const char *name, void *value,
+                              size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), name, value, size, flags);
+}
+
+static inline int pt_removexattr(FsContext *ctx,
+                                 const char *path, const char *name)
+{
+    return lremovexattr(rpath(ctx, path), name);
+}
+
+static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
+                                      const char *name, void *value,
+                                      size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static inline int notsup_setxattr(FsContext *ctx, const char *path,
+                                  const char *name, void *value,
+                                  size_t size, int flags)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
+                                       char *name, void *value, size_t size)
+{
+    return 0;
+}
+
+static inline int notsup_removexattr(FsContext *ctx,
+                                     const char *path, const char *name)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+#endif
index 3b2d49cde02c65d87920b92fc51964912653d832..daade77ed918ae6e858ba331237283e5fa99a23c 100644 (file)
@@ -17,6 +17,7 @@
 #include "virtio-9p.h"
 #include "fsdev/qemu-fsdev.h"
 #include "virtio-9p-debug.h"
+#include "virtio-9p-xattr.h"
 
 int debug_9p_pdu;
 
@@ -134,21 +135,16 @@ static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
     return s->ops->seekdir(&s->ctx, dir, off);
 }
 
-static int v9fs_do_readv(V9fsState *s, int fd, const struct iovec *iov,
-                            int iovcnt)
+static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
+                            int iovcnt, int64_t offset)
 {
-    return s->ops->readv(&s->ctx, fd, iov, iovcnt);
+    return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
 }
 
-static off_t v9fs_do_lseek(V9fsState *s, int fd, off_t offset, int whence)
+static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
+                       int iovcnt, int64_t offset)
 {
-    return s->ops->lseek(&s->ctx, fd, offset, whence);
-}
-
-static int v9fs_do_writev(V9fsState *s, int fd, const struct iovec *iov,
-                       int iovcnt)
-{
-    return s->ops->writev(&s->ctx, fd, iov, iovcnt);
+    return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
 }
 
 static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
@@ -325,6 +321,14 @@ static int number_to_string(void *arg, char type)
         } while (num);
         break;
     }
+    case 'U': {
+        unsigned long num = *(unsigned long *)arg;
+        do {
+            ret++;
+            num = num/10;
+        } while (num);
+        break;
+    }
     default:
         printf("Number_to_string: Unknown number format\n");
         return -1;
@@ -342,6 +346,7 @@ v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
     int nr_args = 0;
     char *arg_char_ptr;
     unsigned int arg_uint;
+    unsigned long arg_ulong;
 
     /* Find the number of %'s that denotes an argument */
     for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
@@ -367,6 +372,14 @@ v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
             arg_uint = va_arg(ap2, unsigned int);
             len += number_to_string((void *)&arg_uint, 'u');
             break;
+        case 'l':
+            if (*++iter == 'u') {
+                arg_ulong = va_arg(ap2, unsigned long);
+                len += number_to_string((void *)&arg_ulong, 'U');
+            } else {
+                return -1;
+            }
+            break;
         case 's':
             arg_char_ptr = va_arg(ap2, char *);
             len += strlen(arg_char_ptr);
@@ -1704,6 +1717,8 @@ static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
         if (s->proto_version == V9FS_PROTO_2000L) {
             flags = vs->mode;
             flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
+            /* Ignore direct disk access hint until the server supports it. */
+            flags &= ~O_DIRECT;
         } else {
             flags = omode_to_uflags(vs->mode);
         }
@@ -1760,8 +1775,10 @@ static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
         err = vs->offset;
     } else {
         vs->fidp->fid_type = P9_FID_NONE;
-        close(vs->fidp->fs.fd);
         err = -errno;
+        if (vs->fidp->fs.fd > 0) {
+            close(vs->fidp->fs.fd);
+        }
     }
 
     complete_pdu(s, vs->pdu, err);
@@ -1824,6 +1841,9 @@ static void v9fs_lcreate(V9fsState *s, V9fsPDU *pdu)
     v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
              vs->name.data);
 
+    /* Ignore direct disk access hint until the server supports it. */
+    flags &= ~O_DIRECT;
+
     vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
             gid, flags, mode);
     v9fs_lcreate_post_do_open2(s, vs, err);
@@ -1835,6 +1855,32 @@ out:
     qemu_free(vs);
 }
 
+static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
+{
+    if (err == -1) {
+        err = -errno;
+    }
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    int err;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        v9fs_post_do_fsync(s, pdu, err);
+        return;
+    }
+    err = v9fs_do_fsync(s, fidp->fs.fd);
+    v9fs_post_do_fsync(s, pdu, err);
+}
+
 static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
 {
     int32_t fid;
@@ -1941,7 +1987,7 @@ static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
     return;
 }
 
-static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
+static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
 {
     if (err  < 0) {
         /* IO error return the error */
@@ -1955,12 +2001,16 @@ static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
             if (0) {
                 print_sg(vs->sg, vs->cnt);
             }
-            vs->len = v9fs_do_readv(s, vs->fidp->fs.fd, vs->sg, vs->cnt);
+            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                      vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
         } while (vs->len == -1 && errno == EINTR);
         if (vs->len == -1) {
             err  = -errno;
         }
-        v9fs_read_post_readv(s, vs, err);
+        v9fs_read_post_preadv(s, vs, err);
         return;
     }
     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
@@ -1972,32 +2022,6 @@ out:
     qemu_free(vs);
 }
 
-static void v9fs_read_post_lseek(V9fsState *s, V9fsReadState *vs, ssize_t err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-
-    if (vs->total < vs->count) {
-        do {
-            if (0) {
-                print_sg(vs->sg, vs->cnt);
-            }
-            vs->len = v9fs_do_readv(s, vs->fidp->fs.fd, vs->sg, vs->cnt);
-        } while (vs->len == -1 && errno == EINTR);
-        if (vs->len == -1) {
-            err  = -errno;
-        }
-        v9fs_read_post_readv(s, vs, err);
-        return;
-    }
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
 static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
 {
     ssize_t err = 0;
@@ -2055,8 +2079,16 @@ static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
     } else if (vs->fidp->fid_type == P9_FID_FILE) {
         vs->sg = vs->iov;
         pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
-        err = v9fs_do_lseek(s, vs->fidp->fs.fd, vs->off, SEEK_SET);
-        v9fs_read_post_lseek(s, vs, err);
+        vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
+        if (vs->total <= vs->count) {
+            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                                    vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
+            err = vs->len;
+            v9fs_read_post_preadv(s, vs, err);
+        }
         return;
     } else if (vs->fidp->fid_type == P9_FID_XATTR) {
         v9fs_xattr_read(s, vs);
@@ -2190,7 +2222,7 @@ out:
     return;
 }
 
-static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
+static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
                                    ssize_t err)
 {
     if (err  < 0) {
@@ -2205,49 +2237,25 @@ static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
             if (0) {
                 print_sg(vs->sg, vs->cnt);
             }
-            vs->len =  v9fs_do_writev(s, vs->fidp->fs.fd, vs->sg, vs->cnt);
+            vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+                      vs->off);
+            if (vs->len > 0) {
+                vs->off += vs->len;
+            }
         } while (vs->len == -1 && errno == EINTR);
         if (vs->len == -1) {
             err  = -errno;
         }
-        v9fs_write_post_writev(s, vs, err);
+        v9fs_write_post_pwritev(s, vs, err);
         return;
     }
     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
-
     err = vs->offset;
 out:
     complete_pdu(s, vs->pdu, err);
     qemu_free(vs);
 }
 
-static void v9fs_write_post_lseek(V9fsState *s, V9fsWriteState *vs, ssize_t err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-
-    if (vs->total < vs->count) {
-        do {
-            if (0) {
-                print_sg(vs->sg, vs->cnt);
-            }
-            vs->len = v9fs_do_writev(s, vs->fidp->fs.fd, vs->sg, vs->cnt);
-        } while (vs->len == -1 && errno == EINTR);
-        if (vs->len == -1) {
-            err  = -errno;
-        }
-        v9fs_write_post_writev(s, vs, err);
-        return;
-    }
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    qemu_free(vs);
-}
-
 static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
 {
     int i, to_copy;
@@ -2328,11 +2336,16 @@ static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
         err = -EINVAL;
         goto out;
     }
-    err = v9fs_do_lseek(s, vs->fidp->fs.fd, vs->off, SEEK_SET);
-
-    v9fs_write_post_lseek(s, vs, err);
+    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
+    if (vs->total <= vs->count) {
+        vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
+        if (vs->len > 0) {
+            vs->off += vs->len;
+        }
+        err = vs->len;
+        v9fs_write_post_pwritev(s, vs, err);
+    }
     return;
-
 out:
     complete_pdu(s, vs->pdu, err);
     qemu_free(vs);
@@ -3152,6 +3165,95 @@ out:
     qemu_free(vs);
 }
 
+/*
+ * Implement posix byte range locking code
+ * Server side handling of locking code is very simple, because 9p server in
+ * QEMU can handle only one client. And most of the lock handling
+ * (like conflict, merging) etc is done by the VFS layer itself, so no need to
+ * do any thing in * qemu 9p server side lock code path.
+ * So when a TLOCK request comes, always return success
+ */
+
+static void v9fs_lock(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, err = 0;
+    V9fsLockState *vs;
+
+    vs = qemu_mallocz(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    vs->flock = qemu_malloc(sizeof(*vs->flock));
+    pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
+                &vs->flock->flags, &vs->flock->start, &vs->flock->length,
+                            &vs->flock->proc_id, &vs->flock->client_id);
+
+    vs->status = P9_LOCK_ERROR;
+
+    /* We support only block flag now (that too ignored currently) */
+    if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
+        err = -EINVAL;
+        goto out;
+    }
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->status = P9_LOCK_SUCCESS;
+out:
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs->flock);
+    qemu_free(vs);
+}
+
+/*
+ * When a TGETLOCK request comes, always return success because all lock
+ * handling is done by client's VFS layer.
+ */
+
+static void v9fs_getlock(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, err = 0;
+    V9fsGetlockState *vs;
+
+    vs = qemu_mallocz(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    vs->glock = qemu_malloc(sizeof(*vs->glock));
+    pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
+                &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
+               &vs->glock->client_id);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->glock->type = F_UNLCK;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
+                vs->glock->start, vs->glock->length, vs->glock->proc_id,
+               &vs->glock->client_id);
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs->glock);
+    qemu_free(vs);
+}
+
 static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
 {
     if (err == -1) {
@@ -3403,6 +3505,49 @@ out:
     qemu_free(vs);
 }
 
+static void v9fs_readlink_post_readlink(V9fsState *s, V9fsReadLinkState *vs,
+                                                    int err)
+{
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "s", &vs->target);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->target);
+    qemu_free(vs);
+}
+
+static void v9fs_readlink(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadLinkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_init(&vs->target);
+    err = v9fs_do_readlink(s, &fidp->path, &vs->target);
+    v9fs_readlink_post_readlink(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
 typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
 
 static pdu_handler_t *pdu_handlers[] = {
@@ -3414,6 +3559,9 @@ static pdu_handler_t *pdu_handlers[] = {
     [P9_TXATTRCREATE] = v9fs_xattrcreate,
     [P9_TMKNOD] = v9fs_mknod,
     [P9_TRENAME] = v9fs_rename,
+    [P9_TLOCK] = v9fs_lock,
+    [P9_TGETLOCK] = v9fs_getlock,
+    [P9_TREADLINK] = v9fs_readlink,
     [P9_TMKDIR] = v9fs_mkdir,
     [P9_TVERSION] = v9fs_version,
     [P9_TLOPEN] = v9fs_open,
@@ -3421,6 +3569,7 @@ static pdu_handler_t *pdu_handlers[] = {
     [P9_TSTAT] = v9fs_stat,
     [P9_TWALK] = v9fs_walk,
     [P9_TCLUNK] = v9fs_clunk,
+    [P9_TFSYNC] = v9fs_fsync,
     [P9_TOPEN] = v9fs_open,
     [P9_TREAD] = v9fs_read,
 #if 0
@@ -3527,8 +3676,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
 
     if (!fse) {
         /* We don't have a fsdev identified by fsdev_id */
-        fprintf(stderr, "Virtio-9p device couldn't find fsdev "
-                    "with the id %s\n", conf->fsdev_id);
+        fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
+                "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
         exit(1);
     }
 
@@ -3543,23 +3692,26 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
     if (!strcmp(fse->security_model, "passthrough")) {
         /* Files on the Fileserver set to client user credentials */
         s->ctx.fs_sm = SM_PASSTHROUGH;
+        s->ctx.xops = passthrough_xattr_ops;
     } else if (!strcmp(fse->security_model, "mapped")) {
         /* Files on the fileserver are set to QEMU credentials.
          * Client user credentials are saved in extended attributes.
          */
         s->ctx.fs_sm = SM_MAPPED;
+        s->ctx.xops = mapped_xattr_ops;
     } else if (!strcmp(fse->security_model, "none")) {
         /*
          * Files on the fileserver are set to QEMU credentials.
          */
         s->ctx.fs_sm = SM_NONE;
-
+        s->ctx.xops = none_xattr_ops;
     } else {
         fprintf(stderr, "Default to security_model=none. You may want"
                 " enable advanced security model using "
                 "security option:\n\t security_model=passthrough \n\t "
                 "security_model=mapped\n");
         s->ctx.fs_sm = SM_NONE;
+        s->ctx.xops = none_xattr_ops;
     }
 
     if (lstat(fse->path, &stat)) {
index 0816ad66ecffbce0743d6a7a8964ce947b76a19f..6c233192e36eba335ef967b44bdbe2531a7090ab 100644 (file)
@@ -27,6 +27,8 @@ enum {
     P9_RMKNOD,
     P9_TRENAME = 20,
     P9_RRENAME,
+    P9_TREADLINK = 22,
+    P9_RREADLINK,
     P9_TGETATTR = 24,
     P9_RGETATTR,
     P9_TSETATTR = 26,
@@ -37,6 +39,12 @@ enum {
     P9_RXATTRCREATE,
     P9_TREADDIR = 40,
     P9_RREADDIR,
+    P9_TFSYNC = 50,
+    P9_RFSYNC,
+    P9_TLOCK = 52,
+    P9_RLOCK,
+    P9_TGETLOCK = 54,
+    P9_RGETLOCK,
     P9_TLINK = 70,
     P9_RLINK,
     P9_TMKDIR = 72,
@@ -434,6 +442,59 @@ typedef struct V9fsXattrState
     void *value;
 } V9fsXattrState;
 
+#define P9_LOCK_SUCCESS 0
+#define P9_LOCK_BLOCKED 1
+#define P9_LOCK_ERROR 2
+#define P9_LOCK_GRACE 3
+
+#define P9_LOCK_FLAGS_BLOCK 1
+#define P9_LOCK_FLAGS_RECLAIM 2
+
+typedef struct V9fsFlock
+{
+    uint8_t type;
+    uint32_t flags;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    V9fsString client_id;
+} V9fsFlock;
+
+typedef struct V9fsLockState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    int8_t status;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsFlock *flock;
+} V9fsLockState;
+
+typedef struct V9fsGetlock
+{
+    uint8_t type;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    V9fsString client_id;
+} V9fsGetlock;
+
+typedef struct V9fsGetlockState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsGetlock *glock;
+} V9fsGetlockState;
+
+typedef struct V9fsReadLinkState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsString target;
+} V9fsReadLinkState;
+
 extern size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
                             size_t offset, size_t size, int pack);
 
index a1df26dbcf311490a66ddcc8aa198a0033953797..dbe207070e11dc5aded47563fec5b30f87ae61c2 100644 (file)
@@ -106,7 +106,13 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
 {
     VirtIOBlockReq *req = opaque;
 
-    virtio_blk_req_complete(req, ret ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK);
+    if (ret) {
+        if (virtio_blk_handle_rw_error(req, -ret, 0)) {
+            return;
+        }
+    }
+
+    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
 }
 
 static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
index 0a9cae22c45ead87c34d5383868c379be1ace5ba..7e1688cf69dc5272fd84a27aaf031ce3ce1c6134 100644 (file)
@@ -54,6 +54,7 @@ typedef struct VirtIONet
     uint8_t nouni;
     uint8_t nobcast;
     uint8_t vhost_started;
+    bool vm_running;
     VMChangeStateEntry *vmstate;
     struct {
         int in_use;
@@ -98,6 +99,38 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
     }
 }
 
+static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    if (!n->nic->nc.peer) {
+        return;
+    }
+    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
+        return;
+    }
+
+    if (!tap_get_vhost_net(n->nic->nc.peer)) {
+        return;
+    }
+    if (!!n->vhost_started == ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+                               (n->status & VIRTIO_NET_S_LINK_UP) &&
+                               n->vm_running)) {
+        return;
+    }
+    if (!n->vhost_started) {
+        int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
+        if (r < 0) {
+            fprintf(stderr, "unable to start vhost net: %d: "
+                    "falling back on userspace virtio\n", -r);
+        } else {
+            n->vhost_started = 1;
+        }
+    } else {
+        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
+        n->vhost_started = 0;
+    }
+}
+
 static void virtio_net_set_link_status(VLANClientState *nc)
 {
     VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -110,6 +143,8 @@ static void virtio_net_set_link_status(VLANClientState *nc)
 
     if (n->status != old_status)
         virtio_notify_config(&n->vdev);
+
+    virtio_net_set_status(&n->vdev, n->vdev.status);
 }
 
 static void virtio_net_reset(VirtIODevice *vdev)
@@ -123,10 +158,6 @@ static void virtio_net_reset(VirtIODevice *vdev)
     n->nomulti = 0;
     n->nouni = 0;
     n->nobcast = 0;
-    if (n->vhost_started) {
-        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
-        n->vhost_started = 0;
-    }
 
     /* Flush any MAC and VLAN filter table state */
     n->mac_table.in_use = 0;
@@ -783,12 +814,9 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
 {
     VirtIONet *n = opaque;
 
-    if (n->vhost_started) {
-        /* TODO: should we really stop the backend?
-         * If we don't, it might keep writing to memory. */
-        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
-        n->vhost_started = 0;
-    }
+    /* At this point, backend must be stopped, otherwise
+     * it might keep writing to memory. */
+    assert(!n->vhost_started);
     virtio_save(&n->vdev, f);
 
     qemu_put_buffer(f, n->mac, ETH_ALEN);
@@ -924,44 +952,14 @@ static NetClientInfo net_virtio_info = {
     .link_status_changed = virtio_net_set_link_status,
 };
 
-static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    if (!n->nic->nc.peer) {
-        return;
-    }
-    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
-        return;
-    }
-
-    if (!tap_get_vhost_net(n->nic->nc.peer)) {
-        return;
-    }
-    if (!!n->vhost_started == !!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        return;
-    }
-    if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
-        int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), vdev);
-        if (r < 0) {
-            fprintf(stderr, "unable to start vhost net: %d: "
-                    "falling back on userspace virtio\n", -r);
-        } else {
-            n->vhost_started = 1;
-        }
-    } else {
-        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
-        n->vhost_started = 0;
-    }
-}
-
 static void virtio_net_vmstate_change(void *opaque, int running, int reason)
 {
     VirtIONet *n = opaque;
-    uint8_t status = running ? VIRTIO_CONFIG_S_DRIVER_OK : 0;
+    n->vm_running = running;
     /* This is called when vm is started/stopped,
-     * it will start/stop vhost backend if appropriate
+     * it will start/stop vhost backend if appropriate
      * e.g. after migration. */
-    virtio_net_set_status(&n->vdev, n->vdev.status & status);
+    virtio_net_set_status(&n->vdev, n->vdev.status);
 }
 
 VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
@@ -1028,9 +1026,8 @@ void virtio_net_exit(VirtIODevice *vdev)
     VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
     qemu_del_vm_change_state_handler(n->vmstate);
 
-    if (n->vhost_started) {
-        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
-    }
+    /* This will stop vhost backend if appropriate. */
+    virtio_net_set_status(vdev, 0);
 
     qemu_purge_queued_packets(&n->nic->nc);
 
index 86e6b0a5617c2bc84c18b5cc9eaf6773e69c6beb..729917d89169948250ef42e5366e2e5b2ff13816 100644 (file)
@@ -451,6 +451,33 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
     return 0;
 }
 
+static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    VirtIODevice *vdev = proxy->vdev;
+    int r, n;
+
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(vdev, n)) {
+            break;
+        }
+
+        r = virtio_pci_set_guest_notifier(opaque, n, assign);
+        if (r < 0) {
+            goto assign_error;
+        }
+    }
+
+    return 0;
+
+assign_error:
+    /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
+    while (--n >= 0) {
+        virtio_pci_set_guest_notifier(opaque, n, !assign);
+    }
+    return r;
+}
+
 static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign)
 {
     VirtIOPCIProxy *proxy = opaque;
@@ -488,7 +515,7 @@ static const VirtIOBindings virtio_pci_bindings = {
     .load_queue = virtio_pci_load_queue,
     .get_features = virtio_pci_get_features,
     .set_host_notifier = virtio_pci_set_host_notifier,
-    .set_guest_notifier = virtio_pci_set_guest_notifier,
+    .set_guest_notifiers = virtio_pci_set_guest_notifiers,
 };
 
 static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
index fbef788854a9a633b01fee07fbd15bfc6fce223b..a2a657e132d8c4b8ec11d69f344cb567f3fd5249 100644 (file)
@@ -458,6 +458,8 @@ void virtio_reset(void *opaque)
     VirtIODevice *vdev = opaque;
     int i;
 
+    virtio_set_status(vdev, 0);
+
     if (vdev->reset)
         vdev->reset(vdev);
 
@@ -679,6 +681,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
     uint32_t features;
     uint32_t supported_features =
         vdev->binding->get_features(vdev->binding_opaque);
+    uint16_t num_heads;
 
     if (vdev->binding->load_config) {
         ret = vdev->binding->load_config(vdev->binding_opaque, f);
@@ -711,6 +714,16 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
         if (vdev->vq[i].pa) {
             virtqueue_init(&vdev->vq[i]);
         }
+       num_heads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
+       /* Check it isn't doing very strange things with descriptor numbers. */
+       if (num_heads > vdev->vq[i].vring.num) {
+               fprintf(stderr, "VQ %d size 0x%x Guest index 0x%x "
+                        "inconsistent with Host index 0x%x: delta 0x%x\n",
+                       i, vdev->vq[i].vring.num,
+                        vring_avail_idx(&vdev->vq[i]),
+                        vdev->vq[i].last_avail_idx, num_heads);
+               return -1;
+       }
         if (vdev->binding->load_queue) {
             ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
             if (ret)
index 96514e6c8b9ba2a0d2c1b12afe79b8a46b355e3c..02fa312d3eb2a9f607085c7e5d5764cb3b8c8240 100644 (file)
@@ -93,7 +93,7 @@ typedef struct {
     int (*load_config)(void * opaque, QEMUFile *f);
     int (*load_queue)(void * opaque, int n, QEMUFile *f);
     unsigned (*get_features)(void * opaque);
-    int (*set_guest_notifier)(void * opaque, int n, bool assigned);
+    int (*set_guest_notifiers)(void * opaque, bool assigned);
     int (*set_host_notifier)(void * opaque, int n, bool assigned);
 } VirtIOBindings;
 
index f3593047e776119228a26dec0346722b913b2f45..209711942fa4ad4474d69e701a6ddded23af2334 100644 (file)
@@ -100,16 +100,29 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_
     i8042_isa_mouse_fake_event(s->ps2_mouse);
 }
 
-static void vmmouse_update_handler(VMMouseState *s)
+static void vmmouse_remove_handler(VMMouseState *s)
 {
     if (s->entry) {
         qemu_remove_mouse_event_handler(s->entry);
         s->entry = NULL;
     }
-    if (s->status == 0)
+}
+
+static void vmmouse_update_handler(VMMouseState *s, int absolute)
+{
+    if (s->status != 0) {
+        return;
+    }
+    if (s->absolute != absolute) {
+        s->absolute = absolute;
+        vmmouse_remove_handler(s);
+    }
+    if (s->entry == NULL) {
         s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
                                                 s, s->absolute,
                                                 "vmmouse");
+        qemu_activate_mouse_event_handler(s->entry);
+    }
 }
 
 static void vmmouse_read_id(VMMouseState *s)
@@ -121,28 +134,25 @@ static void vmmouse_read_id(VMMouseState *s)
 
     s->queue[s->nb_queue++] = VMMOUSE_VERSION;
     s->status = 0;
-    vmmouse_update_handler(s);
 }
 
 static void vmmouse_request_relative(VMMouseState *s)
 {
     DPRINTF("vmmouse_request_relative()\n");
-    s->absolute = 0;
-    vmmouse_update_handler(s);
+    vmmouse_update_handler(s, 0);
 }
 
 static void vmmouse_request_absolute(VMMouseState *s)
 {
     DPRINTF("vmmouse_request_absolute()\n");
-    s->absolute = 1;
-    vmmouse_update_handler(s);
+    vmmouse_update_handler(s, 1);
 }
 
 static void vmmouse_disable(VMMouseState *s)
 {
     DPRINTF("vmmouse_disable()\n");
     s->status = 0xffff;
-    vmmouse_update_handler(s);
+    vmmouse_remove_handler(s);
 }
 
 static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
@@ -154,7 +164,7 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
     if (size == 0 || size > 6 || size > s->nb_queue) {
         printf("vmmouse: driver requested too much data %d\n", size);
         s->status = 0xffff;
-        vmmouse_update_handler(s);
+        vmmouse_remove_handler(s);
         return;
     }
 
@@ -239,7 +249,8 @@ static int vmmouse_post_load(void *opaque, int version_id)
 {
     VMMouseState *s = opaque;
 
-    vmmouse_update_handler(s);
+    vmmouse_remove_handler(s);
+    vmmouse_update_handler(s, s->absolute);
     return 0;
 }
 
index ce43c234ac7dd76190b5fa6eca5dcd8e61de3156..c9c674451b4c5664ffa037237d2ebd8f154cea3b 100644 (file)
@@ -171,7 +171,6 @@ static void wm8750_set_format(WM8750State *s)
     int i;
     struct audsettings in_fmt;
     struct audsettings out_fmt;
-    struct audsettings monoout_fmt;
 
     wm8750_out_flush(s);
 
@@ -212,10 +211,6 @@ static void wm8750_set_format(WM8750State *s)
     out_fmt.nchannels = 2;
     out_fmt.freq = s->dac_hz;
     out_fmt.fmt = AUD_FMT_S16;
-    monoout_fmt.endianness = 0;
-    monoout_fmt.nchannels = 1;
-    monoout_fmt.freq = s->rate->dac_hz;
-    monoout_fmt.fmt = AUD_FMT_S16;
 
     s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
                     CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
new file mode 100644 (file)
index 0000000..854eba8
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * x3130_downstream.c
+ * TI X3130 pci express downstream port switch
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "xio3130_downstream.h"
+
+#define PCI_DEVICE_ID_TI_XIO3130D       0x8233  /* downstream port */
+#define XIO3130_REVISION                0x1
+#define XIO3130_MSI_OFFSET              0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR           1
+#define XIO3130_SSVID_OFFSET            0x80
+#define XIO3130_SSVID_SVID              0
+#define XIO3130_SSVID_SSID              0
+#define XIO3130_EXP_OFFSET              0x90
+#define XIO3130_AER_OFFSET              0x100
+
+static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
+                                         uint32_t val, int len)
+{
+    pci_bridge_write_config(d, address, val, len);
+    pcie_cap_flr_write_config(d, address, val, len);
+    pcie_cap_slot_write_config(d, address, val, len);
+    msi_write_config(d, address, val, len);
+    /* TODO: AER */
+}
+
+static void xio3130_downstream_reset(DeviceState *qdev)
+{
+    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    msi_reset(d);
+    pcie_cap_deverr_reset(d);
+    pcie_cap_slot_reset(d);
+    pcie_cap_ari_reset(d);
+    pci_bridge_reset(qdev);
+}
+
+static int xio3130_downstream_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+    int rc;
+
+    rc = pci_bridge_initfn(d);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pcie_port_init_reg(d);
+    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_TI);
+    pci_config_set_device_id(d->config, PCI_DEVICE_ID_TI_XIO3130D);
+    d->config[PCI_REVISION_ID] = XIO3130_REVISION;
+
+    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        return rc;
+    }
+    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
+    if (rc < 0) {
+        return rc;
+    }
+    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
+                       p->port);
+    if (rc < 0) {
+        return rc;
+    }
+    pcie_cap_flr_init(d);       /* TODO: implement FLR */
+    pcie_cap_deverr_init(d);
+    pcie_cap_slot_init(d, s->slot);
+    pcie_chassis_create(s->chassis);
+    rc = pcie_chassis_add_slot(s);
+    if (rc < 0) {
+        return rc;
+    }
+    pcie_cap_ari_init(d);
+    /* TODO: AER */
+
+    return 0;
+}
+
+static int xio3130_downstream_exitfn(PCIDevice *d)
+{
+    /* TODO: AER */
+    msi_uninit(d);
+    pcie_cap_exit(d);
+    return pci_bridge_exitfn(d);
+}
+
+PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                  const char *bus_name, pci_map_irq_fn map_irq,
+                                  uint8_t port, uint8_t chassis,
+                                  uint16_t slot)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction,
+                                 "xio3130-downstream");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_prop_set_uint8(qdev, "chassis", chassis);
+    qdev_prop_set_uint16(qdev, "slot", slot);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
+}
+
+static const VMStateDescription vmstate_xio3130_downstream = {
+    .name = "xio3130-express-downstream-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pcie_cap_slot_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
+        /* TODO: AER */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PCIDeviceInfo xio3130_downstream_info = {
+    .qdev.name = "xio3130-downstream",
+    .qdev.desc = "TI X3130 Downstream Port of PCI Express Switch",
+    .qdev.size = sizeof(PCIESlot),
+    .qdev.reset = xio3130_downstream_reset,
+    .qdev.vmsd = &vmstate_xio3130_downstream,
+
+    .is_express = 1,
+    .is_bridge = 1,
+    .config_write = xio3130_downstream_write_config,
+    .init = xio3130_downstream_initfn,
+    .exit = xio3130_downstream_exitfn,
+
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+        DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+        DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+        /* TODO: AER */
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xio3130_downstream_register(void)
+{
+    pci_qdev_register(&xio3130_downstream_info);
+}
+
+device_init(xio3130_downstream_register);
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/xio3130_downstream.h b/hw/xio3130_downstream.h
new file mode 100644 (file)
index 0000000..010487f
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef QEMU_XIO3130_DOWNSTREAM_H
+#define QEMU_XIO3130_DOWNSTREAM_H
+
+#include "pcie_port.h"
+
+PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                  const char *bus_name, pci_map_irq_fn map_irq,
+                                  uint8_t port, uint8_t chassis,
+                                  uint16_t slot);
+
+#endif /* QEMU_XIO3130_DOWNSTREAM_H */
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
new file mode 100644 (file)
index 0000000..d9d637f
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * xio3130_upstream.c
+ * TI X3130 pci express upstream port switch
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci_ids.h"
+#include "msi.h"
+#include "pcie.h"
+#include "xio3130_upstream.h"
+
+#define PCI_DEVICE_ID_TI_XIO3130U       0x8232  /* upstream port */
+#define XIO3130_REVISION                0x2
+#define XIO3130_MSI_OFFSET              0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR           1
+#define XIO3130_SSVID_OFFSET            0x80
+#define XIO3130_SSVID_SVID              0
+#define XIO3130_SSVID_SSID              0
+#define XIO3130_EXP_OFFSET              0x90
+#define XIO3130_AER_OFFSET              0x100
+
+static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
+                                          uint32_t val, int len)
+{
+    pci_bridge_write_config(d, address, val, len);
+    pcie_cap_flr_write_config(d, address, val, len);
+    msi_write_config(d, address, val, len);
+    /* TODO: AER */
+}
+
+static void xio3130_upstream_reset(DeviceState *qdev)
+{
+    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+    msi_reset(d);
+    pci_bridge_reset(qdev);
+    pcie_cap_deverr_reset(d);
+}
+
+static int xio3130_upstream_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    int rc;
+
+    rc = pci_bridge_initfn(d);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pcie_port_init_reg(d);
+    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_TI);
+    pci_config_set_device_id(d->config, PCI_DEVICE_ID_TI_XIO3130U);
+    d->config[PCI_REVISION_ID] = XIO3130_REVISION;
+
+    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        return rc;
+    }
+    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
+    if (rc < 0) {
+        return rc;
+    }
+    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
+                       p->port);
+    if (rc < 0) {
+        return rc;
+    }
+
+    /* TODO: implement FLR */
+    pcie_cap_flr_init(d);
+
+    pcie_cap_deverr_init(d);
+    /* TODO: AER */
+
+    return 0;
+}
+
+static int xio3130_upstream_exitfn(PCIDevice *d)
+{
+    /* TODO: AER */
+    msi_uninit(d);
+    pcie_cap_exit(d);
+    return pci_bridge_exitfn(d);
+}
+
+PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
+                             const char *bus_name, pci_map_irq_fn map_irq,
+                             uint8_t port)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction, "x3130-upstream");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIEPort, br, br);
+}
+
+static const VMStateDescription vmstate_xio3130_upstream = {
+    .name = "xio3130-express-upstream-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(br.dev, PCIEPort),
+        /* TODO: AER */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PCIDeviceInfo xio3130_upstream_info = {
+    .qdev.name = "x3130-upstream",
+    .qdev.desc = "TI X3130 Upstream Port of PCI Express Switch",
+    .qdev.size = sizeof(PCIEPort),
+    .qdev.reset = xio3130_upstream_reset,
+    .qdev.vmsd = &vmstate_xio3130_upstream,
+
+    .is_express = 1,
+    .is_bridge = 1,
+    .config_write = xio3130_upstream_write_config,
+    .init = xio3130_upstream_initfn,
+    .exit = xio3130_upstream_exitfn,
+
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
+        /* TODO: AER */
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xio3130_upstream_register(void)
+{
+    pci_qdev_register(&xio3130_upstream_info);
+}
+
+device_init(xio3130_upstream_register);
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/xio3130_upstream.h b/hw/xio3130_upstream.h
new file mode 100644 (file)
index 0000000..e996997
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef QEMU_XIO3130_UPSTREAM_H
+#define QEMU_XIO3130_UPSTREAM_H
+
+#include "pcie_port.h"
+
+PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                const char *bus_name, pci_map_irq_fn map_irq,
+                                uint8_t port);
+
+#endif /* QEMU_XIO3130_H */
index 1cc696f3c536eff11b3799888fa79f9988e113b4..37b99c75109429a749127a2cda6dd8579943f1ce 100644 (file)
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -137,6 +137,24 @@ static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s,
     return found;
 }
 
+int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
+                                      target_phys_addr_t *phys_addr)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
+
+        if (ram_addr >= mem->phys_offset &&
+            ram_addr < mem->phys_offset + mem->memory_size) {
+            *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
 {
     struct kvm_userspace_memory_region mem;
index d45f9fa1dfd1c58e6bbba24929833d44b4cc6b4b..5384a4b9a4187ad11426069bf7021b1fdc498d9c 100644 (file)
@@ -141,3 +141,8 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
 {
     return -ENOSYS;
 }
+
+int kvm_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
diff --git a/kvm.h b/kvm.h
index 50b6c01ec7d591fb9b50263d7814351ee40dda73..60a9b425c828863940b60a49a3191f58ebb5fe75 100644 (file)
--- a/kvm.h
+++ b/kvm.h
@@ -110,6 +110,9 @@ int kvm_arch_init_vcpu(CPUState *env);
 
 void kvm_arch_reset_vcpu(CPUState *env);
 
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
+int kvm_on_sigbus(int code, void *addr);
+
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
 
@@ -174,6 +177,12 @@ static inline void cpu_synchronize_post_init(CPUState *env)
     }
 }
 
+
+#if !defined(CONFIG_USER_ONLY)
+int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
+                                      target_phys_addr_t *phys_addr);
+#endif
+
 #endif
 int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign);
 
index d16bc671c6c7f39f92a31a79f47cbf26523a4c04..0371089b982c47e14a3cf0160a86359d6870335c 100644 (file)
 #define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024)
 #else
 #include "qemu-common.h"
-#include "sysemu.h"
 #include "gdbstub.h"
 #include "softmmu-semi.h"
 #endif
+#include "sysemu.h"
 
 #define HOSTED_EXIT  0
 #define HOSTED_INIT_SIM 1
index fbb678d78978a68312331dd984652ea24946b3c6..61607c5bd6c5f9202c251300b12e29915380f594 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -549,7 +549,11 @@ static void do_change_trace_event_state(Monitor *mon, const QDict *qdict)
 {
     const char *tp_name = qdict_get_str(qdict, "name");
     bool new_state = qdict_get_bool(qdict, "option");
-    st_change_trace_event_state(tp_name, new_state);
+    int ret = st_change_trace_event_state(tp_name, new_state);
+
+    if (!ret) {
+        monitor_printf(mon, "unknown event name \"%s\"\n", tp_name);
+    }
 }
 
 static void do_trace_file(Monitor *mon, const QDict *qdict)
@@ -3972,6 +3976,11 @@ static void file_completion(const char *input)
         d = readdir(ffs);
         if (!d)
             break;
+
+        if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
+            continue;
+        }
+
         if (strstart(d->d_name, file_prefix, NULL)) {
             memcpy(file, input, input_path_len);
             if (input_path_len < sizeof(file))
diff --git a/net.c b/net.c
index 3d0fde77b22af0574fd042316323436a6472f7d6..c5e6063fcf24c0aabe7606f3e7238eb9fb701057 100644 (file)
--- a/net.c
+++ b/net.c
@@ -281,29 +281,64 @@ NICState *qemu_new_nic(NetClientInfo *info,
     return nic;
 }
 
-void qemu_del_vlan_client(VLANClientState *vc)
+static void qemu_cleanup_vlan_client(VLANClientState *vc)
 {
     if (vc->vlan) {
         QTAILQ_REMOVE(&vc->vlan->clients, vc, next);
     } else {
-        if (vc->send_queue) {
-            qemu_del_net_queue(vc->send_queue);
-        }
         QTAILQ_REMOVE(&non_vlan_clients, vc, next);
-        if (vc->peer) {
-            vc->peer->peer = NULL;
-        }
     }
 
     if (vc->info->cleanup) {
         vc->info->cleanup(vc);
     }
+}
 
+static void qemu_free_vlan_client(VLANClientState *vc)
+{
+    if (!vc->vlan) {
+        if (vc->send_queue) {
+            qemu_del_net_queue(vc->send_queue);
+        }
+        if (vc->peer) {
+            vc->peer->peer = NULL;
+        }
+    }
     qemu_free(vc->name);
     qemu_free(vc->model);
     qemu_free(vc);
 }
 
+void qemu_del_vlan_client(VLANClientState *vc)
+{
+    /* If there is a peer NIC, delete and cleanup client, but do not free. */
+    if (!vc->vlan && vc->peer && vc->peer->info->type == NET_CLIENT_TYPE_NIC) {
+        NICState *nic = DO_UPCAST(NICState, nc, vc->peer);
+        if (nic->peer_deleted) {
+            return;
+        }
+        nic->peer_deleted = true;
+        /* Let NIC know peer is gone. */
+        vc->peer->link_down = true;
+        if (vc->peer->info->link_status_changed) {
+            vc->peer->info->link_status_changed(vc->peer);
+        }
+        qemu_cleanup_vlan_client(vc);
+        return;
+    }
+
+    /* If this is a peer NIC and peer has already been deleted, free it now. */
+    if (!vc->vlan && vc->peer && vc->info->type == NET_CLIENT_TYPE_NIC) {
+        NICState *nic = DO_UPCAST(NICState, nc, vc);
+        if (nic->peer_deleted) {
+            qemu_free_vlan_client(vc->peer);
+        }
+    }
+
+    qemu_cleanup_vlan_client(vc);
+    qemu_free_vlan_client(vc);
+}
+
 VLANClientState *
 qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id,
                               const char *client_str)
@@ -739,19 +774,25 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
 
 int net_handle_fd_param(Monitor *mon, const char *param)
 {
-    if (!qemu_isdigit(param[0])) {
-        int fd;
+    int fd;
+
+    if (!qemu_isdigit(param[0]) && mon) {
 
         fd = monitor_get_fd(mon, param);
         if (fd == -1) {
             error_report("No file descriptor named %s found", param);
             return -1;
         }
-
-        return fd;
     } else {
-        return strtol(param, NULL, 0);
+        char *endptr = NULL;
+
+        fd = strtol(param, &endptr, 10);
+        if (*endptr || (fd == 0 && param == endptr)) {
+            return -1;
+        }
     }
+
+    return fd;
 }
 
 static int net_init_nic(QemuOpts *opts,
diff --git a/net.h b/net.h
index 518cf9c1f73a080790d212bc7265b2efa53a658c..44c31a9b321f468ca4a3dbbca2bd97b5d9d45a66 100644 (file)
--- a/net.h
+++ b/net.h
@@ -72,6 +72,7 @@ typedef struct NICState {
     VLANClientState nc;
     NICConf *conf;
     void *opaque;
+    bool peer_deleted;
 } NICState;
 
 struct VLANState {
index 9fe4fcd5f48d148af946846496ec6843bad3fb28..081904e8d74502684654a8c3463fb9d44816e886 100644 (file)
@@ -579,7 +579,6 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
     } version;
     DWORD version_len;
     DWORD idThread;
-    HANDLE hThread;
 
     if (prefered_name != NULL)
         snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name);
@@ -623,8 +622,8 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
 
     *phandle = &tap_overlapped;
 
-    hThread = CreateThread(NULL, 0, tap_win32_thread_entry,
-                           (LPVOID)&tap_overlapped, 0, &idThread);
+    CreateThread(NULL, 0, tap_win32_thread_entry,
+                 (LPVOID)&tap_overlapped, 0, &idThread);
     return 0;
 }
 
index 6321e990c5fcce0a7b6c9b67def844ec21b6c60d..38c29d1afe42ff3b2e7fc28f938e5798a2551053 100644 (file)
 #include <sys/prctl.h>
 #endif
 
+#ifdef CONFIG_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
 static struct passwd *user_pwd;
 static const char *chroot_dir;
 static int daemonize;
@@ -329,3 +333,52 @@ void os_set_line_buffering(void)
 {
     setvbuf(stdout, NULL, _IOLBF, 0);
 }
+
+/*
+ * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set.
+ */
+int qemu_eventfd(int fds[2])
+{
+#ifdef CONFIG_EVENTFD
+    int ret;
+
+    ret = eventfd(0, 0);
+    if (ret >= 0) {
+        fds[0] = ret;
+        qemu_set_cloexec(ret);
+        if ((fds[1] = dup(ret)) == -1) {
+            close(ret);
+            return -1;
+        }
+        qemu_set_cloexec(fds[1]);
+        return 0;
+    }
+
+    if (errno != ENOSYS) {
+        return -1;
+    }
+#endif
+
+    return qemu_pipe(fds);
+}
+
+int qemu_create_pidfile(const char *filename)
+{
+    char buffer[128];
+    int len;
+    int fd;
+
+    fd = qemu_open(filename, O_RDWR | O_CREAT, 0600);
+    if (fd == -1) {
+        return -1;
+    }
+    if (lockf(fd, F_TLOCK, 0) == -1) {
+        return -1;
+    }
+    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+    if (write(fd, buffer, len) != len) {
+        return -1;
+    }
+
+    return 0;
+}
index dd46bf459db4a150d2866468fa2c9bc1adb8a885..566d5e985352467b250396e0236a20e0647af2b0 100644 (file)
@@ -221,6 +221,12 @@ char *os_find_datadir(const char *argv0)
     return NULL;
 }
 
+void os_set_line_buffering(void)
+{
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+}
+
 /*
  * Parse OS specific command line options.
  * return 0 if option handled, -1 otherwise
@@ -234,3 +240,27 @@ void os_pidfile_error(void)
 {
     fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
 }
+
+int qemu_create_pidfile(const char *filename)
+{
+    char buffer[128];
+    int len;
+    HANDLE file;
+    OVERLAPPED overlap;
+    BOOL ret;
+    memset(&overlap, 0, sizeof(overlap));
+
+    file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                     OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    if (file == INVALID_HANDLE_VALUE) {
+        return -1;
+    }
+    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+    ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len,
+                     &overlap, NULL);
+    if (ret == 0) {
+        return -1;
+    }
+    return 0;
+}
diff --git a/osdep.c b/osdep.c
index 2e05b21ad95b6404cd5661f46471300a4a9c543d..327583baf73a8b1b10f3b6456bcd80a7861a49e7 100644 (file)
--- a/osdep.c
+++ b/osdep.c
 extern int madvise(caddr_t, size_t, int);
 #endif
 
-#ifdef CONFIG_EVENTFD
-#include <sys/eventfd.h>
-#endif
-
-#ifdef _WIN32
-#include <windows.h>
-#elif defined(CONFIG_BSD)
-#include <stdlib.h>
-#else
-#include <malloc.h>
-#endif
-
 #include "qemu-common.h"
 #include "trace.h"
 #include "sysemu.h"
 #include "qemu_socket.h"
 
-#if !defined(_POSIX_C_SOURCE) || defined(_WIN32) || defined(__sun__)
-static void *oom_check(void *ptr)
-{
-    if (ptr == NULL) {
-#if defined(_WIN32)
-        fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError());
-#else
-        fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
-#endif
-        abort();
-    }
-    return ptr;
-}
-#endif
-
-#if defined(_WIN32)
-void *qemu_memalign(size_t alignment, size_t size)
-{
-    void *ptr;
-
-    if (!size) {
-        abort();
-    }
-    ptr = oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
-    trace_qemu_memalign(alignment, size, ptr);
-    return ptr;
-}
-
-void *qemu_vmalloc(size_t size)
-{
-    void *ptr;
-
-    /* FIXME: this is not exactly optimal solution since VirtualAlloc
-       has 64Kb granularity, but at least it guarantees us that the
-       memory is page aligned. */
-    if (!size) {
-        abort();
-    }
-    ptr = oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
-    trace_qemu_vmalloc(size, ptr);
-    return ptr;
-}
-
-void qemu_vfree(void *ptr)
-{
-    trace_qemu_vfree(ptr);
-    VirtualFree(ptr, 0, MEM_RELEASE);
-}
-
-#else
-
-void *qemu_memalign(size_t alignment, size_t size)
-{
-    void *ptr;
-#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
-    int ret;
-    ret = posix_memalign(&ptr, alignment, size);
-    if (ret != 0) {
-        fprintf(stderr, "Failed to allocate %zu B: %s\n",
-                size, strerror(ret));
-        abort();
-    }
-#elif defined(CONFIG_BSD)
-    ptr = oom_check(valloc(size));
-#else
-    ptr = oom_check(memalign(alignment, size));
-#endif
-    trace_qemu_memalign(alignment, size, ptr);
-    return ptr;
-}
-
-/* alloc shared memory pages */
-void *qemu_vmalloc(size_t size)
-{
-    return qemu_memalign(getpagesize(), size);
-}
-
-void qemu_vfree(void *ptr)
-{
-    trace_qemu_vfree(ptr);
-    free(ptr);
-}
-
-#endif
-
 int qemu_madvise(void *addr, size_t len, int advice)
 {
     if (advice == QEMU_MADV_INVALID) {
@@ -162,113 +65,6 @@ int qemu_madvise(void *addr, size_t len, int advice)
 #endif
 }
 
-int qemu_create_pidfile(const char *filename)
-{
-    char buffer[128];
-    int len;
-#ifndef _WIN32
-    int fd;
-
-    fd = qemu_open(filename, O_RDWR | O_CREAT, 0600);
-    if (fd == -1)
-        return -1;
-
-    if (lockf(fd, F_TLOCK, 0) == -1)
-        return -1;
-
-    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
-    if (write(fd, buffer, len) != len)
-        return -1;
-#else
-    HANDLE file;
-    OVERLAPPED overlap;
-    BOOL ret;
-    memset(&overlap, 0, sizeof(overlap));
-
-    file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
-                     OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-
-    if (file == INVALID_HANDLE_VALUE)
-      return -1;
-
-    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
-    ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len,
-                     &overlap, NULL);
-    if (ret == 0)
-      return -1;
-#endif
-    return 0;
-}
-
-#ifdef _WIN32
-
-/* mingw32 needs ffs for compilations without optimization. */
-int ffs(int i)
-{
-    /* Use gcc's builtin ffs. */
-    return __builtin_ffs(i);
-}
-
-/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
-#define _W32_FT_OFFSET (116444736000000000ULL)
-
-int qemu_gettimeofday(qemu_timeval *tp)
-{
-  union {
-    unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
-    FILETIME ft;
-  }  _now;
-
-  if(tp)
-    {
-      GetSystemTimeAsFileTime (&_now.ft);
-      tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
-      tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
-    }
-  /* Always return 0 as per Open Group Base Specifications Issue 6.
-     Do not set errno on error.  */
-  return 0;
-}
-#endif /* _WIN32 */
-
-
-#ifdef _WIN32
-void socket_set_nonblock(int fd)
-{
-    unsigned long opt = 1;
-    ioctlsocket(fd, FIONBIO, &opt);
-}
-
-int inet_aton(const char *cp, struct in_addr *ia)
-{
-    uint32_t addr = inet_addr(cp);
-    if (addr == 0xffffffff)
-       return 0;
-    ia->s_addr = addr;
-    return 1;
-}
-
-void qemu_set_cloexec(int fd)
-{
-}
-
-#else
-
-void socket_set_nonblock(int fd)
-{
-    int f;
-    f = fcntl(fd, F_GETFL);
-    fcntl(fd, F_SETFL, f | O_NONBLOCK);
-}
-
-void qemu_set_cloexec(int fd)
-{
-    int f;
-    f = fcntl(fd, F_GETFD);
-    fcntl(fd, F_SETFD, f | FD_CLOEXEC);
-}
-
-#endif
 
 /*
  * Opens a file with FD_CLOEXEC set
@@ -330,58 +126,6 @@ ssize_t qemu_write_full(int fd, const void *buf, size_t count)
     return total;
 }
 
-#ifndef _WIN32
-/*
- * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set.
- */
-int qemu_eventfd(int fds[2])
-{
-#ifdef CONFIG_EVENTFD
-    int ret;
-
-    ret = eventfd(0, 0);
-    if (ret >= 0) {
-        fds[0] = ret;
-        qemu_set_cloexec(ret);
-        if ((fds[1] = dup(ret)) == -1) {
-            close(ret);
-            return -1;
-        }
-        qemu_set_cloexec(fds[1]);
-        return 0;
-    }
-
-    if (errno != ENOSYS) {
-        return -1;
-    }
-#endif
-
-    return qemu_pipe(fds);
-}
-
-/*
- * Creates a pipe with FD_CLOEXEC set on both file descriptors
- */
-int qemu_pipe(int pipefd[2])
-{
-    int ret;
-
-#ifdef CONFIG_PIPE2
-    ret = pipe2(pipefd, O_CLOEXEC);
-    if (ret != -1 || errno != ENOSYS) {
-        return ret;
-    }
-#endif
-    ret = pipe(pipefd);
-    if (ret == 0) {
-        qemu_set_cloexec(pipefd[0]);
-        qemu_set_cloexec(pipefd[1]);
-    }
-
-    return ret;
-}
-#endif
-
 /*
  * Opens a socket with FD_CLOEXEC set
  */
diff --git a/osdep.h b/osdep.h
index 671628114abcb42f9788f94aaaf616967213a212..8bd30d764d2a4ed922b4de3383d0502980636185 100644 (file)
--- a/osdep.h
+++ b/osdep.h
@@ -127,19 +127,4 @@ int qemu_madvise(void *addr, size_t len, int advice);
 
 int qemu_create_pidfile(const char *filename);
 
-#ifdef _WIN32
-int ffs(int i);
-
-int setenv(const char *name, const char *value, int overwrite);
-
-typedef struct {
-    long tv_sec;
-    long tv_usec;
-} qemu_timeval;
-int qemu_gettimeofday(qemu_timeval *tp);
-#else
-typedef struct timeval qemu_timeval;
-#define qemu_gettimeofday(tp) gettimeofday(tp, NULL);
-#endif /* !_WIN32 */
-
 #endif
diff --git a/oslib-posix.c b/oslib-posix.c
new file mode 100644 (file)
index 0000000..6e9b0c3
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * os-posix-lib.c
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Red Hat, Inc.
+ *
+ * QEMU library functions on POSIX which are shared between QEMU and
+ * the QEMU tools.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config-host.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu_socket.h"
+
+void *qemu_oom_check(void *ptr)
+{
+    if (ptr == NULL) {
+        fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
+        abort();
+    }
+    return ptr;
+}
+
+void *qemu_memalign(size_t alignment, size_t size)
+{
+    void *ptr;
+#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
+    int ret;
+    ret = posix_memalign(&ptr, alignment, size);
+    if (ret != 0) {
+        fprintf(stderr, "Failed to allocate %zu B: %s\n",
+                size, strerror(ret));
+        abort();
+    }
+#elif defined(CONFIG_BSD)
+    ptr = qemu_oom_check(valloc(size));
+#else
+    ptr = qemu_oom_check(memalign(alignment, size));
+#endif
+    trace_qemu_memalign(alignment, size, ptr);
+    return ptr;
+}
+
+/* alloc shared memory pages */
+void *qemu_vmalloc(size_t size)
+{
+    return qemu_memalign(getpagesize(), size);
+}
+
+void qemu_vfree(void *ptr)
+{
+    trace_qemu_vfree(ptr);
+    free(ptr);
+}
+
+void socket_set_nonblock(int fd)
+{
+    int f;
+    f = fcntl(fd, F_GETFL);
+    fcntl(fd, F_SETFL, f | O_NONBLOCK);
+}
+
+void qemu_set_cloexec(int fd)
+{
+    int f;
+    f = fcntl(fd, F_GETFD);
+    fcntl(fd, F_SETFD, f | FD_CLOEXEC);
+}
+
+/*
+ * Creates a pipe with FD_CLOEXEC set on both file descriptors
+ */
+int qemu_pipe(int pipefd[2])
+{
+    int ret;
+
+#ifdef CONFIG_PIPE2
+    ret = pipe2(pipefd, O_CLOEXEC);
+    if (ret != -1 || errno != ENOSYS) {
+        return ret;
+    }
+#endif
+    ret = pipe(pipefd);
+    if (ret == 0) {
+        qemu_set_cloexec(pipefd[0]);
+        qemu_set_cloexec(pipefd[1]);
+    }
+
+    return ret;
+}
diff --git a/oslib-win32.c b/oslib-win32.c
new file mode 100644 (file)
index 0000000..ab29eae
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * os-win32.c
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Red Hat, Inc.
+ *
+ * QEMU library functions for win32 which are shared between QEMU and
+ * the QEMU tools.
+ *
+ * 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 <windows.h>
+#include "config-host.h"
+#include "sysemu.h"
+#include "trace.h"
+#include "qemu_socket.h"
+
+void *qemu_oom_check(void *ptr)
+{
+    if (ptr == NULL) {
+        fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError());
+        abort();
+    }
+    return ptr;
+}
+
+void *qemu_memalign(size_t alignment, size_t size)
+{
+    void *ptr;
+
+    if (!size) {
+        abort();
+    }
+    ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
+    trace_qemu_memalign(alignment, size, ptr);
+    return ptr;
+}
+
+void *qemu_vmalloc(size_t size)
+{
+    void *ptr;
+
+    /* FIXME: this is not exactly optimal solution since VirtualAlloc
+       has 64Kb granularity, but at least it guarantees us that the
+       memory is page aligned. */
+    if (!size) {
+        abort();
+    }
+    ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
+    trace_qemu_vmalloc(size, ptr);
+    return ptr;
+}
+
+void qemu_vfree(void *ptr)
+{
+    trace_qemu_vfree(ptr);
+    VirtualFree(ptr, 0, MEM_RELEASE);
+}
+
+void socket_set_nonblock(int fd)
+{
+    unsigned long opt = 1;
+    ioctlsocket(fd, FIONBIO, &opt);
+}
+
+int inet_aton(const char *cp, struct in_addr *ia)
+{
+    uint32_t addr = inet_addr(cp);
+    if (addr == 0xffffffff) {
+       return 0;
+    }
+    ia->s_addr = addr;
+    return 1;
+}
+
+void qemu_set_cloexec(int fd)
+{
+}
+
+/* mingw32 needs ffs for compilations without optimization. */
+int ffs(int i)
+{
+    /* Use gcc's builtin ffs. */
+    return __builtin_ffs(i);
+}
+
+/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
+#define _W32_FT_OFFSET (116444736000000000ULL)
+
+int qemu_gettimeofday(qemu_timeval *tp)
+{
+  union {
+    unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
+    FILETIME ft;
+  }  _now;
+
+  if(tp) {
+      GetSystemTimeAsFileTime (&_now.ft);
+      tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
+      tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
+  }
+  /* Always return 0 as per Open Group Base Specifications Issue 6.
+     Do not set errno on error.  */
+  return 0;
+}
index ec5e2e1c8c0a426a49e76a093d083fe504ad544d..3172cf789637230d4847058fc9d51f7ee61ab88c 100644 (file)
@@ -7,10 +7,6 @@
 - The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is
   available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm.
 
-- video.x is a PowerMac NDRV compatible driver for a VGA frame
-  buffer. It comes from the Mac-on-Linux project
-  (http://www.maconlinux.org/).
-
 - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
   firmware implementation. The goal is to implement a 100% IEEE
   1275-1994 (referred to as Open Firmware) compliant firmware.
index d0d4b6aa43b8f306062797b8e53ce469f8c2820f..f79c342264ebfce9b393d5809079cb4ec3c3a899 100644 (file)
Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ
diff --git a/pc-bios/video.x b/pc-bios/video.x
deleted file mode 100644 (file)
index 761aa0c..0000000
Binary files a/pc-bios/video.x and /dev/null differ
index 7b862b5400377b932c374de0fc9eb049e7520330..fa5494db8ceb683d037e969df5f0c1c7c753610a 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "qemu-queue.h"
 #include "osdep.h"
+#include "sysemu.h"
 #include "qemu-common.h"
 #include "trace.h"
 #include "block_int.h"
index 81aafa0a49441ba09231d0ac2df23ba32e151357..21fc3a5308f5beca7b0ed1f2a5e2e35069bfe095 100644 (file)
@@ -18,11 +18,6 @@ typedef struct QEMUFile QEMUFile;
 typedef struct QEMUBH QEMUBH;
 typedef struct DeviceState DeviceState;
 
-/* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that
-   cannot include the following headers without conflicts. This condition has
-   to be removed once dyngen is gone. */
-#ifndef __DYNGEN_EXEC_H__
-
 /* we put basic includes here to avoid repeating them in device drivers */
 #include <stdlib.h>
 #include <stdio.h>
@@ -86,6 +81,9 @@ struct iovec {
 #define GCC_FMT_ATTR(n, m)
 #endif
 
+typedef int (*fprintf_function)(FILE *f, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
 #ifdef _WIN32
 #define fsync _commit
 #define lseek _lseeki64
@@ -138,8 +136,6 @@ void qemu_bh_delete(QEMUBH *bh);
 int qemu_bh_poll(void);
 void qemu_bh_update_timeout(int *timeout);
 
-uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c);
-
 void qemu_get_timedate(struct tm *tm, int offset);
 int qemu_timedate_diff(struct tm *tm);
 
@@ -174,6 +170,12 @@ const char *path(const char *pathname);
 #define qemu_isascii(c)                isascii((unsigned char)(c))
 #define qemu_toascii(c)                toascii((unsigned char)(c))
 
+#ifdef _WIN32
+/* ffs() in oslib-win32.c for WIN32, strings.h for the rest of the world */
+int ffs(int i);
+#endif
+
+void *qemu_oom_check(void *ptr);
 void *qemu_malloc(size_t size);
 void *qemu_realloc(void *ptr, size_t size);
 void *qemu_mallocz(size_t size);
@@ -235,6 +237,10 @@ typedef struct PCIHostState PCIHostState;
 typedef struct PCIExpressHost PCIExpressHost;
 typedef struct PCIBus PCIBus;
 typedef struct PCIDevice PCIDevice;
+typedef struct PCIExpressDevice PCIExpressDevice;
+typedef struct PCIBridge PCIBridge;
+typedef struct PCIEPort PCIEPort;
+typedef struct PCIESlot PCIESlot;
 typedef struct SerialState SerialState;
 typedef struct IRQState *qemu_irq;
 typedef struct PCMCIACardState PCMCIACardState;
@@ -316,8 +322,30 @@ static inline uint8_t from_bcd(uint8_t val)
     return ((val >> 4) * 10) + (val & 0x0f);
 }
 
-#include "module.h"
+/* compute with 96 bit intermediate result: (a*b)/c */
+static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+    union {
+        uint64_t ll;
+        struct {
+#ifdef HOST_WORDS_BIGENDIAN
+            uint32_t high, low;
+#else
+            uint32_t low, high;
+#endif
+        } l;
+    } u, res;
+    uint64_t rl, rh;
+
+    u.ll = a;
+    rl = (uint64_t)u.l.low * (uint64_t)b;
+    rh = (uint64_t)u.l.high * (uint64_t)b;
+    rh += (rl >> 32);
+    res.l.high = rh / c;
+    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+    return res.ll;
+}
 
-#endif /* dyngen-exec.h hack */
+#include "module.h"
 
 #endif
index 6d3e5f8e693a3e09f4a1c53492682e7e0fcd416c..6c7176f8b4643fe120f9abe4bf0258a41d558f05 100644 (file)
@@ -28,9 +28,9 @@ STEXI
 ETEXI
 
 DEF("convert", img_convert,
-    "convert [-c] [-f fmt] [-O output_fmt] [-o options] filename [filename2 [...]] output_filename")
+    "convert [-c] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
 STEXI
-@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 ETEXI
 
 DEF("info", img_info,
index 578b8ebe8cc6497f3679b68983bce7d3f96924ab..fa77ac0dbe87f6fb36d9e6a0b1abd62b752826a7 100644 (file)
@@ -24,6 +24,7 @@
 #include "qemu-common.h"
 #include "qemu-option.h"
 #include "osdep.h"
+#include "sysemu.h"
 #include "block_int.h"
 #include <stdio.h>
 
@@ -645,14 +646,16 @@ static int img_convert(int argc, char **argv)
     const uint8_t *buf1;
     BlockDriverInfo bdi;
     QEMUOptionParameter *param = NULL, *create_options = NULL;
+    QEMUOptionParameter *out_baseimg_param;
     char *options = NULL;
+    const char *snapshot_name = NULL;
 
     fmt = NULL;
     out_fmt = "raw";
     out_baseimg = NULL;
     flags = 0;
     for(;;) {
-        c = getopt(argc, argv, "f:O:B:hce6o:");
+        c = getopt(argc, argv, "f:O:B:s:hce6o:");
         if (c == -1)
             break;
         switch(c) {
@@ -680,6 +683,9 @@ static int img_convert(int argc, char **argv)
         case 'o':
             options = optarg;
             break;
+        case 's':
+            snapshot_name = optarg;
+            break;
         }
     }
 
@@ -711,6 +717,19 @@ static int img_convert(int argc, char **argv)
         total_sectors += bs_sectors;
     }
 
+    if (snapshot_name != NULL) {
+        if (bs_n > 1) {
+            error("No support for concatenating multiple snapshot\n");
+            ret = -1;
+            goto out;
+        }
+        if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
+            error("Failed to load snapshot\n");
+            ret = -1;
+            goto out;
+        }
+    }
+
     /* Find driver and parse its options */
     drv = bdrv_find_format(out_fmt);
     if (!drv) {
@@ -752,6 +771,12 @@ static int img_convert(int argc, char **argv)
         goto out;
     }
 
+    /* Get backing file name if -o backing_file was used */
+    out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
+    if (out_baseimg_param) {
+        out_baseimg = out_baseimg_param->value.s;
+    }
+
     /* Check if compression is supported */
     if (flags & BLOCK_FLAG_COMPRESS) {
         QEMUOptionParameter *encryption =
index c1b1f2717ef004496b6f52480fa1e4f3c8e3346b..1b90ddbcfce7ae05631ff99a233bbd790c6a2f77 100644 (file)
@@ -77,9 +77,9 @@ it doesn't need to be specified separately in this case.
 
 Commit the changes recorded in @var{filename} in its base image.
 
-@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 
-Convert the disk image @var{filename} to disk image @var{output_filename}
+Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename}
 using format @var{output_fmt}. It can be optionally compressed (@code{-c}
 option) or use any format specific options like encryption (@code{-o} option).
 
index b4e5cc8fe623b395479ba8bdd342e45489e9d8b7..ff353ebba358885764db7d77dfa7fc43fbf223a2 100644 (file)
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1442,6 +1442,44 @@ static const cmdinfo_t alloc_cmd = {
        .oneline        = "checks if a sector is present in the file",
 };
 
+static int
+map_f(int argc, char **argv)
+{
+       int64_t offset;
+       int64_t nb_sectors;
+       char s1[64];
+       int num, num_checked;
+       int ret;
+       const char *retstr;
+
+       offset = 0;
+       nb_sectors = bs->total_sectors;
+
+       do {
+               num_checked = MIN(nb_sectors, INT_MAX);
+               ret = bdrv_is_allocated(bs, offset, num_checked, &num);
+               retstr = ret ? "    allocated" : "not allocated";
+               cvtstr(offset << 9ULL, s1, sizeof(s1));
+               printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n",
+                               offset << 9ULL, num, num_checked, retstr, s1, ret);
+
+               offset += num;
+               nb_sectors -= num;
+       } while(offset < bs->total_sectors);
+
+       return 0;
+}
+
+static const cmdinfo_t map_cmd = {
+       .name           = "map",
+       .argmin         = 0,
+       .argmax         = 0,
+       .cfunc          = map_f,
+       .args           = "",
+       .oneline        = "prints the allocated areas of a file",
+};
+
+
 static int
 close_f(int argc, char **argv)
 {
@@ -1680,6 +1718,7 @@ int main(int argc, char **argv)
        add_command(&length_cmd);
        add_command(&info_cmd);
        add_command(&alloc_cmd);
+       add_command(&map_cmd);
 
        add_args_command(init_args_command);
        add_check_command(init_check_command);
index ecffb676e267719dd21d67f0738368a77b1788a6..28fb05a481f6288427907d78b68a4dd39dd11278 100644 (file)
 #include "trace.h"
 #include <stdlib.h>
 
-static void *oom_check(void *ptr)
-{
-    if (ptr == NULL) {
-        abort();
-    }
-    return ptr;
-}
-
 void qemu_free(void *ptr)
 {
     trace_qemu_free(ptr);
@@ -54,7 +46,7 @@ void *qemu_malloc(size_t size)
     if (!size && !allow_zero_malloc()) {
         abort();
     }
-    ptr = oom_check(malloc(size ? size : 1));
+    ptr = qemu_oom_check(malloc(size ? size : 1));
     trace_qemu_malloc(size, ptr);
     return ptr;
 }
@@ -65,7 +57,7 @@ void *qemu_realloc(void *ptr, size_t size)
     if (!size && !allow_zero_malloc()) {
         abort();
     }
-    newptr = oom_check(realloc(ptr, size ? size : 1));
+    newptr = qemu_oom_check(realloc(ptr, size ? size : 1));
     trace_qemu_realloc(ptr, size, newptr);
     return newptr;
 }
@@ -75,7 +67,7 @@ void *qemu_mallocz(size_t size)
     if (!size && !allow_zero_malloc()) {
         abort();
     }
-    return oom_check(calloc(1, size ? size : 1));
+    return qemu_oom_check(calloc(1, size ? size : 1));
 }
 
 char *qemu_strdup(const char *str)
index ed5c058bc3e551e648cb669b8257f533143b3042..353f87813f8d8f4d558fe8962fbf9749e54c1fe0 100644 (file)
@@ -36,4 +36,7 @@ void os_setup_signal_handling(void);
 void os_daemonize(void);
 void os_setup_post(void);
 
+typedef struct timeval qemu_timeval;
+#define qemu_gettimeofday(tp) gettimeofday(tp, NULL)
+
 #endif
index 2ff9f45a6c725c2f9c624036c6def98a1eb4d51d..1a07e5e264a98a16791b79244ce0afda48461b85 100644 (file)
@@ -45,12 +45,19 @@ void os_host_main_loop_wait(int *timeout);
 static inline void os_setup_signal_handling(void) {}
 static inline void os_daemonize(void) {}
 static inline void os_setup_post(void) {}
-/* Win32 doesn't support line-buffering and requires size >= 2 */
-static inline void os_set_line_buffering(void) {}
+void os_set_line_buffering(void);
 static inline void os_set_proc_name(const char *dummy) {}
 
 #if !defined(EPROTONOSUPPORT)
 # define EPROTONOSUPPORT EINVAL
 #endif
 
+int setenv(const char *name, const char *value, int overwrite);
+
+typedef struct {
+    long tv_sec;
+    long tv_usec;
+} qemu_timeval;
+int qemu_gettimeofday(qemu_timeval *tp);
+
 #endif
diff --git a/qemu-timer-common.c b/qemu-timer-common.c
new file mode 100644 (file)
index 0000000..fff4399
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-timer.h"
+
+/***********************************************************/
+/* real time host monotonic timer */
+
+#ifdef _WIN32
+
+int64_t clock_freq;
+
+static void __attribute__((constructor)) init_get_clock(void)
+{
+    LARGE_INTEGER freq;
+    int ret;
+    ret = QueryPerformanceFrequency(&freq);
+    if (ret == 0) {
+        fprintf(stderr, "Could not calibrate ticks\n");
+        exit(1);
+    }
+    clock_freq = freq.QuadPart;
+}
+
+#else
+
+int use_rt_clock;
+
+static void __attribute__((constructor)) init_get_clock(void)
+{
+    use_rt_clock = 0;
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
+    || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+    {
+        struct timespec ts;
+        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+            use_rt_clock = 1;
+        }
+    }
+#endif
+}
+#endif
index bc5f207bb6e5c4cac2edb686286235f7464f772b..95814af798392a77486677da19c3092b78387f60 100644 (file)
@@ -64,78 +64,6 @@ int64_t qemu_icount_bias;
 static QEMUTimer *icount_rt_timer;
 static QEMUTimer *icount_vm_timer;
 
-
-/***********************************************************/
-/* real time host monotonic timer */
-
-
-static int64_t get_clock_realtime(void)
-{
-    struct timeval tv;
-
-    gettimeofday(&tv, NULL);
-    return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
-}
-
-#ifdef WIN32
-
-static int64_t clock_freq;
-
-static void init_get_clock(void)
-{
-    LARGE_INTEGER freq;
-    int ret;
-    ret = QueryPerformanceFrequency(&freq);
-    if (ret == 0) {
-        fprintf(stderr, "Could not calibrate ticks\n");
-        exit(1);
-    }
-    clock_freq = freq.QuadPart;
-}
-
-static int64_t get_clock(void)
-{
-    LARGE_INTEGER ti;
-    QueryPerformanceCounter(&ti);
-    return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq);
-}
-
-#else
-
-static int use_rt_clock;
-
-static void init_get_clock(void)
-{
-    use_rt_clock = 0;
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
-    || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-    {
-        struct timespec ts;
-        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
-            use_rt_clock = 1;
-        }
-    }
-#endif
-}
-
-static int64_t get_clock(void)
-{
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
-       || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-    if (use_rt_clock) {
-        struct timespec ts;
-        clock_gettime(CLOCK_MONOTONIC, &ts);
-        return ts.tv_sec * 1000000000LL + ts.tv_nsec;
-    } else
-#endif
-    {
-        /* XXX: using gettimeofday leads to problems if the date
-           changes, so it should be avoided. */
-        return get_clock_realtime();
-    }
-}
-#endif
-
 /***********************************************************/
 /* guest cycle counter */
 
@@ -614,7 +542,6 @@ int64_t qemu_get_clock_ns(QEMUClock *clock)
 
 void init_clocks(void)
 {
-    init_get_clock();
     rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME);
     vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL);
     host_clock = qemu_new_clock(QEMU_CLOCK_HOST);
index 1494f7940612fb97c85a886b939686931b446e86..8cd8f8368ad50c1802bf9b05a59f008370f54af3 100644 (file)
@@ -2,6 +2,13 @@
 #define QEMU_TIMER_H
 
 #include "qemu-common.h"
+#include <time.h>
+#include <sys/time.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <mmsystem.h>
+#endif
 
 /* timers */
 
@@ -52,6 +59,49 @@ static inline int64_t get_ticks_per_sec(void)
     return 1000000000LL;
 }
 
+/* real time host monotonic timer */
+static inline int64_t get_clock_realtime(void)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
+}
+
+/* Warning: don't insert tracepoints into these functions, they are
+   also used by simpletrace backend and tracepoints would cause
+   an infinite recursion! */
+#ifdef _WIN32
+extern int64_t clock_freq;
+
+static inline int64_t get_clock(void)
+{
+    LARGE_INTEGER ti;
+    QueryPerformanceCounter(&ti);
+    return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq);
+}
+
+#else
+
+extern int use_rt_clock;
+
+static inline int64_t get_clock(void)
+{
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
+    || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+    if (use_rt_clock) {
+        struct timespec ts;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+    } else
+#endif
+    {
+        /* XXX: using gettimeofday leads to problems if the date
+           changes, so it should be avoided. */
+        return get_clock_realtime();
+    }
+}
+#endif
 
 void qemu_get_timer(QEMUFile *f, QEMUTimer *ts);
 void qemu_put_timer(QEMUFile *f, QEMUTimer *ts);
index b39af86e0105fc165e03715ecfc3ff6ed63531b3..392e1c9505bc5dfdc17d3c00ce1d7989428972f1 100644 (file)
@@ -15,6 +15,7 @@
 #include "monitor.h"
 #include "qemu-timer.h"
 #include "qemu-log.h"
+#include "sysemu.h"
 
 #include <sys/time.h>
 
@@ -110,10 +111,3 @@ int qemu_set_fd_handler2(int fd,
 {
     return 0;
 }
-
-int64_t qemu_get_clock(QEMUClock *clock)
-{
-    qemu_timeval tv;
-    qemu_gettimeofday(&tv);
-    return (tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000)) / 1000000;
-}
index 17d3e46511aeedc9f09a8216d194d749187b80aa..0ff9051f756ba739bc2edca77925191c3c6cbc2f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 17d3e46511aeedc9f09a8216d194d749187b80aa
+Subproject commit 0ff9051f756ba739bc2edca77925191c3c6cbc2f
index c843a131e8c652f3aab73dd06d5794c7c86a4395..6dac7773d5de6aa8337061d7f874a83cae37cce1 100644 (file)
--- a/rules.mak
+++ b/rules.mak
@@ -42,6 +42,15 @@ cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \
 VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi
 set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1)))
 
+# find-in-path
+# Usage: $(call find-in-path, prog)
+# Looks in the PATH if the argument contains no slash, else only considers one
+# specific directory.  Returns an # empty string if the program doesn't exist
+# there.
+find-in-path = $(if $(find-string /, $1), \
+        $(wildcard $1), \
+        $(wildcard $(patsubst %, %/$1, $(subst :, ,$(PATH)))))
+
 # Generate timestamp files for .h include files
 
 %.h: %.h-timestamp
index 6fa7a5fe8e41ae1039754287c059ddb66d06c3f2..4e49765816d03e0b7b99d90c69bbfb753c7a1b02 100644 (file)
--- a/savevm.c
+++ b/savevm.c
@@ -675,6 +675,27 @@ uint64_t qemu_get_be64(QEMUFile *f)
     return v;
 }
 
+/* bool */
+
+static int get_bool(QEMUFile *f, void *pv, size_t size)
+{
+    bool *v = pv;
+    *v = qemu_get_byte(f);
+    return 0;
+}
+
+static void put_bool(QEMUFile *f, void *pv, size_t size)
+{
+    bool *v = pv;
+    qemu_put_byte(f, *v);
+}
+
+const VMStateInfo vmstate_info_bool = {
+    .name = "bool",
+    .get  = get_bool,
+    .put  = put_bool,
+};
+
 /* 8 bit int */
 
 static int get_int8(QEMUFile *f, void *pv, size_t size)
@@ -1615,10 +1636,10 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
     while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
         char idstr[256];
         int ret;
-        uint8_t version_id, subsection, len;
+        uint8_t version_id, len;
         const VMStateDescription *sub_vmsd;
 
-        subsection = qemu_get_byte(f);
+        qemu_get_byte(f); /* subsection */
         len = qemu_get_byte(f);
         qemu_get_buffer(f, (uint8_t *)idstr, len);
         idstr[len] = 0;
index f849e429145d3d193b86d6cd373428dd47ed0fb4..9ea0d1f98443fcd5b801a1d33d88997fe41395b5 100644 (file)
@@ -12,6 +12,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <time.h>
+#include "qemu-timer.h"
 #include "trace.h"
 
 /** Trace file header event ID */
@@ -140,20 +141,13 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
                   uint64_t x4, uint64_t x5, uint64_t x6)
 {
     TraceRecord *rec = &trace_buf[trace_idx];
-    struct timespec ts;
-
-    /* TODO Windows?  It would be good to use qemu-timer here but that isn't
-     * linked into qemu-tools.  Also we should avoid recursion in the tracing
-     * code, therefore it is useful to be self-contained.
-     */
-    clock_gettime(CLOCK_MONOTONIC, &ts);
 
     if (!trace_list[event].state) {
         return;
     }
 
     rec->event = event;
-    rec->timestamp_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec;
+    rec->timestamp_ns = get_clock();
     rec->x1 = x1;
     rec->x2 = x2;
     rec->x3 = x3;
@@ -214,9 +208,11 @@ void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char
     unsigned int i;
 
     for (i = 0; i < trace_idx; i++) {
-        stream_printf(stream, "Event %lu : %lx %lx %lx %lx %lx\n",
+        stream_printf(stream, "Event %" PRIu64 " : %" PRIx64 " %" PRIx64
+                      " %" PRIx64 " %" PRIx64 " %" PRIx64 " %" PRIx64 "\n",
                       trace_buf[i].event, trace_buf[i].x1, trace_buf[i].x2,
-                      trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5);
+                      trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5,
+                      trace_buf[i].x6);
     }
 }
 
@@ -246,12 +242,14 @@ static TraceEvent* find_trace_event_by_name(const char *tname)
     return NULL; /* indicates end of list reached without a match */
 }
 
-void st_change_trace_event_state(const char *tname, bool tstate)
+bool st_change_trace_event_state(const char *tname, bool tstate)
 {
     TraceEvent *tp;
 
     tp = find_trace_event_by_name(tname);
     if (tp) {
         tp->state = tstate;
+        return true;
     }
+    return false;
 }
index cf3589774b438f31214837eec14de25555277281..72614ec1d159fc57f706875cca100e8290bb2945 100644 (file)
@@ -31,7 +31,7 @@ void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t
 void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
 void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
 void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
-void st_change_trace_event_state(const char *tname, bool tstate);
+bool st_change_trace_event_state(const char *tname, bool tstate);
 void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
 void st_set_trace_file_enabled(bool enable);
 bool st_set_trace_file(const char *file);
index c2cf1682d0242a033928ea9baae4e78aad71adb8..553a72709f99901b409085dd8ea5581985024405 100755 (executable)
@@ -19,7 +19,7 @@ header_version  = 0
 
 trace_fmt = '=QQQQQQQQ'
 trace_len = struct.calcsize(trace_fmt)
-event_re  = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\)\s+"([^"]*)"')
+event_re  = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\).*')
 
 def err(msg):
     sys.stderr.write(msg + '\n')
@@ -39,7 +39,7 @@ def parse_events(fobj):
         if m is None:
             continue
 
-        disable, name, args, fmt = m.groups()
+        disable, name, args = m.groups()
         events[event_num] = (name,) + get_argnames(args)
         event_num += 1
     return events
index b6d21601d5a7a9e692a3833161ea45891d07429b..3ba4478c8e77202dc863a1d7e025621dfa53b507 100644 (file)
@@ -537,8 +537,7 @@ void do_interrupt (CPUState *env)
 }
 #endif
 
-void cpu_dump_state (CPUState *env, FILE *f,
-                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                      int flags)
 {
     static const char *linux_reg_names[] = {
index 39c4a0e987c3d1c9b910dd1f6938f81ab10c499d..b87c605f7f7e63e1419ce2fd85d4d860d53dc699 100644 (file)
@@ -25,6 +25,8 @@
 
 #define CPUState struct CPUARMState
 
+#include "config.h"
+#include "qemu-common.h"
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -353,7 +355,7 @@ static inline int arm_feature(CPUARMState *env, int feature)
     return (env->features & (1u << feature)) != 0;
 }
 
-void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
 /* Interface between CPU and Interrupt controller.  */
 void armv7m_nvic_set_pending(void *opaque, int irq);
index 2dd64d94d855d89c67e42806fefbea04eb99c4df..996d40d1858cc4478a9f784b4f8b7d005b21a1e9 100644 (file)
@@ -348,7 +348,7 @@ static const struct arm_cpu_t arm_cpu_names[] = {
     { 0, NULL}
 };
 
-void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
     int i;
 
index 6fcdd7e544dca336ca59acba3203a79ef5c6a8ca..99464ab73003f47278158b0d43bb04f9795b6afb 100644 (file)
@@ -9262,8 +9262,7 @@ static const char *cpu_mode_names[16] = {
   "???", "???", "???", "und", "???", "???", "???", "sys"
 };
 
-void cpu_dump_state(CPUState *env, FILE *f,
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     int flags)
 {
     int i;
index e1d48ed77ebc1806fd7b30a0598b4fe12de48b25..d9087759d303ece8a915d56eb72d3f4b37dea0b0 100644 (file)
@@ -263,6 +263,6 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 }
 
 #define cpu_list cris_cpu_list
-void cris_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
 #endif
index a60da94f309628df4f4bf9815c769aa1cddd30bf..be9eb06fd06a29fd19e4e2bd3db2cc13d2dde281 100644 (file)
@@ -164,7 +164,9 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
 
                        D_LOG("tlb flush vaddr=%x v=%d pc=%x\n", 
                                  vaddr, tlb_v, env->pc);
-                       tlb_flush_page(env, vaddr);
+                       if (tlb_v) {
+                               tlb_flush_page(env, vaddr);
+                       }
                }
        }
 #endif
index 836136921408ea6aab38f60d5b73f303154a87fb..4e4606cb2566c73ea77a18099b5e7884a95c3f1b 100644 (file)
@@ -3426,8 +3426,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-void cpu_dump_state (CPUState *env, FILE *f,
-                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                      int flags)
 {
        int i;
@@ -3480,7 +3479,7 @@ struct
        {32, "crisv32"},
 };
 
-void cris_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
     unsigned int i;
 
index 14e590da3c4d16832e9f8ccd930422db5ee2cc1a..6944827a574a0d47f1fe4ecc8b5e408a9235b995 100644 (file)
@@ -108,16 +108,15 @@ static unsigned int crisv10_post_memaddr(DisasContext *dc, unsigned int size)
 static int dec10_prep_move_m(DisasContext *dc, int s_ext, int memsize,
                            TCGv dst)
 {
-    unsigned int rs, rd;
+    unsigned int rs;
     uint32_t imm;
     int is_imm;
     int insn_len = 0;
 
     rs = dc->src;
-    rd = dc->dst;
     is_imm = rs == 15 && !(dc->tb_flags & PFIX_FLAG);
     LOG_DIS("rs=%d rd=%d is_imm=%d mode=%d pfix=%d\n",
-             rs, rd, is_imm, dc->mode, dc->tb_flags & PFIX_FLAG);
+             rs, dc->dst, is_imm, dc->mode, dc->tb_flags & PFIX_FLAG);
 
     /* Load [$rs] onto T1.  */
     if (is_imm) {
index 1144d4e387d15f1f979dddaae69a8206dc854cce..2440d6536c402a778a4ab17b5ba39ff925057baf 100644 (file)
@@ -20,6 +20,7 @@
 #define CPU_I386_H
 
 #include "config.h"
+#include "qemu-common.h"
 
 #ifdef TARGET_X86_64
 #define TARGET_LONG_BITS 64
 #define PG_ERROR_RSVD_MASK 0x08
 #define PG_ERROR_I_D_MASK  0x10
 
-#define MCG_CTL_P      (1UL<<8)   /* MCG_CAP register available */
+#define MCG_CTL_P      (1ULL<<8)   /* MCG_CAP register available */
+#define MCG_SER_P      (1ULL<<24) /* MCA recovery/new status bits */
 
-#define MCE_CAP_DEF    MCG_CTL_P
+#define MCE_CAP_DEF    (MCG_CTL_P|MCG_SER_P)
 #define MCE_BANKS_DEF  10
 
+#define MCG_STATUS_RIPV        (1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV        (1ULL<<1)   /* ip points to correct instruction */
 #define MCG_STATUS_MCIP        (1ULL<<2)   /* machine check in progress */
 
 #define MCI_STATUS_VAL (1ULL<<63)  /* valid error */
 #define MCI_STATUS_OVER        (1ULL<<62)  /* previous errors lost */
 #define MCI_STATUS_UC  (1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN  (1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
+#define MCI_STATUS_PCC (1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S   (1ULL<<56)  /* Signaled machine check */
+#define MCI_STATUS_AR  (1ULL<<55)  /* Action required */
+
+/* MISC register defines */
+#define MCM_ADDR_SEGOFF        0       /* segment offset */
+#define MCM_ADDR_LINEAR        1       /* linear address */
+#define MCM_ADDR_PHYS  2       /* physical address */
+#define MCM_ADDR_MEM   3       /* memory address */
+#define MCM_ADDR_GENERIC 7     /* generic */
 
 #define MSR_IA32_TSC                    0x10
 #define MSR_IA32_APICBASE               0x1b
 #define CPUID_EXT3_IBS     (1 << 10)
 #define CPUID_EXT3_SKINIT  (1 << 12)
 
+#define CPUID_SVM_NPT          (1 << 0)
+#define CPUID_SVM_LBRV         (1 << 1)
+#define CPUID_SVM_SVMLOCK      (1 << 2)
+#define CPUID_SVM_NRIPSAVE     (1 << 3)
+#define CPUID_SVM_TSCSCALE     (1 << 4)
+#define CPUID_SVM_VMCBCLEAN    (1 << 5)
+#define CPUID_SVM_FLUSHASID    (1 << 6)
+#define CPUID_SVM_DECODEASSIST (1 << 7)
+#define CPUID_SVM_PAUSEFILTER  (1 << 10)
+#define CPUID_SVM_PFTHRESHOLD  (1 << 12)
+
 #define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */
 #define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */
 #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
@@ -702,6 +730,7 @@ typedef struct CPUX86State {
     uint8_t has_error_code;
     uint32_t sipi_vector;
     uint32_t cpuid_kvm_features;
+    uint32_t cpuid_svm_features;
     
     /* in order to simplify APIC support, we leave this pointer to the
        user */
@@ -728,8 +757,7 @@ typedef struct CPUX86State {
 CPUX86State *cpu_x86_init(const char *cpu_model);
 int cpu_x86_exec(CPUX86State *s);
 void cpu_x86_close(CPUX86State *s);
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
-                   const char *optarg);
+void x86_cpu_list (FILE *f, fprintf_function cpu_fprintf, const char *optarg);
 void x86_cpudef_setup(void);
 
 int cpu_get_pic_interrupt(CPUX86State *s);
index 04ba8d5152ac6e804c294fa8c6244e5c67df2797..650a7192de3d68b39aca4e396f2717de733e00d7 100644 (file)
@@ -79,6 +79,17 @@ static const char *kvm_feature_name[] = {
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 };
 
+static const char *svm_feature_name[] = {
+    "npt", "lbrv", "svm_lock", "nrip_save",
+    "tsc_scale", "vmcb_clean",  "flushbyasid", "decodeassists",
+    NULL, NULL, "pause_filter", NULL,
+    "pfthreshold", NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+};
+
 /* collects per-function cpuid data
  */
 typedef struct model_features_t {
@@ -192,13 +203,15 @@ static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
                                     uint32_t *ext_features,
                                     uint32_t *ext2_features,
                                     uint32_t *ext3_features,
-                                    uint32_t *kvm_features)
+                                    uint32_t *kvm_features,
+                                    uint32_t *svm_features)
 {
     if (!lookup_feature(features, flagname, NULL, feature_name) &&
         !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
         !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
         !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
-        !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name))
+        !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name) &&
+        !lookup_feature(svm_features, flagname, NULL, svm_feature_name))
             fprintf(stderr, "CPU feature %s not found\n", flagname);
 }
 
@@ -210,7 +223,8 @@ typedef struct x86_def_t {
     int family;
     int model;
     int stepping;
-    uint32_t features, ext_features, ext2_features, ext3_features, kvm_features;
+    uint32_t features, ext_features, ext2_features, ext3_features;
+    uint32_t kvm_features, svm_features;
     uint32_t xlevel;
     char model_id[48];
     int vendor_override;
@@ -253,6 +267,7 @@ typedef struct x86_def_t {
           CPUID_EXT2_PDPE1GB */
 #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
           CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
+#define TCG_SVM_FEATURES 0
 
 /* maintains list of cpu model definitions
  */
@@ -305,6 +320,7 @@ static x86_def_t builtin_x86_defs[] = {
                     CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
         .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
             CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
+        .svm_features = CPUID_SVM_NPT | CPUID_SVM_LBRV,
         .xlevel = 0x8000001A,
         .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
     },
@@ -505,6 +521,15 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
     cpu_x86_fill_model_id(x86_cpu_def->model_id);
     x86_cpu_def->vendor_override = 0;
 
+
+    /*
+     * Every SVM feature requires emulation support in KVM - so we can't just
+     * read the host features here. KVM might even support SVM features not
+     * available on the host hardware. Just set all bits and mask out the
+     * unsupported ones later.
+     */
+    x86_cpu_def->svm_features = -1;
+
     return 0;
 }
 
@@ -560,8 +585,14 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 
     char *s = strdup(cpu_model);
     char *featurestr, *name = strtok(s, ",");
-    uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0, plus_kvm_features = 0;
-    uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0, minus_kvm_features = 0;
+    /* Features to be added*/
+    uint32_t plus_features = 0, plus_ext_features = 0;
+    uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
+    uint32_t plus_kvm_features = 0, plus_svm_features = 0;
+    /* Features to be removed */
+    uint32_t minus_features = 0, minus_ext_features = 0;
+    uint32_t minus_ext2_features = 0, minus_ext3_features = 0;
+    uint32_t minus_kvm_features = 0, minus_svm_features = 0;
     uint32_t numvalue;
 
     for (def = x86_defs; def; def = def->next)
@@ -579,16 +610,22 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
 
     add_flagname_to_bitmaps("hypervisor", &plus_features,
         &plus_ext_features, &plus_ext2_features, &plus_ext3_features,
-        &plus_kvm_features);
+        &plus_kvm_features, &plus_svm_features);
 
     featurestr = strtok(NULL, ",");
 
     while (featurestr) {
         char *val;
         if (featurestr[0] == '+') {
-            add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features, &plus_kvm_features);
+            add_flagname_to_bitmaps(featurestr + 1, &plus_features,
+                            &plus_ext_features, &plus_ext2_features,
+                            &plus_ext3_features, &plus_kvm_features,
+                            &plus_svm_features);
         } else if (featurestr[0] == '-') {
-            add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features, &minus_kvm_features);
+            add_flagname_to_bitmaps(featurestr + 1, &minus_features,
+                            &minus_ext_features, &minus_ext2_features,
+                            &minus_ext3_features, &minus_kvm_features,
+                            &minus_svm_features);
         } else if ((val = strchr(featurestr, '='))) {
             *val = 0; val++;
             if (!strcmp(featurestr, "family")) {
@@ -670,11 +707,13 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
     x86_cpu_def->ext2_features |= plus_ext2_features;
     x86_cpu_def->ext3_features |= plus_ext3_features;
     x86_cpu_def->kvm_features |= plus_kvm_features;
+    x86_cpu_def->svm_features |= plus_svm_features;
     x86_cpu_def->features &= ~minus_features;
     x86_cpu_def->ext_features &= ~minus_ext_features;
     x86_cpu_def->ext2_features &= ~minus_ext2_features;
     x86_cpu_def->ext3_features &= ~minus_ext3_features;
     x86_cpu_def->kvm_features &= ~minus_kvm_features;
+    x86_cpu_def->svm_features &= ~minus_svm_features;
     if (check_cpuid) {
         if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
             goto error;
@@ -723,8 +762,7 @@ static void listflags(char *buf, int bufsize, uint32_t fbits,
  * -?dump    output all model (x86_def_t) data
  * -?cpuid   list all recognized cpuid flag names
  */
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
-                  const char *optarg)
+void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
 {
     unsigned char model = !strcmp("?model", optarg);
     unsigned char dump = !strcmp("?dump", optarg);
@@ -788,6 +826,8 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
 {
     x86_def_t def1, *def = &def1;
 
+    memset(def, 0, sizeof(*def));
+
     if (cpu_x86_find_by_name(def, cpu_model) < 0)
         return -1;
     if (def->vendor1) {
@@ -814,6 +854,7 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
     env->cpuid_ext3_features = def->ext3_features;
     env->cpuid_xlevel = def->xlevel;
     env->cpuid_kvm_features = def->kvm_features;
+    env->cpuid_svm_features = def->svm_features;
     if (!kvm_enabled()) {
         env->cpuid_features &= TCG_FEATURES;
         env->cpuid_ext_features &= TCG_EXT_FEATURES;
@@ -823,6 +864,7 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
 #endif
             );
         env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
+        env->cpuid_svm_features &= TCG_SVM_FEATURES;
     }
     {
         const char *model_id = def->model_id;
@@ -1133,11 +1175,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                 *ecx |= 1 << 1;    /* CmpLegacy bit */
             }
         }
-
-        if (kvm_enabled()) {
-            /* Nested SVM not yet supported in upstream QEMU */
-            *ecx &= ~CPUID_EXT3_SVM;
-        }
         break;
     case 0x80000002:
     case 0x80000003:
@@ -1182,10 +1219,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         }
         break;
     case 0x8000000A:
-        *eax = 0x00000001; /* SVM Revision */
-        *ebx = 0x00000010; /* nr of ASIDs */
-        *ecx = 0;
-        *edx = 0; /* optional features */
+       if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
+               *eax = 0x00000001; /* SVM Revision */
+               *ebx = 0x00000010; /* nr of ASIDs */
+               *ecx = 0;
+               *edx = env->cpuid_svm_features; /* optional features */
+       } else {
+               *eax = 0;
+               *ebx = 0;
+               *ecx = 0;
+               *edx = 0;
+       }
         break;
     default:
         /* reserved values: zero */
index e13434097f095b0f39e952e46ce6151cfab3474e..26ea1e58e08fb580f52a1f0b6516673b11aea2d1 100644 (file)
@@ -27,6 +27,7 @@
 #include "exec-all.h"
 #include "qemu-common.h"
 #include "kvm.h"
+#include "kvm_x86.h"
 
 //#define DEBUG_MMU
 
@@ -168,8 +169,7 @@ static const char *cc_op_str[] = {
 };
 
 static void
-cpu_x86_dump_seg_cache(CPUState *env, FILE *f,
-                       int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+cpu_x86_dump_seg_cache(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                        const char *name, struct SegmentCache *sc)
 {
 #ifdef TARGET_X86_64
@@ -223,8 +223,7 @@ done:
     cpu_fprintf(f, "\n");
 }
 
-void cpu_dump_state(CPUState *env, FILE *f,
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     int flags)
 {
     int eflags, i, nb;
@@ -334,9 +333,11 @@ void cpu_dump_state(CPUState *env, FILE *f,
                     (uint32_t)env->cr[2],
                     (uint32_t)env->cr[3],
                     (uint32_t)env->cr[4]);
-        for(i = 0; i < 4; i++)
-            cpu_fprintf(f, "DR%d=%08x ", i, env->dr[i]);
-        cpu_fprintf(f, "\nDR6=%08x DR7=%08x\n", env->dr[6], env->dr[7]);
+        for(i = 0; i < 4; i++) {
+            cpu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
+        }
+        cpu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
+                    env->dr[6], env->dr[7]);
     }
     if (flags & X86_DUMP_CCOP) {
         if ((unsigned)env->cc_op < CC_OP_NB)
@@ -1030,6 +1031,11 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
     if (bank >= bank_num || !(status & MCI_STATUS_VAL))
         return;
 
+    if (kvm_enabled()) {
+        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, 0);
+        return;
+    }
+
     /*
      * if MSR_MCG_CTL is not all 1s, the uncorrected error
      * reporting is disabled
index a33d2fad6a89281efef249238f772d746f5b5c3d..ae0a034ab0f2048adfe3aaa4148f0e5263f7b22b 100644 (file)
@@ -15,6 +15,7 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <sys/utsname.h>
 
 #include <linux/kvm.h>
 
@@ -27,6 +28,7 @@
 #include "hw/pc.h"
 #include "hw/apic.h"
 #include "ioport.h"
+#include "kvm_x86.h"
 
 #ifdef CONFIG_KVM_PARA
 #include <linux/kvm_para.h>
 #define MSR_KVM_WALL_CLOCK  0x11
 #define MSR_KVM_SYSTEM_TIME 0x12
 
+#ifndef BUS_MCEERR_AR
+#define BUS_MCEERR_AR 4
+#endif
+#ifndef BUS_MCEERR_AO
+#define BUS_MCEERR_AO 5
+#endif
+
+static int lm_capable_kernel;
+
 #ifdef KVM_CAP_EXT_CPUID
 
 static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
@@ -167,6 +178,120 @@ static int get_para_features(CPUState *env)
 }
 #endif
 
+#ifdef KVM_CAP_MCE
+static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
+                                     int *max_banks)
+{
+    int r;
+
+    r = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_MCE);
+    if (r > 0) {
+        *max_banks = r;
+        return kvm_ioctl(s, KVM_X86_GET_MCE_CAP_SUPPORTED, mce_cap);
+    }
+    return -ENOSYS;
+}
+
+static int kvm_setup_mce(CPUState *env, uint64_t *mcg_cap)
+{
+    return kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, mcg_cap);
+}
+
+static int kvm_set_mce(CPUState *env, struct kvm_x86_mce *m)
+{
+    return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, m);
+}
+
+static int kvm_get_msr(CPUState *env, struct kvm_msr_entry *msrs, int n)
+{
+    struct kvm_msrs *kmsrs = qemu_malloc(sizeof *kmsrs + n * sizeof *msrs);
+    int r;
+
+    kmsrs->nmsrs = n;
+    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
+    r = kvm_vcpu_ioctl(env, KVM_GET_MSRS, kmsrs);
+    memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
+    free(kmsrs);
+    return r;
+}
+
+/* FIXME: kill this and kvm_get_msr, use env->mcg_status instead */
+static int kvm_mce_in_exception(CPUState *env)
+{
+    struct kvm_msr_entry msr_mcg_status = {
+        .index = MSR_MCG_STATUS,
+    };
+    int r;
+
+    r = kvm_get_msr(env, &msr_mcg_status, 1);
+    if (r == -1 || r == 0) {
+        return -1;
+    }
+    return !!(msr_mcg_status.data & MCG_STATUS_MCIP);
+}
+
+struct kvm_x86_mce_data
+{
+    CPUState *env;
+    struct kvm_x86_mce *mce;
+    int abort_on_error;
+};
+
+static void kvm_do_inject_x86_mce(void *_data)
+{
+    struct kvm_x86_mce_data *data = _data;
+    int r;
+
+    /* If there is an MCE exception being processed, ignore this SRAO MCE */
+    if ((data->env->mcg_cap & MCG_SER_P) &&
+        !(data->mce->status & MCI_STATUS_AR)) {
+        r = kvm_mce_in_exception(data->env);
+        if (r == -1) {
+            fprintf(stderr, "Failed to get MCE status\n");
+        } else if (r) {
+            return;
+        }
+    }
+
+    r = kvm_set_mce(data->env, data->mce);
+    if (r < 0) {
+        perror("kvm_set_mce FAILED");
+        if (data->abort_on_error) {
+            abort();
+        }
+    }
+}
+#endif
+
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
+                        int abort_on_error)
+{
+#ifdef KVM_CAP_MCE
+    struct kvm_x86_mce mce = {
+        .bank = bank,
+        .status = status,
+        .mcg_status = mcg_status,
+        .addr = addr,
+        .misc = misc,
+    };
+    struct kvm_x86_mce_data data = {
+            .env = cenv,
+            .mce = &mce,
+    };
+
+    if (!cenv->mcg_cap) {
+        fprintf(stderr, "MCE support is not enabled!\n");
+        return;
+    }
+
+    run_on_cpu(cenv, kvm_do_inject_x86_mce, &data);
+#else
+    if (abort_on_error)
+        abort();
+#endif
+}
+
 int kvm_arch_init_vcpu(CPUState *env)
 {
     struct {
@@ -192,6 +317,9 @@ int kvm_arch_init_vcpu(CPUState *env)
                                                              0, R_EDX);
     env->cpuid_ext3_features &= kvm_arch_get_supported_cpuid(env, 0x80000001,
                                                              0, R_ECX);
+    env->cpuid_svm_features  &= kvm_arch_get_supported_cpuid(env, 0x8000000A,
+                                                             0, R_EDX);
+
 
     cpuid_i = 0;
 
@@ -274,6 +402,28 @@ int kvm_arch_init_vcpu(CPUState *env)
 
     cpuid_data.cpuid.nent = cpuid_i;
 
+#ifdef KVM_CAP_MCE
+    if (((env->cpuid_version >> 8)&0xF) >= 6
+        && (env->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
+        && kvm_check_extension(env->kvm_state, KVM_CAP_MCE) > 0) {
+        uint64_t mcg_cap;
+        int banks;
+
+        if (kvm_get_mce_cap_supported(env->kvm_state, &mcg_cap, &banks))
+            perror("kvm_get_mce_cap_supported FAILED");
+        else {
+            if (banks > MCE_BANKS_DEF)
+                banks = MCE_BANKS_DEF;
+            mcg_cap &= MCE_CAP_DEF;
+            mcg_cap |= banks;
+            if (kvm_setup_mce(env, &mcg_cap))
+                perror("kvm_setup_mce FAILED");
+            else
+                env->mcg_cap = mcg_cap;
+        }
+    }
+#endif
+
     return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
 }
 
@@ -291,23 +441,26 @@ void kvm_arch_reset_vcpu(CPUState *env)
     }
 }
 
-static int kvm_has_msr_star(CPUState *env)
+int has_msr_star;
+int has_msr_hsave_pa;
+
+static void kvm_supported_msrs(CPUState *env)
 {
-    static int has_msr_star;
+    static int kvm_supported_msrs;
     int ret;
 
     /* first time */
-    if (has_msr_star == 0) {        
+    if (kvm_supported_msrs == 0) {
         struct kvm_msr_list msr_list, *kvm_msr_list;
 
-        has_msr_star = -1;
+        kvm_supported_msrs = -1;
 
         /* Obtain MSR list from KVM.  These are the MSRs that we must
          * save/restore */
         msr_list.nmsrs = 0;
         ret = kvm_ioctl(env->kvm_state, KVM_GET_MSR_INDEX_LIST, &msr_list);
         if (ret < 0 && ret != -E2BIG) {
-            return 0;
+            return;
         }
         /* Old kernel modules had a bug and could write beyond the provided
            memory. Allocate at least a safe amount of 1K. */
@@ -323,7 +476,11 @@ static int kvm_has_msr_star(CPUState *env)
             for (i = 0; i < kvm_msr_list->nmsrs; i++) {
                 if (kvm_msr_list->indices[i] == MSR_STAR) {
                     has_msr_star = 1;
-                    break;
+                    continue;
+                }
+                if (kvm_msr_list->indices[i] == MSR_VM_HSAVE_PA) {
+                    has_msr_hsave_pa = 1;
+                    continue;
                 }
             }
         }
@@ -331,9 +488,19 @@ static int kvm_has_msr_star(CPUState *env)
         free(kvm_msr_list);
     }
 
-    if (has_msr_star == 1)
-        return 1;
-    return 0;
+    return;
+}
+
+static int kvm_has_msr_hsave_pa(CPUState *env)
+{
+    kvm_supported_msrs(env);
+    return has_msr_hsave_pa;
+}
+
+static int kvm_has_msr_star(CPUState *env)
+{
+    kvm_supported_msrs(env);
+    return has_msr_star;
 }
 
 static int kvm_init_identity_map_page(KVMState *s)
@@ -359,6 +526,11 @@ int kvm_arch_init(KVMState *s, int smp_cpus)
 {
     int ret;
 
+    struct utsname utsname;
+
+    uname(&utsname);
+    lm_capable_kernel = strcmp(utsname.machine, "x86_64") == 0;
+
     /* create vm86 tss.  KVM uses vm86 mode to emulate 16-bit code
      * directly.  In order to use vm86 mode, a TSS is needed.  Since this
      * must be part of guest physical memory, we need to allocate it.  Older
@@ -517,7 +689,7 @@ static int kvm_put_fpu(CPUState *env)
 static int kvm_put_xsave(CPUState *env)
 {
 #ifdef KVM_CAP_XSAVE
-    int i;
+    int i, r;
     struct kvm_xsave* xsave;
     uint16_t cwd, swd, twd, fop;
 
@@ -542,7 +714,9 @@ static int kvm_put_xsave(CPUState *env)
     *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV] = env->xstate_bv;
     memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs,
             sizeof env->ymmh_regs);
-    return kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave);
+    r = kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave);
+    qemu_free(xsave);
+    return r;
 #else
     return kvm_put_fpu(env);
 #endif
@@ -641,19 +815,43 @@ static int kvm_put_msrs(CPUState *env, int level)
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
     if (kvm_has_msr_star(env))
        kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star);
+    if (kvm_has_msr_hsave_pa(env))
+        kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
 #ifdef TARGET_X86_64
-    /* FIXME if lm capable */
-    kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
-    kvm_msr_entry_set(&msrs[n++], MSR_KERNELGSBASE, env->kernelgsbase);
-    kvm_msr_entry_set(&msrs[n++], MSR_FMASK, env->fmask);
-    kvm_msr_entry_set(&msrs[n++], MSR_LSTAR, env->lstar);
+    if (lm_capable_kernel) {
+        kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
+        kvm_msr_entry_set(&msrs[n++], MSR_KERNELGSBASE, env->kernelgsbase);
+        kvm_msr_entry_set(&msrs[n++], MSR_FMASK, env->fmask);
+        kvm_msr_entry_set(&msrs[n++], MSR_LSTAR, env->lstar);
+    }
 #endif
     if (level == KVM_PUT_FULL_STATE) {
-        kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
+        /*
+         * KVM is yet unable to synchronize TSC values of multiple VCPUs on
+         * writeback. Until this is fixed, we only write the offset to SMP
+         * guests after migration, desynchronizing the VCPUs, but avoiding
+         * huge jump-backs that would occur without any writeback at all.
+         */
+        if (smp_cpus == 1 || env->tsc != 0) {
+            kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
+        }
         kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME,
                           env->system_time_msr);
         kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
     }
+#ifdef KVM_CAP_MCE
+    if (env->mcg_cap) {
+        int i;
+        if (level == KVM_PUT_RESET_STATE)
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
+        else if (level == KVM_PUT_FULL_STATE) {
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_CTL, env->mcg_ctl);
+            for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++)
+                kvm_msr_entry_set(&msrs[n++], MSR_MC0_CTL + i, env->mce_banks[i]);
+        }
+    }
+#endif
 
     msr_data.info.nmsrs = n;
 
@@ -695,8 +893,10 @@ static int kvm_get_xsave(CPUState *env)
 
     xsave = qemu_memalign(4096, sizeof(struct kvm_xsave));
     ret = kvm_vcpu_ioctl(env, KVM_GET_XSAVE, xsave);
-    if (ret < 0)
+    if (ret < 0) {
+        qemu_free(xsave);
         return ret;
+    }
 
     cwd = (uint16_t)xsave->region[0];
     swd = (uint16_t)(xsave->region[0] >> 16);
@@ -715,6 +915,7 @@ static int kvm_get_xsave(CPUState *env)
     env->xstate_bv = *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV];
     memcpy(env->ymmh_regs, &xsave->region[XSAVE_YMMH_SPACE],
             sizeof env->ymmh_regs);
+    qemu_free(xsave);
     return 0;
 #else
     return kvm_get_fpu(env);
@@ -850,17 +1051,29 @@ static int kvm_get_msrs(CPUState *env)
     msrs[n++].index = MSR_IA32_SYSENTER_EIP;
     if (kvm_has_msr_star(env))
        msrs[n++].index = MSR_STAR;
+    if (kvm_has_msr_hsave_pa(env))
+        msrs[n++].index = MSR_VM_HSAVE_PA;
     msrs[n++].index = MSR_IA32_TSC;
 #ifdef TARGET_X86_64
-    /* FIXME lm_capable_kernel */
-    msrs[n++].index = MSR_CSTAR;
-    msrs[n++].index = MSR_KERNELGSBASE;
-    msrs[n++].index = MSR_FMASK;
-    msrs[n++].index = MSR_LSTAR;
+    if (lm_capable_kernel) {
+        msrs[n++].index = MSR_CSTAR;
+        msrs[n++].index = MSR_KERNELGSBASE;
+        msrs[n++].index = MSR_FMASK;
+        msrs[n++].index = MSR_LSTAR;
+    }
 #endif
     msrs[n++].index = MSR_KVM_SYSTEM_TIME;
     msrs[n++].index = MSR_KVM_WALL_CLOCK;
 
+#ifdef KVM_CAP_MCE
+    if (env->mcg_cap) {
+        msrs[n++].index = MSR_MCG_STATUS;
+        msrs[n++].index = MSR_MCG_CTL;
+        for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++)
+            msrs[n++].index = MSR_MC0_CTL + i;
+    }
+#endif
+
     msr_data.info.nmsrs = n;
     ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &msr_data);
     if (ret < 0)
@@ -897,12 +1110,31 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_IA32_TSC:
             env->tsc = msrs[i].data;
             break;
+        case MSR_VM_HSAVE_PA:
+            env->vm_hsave = msrs[i].data;
+            break;
         case MSR_KVM_SYSTEM_TIME:
             env->system_time_msr = msrs[i].data;
             break;
         case MSR_KVM_WALL_CLOCK:
             env->wall_clock_msr = msrs[i].data;
             break;
+#ifdef KVM_CAP_MCE
+        case MSR_MCG_STATUS:
+            env->mcg_status = msrs[i].data;
+            break;
+        case MSR_MCG_CTL:
+            env->mcg_ctl = msrs[i].data;
+            break;
+#endif
+        default:
+#ifdef KVM_CAP_MCE
+            if (msrs[i].index >= MSR_MC0_CTL &&
+                msrs[i].index < MSR_MC0_CTL + (env->mcg_cap & 0xff) * 4) {
+                env->mce_banks[msrs[i].index - MSR_MC0_CTL] = msrs[i].data;
+            }
+#endif
+            break;
         }
     }
 
@@ -1441,3 +1673,140 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)
               ((env->segs[R_CS].selector  & 3) != 3);
 }
 
+static void hardware_memory_error(void)
+{
+    fprintf(stderr, "Hardware memory error!\n");
+    exit(1);
+}
+
+#ifdef KVM_CAP_MCE
+static void kvm_mce_broadcast_rest(CPUState *env)
+{
+    CPUState *cenv;
+    int family, model, cpuver = env->cpuid_version;
+
+    family = (cpuver >> 8) & 0xf;
+    model = ((cpuver >> 12) & 0xf0) + ((cpuver >> 4) & 0xf);
+
+    /* Broadcast MCA signal for processor version 06H_EH and above */
+    if ((family == 6 && model >= 14) || family > 6) {
+        for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
+            if (cenv == env) {
+                continue;
+            }
+            kvm_inject_x86_mce(cenv, 1, MCI_STATUS_VAL | MCI_STATUS_UC,
+                               MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0, 1);
+        }
+    }
+}
+#endif
+
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+#if defined(KVM_CAP_MCE)
+    struct kvm_x86_mce mce = {
+            .bank = 9,
+    };
+    void *vaddr;
+    ram_addr_t ram_addr;
+    target_phys_addr_t paddr;
+    int r;
+
+    if ((env->mcg_cap & MCG_SER_P) && addr
+        && (code == BUS_MCEERR_AR
+            || code == BUS_MCEERR_AO)) {
+        if (code == BUS_MCEERR_AR) {
+            /* Fake an Intel architectural Data Load SRAR UCR */
+            mce.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+                | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                | MCI_STATUS_AR | 0x134;
+            mce.misc = (MCM_ADDR_PHYS << 6) | 0xc;
+            mce.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
+        } else {
+            /*
+             * If there is an MCE excpetion being processed, ignore
+             * this SRAO MCE
+             */
+            r = kvm_mce_in_exception(env);
+            if (r == -1) {
+                fprintf(stderr, "Failed to get MCE status\n");
+            } else if (r) {
+                return 0;
+            }
+            /* Fake an Intel architectural Memory scrubbing UCR */
+            mce.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+                | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                | 0xc0;
+            mce.misc = (MCM_ADDR_PHYS << 6) | 0xc;
+            mce.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
+        }
+        vaddr = (void *)addr;
+        if (qemu_ram_addr_from_host(vaddr, &ram_addr) ||
+            !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, &paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!\n");
+            /* Hope we are lucky for AO MCE */
+            if (code == BUS_MCEERR_AO) {
+                return 0;
+            } else {
+                hardware_memory_error();
+            }
+        }
+        mce.addr = paddr;
+        r = kvm_set_mce(env, &mce);
+        if (r < 0) {
+            fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
+            abort();
+        }
+        kvm_mce_broadcast_rest(env);
+    } else
+#endif
+    {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int kvm_on_sigbus(int code, void *addr)
+{
+#if defined(KVM_CAP_MCE)
+    if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) {
+        uint64_t status;
+        void *vaddr;
+        ram_addr_t ram_addr;
+        target_phys_addr_t paddr;
+
+        /* Hope we are lucky for AO MCE */
+        vaddr = addr;
+        if (qemu_ram_addr_from_host(vaddr, &ram_addr) ||
+            !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, &paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!: %p\n", addr);
+            return 0;
+        }
+        status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+            | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+            | 0xc0;
+        kvm_inject_x86_mce(first_cpu, 9, status,
+                           MCG_STATUS_MCIP | MCG_STATUS_RIPV, paddr,
+                           (MCM_ADDR_PHYS << 6) | 0xc, 1);
+        kvm_mce_broadcast_rest(first_cpu);
+    } else
+#endif
+    {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
+    }
+    return 0;
+}
diff --git a/target-i386/kvm_x86.h b/target-i386/kvm_x86.h
new file mode 100644 (file)
index 0000000..04932cf
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * QEMU KVM support
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef __KVM_X86_H__
+#define __KVM_X86_H__
+
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
+                        int abort_on_error);
+
+#endif
index ec6b3e938457cc591c7b3725732362deb0a5f796..43fbd0c778ae3b946ecf46942a7a31d939cde955 100644 (file)
@@ -349,6 +349,10 @@ static void switch_tss(int tss_selector,
         new_segs[R_GS] = 0;
         new_trap = 0;
     }
+    /* XXX: avoid a compiler warning, see
+     http://support.amd.com/us/Processor_TechDocs/24593.pdf
+     chapters 12.2.5 and 13.2.4 on how to implement TSS Trap bit */
+    (void)new_trap;
 
     /* NOTE: we must avoid memory exceptions during the task switch,
        so we make dummy accesses before */
index 33c41b2ebcd30f14dbf113430eaac059a9fc4c08..b025b6689d6f100ff11d70aea7e8c340fda2cef3 100644 (file)
@@ -24,6 +24,7 @@
 
 #define CPUState struct CPUM68KState
 
+#include "qemu-common.h"
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -198,7 +199,7 @@ static inline int m68k_feature(CPUM68KState *env, int feature)
     return (env->features & (1u << feature)) != 0;
 }
 
-void m68k_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
 void register_m68k_insns (CPUM68KState *env);
 
index b4ebb14e838affa5adb449fbffb785b68858f1aa..56de897c1df9da4df74871d0c5f0e0eab4308602 100644 (file)
@@ -53,7 +53,7 @@ static m68k_def_t m68k_cpu_defs[] = {
     {NULL, 0},
 };
 
-void m68k_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
     unsigned int i;
 
index 5351880c68df662c3f4a052341e2fe32f7b539d1..6f72a2bdd2fc4ccd5270aa6bfb0c6118a590025b 100644 (file)
@@ -3092,8 +3092,7 @@ void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-void cpu_dump_state(CPUState *env, FILE *f,
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     int flags)
 {
     int i;
index 38149bb357bd00d644f3f960d10cfcccefb7ce33..1ada15e19da73e6139eea24c39a69191b7de5d7b 100644 (file)
@@ -1534,8 +1534,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-void cpu_dump_state (CPUState *env, FILE *f,
-                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                      int flags)
 {
     int i;
index 19511d7f02b4ae327b0b5788a44fd409cbe1e216..c1f211fc17827c574a1ef01a65083b715aa02cf5 100644 (file)
@@ -8,6 +8,7 @@
 #define CPUState struct CPUMIPSState
 
 #include "config.h"
+#include "qemu-common.h"
 #include "mips-defs.h"
 #include "cpu-defs.h"
 #include "softfloat.h"
@@ -496,7 +497,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
                           int unused, int size);
 #endif
 
-void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);
 
 #define cpu_init cpu_mips_init
 #define cpu_exec cpu_mips_exec
index 20b66a8a51bd0ac97146d8758bbb46873b55e086..ba45eb0e523bd6e2097d01a5c3de2bf76d320347 100644 (file)
@@ -1153,6 +1153,7 @@ static void gen_ld (CPUState *env, DisasContext *ctx, uint32_t opc,
         opn = "ll";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -1212,6 +1213,7 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt,
         opn = "swr";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -1247,6 +1249,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
         opn = "sc";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
     tcg_temp_free(t1);
     tcg_temp_free(t0);
@@ -1312,6 +1315,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
         generate_exception(ctx, EXCP_RI);
         goto out;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
  out:
     tcg_temp_free(t0);
@@ -1412,6 +1416,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
 }
 
@@ -1454,6 +1459,7 @@ static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t
         opn = "lui";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
 }
 
@@ -1481,6 +1487,7 @@ static void gen_slt_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t im
         opn = "sltiu";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
     tcg_temp_free(t0);
 }
@@ -1572,6 +1579,7 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
     tcg_temp_free(t0);
 }
@@ -1752,6 +1760,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
         opn = "mul";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
 }
 
@@ -1789,6 +1798,7 @@ static void gen_cond_move (CPUState *env, uint32_t opc, int rd, int rs, int rt)
         tcg_gen_movi_tl(cpu_gpr[rd], 0);
     gen_set_label(l1);
 
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
 }
 
@@ -1849,6 +1859,7 @@ static void gen_logic (CPUState *env, uint32_t opc, int rd, int rs, int rt)
         opn = "xor";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
 }
 
@@ -1878,6 +1889,7 @@ static void gen_slt (CPUState *env, uint32_t opc, int rd, int rs, int rt)
         opn = "sltu";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -1958,6 +1970,7 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -1997,6 +2010,7 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
         opn = "mtlo";
         break;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s", opn, regnames[reg]);
 }
 
@@ -2229,6 +2243,7 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
         generate_exception(ctx, EXCP_RI);
         goto out;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
  out:
     tcg_temp_free(t0);
@@ -2308,6 +2323,7 @@ static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc,
         goto out;
     }
     gen_store_gpr(t0, rd);
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
 
  out:
@@ -2348,6 +2364,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
     tcg_temp_free(t0);
 }
@@ -2561,6 +2578,7 @@ static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
 #endif
     }
 
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -3730,6 +3748,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
     default:
        goto die;
     }
+    (void)rn; /* avoid a compiler warning */
     LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel);
     return;
 
@@ -4320,6 +4339,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
     default:
        goto die;
     }
+    (void)rn; /* avoid a compiler warning */
     LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel);
     /* For simplicity assume that all writes can cause interrupts.  */
     if (use_icount) {
@@ -4892,6 +4912,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
     default:
         goto die;
     }
+    (void)rn; /* avoid a compiler warning */
     LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel);
     return;
 
@@ -5483,6 +5504,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
     default:
         goto die;
     }
+    (void)rn; /* avoid a compiler warning */
     LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel);
     /* For simplicity assume that all writes can cause interrupts.  */
     if (use_icount) {
@@ -5943,6 +5965,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
         generate_exception(ctx, EXCP_RI);
         return;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
 }
 #endif /* !CONFIG_USER_ONLY */
@@ -6052,6 +6075,7 @@ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
         generate_exception (ctx, EXCP_RI);
         goto out;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
                ctx->hflags, btarget);
     ctx->btarget = btarget;
@@ -6281,6 +6305,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
         generate_exception (ctx, EXCP_RI);
         goto out;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
 
  out:
@@ -7608,6 +7633,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
         generate_exception (ctx, EXCP_RI);
         return;
     }
+    (void)opn; /* avoid a compiler warning */
     switch (optype) {
     case BINOP:
         MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
@@ -7720,6 +7746,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
         break;
     }
     tcg_temp_free(t0);
+    (void)opn; (void)store; /* avoid compiler warnings */
     MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd],
                regnames[index], regnames[base]);
 }
@@ -7993,6 +8020,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
         generate_exception (ctx, EXCP_RI);
         return;
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr],
                fregnames[fs], fregnames[ft]);
 }
@@ -9971,6 +9999,7 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
         break;
 #endif
     }
+    (void)opn; /* avoid a compiler warning */
     MIPS_DEBUG("%s, %s, %d(%s)", opn, regnames[rd], offset, regnames[base]);
     tcg_temp_free(t0);
     tcg_temp_free(t1);
@@ -12421,8 +12450,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
     gen_intermediate_code_internal(env, tb, 1);
 }
 
-static void fpu_dump_state(CPUState *env, FILE *f,
-                           int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
+static void fpu_dump_state(CPUState *env, FILE *f, fprintf_function fpu_fprintf,
                            int flags)
 {
     int i;
@@ -12451,8 +12479,8 @@ static void fpu_dump_state(CPUState *env, FILE *f,
     } while(0)
 
 
-    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d  fp_status 0x%08x(0x%02x)\n",
-                env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, env->active_fpu.fp_status,
+    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d  fp_status 0x%02x\n",
+                env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64,
                 get_float_exception_flags(&env->active_fpu.fp_status));
     for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
         fpu_fprintf(f, "%3s: ", fregnames[i]);
@@ -12470,7 +12498,7 @@ static void fpu_dump_state(CPUState *env, FILE *f,
 
 static void
 cpu_mips_check_sign_extensions (CPUState *env, FILE *f,
-                                int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                                fprintf_function cpu_fprintf,
                                 int flags)
 {
     int i;
@@ -12496,8 +12524,7 @@ cpu_mips_check_sign_extensions (CPUState *env, FILE *f,
 }
 #endif
 
-void cpu_dump_state (CPUState *env, FILE *f,
-                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                      int flags)
 {
     int i;
index 8d1ece704da92e9720d84e78ce187eca33bb8a84..590e092a1dbb453cdd34a3b1e7f3862cffc2c2b9 100644 (file)
@@ -500,7 +500,7 @@ static const mips_def_t *cpu_mips_find_by_name (const char *name)
     return NULL;
 }
 
-void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf)
 {
     int i;
 
index bf819412212f7d60b8825c5bfc35933aef39155d..deb8d7c9c50c7832fb2ac63d71681929f4b05800 100644 (file)
@@ -20,7 +20,7 @@
 #define __CPU_PPC_H__
 
 #include "config.h"
-#include <inttypes.h>
+#include "qemu-common.h"
 
 //#define PPC_EMULATE_32BITS_HYPV
 
@@ -700,9 +700,6 @@ struct CPUPPCState {
     int power_mode;
     int (*check_pow)(CPUPPCState *env);
 
-    /* temporary hack to handle OSI calls (only used if non NULL) */
-    int (*osi_call)(struct CPUPPCState *env);
-
 #if !defined(CONFIG_USER_ONLY)
     void *load_info;    /* Holds boot loading state.  */
 #endif
@@ -764,7 +761,7 @@ void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value);
 #endif /* !defined(CONFIG_USER_ONLY) */
 void ppc_store_msr (CPUPPCState *env, target_ulong value);
 
-void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
 
 const ppc_def_t *cpu_ppc_find_by_name (const char *name);
 int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def);
index edbdd80945afcbeb8601e2da6cfabef8689cd380..4b491012d726cede9bd49ae5d267d0fbc1dcc459 100644 (file)
@@ -2226,17 +2226,6 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
             new_msr |= (target_ulong)MSR_HVB;
         goto store_current;
     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
-        /* NOTE: this is a temporary hack to support graphics OSI
-           calls from the MOL driver */
-        /* XXX: To be removed */
-        if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
-            env->osi_call) {
-            if (env->osi_call(env) != 0) {
-                env->exception_index = POWERPC_EXCP_NONE;
-                env->error_code = 0;
-                return;
-            }
-        }
         dump_syscall(env);
         lev = env->error_code;
         if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
index 45f1655cb64c826fe544a2a9db8864fe975976e1..f32a5fffd6078797e7eef80fa90ab0497e61e1ce 100644 (file)
@@ -348,15 +348,13 @@ void helper_dcbz_970(target_ulong addr)
 
 void helper_icbi(target_ulong addr)
 {
-    uint32_t tmp;
-
     addr &= ~(env->dcache_line_size - 1);
     /* Invalidate one cache line :
      * PowerPC specification says this is to be treated like a load
      * (not a fetch) by the MMU. To be sure it will be so,
      * do the load "by hand".
      */
-    tmp = ldl(addr);
+    ldl(addr);
     tb_invalidate_page_range(addr, addr + env->icache_line_size);
 }
 
@@ -3814,6 +3812,7 @@ static void do_6xx_tlb (target_ulong new_EPN, int is_code)
         EPN = env->spr[SPR_DMISS];
     }
     way = (env->spr[SPR_SRR1] >> 17) & 1;
+    (void)EPN; /* avoid a compiler warning */
     LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
               " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
               RPN, way);
@@ -3842,6 +3841,7 @@ static void do_74xx_tlb (target_ulong new_EPN, int is_code)
     CMP = env->spr[SPR_PTEHI];
     EPN = env->spr[SPR_TLBMISS] & ~0x3;
     way = env->spr[SPR_TLBMISS] & 0x3;
+    (void)EPN; /* avoid a compiler warning */
     LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
               " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
               RPN, way);
index fd0686182e3698841fbc55a20809349d0d3587fe..c82a4835d44f8f2059d90075242332938559fc6c 100644 (file)
@@ -8830,8 +8830,7 @@ GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
 
 /*****************************************************************************/
 /* Misc PowerPC helpers */
-void cpu_dump_state (CPUState *env, FILE *f,
-                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                      int flags)
 {
 #define RGPL  4
@@ -8840,15 +8839,15 @@ void cpu_dump_state (CPUState *env, FILE *f,
     int i;
 
     cpu_fprintf(f, "NIP " TARGET_FMT_lx "   LR " TARGET_FMT_lx " CTR "
-                TARGET_FMT_lx " XER %08x\n", env->nip, env->lr, env->ctr,
-                env->xer);
+                TARGET_FMT_lx " XER " TARGET_FMT_lx "\n",
+                env->nip, env->lr, env->ctr, env->xer);
     cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx "  HF "
                 TARGET_FMT_lx " idx %d\n", env->msr, env->spr[SPR_HID0],
                 env->hflags, env->mmu_idx);
 #if !defined(NO_TIMER_DUMP)
-    cpu_fprintf(f, "TB %08x %08x "
+    cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
 #if !defined(CONFIG_USER_ONLY)
-                "DECR %08x"
+                " DECR %08" PRIu32
 #endif
                 "\n",
                 cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
@@ -8898,8 +8897,7 @@ void cpu_dump_state (CPUState *env, FILE *f,
 #undef RFPL
 }
 
-void cpu_dump_statistics (CPUState *env, FILE*f,
-                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_statistics (CPUState *env, FILE*f, fprintf_function cpu_fprintf,
                           int flags)
 {
 #if defined(DO_PPC_STATISTICS)
index 05ffe9576210d512f039d06abf9d6824e4488c30..dfcd94980f85eba9bd07093914af2920ba05befb 100644 (file)
@@ -9756,7 +9756,7 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name)
     return ret;
 }
 
-void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
 {
     int i, max;
 
index 44dfa65085dec62066779658e0a90be3c8dd0d34..881d8c4acf910e640f49237e4e68d2766d2e459d 100644 (file)
@@ -23,8 +23,7 @@
 #include "tcg-op.h"
 #include "qemu-log.h"
 
-void cpu_dump_state(CPUState *env, FILE *f,
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     int flags)
 {
     int i;
index 64a609b8ad566e38a26c2632082cd595396c29c8..e19776643b98f93168878bc97f9bd730d4c66336 100644 (file)
@@ -20,6 +20,7 @@
 #define _CPU_SH4_H
 
 #include "config.h"
+#include "qemu-common.h"
 
 #define TARGET_LONG_BITS 32
 #define TARGET_HAS_ICE 1
@@ -168,7 +169,7 @@ int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
 #define cpu_handle_mmu_fault cpu_sh4_handle_mmu_fault
 void do_interrupt(CPUSH4State * env);
 
-void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 #if !defined(CONFIG_USER_ONLY)
 void cpu_sh4_invalidate_tlb(CPUSH4State *s);
 void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
index deee939e12624495e922163a1365c50ea8251801..f41813993172b976f3ec5ac3ac60671ee86bb57e 100644 (file)
@@ -257,7 +257,7 @@ static const sh4_def_t *cpu_sh4_find_by_name(const char *name)
     return NULL;
 }
 
-void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
     int i;
 
index aa1fd632cc586bf35296a49d8c2274569b73a44f..e84c31256f2d65451fcac140597ba4bb1c78adcd 100644 (file)
@@ -1323,8 +1323,7 @@ static const char * const feature_name[] = {
     "gl",
 };
 
-static void print_features(FILE *f,
-                           int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+static void print_features(FILE *f, fprintf_function cpu_fprintf,
                            uint32_t features, const char *prefix)
 {
     unsigned int i;
@@ -1452,7 +1451,7 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
     return -1;
 }
 
-void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
     unsigned int i;
 
@@ -1479,8 +1478,7 @@ void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
                    "fpu_version mmu_version nwindows\n");
 }
 
-static void cpu_print_cc(FILE *f,
-                         int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
                          uint32_t cc)
 {
     cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
@@ -1494,8 +1492,7 @@ static void cpu_print_cc(FILE *f,
 #define REGS_PER_LINE 8
 #endif
 
-void cpu_dump_state(CPUState *env, FILE *f,
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
                     int flags)
 {
     int i, x;
index e0a90302a7e98577496584e2b45d207929dde4f8..5dd6a2c613f38c7bad1a174a5f27993afd17cd79 100644 (file)
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1027,7 +1027,7 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
         if (tdefs->op == (TCGOpcode)-1)
             break;
         op = tdefs->op;
-        assert(op >= 0 && op < NB_OPS);
+        assert((unsigned)op < NB_OPS);
         def = &tcg_op_defs[op];
 #if defined(CONFIG_DEBUG_TCG)
         /* Duplicate entry in op definitions? */
@@ -2124,8 +2124,7 @@ int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
 }
 
 #ifdef CONFIG_PROFILER
-void tcg_dump_info(FILE *f,
-                   int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
 {
     TCGContext *s = &tcg_ctx;
     int64_t tot;
@@ -2169,8 +2168,7 @@ void tcg_dump_info(FILE *f,
     dump_op_count();
 }
 #else
-void tcg_dump_info(FILE *f,
-                   int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
 {
     cpu_fprintf(f, "[TCG profiler not compiled]\n");
 }
index 972df729ff78f6008efb6d622b95862084f19b32..e1afde26b4d503a09ee2d63acc7ecdbb830f7ec0 100644 (file)
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -392,8 +392,7 @@ static inline TCGv_i64 tcg_temp_local_new_i64(void)
 void tcg_temp_free_i64(TCGv_i64 arg);
 char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
 
-void tcg_dump_info(FILE *f,
-                   int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf);
 
 #define TCG_CT_ALIAS  0x80
 #define TCG_CT_IALIAS 0x40
index ff7f787a9a5af192b8c933a814de964b8b510175..e43ec70b6d236b9ebd8d4aacda39ef01c72bbcb8 100644 (file)
 -include ../config-host.mak
+-include $(SRC_PATH)/rules.mak
 
 $(call set-vpath, $(SRC_PATH)/tests)
 
-CFLAGS=-Wall -O2 -g -fno-strict-aliasing
+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..
 #CFLAGS+=-msse2
 LDFLAGS=
 
-ifeq ($(ARCH),i386)
-TESTS=linux-test testthread sha1-i386 test-i386
+# TODO: automatically detect ARM and MIPS compilers, and run those too
+
+# runcom maps page 0, so it requires root privileges
+# also, pi_10.com runs indefinitely
+
+I386_TESTS=hello-i386 \
+          linux-test \
+          testthread \
+          sha1-i386 \
+          test-i386 \
+          test-mmap \
+          # runcom
+
+# native i386 compilers sometimes are not biarch.  assume cross-compilers are
+ifneq ($(ARCH),i386)
+I386_TESTS+=run-test-x86_64
 endif
-ifeq ($(ARCH),x86_64)
-TESTS=test-x86_64
+
+TESTS = test_path
+ifneq ($(call find-in-path, $(CC_I386)),)
+TESTS += $(I386_TESTS)
 endif
-TESTS+=sha1# test_path
-#TESTS+=test_path
-#TESTS+=runcom
 
-QEMU=../i386-linux-user/qemu-i386
+all: $(patsubst %,run-%,$(TESTS))
+
+# rules to run tests
+
+.PHONY: $(patsubst %,run-%,$(TESTS))
+
+run-%: %
+       -$(QEMU) ./$*
+
+run-hello-i386: hello-i386
+run-linux-test: linux-test
+run-testthread: testthread
+run-sha1-i386: sha1-i386
+
+run-test-i386: test-i386
+       ./test-i386 > test-i386.ref
+       -$(QEMU) test-i386 > test-i386.out
+       @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
+
+run-test-x86_64: test-x86_64
+       ./test-x86_64 > test-x86_64.ref
+       -$(QEMU_X86_64) test-x86_64 > test-x86_64.out
+       @if diff -u test-x86_64.ref test-x86_64.out ; then echo "Auto Test OK"; fi
+
+run-test-mmap: test-mmap
+       -$(QEMU) ./test-mmap
+       -$(QEMU) -p 8192 ./test-mmap 8192
+       -$(QEMU) -p 16384 ./test-mmap 16384
+       -$(QEMU) -p 32768 ./test-mmap 32768
+
+run-runcom: runcom
+       -$(QEMU) ./runcom $(SRC_PATH)/tests/pi_10.com
+
+run-test_path: test_path
+       ./test_path
+
+# rules to compile tests
 
-all: $(TESTS)
+test_path: test_path.o
+test_path.o: test_path.c
 
 hello-i386: hello-i386.c
-       $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
+       $(CC_I386) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
        strip $@
 
 testthread: testthread.c
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
-
-test_path: test_path.c
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
-       ./$@ || { rm $@; exit 1; }
+       $(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
 
 # i386/x86_64 emulation test (test various opcodes) */
 test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
            test-i386.h test-i386-shift.h test-i386-muldiv.h
-       $(CC) -m32 $(CFLAGS) $(LDFLAGS) -static -o $@ \
+       $(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ \
               $(<D)/test-i386.c $(<D)/test-i386-code16.S $(<D)/test-i386-vm86.S -lm
 
 test-x86_64: test-i386.c \
            test-i386.h test-i386-shift.h test-i386-muldiv.h
-       $(CC) -m64 $(CFLAGS) $(LDFLAGS) -static -o $@ $(<D)/test-i386.c -lm
-
-ifeq ($(ARCH),i386)
-test: test-i386
-       ./test-i386 > test-i386.ref
-else
-test:
-endif
-       $(QEMU) test-i386 > test-i386.out
-       @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
-
-.PHONY: test-mmap
-test-mmap: test-mmap.c
-       $(CC) $(CFLAGS) -Wall -static -O2 $(LDFLAGS) -o $@ $<
-       -./test-mmap
-       -$(QEMU) ./test-mmap
-       -$(QEMU) -p 8192 ./test-mmap 8192
-       -$(QEMU) -p 16384 ./test-mmap 16384
-       -$(QEMU) -p 32768 ./test-mmap 32768
+       $(CC_X86_64) $(CFLAGS) $(LDFLAGS) -o $@ $(<D)/test-i386.c -lm
 
 # generic Linux and CPU test
 linux-test: linux-test.c
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lm
+       $(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ $< -lm
+
+# vm86 test
+runcom: runcom.c
+       $(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+test-mmap: test-mmap.c
+       $(CC_I386) -m32 $(CFLAGS) -Wall -O2 $(LDFLAGS) -o $@ $<
 
 # speed test
 sha1-i386: sha1.c
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+       $(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ $<
 
 sha1: sha1.c
-       $(HOST_CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
 
 speed: sha1 sha1-i386
        time ./sha1
        time $(QEMU) ./sha1-i386
 
-# vm86 test
-runcom: runcom.c
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
-
+# broken test
 # NOTE: -fomit-frame-pointer is currently needed : this is a bug in libqemu
 qruncom: qruncom.c ../ioport-user.c ../i386-user/libqemu.a
        $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -I../target-i386 -I.. -I../i386-user -I../fpu \
index 6380566635538137bf9aeaede2cb523af1de8b83..d60342bfc65a9c4f0e18b63286661afa512c9288 100644 (file)
 #include <linux/unistd.h>
 #include <asm/vm86.h>
 
-//#define SIGTEST
+extern int vm86 (unsigned long int subfunction,
+                struct vm86plus_struct *info);
 
-#undef __syscall_return
-#define __syscall_return(type, res) \
-do { \
-       return (type) (res); \
-} while (0)
+#define VIF_MASK                0x00080000
 
-_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
+//#define SIGTEST
 
 #define COM_BASE_ADDR    0x10100
 
index b28b257f8157eaa49e80608eb5fa7274146ace3c..8f481c7f7ad01c10ae5bbc8e8d9b7f0fdde2ad2a 100644 (file)
@@ -2047,6 +2047,10 @@ long enter_stack[4096];
 #define RBP "%%ebp"
 #endif
 
+#if !defined(__x86_64__)
+/* causes an infinite loop, disable it for now.  */
+#define TEST_ENTER(size, stack_type, level)
+#else
 #define TEST_ENTER(size, stack_type, level)\
 {\
     long esp_save, esp_val, ebp_val, ebp_save, i;\
@@ -2078,6 +2082,7 @@ long enter_stack[4096];
     for(ptr = (stack_type *)esp_val; ptr < stack_end; ptr++)\
         printf(FMTLX "\n", (long)ptr[0]);\
 }
+#endif
 
 static void test_enter(void)
 {
index def7441c8cb64c76ee78d08a2d8473c4b7fe110e..234ed97088d308eaa947cc970a10f0a33eef07a5 100644 (file)
@@ -1,12 +1,21 @@
 /* Test path override code */
-#define _GNU_SOURCE
+#include "../config-host.h"
+#include "../qemu-malloc.c"
+#include "../cutils.c"
 #include "../path.c"
+#include "../trace.c"
+#ifdef CONFIG_SIMPLE_TRACE
+#include "../simpletrace.c"
+#endif
+
 #include <stdarg.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 
+void qemu_log(const char *fmt, ...);
+
 /* Any log message kills the test. */
-void gemu_log(const char *fmt, ...)
+void qemu_log(const char *fmt, ...)
 {
     va_list ap;
 
index f32c83fa2638a7bd21adbff21256cff11dcef9a3..947f8b08cb85f10f274ced335ae305239b07fbdd 100644 (file)
@@ -51,14 +51,16 @@ disable multiwrite_cb(void *mcb, int ret) "mcb %p ret %d"
 disable bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d"
 disable bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p"
 disable bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
+disable bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
+disable bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 
 # hw/virtio-blk.c
 disable virtio_blk_req_complete(void *req, int status) "req %p status %d"
 disable virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
-disable virtio_blk_handle_write(void *req, unsigned long sector, unsigned long nsectors) "req %p sector %lu nsectors %lu"
+disable virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
 
 # posix-aio-compat.c
-disable paio_submit(void *acb, void *opaque, unsigned long sector_num, unsigned long nb_sectors, unsigned long type) "acb %p opaque %p sector_num %lu nb_sectors %lu type %lu"
+disable paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
 
 # ioport.c
 disable cpu_in(unsigned int addr, unsigned int val) "addr %#x value %u"
@@ -67,3 +69,123 @@ disable cpu_out(unsigned int addr, unsigned int val) "addr %#x value %u"
 # balloon.c
 # Since requests are raised via monitor, not many tracepoints are needed.
 disable balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
+
+# hw/apic.c
+disable apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d"
+disable apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d polarity %d trigger_mode %d"
+disable cpu_set_apic_base(uint64_t val) "%016"PRIx64""
+disable cpu_get_apic_base(uint64_t val) "%016"PRIx64""
+disable apic_mem_readl(uint64_t addr, uint32_t val)  "%"PRIx64" = %08x"
+disable apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
+# coalescing
+disable apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
+disable apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
+disable apic_set_irq(int apic_irq_delivered) "coalescing %d"
+
+# hw/cs4231.c
+disable cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
+disable cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x"
+disable cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x"
+disable cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x"
+
+# hw/eccmemctl.c
+disable ecc_mem_writel_mer(uint32_t val) "Write memory enable %08x"
+disable ecc_mem_writel_mdr(uint32_t val) "Write memory delay %08x"
+disable ecc_mem_writel_mfsr(uint32_t val) "Write memory fault status %08x"
+disable ecc_mem_writel_vcr(uint32_t val) "Write slot configuration %08x"
+disable ecc_mem_writel_dr(uint32_t val) "Write diagnostic %08x"
+disable ecc_mem_writel_ecr0(uint32_t val) "Write event count 1 %08x"
+disable ecc_mem_writel_ecr1(uint32_t val) "Write event count 2 %08x"
+disable ecc_mem_readl_mer(uint32_t ret) "Read memory enable %08x"
+disable ecc_mem_readl_mdr(uint32_t ret) "Read memory delay %08x"
+disable ecc_mem_readl_mfsr(uint32_t ret) "Read memory fault status %08x"
+disable ecc_mem_readl_vcr(uint32_t ret) "Read slot configuration %08x"
+disable ecc_mem_readl_mfar0(uint32_t ret) "Read memory fault address 0 %08x"
+disable ecc_mem_readl_mfar1(uint32_t ret) "Read memory fault address 1 %08x"
+disable ecc_mem_readl_dr(uint32_t ret) "Read diagnostic %08x"
+disable ecc_mem_readl_ecr0(uint32_t ret) "Read event count 1 %08x"
+disable ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x"
+disable ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x"
+disable ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x"
+
+# hw/lance.c
+disable lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x"
+disable lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x"
+
+# hw/slavio_intctl.c
+disable slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = %x"
+disable slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = %x"
+disable slavio_intctl_mem_writel_clear(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Cleared cpu %d irq mask %x, curmask %x"
+disable slavio_intctl_mem_writel_set(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Set cpu %d irq mask %x, curmask %x"
+disable slavio_intctlm_mem_readl(uint64_t addr, uint32_t ret) "read system reg 0x%"PRIx64" = %x"
+disable slavio_intctlm_mem_writel(uint64_t addr, uint32_t val) "write system reg 0x%"PRIx64" = %x"
+disable slavio_intctlm_mem_writel_enable(uint32_t val, uint32_t intregm_disabled) "Enabled master irq mask %x, curmask %x"
+disable slavio_intctlm_mem_writel_disable(uint32_t val, uint32_t intregm_disabled) "Disabled master irq mask %x, curmask %x"
+disable slavio_intctlm_mem_writel_target(uint32_t cpu) "Set master irq cpu %d"
+disable slavio_check_interrupts(uint32_t pending, uint32_t intregm_disabled) "pending %x disabled %x"
+disable slavio_set_irq(uint32_t target_cpu, int irq, uint32_t pil, int level) "Set cpu %d irq %d -> pil %d level %d"
+disable slavio_set_timer_irq_cpu(int cpu, int level) "Set cpu %d local timer level %d"
+
+# hw/slavio_misc.c
+disable slavio_misc_update_irq_raise(void) "Raise IRQ"
+disable slavio_misc_update_irq_lower(void) "Lower IRQ"
+disable slavio_set_power_fail(int power_failing, uint8_t config) "Power fail: %d, config: %d"
+disable slavio_cfg_mem_writeb(uint32_t val) "Write config %02x"
+disable slavio_cfg_mem_readb(uint32_t ret) "Read config %02x"
+disable slavio_diag_mem_writeb(uint32_t val) "Write diag %02x"
+disable slavio_diag_mem_readb(uint32_t ret) "Read diag %02x"
+disable slavio_mdm_mem_writeb(uint32_t val) "Write modem control %02x"
+disable slavio_mdm_mem_readb(uint32_t ret) "Read modem control %02x"
+disable slavio_aux1_mem_writeb(uint32_t val) "Write aux1 %02x"
+disable slavio_aux1_mem_readb(uint32_t ret) "Read aux1 %02x"
+disable slavio_aux2_mem_writeb(uint32_t val) "Write aux2 %02x"
+disable slavio_aux2_mem_readb(uint32_t ret) "Read aux2 %02x"
+disable apc_mem_writeb(uint32_t val) "Write power management %02x"
+disable apc_mem_readb(uint32_t ret) "Read power management %02x"
+disable slavio_sysctrl_mem_writel(uint32_t val) "Write system control %08x"
+disable slavio_sysctrl_mem_readl(uint32_t ret) "Read system control %08x"
+disable slavio_led_mem_writew(uint32_t val) "Write diagnostic LED %04x"
+disable slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x"
+
+# hw/slavio_timer.c
+disable slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x"
+disable slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x"
+disable slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64""
+disable slavio_timer_mem_readl(uint64_t addr, uint32_t ret) "read %"PRIx64" = %08x"
+disable slavio_timer_mem_writel(uint64_t addr, uint32_t val) "write %"PRIx64" = %08x"
+disable slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64""
+disable slavio_timer_mem_writel_counter_invalid(void) "not user timer"
+disable slavio_timer_mem_writel_status_start(unsigned int timer_index) "processor %d user timer started"
+disable slavio_timer_mem_writel_status_stop(unsigned int timer_index) "processor %d user timer stopped"
+disable slavio_timer_mem_writel_mode_user(unsigned int timer_index) "processor %d changed from counter to user timer"
+disable slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d changed from user timer to counter"
+disable slavio_timer_mem_writel_mode_invalid(void) "not system timer"
+disable slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64""
+
+# hw/sparc32_dma.c
+disable ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64""
+disable ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64""
+disable sparc32_dma_set_irq_raise(void) "Raise IRQ"
+disable sparc32_dma_set_irq_lower(void) "Lower IRQ"
+disable espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x"
+disable espdma_memory_write(uint32_t addr) "DMA write addr 0x%08x"
+disable sparc32_dma_mem_readl(uint64_t addr, uint32_t ret) "read dmareg %"PRIx64": 0x%08x"
+disable sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg %"PRIx64": 0x%08x -> 0x%08x"
+disable sparc32_dma_enable_raise(void) "Raise DMA enable"
+disable sparc32_dma_enable_lower(void) "Lower DMA enable"
+
+# hw/sun4m.c
+disable sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d"
+disable sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d"
+disable sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d"
+disable sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d"
+
+# hw/sun4m_iommu.c
+disable sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x"
+disable sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x"
+disable sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64""
+disable sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush %x"
+disable sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x"
+disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x"
+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""
index 534cc709f48179783cb9160768700e01957db04f..701085837f6b83f68fbdde9c54751d2aaec3db18 100755 (executable)
--- a/tracetool
+++ b/tracetool
@@ -250,7 +250,7 @@ linetoh_ust()
     argnames=$(get_argnames "$1")
 
     cat <<EOF
-DECLARE_TRACE(ust_$name, TPPROTO($args), TPARGS($argnames));
+DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
 #define trace_$name trace_ust_$name
 EOF
 }
@@ -318,8 +318,7 @@ convert()
 
     while read -r str; do
         # Skip comments and empty lines
-        str=${str%%#*}
-        test -z "$str" && continue
+        test -z "${str%%#*}" && continue
 
         # Process the line.  The nop backend handles disabled lines.
         disable=${str%%disable *}
index ed3165e45e56efd4b28bb74d4d821a87a422470d..82bc614040590dd5379b9a7f4f7b508b1a1e305a 100644 (file)
@@ -238,9 +238,12 @@ static void curses_refresh(DisplayState *ds)
                 keysym = curses2keysym[chr];
 
             if (keysym == -1) {
-                if (chr < ' ')
-                    keysym = (chr + '@' - 'A' + 'a') | KEYSYM_CNTRL;
-                else
+                if (chr < ' ') {
+                    keysym = chr + '@';
+                    if (keysym >= 'A' && keysym <= 'Z')
+                        keysym += 'a' - 'A';
+                    keysym |= KEYSYM_CNTRL;
+                } else
                     keysym = chr;
             }
 
index 1decd1119d9ee436eb8239fd4059fd3385401a60..c0d5eb452fa4922dc4d10f5237607239c50ab604 100644 (file)
@@ -55,6 +55,7 @@ static const int curses2keysym[CURSES_KEYS] = {
     [0x7f] = KEY_BACKSPACE,
     ['\r'] = KEY_ENTER,
     ['\n'] = KEY_ENTER,
+    [27] = 27,
     [KEY_BTAB] = '\t' | KEYSYM_SHIFT,
 };
 
index 6702dfd7ea8f8ede96ddc35ba0b6dccd0a9b172b..7b4f5c1bc9a7266b435f950062828b17bd3d534e 100644 (file)
@@ -29,8 +29,7 @@
 
 static int debug = 0;
 
-static void __attribute__((format(printf,2,3)))
-dprint(int level, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...)
 {
     va_list args;
 
index c7a18311f089a47bb7dc43cecbf4a75078e775ee..864342e84d2d5d84e750218df408a2c803c1f64e 100644 (file)
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -214,13 +214,17 @@ static int vnc_server_info_put(QDict *qdict)
 
 static void vnc_client_cache_auth(VncState *client)
 {
+#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
     QDict *qdict;
+#endif
 
     if (!client->info) {
         return;
     }
 
+#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
     qdict = qobject_to_qdict(client->info);
+#endif
 
 #ifdef CONFIG_VNC_TLS
     if (client->tls.session &&
@@ -2523,7 +2527,9 @@ int vnc_display_open(DisplayState *ds, const char *display)
     int sasl = 0;
     int saslErr;
 #endif
+#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
     int acl = 0;
+#endif
     int lock_key_sync = 1;
 
     if (!vnc_display)
@@ -2581,8 +2587,10 @@ int vnc_display_open(DisplayState *ds, const char *display)
                 return -1;
             }
 #endif
+#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
         } else if (strncmp(options, "acl", 3) == 0) {
             acl = 1;
+#endif
         } else if (strncmp(options, "lossy", 5) == 0) {
             vs->lossy = true;
         }
diff --git a/vl.c b/vl.c
index df414ef5ac3e880b59675c7b9473fcc253e50740..7038952dc6be9fc31f4dcf4875be501911effb84 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -289,30 +289,6 @@ static int default_driver_check(QemuOpts *opts, void *opaque)
 /***********************************************************/
 /* real time host monotonic timer */
 
-/* compute with 96 bit intermediate result: (a*b)/c */
-uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
-{
-    union {
-        uint64_t ll;
-        struct {
-#ifdef HOST_WORDS_BIGENDIAN
-            uint32_t high, low;
-#else
-            uint32_t low, high;
-#endif
-        } l;
-    } u, res;
-    uint64_t rl, rh;
-
-    u.ll = a;
-    rl = (uint64_t)u.l.low * (uint64_t)b;
-    rh = (uint64_t)u.l.high * (uint64_t)b;
-    rh += (rl >> 32);
-    res.l.high = rh / c;
-    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
-    return res.ll;
-}
-
 /***********************************************************/
 /* host time/date access */
 void qemu_get_timedate(struct tm *tm, int offset)