Merge remote-tracking branch 'aneesh/for-upstream' into staging
* aneesh/for-upstream:
hw/9pfs: Remove O_NOATIME flag from 9pfs open() calls in readonly mode
hw/9pfs: Update MAINTAINERS file
fsdev: Fix parameter parsing for proxy helper
hw/9pfs: Fix crash when mounting with synthfs
hw/9pfs: Preserve S_ISGID
hw/9pfs: Add new security model mapped-file.
diff --git a/.gitignore b/.gitignore
index 406f75f..f5aab2c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,10 @@
qemu-monitor.texi
QMP/qmp-commands.txt
test-coroutine
+test-qmp-input-visitor
+test-qmp-output-visitor
+fsdev/virtfs-proxy-helper.1
+fsdev/virtfs-proxy-helper.pod
.gdbinit
*.a
*.aux
diff --git a/MAINTAINERS b/MAINTAINERS
index f9f131c..173e893 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -93,6 +93,7 @@
PowerPC
M: Alexander Graf <agraf@suse.de>
+L: qemu-ppc@nongnu.org
S: Maintained
F: target-ppc/
@@ -160,6 +161,26 @@
F: xen-*
F: */xen*
+Hosts:
+------
+
+LINUX
+L: qemu-devel@nongnu.org
+S: Maintained
+F: linux-*
+F: linux-headers/
+
+POSIX
+L: qemu-devel@nongnu.org
+S: Maintained
+F: *posix*
+
+W32, W64
+L: qemu-devel@nongnu.org
+M: Stefan Weil <sw@weilnetz.de>
+S: Maintained
+F: *win32*
+
ARM Machines
------------
Gumstix
@@ -290,23 +311,31 @@
----------------
405
M: Alexander Graf <agraf@suse.de>
+L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc405_boards.c
New World
M: Alexander Graf <agraf@suse.de>
+L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc_newworld.c
+F: hw/unin_pci.c
+F: hw/dec_pci.[hc]
Old World
M: Alexander Graf <agraf@suse.de>
+L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc_oldworld.c
+F: hw/grackle_pci.c
PReP
M: Andreas Färber <andreas.faerber@web.de>
+L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc_prep.c
+F: hw/prep_pci.[hc]
SH4 Machines
------------
diff --git a/Makefile b/Makefile
index 2bbc547..47acf3d 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,8 @@
LIBS+=-lz $(LIBS_TOOLS)
+HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
+
ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
DOCS+=fsdev/virtfs-proxy-helper.1
@@ -77,7 +79,7 @@
-include config-all-devices.mak
-build-all: $(DOCS) $(TOOLS) recurse-all
+build-all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
config-host.h: config-host.h-timestamp
config-host.h-timestamp: config-host.mak
@@ -114,6 +116,8 @@
QEMU_CFLAGS+=$(GLIB_CFLAGS)
+QEMU_CFLAGS += -I$(SRC_PATH)/include
+
ui/cocoa.o: ui/cocoa.m
ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
@@ -156,6 +160,8 @@
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
+qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
+
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
@@ -168,7 +174,9 @@
gen-out-type = $(subst .,-,$(suffix $@))
+ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/tests/Makefile
+endif
$(qapi-dir)/qga-qapi-types.c $(qapi-dir)/qga-qapi-types.h :\
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
@@ -203,7 +211,7 @@
# 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 *.lo $(TOOLS) qemu-ga TAGS cscope.* *.pod *~ */*~
+ rm -f *.o *.d *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
rm -Rf .libs
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
rm -f qemu-img-cmds.h
@@ -211,6 +219,7 @@
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
rm -f trace-dtrace.h trace-dtrace.h-timestamp
+ rm -f $(GENERATED_HEADERS)
rm -f $(GENERATED_SOURCES)
rm -rf $(qapi-dir)
$(MAKE) -C tests/tcg clean
@@ -228,6 +237,7 @@
rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
rm -f qemu-doc.vr
rm -f config.log
+ rm -f linux-headers/asm
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
for d in $(TARGET_DIRS) $(QEMULIBS); do \
rm -rf $$d || exit 1 ; \
@@ -275,6 +285,10 @@
ifneq ($(TOOLS),)
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
endif
+ifneq ($(HELPERS-y),)
+ $(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
+ $(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
+endif
ifneq ($(BLOBS),)
$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
set -e; for x in $(BLOBS); do \
diff --git a/Makefile.hw b/Makefile.hw
index 63eb7e4..7b8d068 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -11,6 +11,7 @@
QEMU_CFLAGS+=-I..
QEMU_CFLAGS += $(GLIB_CFLAGS)
+QEMU_CFLAGS += -I$(SRC_PATH)/include
include $(SRC_PATH)/Makefile.objs
diff --git a/Makefile.objs b/Makefile.objs
index 4f6d26c..ec35320 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -13,6 +13,7 @@
#######################################################################
# coroutines
coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
+coroutine-obj-y += qemu-coroutine-sleep.o
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
else
@@ -34,6 +35,7 @@
block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-nested-y += qed-check.o
block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
+block-nested-y += stream.o
block-nested-$(CONFIG_WIN32) += raw-win32.o
block-nested-$(CONFIG_POSIX) += raw-posix.o
block-nested-$(CONFIG_LIBISCSI) += iscsi.o
@@ -102,7 +104,7 @@
common-obj-y += scsi-generic.o scsi-bus.o
common-obj-y += hid.o
common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
-common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
+common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o usb-audio.o
common-obj-$(CONFIG_SSI) += ssi.o
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
common-obj-$(CONFIG_SD) += sd.o
@@ -111,7 +113,7 @@
common-obj-y += buffered_file.o migration.o migration-tcp.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += msmouse.o ps2.o
-common-obj-y += qdev.o qdev-properties.o
+common-obj-y += qdev.o qdev-properties.o qdev-monitor.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += pflib.o
common-obj-y += bitmap.o bitops.o
@@ -122,6 +124,9 @@
common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o spice-qemu-char.o
+include $(SRC_PATH)/qom/Makefile
+common-obj-y += $(addprefix qom/, $(qom-y))
+
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
audio-obj-$(CONFIG_OSS) += ossaudio.o
@@ -211,19 +216,22 @@
hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
+hw-obj-$(CONFIG_USB_XHCI) += usb-xhci.o
hw-obj-$(CONFIG_FDC) += fdc.o
hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
hw-obj-$(CONFIG_DMA) += dma.o
+hw-obj-$(CONFIG_I82374) += i82374.o
hw-obj-$(CONFIG_HPET) += hpet.o
hw-obj-$(CONFIG_APPLESMC) += applesmc.o
hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
-hw-obj-$(CONFIG_I8259) += i8259.o
+hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
# PPC devices
hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
+hw-obj-$(CONFIG_I82378) += i82378.o
# Mac shared devices
hw-obj-$(CONFIG_MACIO) += macio.o
hw-obj-$(CONFIG_CUDA) += cuda.o
@@ -278,7 +286,7 @@
hw-obj-$(CONFIG_ESP) += esp.o
hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
-hw-obj-y += qdev-addr.o container.o
+hw-obj-y += qdev-addr.o
# VGA
hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
@@ -286,6 +294,7 @@
hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
+hw-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
hw-obj-$(CONFIG_RC4030) += rc4030.o
hw-obj-$(CONFIG_DP8393X) += dp8393x.o
diff --git a/Makefile.target b/Makefile.target
index 06d79b8..7ed4979 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -22,15 +22,24 @@
include $(SRC_PATH)/Makefile.objs
+QEMU_CFLAGS+=-I$(SRC_PATH)/include
+
ifdef CONFIG_USER_ONLY
# user emulator name
QEMU_PROG=qemu-$(TARGET_ARCH2)
else
# system emulator name
+ifneq (,$(findstring -mwindows,$(LIBS)))
+# Terminate program name with a 'w' because the linker builds a windows executable.
+QEMU_PROGW=qemu-system-$(TARGET_ARCH2)w$(EXESUF)
+endif # windows executable
QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
endif
PROGS=$(QEMU_PROG)
+ifdef QEMU_PROGW
+PROGS+=$(QEMU_PROGW)
+endif
STPFILES=
ifndef CONFIG_HAIKU
@@ -196,9 +205,12 @@
obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
+obj-$(CONFIG_VGA) += vga.o
obj-y += memory.o savevm.o
LIBS+=-lz
+obj-i386-$(CONFIG_KVM) += hyperv.o
+
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
@@ -224,19 +236,17 @@
obj-y += device-hotplug.o
# Hardware support
-obj-i386-y += vga.o
obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o
obj-i386-y += vmport.o
obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += debugcon.o multiboot.o
obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvmclock.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
# shared objects
obj-ppc-y = ppc.o ppc_booke.o
-obj-ppc-y += vga.o
# PREP target
obj-ppc-y += mc146818rtc.o
obj-ppc-y += ppc_prep.o
@@ -250,7 +260,7 @@
obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o
# PowerPC 4xx boards
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
-obj-ppc-y += ppc440.o ppc440_bamboo.o
+obj-ppc-y += ppc440_bamboo.o
# PowerPC E500 boards
obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
# PowerPC 440 Xilinx ML507 reference board.
@@ -290,10 +300,8 @@
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
obj-mips-y += mips_addr.o mips_timer.o mips_int.o
-obj-mips-y += vga.o
obj-mips-y += jazz_led.o
obj-mips-y += gt64xxx.o mc146818rtc.o
-obj-mips-y += cirrus_vga.o
obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
obj-microblaze-y = petalogix_s3adsp1800_mmu.o
@@ -323,9 +331,7 @@
ifeq ($(TARGET_ARCH), sparc64)
obj-sparc-y = sun4u.o apb_pci.o
-obj-sparc-y += vga.o
obj-sparc-y += mc146818rtc.o
-obj-sparc-y += cirrus_vga.o
else
obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
@@ -342,7 +348,9 @@
obj-arm-y += arm_l2x0.o
obj-arm-y += arm_mptimer.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
+obj-arm-y += highbank.o
obj-arm-y += pl061.o
+obj-arm-y += xgmac.o
obj-arm-y += arm-semi.o
obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
@@ -353,7 +361,7 @@
obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
obj-arm-y += omap_sx1.o palm.o tsc210x.o
-obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
+obj-arm-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb-musb.o
obj-arm-y += mst_fpga.o mainstone.o
obj-arm-y += z2.o
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
@@ -373,7 +381,6 @@
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
obj-alpha-y = mc146818rtc.o
-obj-alpha-y += vga.o cirrus_vga.o
obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
obj-xtensa-y += xtensa_pic.o
@@ -407,9 +414,16 @@
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
+ifdef QEMU_PROGW
+# The linker builds a windows executable. Make also a console executable.
+$(QEMU_PROGW): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
+ $(call LINK,$^)
+$(QEMU_PROG): $(QEMU_PROGW)
+ $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
+else
$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
$(call LINK,$^)
-
+endif
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
@@ -422,7 +436,7 @@
clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
- rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
+ rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o kvm/*.o
rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
ifdef CONFIG_TRACE_SYSTEMTAP
rm -f *.stp
diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index af586ec..06cb404 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -264,3 +264,56 @@
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events.
+
+
+BLOCK_JOB_COMPLETED
+-------------------
+
+Emitted when a block job has completed.
+
+Data:
+
+- "type": Job type ("stream" for image streaming, json-string)
+- "device": Device name (json-string)
+- "len": Maximum progress value (json-int)
+- "offset": Current progress value (json-int)
+ On success this is equal to len.
+ On failure this is less than len.
+- "speed": Rate limit, bytes per second (json-int)
+- "error": Error message (json-string, optional)
+ Only present on failure. This field contains a human-readable
+ error message. There are no semantics other than that streaming
+ has failed and clients should not try to interpret the error
+ string.
+
+Example:
+
+{ "event": "BLOCK_JOB_COMPLETED",
+ "data": { "type": "stream", "device": "virtio-disk0",
+ "len": 10737418240, "offset": 10737418240,
+ "speed": 0 },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+
+BLOCK_JOB_CANCELLED
+-------------------
+
+Emitted when a block job has been cancelled.
+
+Data:
+
+- "type": Job type ("stream" for image streaming, json-string)
+- "device": Device name (json-string)
+- "len": Maximum progress value (json-int)
+- "offset": Current progress value (json-int)
+ On success this is equal to len.
+ On failure this is less than len.
+- "speed": Rate limit, bytes per second (json-int)
+
+Example:
+
+{ "event": "BLOCK_JOB_CANCELLED",
+ "data": { "type": "stream", "device": "virtio-disk0",
+ "len": 10737418240, "offset": 134217728,
+ "speed": 0 },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
diff --git a/arch_init.c b/arch_init.c
index 95ac682..699bdd1 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -141,7 +141,8 @@
do {
mr = block->mr;
- if (memory_region_get_dirty(mr, offset, DIRTY_MEMORY_MIGRATION)) {
+ if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION)) {
uint8_t *p;
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
@@ -198,7 +199,7 @@
QLIST_FOREACH(block, &ram_list.blocks, next) {
ram_addr_t addr;
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
- if (memory_region_get_dirty(block->mr, addr,
+ if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
count++;
}
@@ -283,9 +284,9 @@
/* Make sure all dirty bits are set */
QLIST_FOREACH(block, &ram_list.blocks, next) {
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
- if (!memory_region_get_dirty(block->mr, addr,
+ if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
- memory_region_set_dirty(block->mr, addr);
+ memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
}
}
}
diff --git a/block.c b/block.c
index 3f072f6..3621d11 100644
--- a/block.c
+++ b/block.c
@@ -48,6 +48,10 @@
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
+typedef enum {
+ BDRV_REQ_COPY_ON_READ = 0x1,
+} BdrvRequestFlags;
+
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
@@ -62,7 +66,8 @@
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+ BdrvRequestFlags flags);
static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
@@ -1020,6 +1025,10 @@
return -EACCES;
}
+ if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) {
+ return -EBUSY;
+ }
+
backing_drv = bs->backing_hd->drv;
ro = bs->backing_hd->read_only;
strncpy(filename, bs->backing_hd->filename, sizeof(filename));
@@ -1288,7 +1297,7 @@
if (!rwco->is_write) {
rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num,
- rwco->nb_sectors, rwco->qiov);
+ rwco->nb_sectors, rwco->qiov, 0);
} else {
rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
rwco->nb_sectors, rwco->qiov);
@@ -1496,7 +1505,7 @@
return 0;
}
-static int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{
/* Perform I/O through a temporary buffer so that users who scribble over
@@ -1519,8 +1528,8 @@
round_to_clusters(bs, sector_num, nb_sectors,
&cluster_sector_num, &cluster_nb_sectors);
- trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors,
- cluster_sector_num, cluster_nb_sectors);
+ trace_bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors,
+ cluster_sector_num, cluster_nb_sectors);
iov.iov_len = cluster_nb_sectors * BDRV_SECTOR_SIZE;
iov.iov_base = bounce_buffer = qemu_blockalign(bs, iov.iov_len);
@@ -1555,7 +1564,8 @@
* Handle a read request in coroutine context
*/
static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+ BdrvRequestFlags flags)
{
BlockDriver *drv = bs->drv;
BdrvTrackedRequest req;
@@ -1574,12 +1584,19 @@
}
if (bs->copy_on_read) {
+ flags |= BDRV_REQ_COPY_ON_READ;
+ }
+ if (flags & BDRV_REQ_COPY_ON_READ) {
+ bs->copy_on_read_in_flight++;
+ }
+
+ if (bs->copy_on_read_in_flight) {
wait_for_overlapping_requests(bs, sector_num, nb_sectors);
}
tracked_request_begin(&req, bs, sector_num, nb_sectors, false);
- if (bs->copy_on_read) {
+ if (flags & BDRV_REQ_COPY_ON_READ) {
int pnum;
ret = bdrv_co_is_allocated(bs, sector_num, nb_sectors, &pnum);
@@ -1588,7 +1605,7 @@
}
if (!ret || pnum != nb_sectors) {
- ret = bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, qiov);
+ ret = bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors, qiov);
goto out;
}
}
@@ -1597,6 +1614,11 @@
out:
tracked_request_end(&req);
+
+ if (flags & BDRV_REQ_COPY_ON_READ) {
+ bs->copy_on_read_in_flight--;
+ }
+
return ret;
}
@@ -1605,7 +1627,16 @@
{
trace_bdrv_co_readv(bs, sector_num, nb_sectors);
- return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov);
+ return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, 0);
+}
+
+int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+{
+ trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors);
+
+ return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov,
+ BDRV_REQ_COPY_ON_READ);
}
/*
@@ -1633,7 +1664,7 @@
bdrv_io_limits_intercept(bs, true, nb_sectors);
}
- if (bs->copy_on_read) {
+ if (bs->copy_on_read_in_flight) {
wait_for_overlapping_requests(bs, sector_num, nb_sectors);
}
@@ -2564,6 +2595,24 @@
return -ENOTSUP;
}
+BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
+ const char *backing_file)
+{
+ if (!bs->drv) {
+ return NULL;
+ }
+
+ if (bs->backing_hd) {
+ if (strcmp(bs->backing_file, backing_file) == 0) {
+ return bs->backing_hd;
+ } else {
+ return bdrv_find_backing_image(bs->backing_hd, backing_file);
+ }
+ }
+
+ return NULL;
+}
+
#define NB_SUFFIXES 4
char *get_human_readable_size(char *buf, int buf_size, int64_t size)
@@ -3140,7 +3189,7 @@
if (!acb->is_write) {
acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
- acb->req.nb_sectors, acb->req.qiov);
+ acb->req.nb_sectors, acb->req.qiov, 0);
} else {
acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
acb->req.nb_sectors, acb->req.qiov);
@@ -3827,3 +3876,51 @@
return ret;
}
+
+void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockJob *job;
+
+ if (bs->job || bdrv_in_use(bs)) {
+ return NULL;
+ }
+ bdrv_set_in_use(bs, 1);
+
+ job = g_malloc0(job_type->instance_size);
+ job->job_type = job_type;
+ job->bs = bs;
+ job->cb = cb;
+ job->opaque = opaque;
+ bs->job = job;
+ return job;
+}
+
+void block_job_complete(BlockJob *job, int ret)
+{
+ BlockDriverState *bs = job->bs;
+
+ assert(bs->job == job);
+ job->cb(job->opaque, ret);
+ bs->job = NULL;
+ g_free(job);
+ bdrv_set_in_use(bs, 0);
+}
+
+int block_job_set_speed(BlockJob *job, int64_t value)
+{
+ if (!job->job_type->set_speed) {
+ return -ENOTSUP;
+ }
+ return job->job_type->set_speed(job, value);
+}
+
+void block_job_cancel(BlockJob *job)
+{
+ job->cancelled = true;
+}
+
+bool block_job_is_cancelled(BlockJob *job)
+{
+ return job->cancelled;
+}
diff --git a/block.h b/block.h
index 3bd4398..cae289b 100644
--- a/block.h
+++ b/block.h
@@ -142,10 +142,14 @@
const void *buf, int count);
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov);
+int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
+BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
+ const char *backing_file);
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
int64_t bdrv_getlength(BlockDriverState *bs);
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 9b88535..a251802 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -292,10 +292,10 @@
return -EINVAL;
}
- config = strdup(filename);
+ config = g_strdup(filename);
config[c - filename] = '\0';
ret = read_config(s, config);
- free(config);
+ g_free(config);
if (ret < 0) {
return ret;
}
diff --git a/block/blkverify.c b/block/blkverify.c
index 4ca8584..9d5f1ec 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -87,10 +87,10 @@
return -EINVAL;
}
- raw = strdup(filename);
+ raw = g_strdup(filename);
raw[c - filename] = '\0';
ret = bdrv_file_open(&bs->file, raw, flags);
- free(raw);
+ g_free(raw);
if (ret < 0) {
return ret;
}
diff --git a/block/qcow.c b/block/qcow.c
index b16955d..b1cfe1f 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -95,11 +95,13 @@
static int qcow_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
- int len, i, shift;
+ int len, i, shift, ret;
QCowHeader header;
- if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header))
+ ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
+ if (ret < 0) {
goto fail;
+ }
be32_to_cpus(&header.magic);
be32_to_cpus(&header.version);
be64_to_cpus(&header.backing_file_offset);
@@ -109,15 +111,31 @@
be32_to_cpus(&header.crypt_method);
be64_to_cpus(&header.l1_table_offset);
- if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
+ if (header.magic != QCOW_MAGIC) {
+ ret = -EINVAL;
goto fail;
- if (header.size <= 1 || header.cluster_bits < 9)
+ }
+ if (header.version != QCOW_VERSION) {
+ char version[64];
+ snprintf(version, sizeof(version), "QCOW version %d", header.version);
+ qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+ bs->device_name, "qcow", version);
+ ret = -ENOTSUP;
goto fail;
- if (header.crypt_method > QCOW_CRYPT_AES)
+ }
+
+ if (header.size <= 1 || header.cluster_bits < 9) {
+ ret = -EINVAL;
goto fail;
+ }
+ if (header.crypt_method > QCOW_CRYPT_AES) {
+ ret = -EINVAL;
+ goto fail;
+ }
s->crypt_method_header = header.crypt_method;
- if (s->crypt_method_header)
+ if (s->crypt_method_header) {
bs->encrypted = 1;
+ }
s->cluster_bits = header.cluster_bits;
s->cluster_size = 1 << s->cluster_bits;
s->cluster_sectors = 1 << (s->cluster_bits - 9);
@@ -132,33 +150,33 @@
s->l1_table_offset = header.l1_table_offset;
s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
- if (!s->l1_table)
+
+ ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
+ s->l1_size * sizeof(uint64_t));
+ if (ret < 0) {
goto fail;
- if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
- s->l1_size * sizeof(uint64_t))
- goto fail;
+ }
+
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
/* alloc L2 cache */
s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
- if (!s->l2_cache)
- goto fail;
s->cluster_cache = g_malloc(s->cluster_size);
- if (!s->cluster_cache)
- goto fail;
s->cluster_data = g_malloc(s->cluster_size);
- if (!s->cluster_data)
- goto fail;
s->cluster_cache_offset = -1;
/* read the backing file name */
if (header.backing_file_offset != 0) {
len = header.backing_file_size;
- if (len > 1023)
+ if (len > 1023) {
len = 1023;
- if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
+ }
+ ret = bdrv_pread(bs->file, header.backing_file_offset,
+ bs->backing_file, len);
+ if (ret < 0) {
goto fail;
+ }
bs->backing_file[len] = '\0';
}
@@ -176,7 +194,7 @@
g_free(s->l2_cache);
g_free(s->cluster_cache);
g_free(s->cluster_data);
- return -1;
+ return ret;
}
static int qcow_set_key(BlockDriverState *bs, const char *key)
@@ -626,13 +644,14 @@
static int qcow_create(const char *filename, QEMUOptionParameter *options)
{
- int fd, header_size, backing_filename_len, l1_size, i, shift;
+ int header_size, backing_filename_len, l1_size, shift, i;
QCowHeader header;
- uint64_t tmp;
+ uint8_t *tmp;
int64_t total_size = 0;
const char *backing_file = NULL;
int flags = 0;
int ret;
+ BlockDriverState *qcow_bs;
/* Read out options */
while (options && options->name) {
@@ -646,9 +665,21 @@
options++;
}
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
- if (fd < 0)
- return -errno;
+ ret = bdrv_create_file(filename, options);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = bdrv_file_open(&qcow_bs, filename, BDRV_O_RDWR);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = bdrv_truncate(qcow_bs, 0);
+ if (ret < 0) {
+ goto exit;
+ }
+
memset(&header, 0, sizeof(header));
header.magic = cpu_to_be32(QCOW_MAGIC);
header.version = cpu_to_be32(QCOW_VERSION);
@@ -684,33 +715,34 @@
}
/* write all the data */
- ret = qemu_write_full(fd, &header, sizeof(header));
+ ret = bdrv_pwrite(qcow_bs, 0, &header, sizeof(header));
if (ret != sizeof(header)) {
- ret = -errno;
goto exit;
}
if (backing_file) {
- ret = qemu_write_full(fd, backing_file, backing_filename_len);
+ ret = bdrv_pwrite(qcow_bs, sizeof(header),
+ backing_file, backing_filename_len);
if (ret != backing_filename_len) {
- ret = -errno;
- goto exit;
- }
-
- }
- lseek(fd, header_size, 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;
}
}
+ tmp = g_malloc0(BDRV_SECTOR_SIZE);
+ for (i = 0; i < ((sizeof(uint64_t)*l1_size + BDRV_SECTOR_SIZE - 1)/
+ BDRV_SECTOR_SIZE); i++) {
+ ret = bdrv_pwrite(qcow_bs, header_size +
+ BDRV_SECTOR_SIZE*i, tmp, BDRV_SECTOR_SIZE);
+ if (ret != BDRV_SECTOR_SIZE) {
+ g_free(tmp);
+ goto exit;
+ }
+ }
+
+ g_free(tmp);
ret = 0;
exit:
- close(fd);
+ bdrv_delete(qcow_bs);
return ret;
}
diff --git a/block/rbd.c b/block/rbd.c
index db5abf2..46a8579 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -789,6 +789,26 @@
return 0;
}
+static int qemu_rbd_snap_remove(BlockDriverState *bs,
+ const char *snapshot_name)
+{
+ BDRVRBDState *s = bs->opaque;
+ int r;
+
+ r = rbd_snap_remove(s->image, snapshot_name);
+ return r;
+}
+
+static int qemu_rbd_snap_rollback(BlockDriverState *bs,
+ const char *snapshot_name)
+{
+ BDRVRBDState *s = bs->opaque;
+ int r;
+
+ r = rbd_snap_rollback(s->image, snapshot_name);
+ return r;
+}
+
static int qemu_rbd_snap_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_tab)
{
@@ -862,7 +882,9 @@
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
.bdrv_snapshot_create = qemu_rbd_snap_create,
+ .bdrv_snapshot_delete = qemu_rbd_snap_remove,
.bdrv_snapshot_list = qemu_rbd_snap_list,
+ .bdrv_snapshot_goto = qemu_rbd_snap_rollback,
};
static void bdrv_rbd_init(void)
diff --git a/block/stream.c b/block/stream.c
new file mode 100644
index 0000000..d1b3986
--- /dev/null
+++ b/block/stream.c
@@ -0,0 +1,269 @@
+/*
+ * Image streaming
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "trace.h"
+#include "block_int.h"
+
+enum {
+ /*
+ * Size of data buffer for populating the image file. This should be large
+ * enough to process multiple clusters in a single call, so that populating
+ * contiguous regions of the image is efficient.
+ */
+ STREAM_BUFFER_SIZE = 512 * 1024, /* in bytes */
+};
+
+#define SLICE_TIME 100000000ULL /* ns */
+
+typedef struct {
+ int64_t next_slice_time;
+ uint64_t slice_quota;
+ uint64_t dispatched;
+} RateLimit;
+
+static int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
+{
+ int64_t delay_ns = 0;
+ int64_t now = qemu_get_clock_ns(rt_clock);
+
+ if (limit->next_slice_time < now) {
+ limit->next_slice_time = now + SLICE_TIME;
+ limit->dispatched = 0;
+ }
+ if (limit->dispatched + n > limit->slice_quota) {
+ delay_ns = limit->next_slice_time - now;
+ } else {
+ limit->dispatched += n;
+ }
+ return delay_ns;
+}
+
+static void ratelimit_set_speed(RateLimit *limit, uint64_t speed)
+{
+ limit->slice_quota = speed / (1000000000ULL / SLICE_TIME);
+}
+
+typedef struct StreamBlockJob {
+ BlockJob common;
+ RateLimit limit;
+ BlockDriverState *base;
+ char backing_file_id[1024];
+} StreamBlockJob;
+
+static int coroutine_fn stream_populate(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors,
+ void *buf)
+{
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = nb_sectors * BDRV_SECTOR_SIZE,
+ };
+ QEMUIOVector qiov;
+
+ qemu_iovec_init_external(&qiov, &iov, 1);
+
+ /* Copy-on-read the unallocated clusters */
+ return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov);
+}
+
+/*
+ * Given an image chain: [BASE] -> [INTER1] -> [INTER2] -> [TOP]
+ *
+ * Return true if the given sector is allocated in top.
+ * Return false if the given sector is allocated in intermediate images.
+ * Return true otherwise.
+ *
+ * 'pnum' is set to the number of sectors (including and immediately following
+ * the specified sector) that are known to be in the same
+ * allocated/unallocated state.
+ *
+ */
+static int coroutine_fn is_allocated_base(BlockDriverState *top,
+ BlockDriverState *base,
+ int64_t sector_num,
+ int nb_sectors, int *pnum)
+{
+ BlockDriverState *intermediate;
+ int ret, n;
+
+ ret = bdrv_co_is_allocated(top, sector_num, nb_sectors, &n);
+ if (ret) {
+ *pnum = n;
+ return ret;
+ }
+
+ /*
+ * Is the unallocated chunk [sector_num, n] also
+ * unallocated between base and top?
+ */
+ intermediate = top->backing_hd;
+
+ while (intermediate) {
+ int pnum_inter;
+
+ /* reached base */
+ if (intermediate == base) {
+ *pnum = n;
+ return 1;
+ }
+ ret = bdrv_co_is_allocated(intermediate, sector_num, nb_sectors,
+ &pnum_inter);
+ if (ret < 0) {
+ return ret;
+ } else if (ret) {
+ *pnum = pnum_inter;
+ return 0;
+ }
+
+ /*
+ * [sector_num, nb_sectors] is unallocated on top but intermediate
+ * might have
+ *
+ * [sector_num+x, nr_sectors] allocated.
+ */
+ if (n > pnum_inter) {
+ n = pnum_inter;
+ }
+
+ intermediate = intermediate->backing_hd;
+ }
+
+ return 1;
+}
+
+static void coroutine_fn stream_run(void *opaque)
+{
+ StreamBlockJob *s = opaque;
+ BlockDriverState *bs = s->common.bs;
+ BlockDriverState *base = s->base;
+ int64_t sector_num, end;
+ int ret = 0;
+ int n;
+ void *buf;
+
+ s->common.len = bdrv_getlength(bs);
+ if (s->common.len < 0) {
+ block_job_complete(&s->common, s->common.len);
+ return;
+ }
+
+ end = s->common.len >> BDRV_SECTOR_BITS;
+ buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE);
+
+ /* Turn on copy-on-read for the whole block device so that guest read
+ * requests help us make progress. Only do this when copying the entire
+ * backing chain since the copy-on-read operation does not take base into
+ * account.
+ */
+ if (!base) {
+ bdrv_enable_copy_on_read(bs);
+ }
+
+ for (sector_num = 0; sector_num < end; sector_num += n) {
+retry:
+ if (block_job_is_cancelled(&s->common)) {
+ break;
+ }
+
+
+ if (base) {
+ ret = is_allocated_base(bs, base, sector_num,
+ STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
+ } else {
+ ret = bdrv_co_is_allocated(bs, sector_num,
+ STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE,
+ &n);
+ }
+ trace_stream_one_iteration(s, sector_num, n, ret);
+ if (ret == 0) {
+ if (s->common.speed) {
+ uint64_t delay_ns = ratelimit_calculate_delay(&s->limit, n);
+ if (delay_ns > 0) {
+ co_sleep_ns(rt_clock, delay_ns);
+
+ /* Recheck cancellation and that sectors are unallocated */
+ goto retry;
+ }
+ }
+ ret = stream_populate(bs, sector_num, n, buf);
+ }
+ if (ret < 0) {
+ break;
+ }
+ ret = 0;
+
+ /* Publish progress */
+ s->common.offset += n * BDRV_SECTOR_SIZE;
+
+ /* Note that even when no rate limit is applied we need to yield
+ * with no pending I/O here so that qemu_aio_flush() returns.
+ */
+ co_sleep_ns(rt_clock, 0);
+ }
+
+ if (!base) {
+ bdrv_disable_copy_on_read(bs);
+ }
+
+ if (sector_num == end && ret == 0) {
+ const char *base_id = NULL;
+ if (base) {
+ base_id = s->backing_file_id;
+ }
+ ret = bdrv_change_backing_file(bs, base_id, NULL);
+ }
+
+ qemu_vfree(buf);
+ block_job_complete(&s->common, ret);
+}
+
+static int stream_set_speed(BlockJob *job, int64_t value)
+{
+ StreamBlockJob *s = container_of(job, StreamBlockJob, common);
+
+ if (value < 0) {
+ return -EINVAL;
+ }
+ job->speed = value;
+ ratelimit_set_speed(&s->limit, value / BDRV_SECTOR_SIZE);
+ return 0;
+}
+
+static BlockJobType stream_job_type = {
+ .instance_size = sizeof(StreamBlockJob),
+ .job_type = "stream",
+ .set_speed = stream_set_speed,
+};
+
+int stream_start(BlockDriverState *bs, BlockDriverState *base,
+ const char *base_id, BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ StreamBlockJob *s;
+ Coroutine *co;
+
+ s = block_job_create(&stream_job_type, bs, cb, opaque);
+ if (!s) {
+ return -EBUSY; /* bs must already be in use */
+ }
+
+ s->base = base;
+ if (base_id) {
+ pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
+ }
+
+ co = qemu_coroutine_create(stream_run);
+ trace_stream_start(bs, base, s, co, opaque);
+ qemu_coroutine_enter(co, s);
+ return 0;
+}
diff --git a/block/vdi.c b/block/vdi.c
index 31cdfab..6a0011f 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -1,7 +1,7 @@
/*
* Block driver for the Virtual Disk Image (VDI) format
*
- * Copyright (c) 2009 Stefan Weil
+ * Copyright (c) 2009, 2012 Stefan Weil
*
* 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
@@ -756,15 +756,19 @@
(uint64_t)bmap_entry * s->block_sectors;
block = acb->block_buffer;
if (block == NULL) {
- block = g_malloc0(s->block_size);
+ block = g_malloc(s->block_size);
acb->block_buffer = block;
acb->bmap_first = block_index;
assert(!acb->header_modified);
acb->header_modified = 1;
}
acb->bmap_last = block_index;
+ /* Copy data to be written to new block and zero unused parts. */
+ memset(block, 0, sector_in_block * SECTOR_SIZE);
memcpy(block + sector_in_block * SECTOR_SIZE,
acb->buf, n_sectors * SECTOR_SIZE);
+ memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
+ (s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
acb->hd_iov.iov_base = (void *)block;
acb->hd_iov.iov_len = s->block_size;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
diff --git a/block_int.h b/block_int.h
index 311bd2a..7be2988 100644
--- a/block_int.h
+++ b/block_int.h
@@ -69,6 +69,36 @@
uint64_t ios[2];
} BlockIOBaseValue;
+typedef void BlockJobCancelFunc(void *opaque);
+typedef struct BlockJob BlockJob;
+typedef struct BlockJobType {
+ /** Derived BlockJob struct size */
+ size_t instance_size;
+
+ /** String describing the operation, part of query-block-jobs QMP API */
+ const char *job_type;
+
+ /** Optional callback for job types that support setting a speed limit */
+ int (*set_speed)(BlockJob *job, int64_t value);
+} BlockJobType;
+
+/**
+ * Long-running operation on a BlockDriverState
+ */
+struct BlockJob {
+ const BlockJobType *job_type;
+ BlockDriverState *bs;
+ bool cancelled;
+
+ /* These fields are published by the query-block-jobs QMP API */
+ int64_t offset;
+ int64_t len;
+ int64_t speed;
+
+ BlockDriverCompletionFunc *cb;
+ void *opaque;
+};
+
struct BlockDriver {
const char *format_name;
int instance_size;
@@ -218,6 +248,9 @@
BlockDriverState *backing_hd;
BlockDriverState *file;
+ /* number of in-flight copy-on-read requests */
+ unsigned int copy_on_read_in_flight;
+
/* async read/write emulation */
void *sync_aiocb;
@@ -261,6 +294,9 @@
void *private;
QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
+
+ /* long-running background operation */
+ BlockJob *job;
};
struct BlockDriverAIOCB {
@@ -284,4 +320,15 @@
int is_windows_drive(const char *filename);
#endif
+void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
+void block_job_complete(BlockJob *job, int ret);
+int block_job_set_speed(BlockJob *job, int64_t value);
+void block_job_cancel(BlockJob *job);
+bool block_job_is_cancelled(BlockJob *job);
+
+int stream_start(BlockDriverState *bs, BlockDriverState *base,
+ const char *base_id, BlockDriverCompletionFunc *cb,
+ void *opaque);
+
#endif /* BLOCK_INT_H */
diff --git a/blockdev.c b/blockdev.c
index c832782..7a6613a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -13,9 +13,12 @@
#include "qerror.h"
#include "qemu-option.h"
#include "qemu-config.h"
+#include "qemu-objects.h"
#include "sysemu.h"
#include "block_int.h"
#include "qmp-commands.h"
+#include "trace.h"
+#include "arch_init.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@@ -200,6 +203,37 @@
dinfo->refcount++;
}
+typedef struct {
+ QEMUBH *bh;
+ DriveInfo *dinfo;
+} DrivePutRefBH;
+
+static void drive_put_ref_bh(void *opaque)
+{
+ DrivePutRefBH *s = opaque;
+
+ drive_put_ref(s->dinfo);
+ qemu_bh_delete(s->bh);
+ g_free(s);
+}
+
+/*
+ * Release a drive reference in a BH
+ *
+ * It is not possible to use drive_put_ref() from a callback function when the
+ * callers still need the drive. In such cases we schedule a BH to release the
+ * reference.
+ */
+static void drive_put_ref_bh_schedule(DriveInfo *dinfo)
+{
+ DrivePutRefBH *s;
+
+ s = g_new(DrivePutRefBH, 1);
+ s->bh = qemu_bh_new(drive_put_ref_bh, s);
+ s->dinfo = dinfo;
+ qemu_bh_schedule(s->bh);
+}
+
static int parse_block_error_action(const char *buf, int is_read)
{
if (!strcmp(buf, "ignore")) {
@@ -532,7 +566,11 @@
case IF_VIRTIO:
/* add virtio block device */
opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
- qemu_opt_set(opts, "driver", "virtio-blk");
+ if (arch_type == QEMU_ARCH_S390X) {
+ qemu_opt_set(opts, "driver", "virtio-blk-s390");
+ } else {
+ qemu_opt_set(opts, "driver", "virtio-blk-pci");
+ }
qemu_opt_set(opts, "drive", dinfo->id);
if (devaddr)
qemu_opt_set(opts, "addr", devaddr);
@@ -592,12 +630,18 @@
if (!strcmp(device, "all")) {
bdrv_commit_all();
} else {
+ int ret;
+
bs = bdrv_find(device);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, device);
return;
}
- bdrv_commit(bs);
+ ret = bdrv_commit(bs);
+ if (ret == -EBUSY) {
+ qerror_report(QERR_DEVICE_IN_USE, device);
+ return;
+ }
}
}
@@ -616,6 +660,10 @@
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
+ if (bdrv_in_use(bs)) {
+ error_set(errp, QERR_DEVICE_IN_USE, device);
+ return;
+ }
pstrcpy(old_filename, sizeof(old_filename), bs->filename);
@@ -665,35 +713,39 @@
}
}
-static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
+static void eject_device(BlockDriverState *bs, int force, Error **errp)
{
- if (!bdrv_dev_has_removable_media(bs)) {
- qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
- return -1;
+ if (bdrv_in_use(bs)) {
+ error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
+ return;
}
+ if (!bdrv_dev_has_removable_media(bs)) {
+ error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
+ return;
+ }
+
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
bdrv_dev_eject_request(bs, force);
if (!force) {
- qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
- return -1;
+ error_set(errp, QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+ return;
}
}
+
bdrv_close(bs);
- return 0;
}
-int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
{
BlockDriverState *bs;
- int force = qdict_get_try_bool(qdict, "force", 0);
- const char *filename = qdict_get_str(qdict, "device");
- bs = bdrv_find(filename);
+ bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, filename);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- return eject_device(mon, bs, force);
+
+ eject_device(bs, force, errp);
}
void qmp_block_passwd(const char *device, const char *password, Error **errp)
@@ -717,78 +769,87 @@
}
}
-int do_change_block(Monitor *mon, const char *device,
- const char *filename, const char *fmt)
+static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
+ int bdrv_flags, BlockDriver *drv,
+ const char *password, Error **errp)
+{
+ if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, filename);
+ return;
+ }
+
+ if (bdrv_key_required(bs)) {
+ if (password) {
+ if (bdrv_set_key(bs, password) < 0) {
+ error_set(errp, QERR_INVALID_PASSWORD);
+ }
+ } else {
+ error_set(errp, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+ bdrv_get_encrypted_filename(bs));
+ }
+ } else if (password) {
+ error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
+ }
+}
+
+void qmp_change_blockdev(const char *device, const char *filename,
+ bool has_format, const char *format, Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv = NULL;
int bdrv_flags;
+ Error *err = NULL;
bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, device);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- if (fmt) {
- drv = bdrv_find_whitelisted_format(fmt);
+
+ if (format) {
+ drv = bdrv_find_whitelisted_format(format);
if (!drv) {
- qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
- return -1;
+ error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
+ return;
}
}
- if (eject_device(mon, bs, 0) < 0) {
- return -1;
+
+ eject_device(bs, 0, &err);
+ if (error_is_set(&err)) {
+ error_propagate(errp, err);
+ return;
}
+
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
- if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
- qerror_report(QERR_OPEN_FILE_FAILED, filename);
- return -1;
- }
- return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+
+ qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
}
/* throttling disk I/O limits */
-int do_block_set_io_throttle(Monitor *mon,
- const QDict *qdict, QObject **ret_data)
+void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
+ int64_t bps_wr, int64_t iops, int64_t iops_rd,
+ int64_t iops_wr, Error **errp)
{
BlockIOLimit io_limits;
- const char *devname = qdict_get_str(qdict, "device");
BlockDriverState *bs;
- io_limits.bps[BLOCK_IO_LIMIT_TOTAL]
- = qdict_get_try_int(qdict, "bps", -1);
- io_limits.bps[BLOCK_IO_LIMIT_READ]
- = qdict_get_try_int(qdict, "bps_rd", -1);
- io_limits.bps[BLOCK_IO_LIMIT_WRITE]
- = qdict_get_try_int(qdict, "bps_wr", -1);
- io_limits.iops[BLOCK_IO_LIMIT_TOTAL]
- = qdict_get_try_int(qdict, "iops", -1);
- io_limits.iops[BLOCK_IO_LIMIT_READ]
- = qdict_get_try_int(qdict, "iops_rd", -1);
- io_limits.iops[BLOCK_IO_LIMIT_WRITE]
- = qdict_get_try_int(qdict, "iops_wr", -1);
-
- bs = bdrv_find(devname);
+ bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, devname);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- if ((io_limits.bps[BLOCK_IO_LIMIT_TOTAL] == -1)
- || (io_limits.bps[BLOCK_IO_LIMIT_READ] == -1)
- || (io_limits.bps[BLOCK_IO_LIMIT_WRITE] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_TOTAL] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_READ] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_WRITE] == -1)) {
- qerror_report(QERR_MISSING_PARAMETER,
- "bps/bps_rd/bps_wr/iops/iops_rd/iops_wr");
- return -1;
- }
+ io_limits.bps[BLOCK_IO_LIMIT_TOTAL] = bps;
+ io_limits.bps[BLOCK_IO_LIMIT_READ] = bps_rd;
+ io_limits.bps[BLOCK_IO_LIMIT_WRITE] = bps_wr;
+ io_limits.iops[BLOCK_IO_LIMIT_TOTAL]= iops;
+ io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
+ io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
if (!do_check_io_limits(&io_limits)) {
- qerror_report(QERR_INVALID_PARAMETER_COMBINATION);
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
+ return;
}
bs->io_limits = io_limits;
@@ -803,8 +864,6 @@
qemu_mod_timer(bs->block_timer, qemu_get_clock_ns(vm_clock));
}
}
-
- return 0;
}
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
@@ -841,11 +900,6 @@
return 0;
}
-/*
- * XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the
- * existing QERR_ macro mess is cleaned up. A good example for better
- * error reports can be found in the qemu-img resize code.
- */
void qmp_block_resize(const char *device, int64_t size, Error **errp)
{
BlockDriverState *bs;
@@ -857,12 +911,177 @@
}
if (size < 0) {
- error_set(errp, QERR_UNDEFINED_ERROR);
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
return;
}
- if (bdrv_truncate(bs, size)) {
+ switch (bdrv_truncate(bs, size)) {
+ case 0:
+ break;
+ case -ENOMEDIUM:
+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+ break;
+ case -ENOTSUP:
+ error_set(errp, QERR_UNSUPPORTED);
+ break;
+ case -EACCES:
+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
+ break;
+ case -EBUSY:
+ error_set(errp, QERR_DEVICE_IN_USE, device);
+ break;
+ default:
error_set(errp, QERR_UNDEFINED_ERROR);
+ break;
+ }
+}
+
+static QObject *qobject_from_block_job(BlockJob *job)
+{
+ return qobject_from_jsonf("{ 'type': %s,"
+ "'device': %s,"
+ "'len': %" PRId64 ","
+ "'offset': %" PRId64 ","
+ "'speed': %" PRId64 " }",
+ job->job_type->job_type,
+ bdrv_get_device_name(job->bs),
+ job->len,
+ job->offset,
+ job->speed);
+}
+
+static void block_stream_cb(void *opaque, int ret)
+{
+ BlockDriverState *bs = opaque;
+ QObject *obj;
+
+ trace_block_stream_cb(bs, bs->job, ret);
+
+ assert(bs->job);
+ obj = qobject_from_block_job(bs->job);
+ if (ret < 0) {
+ QDict *dict = qobject_to_qdict(obj);
+ qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
+ }
+
+ if (block_job_is_cancelled(bs->job)) {
+ monitor_protocol_event(QEVENT_BLOCK_JOB_CANCELLED, obj);
+ } else {
+ monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
+ }
+ qobject_decref(obj);
+
+ drive_put_ref_bh_schedule(drive_get_by_blockdev(bs));
+}
+
+void qmp_block_stream(const char *device, bool has_base,
+ const char *base, Error **errp)
+{
+ BlockDriverState *bs;
+ BlockDriverState *base_bs = NULL;
+ int ret;
+
+ bs = bdrv_find(device);
+ if (!bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
+
+ if (base) {
+ base_bs = bdrv_find_backing_image(bs, base);
+ if (base_bs == NULL) {
+ error_set(errp, QERR_BASE_NOT_FOUND, base);
+ return;
+ }
+ }
+
+ ret = stream_start(bs, base_bs, base, block_stream_cb, bs);
+ if (ret < 0) {
+ switch (ret) {
+ case -EBUSY:
+ error_set(errp, QERR_DEVICE_IN_USE, device);
+ return;
+ default:
+ error_set(errp, QERR_NOT_SUPPORTED);
+ return;
+ }
+ }
+
+ /* Grab a reference so hotplug does not delete the BlockDriverState from
+ * underneath us.
+ */
+ drive_get_ref(drive_get_by_blockdev(bs));
+
+ trace_qmp_block_stream(bs, bs->job);
+}
+
+static BlockJob *find_block_job(const char *device)
+{
+ BlockDriverState *bs;
+
+ bs = bdrv_find(device);
+ if (!bs || !bs->job) {
+ return NULL;
+ }
+ return bs->job;
+}
+
+void qmp_block_job_set_speed(const char *device, int64_t value, Error **errp)
+{
+ BlockJob *job = find_block_job(device);
+
+ if (!job) {
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
+ return;
+ }
+
+ if (block_job_set_speed(job, value) < 0) {
+ error_set(errp, QERR_NOT_SUPPORTED);
+ }
+}
+
+void qmp_block_job_cancel(const char *device, Error **errp)
+{
+ BlockJob *job = find_block_job(device);
+
+ if (!job) {
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
+ return;
+ }
+
+ trace_qmp_block_job_cancel(job);
+ block_job_cancel(job);
+}
+
+static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
+{
+ BlockJobInfoList **prev = opaque;
+ BlockJob *job = bs->job;
+
+ if (job) {
+ BlockJobInfoList *elem;
+ BlockJobInfo *info = g_new(BlockJobInfo, 1);
+ *info = (BlockJobInfo){
+ .type = g_strdup(job->job_type->job_type),
+ .device = g_strdup(bdrv_get_device_name(bs)),
+ .len = job->len,
+ .offset = job->offset,
+ .speed = job->speed,
+ };
+
+ elem = g_new0(BlockJobInfoList, 1);
+ elem->value = info;
+
+ (*prev)->next = elem;
+ *prev = elem;
+ }
+}
+
+BlockJobInfoList *qmp_query_block_jobs(Error **errp)
+{
+ /* Dummy is a fake list element for holding the head pointer */
+ BlockJobInfoList dummy = {};
+ BlockJobInfoList *prev = &dummy;
+ bdrv_iterate(do_qmp_query_block_jobs_one, &prev);
+ return dummy.next;
}
diff --git a/blockdev.h b/blockdev.h
index f1b6396..260e16b 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -11,6 +11,7 @@
#define BLOCKDEV_H
#include "block.h"
+#include "error.h"
#include "qemu-queue.h"
void blockdev_mark_auto_del(BlockDriverState *bs);
@@ -57,11 +58,8 @@
DriveInfo *add_init_drive(const char *opts);
+void qmp_change_blockdev(const char *device, const char *filename,
+ bool has_format, const char *format, Error **errp);
void do_commit(Monitor *mon, const QDict *qdict);
-int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
-int do_change_block(Monitor *mon, const char *device,
- const char *filename, const char *fmt);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
-int do_block_set_io_throttle(Monitor *mon,
- const QDict *qdict, QObject **ret_data);
#endif
diff --git a/configure b/configure
index 467e87b..763db24 100755
--- a/configure
+++ b/configure
@@ -133,6 +133,7 @@
xen=""
xen_ctrl_version=""
linux_aio=""
+cap_ng=""
attr=""
libattr=""
xfs=""
@@ -234,7 +235,11 @@
libtool="${LIBTOOL-${cross_prefix}libtool}"
strip="${STRIP-${cross_prefix}strip}"
windres="${WINDRES-${cross_prefix}windres}"
-pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
+pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}"
+query_pkg_config() {
+ "${pkg_config_exe}" ${QEMU_PKG_CONFIG_FLAGS} "$@"
+}
+pkg_config=query_pkg_config
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
# default flags for all hosts
@@ -553,6 +558,7 @@
--static)
static="yes"
LDFLAGS="-static $LDFLAGS"
+ QEMU_PKG_CONFIG_FLAGS="--static $QEMU_PKG_CONFIG_FLAGS"
;;
--mandir=*) mandir="$optarg"
;;
@@ -667,6 +673,10 @@
;;
--enable-tcg-interpreter) tcg_interpreter="yes"
;;
+ --disable-cap-ng) cap_ng="no"
+ ;;
+ --enable-cap-ng) cap_ng="yes"
+ ;;
--disable-spice) spice="no"
;;
--enable-spice) spice="yes"
@@ -766,6 +776,10 @@
;;
--enable-rbd) rbd="yes"
;;
+ --disable-xfsctl) xfs="no"
+ ;;
+ --enable-xfsctl) xfs="yes"
+ ;;
--disable-smartcard) smartcard="no"
;;
--enable-smartcard) smartcard="yes"
@@ -1044,6 +1058,8 @@
echo " --enable-vde enable support for vde network"
echo " --disable-linux-aio disable Linux AIO support"
echo " --enable-linux-aio enable Linux AIO support"
+echo " --disable-cap-ng disable libcap-ng support"
+echo " --enable-cap-ng enable libcap-ng support"
echo " --disable-attr disables attr and xattr support"
echo " --enable-attr enable attr and xattr support"
echo " --disable-blobs disable installing provided firmware blobs"
@@ -1445,8 +1461,8 @@
##########################################
# pkg-config probe
-if ! has $pkg_config; then
- echo "Error: pkg-config binary '$pkg_config' not found"
+if ! has "$pkg_config_exe"; then
+ echo "Error: pkg-config binary '$pkg_config_exe' not found"
exit 1
fi
@@ -1736,6 +1752,29 @@
fi
##########################################
+# libcap-ng library probe
+if test "$cap_ng" != "no" ; then
+ cap_libs="-lcap-ng"
+ cat > $TMPC << EOF
+#include <cap-ng.h>
+int main(void)
+{
+ capng_capability_to_name(CAPNG_EFFECTIVE);
+ return 0;
+}
+EOF
+ if compile_prog "" "$cap_libs" ; then
+ cap_ng=yes
+ libs_tools="$cap_libs $libs_tools"
+ else
+ if test "$cap_ng" = "yes" ; then
+ feature_not_found "cap_ng"
+ fi
+ cap_ng=no
+ fi
+fi
+
+##########################################
# Sound support libraries probe
audio_drv_probe()
@@ -2519,11 +2558,16 @@
smartcard_cflags=""
# TODO - what's the minimal nss version we support?
if test "$smartcard_nss" != "no"; then
- if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then
+ cat > $TMPC << EOF
+#include <pk11pub.h>
+int main(void) { PK11_FreeSlot(0); return 0; }
+EOF
+ smartcard_cflags="-I\$(SRC_PATH)/libcacard"
+ libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
+ libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
+ if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \
+ compile_prog "$smartcard_cflags $libcacard_cflags" "$libcacard_libs"; then
smartcard_nss="yes"
- smartcard_cflags="-I\$(SRC_PATH)/libcacard"
- libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
- libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags"
LIBS="$libcacard_libs $LIBS"
else
@@ -2862,6 +2906,7 @@
echo "madvise $madvise"
echo "posix_madvise $posix_madvise"
echo "uuid support $uuid"
+echo "libcap-ng support $cap_ng"
echo "vhost-net support $vhost_net"
echo "Trace backend $trace_backend"
echo "Trace output file $trace_file-<pid>"
@@ -2896,6 +2941,9 @@
echo "sysconfdir=$sysconfdir" >> $config_host_mak
echo "docdir=$docdir" >> $config_host_mak
echo "confdir=$confdir" >> $config_host_mak
+echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
+echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
+echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
if test "$debug_tcg" = "yes" ; then
@@ -2965,6 +3013,9 @@
if test "$vde" = "yes" ; then
echo "CONFIG_VDE=y" >> $config_host_mak
fi
+if test "$cap_ng" = "yes" ; then
+ echo "CONFIG_LIBCAP=y" >> $config_host_mak
+fi
for card in $audio_card_list; do
def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
echo "$def=y" >> $config_host_mak
@@ -3363,6 +3414,7 @@
mkdir -p $target_dir/tcg
mkdir -p $target_dir/ide
mkdir -p $target_dir/9pfs
+mkdir -p $target_dir/kvm
if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
mkdir -p $target_dir/nwfpe
fi
@@ -3780,7 +3832,7 @@
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui"
DIRS="$DIRS qapi qapi-generated"
-DIRS="$DIRS qga trace"
+DIRS="$DIRS qga trace qom"
FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/console.h b/console.h
index 9466886..6ba0d5d 100644
--- a/console.h
+++ b/console.h
@@ -4,7 +4,6 @@
#include "qemu-char.h"
#include "qdict.h"
#include "notify.h"
-#include "qerror.h"
#include "monitor.h"
/* keyboard/mouse support */
@@ -384,12 +383,10 @@
#else
static inline int vnc_display_password(DisplayState *ds, const char *password)
{
- qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV;
}
static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
{
- qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV;
};
#endif
diff --git a/cpus.c b/cpus.c
index 2dae549..f45a438 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1217,7 +1217,11 @@
CPUState *env;
for (env = first_cpu; env != NULL; env = env->next_cpu) {
- cpu_interrupt(env, CPU_INTERRUPT_NMI);
+ if (!env->apic_state) {
+ cpu_interrupt(env, CPU_INTERRUPT_NMI);
+ } else {
+ apic_deliver_nmi(env->apic_state);
+ }
}
#else
error_set(errp, QERR_UNSUPPORTED);
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
index bd1dd95..501dd41 100644
--- a/default-configs/alpha-softmmu.mak
+++ b/default-configs/alpha-softmmu.mak
@@ -4,7 +4,9 @@
CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
+CONFIG_VGA_CIRRUS=y
CONFIG_IDE_CORE=y
CONFIG_IDE_QDEV=y
CONFIG_VMWARE_VGA=y
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 8d1174f..e542b4f 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -2,6 +2,7 @@
include pci.mak
CONFIG_GDBSTUB_XML=y
+CONFIG_VGA=y
CONFIG_ISA_MMIO=y
CONFIG_NAND=y
CONFIG_ECC=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index e67ebb3..662348e 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -1,8 +1,10 @@
# Default configuration for i386-softmmu
include pci.mak
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_VMMOUSE=y
CONFIG_SERIAL=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 94a3486..308d04a 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -3,9 +3,11 @@
include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
diff --git a/default-configs/mips64-linux-user.mak b/default-configs/mips64-linux-user.mak
new file mode 100644
index 0000000..1598bfc
--- /dev/null
+++ b/default-configs/mips64-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64-linux-user
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index b5d3108..f1b92da 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -3,9 +3,11 @@
include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
diff --git a/default-configs/mips64el-linux-user.mak b/default-configs/mips64el-linux-user.mak
new file mode 100644
index 0000000..629f084
--- /dev/null
+++ b/default-configs/mips64el-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64el-linux-user
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 2831f44..567396c 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -3,9 +3,11 @@
include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 14c949d..a8e421b 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -3,9 +3,11 @@
include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
diff --git a/default-configs/mipsn32-linux-user.mak b/default-configs/mipsn32-linux-user.mak
new file mode 100644
index 0000000..5b97919
--- /dev/null
+++ b/default-configs/mipsn32-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsn32-linux-user
diff --git a/default-configs/mipsn32el-linux-user.mak b/default-configs/mipsn32el-linux-user.mak
new file mode 100644
index 0000000..d6367ff
--- /dev/null
+++ b/default-configs/mipsn32el-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsn32el-linux-user
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 22bd350..9d3e1db 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -4,6 +4,7 @@
CONFIG_USB_UHCI=y
CONFIG_USB_OHCI=y
CONFIG_USB_EHCI=y
+CONFIG_USB_XHCI=y
CONFIG_NE2000_PCI=y
CONFIG_EEPRO100_PCI=y
CONFIG_PCNET_PCI=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index c85cdce..1a768fc 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -5,15 +5,19 @@
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_DMA=y
+CONFIG_I82374=y
CONFIG_OPENPIC=y
CONFIG_PREP_PCI=y
+CONFIG_I82378=y
CONFIG_MACIO=y
+CONFIG_PCSPK=y
CONFIG_CUDA=y
CONFIG_ADB=y
CONFIG_MAC_NVRAM=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index 8874115..f490368 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -5,6 +5,7 @@
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_I8254=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index 5db7205..829f462 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -5,6 +5,7 @@
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_I8254=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index d8f17e7..c9a36c1 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -4,7 +4,9 @@
CONFIG_ISA_MMIO=y
CONFIG_M48T59=y
CONFIG_PTIMER=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
+CONFIG_VGA_CIRRUS=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
CONFIG_PCKBD=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index b75757e..b445be2 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -1,8 +1,10 @@
# Default configuration for x86_64-softmmu
include pci.mak
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_VMMOUSE=y
CONFIG_SERIAL=y
diff --git a/docs/live-block-ops.txt b/docs/live-block-ops.txt
new file mode 100644
index 0000000..a257087
--- /dev/null
+++ b/docs/live-block-ops.txt
@@ -0,0 +1,58 @@
+LIVE BLOCK OPERATIONS
+=====================
+
+High level description of live block operations. Note these are not
+supported for use with the raw format at the moment.
+
+Snapshot live merge
+===================
+
+Given a snapshot chain, described in this document in the following
+format:
+
+[A] -> [B] -> [C] -> [D]
+
+Where the rightmost object ([D] in the example) described is the current
+image which the guest OS has write access to. To the left of it is its base
+image, and so on accordingly until the leftmost image, which has no
+base.
+
+The snapshot live merge operation transforms such a chain into a
+smaller one with fewer elements, such as this transformation relative
+to the first example:
+
+[A] -> [D]
+
+Currently only forward merge with target being the active image is
+supported, that is, data copy is performed in the right direction with
+destination being the rightmost image.
+
+The operation is implemented in QEMU through image streaming facilities.
+
+The basic idea is to execute 'block_stream virtio0' while the guest is
+running. Progress can be monitored using 'info block-jobs'. When the
+streaming operation completes it raises a QMP event. 'block_stream'
+copies data from the backing file(s) into the active image. When finished,
+it adjusts the backing file pointer.
+
+The 'base' parameter specifies an image which data need not be streamed from.
+This image will be used as the backing file for the active image when the
+operation is finished.
+
+In the example above, the command would be:
+
+(qemu) block_stream virtio0 A
+
+
+Live block copy
+===============
+
+To copy an in use image to another destination in the filesystem, one
+should create a live snapshot in the desired destination, then stream
+into that image. Example:
+
+(qemu) snapshot_blkdev ide0-hd0 /new-path/disk.img qcow2
+
+(qemu) block_stream ide0-hd0
+
+
diff --git a/exec-obsolete.h b/exec-obsolete.h
index c412be9..94c23d0 100644
--- a/exec-obsolete.h
+++ b/exec-obsolete.h
@@ -59,10 +59,21 @@
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS];
}
-static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
+static inline int cpu_physical_memory_get_dirty(ram_addr_t start,
+ ram_addr_t length,
int dirty_flags)
{
- return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
+ int ret = 0;
+ uint8_t *p;
+ ram_addr_t addr, end;
+
+ end = TARGET_PAGE_ALIGN(start + length);
+ start &= TARGET_PAGE_MASK;
+ p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+ for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+ ret |= *p++ & dirty_flags;
+ }
+ return ret;
}
static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
@@ -76,18 +87,35 @@
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags;
}
+static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
+ ram_addr_t length,
+ int dirty_flags)
+{
+ uint8_t *p;
+ ram_addr_t addr, end;
+
+ end = TARGET_PAGE_ALIGN(start + length);
+ start &= TARGET_PAGE_MASK;
+ p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+ for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+ *p++ |= dirty_flags;
+ }
+}
+
static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
- int length,
+ ram_addr_t length,
int dirty_flags)
{
- int i, mask, len;
+ int mask;
uint8_t *p;
+ ram_addr_t addr, end;
- len = length >> TARGET_PAGE_BITS;
+ end = TARGET_PAGE_ALIGN(start + length);
+ start &= TARGET_PAGE_MASK;
mask = ~dirty_flags;
p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
- for (i = 0; i < len; i++) {
- p[i] &= mask;
+ for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+ *p++ &= mask;
}
}
diff --git a/exec.c b/exec.c
index 7f9f730..b81677a 100644
--- a/exec.c
+++ b/exec.c
@@ -1876,8 +1876,18 @@
.addend = -1,
};
-/* NOTE: if flush_global is true, also flush global entries (not
- implemented yet) */
+/* NOTE:
+ * If flush_global is true (the usual case), flush all tlb entries.
+ * If flush_global is false, flush (at least) all tlb entries not
+ * marked global.
+ *
+ * Since QEMU doesn't currently implement a global/not-global flag
+ * for tlb entries, at the moment tlb_flush() will also flush all
+ * tlb entries in the flush_global == false case. This is OK because
+ * CPU architectures generally permit an implementation to drop
+ * entries from the TLB at any time, so flushing more entries than
+ * required is only an efficiency issue, not a correctness issue.
+ */
void tlb_flush(CPUState *env, int flush_global)
{
int i;
@@ -4390,6 +4400,20 @@
return qemu_ram_addr_from_host_nofail(p);
}
+/*
+ * A helper function for the _utterly broken_ virtio device model to find out if
+ * it's running on a big endian machine. Don't do this at home kids!
+ */
+bool virtio_is_big_endian(void);
+bool virtio_is_big_endian(void)
+{
+#if defined(TARGET_WORDS_BIGENDIAN)
+ return true;
+#else
+ return false;
+#endif
+}
+
#define MMUSUFFIX _cmmu
#undef GETPC
#define GETPC() NULL
diff --git a/hmp-commands.hx b/hmp-commands.hx
index a586498..573b823 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -69,14 +69,54 @@
resizes image files, it can not resize block devices like LVM volumes.
ETEXI
+ {
+ .name = "block_stream",
+ .args_type = "device:B,base:s?",
+ .params = "device [base]",
+ .help = "copy data from a backing file into a block device",
+ .mhandler.cmd = hmp_block_stream,
+ },
+
+STEXI
+@item block_stream
+@findex block_stream
+Copy data from a backing file into a block device.
+ETEXI
+
+ {
+ .name = "block_job_set_speed",
+ .args_type = "device:B,value:o",
+ .params = "device value",
+ .help = "set maximum speed for a background block operation",
+ .mhandler.cmd = hmp_block_job_set_speed,
+ },
+
+STEXI
+@item block_job_set_stream
+@findex block_job_set_stream
+Set maximum speed for a background block operation.
+ETEXI
+
+ {
+ .name = "block_job_cancel",
+ .args_type = "device:B",
+ .params = "device",
+ .help = "stop an active block streaming operation",
+ .mhandler.cmd = hmp_block_job_cancel,
+ },
+
+STEXI
+@item block_job_cancel
+@findex block_job_cancel
+Stop an active block streaming operation.
+ETEXI
{
.name = "eject",
.args_type = "force:-f,device:B",
.params = "[-f] device",
.help = "eject a removable medium (use -f to force it)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_eject,
+ .mhandler.cmd = hmp_eject,
},
STEXI
@@ -108,8 +148,7 @@
.args_type = "device:B,target:F,arg:s?",
.params = "device filename [format]",
.help = "change a removable medium, optional format",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_change,
+ .mhandler.cmd = hmp_change,
},
STEXI
@@ -1204,8 +1243,7 @@
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
.help = "change I/O throttle limits for a block drive",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_set_io_throttle,
+ .mhandler.cmd = hmp_block_set_io_throttle,
},
STEXI
@@ -1219,8 +1257,7 @@
.args_type = "protocol:s,password:s,connected:s?",
.params = "protocol password action-if-connected",
.help = "set spice/vnc password",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = set_password,
+ .mhandler.cmd = hmp_set_password,
},
STEXI
@@ -1240,8 +1277,7 @@
.args_type = "protocol:s,time:s",
.params = "protocol time",
.help = "set spice/vnc password expire-time",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = expire_password,
+ .mhandler.cmd = hmp_expire_password,
},
STEXI
diff --git a/hmp.c b/hmp.c
index 8a77780..8ff8c94 100644
--- a/hmp.c
+++ b/hmp.c
@@ -509,6 +509,42 @@
qapi_free_PciInfoList(info_list);
}
+void hmp_info_block_jobs(Monitor *mon)
+{
+ BlockJobInfoList *list;
+ Error *err = NULL;
+
+ list = qmp_query_block_jobs(&err);
+ assert(!err);
+
+ if (!list) {
+ monitor_printf(mon, "No active jobs\n");
+ return;
+ }
+
+ while (list) {
+ if (strcmp(list->value->type, "stream") == 0) {
+ monitor_printf(mon, "Streaming device %s: Completed %" PRId64
+ " of %" PRId64 " bytes, speed limit %" PRId64
+ " bytes/s\n",
+ list->value->device,
+ list->value->offset,
+ list->value->len,
+ list->value->speed);
+ } else {
+ monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
+ " of %" PRId64 " bytes, speed limit %" PRId64
+ " bytes/s\n",
+ list->value->type,
+ list->value->device,
+ list->value->offset,
+ list->value->len,
+ list->value->speed);
+ }
+ list = list->next;
+ }
+}
+
void hmp_quit(Monitor *mon, const QDict *qdict)
{
monitor_suspend(mon);
@@ -681,3 +717,137 @@
int64_t value = qdict_get_int(qdict, "value");
qmp_migrate_set_speed(value, NULL);
}
+
+void hmp_set_password(Monitor *mon, const QDict *qdict)
+{
+ const char *protocol = qdict_get_str(qdict, "protocol");
+ const char *password = qdict_get_str(qdict, "password");
+ const char *connected = qdict_get_try_str(qdict, "connected");
+ Error *err = NULL;
+
+ qmp_set_password(protocol, password, !!connected, connected, &err);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_expire_password(Monitor *mon, const QDict *qdict)
+{
+ const char *protocol = qdict_get_str(qdict, "protocol");
+ const char *whenstr = qdict_get_str(qdict, "time");
+ Error *err = NULL;
+
+ qmp_expire_password(protocol, whenstr, &err);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_eject(Monitor *mon, const QDict *qdict)
+{
+ int force = qdict_get_try_bool(qdict, "force", 0);
+ const char *device = qdict_get_str(qdict, "device");
+ Error *err = NULL;
+
+ qmp_eject(device, true, force, &err);
+ hmp_handle_error(mon, &err);
+}
+
+static void hmp_change_read_arg(Monitor *mon, const char *password,
+ void *opaque)
+{
+ qmp_change_vnc_password(password, NULL);
+ monitor_read_command(mon, 1);
+}
+
+static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
+ void *opaque)
+{
+ Error *encryption_err = opaque;
+ Error *err = NULL;
+ const char *device;
+
+ device = error_get_field(encryption_err, "device");
+
+ qmp_block_passwd(device, password, &err);
+ hmp_handle_error(mon, &err);
+ error_free(encryption_err);
+
+ monitor_read_command(mon, 1);
+}
+
+void hmp_change(Monitor *mon, const QDict *qdict)
+{
+ const char *device = qdict_get_str(qdict, "device");
+ const char *target = qdict_get_str(qdict, "target");
+ const char *arg = qdict_get_try_str(qdict, "arg");
+ Error *err = NULL;
+
+ if (strcmp(device, "vnc") == 0 &&
+ (strcmp(target, "passwd") == 0 ||
+ strcmp(target, "password") == 0)) {
+ if (!arg) {
+ monitor_read_password(mon, hmp_change_read_arg, NULL);
+ return;
+ }
+ }
+
+ qmp_change(device, target, !!arg, arg, &err);
+ if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
+ monitor_printf(mon, "%s (%s) is encrypted.\n",
+ error_get_field(err, "device"),
+ error_get_field(err, "filename"));
+ if (!monitor_get_rs(mon)) {
+ monitor_printf(mon,
+ "terminal does not support password prompting\n");
+ error_free(err);
+ return;
+ }
+ readline_start(monitor_get_rs(mon), "Password: ", 1,
+ cb_hmp_change_bdrv_pwd, err);
+ return;
+ }
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+
+ qmp_block_set_io_throttle(qdict_get_str(qdict, "device"),
+ qdict_get_int(qdict, "bps"),
+ qdict_get_int(qdict, "bps_rd"),
+ qdict_get_int(qdict, "bps_wr"),
+ qdict_get_int(qdict, "iops"),
+ qdict_get_int(qdict, "iops_rd"),
+ qdict_get_int(qdict, "iops_wr"), &err);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_block_stream(Monitor *mon, const QDict *qdict)
+{
+ Error *error = NULL;
+ const char *device = qdict_get_str(qdict, "device");
+ const char *base = qdict_get_try_str(qdict, "base");
+
+ qmp_block_stream(device, base != NULL, base, &error);
+
+ hmp_handle_error(mon, &error);
+}
+
+void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
+{
+ Error *error = NULL;
+ const char *device = qdict_get_str(qdict, "device");
+ int64_t value = qdict_get_int(qdict, "value");
+
+ qmp_block_job_set_speed(device, value, &error);
+
+ hmp_handle_error(mon, &error);
+}
+
+void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
+{
+ Error *error = NULL;
+ const char *device = qdict_get_str(qdict, "device");
+
+ qmp_block_job_cancel(device, &error);
+
+ hmp_handle_error(mon, &error);
+}
diff --git a/hmp.h b/hmp.h
index 093242d..18eecbd 100644
--- a/hmp.h
+++ b/hmp.h
@@ -32,6 +32,7 @@
void hmp_info_spice(Monitor *mon);
void hmp_info_balloon(Monitor *mon);
void hmp_info_pci(Monitor *mon);
+void hmp_info_block_jobs(Monitor *mon);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
@@ -49,5 +50,13 @@
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_set_password(Monitor *mon, const QDict *qdict);
+void hmp_expire_password(Monitor *mon, const QDict *qdict);
+void hmp_eject(Monitor *mon, const QDict *qdict);
+void hmp_change(Monitor *mon, const QDict *qdict);
+void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
+void hmp_block_stream(Monitor *mon, const QDict *qdict);
+void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 41a1a82..791a557 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -154,29 +154,39 @@
return 0;
}
-static PCIDeviceInfo virtio_9p_info = {
- .qdev.name = "virtio-9p-pci",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_9p_init_pci,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = 0x1009,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = 0x2,
- .qdev.props = (Property[]) {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
- DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
+static Property virtio_9p_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+ DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_9p_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_9p_init_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = 0x1009;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = 0x2;
+ dc->props = virtio_9p_properties;
+ dc->reset = virtio_pci_reset;
+}
+
+static TypeInfo virtio_9p_info = {
+ .name = "virtio-9p-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_9p_class_init,
};
static void virtio_9p_register_devices(void)
{
- pci_qdev_register(&virtio_9p_info);
+ type_register_static(&virtio_9p_info);
virtio_9p_set_fd_limit();
}
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 3ef0e13..19de12b 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -11,9 +11,8 @@
#include "sysbus.h"
/* Configuration for arm_gic.c:
- * number of external IRQ lines, max number of CPUs, how to ID current CPU
+ * max number of CPUs, how to ID current CPU
*/
-#define GIC_NIRQ 96
#define NCPU 4
static inline int
@@ -37,6 +36,7 @@
MemoryRegion ptimer_iomem;
MemoryRegion container;
DeviceState *mptimer;
+ uint32_t num_irq;
} a9mp_priv_state;
static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
@@ -153,7 +153,7 @@
hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
}
- gic_init(&s->gic, s->num_cpu);
+ gic_init(&s->gic, s->num_cpu, s->num_irq);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
@@ -208,21 +208,39 @@
}
};
-static SysBusDeviceInfo a9mp_priv_info = {
- .init = a9mp_priv_init,
- .qdev.name = "a9mpcore_priv",
- .qdev.size = sizeof(a9mp_priv_state),
- .qdev.vmsd = &vmstate_a9mp_priv,
- .qdev.reset = a9mp_priv_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property a9mp_priv_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
+ /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
+ * IRQ lines (with another 32 internal). We default to 64+32, which
+ * is the number provided by the Cortex-A9MP test chip in the
+ * Realview PBX-A9 and Versatile Express A9 development boards.
+ * Other boards may differ and should set this property appropriately.
+ */
+ DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void a9mp_priv_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = a9mp_priv_init;
+ dc->props = a9mp_priv_properties;
+ dc->vmsd = &vmstate_a9mp_priv;
+ dc->reset = a9mp_priv_reset;
+}
+
+static TypeInfo a9mp_priv_info = {
+ .name = "a9mpcore_priv",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(a9mp_priv_state),
+ .class_init = a9mp_priv_class_init,
};
static void a9mp_register_devices(void)
{
- sysbus_register_withprop(&a9mp_priv_info);
+ type_register_static(&a9mp_priv_info);
}
device_init(a9mp_register_devices)
diff --git a/hw/ac97.c b/hw/ac97.c
index 03be99b..7bf9171 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1175,17 +1175,17 @@
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
- VMSTATE_UINT32(bdbar, AC97BusMasterRegs),
- VMSTATE_UINT8(civ, AC97BusMasterRegs),
- VMSTATE_UINT8(lvi, AC97BusMasterRegs),
- VMSTATE_UINT16(sr, AC97BusMasterRegs),
- VMSTATE_UINT16(picb, AC97BusMasterRegs),
- VMSTATE_UINT8(piv, AC97BusMasterRegs),
- VMSTATE_UINT8(cr, AC97BusMasterRegs),
- VMSTATE_UINT32(bd_valid, AC97BusMasterRegs),
- VMSTATE_UINT32(bd.addr, AC97BusMasterRegs),
- VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs),
- VMSTATE_END_OF_LIST()
+ VMSTATE_UINT32 (bdbar, AC97BusMasterRegs),
+ VMSTATE_UINT8 (civ, AC97BusMasterRegs),
+ VMSTATE_UINT8 (lvi, AC97BusMasterRegs),
+ VMSTATE_UINT16 (sr, AC97BusMasterRegs),
+ VMSTATE_UINT16 (picb, AC97BusMasterRegs),
+ VMSTATE_UINT8 (piv, AC97BusMasterRegs),
+ VMSTATE_UINT8 (cr, AC97BusMasterRegs),
+ VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs),
+ VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs),
+ VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -1224,15 +1224,15 @@
.minimum_version_id_old = 2,
.post_load = ac97_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, AC97LinkState),
- VMSTATE_UINT32(glob_cnt, AC97LinkState),
- VMSTATE_UINT32(glob_sta, AC97LinkState),
- VMSTATE_UINT32(cas, AC97LinkState),
- VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1,
- vmstate_ac97_bm_regs, AC97BusMasterRegs),
- VMSTATE_BUFFER(mixer_data, AC97LinkState),
- VMSTATE_UNUSED_TEST(is_version_2, 3),
- VMSTATE_END_OF_LIST()
+ VMSTATE_PCI_DEVICE (dev, AC97LinkState),
+ VMSTATE_UINT32 (glob_cnt, AC97LinkState),
+ VMSTATE_UINT32 (glob_sta, AC97LinkState),
+ VMSTATE_UINT32 (cas, AC97LinkState),
+ VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1,
+ vmstate_ac97_bm_regs, AC97BusMasterRegs),
+ VMSTATE_BUFFER (mixer_data, AC97LinkState),
+ VMSTATE_UNUSED_TEST (is_version_2, 3),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -1243,7 +1243,7 @@
{ 0, 256 * 1, 1, .write = nam_writeb, },
{ 0, 256 * 2, 2, .write = nam_writew, },
{ 0, 256 * 4, 4, .write = nam_writel, },
- PORTIO_END_OF_LIST(),
+ PORTIO_END_OF_LIST (),
};
static const MemoryRegionOps ac97_io_nam_ops = {
@@ -1257,7 +1257,7 @@
{ 0, 64 * 1, 1, .write = nabm_writeb, },
{ 0, 64 * 2, 2, .write = nabm_writew, },
{ 0, 64 * 4, 4, .write = nabm_writel, },
- PORTIO_END_OF_LIST()
+ PORTIO_END_OF_LIST ()
};
static const MemoryRegionOps ac97_io_nabm_ops = {
@@ -1344,26 +1344,37 @@
return 0;
}
-static PCIDeviceInfo ac97_info = {
- .qdev.name = "AC97",
- .qdev.desc = "Intel 82801AA AC97 Audio",
- .qdev.size = sizeof (AC97LinkState),
- .qdev.vmsd = &vmstate_ac97,
- .init = ac97_initfn,
- .exit = ac97_exitfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801AA_5,
- .revision = 0x01,
- .class_id = PCI_CLASS_MULTIMEDIA_AUDIO,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("use_broken_id", AC97LinkState, use_broken_id, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ac97_properties[] = {
+ DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
+ DEFINE_PROP_END_OF_LIST (),
+};
+
+static void ac97_class_init (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+
+ k->init = ac97_initfn;
+ k->exit = ac97_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+ dc->desc = "Intel 82801AA AC97 Audio";
+ dc->vmsd = &vmstate_ac97;
+ dc->props = ac97_properties;
+}
+
+static TypeInfo ac97_info = {
+ .name = "AC97",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof (AC97LinkState),
+ .class_init = ac97_class_init,
};
static void ac97_register (void)
{
- pci_qdev_register (&ac97_info);
+ type_register_static (&ac97_info);
}
device_init (ac97_register);
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index bdc55a1..21484ae 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -280,11 +280,11 @@
s->pci0_hotplug_enable = ~0;
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
- PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
- PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *pdev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
int slot = PCI_SLOT(pdev->devfn);
- if (info->no_hotplug) {
+ if (pc->no_hotplug) {
s->pci0_hotplug_enable &= ~(1 << slot);
}
}
@@ -396,28 +396,39 @@
return s->smb.smbus;
}
-static PCIDeviceInfo piix4_pm_info = {
- .qdev.name = "PIIX4_PM",
- .qdev.desc = "PM",
- .qdev.size = sizeof(PIIX4PMState),
- .qdev.vmsd = &vmstate_acpi,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = piix4_pm_initfn,
- .config_write = pm_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB_3,
- .revision = 0x03,
- .class_id = PCI_CLASS_BRIDGE_OTHER,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property piix4_pm_properties[] = {
+ DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void piix4_pm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = piix4_pm_initfn;
+ k->config_write = pm_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+ dc->desc = "PM";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_acpi;
+ dc->props = piix4_pm_properties;
+}
+
+static TypeInfo piix4_pm_info = {
+ .name = "PIIX4_PM",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX4PMState),
+ .class_init = piix4_pm_class_init,
};
static void piix4_pm_register(void)
{
- pci_qdev_register(&piix4_pm_info);
+ type_register_static(&piix4_pm_info);
}
device_init(piix4_pm_register);
@@ -485,14 +496,12 @@
{
BusState *bus = opaque;
DeviceState *qdev, *next;
- PCIDevice *dev;
- PCIDeviceInfo *info;
int slot = ffs(val) - 1;
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
- dev = DO_UPCAST(PCIDevice, qdev, qdev);
- info = container_of(qdev->info, PCIDeviceInfo, qdev);
- if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
+ PCIDevice *dev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) {
qdev_free(qdev);
}
}
@@ -553,7 +562,7 @@
{
int slot = PCI_SLOT(dev->devfn);
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
- DO_UPCAST(PCIDevice, qdev, qdev));
+ PCI_DEVICE(qdev));
/* Don't send event when device is enabled during qemu machine creation:
* it is present on boot, no hotplug event is necessary. We do send an
diff --git a/hw/adlib.c b/hw/adlib.c
index dd8b188..d39cd97 100644
--- a/hw/adlib.c
+++ b/hw/adlib.c
@@ -164,7 +164,7 @@
s->ticking[n] = 1;
#ifdef DEBUG
- interval = get_ticks_per_sec() * interval_Sec;
+ interval = get_ticks_per_sec () * interval_Sec;
exp = qemu_get_clock_ns (vm_clock) + interval;
s->exp[n] = exp;
#endif
diff --git a/hw/ads7846.c b/hw/ads7846.c
index de3f7af..3cfdecb 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -153,16 +153,24 @@
return 0;
}
-static SSISlaveInfo ads7846_info = {
- .qdev.name ="ads7846",
- .qdev.size = sizeof(ADS7846State),
- .init = ads7846_init,
- .transfer = ads7846_transfer
+static void ads7846_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = ads7846_init;
+ k->transfer = ads7846_transfer;
+}
+
+static TypeInfo ads7846_info = {
+ .name = "ads7846",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(ADS7846State),
+ .class_init = ads7846_class_init,
};
static void ads7846_register_devices(void)
{
- ssi_register_slave(&ads7846_info);
+ type_register_static(&ads7846_info);
}
device_init(ads7846_register_devices)
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
index e975702..6735577 100644
--- a/hw/alpha_pci.c
+++ b/hw/alpha_pci.c
@@ -121,10 +121,8 @@
pci_cirrus_vga_init(pci_bus);
return;
case VGA_VMWARE:
- if (pci_vmsvga_init(pci_bus)) {
- return;
- }
- break;
+ pci_vmsvga_init(pci_bus);
+ return;
}
/* If VGA is enabled at all, and one of the above didn't work, then
fallback to Standard VGA. */
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 7d924a3..736c28a 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -808,15 +808,24 @@
return 0;
}
-static SysBusDeviceInfo typhoon_pcihost_info = {
- .init = typhoon_pcihost_init,
- .qdev.name = "typhoon-pcihost",
- .qdev.size = sizeof(TyphoonState),
- .qdev.no_user = 1
+static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = typhoon_pcihost_init;
+ dc->no_user = 1;
+}
+
+static TypeInfo typhoon_pcihost_info = {
+ .name = "typhoon-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TyphoonState),
+ .class_init = typhoon_pcihost_class_init,
};
static void typhoon_register(void)
{
- sysbus_register_withprop(&typhoon_pcihost_info);
+ type_register_static(&typhoon_pcihost_info);
}
device_init(typhoon_register);
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 3a1b111..c7aaa72 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -350,7 +350,7 @@
sysbus_connect_irq(s, i, pic[i]);
}
- pci_create_simple(d->bus, 0, "pbm");
+ pci_create_simple(d->bus, 0, "pbm-pci");
/* APB secondary busses */
pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
@@ -436,42 +436,68 @@
return 0;
}
-static PCIDeviceInfo pbm_pci_host_info = {
- .qdev.name = "pbm",
- .qdev.size = sizeof(PCIDevice),
- .init = pbm_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_SUN,
- .device_id = PCI_DEVICE_ID_SUN_SABRE,
- .class_id = PCI_CLASS_BRIDGE_HOST,
- .is_bridge = 1,
+static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pbm_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_SUN;
+ k->device_id = PCI_DEVICE_ID_SUN_SABRE;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ k->is_bridge = 1;
+}
+
+static TypeInfo pbm_pci_host_info = {
+ .name = "pbm-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = pbm_pci_host_class_init,
};
-static SysBusDeviceInfo pbm_host_info = {
- .qdev.name = "pbm",
- .qdev.size = sizeof(APBState),
- .qdev.reset = pci_pbm_reset,
- .init = pci_pbm_init_device,
+static void pbm_host_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pci_pbm_init_device;
+ dc->reset = pci_pbm_reset;
+}
+
+static TypeInfo pbm_host_info = {
+ .name = "pbm",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(APBState),
+ .class_init = pbm_host_class_init,
};
-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,
- .vendor_id = PCI_VENDOR_ID_SUN,
- .device_id = PCI_DEVICE_ID_SUN_SIMBA,
- .revision = 0x11,
- .config_write = pci_bridge_write_config,
- .is_bridge = 1,
+static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = apb_pci_bridge_initfn;
+ k->exit = pci_bridge_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_SUN;
+ k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
+ k->revision = 0x11;
+ k->config_write = pci_bridge_write_config;
+ k->is_bridge = 1;
+ dc->reset = pci_bridge_reset;
+ dc->vmsd = &vmstate_pci_device;
+}
+
+static TypeInfo pbm_pci_bridge_info = {
+ .name = "pbm-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIBridge),
+ .class_init = pbm_pci_bridge_class_init,
};
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);
+ type_register_static(&pbm_host_info);
+ type_register_static(&pbm_pci_host_info);
+ type_register_static(&pbm_pci_bridge_info);
}
device_init(pbm_register_devices)
diff --git a/hw/apic.c b/hw/apic.c
index 9d0f460..086c544 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -16,53 +16,13 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
-#include "hw.h"
+#include "apic_internal.h"
#include "apic.h"
#include "ioapic.h"
-#include "qemu-timer.h"
#include "host-utils.h"
-#include "sysbus.h"
#include "trace.h"
#include "pc.h"
-/* APIC Local Vector Table */
-#define APIC_LVT_TIMER 0
-#define APIC_LVT_THERMAL 1
-#define APIC_LVT_PERFORM 2
-#define APIC_LVT_LINT0 3
-#define APIC_LVT_LINT1 4
-#define APIC_LVT_ERROR 5
-#define APIC_LVT_NB 6
-
-/* APIC delivery modes */
-#define APIC_DM_FIXED 0
-#define APIC_DM_LOWPRI 1
-#define APIC_DM_SMI 2
-#define APIC_DM_NMI 4
-#define APIC_DM_INIT 5
-#define APIC_DM_SIPI 6
-#define APIC_DM_EXTINT 7
-
-/* APIC destination mode */
-#define APIC_DESTMODE_FLAT 0xf
-#define APIC_DESTMODE_CLUSTER 1
-
-#define APIC_TRIGGER_EDGE 0
-#define APIC_TRIGGER_LEVEL 1
-
-#define APIC_LVT_TIMER_PERIODIC (1<<17)
-#define APIC_LVT_MASKED (1<<16)
-#define APIC_LVT_LEVEL_TRIGGER (1<<15)
-#define APIC_LVT_REMOTE_IRR (1<<14)
-#define APIC_INPUT_POLARITY (1<<13)
-#define APIC_SEND_PENDING (1<<12)
-
-#define ESR_ILLEGAL_ADDRESS (1 << 7)
-
-#define APIC_SV_DIRECTED_IO (1<<12)
-#define APIC_SV_ENABLE (1<<8)
-
-#define MAX_APICS 255
#define MAX_APIC_WORDS 8
/* Intel APIC constants: from include/asm/msidef.h */
@@ -75,43 +35,10 @@
#define MSI_ADDR_DEST_ID_SHIFT 12
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
-#define MSI_ADDR_SIZE 0x100000
+static APICCommonState *local_apics[MAX_APICS + 1];
-typedef struct APICState APICState;
-
-struct APICState {
- SysBusDevice busdev;
- MemoryRegion io_memory;
- void *cpu_env;
- uint32_t apicbase;
- uint8_t id;
- uint8_t arb_id;
- uint8_t tpr;
- uint32_t spurious_vec;
- uint8_t log_dest;
- uint8_t dest_mode;
- uint32_t isr[8]; /* in service register */
- uint32_t tmr[8]; /* trigger mode register */
- uint32_t irr[8]; /* interrupt request register */
- uint32_t lvt[APIC_LVT_NB];
- uint32_t esr; /* error register */
- uint32_t icr[2];
-
- uint32_t divide_conf;
- int count_shift;
- uint32_t initial_count;
- int64_t initial_count_load_time, next_time;
- uint32_t idx;
- QEMUTimer *timer;
- int sipi_vector;
- int wait_for_sipi;
-};
-
-static APICState *local_apics[MAX_APICS + 1];
-static int apic_irq_delivered;
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
-static void apic_update_irq(APICState *s);
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
+static void apic_update_irq(APICCommonState *s);
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
uint8_t dest, uint8_t dest_mode);
@@ -151,7 +78,7 @@
return !!(tab[i] & mask);
}
-static void apic_local_deliver(APICState *s, int vector)
+static void apic_local_deliver(APICCommonState *s, int vector)
{
uint32_t lvt = s->lvt[vector];
int trigger_mode;
@@ -185,7 +112,7 @@
void apic_deliver_pic_intr(DeviceState *d, int level)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
if (level) {
apic_local_deliver(s, APIC_LVT_LINT0);
@@ -205,6 +132,11 @@
}
}
+static void apic_external_nmi(APICCommonState *s)
+{
+ apic_local_deliver(s, APIC_LVT_LINT1);
+}
+
#define foreach_apic(apic, deliver_bitmask, code) \
{\
int __i, __j, __mask;\
@@ -227,7 +159,7 @@
uint8_t delivery_mode, uint8_t vector_num,
uint8_t trigger_mode)
{
- APICState *apic_iter;
+ APICCommonState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
@@ -293,14 +225,8 @@
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
}
-void cpu_set_apic_base(DeviceState *d, uint64_t val)
+static void apic_set_base(APICCommonState *s, uint64_t val)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
- trace_cpu_set_apic_base(val);
-
- if (!s)
- return;
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
/* if disabled, cannot be enabled again */
@@ -311,32 +237,12 @@
}
}
-uint64_t cpu_get_apic_base(DeviceState *d)
+static void apic_set_tpr(APICCommonState *s, uint8_t val)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
- trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
-
- return s ? s->apicbase : 0;
-}
-
-void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
-{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
- if (!s)
- return;
s->tpr = (val & 0x0f) << 4;
apic_update_irq(s);
}
-uint8_t cpu_get_apic_tpr(DeviceState *d)
-{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
- return s ? s->tpr >> 4 : 0;
-}
-
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
@@ -349,7 +255,7 @@
return -1;
}
-static int apic_get_ppr(APICState *s)
+static int apic_get_ppr(APICCommonState *s)
{
int tpr, isrv, ppr;
@@ -365,7 +271,7 @@
return ppr;
}
-static int apic_get_arb_pri(APICState *s)
+static int apic_get_arb_pri(APICCommonState *s)
{
/* XXX: arbitration */
return 0;
@@ -377,7 +283,7 @@
* 0 - no interrupt,
* >0 - interrupt number
*/
-static int apic_irq_pending(APICState *s)
+static int apic_irq_pending(APICCommonState *s)
{
int irrv, ppr;
irrv = get_highest_priority_int(s->irr);
@@ -393,7 +299,7 @@
}
/* signal the CPU if an irq is pending */
-static void apic_update_irq(APICState *s)
+static void apic_update_irq(APICCommonState *s)
{
if (!(s->spurious_vec & APIC_SV_ENABLE)) {
return;
@@ -406,25 +312,9 @@
}
}
-void apic_reset_irq_delivered(void)
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
{
- trace_apic_reset_irq_delivered(apic_irq_delivered);
-
- apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
- 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);
-
- trace_apic_set_irq(apic_irq_delivered);
+ apic_report_irq_delivered(!get_bit(s->irr, vector_num));
set_bit(s->irr, vector_num);
if (trigger_mode)
@@ -434,7 +324,7 @@
apic_update_irq(s);
}
-static void apic_eoi(APICState *s)
+static void apic_eoi(APICCommonState *s)
{
int isrv;
isrv = get_highest_priority_int(s->isr);
@@ -449,7 +339,7 @@
static int apic_find_dest(uint8_t dest)
{
- APICState *apic = local_apics[dest];
+ APICCommonState *apic = local_apics[dest];
int i;
if (apic && apic->id == dest)
@@ -469,7 +359,7 @@
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
uint8_t dest, uint8_t dest_mode)
{
- APICState *apic_iter;
+ APICCommonState *apic_iter;
int i;
if (dest_mode == 0) {
@@ -503,34 +393,7 @@
}
}
-void apic_init_reset(DeviceState *d)
-{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
- int i;
-
- if (!s)
- return;
-
- s->tpr = 0;
- s->spurious_vec = 0xff;
- s->log_dest = 0;
- s->dest_mode = 0xf;
- memset(s->isr, 0, sizeof(s->isr));
- memset(s->tmr, 0, sizeof(s->tmr));
- memset(s->irr, 0, sizeof(s->irr));
- for(i = 0; i < APIC_LVT_NB; i++)
- s->lvt[i] = 1 << 16; /* mask LVT */
- s->esr = 0;
- memset(s->icr, 0, sizeof(s->icr));
- s->divide_conf = 0;
- s->count_shift = 0;
- s->initial_count = 0;
- s->initial_count_load_time = 0;
- s->next_time = 0;
- s->wait_for_sipi = 1;
-}
-
-static void apic_startup(APICState *s, int vector_num)
+static void apic_startup(APICCommonState *s, int vector_num)
{
s->sipi_vector = vector_num;
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
@@ -538,7 +401,7 @@
void apic_sipi(DeviceState *d)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
@@ -552,10 +415,10 @@
uint8_t delivery_mode, uint8_t vector_num,
uint8_t trigger_mode)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
uint32_t deliver_bitmask[MAX_APIC_WORDS];
int dest_shorthand = (s->icr[0] >> 18) & 3;
- APICState *apic_iter;
+ APICCommonState *apic_iter;
switch (dest_shorthand) {
case 0:
@@ -598,7 +461,7 @@
int apic_get_interrupt(DeviceState *d)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
int intno;
/* if the APIC is installed or enabled, we let the 8259 handle the
@@ -623,7 +486,7 @@
int apic_accept_pic_intr(DeviceState *d)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
uint32_t lvt0;
if (!s)
@@ -638,7 +501,7 @@
return 0;
}
-static uint32_t apic_get_current_count(APICState *s)
+static uint32_t apic_get_current_count(APICCommonState *s)
{
int64_t d;
uint32_t val;
@@ -656,34 +519,18 @@
return val;
}
-static void apic_timer_update(APICState *s, int64_t current_time)
+static void apic_timer_update(APICCommonState *s, int64_t current_time)
{
- int64_t next_time, d;
-
- if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
- d = (current_time - s->initial_count_load_time) >>
- s->count_shift;
- if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
- if (!s->initial_count)
- goto no_timer;
- d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
- } else {
- if (d >= s->initial_count)
- goto no_timer;
- d = (uint64_t)s->initial_count + 1;
- }
- next_time = s->initial_count_load_time + (d << s->count_shift);
- qemu_mod_timer(s->timer, next_time);
- s->next_time = next_time;
+ if (apic_next_timer(s, current_time)) {
+ qemu_mod_timer(s->timer, s->next_time);
} else {
- no_timer:
qemu_del_timer(s->timer);
}
}
static void apic_timer(void *opaque)
{
- APICState *s = opaque;
+ APICCommonState *s = opaque;
apic_local_deliver(s, APIC_LVT_TIMER);
apic_timer_update(s, s->next_time);
@@ -710,7 +557,7 @@
static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
{
DeviceState *d;
- APICState *s;
+ APICCommonState *s;
uint32_t val;
int index;
@@ -718,7 +565,7 @@
if (!d) {
return 0;
}
- s = DO_UPCAST(APICState, busdev.qdev, d);
+ s = DO_UPCAST(APICCommonState, busdev.qdev, d);
index = (addr >> 4) & 0xff;
switch(index) {
@@ -801,7 +648,7 @@
static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
DeviceState *d;
- APICState *s;
+ APICCommonState *s;
int index = (addr >> 4) & 0xff;
if (addr > 0xfff || !index) {
/* MSI and MMIO APIC are at the same memory location,
@@ -817,7 +664,7 @@
if (!d) {
return;
}
- s = DO_UPCAST(APICState, busdev.qdev, d);
+ s = DO_UPCAST(APICCommonState, busdev.qdev, d);
trace_apic_mem_writel(addr, val);
@@ -890,93 +737,12 @@
}
}
-/* This function is only used for old state version 1 and 2 */
-static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+static void apic_post_load(APICCommonState *s)
{
- APICState *s = opaque;
- int i;
-
- if (version_id > 2)
- return -EINVAL;
-
- /* XXX: what if the base changes? (registered memory regions) */
- qemu_get_be32s(f, &s->apicbase);
- qemu_get_8s(f, &s->id);
- qemu_get_8s(f, &s->arb_id);
- qemu_get_8s(f, &s->tpr);
- qemu_get_be32s(f, &s->spurious_vec);
- qemu_get_8s(f, &s->log_dest);
- qemu_get_8s(f, &s->dest_mode);
- for (i = 0; i < 8; i++) {
- qemu_get_be32s(f, &s->isr[i]);
- qemu_get_be32s(f, &s->tmr[i]);
- qemu_get_be32s(f, &s->irr[i]);
- }
- for (i = 0; i < APIC_LVT_NB; i++) {
- qemu_get_be32s(f, &s->lvt[i]);
- }
- qemu_get_be32s(f, &s->esr);
- qemu_get_be32s(f, &s->icr[0]);
- qemu_get_be32s(f, &s->icr[1]);
- qemu_get_be32s(f, &s->divide_conf);
- s->count_shift=qemu_get_be32(f);
- qemu_get_be32s(f, &s->initial_count);
- s->initial_count_load_time=qemu_get_be64(f);
- s->next_time=qemu_get_be64(f);
-
- if (version_id >= 2)
- qemu_get_timer(f, s->timer);
- return 0;
-}
-
-static const VMStateDescription vmstate_apic = {
- .name = "apic",
- .version_id = 3,
- .minimum_version_id = 3,
- .minimum_version_id_old = 1,
- .load_state_old = apic_load_old,
- .fields = (VMStateField []) {
- VMSTATE_UINT32(apicbase, APICState),
- VMSTATE_UINT8(id, APICState),
- VMSTATE_UINT8(arb_id, APICState),
- VMSTATE_UINT8(tpr, APICState),
- VMSTATE_UINT32(spurious_vec, APICState),
- VMSTATE_UINT8(log_dest, APICState),
- VMSTATE_UINT8(dest_mode, APICState),
- VMSTATE_UINT32_ARRAY(isr, APICState, 8),
- VMSTATE_UINT32_ARRAY(tmr, APICState, 8),
- VMSTATE_UINT32_ARRAY(irr, APICState, 8),
- VMSTATE_UINT32_ARRAY(lvt, APICState, APIC_LVT_NB),
- VMSTATE_UINT32(esr, APICState),
- VMSTATE_UINT32_ARRAY(icr, APICState, 2),
- VMSTATE_UINT32(divide_conf, APICState),
- VMSTATE_INT32(count_shift, APICState),
- VMSTATE_UINT32(initial_count, APICState),
- VMSTATE_INT64(initial_count_load_time, APICState),
- VMSTATE_INT64(next_time, APICState),
- VMSTATE_TIMER(timer, APICState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void apic_reset(DeviceState *d)
-{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
- int bsp;
-
- bsp = cpu_is_bsp(s->cpu_env);
- s->apicbase = 0xfee00000 |
- (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
-
- apic_init_reset(d);
-
- if (bsp) {
- /*
- * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
- * time typically by BIOS, so PIC interrupt can be delivered to the
- * processor when local APIC is enabled.
- */
- s->lvt[APIC_LVT_LINT0] = 0x700;
+ if (s->timer_expiry != -1) {
+ qemu_mod_timer(s->timer, s->timer_expiry);
+ } else {
+ qemu_del_timer(s->timer);
}
}
@@ -988,41 +754,36 @@
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int apic_init1(SysBusDevice *dev)
+static void apic_init(APICCommonState *s)
{
- APICState *s = FROM_SYSBUS(APICState, dev);
- static int last_apic_idx;
-
- if (last_apic_idx >= MAX_APICS) {
- return -1;
- }
- memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic",
- MSI_ADDR_SIZE);
- sysbus_init_mmio(dev, &s->io_memory);
+ memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
+ MSI_SPACE_SIZE);
s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
- s->idx = last_apic_idx++;
local_apics[s->idx] = s;
- return 0;
}
-static SysBusDeviceInfo apic_info = {
- .init = apic_init1,
- .qdev.name = "apic",
- .qdev.size = sizeof(APICState),
- .qdev.vmsd = &vmstate_apic,
- .qdev.reset = apic_reset,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("id", APICState, id, -1),
- DEFINE_PROP_PTR("cpu_env", APICState, cpu_env),
- DEFINE_PROP_END_OF_LIST(),
- }
+static void apic_class_init(ObjectClass *klass, void *data)
+{
+ APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+ k->init = apic_init;
+ k->set_base = apic_set_base;
+ k->set_tpr = apic_set_tpr;
+ k->external_nmi = apic_external_nmi;
+ k->post_load = apic_post_load;
+}
+
+static TypeInfo apic_info = {
+ .name = "apic",
+ .instance_size = sizeof(APICCommonState),
+ .parent = TYPE_APIC_COMMON,
+ .class_init = apic_class_init,
};
static void apic_register_devices(void)
{
- sysbus_register_withprop(&apic_info);
+ type_register_static(&apic_info);
}
device_init(apic_register_devices)
diff --git a/hw/apic.h b/hw/apic.h
index a5c910f..a62d83b 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -8,6 +8,7 @@
uint8_t vector_num, uint8_t trigger_mode);
int apic_accept_pic_intr(DeviceState *s);
void apic_deliver_pic_intr(DeviceState *s, int level);
+void apic_deliver_nmi(DeviceState *d);
int apic_get_interrupt(DeviceState *s);
void apic_reset_irq_delivered(void);
int apic_get_irq_delivered(void);
diff --git a/hw/apic_common.c b/hw/apic_common.c
new file mode 100644
index 0000000..26991b4
--- /dev/null
+++ b/hw/apic_common.c
@@ -0,0 +1,321 @@
+/*
+ * APIC support - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "apic.h"
+#include "apic_internal.h"
+#include "trace.h"
+
+static int apic_irq_delivered;
+
+void cpu_set_apic_base(DeviceState *d, uint64_t val)
+{
+ trace_cpu_set_apic_base(val);
+
+ if (d) {
+ APICCommonState *s = APIC_COMMON(d);
+ APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+ info->set_base(s, val);
+ }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+ if (d) {
+ APICCommonState *s = APIC_COMMON(d);
+ trace_cpu_get_apic_base((uint64_t)s->apicbase);
+ return s->apicbase;
+ } else {
+ trace_cpu_get_apic_base(0);
+ return 0;
+ }
+}
+
+void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+{
+ APICCommonState *s;
+ APICCommonClass *info;
+
+ if (!d) {
+ return;
+ }
+
+ s = APIC_COMMON(d);
+ info = APIC_COMMON_GET_CLASS(s);
+
+ info->set_tpr(s, val);
+}
+
+uint8_t cpu_get_apic_tpr(DeviceState *d)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+ return s ? s->tpr >> 4 : 0;
+}
+
+void apic_report_irq_delivered(int delivered)
+{
+ apic_irq_delivered += delivered;
+
+ trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
+void apic_reset_irq_delivered(void)
+{
+ trace_apic_reset_irq_delivered(apic_irq_delivered);
+
+ apic_irq_delivered = 0;
+}
+
+int apic_get_irq_delivered(void)
+{
+ trace_apic_get_irq_delivered(apic_irq_delivered);
+
+ return apic_irq_delivered;
+}
+
+void apic_deliver_nmi(DeviceState *d)
+{
+ APICCommonState *s = APIC_COMMON(d);
+ APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+ info->external_nmi(s);
+}
+
+bool apic_next_timer(APICCommonState *s, int64_t current_time)
+{
+ int64_t d;
+
+ /* We need to store the timer state separately to support APIC
+ * implementations that maintain a non-QEMU timer, e.g. inside the
+ * host kernel. This open-coded state allows us to migrate between
+ * both models. */
+ s->timer_expiry = -1;
+
+ if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
+ return false;
+ }
+
+ d = (current_time - s->initial_count_load_time) >> s->count_shift;
+
+ if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+ if (!s->initial_count) {
+ return false;
+ }
+ d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
+ ((uint64_t)s->initial_count + 1);
+ } else {
+ if (d >= s->initial_count) {
+ return false;
+ }
+ d = (uint64_t)s->initial_count + 1;
+ }
+ s->next_time = s->initial_count_load_time + (d << s->count_shift);
+ s->timer_expiry = s->next_time;
+ return true;
+}
+
+void apic_init_reset(DeviceState *d)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+ int i;
+
+ if (!s) {
+ return;
+ }
+ s->tpr = 0;
+ s->spurious_vec = 0xff;
+ s->log_dest = 0;
+ s->dest_mode = 0xf;
+ memset(s->isr, 0, sizeof(s->isr));
+ memset(s->tmr, 0, sizeof(s->tmr));
+ memset(s->irr, 0, sizeof(s->irr));
+ for (i = 0; i < APIC_LVT_NB; i++) {
+ s->lvt[i] = APIC_LVT_MASKED;
+ }
+ s->esr = 0;
+ memset(s->icr, 0, sizeof(s->icr));
+ s->divide_conf = 0;
+ s->count_shift = 0;
+ s->initial_count = 0;
+ s->initial_count_load_time = 0;
+ s->next_time = 0;
+ s->wait_for_sipi = 1;
+
+ if (s->timer) {
+ qemu_del_timer(s->timer);
+ }
+ s->timer_expiry = -1;
+}
+
+static void apic_reset_common(DeviceState *d)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+ bool bsp;
+
+ bsp = cpu_is_bsp(s->cpu_env);
+ s->apicbase = 0xfee00000 |
+ (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
+
+ apic_init_reset(d);
+
+ if (bsp) {
+ /*
+ * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
+ * time typically by BIOS, so PIC interrupt can be delivered to the
+ * processor when local APIC is enabled.
+ */
+ s->lvt[APIC_LVT_LINT0] = 0x700;
+ }
+}
+
+/* This function is only used for old state version 1 and 2 */
+static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+ APICCommonState *s = opaque;
+ int i;
+
+ if (version_id > 2) {
+ return -EINVAL;
+ }
+
+ /* XXX: what if the base changes? (registered memory regions) */
+ qemu_get_be32s(f, &s->apicbase);
+ qemu_get_8s(f, &s->id);
+ qemu_get_8s(f, &s->arb_id);
+ qemu_get_8s(f, &s->tpr);
+ qemu_get_be32s(f, &s->spurious_vec);
+ qemu_get_8s(f, &s->log_dest);
+ qemu_get_8s(f, &s->dest_mode);
+ for (i = 0; i < 8; i++) {
+ qemu_get_be32s(f, &s->isr[i]);
+ qemu_get_be32s(f, &s->tmr[i]);
+ qemu_get_be32s(f, &s->irr[i]);
+ }
+ for (i = 0; i < APIC_LVT_NB; i++) {
+ qemu_get_be32s(f, &s->lvt[i]);
+ }
+ qemu_get_be32s(f, &s->esr);
+ qemu_get_be32s(f, &s->icr[0]);
+ qemu_get_be32s(f, &s->icr[1]);
+ qemu_get_be32s(f, &s->divide_conf);
+ s->count_shift = qemu_get_be32(f);
+ qemu_get_be32s(f, &s->initial_count);
+ s->initial_count_load_time = qemu_get_be64(f);
+ s->next_time = qemu_get_be64(f);
+
+ if (version_id >= 2) {
+ qemu_get_timer(f, s->timer);
+ }
+ return 0;
+}
+
+static int apic_init_common(SysBusDevice *dev)
+{
+ APICCommonState *s = APIC_COMMON(dev);
+ APICCommonClass *info;
+ static int apic_no;
+
+ if (apic_no >= MAX_APICS) {
+ return -1;
+ }
+ s->idx = apic_no++;
+
+ info = APIC_COMMON_GET_CLASS(s);
+ info->init(s);
+
+ sysbus_init_mmio(&s->busdev, &s->io_memory);
+ return 0;
+}
+
+static int apic_dispatch_post_load(void *opaque, int version_id)
+{
+ APICCommonState *s = APIC_COMMON(opaque);
+ APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+ if (info->post_load) {
+ info->post_load(s);
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_apic_common = {
+ .name = "apic",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .minimum_version_id_old = 1,
+ .load_state_old = apic_load_old,
+ .post_load = apic_dispatch_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(apicbase, APICCommonState),
+ VMSTATE_UINT8(id, APICCommonState),
+ VMSTATE_UINT8(arb_id, APICCommonState),
+ VMSTATE_UINT8(tpr, APICCommonState),
+ VMSTATE_UINT32(spurious_vec, APICCommonState),
+ VMSTATE_UINT8(log_dest, APICCommonState),
+ VMSTATE_UINT8(dest_mode, APICCommonState),
+ VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
+ VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
+ VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
+ VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
+ VMSTATE_UINT32(esr, APICCommonState),
+ VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
+ VMSTATE_UINT32(divide_conf, APICCommonState),
+ VMSTATE_INT32(count_shift, APICCommonState),
+ VMSTATE_UINT32(initial_count, APICCommonState),
+ VMSTATE_INT64(initial_count_load_time, APICCommonState),
+ VMSTATE_INT64(next_time, APICCommonState),
+ VMSTATE_INT64(timer_expiry,
+ APICCommonState), /* open-coded timer state */
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property apic_properties_common[] = {
+ DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
+ DEFINE_PROP_PTR("cpu_env", APICCommonState, cpu_env),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void apic_common_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_apic_common;
+ dc->reset = apic_reset_common;
+ dc->no_user = 1;
+ dc->props = apic_properties_common;
+ sc->init = apic_init_common;
+}
+
+static TypeInfo apic_common_type = {
+ .name = TYPE_APIC_COMMON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(APICCommonState),
+ .class_size = sizeof(APICCommonClass),
+ .class_init = apic_common_class_init,
+ .abstract = true,
+};
+
+static void register_devices(void)
+{
+ type_register_static(&apic_common_type);
+}
+
+device_init(register_devices);
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
new file mode 100644
index 0000000..0cab010
--- /dev/null
+++ b/hw/apic_internal.h
@@ -0,0 +1,122 @@
+/*
+ * APIC support - internal interfaces
+ *
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#ifndef QEMU_APIC_INTERNAL_H
+#define QEMU_APIC_INTERNAL_H
+
+#include "memory.h"
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+/* APIC Local Vector Table */
+#define APIC_LVT_TIMER 0
+#define APIC_LVT_THERMAL 1
+#define APIC_LVT_PERFORM 2
+#define APIC_LVT_LINT0 3
+#define APIC_LVT_LINT1 4
+#define APIC_LVT_ERROR 5
+#define APIC_LVT_NB 6
+
+/* APIC delivery modes */
+#define APIC_DM_FIXED 0
+#define APIC_DM_LOWPRI 1
+#define APIC_DM_SMI 2
+#define APIC_DM_NMI 4
+#define APIC_DM_INIT 5
+#define APIC_DM_SIPI 6
+#define APIC_DM_EXTINT 7
+
+/* APIC destination mode */
+#define APIC_DESTMODE_FLAT 0xf
+#define APIC_DESTMODE_CLUSTER 1
+
+#define APIC_TRIGGER_EDGE 0
+#define APIC_TRIGGER_LEVEL 1
+
+#define APIC_LVT_TIMER_PERIODIC (1<<17)
+#define APIC_LVT_MASKED (1<<16)
+#define APIC_LVT_LEVEL_TRIGGER (1<<15)
+#define APIC_LVT_REMOTE_IRR (1<<14)
+#define APIC_INPUT_POLARITY (1<<13)
+#define APIC_SEND_PENDING (1<<12)
+
+#define ESR_ILLEGAL_ADDRESS (1 << 7)
+
+#define APIC_SV_DIRECTED_IO (1<<12)
+#define APIC_SV_ENABLE (1<<8)
+
+#define MAX_APICS 255
+
+#define MSI_SPACE_SIZE 0x100000
+
+typedef struct APICCommonState APICCommonState;
+
+#define TYPE_APIC_COMMON "apic-common"
+#define APIC_COMMON(obj) \
+ OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC_COMMON)
+#define APIC_COMMON_CLASS(klass) \
+ OBJECT_CLASS_CHECK(APICCommonClass, (klass), TYPE_APIC_COMMON)
+#define APIC_COMMON_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(APICCommonClass, (obj), TYPE_APIC_COMMON)
+
+typedef struct APICCommonClass
+{
+ SysBusDeviceClass parent_class;
+
+ void (*init)(APICCommonState *s);
+ void (*set_base)(APICCommonState *s, uint64_t val);
+ void (*set_tpr)(APICCommonState *s, uint8_t val);
+ void (*external_nmi)(APICCommonState *s);
+ void (*post_load)(APICCommonState *s);
+} APICCommonClass;
+
+struct APICCommonState {
+ SysBusDevice busdev;
+ MemoryRegion io_memory;
+ void *cpu_env;
+ uint32_t apicbase;
+ uint8_t id;
+ uint8_t arb_id;
+ uint8_t tpr;
+ uint32_t spurious_vec;
+ uint8_t log_dest;
+ uint8_t dest_mode;
+ uint32_t isr[8]; /* in service register */
+ uint32_t tmr[8]; /* trigger mode register */
+ uint32_t irr[8]; /* interrupt request register */
+ uint32_t lvt[APIC_LVT_NB];
+ uint32_t esr; /* error register */
+ uint32_t icr[2];
+
+ uint32_t divide_conf;
+ int count_shift;
+ uint32_t initial_count;
+ int64_t initial_count_load_time;
+ int64_t next_time;
+ int idx;
+ QEMUTimer *timer;
+ int64_t timer_expiry;
+ int sipi_vector;
+ int wait_for_sipi;
+};
+
+void apic_report_irq_delivered(int delivered);
+bool apic_next_timer(APICCommonState *s, int64_t current_time);
+
+#endif /* !QEMU_APIC_INTERNAL_H */
diff --git a/hw/applesmc.c b/hw/applesmc.c
index c47b592..b06487f 100644
--- a/hw/applesmc.c
+++ b/hw/applesmc.c
@@ -220,22 +220,32 @@
return 0;
}
-static ISADeviceInfo applesmc_isa_info = {
- .qdev.name = "isa-applesmc",
- .qdev.size = sizeof(struct AppleSMCStatus),
- .qdev.reset = qdev_applesmc_isa_reset,
- .init = applesmc_isa_init,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase,
- APPLESMC_DEFAULT_IOBASE),
- DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property applesmc_isa_properties[] = {
+ DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase,
+ APPLESMC_DEFAULT_IOBASE),
+ DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = applesmc_isa_init;
+ dc->reset = qdev_applesmc_isa_reset;
+ dc->props = applesmc_isa_properties;
+}
+
+static TypeInfo applesmc_isa_info = {
+ .name = "isa-applesmc",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(struct AppleSMCStatus),
+ .class_init = qdev_applesmc_class_init,
};
static void applesmc_register_devices(void)
{
- isa_qdev_register(&applesmc_isa_info);
+ type_register_static(&applesmc_isa_info);
}
device_init(applesmc_register_devices)
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 6e8ae6b..5e5204b 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -30,12 +30,29 @@
const char *kernel_cmdline;
const char *initrd_filename;
target_phys_addr_t loader_start;
+ /* multicore boards that use the default secondary core boot functions
+ * need to put the address of the secondary boot code, the boot reg,
+ * and the GIC address in the next 3 values, respectively. boards that
+ * have their own boot functions can use these values as they want.
+ */
target_phys_addr_t smp_loader_start;
target_phys_addr_t smp_bootreg_addr;
target_phys_addr_t smp_priv_base;
int nb_cpus;
int board_id;
int (*atag_board)(const struct arm_boot_info *info, void *p);
+ /* multicore boards that use the default secondary core boot functions
+ * can ignore these two function calls. If the default functions won't
+ * work, then write_secondary_boot() should write a suitable blob of
+ * code mimicing the secondary CPU startup process used by the board's
+ * boot loader/boot ROM code, and secondary_cpu_reset_hook() should
+ * perform any necessary CPU reset handling and set the PC for thei
+ * secondary CPUs to point at this boot blob.
+ */
+ void (*write_secondary_boot)(CPUState *env,
+ const struct arm_boot_info *info);
+ void (*secondary_cpu_reset_hook)(CPUState *env,
+ const struct arm_boot_info *info);
/* Used internally by arm_boot.c */
int is_linux;
target_phys_addr_t initrd_size;
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index bc0457e..3c0839c 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,11 +10,6 @@
#include "sysbus.h"
#include "qemu-timer.h"
-/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
- (+ 32 internal). However my test chip only exposes/reports 32.
- More importantly Linux falls over if more than 32 are present! */
-#define GIC_NIRQ 64
-
#define NCPU 4
static inline int
@@ -37,6 +32,7 @@
MemoryRegion iomem;
MemoryRegion container;
DeviceState *mptimer;
+ uint32_t num_irq;
} mpcore_priv_state;
/* Per-CPU private memory mapped IO. */
@@ -132,7 +128,7 @@
{
mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
- gic_init(&s->gic, s->num_cpu);
+ gic_init(&s->gic, s->num_cpu, s->num_irq);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
qdev_init_nofail(s->mptimer);
@@ -205,30 +201,61 @@
return 0;
}
-static SysBusDeviceInfo mpcore_rirq_info = {
- .init = realview_mpcore_init,
- .qdev.name = "realview_mpcore",
- .qdev.size = sizeof(mpcore_rirq_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property mpcore_rirq_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+ /* The ARM11 MPCORE TRM says the on-chip controller may have
+ * anything from 0 to 224 external interrupt IRQ lines (with another
+ * 32 internal). We default to 32+32, which is the number provided by
+ * the ARM11 MPCore test chip in the Realview Versatile Express
+ * coretile. Other boards may differ and should set this property
+ * appropriately. Some Linux kernels may not boot if the hardware
+ * has more IRQ lines than the kernel expects.
+ */
+ DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo mpcore_priv_info = {
- .init = mpcore_priv_init,
- .qdev.name = "arm11mpcore_priv",
- .qdev.size = sizeof(mpcore_priv_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = realview_mpcore_init;
+ dc->props = mpcore_rirq_properties;
+}
+
+static TypeInfo mpcore_rirq_info = {
+ .name = "realview_mpcore",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mpcore_rirq_state),
+ .class_init = mpcore_rirq_class_init,
+};
+
+static Property mpcore_priv_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mpcore_priv_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mpcore_priv_init;
+ dc->props = mpcore_priv_properties;
+}
+
+static TypeInfo mpcore_priv_info = {
+ .name = "arm11mpcore_priv",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mpcore_priv_state),
+ .class_init = mpcore_priv_class_init,
};
static void arm11mpcore_register_devices(void)
{
- sysbus_register_withprop(&mpcore_rirq_info);
- sysbus_register_withprop(&mpcore_priv_info);
+ type_register_static(&mpcore_rirq_info);
+ type_register_static(&mpcore_priv_info);
}
device_init(arm11mpcore_register_devices)
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index bf509a8..5f163fd 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -20,16 +20,28 @@
/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
static uint32_t bootloader[] = {
0xe3a00000, /* mov r0, #0 */
- 0xe3a01000, /* mov r1, #0x?? */
- 0xe3811c00, /* orr r1, r1, #0x??00 */
- 0xe59f2000, /* ldr r2, [pc, #0] */
- 0xe59ff000, /* ldr pc, [pc, #0] */
+ 0xe59f1004, /* ldr r1, [pc, #4] */
+ 0xe59f2004, /* ldr r2, [pc, #4] */
+ 0xe59ff004, /* ldr pc, [pc, #4] */
+ 0, /* Board ID */
0, /* Address of kernel args. Set by integratorcp_init. */
0 /* Kernel entry point. Set by integratorcp_init. */
};
-/* Entry point for secondary CPUs. Enable interrupt controller and
- Issue WFI until start address is written to system controller. */
+/* Handling for secondary CPU boot in a multicore system.
+ * Unlike the uniprocessor/primary CPU boot, this is platform
+ * dependent. The default code here is based on the secondary
+ * CPU boot protocol used on realview/vexpress boards, with
+ * some parameterisation to increase its flexibility.
+ * QEMU platform models for which this code is not appropriate
+ * should override write_secondary_boot and secondary_cpu_reset_hook
+ * instead.
+ *
+ * This code enables the interrupt controllers for the secondary
+ * CPUs and then puts all the secondary CPUs into a loop waiting
+ * for an interprocessor interrupt and polling a configurable
+ * location for the kernel secondary CPU entry point.
+ */
static uint32_t smpboot[] = {
0xe59f201c, /* ldr r2, privbase */
0xe59f001c, /* ldr r0, startaddr */
@@ -44,6 +56,26 @@
0 /* bootreg: Boot register address is held here */
};
+static void default_write_secondary(CPUState *env,
+ const struct arm_boot_info *info)
+{
+ int n;
+ smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
+ smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base;
+ for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+ smpboot[n] = tswap32(smpboot[n]);
+ }
+ rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+ info->smp_loader_start);
+}
+
+static void default_reset_secondary(CPUState *env,
+ const struct arm_boot_info *info)
+{
+ stl_phys_notdirty(info->smp_bootreg_addr, 0);
+ env->regs[15] = info->smp_loader_start;
+}
+
#define WRITE_WORD(p, value) do { \
stl_phys_notdirty(p, value); \
p += 4; \
@@ -197,8 +229,7 @@
info->loader_start);
}
} else {
- stl_phys_notdirty(info->smp_bootreg_addr, 0);
- env->regs[15] = info->smp_loader_start;
+ info->secondary_cpu_reset_hook(env, info);
}
}
}
@@ -220,6 +251,13 @@
exit(1);
}
+ if (!info->secondary_cpu_reset_hook) {
+ info->secondary_cpu_reset_hook = default_reset_secondary;
+ }
+ if (!info->write_secondary_boot) {
+ info->write_secondary_boot = default_write_secondary;
+ }
+
if (info->nb_cpus == 0)
info->nb_cpus = 1;
@@ -263,8 +301,7 @@
} else {
initrd_size = 0;
}
- bootloader[1] |= info->board_id & 0xff;
- bootloader[2] |= (info->board_id >> 8) & 0xff;
+ bootloader[4] = info->board_id;
bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
bootloader[6] = entry;
for (n = 0; n < sizeof(bootloader) / 4; n++) {
@@ -273,13 +310,7 @@
rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
info->loader_start);
if (info->nb_cpus > 1) {
- smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
- smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base;
- for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
- smpboot[n] = tswap32(smpboot[n]);
- }
- rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
+ info->write_secondary_boot(env, info);
}
info->initrd_size = initrd_size;
}
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 0339cf5..cf582a5 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -11,6 +11,8 @@
controller, MPCore distributed interrupt controller and ARMv7-M
Nested Vectored Interrupt Controller. */
+/* Maximum number of possible interrupts, determined by the GIC architecture */
+#define GIC_MAXIRQ 1020
//#define DEBUG_GIC
#ifdef DEBUG_GIC
@@ -86,13 +88,13 @@
int enabled;
int cpu_enabled[NCPU];
- gic_irq_state irq_state[GIC_NIRQ];
+ gic_irq_state irq_state[GIC_MAXIRQ];
#ifndef NVIC
- int irq_target[GIC_NIRQ];
+ int irq_target[GIC_MAXIRQ];
#endif
int priority1[32][NCPU];
- int priority2[GIC_NIRQ - 32];
- int last_active[GIC_NIRQ][NCPU];
+ int priority2[GIC_MAXIRQ - 32];
+ int last_active[GIC_MAXIRQ][NCPU];
int priority_mask[NCPU];
int running_irq[NCPU];
@@ -111,6 +113,7 @@
struct gic_state *backref[NCPU];
MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
#endif
+ uint32_t num_irq;
} gic_state;
/* TODO: Many places that call this routine could be optimized. */
@@ -133,7 +136,7 @@
}
best_prio = 0x100;
best_irq = 1023;
- for (irq = 0; irq < GIC_NIRQ; irq++) {
+ for (irq = 0; irq < s->num_irq; irq++) {
if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
best_prio = GIC_GET_PRIORITY(irq, cpu);
@@ -222,7 +225,7 @@
int update = 0;
int cm = 1 << cpu;
DPRINTF("EOI %d\n", irq);
- if (irq >= GIC_NIRQ) {
+ if (irq >= s->num_irq) {
/* This handles two cases:
* 1. If software writes the ID of a spurious interrupt [ie 1023]
* to the GICC_EOIR, the GIC ignores that write.
@@ -279,7 +282,7 @@
if (offset == 0)
return s->enabled;
if (offset == 4)
- return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
+ return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
if (offset < 0x08)
return 0;
if (offset >= 0x80) {
@@ -295,7 +298,7 @@
else
irq = (offset - 0x180) * 8;
irq += GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
for (i = 0; i < 8; i++) {
@@ -310,7 +313,7 @@
else
irq = (offset - 0x280) * 8;
irq += GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
mask = (irq < 32) ? cm : ALL_CPU_MASK;
@@ -322,7 +325,7 @@
} else if (offset < 0x400) {
/* Interrupt Active. */
irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
mask = (irq < 32) ? cm : ALL_CPU_MASK;
@@ -334,14 +337,14 @@
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = (offset - 0x400) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = GIC_GET_PRIORITY(irq, cpu);
#ifndef NVIC
} else if (offset < 0xc00) {
/* Interrupt CPU Target. */
irq = (offset - 0x800) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq >= 29 && irq <= 31) {
res = cm;
@@ -351,7 +354,7 @@
} else if (offset < 0xf00) {
/* Interrupt Configuration. */
irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
for (i = 0; i < 4; i++) {
@@ -426,7 +429,7 @@
} else if (offset < 0x180) {
/* Interrupt Set Enable. */
irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
value = 0xff;
@@ -451,7 +454,7 @@
} else if (offset < 0x200) {
/* Interrupt Clear Enable. */
irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
value = 0;
@@ -468,7 +471,7 @@
} else if (offset < 0x280) {
/* Interrupt Set Pending. */
irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
irq = 0;
@@ -481,7 +484,7 @@
} else if (offset < 0x300) {
/* Interrupt Clear Pending. */
irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
for (i = 0; i < 8; i++) {
/* ??? This currently clears the pending bit for all CPUs, even
@@ -497,7 +500,7 @@
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = (offset - 0x400) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 32) {
s->priority1[irq][cpu] = value;
@@ -508,7 +511,7 @@
} else if (offset < 0xc00) {
/* Interrupt CPU Target. */
irq = (offset - 0x800) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 29)
value = 0;
@@ -518,7 +521,7 @@
} else if (offset < 0xf00) {
/* Interrupt Configuration. */
irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 32)
value |= 0xaa;
@@ -699,7 +702,7 @@
static void gic_reset(gic_state *s)
{
int i;
- memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
+ memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
for (i = 0 ; i < NUM_CPU(s); i++) {
s->priority_mask[i] = 0xf0;
s->current_pending[i] = 1023;
@@ -735,17 +738,17 @@
qemu_put_be32(f, s->cpu_enabled[i]);
for (j = 0; j < 32; j++)
qemu_put_be32(f, s->priority1[j][i]);
- for (j = 0; j < GIC_NIRQ; j++)
+ for (j = 0; j < s->num_irq; j++)
qemu_put_be32(f, s->last_active[j][i]);
qemu_put_be32(f, s->priority_mask[i]);
qemu_put_be32(f, s->running_irq[i]);
qemu_put_be32(f, s->running_priority[i]);
qemu_put_be32(f, s->current_pending[i]);
}
- for (i = 0; i < GIC_NIRQ - 32; i++) {
+ for (i = 0; i < s->num_irq - 32; i++) {
qemu_put_be32(f, s->priority2[i]);
}
- for (i = 0; i < GIC_NIRQ; i++) {
+ for (i = 0; i < s->num_irq; i++) {
#ifndef NVIC
qemu_put_be32(f, s->irq_target[i]);
#endif
@@ -772,17 +775,17 @@
s->cpu_enabled[i] = qemu_get_be32(f);
for (j = 0; j < 32; j++)
s->priority1[j][i] = qemu_get_be32(f);
- for (j = 0; j < GIC_NIRQ; j++)
+ for (j = 0; j < s->num_irq; j++)
s->last_active[j][i] = qemu_get_be32(f);
s->priority_mask[i] = qemu_get_be32(f);
s->running_irq[i] = qemu_get_be32(f);
s->running_priority[i] = qemu_get_be32(f);
s->current_pending[i] = qemu_get_be32(f);
}
- for (i = 0; i < GIC_NIRQ - 32; i++) {
+ for (i = 0; i < s->num_irq - 32; i++) {
s->priority2[i] = qemu_get_be32(f);
}
- for (i = 0; i < GIC_NIRQ; i++) {
+ for (i = 0; i < s->num_irq; i++) {
#ifndef NVIC
s->irq_target[i] = qemu_get_be32(f);
#endif
@@ -798,9 +801,9 @@
}
#if NCPU > 1
-static void gic_init(gic_state *s, int num_cpu)
+static void gic_init(gic_state *s, int num_cpu, int num_irq)
#else
-static void gic_init(gic_state *s)
+static void gic_init(gic_state *s, int num_irq)
#endif
{
int i;
@@ -808,7 +811,12 @@
#if NCPU > 1
s->num_cpu = num_cpu;
#endif
- qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
+ s->num_irq = num_irq + GIC_BASE_IRQ;
+ if (s->num_irq > GIC_MAXIRQ) {
+ hw_error("requested %u interrupt lines exceeds GIC maximum %d\n",
+ num_irq, GIC_MAXIRQ);
+ }
+ qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - 32);
for (i = 0; i < NUM_CPU(s); i++) {
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
index 2faed39..ba26abc 100644
--- a/hw/arm_l2x0.c
+++ b/hw/arm_l2x0.c
@@ -160,22 +160,33 @@
return 0;
}
-static SysBusDeviceInfo l2x0_info = {
- .init = l2x0_priv_init,
- .qdev.name = "l2x0",
- .qdev.size = sizeof(l2x0_state),
- .qdev.vmsd = &vmstate_l2x0,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = l2x0_priv_reset,
+static Property l2x0_properties[] = {
+ DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void l2x0_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = l2x0_priv_init;
+ dc->vmsd = &vmstate_l2x0;
+ dc->no_user = 1;
+ dc->props = l2x0_properties;
+ dc->reset = l2x0_priv_reset;
+}
+
+static TypeInfo l2x0_info = {
+ .name = "l2x0",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(l2x0_state),
+ .class_init = l2x0_class_init,
};
static void l2x0_register_device(void)
{
- sysbus_register_withprop(&l2x0_info);
+ type_register_static(&l2x0_info);
}
device_init(l2x0_register_device)
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index 455a0aa..5a02365 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -311,22 +311,33 @@
}
};
-static SysBusDeviceInfo arm_mptimer_info = {
- .init = arm_mptimer_init,
- .qdev.name = "arm_mptimer",
- .qdev.size = sizeof(arm_mptimer_state),
- .qdev.vmsd = &vmstate_arm_mptimer,
- .qdev.reset = arm_mptimer_reset,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property arm_mptimer_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void arm_mptimer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = arm_mptimer_init;
+ dc->vmsd = &vmstate_arm_mptimer;
+ dc->reset = arm_mptimer_reset;
+ dc->no_user = 1;
+ dc->props = arm_mptimer_properties;
+}
+
+static TypeInfo arm_mptimer_info = {
+ .name = "arm_mptimer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(arm_mptimer_state),
+ .class_init = arm_mptimer_class_init,
};
static void arm_mptimer_register_devices(void)
{
- sysbus_register_withprop(&arm_mptimer_info);
+ type_register_static(&arm_mptimer_info);
}
device_init(arm_mptimer_register_devices)
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 4b88648..9d25799 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -401,22 +401,33 @@
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
}
-static SysBusDeviceInfo arm_sysctl_info = {
- .init = arm_sysctl_init1,
- .qdev.name = "realview_sysctl",
- .qdev.size = sizeof(arm_sysctl_state),
- .qdev.vmsd = &vmstate_arm_sysctl,
- .qdev.reset = arm_sysctl_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
- DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property arm_sysctl_properties[] = {
+ DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
+ DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_sysctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = arm_sysctl_init1;
+ dc->reset = arm_sysctl_reset;
+ dc->vmsd = &vmstate_arm_sysctl;
+ dc->props = arm_sysctl_properties;
+}
+
+static TypeInfo arm_sysctl_info = {
+ .name = "realview_sysctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(arm_sysctl_state),
+ .class_init = arm_sysctl_class_init,
};
static void arm_sysctl_register_devices(void)
{
- sysbus_register_withprop(&arm_sysctl_info);
+ type_register_static(&arm_sysctl_info);
}
device_init(arm_sysctl_register_devices)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 1902f1a..1019d41 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -273,11 +273,8 @@
qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
sysbus_init_irq(dev, &s->irq);
- /* The timers are configurable between 32kHz and 1MHz
- * defaulting to 1MHz but overrideable as individual properties */
s->timer[0] = arm_timer_init(s->freq0);
s->timer[1] = arm_timer_init(s->freq1);
-
s->timer[0]->irq = qi[0];
s->timer[1]->irq = qi[1];
memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
@@ -286,17 +283,6 @@
return 0;
}
-static SysBusDeviceInfo sp804_info = {
- .init = sp804_init,
- .qdev.name = "sp804",
- .qdev.size = sizeof(sp804_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
- DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
/* Integrator/CP timer module. */
typedef struct {
@@ -361,10 +347,46 @@
return 0;
}
+static void icp_pit_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = icp_pit_init;
+}
+
+static TypeInfo icp_pit_info = {
+ .name = "integrator_pit",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(icp_pit_state),
+ .class_init = icp_pit_class_init,
+};
+
+static Property sp804_properties[] = {
+ DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
+ DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sp804_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *k = DEVICE_CLASS(klass);
+
+ sdc->init = sp804_init;
+ k->props = sp804_properties;
+}
+
+static TypeInfo sp804_info = {
+ .name = "sp804",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(sp804_state),
+ .class_init = sp804_class_init,
+};
+
static void arm_timer_register_devices(void)
{
- sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
- sysbus_register_withprop(&sp804_info);
+ type_register_static(&icp_pit_info);
+ type_register_static(&sp804_info);
}
device_init(arm_timer_register_devices)
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 5c7a950..de3d7e0 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -245,19 +245,30 @@
return pic;
}
-static SysBusDeviceInfo bitband_info = {
- .init = bitband_init,
- .qdev.name = "ARM,bitband-memory",
- .qdev.size = sizeof(BitBandState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("base", BitBandState, base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property bitband_properties[] = {
+ DEFINE_PROP_UINT32("base", BitBandState, base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void bitband_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = bitband_init;
+ dc->props = bitband_properties;
+}
+
+static TypeInfo bitband_info = {
+ .name = "ARM,bitband-memory",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BitBandState),
+ .class_init = bitband_class_init,
};
static void armv7m_register_devices(void)
{
- sysbus_register_withprop(&bitband_info);
+ type_register_static(&bitband_info);
}
device_init(armv7m_register_devices)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index bf8c3c5..1ed0abc 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -15,9 +15,6 @@
#include "arm-misc.h"
#include "exec-memory.h"
-/* 32 internal lines (16 used for system exceptions) plus 64 external
- interrupt lines. */
-#define GIC_NIRQ 96
#define NCPU 1
#define NVIC 1
@@ -41,6 +38,7 @@
int64_t tick;
QEMUTimer *timer;
} systick;
+ uint32_t num_irq;
} nvic_state;
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
@@ -125,7 +123,7 @@
switch (offset) {
case 4: /* Interrupt Control Type. */
- return (GIC_NIRQ / 32) - 1;
+ return (s->num_irq / 32) - 1;
case 0x10: /* SysTick Control and Status. */
val = s->systick.control;
s->systick.control &= ~SYSTICK_COUNTFLAG;
@@ -169,7 +167,7 @@
if (s->gic.current_pending[0] != 1023)
val |= (s->gic.current_pending[0] << 12);
/* ISRPENDING */
- for (irq = 32; irq < GIC_NIRQ; irq++) {
+ for (irq = 32; irq < s->num_irq; irq++) {
if (s->gic.irq_state[irq].pending) {
val |= (1 << 22);
break;
@@ -384,16 +382,44 @@
{
nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
- gic_init(&s->gic);
+ /* note that for the M profile gic_init() takes the number of external
+ * interrupt lines only.
+ */
+ gic_init(&s->gic, s->num_irq);
memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
- vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
return 0;
}
+static Property armv7m_nvic_properties[] = {
+ /* The ARM v7m may have anything from 0 to 496 external interrupt
+ * IRQ lines. We default to 64. Other boards may differ and should
+ * set this property appropriately.
+ */
+ DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = armv7m_nvic_init;
+ dc->vmsd = &vmstate_nvic;
+ dc->props = armv7m_nvic_properties;
+}
+
+static TypeInfo armv7m_nvic_info = {
+ .name = "armv7m_nvic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(nvic_state),
+ .class_init = armv7m_nvic_class_init,
+};
+
static void armv7m_nvic_register_devices(void)
{
- sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
+ type_register_static(&armv7m_nvic_info);
}
device_init(armv7m_nvic_register_devices)
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
index 93fb2ed..c9c1182 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -221,16 +221,25 @@
return 0;
}
-static SysBusDeviceInfo gpio_i2c_info = {
- .init = gpio_i2c_init,
- .qdev.name = "gpio_i2c",
- .qdev.desc = "Virtual GPIO to I2C bridge",
- .qdev.size = sizeof(GPIOI2CState),
+static void gpio_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = gpio_i2c_init;
+ dc->desc = "Virtual GPIO to I2C bridge";
+}
+
+static TypeInfo gpio_i2c_info = {
+ .name = "gpio_i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GPIOI2CState),
+ .class_init = gpio_i2c_class_init,
};
static void bitbang_i2c_register(void)
{
- sysbus_register_withprop(&gpio_i2c_info);
+ type_register_static(&gpio_i2c_info);
}
device_init(bitbang_i2c_register)
diff --git a/hw/boards.h b/hw/boards.h
index 716fd7b..f6d3784 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -22,7 +22,6 @@
unsigned int no_serial:1,
no_parallel:1,
use_virtcon:1,
- no_vga:1,
no_floppy:1,
no_cdrom:1,
no_sdcard:1;
diff --git a/hw/bonito.c b/hw/bonito.c
index f2c7837..7350a4f 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -766,30 +766,47 @@
return b;
}
-static PCIDeviceInfo bonito_info = {
- .qdev.name = "Bonito",
- .qdev.desc = "Host bridge",
- .qdev.size = sizeof(PCIBonitoState),
- .qdev.vmsd = &vmstate_bonito,
- .qdev.no_user = 1,
- .init = bonito_initfn,
- /*Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined"*/
- .vendor_id = 0xdf53,
- .device_id = 0x00d5,
- .revision = 0x01,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void bonito_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = bonito_initfn;
+ k->vendor_id = 0xdf53;
+ k->device_id = 0x00d5;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ dc->desc = "Host bridge";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_bonito;
+}
+
+static TypeInfo bonito_info = {
+ .name = "Bonito",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIBonitoState),
+ .class_init = bonito_class_init,
};
-static SysBusDeviceInfo bonito_pcihost_info = {
- .init = bonito_pcihost_initfn,
- .qdev.name = "Bonito-pcihost",
- .qdev.size = sizeof(BonitoState),
- .qdev.no_user = 1,
+static void bonito_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = bonito_pcihost_initfn;
+ dc->no_user = 1;
+}
+
+static TypeInfo bonito_pcihost_info = {
+ .name = "Bonito-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BonitoState),
+ .class_init = bonito_pcihost_class_init,
};
static void bonito_register(void)
{
- sysbus_register_withprop(&bonito_pcihost_info);
- pci_qdev_register(&bonito_info);
+ type_register_static(&bonito_pcihost_info);
+ type_register_static(&bonito_info);
}
device_init(bonito_register);
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 2d2ebce..9510ed4 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -564,29 +564,39 @@
return 0;
}
-static CCIDCardInfo emulated_card_info = {
- .qdev.name = EMULATED_DEV_NAME,
- .qdev.desc = "emulated smartcard",
- .qdev.size = sizeof(EmulatedState),
- .initfn = emulated_initfn,
- .exitfn = emulated_exitfn,
- .get_atr = emulated_get_atr,
- .apdu_from_guest = emulated_apdu_from_guest,
- .qdev.unplug = qdev_simple_unplug_cb,
- .qdev.props = (Property[]) {
- DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
- DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
- DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
- DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
- DEFINE_PROP_STRING("db", EmulatedState, db),
- DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property emulated_card_properties[] = {
+ DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
+ DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
+ DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
+ DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
+ DEFINE_PROP_STRING("db", EmulatedState, db),
+ DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void emulated_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+ cc->initfn = emulated_initfn;
+ cc->exitfn = emulated_exitfn;
+ cc->get_atr = emulated_get_atr;
+ cc->apdu_from_guest = emulated_apdu_from_guest;
+ dc->desc = "emulated smartcard";
+ dc->props = emulated_card_properties;
+}
+
+static TypeInfo emulated_card_info = {
+ .name = EMULATED_DEV_NAME,
+ .parent = TYPE_CCID_CARD,
+ .instance_size = sizeof(EmulatedState),
+ .class_init = emulated_class_initfn,
};
static void ccid_card_emulated_register_devices(void)
{
- ccid_card_qdev_register(&emulated_card_info);
+ type_register_static(&emulated_card_info);
}
device_init(ccid_card_emulated_register_devices)
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
index 9f51c6c..a7006ca 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -316,25 +316,36 @@
}
};
-static CCIDCardInfo passthru_card_info = {
- .qdev.name = PASSTHRU_DEV_NAME,
- .qdev.desc = "passthrough smartcard",
- .qdev.size = sizeof(PassthruState),
- .qdev.vmsd = &passthru_vmstate,
- .initfn = passthru_initfn,
- .exitfn = passthru_exitfn,
- .get_atr = passthru_get_atr,
- .apdu_from_guest = passthru_apdu_from_guest,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", PassthruState, cs),
- DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property passthru_card_properties[] = {
+ DEFINE_PROP_CHR("chardev", PassthruState, cs),
+ DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void passthru_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+ cc->initfn = passthru_initfn;
+ cc->exitfn = passthru_exitfn;
+ cc->get_atr = passthru_get_atr;
+ cc->apdu_from_guest = passthru_apdu_from_guest;
+ dc->desc = "passthrough smartcard";
+ dc->vmsd = &passthru_vmstate;
+ dc->props = passthru_card_properties;
+}
+
+static TypeInfo passthru_card_info = {
+ .name = PASSTHRU_DEV_NAME,
+ .parent = TYPE_CCID_CARD,
+ .instance_size = sizeof(PassthruState),
+ .class_init = passthru_class_initfn,
};
static void ccid_card_passthru_register_devices(void)
{
- ccid_card_qdev_register(&passthru_card_info);
+ type_register_static(&passthru_card_info);
}
device_init(ccid_card_passthru_register_devices)
diff --git a/hw/ccid.h b/hw/ccid.h
index 9e3abe1..6adc745 100644
--- a/hw/ccid.h
+++ b/hw/ccid.h
@@ -15,26 +15,34 @@
typedef struct CCIDCardState CCIDCardState;
typedef struct CCIDCardInfo CCIDCardInfo;
-/*
- * state of the CCID Card device (i.e. hw/ccid-card-*.c)
- */
-struct CCIDCardState {
- DeviceState qdev;
- uint32_t slot; /* For future use with multiple slot reader. */
-};
+#define TYPE_CCID_CARD "ccid-card"
+#define CCID_CARD(obj) \
+ OBJECT_CHECK(CCIDCardState, (obj), TYPE_CCID_CARD)
+#define CCID_CARD_CLASS(klass) \
+ OBJECT_CLASS_CHECK(CCIDCardClass, (klass), TYPE_CCID_CARD)
+#define CCID_CARD_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(CCIDCardClass, (obj), TYPE_CCID_CARD)
/*
* callbacks to be used by the CCID device (hw/usb-ccid.c) to call
* into the smartcard device (hw/ccid-card-*.c)
*/
-struct CCIDCardInfo {
- DeviceInfo qdev;
+typedef struct CCIDCardClass {
+ DeviceClass parent_class;
const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
void (*apdu_from_guest)(CCIDCardState *card,
const uint8_t *apdu,
uint32_t len);
int (*exitfn)(CCIDCardState *card);
int (*initfn)(CCIDCardState *card);
+} CCIDCardClass;
+
+/*
+ * state of the CCID Card device (i.e. hw/ccid-card-*.c)
+ */
+struct CCIDCardState {
+ DeviceState qdev;
+ uint32_t slot; /* For future use with multiple slot reader. */
};
/*
@@ -46,7 +54,6 @@
void ccid_card_card_removed(CCIDCardState *card);
void ccid_card_card_inserted(CCIDCardState *card);
void ccid_card_card_error(CCIDCardState *card, uint64_t error);
-void ccid_card_qdev_register(CCIDCardInfo *card);
/*
* support guest visible insertion/removal of ccid devices based on actual
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index f7b1d3d..a8e8ab7 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -250,6 +250,11 @@
CirrusVGAState cirrus_vga;
} PCICirrusVGAState;
+typedef struct ISACirrusVGAState {
+ ISADevice dev;
+ CirrusVGAState cirrus_vga;
+} ISACirrusVGAState;
+
static uint8_t rop_to_index[256];
/***************************************
@@ -613,11 +618,7 @@
for (y = 0; y < lines; y++) {
off_cur = off_begin;
off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
- off_cur &= TARGET_PAGE_MASK;
- while (off_cur < off_cur_end) {
- memory_region_set_dirty(&s->vga.vram, off_cur);
- off_cur += TARGET_PAGE_SIZE;
- }
+ memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
off_begin += off_pitch;
}
}
@@ -1895,8 +1896,6 @@
*
* write mode 4/5
*
- * assume TARGET_PAGE_SIZE >= 16
- *
***************************************/
static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
@@ -1918,8 +1917,7 @@
val <<= 1;
dst++;
}
- memory_region_set_dirty(&s->vga.vram, offset);
- memory_region_set_dirty(&s->vga.vram, offset + 7);
+ memory_region_set_dirty(&s->vga.vram, offset, 8);
}
static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
@@ -1943,8 +1941,7 @@
val <<= 1;
dst += 2;
}
- memory_region_set_dirty(&s->vga.vram, offset);
- memory_region_set_dirty(&s->vga.vram, offset + 15);
+ memory_region_set_dirty(&s->vga.vram, offset, 16);
}
/***************************************
@@ -2034,7 +2031,8 @@
mode = s->vga.gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
*(s->vga.vram_ptr + bank_offset) = mem_value;
- memory_region_set_dirty(&s->vga.vram, bank_offset);
+ memory_region_set_dirty(&s->vga.vram, bank_offset,
+ sizeof(mem_value));
} else {
if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
cirrus_mem_writeb_mode4and5_8bpp(s, mode,
@@ -2166,6 +2164,15 @@
}
}
+#define DEPTH 8
+#include "cirrus_vga_template.h"
+
+#define DEPTH 16
+#include "cirrus_vga_template.h"
+
+#define DEPTH 32
+#include "cirrus_vga_template.h"
+
static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
{
CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
@@ -2306,7 +2313,7 @@
mode = s->vga.gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
*(s->vga.vram_ptr + addr) = (uint8_t) val;
- memory_region_set_dirty(&s->vga.vram, addr);
+ memory_region_set_dirty(&s->vga.vram, addr, 1);
} else {
if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
@@ -2883,24 +2890,45 @@
*
***************************************/
-DeviceState *isa_cirrus_vga_init(MemoryRegion *system_memory)
+static int vga_initfn(ISADevice *dev)
{
- CirrusVGAState *s;
+ ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev);
+ VGACommonState *s = &d->cirrus_vga.vga;
- s = g_malloc0(sizeof(CirrusVGAState));
-
- vga_common_init(&s->vga, VGA_RAM_SIZE);
- cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0, system_memory);
- s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
- s->vga.screen_dump, s->vga.text_update,
- &s->vga);
- vmstate_register(NULL, 0, &vmstate_cirrus_vga, s);
+ vga_common_init(s, VGA_RAM_SIZE);
+ cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0,
+ isa_address_space(dev));
+ s->ds = graphic_console_init(s->update, s->invalidate,
+ s->screen_dump, s->text_update,
+ s);
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
/* XXX ISA-LFB support */
/* FIXME not qdev yet */
- return NULL;
+ return 0;
}
+static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+ ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_cirrus_vga;
+ k->init = vga_initfn;
+}
+
+static TypeInfo isa_cirrus_vga_info = {
+ .name = "isa-cirrus-vga",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISACirrusVGAState),
+ .class_init = isa_cirrus_vga_class_init,
+};
+
+static void isa_cirrus_vga_register(void)
+{
+ type_register_static(&isa_cirrus_vga_info);
+}
+device_init(isa_cirrus_vga_register)
+
/***************************************
*
* PCI bus support
@@ -2911,8 +2939,8 @@
{
PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
CirrusVGAState *s = &d->cirrus_vga;
- PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info);
- int16_t device_id = info->device_id;
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ int16_t device_id = pc->device_id;
/* setup VGA */
vga_common_init(&s->vga, VGA_RAM_SIZE);
@@ -2946,21 +2974,30 @@
return &pci_create_simple(bus, -1, "cirrus-vga")->qdev;
}
-static PCIDeviceInfo cirrus_vga_info = {
- .qdev.name = "cirrus-vga",
- .qdev.desc = "Cirrus CLGD 54xx VGA",
- .qdev.size = sizeof(PCICirrusVGAState),
- .qdev.vmsd = &vmstate_pci_cirrus_vga,
- .no_hotplug = 1,
- .init = pci_cirrus_vga_initfn,
- .romfile = VGABIOS_CIRRUS_FILENAME,
- .vendor_id = PCI_VENDOR_ID_CIRRUS,
- .device_id = CIRRUS_ID_CLGD5446,
- .class_id = PCI_CLASS_DISPLAY_VGA,
+static void cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = pci_cirrus_vga_initfn;
+ k->romfile = VGABIOS_CIRRUS_FILENAME;
+ k->vendor_id = PCI_VENDOR_ID_CIRRUS;
+ k->device_id = CIRRUS_ID_CLGD5446;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ dc->desc = "Cirrus CLGD 54xx VGA";
+ dc->vmsd = &vmstate_pci_cirrus_vga;
+}
+
+static TypeInfo cirrus_vga_info = {
+ .name = "cirrus-vga",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCICirrusVGAState),
+ .class_init = cirrus_vga_class_init,
};
static void cirrus_vga_register(void)
{
- pci_qdev_register(&cirrus_vga_info);
+ type_register_static(&cirrus_vga_info);
}
device_init(cirrus_vga_register);
diff --git a/hw/cirrus_vga_template.h b/hw/cirrus_vga_template.h
new file mode 100644
index 0000000..3b28280
--- /dev/null
+++ b/hw/cirrus_vga_template.h
@@ -0,0 +1,102 @@
+/*
+ * QEMU Cirrus VGA Emulator templates
+ *
+ * Copyright (c) 2003 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.
+ */
+
+#if DEPTH == 8
+#define BPP 1
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#elif DEPTH == 32
+#define BPP 4
+#else
+#error unsupported depth
+#endif
+
+static void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
+ const uint8_t *src1,
+ int poffset, int w,
+ unsigned int color0,
+ unsigned int color1,
+ unsigned int color_xor)
+{
+ const uint8_t *plane0, *plane1;
+ int x, b0, b1;
+ uint8_t *d;
+
+ d = d1;
+ plane0 = src1;
+ plane1 = src1 + poffset;
+ for (x = 0; x < w; x++) {
+ b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
+ b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
+#if DEPTH == 8
+ switch (b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ d[0] ^= color_xor;
+ break;
+ case 2:
+ d[0] = color0;
+ break;
+ case 3:
+ d[0] = color1;
+ break;
+ }
+#elif DEPTH == 16
+ switch (b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ ((uint16_t *)d)[0] ^= color_xor;
+ break;
+ case 2:
+ ((uint16_t *)d)[0] = color0;
+ break;
+ case 3:
+ ((uint16_t *)d)[0] = color1;
+ break;
+ }
+#elif DEPTH == 32
+ switch (b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ ((uint32_t *)d)[0] ^= color_xor;
+ break;
+ case 2:
+ ((uint32_t *)d)[0] = color0;
+ break;
+ case 3:
+ ((uint32_t *)d)[0] = color1;
+ break;
+ }
+#else
+#error unsupported depth
+#endif
+ d += BPP;
+ }
+}
+
+#undef DEPTH
+#undef BPP
diff --git a/hw/container.c b/hw/container.c
deleted file mode 100644
index 9cbf399..0000000
--- a/hw/container.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "sysbus.h"
-
-static int container_initfn(SysBusDevice *dev)
-{
- return 0;
-}
-
-static SysBusDeviceInfo container_info = {
- .init = container_initfn,
- .qdev.name = "container",
- .qdev.size = sizeof(SysBusDevice),
- .qdev.no_user = 1,
-};
-
-static void container_init(void)
-{
- sysbus_register_withprop(&container_info);
-}
-
-device_init(container_init);
diff --git a/hw/cs4231.c b/hw/cs4231.c
index 2dfb708..c0badbf 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -151,20 +151,31 @@
return 0;
}
-static SysBusDeviceInfo cs4231_info = {
- .init = cs4231_init1,
- .qdev.name = "SUNW,CS4231",
- .qdev.size = sizeof(CSState),
- .qdev.vmsd = &vmstate_cs4231,
- .qdev.reset = cs_reset,
- .qdev.props = (Property[]) {
- {.name = NULL}
- }
+static Property cs4231_properties[] = {
+ {.name = NULL},
+};
+
+static void cs4231_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = cs4231_init1;
+ dc->reset = cs_reset;
+ dc->vmsd = &vmstate_cs4231;
+ dc->props = cs4231_properties;
+}
+
+static TypeInfo cs4231_info = {
+ .name = "SUNW,CS4231",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(CSState),
+ .class_init = cs4231_class_init,
};
static void cs4231_register_devices(void)
{
- sysbus_register_withprop(&cs4231_info);
+ type_register_static(&cs4231_info);
}
device_init(cs4231_register_devices)
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index dc77a3a..ad04ad6 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -622,13 +622,13 @@
.pre_load = cs4231a_pre_load,
.post_load = cs4231a_post_load,
.fields = (VMStateField []) {
- VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
- VMSTATE_BUFFER(dregs, CSState),
- VMSTATE_INT32(dma_running, CSState),
- VMSTATE_INT32(audio_free, CSState),
- VMSTATE_INT32(transferred, CSState),
- VMSTATE_INT32(aci_counter, CSState),
- VMSTATE_END_OF_LIST()
+ VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
+ VMSTATE_BUFFER (dregs, CSState),
+ VMSTATE_INT32 (dma_running, CSState),
+ VMSTATE_INT32 (audio_free, CSState),
+ VMSTATE_INT32 (transferred, CSState),
+ VMSTATE_INT32 (aci_counter, CSState),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -665,22 +665,32 @@
return 0;
}
-static ISADeviceInfo cs4231a_info = {
- .qdev.name = "cs4231a",
- .qdev.desc = "Crystal Semiconductor CS4231A",
- .qdev.size = sizeof (CSState),
- .qdev.vmsd = &vmstate_cs4231a,
- .init = cs4231a_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32 ("iobase", CSState, port, 0x534),
- DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
- DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
- DEFINE_PROP_END_OF_LIST (),
- },
+static Property cs4231a_properties[] = {
+ DEFINE_PROP_HEX32 ("iobase", CSState, port, 0x534),
+ DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
+ DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
+ DEFINE_PROP_END_OF_LIST (),
+};
+
+static void cs4231a_class_initfn (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+ ic->init = cs4231a_initfn;
+ dc->desc = "Crystal Semiconductor CS4231A";
+ dc->vmsd = &vmstate_cs4231a;
+ dc->props = cs4231a_properties;
+}
+
+static TypeInfo cs4231a_info = {
+ .name = "cs4231a",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof (CSState),
+ .class_init = cs4231a_class_initfn,
};
static void cs4231a_register (void)
{
- isa_qdev_register (&cs4231a_info);
+ type_register_static (&cs4231a_info);
}
device_init (cs4231a_register)
diff --git a/hw/debugcon.c b/hw/debugcon.c
index c9ee6d9..3903b26 100644
--- a/hw/debugcon.c
+++ b/hw/debugcon.c
@@ -87,21 +87,31 @@
return 0;
}
-static ISADeviceInfo debugcon_isa_info = {
- .qdev.name = "isa-debugcon",
- .qdev.size = sizeof(ISADebugconState),
- .init = debugcon_isa_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
- DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
- DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property debugcon_isa_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
+ DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
+ DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void debugcon_isa_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = debugcon_isa_initfn;
+ dc->props = debugcon_isa_properties;
+}
+
+static TypeInfo debugcon_isa_info = {
+ .name = "isa-debugcon",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISADebugconState),
+ .class_init = debugcon_isa_class_initfn,
};
static void debugcon_register_devices(void)
{
- isa_qdev_register(&debugcon_isa_info);
+ type_register_static(&debugcon_isa_info);
}
device_init(debugcon_register_devices)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index 08d4e06..a40fbcf 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -50,18 +50,27 @@
return irq_num;
}
-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 = pci_bridge_initfn,
- .exit = pci_bridge_exitfn,
- .vendor_id = PCI_VENDOR_ID_DEC,
- .device_id = PCI_DEVICE_ID_DEC_21154,
- .config_write = pci_bridge_write_config,
- .is_bridge = 1,
+static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_bridge_initfn;
+ k->exit = pci_bridge_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_DEC;
+ k->device_id = PCI_DEVICE_ID_DEC_21154;
+ k->config_write = pci_bridge_write_config;
+ k->is_bridge = 1;
+ dc->desc = "DEC 21154 PCI-PCI bridge";
+ dc->reset = pci_bridge_reset;
+ dc->vmsd = &vmstate_pci_device;
+}
+
+static TypeInfo dec_21154_pci_bridge_info = {
+ .name = "dec-21154-p2p-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIBridge),
+ .class_init = dec_21154_pci_bridge_class_init,
};
PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
@@ -77,7 +86,7 @@
return pci_bridge_get_sec_bus(br);
}
-static int pci_dec_21154_init_device(SysBusDevice *dev)
+static int pci_dec_21154_device_init(SysBusDevice *dev)
{
DECState *s;
@@ -98,23 +107,44 @@
return 0;
}
-static PCIDeviceInfo dec_21154_pci_host_info = {
- .qdev.name = "dec-21154",
- .qdev.size = sizeof(PCIDevice),
- .init = dec_21154_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_DEC,
- .device_id = PCI_DEVICE_ID_DEC_21154,
- .revision = 0x02,
- .class_id = PCI_CLASS_BRIDGE_PCI,
- .is_bridge = 1,
+static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = dec_21154_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_DEC;
+ k->device_id = PCI_DEVICE_ID_DEC_21154;
+ k->revision = 0x02;
+ k->class_id = PCI_CLASS_BRIDGE_PCI;
+ k->is_bridge = 1;
+}
+
+static TypeInfo dec_21154_pci_host_info = {
+ .name = "dec-21154",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = dec_21154_pci_host_class_init,
+};
+
+static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pci_dec_21154_device_init;
+}
+
+static TypeInfo pci_dec_21154_device_info = {
+ .name = "dec-21154-sysbus",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(DECState),
+ .class_init = pci_dec_21154_device_class_init,
};
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);
+ type_register_static(&pci_dec_21154_device_info);
+ type_register_static(&dec_21154_pci_host_info);
+ type_register_static(&dec_21154_pci_bridge_info);
}
device_init(dec_register_devices)
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 7aa0832..539bceb 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -134,21 +134,32 @@
return 0;
}
-static SysBusDeviceInfo nvram_sysbus_info = {
- .qdev.name = "ds1225y",
- .qdev.size = sizeof(SysBusNvRamState),
- .qdev.vmsd = &vmstate_nvram,
- .init = nvram_sysbus_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
- DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property nvram_sysbus_properties[] = {
+ DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
+ DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nvram_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = nvram_sysbus_initfn;
+ dc->vmsd = &vmstate_nvram;
+ dc->props = nvram_sysbus_properties;
+}
+
+static TypeInfo nvram_sysbus_info = {
+ .name = "ds1225y",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusNvRamState),
+ .class_init = nvram_sysbus_class_init,
};
static void nvram_register(void)
{
- sysbus_register_withprop(&nvram_sysbus_info);
+ type_register_static(&nvram_sysbus_info);
}
device_init(nvram_register)
diff --git a/hw/ds1338.c b/hw/ds1338.c
index f754cb7..b137e13 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -13,7 +13,7 @@
#include "i2c.h"
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
time_t offset;
struct tm now;
uint8_t nvram[56];
@@ -21,7 +21,7 @@
int addr_byte;
} DS1338State;
-static void ds1338_event(i2c_slave *i2c, enum i2c_event event)
+static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
{
DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
@@ -51,7 +51,7 @@
}
}
-static int ds1338_recv(i2c_slave *i2c)
+static int ds1338_recv(I2CSlave *i2c)
{
DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
uint8_t res;
@@ -61,7 +61,7 @@
return res;
}
-static int ds1338_send(i2c_slave *i2c, uint8_t data)
+static int ds1338_send(I2CSlave *i2c, uint8_t data)
{
DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
if (s->addr_byte) {
@@ -113,23 +113,31 @@
return 0;
}
-static int ds1338_init(i2c_slave *i2c)
+static int ds1338_init(I2CSlave *i2c)
{
return 0;
}
-static I2CSlaveInfo ds1338_info = {
- .qdev.name = "ds1338",
- .qdev.size = sizeof(DS1338State),
- .init = ds1338_init,
- .event = ds1338_event,
- .recv = ds1338_recv,
- .send = ds1338_send,
+static void ds1338_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = ds1338_init;
+ k->event = ds1338_event;
+ k->recv = ds1338_recv;
+ k->send = ds1338_send;
+}
+
+static TypeInfo ds1338_info = {
+ .name = "ds1338",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(DS1338State),
+ .class_init = ds1338_class_init,
};
static void ds1338_register_devices(void)
{
- i2c_register_slave(&ds1338_info);
+ type_register_static(&ds1338_info);
}
device_init(ds1338_register_devices)
diff --git a/hw/e1000.c b/hw/e1000.c
index a29c944..751f79d5 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -466,6 +466,8 @@
bytes = split_size;
if (tp->size + bytes > msh)
bytes = msh - tp->size;
+
+ bytes = MIN(sizeof(tp->data) - tp->size, bytes);
pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
memmove(tp->header, tp->data, hdr);
@@ -481,6 +483,7 @@
// context descriptor TSE is not set, while data descriptor TSE is set
DBGOUT(TXERR, "TCP segmentaion Error\n");
} else {
+ split_size = MIN(sizeof(tp->data) - tp->size, split_size);
pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
tp->size += split_size;
}
@@ -1130,6 +1133,11 @@
memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
d->rxbuf_min_shift = 1;
memset(&d->tx, 0, sizeof d->tx);
+
+ if (d->nic->nc.link_down) {
+ d->mac_reg[STATUS] &= ~E1000_STATUS_LU;
+ d->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
+ }
}
static NetClientInfo net_e1000_info = {
@@ -1174,7 +1182,7 @@
d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
- d->dev.qdev.info->name, d->dev.qdev.id, d);
+ object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
qemu_format_nic_info_str(&d->nic->nc, macaddr);
@@ -1189,28 +1197,39 @@
e1000_reset(d);
}
-static PCIDeviceInfo e1000_info = {
- .qdev.name = "e1000",
- .qdev.desc = "Intel Gigabit Ethernet",
- .qdev.size = sizeof(E1000State),
- .qdev.reset = qdev_e1000_reset,
- .qdev.vmsd = &vmstate_e1000,
- .init = pci_e1000_init,
- .exit = pci_e1000_uninit,
- .romfile = "pxe-e1000.rom",
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = E1000_DEVID,
- .revision = 0x03,
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(E1000State, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property e1000_properties[] = {
+ DEFINE_NIC_PROPERTIES(E1000State, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void e1000_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_e1000_init;
+ k->exit = pci_e1000_uninit;
+ k->romfile = "pxe-e1000.rom";
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = E1000_DEVID;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->desc = "Intel Gigabit Ethernet";
+ dc->reset = qdev_e1000_reset;
+ dc->vmsd = &vmstate_e1000;
+ dc->props = e1000_properties;
+}
+
+static TypeInfo e1000_info = {
+ .name = "e1000",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(E1000State),
+ .class_init = e1000_class_init,
};
static void e1000_register_devices(void)
{
- pci_qdev_register(&e1000_info);
+ type_register_static(&e1000_info);
}
device_init(e1000_register_devices)
diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c
index 7743465..1cf2090 100644
--- a/hw/eccmemctl.c
+++ b/hw/eccmemctl.c
@@ -308,22 +308,33 @@
return 0;
}
-static SysBusDeviceInfo ecc_info = {
- .init = ecc_init1,
- .qdev.name = "eccmemctl",
- .qdev.size = sizeof(ECCState),
- .qdev.vmsd = &vmstate_ecc,
- .qdev.reset = ecc_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("version", ECCState, version, -1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ecc_properties[] = {
+ DEFINE_PROP_HEX32("version", ECCState, version, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ecc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ecc_init1;
+ dc->reset = ecc_reset;
+ dc->vmsd = &vmstate_ecc;
+ dc->props = ecc_properties;
+}
+
+static TypeInfo ecc_info = {
+ .name = "eccmemctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ECCState),
+ .class_init = ecc_class_init,
};
static void ecc_register_devices(void)
{
- sysbus_register_withprop(&ecc_info);
+ type_register_static(&ecc_info);
}
device_init(ecc_register_devices)
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 6a162f6..843610c 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -128,7 +128,13 @@
#define DRVR_INT 0x0200 /* Driver generated interrupt. */
typedef struct {
- PCIDeviceInfo pci;
+ const char *name;
+ const char *desc;
+ uint16_t device_id;
+ uint8_t revision;
+ uint16_t subsystem_vendor_id;
+ uint16_t subsystem_id;
+
uint32_t device;
uint8_t stats_size;
bool has_extended_tcb_support;
@@ -318,6 +324,8 @@
#define POLYNOMIAL 0x04c11db6
+static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
+
/* From FreeBSD */
/* XXX: optimize */
static unsigned compute_mcast_idx(const uint8_t * ep)
@@ -487,8 +495,9 @@
}
#endif
-static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
+static void e100_pci_reset(EEPRO100State * s)
{
+ E100PCIDeviceInfo *info = eepro100_get_class(s);
uint32_t device = s->device;
uint8_t *pci_conf = s->dev.config;
@@ -508,8 +517,8 @@
/* Maximum Latency */
pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
- s->stats_size = e100_device->stats_size;
- s->has_extended_tcb_support = e100_device->has_extended_tcb_support;
+ s->stats_size = info->stats_size;
+ s->has_extended_tcb_support = info->has_extended_tcb_support;
switch (device) {
case i82550:
@@ -558,7 +567,7 @@
}
assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
- if (e100_device->power_management) {
+ if (info->power_management) {
/* Power Management Capabilities */
int cfg_offset = 0xdc;
int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
@@ -1847,14 +1856,13 @@
static int e100_nic_init(PCIDevice *pci_dev)
{
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
- E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
- pci_dev->qdev.info);
+ E100PCIDeviceInfo *info = eepro100_get_class(s);
TRACE(OTHER, logout("\n"));
- s->device = e100_device->device;
+ s->device = info->device;
- e100_pci_reset(s, e100_device);
+ e100_pci_reset(s);
/* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
* i82559 and later support 64 or 256 word EEPROM. */
@@ -1878,7 +1886,7 @@
nic_reset(s);
s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
- pci_dev->qdev.info->name, pci_dev->qdev.id, s);
+ object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
TRACE(OTHER, logout("%s\n", s->nic->nc.info_str));
@@ -1897,156 +1905,203 @@
static E100PCIDeviceInfo e100_devices[] = {
{
- .pci.qdev.name = "i82550",
- .pci.qdev.desc = "Intel i82550 Ethernet",
+ .name = "i82550",
+ .desc = "Intel i82550 Ethernet",
.device = i82550,
/* TODO: check device id. */
- .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+ .device_id = PCI_DEVICE_ID_INTEL_82551IT,
/* Revision ID: 0x0c, 0x0d, 0x0e. */
- .pci.revision = 0x0e,
+ .revision = 0x0e,
/* TODO: check size of statistical counters. */
.stats_size = 80,
/* TODO: check extended tcb support. */
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82551",
- .pci.qdev.desc = "Intel i82551 Ethernet",
+ .name = "i82551",
+ .desc = "Intel i82551 Ethernet",
.device = i82551,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+ .device_id = PCI_DEVICE_ID_INTEL_82551IT,
/* Revision ID: 0x0f, 0x10. */
- .pci.revision = 0x0f,
+ .revision = 0x0f,
/* TODO: check size of statistical counters. */
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82557a",
- .pci.qdev.desc = "Intel i82557A Ethernet",
+ .name = "i82557a",
+ .desc = "Intel i82557A Ethernet",
.device = i82557A,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x01,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x01,
.power_management = false,
},{
- .pci.qdev.name = "i82557b",
- .pci.qdev.desc = "Intel i82557B Ethernet",
+ .name = "i82557b",
+ .desc = "Intel i82557B Ethernet",
.device = i82557B,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x02,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x02,
.power_management = false,
},{
- .pci.qdev.name = "i82557c",
- .pci.qdev.desc = "Intel i82557C Ethernet",
+ .name = "i82557c",
+ .desc = "Intel i82557C Ethernet",
.device = i82557C,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x03,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x03,
.power_management = false,
},{
- .pci.qdev.name = "i82558a",
- .pci.qdev.desc = "Intel i82558A Ethernet",
+ .name = "i82558a",
+ .desc = "Intel i82558A Ethernet",
.device = i82558A,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x04,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x04,
.stats_size = 76,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82558b",
- .pci.qdev.desc = "Intel i82558B Ethernet",
+ .name = "i82558b",
+ .desc = "Intel i82558B Ethernet",
.device = i82558B,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x05,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x05,
.stats_size = 76,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82559a",
- .pci.qdev.desc = "Intel i82559A Ethernet",
+ .name = "i82559a",
+ .desc = "Intel i82559A Ethernet",
.device = i82559A,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x06,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x06,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82559b",
- .pci.qdev.desc = "Intel i82559B Ethernet",
+ .name = "i82559b",
+ .desc = "Intel i82559B Ethernet",
.device = i82559B,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x07,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x07,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82559c",
- .pci.qdev.desc = "Intel i82559C Ethernet",
+ .name = "i82559c",
+ .desc = "Intel i82559C Ethernet",
.device = i82559C,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
#if 0
- .pci.revision = 0x08,
+ .revision = 0x08,
#endif
/* TODO: Windows wants revision id 0x0c. */
- .pci.revision = 0x0c,
+ .revision = 0x0c,
#if EEPROM_SIZE > 0
- .pci.subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
- .pci.subsystem_id = 0x0040,
+ .subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
+ .subsystem_id = 0x0040,
#endif
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82559er",
- .pci.qdev.desc = "Intel i82559ER Ethernet",
+ .name = "i82559er",
+ .desc = "Intel i82559ER Ethernet",
.device = i82559ER,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
- .pci.revision = 0x09,
+ .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+ .revision = 0x09,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82562",
- .pci.qdev.desc = "Intel i82562 Ethernet",
+ .name = "i82562",
+ .desc = "Intel i82562 Ethernet",
.device = i82562,
/* TODO: check device id. */
- .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+ .device_id = PCI_DEVICE_ID_INTEL_82551IT,
/* TODO: wrong revision id. */
- .pci.revision = 0x0e,
+ .revision = 0x0e,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
/* Toshiba Tecra 8200. */
- .pci.qdev.name = "i82801",
- .pci.qdev.desc = "Intel i82801 Ethernet",
+ .name = "i82801",
+ .desc = "Intel i82801 Ethernet",
.device = i82801,
- .pci.device_id = 0x2449,
- .pci.revision = 0x03,
+ .device_id = 0x2449,
+ .revision = 0x03,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
}
};
+static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename)
+{
+ E100PCIDeviceInfo *info = NULL;
+ int i;
+
+ /* This is admittedly awkward but also temporary. QOM allows for
+ * parameterized typing and for subclassing both of which would suitable
+ * handle what's going on here. But class_data is already being used as
+ * a stop-gap hack to allow incremental qdev conversion so we cannot use it
+ * right now. Once we merge the final QOM series, we can come back here and
+ * do this in a much more elegant fashion.
+ */
+ for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
+ if (strcmp(e100_devices[i].name, typename) == 0) {
+ info = &e100_devices[i];
+ break;
+ }
+ }
+ assert(info != NULL);
+
+ return info;
+}
+
+static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s)
+{
+ return eepro100_get_class_by_name(object_get_typename(OBJECT(s)));
+}
+
static Property e100_properties[] = {
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
DEFINE_PROP_END_OF_LIST(),
};
+static void eepro100_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ E100PCIDeviceInfo *info;
+
+ info = eepro100_get_class_by_name(object_class_get_name(klass));
+
+ dc->props = e100_properties;
+ dc->desc = info->desc;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ k->romfile = "pxe-eepro100.rom";
+ k->init = e100_nic_init;
+ k->exit = pci_nic_uninit;
+ k->device_id = info->device_id;
+ k->revision = info->revision;
+ k->subsystem_vendor_id = info->subsystem_vendor_id;
+ k->subsystem_id = info->subsystem_id;
+}
+
static void eepro100_register_devices(void)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
- PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
- /* We use the same rom file for all device ids.
- QEMU fixes the device id during rom load. */
- pci_dev->vendor_id = PCI_VENDOR_ID_INTEL;
- pci_dev->class_id = PCI_CLASS_NETWORK_ETHERNET;
- pci_dev->romfile = "pxe-eepro100.rom";
- pci_dev->init = e100_nic_init;
- pci_dev->exit = pci_nic_uninit;
- pci_dev->qdev.props = e100_properties;
- pci_dev->qdev.size = sizeof(EEPRO100State);
- pci_qdev_register(pci_dev);
+ TypeInfo type_info = {};
+ E100PCIDeviceInfo *info = &e100_devices[i];
+
+ type_info.name = info->name;
+ type_info.parent = TYPE_PCI_DEVICE;
+ type_info.class_init = eepro100_class_init;
+ type_info.instance_size = sizeof(EEPRO100State);
+
+ type_register(&type_info);
}
}
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
index 8b734f2..1bc1815 100644
--- a/hw/empty_slot.c
+++ b/hw/empty_slot.c
@@ -76,15 +76,23 @@
return 0;
}
-static SysBusDeviceInfo empty_slot_info = {
- .init = empty_slot_init1,
- .qdev.name = "empty_slot",
- .qdev.size = sizeof(EmptySlot),
+static void empty_slot_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = empty_slot_init1;
+}
+
+static TypeInfo empty_slot_info = {
+ .name = "empty_slot",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(EmptySlot),
+ .class_init = empty_slot_class_init,
};
static void empty_slot_register_devices(void)
{
- sysbus_register_withprop(&empty_slot_info);
+ type_register_static(&empty_slot_info);
}
device_init(empty_slot_register_devices);
diff --git a/hw/es1370.c b/hw/es1370.c
index 6a3ba55..e377c48 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -914,7 +914,7 @@
{ 0, 0x40 * 4, 1, .read = es1370_readb, },
{ 0, 0x40 * 2, 2, .read = es1370_readw, },
{ 0, 0x40, 4, .read = es1370_readl, },
- PORTIO_END_OF_LIST()
+ PORTIO_END_OF_LIST ()
};
static const MemoryRegionOps es1370_io_ops = {
@@ -928,12 +928,12 @@
.minimum_version_id = 2,
.minimum_version_id_old = 2,
.fields = (VMStateField []) {
- VMSTATE_UINT32(shift, struct chan),
- VMSTATE_UINT32(leftover, struct chan),
- VMSTATE_UINT32(scount, struct chan),
- VMSTATE_UINT32(frame_addr, struct chan),
- VMSTATE_UINT32(frame_cnt, struct chan),
- VMSTATE_END_OF_LIST()
+ VMSTATE_UINT32 (shift, struct chan),
+ VMSTATE_UINT32 (leftover, struct chan),
+ VMSTATE_UINT32 (scount, struct chan),
+ VMSTATE_UINT32 (frame_addr, struct chan),
+ VMSTATE_UINT32 (frame_cnt, struct chan),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -973,15 +973,15 @@
.minimum_version_id_old = 2,
.post_load = es1370_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, ES1370State),
- VMSTATE_STRUCT_ARRAY(chan, ES1370State, NB_CHANNELS, 2,
- vmstate_es1370_channel, struct chan),
- VMSTATE_UINT32(ctl, ES1370State),
- VMSTATE_UINT32(status, ES1370State),
- VMSTATE_UINT32(mempage, ES1370State),
- VMSTATE_UINT32(codec, ES1370State),
- VMSTATE_UINT32(sctl, ES1370State),
- VMSTATE_END_OF_LIST()
+ VMSTATE_PCI_DEVICE (dev, ES1370State),
+ VMSTATE_STRUCT_ARRAY (chan, ES1370State, NB_CHANNELS, 2,
+ vmstate_es1370_channel, struct chan),
+ VMSTATE_UINT32 (ctl, ES1370State),
+ VMSTATE_UINT32 (status, ES1370State),
+ VMSTATE_UINT32 (mempage, ES1370State),
+ VMSTATE_UINT32 (codec, ES1370State),
+ VMSTATE_UINT32 (sctl, ES1370State),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -1017,7 +1017,7 @@
return 0;
}
-static int es1370_exitfn(PCIDevice *dev)
+static int es1370_exitfn (PCIDevice *dev)
{
ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
@@ -1031,28 +1031,32 @@
return 0;
}
-static PCIDeviceInfo es1370_info = {
- .qdev.name = "ES1370",
- .qdev.desc = "ENSONIQ AudioPCI ES1370",
- .qdev.size = sizeof (ES1370State),
- .qdev.vmsd = &vmstate_es1370,
- .init = es1370_initfn,
- .exit = es1370_exitfn,
- .vendor_id = PCI_VENDOR_ID_ENSONIQ,
- .device_id = PCI_DEVICE_ID_ENSONIQ_ES1370,
- .class_id = PCI_CLASS_MULTIMEDIA_AUDIO,
-#if 1
- .subsystem_vendor_id = 0x4942,
- .subsystem_id = 0x4c4c,
-#else
- .subsystem_vendor_id = 0x1274,
- .subsystem_id = 0x1371,
-#endif
+static void es1370_class_init (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+
+ k->init = es1370_initfn;
+ k->exit = es1370_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_ENSONIQ;
+ k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370;
+ k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+ k->subsystem_vendor_id = 0x4942;
+ k->subsystem_id = 0x4c4c;
+ dc->desc = "ENSONIQ AudioPCI ES1370";
+ dc->vmsd = &vmstate_es1370;
+}
+
+static TypeInfo es1370_info = {
+ .name = "ES1370",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof (ES1370State),
+ .class_init = es1370_class_init,
};
static void es1370_register (void)
{
- pci_qdev_register (&es1370_info);
+ type_register_static (&es1370_info);
}
device_init (es1370_register);
diff --git a/hw/escc.c b/hw/escc.c
index 81204a6..9fe282f 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -901,28 +901,39 @@
return 0;
}
-static SysBusDeviceInfo escc_info = {
- .init = escc_init1,
- .qdev.name = "escc",
- .qdev.size = sizeof(SerialState),
- .qdev.vmsd = &vmstate_escc,
- .qdev.reset = escc_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0),
- DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0),
- DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
- DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
- DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0),
- DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0),
- DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
- DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property escc_properties[] = {
+ DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0),
+ DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0),
+ DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
+ DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
+ DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0),
+ DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0),
+ DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
+ DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void escc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = escc_init1;
+ dc->reset = escc_reset;
+ dc->vmsd = &vmstate_escc;
+ dc->props = escc_properties;
+}
+
+static TypeInfo escc_info = {
+ .name = "escc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SerialState),
+ .class_init = escc_class_init,
};
static void escc_register_devices(void)
{
- sysbus_register_withprop(&escc_info);
+ type_register_static(&escc_info);
}
device_init(escc_register_devices)
diff --git a/hw/esp.c b/hw/esp.c
index 9551c78..2f44386 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -753,20 +753,31 @@
return scsi_bus_legacy_handle_cmdline(&s->bus);
}
-static SysBusDeviceInfo esp_info = {
- .init = esp_init1,
- .qdev.name = "esp",
- .qdev.size = sizeof(ESPState),
- .qdev.vmsd = &vmstate_esp,
- .qdev.reset = esp_hard_reset,
- .qdev.props = (Property[]) {
- {.name = NULL}
- }
+static Property esp_properties[] = {
+ {.name = NULL},
+};
+
+static void esp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = esp_init1;
+ dc->reset = esp_hard_reset;
+ dc->vmsd = &vmstate_esp;
+ dc->props = esp_properties;
+}
+
+static TypeInfo esp_info = {
+ .name = "esp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ESPState),
+ .class_init = esp_class_init,
};
static void esp_register_devices(void)
{
- sysbus_register_withprop(&esp_info);
+ type_register_static(&esp_info);
}
device_init(esp_register_devices)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 5afa55f..aefd577 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -605,7 +605,7 @@
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(s)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
tdk_init(&s->phy);
@@ -613,22 +613,33 @@
return 0;
}
-static SysBusDeviceInfo etraxfs_eth_info = {
- .init = fs_eth_init,
- .qdev.name = "etraxfs-eth",
- .qdev.size = sizeof(struct fs_eth),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
- DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
- DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
- DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property etraxfs_eth_properties[] = {
+ DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
+ DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
+ DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
+ DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = fs_eth_init;
+ dc->props = etraxfs_eth_properties;
+}
+
+static TypeInfo etraxfs_eth_info = {
+ .name = "etraxfs-eth",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct fs_eth),
+ .class_init = etraxfs_eth_class_init,
};
static void etraxfs_eth_register(void)
{
- sysbus_register_withprop(&etraxfs_eth_info);
+ type_register_static(&etraxfs_eth_info);
}
device_init(etraxfs_eth_register)
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index 993d6a8..33541fc 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -151,19 +151,30 @@
return 0;
}
-static SysBusDeviceInfo etraxfs_pic_info = {
- .init = etraxfs_pic_init,
- .qdev.name = "etraxfs,pic",
- .qdev.size = sizeof(struct etrax_pic),
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property etraxfs_pic_properties[] = {
+ DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = etraxfs_pic_init;
+ dc->props = etraxfs_pic_properties;
+}
+
+static TypeInfo etraxfs_pic_info = {
+ .name = "etraxfs,pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct etrax_pic),
+ .class_init = etraxfs_pic_class_init,
};
static void etraxfs_pic_register(void)
{
- sysbus_register_withprop(&etraxfs_pic_info);
+ type_register_static(&etraxfs_pic_info);
}
device_init(etraxfs_pic_register)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 2623dab..567cb8c 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -216,7 +216,7 @@
memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
sysbus_init_mmio(dev, &s->mmio);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr)
qemu_chr_add_handlers(s->chr,
serial_can_receive, serial_receive,
@@ -224,16 +224,25 @@
return 0;
}
-static SysBusDeviceInfo etraxfs_ser_info = {
- .init = etraxfs_ser_init,
- .qdev.name = "etraxfs,serial",
- .qdev.size = sizeof(struct etrax_serial),
- .qdev.reset = etraxfs_ser_reset,
+static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = etraxfs_ser_init;
+ dc->reset = etraxfs_ser_reset;
+}
+
+static TypeInfo etraxfs_ser_info = {
+ .name = "etraxfs,serial",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct etrax_serial),
+ .class_init = etraxfs_ser_class_init,
};
static void etraxfs_serial_register(void)
{
- sysbus_register_withprop(&etraxfs_ser_info);
+ type_register_static(&etraxfs_ser_info);
}
device_init(etraxfs_serial_register)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index 2dfdb30..b71c5ee 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -329,10 +329,23 @@
return 0;
}
+static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = etraxfs_timer_init;
+}
+
+static TypeInfo etraxfs_timer_info = {
+ .name = "etraxfs,timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof (struct etrax_timer),
+ .class_init = etraxfs_timer_class_init,
+};
+
static void etraxfs_timer_register(void)
{
- sysbus_register_dev("etraxfs,timer", sizeof (struct etrax_timer),
- etraxfs_timer_init);
+ type_register_static(&etraxfs_timer_info);
}
device_init(etraxfs_timer_register)
diff --git a/hw/fdc.c b/hw/fdc.c
index 70aa5c7..f575a2c 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1959,21 +1959,31 @@
}
};
-static ISADeviceInfo isa_fdc_info = {
- .init = isabus_fdc_init1,
- .qdev.name = "isa-fdc",
- .qdev.fw_name = "fdc",
- .qdev.size = sizeof(FDCtrlISABus),
- .qdev.no_user = 1,
- .qdev.vmsd = &vmstate_isa_fdc,
- .qdev.reset = fdctrl_external_reset_isa,
- .qdev.props = (Property[]) {
- DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
- DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
- DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
- DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property isa_fdc_properties[] = {
+ DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
+ DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
+ DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
+ DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isabus_fdc_class_init1(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = isabus_fdc_init1;
+ dc->fw_name = "fdc";
+ dc->no_user = 1;
+ dc->reset = fdctrl_external_reset_isa;
+ dc->vmsd = &vmstate_isa_fdc;
+ dc->props = isa_fdc_properties;
+}
+
+static TypeInfo isa_fdc_info = {
+ .name = "isa-fdc",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(FDCtrlISABus),
+ .class_init = isabus_fdc_class_init1,
};
static const VMStateDescription vmstate_sysbus_fdc ={
@@ -1986,36 +1996,58 @@
}
};
-static SysBusDeviceInfo sysbus_fdc_info = {
- .init = sysbus_fdc_init1,
- .qdev.name = "sysbus-fdc",
- .qdev.size = sizeof(FDCtrlSysBus),
- .qdev.vmsd = &vmstate_sysbus_fdc,
- .qdev.reset = fdctrl_external_reset_sysbus,
- .qdev.props = (Property[]) {
- DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
- DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property sysbus_fdc_properties[] = {
+ DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
+ DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo sun4m_fdc_info = {
- .init = sun4m_fdc_init1,
- .qdev.name = "SUNW,fdtwo",
- .qdev.size = sizeof(FDCtrlSysBus),
- .qdev.vmsd = &vmstate_sysbus_fdc,
- .qdev.reset = fdctrl_external_reset_sysbus,
- .qdev.props = (Property[]) {
- DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void sysbus_fdc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sysbus_fdc_init1;
+ dc->reset = fdctrl_external_reset_sysbus;
+ dc->vmsd = &vmstate_sysbus_fdc;
+ dc->props = sysbus_fdc_properties;
+}
+
+static TypeInfo sysbus_fdc_info = {
+ .name = "sysbus-fdc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FDCtrlSysBus),
+ .class_init = sysbus_fdc_class_init,
+};
+
+static Property sun4m_fdc_properties[] = {
+ DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sun4m_fdc_init1;
+ dc->reset = fdctrl_external_reset_sysbus;
+ dc->vmsd = &vmstate_sysbus_fdc;
+ dc->props = sun4m_fdc_properties;
+}
+
+static TypeInfo sun4m_fdc_info = {
+ .name = "SUNW,fdtwo",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FDCtrlSysBus),
+ .class_init = sun4m_fdc_class_init,
};
static void fdc_register_devices(void)
{
- isa_qdev_register(&isa_fdc_info);
- sysbus_register_withprop(&sysbus_fdc_info);
- sysbus_register_withprop(&sun4m_fdc_info);
+ type_register_static(&isa_fdc_info);
+ type_register_static(&sysbus_fdc_info);
+ type_register_static(&sun4m_fdc_info);
}
device_init(fdc_register_devices)
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index 6bf48dc..ea122fb 100644
--- a/hw/framebuffer.c
+++ b/hw/framebuffer.c
@@ -87,15 +87,8 @@
dest += i * dest_row_pitch;
for (; i < rows; i++) {
- target_phys_addr_t dirty_offset;
- dirty = 0;
- dirty_offset = 0;
- while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
- dirty |= memory_region_get_dirty(mem, addr + dirty_offset,
+ dirty = memory_region_get_dirty(mem, addr, addr + src_width,
DIRTY_MEMORY_VGA);
- dirty_offset += TARGET_PAGE_SIZE;
- }
-
if (dirty || invalidate) {
fn(opaque, dest, src, cols, dest_col_pitch);
if (first == -1)
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index f953532..6b2f7d1 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -531,23 +531,34 @@
return 0;
}
-static SysBusDeviceInfo fw_cfg_info = {
- .init = fw_cfg_init1,
- .qdev.name = "fw_cfg",
- .qdev.size = sizeof(FWCfgState),
- .qdev.vmsd = &vmstate_fw_cfg,
- .qdev.reset = fw_cfg_reset,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
- DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property fw_cfg_properties[] = {
+ DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
+ DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void fw_cfg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = fw_cfg_init1;
+ dc->no_user = 1;
+ dc->reset = fw_cfg_reset;
+ dc->vmsd = &vmstate_fw_cfg;
+ dc->props = fw_cfg_properties;
+}
+
+static TypeInfo fw_cfg_info = {
+ .name = "fw_cfg",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FWCfgState),
+ .class_init = fw_cfg_class_init,
};
static void fw_cfg_register_devices(void)
{
- sysbus_register_withprop(&fw_cfg_info);
+ type_register_static(&fw_cfg_info);
}
device_init(fw_cfg_register_devices)
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 33ec149..66d0044 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -62,7 +62,8 @@
static inline int check_dirty(G364State *s, ram_addr_t page)
{
- return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
+ return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
}
static inline void reset_dirty(G364State *s,
@@ -268,12 +269,9 @@
static inline void g364fb_invalidate_display(void *opaque)
{
G364State *s = opaque;
- int i;
s->blanked = 0;
- for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) {
- memory_region_set_dirty(&s->mem_vram, i);
- }
+ memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
}
static void g364fb_reset(G364State *s)
@@ -385,7 +383,7 @@
static void g364_invalidate_cursor_position(G364State *s)
{
- int ymin, ymax, start, end, i;
+ int ymin, ymax, start, end;
/* invalidate only near the cursor */
ymin = s->cursor_position & 0xfff;
@@ -393,9 +391,7 @@
start = ymin * ds_get_linesize(s->ds);
end = (ymax + 1) * ds_get_linesize(s->ds);
- for (i = start; i < end; i += G364_PAGE_SIZE) {
- memory_region_set_dirty(&s->mem_vram, i);
- }
+ memory_region_set_dirty(&s->mem_vram, start, end - start);
}
static void g364fb_ctrl_write(void *opaque,
@@ -553,23 +549,34 @@
g364fb_reset(&s->g364);
}
-static SysBusDeviceInfo g364fb_sysbus_info = {
- .init = g364fb_sysbus_init,
- .qdev.name = "sysbus-g364",
- .qdev.desc = "G364 framebuffer",
- .qdev.size = sizeof(G364SysBusState),
- .qdev.vmsd = &vmstate_g364fb,
- .qdev.reset = g364fb_sysbus_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
- 8 * 1024 * 1024),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property g364fb_sysbus_properties[] = {
+ DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
+ 8 * 1024 * 1024),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = g364fb_sysbus_init;
+ dc->desc = "G364 framebuffer";
+ dc->reset = g364fb_sysbus_reset;
+ dc->vmsd = &vmstate_g364fb;
+ dc->props = g364fb_sysbus_properties;
+}
+
+static TypeInfo g364fb_sysbus_info = {
+ .name = "sysbus-g364",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(G364SysBusState),
+ .class_init = g364fb_sysbus_class_init,
};
static void g364fb_register(void)
{
- sysbus_register_withprop(&g364fb_sysbus_info);
+ type_register_static(&g364fb_sysbus_info);
}
device_init(g364fb_register);
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 1e529fb..8122baf 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -71,7 +71,7 @@
SysBusDevice *s;
GrackleState *d;
- dev = qdev_create(NULL, "grackle");
+ dev = qdev_create(NULL, "grackle-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
d = FROM_SYSBUS(GrackleState, s);
@@ -121,21 +121,46 @@
return 0;
}
-static PCIDeviceInfo grackle_pci_host_info = {
- .qdev.name = "grackle",
- .qdev.size = sizeof(PCIDevice),
- .init = grackle_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_MOTOROLA,
- .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void grackle_pci_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = grackle_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
+ k->device_id = PCI_DEVICE_ID_MOTOROLA_MPC106;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ dc->no_user = 1;
+}
+
+static TypeInfo grackle_pci_info = {
+ .name = "grackle",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = grackle_pci_class_init,
+};
+
+static void pci_grackle_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = pci_grackle_init_device;
+ dc->no_user = 1;
+}
+
+static TypeInfo grackle_pci_host_info = {
+ .name = "grackle-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GrackleState),
+ .class_init = pci_grackle_class_init,
};
static void grackle_register_devices(void)
{
- sysbus_register_dev("grackle", sizeof(GrackleState),
- pci_grackle_init_device);
- pci_qdev_register(&grackle_pci_host_info);
+ type_register_static(&grackle_pci_info);
+ type_register_static(&grackle_pci_host_info);
}
device_init(grackle_register_devices)
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index f8a64e1..89de2d8 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -24,7 +24,6 @@
#include "sysbus.h"
#include "qemu-char.h"
-#include "ptimer.h"
#include "trace.h"
@@ -66,6 +65,8 @@
#define SCALER_OFFSET 0x0C /* not supported */
#define FIFO_DEBUG_OFFSET 0x10 /* not supported */
+#define FIFO_LENGTH 1024
+
typedef struct UART {
SysBusDevice busdev;
MemoryRegion iomem;
@@ -77,21 +78,67 @@
uint32_t receive;
uint32_t status;
uint32_t control;
+
+ /* FIFO */
+ char buffer[FIFO_LENGTH];
+ int len;
+ int current;
} UART;
+static int uart_data_to_read(UART *uart)
+{
+ return uart->current < uart->len;
+}
+
+static char uart_pop(UART *uart)
+{
+ char ret;
+
+ if (uart->len == 0) {
+ uart->status &= ~UART_DATA_READY;
+ return 0;
+ }
+
+ ret = uart->buffer[uart->current++];
+
+ if (uart->current >= uart->len) {
+ /* Flush */
+ uart->len = 0;
+ uart->current = 0;
+ }
+
+ if (!uart_data_to_read(uart)) {
+ uart->status &= ~UART_DATA_READY;
+ }
+
+ return ret;
+}
+
+static void uart_add_to_fifo(UART *uart,
+ const uint8_t *buffer,
+ int length)
+{
+ if (uart->len + length > FIFO_LENGTH) {
+ abort();
+ }
+ memcpy(uart->buffer + uart->len, buffer, length);
+ uart->len += length;
+}
+
static int grlib_apbuart_can_receive(void *opaque)
{
UART *uart = opaque;
- return !!(uart->status & UART_DATA_READY);
+ return FIFO_LENGTH - uart->len;
}
static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
{
UART *uart = opaque;
- uart->receive = *buf;
- uart->status |= UART_DATA_READY;
+ uart_add_to_fifo(uart, buf, size);
+
+ uart->status |= UART_DATA_READY;
if (uart->control & UART_RECEIVE_INTERRUPT) {
qemu_irq_pulse(uart->irq);
@@ -103,9 +150,39 @@
trace_grlib_apbuart_event(event);
}
-static void
-grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
- uint64_t value, unsigned size)
+
+static uint64_t grlib_apbuart_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ UART *uart = opaque;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case DATA_OFFSET:
+ case DATA_OFFSET + 3: /* when only one byte read */
+ return uart_pop(uart);
+
+ case STATUS_OFFSET:
+ /* Read Only */
+ return uart->status;
+
+ case CONTROL_OFFSET:
+ return uart->control;
+
+ case SCALER_OFFSET:
+ /* Not supported */
+ return 0;
+
+ default:
+ trace_grlib_apbuart_readl_unknown(addr);
+ return 0;
+ }
+}
+
+static void grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
{
UART *uart = opaque;
unsigned char c = 0;
@@ -115,6 +192,7 @@
/* Unit registers */
switch (addr) {
case DATA_OFFSET:
+ case DATA_OFFSET + 3: /* When only one byte write */
c = value & 0xFF;
qemu_chr_fe_write(uart->chr, &c, 1);
return;
@@ -124,7 +202,7 @@
return;
case CONTROL_OFFSET:
- /* Not supported */
+ uart->control = value;
return;
case SCALER_OFFSET:
@@ -138,21 +216,15 @@
trace_grlib_apbuart_writel_unknown(addr, value);
}
-static bool grlib_apbuart_accepts(void *opaque, target_phys_addr_t addr,
- unsigned size, bool is_write)
-{
- return is_write && size == 4;
-}
-
static const MemoryRegionOps grlib_apbuart_ops = {
- .write = grlib_apbuart_write,
- .valid.accepts = grlib_apbuart_accepts,
+ .write = grlib_apbuart_write,
+ .read = grlib_apbuart_read,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static int grlib_apbuart_init(SysBusDevice *dev)
{
- UART *uart = FROM_SYSBUS(typeof(*uart), dev);
+ UART *uart = FROM_SYSBUS(typeof(*uart), dev);
qemu_chr_add_handlers(uart->chr,
grlib_apbuart_can_receive,
@@ -170,19 +242,30 @@
return 0;
}
-static SysBusDeviceInfo grlib_gptimer_info = {
- .init = grlib_apbuart_init,
- .qdev.name = "grlib,apbuart",
- .qdev.size = sizeof(UART),
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chrdev", UART, chr),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property grlib_gptimer_properties[] = {
+ DEFINE_PROP_CHR("chrdev", UART, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = grlib_apbuart_init;
+ dc->props = grlib_gptimer_properties;
+}
+
+static TypeInfo grlib_gptimer_info = {
+ .name = "grlib,apbuart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UART),
+ .class_init = grlib_gptimer_class_init,
};
static void grlib_gptimer_register(void)
{
- sysbus_register_withprop(&grlib_gptimer_info);
+ type_register_static(&grlib_gptimer_info);
}
device_init(grlib_gptimer_register)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
index 9c98a83..fb0b236 100644
--- a/hw/grlib_gptimer.c
+++ b/hw/grlib_gptimer.c
@@ -372,22 +372,33 @@
return 0;
}
-static SysBusDeviceInfo grlib_gptimer_info = {
- .init = grlib_gptimer_init,
- .qdev.name = "grlib,gptimer",
- .qdev.reset = grlib_gptimer_reset,
- .qdev.size = sizeof(GPTimerUnit),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
- DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
- DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property grlib_gptimer_properties[] = {
+ DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
+ DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
+ DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = grlib_gptimer_init;
+ dc->reset = grlib_gptimer_reset;
+ dc->props = grlib_gptimer_properties;
+}
+
+static TypeInfo grlib_gptimer_info = {
+ .name = "grlib,gptimer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GPTimerUnit),
+ .class_init = grlib_gptimer_class_init,
};
static void grlib_gptimer_register(void)
{
- sysbus_register_withprop(&grlib_gptimer_info);
+ type_register_static(&grlib_gptimer_info);
}
device_init(grlib_gptimer_register)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
index 2872556..1e5ad82 100644
--- a/hw/grlib_irqmp.c
+++ b/hw/grlib_irqmp.c
@@ -354,21 +354,32 @@
return 0;
}
-static SysBusDeviceInfo grlib_irqmp_info = {
- .init = grlib_irqmp_init,
- .qdev.name = "grlib,irqmp",
- .qdev.reset = grlib_irqmp_reset,
- .qdev.size = sizeof(IRQMP),
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
- DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property grlib_irqmp_properties[] = {
+ DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
+ DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = grlib_irqmp_init;
+ dc->reset = grlib_irqmp_reset;
+ dc->props = grlib_irqmp_properties;
+}
+
+static TypeInfo grlib_irqmp_info = {
+ .name = "grlib,irqmp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IRQMP),
+ .class_init = grlib_irqmp_class_init,
};
static void grlib_irqmp_register(void)
{
- sysbus_register_withprop(&grlib_irqmp_info);
+ type_register_static(&grlib_irqmp_info);
}
device_init(grlib_irqmp_register)
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 432683a..e8cd59c 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1136,21 +1136,42 @@
return 0;
}
-static PCIDeviceInfo gt64120_pci_info = {
- .qdev.name = "gt64120_pci",
- .qdev.size = sizeof(PCIDevice),
- .init = gt64120_pci_init,
- .vendor_id = PCI_VENDOR_ID_MARVELL,
- .device_id = PCI_DEVICE_ID_MARVELL_GT6412X,
- .revision = 0x10,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void gt64120_pci_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = gt64120_pci_init;
+ k->vendor_id = PCI_VENDOR_ID_MARVELL;
+ k->device_id = PCI_DEVICE_ID_MARVELL_GT6412X;
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo gt64120_pci_info = {
+ .name = "gt64120_pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = gt64120_pci_class_init,
+};
+
+static void gt64120_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = gt64120_init;
+}
+
+static TypeInfo gt64120_info = {
+ .name = "gt64120",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GT64120State),
+ .class_init = gt64120_class_init,
};
static void gt64120_pci_register_devices(void)
{
- sysbus_register_dev("gt64120", sizeof(GT64120State),
- gt64120_init);
- pci_qdev_register(>64120_pci_info);
+ type_register_static(>64120_info);
+ type_register_static(>64120_pci_info);
}
device_init(gt64120_pci_register_devices)
diff --git a/hw/gus.c b/hw/gus.c
index ab872d8..2054707 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -221,14 +221,14 @@
.minimum_version_id = 2,
.minimum_version_id_old = 2,
.fields = (VMStateField []) {
- VMSTATE_INT32(pos, GUSState),
- VMSTATE_INT32(left, GUSState),
- VMSTATE_INT32(shift, GUSState),
- VMSTATE_INT32(irqs, GUSState),
- VMSTATE_INT32(samples, GUSState),
- VMSTATE_INT64(last_ticks, GUSState),
- VMSTATE_BUFFER(himem, GUSState),
- VMSTATE_END_OF_LIST()
+ VMSTATE_INT32 (pos, GUSState),
+ VMSTATE_INT32 (left, GUSState),
+ VMSTATE_INT32 (shift, GUSState),
+ VMSTATE_INT32 (irqs, GUSState),
+ VMSTATE_INT32 (samples, GUSState),
+ VMSTATE_INT64 (last_ticks, GUSState),
+ VMSTATE_BUFFER (himem, GUSState),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -239,13 +239,13 @@
{0x006, 10, 2, .read = gus_readw, .write = gus_writew },
{0x100, 8, 1, .read = gus_readb, .write = gus_writeb },
{0x100, 8, 2, .read = gus_readw, .write = gus_writew },
- PORTIO_END_OF_LIST(),
+ PORTIO_END_OF_LIST (),
};
static const MemoryRegionPortio gus_portio_list2[] = {
{0, 1, 1, .read = gus_readb },
{0, 1, 2, .read = gus_readw },
- PORTIO_END_OF_LIST(),
+ PORTIO_END_OF_LIST (),
};
static int gus_initfn (ISADevice *dev)
@@ -299,23 +299,33 @@
return 0;
}
-static ISADeviceInfo gus_info = {
- .qdev.name = "gus",
- .qdev.desc = "Gravis Ultrasound GF1",
- .qdev.size = sizeof (GUSState),
- .qdev.vmsd = &vmstate_gus,
- .init = gus_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
- DEFINE_PROP_HEX32 ("iobase", GUSState, port, 0x240),
- DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
- DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3),
- DEFINE_PROP_END_OF_LIST (),
- },
+static Property gus_properties[] = {
+ DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
+ DEFINE_PROP_HEX32 ("iobase", GUSState, port, 0x240),
+ DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
+ DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3),
+ DEFINE_PROP_END_OF_LIST (),
+};
+
+static void gus_class_initfn (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+ ic->init = gus_initfn;
+ dc->desc = "Gravis Ultrasound GF1";
+ dc->vmsd = &vmstate_gus;
+ dc->props = gus_properties;
+}
+
+static TypeInfo gus_info = {
+ .name = "gus",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof (GUSState),
+ .class_init = gus_class_initfn,
};
static void gus_register (void)
{
- isa_qdev_register (&gus_info);
+ type_register_static (&gus_info);
}
device_init (gus_register)
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 9b089e6..152f8e6 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -777,7 +777,7 @@
uint32_t i, type;
a->desc = desc;
- a->name = a->hda.qdev.info->name;
+ a->name = object_get_typename(OBJECT(a));
dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
AUD_register_card("hda", &a->card);
@@ -906,33 +906,51 @@
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,
- .exit = hda_audio_exit,
- .command = hda_audio_command,
- .stream = hda_audio_stream,
+static void hda_audio_output_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+ k->init = hda_audio_init_output;
+ k->exit = hda_audio_exit;
+ k->command = hda_audio_command;
+ k->stream = hda_audio_stream;
+ dc->desc = "HDA Audio Codec, output-only";
+ dc->vmsd = &vmstate_hda_audio;
+ dc->props = hda_audio_properties;
+}
+
+static TypeInfo hda_audio_output_info = {
+ .name = "hda-output",
+ .parent = TYPE_HDA_CODEC_DEVICE,
+ .instance_size = sizeof(HDAAudioState),
+ .class_init = hda_audio_output_class_init,
};
-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,
- .exit = hda_audio_exit,
- .command = hda_audio_command,
- .stream = hda_audio_stream,
+static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+ k->init = hda_audio_init_duplex;
+ k->exit = hda_audio_exit;
+ k->command = hda_audio_command;
+ k->stream = hda_audio_stream;
+ dc->desc = "HDA Audio Codec, duplex";
+ dc->vmsd = &vmstate_hda_audio;
+ dc->props = hda_audio_properties;
+}
+
+static TypeInfo hda_audio_duplex_info = {
+ .name = "hda-duplex",
+ .parent = TYPE_HDA_CODEC_DEVICE,
+ .instance_size = sizeof(HDAAudioState),
+ .class_init = hda_audio_duplex_class_init,
};
static void hda_audio_register(void)
{
- hda_codec_register(&hda_audio_info_output);
- hda_codec_register(&hda_audio_info_duplex);
+ type_register_static(&hda_audio_output_info);
+ type_register_static(&hda_audio_duplex_info);
}
device_init(hda_audio_register);
diff --git a/hw/highbank.c b/hw/highbank.c
new file mode 100644
index 0000000..684178e
--- /dev/null
+++ b/hw/highbank.c
@@ -0,0 +1,339 @@
+/*
+ * Calxeda Highbank SoC emulation
+ *
+ * Copyright (c) 2010-2012 Calxeda
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 "sysbus.h"
+#include "arm-misc.h"
+#include "primecell.h"
+#include "devices.h"
+#include "loader.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "sysbus.h"
+#include "blockdev.h"
+#include "exec-memory.h"
+
+#define SMP_BOOT_ADDR 0x100
+#define SMP_BOOT_REG 0x40
+#define GIC_BASE_ADDR 0xfff10000
+
+#define NIRQ_GIC 160
+
+/* Board init. */
+static void highbank_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+
+ env->cp15.c15_config_base_address = GIC_BASE_ADDR;
+}
+
+static void hb_write_secondary(CPUState *env, const struct arm_boot_info *info)
+{
+ int n;
+ uint32_t smpboot[] = {
+ 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */
+ 0xe210000f, /* ands r0, r0, #0x0f */
+ 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
+ 0xe0830200, /* add r0, r3, r0, lsl #4 */
+ 0xe59f2018, /* ldr r2, privbase */
+ 0xe3a01001, /* mov r1, #1 */
+ 0xe5821100, /* str r1, [r2, #256] */
+ 0xe320f003, /* wfi */
+ 0xe5901000, /* ldr r1, [r0] */
+ 0xe1110001, /* tst r1, r1 */
+ 0x0afffffb, /* beq <wfi> */
+ 0xe12fff11, /* bx r1 */
+ GIC_BASE_ADDR /* privbase: gic address. */
+ };
+ for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+ smpboot[n] = tswap32(smpboot[n]);
+ }
+ rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR);
+}
+
+static void hb_reset_secondary(CPUState *env, const struct arm_boot_info *info)
+{
+ switch (info->nb_cpus) {
+ case 4:
+ stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0);
+ case 3:
+ stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0);
+ case 2:
+ stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0);
+ env->regs[15] = SMP_BOOT_ADDR;
+ break;
+ default:
+ break;
+ }
+}
+
+#define NUM_REGS 0x200
+static void hb_regs_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ uint32_t *regs = opaque;
+
+ if (offset == 0xf00) {
+ if (value == 1 || value == 2) {
+ qemu_system_reset_request();
+ } else if (value == 3) {
+ qemu_system_shutdown_request();
+ }
+ }
+
+ regs[offset/4] = value;
+}
+
+static uint64_t hb_regs_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ uint32_t *regs = opaque;
+ uint32_t value = regs[offset/4];
+
+ if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) {
+ value |= 0x30000000;
+ }
+
+ return value;
+}
+
+static const MemoryRegionOps hb_mem_ops = {
+ .read = hb_regs_read,
+ .write = hb_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion *iomem;
+ uint32_t regs[NUM_REGS];
+} HighbankRegsState;
+
+static VMStateDescription vmstate_highbank_regs = {
+ .name = "highbank-regs",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static void highbank_regs_reset(DeviceState *dev)
+{
+ SysBusDevice *sys_dev = sysbus_from_qdev(dev);
+ HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev);
+
+ s->regs[0x40] = 0x05F20121;
+ s->regs[0x41] = 0x2;
+ s->regs[0x42] = 0x05F30121;
+ s->regs[0x43] = 0x05F40121;
+}
+
+static int highbank_regs_init(SysBusDevice *dev)
+{
+ HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev);
+
+ s->iomem = g_new(MemoryRegion, 1);
+ memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs",
+ 0x1000);
+ sysbus_init_mmio(dev, s->iomem);
+
+ return 0;
+}
+
+static void highbank_regs_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ sbc->init = highbank_regs_init;
+ dc->desc = "Calxeda Highbank registers";
+ dc->vmsd = &vmstate_highbank_regs;
+ dc->reset = highbank_regs_reset;
+}
+
+static TypeInfo highbank_regs_info = {
+ .name = "highbank-regs",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HighbankRegsState),
+ .class_init = highbank_regs_class_init,
+};
+
+static void highbank_regs_register_device(void)
+{
+ type_register_static(&highbank_regs_info);
+}
+
+device_init(highbank_regs_register_device)
+
+static struct arm_boot_info highbank_binfo;
+
+/* ram_size must be set to match the upper bound of memory in the
+ * device tree (linux/arch/arm/boot/dts/highbank.dts), which is
+ * normally 0xff900000 or -m 4089. When running this board on a
+ * 32-bit host, set the reg value of memory to 0xf7ff00000 in the
+ * device tree and pass -m 2047 to QEMU.
+ */
+static void highbank_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ CPUState *env = NULL;
+ DeviceState *dev;
+ SysBusDevice *busdev;
+ qemu_irq *irqp;
+ qemu_irq pic[128];
+ int n;
+ qemu_irq cpu_irq[4];
+ MemoryRegion *sysram;
+ MemoryRegion *dram;
+ MemoryRegion *sysmem;
+ char *sysboot_filename;
+
+ if (!cpu_model) {
+ cpu_model = "cortex-a9";
+ }
+
+ for (n = 0; n < smp_cpus; n++) {
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ irqp = arm_pic_init_cpu(env);
+ cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+ qemu_register_reset(highbank_cpu_reset, env);
+ }
+
+ sysmem = get_system_memory();
+ dram = g_new(MemoryRegion, 1);
+ memory_region_init_ram(dram, "highbank.dram", ram_size);
+ /* SDRAM at address zero. */
+ memory_region_add_subregion(sysmem, 0, dram);
+
+ sysram = g_new(MemoryRegion, 1);
+ memory_region_init_ram(sysram, "highbank.sysram", 0x8000);
+ memory_region_add_subregion(sysmem, 0xfff88000, sysram);
+ if (bios_name != NULL) {
+ sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (sysboot_filename != NULL) {
+ uint32_t filesize = get_image_size(sysboot_filename);
+ if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) {
+ hw_error("Unable to load %s\n", bios_name);
+ }
+ } else {
+ hw_error("Unable to find %s\n", bios_name);
+ }
+ }
+
+ dev = qdev_create(NULL, "a9mpcore_priv");
+ qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+ qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR);
+ for (n = 0; n < smp_cpus; n++) {
+ sysbus_connect_irq(busdev, n, cpu_irq[n]);
+ }
+
+ for (n = 0; n < 128; n++) {
+ pic[n] = qdev_get_gpio_in(dev, n);
+ }
+
+ dev = qdev_create(NULL, "l2x0");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, 0xfff12000);
+
+ dev = qdev_create(NULL, "sp804");
+ qdev_prop_set_uint32(dev, "freq0", 150000000);
+ qdev_prop_set_uint32(dev, "freq1", 150000000);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, 0xfff34000);
+ sysbus_connect_irq(busdev, 0, pic[18]);
+ sysbus_create_simple("pl011", 0xfff36000, pic[20]);
+
+ dev = qdev_create(NULL, "highbank-regs");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, 0xfff3c000);
+
+ sysbus_create_simple("pl061", 0xfff30000, pic[14]);
+ sysbus_create_simple("pl061", 0xfff31000, pic[15]);
+ sysbus_create_simple("pl061", 0xfff32000, pic[16]);
+ sysbus_create_simple("pl061", 0xfff33000, pic[17]);
+ sysbus_create_simple("pl031", 0xfff35000, pic[19]);
+ sysbus_create_simple("pl022", 0xfff39000, pic[23]);
+
+ sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]);
+
+ if (nd_table[0].vlan) {
+ qemu_check_nic_model(&nd_table[0], "xgmac");
+ dev = qdev_create(NULL, "xgmac");
+ qdev_set_nic_properties(dev, &nd_table[0]);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff50000);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[77]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[78]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[79]);
+
+ qemu_check_nic_model(&nd_table[1], "xgmac");
+ dev = qdev_create(NULL, "xgmac");
+ qdev_set_nic_properties(dev, &nd_table[1]);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff51000);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[80]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[81]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[82]);
+ }
+
+ highbank_binfo.ram_size = ram_size;
+ highbank_binfo.kernel_filename = kernel_filename;
+ highbank_binfo.kernel_cmdline = kernel_cmdline;
+ highbank_binfo.initrd_filename = initrd_filename;
+ /* highbank requires a dtb in order to boot, and the dtb will override
+ * the board ID. The following value is ignored, so set it to -1 to be
+ * clear that the value is meaningless.
+ */
+ highbank_binfo.board_id = -1;
+ highbank_binfo.nb_cpus = smp_cpus;
+ highbank_binfo.loader_start = 0;
+ highbank_binfo.write_secondary_boot = hb_write_secondary;
+ highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
+ arm_load_kernel(first_cpu, &highbank_binfo);
+}
+
+static QEMUMachine highbank_machine = {
+ .name = "highbank",
+ .desc = "Calxeda Highbank (ECX-1000)",
+ .init = highbank_init,
+ .use_scsi = 1,
+ .max_cpus = 4,
+};
+
+static void highbank_machine_init(void)
+{
+ qemu_register_machine(&highbank_machine);
+}
+
+machine_init(highbank_machine_init);
diff --git a/hw/hpet.c b/hw/hpet.c
index 5312df7..b6ace4e 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -695,23 +695,34 @@
return 0;
}
-static SysBusDeviceInfo hpet_device_info = {
- .qdev.name = "hpet",
- .qdev.size = sizeof(HPETState),
- .qdev.no_user = 1,
- .qdev.vmsd = &vmstate_hpet,
- .qdev.reset = hpet_reset,
- .init = hpet_init,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
- DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property hpet_device_properties[] = {
+ DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
+ DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void hpet_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = hpet_init;
+ dc->no_user = 1;
+ dc->reset = hpet_reset;
+ dc->vmsd = &vmstate_hpet;
+ dc->props = hpet_device_properties;
+}
+
+static TypeInfo hpet_device_info = {
+ .name = "hpet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HPETState),
+ .class_init = hpet_device_class_init,
};
static void hpet_register_device(void)
{
- sysbus_register_withprop(&hpet_device_info);
+ type_register_static(&hpet_device_info);
}
device_init(hpet_register_device)
diff --git a/hw/i2c.c b/hw/i2c.c
index 9bcf3e1..8ae4aaa 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -12,8 +12,8 @@
struct i2c_bus
{
BusState qbus;
- i2c_slave *current_dev;
- i2c_slave *dev;
+ I2CSlave *current_dev;
+ I2CSlave *dev;
uint8_t saved_address;
};
@@ -21,7 +21,7 @@
.name = "I2C",
.size = sizeof(i2c_bus),
.props = (Property[]) {
- DEFINE_PROP_UINT8("address", struct i2c_slave, address, 0),
+ DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
DEFINE_PROP_END_OF_LIST(),
}
};
@@ -66,7 +66,7 @@
return bus;
}
-void i2c_set_slave_address(i2c_slave *dev, uint8_t address)
+void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
{
dev->address = address;
}
@@ -82,71 +82,100 @@
int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
{
DeviceState *qdev;
- i2c_slave *slave = NULL;
+ I2CSlave *slave = NULL;
+ I2CSlaveClass *sc;
QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
- i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
+ I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
if (candidate->address == address) {
slave = candidate;
break;
}
}
- if (!slave)
+ if (!slave) {
return 1;
+ }
+ sc = I2C_SLAVE_GET_CLASS(slave);
/* If the bus is already busy, assume this is a repeated
start condition. */
bus->current_dev = slave;
- slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+ if (sc->event) {
+ sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+ }
return 0;
}
void i2c_end_transfer(i2c_bus *bus)
{
- i2c_slave *dev = bus->current_dev;
+ I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return;
+ }
- dev->info->event(dev, I2C_FINISH);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->event) {
+ sc->event(dev, I2C_FINISH);
+ }
bus->current_dev = NULL;
}
int i2c_send(i2c_bus *bus, uint8_t data)
{
- i2c_slave *dev = bus->current_dev;
+ I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return -1;
+ }
- return dev->info->send(dev, data);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->send) {
+ return sc->send(dev, data);
+ }
+
+ return -1;
}
int i2c_recv(i2c_bus *bus)
{
- i2c_slave *dev = bus->current_dev;
+ I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return -1;
+ }
- return dev->info->recv(dev);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->recv) {
+ return sc->recv(dev);
+ }
+
+ return -1;
}
void i2c_nack(i2c_bus *bus)
{
- i2c_slave *dev = bus->current_dev;
+ I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return;
+ }
- dev->info->event(dev, I2C_NACK);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->event) {
+ sc->event(dev, I2C_NACK);
+ }
}
static int i2c_slave_post_load(void *opaque, int version_id)
{
- i2c_slave *dev = opaque;
+ I2CSlave *dev = opaque;
i2c_bus *bus;
bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
if (bus->saved_address == dev->address) {
@@ -156,33 +185,23 @@
}
const VMStateDescription vmstate_i2c_slave = {
- .name = "i2c_slave",
+ .name = "I2CSlave",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = i2c_slave_post_load,
.fields = (VMStateField []) {
- VMSTATE_UINT8(address, i2c_slave),
+ VMSTATE_UINT8(address, I2CSlave),
VMSTATE_END_OF_LIST()
}
};
-static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
+static int i2c_slave_qdev_init(DeviceState *dev)
{
- I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
- i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev);
+ I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev);
+ I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
- s->info = info;
-
- return info->init(s);
-}
-
-void i2c_register_slave(I2CSlaveInfo *info)
-{
- assert(info->qdev.size >= sizeof(i2c_slave));
- info->qdev.init = i2c_slave_qdev_init;
- info->qdev.bus_info = &i2c_bus_info;
- qdev_register(&info->qdev);
+ return sc->init(s);
}
DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
@@ -194,3 +213,26 @@
qdev_init_nofail(dev);
return dev;
}
+
+static void i2c_slave_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = i2c_slave_qdev_init;
+ k->bus_info = &i2c_bus_info;
+}
+
+static TypeInfo i2c_slave_type_info = {
+ .name = TYPE_I2C_SLAVE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(I2CSlave),
+ .abstract = true,
+ .class_size = sizeof(I2CSlaveClass),
+ .class_init = i2c_slave_class_init,
+};
+
+static void i2c_slave_register_devices(void)
+{
+ type_register_static(&i2c_slave_type_info);
+}
+
+device_init(i2c_slave_register_devices);
diff --git a/hw/i2c.h b/hw/i2c.h
index a3383ff..0f5682b 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -15,36 +15,43 @@
I2C_NACK /* Masker NACKed a receive byte. */
};
-/* Master to slave. */
-typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data);
-/* Slave to master. */
-typedef int (*i2c_recv_cb)(i2c_slave *s);
-/* Notify the slave of a bus state change. */
-typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event);
+typedef struct I2CSlave I2CSlave;
-typedef int (*i2c_slave_initfn)(i2c_slave *dev);
+#define TYPE_I2C_SLAVE "i2c-slave"
+#define I2C_SLAVE(obj) \
+ OBJECT_CHECK(I2CSlave, (obj), TYPE_I2C_SLAVE)
+#define I2C_SLAVE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(I2CSlaveClass, (klass), TYPE_I2C_SLAVE)
+#define I2C_SLAVE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(I2CSlaveClass, (obj), TYPE_I2C_SLAVE)
-typedef struct {
- DeviceInfo qdev;
+typedef struct I2CSlaveClass
+{
+ DeviceClass parent_class;
/* Callbacks provided by the device. */
- i2c_slave_initfn init;
- i2c_event_cb event;
- i2c_recv_cb recv;
- i2c_send_cb send;
-} I2CSlaveInfo;
+ int (*init)(I2CSlave *dev);
-struct i2c_slave
+ /* Master to slave. */
+ int (*send)(I2CSlave *s, uint8_t data);
+
+ /* Slave to master. */
+ int (*recv)(I2CSlave *s);
+
+ /* Notify the slave of a bus state change. */
+ void (*event)(I2CSlave *s, enum i2c_event event);
+} I2CSlaveClass;
+
+struct I2CSlave
{
DeviceState qdev;
- I2CSlaveInfo *info;
/* Remaining fields for internal use by the I2C code. */
uint8_t address;
};
i2c_bus *i2c_init_bus(DeviceState *parent, const char *name);
-void i2c_set_slave_address(i2c_slave *dev, uint8_t address);
+void i2c_set_slave_address(I2CSlave *dev, uint8_t address);
int i2c_bus_busy(i2c_bus *bus);
int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv);
void i2c_end_transfer(i2c_bus *bus);
@@ -52,11 +59,9 @@
int i2c_send(i2c_bus *bus, uint8_t data);
int i2c_recv(i2c_bus *bus);
-#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(i2c_slave, qdev, dev)
+#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(I2CSlave, qdev, dev)
#define FROM_I2C_SLAVE(type, dev) DO_UPCAST(type, i2c, dev)
-void i2c_register_slave(I2CSlaveInfo *type);
-
DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
/* wm8750.c */
@@ -69,7 +74,7 @@
void wm8750_set_bclk_in(void *opaque, int new_hz);
/* tmp105.c */
-void tmp105_set(i2c_slave *i2c, int temp);
+void tmp105_set(I2CSlave *i2c, int temp);
/* lm832x.c */
void lm832x_key_event(DeviceState *dev, int key, int state);
@@ -78,10 +83,10 @@
#define VMSTATE_I2C_SLAVE(_field, _state) { \
.name = (stringify(_field)), \
- .size = sizeof(i2c_slave), \
+ .size = sizeof(I2CSlave), \
.vmsd = &vmstate_i2c_slave, \
.flags = VMS_STRUCT, \
- .offset = vmstate_offset_value(_state, _field, i2c_slave), \
+ .offset = vmstate_offset_value(_state, _field, I2CSlave), \
}
#endif
diff --git a/hw/i82374.c b/hw/i82374.c
new file mode 100644
index 0000000..220e8cc
--- /dev/null
+++ b/hw/i82374.c
@@ -0,0 +1,165 @@
+/*
+ * QEMU Intel 82374 emulation (Enhanced DMA controller)
+ *
+ * Copyright (c) 2010 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "isa.h"
+
+//#define DEBUG_I82374
+
+#ifdef DEBUG_I82374
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "i82374: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+typedef struct I82374State {
+ uint8_t commands[8];
+} I82374State;
+
+static const VMStateDescription vmstate_i82374 = {
+ .name = "i82374",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8_ARRAY(commands, I82374State, 8),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static uint32_t i82374_read_isr(void *opaque, uint32_t nport)
+{
+ uint32_t val = 0;
+
+ BADF("%s: %08x\n", __func__, nport);
+
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+ return val;
+}
+
+static void i82374_write_command(void *opaque, uint32_t nport, uint32_t data)
+{
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
+
+ if (data != 0x42) {
+ /* Not Stop S/G command */
+ BADF("%s: %08x=%08x\n", __func__, nport, data);
+ }
+}
+
+static uint32_t i82374_read_status(void *opaque, uint32_t nport)
+{
+ uint32_t val = 0;
+
+ BADF("%s: %08x\n", __func__, nport);
+
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+ return val;
+}
+
+static void i82374_write_descriptor(void *opaque, uint32_t nport, uint32_t data)
+{
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
+
+ BADF("%s: %08x=%08x\n", __func__, nport, data);
+}
+
+static uint32_t i82374_read_descriptor(void *opaque, uint32_t nport)
+{
+ uint32_t val = 0;
+
+ BADF("%s: %08x\n", __func__, nport);
+
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+ return val;
+}
+
+static void i82374_init(I82374State *s)
+{
+ DMA_init(1, NULL);
+ memset(s->commands, 0, sizeof(s->commands));
+}
+
+typedef struct ISAi82374State {
+ ISADevice dev;
+ uint32_t iobase;
+ I82374State state;
+} ISAi82374State;
+
+static const VMStateDescription vmstate_isa_i82374 = {
+ .name = "isa-i82374",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(state, ISAi82374State, 0, vmstate_i82374, I82374State),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static int i82374_isa_init(ISADevice *dev)
+{
+ ISAi82374State *isa = DO_UPCAST(ISAi82374State, dev, dev);
+ I82374State *s = &isa->state;
+
+ register_ioport_read(isa->iobase + 0x0A, 1, 1, i82374_read_isr, s);
+ register_ioport_write(isa->iobase + 0x10, 8, 1, i82374_write_command, s);
+ register_ioport_read(isa->iobase + 0x18, 8, 1, i82374_read_status, s);
+ register_ioport_write(isa->iobase + 0x20, 0x20, 1, i82374_write_descriptor, s);
+ register_ioport_read(isa->iobase + 0x20, 0x20, 1, i82374_read_descriptor, s);
+
+ i82374_init(s);
+
+ return 0;
+}
+
+static Property i82374_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void i82374_class_init(ObjectClass *klass, void *data)
+{
+ ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = i82374_isa_init;
+ dc->vmsd = &vmstate_isa_i82374;
+ dc->props = i82374_properties;
+}
+
+static TypeInfo i82374_isa_info = {
+ .name = "i82374",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAi82374State),
+ .class_init = i82374_class_init,
+};
+
+static void i82374_register_devices(void)
+{
+ type_register_static(&i82374_isa_info);
+}
+
+device_init(i82374_register_devices)
diff --git a/hw/i82378.c b/hw/i82378.c
new file mode 100644
index 0000000..9c3efe8
--- /dev/null
+++ b/hw/i82378.c
@@ -0,0 +1,275 @@
+/*
+ * QEMU Intel i82378 emulation (PCI to ISA bridge)
+ *
+ * Copyright (c) 2010-2011 Hervé Poussineau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci.h"
+#include "pc.h"
+
+//#define DEBUG_I82378
+
+#ifdef DEBUG_I82378
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "i82378: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "i82378 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+typedef struct I82378State {
+ qemu_irq out[2];
+ qemu_irq *i8259;
+ MemoryRegion io;
+ MemoryRegion mem;
+} I82378State;
+
+typedef struct PCIi82378State {
+ PCIDevice pci_dev;
+ uint32_t isa_io_base;
+ uint32_t isa_mem_base;
+ I82378State state;
+} PCIi82378State;
+
+static const VMStateDescription vmstate_pci_i82378 = {
+ .name = "pci-i82378",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(pci_dev, PCIi82378State),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void i82378_io_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned int size)
+{
+ switch (size) {
+ case 1:
+ DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outb(addr, value);
+ break;
+ case 2:
+ DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outw(addr, value);
+ break;
+ case 4:
+ DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outl(addr, value);
+ break;
+ default:
+ abort();
+ }
+}
+
+static uint64_t i82378_io_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+ switch (size) {
+ case 1:
+ return cpu_inb(addr);
+ case 2:
+ return cpu_inw(addr);
+ case 4:
+ return cpu_inl(addr);
+ default:
+ abort();
+ }
+}
+
+static const MemoryRegionOps i82378_io_ops = {
+ .read = i82378_io_read,
+ .write = i82378_io_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void i82378_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned int size)
+{
+ switch (size) {
+ case 1:
+ DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outb(addr, value);
+ break;
+ case 2:
+ DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outw(addr, value);
+ break;
+ case 4:
+ DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outl(addr, value);
+ break;
+ default:
+ abort();
+ }
+}
+
+static uint64_t i82378_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+ switch (size) {
+ case 1:
+ return cpu_inb(addr);
+ case 2:
+ return cpu_inw(addr);
+ case 4:
+ return cpu_inl(addr);
+ default:
+ abort();
+ }
+}
+
+static const MemoryRegionOps i82378_mem_ops = {
+ .read = i82378_mem_read,
+ .write = i82378_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void i82378_request_out0_irq(void *opaque, int irq, int level)
+{
+ I82378State *s = opaque;
+ qemu_set_irq(s->out[0], level);
+}
+
+static void i82378_request_pic_irq(void *opaque, int irq, int level)
+{
+ DeviceState *dev = opaque;
+ PCIDevice *pci = DO_UPCAST(PCIDevice, qdev, dev);
+ PCIi82378State *s = DO_UPCAST(PCIi82378State, pci_dev, pci);
+
+ qemu_set_irq(s->state.i8259[irq], level);
+}
+
+static void i82378_init(DeviceState *dev, I82378State *s)
+{
+ ISABus *isabus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(dev, "isa.0"));
+ ISADevice *pit;
+ qemu_irq *out0_irq;
+
+ /* This device has:
+ 2 82C59 (irq)
+ 1 82C54 (pit)
+ 2 82C37 (dma)
+ NMI
+ Utility Bus Support Registers
+
+ All devices accept byte access only, except timer
+ */
+
+ qdev_init_gpio_out(dev, s->out, 2);
+ qdev_init_gpio_in(dev, i82378_request_pic_irq, 16);
+
+ /* Workaround the fact that i8259 is not qdev'ified... */
+ out0_irq = qemu_allocate_irqs(i82378_request_out0_irq, s, 1);
+
+ /* 2 82C59 (irq) */
+ s->i8259 = i8259_init(isabus, *out0_irq);
+ isa_bus_irqs(isabus, s->i8259);
+
+ /* 1 82C54 (pit) */
+ pit = pit_init(isabus, 0x40, 0);
+
+ /* speaker */
+ pcspk_init(pit);
+
+ /* 2 82C37 (dma) */
+ DMA_init(1, &s->out[1]);
+ isa_create_simple(isabus, "i82374");
+
+ /* timer */
+ isa_create_simple(isabus, "mc146818rtc");
+}
+
+static int pci_i82378_init(PCIDevice *dev)
+{
+ PCIi82378State *pci = DO_UPCAST(PCIi82378State, pci_dev, dev);
+ I82378State *s = &pci->state;
+ uint8_t *pci_conf;
+
+ pci_conf = dev->config;
+ pci_set_word(pci_conf + PCI_COMMAND,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_set_word(pci_conf + PCI_STATUS,
+ PCI_STATUS_DEVSEL_MEDIUM);
+
+ pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */
+
+ memory_region_init_io(&s->io, &i82378_io_ops, s, "i82378-io", 0x00010000);
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io);
+
+ memory_region_init_io(&s->mem, &i82378_mem_ops, s, "i82378-mem", 0x01000000);
+ memory_region_set_coalescing(&s->mem);
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+
+ /* Make I/O address read only */
+ pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_SPECIAL);
+ pci_set_long(dev->wmask + PCI_BASE_ADDRESS_0, 0);
+ pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, pci->isa_io_base);
+
+ isa_mem_base = pci->isa_mem_base;
+ isa_bus_new(&dev->qdev, pci_address_space_io(dev));
+
+ i82378_init(&dev->qdev, s);
+
+ return 0;
+}
+
+static Property i82378_properties[] = {
+ DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000),
+ DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void pci_i82378_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = pci_i82378_init;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82378;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+ k->subsystem_vendor_id = 0x0;
+ k->subsystem_id = 0x0;
+ dc->vmsd = &vmstate_pci_i82378;
+ dc->props = i82378_properties;
+}
+
+static TypeInfo pci_i82378_info = {
+ .name = "i82378",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIi82378State),
+ .class_init = pci_i82378_class_init,
+};
+
+static void i82378_register_devices(void)
+{
+ type_register_static(&pci_i82378_info);
+}
+
+device_init(i82378_register_devices)
diff --git a/hw/i8254.c b/hw/i8254.c
index cf9ed2f..522fed8 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -535,22 +535,32 @@
return 0;
}
-static ISADeviceInfo pit_info = {
- .qdev.name = "isa-pit",
- .qdev.size = sizeof(PITState),
- .qdev.vmsd = &vmstate_pit,
- .qdev.reset = pit_reset,
- .qdev.no_user = 1,
- .init = pit_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("irq", PITState, irq, -1),
- DEFINE_PROP_HEX32("iobase", PITState, iobase, -1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pit_properties[] = {
+ DEFINE_PROP_UINT32("irq", PITState, irq, -1),
+ DEFINE_PROP_HEX32("iobase", PITState, iobase, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pit_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = pit_initfn;
+ dc->no_user = 1;
+ dc->reset = pit_reset;
+ dc->vmsd = &vmstate_pit;
+ dc->props = pit_properties;
+}
+
+static TypeInfo pit_info = {
+ .name = "isa-pit",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(PITState),
+ .class_init = pit_class_initfn,
};
static void pit_register(void)
{
- isa_qdev_register(&pit_info);
+ type_register_static(&pit_info);
}
device_init(pit_register)
diff --git a/hw/i8259.c b/hw/i8259.c
index 7331e0e..7ae5380 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -26,6 +26,7 @@
#include "isa.h"
#include "monitor.h"
#include "qemu-timer.h"
+#include "i8259_internal.h"
/* debug PIC */
//#define DEBUG_PIC
@@ -40,33 +41,6 @@
//#define DEBUG_IRQ_LATENCY
//#define DEBUG_IRQ_COUNT
-struct PicState {
- ISADevice dev;
- uint8_t last_irr; /* edge detection */
- uint8_t irr; /* interrupt request register */
- uint8_t imr; /* interrupt mask register */
- uint8_t isr; /* interrupt service register */
- uint8_t priority_add; /* highest irq priority */
- uint8_t irq_base;
- uint8_t read_reg_select;
- uint8_t poll;
- uint8_t special_mask;
- uint8_t init_state;
- uint8_t auto_eoi;
- uint8_t rotate_on_auto_eoi;
- uint8_t special_fully_nested_mode;
- uint8_t init4; /* true if 4 byte init */
- uint8_t single_mode; /* true if slave pic is not initialized */
- uint8_t elcr; /* PIIX edge/trigger selection*/
- uint8_t elcr_mask;
- qemu_irq int_out[1];
- uint32_t master; /* reflects /SP input pin */
- uint32_t iobase;
- uint32_t elcr_addr;
- MemoryRegion base_io;
- MemoryRegion elcr_io;
-};
-
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
static int irq_level[16];
#endif
@@ -76,12 +50,12 @@
#ifdef DEBUG_IRQ_LATENCY
static int64_t irq_time[16];
#endif
-PicState *isa_pic;
-static PicState *slave_pic;
+DeviceState *isa_pic;
+static PICCommonState *slave_pic;
/* return the highest priority found in mask (highest = smallest
number). Return 8 if no irq */
-static int get_priority(PicState *s, int mask)
+static int get_priority(PICCommonState *s, int mask)
{
int priority;
@@ -96,7 +70,7 @@
}
/* return the pic wanted interrupt. return -1 if none */
-static int pic_get_irq(PicState *s)
+static int pic_get_irq(PICCommonState *s)
{
int mask, cur_priority, priority;
@@ -125,7 +99,7 @@
}
/* Update INT output. Must be called every time the output may have changed. */
-static void pic_update_irq(PicState *s)
+static void pic_update_irq(PICCommonState *s)
{
int irq;
@@ -142,7 +116,7 @@
/* set irq level. If an edge is detected, then the IRR is set to 1 */
static void pic_set_irq(void *opaque, int irq, int level)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
int mask = 1 << irq;
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
@@ -190,7 +164,7 @@
}
/* acknowledge interrupt 'irq' */
-static void pic_intack(PicState *s, int irq)
+static void pic_intack(PICCommonState *s, int irq)
{
if (s->auto_eoi) {
if (s->rotate_on_auto_eoi) {
@@ -206,8 +180,9 @@
pic_update_irq(s);
}
-int pic_read_irq(PicState *s)
+int pic_read_irq(DeviceState *d)
{
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
int irq, irq2, intno;
irq = pic_get_irq(s);
@@ -246,30 +221,15 @@
return intno;
}
-static void pic_init_reset(PicState *s)
+static void pic_init_reset(PICCommonState *s)
{
- s->last_irr = 0;
- s->irr = 0;
- s->imr = 0;
- s->isr = 0;
- s->priority_add = 0;
- s->irq_base = 0;
- s->read_reg_select = 0;
- s->poll = 0;
- s->special_mask = 0;
- s->init_state = 0;
- s->auto_eoi = 0;
- s->rotate_on_auto_eoi = 0;
- s->special_fully_nested_mode = 0;
- s->init4 = 0;
- s->single_mode = 0;
- /* Note: ELCR is not reset */
+ pic_reset_common(s);
pic_update_irq(s);
}
static void pic_reset(DeviceState *dev)
{
- PicState *s = container_of(dev, PicState, dev.qdev);
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
pic_init_reset(s);
s->elcr = 0;
@@ -278,7 +238,7 @@
static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
uint64_t val64, unsigned size)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
uint32_t addr = addr64;
uint32_t val = val64;
int priority, cmd, irq;
@@ -372,7 +332,7 @@
static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
int ret;
if (s->poll) {
@@ -399,51 +359,27 @@
return ret;
}
-int pic_get_output(PicState *s)
+int pic_get_output(DeviceState *d)
{
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
+
return (pic_get_irq(s) >= 0);
}
static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned size)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
s->elcr = val & s->elcr_mask;
}
static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
return s->elcr;
}
-static const VMStateDescription vmstate_pic = {
- .name = "i8259",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(last_irr, PicState),
- VMSTATE_UINT8(irr, PicState),
- VMSTATE_UINT8(imr, PicState),
- VMSTATE_UINT8(isr, PicState),
- VMSTATE_UINT8(priority_add, PicState),
- VMSTATE_UINT8(irq_base, PicState),
- VMSTATE_UINT8(read_reg_select, PicState),
- VMSTATE_UINT8(poll, PicState),
- VMSTATE_UINT8(special_mask, PicState),
- VMSTATE_UINT8(init_state, PicState),
- VMSTATE_UINT8(auto_eoi, PicState),
- VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
- VMSTATE_UINT8(special_fully_nested_mode, PicState),
- VMSTATE_UINT8(init4, PicState),
- VMSTATE_UINT8(single_mode, PicState),
- VMSTATE_UINT8(elcr, PicState),
- VMSTATE_END_OF_LIST()
- }
-};
-
static const MemoryRegionOps pic_base_ioport_ops = {
.read = pic_ioport_read,
.write = pic_ioport_write,
@@ -462,36 +398,25 @@
},
};
-static int pic_initfn(ISADevice *dev)
+static void pic_init(PICCommonState *s)
{
- PicState *s = DO_UPCAST(PicState, dev, dev);
-
memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
- isa_register_ioport(dev, &s->base_io, s->iobase);
- if (s->elcr_addr != -1) {
- isa_register_ioport(dev, &s->elcr_io, s->elcr_addr);
- }
-
- qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out));
- qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8);
-
- qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1);
-
- return 0;
+ qdev_init_gpio_out(&s->dev.qdev, s->int_out, ARRAY_SIZE(s->int_out));
+ qdev_init_gpio_in(&s->dev.qdev, pic_set_irq, 8);
}
void pic_info(Monitor *mon)
{
int i;
- PicState *s;
+ PICCommonState *s;
if (!isa_pic) {
return;
}
for (i = 0; i < 2; i++) {
- s = i == 0 ? isa_pic : slave_pic;
+ s = i == 0 ? DO_UPCAST(PICCommonState, dev.qdev, isa_pic) : slave_pic;
monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
"irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
i, s->irr, s->imr, s->isr, s->priority_add,
@@ -526,54 +451,46 @@
irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
- dev = isa_create(bus, "isa-i8259");
- qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20);
- qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0);
- qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8);
- qdev_prop_set_bit(&dev->qdev, "master", true);
- qdev_init_nofail(&dev->qdev);
+ dev = i8259_init_chip("isa-i8259", bus, true);
qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
for (i = 0 ; i < 8; i++) {
irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
}
- isa_pic = DO_UPCAST(PicState, dev, dev);
+ isa_pic = &dev->qdev;
- dev = isa_create(bus, "isa-i8259");
- qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
- qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1);
- qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde);
- qdev_init_nofail(&dev->qdev);
+ dev = i8259_init_chip("isa-i8259", bus, false);
qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
for (i = 0 ; i < 8; i++) {
irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
}
- slave_pic = DO_UPCAST(PicState, dev, dev);
+ slave_pic = DO_UPCAST(PICCommonState, dev, dev);
return irq_set;
}
-static ISADeviceInfo i8259_info = {
- .qdev.name = "isa-i8259",
- .qdev.size = sizeof(PicState),
- .qdev.vmsd = &vmstate_pic,
- .qdev.reset = pic_reset,
- .qdev.no_user = 1,
- .init = pic_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", PicState, iobase, -1),
- DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr, -1),
- DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask, -1),
- DEFINE_PROP_BIT("master", PicState, master, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void i8259_class_init(ObjectClass *klass, void *data)
+{
+ PICCommonClass *k = PIC_COMMON_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = pic_init;
+ dc->reset = pic_reset;
+}
+
+static TypeInfo i8259_info = {
+ .name = "isa-i8259",
+ .instance_size = sizeof(PICCommonState),
+ .parent = TYPE_PIC_COMMON,
+ .class_init = i8259_class_init,
};
static void pic_register(void)
{
- isa_qdev_register(&i8259_info);
+ type_register_static(&i8259_info);
}
+
device_init(pic_register)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
new file mode 100644
index 0000000..9f150bc
--- /dev/null
+++ b/hw/i8259_common.c
@@ -0,0 +1,161 @@
+/*
+ * QEMU 8259 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * 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 "pc.h"
+#include "i8259_internal.h"
+
+void pic_reset_common(PICCommonState *s)
+{
+ s->last_irr = 0;
+ s->irr = 0;
+ s->imr = 0;
+ s->isr = 0;
+ s->priority_add = 0;
+ s->irq_base = 0;
+ s->read_reg_select = 0;
+ s->poll = 0;
+ s->special_mask = 0;
+ s->init_state = 0;
+ s->auto_eoi = 0;
+ s->rotate_on_auto_eoi = 0;
+ s->special_fully_nested_mode = 0;
+ s->init4 = 0;
+ s->single_mode = 0;
+ /* Note: ELCR is not reset */
+}
+
+static void pic_dispatch_pre_save(void *opaque)
+{
+ PICCommonState *s = opaque;
+ PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+ if (info->pre_save) {
+ info->pre_save(s);
+ }
+}
+
+static int pic_dispatch_post_load(void *opaque, int version_id)
+{
+ PICCommonState *s = opaque;
+ PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+ if (info->post_load) {
+ info->post_load(s);
+ }
+ return 0;
+}
+
+static int pic_init_common(ISADevice *dev)
+{
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
+ PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+ info->init(s);
+
+ isa_register_ioport(NULL, &s->base_io, s->iobase);
+ if (s->elcr_addr != -1) {
+ isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
+ }
+
+ qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1);
+
+ return 0;
+}
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
+{
+ ISADevice *dev;
+
+ dev = isa_create(bus, name);
+ qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0);
+ qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1);
+ qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde);
+ qdev_prop_set_bit(&dev->qdev, "master", master);
+ qdev_init_nofail(&dev->qdev);
+
+ return dev;
+}
+
+static const VMStateDescription vmstate_pic_common = {
+ .name = "i8259",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_save = pic_dispatch_pre_save,
+ .post_load = pic_dispatch_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(last_irr, PICCommonState),
+ VMSTATE_UINT8(irr, PICCommonState),
+ VMSTATE_UINT8(imr, PICCommonState),
+ VMSTATE_UINT8(isr, PICCommonState),
+ VMSTATE_UINT8(priority_add, PICCommonState),
+ VMSTATE_UINT8(irq_base, PICCommonState),
+ VMSTATE_UINT8(read_reg_select, PICCommonState),
+ VMSTATE_UINT8(poll, PICCommonState),
+ VMSTATE_UINT8(special_mask, PICCommonState),
+ VMSTATE_UINT8(init_state, PICCommonState),
+ VMSTATE_UINT8(auto_eoi, PICCommonState),
+ VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState),
+ VMSTATE_UINT8(special_fully_nested_mode, PICCommonState),
+ VMSTATE_UINT8(init4, PICCommonState),
+ VMSTATE_UINT8(single_mode, PICCommonState),
+ VMSTATE_UINT8(elcr, PICCommonState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property pic_properties_common[] = {
+ DEFINE_PROP_HEX32("iobase", PICCommonState, iobase, -1),
+ DEFINE_PROP_HEX32("elcr_addr", PICCommonState, elcr_addr, -1),
+ DEFINE_PROP_HEX8("elcr_mask", PICCommonState, elcr_mask, -1),
+ DEFINE_PROP_BIT("master", PICCommonState, master, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pic_common_class_init(ObjectClass *klass, void *data)
+{
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_pic_common;
+ dc->no_user = 1;
+ dc->props = pic_properties_common;
+ ic->init = pic_init_common;
+}
+
+static TypeInfo pic_common_type = {
+ .name = TYPE_PIC_COMMON,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(PICCommonState),
+ .class_size = sizeof(PICCommonClass),
+ .class_init = pic_common_class_init,
+ .abstract = true,
+};
+
+static void register_devices(void)
+{
+ type_register_static(&pic_common_type);
+}
+
+device_init(register_devices);
diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
new file mode 100644
index 0000000..4137b61
--- /dev/null
+++ b/hw/i8259_internal.h
@@ -0,0 +1,82 @@
+/*
+ * QEMU 8259 - internal interfaces
+ *
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8259_INTERNAL_H
+#define QEMU_I8259_INTERNAL_H
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+
+typedef struct PICCommonState PICCommonState;
+
+#define TYPE_PIC_COMMON "pic-common"
+#define PIC_COMMON(obj) \
+ OBJECT_CHECK(PICCommon, (obj), TYPE_PIC_COMMON)
+#define PIC_COMMON_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PICCommonClass, (klass), TYPE_PIC_COMMON)
+#define PIC_COMMON_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PICCommonClass, (obj), TYPE_PIC_COMMON)
+
+typedef struct PICCommonClass
+{
+ ISADeviceClass parent_class;
+ void (*init)(PICCommonState *s);
+ void (*pre_save)(PICCommonState *s);
+ void (*post_load)(PICCommonState *s);
+} PICCommonClass;
+
+struct PICCommonState {
+ ISADevice dev;
+ uint8_t last_irr; /* edge detection */
+ uint8_t irr; /* interrupt request register */
+ uint8_t imr; /* interrupt mask register */
+ uint8_t isr; /* interrupt service register */
+ uint8_t priority_add; /* highest irq priority */
+ uint8_t irq_base;
+ uint8_t read_reg_select;
+ uint8_t poll;
+ uint8_t special_mask;
+ uint8_t init_state;
+ uint8_t auto_eoi;
+ uint8_t rotate_on_auto_eoi;
+ uint8_t special_fully_nested_mode;
+ uint8_t init4; /* true if 4 byte init */
+ uint8_t single_mode; /* true if slave pic is not initialized */
+ uint8_t elcr; /* PIIX edge/trigger selection*/
+ uint8_t elcr_mask;
+ qemu_irq int_out[1];
+ uint32_t master; /* reflects /SP input pin */
+ uint32_t iobase;
+ uint32_t elcr_addr;
+ MemoryRegion base_io;
+ MemoryRegion elcr_io;
+};
+
+void pic_reset_common(PICCommonState *s);
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
+
+
+#endif /* !QEMU_I8259_INTERNAL_H */
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 0af201d..c87a6ca 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -25,6 +25,7 @@
#include <hw/msi.h>
#include <hw/pc.h>
#include <hw/pci.h>
+#include <hw/sysbus.h>
#include "monitor.h"
#include "dma.h"
@@ -1214,3 +1215,55 @@
ahci_reset_port(&d->ahci, i);
}
}
+
+typedef struct SysbusAHCIState {
+ SysBusDevice busdev;
+ AHCIState ahci;
+ uint32_t num_ports;
+} SysbusAHCIState;
+
+static const VMStateDescription vmstate_sysbus_ahci = {
+ .name = "sysbus-ahci",
+ .unmigratable = 1,
+};
+
+static int sysbus_ahci_init(SysBusDevice *dev)
+{
+ SysbusAHCIState *s = FROM_SYSBUS(SysbusAHCIState, dev);
+ ahci_init(&s->ahci, &dev->qdev, s->num_ports);
+
+ sysbus_init_mmio(dev, &s->ahci.mem);
+ sysbus_init_irq(dev, &s->ahci.irq);
+
+ qemu_register_reset(ahci_reset, &s->ahci);
+ return 0;
+}
+
+static Property sysbus_ahci_properties[] = {
+ DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ sbc->init = sysbus_ahci_init;
+ dc->vmsd = &vmstate_sysbus_ahci;
+ dc->props = sysbus_ahci_properties;
+}
+
+static TypeInfo sysbus_ahci_info = {
+ .name = "sysbus-ahci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysbusAHCIState),
+ .class_init = sysbus_ahci_class_init,
+};
+
+static void sysbus_ahci_register(void)
+{
+ type_register_static(&sysbus_ahci_info);
+}
+
+device_init(sysbus_ahci_register);
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 5fe98b1..a119500 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -325,27 +325,34 @@
pci_ide_create_devs(dev, hd_table);
}
-static PCIDeviceInfo cmd646_ide_info[] = {
- {
- .qdev.name = "cmd646-ide",
- .qdev.size = sizeof(PCIIDEState),
- .init = pci_cmd646_ide_initfn,
- .exit = pci_cmd646_ide_exitfn,
- .vendor_id = PCI_VENDOR_ID_CMD,
- .device_id = PCI_DEVICE_ID_CMD_646,
- .revision = 0x07, // IDE controller revision
- .class_id = PCI_CLASS_STORAGE_IDE,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
- },{
- /* end of list */
- }
+static Property cmd646_ide_properties[] = {
+ DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cmd646_ide_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_cmd646_ide_initfn;
+ k->exit = pci_cmd646_ide_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_CMD;
+ k->device_id = PCI_DEVICE_ID_CMD_646;
+ k->revision = 0x07;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->props = cmd646_ide_properties;
+}
+
+static TypeInfo cmd646_ide_info = {
+ .name = "cmd646-ide",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = cmd646_ide_class_init,
};
static void cmd646_ide_register(void)
{
- pci_qdev_register_many(cmd646_ide_info);
+ type_register_static(&cmd646_ide_info);
}
device_init(cmd646_ide_register);
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 3f7510f..5cdaa99 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -146,26 +146,30 @@
msi_write_config(pci, addr, val, len);
}
-static PCIDeviceInfo ich_ahci_info[] = {
- {
- .qdev.name = "ich9-ahci",
- .qdev.alias = "ahci",
- .qdev.size = sizeof(AHCIPCIState),
- .qdev.vmsd = &vmstate_ahci,
- .init = pci_ich9_ahci_init,
- .exit = pci_ich9_uninit,
- .config_write = pci_ich9_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801IR,
- .revision = 0x02,
- .class_id = PCI_CLASS_STORAGE_SATA,
- },{
- /* end of list */
- }
+static void ich_ahci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_ich9_ahci_init;
+ k->exit = pci_ich9_uninit;
+ k->config_write = pci_ich9_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801IR;
+ k->revision = 0x02;
+ k->class_id = PCI_CLASS_STORAGE_SATA;
+ dc->vmsd = &vmstate_ahci;
+}
+
+static TypeInfo ich_ahci_info = {
+ .name = "ich9-ahci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(AHCIPCIState),
+ .class_init = ich_ahci_class_init,
};
static void ich_ahci_register(void)
{
- pci_qdev_register_many(ich_ahci_info);
+ type_register_static(&ich_ahci_info);
}
device_init(ich_ahci_register);
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 00b28df..c808a0d 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -21,7 +21,6 @@
typedef struct IDEBus IDEBus;
typedef struct IDEDevice IDEDevice;
-typedef struct IDEDeviceInfo IDEDeviceInfo;
typedef struct IDEState IDEState;
typedef struct IDEDMA IDEDMA;
typedef struct IDEDMAOps IDEDMAOps;
@@ -450,6 +449,19 @@
int error_status;
};
+#define TYPE_IDE_DEVICE "ide-device"
+#define IDE_DEVICE(obj) \
+ OBJECT_CHECK(IDEDevice, (obj), TYPE_IDE_DEVICE)
+#define IDE_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(IDEDeviceClass, (klass), TYPE_IDE_DEVICE)
+#define IDE_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(IDEDeviceClass, (obj), TYPE_IDE_DEVICE)
+
+typedef struct IDEDeviceClass {
+ DeviceClass parent_class;
+ int (*init)(IDEDevice *dev);
+} IDEDeviceClass;
+
struct IDEDevice {
DeviceState qdev;
uint32_t unit;
@@ -458,12 +470,6 @@
char *serial;
};
-typedef int (*ide_qdev_initfn)(IDEDevice *dev);
-struct IDEDeviceInfo {
- DeviceInfo qdev;
- ide_qdev_initfn init;
-};
-
#define BM_STATUS_DMAING 0x01
#define BM_STATUS_ERROR 0x02
#define BM_STATUS_INT 0x04
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 219f3a4..a0bcb43 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -94,23 +94,33 @@
return dev;
}
-static ISADeviceInfo isa_ide_info = {
- .qdev.name = "isa-ide",
- .qdev.fw_name = "ide",
- .qdev.size = sizeof(ISAIDEState),
- .init = isa_ide_initfn,
- .qdev.reset = isa_ide_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", ISAIDEState, iobase, 0x1f0),
- DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
- DEFINE_PROP_UINT32("irq", ISAIDEState, isairq, 14),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property isa_ide_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISAIDEState, iobase, 0x1f0),
+ DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
+ DEFINE_PROP_UINT32("irq", ISAIDEState, isairq, 14),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isa_ide_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = isa_ide_initfn;
+ dc->fw_name = "ide";
+ dc->reset = isa_ide_reset;
+ dc->props = isa_ide_properties;
+}
+
+static TypeInfo isa_ide_info = {
+ .name = "isa-ide",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAIDEState),
+ .class_init = isa_ide_class_initfn,
};
static void isa_ide_register_devices(void)
{
- isa_qdev_register(&isa_ide_info);
+ type_register_static(&isa_ide_info);
}
device_init(isa_ide_register_devices)
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index cb3de65..246dd57 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -327,7 +327,7 @@
bm->cmd = val & 0x09;
}
-static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr,
+static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr,
unsigned width)
{
BMDMAState *bm = opaque;
@@ -341,7 +341,7 @@
return data;
}
-static void bmdma_addr_write(void *opaque, dma_addr_t addr,
+static void bmdma_addr_write(void *opaque, target_phys_addr_t addr,
uint64_t data, unsigned width)
{
BMDMAState *bm = opaque;
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 3473345..bf4465b 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -195,7 +195,6 @@
PCIDevice *dev;
dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
- dev->qdev.info->unplug = pci_piix3_xen_ide_unplug;
pci_ide_create_devs(dev, hd_table);
return dev;
}
@@ -238,42 +237,72 @@
return dev;
}
-static PCIDeviceInfo piix_ide_info[] = {
- {
- .qdev.name = "piix3-ide",
- .qdev.size = sizeof(PCIIDEState),
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = pci_piix_ide_initfn,
- .exit = pci_piix_ide_exitfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_1,
- .class_id = PCI_CLASS_STORAGE_IDE,
- },{
- .qdev.name = "piix3-ide-xen",
- .qdev.size = sizeof(PCIIDEState),
- .qdev.no_user = 1,
- .init = pci_piix_ide_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_1,
- .class_id = PCI_CLASS_STORAGE_IDE,
- },{
- .qdev.name = "piix4-ide",
- .qdev.size = sizeof(PCIIDEState),
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = pci_piix_ide_initfn,
- .exit = pci_piix_ide_exitfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB,
- .class_id = PCI_CLASS_STORAGE_IDE,
- },{
- /* end of list */
- }
+static void piix3_ide_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = pci_piix_ide_initfn;
+ k->exit = pci_piix_ide_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->no_user = 1;
+}
+
+static TypeInfo piix3_ide_info = {
+ .name = "piix3-ide",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = piix3_ide_class_init,
+};
+
+static void piix3_ide_xen_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_piix_ide_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->no_user = 1;
+ dc->unplug = pci_piix3_xen_ide_unplug;
+}
+
+static TypeInfo piix3_ide_xen_info = {
+ .name = "piix3-ide-xen",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = piix3_ide_xen_class_init,
+};
+
+static void piix4_ide_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = pci_piix_ide_initfn;
+ k->exit = pci_piix_ide_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->no_user = 1;
+}
+
+static TypeInfo piix4_ide_info = {
+ .name = "piix4-ide",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = piix4_ide_class_init,
};
static void piix_ide_register(void)
{
- pci_qdev_register_many(piix_ide_info);
+ type_register_static(&piix3_ide_info);
+ type_register_static(&piix3_ide_xen_info);
+ type_register_static(&piix4_ide_info);
}
device_init(piix_ide_register);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 4207127..1640616 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -53,10 +53,10 @@
return strdup(path);
}
-static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int ide_qdev_init(DeviceState *qdev)
{
- IDEDevice *dev = DO_UPCAST(IDEDevice, qdev, qdev);
- IDEDeviceInfo *info = DO_UPCAST(IDEDeviceInfo, qdev, base);
+ IDEDevice *dev = IDE_DEVICE(qdev);
+ IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
if (!dev->conf.bs) {
@@ -85,19 +85,12 @@
error_report("Invalid IDE unit %d", dev->unit);
goto err;
}
- return info->init(dev);
+ return dc->init(dev);
err:
return -1;
}
-static void ide_qdev_register(IDEDeviceInfo *info)
-{
- info->qdev.init = ide_qdev_init;
- info->qdev.bus_info = &ide_bus_info;
- qdev_register(&info->qdev);
-}
-
IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
{
DeviceState *dev;
@@ -182,46 +175,93 @@
DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \
DEFINE_PROP_STRING("serial", IDEDrive, dev.serial)
-static IDEDeviceInfo ide_dev_info[] = {
- {
- .qdev.name = "ide-hd",
- .qdev.fw_name = "drive",
- .qdev.desc = "virtual IDE disk",
- .qdev.size = sizeof(IDEDrive),
- .init = ide_hd_initfn,
- .qdev.props = (Property[]) {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- }
- },{
- .qdev.name = "ide-cd",
- .qdev.fw_name = "drive",
- .qdev.desc = "virtual IDE CD-ROM",
- .qdev.size = sizeof(IDEDrive),
- .init = ide_cd_initfn,
- .qdev.props = (Property[]) {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- }
- },{
- .qdev.name = "ide-drive", /* legacy -device ide-drive */
- .qdev.fw_name = "drive",
- .qdev.desc = "virtual IDE disk or CD-ROM (legacy)",
- .qdev.size = sizeof(IDEDrive),
- .init = ide_drive_initfn,
- .qdev.props = (Property[]) {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- }
- }
+static Property ide_hd_properties[] = {
+ DEFINE_IDE_DEV_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_hd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+ k->init = ide_hd_initfn;
+ dc->fw_name = "drive";
+ dc->desc = "virtual IDE disk";
+ dc->props = ide_hd_properties;
+}
+
+static TypeInfo ide_hd_info = {
+ .name = "ide-hd",
+ .parent = TYPE_IDE_DEVICE,
+ .instance_size = sizeof(IDEDrive),
+ .class_init = ide_hd_class_init,
+};
+
+static Property ide_cd_properties[] = {
+ DEFINE_IDE_DEV_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_cd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+ k->init = ide_cd_initfn;
+ dc->fw_name = "drive";
+ dc->desc = "virtual IDE CD-ROM";
+ dc->props = ide_cd_properties;
+}
+
+static TypeInfo ide_cd_info = {
+ .name = "ide-cd",
+ .parent = TYPE_IDE_DEVICE,
+ .instance_size = sizeof(IDEDrive),
+ .class_init = ide_cd_class_init,
+};
+
+static Property ide_drive_properties[] = {
+ DEFINE_IDE_DEV_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_drive_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+ k->init = ide_drive_initfn;
+ dc->fw_name = "drive";
+ dc->desc = "virtual IDE disk or CD-ROM (legacy)";
+ dc->props = ide_drive_properties;
+}
+
+static TypeInfo ide_drive_info = {
+ .name = "ide-drive",
+ .parent = TYPE_IDE_DEVICE,
+ .instance_size = sizeof(IDEDrive),
+ .class_init = ide_drive_class_init,
+};
+
+static void ide_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = ide_qdev_init;
+ k->bus_info = &ide_bus_info;
+}
+
+static TypeInfo ide_device_type_info = {
+ .name = TYPE_IDE_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(IDEDevice),
+ .abstract = true,
+ .class_size = sizeof(IDEDeviceClass),
+ .class_init = ide_device_class_init,
};
static void ide_dev_register(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ide_dev_info); i++) {
- ide_qdev_register(&ide_dev_info[i]);
- }
+ type_register_static(&ide_hd_info);
+ type_register_static(&ide_cd_info);
+ type_register_static(&ide_drive_info);
+ type_register_static(&ide_device_type_info);
}
device_init(ide_dev_register);
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 4ea2064..b4ca6f2 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -213,20 +213,29 @@
pci_ide_create_devs(dev, hd_table);
}
-static PCIDeviceInfo via_ide_info = {
- .qdev.name = "via-ide",
- .qdev.size = sizeof(PCIIDEState),
- .qdev.no_user = 1,
- .init = vt82c686b_ide_initfn,
- .exit = vt82c686b_ide_exitfn,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_IDE,
- .revision = 0x06,
- .class_id = PCI_CLASS_STORAGE_IDE,
+static void via_ide_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_ide_initfn;
+ k->exit = vt82c686b_ide_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_IDE;
+ k->revision = 0x06;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->no_user = 1;
+}
+
+static TypeInfo via_ide_info = {
+ .name = "via-ide",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = via_ide_class_init,
};
static void via_ide_register(void)
{
- pci_qdev_register(&via_ide_info);
+ type_register_static(&via_ide_info);
}
device_init(via_ide_register);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index e5712fc..6dbd649 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -518,20 +518,45 @@
machine_init(integratorcp_machine_init);
-static SysBusDeviceInfo core_info = {
- .init = integratorcm_init,
- .qdev.name = "integrator_core",
- .qdev.size = sizeof(integratorcm_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property core_properties[] = {
+ DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void core_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = integratorcm_init;
+ dc->props = core_properties;
+}
+
+static TypeInfo core_info = {
+ .name = "integrator_core",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(integratorcm_state),
+ .class_init = core_class_init,
+};
+
+static void icp_pic_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = icp_pic_init;
+}
+
+static TypeInfo icp_pic_info = {
+ .name = "integrator_pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(icp_pic_state),
+ .class_init = icp_pic_class_init,
};
static void integratorcp_register_devices(void)
{
- sysbus_register_dev("integrator_pic", sizeof(icp_pic_state), icp_pic_init);
- sysbus_register_withprop(&core_info);
+ type_register_static(&icp_pic_info);
+ type_register_static(&core_info);
}
device_init(integratorcp_register_devices)
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 10769e0..83c42d5 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -47,13 +47,12 @@
bus->xfer = xfer;
}
-static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
+static int hda_codec_dev_init(DeviceState *qdev)
{
HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base);
+ HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
- dev->info = info;
if (dev->cad == -1) {
dev->cad = bus->next_cad;
}
@@ -61,27 +60,20 @@
return -1;
}
bus->next_cad = dev->cad + 1;
- return info->init(dev);
+ return cdc->init(dev);
}
static int hda_codec_dev_exit(DeviceState *qdev)
{
HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
- if (dev->info->exit) {
- dev->info->exit(dev);
+ if (cdc->exit) {
+ cdc->exit(dev);
}
return 0;
}
-void hda_codec_register(HDACodecDeviceInfo *info)
-{
- info->qdev.init = hda_codec_dev_init;
- info->qdev.exit = hda_codec_dev_exit;
- info->qdev.bus_info = &hda_codec_bus_info;
- qdev_register(&info->qdev);
-}
-
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
{
DeviceState *qdev;
@@ -283,6 +275,7 @@
{
uint32_t cad, nid, data;
HDACodecDevice *codec;
+ HDACodecDeviceClass *cdc;
cad = (verb >> 28) & 0x0f;
if (verb & (1 << 27)) {
@@ -298,7 +291,8 @@
dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
return -1;
}
- codec->info->command(codec, nid, data);
+ cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
+ cdc->command(codec, nid, data);
return 0;
}
@@ -491,9 +485,12 @@
HDACodecDevice *cdev;
QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+ HDACodecDeviceClass *cdc;
+
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- if (cdev->info->stream) {
- cdev->info->stream(cdev, stream, running, output);
+ cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
+ if (cdc->stream) {
+ cdc->stream(cdev, stream, running, output);
}
}
}
@@ -1116,9 +1113,7 @@
/* reset codecs */
QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- if (qdev->info->reset) {
- qdev->info->reset(qdev);
- }
+ device_reset(DEVICE(cdev));
d->state_sts |= (1 << cdev->cad);
}
intel_hda_update_irq(d);
@@ -1129,7 +1124,7 @@
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
uint8_t *conf = d->pci.config;
- d->name = d->pci.qdev.info->name;
+ d->name = object_get_typename(OBJECT(d));
pci_config_set_interrupt_pin(conf, 1);
@@ -1244,29 +1239,58 @@
}
};
-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,
- .exit = intel_hda_exit,
- .config_write = intel_hda_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = 0x2668,
- .revision = 1,
- .class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
- DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property intel_hda_properties[] = {
+ DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+ DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void intel_hda_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = intel_hda_init;
+ k->exit = intel_hda_exit;
+ k->config_write = intel_hda_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = 0x2668;
+ k->revision = 1;
+ k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
+ dc->desc = "Intel HD Audio Controller";
+ dc->reset = intel_hda_reset;
+ dc->vmsd = &vmstate_intel_hda;
+ dc->props = intel_hda_properties;
+}
+
+static TypeInfo intel_hda_info = {
+ .name = "intel-hda",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(IntelHDAState),
+ .class_init = intel_hda_class_init,
+};
+
+static void hda_codec_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = hda_codec_dev_init;
+ k->exit = hda_codec_dev_exit;
+ k->bus_info = &hda_codec_bus_info;
+}
+
+static TypeInfo hda_codec_device_type_info = {
+ .name = TYPE_HDA_CODEC_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(HDACodecDevice),
+ .abstract = true,
+ .class_size = sizeof(HDACodecDeviceClass),
+ .class_init = hda_codec_device_class_init,
};
static void intel_hda_register(void)
{
- pci_qdev_register(&intel_hda_info);
+ type_register_static(&intel_hda_info);
+ type_register_static(&hda_codec_device_type_info);
}
device_init(intel_hda_register);
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index 65fd2a8..a1cca5b 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -6,9 +6,16 @@
/* --------------------------------------------------------------------- */
/* hda bus */
+#define TYPE_HDA_CODEC_DEVICE "hda-codec"
+#define HDA_CODEC_DEVICE(obj) \
+ OBJECT_CHECK(HDACodecDevice, (obj), TYPE_HDA_CODEC_DEVICE)
+#define HDA_CODEC_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(HDACodecDeviceClass, (klass), TYPE_HDA_CODEC_DEVICE)
+#define HDA_CODEC_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(HDACodecDeviceClass, (obj), TYPE_HDA_CODEC_DEVICE)
+
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);
@@ -23,24 +30,24 @@
hda_codec_xfer_func xfer;
};
-struct HDACodecDevice {
- DeviceState qdev;
- HDACodecDeviceInfo *info;
- uint32_t cad; /* codec address */
-};
+typedef struct HDACodecDeviceClass
+{
+ DeviceClass parent_class;
-struct HDACodecDeviceInfo {
- DeviceInfo qdev;
int (*init)(HDACodecDevice *dev);
int (*exit)(HDACodecDevice *dev);
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
+} HDACodecDeviceClass;
+
+struct HDACodecDevice {
+ DeviceState qdev;
+ uint32_t cad; /* codec address */
};
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);
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 27b07c6..79549f8 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -24,9 +24,7 @@
#include "pc.h"
#include "apic.h"
#include "ioapic.h"
-#include "qemu-timer.h"
-#include "host-utils.h"
-#include "sysbus.h"
+#include "ioapic_internal.h"
//#define DEBUG_IOAPIC
@@ -37,65 +35,9 @@
#define DPRINTF(fmt, ...)
#endif
-#define MAX_IOAPICS 1
+static IOAPICCommonState *ioapics[MAX_IOAPICS];
-#define IOAPIC_VERSION 0x11
-
-#define IOAPIC_LVT_DEST_SHIFT 56
-#define IOAPIC_LVT_MASKED_SHIFT 16
-#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15
-#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14
-#define IOAPIC_LVT_POLARITY_SHIFT 13
-#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12
-#define IOAPIC_LVT_DEST_MODE_SHIFT 11
-#define IOAPIC_LVT_DELIV_MODE_SHIFT 8
-
-#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT)
-#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
-
-#define IOAPIC_TRIGGER_EDGE 0
-#define IOAPIC_TRIGGER_LEVEL 1
-
-/*io{apic,sapic} delivery mode*/
-#define IOAPIC_DM_FIXED 0x0
-#define IOAPIC_DM_LOWEST_PRIORITY 0x1
-#define IOAPIC_DM_PMI 0x2
-#define IOAPIC_DM_NMI 0x4
-#define IOAPIC_DM_INIT 0x5
-#define IOAPIC_DM_SIPI 0x6
-#define IOAPIC_DM_EXTINT 0x7
-#define IOAPIC_DM_MASK 0x7
-
-#define IOAPIC_VECTOR_MASK 0xff
-
-#define IOAPIC_IOREGSEL 0x00
-#define IOAPIC_IOWIN 0x10
-
-#define IOAPIC_REG_ID 0x00
-#define IOAPIC_REG_VER 0x01
-#define IOAPIC_REG_ARB 0x02
-#define IOAPIC_REG_REDTBL_BASE 0x10
-#define IOAPIC_ID 0x00
-
-#define IOAPIC_ID_SHIFT 24
-#define IOAPIC_ID_MASK 0xf
-
-#define IOAPIC_VER_ENTRIES_SHIFT 16
-
-typedef struct IOAPICState IOAPICState;
-
-struct IOAPICState {
- SysBusDevice busdev;
- MemoryRegion io_memory;
- uint8_t id;
- uint8_t ioregsel;
- uint32_t irr;
- uint64_t ioredtbl[IOAPIC_NUM_PINS];
-};
-
-static IOAPICState *ioapics[MAX_IOAPICS];
-
-static void ioapic_service(IOAPICState *s)
+static void ioapic_service(IOAPICCommonState *s)
{
uint8_t i;
uint8_t trig_mode;
@@ -135,7 +77,7 @@
static void ioapic_set_irq(void *opaque, int vector, int level)
{
- IOAPICState *s = opaque;
+ IOAPICCommonState *s = opaque;
/* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
* to GSI 2. GSI maps to ioapic 1-1. This is not
@@ -174,7 +116,7 @@
void ioapic_eoi_broadcast(int vector)
{
- IOAPICState *s;
+ IOAPICCommonState *s;
uint64_t entry;
int i, n;
@@ -199,7 +141,7 @@
static uint64_t
ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size)
{
- IOAPICState *s = opaque;
+ IOAPICCommonState *s = opaque;
int index;
uint32_t val = 0;
@@ -242,7 +184,7 @@
ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
unsigned int size)
{
- IOAPICState *s = opaque;
+ IOAPICCommonState *s = opaque;
int index;
switch (addr & 0xff) {
@@ -278,83 +220,40 @@
}
}
-static int ioapic_post_load(void *opaque, int version_id)
-{
- IOAPICState *s = opaque;
-
- if (version_id == 1) {
- /* set sane value */
- s->irr = 0;
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_ioapic = {
- .name = "ioapic",
- .version_id = 3,
- .post_load = ioapic_post_load,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(id, IOAPICState),
- VMSTATE_UINT8(ioregsel, IOAPICState),
- VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
- VMSTATE_UINT32_V(irr, IOAPICState, 2),
- VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ioapic_reset(DeviceState *d)
-{
- IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, d);
- int i;
-
- s->id = 0;
- s->ioregsel = 0;
- s->irr = 0;
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
- }
-}
-
static const MemoryRegionOps ioapic_io_ops = {
.read = ioapic_mem_read,
.write = ioapic_mem_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int ioapic_init1(SysBusDevice *dev)
+static void ioapic_init(IOAPICCommonState *s, int instance_no)
{
- IOAPICState *s = FROM_SYSBUS(IOAPICState, dev);
- static int ioapic_no;
-
- if (ioapic_no >= MAX_IOAPICS) {
- return -1;
- }
-
memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
- sysbus_init_mmio(dev, &s->io_memory);
- qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+ qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
- ioapics[ioapic_no++] = s;
-
- return 0;
+ ioapics[instance_no] = s;
}
-static SysBusDeviceInfo ioapic_info = {
- .init = ioapic_init1,
- .qdev.name = "ioapic",
- .qdev.size = sizeof(IOAPICState),
- .qdev.vmsd = &vmstate_ioapic,
- .qdev.reset = ioapic_reset,
- .qdev.no_user = 1,
+static void ioapic_class_init(ObjectClass *klass, void *data)
+{
+ IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = ioapic_init;
+ dc->reset = ioapic_reset_common;
+}
+
+static TypeInfo ioapic_info = {
+ .name = "ioapic",
+ .parent = TYPE_IOAPIC_COMMON,
+ .instance_size = sizeof(IOAPICCommonState),
+ .class_init = ioapic_class_init,
};
static void ioapic_register_devices(void)
{
- sysbus_register_withprop(&ioapic_info);
+ type_register_static(&ioapic_info);
}
device_init(ioapic_register_devices)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
new file mode 100644
index 0000000..f932700
--- /dev/null
+++ b/hw/ioapic_common.c
@@ -0,0 +1,121 @@
+/*
+ * IOAPIC emulation logic - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ * Copyright (c) 2009 Xiantao Zhang, Intel
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ioapic.h"
+#include "ioapic_internal.h"
+#include "sysbus.h"
+
+void ioapic_reset_common(DeviceState *dev)
+{
+ IOAPICCommonState *s = IOAPIC_COMMON(dev);
+ int i;
+
+ s->id = 0;
+ s->ioregsel = 0;
+ s->irr = 0;
+ for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+ s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
+ }
+}
+
+static void ioapic_dispatch_pre_save(void *opaque)
+{
+ IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+ IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+ if (info->pre_save) {
+ info->pre_save(s);
+ }
+}
+
+static int ioapic_dispatch_post_load(void *opaque, int version_id)
+{
+ IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+ IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+ if (info->post_load) {
+ info->post_load(s);
+ }
+ return 0;
+}
+
+static int ioapic_init_common(SysBusDevice *dev)
+{
+ IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
+ IOAPICCommonClass *info;
+ static int ioapic_no;
+
+ if (ioapic_no >= MAX_IOAPICS) {
+ return -1;
+ }
+
+ info = IOAPIC_COMMON_GET_CLASS(s);
+ info->init(s, ioapic_no);
+
+ sysbus_init_mmio(&s->busdev, &s->io_memory);
+ ioapic_no++;
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_ioapic_common = {
+ .name = "ioapic",
+ .version_id = 3,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_save = ioapic_dispatch_pre_save,
+ .post_load = ioapic_dispatch_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(id, IOAPICCommonState),
+ VMSTATE_UINT8(ioregsel, IOAPICCommonState),
+ VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
+ VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
+ VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void ioapic_common_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ sc->init = ioapic_init_common;
+ dc->vmsd = &vmstate_ioapic_common;
+ dc->no_user = 1;
+}
+
+static TypeInfo ioapic_common_type = {
+ .name = TYPE_IOAPIC_COMMON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IOAPICCommonState),
+ .class_size = sizeof(IOAPICCommonClass),
+ .class_init = ioapic_common_class_init,
+ .abstract = true,
+};
+
+static void register_devices(void)
+{
+ type_register_static(&ioapic_common_type);
+}
+
+device_init(register_devices);
+
diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h
new file mode 100644
index 0000000..e04c9f3
--- /dev/null
+++ b/hw/ioapic_internal.h
@@ -0,0 +1,102 @@
+/*
+ * IOAPIC emulation logic - internal interfaces
+ *
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ * Copyright (c) 2009 Xiantao Zhang, Intel
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_IOAPIC_INTERNAL_H
+#define QEMU_IOAPIC_INTERNAL_H
+
+#include "hw.h"
+#include "memory.h"
+#include "sysbus.h"
+
+#define MAX_IOAPICS 1
+
+#define IOAPIC_VERSION 0x11
+
+#define IOAPIC_LVT_DEST_SHIFT 56
+#define IOAPIC_LVT_MASKED_SHIFT 16
+#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15
+#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14
+#define IOAPIC_LVT_POLARITY_SHIFT 13
+#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12
+#define IOAPIC_LVT_DEST_MODE_SHIFT 11
+#define IOAPIC_LVT_DELIV_MODE_SHIFT 8
+
+#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT)
+#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
+
+#define IOAPIC_TRIGGER_EDGE 0
+#define IOAPIC_TRIGGER_LEVEL 1
+
+/*io{apic,sapic} delivery mode*/
+#define IOAPIC_DM_FIXED 0x0
+#define IOAPIC_DM_LOWEST_PRIORITY 0x1
+#define IOAPIC_DM_PMI 0x2
+#define IOAPIC_DM_NMI 0x4
+#define IOAPIC_DM_INIT 0x5
+#define IOAPIC_DM_SIPI 0x6
+#define IOAPIC_DM_EXTINT 0x7
+#define IOAPIC_DM_MASK 0x7
+
+#define IOAPIC_VECTOR_MASK 0xff
+
+#define IOAPIC_IOREGSEL 0x00
+#define IOAPIC_IOWIN 0x10
+
+#define IOAPIC_REG_ID 0x00
+#define IOAPIC_REG_VER 0x01
+#define IOAPIC_REG_ARB 0x02
+#define IOAPIC_REG_REDTBL_BASE 0x10
+#define IOAPIC_ID 0x00
+
+#define IOAPIC_ID_SHIFT 24
+#define IOAPIC_ID_MASK 0xf
+
+#define IOAPIC_VER_ENTRIES_SHIFT 16
+
+typedef struct IOAPICCommonState IOAPICCommonState;
+
+#define TYPE_IOAPIC_COMMON "ioapic-common"
+#define IOAPIC_COMMON(obj) \
+ OBJECT_CHECK(IOAPICCommonState, (obj), TYPE_IOAPIC_COMMON)
+#define IOAPIC_COMMON_CLASS(klass) \
+ OBJECT_CLASS_CHECK(IOAPICCommonClass, (klass), TYPE_IOAPIC_COMMON)
+#define IOAPIC_COMMON_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(IOAPICCommonClass, (obj), TYPE_IOAPIC_COMMON)
+
+typedef struct IOAPICCommonClass {
+ SysBusDeviceClass parent_class;
+ void (*init)(IOAPICCommonState *s, int instance_no);
+ void (*pre_save)(IOAPICCommonState *s);
+ void (*post_load)(IOAPICCommonState *s);
+} IOAPICCommonClass;
+
+struct IOAPICCommonState {
+ SysBusDevice busdev;
+ MemoryRegion io_memory;
+ uint8_t id;
+ uint8_t ioregsel;
+ uint32_t irr;
+ uint64_t ioredtbl[IOAPIC_NUM_PINS];
+};
+
+void ioapic_reset_common(DeviceState *dev);
+
+#endif /* !QEMU_IOAPIC_INTERNAL_H */
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index a6bfbb9..1c60123 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -80,7 +80,7 @@
static void ioh3420_reset(DeviceState *qdev)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *d = PCI_DEVICE(qdev);
msi_reset(d);
ioh3420_aer_vector_update(d);
pcie_cap_root_reset(d);
@@ -201,36 +201,45 @@
}
};
-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,
+static Property ioh3420_properties[] = {
+ DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+ DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+ DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+ DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+ port.br.dev.exp.aer_log.log_max,
+ PCIE_AER_LOG_MAX_DEFAULT),
+ DEFINE_PROP_END_OF_LIST(),
+};
- .is_express = 1,
- .is_bridge = 1,
- .config_write = ioh3420_write_config,
- .init = ioh3420_initfn,
- .exit = ioh3420_exitfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_IOH_EPORT,
- .revision = PCI_DEVICE_ID_IOH_REV,
+static void ioh3420_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- .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),
- DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
- port.br.dev.exp.aer_log.log_max,
- PCIE_AER_LOG_MAX_DEFAULT),
- DEFINE_PROP_END_OF_LIST(),
- }
+ k->is_express = 1;
+ k->is_bridge = 1;
+ k->config_write = ioh3420_write_config;
+ k->init = ioh3420_initfn;
+ k->exit = ioh3420_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_IOH_EPORT;
+ k->revision = PCI_DEVICE_ID_IOH_REV;
+ dc->desc = "Intel IOH device id 3420 PCIE Root Port";
+ dc->reset = ioh3420_reset;
+ dc->vmsd = &vmstate_ioh3420;
+ dc->props = ioh3420_properties;
+}
+
+static TypeInfo ioh3420_info = {
+ .name = "ioh3420",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIESlot),
+ .class_init = ioh3420_class_init,
};
static void ioh3420_register(void)
{
- pci_qdev_register(&ioh3420_info);
+ type_register_static(&ioh3420_info);
}
device_init(ioh3420_register);
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 5af790b..d03f828 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -110,22 +110,19 @@
portio_list_add(piolist, isabus->address_space_io, start);
}
-static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int isa_qdev_init(DeviceState *qdev)
{
- ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev);
- ISADeviceInfo *info = DO_UPCAST(ISADeviceInfo, qdev, base);
+ ISADevice *dev = ISA_DEVICE(qdev);
+ ISADeviceClass *klass = ISA_DEVICE_GET_CLASS(dev);
dev->isairq[0] = -1;
dev->isairq[1] = -1;
- return info->init(dev);
-}
+ if (klass->init) {
+ return klass->init(dev);
+ }
-void isa_qdev_register(ISADeviceInfo *info)
-{
- info->qdev.init = isa_qdev_init;
- info->qdev.bus_info = &isa_bus_info;
- qdev_register(&info->qdev);
+ return 0;
}
ISADevice *isa_create(ISABus *bus, const char *name)
@@ -137,7 +134,7 @@
name);
}
dev = qdev_create(&bus->qbus, name);
- return DO_UPCAST(ISADevice, qdev, dev);
+ return ISA_DEVICE(dev);
}
ISADevice *isa_try_create(ISABus *bus, const char *name)
@@ -149,7 +146,7 @@
name);
}
dev = qdev_try_create(&bus->qbus, name);
- return DO_UPCAST(ISADevice, qdev, dev);
+ return ISA_DEVICE(dev);
}
ISADevice *isa_create_simple(ISABus *bus, const char *name)
@@ -163,7 +160,7 @@
static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
{
- ISADevice *d = DO_UPCAST(ISADevice, qdev, dev);
+ ISADevice *d = ISA_DEVICE(dev);
if (d->isairq[1] != -1) {
monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
@@ -180,17 +177,43 @@
return 0;
}
-static SysBusDeviceInfo isabus_bridge_info = {
- .init = isabus_bridge_init,
- .qdev.name = "isabus-bridge",
- .qdev.fw_name = "isa",
- .qdev.size = sizeof(SysBusDevice),
- .qdev.no_user = 1,
+static void isabus_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = isabus_bridge_init;
+ dc->fw_name = "isa";
+ dc->no_user = 1;
+}
+
+static TypeInfo isabus_bridge_info = {
+ .name = "isabus-bridge",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = isabus_bridge_class_init,
+};
+
+static void isa_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = isa_qdev_init;
+ k->bus_info = &isa_bus_info;
+}
+
+static TypeInfo isa_device_type_info = {
+ .name = TYPE_ISA_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(ISADevice),
+ .abstract = true,
+ .class_size = sizeof(ISADeviceClass),
+ .class_init = isa_device_class_init,
};
static void isabus_register_devices(void)
{
- sysbus_register_withprop(&isabus_bridge_info);
+ type_register_static(&isabus_bridge_info);
+ type_register_static(&isa_device_type_info);
}
static char *isabus_get_fw_dev_path(DeviceState *dev)
diff --git a/hw/isa.h b/hw/isa.h
index b11a0be..40373fb 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -10,7 +10,19 @@
#define ISA_NUM_IRQS 16
typedef struct ISADevice ISADevice;
-typedef struct ISADeviceInfo ISADeviceInfo;
+
+#define TYPE_ISA_DEVICE "isa-device"
+#define ISA_DEVICE(obj) \
+ OBJECT_CHECK(ISADevice, (obj), TYPE_ISA_DEVICE)
+#define ISA_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(ISADeviceClass, (klass), TYPE_ISA_DEVICE)
+#define ISA_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(ISADeviceClass, (obj), TYPE_ISA_DEVICE)
+
+typedef struct ISADeviceClass {
+ DeviceClass parent_class;
+ int (*init)(ISADevice *dev);
+} ISADeviceClass;
struct ISABus {
BusState qbus;
@@ -25,17 +37,10 @@
int ioport_id;
};
-typedef int (*isa_qdev_initfn)(ISADevice *dev);
-struct ISADeviceInfo {
- DeviceInfo qdev;
- isa_qdev_initfn init;
-};
-
ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io);
void isa_bus_irqs(ISABus *bus, qemu_irq *irqs);
qemu_irq isa_get_irq(ISADevice *dev, int isairq);
void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
-void isa_qdev_register(ISADeviceInfo *info);
MemoryRegion *isa_address_space(ISADevice *dev);
ISADevice *isa_create(ISABus *bus, const char *name);
ISADevice *isa_try_create(ISABus *bus, const char *name);
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index bec2e0b..6f017d4 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -766,30 +766,41 @@
return 0;
}
-static PCIDeviceInfo ivshmem_info = {
- .qdev.name = "ivshmem",
- .qdev.size = sizeof(IVShmemState),
- .qdev.reset = ivshmem_reset,
- .init = pci_ivshmem_init,
- .exit = pci_ivshmem_uninit,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = 0x1110,
- .class_id = PCI_CLASS_MEMORY_RAM,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
- DEFINE_PROP_STRING("size", IVShmemState, sizearg),
- DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
- DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
- DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
- DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
- DEFINE_PROP_STRING("role", IVShmemState, role),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ivshmem_properties[] = {
+ DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
+ DEFINE_PROP_STRING("size", IVShmemState, sizearg),
+ DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
+ DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
+ DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
+ DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
+ DEFINE_PROP_STRING("role", IVShmemState, role),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ivshmem_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_ivshmem_init;
+ k->exit = pci_ivshmem_uninit;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = 0x1110;
+ k->class_id = PCI_CLASS_MEMORY_RAM;
+ dc->reset = ivshmem_reset;
+ dc->props = ivshmem_properties;
+}
+
+static TypeInfo ivshmem_info = {
+ .name = "ivshmem",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(IVShmemState),
+ .class_init = ivshmem_class_init,
};
static void ivshmem_register_devices(void)
{
- pci_qdev_register(&ivshmem_info);
+ type_register_static(&ivshmem_info);
}
device_init(ivshmem_register_devices)
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
new file mode 100644
index 0000000..dfc2ab3
--- /dev/null
+++ b/hw/kvm/apic.c
@@ -0,0 +1,147 @@
+/*
+ * KVM in-kernel APIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
+ int reg_id, uint32_t val)
+{
+ *((uint32_t *)(kapic->regs + (reg_id << 4))) = val;
+}
+
+static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic,
+ int reg_id)
+{
+ return *((uint32_t *)(kapic->regs + (reg_id << 4)));
+}
+
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+ int i;
+
+ memset(kapic, 0, sizeof(kapic));
+ kvm_apic_set_reg(kapic, 0x2, s->id << 24);
+ kvm_apic_set_reg(kapic, 0x8, s->tpr);
+ kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
+ kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
+ kvm_apic_set_reg(kapic, 0xf, s->spurious_vec);
+ for (i = 0; i < 8; i++) {
+ kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]);
+ kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]);
+ kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]);
+ }
+ kvm_apic_set_reg(kapic, 0x28, s->esr);
+ kvm_apic_set_reg(kapic, 0x30, s->icr[0]);
+ kvm_apic_set_reg(kapic, 0x31, s->icr[1]);
+ for (i = 0; i < APIC_LVT_NB; i++) {
+ kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]);
+ }
+ kvm_apic_set_reg(kapic, 0x38, s->initial_count);
+ kvm_apic_set_reg(kapic, 0x3e, s->divide_conf);
+}
+
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+ int i, v;
+
+ s->id = kvm_apic_get_reg(kapic, 0x2) >> 24;
+ s->tpr = kvm_apic_get_reg(kapic, 0x8);
+ s->arb_id = kvm_apic_get_reg(kapic, 0x9);
+ s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24;
+ s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28;
+ s->spurious_vec = kvm_apic_get_reg(kapic, 0xf);
+ for (i = 0; i < 8; i++) {
+ s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i);
+ s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i);
+ s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i);
+ }
+ s->esr = kvm_apic_get_reg(kapic, 0x28);
+ s->icr[0] = kvm_apic_get_reg(kapic, 0x30);
+ s->icr[1] = kvm_apic_get_reg(kapic, 0x31);
+ for (i = 0; i < APIC_LVT_NB; i++) {
+ s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i);
+ }
+ s->initial_count = kvm_apic_get_reg(kapic, 0x38);
+ s->divide_conf = kvm_apic_get_reg(kapic, 0x3e);
+
+ v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+ s->count_shift = (v + 1) & 7;
+
+ s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+ apic_next_timer(s, s->initial_count_load_time);
+}
+
+static void kvm_apic_set_base(APICCommonState *s, uint64_t val)
+{
+ s->apicbase = val;
+}
+
+static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+ s->tpr = (val & 0x0f) << 4;
+}
+
+static void do_inject_external_nmi(void *data)
+{
+ APICCommonState *s = data;
+ CPUState *env = s->cpu_env;
+ uint32_t lvt;
+ int ret;
+
+ cpu_synchronize_state(env);
+
+ lvt = s->lvt[APIC_LVT_LINT1];
+ if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
+ ret = kvm_vcpu_ioctl(env, KVM_NMI);
+ if (ret < 0) {
+ fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
+ strerror(-ret));
+ }
+ }
+}
+
+static void kvm_apic_external_nmi(APICCommonState *s)
+{
+ run_on_cpu(s->cpu_env, do_inject_external_nmi, s);
+}
+
+static void kvm_apic_init(APICCommonState *s)
+{
+ memory_region_init_reservation(&s->io_memory, "kvm-apic-msi",
+ MSI_SPACE_SIZE);
+}
+
+static void kvm_apic_class_init(ObjectClass *klass, void *data)
+{
+ APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+ k->init = kvm_apic_init;
+ k->set_base = kvm_apic_set_base;
+ k->set_tpr = kvm_apic_set_tpr;
+ k->external_nmi = kvm_apic_external_nmi;
+}
+
+static TypeInfo kvm_apic_info = {
+ .name = "kvm-apic",
+ .parent = TYPE_APIC_COMMON,
+ .instance_size = sizeof(APICCommonState),
+ .class_init = kvm_apic_class_init,
+};
+
+static void kvm_apic_register_device(void)
+{
+ type_register_static(&kvm_apic_info);
+}
+
+device_init(kvm_apic_register_device)
diff --git a/hw/kvmclock.c b/hw/kvm/clock.c
similarity index 83%
rename from hw/kvmclock.c
rename to hw/kvm/clock.c
index 3b9fb20..d5a5386 100644
--- a/hw/kvmclock.c
+++ b/hw/kvm/clock.c
@@ -15,9 +15,9 @@
#include "qemu-common.h"
#include "sysemu.h"
-#include "sysbus.h"
#include "kvm.h"
-#include "kvmclock.h"
+#include "hw/sysbus.h"
+#include "hw/kvm/clock.h"
#include <linux/kvm.h>
#include <linux/kvm_para.h>
@@ -92,12 +92,21 @@
}
};
-static SysBusDeviceInfo kvmclock_info = {
- .qdev.name = "kvmclock",
- .qdev.size = sizeof(KVMClockState),
- .qdev.vmsd = &kvmclock_vmsd,
- .qdev.no_user = 1,
- .init = kvmclock_init,
+static void kvmclock_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = kvmclock_init;
+ dc->no_user = 1;
+ dc->vmsd = &kvmclock_vmsd;
+}
+
+static TypeInfo kvmclock_info = {
+ .name = "kvmclock",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMClockState),
+ .class_init = kvmclock_class_init,
};
/* Note: Must be called after VCPU initialization. */
@@ -113,7 +122,7 @@
static void kvmclock_register_device(void)
{
if (kvm_enabled()) {
- sysbus_register_withprop(&kvmclock_info);
+ type_register_static(&kvmclock_info);
}
}
diff --git a/hw/kvmclock.h b/hw/kvm/clock.h
similarity index 100%
rename from hw/kvmclock.h
rename to hw/kvm/clock.h
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
new file mode 100644
index 0000000..14bd427
--- /dev/null
+++ b/hw/kvm/i8259.c
@@ -0,0 +1,138 @@
+/*
+ * KVM in-kernel PIC (i8259) support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/i8259_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+static void kvm_pic_get(PICCommonState *s)
+{
+ struct kvm_irqchip chip;
+ struct kvm_pic_state *kpic;
+ int ret;
+
+ chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+ abort();
+ }
+
+ kpic = &chip.chip.pic;
+
+ s->last_irr = kpic->last_irr;
+ s->irr = kpic->irr;
+ s->imr = kpic->imr;
+ s->isr = kpic->isr;
+ s->priority_add = kpic->priority_add;
+ s->irq_base = kpic->irq_base;
+ s->read_reg_select = kpic->read_reg_select;
+ s->poll = kpic->poll;
+ s->special_mask = kpic->special_mask;
+ s->init_state = kpic->init_state;
+ s->auto_eoi = kpic->auto_eoi;
+ s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
+ s->special_fully_nested_mode = kpic->special_fully_nested_mode;
+ s->init4 = kpic->init4;
+ s->elcr = kpic->elcr;
+ s->elcr_mask = kpic->elcr_mask;
+}
+
+static void kvm_pic_put(PICCommonState *s)
+{
+ struct kvm_irqchip chip;
+ struct kvm_pic_state *kpic;
+ int ret;
+
+ chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+
+ kpic = &chip.chip.pic;
+
+ kpic->last_irr = s->last_irr;
+ kpic->irr = s->irr;
+ kpic->imr = s->imr;
+ kpic->isr = s->isr;
+ kpic->priority_add = s->priority_add;
+ kpic->irq_base = s->irq_base;
+ kpic->read_reg_select = s->read_reg_select;
+ kpic->poll = s->poll;
+ kpic->special_mask = s->special_mask;
+ kpic->init_state = s->init_state;
+ kpic->auto_eoi = s->auto_eoi;
+ kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
+ kpic->special_fully_nested_mode = s->special_fully_nested_mode;
+ kpic->init4 = s->init4;
+ kpic->elcr = s->elcr;
+ kpic->elcr_mask = s->elcr_mask;
+
+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+ abort();
+ }
+}
+
+static void kvm_pic_reset(DeviceState *dev)
+{
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
+
+ pic_reset_common(s);
+ s->elcr = 0;
+
+ kvm_pic_put(s);
+}
+
+static void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+ int delivered;
+
+ delivered = kvm_irqchip_set_irq(kvm_state, irq, level);
+ apic_report_irq_delivered(delivered);
+}
+
+static void kvm_pic_init(PICCommonState *s)
+{
+ memory_region_init_reservation(&s->base_io, "kvm-pic", 2);
+ memory_region_init_reservation(&s->elcr_io, "kvm-elcr", 1);
+}
+
+qemu_irq *kvm_i8259_init(ISABus *bus)
+{
+ i8259_init_chip("kvm-i8259", bus, true);
+ i8259_init_chip("kvm-i8259", bus, false);
+
+ return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
+}
+
+static void kvm_i8259_class_init(ObjectClass *klass, void *data)
+{
+ PICCommonClass *k = PIC_COMMON_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = kvm_pic_reset;
+ k->init = kvm_pic_init;
+ k->pre_save = kvm_pic_get;
+ k->post_load = kvm_pic_put;
+}
+
+static TypeInfo kvm_i8259_info = {
+ .name = "kvm-i8259",
+ .parent = TYPE_PIC_COMMON,
+ .instance_size = sizeof(PICCommonState),
+ .class_init = kvm_i8259_class_init,
+};
+
+static void kvm_pic_register(void)
+{
+ type_register_static(&kvm_i8259_info);
+}
+
+device_init(kvm_pic_register)
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
new file mode 100644
index 0000000..b316933
--- /dev/null
+++ b/hw/kvm/ioapic.c
@@ -0,0 +1,125 @@
+/*
+ * KVM in-kernel IOPIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/pc.h"
+#include "hw/ioapic_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMIOAPICState KVMIOAPICState;
+
+struct KVMIOAPICState {
+ IOAPICCommonState ioapic;
+ uint32_t kvm_gsi_base;
+};
+
+static void kvm_ioapic_get(IOAPICCommonState *s)
+{
+ struct kvm_irqchip chip;
+ struct kvm_ioapic_state *kioapic;
+ int ret, i;
+
+ chip.chip_id = KVM_IRQCHIP_IOAPIC;
+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+ abort();
+ }
+
+ kioapic = &chip.chip.ioapic;
+
+ s->id = kioapic->id;
+ s->ioregsel = kioapic->ioregsel;
+ s->irr = kioapic->irr;
+ for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+ s->ioredtbl[i] = kioapic->redirtbl[i].bits;
+ }
+}
+
+static void kvm_ioapic_put(IOAPICCommonState *s)
+{
+ struct kvm_irqchip chip;
+ struct kvm_ioapic_state *kioapic;
+ int ret, i;
+
+ chip.chip_id = KVM_IRQCHIP_IOAPIC;
+ kioapic = &chip.chip.ioapic;
+
+ kioapic->id = s->id;
+ kioapic->ioregsel = s->ioregsel;
+ kioapic->base_address = s->busdev.mmio[0].addr;
+ kioapic->irr = s->irr;
+ for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+ kioapic->redirtbl[i].bits = s->ioredtbl[i];
+ }
+
+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+ abort();
+ }
+}
+
+static void kvm_ioapic_reset(DeviceState *dev)
+{
+ IOAPICCommonState *s = DO_UPCAST(IOAPICCommonState, busdev.qdev, dev);
+
+ ioapic_reset_common(dev);
+ kvm_ioapic_put(s);
+}
+
+static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
+{
+ KVMIOAPICState *s = opaque;
+ int delivered;
+
+ delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
+ apic_report_irq_delivered(delivered);
+}
+
+static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
+{
+ memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000);
+
+ qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
+}
+
+static Property kvm_ioapic_properties[] = {
+ DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
+{
+ IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = kvm_ioapic_init;
+ k->pre_save = kvm_ioapic_get;
+ k->post_load = kvm_ioapic_put;
+ dc->reset = kvm_ioapic_reset;
+ dc->props = kvm_ioapic_properties;
+}
+
+static TypeInfo kvm_ioapic_info = {
+ .name = "kvm-ioapic",
+ .parent = TYPE_IOAPIC_COMMON,
+ .instance_size = sizeof(KVMIOAPICState),
+ .class_init = kvm_ioapic_class_init,
+};
+
+static void kvm_ioapic_register_device(void)
+{
+ type_register_static(&kvm_ioapic_info);
+}
+
+device_init(kvm_ioapic_register_device)
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 8b83fe2..78777c7 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -140,17 +140,36 @@
};
typedef struct {
- enum tx_state state;
+ /* state is a tx_state but we can't put enums in VMStateDescriptions. */
+ uint32_t state;
uint32_t cmd_a;
uint32_t cmd_b;
- int buffer_size;
- int offset;
- int pad;
- int fifo_used;
- int len;
+ int32_t buffer_size;
+ int32_t offset;
+ int32_t pad;
+ int32_t fifo_used;
+ int32_t len;
uint8_t data[2048];
} LAN9118Packet;
+static const VMStateDescription vmstate_lan9118_packet = {
+ .name = "lan9118_packet",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(state, LAN9118Packet),
+ VMSTATE_UINT32(cmd_a, LAN9118Packet),
+ VMSTATE_UINT32(cmd_b, LAN9118Packet),
+ VMSTATE_INT32(buffer_size, LAN9118Packet),
+ VMSTATE_INT32(offset, LAN9118Packet),
+ VMSTATE_INT32(pad, LAN9118Packet),
+ VMSTATE_INT32(fifo_used, LAN9118Packet),
+ VMSTATE_INT32(len, LAN9118Packet),
+ VMSTATE_UINT8_ARRAY(data, LAN9118Packet, 2048),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
typedef struct {
SysBusDevice busdev;
NICState *nic;
@@ -190,34 +209,95 @@
uint32_t phy_int;
uint32_t phy_int_mask;
- int eeprom_writable;
+ int32_t eeprom_writable;
uint8_t eeprom[128];
- int tx_fifo_size;
+ int32_t tx_fifo_size;
LAN9118Packet *txp;
LAN9118Packet tx_packet;
- int tx_status_fifo_used;
- int tx_status_fifo_head;
+ int32_t tx_status_fifo_used;
+ int32_t tx_status_fifo_head;
uint32_t tx_status_fifo[512];
- int rx_status_fifo_size;
- int rx_status_fifo_used;
- int rx_status_fifo_head;
+ int32_t rx_status_fifo_size;
+ int32_t rx_status_fifo_used;
+ int32_t rx_status_fifo_head;
uint32_t rx_status_fifo[896];
- int rx_fifo_size;
- int rx_fifo_used;
- int rx_fifo_head;
+ int32_t rx_fifo_size;
+ int32_t rx_fifo_used;
+ int32_t rx_fifo_head;
uint32_t rx_fifo[3360];
- int rx_packet_size_head;
- int rx_packet_size_tail;
- int rx_packet_size[1024];
+ int32_t rx_packet_size_head;
+ int32_t rx_packet_size_tail;
+ int32_t rx_packet_size[1024];
- int rxp_offset;
- int rxp_size;
- int rxp_pad;
+ int32_t rxp_offset;
+ int32_t rxp_size;
+ int32_t rxp_pad;
} lan9118_state;
+static const VMStateDescription vmstate_lan9118 = {
+ .name = "lan9118",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PTIMER(timer, lan9118_state),
+ VMSTATE_UINT32(irq_cfg, lan9118_state),
+ VMSTATE_UINT32(int_sts, lan9118_state),
+ VMSTATE_UINT32(int_en, lan9118_state),
+ VMSTATE_UINT32(fifo_int, lan9118_state),
+ VMSTATE_UINT32(rx_cfg, lan9118_state),
+ VMSTATE_UINT32(tx_cfg, lan9118_state),
+ VMSTATE_UINT32(hw_cfg, lan9118_state),
+ VMSTATE_UINT32(pmt_ctrl, lan9118_state),
+ VMSTATE_UINT32(gpio_cfg, lan9118_state),
+ VMSTATE_UINT32(gpt_cfg, lan9118_state),
+ VMSTATE_UINT32(word_swap, lan9118_state),
+ VMSTATE_UINT32(free_timer_start, lan9118_state),
+ VMSTATE_UINT32(mac_cmd, lan9118_state),
+ VMSTATE_UINT32(mac_data, lan9118_state),
+ VMSTATE_UINT32(afc_cfg, lan9118_state),
+ VMSTATE_UINT32(e2p_cmd, lan9118_state),
+ VMSTATE_UINT32(e2p_data, lan9118_state),
+ VMSTATE_UINT32(mac_cr, lan9118_state),
+ VMSTATE_UINT32(mac_hashh, lan9118_state),
+ VMSTATE_UINT32(mac_hashl, lan9118_state),
+ VMSTATE_UINT32(mac_mii_acc, lan9118_state),
+ VMSTATE_UINT32(mac_mii_data, lan9118_state),
+ VMSTATE_UINT32(mac_flow, lan9118_state),
+ VMSTATE_UINT32(phy_status, lan9118_state),
+ VMSTATE_UINT32(phy_control, lan9118_state),
+ VMSTATE_UINT32(phy_advertise, lan9118_state),
+ VMSTATE_UINT32(phy_int, lan9118_state),
+ VMSTATE_UINT32(phy_int_mask, lan9118_state),
+ VMSTATE_INT32(eeprom_writable, lan9118_state),
+ VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
+ VMSTATE_INT32(tx_fifo_size, lan9118_state),
+ /* txp always points at tx_packet so need not be saved */
+ VMSTATE_STRUCT(tx_packet, lan9118_state, 0,
+ vmstate_lan9118_packet, LAN9118Packet),
+ VMSTATE_INT32(tx_status_fifo_used, lan9118_state),
+ VMSTATE_INT32(tx_status_fifo_head, lan9118_state),
+ VMSTATE_UINT32_ARRAY(tx_status_fifo, lan9118_state, 512),
+ VMSTATE_INT32(rx_status_fifo_size, lan9118_state),
+ VMSTATE_INT32(rx_status_fifo_used, lan9118_state),
+ VMSTATE_INT32(rx_status_fifo_head, lan9118_state),
+ VMSTATE_UINT32_ARRAY(rx_status_fifo, lan9118_state, 896),
+ VMSTATE_INT32(rx_fifo_size, lan9118_state),
+ VMSTATE_INT32(rx_fifo_used, lan9118_state),
+ VMSTATE_INT32(rx_fifo_head, lan9118_state),
+ VMSTATE_UINT32_ARRAY(rx_fifo, lan9118_state, 3360),
+ VMSTATE_INT32(rx_packet_size_head, lan9118_state),
+ VMSTATE_INT32(rx_packet_size_tail, lan9118_state),
+ VMSTATE_INT32_ARRAY(rx_packet_size, lan9118_state, 1024),
+ VMSTATE_INT32(rxp_offset, lan9118_state),
+ VMSTATE_INT32(rxp_size, lan9118_state),
+ VMSTATE_INT32(rxp_pad, lan9118_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void lan9118_update(lan9118_state *s)
{
int level;
@@ -1141,7 +1221,7 @@
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_lan9118_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
s->eeprom[0] = 0xa5;
for (i = 0; i < 6; i++) {
@@ -1155,24 +1235,35 @@
ptimer_set_freq(s->timer, 10000);
ptimer_set_limit(s->timer, 0xffff, 1);
- /* ??? Save/restore. */
return 0;
}
-static SysBusDeviceInfo lan9118_info = {
- .init = lan9118_init1,
- .qdev.name = "lan9118",
- .qdev.size = sizeof(lan9118_state),
- .qdev.reset = lan9118_reset,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(lan9118_state, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property lan9118_properties[] = {
+ DEFINE_NIC_PROPERTIES(lan9118_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lan9118_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lan9118_init1;
+ dc->reset = lan9118_reset;
+ dc->props = lan9118_properties;
+ dc->vmsd = &vmstate_lan9118;
+}
+
+static TypeInfo lan9118_info = {
+ .name = "lan9118",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(lan9118_state),
+ .class_init = lan9118_class_init,
};
static void lan9118_register_devices(void)
{
- sysbus_register_withprop(&lan9118_info);
+ type_register_static(&lan9118_info);
}
/* Legacy helper function. Should go away when machine config files are
diff --git a/hw/lance.c b/hw/lance.c
index 7164700..519720b 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -137,22 +137,33 @@
pcnet_h_reset(&d->state);
}
-static SysBusDeviceInfo lance_info = {
- .init = lance_init,
- .qdev.name = "lance",
- .qdev.fw_name = "ethernet",
- .qdev.size = sizeof(SysBusPCNetState),
- .qdev.reset = lance_reset,
- .qdev.vmsd = &vmstate_lance,
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
- DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property lance_properties[] = {
+ DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
+ DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lance_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lance_init;
+ dc->fw_name = "ethernet";
+ dc->reset = lance_reset;
+ dc->vmsd = &vmstate_lance;
+ dc->props = lance_properties;
+}
+
+static TypeInfo lance_info = {
+ .name = "lance",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusPCNetState),
+ .class_init = lance_class_init,
};
static void lance_register_devices(void)
{
- sysbus_register_withprop(&lance_info);
+ type_register_static(&lance_info);
}
device_init(lance_register_devices)
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
index 5454aa4..38dd282 100644
--- a/hw/lm32_juart.c
+++ b/hw/lm32_juart.c
@@ -114,7 +114,7 @@
{
LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr) {
qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
}
@@ -134,17 +134,26 @@
}
};
-static SysBusDeviceInfo lm32_juart_info = {
- .init = lm32_juart_init,
- .qdev.name = "lm32-juart",
- .qdev.size = sizeof(LM32JuartState),
- .qdev.vmsd = &vmstate_lm32_juart,
- .qdev.reset = juart_reset,
+static void lm32_juart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_juart_init;
+ dc->reset = juart_reset;
+ dc->vmsd = &vmstate_lm32_juart;
+}
+
+static TypeInfo lm32_juart_info = {
+ .name = "lm32-juart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32JuartState),
+ .class_init = lm32_juart_class_init,
};
static void lm32_juart_register(void)
{
- sysbus_register_withprop(&lm32_juart_info);
+ type_register_static(&lm32_juart_info);
}
device_init(lm32_juart_register)
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
index 8dd0050..7be6d0d 100644
--- a/hw/lm32_pic.c
+++ b/hw/lm32_pic.c
@@ -174,17 +174,26 @@
}
};
-static SysBusDeviceInfo lm32_pic_info = {
- .init = lm32_pic_init,
- .qdev.name = "lm32-pic",
- .qdev.size = sizeof(LM32PicState),
- .qdev.vmsd = &vmstate_lm32_pic,
- .qdev.reset = pic_reset,
+static void lm32_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_pic_init;
+ dc->reset = pic_reset;
+ dc->vmsd = &vmstate_lm32_pic;
+}
+
+static TypeInfo lm32_pic_info = {
+ .name = "lm32-pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32PicState),
+ .class_init = lm32_pic_class_init,
};
static void lm32_pic_register(void)
{
- sysbus_register_withprop(&lm32_pic_info);
+ type_register_static(&lm32_pic_info);
}
device_init(lm32_pic_register)
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
index 83974ee..ba6f4ac 100644
--- a/hw/lm32_sys.c
+++ b/hw/lm32_sys.c
@@ -141,21 +141,32 @@
}
};
-static SysBusDeviceInfo lm32_sys_info = {
- .init = lm32_sys_init,
- .qdev.name = "lm32-sys",
- .qdev.size = sizeof(LM32SysState),
- .qdev.vmsd = &vmstate_lm32_sys,
- .qdev.reset = sys_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property lm32_sys_properties[] = {
+ DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_sys_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_sys_init;
+ dc->reset = sys_reset;
+ dc->vmsd = &vmstate_lm32_sys;
+ dc->props = lm32_sys_properties;
+}
+
+static TypeInfo lm32_sys_info = {
+ .name = "lm32-sys",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32SysState),
+ .class_init = lm32_sys_class_init,
};
static void lm32_sys_register(void)
{
- sysbus_register_withprop(&lm32_sys_info);
+ type_register_static(&lm32_sys_info);
}
device_init(lm32_sys_register)
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
index 115e1e9..3cb4e0a 100644
--- a/hw/lm32_timer.c
+++ b/hw/lm32_timer.c
@@ -199,23 +199,32 @@
}
};
-static SysBusDeviceInfo lm32_timer_info = {
- .init = lm32_timer_init,
- .qdev.name = "lm32-timer",
- .qdev.size = sizeof(LM32TimerState),
- .qdev.vmsd = &vmstate_lm32_timer,
- .qdev.reset = timer_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32(
- "frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY
- ),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property lm32_timer_properties[] = {
+ DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_timer_init;
+ dc->reset = timer_reset;
+ dc->vmsd = &vmstate_lm32_timer;
+ dc->props = lm32_timer_properties;
+}
+
+static TypeInfo lm32_timer_info = {
+ .name = "lm32-timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32TimerState),
+ .class_init = lm32_timer_class_init,
};
static void lm32_timer_register(void)
{
- sysbus_register_withprop(&lm32_timer_info);
+ type_register_static(&lm32_timer_info);
}
device_init(lm32_timer_register)
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
index d013abd..630ccb7 100644
--- a/hw/lm32_uart.c
+++ b/hw/lm32_uart.c
@@ -252,7 +252,7 @@
memory_region_init_io(&s->iomem, &uart_ops, s, "uart", R_MAX * 4);
sysbus_init_mmio(dev, &s->iomem);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr) {
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
}
@@ -271,17 +271,26 @@
}
};
-static SysBusDeviceInfo lm32_uart_info = {
- .init = lm32_uart_init,
- .qdev.name = "lm32-uart",
- .qdev.size = sizeof(LM32UartState),
- .qdev.vmsd = &vmstate_lm32_uart,
- .qdev.reset = uart_reset,
+static void lm32_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_uart_init;
+ dc->reset = uart_reset;
+ dc->vmsd = &vmstate_lm32_uart;
+}
+
+static TypeInfo lm32_uart_info = {
+ .name = "lm32-uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32UartState),
+ .class_init = lm32_uart_class_init,
};
static void lm32_uart_register(void)
{
- sysbus_register_withprop(&lm32_uart_info);
+ type_register_static(&lm32_uart_info);
}
device_init(lm32_uart_register)
diff --git a/hw/lm832x.c b/hw/lm832x.c
index 992ce49..895d306 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -24,7 +24,7 @@
#include "console.h"
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
uint8_t i2c_dir;
uint8_t i2c_cycle;
uint8_t reg;
@@ -378,7 +378,7 @@
}
}
-static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event)
+static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
{
LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
@@ -394,14 +394,14 @@
}
}
-static int lm_i2c_rx(i2c_slave *i2c)
+static int lm_i2c_rx(I2CSlave *i2c)
{
LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
}
-static int lm_i2c_tx(i2c_slave *i2c, uint8_t data)
+static int lm_i2c_tx(I2CSlave *i2c, uint8_t data)
{
LM823KbdState *s = (LM823KbdState *) i2c;
@@ -458,7 +458,7 @@
};
-static int lm8323_init(i2c_slave *i2c)
+static int lm8323_init(I2CSlave *i2c)
{
LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
@@ -494,19 +494,28 @@
lm_kbd_irq_update(s);
}
-static I2CSlaveInfo lm8323_info = {
- .qdev.name = "lm8323",
- .qdev.size = sizeof(LM823KbdState),
- .qdev.vmsd = &vmstate_lm_kbd,
- .init = lm8323_init,
- .event = lm_i2c_event,
- .recv = lm_i2c_rx,
- .send = lm_i2c_tx
+static void lm8323_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = lm8323_init;
+ k->event = lm_i2c_event;
+ k->recv = lm_i2c_rx;
+ k->send = lm_i2c_tx;
+ dc->vmsd = &vmstate_lm_kbd;
+}
+
+static TypeInfo lm8323_info = {
+ .name = "lm8323",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(LM823KbdState),
+ .class_init = lm8323_class_init,
};
static void lm832x_register_devices(void)
{
- i2c_register_slave(&lm8323_info);
+ type_register_static(&lm8323_info);
}
device_init(lm832x_register_devices)
diff --git a/hw/loader.c b/hw/loader.c
index 446b628..415cdce 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -108,8 +108,12 @@
int size;
size = get_image_size(filename);
- if (size > 0)
+ if (size > max_sz) {
+ return -1;
+ }
+ if (size > 0) {
rom_add_file_fixed(filename, addr, -1);
+ }
return size;
}
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 0d3a101..9a7ffe3 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -1681,7 +1681,7 @@
DeviceState *dev;
QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
- dev->info->reset(dev);
+ device_reset(dev);
}
s->sstat0 |= LSI_SSTAT0_RST;
lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
@@ -2120,23 +2120,31 @@
return 0;
}
-static PCIDeviceInfo lsi_info = {
- .qdev.name = "lsi53c895a",
- .qdev.alias = "lsi",
- .qdev.size = sizeof(LSIState),
- .qdev.reset = lsi_scsi_reset,
- .qdev.vmsd = &vmstate_lsi_scsi,
- .init = lsi_scsi_init,
- .exit = lsi_scsi_uninit,
- .vendor_id = PCI_VENDOR_ID_LSI_LOGIC,
- .device_id = PCI_DEVICE_ID_LSI_53C895A,
- .class_id = PCI_CLASS_STORAGE_SCSI,
- .subsystem_id = 0x1000,
+static void lsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = lsi_scsi_init;
+ k->exit = lsi_scsi_uninit;
+ k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+ k->device_id = PCI_DEVICE_ID_LSI_53C895A;
+ k->class_id = PCI_CLASS_STORAGE_SCSI;
+ k->subsystem_id = 0x1000;
+ dc->reset = lsi_scsi_reset;
+ dc->vmsd = &vmstate_lsi_scsi;
+}
+
+static TypeInfo lsi_info = {
+ .name = "lsi53c895a",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(LSIState),
+ .class_init = lsi_class_init,
};
static void lsi53c895a_register_devices(void)
{
- pci_qdev_register(&lsi_info);
+ type_register_static(&lsi_info);
}
device_init(lsi53c895a_register_devices);
diff --git a/hw/m48t59.c b/hw/m48t59.c
index c043996..c35867d 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -126,7 +126,7 @@
/* Repeat once a second */
next_time = 1;
}
- qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(vm_clock) +
+ qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(rtc_clock) +
next_time * 1000);
qemu_set_irq(NVRAM->IRQ, 0);
}
@@ -687,7 +687,7 @@
{
s->buffer = g_malloc0(s->size);
if (s->type == 59) {
- s->alrm_timer = qemu_new_timer_ns(vm_clock, &alarm_cb, s);
+ s->alrm_timer = qemu_new_timer_ns(rtc_clock, &alarm_cb, s);
s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, s);
}
qemu_get_timedate(&s->alarm, 0);
@@ -720,37 +720,58 @@
return 0;
}
-static ISADeviceInfo m48t59_isa_info = {
- .init = m48t59_init_isa1,
- .qdev.name = "m48t59_isa",
- .qdev.size = sizeof(M48t59ISAState),
- .qdev.reset = m48t59_reset_isa,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", M48t59ISAState, state.size, -1),
- DEFINE_PROP_UINT32("type", M48t59ISAState, state.type, -1),
- DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property m48t59_isa_properties[] = {
+ DEFINE_PROP_UINT32("size", M48t59ISAState, state.size, -1),
+ DEFINE_PROP_UINT32("type", M48t59ISAState, state.type, -1),
+ DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo m48t59_info = {
- .init = m48t59_init1,
- .qdev.name = "m48t59",
- .qdev.size = sizeof(M48t59SysBusState),
- .qdev.reset = m48t59_reset_sysbus,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", M48t59SysBusState, state.size, -1),
- DEFINE_PROP_UINT32("type", M48t59SysBusState, state.type, -1),
- DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static void m48t59_init_class_isa1(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = m48t59_init_isa1;
+ dc->no_user = 1;
+ dc->reset = m48t59_reset_isa;
+ dc->props = m48t59_isa_properties;
+}
+
+static TypeInfo m48t59_isa_info = {
+ .name = "m48t59_isa",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(M48t59ISAState),
+ .class_init = m48t59_init_class_isa1,
+};
+
+static Property m48t59_properties[] = {
+ DEFINE_PROP_UINT32("size", M48t59SysBusState, state.size, -1),
+ DEFINE_PROP_UINT32("type", M48t59SysBusState, state.type, -1),
+ DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void m48t59_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = m48t59_init1;
+ dc->reset = m48t59_reset_sysbus;
+ dc->props = m48t59_properties;
+}
+
+static TypeInfo m48t59_info = {
+ .name = "m48t59",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(M48t59SysBusState),
+ .class_init = m48t59_class_init,
};
static void m48t59_register_devices(void)
{
- sysbus_register_withprop(&m48t59_info);
- isa_qdev_register(&m48t59_isa_info);
+ type_register_static(&m48t59_info);
+ type_register_static(&m48t59_isa_info);
}
device_init(m48t59_register_devices)
diff --git a/hw/macio.c b/hw/macio.c
index cc6ae40..3d648e9 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -27,8 +27,9 @@
#include "pci.h"
#include "escc.h"
-typedef struct macio_state_t macio_state_t;
-struct macio_state_t {
+typedef struct MacIOState
+{
+ PCIDevice parent;
int is_oldworld;
MemoryRegion bar;
MemoryRegion *pic_mem;
@@ -38,9 +39,9 @@
void *nvram;
int nb_ide;
MemoryRegion *ide_mem[4];
-};
+} MacIOState;
-static void macio_bar_setup(macio_state_t *macio_state)
+static void macio_bar_setup(MacIOState *macio_state)
{
int i;
MemoryRegion *bar = &macio_state->bar;
@@ -74,6 +75,35 @@
macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000);
}
+static int macio_initfn(PCIDevice *d)
+{
+ d->config[0x3d] = 0x01; // interrupt on pin 1
+ return 0;
+}
+
+static void macio_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = macio_initfn;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->class_id = PCI_CLASS_OTHERS << 8;
+}
+
+static TypeInfo macio_info = {
+ .name = "macio",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(MacIOState),
+ .class_init = macio_class_init,
+};
+
+static void macio_register(void)
+{
+ type_register_static(&macio_info);
+}
+
+device_init(macio_register);
+
void macio_init (PCIBus *bus, int device_id, int is_oldworld,
MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
MemoryRegion *cuda_mem, void *nvram,
@@ -81,13 +111,12 @@
MemoryRegion *escc_mem)
{
PCIDevice *d;
- macio_state_t *macio_state;
+ MacIOState *macio_state;
int i;
- d = pci_register_device(bus, "macio",
- sizeof(PCIDevice) + sizeof(macio_state_t),
- -1, NULL, NULL);
- macio_state = (macio_state_t *)(d + 1);
+ d = pci_create_simple(bus, -1, "macio");
+
+ macio_state = DO_UPCAST(MacIOState, parent, d);
macio_state->is_oldworld = is_oldworld;
macio_state->pic_mem = pic_mem;
macio_state->dbdma_mem = dbdma_mem;
@@ -104,11 +133,7 @@
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
- pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
pci_config_set_device_id(d->config, device_id);
- pci_config_set_class(d->config, PCI_CLASS_OTHERS << 8);
-
- d->config[0x3d] = 0x01; // interrupt on pin 1
macio_bar_setup(macio_state);
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar);
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 0cd8410..b628f17 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -50,7 +50,7 @@
uint32_t play_pos;
uint32_t last_free;
uint32_t clock_div;
- DeviceState *wm;
+ void *wm;
} mv88w8618_audio_state;
static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
@@ -272,25 +272,32 @@
}
};
-static SysBusDeviceInfo mv88w8618_audio_info = {
- .init = mv88w8618_audio_init,
- .qdev.name = "mv88w8618_audio",
- .qdev.size = sizeof(mv88w8618_audio_state),
- .qdev.reset = mv88w8618_audio_reset,
- .qdev.vmsd = &mv88w8618_audio_vmsd,
- .qdev.props = (Property[]) {
- {
- .name = "wm8750",
- .info = &qdev_prop_ptr,
- .offset = offsetof(mv88w8618_audio_state, wm),
- },
- {/* end of list */}
- }
+static Property mv88w8618_audio_properties[] = {
+ DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
+ {/* end of list */},
+};
+
+static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_audio_init;
+ dc->reset = mv88w8618_audio_reset;
+ dc->vmsd = &mv88w8618_audio_vmsd;
+ dc->props = mv88w8618_audio_properties;
+}
+
+static TypeInfo mv88w8618_audio_info = {
+ .name = "mv88w8618_audio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_audio_state),
+ .class_init = mv88w8618_audio_class_init,
};
static void mv88w8618_register_devices(void)
{
- sysbus_register_withprop(&mv88w8618_audio_info);
+ type_register_static(&mv88w8618_audio_info);
}
device_init(mv88w8618_register_devices)
diff --git a/hw/max111x.c b/hw/max111x.c
index fc79814..9d61aa9 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -153,24 +153,40 @@
s->input[line] = value;
}
-static SSISlaveInfo max1110_info = {
- .qdev.name = "max1110",
- .qdev.size = sizeof(MAX111xState),
- .init = max1110_init,
- .transfer = max111x_transfer
+static void max1110_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = max1110_init;
+ k->transfer = max111x_transfer;
+}
+
+static TypeInfo max1110_info = {
+ .name = "max1110",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(MAX111xState),
+ .class_init = max1110_class_init,
};
-static SSISlaveInfo max1111_info = {
- .qdev.name = "max1111",
- .qdev.size = sizeof(MAX111xState),
- .init = max1111_init,
- .transfer = max111x_transfer
+static void max1111_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = max1111_init;
+ k->transfer = max111x_transfer;
+}
+
+static TypeInfo max1111_info = {
+ .name = "max1111",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(MAX111xState),
+ .class_init = max1111_class_init,
};
static void max111x_register_devices(void)
{
- ssi_register_slave(&max1110_info);
- ssi_register_slave(&max1111_info);
+ type_register_static(&max1110_info);
+ type_register_static(&max1111_info);
}
device_init(max111x_register_devices)
diff --git a/hw/max7310.c b/hw/max7310.c
index c1bdb2e..3a6bb96 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -10,7 +10,7 @@
#include "i2c.h"
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
int i2c_command_byte;
int len;
@@ -33,7 +33,7 @@
s->command = 0x00;
}
-static int max7310_rx(i2c_slave *i2c)
+static int max7310_rx(I2CSlave *i2c)
{
MAX7310State *s = (MAX7310State *) i2c;
@@ -68,7 +68,7 @@
return 0xff;
}
-static int max7310_tx(i2c_slave *i2c, uint8_t data)
+static int max7310_tx(I2CSlave *i2c, uint8_t data)
{
MAX7310State *s = (MAX7310State *) i2c;
uint8_t diff;
@@ -123,7 +123,7 @@
return 0;
}
-static void max7310_event(i2c_slave *i2c, enum i2c_event event)
+static void max7310_event(I2CSlave *i2c, enum i2c_event event)
{
MAX7310State *s = (MAX7310State *) i2c;
s->len = 0;
@@ -175,7 +175,7 @@
/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
* but also accepts sequences that are not SMBus so return an I2C device. */
-static int max7310_init(i2c_slave *i2c)
+static int max7310_init(I2CSlave *i2c)
{
MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c);
@@ -185,20 +185,29 @@
return 0;
}
-static I2CSlaveInfo max7310_info = {
- .qdev.name = "max7310",
- .qdev.size = sizeof(MAX7310State),
- .qdev.vmsd = &vmstate_max7310,
- .qdev.reset = max7310_reset,
- .init = max7310_init,
- .event = max7310_event,
- .recv = max7310_rx,
- .send = max7310_tx
+static void max7310_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = max7310_init;
+ k->event = max7310_event;
+ k->recv = max7310_rx;
+ k->send = max7310_tx;
+ dc->reset = max7310_reset;
+ dc->vmsd = &vmstate_max7310;
+}
+
+static TypeInfo max7310_info = {
+ .name = "max7310",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(MAX7310State),
+ .class_init = max7310_class_init,
};
static void max7310_register_devices(void)
{
- i2c_register_slave(&max7310_info);
+ type_register_static(&max7310_info);
}
device_init(max7310_register_devices)
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 657fa10..4a43225 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -101,6 +101,7 @@
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
Notifier clock_reset_notifier;
+ LostTickPolicy lost_tick_policy;
} RTCState;
static void rtc_set_time(RTCState *s);
@@ -183,7 +184,7 @@
if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
#ifdef TARGET_I386
- if(rtc_td_hack) {
+ if (s->lost_tick_policy == LOST_TICK_SLEW) {
if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
s->irq_reinject_on_ack_count = 0;
apic_reset_irq_delivered();
@@ -544,7 +545,7 @@
RTCState *s = opaque;
if (version_id >= 2) {
- if (rtc_td_hack) {
+ if (s->lost_tick_policy == LOST_TICK_SLEW) {
rtc_coalesced_timer_update(s);
}
}
@@ -589,7 +590,7 @@
qemu_mod_timer(s->second_timer2, s->next_second_time);
rtc_timer_update(s, now);
#ifdef TARGET_I386
- if (rtc_td_hack) {
+ if (s->lost_tick_policy == LOST_TICK_SLEW) {
rtc_coalesced_timer_update(s);
}
#endif
@@ -605,8 +606,9 @@
qemu_irq_lower(s->irq);
#ifdef TARGET_I386
- if (rtc_td_hack)
- s->irq_coalesced = 0;
+ if (s->lost_tick_policy == LOST_TICK_SLEW) {
+ s->irq_coalesced = 0;
+ }
#endif
}
@@ -626,10 +628,10 @@
visit_type_int(v, &val, name, errp);
}
-static void rtc_get_date(DeviceState *dev, Visitor *v, void *opaque,
+static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
- ISADevice *isa = DO_UPCAST(ISADevice, qdev, dev);
+ ISADevice *isa = ISA_DEVICE(obj);
RTCState *s = DO_UPCAST(RTCState, dev, isa);
visit_start_struct(v, NULL, "struct tm", name, 0, errp);
@@ -654,12 +656,20 @@
rtc_set_date_from_host(dev);
- s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
#ifdef TARGET_I386
- if (rtc_td_hack)
+ switch (s->lost_tick_policy) {
+ case LOST_TICK_SLEW:
s->coalesced_timer =
qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
+ break;
+ case LOST_TICK_DISCARD:
+ break;
+ default:
+ return -EINVAL;
+ }
#endif
+
+ s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
@@ -676,8 +686,8 @@
qdev_set_legacy_instance_id(&dev->qdev, base, 2);
qemu_register_reset(rtc_reset, s);
- qdev_property_add(&s->dev.qdev, "date", "struct tm",
- rtc_get_date, NULL, NULL, s, NULL);
+ object_property_add(OBJECT(s), "date", "struct tm",
+ rtc_get_date, NULL, NULL, s, NULL);
return 0;
}
@@ -699,20 +709,32 @@
return dev;
}
-static ISADeviceInfo mc146818rtc_info = {
- .qdev.name = "mc146818rtc",
- .qdev.size = sizeof(RTCState),
- .qdev.no_user = 1,
- .qdev.vmsd = &vmstate_rtc,
- .init = rtc_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property mc146818rtc_properties[] = {
+ DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
+ DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState,
+ lost_tick_policy, LOST_TICK_DISCARD),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtc_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = rtc_initfn;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_rtc;
+ dc->props = mc146818rtc_properties;
+}
+
+static TypeInfo mc146818rtc_info = {
+ .name = "mc146818rtc",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(RTCState),
+ .class_init = rtc_class_initfn,
};
static void mc146818rtc_register(void)
{
- isa_qdev_register(&mc146818rtc_info);
+ type_register_static(&mc146818rtc_info);
}
device_init(mc146818rtc_register)
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
index e824a49..0881643 100644
--- a/hw/milkymist-ac97.c
+++ b/hw/milkymist-ac97.c
@@ -319,17 +319,26 @@
}
};
-static SysBusDeviceInfo milkymist_ac97_info = {
- .init = milkymist_ac97_init,
- .qdev.name = "milkymist-ac97",
- .qdev.size = sizeof(MilkymistAC97State),
- .qdev.vmsd = &vmstate_milkymist_ac97,
- .qdev.reset = milkymist_ac97_reset,
+static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_ac97_init;
+ dc->reset = milkymist_ac97_reset;
+ dc->vmsd = &vmstate_milkymist_ac97;
+}
+
+static TypeInfo milkymist_ac97_info = {
+ .name = "milkymist-ac97",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistAC97State),
+ .class_init = milkymist_ac97_class_init,
};
static void milkymist_ac97_register(void)
{
- sysbus_register_withprop(&milkymist_ac97_info);
+ type_register_static(&milkymist_ac97_info);
}
device_init(milkymist_ac97_register)
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
index be575c9..b5122af 100644
--- a/hw/milkymist-hpdmc.c
+++ b/hw/milkymist-hpdmc.c
@@ -145,17 +145,26 @@
}
};
-static SysBusDeviceInfo milkymist_hpdmc_info = {
- .init = milkymist_hpdmc_init,
- .qdev.name = "milkymist-hpdmc",
- .qdev.size = sizeof(MilkymistHpdmcState),
- .qdev.vmsd = &vmstate_milkymist_hpdmc,
- .qdev.reset = milkymist_hpdmc_reset,
+static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_hpdmc_init;
+ dc->reset = milkymist_hpdmc_reset;
+ dc->vmsd = &vmstate_milkymist_hpdmc;
+}
+
+static TypeInfo milkymist_hpdmc_info = {
+ .name = "milkymist-hpdmc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistHpdmcState),
+ .class_init = milkymist_hpdmc_class_init,
};
static void milkymist_hpdmc_register(void)
{
- sysbus_register_withprop(&milkymist_hpdmc_info);
+ type_register_static(&milkymist_hpdmc_info);
}
device_init(milkymist_hpdmc_register)
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
index 865a46c..3c1c68a 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -278,17 +278,26 @@
}
};
-static SysBusDeviceInfo milkymist_memcard_info = {
- .init = milkymist_memcard_init,
- .qdev.name = "milkymist-memcard",
- .qdev.size = sizeof(MilkymistMemcardState),
- .qdev.vmsd = &vmstate_milkymist_memcard,
- .qdev.reset = milkymist_memcard_reset,
+static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_memcard_init;
+ dc->reset = milkymist_memcard_reset;
+ dc->vmsd = &vmstate_milkymist_memcard;
+}
+
+static TypeInfo milkymist_memcard_info = {
+ .name = "milkymist-memcard",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistMemcardState),
+ .class_init = milkymist_memcard_class_init,
};
static void milkymist_memcard_register(void)
{
- sysbus_register_withprop(&milkymist_memcard_info);
+ type_register_static(&milkymist_memcard_info);
}
device_init(milkymist_memcard_register)
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index 7006d29..b9b553f 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -479,7 +479,7 @@
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
return 0;
@@ -516,24 +516,35 @@
}
};
-static SysBusDeviceInfo milkymist_minimac2_info = {
- .init = milkymist_minimac2_init,
- .qdev.name = "milkymist-minimac2",
- .qdev.size = sizeof(MilkymistMinimac2State),
- .qdev.vmsd = &vmstate_milkymist_minimac2,
- .qdev.reset = milkymist_minimac2_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State,
- buffers_base, 0),
- DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
- DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property milkymist_minimac2_properties[] = {
+ DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State,
+ buffers_base, 0),
+ DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
+ DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_minimac2_init;
+ dc->reset = milkymist_minimac2_reset;
+ dc->vmsd = &vmstate_milkymist_minimac2;
+ dc->props = milkymist_minimac2_properties;
+}
+
+static TypeInfo milkymist_minimac2_info = {
+ .name = "milkymist-minimac2",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistMinimac2State),
+ .class_init = milkymist_minimac2_class_init,
};
static void milkymist_minimac2_register(void)
{
- sysbus_register_withprop(&milkymist_minimac2_info);
+ type_register_static(&milkymist_minimac2_info);
}
device_init(milkymist_minimac2_register)
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
index dc92eb6..1b73a46 100644
--- a/hw/milkymist-pfpu.c
+++ b/hw/milkymist-pfpu.c
@@ -519,17 +519,26 @@
}
};
-static SysBusDeviceInfo milkymist_pfpu_info = {
- .init = milkymist_pfpu_init,
- .qdev.name = "milkymist-pfpu",
- .qdev.size = sizeof(MilkymistPFPUState),
- .qdev.vmsd = &vmstate_milkymist_pfpu,
- .qdev.reset = milkymist_pfpu_reset,
+static void milkymist_pfpu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_pfpu_init;
+ dc->reset = milkymist_pfpu_reset;
+ dc->vmsd = &vmstate_milkymist_pfpu;
+}
+
+static TypeInfo milkymist_pfpu_info = {
+ .name = "milkymist-pfpu",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistPFPUState),
+ .class_init = milkymist_pfpu_class_init,
};
static void milkymist_pfpu_register(void)
{
- sysbus_register_withprop(&milkymist_pfpu_info);
+ type_register_static(&milkymist_pfpu_info);
}
device_init(milkymist_pfpu_register)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 83bd1c4..5d496cb 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -297,32 +297,35 @@
}
};
-static SysBusDeviceInfo milkymist_softusb_info = {
- .init = milkymist_softusb_init,
- .qdev.name = "milkymist-softusb",
- .qdev.size = sizeof(MilkymistSoftUsbState),
- .qdev.vmsd = &vmstate_milkymist_softusb,
- .qdev.reset = milkymist_softusb_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32(
- "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
- ),
- DEFINE_PROP_UINT32(
- "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
- ),
- DEFINE_PROP_UINT32(
- "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
- ),
- DEFINE_PROP_UINT32(
- "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
- ),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property milkymist_softusb_properties[] = {
+ DEFINE_PROP_UINT32("pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000),
+ DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
+ DEFINE_PROP_UINT32("dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000),
+ DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_softusb_init;
+ dc->reset = milkymist_softusb_reset;
+ dc->vmsd = &vmstate_milkymist_softusb;
+ dc->props = milkymist_softusb_properties;
+}
+
+static TypeInfo milkymist_softusb_info = {
+ .name = "milkymist-softusb",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistSoftUsbState),
+ .class_init = milkymist_softusb_class_init,
};
static void milkymist_softusb_register(void)
{
- sysbus_register_withprop(&milkymist_softusb_info);
+ type_register_static(&milkymist_softusb_info);
}
device_init(milkymist_softusb_register)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index bd2a298..18171f6 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -292,28 +292,39 @@
}
};
-static SysBusDeviceInfo milkymist_sysctl_info = {
- .init = milkymist_sysctl_init,
- .qdev.name = "milkymist-sysctl",
- .qdev.size = sizeof(MilkymistSysctlState),
- .qdev.vmsd = &vmstate_milkymist_sysctl,
- .qdev.reset = milkymist_sysctl_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
- freq_hz, 80000000),
- DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
- capabilities, 0x00000000),
- DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
- systemid, 0x10014d31),
- DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
- strappings, 0x00000001),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property milkymist_sysctl_properties[] = {
+ DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
+ freq_hz, 80000000),
+ DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
+ capabilities, 0x00000000),
+ DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
+ systemid, 0x10014d31),
+ DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
+ strappings, 0x00000001),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_sysctl_init;
+ dc->reset = milkymist_sysctl_reset;
+ dc->vmsd = &vmstate_milkymist_sysctl;
+ dc->props = milkymist_sysctl_properties;
+}
+
+static TypeInfo milkymist_sysctl_info = {
+ .name = "milkymist-sysctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistSysctlState),
+ .class_init = milkymist_sysctl_class_init,
};
static void milkymist_sysctl_register(void)
{
- sysbus_register_withprop(&milkymist_sysctl_info);
+ type_register_static(&milkymist_sysctl_info);
}
device_init(milkymist_sysctl_register)
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
index 20110e5..474eae0 100644
--- a/hw/milkymist-tmu2.c
+++ b/hw/milkymist-tmu2.c
@@ -465,17 +465,26 @@
}
};
-static SysBusDeviceInfo milkymist_tmu2_info = {
- .init = milkymist_tmu2_init,
- .qdev.name = "milkymist-tmu2",
- .qdev.size = sizeof(MilkymistTMU2State),
- .qdev.vmsd = &vmstate_milkymist_tmu2,
- .qdev.reset = milkymist_tmu2_reset,
+static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_tmu2_init;
+ dc->reset = milkymist_tmu2_reset;
+ dc->vmsd = &vmstate_milkymist_tmu2;
+}
+
+static TypeInfo milkymist_tmu2_info = {
+ .name = "milkymist-tmu2",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistTMU2State),
+ .class_init = milkymist_tmu2_class_init,
};
static void milkymist_tmu2_register(void)
{
- sysbus_register_withprop(&milkymist_tmu2_info);
+ type_register_static(&milkymist_tmu2_info);
}
device_init(milkymist_tmu2_register)
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index eaf1c0d..f9a229c 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -199,7 +199,7 @@
"milkymist-uart", R_MAX * 4);
sysbus_init_mmio(dev, &s->regs_region);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr) {
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
}
@@ -218,17 +218,26 @@
}
};
-static SysBusDeviceInfo milkymist_uart_info = {
- .init = milkymist_uart_init,
- .qdev.name = "milkymist-uart",
- .qdev.size = sizeof(MilkymistUartState),
- .qdev.vmsd = &vmstate_milkymist_uart,
- .qdev.reset = milkymist_uart_reset,
+static void milkymist_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_uart_init;
+ dc->reset = milkymist_uart_reset;
+ dc->vmsd = &vmstate_milkymist_uart;
+}
+
+static TypeInfo milkymist_uart_info = {
+ .name = "milkymist-uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistUartState),
+ .class_init = milkymist_uart_class_init,
};
static void milkymist_uart_register(void)
{
- sysbus_register_withprop(&milkymist_uart_info);
+ type_register_static(&milkymist_uart_info);
}
device_init(milkymist_uart_register)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
index 108115e..92ad02f 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -299,22 +299,33 @@
}
};
-static SysBusDeviceInfo milkymist_vgafb_info = {
- .init = milkymist_vgafb_init,
- .qdev.name = "milkymist-vgafb",
- .qdev.size = sizeof(MilkymistVgafbState),
- .qdev.vmsd = &vmstate_milkymist_vgafb,
- .qdev.reset = milkymist_vgafb_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
- DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property milkymist_vgafb_properties[] = {
+ DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
+ DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_vgafb_init;
+ dc->reset = milkymist_vgafb_reset;
+ dc->vmsd = &vmstate_milkymist_vgafb;
+ dc->props = milkymist_vgafb_properties;
+}
+
+static TypeInfo milkymist_vgafb_info = {
+ .name = "milkymist-vgafb",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistVgafbState),
+ .class_init = milkymist_vgafb_class_init,
};
static void milkymist_vgafb_register(void)
{
- sysbus_register_withprop(&milkymist_vgafb_info);
+ type_register_static(&milkymist_vgafb_info);
}
device_init(milkymist_vgafb_register)
diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h
index 69af9ef..1d33ee8 100644
--- a/hw/milkymist-vgafb_template.h
+++ b/hw/milkymist-vgafb_template.h
@@ -39,7 +39,7 @@
#elif BITS == 24
#define COPY_PIXEL(to, r, g, b) \
do { \
- uint32 tmp = rgb_to_pixel24(r, g, b); \
+ uint32_t tmp = rgb_to_pixel24(r, g, b); \
*(to++) = tmp & 0xff; \
*(to++) = (tmp >> 8) & 0xff; \
*(to++) = (tmp >> 16) & 0xff; \
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index e625ec3..d232630 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -996,11 +996,7 @@
if (cirrus_vga_enabled) {
pci_cirrus_vga_init(pci_bus);
} else if (vmsvga_enabled) {
- if (!pci_vmsvga_init(pci_bus)) {
- fprintf(stderr, "Warning: vmware_vga not available,"
- " using standard VGA instead\n");
- pci_vga_init(pci_bus);
- }
+ pci_vmsvga_init(pci_bus);
} else if (std_vga_enabled) {
pci_vga_init(pci_bus);
}
@@ -1011,13 +1007,18 @@
return 0;
}
-static SysBusDeviceInfo mips_malta_device = {
- .init = mips_malta_sysbus_device_init,
- .qdev.name = "mips-malta",
- .qdev.size = sizeof(MaltaState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_END_OF_LIST(),
- }
+static void mips_malta_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mips_malta_sysbus_device_init;
+}
+
+static TypeInfo mips_malta_device = {
+ .name = "mips-malta",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MaltaState),
+ .class_init = mips_malta_class_init,
};
static QEMUMachine mips_malta_machine = {
@@ -1030,7 +1031,7 @@
static void mips_malta_device_init(void)
{
- sysbus_register_withprop(&mips_malta_device);
+ type_register_static(&mips_malta_device);
}
static void mips_malta_machine_init(void)
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index b1234b8..a0e6c9f 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -240,7 +240,7 @@
sysbus_init_irq(dev, &s->irq);
s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
return 0;
@@ -252,22 +252,33 @@
mipsnet_reset(s);
}
-static SysBusDeviceInfo mipsnet_info = {
- .init = mipsnet_sysbus_init,
- .qdev.name = "mipsnet",
- .qdev.desc = "MIPS Simulator network device",
- .qdev.size = sizeof(MIPSnetState),
- .qdev.vmsd = &vmstate_mipsnet,
- .qdev.reset = mipsnet_sysbus_reset,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property mipsnet_properties[] = {
+ DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mipsnet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mipsnet_sysbus_init;
+ dc->desc = "MIPS Simulator network device";
+ dc->reset = mipsnet_sysbus_reset;
+ dc->vmsd = &vmstate_mipsnet;
+ dc->props = mipsnet_properties;
+}
+
+static TypeInfo mipsnet_info = {
+ .name = "mipsnet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MIPSnetState),
+ .class_init = mipsnet_class_init,
};
static void mipsnet_register_devices(void)
{
- sysbus_register_withprop(&mipsnet_info);
+ type_register_static(&mipsnet_info);
}
device_init(mipsnet_register_devices)
diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
index f01b38c..28cd60d 100644
--- a/hw/mpc8544_guts.c
+++ b/hw/mpc8544_guts.c
@@ -121,14 +121,22 @@
return 0;
}
-static SysBusDeviceInfo mpc8544_guts_info = {
- .init = mpc8544_guts_initfn,
- .qdev.name = "mpc8544-guts",
- .qdev.size = sizeof(GutsState),
+static void mpc8544_guts_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mpc8544_guts_initfn;
+}
+
+static TypeInfo mpc8544_guts_info = {
+ .name = "mpc8544-guts",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GutsState),
+ .class_init = mpc8544_guts_class_init,
};
static void mpc8544_guts_register(void)
{
- sysbus_register_withprop(&mpc8544_guts_info);
+ type_register_static(&mpc8544_guts_info);
}
device_init(mpc8544_guts_register);
diff --git a/hw/msi.c b/hw/msi.c
index f214fcf..5d6ceb6 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -36,6 +36,9 @@
#define PCI_MSI_VECTORS_MAX 32
+/* Flag for interrupt controller to declare MSI/MSI-X support */
+bool msi_supported;
+
/* If we get rid of cap allocator, we won't need this. */
static inline uint8_t msi_cap_sizeof(uint16_t flags)
{
@@ -116,6 +119,11 @@
uint16_t flags;
uint8_t cap_size;
int config_offset;
+
+ if (!msi_supported) {
+ return -ENOTSUP;
+ }
+
MSI_DEV_PRINTF(dev,
"init offset: 0x%"PRIx8" vector: %"PRId8
" 64bit %d mask %d\n",
diff --git a/hw/msi.h b/hw/msi.h
index 5766018..3040bb0 100644
--- a/hw/msi.h
+++ b/hw/msi.h
@@ -24,6 +24,8 @@
#include "qemu-common.h"
#include "pci.h"
+extern bool msi_supported;
+
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);
diff --git a/hw/msix.c b/hw/msix.c
index f47d26b..3835eaa 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -15,6 +15,7 @@
*/
#include "hw.h"
+#include "msi.h"
#include "msix.h"
#include "pci.h"
#include "range.h"
@@ -35,9 +36,6 @@
#define MSIX_MAX_ENTRIES 32
-/* Flag for interrupt controller to declare MSI-X support */
-int msix_supported;
-
/* Add MSI-X capability to the config space for the device. */
/* Given a bar and its size, add MSI-X table on top of it
* and fill MSI-X capability in the config space.
@@ -238,10 +236,11 @@
unsigned bar_nr, unsigned bar_size)
{
int ret;
- /* Nothing to do if MSI is not supported by interrupt controller */
- if (!msix_supported)
- return -ENOTSUP;
+ /* Nothing to do if MSI is not supported by interrupt controller */
+ if (!msi_supported) {
+ return -ENOTSUP;
+ }
if (nentries > MSIX_MAX_ENTRIES)
return -EINVAL;
diff --git a/hw/msix.h b/hw/msix.h
index 7e04336..5aba22b 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -29,6 +29,4 @@
void msix_reset(PCIDevice *dev);
-extern int msix_supported;
-
#endif
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 8bfa5dd..1729db0 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -238,16 +238,25 @@
},
};
-static SysBusDeviceInfo mst_fpga_info = {
- .init = mst_fpga_init,
- .qdev.name = "mainstone-fpga",
- .qdev.desc = "Mainstone II FPGA",
- .qdev.size = sizeof(mst_irq_state),
- .qdev.vmsd = &vmstate_mst_fpga_regs,
+static void mst_fpga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mst_fpga_init;
+ dc->desc = "Mainstone II FPGA";
+ dc->vmsd = &vmstate_mst_fpga_regs;
+}
+
+static TypeInfo mst_fpga_info = {
+ .name = "mainstone-fpga",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mst_irq_state),
+ .class_init = mst_fpga_class_init,
};
static void mst_fpga_register(void)
{
- sysbus_register_withprop(&mst_fpga_info);
+ type_register_static(&mst_fpga_info);
}
device_init(mst_fpga_register);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 977ffb6..ac90924 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -387,7 +387,7 @@
sysbus_init_irq(dev, &s->irq);
s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth",
MP_ETH_SIZE);
sysbus_init_mmio(dev, &s->iomem);
@@ -412,15 +412,26 @@
}
};
-static SysBusDeviceInfo mv88w8618_eth_info = {
- .init = mv88w8618_eth_init,
- .qdev.name = "mv88w8618_eth",
- .qdev.size = sizeof(mv88w8618_eth_state),
- .qdev.vmsd = &mv88w8618_eth_vmsd,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property mv88w8618_eth_properties[] = {
+ DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_eth_init;
+ dc->vmsd = &mv88w8618_eth_vmsd;
+ dc->props = mv88w8618_eth_properties;
+}
+
+static TypeInfo mv88w8618_eth_info = {
+ .name = "mv88w8618_eth",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_eth_state),
+ .class_init = mv88w8618_eth_class_init,
};
/* LCD register offsets */
@@ -624,11 +635,20 @@
}
};
-static SysBusDeviceInfo musicpal_lcd_info = {
- .init = musicpal_lcd_init,
- .qdev.name = "musicpal_lcd",
- .qdev.size = sizeof(musicpal_lcd_state),
- .qdev.vmsd = &musicpal_lcd_vmsd,
+static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = musicpal_lcd_init;
+ dc->vmsd = &musicpal_lcd_vmsd;
+}
+
+static TypeInfo musicpal_lcd_info = {
+ .name = "musicpal_lcd",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(musicpal_lcd_state),
+ .class_init = musicpal_lcd_class_init,
};
/* PIC register offsets */
@@ -733,12 +753,21 @@
}
};
-static SysBusDeviceInfo mv88w8618_pic_info = {
- .init = mv88w8618_pic_init,
- .qdev.name = "mv88w8618_pic",
- .qdev.size = sizeof(mv88w8618_pic_state),
- .qdev.reset = mv88w8618_pic_reset,
- .qdev.vmsd = &mv88w8618_pic_vmsd,
+static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_pic_init;
+ dc->reset = mv88w8618_pic_reset;
+ dc->vmsd = &mv88w8618_pic_vmsd;
+}
+
+static TypeInfo mv88w8618_pic_info = {
+ .name = "mv88w8618_pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_pic_state),
+ .class_init = mv88w8618_pic_class_init,
};
/* PIT register offsets */
@@ -901,12 +930,21 @@
}
};
-static SysBusDeviceInfo mv88w8618_pit_info = {
- .init = mv88w8618_pit_init,
- .qdev.name = "mv88w8618_pit",
- .qdev.size = sizeof(mv88w8618_pit_state),
- .qdev.reset = mv88w8618_pit_reset,
- .qdev.vmsd = &mv88w8618_pit_vmsd,
+static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_pit_init;
+ dc->reset = mv88w8618_pit_reset;
+ dc->vmsd = &mv88w8618_pit_vmsd;
+}
+
+static TypeInfo mv88w8618_pit_info = {
+ .name = "mv88w8618_pit",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_pit_state),
+ .class_init = mv88w8618_pit_class_init,
};
/* Flash config register offsets */
@@ -973,11 +1011,20 @@
}
};
-static SysBusDeviceInfo mv88w8618_flashcfg_info = {
- .init = mv88w8618_flashcfg_init,
- .qdev.name = "mv88w8618_flashcfg",
- .qdev.size = sizeof(mv88w8618_flashcfg_state),
- .qdev.vmsd = &mv88w8618_flashcfg_vmsd,
+static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_flashcfg_init;
+ dc->vmsd = &mv88w8618_flashcfg_vmsd;
+}
+
+static TypeInfo mv88w8618_flashcfg_info = {
+ .name = "mv88w8618_flashcfg",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_flashcfg_state),
+ .class_init = mv88w8618_flashcfg_class_init,
};
/* Misc register offsets */
@@ -1285,12 +1332,21 @@
}
};
-static SysBusDeviceInfo musicpal_gpio_info = {
- .init = musicpal_gpio_init,
- .qdev.name = "musicpal_gpio",
- .qdev.size = sizeof(musicpal_gpio_state),
- .qdev.reset = musicpal_gpio_reset,
- .qdev.vmsd = &musicpal_gpio_vmsd,
+static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = musicpal_gpio_init;
+ dc->reset = musicpal_gpio_reset;
+ dc->vmsd = &musicpal_gpio_vmsd;
+}
+
+static TypeInfo musicpal_gpio_info = {
+ .name = "musicpal_gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(musicpal_gpio_state),
+ .class_init = musicpal_gpio_class_init,
};
/* Keyboard codes & masks */
@@ -1431,11 +1487,20 @@
}
};
-static SysBusDeviceInfo musicpal_key_info = {
- .init = musicpal_key_init,
- .qdev.name = "musicpal_key",
- .qdev.size = sizeof(musicpal_key_state),
- .qdev.vmsd = &musicpal_key_vmsd,
+static void musicpal_key_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = musicpal_key_init;
+ dc->vmsd = &musicpal_key_vmsd;
+}
+
+static TypeInfo musicpal_key_info = {
+ .name = "musicpal_key",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(musicpal_key_state),
+ .class_init = musicpal_key_class_init,
};
static struct arm_boot_info musicpal_binfo = {
@@ -1602,17 +1667,30 @@
machine_init(musicpal_machine_init);
+static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = mv88w8618_wlan_init;
+}
+
+static TypeInfo mv88w8618_wlan_info = {
+ .name = "mv88w8618_wlan",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = mv88w8618_wlan_class_init,
+};
+
static void musicpal_register_devices(void)
{
- sysbus_register_withprop(&mv88w8618_pic_info);
- sysbus_register_withprop(&mv88w8618_pit_info);
- sysbus_register_withprop(&mv88w8618_flashcfg_info);
- sysbus_register_withprop(&mv88w8618_eth_info);
- sysbus_register_dev("mv88w8618_wlan", sizeof(SysBusDevice),
- mv88w8618_wlan_init);
- sysbus_register_withprop(&musicpal_lcd_info);
- sysbus_register_withprop(&musicpal_gpio_info);
- sysbus_register_withprop(&musicpal_key_info);
+ type_register_static(&mv88w8618_pic_info);
+ type_register_static(&mv88w8618_pit_info);
+ type_register_static(&mv88w8618_flashcfg_info);
+ type_register_static(&mv88w8618_eth_info);
+ type_register_static(&mv88w8618_wlan_info);
+ type_register_static(&musicpal_lcd_info);
+ type_register_static(&musicpal_gpio_info);
+ type_register_static(&musicpal_key_info);
}
device_init(musicpal_register_devices)
diff --git a/hw/nand.c b/hw/nand.c
index 8597aa6..5d947b1 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -417,23 +417,34 @@
return 0;
}
-static SysBusDeviceInfo nand_info = {
- .init = nand_device_init,
- .qdev.name = "nand",
- .qdev.size = sizeof(NANDFlashState),
- .qdev.reset = nand_reset,
- .qdev.vmsd = &vmstate_nand,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
- DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
- DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property nand_properties[] = {
+ DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
+ DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
+ DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nand_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = nand_device_init;
+ dc->reset = nand_reset;
+ dc->vmsd = &vmstate_nand;
+ dc->props = nand_properties;
+}
+
+static TypeInfo nand_info = {
+ .name = "nand",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NANDFlashState),
+ .class_init = nand_class_init,
};
static void nand_create_device(void)
{
- sysbus_register_withprop(&nand_info);
+ type_register_static(&nand_info);
}
/*
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 11ffee7..1352282 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -76,27 +76,37 @@
ne2000_reset(s);
s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
return 0;
}
-static ISADeviceInfo ne2000_isa_info = {
- .qdev.name = "ne2k_isa",
- .qdev.size = sizeof(ISANE2000State),
- .init = isa_ne2000_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300),
- DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9),
- DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property ne2000_isa_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300),
+ DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9),
+ DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isa_ne2000_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = isa_ne2000_initfn;
+ dc->props = ne2000_isa_properties;
+}
+
+static TypeInfo ne2000_isa_info = {
+ .name = "ne2k_isa",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISANE2000State),
+ .class_init = isa_ne2000_class_initfn,
};
static void ne2000_isa_register_devices(void)
{
- isa_qdev_register(&ne2000_isa_info);
+ type_register_static(&ne2000_isa_info);
}
device_init(ne2000_isa_register_devices)
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 62e082f..080811e 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -760,7 +760,7 @@
ne2000_reset(s);
s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
- pci_dev->qdev.info->name, pci_dev->qdev.id, s);
+ object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
if (!pci_dev->qdev.hotplugged) {
@@ -786,24 +786,35 @@
return 0;
}
-static PCIDeviceInfo ne2000_info = {
- .qdev.name = "ne2k_pci",
- .qdev.size = sizeof(PCINE2000State),
- .qdev.vmsd = &vmstate_pci_ne2000,
- .init = pci_ne2000_init,
- .exit = pci_ne2000_exit,
- .vendor_id = PCI_VENDOR_ID_REALTEK,
- .device_id = PCI_DEVICE_ID_REALTEK_8029,
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ne2000_properties[] = {
+ DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ne2000_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_ne2000_init;
+ k->exit = pci_ne2000_exit;
+ k->vendor_id = PCI_VENDOR_ID_REALTEK;
+ k->device_id = PCI_DEVICE_ID_REALTEK_8029;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->vmsd = &vmstate_pci_ne2000;
+ dc->props = ne2000_properties;
+}
+
+static TypeInfo ne2000_info = {
+ .name = "ne2k_pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCINE2000State),
+ .class_init = ne2000_class_init,
};
static void ne2000_register_devices(void)
{
- pci_qdev_register(&ne2000_info);
+ type_register_static(&ne2000_info);
}
device_init(ne2000_register_devices)
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 29147be..9a9a8e1 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -731,40 +731,62 @@
* translation.)
*/
-static SysBusDeviceInfo omap_gpio_info = {
- .init = omap_gpio_init,
- .qdev.name = "omap-gpio",
- .qdev.size = sizeof(struct omap_gpif_s),
- .qdev.reset = omap_gpif_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
- DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property omap_gpio_properties[] = {
+ DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo omap2_gpio_info = {
- .init = omap2_gpio_init,
- .qdev.name = "omap2-gpio",
- .qdev.size = sizeof(struct omap2_gpif_s),
- .qdev.reset = omap2_gpif_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
- DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
- DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
- DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
- DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
- DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
- DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
- DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
- DEFINE_PROP_END_OF_LIST()
- }
+static void omap_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = omap_gpio_init;
+ dc->reset = omap_gpif_reset;
+ dc->props = omap_gpio_properties;
+}
+
+static TypeInfo omap_gpio_info = {
+ .name = "omap-gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap_gpif_s),
+ .class_init = omap_gpio_class_init,
+};
+
+static Property omap2_gpio_properties[] = {
+ DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
+ DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
+ DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
+ DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
+ DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
+ DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
+ DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = omap2_gpio_init;
+ dc->reset = omap2_gpif_reset;
+ dc->props = omap2_gpio_properties;
+}
+
+static TypeInfo omap2_gpio_info = {
+ .name = "omap2-gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap2_gpif_s),
+ .class_init = omap2_gpio_class_init,
};
static void omap_gpio_register_device(void)
{
- sysbus_register_withprop(&omap_gpio_info);
- sysbus_register_withprop(&omap2_gpio_info);
+ type_register_static(&omap_gpio_info);
+ type_register_static(&omap2_gpio_info);
}
device_init(omap_gpio_register_device)
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index fc53ec7..5aa98a8 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -373,16 +373,27 @@
return 0;
}
-static SysBusDeviceInfo omap_intc_info = {
- .init = omap_intc_init,
- .qdev.name = "omap-intc",
- .qdev.size = sizeof(struct omap_intr_handler_s),
- .qdev.reset = omap_inth_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
- DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property omap_intc_properties[] = {
+ DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
+ DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap_intc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = omap_intc_init;
+ dc->reset = omap_inth_reset;
+ dc->props = omap_intc_properties;
+}
+
+static TypeInfo omap_intc_info = {
+ .name = "omap-intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap_intr_handler_s),
+ .class_init = omap_intc_class_init,
};
static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
@@ -604,24 +615,35 @@
return 0;
}
-static SysBusDeviceInfo omap2_intc_info = {
- .init = omap2_intc_init,
- .qdev.name = "omap2-intc",
- .qdev.size = sizeof(struct omap_intr_handler_s),
- .qdev.reset = omap_inth_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
- revision, 0x21),
- DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
- DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property omap2_intc_properties[] = {
+ DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
+ revision, 0x21),
+ DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
+ DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_intc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = omap2_intc_init;
+ dc->reset = omap_inth_reset;
+ dc->props = omap2_intc_properties;
+}
+
+static TypeInfo omap2_intc_info = {
+ .name = "omap2-intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap_intr_handler_s),
+ .class_init = omap2_intc_class_init,
};
static void omap_intc_register_device(void)
{
- sysbus_register_withprop(&omap_intc_info);
- sysbus_register_withprop(&omap2_intc_info);
+ type_register_static(&omap_intc_info);
+ type_register_static(&omap2_intc_info);
}
device_init(omap_intc_register_device)
diff --git a/hw/onenand.c b/hw/onenand.c
index 33c9718..8744b04 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -802,24 +802,35 @@
return 0;
}
-static SysBusDeviceInfo onenand_info = {
- .init = onenand_initfn,
- .qdev.name = "onenand",
- .qdev.size = sizeof(OneNANDState),
- .qdev.reset = onenand_system_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
- DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
- DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
- DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
- DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property onenand_properties[] = {
+ DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
+ DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
+ DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
+ DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
+ DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void onenand_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = onenand_initfn;
+ dc->reset = onenand_system_reset;
+ dc->props = onenand_properties;
+}
+
+static TypeInfo onenand_info = {
+ .name = "onenand",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(OneNANDState),
+ .class_init = onenand_class_init,
};
static void onenand_register_device(void)
{
- sysbus_register_withprop(&onenand_info);
+ type_register_static(&onenand_info);
}
void *onenand_raw_otp(DeviceState *onenand_device)
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index f7cc1b4..09f2757 100644
--- a/hw/opencores_eth.c
+++ b/hw/opencores_eth.c
@@ -717,7 +717,7 @@
sysbus_init_irq(dev, &s->irq);
s->nic = qemu_new_nic(&net_open_eth_info, &s->conf,
- s->dev.qdev.info->name, s->dev.qdev.id, s);
+ object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
return 0;
}
@@ -727,21 +727,32 @@
open_eth_reset(d);
}
-static SysBusDeviceInfo open_eth_info = {
- .qdev.name = "open_eth",
- .qdev.desc = "Opencores 10/100 Mbit Ethernet",
- .qdev.size = sizeof(OpenEthState),
- .qdev.reset = qdev_open_eth_reset,
- .init = sysbus_open_eth_init,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(OpenEthState, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property open_eth_properties[] = {
+ DEFINE_NIC_PROPERTIES(OpenEthState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void open_eth_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sysbus_open_eth_init;
+ dc->desc = "Opencores 10/100 Mbit Ethernet";
+ dc->reset = qdev_open_eth_reset;
+ dc->props = open_eth_properties;
+}
+
+static TypeInfo open_eth_info = {
+ .name = "open_eth",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(OpenEthState),
+ .class_init = open_eth_class_init,
};
static void open_eth_register_devices(void)
{
- sysbus_register_withprop(&open_eth_info);
+ type_register_static(&open_eth_info);
}
device_init(open_eth_register_devices)
diff --git a/hw/openpic.c b/hw/openpic.c
index 22fc275..280b7a9 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1181,41 +1181,17 @@
qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
}
-qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
+qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
qemu_irq **irqs, qemu_irq irq_out)
{
openpic_t *opp;
- uint8_t *pci_conf;
int i, m;
/* XXX: for now, only one CPU is supported */
if (nb_cpus != 1)
return NULL;
- if (bus) {
- opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
- -1, NULL, NULL);
- pci_conf = opp->pci_dev.config;
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
- pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
- pci_conf[0x3d] = 0x00; // no interrupt pin
-
- memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
-#if 0 // Don't implement ISU for now
- opp_io_memory = cpu_register_io_memory(openpic_src_read,
- openpic_src_write, NULL
- DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
- opp_io_memory);
-#endif
-
- /* Register I/O spaces */
- pci_register_bar(&opp->pci_dev, 0,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
- } else {
- opp = g_malloc0(sizeof(openpic_t));
- memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
- }
+ opp = g_malloc0(sizeof(openpic_t));
+ memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
// isu_base &= 0xFFFC0000;
opp->nb_cpus = nb_cpus;
diff --git a/hw/openpic.h b/hw/openpic.h
index 715f084..8556030 100644
--- a/hw/openpic.h
+++ b/hw/openpic.h
@@ -11,7 +11,7 @@
OPENPIC_OUTPUT_NB,
};
-qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
+qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
qemu_irq **irqs, qemu_irq irq_out);
qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
int nb_cpus, qemu_irq **irqs, qemu_irq irq_out);
diff --git a/hw/parallel.c b/hw/parallel.c
index c4c5dbe..484d727 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -583,22 +583,32 @@
return true;
}
-static ISADeviceInfo parallel_isa_info = {
- .qdev.name = "isa-parallel",
- .qdev.size = sizeof(ISAParallelState),
- .init = parallel_isa_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("index", ISAParallelState, index, -1),
- DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase, -1),
- DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7),
- DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property parallel_isa_properties[] = {
+ DEFINE_PROP_UINT32("index", ISAParallelState, index, -1),
+ DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase, -1),
+ DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7),
+ DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = parallel_isa_initfn;
+ dc->props = parallel_isa_properties;
+}
+
+static TypeInfo parallel_isa_info = {
+ .name = "isa-parallel",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAParallelState),
+ .class_init = parallel_isa_class_initfn,
};
static void parallel_register_devices(void)
{
- isa_qdev_register(¶llel_isa_info);
+ type_register_static(¶llel_isa_info);
}
device_init(parallel_register_devices)
diff --git a/hw/pc.c b/hw/pc.c
index 85304cf..7f3aa65 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,9 +36,10 @@
#include "elf.h"
#include "multiboot.h"
#include "mc146818rtc.h"
-#include "msix.h"
+#include "msi.h"
#include "sysbus.h"
#include "sysemu.h"
+#include "kvm.h"
#include "blockdev.h"
#include "ui/qemu-spice.h"
#include "memory.h"
@@ -496,18 +497,26 @@
return 0;
}
-static ISADeviceInfo port92_info = {
- .qdev.name = "port92",
- .qdev.size = sizeof(Port92State),
- .qdev.vmsd = &vmstate_port92_isa,
- .qdev.no_user = 1,
- .qdev.reset = port92_reset,
- .init = port92_initfn,
+static void port92_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = port92_initfn;
+ dc->no_user = 1;
+ dc->reset = port92_reset;
+ dc->vmsd = &vmstate_port92_isa;
+}
+
+static TypeInfo port92_info = {
+ .name = "port92",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(Port92State),
+ .class_init = port92_class_initfn,
};
static void port92_register(void)
{
- isa_qdev_register(&port92_info);
+ type_register_static(&port92_info);
}
device_init(port92_register)
@@ -609,7 +618,7 @@
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
acpi_tables_len);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
smbios_table = smbios_get_table(&smbios_len);
if (smbios_table)
@@ -878,25 +887,30 @@
static DeviceState *apic_init(void *env, uint8_t apic_id)
{
DeviceState *dev;
- SysBusDevice *d;
static int apic_mapped;
- dev = qdev_create(NULL, "apic");
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ dev = qdev_create(NULL, "kvm-apic");
+ } else {
+ dev = qdev_create(NULL, "apic");
+ }
qdev_prop_set_uint8(dev, "id", apic_id);
qdev_prop_set_ptr(dev, "cpu_env", env);
qdev_init_nofail(dev);
- d = sysbus_from_qdev(dev);
/* XXX: mapping more APICs at the same memory location */
if (apic_mapped == 0) {
/* NOTE: the APIC is directly connected to the CPU - it is not
on the global memory bus. */
/* XXX: what if the base changes? */
- sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, MSI_ADDR_BASE);
apic_mapped = 1;
}
- msix_supported = 1;
+ /* KVM does not support MSI yet. */
+ if (!kvm_enabled() || !kvm_irqchip_in_kernel()) {
+ msi_supported = true;
+ }
return dev;
}
@@ -1080,16 +1094,11 @@
if (pci_bus) {
dev = pci_cirrus_vga_init(pci_bus);
} else {
- dev = isa_cirrus_vga_init(get_system_memory());
+ dev = &isa_create_simple(isa_bus, "isa-cirrus-vga")->qdev;
}
} else if (vmsvga_enabled) {
if (pci_bus) {
dev = pci_vmsvga_init(pci_bus);
- if (!dev) {
- fprintf(stderr, "Warning: vmware_vga not available,"
- " using standard VGA instead\n");
- dev = pci_vga_init(pci_bus);
- }
} else {
fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
}
diff --git a/hw/pc.h b/hw/pc.h
index 13e41f1..c666ec9 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -62,11 +62,11 @@
/* i8259.c */
-typedef struct PicState PicState;
-extern PicState *isa_pic;
+extern DeviceState *isa_pic;
qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
-int pic_read_irq(PicState *s);
-int pic_get_output(PicState *s);
+qemu_irq *kvm_i8259_init(ISABus *bus);
+int pic_read_irq(DeviceState *d);
+int pic_get_output(DeviceState *d);
void pic_info(Monitor *mon);
void irq_info(Monitor *mon);
@@ -226,7 +226,6 @@
/* cirrus_vga.c */
DeviceState *pci_cirrus_vga_init(PCIBus *bus);
-DeviceState *isa_cirrus_vga_init(MemoryRegion *address_space);
/* ne2000.c */
static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 3aea3cc..c06f1b5 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,7 +34,7 @@
#include "boards.h"
#include "ide.h"
#include "kvm.h"
-#include "kvmclock.h"
+#include "kvm/clock.h"
#include "sysemu.h"
#include "sysbus.h"
#include "arch_init.h"
@@ -53,13 +53,62 @@
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+static void kvm_piix3_setup_irq_routing(bool pci_enabled)
+{
+#ifdef CONFIG_KVM
+ KVMState *s = kvm_state;
+ int ret, i;
+
+ if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+ for (i = 0; i < 8; ++i) {
+ if (i == 2) {
+ continue;
+ }
+ kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
+ }
+ for (i = 8; i < 16; ++i) {
+ kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
+ }
+ if (pci_enabled) {
+ for (i = 0; i < 24; ++i) {
+ if (i == 0) {
+ kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
+ } else if (i != 2) {
+ kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, i);
+ }
+ }
+ }
+ ret = kvm_irqchip_commit_routes(s);
+ if (ret < 0) {
+ hw_error("KVM IRQ routing setup failed");
+ }
+ }
+#endif /* CONFIG_KVM */
+}
+
+static void kvm_piix3_gsi_handler(void *opaque, int n, int level)
+{
+ GSIState *s = opaque;
+
+ if (n < ISA_NUM_IRQS) {
+ /* Kernel will forward to both PIC and IOAPIC */
+ qemu_set_irq(s->i8259_irq[n], level);
+ } else {
+ qemu_set_irq(s->ioapic_irq[n], level);
+ }
+}
+
static void ioapic_init(GSIState *gsi_state)
{
DeviceState *dev;
SysBusDevice *d;
unsigned int i;
- dev = qdev_create(NULL, "ioapic");
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ dev = qdev_create(NULL, "kvm-ioapic");
+ } else {
+ dev = qdev_create(NULL, "ioapic");
+ }
qdev_init_nofail(dev);
d = sysbus_from_qdev(dev);
sysbus_mmio_map(d, 0, 0xfec00000);
@@ -134,7 +183,13 @@
}
gsi_state = g_malloc0(sizeof(*gsi_state));
- gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ kvm_piix3_setup_irq_routing(pci_enabled);
+ gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
+ GSI_NUM_PINS);
+ } else {
+ gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+ }
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
@@ -154,11 +209,13 @@
}
isa_bus_irqs(isa_bus, gsi);
- if (!xen_enabled()) {
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ i8259 = kvm_i8259_init(isa_bus);
+ } else if (xen_enabled()) {
+ i8259 = xen_interrupt_controller_init();
+ } else {
cpu_irq = pc_allocate_cpu_irq();
i8259 = i8259_init(isa_bus, cpu_irq[0]);
- } else {
- i8259 = xen_interrupt_controller_init();
}
for (i = 0; i < ISA_NUM_IRQS; i++) {
@@ -172,7 +229,7 @@
dev = pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
if (dev) {
- qdev_property_add_child(qdev_get_root(), "vga", dev, NULL);
+ object_property_add_child(object_get_root(), "vga", OBJECT(dev), NULL);
}
if (xen_enabled()) {
@@ -210,8 +267,8 @@
* For now, let's "fix" this by making judicious use of paths. This
* is not generally the right way to do this.
*/
- qdev_property_add_child(qdev_resolve_path("/i440fx/piix3", NULL),
- "rtc", (DeviceState *)rtc_state, NULL);
+ object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
+ "rtc", (Object *)rtc_state, NULL);
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
diff --git a/hw/pci.c b/hw/pci.c
index c3082bc..5f4f80e 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -89,7 +89,6 @@
VMSTATE_END_OF_LIST()
}
};
-
static int pci_bar(PCIDevice *d, int reg)
{
uint8_t type;
@@ -159,11 +158,8 @@
void pci_device_reset(PCIDevice *dev)
{
int r;
- /* TODO: call the below unconditionally once all pci devices
- * are qdevified */
- if (dev->qdev.info) {
- qdev_reset_all(&dev->qdev);
- }
+
+ qdev_reset_all(&dev->qdev);
dev->irq_state = 0;
pci_update_irq_status(dev);
@@ -733,11 +729,11 @@
/* -1 for devfn means auto assign */
static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
- const char *name, int devfn,
- const PCIDeviceInfo *info)
+ const char *name, int devfn)
{
- PCIConfigReadFunc *config_read = info->config_read;
- PCIConfigWriteFunc *config_write = info->config_write;
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
+ PCIConfigReadFunc *config_read = pc->config_read;
+ PCIConfigWriteFunc *config_write = pc->config_write;
if (devfn < 0) {
for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
@@ -759,29 +755,29 @@
pci_dev->irq_state = 0;
pci_config_alloc(pci_dev);
- pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
- pci_config_set_device_id(pci_dev->config, info->device_id);
- pci_config_set_revision(pci_dev->config, info->revision);
- pci_config_set_class(pci_dev->config, info->class_id);
+ pci_config_set_vendor_id(pci_dev->config, pc->vendor_id);
+ pci_config_set_device_id(pci_dev->config, pc->device_id);
+ pci_config_set_revision(pci_dev->config, pc->revision);
+ pci_config_set_class(pci_dev->config, pc->class_id);
- if (!info->is_bridge) {
- if (info->subsystem_vendor_id || info->subsystem_id) {
+ if (!pc->is_bridge) {
+ if (pc->subsystem_vendor_id || pc->subsystem_id) {
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
- info->subsystem_vendor_id);
+ pc->subsystem_vendor_id);
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
- info->subsystem_id);
+ pc->subsystem_id);
} else {
pci_set_default_subsystem_id(pci_dev);
}
} else {
/* subsystem_vendor_id/subsystem_id are only for header type 0 */
- assert(!info->subsystem_vendor_id);
- assert(!info->subsystem_id);
+ assert(!pc->subsystem_vendor_id);
+ assert(!pc->subsystem_id);
}
pci_init_cmask(pci_dev);
pci_init_wmask(pci_dev);
pci_init_w1cmask(pci_dev);
- if (info->is_bridge) {
+ if (pc->is_bridge) {
pci_init_wmask_bridge(pci_dev);
}
if (pci_init_multifunction(bus, pci_dev)) {
@@ -808,26 +804,6 @@
pci_config_free(pci_dev);
}
-/* TODO: obsolete. eliminate this once all pci devices are qdevifed. */
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
- int instance_size, int devfn,
- PCIConfigReadFunc *config_read,
- PCIConfigWriteFunc *config_write)
-{
- PCIDevice *pci_dev;
- PCIDeviceInfo info = {
- .config_read = config_read,
- .config_write = config_write,
- };
-
- pci_dev = g_malloc0(instance_size);
- pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);
- if (pci_dev == NULL) {
- hw_error("PCI: can't register device\n");
- }
- return pci_dev;
-}
-
static void pci_unregister_io_regions(PCIDevice *pci_dev)
{
PCIIORegion *r;
@@ -843,12 +819,12 @@
static int pci_unregister_device(DeviceState *dev)
{
- PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
- PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->info);
+ PCIDevice *pci_dev = PCI_DEVICE(dev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
int ret = 0;
- if (info->exit)
- ret = info->exit(pci_dev);
+ if (pc->exit)
+ ret = pc->exit(pci_dev);
if (ret)
return ret;
@@ -1477,31 +1453,32 @@
return bus->devices[devfn];
}
-static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int pci_qdev_init(DeviceState *qdev)
{
PCIDevice *pci_dev = (PCIDevice *)qdev;
- PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
PCIBus *bus;
int rc;
bool is_default_rom;
/* initialize cap_present for pci_is_express() and pci_config_size() */
- if (info->is_express) {
+ if (pc->is_express) {
pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
- pci_dev = do_pci_register_device(pci_dev, bus, base->name,
- pci_dev->devfn, info);
+ pci_dev = do_pci_register_device(pci_dev, bus,
+ object_get_typename(OBJECT(qdev)),
+ pci_dev->devfn);
if (pci_dev == NULL)
return -1;
- if (qdev->hotplugged && info->no_hotplug) {
- qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+ if (qdev->hotplugged && pc->no_hotplug) {
+ qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev)));
do_pci_unregister_device(pci_dev);
return -1;
}
- if (info->init) {
- rc = info->init(pci_dev);
+ if (pc->init) {
+ rc = pc->init(pci_dev);
if (rc != 0) {
do_pci_unregister_device(pci_dev);
return rc;
@@ -1510,8 +1487,8 @@
/* rom loading */
is_default_rom = false;
- if (pci_dev->romfile == NULL && info->romfile != NULL) {
- pci_dev->romfile = g_strdup(info->romfile);
+ if (pci_dev->romfile == NULL && pc->romfile != NULL) {
+ pci_dev->romfile = g_strdup(pc->romfile);
is_default_rom = true;
}
pci_add_option_rom(pci_dev, is_default_rom);
@@ -1533,34 +1510,18 @@
static int pci_unplug_device(DeviceState *qdev)
{
- PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
- PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+ PCIDevice *dev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- if (info->no_hotplug) {
- qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+ if (pc->no_hotplug) {
+ qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
return -1;
}
+ object_unparent(OBJECT(dev));
return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
PCI_HOTPLUG_DISABLED);
}
-void pci_qdev_register(PCIDeviceInfo *info)
-{
- info->qdev.init = pci_qdev_init;
- info->qdev.unplug = pci_unplug_device;
- info->qdev.exit = pci_unregister_device;
- info->qdev.bus_info = &pci_bus_info;
- qdev_register(&info->qdev);
-}
-
-void pci_qdev_register_many(PCIDeviceInfo *info)
-{
- while (info->qdev.name) {
- pci_qdev_register(info);
- info++;
- }
-}
-
PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
const char *name)
{
@@ -1569,22 +1530,7 @@
dev = qdev_create(&bus->qbus, name);
qdev_prop_set_uint32(dev, "addr", devfn);
qdev_prop_set_bit(dev, "multifunction", multifunction);
- return DO_UPCAST(PCIDevice, qdev, dev);
-}
-
-PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
- bool multifunction,
- const char *name)
-{
- DeviceState *dev;
-
- dev = qdev_try_create(&bus->qbus, name);
- if (!dev) {
- return NULL;
- }
- qdev_prop_set_uint32(dev, "addr", devfn);
- qdev_prop_set_bit(dev, "multifunction", multifunction);
- return DO_UPCAST(PCIDevice, qdev, dev);
+ return PCI_DEVICE(dev);
}
PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
@@ -1606,11 +1552,6 @@
return pci_create_simple_multifunction(bus, devfn, false, name);
}
-PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name)
-{
- return pci_try_create_multifunction(bus, devfn, false, name);
-}
-
static int pci_find_space(PCIDevice *pdev, uint8_t size)
{
int config_size = pci_config_size(pdev);
@@ -1724,6 +1665,7 @@
char *path;
void *ptr;
char name[32];
+ const VMStateDescription *vmsd;
if (!pdev->romfile)
return 0;
@@ -1760,10 +1702,13 @@
size = 1 << qemu_fls(size);
}
- if (pdev->qdev.info->vmsd)
- snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
- else
- snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
+ vmsd = qdev_get_vmsd(DEVICE(pdev));
+
+ if (vmsd) {
+ snprintf(name, sizeof(name), "%s.rom", vmsd->name);
+ } else {
+ snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev)));
+ }
pdev->has_rom = true;
memory_region_init_ram(&pdev->rom, name, size);
vmstate_register_ram(&pdev->rom, &pdev->qdev);
@@ -2004,9 +1949,8 @@
}
/* roughly check if given qdev is pci device */
- if (qdev->info->init == &pci_qdev_init &&
- qdev->parent_bus->info == &pci_bus_info) {
- *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+ if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) {
+ *pdev = PCI_DEVICE(qdev);
return 0;
}
return -EINVAL;
@@ -2040,3 +1984,28 @@
{
return dev->bus->address_space_io;
}
+
+static void pci_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = pci_qdev_init;
+ k->unplug = pci_unplug_device;
+ k->exit = pci_unregister_device;
+ k->bus_info = &pci_bus_info;
+}
+
+static TypeInfo pci_device_type_info = {
+ .name = TYPE_PCI_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .abstract = true,
+ .class_size = sizeof(PCIDeviceClass),
+ .class_init = pci_device_class_init,
+};
+
+static void pci_register_devices(void)
+{
+ type_register_static(&pci_device_type_info);
+}
+
+device_init(pci_register_devices);
diff --git a/hw/pci.h b/hw/pci.h
index 0d2cff6..33b0b18 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -127,6 +127,46 @@
QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
};
+#define TYPE_PCI_DEVICE "pci-device"
+#define PCI_DEVICE(obj) \
+ OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE)
+#define PCI_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE)
+#define PCI_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE)
+
+typedef struct PCIDeviceClass {
+ DeviceClass parent_class;
+
+ int (*init)(PCIDevice *dev);
+ PCIUnregisterFunc *exit;
+ PCIConfigReadFunc *config_read;
+ PCIConfigWriteFunc *config_write;
+
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint8_t revision;
+ uint16_t class_id;
+ uint16_t subsystem_vendor_id; /* only for header type = 0 */
+ uint16_t subsystem_id; /* only for header type = 0 */
+
+ /*
+ * pci-to-pci bridge or normal device.
+ * This doesn't mean pci host switch.
+ * When card bus bridge is supported, this would be enhanced.
+ */
+ int is_bridge;
+
+ /* pcie stuff */
+ int is_express; /* is this device pci express? */
+
+ /* device isn't hot-pluggable */
+ int no_hotplug;
+
+ /* rom bar */
+ const char *romfile;
+} PCIDeviceClass;
+
struct PCIDevice {
DeviceState qdev;
/* PCI config space */
@@ -196,11 +236,6 @@
uint32_t rom_bar;
};
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
- int instance_size, int devfn,
- PCIConfigReadFunc *config_read,
- PCIConfigWriteFunc *config_write);
-
void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint8_t attr, MemoryRegion *memory);
pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
@@ -429,52 +464,13 @@
return val & mask;
}
-typedef int (*pci_qdev_initfn)(PCIDevice *dev);
-typedef struct {
- DeviceInfo qdev;
- pci_qdev_initfn init;
- PCIUnregisterFunc *exit;
- PCIConfigReadFunc *config_read;
- PCIConfigWriteFunc *config_write;
-
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- uint16_t class_id;
- uint16_t subsystem_vendor_id; /* only for header type = 0 */
- uint16_t subsystem_id; /* only for header type = 0 */
-
- /*
- * pci-to-pci bridge or normal device.
- * This doesn't mean pci host switch.
- * When card bus bridge is supported, this would be enhanced.
- */
- int is_bridge;
-
- /* pcie stuff */
- int is_express; /* is this device pci express? */
-
- /* device isn't hot-pluggable */
- int no_hotplug;
-
- /* rom bar */
- const char *romfile;
-} PCIDeviceInfo;
-
-void pci_qdev_register(PCIDeviceInfo *info);
-void pci_qdev_register_many(PCIDeviceInfo *info);
-
PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
const char *name);
PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
bool multifunction,
const char *name);
-PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
- bool multifunction,
- const char *name);
PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name);
PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
-PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name);
static inline int pci_is_express(const PCIDevice *d)
{
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 650d165..1ed4339 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -294,7 +294,7 @@
/* default reset function for PCI-to-PCI bridge */
void pci_bridge_reset(DeviceState *qdev)
{
- PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *dev = PCI_DEVICE(qdev);
pci_bridge_reset_reg(dev);
}
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 83f3893..e8235a7 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -98,6 +98,7 @@
#define PCI_DEVICE_ID_MPC8533E 0x0030
#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_82378 0x0484
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
#define PCI_DEVICE_ID_INTEL_82801D 0x24CD
@@ -120,3 +121,6 @@
#define PCI_VENDOR_ID_XEN 0x5853
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
+
+#define PCI_VENDOR_ID_NEC 0x1033
+#define PCI_DEVICE_ID_NEC_UPD720200 0x0194
diff --git a/hw/pcie.c b/hw/pcie.c
index 5c9eb2f..7c92f19 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -203,7 +203,7 @@
static int pcie_cap_slot_hotplug(DeviceState *qdev,
PCIDevice *pci_dev, PCIHotplugState state)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *d = PCI_DEVICE(qdev);
uint8_t *exp_cap = d->config + d->exp.exp_cap;
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 06b40c5..b4c53be 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -497,16 +497,24 @@
return 0;
}
-static ISADeviceInfo i8042_info = {
- .qdev.name = "i8042",
- .qdev.size = sizeof(ISAKBDState),
- .qdev.vmsd = &vmstate_kbd_isa,
- .qdev.no_user = 1,
- .init = i8042_initfn,
+static void i8042_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = i8042_initfn;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_kbd_isa;
+}
+
+static TypeInfo i8042_info = {
+ .name = "i8042",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAKBDState),
+ .class_init = i8042_class_initfn,
};
static void i8042_register(void)
{
- isa_qdev_register(&i8042_info);
+ type_register_static(&i8042_info);
}
device_init(i8042_register)
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 4e164da..439f32c 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -348,26 +348,37 @@
pcnet_h_reset(&d->state);
}
-static PCIDeviceInfo pcnet_info = {
- .qdev.name = "pcnet",
- .qdev.size = sizeof(PCIPCNetState),
- .qdev.reset = pci_reset,
- .qdev.vmsd = &vmstate_pci_pcnet,
- .init = pci_pcnet_init,
- .exit = pci_pcnet_uninit,
- .vendor_id = PCI_VENDOR_ID_AMD,
- .device_id = PCI_DEVICE_ID_AMD_LANCE,
- .revision = 0x10,
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property pcnet_properties[] = {
+ DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pcnet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_pcnet_init;
+ k->exit = pci_pcnet_uninit;
+ k->vendor_id = PCI_VENDOR_ID_AMD;
+ k->device_id = PCI_DEVICE_ID_AMD_LANCE;
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->reset = pci_reset;
+ dc->vmsd = &vmstate_pci_pcnet;
+ dc->props = pcnet_properties;
+}
+
+static TypeInfo pcnet_info = {
+ .name = "pcnet",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIPCNetState),
+ .class_init = pcnet_class_init,
};
static void pci_pcnet_register_devices(void)
{
- pci_qdev_register(&pcnet_info);
+ type_register_static(&pcnet_info);
}
device_init(pci_pcnet_register_devices)
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 306dc6e..c53f06e 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -688,7 +688,6 @@
printf("pcnet_s_reset\n");
#endif
- s->lnkst = 0x40;
s->rdra = 0;
s->tdra = 0;
s->rap = 0;
@@ -1719,7 +1718,7 @@
s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s);
+ s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
@@ -1751,5 +1750,7 @@
}
*(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
+ s->lnkst = 0x40; /* initial link state: up */
+
return 0;
}
diff --git a/hw/piix4.c b/hw/piix4.c
index 51af459..4e7a237 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -102,25 +102,30 @@
return d->devfn;
}
-static PCIDeviceInfo piix4_info[] = {
- {
- .qdev.name = "PIIX4",
- .qdev.desc = "ISA bridge",
- .qdev.size = sizeof(PIIX4State),
- .qdev.vmsd = &vmstate_piix4,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = piix4_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB_0, // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
- .class_id = PCI_CLASS_BRIDGE_ISA,
- },{
- /* end of list */
- }
+static void piix4_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = piix4_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+ dc->desc = "ISA bridge";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_piix4;
+}
+
+static TypeInfo piix4_info = {
+ .name = "PIIX4",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX4State),
+ .class_init = piix4_class_init,
};
static void piix4_register(void)
{
- pci_qdev_register_many(piix4_info);
+ type_register_static(&piix4_info);
}
device_init(piix4_register);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 3652522..1906427 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -277,7 +277,7 @@
address_space_io, 0);
s->bus = b;
qdev_init_nofail(dev);
- qdev_property_add_child(qdev_get_root(), "i440fx", dev, NULL);
+ object_property_add_child(object_get_root(), "i440fx", OBJECT(dev), NULL);
d = pci_create_simple(b, 0, device_name);
*pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
@@ -316,7 +316,7 @@
pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
PIIX_NUM_PIRQS);
}
- qdev_property_add_child(dev, "piix3", &piix3->dev.qdev, NULL);
+ object_property_add_child(OBJECT(dev), "piix3", OBJECT(piix3), NULL);
piix3->pic = pic;
*isa_bus = DO_UPCAST(ISABus, qbus,
qdev_get_child_bus(&piix3->dev.qdev, "isa.0"));
@@ -502,60 +502,98 @@
return 0;
}
-static PCIDeviceInfo i440fx_info[] = {
- {
- .qdev.name = "i440FX",
- .qdev.desc = "Host bridge",
- .qdev.size = sizeof(PCII440FXState),
- .qdev.vmsd = &vmstate_i440fx,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = i440fx_initfn,
- .config_write = i440fx_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82441,
- .revision = 0x02,
- .class_id = PCI_CLASS_BRIDGE_HOST,
- },{
- .qdev.name = "PIIX3",
- .qdev.desc = "ISA bridge",
- .qdev.size = sizeof(PIIX3State),
- .qdev.vmsd = &vmstate_piix3,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = piix3_initfn,
- .config_write = piix3_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
- .class_id = PCI_CLASS_BRIDGE_ISA,
- },{
- .qdev.name = "PIIX3-xen",
- .qdev.desc = "ISA bridge",
- .qdev.size = sizeof(PIIX3State),
- .qdev.vmsd = &vmstate_piix3,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = piix3_initfn,
- .config_write = piix3_write_config_xen,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
- .class_id = PCI_CLASS_BRIDGE_ISA,
- },{
- /* end of list */
- }
+static void piix3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ dc->desc = "ISA bridge";
+ dc->vmsd = &vmstate_piix3;
+ dc->no_user = 1,
+ k->no_hotplug = 1;
+ k->init = piix3_initfn;
+ k->config_write = piix3_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+}
+
+static TypeInfo piix3_info = {
+ .name = "PIIX3",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX3State),
+ .class_init = piix3_class_init,
};
-static SysBusDeviceInfo i440fx_pcihost_info = {
- .init = i440fx_pcihost_initfn,
- .qdev.name = "i440FX-pcihost",
- .qdev.fw_name = "pci",
- .qdev.size = sizeof(I440FXState),
- .qdev.no_user = 1,
+static void piix3_xen_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ dc->desc = "ISA bridge";
+ dc->vmsd = &vmstate_piix3;
+ dc->no_user = 1;
+ k->no_hotplug = 1;
+ k->init = piix3_initfn;
+ k->config_write = piix3_write_config_xen;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+};
+
+static TypeInfo piix3_xen_info = {
+ .name = "PIIX3-xen",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX3State),
+ .class_init = piix3_xen_class_init,
+};
+
+static void i440fx_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = i440fx_initfn;
+ k->config_write = i440fx_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82441;
+ k->revision = 0x02;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ dc->desc = "Host bridge";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_i440fx;
+}
+
+static TypeInfo i440fx_info = {
+ .name = "i440FX",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCII440FXState),
+ .class_init = i440fx_class_init,
+};
+
+static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = i440fx_pcihost_initfn;
+ dc->fw_name = "pci";
+ dc->no_user = 1;
+}
+
+static TypeInfo i440fx_pcihost_info = {
+ .name = "i440FX-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(I440FXState),
+ .class_init = i440fx_pcihost_class_init,
};
static void i440fx_register(void)
{
- sysbus_register_withprop(&i440fx_pcihost_info);
- pci_qdev_register_many(i440fx_info);
+ type_register_static(&i440fx_info);
+ type_register_static(&piix3_info);
+ type_register_static(&piix3_xen_info);
+ type_register_static(&i440fx_pcihost_info);
}
device_init(i440fx_register);
diff --git a/hw/pl011.c b/hw/pl011.c
index 1b05d76..752cbf9 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -264,7 +264,7 @@
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
s->id = id;
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
s->read_trigger = 1;
s->ifl = 0x12;
@@ -278,22 +278,48 @@
return 0;
}
-static int pl011_init_arm(SysBusDevice *dev)
+static int pl011_arm_init(SysBusDevice *dev)
{
return pl011_init(dev, pl011_id_arm);
}
-static int pl011_init_luminary(SysBusDevice *dev)
+static int pl011_luminary_init(SysBusDevice *dev)
{
return pl011_init(dev, pl011_id_luminary);
}
+static void pl011_arm_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pl011_arm_init;
+}
+
+static TypeInfo pl011_arm_info = {
+ .name = "pl011",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl011_state),
+ .class_init = pl011_arm_class_init,
+};
+
+static void pl011_luminary_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pl011_luminary_init;
+}
+
+static TypeInfo pl011_luminary_info = {
+ .name = "pl011_luminary",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl011_state),
+ .class_init = pl011_luminary_class_init,
+};
+
static void pl011_register_devices(void)
{
- sysbus_register_dev("pl011", sizeof(pl011_state),
- pl011_init_arm);
- sysbus_register_dev("pl011_luminary", sizeof(pl011_state),
- pl011_init_luminary);
+ type_register_static(&pl011_arm_info);
+ type_register_static(&pl011_luminary_info);
}
device_init(pl011_register_devices)
diff --git a/hw/pl022.c b/hw/pl022.c
index d43e4a2..30bd344 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -285,9 +285,23 @@
return 0;
}
+static void pl022_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pl022_init;
+}
+
+static TypeInfo pl022_info = {
+ .name = "pl022",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl022_state),
+ .class_init = pl022_class_init,
+};
+
static void pl022_register_devices(void)
{
- sysbus_register_dev("pl022", sizeof(pl022_state), pl022_init);
+ type_register_static(&pl022_info);
}
device_init(pl022_register_devices)
diff --git a/hw/pl031.c b/hw/pl031.c
index 2fb0c8e..8416a60 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -213,17 +213,26 @@
return 0;
}
-static SysBusDeviceInfo pl031_info = {
- .init = pl031_init,
- .qdev.name = "pl031",
- .qdev.size = sizeof(pl031_state),
- .qdev.vmsd = &vmstate_pl031,
- .qdev.no_user = 1,
+static void pl031_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl031_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl031;
+}
+
+static TypeInfo pl031_info = {
+ .name = "pl031",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl031_state),
+ .class_init = pl031_class_init,
};
static void pl031_register_devices(void)
{
- sysbus_register_withprop(&pl031_info);
+ type_register_static(&pl031_info);
}
device_init(pl031_register_devices)
diff --git a/hw/pl041.c b/hw/pl041.c
index 4585ccf..6d99c9c 100644
--- a/hw/pl041.c
+++ b/hw/pl041.c
@@ -613,24 +613,34 @@
}
};
-static SysBusDeviceInfo pl041_device_info = {
- .init = pl041_init,
- .qdev.name = "pl041",
- .qdev.size = sizeof(pl041_state),
- .qdev.vmsd = &vmstate_pl041,
- .qdev.reset = pl041_device_reset,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- /* Non-compact FIFO depth property */
- DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state,
- fifo_depth, DEFAULT_FIFO_DEPTH),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pl041_device_properties[] = {
+ /* Non-compact FIFO depth property */
+ DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state, fifo_depth, DEFAULT_FIFO_DEPTH),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pl041_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl041_init;
+ dc->no_user = 1;
+ dc->reset = pl041_device_reset;
+ dc->vmsd = &vmstate_pl041;
+ dc->props = pl041_device_properties;
+}
+
+static TypeInfo pl041_device_info = {
+ .name = "pl041",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl041_state),
+ .class_init = pl041_device_class_init,
};
static void pl041_register_device(void)
{
- sysbus_register_withprop(&pl041_device_info);
+ type_register_static(&pl041_device_info);
}
device_init(pl041_register_device)
diff --git a/hw/pl050.c b/hw/pl050.c
index 8182a1c..b0094ac 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -157,24 +157,42 @@
return pl050_init(dev, 1);
}
-static SysBusDeviceInfo pl050_kbd_info = {
- .init = pl050_init_keyboard,
- .qdev.name = "pl050_keyboard",
- .qdev.size = sizeof(pl050_state),
- .qdev.vmsd = &vmstate_pl050,
+static void pl050_kbd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl050_init_keyboard;
+ dc->vmsd = &vmstate_pl050;
+}
+
+static TypeInfo pl050_kbd_info = {
+ .name = "pl050_keyboard",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl050_state),
+ .class_init = pl050_kbd_class_init,
};
-static SysBusDeviceInfo pl050_mouse_info = {
- .init = pl050_init_mouse,
- .qdev.name = "pl050_mouse",
- .qdev.size = sizeof(pl050_state),
- .qdev.vmsd = &vmstate_pl050,
+static void pl050_mouse_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl050_init_mouse;
+ dc->vmsd = &vmstate_pl050;
+}
+
+static TypeInfo pl050_mouse_info = {
+ .name = "pl050_mouse",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl050_state),
+ .class_init = pl050_mouse_class_init,
};
static void pl050_register_devices(void)
{
- sysbus_register_withprop(&pl050_kbd_info);
- sysbus_register_withprop(&pl050_mouse_info);
+ type_register_static(&pl050_kbd_info);
+ type_register_static(&pl050_mouse_info);
}
device_init(pl050_register_devices)
diff --git a/hw/pl061.c b/hw/pl061.c
index f33ae84..3136c99 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -293,24 +293,42 @@
return pl061_init(dev, pl061_id);
}
-static SysBusDeviceInfo pl061_info = {
- .init = pl061_init_arm,
- .qdev.name = "pl061",
- .qdev.size = sizeof(pl061_state),
- .qdev.vmsd = &vmstate_pl061,
+static void pl061_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl061_init_arm;
+ dc->vmsd = &vmstate_pl061;
+}
+
+static TypeInfo pl061_info = {
+ .name = "pl061",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl061_state),
+ .class_init = pl061_class_init,
};
-static SysBusDeviceInfo pl061_luminary_info = {
- .init = pl061_init_luminary,
- .qdev.name = "pl061_luminary",
- .qdev.size = sizeof(pl061_state),
- .qdev.vmsd = &vmstate_pl061,
+static void pl061_luminary_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl061_init_luminary;
+ dc->vmsd = &vmstate_pl061;
+}
+
+static TypeInfo pl061_luminary_info = {
+ .name = "pl061_luminary",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl061_state),
+ .class_init = pl061_luminary_class_init,
};
static void pl061_register_devices(void)
{
- sysbus_register_withprop(&pl061_info);
- sysbus_register_withprop(&pl061_luminary_info);
+ type_register_static(&pl061_info);
+ type_register_static(&pl061_luminary_info);
}
device_init(pl061_register_devices)
diff --git a/hw/pl080.c b/hw/pl080.c
index e001df9..4405d18 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -373,28 +373,46 @@
return pl08x_init(dev, 2);
}
-static SysBusDeviceInfo pl080_info = {
- .init = pl080_init,
- .qdev.name = "pl080",
- .qdev.size = sizeof(pl080_state),
- .qdev.vmsd = &vmstate_pl080,
- .qdev.no_user = 1,
+static void pl080_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl080_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl080;
+}
+
+static TypeInfo pl080_info = {
+ .name = "pl080",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl080_state),
+ .class_init = pl080_class_init,
};
-static SysBusDeviceInfo pl081_info = {
- .init = pl081_init,
- .qdev.name = "pl081",
- .qdev.size = sizeof(pl080_state),
- .qdev.vmsd = &vmstate_pl080,
- .qdev.no_user = 1,
+static void pl081_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl081_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl080;
+}
+
+static TypeInfo pl081_info = {
+ .name = "pl081",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl080_state),
+ .class_init = pl081_class_init,
};
/* The PL080 and PL081 are the same except for the number of channels
they implement (8 and 2 respectively). */
static void pl080_register_devices(void)
{
- sysbus_register_withprop(&pl080_info);
- sysbus_register_withprop(&pl081_info);
+ type_register_static(&pl080_info);
+ type_register_static(&pl081_info);
}
device_init(pl080_register_devices)
diff --git a/hw/pl110.c b/hw/pl110.c
index 0e1f415..86e95a3 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -469,35 +469,62 @@
return pl110_init(dev);
}
-static SysBusDeviceInfo pl110_info = {
- .init = pl110_init,
- .qdev.name = "pl110",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl110_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl110_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl110_info = {
+ .name = "pl110",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl110_class_init,
};
-static SysBusDeviceInfo pl110_versatile_info = {
- .init = pl110_versatile_init,
- .qdev.name = "pl110_versatile",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl110_versatile_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl110_versatile_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl110_versatile_info = {
+ .name = "pl110_versatile",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl110_versatile_class_init,
};
-static SysBusDeviceInfo pl111_info = {
- .init = pl111_init,
- .qdev.name = "pl111",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl111_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl111_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl111_info = {
+ .name = "pl111",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl111_class_init,
};
static void pl110_register_devices(void)
{
- sysbus_register_withprop(&pl110_info);
- sysbus_register_withprop(&pl110_versatile_info);
- sysbus_register_withprop(&pl111_info);
+ type_register_static(&pl110_info);
+ type_register_static(&pl110_versatile_info);
+ type_register_static(&pl111_info);
}
device_init(pl110_register_devices)
diff --git a/hw/pl181.c b/hw/pl181.c
index b79aa41..ae636e2 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -487,18 +487,27 @@
return 0;
}
-static SysBusDeviceInfo pl181_info = {
- .init = pl181_init,
- .qdev.name = "pl181",
- .qdev.size = sizeof(pl181_state),
- .qdev.vmsd = &vmstate_pl181,
- .qdev.reset = pl181_reset,
- .qdev.no_user = 1,
+static void pl181_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *k = DEVICE_CLASS(klass);
+
+ sdc->init = pl181_init;
+ k->vmsd = &vmstate_pl181;
+ k->reset = pl181_reset;
+ k->no_user = 1;
+}
+
+static TypeInfo pl181_info = {
+ .name = "pl181",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl181_state),
+ .class_init = pl181_class_init,
};
static void pl181_register_devices(void)
{
- sysbus_register_withprop(&pl181_info);
+ type_register_static(&pl181_info);
}
device_init(pl181_register_devices)
diff --git a/hw/pl190.c b/hw/pl190.c
index 6fc2656..956ab21 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -255,18 +255,27 @@
}
};
-static SysBusDeviceInfo pl190_info = {
- .init = pl190_init,
- .qdev.name = "pl190",
- .qdev.size = sizeof(pl190_state),
- .qdev.vmsd = &vmstate_pl190,
- .qdev.reset = pl190_reset,
- .qdev.no_user = 1,
+static void pl190_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl190_init;
+ dc->no_user = 1;
+ dc->reset = pl190_reset;
+ dc->vmsd = &vmstate_pl190;
+}
+
+static TypeInfo pl190_info = {
+ .name = "pl190",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl190_state),
+ .class_init = pl190_class_init,
};
static void pl190_register_devices(void)
{
- sysbus_register_withprop(&pl190_info);
+ type_register_static(&pl190_info);
}
device_init(pl190_register_devices)
diff --git a/hw/ppc440.c b/hw/ppc440.c
deleted file mode 100644
index cd8a95d..0000000
--- a/hw/ppc440.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Qemu PowerPC 440 chip emulation
- *
- * Copyright 2007 IBM Corporation.
- * Authors:
- * Jerone Young <jyoung5@us.ibm.com>
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- * Hollis Blanchard <hollisb@us.ibm.com>
- *
- * This work is licensed under the GNU GPL license version 2 or later.
- *
- */
-
-#include "hw.h"
-#include "pc.h"
-#include "isa.h"
-#include "ppc.h"
-#include "ppc4xx.h"
-#include "ppc440.h"
-#include "ppc405.h"
-#include "sysemu.h"
-#include "kvm.h"
-
-#define PPC440EP_PCI_CONFIG 0xeec00000
-#define PPC440EP_PCI_INTACK 0xeed00000
-#define PPC440EP_PCI_SPECIAL 0xeed00000
-#define PPC440EP_PCI_REGS 0xef400000
-#define PPC440EP_PCI_IO 0xe8000000
-#define PPC440EP_PCI_IOLEN 0x00010000
-
-#define PPC440EP_SDRAM_NR_BANKS 4
-
-static const unsigned int ppc440ep_sdram_bank_sizes[] = {
- 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
-};
-
-CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size,
- PCIBus **pcip, const unsigned int pci_irq_nrs[4],
- int do_init, const char *cpu_model)
-{
- MemoryRegion *ram_memories
- = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
- target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
- target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
- CPUState *env;
- qemu_irq *pic;
- qemu_irq *irqs;
- qemu_irq *pci_irqs;
-
- if (cpu_model == NULL) {
- cpu_model = "440-Xilinx"; // XXX: should be 440EP
- }
- env = cpu_init(cpu_model);
- if (!env) {
- fprintf(stderr, "Unable to initialize CPU!\n");
- exit(1);
- }
-
- ppc_dcr_init(env, NULL, NULL);
-
- /* interrupt controller */
- irqs = g_malloc0(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);
-
- /* SDRAM controller */
- memset(ram_bases, 0, sizeof(ram_bases));
- memset(ram_sizes, 0, sizeof(ram_sizes));
- *ram_size = ppc4xx_sdram_adjust(*ram_size, PPC440EP_SDRAM_NR_BANKS,
- ram_memories,
- ram_bases, ram_sizes,
- ppc440ep_sdram_bank_sizes);
- /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
- ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
- ram_bases, ram_sizes, do_init);
-
- /* PCI */
- pci_irqs = g_malloc(sizeof(qemu_irq) * 4);
- pci_irqs[0] = pic[pci_irq_nrs[0]];
- pci_irqs[1] = pic[pci_irq_nrs[1]];
- pci_irqs[2] = pic[pci_irq_nrs[2]];
- pci_irqs[3] = pic[pci_irq_nrs[3]];
- *pcip = ppc4xx_pci_init(env, pci_irqs,
- PPC440EP_PCI_CONFIG,
- PPC440EP_PCI_INTACK,
- PPC440EP_PCI_SPECIAL,
- PPC440EP_PCI_REGS);
- if (!*pcip)
- printf("couldn't create PCI controller!\n");
-
- isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
-
- if (serial_hds[0] != NULL) {
- serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
- DEVICE_BIG_ENDIAN);
- }
- if (serial_hds[1] != NULL) {
- serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
- DEVICE_BIG_ENDIAN);
- }
-
- return env;
-}
diff --git a/hw/ppc440.h b/hw/ppc440.h
deleted file mode 100644
index 9c27c36..0000000
--- a/hw/ppc440.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Qemu PowerPC 440 board emualtion
- *
- * Copyright 2007 IBM Corporation.
- * Authors: Jerone Young <jyoung5@us.ibm.com>
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- *
- * This work is licensed under the GNU GPL licence version 2 or later
- *
- */
-
-#ifndef QEMU_PPC440_H
-#define QEMU_PPC440_H
-
-#include "hw.h"
-
-CPUState *ppc440ep_init(MemoryRegion *address_space, ram_addr_t *ram_size,
- PCIBus **pcip, const unsigned int pci_irq_nrs[4],
- int do_init, const char *cpu_model);
-
-#endif
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index b734e3a..f86b168 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -3,9 +3,9 @@
*
* Copyright 2007 IBM Corporation.
* Authors:
- * Jerone Young <jyoung5@us.ibm.com>
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- * Hollis Blanchard <hollisb@us.ibm.com>
+ * Jerone Young <jyoung5@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
*
* This work is licensed under the GNU GPL license version 2 or later.
*
@@ -17,13 +17,17 @@
#include "hw.h"
#include "pci.h"
#include "boards.h"
-#include "ppc440.h"
#include "kvm.h"
#include "kvm_ppc.h"
#include "device_tree.h"
#include "loader.h"
#include "elf.h"
#include "exec-memory.h"
+#include "pc.h"
+#include "ppc.h"
+#include "ppc405.h"
+#include "sysemu.h"
+#include "sysbus.h"
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
@@ -32,6 +36,21 @@
#define FDT_ADDR 0x1800000
#define RAMDISK_ADDR 0x1900000
+#define PPC440EP_PCI_CONFIG 0xeec00000
+#define PPC440EP_PCI_INTACK 0xeed00000
+#define PPC440EP_PCI_SPECIAL 0xeed00000
+#define PPC440EP_PCI_REGS 0xef400000
+#define PPC440EP_PCI_IO 0xe8000000
+#define PPC440EP_PCI_IOLEN 0x00010000
+
+#define PPC440EP_SDRAM_NR_BANKS 4
+
+static const unsigned int ppc440ep_sdram_bank_sizes[] = {
+ 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
+};
+
+static target_phys_addr_t entry;
+
static int bamboo_load_device_tree(target_phys_addr_t addr,
uint32_t ramsize,
target_phys_addr_t initrd_base,
@@ -101,6 +120,42 @@
return ret;
}
+/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
+static void mmubooke_create_initial_mapping(CPUState *env,
+ target_ulong va,
+ target_phys_addr_t pa)
+{
+ ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 1 << 31; /* up to 0x80000000 */
+ tlb->EPN = va & TARGET_PAGE_MASK;
+ tlb->RPN = pa & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+
+ tlb = &env->tlb.tlbe[1];
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 1 << 31; /* up to 0xffffffff */
+ tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
+ tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+
+ cpu_reset(env);
+ env->gpr[1] = (16<<20) - 8;
+ env->gpr[3] = FDT_ADDR;
+ env->nip = entry;
+
+ /* Create a mapping for the kernel. */
+ mmubooke_create_initial_mapping(env, 0, 0);
+}
+
static void bamboo_init(ram_addr_t ram_size,
const char *boot_device,
const char *kernel_filename,
@@ -110,19 +165,76 @@
{
unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *ram_memories
+ = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
+ target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
+ target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
+ qemu_irq *pic;
+ qemu_irq *irqs;
PCIBus *pcibus;
CPUState *env;
uint64_t elf_entry;
uint64_t elf_lowaddr;
- target_phys_addr_t entry = 0;
target_phys_addr_t loadaddr = 0;
target_long initrd_size = 0;
+ DeviceState *dev;
int success;
int i;
/* Setup CPU. */
- env = ppc440ep_init(address_space_mem, &ram_size, &pcibus,
- pci_irq_nrs, 1, cpu_model);
+ if (cpu_model == NULL) {
+ cpu_model = "440EP";
+ }
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to initialize CPU!\n");
+ exit(1);
+ }
+
+ qemu_register_reset(main_cpu_reset, env);
+ ppc_booke_timers_init(env, 400000000, 0);
+ ppc_dcr_init(env, NULL, NULL);
+
+ /* interrupt controller */
+ irqs = g_malloc0(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);
+
+ /* SDRAM controller */
+ memset(ram_bases, 0, sizeof(ram_bases));
+ memset(ram_sizes, 0, sizeof(ram_sizes));
+ ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS,
+ ram_memories,
+ ram_bases, ram_sizes,
+ ppc440ep_sdram_bank_sizes);
+ /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
+ ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
+ ram_bases, ram_sizes, 1);
+
+ /* PCI */
+ dev = sysbus_create_varargs("ppc4xx-pcihost", PPC440EP_PCI_CONFIG,
+ pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
+ pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
+ NULL);
+ pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+ if (!pcibus) {
+ fprintf(stderr, "couldn't create PCI controller!\n");
+ exit(1);
+ }
+
+ isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
+
+ if (serial_hds[0] != NULL) {
+ serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+ PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+ DEVICE_BIG_ENDIAN);
+ }
+ if (serial_hds[1] != NULL) {
+ serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+ PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+ DEVICE_BIG_ENDIAN);
+ }
if (pcibus) {
/* Register network interfaces. */
@@ -169,12 +281,6 @@
fprintf(stderr, "couldn't load device tree\n");
exit(1);
}
-
- /* Set initial guest state. */
- env->gpr[1] = (16<<20) - 8;
- env->gpr[3] = FDT_ADDR;
- env->nip = entry;
- /* XXX we currently depend on KVM to create some initial TLB entries. */
}
if (kvm_enabled())
@@ -182,34 +288,14 @@
}
static QEMUMachine bamboo_machine = {
- .name = "bamboo-0.13",
- .alias = "bamboo",
+ .name = "bamboo",
.desc = "bamboo",
.init = bamboo_init,
};
-static QEMUMachine bamboo_machine_v0_12 = {
- .name = "bamboo-0.12",
- .desc = "bamboo",
- .init = bamboo_init,
- .compat_props = (GlobalProperty[]) {
- {
- .driver = "virtio-serial-pci",
- .property = "max_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },
- { /* end of list */ }
- },
-};
-
static void bamboo_machine_init(void)
{
qemu_register_machine(&bamboo_machine);
- qemu_register_machine(&bamboo_machine_v0_12);
}
machine_init(bamboo_machine_init);
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 2c69210..d11f120 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -49,13 +49,14 @@
#define PPC4xx_PCI_NR_PTMS 2
struct PPC4xxPCIState {
+ PCIHostState pci_state;
+
struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
+ qemu_irq irq[4];
- PCIHostState pci_state;
- PCIDevice *pci_dev;
- MemoryRegion iomem_addr;
- MemoryRegion iomem_regs;
+ MemoryRegion container;
+ MemoryRegion iomem;
};
typedef struct PPC4xxPCIState PPC4xxPCIState;
@@ -83,8 +84,10 @@
#define PCIL0_PTM1LA 0x34
#define PCIL0_PTM2MS 0x38
#define PCIL0_PTM2LA 0x3c
+#define PCI_REG_BASE 0x800000
#define PCI_REG_SIZE 0x40
+#define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE)
static uint64_t pci4xx_cfgaddr_read(void *opaque, target_phys_addr_t addr,
unsigned size)
@@ -275,6 +278,10 @@
qemu_irq *pci_irqs = opaque;
DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
+ if (irq_num < 0) {
+ fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num);
+ return;
+ }
qemu_set_irq(pci_irqs[irq_num], level);
}
@@ -310,7 +317,6 @@
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState),
VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1,
vmstate_pci_master_map,
struct PCIMasterMap),
@@ -322,60 +328,81 @@
};
/* XXX Interrupt acknowledge cycles not supported. */
-PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
- target_phys_addr_t config_space,
- target_phys_addr_t int_ack,
- target_phys_addr_t special_cycle,
- target_phys_addr_t registers)
+static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
{
- PPC4xxPCIState *controller;
- static int ppc4xx_pci_id;
- uint8_t *pci_conf;
+ PPC4xxPCIState *s;
+ PCIHostState *h;
+ PCIBus *b;
+ int i;
- controller = g_malloc0(sizeof(PPC4xxPCIState));
+ h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+ s = DO_UPCAST(PPC4xxPCIState, pci_state, h);
- controller->pci_state.bus = pci_register_bus(NULL, "pci",
- ppc4xx_pci_set_irq,
- ppc4xx_pci_map_irq,
- pci_irqs,
- get_system_memory(),
- get_system_io(),
- 0, 4);
+ for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+ sysbus_init_irq(dev, &s->irq[i]);
+ }
- controller->pci_dev = pci_register_device(controller->pci_state.bus,
- "host bridge", sizeof(PCIDevice),
- 0, NULL, NULL);
- pci_conf = controller->pci_dev->config;
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_440GX);
- pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
+ b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, ppc4xx_pci_set_irq,
+ ppc4xx_pci_map_irq, s->irq, get_system_memory(),
+ get_system_io(), 0, 4);
+ s->pci_state.bus = b;
- /* CFGADDR */
- memory_region_init_io(&controller->iomem_addr, &pci4xx_cfgaddr_ops,
- controller, "pci.cfgaddr", 4);
- memory_region_add_subregion(get_system_memory(),
- config_space + PCIC0_CFGADDR,
- &controller->iomem_addr);
+ pci_create_simple(b, 0, "ppc4xx-host-bridge");
- /* CFGDATA */
- memory_region_init_io(&controller->pci_state.data_mem,
- &pci_host_data_be_ops,
- &controller->pci_state, "pci-conf-data", 4);
- memory_region_add_subregion(get_system_memory(),
- config_space + PCIC0_CFGDATA,
- &controller->pci_state.data_mem);
+ /* XXX split into 2 memory regions, one for config space, one for regs */
+ memory_region_init(&s->container, "pci-container", PCI_ALL_SIZE);
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, h,
+ "pci-conf-idx", 4);
+ memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h,
+ "pci-conf-data", 4);
+ memory_region_init_io(&s->iomem, &pci_reg_ops, s,
+ "pci.reg", PCI_REG_SIZE);
+ memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
+ memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
+ memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem);
+ sysbus_init_mmio(dev, &s->container);
+ qemu_register_reset(ppc4xx_pci_reset, s);
- /* Internal registers */
- memory_region_init_io(&controller->iomem_regs, &pci_reg_ops, controller,
- "pci.regs", PCI_REG_SIZE);
- memory_region_add_subregion(get_system_memory(), registers,
- &controller->iomem_regs);
-
- qemu_register_reset(ppc4xx_pci_reset, controller);
-
- /* XXX load/save code not tested. */
- vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++,
- &vmstate_ppc4xx_pci, controller);
-
- return controller->pci_state.bus;
+ return 0;
}
+
+static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "Host bridge";
+ k->vendor_id = PCI_VENDOR_ID_IBM;
+ k->device_id = PCI_DEVICE_ID_IBM_440GX;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static TypeInfo ppc4xx_host_bridge_info = {
+ .name = "ppc4xx-host-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = ppc4xx_host_bridge_class_init,
+};
+
+static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = ppc4xx_pcihost_initfn;
+ dc->vmsd = &vmstate_ppc4xx_pci;
+}
+
+static TypeInfo ppc4xx_pcihost_info = {
+ .name = "ppc4xx-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PPC4xxPCIState),
+ .class_init = ppc4xx_pcihost_class_init,
+};
+
+static void ppc4xx_pci_register(void)
+{
+ type_register_static(&ppc4xx_pcihost_info);
+ type_register_static(&ppc4xx_host_bridge_info);
+}
+device_init(ppc4xx_pci_register);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index a746c9c..506187b 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -311,7 +311,7 @@
exit(1);
}
}
- pic = openpic_init(NULL, &pic_mem, smp_cpus, openpic_irqs, NULL);
+ pic = openpic_init(&pic_mem, smp_cpus, openpic_irqs, NULL);
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
/* 970 gets a U3 bus */
pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 47dab3f..eb43fb5 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -29,7 +29,7 @@
#include "sysemu.h"
#include "isa.h"
#include "pci.h"
-#include "prep_pci.h"
+#include "pci_host.h"
#include "usb-ohci.h"
#include "ppc.h"
#include "boards.h"
@@ -83,37 +83,9 @@
static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-//static ISADevice *pit;
-
/* ISA IO ports bridge */
#define PPC_IO_BASE 0x80000000
-#if 0
-/* Speaker port 0x61 */
-static int speaker_data_on;
-static int dummy_refresh_clock;
-#endif
-
-static void speaker_ioport_write (void *opaque, uint32_t addr, uint32_t val)
-{
-#if 0
- speaker_data_on = (val >> 1) & 1;
- pit_set_gate(pit, 2, val & 1);
-#endif
-}
-
-static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
-{
-#if 0
- int out;
- out = pit_get_out(pit, 2, qemu_get_clock_ns(vm_clock));
- dummy_refresh_clock ^= 1;
- return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
- (dummy_refresh_clock << 4);
-#endif
- return 0;
-}
-
/* PCI intack register */
/* Read-only register (?) */
static void PPC_intack_write (void *opaque, target_phys_addr_t addr,
@@ -522,9 +494,12 @@
MemoryRegion *bios = g_new(MemoryRegion, 1);
uint32_t kernel_base, initrd_base;
long kernel_size, initrd_size;
+ DeviceState *dev;
+ SysBusDevice *sys;
+ PCIHostState *pcihost;
PCIBus *pci_bus;
+ PCIDevice *pci;
ISABus *isa_bus;
- qemu_irq *i8259;
qemu_irq *cpu_exit_irq;
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@@ -560,6 +535,8 @@
/* allocate and load BIOS */
memory_region_init_ram(bios, "ppc_prep.bios", BIOS_SIZE);
+ memory_region_set_readonly(bios, true);
+ memory_region_add_subregion(sysmem, (uint32_t)(-BIOS_SIZE), bios);
vmstate_register_ram_global(bios);
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
@@ -573,8 +550,6 @@
target_phys_addr_t bios_addr;
bios_size = (bios_size + 0xfff) & ~0xfff;
bios_addr = (uint32_t)(-bios_size);
- memory_region_set_readonly(bios, true);
- memory_region_add_subregion(sysmem, bios_addr, bios);
bios_size = load_image_targphys(filename, bios_addr, bios_size);
}
if (bios_size < 0 || bios_size > BIOS_SIZE) {
@@ -626,16 +601,34 @@
}
}
- isa_mem_base = 0xc0000000;
if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
hw_error("Only 6xx bus is supported on PREP machine\n");
}
- /* Hmm, prep has no pci-isa bridge ??? */
- isa_bus = isa_bus_new(NULL, get_system_io());
- i8259 = i8259_init(isa_bus, first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
- pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io());
- isa_bus_irqs(isa_bus, i8259);
- // pci_bus = i440fx_init();
+
+ dev = qdev_create(NULL, "raven-pcihost");
+ sys = sysbus_from_qdev(dev);
+ pcihost = DO_UPCAST(PCIHostState, busdev, sys);
+ pcihost->address_space = get_system_memory();
+ qdev_init_nofail(dev);
+ object_property_add_child(object_get_root(), "raven", OBJECT(dev), NULL);
+ pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+ if (pci_bus == NULL) {
+ fprintf(stderr, "Couldn't create PCI host controller.\n");
+ exit(1);
+ }
+
+ /* PCI -> ISA bridge */
+ pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
+ cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+ qdev_connect_gpio_out(&pci->qdev, 0,
+ first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
+ qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq);
+ sysbus_connect_irq(&pcihost->busdev, 0, qdev_get_gpio_in(&pci->qdev, 9));
+ sysbus_connect_irq(&pcihost->busdev, 1, qdev_get_gpio_in(&pci->qdev, 11));
+ sysbus_connect_irq(&pcihost->busdev, 2, qdev_get_gpio_in(&pci->qdev, 9));
+ sysbus_connect_irq(&pcihost->busdev, 3, qdev_get_gpio_in(&pci->qdev, 11));
+ isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&pci->qdev, "isa.0"));
+
/* Register 8 MB of ISA IO space (needed for non-contiguous map) */
memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl,
"ppc-io", 0x00800000);
@@ -643,9 +636,6 @@
/* init basic PC hardware */
pci_vga_init(pci_bus);
- // openpic = openpic_init(0x00000000, 0xF0000000, 1);
- // pit = pit_init(0x40, 0);
- rtc_init(isa_bus, 2000, NULL);
if (serial_hds[0])
serial_isa_init(isa_bus, 0, serial_hds[0]);
@@ -672,9 +662,6 @@
}
isa_create_simple(isa_bus, "i8042");
- cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
- DMA_init(1, cpu_exit_irq);
-
// SB16_init();
for(i = 0; i < MAX_FD; i++) {
@@ -682,9 +669,6 @@
}
fdctrl_init_isa(isa_bus, fd);
- /* Register speaker port */
- register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
- register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
/* Register fake IO ports for PREP */
sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET];
register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
@@ -707,7 +691,7 @@
usb_ohci_init_pci(pci_bus, -1);
}
- m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
+ m48t59 = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
if (m48t59 == NULL)
return;
sysctrl->nvram = m48t59;
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index b606206..d5bce71 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -339,25 +339,43 @@
return 0;
}
-static PCIDeviceInfo e500_host_bridge_info = {
- .qdev.name = "e500-host-bridge",
- .qdev.desc = "Host bridge",
- .qdev.size = sizeof(PCIDevice),
- .vendor_id = PCI_VENDOR_ID_FREESCALE,
- .device_id = PCI_DEVICE_ID_MPC8533E,
- .class_id = PCI_CLASS_PROCESSOR_POWERPC,
+static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->vendor_id = PCI_VENDOR_ID_FREESCALE;
+ k->device_id = PCI_DEVICE_ID_MPC8533E;
+ k->class_id = PCI_CLASS_PROCESSOR_POWERPC;
+ dc->desc = "Host bridge";
+}
+
+static TypeInfo e500_host_bridge_info = {
+ .name = "e500-host-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = e500_host_bridge_class_init,
};
-static SysBusDeviceInfo e500_pcihost_info = {
- .init = e500_pcihost_initfn,
- .qdev.name = "e500-pcihost",
- .qdev.size = sizeof(PPCE500PCIState),
- .qdev.vmsd = &vmstate_ppce500_pci,
+static void e500_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = e500_pcihost_initfn;
+ dc->vmsd = &vmstate_ppce500_pci;
+}
+
+static TypeInfo e500_pcihost_info = {
+ .name = "e500-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PPCE500PCIState),
+ .class_init = e500_pcihost_class_init,
};
static void e500_pci_register(void)
{
- sysbus_register_withprop(&e500_pcihost_info);
- pci_qdev_register(&e500_host_bridge_info);
+ type_register_static(&e500_pcihost_info);
+ type_register_static(&e500_host_bridge_info);
}
device_init(e500_pci_register);
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
index e7b1453..9d648ec 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -203,14 +203,22 @@
return 0;
}
-static SysBusDeviceInfo ppce500_spin_info = {
- .init = ppce500_spin_initfn,
- .qdev.name = "e500-spin",
- .qdev.size = sizeof(SpinState),
+static void ppce500_spin_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ppce500_spin_initfn;
+}
+
+static TypeInfo ppce500_spin_info = {
+ .name = "e500-spin",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SpinState),
+ .class_init = ppce500_spin_class_init,
};
static void ppce500_spin_register(void)
{
- sysbus_register_withprop(&ppce500_spin_info);
+ type_register_static(&ppce500_spin_info);
}
device_init(ppce500_spin_register);
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index ea9fb69..40b8bb0 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -25,9 +25,16 @@
#include "hw.h"
#include "pci.h"
#include "pci_host.h"
-#include "prep_pci.h"
+#include "exec-memory.h"
-typedef PCIHostState PREPPCIState;
+typedef struct PRePPCIState {
+ PCIHostState host_state;
+ qemu_irq irq[4];
+} PREPPCIState;
+
+typedef struct RavenPCIState {
+ PCIDevice dev;
+} RavenPCIState;
static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
{
@@ -40,58 +47,24 @@
return (addr & 0x7ff) | (i << 11);
}
-static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
+static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned int size)
{
PREPPCIState *s = opaque;
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
+ pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, size);
}
-static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
+static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
{
PREPPCIState *s = opaque;
- val = bswap16(val);
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
-}
-
-static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PREPPCIState *s = opaque;
- val = bswap32(val);
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
-}
-
-static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
-{
- PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
- return val;
-}
-
-static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
-{
- PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2);
- val = bswap16(val);
- return val;
-}
-
-static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
-{
- PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4);
- val = bswap32(val);
- return val;
+ return pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), size);
}
static const MemoryRegionOps PPC_PCIIO_ops = {
- .old_mmio = {
- .read = { PPC_PCIIO_readb, PPC_PCIIO_readw, PPC_PCIIO_readl, },
- .write = { PPC_PCIIO_writeb, PPC_PCIIO_writew, PPC_PCIIO_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .read = ppc_pci_io_read,
+ .write = ppc_pci_io_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -103,46 +76,107 @@
{
qemu_irq *pic = opaque;
- qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level);
+ qemu_set_irq(pic[irq_num] , level);
}
-PCIBus *pci_prep_init(qemu_irq *pic,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io)
+static int raven_pcihost_init(SysBusDevice *dev)
{
- PREPPCIState *s;
- PCIDevice *d;
+ PCIHostState *h = FROM_SYSBUS(PCIHostState, dev);
+ PREPPCIState *s = DO_UPCAST(PREPPCIState, host_state, h);
+ MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *address_space_io = get_system_io();
+ PCIBus *bus;
+ int i;
- s = g_malloc0(sizeof(PREPPCIState));
- s->bus = pci_register_bus(NULL, "pci",
- prep_set_irq, prep_map_irq, pic,
- address_space_mem,
- address_space_io,
- 0, 4);
+ for (i = 0; i < 4; i++) {
+ sysbus_init_irq(dev, &s->irq[i]);
+ }
- memory_region_init_io(&s->conf_mem, &pci_host_conf_be_ops, s,
+ bus = pci_register_bus(&h->busdev.qdev, NULL,
+ prep_set_irq, prep_map_irq, s->irq,
+ address_space_mem, address_space_io, 0, 4);
+ h->bus = bus;
+
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, s,
"pci-conf-idx", 1);
- memory_region_add_subregion(address_space_io, 0xcf8, &s->conf_mem);
- sysbus_init_ioports(&s->busdev, 0xcf8, 1);
+ sysbus_add_io(dev, 0xcf8, &h->conf_mem);
+ sysbus_init_ioports(&h->busdev, 0xcf8, 1);
- memory_region_init_io(&s->data_mem, &pci_host_data_be_ops, s,
+ memory_region_init_io(&h->data_mem, &pci_host_data_be_ops, s,
"pci-conf-data", 1);
- memory_region_add_subregion(address_space_io, 0xcfc, &s->data_mem);
- sysbus_init_ioports(&s->busdev, 0xcfc, 1);
+ sysbus_add_io(dev, 0xcfc, &h->data_mem);
+ sysbus_init_ioports(&h->busdev, 0xcfc, 1);
- memory_region_init_io(&s->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000);
- memory_region_add_subregion(address_space_mem, 0x80800000, &s->mmcfg);
+ memory_region_init_io(&h->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000);
+ memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
- /* PCI host bridge */
- d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
- sizeof(PCIDevice), 0, NULL, NULL);
- pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
- pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_RAVEN);
- d->config[0x08] = 0x00; // revision
- pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+ pci_create_simple(bus, 0, "raven");
+
+ return 0;
+}
+
+static int raven_init(PCIDevice *d)
+{
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x34] = 0x00; // capabilities_pointer
- return s->bus;
+ return 0;
}
+
+static const VMStateDescription vmstate_raven = {
+ .name = "raven",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, RavenPCIState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void raven_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = raven_init;
+ k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
+ k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ dc->desc = "PReP Host Bridge - Motorola Raven";
+ dc->vmsd = &vmstate_raven;
+ dc->no_user = 1;
+}
+
+static TypeInfo raven_info = {
+ .name = "raven",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(RavenPCIState),
+ .class_init = raven_class_init,
+};
+
+static void raven_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = raven_pcihost_init;
+ dc->fw_name = "pci";
+ dc->no_user = 1;
+}
+
+static TypeInfo raven_pcihost_info = {
+ .name = "raven-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PREPPCIState),
+ .class_init = raven_pcihost_class_init,
+};
+
+static void raven_register_devices(void)
+{
+ type_register_static(&raven_pcihost_info);
+ type_register_static(&raven_info);
+}
+
+device_init(raven_register_devices)
diff --git a/hw/prep_pci.h b/hw/prep_pci.h
deleted file mode 100644
index b6b481a..0000000
--- a/hw/prep_pci.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef QEMU_PREP_PCI_H
-#define QEMU_PREP_PCI_H
-
-#include "qemu-common.h"
-#include "memory.h"
-
-PCIBus *pci_prep_init(qemu_irq *pic,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io);
-
-#endif
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 6ddd500..244c614 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1233,17 +1233,26 @@
},
};
-static SysBusDeviceInfo pxa2xx_rtc_sysbus_info = {
- .init = pxa2xx_rtc_init,
- .qdev.name = "pxa2xx_rtc",
- .qdev.desc = "PXA2xx RTC Controller",
- .qdev.size = sizeof(PXA2xxRTCState),
- .qdev.vmsd = &vmstate_pxa2xx_rtc_regs,
+static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_rtc_init;
+ dc->desc = "PXA2xx RTC Controller";
+ dc->vmsd = &vmstate_pxa2xx_rtc_regs;
+}
+
+static TypeInfo pxa2xx_rtc_sysbus_info = {
+ .name = "pxa2xx_rtc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxRTCState),
+ .class_init = pxa2xx_rtc_sysbus_class_init,
};
/* I2C Interface */
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
PXA2xxI2CState *host;
} PXA2xxI2CSlaveState;
@@ -1279,7 +1288,7 @@
}
/* These are only stubs now. */
-static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
+static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
@@ -1303,7 +1312,7 @@
pxa2xx_i2c_update(s);
}
-static int pxa2xx_i2c_rx(i2c_slave *i2c)
+static int pxa2xx_i2c_rx(I2CSlave *i2c)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
@@ -1318,7 +1327,7 @@
return s->data;
}
-static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data)
+static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
@@ -1466,19 +1475,27 @@
}
};
-static int pxa2xx_i2c_slave_init(i2c_slave *i2c)
+static int pxa2xx_i2c_slave_init(I2CSlave *i2c)
{
/* Nothing to do. */
return 0;
}
-static I2CSlaveInfo pxa2xx_i2c_slave_info = {
- .qdev.name = "pxa2xx-i2c-slave",
- .qdev.size = sizeof(PXA2xxI2CSlaveState),
- .init = pxa2xx_i2c_slave_init,
- .event = pxa2xx_i2c_event,
- .recv = pxa2xx_i2c_rx,
- .send = pxa2xx_i2c_tx
+static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = pxa2xx_i2c_slave_init;
+ k->event = pxa2xx_i2c_event;
+ k->recv = pxa2xx_i2c_rx;
+ k->send = pxa2xx_i2c_tx;
+}
+
+static TypeInfo pxa2xx_i2c_slave_info = {
+ .name = "pxa2xx-i2c-slave",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(PXA2xxI2CSlaveState),
+ .class_init = pxa2xx_i2c_slave_class_init,
};
PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
@@ -1526,17 +1543,28 @@
return s->bus;
}
-static SysBusDeviceInfo pxa2xx_i2c_info = {
- .init = pxa2xx_i2c_initfn,
- .qdev.name = "pxa2xx_i2c",
- .qdev.desc = "PXA2xx I2C Bus Controller",
- .qdev.size = sizeof(PXA2xxI2CState),
- .qdev.vmsd = &vmstate_pxa2xx_i2c,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
- DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pxa2xx_i2c_properties[] = {
+ DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
+ DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_i2c_initfn;
+ dc->desc = "PXA2xx I2C Bus Controller";
+ dc->vmsd = &vmstate_pxa2xx_i2c;
+ dc->props = pxa2xx_i2c_properties;
+}
+
+static TypeInfo pxa2xx_i2c_info = {
+ .name = "pxa2xx_i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxI2CState),
+ .class_init = pxa2xx_i2c_class_init,
};
/* PXA Inter-IC Sound Controller */
@@ -2288,12 +2316,26 @@
return s;
}
+static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pxa2xx_ssp_init;
+}
+
+static TypeInfo pxa2xx_ssp_info = {
+ .name = "pxa2xx-ssp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxSSPState),
+ .class_init = pxa2xx_ssp_class_init,
+};
+
static void pxa2xx_register_devices(void)
{
- i2c_register_slave(&pxa2xx_i2c_slave_info);
- sysbus_register_dev("pxa2xx-ssp", sizeof(PXA2xxSSPState), pxa2xx_ssp_init);
- sysbus_register_withprop(&pxa2xx_i2c_info);
- sysbus_register_withprop(&pxa2xx_rtc_sysbus_info);
+ type_register_static(&pxa2xx_i2c_slave_info);
+ type_register_static(&pxa2xx_ssp_info);
+ type_register_static(&pxa2xx_i2c_info);
+ type_register_static(&pxa2xx_rtc_sysbus_info);
}
device_init(pxa2xx_register_devices)
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index cb28107..2d61565 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -543,20 +543,31 @@
},
};
-static SysBusDeviceInfo pxa2xx_dma_info = {
- .init = pxa2xx_dma_init,
- .qdev.name = "pxa2xx-dma",
- .qdev.desc = "PXA2xx DMA controller",
- .qdev.size = sizeof(PXA2xxDMAState),
- .qdev.vmsd = &vmstate_pxa2xx_dma,
- .qdev.props = (Property[]) {
- DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pxa2xx_dma_properties[] = {
+ DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_dma_init;
+ dc->desc = "PXA2xx DMA controller";
+ dc->vmsd = &vmstate_pxa2xx_dma;
+ dc->props = pxa2xx_dma_properties;
+}
+
+static TypeInfo pxa2xx_dma_info = {
+ .name = "pxa2xx-dma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxDMAState),
+ .class_init = pxa2xx_dma_class_init,
};
static void pxa2xx_dma_register(void)
{
- sysbus_register_withprop(&pxa2xx_dma_info);
+ type_register_static(&pxa2xx_dma_info);
}
device_init(pxa2xx_dma_register);
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index cc58c40..67fd17c 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -317,20 +317,31 @@
},
};
-static SysBusDeviceInfo pxa2xx_gpio_info = {
- .init = pxa2xx_gpio_initfn,
- .qdev.name = "pxa2xx-gpio",
- .qdev.desc = "PXA2xx GPIO controller",
- .qdev.size = sizeof(PXA2xxGPIOInfo),
- .qdev.props = (Property []) {
- DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
- DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property pxa2xx_gpio_properties[] = {
+ DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
+ DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_gpio_initfn;
+ dc->desc = "PXA2xx GPIO controller";
+ dc->props = pxa2xx_gpio_properties;
+}
+
+static TypeInfo pxa2xx_gpio_info = {
+ .name = "pxa2xx-gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxGPIOInfo),
+ .class_init = pxa2xx_gpio_class_init,
};
static void pxa2xx_gpio_register(void)
{
- sysbus_register_withprop(&pxa2xx_gpio_info);
+ type_register_static(&pxa2xx_gpio_info);
}
device_init(pxa2xx_gpio_register);
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
index 92effbc..ca85743 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -296,16 +296,25 @@
return 0;
}
-static SysBusDeviceInfo pxa2xx_pic_info = {
- .init = pxa2xx_pic_initfn,
- .qdev.name = "pxa2xx_pic",
- .qdev.desc = "PXA2xx PIC",
- .qdev.size = sizeof(PXA2xxPICState),
- .qdev.vmsd = &vmstate_pxa2xx_pic_regs,
+static void pxa2xx_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_pic_initfn;
+ dc->desc = "PXA2xx PIC";
+ dc->vmsd = &vmstate_pxa2xx_pic_regs;
+}
+
+static TypeInfo pxa2xx_pic_info = {
+ .name = "pxa2xx_pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxPICState),
+ .class_init = pxa2xx_pic_class_init,
};
static void pxa2xx_pic_register(void)
{
- sysbus_register_withprop(&pxa2xx_pic_info);
+ type_register_static(&pxa2xx_pic_info);
}
device_init(pxa2xx_pic_register);
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
index 50e2678..9080075 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -477,37 +477,59 @@
}
};
-static SysBusDeviceInfo pxa25x_timer_dev_info = {
- .init = pxa2xx_timer_init,
- .qdev.name = "pxa25x-timer",
- .qdev.desc = "PXA25x timer",
- .qdev.size = sizeof(PXA2xxTimerInfo),
- .qdev.vmsd = &vmstate_pxa2xx_timer_regs,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
- DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
- PXA2XX_TIMER_HAVE_TM4, false),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pxa25x_timer_dev_properties[] = {
+ DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
+ DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+ PXA2XX_TIMER_HAVE_TM4, false),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo pxa27x_timer_dev_info = {
- .init = pxa2xx_timer_init,
- .qdev.name = "pxa27x-timer",
- .qdev.desc = "PXA27x timer",
- .qdev.size = sizeof(PXA2xxTimerInfo),
- .qdev.vmsd = &vmstate_pxa2xx_timer_regs,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
- DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
- PXA2XX_TIMER_HAVE_TM4, true),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_timer_init;
+ dc->desc = "PXA25x timer";
+ dc->vmsd = &vmstate_pxa2xx_timer_regs;
+ dc->props = pxa25x_timer_dev_properties;
+}
+
+static TypeInfo pxa25x_timer_dev_info = {
+ .name = "pxa25x-timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxTimerInfo),
+ .class_init = pxa25x_timer_dev_class_init,
+};
+
+static Property pxa27x_timer_dev_properties[] = {
+ DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
+ DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+ PXA2XX_TIMER_HAVE_TM4, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_timer_init;
+ dc->desc = "PXA27x timer";
+ dc->vmsd = &vmstate_pxa2xx_timer_regs;
+ dc->props = pxa27x_timer_dev_properties;
+}
+
+static TypeInfo pxa27x_timer_dev_info = {
+ .name = "pxa27x-timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxTimerInfo),
+ .class_init = pxa27x_timer_dev_class_init,
};
static void pxa2xx_timer_register(void)
{
- sysbus_register_withprop(&pxa25x_timer_dev_info);
- sysbus_register_withprop(&pxa27x_timer_dev_info);
+ type_register_static(&pxa25x_timer_dev_info);
+ type_register_static(&pxa27x_timer_dev_info);
};
device_init(pxa2xx_timer_register);
diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c
index 5ddda2d..5976dcd 100644
--- a/hw/qdev-addr.c
+++ b/hw/qdev-addr.c
@@ -18,9 +18,10 @@
return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr);
}
-static void get_taddr(DeviceState *dev, Visitor *v, void *opaque,
+static void get_taddr(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@@ -29,9 +30,10 @@
visit_type_int(v, &value, name, errp);
}
-static void set_taddr(DeviceState *dev, Visitor *v, void *opaque,
+static void set_taddr(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
new file mode 100644
index 0000000..135c2bf
--- /dev/null
+++ b/hw/qdev-monitor.c
@@ -0,0 +1,588 @@
+/*
+ * Dynamic device configuration and creation.
+ *
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qdev.h"
+#include "monitor.h"
+
+/*
+ * Aliases were a bad idea from the start. Let's keep them
+ * from spreading further.
+ */
+typedef struct QDevAlias
+{
+ const char *typename;
+ const char *alias;
+} QDevAlias;
+
+static const QDevAlias qdev_alias_table[] = {
+ { "virtio-blk-pci", "virtio-blk" },
+ { "virtio-net-pci", "virtio-net" },
+ { "virtio-serial-pci", "virtio-serial" },
+ { "virtio-balloon-pci", "virtio-balloon" },
+ { "virtio-blk-s390", "virtio-blk" },
+ { "virtio-net-s390", "virtio-net" },
+ { "virtio-serial-s390", "virtio-serial" },
+ { "lsi53c895a", "lsi" },
+ { "ich9-ahci", "ahci" },
+ { }
+};
+
+static const char *qdev_class_get_alias(DeviceClass *dc)
+{
+ const char *typename = object_class_get_name(OBJECT_CLASS(dc));
+ int i;
+
+ for (i = 0; qdev_alias_table[i].typename; i++) {
+ if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
+ return qdev_alias_table[i].alias;
+ }
+ }
+
+ return NULL;
+}
+
+static bool qdev_class_has_alias(DeviceClass *dc)
+{
+ return (qdev_class_get_alias(dc) != NULL);
+}
+
+static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
+{
+ DeviceClass *dc;
+ bool *show_no_user = opaque;
+
+ dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE);
+
+ if (!dc || (show_no_user && !*show_no_user && dc->no_user)) {
+ return;
+ }
+
+ error_printf("name \"%s\"", object_class_get_name(klass));
+ if (dc->bus_info) {
+ error_printf(", bus %s", dc->bus_info->name);
+ }
+ if (qdev_class_has_alias(dc)) {
+ error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
+ }
+ if (dc->desc) {
+ error_printf(", desc \"%s\"", dc->desc);
+ }
+ if (dc->no_user) {
+ error_printf(", no-user");
+ }
+ error_printf("\n");
+}
+
+static int set_property(const char *name, const char *value, void *opaque)
+{
+ DeviceState *dev = opaque;
+
+ if (strcmp(name, "driver") == 0)
+ return 0;
+ if (strcmp(name, "bus") == 0)
+ return 0;
+
+ if (qdev_prop_parse(dev, name, value) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+static const char *find_typename_by_alias(const char *alias)
+{
+ int i;
+
+ for (i = 0; qdev_alias_table[i].alias; i++) {
+ if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
+ return qdev_alias_table[i].typename;
+ }
+ }
+
+ return NULL;
+}
+
+int qdev_device_help(QemuOpts *opts)
+{
+ const char *driver;
+ Property *prop;
+ ObjectClass *klass;
+ DeviceClass *info;
+
+ driver = qemu_opt_get(opts, "driver");
+ if (driver && !strcmp(driver, "?")) {
+ bool show_no_user = false;
+ object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user);
+ return 1;
+ }
+
+ if (!driver || !qemu_opt_get(opts, "?")) {
+ return 0;
+ }
+
+ klass = object_class_by_name(driver);
+ if (!klass) {
+ const char *typename = find_typename_by_alias(driver);
+
+ if (typename) {
+ driver = typename;
+ klass = object_class_by_name(driver);
+ }
+ }
+
+ if (!klass) {
+ return 0;
+ }
+ info = DEVICE_CLASS(klass);
+
+ for (prop = info->props; prop && prop->name; prop++) {
+ /*
+ * TODO Properties without a parser are just for dirty hacks.
+ * qdev_prop_ptr is the only such PropertyInfo. It's marked
+ * for removal. This conditional should be removed along with
+ * it.
+ */
+ if (!prop->info->parse) {
+ continue; /* no way to set it, don't show */
+ }
+ error_printf("%s.%s=%s\n", driver, prop->name,
+ prop->info->legacy_name ?: prop->info->name);
+ }
+ if (info->bus_info) {
+ for (prop = info->bus_info->props; prop && prop->name; prop++) {
+ if (!prop->info->parse) {
+ continue; /* no way to set it, don't show */
+ }
+ error_printf("%s.%s=%s\n", driver, prop->name,
+ prop->info->legacy_name ?: prop->info->name);
+ }
+ }
+ return 1;
+}
+
+static Object *qdev_get_peripheral(void)
+{
+ static Object *dev;
+
+ if (dev == NULL) {
+ dev = object_new("container");
+ object_property_add_child(object_get_root(), "peripheral",
+ OBJECT(dev), NULL);
+ }
+
+ return dev;
+}
+
+static Object *qdev_get_peripheral_anon(void)
+{
+ static Object *dev;
+
+ if (dev == NULL) {
+ dev = object_new("container");
+ object_property_add_child(object_get_root(), "peripheral-anon",
+ OBJECT(dev), NULL);
+ }
+
+ return dev;
+}
+
+static void qbus_list_bus(DeviceState *dev)
+{
+ BusState *child;
+ const char *sep = " ";
+
+ error_printf("child busses at \"%s\":",
+ dev->id ? dev->id : object_get_typename(OBJECT(dev)));
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ error_printf("%s\"%s\"", sep, child->name);
+ sep = ", ";
+ }
+ error_printf("\n");
+}
+
+static void qbus_list_dev(BusState *bus)
+{
+ DeviceState *dev;
+ const char *sep = " ";
+
+ error_printf("devices at \"%s\":", bus->name);
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
+ if (dev->id)
+ error_printf("/\"%s\"", dev->id);
+ sep = ", ";
+ }
+ error_printf("\n");
+}
+
+static BusState *qbus_find_bus(DeviceState *dev, char *elem)
+{
+ BusState *child;
+
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ if (strcmp(child->name, elem) == 0) {
+ return child;
+ }
+ }
+ return NULL;
+}
+
+static DeviceState *qbus_find_dev(BusState *bus, char *elem)
+{
+ DeviceState *dev;
+
+ /*
+ * try to match in order:
+ * (1) instance id, if present
+ * (2) driver name
+ * (3) driver alias, if present
+ */
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ if (dev->id && strcmp(dev->id, elem) == 0) {
+ return dev;
+ }
+ }
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
+ return dev;
+ }
+ }
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+ if (qdev_class_has_alias(dc) &&
+ strcmp(qdev_class_get_alias(dc), elem) == 0) {
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+static BusState *qbus_find_recursive(BusState *bus, const char *name,
+ const BusInfo *info)
+{
+ DeviceState *dev;
+ BusState *child, *ret;
+ int match = 1;
+
+ if (name && (strcmp(bus->name, name) != 0)) {
+ match = 0;
+ }
+ if (info && (bus->info != info)) {
+ match = 0;
+ }
+ if (match) {
+ return bus;
+ }
+
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ ret = qbus_find_recursive(child, name, info);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+ return NULL;
+}
+
+static BusState *qbus_find(const char *path)
+{
+ DeviceState *dev;
+ BusState *bus;
+ char elem[128];
+ int pos, len;
+
+ /* find start element */
+ if (path[0] == '/') {
+ bus = sysbus_get_default();
+ pos = 0;
+ } else {
+ if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
+ assert(!path[0]);
+ elem[0] = len = 0;
+ }
+ bus = qbus_find_recursive(sysbus_get_default(), elem, NULL);
+ if (!bus) {
+ qerror_report(QERR_BUS_NOT_FOUND, elem);
+ return NULL;
+ }
+ pos = len;
+ }
+
+ for (;;) {
+ assert(path[pos] == '/' || !path[pos]);
+ while (path[pos] == '/') {
+ pos++;
+ }
+ if (path[pos] == '\0') {
+ return bus;
+ }
+
+ /* find device */
+ if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
+ assert(0);
+ elem[0] = len = 0;
+ }
+ pos += len;
+ dev = qbus_find_dev(bus, elem);
+ if (!dev) {
+ qerror_report(QERR_DEVICE_NOT_FOUND, elem);
+ if (!monitor_cur_is_qmp()) {
+ qbus_list_dev(bus);
+ }
+ return NULL;
+ }
+
+ assert(path[pos] == '/' || !path[pos]);
+ while (path[pos] == '/') {
+ pos++;
+ }
+ if (path[pos] == '\0') {
+ /* last specified element is a device. If it has exactly
+ * one child bus accept it nevertheless */
+ switch (dev->num_child_bus) {
+ case 0:
+ qerror_report(QERR_DEVICE_NO_BUS, elem);
+ return NULL;
+ case 1:
+ return QLIST_FIRST(&dev->child_bus);
+ default:
+ qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
+ if (!monitor_cur_is_qmp()) {
+ qbus_list_bus(dev);
+ }
+ return NULL;
+ }
+ }
+
+ /* find bus */
+ if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
+ assert(0);
+ elem[0] = len = 0;
+ }
+ pos += len;
+ bus = qbus_find_bus(dev, elem);
+ if (!bus) {
+ qerror_report(QERR_BUS_NOT_FOUND, elem);
+ if (!monitor_cur_is_qmp()) {
+ qbus_list_bus(dev);
+ }
+ return NULL;
+ }
+ }
+}
+
+DeviceState *qdev_device_add(QemuOpts *opts)
+{
+ ObjectClass *obj;
+ DeviceClass *k;
+ const char *driver, *path, *id;
+ DeviceState *qdev;
+ BusState *bus;
+
+ driver = qemu_opt_get(opts, "driver");
+ if (!driver) {
+ qerror_report(QERR_MISSING_PARAMETER, "driver");
+ return NULL;
+ }
+
+ /* find driver */
+ obj = object_class_by_name(driver);
+ if (!obj) {
+ const char *typename = find_typename_by_alias(driver);
+
+ if (typename) {
+ driver = typename;
+ obj = object_class_by_name(driver);
+ }
+ }
+
+ if (!obj) {
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type");
+ return NULL;
+ }
+
+ k = DEVICE_CLASS(obj);
+
+ /* find bus */
+ path = qemu_opt_get(opts, "bus");
+ if (path != NULL) {
+ bus = qbus_find(path);
+ if (!bus) {
+ return NULL;
+ }
+ if (bus->info != k->bus_info) {
+ qerror_report(QERR_BAD_BUS_FOR_DEVICE,
+ driver, bus->info->name);
+ return NULL;
+ }
+ } else {
+ bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_info);
+ if (!bus) {
+ qerror_report(QERR_NO_BUS_FOR_DEVICE,
+ driver, k->bus_info->name);
+ return NULL;
+ }
+ }
+ if (qdev_hotplug && !bus->allow_hotplug) {
+ qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
+ return NULL;
+ }
+
+ if (!bus) {
+ bus = sysbus_get_default();
+ }
+
+ /* create device, set properties */
+ qdev = DEVICE(object_new(driver));
+ qdev_set_parent_bus(qdev, bus);
+ qdev_prop_set_globals(qdev);
+
+ id = qemu_opts_id(opts);
+ if (id) {
+ qdev->id = id;
+ object_property_add_child(qdev_get_peripheral(), qdev->id,
+ OBJECT(qdev), NULL);
+ } else {
+ static int anon_count;
+ gchar *name = g_strdup_printf("device[%d]", anon_count++);
+ object_property_add_child(qdev_get_peripheral_anon(), name,
+ OBJECT(qdev), NULL);
+ g_free(name);
+ }
+ if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
+ qdev_free(qdev);
+ return NULL;
+ }
+ if (qdev_init(qdev) < 0) {
+ qerror_report(QERR_DEVICE_INIT_FAILED, driver);
+ return NULL;
+ }
+ qdev->opts = opts;
+ return qdev;
+}
+
+
+#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
+static void qbus_print(Monitor *mon, BusState *bus, int indent);
+
+static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
+ const char *prefix, int indent)
+{
+ char buf[64];
+
+ if (!props)
+ return;
+ while (props->name) {
+ /*
+ * TODO Properties without a print method are just for dirty
+ * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
+ * marked for removal. The test props->info->print should be
+ * removed along with it.
+ */
+ if (props->info->print) {
+ props->info->print(dev, props, buf, sizeof(buf));
+ qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
+ }
+ props++;
+ }
+}
+
+static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+ BusState *child;
+ qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
+ dev->id ? dev->id : "");
+ indent += 2;
+ if (dev->num_gpio_in) {
+ qdev_printf("gpio-in %d\n", dev->num_gpio_in);
+ }
+ if (dev->num_gpio_out) {
+ qdev_printf("gpio-out %d\n", dev->num_gpio_out);
+ }
+ qdev_print_props(mon, dev, qdev_get_props(dev), "dev", indent);
+ qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
+ if (dev->parent_bus->info->print_dev)
+ dev->parent_bus->info->print_dev(mon, dev, indent);
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ qbus_print(mon, child, indent);
+ }
+}
+
+static void qbus_print(Monitor *mon, BusState *bus, int indent)
+{
+ struct DeviceState *dev;
+
+ qdev_printf("bus: %s\n", bus->name);
+ indent += 2;
+ qdev_printf("type %s\n", bus->info->name);
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ qdev_print(mon, dev, indent);
+ }
+}
+#undef qdev_printf
+
+void do_info_qtree(Monitor *mon)
+{
+ if (sysbus_get_default())
+ qbus_print(mon, sysbus_get_default(), 0);
+}
+
+void do_info_qdm(Monitor *mon)
+{
+ object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL);
+}
+
+int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ QemuOpts *opts;
+
+ opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
+ if (!opts) {
+ return -1;
+ }
+ if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
+ qemu_opts_del(opts);
+ return 0;
+ }
+ if (!qdev_device_add(opts)) {
+ qemu_opts_del(opts);
+ return -1;
+ }
+ return 0;
+}
+
+int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *id = qdict_get_str(qdict, "id");
+ DeviceState *dev;
+
+ dev = qdev_find_recursive(sysbus_get_default(), id);
+ if (NULL == dev) {
+ qerror_report(QERR_DEVICE_NOT_FOUND, id);
+ return -1;
+ }
+ return qdev_unplug(dev);
+}
+
+void qdev_machine_init(void)
+{
+ qdev_get_peripheral_anon();
+ qdev_get_peripheral();
+}
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 02f0dae..c4583a1 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -40,9 +40,9 @@
/* Bit */
static int parse_bit(DeviceState *dev, Property *prop, const char *str)
{
- if (!strncasecmp(str, "on", 2))
+ if (!strcasecmp(str, "on"))
bit_prop_set(dev, prop, true);
- else if (!strncasecmp(str, "off", 3))
+ else if (!strcasecmp(str, "off"))
bit_prop_set(dev, prop, false);
else
return -EINVAL;
@@ -55,9 +55,10 @@
return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
}
-static void get_bit(DeviceState *dev, Visitor *v, void *opaque,
+static void get_bit(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *p = qdev_get_prop_ptr(dev, prop);
bool value = (*p & qdev_get_prop_mask(prop)) != 0;
@@ -65,9 +66,10 @@
visit_type_bool(v, &value, name, errp);
}
-static void set_bit(DeviceState *dev, Visitor *v, void *opaque,
+static void set_bit(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
bool value;
@@ -118,9 +120,10 @@
return snprintf(dest, len, "%" PRIu8, *ptr);
}
-static void get_int8(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int8(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int8_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@@ -129,9 +132,10 @@
visit_type_int(v, &value, name, errp);
}
-static void set_int8(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void set_int8(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int8_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -224,9 +228,10 @@
return snprintf(dest, len, "%" PRIu16, *ptr);
}
-static void get_int16(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int16(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int16_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@@ -235,9 +240,10 @@
visit_type_int(v, &value, name, errp);
}
-static void set_int16(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int16(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int16_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -296,9 +302,10 @@
return snprintf(dest, len, "%" PRIu32, *ptr);
}
-static void get_int32(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int32(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@@ -307,9 +314,10 @@
visit_type_int(v, &value, name, errp);
}
-static void set_int32(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int32(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -433,18 +441,20 @@
return snprintf(dest, len, "%" PRIu64, *ptr);
}
-static void get_int64(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int64(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int64_t *ptr = qdev_get_prop_ptr(dev, prop);
visit_type_int(v, ptr, name, errp);
}
-static void set_int64(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int64(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int64_t *ptr = qdev_get_prop_ptr(dev, prop);
@@ -523,9 +533,10 @@
return snprintf(dest, len, "\"%s\"", *ptr);
}
-static void get_string(DeviceState *dev, Visitor *v, void *opaque,
+static void get_string(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char **ptr = qdev_get_prop_ptr(dev, prop);
@@ -537,9 +548,10 @@
}
}
-static void set_string(DeviceState *dev, Visitor *v, void *opaque,
+static void set_string(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char **ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -609,9 +621,10 @@
*ptr ? bdrv_get_device_name(*ptr) : "<null>");
}
-static void get_generic(DeviceState *dev, Visitor *v, void *opaque,
+static void get_generic(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
void **ptr = qdev_get_prop_ptr(dev, prop);
char buffer[1024];
@@ -624,9 +637,10 @@
visit_type_str(v, &p, name, errp);
}
-static void set_generic(DeviceState *dev, Visitor *v, void *opaque,
+static void set_generic(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
char *str;
@@ -774,9 +788,10 @@
}
}
-static void get_vlan(DeviceState *dev, Visitor *v, void *opaque,
+static void get_vlan(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
int64_t id;
@@ -785,9 +800,10 @@
visit_type_int(v, &id, name, errp);
}
-static void set_vlan(DeviceState *dev, Visitor *v, void *opaque,
+static void set_vlan(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -885,6 +901,55 @@
.set = set_generic,
};
+
+/* --- lost tick policy --- */
+
+static const struct {
+ const char *name;
+ LostTickPolicy code;
+} lost_tick_policy_table[] = {
+ { .name = "discard", .code = LOST_TICK_DISCARD },
+ { .name = "delay", .code = LOST_TICK_DELAY },
+ { .name = "merge", .code = LOST_TICK_MERGE },
+ { .name = "slew", .code = LOST_TICK_SLEW },
+};
+
+static int parse_lost_tick_policy(DeviceState *dev, Property *prop,
+ const char *str)
+{
+ LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lost_tick_policy_table); i++) {
+ if (!strcasecmp(str, lost_tick_policy_table[i].name)) {
+ *ptr = lost_tick_policy_table[i].code;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(lost_tick_policy_table)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int print_lost_tick_policy(DeviceState *dev, Property *prop, char *dest,
+ size_t len)
+{
+ LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+
+ return snprintf(dest, len, "%s", lost_tick_policy_table[*ptr].name);
+}
+
+PropertyInfo qdev_prop_losttickpolicy = {
+ .name = "lost_tick_policy",
+ .type = PROP_TYPE_LOSTTICKPOLICY,
+ .size = sizeof(LostTickPolicy),
+ .parse = parse_lost_tick_policy,
+ .print = print_lost_tick_policy,
+ .get = get_generic,
+ .set = set_generic,
+};
+
/* --- pci address --- */
/*
@@ -922,9 +987,10 @@
}
}
-static void get_pci_devfn(DeviceState *dev, Visitor *v, void *opaque,
+static void get_pci_devfn(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
char buffer[32];
@@ -966,7 +1032,7 @@
Property *prop;
/* device properties */
- prop = qdev_prop_walk(dev->info->props, name);
+ prop = qdev_prop_walk(qdev_get_props(dev), name);
if (prop)
return prop;
@@ -989,16 +1055,16 @@
switch (ret) {
case -EEXIST:
error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
- dev->info->name, prop->name, value);
+ object_get_typename(OBJECT(dev)), prop->name, value);
break;
default:
case -EINVAL:
error_set(errp, QERR_PROPERTY_VALUE_BAD,
- dev->info->name, prop->name, value);
+ object_get_typename(OBJECT(dev)), prop->name, value);
break;
case -ENOENT:
error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
- dev->info->name, prop->name, value);
+ object_get_typename(OBJECT(dev)), prop->name, value);
break;
case 0:
break;
@@ -1018,7 +1084,7 @@
* removed along with it.
*/
if (!prop || !prop->info->parse) {
- qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name);
+ qerror_report(QERR_PROPERTY_NOT_FOUND, object_get_typename(OBJECT(dev)), name);
return -1;
}
ret = prop->info->parse(dev, prop, value);
@@ -1039,12 +1105,12 @@
prop = qdev_prop_find(dev, name);
if (!prop) {
fprintf(stderr, "%s: property \"%s.%s\" not found\n",
- __FUNCTION__, dev->info->name, name);
+ __FUNCTION__, object_get_typename(OBJECT(dev)), name);
abort();
}
if (prop->info->type != type) {
fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
- __FUNCTION__, dev->info->name, name);
+ __FUNCTION__, object_get_typename(OBJECT(dev)), name);
abort();
}
qdev_prop_cpy(dev, prop, src);
@@ -1093,7 +1159,7 @@
if (res < 0) {
error_report("Can't attach drive %s to %s.%s: %s",
bdrv_get_device_name(value),
- dev->id ? dev->id : dev->info->name,
+ dev->id ? dev->id : object_get_typename(OBJECT(dev)),
name, strerror(-res));
return -1;
}
@@ -1127,6 +1193,12 @@
qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR);
}
+void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
+ LostTickPolicy *value)
+{
+ qdev_prop_set(dev, name, value, PROP_TYPE_LOSTTICKPOLICY);
+}
+
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
{
qdev_prop_set(dev, name, &value, PROP_TYPE_PTR);
@@ -1165,8 +1237,8 @@
GlobalProperty *prop;
QTAILQ_FOREACH(prop, &global_props, next) {
- if (strcmp(dev->info->name, prop->driver) != 0 &&
- strcmp(dev->info->bus_info->name, prop->driver) != 0) {
+ if (strcmp(object_get_typename(OBJECT(dev)), prop->driver) != 0 &&
+ strcmp(qdev_get_bus_info(dev)->name, prop->driver) != 0) {
continue;
}
if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
diff --git a/hw/qdev.c b/hw/qdev.c
index e59f345..e3b53b7 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -28,9 +28,8 @@
#include "net.h"
#include "qdev.h"
#include "sysemu.h"
-#include "monitor.h"
-static int qdev_hotplug = 0;
+int qdev_hotplug = 0;
static bool qdev_hot_added = false;
static bool qdev_hot_removed = false;
@@ -38,86 +37,60 @@
static BusState *main_system_bus;
static void main_system_bus_create(void);
-DeviceInfo *device_info_list;
-
-static BusState *qbus_find_recursive(BusState *bus, const char *name,
- const BusInfo *info);
-static BusState *qbus_find(const char *path);
-
/* Register a new device type. */
-void qdev_register(DeviceInfo *info)
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
{
- assert(info->size >= sizeof(DeviceState));
- assert(!info->next);
-
- info->next = device_info_list;
- device_info_list = info;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->vmsd;
}
-static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
+BusInfo *qdev_get_bus_info(DeviceState *dev)
{
- DeviceInfo *info;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->bus_info;
+}
- /* first check device names */
- for (info = device_info_list; info != NULL; info = info->next) {
- if (bus_info && info->bus_info != bus_info)
- continue;
- if (strcmp(info->name, name) != 0)
- continue;
- return info;
+Property *qdev_get_props(DeviceState *dev)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->props;
+}
+
+const char *qdev_fw_name(DeviceState *dev)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+ if (dc->fw_name) {
+ return dc->fw_name;
}
- /* failing that check the aliases */
- for (info = device_info_list; info != NULL; info = info->next) {
- if (bus_info && info->bus_info != bus_info)
- continue;
- if (!info->alias)
- continue;
- if (strcmp(info->alias, name) != 0)
- continue;
- return info;
- }
- return NULL;
+ return object_get_typename(OBJECT(dev));
+}
+
+bool qdev_exists(const char *name)
+{
+ return !!object_class_by_name(name);
}
static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
Error **errp);
-static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
{
- DeviceState *dev;
Property *prop;
- assert(bus->info == info->bus_info);
- dev = g_malloc0(info->size);
- dev->info = info;
- dev->parent_bus = bus;
- qdev_prop_set_defaults(dev, dev->info->props);
- qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
- qdev_prop_set_globals(dev);
- QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
if (qdev_hotplug) {
assert(bus->allow_hotplug);
- dev->hotplugged = 1;
- qdev_hot_added = true;
}
- dev->instance_id_alias = -1;
- QTAILQ_INIT(&dev->properties);
- dev->state = DEV_STATE_CREATED;
- for (prop = dev->info->props; prop && prop->name; prop++) {
+ dev->parent_bus = bus;
+ QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
+
+ qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
+ for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
qdev_property_add_legacy(dev, prop, NULL);
qdev_property_add_static(dev, prop, NULL);
}
-
- for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
- qdev_property_add_legacy(dev, prop, NULL);
- qdev_property_add_static(dev, prop, NULL);
- }
-
- qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
-
- return dev;
}
/* Create a new device. This only initializes the device state structure
@@ -142,197 +115,23 @@
DeviceState *qdev_try_create(BusState *bus, const char *name)
{
- DeviceInfo *info;
+ DeviceState *dev;
+
+ dev = DEVICE(object_new(name));
+ if (!dev) {
+ return NULL;
+ }
if (!bus) {
bus = sysbus_get_default();
}
- info = qdev_find_info(bus->info, name);
- if (!info) {
- return NULL;
- }
-
- return qdev_create_from_info(bus, info);
-}
-
-static void qdev_print_devinfo(DeviceInfo *info)
-{
- error_printf("name \"%s\", bus %s",
- info->name, info->bus_info->name);
- if (info->alias) {
- error_printf(", alias \"%s\"", info->alias);
- }
- if (info->desc) {
- error_printf(", desc \"%s\"", info->desc);
- }
- if (info->no_user) {
- error_printf(", no-user");
- }
- error_printf("\n");
-}
-
-static int set_property(const char *name, const char *value, void *opaque)
-{
- DeviceState *dev = opaque;
-
- if (strcmp(name, "driver") == 0)
- return 0;
- if (strcmp(name, "bus") == 0)
- return 0;
-
- if (qdev_prop_parse(dev, name, value) == -1) {
- return -1;
- }
- return 0;
-}
-
-int qdev_device_help(QemuOpts *opts)
-{
- const char *driver;
- DeviceInfo *info;
- Property *prop;
-
- driver = qemu_opt_get(opts, "driver");
- if (driver && !strcmp(driver, "?")) {
- for (info = device_info_list; info != NULL; info = info->next) {
- if (info->no_user) {
- continue; /* not available, don't show */
- }
- qdev_print_devinfo(info);
- }
- return 1;
- }
-
- if (!driver || !qemu_opt_get(opts, "?")) {
- return 0;
- }
-
- info = qdev_find_info(NULL, driver);
- if (!info) {
- return 0;
- }
-
- for (prop = info->props; prop && prop->name; prop++) {
- /*
- * TODO Properties without a parser are just for dirty hacks.
- * qdev_prop_ptr is the only such PropertyInfo. It's marked
- * for removal. This conditional should be removed along with
- * it.
- */
- if (!prop->info->parse) {
- continue; /* no way to set it, don't show */
- }
- error_printf("%s.%s=%s\n", info->name, prop->name,
- prop->info->legacy_name ?: prop->info->name);
- }
- for (prop = info->bus_info->props; prop && prop->name; prop++) {
- if (!prop->info->parse) {
- continue; /* no way to set it, don't show */
- }
- error_printf("%s.%s=%s\n", info->name, prop->name,
- prop->info->legacy_name ?: prop->info->name);
- }
- return 1;
-}
-
-static DeviceState *qdev_get_peripheral(void)
-{
- static DeviceState *dev;
-
- if (dev == NULL) {
- dev = qdev_create(NULL, "container");
- qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
- qdev_init_nofail(dev);
- }
+ qdev_set_parent_bus(dev, bus);
+ qdev_prop_set_globals(dev);
return dev;
}
-static DeviceState *qdev_get_peripheral_anon(void)
-{
- static DeviceState *dev;
-
- if (dev == NULL) {
- dev = qdev_create(NULL, "container");
- qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
- qdev_init_nofail(dev);
- }
-
- return dev;
-}
-
-DeviceState *qdev_device_add(QemuOpts *opts)
-{
- const char *driver, *path, *id;
- DeviceInfo *info;
- DeviceState *qdev;
- BusState *bus;
-
- driver = qemu_opt_get(opts, "driver");
- if (!driver) {
- qerror_report(QERR_MISSING_PARAMETER, "driver");
- return NULL;
- }
-
- /* find driver */
- info = qdev_find_info(NULL, driver);
- if (!info || info->no_user) {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
- error_printf_unless_qmp("Try with argument '?' for a list.\n");
- return NULL;
- }
-
- /* find bus */
- path = qemu_opt_get(opts, "bus");
- if (path != NULL) {
- bus = qbus_find(path);
- if (!bus) {
- return NULL;
- }
- if (bus->info != info->bus_info) {
- qerror_report(QERR_BAD_BUS_FOR_DEVICE,
- driver, bus->info->name);
- return NULL;
- }
- } else {
- bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
- if (!bus) {
- qerror_report(QERR_NO_BUS_FOR_DEVICE,
- info->name, info->bus_info->name);
- return NULL;
- }
- }
- if (qdev_hotplug && !bus->allow_hotplug) {
- qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
- return NULL;
- }
-
- /* create device, set properties */
- qdev = qdev_create_from_info(bus, info);
- id = qemu_opts_id(opts);
- if (id) {
- qdev->id = id;
- qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
- } else {
- static int anon_count;
- gchar *name = g_strdup_printf("device[%d]", anon_count++);
- qdev_property_add_child(qdev_get_peripheral_anon(), name,
- qdev, NULL);
- g_free(name);
- }
- if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
- qdev_free(qdev);
- return NULL;
- }
- if (qdev_init(qdev) < 0) {
- qerror_report(QERR_DEVICE_INIT_FAILED, driver);
- return NULL;
- }
- qdev->opts = opts;
- return qdev;
-}
-
/* Initialize a device. Device properties should be set before calling
this function. IRQs and MMIO regions should be connected/mapped after
calling this function.
@@ -340,22 +139,24 @@
Return 0 on success. */
int qdev_init(DeviceState *dev)
{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
int rc;
assert(dev->state == DEV_STATE_CREATED);
- rc = dev->info->init(dev, dev->info);
+
+ rc = dc->init(dev);
if (rc < 0) {
qdev_free(dev);
return rc;
}
- if (dev->info->vmsd) {
- vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
+ if (qdev_get_vmsd(dev)) {
+ vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
dev->instance_id_alias,
dev->alias_required_for_version);
}
dev->state = DEV_STATE_INITIALIZED;
- if (dev->hotplugged && dev->info->reset) {
- dev->info->reset(dev);
+ if (dev->hotplugged) {
+ device_reset(dev);
}
return 0;
}
@@ -370,22 +171,22 @@
int qdev_unplug(DeviceState *dev)
{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
if (!dev->parent_bus->allow_hotplug) {
qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
return -1;
}
- assert(dev->info->unplug != NULL);
+ assert(dc->unplug != NULL);
qdev_hot_removed = true;
- return dev->info->unplug(dev);
+ return dc->unplug(dev);
}
static int qdev_reset_one(DeviceState *dev, void *opaque)
{
- if (dev->info->reset) {
- dev->info->reset(dev);
- }
+ device_reset(dev);
return 0;
}
@@ -421,6 +222,7 @@
int qdev_simple_unplug_cb(DeviceState *dev)
{
/* just zap it */
+ object_unparent(OBJECT(dev));
qdev_free(dev);
return 0;
}
@@ -435,87 +237,17 @@
way is somewhat unclean, and best avoided. */
void qdev_init_nofail(DeviceState *dev)
{
- DeviceInfo *info = dev->info;
-
if (qdev_init(dev) < 0) {
- error_report("Initialization of device %s failed", info->name);
+ error_report("Initialization of device %s failed",
+ object_get_typename(OBJECT(dev)));
exit(1);
}
}
-static void qdev_property_del_all(DeviceState *dev)
-{
- while (!QTAILQ_EMPTY(&dev->properties)) {
- DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
-
- QTAILQ_REMOVE(&dev->properties, prop, node);
-
- if (prop->release) {
- prop->release(dev, prop->name, prop->opaque);
- }
-
- g_free(prop->name);
- g_free(prop->type);
- g_free(prop);
- }
-}
-
-static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp)
-{
- DeviceProperty *prop;
-
- QTAILQ_FOREACH(prop, &dev->properties, node) {
- if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
- break;
- }
- }
-
- g_assert(prop != NULL);
-
- QTAILQ_REMOVE(&dev->properties, prop, node);
-
- if (prop->release) {
- prop->release(dev, prop->name, prop->opaque);
- }
-
- g_free(prop->name);
- g_free(prop->type);
- g_free(prop);
-}
-
/* Unlink device from bus and free the structure. */
void qdev_free(DeviceState *dev)
{
- BusState *bus;
- Property *prop;
-
- qdev_property_del_all(dev);
-
- if (dev->state == DEV_STATE_INITIALIZED) {
- while (dev->num_child_bus) {
- bus = QLIST_FIRST(&dev->child_bus);
- qbus_free(bus);
- }
- if (dev->info->vmsd)
- vmstate_unregister(dev, dev->info->vmsd, dev);
- if (dev->info->exit)
- dev->info->exit(dev);
- if (dev->opts)
- qemu_opts_del(dev->opts);
- }
- QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
- for (prop = dev->info->props; prop && prop->name; prop++) {
- if (prop->info->free) {
- prop->info->free(dev, prop);
- }
- }
- if (dev->parent) {
- qdev_property_del_child(dev->parent, dev, NULL);
- }
- if (dev->ref != 0) {
- qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
- }
- g_free(dev);
+ object_delete(OBJECT(dev));
}
void qdev_machine_creation_done(void)
@@ -532,15 +264,6 @@
return qdev_hot_added || qdev_hot_removed;
}
-/* Get a character (serial) device interface. */
-CharDriverState *qdev_init_chardev(DeviceState *dev)
-{
- static int next_serial;
-
- /* FIXME: This function needs to go away: use chardev properties! */
- return serial_hds[next_serial++];
-}
-
BusState *qdev_get_parent_bus(DeviceState *dev)
{
return dev->parent_bus;
@@ -644,34 +367,6 @@
return 0;
}
-static BusState *qbus_find_recursive(BusState *bus, const char *name,
- const BusInfo *info)
-{
- DeviceState *dev;
- BusState *child, *ret;
- int match = 1;
-
- if (name && (strcmp(bus->name, name) != 0)) {
- match = 0;
- }
- if (info && (bus->info != info)) {
- match = 0;
- }
- if (match) {
- return bus;
- }
-
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- ret = qbus_find_recursive(child, name, info);
- if (ret) {
- return ret;
- }
- }
- }
- return NULL;
-}
-
DeviceState *qdev_find_recursive(BusState *bus, const char *id)
{
DeviceState *dev, *ret;
@@ -690,162 +385,6 @@
return NULL;
}
-static void qbus_list_bus(DeviceState *dev)
-{
- BusState *child;
- const char *sep = " ";
-
- error_printf("child busses at \"%s\":",
- dev->id ? dev->id : dev->info->name);
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- error_printf("%s\"%s\"", sep, child->name);
- sep = ", ";
- }
- error_printf("\n");
-}
-
-static void qbus_list_dev(BusState *bus)
-{
- DeviceState *dev;
- const char *sep = " ";
-
- error_printf("devices at \"%s\":", bus->name);
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- error_printf("%s\"%s\"", sep, dev->info->name);
- if (dev->id)
- error_printf("/\"%s\"", dev->id);
- sep = ", ";
- }
- error_printf("\n");
-}
-
-static BusState *qbus_find_bus(DeviceState *dev, char *elem)
-{
- BusState *child;
-
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- if (strcmp(child->name, elem) == 0) {
- return child;
- }
- }
- return NULL;
-}
-
-static DeviceState *qbus_find_dev(BusState *bus, char *elem)
-{
- DeviceState *dev;
-
- /*
- * try to match in order:
- * (1) instance id, if present
- * (2) driver name
- * (3) driver alias, if present
- */
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (dev->id && strcmp(dev->id, elem) == 0) {
- return dev;
- }
- }
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (strcmp(dev->info->name, elem) == 0) {
- return dev;
- }
- }
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
- return dev;
- }
- }
- return NULL;
-}
-
-static BusState *qbus_find(const char *path)
-{
- DeviceState *dev;
- BusState *bus;
- char elem[128];
- int pos, len;
-
- /* find start element */
- if (path[0] == '/') {
- bus = main_system_bus;
- pos = 0;
- } else {
- if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
- assert(!path[0]);
- elem[0] = len = 0;
- }
- bus = qbus_find_recursive(main_system_bus, elem, NULL);
- if (!bus) {
- qerror_report(QERR_BUS_NOT_FOUND, elem);
- return NULL;
- }
- pos = len;
- }
-
- for (;;) {
- assert(path[pos] == '/' || !path[pos]);
- while (path[pos] == '/') {
- pos++;
- }
- if (path[pos] == '\0') {
- return bus;
- }
-
- /* find device */
- if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
- assert(0);
- elem[0] = len = 0;
- }
- pos += len;
- dev = qbus_find_dev(bus, elem);
- if (!dev) {
- qerror_report(QERR_DEVICE_NOT_FOUND, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_dev(bus);
- }
- return NULL;
- }
-
- assert(path[pos] == '/' || !path[pos]);
- while (path[pos] == '/') {
- pos++;
- }
- if (path[pos] == '\0') {
- /* last specified element is a device. If it has exactly
- * one child bus accept it nevertheless */
- switch (dev->num_child_bus) {
- case 0:
- qerror_report(QERR_DEVICE_NO_BUS, elem);
- return NULL;
- case 1:
- return QLIST_FIRST(&dev->child_bus);
- default:
- qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_bus(dev);
- }
- return NULL;
- }
- }
-
- /* find bus */
- if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
- assert(0);
- elem[0] = len = 0;
- }
- pos += len;
- bus = qbus_find_bus(dev, elem);
- if (!bus) {
- qerror_report(QERR_BUS_NOT_FOUND, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_bus(dev);
- }
- return NULL;
- }
- }
-}
-
void qbus_create_inplace(BusState *bus, BusInfo *info,
DeviceState *parent, const char *name)
{
@@ -926,112 +465,6 @@
}
}
-#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
-static void qbus_print(Monitor *mon, BusState *bus, int indent);
-
-static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
- const char *prefix, int indent)
-{
- char buf[64];
-
- if (!props)
- return;
- while (props->name) {
- /*
- * TODO Properties without a print method are just for dirty
- * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
- * marked for removal. The test props->info->print should be
- * removed along with it.
- */
- if (props->info->print) {
- props->info->print(dev, props, buf, sizeof(buf));
- qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
- }
- props++;
- }
-}
-
-static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
-{
- BusState *child;
- qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
- dev->id ? dev->id : "");
- indent += 2;
- if (dev->num_gpio_in) {
- qdev_printf("gpio-in %d\n", dev->num_gpio_in);
- }
- if (dev->num_gpio_out) {
- qdev_printf("gpio-out %d\n", dev->num_gpio_out);
- }
- qdev_print_props(mon, dev, dev->info->props, "dev", indent);
- qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
- if (dev->parent_bus->info->print_dev)
- dev->parent_bus->info->print_dev(mon, dev, indent);
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- qbus_print(mon, child, indent);
- }
-}
-
-static void qbus_print(Monitor *mon, BusState *bus, int indent)
-{
- struct DeviceState *dev;
-
- qdev_printf("bus: %s\n", bus->name);
- indent += 2;
- qdev_printf("type %s\n", bus->info->name);
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- qdev_print(mon, dev, indent);
- }
-}
-#undef qdev_printf
-
-void do_info_qtree(Monitor *mon)
-{
- if (main_system_bus)
- qbus_print(mon, main_system_bus, 0);
-}
-
-void do_info_qdm(Monitor *mon)
-{
- DeviceInfo *info;
-
- for (info = device_info_list; info != NULL; info = info->next) {
- qdev_print_devinfo(info);
- }
-}
-
-int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- QemuOpts *opts;
-
- opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
- if (!opts) {
- return -1;
- }
- if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
- qemu_opts_del(opts);
- return 0;
- }
- if (!qdev_device_add(opts)) {
- qemu_opts_del(opts);
- return -1;
- }
- return 0;
-}
-
-int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *id = qdict_get_str(qdict, "id");
- DeviceState *dev;
-
- dev = qdev_find_recursive(main_system_bus, id);
- if (NULL == dev) {
- qerror_report(QERR_DEVICE_NOT_FOUND, id);
- return -1;
- }
- return qdev_unplug(dev);
-}
-
static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
{
int l = 0;
@@ -1044,7 +477,7 @@
l += snprintf(p + l, size - l, "%s", d);
g_free(d);
} else {
- l += snprintf(p + l, size - l, "%s", dev->info->name);
+ l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
}
}
l += snprintf(p + l , size - l, "/");
@@ -1064,106 +497,19 @@
return strdup(path);
}
-char *qdev_get_type(DeviceState *dev, Error **errp)
+static char *qdev_get_type(Object *obj, Error **errp)
{
- return g_strdup(dev->info->name);
-}
-
-void qdev_ref(DeviceState *dev)
-{
- dev->ref++;
-}
-
-void qdev_unref(DeviceState *dev)
-{
- g_assert(dev->ref > 0);
- dev->ref--;
-}
-
-void qdev_property_add(DeviceState *dev, const char *name, const char *type,
- DevicePropertyAccessor *get, DevicePropertyAccessor *set,
- DevicePropertyRelease *release,
- void *opaque, Error **errp)
-{
- DeviceProperty *prop = g_malloc0(sizeof(*prop));
-
- prop->name = g_strdup(name);
- prop->type = g_strdup(type);
-
- prop->get = get;
- prop->set = set;
- prop->release = release;
- prop->opaque = opaque;
-
- QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
-}
-
-static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
-{
- DeviceProperty *prop;
-
- QTAILQ_FOREACH(prop, &dev->properties, node) {
- if (strcmp(prop->name, name) == 0) {
- return prop;
- }
- }
-
- return NULL;
-}
-
-void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
- Error **errp)
-{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return;
- }
-
- if (!prop->get) {
- error_set(errp, QERR_PERMISSION_DENIED);
- } else {
- prop->get(dev, v, prop->opaque, name, errp);
- }
-}
-
-void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
- Error **errp)
-{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return;
- }
-
- if (!prop->set) {
- error_set(errp, QERR_PERMISSION_DENIED);
- } else {
- prop->set(dev, v, prop->opaque, name, errp);
- }
-}
-
-const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
-{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return NULL;
- }
-
- return prop->type;
+ return g_strdup(object_get_typename(obj));
}
/**
* Legacy property handling
*/
-static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
+static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char buffer[1024];
@@ -1173,9 +519,10 @@
visit_type_str(v, &ptr, name, errp);
}
-static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
+static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
char *ptr = NULL;
@@ -1215,11 +562,11 @@
type = g_strdup_printf("legacy<%s>",
prop->info->legacy_name ?: prop->info->name);
- qdev_property_add(dev, name, type,
- prop->info->print ? qdev_get_legacy_property : NULL,
- prop->info->parse ? qdev_set_legacy_property : NULL,
- NULL,
- prop, errp);
+ object_property_add(OBJECT(dev), name, type,
+ prop->info->print ? qdev_get_legacy_property : NULL,
+ prop->info->parse ? qdev_set_legacy_property : NULL,
+ NULL,
+ prop, errp);
g_free(type);
g_free(name);
@@ -1234,337 +581,87 @@
void qdev_property_add_static(DeviceState *dev, Property *prop,
Error **errp)
{
- qdev_property_add(dev, prop->name, prop->info->name,
- prop->info->get, prop->info->set,
- NULL,
- prop, errp);
+ object_property_add(OBJECT(dev), prop->name, prop->info->name,
+ prop->info->get, prop->info->set,
+ NULL,
+ prop, errp);
}
-DeviceState *qdev_get_root(void)
+static void device_initfn(Object *obj)
{
- static DeviceState *qdev_root;
+ DeviceState *dev = DEVICE(obj);
+ Property *prop;
- if (!qdev_root) {
- qdev_root = qdev_create(NULL, "container");
- qdev_init_nofail(qdev_root);
+ if (qdev_hotplug) {
+ dev->hotplugged = 1;
+ qdev_hot_added = true;
}
- return qdev_root;
-}
+ dev->instance_id_alias = -1;
+ dev->state = DEV_STATE_CREATED;
-static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- DeviceState *child = opaque;
- gchar *path;
-
- path = qdev_get_canonical_path(child);
- visit_type_str(v, &path, name, errp);
- g_free(path);
-}
-
-static void qdev_release_child_property(DeviceState *dev, const char *name,
- void *opaque)
-{
- DeviceState *child = opaque;
-
- qdev_unref(child);
-}
-
-void qdev_property_add_child(DeviceState *dev, const char *name,
- DeviceState *child, Error **errp)
-{
- gchar *type;
-
- type = g_strdup_printf("child<%s>", child->info->name);
-
- qdev_property_add(dev, name, type, qdev_get_child_property,
- NULL, qdev_release_child_property,
- child, errp);
-
- qdev_ref(child);
- g_assert(child->parent == NULL);
- child->parent = dev;
-
- g_free(type);
-}
-
-static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- DeviceState **child = opaque;
- gchar *path;
-
- if (*child) {
- path = qdev_get_canonical_path(*child);
- visit_type_str(v, &path, name, errp);
- g_free(path);
- } else {
- path = (gchar *)"";
- visit_type_str(v, &path, name, errp);
- }
-}
-
-static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- DeviceState **child = opaque;
- bool ambiguous = false;
- const char *type;
- char *path;
-
- type = qdev_property_get_type(dev, name, NULL);
-
- visit_type_str(v, &path, name, errp);
-
- if (*child) {
- qdev_unref(*child);
+ qdev_prop_set_defaults(dev, qdev_get_props(dev));
+ for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
+ qdev_property_add_legacy(dev, prop, NULL);
+ qdev_property_add_static(dev, prop, NULL);
}
- if (strcmp(path, "") != 0) {
- DeviceState *target;
+ object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
+}
- target = qdev_resolve_path(path, &ambiguous);
- if (target) {
- gchar *target_type;
+/* Unlink device from bus and free the structure. */
+static void device_finalize(Object *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+ BusState *bus;
+ Property *prop;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
- target_type = g_strdup_printf("link<%s>", target->info->name);
- if (strcmp(target_type, type) == 0) {
- *child = target;
- qdev_ref(target);
- } else {
- error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
- }
-
- g_free(target_type);
- } else {
- error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+ if (dev->state == DEV_STATE_INITIALIZED) {
+ while (dev->num_child_bus) {
+ bus = QLIST_FIRST(&dev->child_bus);
+ qbus_free(bus);
}
- } else {
- *child = NULL;
- }
-
- g_free(path);
-}
-
-void qdev_property_add_link(DeviceState *dev, const char *name,
- const char *type, DeviceState **child,
- Error **errp)
-{
- gchar *full_type;
-
- full_type = g_strdup_printf("link<%s>", type);
-
- qdev_property_add(dev, name, full_type,
- qdev_get_link_property,
- qdev_set_link_property,
- NULL, child, errp);
-
- g_free(full_type);
-}
-
-gchar *qdev_get_canonical_path(DeviceState *dev)
-{
- DeviceState *root = qdev_get_root();
- char *newpath = NULL, *path = NULL;
-
- while (dev != root) {
- DeviceProperty *prop = NULL;
-
- g_assert(dev->parent != NULL);
-
- QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
- if (!strstart(prop->type, "child<", NULL)) {
- continue;
- }
-
- if (prop->opaque == dev) {
- if (path) {
- newpath = g_strdup_printf("%s/%s", prop->name, path);
- g_free(path);
- path = newpath;
- } else {
- path = g_strdup(prop->name);
- }
- break;
- }
+ if (qdev_get_vmsd(dev)) {
+ vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
}
-
- g_assert(prop != NULL);
-
- dev = dev->parent;
- }
-
- newpath = g_strdup_printf("/%s", path);
- g_free(path);
-
- return newpath;
-}
-
-static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
- gchar **parts,
- int index)
-{
- DeviceProperty *prop;
- DeviceState *child;
-
- if (parts[index] == NULL) {
- return parent;
- }
-
- if (strcmp(parts[index], "") == 0) {
- return qdev_resolve_abs_path(parent, parts, index + 1);
- }
-
- prop = qdev_property_find(parent, parts[index]);
- if (prop == NULL) {
- return NULL;
- }
-
- child = NULL;
- if (strstart(prop->type, "link<", NULL)) {
- DeviceState **pchild = prop->opaque;
- if (*pchild) {
- child = *pchild;
+ if (dc->exit) {
+ dc->exit(dev);
}
- } else if (strstart(prop->type, "child<", NULL)) {
- child = prop->opaque;
- }
-
- if (!child) {
- return NULL;
- }
-
- return qdev_resolve_abs_path(child, parts, index + 1);
-}
-
-static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
- gchar **parts,
- bool *ambiguous)
-{
- DeviceState *dev;
- DeviceProperty *prop;
-
- dev = qdev_resolve_abs_path(parent, parts, 0);
-
- QTAILQ_FOREACH(prop, &parent->properties, node) {
- DeviceState *found;
-
- if (!strstart(prop->type, "child<", NULL)) {
- continue;
- }
-
- found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
- if (found) {
- if (dev) {
- if (ambiguous) {
- *ambiguous = true;
- }
- return NULL;
- }
- dev = found;
- }
-
- if (ambiguous && *ambiguous) {
- return NULL;
+ if (dev->opts) {
+ qemu_opts_del(dev->opts);
}
}
-
- return dev;
-}
-
-DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
-{
- bool partial_path = true;
- DeviceState *dev;
- gchar **parts;
-
- parts = g_strsplit(path, "/", 0);
- if (parts == NULL || parts[0] == NULL) {
- g_strfreev(parts);
- return qdev_get_root();
- }
-
- if (strcmp(parts[0], "") == 0) {
- partial_path = false;
- }
-
- if (partial_path) {
- if (ambiguous) {
- *ambiguous = false;
+ QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
+ for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
+ if (prop->info->free) {
+ prop->info->free(dev, prop);
}
- dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
- } else {
- dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
- }
-
- g_strfreev(parts);
-
- return dev;
-}
-
-typedef struct StringProperty
-{
- char *(*get)(DeviceState *, Error **);
- void (*set)(DeviceState *, const char *, Error **);
-} StringProperty;
-
-static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- StringProperty *prop = opaque;
- char *value;
-
- value = prop->get(dev, errp);
- if (value) {
- visit_type_str(v, &value, name, errp);
- g_free(value);
}
}
-static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
+void device_reset(DeviceState *dev)
{
- StringProperty *prop = opaque;
- char *value;
- Error *local_err = NULL;
+ DeviceClass *klass = DEVICE_GET_CLASS(dev);
- visit_type_str(v, &value, name, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
+ if (klass->reset) {
+ klass->reset(dev);
}
-
- prop->set(dev, value, errp);
- g_free(value);
}
-static void qdev_property_release_str(DeviceState *dev, const char *name,
- void *opaque)
+static TypeInfo device_type_info = {
+ .name = TYPE_DEVICE,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(DeviceState),
+ .instance_init = device_initfn,
+ .instance_finalize = device_finalize,
+ .abstract = true,
+ .class_size = sizeof(DeviceClass),
+};
+
+static void init_qdev(void)
{
- StringProperty *prop = opaque;
- g_free(prop);
+ type_register_static(&device_type_info);
}
-void qdev_property_add_str(DeviceState *dev, const char *name,
- char *(*get)(DeviceState *, Error **),
- void (*set)(DeviceState *, const char *, Error **),
- Error **errp)
-{
- StringProperty *prop = g_malloc0(sizeof(*prop));
-
- prop->get = get;
- prop->set = set;
-
- qdev_property_add(dev, name, "string",
- get ? qdev_property_get_str : NULL,
- set ? qdev_property_set_str : NULL,
- qdev_property_release_str,
- prop, errp);
-}
-
-void qdev_machine_init(void)
-{
- qdev_get_peripheral_anon();
- qdev_get_peripheral();
-}
+device_init(init_qdev);
diff --git a/hw/qdev.h b/hw/qdev.h
index 2abb767..ab53273 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -6,6 +6,7 @@
#include "qemu-char.h"
#include "qemu-option.h"
#include "qapi/qapi-visit-core.h"
+#include "qemu/object.h"
typedef struct Property Property;
@@ -13,8 +14,6 @@
typedef struct CompatProperty CompatProperty;
-typedef struct DeviceInfo DeviceInfo;
-
typedef struct BusState BusState;
typedef struct BusInfo BusInfo;
@@ -28,52 +27,45 @@
DEV_NVECTORS_UNSPECIFIED = -1,
};
-/**
- * @DevicePropertyAccessor - called when trying to get/set a property
- *
- * @dev the device that owns the property
- * @v the visitor that contains the property data
- * @opaque the device property opaque
- * @name the name of the property
- * @errp a pointer to an Error that is filled if getting/setting fails.
- */
-typedef void (DevicePropertyAccessor)(DeviceState *dev,
- Visitor *v,
- void *opaque,
- const char *name,
- Error **errp);
+#define TYPE_DEVICE "device"
+#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
+#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
+#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE)
-/**
- * @DevicePropertyRelease - called when a property is removed from a device
- *
- * @dev the device that owns the property
- * @name the name of the property
- * @opaque the opaque registered with the property
- */
-typedef void (DevicePropertyRelease)(DeviceState *dev,
- const char *name,
- void *opaque);
+typedef int (*qdev_initfn)(DeviceState *dev);
+typedef int (*qdev_event)(DeviceState *dev);
+typedef void (*qdev_resetfn)(DeviceState *dev);
-typedef struct DeviceProperty
-{
- gchar *name;
- gchar *type;
- DevicePropertyAccessor *get;
- DevicePropertyAccessor *set;
- DevicePropertyRelease *release;
- void *opaque;
+typedef struct DeviceClass {
+ ObjectClass parent_class;
- QTAILQ_ENTRY(DeviceProperty) node;
-} DeviceProperty;
+ const char *fw_name;
+ const char *desc;
+ Property *props;
+ int no_user;
+
+ /* callbacks */
+ void (*reset)(DeviceState *dev);
+
+ /* device state */
+ const VMStateDescription *vmsd;
+
+ /* Private to qdev / bus. */
+ qdev_initfn init;
+ qdev_event unplug;
+ qdev_event exit;
+ BusInfo *bus_info;
+} DeviceClass;
/* This structure should not be accessed directly. We declare it here
so that it can be embedded in individual device state structures. */
struct DeviceState {
+ Object parent_obj;
+
const char *id;
enum DevState state;
QemuOpts *opts;
int hotplugged;
- DeviceInfo *info;
BusState *parent_bus;
int num_gpio_out;
qemu_irq *gpio_out;
@@ -84,18 +76,6 @@
QTAILQ_ENTRY(DeviceState) sibling;
int instance_id_alias;
int alias_required_for_version;
-
- /**
- * This tracks the number of references between devices. See @qdev_ref for
- * more information.
- */
- uint32_t ref;
-
- QTAILQ_HEAD(, DeviceProperty) properties;
-
- /* Do not, under any circumstance, use this parent link below anywhere
- * outside of qdev.c. You have been warned. */
- DeviceState *parent;
};
typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
@@ -145,6 +125,7 @@
PROP_TYPE_UINT64,
PROP_TYPE_TADDR,
PROP_TYPE_MACADDR,
+ PROP_TYPE_LOSTTICKPOLICY,
PROP_TYPE_DRIVE,
PROP_TYPE_CHR,
PROP_TYPE_STRING,
@@ -164,8 +145,8 @@
int (*parse)(DeviceState *dev, Property *prop, const char *str);
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
void (*free)(DeviceState *dev, Property *prop);
- DevicePropertyAccessor *get;
- DevicePropertyAccessor *set;
+ ObjectPropertyAccessor *get;
+ ObjectPropertyAccessor *set;
};
typedef struct GlobalProperty {
@@ -179,6 +160,7 @@
DeviceState *qdev_create(BusState *bus, const char *name);
DeviceState *qdev_try_create(BusState *bus, const char *name);
+bool qdev_exists(const char *name);
int qdev_device_help(QemuOpts *opts);
DeviceState *qdev_device_add(QemuOpts *opts);
int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
@@ -198,43 +180,11 @@
/*** Device API. ***/
-typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
-typedef int (*qdev_event)(DeviceState *dev);
-typedef void (*qdev_resetfn)(DeviceState *dev);
-
-struct DeviceInfo {
- const char *name;
- const char *fw_name;
- const char *alias;
- const char *desc;
- size_t size;
- Property *props;
- int no_user;
-
- /* callbacks */
- qdev_resetfn reset;
-
- /* device state */
- const VMStateDescription *vmsd;
-
- /* Private to qdev / bus. */
- qdev_initfn init;
- qdev_event unplug;
- qdev_event exit;
- BusInfo *bus_info;
- struct DeviceInfo *next;
-};
-extern DeviceInfo *device_info_list;
-
-void qdev_register(DeviceInfo *info);
-
/* Register device properties. */
/* GPIO inputs also double as IRQ sinks. */
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
-CharDriverState *qdev_init_chardev(DeviceState *dev);
-
BusState *qdev_get_parent_bus(DeviceState *dev);
/*** BUS API. ***/
@@ -287,6 +237,7 @@
extern PropertyInfo qdev_prop_chr;
extern PropertyInfo qdev_prop_ptr;
extern PropertyInfo qdev_prop_macaddr;
+extern PropertyInfo qdev_prop_losttickpolicy;
extern PropertyInfo qdev_prop_drive;
extern PropertyInfo qdev_prop_netdev;
extern PropertyInfo qdev_prop_vlan;
@@ -347,6 +298,9 @@
DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
+#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
+ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
+ LostTickPolicy)
#define DEFINE_PROP_END_OF_LIST() \
{}
@@ -369,6 +323,8 @@
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
+void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
+ LostTickPolicy *value);
/* FIXME: Remove opaque pointer properties. */
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
void qdev_prop_set_defaults(DeviceState *dev, Property *props);
@@ -378,245 +334,18 @@
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
Property *prop, const char *value);
-static inline const char *qdev_fw_name(DeviceState *dev)
-{
- return dev->info->fw_name ? : dev->info->alias ? : dev->info->name;
-}
-
char *qdev_get_fw_dev_path(DeviceState *dev);
+
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
extern struct BusInfo system_bus_info;
/**
- * @qdev_ref
- *
- * Increase the reference count of a device. A device cannot be freed as long
- * as its reference count is greater than zero.
- *
- * @dev - the device
- */
-void qdev_ref(DeviceState *dev);
-
-/**
- * @qdef_unref
- *
- * Decrease the reference count of a device. A device cannot be freed as long
- * as its reference count is greater than zero.
- *
- * @dev - the device
- */
-void qdev_unref(DeviceState *dev);
-
-/**
- * @qdev_property_add - add a new property to a device
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property. This can contain any character except for
- * a forward slash. In general, you should use hyphens '-' instead of
- * underscores '_' when naming properties.
- *
- * @type - the type name of the property. This namespace is pretty loosely
- * defined. Sub namespaces are constructed by using a prefix and then
- * to angle brackets. For instance, the type 'virtio-net-pci' in the
- * 'link' namespace would be 'link<virtio-net-pci>'.
- *
- * @get - the getter to be called to read a property. If this is NULL, then
- * the property cannot be read.
- *
- * @set - the setter to be called to write a property. If this is NULL,
- * then the property cannot be written.
- *
- * @release - called when the property is removed from the device. This is
- * meant to allow a property to free its opaque upon device
- * destruction. This may be NULL.
- *
- * @opaque - an opaque pointer to pass to the callbacks for the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_add(DeviceState *dev, const char *name, const char *type,
- DevicePropertyAccessor *get, DevicePropertyAccessor *set,
- DevicePropertyRelease *release,
- void *opaque, Error **errp);
-
-/**
- * @qdev_property_get - reads a property from a device
- *
- * @dev - the device
- *
- * @v - the visitor that will receive the property value. This should be an
- * Output visitor and the data will be written with @name as the name.
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
- Error **errp);
-
-/**
- * @qdev_property_set - writes a property to a device
- *
- * @dev - the device
- *
- * @v - the visitor that will be used to write the property value. This should
- * be an Input visitor and the data will be first read with @name as the
- * name and then written as the property value.
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
- Error **errp);
-
-/**
- * @qdev_property_get_type - returns the type of a property
- *
- * @dev - the device
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- *
- * Returns:
- * The type name of the property.
- */
-const char *qdev_property_get_type(DeviceState *dev, const char *name,
- Error **errp);
-
-/**
* @qdev_property_add_static - add a @Property to a device referencing a
* field in a struct.
*/
void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp);
/**
- * @qdev_get_root - returns the root device of the composition tree
- *
- * Returns:
- * The root of the composition tree.
- */
-DeviceState *qdev_get_root(void);
-
-/**
- * @qdev_get_canonical_path - returns the canonical path for a device. This
- * is the path within the composition tree starting from the root.
- *
- * Returns:
- * The canonical path in the composition tree.
- */
-gchar *qdev_get_canonical_path(DeviceState *dev);
-
-/**
- * @qdev_resolve_path - resolves a path returning a device
- *
- * There are two types of supported paths--absolute paths and partial paths.
- *
- * Absolute paths are derived from the root device and can follow child<> or
- * link<> properties. Since they can follow link<> properties, they can be
- * arbitrarily long. Absolute paths look like absolute filenames and are
- * prefixed with a leading slash.
- *
- * Partial paths look like relative filenames. They do not begin with a
- * prefix. The matching rules for partial paths are subtle but designed to make
- * specifying devices easy. At each level of the composition tree, the partial
- * path is matched as an absolute path. The first match is not returned. At
- * least two matches are searched for. A successful result is only returned if
- * only one match is founded. If more than one match is found, a flag is
- * return to indicate that the match was ambiguous.
- *
- * @path - the path to resolve
- *
- * @ambiguous - returns true if the path resolution failed because of an
- * ambiguous match
- *
- * Returns:
- * The matched device or NULL on path lookup failure.
- */
-DeviceState *qdev_resolve_path(const char *path, bool *ambiguous);
-
-/**
- * @qdev_property_add_child - Add a child property to a device
- *
- * Child properties form the composition tree. All devices need to be a child
- * of another device. Devices can only be a child of one device.
- *
- * There is no way for a child to determine what its parent is. It is not
- * a bidirectional relationship. This is by design.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @child - the child device
- *
- * @errp - if an error occurs, a pointer to an area to store the area
- */
-void qdev_property_add_child(DeviceState *dev, const char *name,
- DeviceState *child, Error **errp);
-
-/**
- * @qdev_property_add_link - Add a link property to a device
- *
- * Links establish relationships between devices. Links are unidirectional
- * although two links can be combined to form a bidirectional relationship
- * between devices.
- *
- * Links form the graph in the device model.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @type - the qdev type of the link
- *
- * @child - a pointer to where the link device reference is stored
- *
- * @errp - if an error occurs, a pointer to an area to store the area
- */
-void qdev_property_add_link(DeviceState *dev, const char *name,
- const char *type, DeviceState **child,
- Error **errp);
-
-/**
- * @qdev_property_add_str
- *
- * Add a string property using getters/setters. This function will add a
- * property of type 'string'.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @get - the getter or NULL if the property is write-only. This function must
- * return a string to be freed by @g_free().
- *
- * @set - the setter or NULL if the property is read-only
- *
- * @errp - if an error occurs, a pointer to an area to store the error
- */
-void qdev_property_add_str(DeviceState *dev, const char *name,
- char *(*get)(DeviceState *, Error **),
- void (*set)(DeviceState *, const char *, Error **),
- Error **errp);
-
-/**
- * @qdev_get_type
- *
- * Returns the string representation of the type of this object.
- *
- * @dev - the device
- *
- * @errp - if an error occurs, a pointer to an area to store the error
- *
- * Returns: a string representing the type. This must be freed by the caller
- * with g_free().
- */
-char *qdev_get_type(DeviceState *dev, Error **errp);
-
-/**
* @qdev_machine_init
*
* Initialize platform devices before machine init. This is a hack until full
@@ -624,4 +353,24 @@
*/
void qdev_machine_init(void);
+/**
+ * @device_reset
+ *
+ * Reset a single device (by calling the reset method).
+ */
+void device_reset(DeviceState *dev);
+
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev);
+
+const char *qdev_fw_name(DeviceState *dev);
+
+BusInfo *qdev_get_bus_info(DeviceState *dev);
+
+Property *qdev_get_props(DeviceState *dev);
+
+/* FIXME: make this a link<> */
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
+
+extern int qdev_hotplug;
+
#endif
diff --git a/hw/qxl.c b/hw/qxl.c
index ac81927..bc03c1d 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -343,10 +343,7 @@
/* can be called from spice server thread context */
static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
{
- while (addr < end) {
- memory_region_set_dirty(mr, addr);
- addr += TARGET_PAGE_SIZE;
- }
+ memory_region_set_dirty(mr, addr, end - addr);
}
static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
@@ -1020,7 +1017,7 @@
case MEMSLOT_GROUP_HOST:
return (void*)offset;
case MEMSLOT_GROUP_GUEST:
- PANIC_ON(slot > NUM_MEMSLOTS);
+ PANIC_ON(slot >= NUM_MEMSLOTS);
PANIC_ON(!qxl->guest_slots[slot].active);
PANIC_ON(offset < qxl->guest_slots[slot].delta);
offset -= qxl->guest_slots[slot].delta;
@@ -1827,38 +1824,56 @@
DEFINE_PROP_END_OF_LIST(),
};
-static PCIDeviceInfo qxl_info_primary = {
- .qdev.name = "qxl-vga",
- .qdev.desc = "Spice QXL GPU (primary, vga compatible)",
- .qdev.size = sizeof(PCIQXLDevice),
- .qdev.reset = qxl_reset_handler,
- .qdev.vmsd = &qxl_vmstate,
- .no_hotplug = 1,
- .init = qxl_init_primary,
- .romfile = "vgabios-qxl.bin",
- .vendor_id = REDHAT_PCI_VENDOR_ID,
- .device_id = QXL_DEVICE_ID_STABLE,
- .class_id = PCI_CLASS_DISPLAY_VGA,
- .qdev.props = qxl_properties,
+static void qxl_primary_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = qxl_init_primary;
+ k->romfile = "vgabios-qxl.bin";
+ k->vendor_id = REDHAT_PCI_VENDOR_ID;
+ k->device_id = QXL_DEVICE_ID_STABLE;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ dc->desc = "Spice QXL GPU (primary, vga compatible)";
+ dc->reset = qxl_reset_handler;
+ dc->vmsd = &qxl_vmstate;
+ dc->props = qxl_properties;
+}
+
+static TypeInfo qxl_primary_info = {
+ .name = "qxl-vga",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIQXLDevice),
+ .class_init = qxl_primary_class_init,
};
-static PCIDeviceInfo qxl_info_secondary = {
- .qdev.name = "qxl",
- .qdev.desc = "Spice QXL GPU (secondary)",
- .qdev.size = sizeof(PCIQXLDevice),
- .qdev.reset = qxl_reset_handler,
- .qdev.vmsd = &qxl_vmstate,
- .init = qxl_init_secondary,
- .vendor_id = REDHAT_PCI_VENDOR_ID,
- .device_id = QXL_DEVICE_ID_STABLE,
- .class_id = PCI_CLASS_DISPLAY_OTHER,
- .qdev.props = qxl_properties,
+static void qxl_secondary_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = qxl_init_secondary;
+ k->vendor_id = REDHAT_PCI_VENDOR_ID;
+ k->device_id = QXL_DEVICE_ID_STABLE;
+ k->class_id = PCI_CLASS_DISPLAY_OTHER;
+ dc->desc = "Spice QXL GPU (secondary)";
+ dc->reset = qxl_reset_handler;
+ dc->vmsd = &qxl_vmstate;
+ dc->props = qxl_properties;
+}
+
+static TypeInfo qxl_secondary_info = {
+ .name = "qxl",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIQXLDevice),
+ .class_init = qxl_secondary_class_init,
};
static void qxl_register(void)
{
- pci_qdev_register(&qxl_info_primary);
- pci_qdev_register(&qxl_info_secondary);
+ type_register_static(&qxl_primary_info);
+ type_register_static(&qxl_secondary_info);
}
device_init(qxl_register);
diff --git a/hw/realview.c b/hw/realview.c
index 3f35118..821e627 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -82,15 +82,23 @@
return 0;
}
-static SysBusDeviceInfo realview_i2c_info = {
- .init = realview_i2c_init,
- .qdev.name = "realview_i2c",
- .qdev.size = sizeof(RealViewI2CState),
+static void realview_i2c_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = realview_i2c_init;
+}
+
+static TypeInfo realview_i2c_info = {
+ .name = "realview_i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RealViewI2CState),
+ .class_init = realview_i2c_class_init,
};
static void realview_register_devices(void)
{
- sysbus_register_withprop(&realview_i2c_info);
+ type_register_static(&realview_i2c_info);
}
/* Board init. */
@@ -227,6 +235,8 @@
for (n = 0; n < smp_cpus; n++) {
sysbus_connect_irq(busdev, n, cpu_irq[n]);
}
+ sysbus_create_varargs("l2x0", realview_binfo.smp_priv_base + 0x2000,
+ NULL);
} else {
uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
/* For now just create the nIRQ GIC, and ignore the others. */
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 8c4d509..4121502 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,7 +9,6 @@
#include "sysbus.h"
-#define GIC_NIRQ 96
#define NCPU 1
/* Only a single "CPU" interface is present. */
@@ -37,16 +36,33 @@
{
RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
- gic_init(&s->gic);
+ /* The GICs on the RealView boards have a fixed nonconfigurable
+ * number of interrupt lines, so we don't need to expose this as
+ * a qdev property.
+ */
+ gic_init(&s->gic, 96);
realview_gic_map_setup(s);
sysbus_init_mmio(dev, &s->container);
return 0;
}
+static void realview_gic_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = realview_gic_init;
+}
+
+static TypeInfo realview_gic_info = {
+ .name = "realview_gic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RealViewGICState),
+ .class_init = realview_gic_class_init,
+};
+
static void realview_gic_register_devices(void)
{
- sysbus_register_dev("realview_gic", sizeof(RealViewGICState),
- realview_gic_init);
+ type_register_static(&realview_gic_info);
}
device_init(realview_gic_register_devices)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 0ae9f57..1668390 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3478,7 +3478,7 @@
s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
s->cplus_txbuffer = NULL;
@@ -3494,27 +3494,38 @@
return 0;
}
-static PCIDeviceInfo rtl8139_info = {
- .qdev.name = "rtl8139",
- .qdev.size = sizeof(RTL8139State),
- .qdev.reset = rtl8139_reset,
- .qdev.vmsd = &vmstate_rtl8139,
- .init = pci_rtl8139_init,
- .exit = pci_rtl8139_uninit,
- .romfile = "pxe-rtl8139.rom",
- .vendor_id = PCI_VENDOR_ID_REALTEK,
- .device_id = PCI_DEVICE_ID_REALTEK_8139,
- .revision = RTL8139_PCI_REVID, /* >=0x20 is for 8139C+ */
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(RTL8139State, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property rtl8139_properties[] = {
+ DEFINE_NIC_PROPERTIES(RTL8139State, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtl8139_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_rtl8139_init;
+ k->exit = pci_rtl8139_uninit;
+ k->romfile = "pxe-rtl8139.rom";
+ k->vendor_id = PCI_VENDOR_ID_REALTEK;
+ k->device_id = PCI_DEVICE_ID_REALTEK_8139;
+ k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->reset = rtl8139_reset;
+ dc->vmsd = &vmstate_rtl8139;
+ dc->props = rtl8139_properties;
+}
+
+static TypeInfo rtl8139_info = {
+ .name = "rtl8139",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(RTL8139State),
+ .class_init = rtl8139_class_init,
};
static void rtl8139_register_devices(void)
{
- pci_qdev_register(&rtl8139_info);
+ type_register_static(&rtl8139_info);
}
device_init(rtl8139_register_devices)
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 2efea9f..49140f8 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -50,12 +50,6 @@
.size = sizeof(VirtIOS390Bus),
};
-typedef struct {
- DeviceInfo qdev;
- int (*init)(VirtIOS390Device *dev);
-} VirtIOS390DeviceInfo;
-
-
static const VirtIOBindings virtio_s390_bindings;
static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev);
@@ -343,69 +337,108 @@
.get_features = virtio_s390_get_features,
};
-static VirtIOS390DeviceInfo s390_virtio_net = {
- .init = s390_virtio_net_init,
- .qdev.name = "virtio-net-s390",
- .qdev.alias = "virtio-net",
- .qdev.size = sizeof(VirtIOS390Device),
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
- DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
- net.txtimer, TX_TIMER_INTERVAL),
- DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
- net.txburst, TX_BURST),
- DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property s390_virtio_net_properties[] = {
+ DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
+ DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
+ net.txtimer, TX_TIMER_INTERVAL),
+ DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
+ net.txburst, TX_BURST),
+ DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
+ DEFINE_PROP_END_OF_LIST(),
};
-static VirtIOS390DeviceInfo s390_virtio_blk = {
- .init = s390_virtio_blk_init,
- .qdev.name = "virtio-blk-s390",
- .qdev.alias = "virtio-blk",
- .qdev.size = sizeof(VirtIOS390Device),
- .qdev.props = (Property[]) {
- DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
- DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
- DEFINE_PROP_END_OF_LIST(),
- },
-};
-
-static VirtIOS390DeviceInfo s390_virtio_serial = {
- .init = s390_virtio_serial_init,
- .qdev.name = "virtio-serial-s390",
- .qdev.alias = "virtio-serial",
- .qdev.size = sizeof(VirtIOS390Device),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
- serial.max_virtserial_ports, 31),
- DEFINE_PROP_END_OF_LIST(),
- },
-};
-
-static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info)
+static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
{
- VirtIOS390DeviceInfo *_info = (VirtIOS390DeviceInfo *)info;
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_net_init;
+ dc->props = s390_virtio_net_properties;
+}
+
+static TypeInfo s390_virtio_net = {
+ .name = "virtio-net-s390",
+ .parent = TYPE_VIRTIO_S390_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = s390_virtio_net_class_init,
+};
+
+static Property s390_virtio_blk_properties[] = {
+ DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
+ DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_blk_init;
+ dc->props = s390_virtio_blk_properties;
+}
+
+static TypeInfo s390_virtio_blk = {
+ .name = "virtio-blk-s390",
+ .parent = TYPE_VIRTIO_S390_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = s390_virtio_blk_class_init,
+};
+
+static Property s390_virtio_serial_properties[] = {
+ DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
+ serial.max_virtserial_ports, 31),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_serial_init;
+ dc->props = s390_virtio_serial_properties;
+}
+
+static TypeInfo s390_virtio_serial = {
+ .name = "virtio-serial-s390",
+ .parent = TYPE_VIRTIO_S390_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = s390_virtio_serial_class_init,
+};
+
+static int s390_virtio_busdev_init(DeviceState *dev)
+{
VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
+ VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev);
return _info->init(_dev);
}
-static void s390_virtio_bus_register_withprop(VirtIOS390DeviceInfo *info)
+static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
{
- info->qdev.init = s390_virtio_busdev_init;
- info->qdev.bus_info = &s390_virtio_bus_info;
- info->qdev.unplug = qdev_simple_unplug_cb;
+ DeviceClass *dc = DEVICE_CLASS(klass);
- assert(info->qdev.size >= sizeof(VirtIOS390Device));
- qdev_register(&info->qdev);
+ dc->init = s390_virtio_busdev_init;
+ dc->bus_info = &s390_virtio_bus_info;
+ dc->unplug = qdev_simple_unplug_cb;
}
+static TypeInfo virtio_s390_device_info = {
+ .name = TYPE_VIRTIO_S390_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = virtio_s390_device_class_init,
+ .class_size = sizeof(VirtIOS390DeviceClass),
+ .abstract = true,
+};
+
static void s390_virtio_register(void)
{
- s390_virtio_bus_register_withprop(&s390_virtio_serial);
- s390_virtio_bus_register_withprop(&s390_virtio_blk);
- s390_virtio_bus_register_withprop(&s390_virtio_net);
+ type_register_static(&virtio_s390_device_info);
+ type_register_static(&s390_virtio_serial);
+ type_register_static(&s390_virtio_blk);
+ type_register_static(&s390_virtio_net);
}
device_init(s390_virtio_register);
@@ -419,16 +452,25 @@
return 0;
}
-static SysBusDeviceInfo s390_virtio_bridge_info = {
- .init = s390_virtio_bridge_init,
- .qdev.name = "s390-virtio-bridge",
- .qdev.size = sizeof(SysBusDevice),
- .qdev.no_user = 1,
+static void s390_virtio_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_bridge_init;
+ dc->no_user = 1;
+}
+
+static TypeInfo s390_virtio_bridge_info = {
+ .name = "s390-virtio-bridge",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = s390_virtio_bridge_class_init,
};
static void s390_virtio_register_devices(void)
{
- sysbus_register_withprop(&s390_virtio_bridge_info);
+ type_register_static(&s390_virtio_bridge_info);
}
device_init(s390_virtio_register_devices)
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index d02a907..b5e59b7 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -40,7 +40,22 @@
#define VIRTIO_PARAM_CONFIG_CHANGED 0x1
#define VIRTIO_PARAM_DEV_ADD 0x2
-typedef struct VirtIOS390Device {
+#define TYPE_VIRTIO_S390_DEVICE "virtio-s390-device"
+#define VIRTIO_S390_DEVICE(obj) \
+ OBJECT_CHECK(VirtIOS390Device, (obj), TYPE_VIRTIO_S390_DEVICE)
+#define VIRTIO_S390_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VirtIOS390DeviceClass, (klass), TYPE_VIRTIO_S390_DEVICE)
+#define VIRTIO_S390_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VirtIOS390DeviceClass, (obj), TYPE_VIRTIO_S390_DEVICE)
+
+typedef struct VirtIOS390Device VirtIOS390Device;
+
+typedef struct VirtIOS390DeviceClass {
+ DeviceClass qdev;
+ int (*init)(VirtIOS390Device *dev);
+} VirtIOS390DeviceClass;
+
+struct VirtIOS390Device {
DeviceState qdev;
ram_addr_t dev_offs;
ram_addr_t feat_offs;
@@ -52,7 +67,7 @@
uint32_t host_features;
virtio_serial_conf serial;
virtio_net_conf net;
-} VirtIOS390Device;
+};
typedef struct VirtIOS390Bus {
BusState bus;
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index 2210b8a..51123a7 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -317,7 +317,6 @@
.no_serial = 1,
.no_parallel = 1,
.use_virtcon = 1,
- .no_vga = 1,
.max_cpus = 255,
.is_default = 1,
};
diff --git a/hw/sb16.c b/hw/sb16.c
index 887b32e..db8929b 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1289,55 +1289,55 @@
.minimum_version_id_old = 1,
.post_load = sb16_post_load,
.fields = (VMStateField []) {
- VMSTATE_UINT32(irq, SB16State),
- VMSTATE_UINT32(dma, SB16State),
- VMSTATE_UINT32(hdma, SB16State),
- VMSTATE_UINT32(port, SB16State),
- VMSTATE_UINT32(ver, SB16State),
- VMSTATE_INT32(in_index, SB16State),
- VMSTATE_INT32(out_data_len, SB16State),
- VMSTATE_INT32(fmt_stereo, SB16State),
- VMSTATE_INT32(fmt_signed, SB16State),
- VMSTATE_INT32(fmt_bits, SB16State),
- VMSTATE_UINT32(fmt, SB16State),
- VMSTATE_INT32(dma_auto, SB16State),
- VMSTATE_INT32(block_size, SB16State),
- VMSTATE_INT32(fifo, SB16State),
- VMSTATE_INT32(freq, SB16State),
- VMSTATE_INT32(time_const, SB16State),
- VMSTATE_INT32(speaker, SB16State),
- VMSTATE_INT32(needed_bytes, SB16State),
- VMSTATE_INT32(cmd, SB16State),
- VMSTATE_INT32(use_hdma, SB16State),
- VMSTATE_INT32(highspeed, SB16State),
- VMSTATE_INT32(can_write, SB16State),
- VMSTATE_INT32(v2x6, SB16State),
+ VMSTATE_UINT32 (irq, SB16State),
+ VMSTATE_UINT32 (dma, SB16State),
+ VMSTATE_UINT32 (hdma, SB16State),
+ VMSTATE_UINT32 (port, SB16State),
+ VMSTATE_UINT32 (ver, SB16State),
+ VMSTATE_INT32 (in_index, SB16State),
+ VMSTATE_INT32 (out_data_len, SB16State),
+ VMSTATE_INT32 (fmt_stereo, SB16State),
+ VMSTATE_INT32 (fmt_signed, SB16State),
+ VMSTATE_INT32 (fmt_bits, SB16State),
+ VMSTATE_UINT32 (fmt, SB16State),
+ VMSTATE_INT32 (dma_auto, SB16State),
+ VMSTATE_INT32 (block_size, SB16State),
+ VMSTATE_INT32 (fifo, SB16State),
+ VMSTATE_INT32 (freq, SB16State),
+ VMSTATE_INT32 (time_const, SB16State),
+ VMSTATE_INT32 (speaker, SB16State),
+ VMSTATE_INT32 (needed_bytes, SB16State),
+ VMSTATE_INT32 (cmd, SB16State),
+ VMSTATE_INT32 (use_hdma, SB16State),
+ VMSTATE_INT32 (highspeed, SB16State),
+ VMSTATE_INT32 (can_write, SB16State),
+ VMSTATE_INT32 (v2x6, SB16State),
- VMSTATE_UINT8(csp_param, SB16State),
- VMSTATE_UINT8(csp_value, SB16State),
- VMSTATE_UINT8(csp_mode, SB16State),
- VMSTATE_UINT8(csp_param, SB16State),
- VMSTATE_BUFFER(csp_regs, SB16State),
- VMSTATE_UINT8(csp_index, SB16State),
- VMSTATE_BUFFER(csp_reg83, SB16State),
- VMSTATE_INT32(csp_reg83r, SB16State),
- VMSTATE_INT32(csp_reg83w, SB16State),
+ VMSTATE_UINT8 (csp_param, SB16State),
+ VMSTATE_UINT8 (csp_value, SB16State),
+ VMSTATE_UINT8 (csp_mode, SB16State),
+ VMSTATE_UINT8 (csp_param, SB16State),
+ VMSTATE_BUFFER (csp_regs, SB16State),
+ VMSTATE_UINT8 (csp_index, SB16State),
+ VMSTATE_BUFFER (csp_reg83, SB16State),
+ VMSTATE_INT32 (csp_reg83r, SB16State),
+ VMSTATE_INT32 (csp_reg83w, SB16State),
- VMSTATE_BUFFER(in2_data, SB16State),
- VMSTATE_BUFFER(out_data, SB16State),
- VMSTATE_UINT8(test_reg, SB16State),
- VMSTATE_UINT8(last_read_byte, SB16State),
+ VMSTATE_BUFFER (in2_data, SB16State),
+ VMSTATE_BUFFER (out_data, SB16State),
+ VMSTATE_UINT8 (test_reg, SB16State),
+ VMSTATE_UINT8 (last_read_byte, SB16State),
- VMSTATE_INT32(nzero, SB16State),
- VMSTATE_INT32(left_till_irq, SB16State),
- VMSTATE_INT32(dma_running, SB16State),
- VMSTATE_INT32(bytes_per_second, SB16State),
- VMSTATE_INT32(align, SB16State),
+ VMSTATE_INT32 (nzero, SB16State),
+ VMSTATE_INT32 (left_till_irq, SB16State),
+ VMSTATE_INT32 (dma_running, SB16State),
+ VMSTATE_INT32 (bytes_per_second, SB16State),
+ VMSTATE_INT32 (align, SB16State),
- VMSTATE_INT32(mixer_nreg, SB16State),
- VMSTATE_BUFFER(mixer_regs, SB16State),
+ VMSTATE_INT32 (mixer_nreg, SB16State),
+ VMSTATE_BUFFER (mixer_regs, SB16State),
- VMSTATE_END_OF_LIST()
+ VMSTATE_END_OF_LIST ()
}
};
@@ -1349,7 +1349,7 @@
{ 10, 1, 1, .read = dsp_read },
{ 12, 1, 1, .write = dsp_write },
{ 12, 4, 1, .read = dsp_read },
- PORTIO_END_OF_LIST(),
+ PORTIO_END_OF_LIST (),
};
@@ -1391,24 +1391,34 @@
return 0;
}
-static ISADeviceInfo sb16_info = {
- .qdev.name = "sb16",
- .qdev.desc = "Creative Sound Blaster 16",
- .qdev.size = sizeof (SB16State),
- .qdev.vmsd = &vmstate_sb16,
- .init = sb16_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32 ("version", SB16State, ver, 0x0405), /* 4.5 */
- DEFINE_PROP_HEX32 ("iobase", SB16State, port, 0x220),
- DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
- DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
- DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
- DEFINE_PROP_END_OF_LIST (),
- },
+static Property sb16_properties[] = {
+ DEFINE_PROP_HEX32 ("version", SB16State, ver, 0x0405), /* 4.5 */
+ DEFINE_PROP_HEX32 ("iobase", SB16State, port, 0x220),
+ DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
+ DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
+ DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
+ DEFINE_PROP_END_OF_LIST (),
+};
+
+static void sb16_class_initfn (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+ ic->init = sb16_initfn;
+ dc->desc = "Creative Sound Blaster 16";
+ dc->vmsd = &vmstate_sb16;
+ dc->props = sb16_properties;
+}
+
+static TypeInfo sb16_info = {
+ .name = "sb16",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof (SB16State),
+ .class_init = sb16_class_initfn,
};
static void sb16_register (void)
{
- isa_qdev_register (&sb16_info);
+ type_register_static (&sb16_info);
}
device_init (sb16_register)
diff --git a/hw/sbi.c b/hw/sbi.c
index 8965a71..847a4dd 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -131,17 +131,26 @@
return 0;
}
-static SysBusDeviceInfo sbi_info = {
- .init = sbi_init1,
- .qdev.name = "sbi",
- .qdev.size = sizeof(SBIState),
- .qdev.vmsd = &vmstate_sbi,
- .qdev.reset = sbi_reset,
+static void sbi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sbi_init1;
+ dc->reset = sbi_reset;
+ dc->vmsd = &vmstate_sbi;
+}
+
+static TypeInfo sbi_info = {
+ .name = "sbi",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SBIState),
+ .class_init = sbi_class_init,
};
static void sbi_register_devices(void)
{
- sysbus_register_withprop(&sbi_info);
+ type_register_static(&sbi_info);
}
device_init(sbi_register_devices)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 64e709e..0ee50a8 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -23,6 +23,42 @@
};
static int next_scsi_bus;
+static int scsi_device_init(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->init) {
+ return sc->init(s);
+ }
+ return 0;
+}
+
+static void scsi_device_destroy(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->destroy) {
+ sc->destroy(s);
+ }
+}
+
+static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun,
+ uint8_t *buf, void *hba_private)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->alloc_req) {
+ return sc->alloc_req(s, tag, lun, buf, hba_private);
+ }
+
+ return NULL;
+}
+
+static void scsi_device_unit_attention_reported(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->unit_attention_reported) {
+ sc->unit_attention_reported(s);
+ }
+}
+
/* Create a scsi bus, and attach devices to it. */
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
{
@@ -79,10 +115,9 @@
}
}
-static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int scsi_qdev_init(DeviceState *qdev)
{
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
- SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
SCSIDevice *d;
int rc = -1;
@@ -126,9 +161,8 @@
}
}
- dev->info = info;
QTAILQ_INIT(&dev->requests);
- rc = dev->info->init(dev);
+ rc = scsi_device_init(dev);
if (rc == 0) {
dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
dev);
@@ -140,26 +174,15 @@
static int scsi_qdev_exit(DeviceState *qdev)
{
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->vmsentry) {
qemu_del_vm_change_state_handler(dev->vmsentry);
}
- if (dev->info->destroy) {
- dev->info->destroy(dev);
- }
+ scsi_device_destroy(dev);
return 0;
}
-void scsi_qdev_register(SCSIDeviceInfo *info)
-{
- info->qdev.bus_info = &scsi_bus_info;
- info->qdev.init = scsi_qdev_init;
- info->qdev.unplug = qdev_simple_unplug_cb;
- info->qdev.exit = scsi_qdev_exit;
- qdev_register(&info->qdev);
-}
-
/* handle legacy '-drive if=scsi,...' cmd line args */
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
int unit, bool removable, int bootindex)
@@ -182,7 +205,7 @@
}
if (qdev_init(dev) < 0)
return NULL;
- return DO_UPCAST(SCSIDevice, qdev, dev);
+ return SCSI_DEVICE(dev);
}
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
@@ -278,7 +301,7 @@
found_lun0 = false;
n = 0;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == 0) {
@@ -300,7 +323,7 @@
stl_be_p(&r->buf, n);
i = found_lun0 ? 8 : 16;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
store_lun(&r->buf[i], dev->lun);
@@ -398,9 +421,7 @@
MIN(req->cmd.xfer, sizeof r->buf),
(req->cmd.buf[1] & 1) == 0);
if (r->req.dev->sense_is_ua) {
- if (r->req.dev->info->unit_attention_reported) {
- r->req.dev->info->unit_attention_reported(req->dev);
- }
+ scsi_device_unit_attention_reported(req->dev);
r->req.dev->sense_len = 0;
r->req.dev->sense_is_ua = false;
}
@@ -507,7 +528,7 @@
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
hba_private);
} else {
- req = d->info->alloc_req(d, tag, lun, buf, hba_private);
+ req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
}
}
@@ -597,9 +618,7 @@
* Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
*/
if (req->dev->sense_is_ua) {
- if (req->dev->info->unit_attention_reported) {
- req->dev->info->unit_attention_reported(req->dev);
- }
+ scsi_device_unit_attention_reported(req->dev);
req->dev->sense_len = 0;
req->dev->sense_is_ua = false;
}
@@ -1367,7 +1386,7 @@
static char *scsibus_get_fw_dev_path(DeviceState *dev)
{
- SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
+ SCSIDevice *d = SCSI_DEVICE(dev);
char path[100];
snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel,
@@ -1382,7 +1401,7 @@
SCSIDevice *target_dev = NULL;
QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == lun) {
@@ -1393,3 +1412,28 @@
}
return target_dev;
}
+
+static void scsi_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->bus_info = &scsi_bus_info;
+ k->init = scsi_qdev_init;
+ k->unplug = qdev_simple_unplug_cb;
+ k->exit = scsi_qdev_exit;
+}
+
+static TypeInfo scsi_device_type_info = {
+ .name = TYPE_SCSI_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SCSIDevice),
+ .abstract = true,
+ .class_size = sizeof(SCSIDeviceClass),
+ .class_init = scsi_device_class_init,
+};
+
+static void scsi_register_devices(void)
+{
+ type_register_static(&scsi_device_type_info);
+}
+
+device_init(scsi_register_devices);
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 5d8bf53..399e51e 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -391,9 +391,6 @@
}
l = strlen(s->serial);
- if (l > req->cmd.xfer) {
- l = req->cmd.xfer;
- }
if (l > 20) {
l = 20;
}
@@ -1002,9 +999,6 @@
outbuf[0] = ((buflen - 2) >> 8) & 0xff;
outbuf[1] = (buflen - 2) & 0xff;
}
- if (buflen > r->req.cmd.xfer) {
- buflen = r->req.cmd.xfer;
- }
return buflen;
}
@@ -1038,9 +1032,6 @@
default:
return -1;
}
- if (toclen > req->cmd.xfer) {
- toclen = req->cmd.xfer;
- }
return toclen;
}
@@ -1251,6 +1242,7 @@
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
return -1;
}
+ buflen = MIN(buflen, req->cmd.xfer);
return buflen;
not_ready:
@@ -1720,75 +1712,124 @@
DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
DEFINE_PROP_STRING("serial", SCSIDiskState, serial)
-static SCSIDeviceInfo scsi_disk_info[] = {
- {
- .qdev.name = "scsi-hd",
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI disk",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_hd_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- }
- },{
- .qdev.name = "scsi-cd",
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI CD-ROM",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_cd_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property scsi_hd_properties[] = {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_hd_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+ dc->fw_name = "disk";
+ dc->desc = "virtual SCSI disk";
+ dc->reset = scsi_disk_reset;
+ dc->props = scsi_hd_properties;
+}
+
+static TypeInfo scsi_hd_info = {
+ .name = "scsi-hd",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDiskState),
+ .class_init = scsi_hd_class_initfn,
+};
+
+static Property scsi_cd_properties[] = {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_cd_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+ dc->fw_name = "disk";
+ dc->desc = "virtual SCSI CD-ROM";
+ dc->reset = scsi_disk_reset;
+ dc->props = scsi_cd_properties;
+}
+
+static TypeInfo scsi_cd_info = {
+ .name = "scsi-cd",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDiskState),
+ .class_init = scsi_cd_class_initfn,
+};
+
#ifdef __linux__
- },{
- .qdev.name = "scsi-block",
- .qdev.fw_name = "disk",
- .qdev.desc = "SCSI block device passthrough",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_block_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_block_new_request,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property scsi_block_properties[] = {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_block_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_block_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_block_new_request;
+ dc->fw_name = "disk";
+ dc->desc = "SCSI block device passthrough";
+ dc->reset = scsi_disk_reset;
+ dc->props = scsi_block_properties;
+}
+
+static TypeInfo scsi_block_info = {
+ .name = "scsi-block",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDiskState),
+ .class_init = scsi_block_class_initfn,
+};
#endif
- },{
- .qdev.name = "scsi-disk", /* legacy -device scsi-disk */
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI disk or CD-ROM (legacy)",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_disk_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- }
- }
+
+static Property scsi_disk_properties[] = {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_disk_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_disk_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+ dc->fw_name = "disk";
+ dc->desc = "virtual SCSI disk or CD-ROM (legacy)";
+ dc->reset = scsi_disk_reset;
+ dc->props = scsi_disk_properties;
+}
+
+static TypeInfo scsi_disk_info = {
+ .name = "scsi-disk",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDiskState),
+ .class_init = scsi_disk_class_initfn,
};
static void scsi_disk_register_devices(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
- scsi_qdev_register(&scsi_disk_info[i]);
- }
+ type_register_static(&scsi_hd_info);
+ type_register_static(&scsi_cd_info);
+#ifdef __linux__
+ type_register_static(&scsi_block_info);
+#endif
+ type_register_static(&scsi_disk_info);
}
device_init(scsi_disk_register_devices)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 0aebcddf..4859212 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -357,7 +357,7 @@
static void scsi_generic_reset(DeviceState *dev)
{
- SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
+ SCSIDevice *s = SCSI_DEVICE(dev);
scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
@@ -457,24 +457,35 @@
return req;
}
-static SCSIDeviceInfo scsi_generic_info = {
- .qdev.name = "scsi-generic",
- .qdev.fw_name = "disk",
- .qdev.desc = "pass through generic scsi device (/dev/sg*)",
- .qdev.size = sizeof(SCSIDevice),
- .qdev.reset = scsi_generic_reset,
- .init = scsi_generic_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .qdev.props = (Property[]) {
- DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property scsi_generic_properties[] = {
+ DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_generic_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ dc->fw_name = "disk";
+ dc->desc = "pass through generic scsi device (/dev/sg*)";
+ dc->reset = scsi_generic_reset;
+ dc->props = scsi_generic_properties;
+}
+
+static TypeInfo scsi_generic_info = {
+ .name = "scsi-generic",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDevice),
+ .class_init = scsi_generic_class_initfn,
};
static void scsi_generic_register_devices(void)
{
- scsi_qdev_register(&scsi_generic_info);
+ type_register_static(&scsi_generic_info);
}
device_init(scsi_generic_register_devices)
diff --git a/hw/scsi.h b/hw/scsi.h
index ab6e952..dc72b6f 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -13,7 +13,6 @@
typedef struct SCSIBusInfo SCSIBusInfo;
typedef struct SCSICommand SCSICommand;
typedef struct SCSIDevice SCSIDevice;
-typedef struct SCSIDeviceInfo SCSIDeviceInfo;
typedef struct SCSIRequest SCSIRequest;
typedef struct SCSIReqOps SCSIReqOps;
@@ -58,6 +57,23 @@
QTAILQ_ENTRY(SCSIRequest) next;
};
+#define TYPE_SCSI_DEVICE "scsi-device"
+#define SCSI_DEVICE(obj) \
+ OBJECT_CHECK(SCSIDevice, (obj), TYPE_SCSI_DEVICE)
+#define SCSI_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SCSIDeviceClass, (klass), TYPE_SCSI_DEVICE)
+#define SCSI_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SCSIDeviceClass, (obj), TYPE_SCSI_DEVICE)
+
+typedef struct SCSIDeviceClass {
+ DeviceClass parent_class;
+ int (*init)(SCSIDevice *dev);
+ void (*destroy)(SCSIDevice *s);
+ SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
+ uint8_t *buf, void *hba_private);
+ void (*unit_attention_reported)(SCSIDevice *s);
+} SCSIDeviceClass;
+
struct SCSIDevice
{
DeviceState qdev;
@@ -65,7 +81,6 @@
QEMUBH *bh;
uint32_t id;
BlockConf conf;
- SCSIDeviceInfo *info;
SCSISense unit_attention;
bool sense_is_ua;
uint8_t sense[SCSI_SENSE_BUF_SIZE];
@@ -93,16 +108,6 @@
uint8_t *(*get_buf)(SCSIRequest *req);
};
-typedef int (*scsi_qdev_initfn)(SCSIDevice *dev);
-struct SCSIDeviceInfo {
- DeviceInfo qdev;
- scsi_qdev_initfn init;
- void (*destroy)(SCSIDevice *s);
- SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
- uint8_t *buf, void *hba_private);
- void (*unit_attention_reported)(SCSIDevice *s);
-};
-
struct SCSIBusInfo {
int tcq;
int max_channel, max_target, max_lun;
@@ -120,7 +125,6 @@
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
-void scsi_qdev_register(SCSIDeviceInfo *info);
static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
{
diff --git a/hw/serial.c b/hw/serial.c
index d35c7a9..82917e2 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -879,23 +879,33 @@
return s;
}
-static ISADeviceInfo serial_isa_info = {
- .qdev.name = "isa-serial",
- .qdev.size = sizeof(ISASerialState),
- .qdev.vmsd = &vmstate_isa_serial,
- .init = serial_isa_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
- DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1),
- DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1),
- DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property serial_isa_properties[] = {
+ DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
+ DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1),
+ DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1),
+ DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void serial_isa_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = serial_isa_initfn;
+ dc->vmsd = &vmstate_isa_serial;
+ dc->props = serial_isa_properties;
+}
+
+static TypeInfo serial_isa_info = {
+ .name = "isa-serial",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISASerialState),
+ .class_init = serial_isa_class_initfn,
};
static void serial_register_devices(void)
{
- isa_qdev_register(&serial_isa_info);
+ type_register_static(&serial_isa_info);
}
device_init(serial_register_devices)
diff --git a/hw/sga.c b/hw/sga.c
index 7ef750a..b08e3c5 100644
--- a/hw/sga.c
+++ b/hw/sga.c
@@ -35,22 +35,29 @@
ISADevice dev;
} ISASGAState;
-static int isa_cirrus_vga_initfn(ISADevice *dev)
+static int sga_initfn(ISADevice *dev)
{
rom_add_vga(SGABIOS_FILENAME);
return 0;
}
+static void sga_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = sga_initfn;
+ dc->desc = "Serial Graphics Adapter";
+}
-static ISADeviceInfo sga_info = {
- .qdev.name = "sga",
- .qdev.desc = "Serial Graphics Adapter",
- .qdev.size = sizeof(ISASGAState),
- .init = isa_cirrus_vga_initfn,
+static TypeInfo sga_info = {
+ .name = "sga",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISASGAState),
+ .class_init = sga_class_initfn,
};
static void sga_register(void)
{
- isa_qdev_register(&sga_info);
+ type_register_static(&sga_info);
}
device_init(sga_register);
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index d4d028d..4234d93 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -110,7 +110,7 @@
qemu_set_irq(pic[irq_num], level);
}
-static int sh_pci_init_device(SysBusDevice *dev)
+static int sh_pci_device_init(SysBusDevice *dev)
{
SHPCIState *s;
int i;
@@ -147,19 +147,40 @@
return 0;
}
-static PCIDeviceInfo sh_pci_host_info = {
- .qdev.name = "sh_pci_host",
- .qdev.size = sizeof(PCIDevice),
- .init = sh_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_HITACHI,
- .device_id = PCI_DEVICE_ID_HITACHI_SH7751R,
+static void sh_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = sh_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_HITACHI;
+ k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R;
+}
+
+static TypeInfo sh_pci_host_info = {
+ .name = "sh_pci_host",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = sh_pci_host_class_init,
+};
+
+static void sh_pci_device_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = sh_pci_device_init;
+}
+
+static TypeInfo sh_pci_device_info = {
+ .name = "sh_pci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SHPCIState),
+ .class_init = sh_pci_device_class_init,
};
static void sh_pci_register_devices(void)
{
- sysbus_register_dev("sh_pci", sizeof(SHPCIState),
- sh_pci_init_device);
- pci_qdev_register(&sh_pci_host_info);
+ type_register_static(&sh_pci_device_info);
+ type_register_static(&sh_pci_host_info);
}
device_init(sh_pci_register_devices)
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index 9925e64..e3701c7 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -446,17 +446,26 @@
return 0;
}
-static SysBusDeviceInfo slavio_intctl_info = {
- .init = slavio_intctl_init1,
- .qdev.name = "slavio_intctl",
- .qdev.size = sizeof(SLAVIO_INTCTLState),
- .qdev.vmsd = &vmstate_intctl,
- .qdev.reset = slavio_intctl_reset,
+static void slavio_intctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = slavio_intctl_init1;
+ dc->reset = slavio_intctl_reset;
+ dc->vmsd = &vmstate_intctl;
+}
+
+static TypeInfo slavio_intctl_info = {
+ .name = "slavio_intctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SLAVIO_INTCTLState),
+ .class_init = slavio_intctl_class_init,
};
static void slavio_intctl_register_devices(void)
{
- sysbus_register_withprop(&slavio_intctl_info);
+ type_register_static(&slavio_intctl_info);
}
device_init(slavio_intctl_register_devices)
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 484301c..5a02518 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -468,24 +468,41 @@
return 0;
}
-static SysBusDeviceInfo slavio_misc_info = {
- .init = slavio_misc_init1,
- .qdev.name = "slavio_misc",
- .qdev.size = sizeof(MiscState),
- .qdev.vmsd = &vmstate_misc,
- .qdev.reset = slavio_misc_reset,
+static void slavio_misc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = slavio_misc_init1;
+ dc->reset = slavio_misc_reset;
+ dc->vmsd = &vmstate_misc;
+}
+
+static TypeInfo slavio_misc_info = {
+ .name = "slavio_misc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MiscState),
+ .class_init = slavio_misc_class_init,
};
-static SysBusDeviceInfo apc_info = {
- .init = apc_init1,
- .qdev.name = "apc",
- .qdev.size = sizeof(MiscState),
+static void apc_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = apc_init1;
+}
+
+static TypeInfo apc_info = {
+ .name = "apc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MiscState),
+ .class_init = apc_class_init,
};
static void slavio_misc_register_devices(void)
{
- sysbus_register_withprop(&slavio_misc_info);
- sysbus_register_withprop(&apc_info);
+ type_register_static(&slavio_misc_info);
+ type_register_static(&apc_info);
}
device_init(slavio_misc_register_devices)
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 44b500a..3878f6f 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -404,21 +404,32 @@
return 0;
}
-static SysBusDeviceInfo slavio_timer_info = {
- .init = slavio_timer_init1,
- .qdev.name = "slavio_timer",
- .qdev.size = sizeof(SLAVIO_TIMERState),
- .qdev.vmsd = &vmstate_slavio_timer,
- .qdev.reset = slavio_timer_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property slavio_timer_properties[] = {
+ DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void slavio_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = slavio_timer_init1;
+ dc->reset = slavio_timer_reset;
+ dc->vmsd = &vmstate_slavio_timer;
+ dc->props = slavio_timer_properties;
+}
+
+static TypeInfo slavio_timer_info = {
+ .name = "slavio_timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SLAVIO_TIMERState),
+ .class_init = slavio_timer_class_init,
};
static void slavio_timer_register_devices(void)
{
- sysbus_register_withprop(&slavio_timer_info);
+ type_register_static(&slavio_timer_info);
}
device_init(slavio_timer_register_devices)
diff --git a/hw/sm501.c b/hw/sm501.c
index 09c5894..94c0abf 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -1323,15 +1323,12 @@
for (y = 0; y < height; y++) {
int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
int update = full_update || update_hwc;
- ram_addr_t page0 = offset & TARGET_PAGE_MASK;
- ram_addr_t page1 = (offset + width * src_bpp - 1) & TARGET_PAGE_MASK;
- ram_addr_t page;
+ ram_addr_t page0 = offset;
+ ram_addr_t page1 = offset + width * src_bpp - 1;
/* check dirty flags for each line */
- for (page = page0; page <= page1; page += TARGET_PAGE_SIZE)
- if (memory_region_get_dirty(&s->local_mem_region, page,
- DIRTY_MEMORY_VGA))
- update = 1;
+ update = memory_region_get_dirty(&s->local_mem_region, page0, page1,
+ DIRTY_MEMORY_VGA);
/* draw line and change status */
if (update) {
diff --git a/hw/smbus.c b/hw/smbus.c
index ff027c8..77626f3 100644
--- a/hw/smbus.c
+++ b/hw/smbus.c
@@ -37,37 +37,38 @@
static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
{
- SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
DPRINTF("Quick Command %d\n", recv);
- if (t->quick_cmd)
- t->quick_cmd(dev, recv);
+ if (sc->quick_cmd) {
+ sc->quick_cmd(dev, recv);
+ }
}
static void smbus_do_write(SMBusDevice *dev)
{
- SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
if (dev->data_len == 0) {
smbus_do_quick_cmd(dev, 0);
} else if (dev->data_len == 1) {
DPRINTF("Send Byte\n");
- if (t->send_byte) {
- t->send_byte(dev, dev->data_buf[0]);
+ if (sc->send_byte) {
+ sc->send_byte(dev, dev->data_buf[0]);
}
} else {
dev->command = dev->data_buf[0];
DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
- if (t->write_data) {
- t->write_data(dev, dev->command, dev->data_buf + 1,
- dev->data_len - 1);
+ if (sc->write_data) {
+ sc->write_data(dev, dev->command, dev->data_buf + 1,
+ dev->data_len - 1);
}
}
}
-static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
+static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
{
- SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+ SMBusDevice *dev = SMBUS_DEVICE(s);
switch (event) {
case I2C_START_SEND:
@@ -148,16 +149,16 @@
}
}
-static int smbus_i2c_recv(i2c_slave *s)
+static int smbus_i2c_recv(I2CSlave *s)
{
- SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c);
- SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+ SMBusDevice *dev = SMBUS_DEVICE(s);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
int ret;
switch (dev->mode) {
case SMBUS_RECV_BYTE:
- if (t->receive_byte) {
- ret = t->receive_byte(dev);
+ if (sc->receive_byte) {
+ ret = sc->receive_byte(dev);
} else {
ret = 0;
}
@@ -165,8 +166,8 @@
dev->mode = SMBUS_DONE;
break;
case SMBUS_READ_DATA:
- if (t->read_data) {
- ret = t->read_data(dev, dev->command, dev->data_len);
+ if (sc->read_data) {
+ ret = sc->read_data(dev, dev->command, dev->data_len);
dev->data_len++;
} else {
ret = 0;
@@ -182,9 +183,9 @@
return ret;
}
-static int smbus_i2c_send(i2c_slave *s, uint8_t data)
+static int smbus_i2c_send(I2CSlave *s, uint8_t data)
{
- SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+ SMBusDevice *dev = SMBUS_DEVICE(s);
switch (dev->mode) {
case SMBUS_WRITE_DATA:
@@ -198,22 +199,12 @@
return 0;
}
-static int smbus_device_init(i2c_slave *i2c)
+static int smbus_device_init(I2CSlave *i2c)
{
- SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c);
- SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c);
+ SMBusDevice *dev = SMBUS_DEVICE(i2c);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
- return t->init(dev);
-}
-
-void smbus_register_device(SMBusDeviceInfo *info)
-{
- assert(info->i2c.qdev.size >= sizeof(SMBusDevice));
- info->i2c.init = smbus_device_init;
- info->i2c.event = smbus_i2c_event;
- info->i2c.recv = smbus_i2c_recv;
- info->i2c.send = smbus_i2c_send;
- i2c_register_slave(&info->i2c);
+ return sc->init(dev);
}
/* Master device commands. */
@@ -316,3 +307,29 @@
i2c_send(bus, data[i]);
i2c_end_transfer(bus);
}
+
+static void smbus_device_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+ sc->init = smbus_device_init;
+ sc->event = smbus_i2c_event;
+ sc->recv = smbus_i2c_recv;
+ sc->send = smbus_i2c_send;
+}
+
+static TypeInfo smbus_device_type_info = {
+ .name = TYPE_SMBUS_DEVICE,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(SMBusDevice),
+ .abstract = true,
+ .class_size = sizeof(SMBusDeviceClass),
+ .class_init = smbus_device_class_init,
+};
+
+static void smbus_device_register_devices(void)
+{
+ type_register_static(&smbus_device_type_info);
+}
+
+device_init(smbus_device_register_devices);
diff --git a/hw/smbus.h b/hw/smbus.h
index a398715..6ed45bd 100644
--- a/hw/smbus.h
+++ b/hw/smbus.h
@@ -1,3 +1,6 @@
+#ifndef QEMU_SMBUS_H
+#define QEMU_SMBUS_H
+
/*
* QEMU SMBus API
*
@@ -24,19 +27,17 @@
#include "i2c.h"
-struct SMBusDevice {
- /* The SMBus protocol is implemented on top of I2C. */
- i2c_slave i2c;
+#define TYPE_SMBUS_DEVICE "smbus-device"
+#define SMBUS_DEVICE(obj) \
+ OBJECT_CHECK(SMBusDevice, (obj), TYPE_SMBUS_DEVICE)
+#define SMBUS_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SMBusDeviceClass, (klass), TYPE_SMBUS_DEVICE)
+#define SMBUS_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SMBusDeviceClass, (obj), TYPE_SMBUS_DEVICE)
- /* Remaining fields for internal use only. */
- int mode;
- int data_len;
- uint8_t data_buf[34]; /* command + len + 32 bytes of data. */
- uint8_t command;
-};
-
-typedef struct {
- I2CSlaveInfo i2c;
+typedef struct SMBusDeviceClass
+{
+ I2CSlaveClass parent_class;
int (*init)(SMBusDevice *dev);
void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
void (*send_byte)(SMBusDevice *dev, uint8_t val);
@@ -51,9 +52,18 @@
byte at a time. The device is responsible for adding the length
byte on block reads. */
uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n);
-} SMBusDeviceInfo;
+} SMBusDeviceClass;
-void smbus_register_device(SMBusDeviceInfo *info);
+struct SMBusDevice {
+ /* The SMBus protocol is implemented on top of I2C. */
+ I2CSlave i2c;
+
+ /* Remaining fields for internal use only. */
+ int mode;
+ int data_len;
+ uint8_t data_buf[34]; /* command + len + 32 bytes of data. */
+ uint8_t command;
+};
/* Master device commands. */
void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read);
@@ -69,3 +79,5 @@
void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
const uint8_t *eeprom_spd, int size);
+
+#endif
diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c
index 5d080ab..9d96cbe 100644
--- a/hw/smbus_eeprom.c
+++ b/hw/smbus_eeprom.c
@@ -104,24 +104,35 @@
return 0;
}
-static SMBusDeviceInfo smbus_eeprom_info = {
- .i2c.qdev.name = "smbus-eeprom",
- .i2c.qdev.size = sizeof(SMBusEEPROMDevice),
- .i2c.qdev.props = (Property[]) {
- DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
- DEFINE_PROP_END_OF_LIST(),
- },
- .init = smbus_eeprom_initfn,
- .quick_cmd = eeprom_quick_cmd,
- .send_byte = eeprom_send_byte,
- .receive_byte = eeprom_receive_byte,
- .write_data = eeprom_write_data,
- .read_data = eeprom_read_data
+static Property smbus_eeprom_properties[] = {
+ DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
+
+ sc->init = smbus_eeprom_initfn;
+ sc->quick_cmd = eeprom_quick_cmd;
+ sc->send_byte = eeprom_send_byte;
+ sc->receive_byte = eeprom_receive_byte;
+ sc->write_data = eeprom_write_data;
+ sc->read_data = eeprom_read_data;
+ dc->props = smbus_eeprom_properties;
+}
+
+static TypeInfo smbus_eeprom_info = {
+ .name = "smbus-eeprom",
+ .parent = TYPE_SMBUS_DEVICE,
+ .instance_size = sizeof(SMBusEEPROMDevice),
+ .class_init = smbus_eeprom_class_initfn,
};
static void smbus_eeprom_register_devices(void)
{
- smbus_register_device(&smbus_eeprom_info);
+ type_register_static(&smbus_eeprom_info);
}
device_init(smbus_eeprom_register_devices)
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 82b8811..1bf2901 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -752,27 +752,38 @@
sysbus_init_irq(dev, &s->irq);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
/* ??? Save/restore. */
return 0;
}
-static SysBusDeviceInfo smc91c111_info = {
- .init = smc91c111_init1,
- .qdev.name = "smc91c111",
- .qdev.size = sizeof(smc91c111_state),
- .qdev.vmsd = &vmstate_smc91c111,
- .qdev.reset = smc91c111_reset,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property smc91c111_properties[] = {
+ DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void smc91c111_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = smc91c111_init1;
+ dc->reset = smc91c111_reset;
+ dc->vmsd = &vmstate_smc91c111;
+ dc->props = smc91c111_properties;
+}
+
+static TypeInfo smc91c111_info = {
+ .name = "smc91c111",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(smc91c111_state),
+ .class_init = smc91c111_class_init,
};
static void smc91c111_register_devices(void)
{
- sysbus_register_withprop(&smc91c111_info);
+ type_register_static(&smc91c111_info);
}
/* Legacy helper function. Should go away when machine config files are
diff --git a/hw/spapr.c b/hw/spapr.c
index 0e1f80d..dffb6a2 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -50,19 +50,29 @@
#include <libfdt.h>
-#define KERNEL_LOAD_ADDR 0x00000000
-#define INITRD_LOAD_ADDR 0x02800000
+/* SLOF memory layout:
+ *
+ * SLOF raw image loaded at 0, copies its romfs right below the flat
+ * device-tree, then position SLOF itself 31M below that
+ *
+ * So we set FW_OVERHEAD to 40MB which should account for all of that
+ * and more
+ *
+ * We load our kernel at 4M, leaving space for SLOF initial image
+ */
#define FDT_MAX_SIZE 0x10000
#define RTAS_MAX_SIZE 0x10000
#define FW_MAX_SIZE 0x400000
#define FW_FILE_NAME "slof.bin"
+#define FW_OVERHEAD 0x2800000
+#define KERNEL_LOAD_ADDR FW_MAX_SIZE
-#define MIN_RMA_SLOF 128UL
+#define MIN_RMA_SLOF 128UL
#define TIMEBASE_FREQ 512000000ULL
#define MAX_CPUS 256
-#define XICS_IRQS 1024
+#define XICS_IRQS 1024
#define SPAPR_PCI_BUID 0x800000020000001ULL
#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000)
@@ -139,6 +149,7 @@
target_phys_addr_t rma_size,
target_phys_addr_t initrd_base,
target_phys_addr_t initrd_size,
+ target_phys_addr_t kernel_size,
const char *boot_device,
const char *kernel_cmdline,
long hash_shift)
@@ -176,6 +187,12 @@
fdt = g_malloc0(FDT_MAX_SIZE);
_FDT((fdt_create(fdt, FDT_MAX_SIZE)));
+ if (kernel_size) {
+ _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size)));
+ }
+ if (initrd_size) {
+ _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size)));
+ }
_FDT((fdt_finish_reservemap(fdt)));
/* Root node */
@@ -197,15 +214,13 @@
&start_prop, sizeof(start_prop))));
_FDT((fdt_property(fdt, "linux,initrd-end",
&end_prop, sizeof(end_prop))));
- _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+ if (kernel_size) {
+ uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
+ cpu_to_be64(kernel_size) };
- /*
- * Because we don't always invoke any firmware, we can't rely on
- * that to do BAR allocation. Long term, we should probably do
- * that ourselves, but for now, this setting (plus advertising the
- * current BARs as 0) causes sufficiently recent kernels to to the
- * BAR assignment themselves */
- _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0)));
+ _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
+ }
+ _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
_FDT((fdt_end_node(fdt)));
@@ -445,6 +460,12 @@
_FDT((fdt_pack(fdt)));
+ if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
+ hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n",
+ fdt_totalsize(fdt), FDT_MAX_SIZE);
+ exit(1);
+ }
+
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
g_free(fdt);
@@ -494,8 +515,9 @@
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
target_phys_addr_t rma_alloc_size, rma_size;
- uint32_t initrd_base;
- long kernel_size, initrd_size, fw_size;
+ uint32_t initrd_base = 0;
+ long kernel_size = 0, initrd_size = 0;
+ long load_limit, rtas_limit, fw_size;
long pteg_shift = 17;
char *filename;
@@ -517,11 +539,13 @@
rma_size = ram_size;
}
- /* We place the device tree just below either the top of the RMA,
+ /* We place the device tree and RTAS just below either the top of the RMA,
* or just below 2GB, whichever is lowere, so that it can be
* processed with 32-bit real mode code if necessary */
- spapr->fdt_addr = MIN(rma_size, 0x80000000) - FDT_MAX_SIZE;
- spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE;
+ rtas_limit = MIN(rma_size, 0x80000000);
+ spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
+ spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
+ load_limit = spapr->fdt_addr - FW_OVERHEAD;
/* init CPUs */
if (cpu_model == NULL) {
@@ -577,13 +601,19 @@
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
- ram_size - spapr->rtas_addr);
+ rtas_limit - spapr->rtas_addr);
if (spapr->rtas_size < 0) {
hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
exit(1);
}
+ if (spapr->rtas_size > RTAS_MAX_SIZE) {
+ hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n",
+ spapr->rtas_size, RTAS_MAX_SIZE);
+ exit(1);
+ }
g_free(filename);
+
/* Set up Interrupt Controller */
spapr->icp = xics_system_init(XICS_IRQS);
spapr->next_irq = 16;
@@ -622,6 +652,20 @@
spapr_vscsi_create(spapr->vio_bus, 0x2000 + i);
}
+ if (rma_size < (MIN_RMA_SLOF << 20)) {
+ fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
+ "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
+ exit(1);
+ }
+
+ fprintf(stderr, "sPAPR memory map:\n");
+ fprintf(stderr, "RTAS : 0x%08lx..%08lx\n",
+ (unsigned long)spapr->rtas_addr,
+ (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1));
+ fprintf(stderr, "FDT : 0x%08lx..%08lx\n",
+ (unsigned long)spapr->fdt_addr,
+ (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1));
+
if (kernel_filename) {
uint64_t lowaddr = 0;
@@ -630,57 +674,60 @@
if (kernel_size < 0) {
kernel_size = load_image_targphys(kernel_filename,
KERNEL_LOAD_ADDR,
- ram_size - KERNEL_LOAD_ADDR);
+ load_limit - KERNEL_LOAD_ADDR);
}
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
+ fprintf(stderr, "Kernel : 0x%08x..%08lx\n",
+ KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1);
/* load initrd */
if (initrd_filename) {
- initrd_base = INITRD_LOAD_ADDR;
+ /* Try to locate the initrd in the gap between the kernel
+ * and the firmware. Add a bit of space just in case
+ */
+ initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff;
initrd_size = load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
+ load_limit - initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
+ fprintf(stderr, "Ramdisk : 0x%08lx..%08lx\n",
+ (long)initrd_base, (long)(initrd_base + initrd_size - 1));
} else {
initrd_base = 0;
initrd_size = 0;
}
+ }
- spapr->entry_point = KERNEL_LOAD_ADDR;
- } else {
- if (rma_size < (MIN_RMA_SLOF << 20)) {
- fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
- "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
- exit(1);
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
- fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
- if (fw_size < 0) {
- hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
- exit(1);
- }
- g_free(filename);
- spapr->entry_point = 0x100;
- initrd_base = 0;
- initrd_size = 0;
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
+ fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
+ if (fw_size < 0) {
+ hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+ exit(1);
+ }
+ g_free(filename);
+ fprintf(stderr, "Firmware load : 0x%08x..%08lx\n",
+ 0, fw_size);
+ fprintf(stderr, "Firmware runtime : 0x%08lx..%08lx\n",
+ load_limit, (unsigned long)spapr->fdt_addr);
- /* SLOF will startup the secondary CPUs using RTAS,
- rather than expecting a kexec() style entry */
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- env->halted = 1;
- }
+ spapr->entry_point = 0x100;
+
+ /* SLOF will startup the secondary CPUs using RTAS */
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ env->halted = 1;
}
/* Prepare the device tree */
spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size,
initrd_base, initrd_size,
+ kernel_size,
boot_device, kernel_cmdline,
pteg_shift + 7);
assert(spapr->fdt_skel != NULL);
@@ -693,7 +740,6 @@
.desc = "pSeries Logical Partition (PAPR compliant)",
.init = ppc_spapr_init,
.max_cpus = MAX_CPUS,
- .no_vga = 1,
.no_parallel = 1,
.use_scsi = 1,
};
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 45674c4..79b3941 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -189,7 +189,7 @@
qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
- sdev->qdev.info->name, sdev->qdev.id, dev);
+ object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a);
return 0;
@@ -474,30 +474,41 @@
return H_SUCCESS;
}
-static VIOsPAPRDeviceInfo spapr_vlan = {
- .init = spapr_vlan_init,
- .devnode = spapr_vlan_devnode,
- .dt_name = "l-lan",
- .dt_type = "network",
- .dt_compatible = "IBM,l-lan",
- .signal_mask = 0x1,
- .qdev.name = "spapr-vlan",
- .qdev.size = sizeof(VIOsPAPRVLANDevice),
- .qdev.props = (Property[]) {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000),
- DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property spapr_vlan_properties[] = {
+ DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000),
+ DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vlan_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+ k->init = spapr_vlan_init;
+ k->devnode = spapr_vlan_devnode;
+ k->dt_name = "l-lan";
+ k->dt_type = "network";
+ k->dt_compatible = "IBM,l-lan";
+ k->signal_mask = 0x1;
+ dc->props = spapr_vlan_properties;
+}
+
+static TypeInfo spapr_vlan_info = {
+ .name = "spapr-vlan",
+ .parent = TYPE_VIO_SPAPR_DEVICE,
+ .instance_size = sizeof(VIOsPAPRVLANDevice),
+ .class_init = spapr_vlan_class_init,
};
static void spapr_vlan_register(void)
{
- spapr_vio_bus_register_withprop(&spapr_vlan);
spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
h_add_logical_lan_buffer);
spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
+ type_register_static(&spapr_vlan_info);
}
device_init(spapr_vlan_register);
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 9b6a032..ed2e4b3 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -62,6 +62,30 @@
return NULL;
}
+static uint32_t rtas_pci_cfgaddr(uint32_t arg)
+{
+ return ((arg >> 20) & 0xf00) | (arg & 0xff);
+}
+
+static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
+ uint32_t limit, uint32_t len)
+{
+ if ((addr + len) <= limit) {
+ return pci_host_config_read_common(pci_dev, addr, limit, len);
+ } else {
+ return ~0x0;
+ }
+}
+
+static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
+ uint32_t limit, uint32_t val,
+ uint32_t len)
+{
+ if ((addr + len) <= limit) {
+ pci_host_config_write_common(pci_dev, addr, limit, val, len);
+ }
+}
+
static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
@@ -76,8 +100,8 @@
return;
}
size = rtas_ld(args, 3);
- addr = rtas_ld(args, 0) & 0xFF;
- val = pci_default_read_config(dev, addr, size);
+ addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+ val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
rtas_st(rets, 0, 0);
rtas_st(rets, 1, val);
}
@@ -95,8 +119,8 @@
return;
}
size = rtas_ld(args, 1);
- addr = rtas_ld(args, 0) & 0xFF;
- val = pci_default_read_config(dev, addr, size);
+ addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+ val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
rtas_st(rets, 0, 0);
rtas_st(rets, 1, val);
}
@@ -116,8 +140,8 @@
}
val = rtas_ld(args, 4);
size = rtas_ld(args, 3);
- addr = rtas_ld(args, 0) & 0xFF;
- pci_default_write_config(dev, addr, val, size);
+ addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+ rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
rtas_st(rets, 0, 0);
}
@@ -135,8 +159,8 @@
}
val = rtas_ld(args, 2);
size = rtas_ld(args, 1);
- addr = rtas_ld(args, 0) & 0xFF;
- pci_default_write_config(dev, addr, val, size);
+ addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+ rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
rtas_st(rets, 0, 0);
}
@@ -190,17 +214,38 @@
return 0;
}
-static PCIDeviceInfo spapr_main_pci_host_info = {
- .qdev.name = "spapr-pci-host-bridge",
- .qdev.size = sizeof(PCIDevice),
- .init = spapr_main_pci_host_init,
+static void spapr_main_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = spapr_main_pci_host_init;
+}
+
+static TypeInfo spapr_main_pci_host_info = {
+ .name = "spapr-pci-host-bridge-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = spapr_main_pci_host_class_init,
+};
+
+static void spapr_phb_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = spapr_phb_init;
+}
+
+static TypeInfo spapr_phb_info = {
+ .name = "spapr-pci-host-bridge",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(sPAPRPHBState),
+ .class_init = spapr_phb_class_init,
};
static void spapr_register_devices(void)
{
- sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState),
- spapr_phb_init);
- pci_qdev_register(&spapr_main_pci_host_info);
+ type_register_static(&spapr_phb_info);
+ type_register_static(&spapr_main_pci_host_info);
}
device_init(spapr_register_devices)
@@ -319,31 +364,13 @@
#define b_fff(x) b_x((x), 8, 3) /* function number */
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
-static uint32_t regtype_to_ss(uint8_t type)
-{
- if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- return 3;
- }
- if (type == PCI_BASE_ADDRESS_SPACE_IO) {
- return 1;
- }
- return 2;
-}
-
int spapr_populate_pci_devices(sPAPRPHBState *phb,
uint32_t xics_phandle,
void *fdt)
{
PCIBus *bus = phb->host_state.bus;
- int bus_off, node_off = 0, devid, fn, i, n, devices;
- DeviceState *qdev;
+ int bus_off, i;
char nodename[256];
- struct {
- uint32_t hi;
- uint64_t addr;
- uint64_t size;
- } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
- assigned_addresses[PCI_NUM_REGIONS];
uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
struct {
uint32_t hi;
@@ -364,7 +391,7 @@
};
uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
uint32_t interrupt_map_mask[] = {
- cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0};
+ cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, 0x0};
uint32_t interrupt_map[bus->nirq][7];
/* Start populating the FDT */
@@ -392,117 +419,26 @@
_FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
+ _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
+
+ /* Build the interrupt-map, this must matches what is done
+ * in pci_spapr_map_irq
+ */
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
&interrupt_map_mask, sizeof(interrupt_map_mask)));
-
- /* Populate PCI devices and allocate IRQs */
- devices = 0;
- QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
- PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
- int irq_index = pci_spapr_map_irq(dev, 0);
- uint32_t *irqmap = interrupt_map[devices];
- uint8_t *config = dev->config;
-
- devid = dev->devfn >> 3;
- fn = dev->devfn & 7;
-
- sprintf(nodename, "pci@%u,%u", devid, fn);
-
- /* Allocate interrupt from the map */
- if (devid > bus->nirq) {
- printf("Unexpected behaviour in spapr_populate_pci_devices,"
- "wrong devid %u\n", devid);
- exit(-1);
- }
- irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
+ for (i = 0; i < 7; i++) {
+ uint32_t *irqmap = interrupt_map[i];
+ irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0));
irqmap[1] = 0;
irqmap[2] = 0;
irqmap[3] = 0;
irqmap[4] = cpu_to_be32(xics_phandle);
- irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq);
+ irqmap[5] = cpu_to_be32(phb->lsi_table[i % SPAPR_PCI_NUM_LSI].dt_irq);
irqmap[6] = cpu_to_be32(0x8);
-
- /* Add node to FDT */
- node_off = fdt_add_subnode(fdt, bus_off, nodename);
- if (node_off < 0) {
- return node_off;
- }
-
- _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
- pci_get_word(&config[PCI_VENDOR_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "device-id",
- pci_get_word(&config[PCI_DEVICE_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
- pci_get_byte(&config[PCI_REVISION_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "class-code",
- pci_get_long(&config[PCI_CLASS_REVISION]) >> 8));
- _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
- pci_get_word(&config[PCI_SUBSYSTEM_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
- pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID])));
-
- /* Config space region comes first */
- reg[0].hi = cpu_to_be32(
- b_n(0) |
- b_p(0) |
- b_t(0) |
- b_ss(0/*config*/) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn));
- reg[0].addr = 0;
- reg[0].size = 0;
-
- n = 0;
- for (i = 0; i < ARRAY_SIZE(bars); ++i) {
- if (0 == dev->io_regions[i].size) {
- continue;
- }
-
- reg[n+1].hi = cpu_to_be32(
- b_n(0) |
- b_p(0) |
- b_t(0) |
- b_ss(regtype_to_ss(dev->io_regions[i].type)) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn) |
- b_rrrrrrrr(bars[i]));
- reg[n+1].addr = 0;
- reg[n+1].size = cpu_to_be64(dev->io_regions[i].size);
-
- assigned_addresses[n].hi = cpu_to_be32(
- b_n(1) |
- b_p(0) |
- b_t(0) |
- b_ss(regtype_to_ss(dev->io_regions[i].type)) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn) |
- b_rrrrrrrr(bars[i]));
-
- /*
- * Writing zeroes to assigned_addresses causes the guest kernel to
- * reassign BARs
- */
- assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr);
- assigned_addresses[n].size = reg[n+1].size;
-
- ++n;
- }
- _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
- _FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
- assigned_addresses,
- sizeof(assigned_addresses[0])*(n)));
- _FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
- pci_get_byte(&config[PCI_INTERRUPT_PIN])));
-
- ++devices;
}
-
/* Write interrupt map */
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
- devices * sizeof(interrupt_map[0])));
+ 7 * sizeof(interrupt_map[0])));
return 0;
}
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 7a86dc8..64f0009 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -75,11 +75,11 @@
static char *vio_format_dev_name(VIOsPAPRDevice *dev)
{
- VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+ VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
char *name;
/* Device tree style name device@reg */
- if (asprintf(&name, "%s@%x", info->dt_name, dev->reg) < 0) {
+ if (asprintf(&name, "%s@%x", pc->dt_name, dev->reg) < 0) {
return NULL;
}
@@ -90,7 +90,7 @@
static int vio_make_devnode(VIOsPAPRDevice *dev,
void *fdt)
{
- VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+ VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
int vdevice_off, node_off, ret;
char *dt_name;
@@ -115,17 +115,17 @@
return ret;
}
- if (info->dt_type) {
+ if (pc->dt_type) {
ret = fdt_setprop_string(fdt, node_off, "device_type",
- info->dt_type);
+ pc->dt_type);
if (ret < 0) {
return ret;
}
}
- if (info->dt_compatible) {
+ if (pc->dt_compatible) {
ret = fdt_setprop_string(fdt, node_off, "compatible",
- info->dt_compatible);
+ pc->dt_compatible);
if (ret < 0) {
return ret;
}
@@ -163,8 +163,8 @@
}
}
- if (info->devnode) {
- ret = (info->devnode)(dev, fdt, node_off);
+ if (pc->devnode) {
+ ret = (pc->devnode)(dev, fdt, node_off);
if (ret < 0) {
return ret;
}
@@ -621,7 +621,7 @@
rtas_st(rets, 0, 0);
}
-static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
+static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
{
VIOsPAPRDevice *other_sdev;
DeviceState *qdev;
@@ -639,7 +639,9 @@
if (other_sdev != sdev && other_sdev->reg == sdev->reg) {
fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
- info->qdev.name, other_sdev->qdev.info->name, sdev->reg);
+ object_get_typename(OBJECT(sdev)),
+ object_get_typename(OBJECT(qdev)),
+ sdev->reg);
return -EEXIST;
}
}
@@ -647,14 +649,14 @@
return 0;
}
-static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
+static int spapr_vio_busdev_init(DeviceState *qdev)
{
- VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+ VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
char *id;
int ret;
- ret = spapr_vio_check_reg(dev, info);
+ ret = spapr_vio_check_reg(dev);
if (ret) {
return ret;
}
@@ -675,16 +677,7 @@
rtce_init(dev);
- return info->init(dev);
-}
-
-void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
-{
- info->qdev.init = spapr_vio_busdev_init;
- info->qdev.bus_info = &spapr_vio_bus_info;
-
- assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
- qdev_register(&info->qdev);
+ return pc->init(dev);
}
static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
@@ -694,15 +687,15 @@
target_ulong reg = args[0];
target_ulong mode = args[1];
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRDeviceInfo *info;
+ VIOsPAPRDeviceClass *pc;
if (!dev) {
return H_PARAMETER;
}
- info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+ pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
- if (mode & ~info->signal_mask) {
+ if (mode & ~pc->signal_mask) {
return H_PARAMETER;
}
@@ -753,16 +746,42 @@
return 0;
}
-static SysBusDeviceInfo spapr_vio_bridge_info = {
- .init = spapr_vio_bridge_init,
- .qdev.name = "spapr-vio-bridge",
- .qdev.size = sizeof(SysBusDevice),
- .qdev.no_user = 1,
+static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = spapr_vio_bridge_init;
+ dc->no_user = 1;
+}
+
+static TypeInfo spapr_vio_bridge_info = {
+ .name = "spapr-vio-bridge",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = spapr_vio_bridge_class_init,
+};
+
+static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = spapr_vio_busdev_init;
+ k->bus_info = &spapr_vio_bus_info;
+}
+
+static TypeInfo spapr_vio_type_info = {
+ .name = TYPE_VIO_SPAPR_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(VIOsPAPRDevice),
+ .abstract = true,
+ .class_size = sizeof(VIOsPAPRDeviceClass),
+ .class_init = vio_spapr_device_class_init,
};
static void spapr_vio_register_devices(void)
{
- sysbus_register_withprop(&spapr_vio_bridge_info);
+ type_register_static(&spapr_vio_bridge_info);
+ type_register_static(&spapr_vio_type_info);
}
device_init(spapr_vio_register_devices)
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 0984d55..d8527be 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -34,6 +34,14 @@
#define SPAPR_VTY_BASE_ADDRESS 0x30000000
+#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device"
+#define VIO_SPAPR_DEVICE(obj) \
+ OBJECT_CHECK(VIOsPAPRDevice, (obj), TYPE_VIO_SPAPR_DEVICE)
+#define VIO_SPAPR_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VIOsPAPRDeviceClass, (klass), TYPE_VIO_SPAPR_DEVICE)
+#define VIO_SPAPR_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VIOsPAPRDeviceClass, (obj), TYPE_VIO_SPAPR_DEVICE)
+
struct VIOsPAPRDevice;
typedef struct VIOsPAPR_RTCE {
@@ -47,7 +55,20 @@
int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
} VIOsPAPR_CRQ;
-typedef struct VIOsPAPRDevice {
+typedef struct VIOsPAPRDevice VIOsPAPRDevice;
+typedef struct VIOsPAPRBus VIOsPAPRBus;
+
+typedef struct VIOsPAPRDeviceClass {
+ DeviceClass parent_class;
+
+ const char *dt_name, *dt_type, *dt_compatible;
+ target_ulong signal_mask;
+ int (*init)(VIOsPAPRDevice *dev);
+ void (*hcalls)(VIOsPAPRBus *bus);
+ int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
+} VIOsPAPRDeviceClass;
+
+struct VIOsPAPRDevice {
DeviceState qdev;
uint32_t reg;
uint32_t flags;
@@ -59,28 +80,23 @@
VIOsPAPR_RTCE *rtce_table;
int kvmtce_fd;
VIOsPAPR_CRQ crq;
-} VIOsPAPRDevice;
+};
#define DEFINE_SPAPR_PROPERTIES(type, field, default_reg, default_dma_window) \
DEFINE_PROP_UINT32("reg", type, field.reg, default_reg), \
DEFINE_PROP_UINT32("dma-window", type, field.rtce_window_size, \
default_dma_window)
-typedef struct VIOsPAPRBus {
+struct VIOsPAPRBus {
BusState bus;
-} VIOsPAPRBus;
-
-typedef struct {
- DeviceInfo qdev;
const char *dt_name, *dt_type, *dt_compatible;
target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
-} VIOsPAPRDeviceInfo;
+};
extern VIOsPAPRBus *spapr_vio_bus_init(void);
extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
-extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 00e2d2d..9cfce19 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -947,23 +947,34 @@
return 0;
}
-static VIOsPAPRDeviceInfo spapr_vscsi = {
- .init = spapr_vscsi_init,
- .devnode = spapr_vscsi_devnode,
- .dt_name = "v-scsi",
- .dt_type = "vscsi",
- .dt_compatible = "IBM,v-scsi",
- .signal_mask = 0x00000001,
- .qdev.name = "spapr-vscsi",
- .qdev.size = sizeof(VSCSIState),
- .qdev.props = (Property[]) {
- DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property spapr_vscsi_properties[] = {
+ DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+ k->init = spapr_vscsi_init;
+ k->devnode = spapr_vscsi_devnode;
+ k->dt_name = "v-scsi";
+ k->dt_type = "vscsi";
+ k->dt_compatible = "IBM,v-scsi";
+ k->signal_mask = 0x00000001;
+ dc->props = spapr_vscsi_properties;
+}
+
+static TypeInfo spapr_vscsi_info = {
+ .name = "spapr-vscsi",
+ .parent = TYPE_VIO_SPAPR_DEVICE,
+ .instance_size = sizeof(VSCSIState),
+ .class_init = spapr_vscsi_class_init,
};
static void spapr_vscsi_register(void)
{
- spapr_vio_bus_register_withprop(&spapr_vscsi);
+ type_register_static(&spapr_vscsi_info);
}
device_init(spapr_vscsi_register);
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index c5fb096..a954e7d 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -135,18 +135,29 @@
qdev_init_nofail(dev);
}
-static VIOsPAPRDeviceInfo spapr_vty = {
- .init = spapr_vty_init,
- .dt_name = "vty",
- .dt_type = "serial",
- .dt_compatible = "hvterm1",
- .qdev.name = "spapr-vty",
- .qdev.size = sizeof(VIOsPAPRVTYDevice),
- .qdev.props = (Property[]) {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
- DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property spapr_vty_properties[] = {
+ DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
+ DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vty_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+ k->init = spapr_vty_init;
+ k->dt_name = "vty";
+ k->dt_type = "serial";
+ k->dt_compatible = "hvterm1";
+ dc->props = spapr_vty_properties;
+}
+
+static TypeInfo spapr_vty_info = {
+ .name = "spapr-vty",
+ .parent = TYPE_VIO_SPAPR_DEVICE,
+ .instance_size = sizeof(VIOsPAPRVTYDevice),
+ .class_init = spapr_vty_class_init,
};
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
@@ -163,7 +174,7 @@
selected = NULL;
QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
/* Only look at VTY devices */
- if (iter->info != &spapr_vty.qdev) {
+ if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
continue;
}
@@ -203,8 +214,8 @@
static void spapr_vty_register(void)
{
- spapr_vio_bus_register_withprop(&spapr_vty);
spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+ type_register_static(&spapr_vty_info);
}
device_init(spapr_vty_register);
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index 035d2e2..f07cc6f 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -283,22 +283,33 @@
return 0;
}
-static SysBusDeviceInfo sparc32_dma_info = {
- .init = sparc32_dma_init1,
- .qdev.name = "sparc32_dma",
- .qdev.size = sizeof(DMAState),
- .qdev.vmsd = &vmstate_dma,
- .qdev.reset = dma_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
- DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property sparc32_dma_properties[] = {
+ DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
+ DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sparc32_dma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sparc32_dma_init1;
+ dc->reset = dma_reset;
+ dc->vmsd = &vmstate_dma;
+ dc->props = sparc32_dma_properties;
+}
+
+static TypeInfo sparc32_dma_info = {
+ .name = "sparc32_dma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(DMAState),
+ .class_init = sparc32_dma_class_init,
};
static void sparc32_dma_register_devices(void)
{
- sysbus_register_withprop(&sparc32_dma_info);
+ type_register_static(&sparc32_dma_info);
}
device_init(sparc32_dma_register_devices)
diff --git a/hw/spitz.c b/hw/spitz.c
index 9d129c2..4e6540d 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -717,7 +717,7 @@
static void spitz_wm8750_addr(void *opaque, int line, int level)
{
- i2c_slave *wm = (i2c_slave *) opaque;
+ I2CSlave *wm = (I2CSlave *) opaque;
if (level)
i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
else
@@ -1023,16 +1023,27 @@
},
};
-static SysBusDeviceInfo sl_nand_info = {
- .init = sl_nand_init,
- .qdev.name = "sl-nand",
- .qdev.size = sizeof(SLNANDState),
- .qdev.vmsd = &vmstate_sl_nand_info,
- .qdev.props = (Property []) {
- DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
- DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property sl_nand_properties[] = {
+ DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
+ DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sl_nand_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sl_nand_init;
+ dc->vmsd = &vmstate_sl_nand_info;
+ dc->props = sl_nand_properties;
+}
+
+static TypeInfo sl_nand_info = {
+ .name = "sl-nand",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SLNANDState),
+ .class_init = sl_nand_class_init,
};
static VMStateDescription vmstate_spitz_kbd = {
@@ -1049,14 +1060,25 @@
},
};
-static SysBusDeviceInfo spitz_keyboard_info = {
- .init = spitz_keyboard_init,
- .qdev.name = "spitz-keyboard",
- .qdev.size = sizeof(SpitzKeyboardState),
- .qdev.vmsd = &vmstate_spitz_kbd,
- .qdev.props = (Property []) {
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property spitz_keyboard_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = spitz_keyboard_init;
+ dc->vmsd = &vmstate_spitz_kbd;
+ dc->props = spitz_keyboard_properties;
+}
+
+static TypeInfo spitz_keyboard_info = {
+ .name = "spitz-keyboard",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SpitzKeyboardState),
+ .class_init = spitz_keyboard_class_init,
};
static const VMStateDescription vmstate_corgi_ssp_regs = {
@@ -1070,12 +1092,21 @@
}
};
-static SSISlaveInfo corgi_ssp_info = {
- .qdev.name = "corgi-ssp",
- .qdev.size = sizeof(CorgiSSPState),
- .qdev.vmsd = &vmstate_corgi_ssp_regs,
- .init = corgi_ssp_init,
- .transfer = corgi_ssp_transfer
+static void corgi_ssp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = corgi_ssp_init;
+ k->transfer = corgi_ssp_transfer;
+ dc->vmsd = &vmstate_corgi_ssp_regs;
+}
+
+static TypeInfo corgi_ssp_info = {
+ .name = "corgi-ssp",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(CorgiSSPState),
+ .class_init = corgi_ssp_class_init,
};
static const VMStateDescription vmstate_spitz_lcdtg_regs = {
@@ -1090,20 +1121,29 @@
}
};
-static SSISlaveInfo spitz_lcdtg_info = {
- .qdev.name = "spitz-lcdtg",
- .qdev.size = sizeof(SpitzLCDTG),
- .qdev.vmsd = &vmstate_spitz_lcdtg_regs,
- .init = spitz_lcdtg_init,
- .transfer = spitz_lcdtg_transfer
+static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = spitz_lcdtg_init;
+ k->transfer = spitz_lcdtg_transfer;
+ dc->vmsd = &vmstate_spitz_lcdtg_regs;
+}
+
+static TypeInfo spitz_lcdtg_info = {
+ .name = "spitz-lcdtg",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(SpitzLCDTG),
+ .class_init = spitz_lcdtg_class_init,
};
static void spitz_register_devices(void)
{
- ssi_register_slave(&corgi_ssp_info);
- ssi_register_slave(&spitz_lcdtg_info);
- sysbus_register_withprop(&spitz_keyboard_info);
- sysbus_register_withprop(&sl_nand_info);
+ type_register_static(&corgi_ssp_info);
+ type_register_static(&spitz_lcdtg_info);
+ type_register_static(&spitz_keyboard_info);
+ type_register_static(&sl_nand_info);
}
device_init(spitz_register_devices)
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index bcad7bf..685602a 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -42,7 +42,7 @@
};
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
DisplayState *ds;
int row;
int col;
@@ -57,13 +57,13 @@
uint8_t framebuffer[132*8];
} ssd0303_state;
-static int ssd0303_recv(i2c_slave *i2c)
+static int ssd0303_recv(I2CSlave *i2c)
{
BADF("Reads not implemented\n");
return -1;
}
-static int ssd0303_send(i2c_slave *i2c, uint8_t data)
+static int ssd0303_send(I2CSlave *i2c, uint8_t data)
{
ssd0303_state *s = (ssd0303_state *)i2c;
enum ssd0303_cmd old_cmd_state;
@@ -173,7 +173,7 @@
return 0;
}
-static void ssd0303_event(i2c_slave *i2c, enum i2c_event event)
+static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
{
ssd0303_state *s = (ssd0303_state *)i2c;
switch (event) {
@@ -283,7 +283,7 @@
}
};
-static int ssd0303_init(i2c_slave *i2c)
+static int ssd0303_init(I2CSlave *i2c)
{
ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c);
@@ -294,19 +294,28 @@
return 0;
}
-static I2CSlaveInfo ssd0303_info = {
- .qdev.name = "ssd0303",
- .qdev.size = sizeof(ssd0303_state),
- .qdev.vmsd = &vmstate_ssd0303,
- .init = ssd0303_init,
- .event = ssd0303_event,
- .recv = ssd0303_recv,
- .send = ssd0303_send
+static void ssd0303_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = ssd0303_init;
+ k->event = ssd0303_event;
+ k->recv = ssd0303_recv;
+ k->send = ssd0303_send;
+ dc->vmsd = &vmstate_ssd0303;
+}
+
+static TypeInfo ssd0303_info = {
+ .name = "ssd0303",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(ssd0303_state),
+ .class_init = ssd0303_class_init,
};
static void ssd0303_register_devices(void)
{
- i2c_register_slave(&ssd0303_info);
+ type_register_static(&ssd0303_info);
}
device_init(ssd0303_register_devices)
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index 1eb3823..3c43738 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -340,16 +340,24 @@
return 0;
}
-static SSISlaveInfo ssd0323_info = {
- .qdev.name = "ssd0323",
- .qdev.size = sizeof(ssd0323_state),
- .init = ssd0323_init,
- .transfer = ssd0323_transfer
+static void ssd0323_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = ssd0323_init;
+ k->transfer = ssd0323_transfer;
+}
+
+static TypeInfo ssd0323_info = {
+ .name = "ssd0323",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(ssd0323_state),
+ .class_init = ssd0323_class_init,
};
static void ssd03232_register_devices(void)
{
- ssi_register_slave(&ssd0323_info);
+ type_register_static(&ssd0323_info);
}
device_init(ssd03232_register_devices)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index 2d89cfe..f2e6cec 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -244,16 +244,24 @@
return 0;
}
-static SSISlaveInfo ssi_sd_info = {
- .qdev.name = "ssi-sd",
- .qdev.size = sizeof(ssi_sd_state),
- .init = ssi_sd_init,
- .transfer = ssi_sd_transfer
+static void ssi_sd_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = ssi_sd_init;
+ k->transfer = ssi_sd_transfer;
+}
+
+static TypeInfo ssi_sd_info = {
+ .name = "ssi-sd",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(ssi_sd_state),
+ .class_init = ssi_sd_class_init,
};
static void ssi_sd_register_devices(void)
{
- ssi_register_slave(&ssi_sd_info);
+ type_register_static(&ssi_sd_info);
}
device_init(ssi_sd_register_devices)
diff --git a/hw/ssi.c b/hw/ssi.c
index b47953a..ead446c 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -21,10 +21,10 @@
.size = sizeof(SSIBus),
};
-static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
+static int ssi_slave_init(DeviceState *dev)
{
- SSISlaveInfo *info = container_of(base_info, SSISlaveInfo, qdev);
- SSISlave *s = SSI_SLAVE_FROM_QDEV(dev);
+ SSISlave *s = SSI_SLAVE(dev);
+ SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
SSIBus *bus;
bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
@@ -33,18 +33,24 @@
hw_error("Too many devices on SSI bus");
}
- s->info = info;
- return info->init(s);
+ return ssc->init(s);
}
-void ssi_register_slave(SSISlaveInfo *info)
+static void ssi_slave_class_init(ObjectClass *klass, void *data)
{
- assert(info->qdev.size >= sizeof(SSISlave));
- info->qdev.init = ssi_slave_init;
- info->qdev.bus_info = &ssi_bus_info;
- qdev_register(&info->qdev);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->init = ssi_slave_init;
+ dc->bus_info = &ssi_bus_info;
}
+static TypeInfo ssi_slave_info = {
+ .name = TYPE_SSI_SLAVE,
+ .parent = TYPE_DEVICE,
+ .class_init = ssi_slave_class_init,
+ .class_size = sizeof(SSISlaveClass),
+ .abstract = true,
+};
+
DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
{
DeviceState *dev;
@@ -64,10 +70,19 @@
{
DeviceState *dev;
SSISlave *slave;
+ SSISlaveClass *ssc;
dev = QTAILQ_FIRST(&bus->qbus.children);
if (!dev) {
return 0;
}
- slave = SSI_SLAVE_FROM_QDEV(dev);
- return slave->info->transfer(slave, val);
+ slave = SSI_SLAVE(dev);
+ ssc = SSI_SLAVE_GET_CLASS(slave);
+ return ssc->transfer(slave, val);
}
+
+static void register_ssi_slave(void)
+{
+ type_register_static(&ssi_slave_info);
+}
+
+device_init(register_ssi_slave);
diff --git a/hw/ssi.h b/hw/ssi.h
index 24610a8..06657d7 100644
--- a/hw/ssi.h
+++ b/hw/ssi.h
@@ -15,23 +15,29 @@
typedef struct SSISlave SSISlave;
+#define TYPE_SSI_SLAVE "ssi-slave"
+#define SSI_SLAVE(obj) \
+ OBJECT_CHECK(SSISlave, (obj), TYPE_SSI_SLAVE)
+#define SSI_SLAVE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SSISlaveClass, (klass), TYPE_SSI_SLAVE)
+#define SSI_SLAVE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE)
+
/* Slave devices. */
-typedef struct {
- DeviceInfo qdev;
+typedef struct SSISlaveClass {
+ DeviceClass parent_class;
+
int (*init)(SSISlave *dev);
uint32_t (*transfer)(SSISlave *dev, uint32_t val);
-} SSISlaveInfo;
+} SSISlaveClass;
struct SSISlave {
DeviceState qdev;
- SSISlaveInfo *info;
};
#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev)
#define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
-void ssi_register_slave(SSISlaveInfo *info);
-
DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
/* Master interface. */
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 7a73074..31a65cfb 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1394,22 +1394,69 @@
machine_init(stellaris_machine_init);
-static SSISlaveInfo stellaris_ssi_bus_info = {
- .qdev.name = "evb6965-ssi",
- .qdev.size = sizeof(stellaris_ssi_bus_state),
- .init = stellaris_ssi_bus_init,
- .transfer = stellaris_ssi_bus_transfer
+static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = stellaris_ssi_bus_init;
+ k->transfer = stellaris_ssi_bus_transfer;
+}
+
+static TypeInfo stellaris_ssi_bus_info = {
+ .name = "evb6965-ssi",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(stellaris_ssi_bus_state),
+ .class_init = stellaris_ssi_bus_class_init,
+};
+
+static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = stellaris_i2c_init;
+}
+
+static TypeInfo stellaris_i2c_info = {
+ .name = "stellaris-i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(stellaris_i2c_state),
+ .class_init = stellaris_i2c_class_init,
+};
+
+static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = stellaris_gptm_init;
+}
+
+static TypeInfo stellaris_gptm_info = {
+ .name = "stellaris-gptm",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(gptm_state),
+ .class_init = stellaris_gptm_class_init,
+};
+
+static void stellaris_adc_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = stellaris_adc_init;
+}
+
+static TypeInfo stellaris_adc_info = {
+ .name = "stellaris-adc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(stellaris_adc_state),
+ .class_init = stellaris_adc_class_init,
};
static void stellaris_register_devices(void)
{
- sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
- stellaris_i2c_init);
- sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
- stellaris_gptm_init);
- sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
- stellaris_adc_init);
- ssi_register_slave(&stellaris_ssi_bus_info);
+ type_register_static(&stellaris_i2c_info);
+ type_register_static(&stellaris_gptm_info);
+ type_register_static(&stellaris_adc_info);
+ type_register_static(&stellaris_ssi_bus_info);
}
device_init(stellaris_register_devices)
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 866c9a2..9b1be8d 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -411,7 +411,7 @@
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
stellaris_enet_reset(s);
@@ -420,19 +420,30 @@
return 0;
}
-static SysBusDeviceInfo stellaris_enet_info = {
- .init = stellaris_enet_init,
- .qdev.name = "stellaris_enet",
- .qdev.size = sizeof(stellaris_enet_state),
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property stellaris_enet_properties[] = {
+ DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stellaris_enet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = stellaris_enet_init;
+ dc->props = stellaris_enet_properties;
+}
+
+static TypeInfo stellaris_enet_info = {
+ .name = "stellaris_enet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(stellaris_enet_state),
+ .class_init = stellaris_enet_class_init,
};
static void stellaris_enet_register_devices(void)
{
- sysbus_register_withprop(&stellaris_enet_info);
+ type_register_static(&stellaris_enet_info);
}
device_init(stellaris_enet_register_devices)
diff --git a/hw/strongarm.c b/hw/strongarm.c
index fe63fd7..8d2e7eb 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -201,12 +201,21 @@
},
};
-static SysBusDeviceInfo strongarm_pic_info = {
- .init = strongarm_pic_initfn,
- .qdev.name = "strongarm_pic",
- .qdev.desc = "StrongARM PIC",
- .qdev.size = sizeof(StrongARMPICState),
- .qdev.vmsd = &vmstate_strongarm_pic_regs,
+static void strongarm_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_pic_initfn;
+ dc->desc = "StrongARM PIC";
+ dc->vmsd = &vmstate_strongarm_pic_regs;
+}
+
+static TypeInfo strongarm_pic_info = {
+ .name = "strongarm_pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMPICState),
+ .class_init = strongarm_pic_class_init,
};
/* Real-Time Clock */
@@ -413,12 +422,21 @@
},
};
-static SysBusDeviceInfo strongarm_rtc_sysbus_info = {
- .init = strongarm_rtc_init,
- .qdev.name = "strongarm-rtc",
- .qdev.desc = "StrongARM RTC Controller",
- .qdev.size = sizeof(StrongARMRTCState),
- .qdev.vmsd = &vmstate_strongarm_rtc_regs,
+static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_rtc_init;
+ dc->desc = "StrongARM RTC Controller";
+ dc->vmsd = &vmstate_strongarm_rtc_regs;
+}
+
+static TypeInfo strongarm_rtc_sysbus_info = {
+ .name = "strongarm-rtc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMRTCState),
+ .class_init = strongarm_rtc_sysbus_class_init,
};
/* GPIO */
@@ -646,11 +664,20 @@
},
};
-static SysBusDeviceInfo strongarm_gpio_info = {
- .init = strongarm_gpio_initfn,
- .qdev.name = "strongarm-gpio",
- .qdev.desc = "StrongARM GPIO controller",
- .qdev.size = sizeof(StrongARMGPIOInfo),
+static void strongarm_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_gpio_initfn;
+ dc->desc = "StrongARM GPIO controller";
+}
+
+static TypeInfo strongarm_gpio_info = {
+ .name = "strongarm-gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMGPIOInfo),
+ .class_init = strongarm_gpio_class_init,
};
/* Peripheral Pin Controller */
@@ -803,11 +830,20 @@
},
};
-static SysBusDeviceInfo strongarm_ppc_info = {
- .init = strongarm_ppc_init,
- .qdev.name = "strongarm-ppc",
- .qdev.desc = "StrongARM PPC controller",
- .qdev.size = sizeof(StrongARMPPCInfo),
+static void strongarm_ppc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_ppc_init;
+ dc->desc = "StrongARM PPC controller";
+}
+
+static TypeInfo strongarm_ppc_info = {
+ .name = "strongarm-ppc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMPPCInfo),
+ .class_init = strongarm_ppc_class_init,
};
/* UART Ports */
@@ -1245,17 +1281,28 @@
},
};
-static SysBusDeviceInfo strongarm_uart_info = {
- .init = strongarm_uart_init,
- .qdev.name = "strongarm-uart",
- .qdev.desc = "StrongARM UART controller",
- .qdev.size = sizeof(StrongARMUARTState),
- .qdev.reset = strongarm_uart_reset,
- .qdev.vmsd = &vmstate_strongarm_uart_regs,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property strongarm_uart_properties[] = {
+ DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void strongarm_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_uart_init;
+ dc->desc = "StrongARM UART controller";
+ dc->reset = strongarm_uart_reset;
+ dc->vmsd = &vmstate_strongarm_uart_regs;
+ dc->props = strongarm_uart_properties;
+}
+
+static TypeInfo strongarm_uart_info = {
+ .name = "strongarm-uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMUARTState),
+ .class_init = strongarm_uart_class_init,
};
/* Synchronous Serial Ports */
@@ -1479,13 +1526,22 @@
},
};
-static SysBusDeviceInfo strongarm_ssp_info = {
- .init = strongarm_ssp_init,
- .qdev.name = "strongarm-ssp",
- .qdev.desc = "StrongARM SSP controller",
- .qdev.size = sizeof(StrongARMSSPState),
- .qdev.reset = strongarm_ssp_reset,
- .qdev.vmsd = &vmstate_strongarm_ssp_regs,
+static void strongarm_ssp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_ssp_init;
+ dc->desc = "StrongARM SSP controller";
+ dc->reset = strongarm_ssp_reset;
+ dc->vmsd = &vmstate_strongarm_ssp_regs;
+}
+
+static TypeInfo strongarm_ssp_info = {
+ .name = "strongarm-ssp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMSSPState),
+ .class_init = strongarm_ssp_class_init,
};
/* Main CPU functions */
@@ -1555,11 +1611,11 @@
static void strongarm_register_devices(void)
{
- sysbus_register_withprop(&strongarm_pic_info);
- sysbus_register_withprop(&strongarm_rtc_sysbus_info);
- sysbus_register_withprop(&strongarm_gpio_info);
- sysbus_register_withprop(&strongarm_ppc_info);
- sysbus_register_withprop(&strongarm_uart_info);
- sysbus_register_withprop(&strongarm_ssp_info);
+ type_register_static(&strongarm_pic_info);
+ type_register_static(&strongarm_rtc_sysbus_info);
+ type_register_static(&strongarm_gpio_info);
+ type_register_static(&strongarm_ppc_info);
+ type_register_static(&strongarm_uart_info);
+ type_register_static(&strongarm_ssp_info);
}
device_init(strongarm_register_devices)
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
index e15b167..081d6cc 100644
--- a/hw/sun4c_intctl.c
+++ b/hw/sun4c_intctl.c
@@ -206,17 +206,26 @@
return 0;
}
-static SysBusDeviceInfo sun4c_intctl_info = {
- .init = sun4c_intctl_init1,
- .qdev.name = "sun4c_intctl",
- .qdev.size = sizeof(Sun4c_INTCTLState),
- .qdev.vmsd = &vmstate_sun4c_intctl,
- .qdev.reset = sun4c_intctl_reset,
+static void sun4c_intctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sun4c_intctl_init1;
+ dc->reset = sun4c_intctl_reset;
+ dc->vmsd = &vmstate_sun4c_intctl;
+}
+
+static TypeInfo sun4c_intctl_info = {
+ .name = "sun4c_intctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Sun4c_INTCTLState),
+ .class_init = sun4c_intctl_class_init,
};
static void sun4c_intctl_register_devices(void)
{
- sysbus_register_withprop(&sun4c_intctl_info);
+ type_register_static(&sun4c_intctl_info);
}
device_init(sun4c_intctl_register_devices)
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 941cc98..b79d14c 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -609,15 +609,23 @@
return 0;
}
-static SysBusDeviceInfo idreg_info = {
- .init = idreg_init1,
- .qdev.name = "macio_idreg",
- .qdev.size = sizeof(IDRegState),
+static void idreg_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = idreg_init1;
+}
+
+static TypeInfo idreg_info = {
+ .name = "macio_idreg",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IDRegState),
+ .class_init = idreg_class_init,
};
static void idreg_register_devices(void)
{
- sysbus_register_withprop(&idreg_info);
+ type_register_static(&idreg_info);
}
device_init(idreg_register_devices);
@@ -650,15 +658,23 @@
return 0;
}
-static SysBusDeviceInfo afx_info = {
- .init = afx_init1,
- .qdev.name = "tcx_afx",
- .qdev.size = sizeof(AFXState),
+static void afx_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = afx_init1;
+}
+
+static TypeInfo afx_info = {
+ .name = "tcx_afx",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AFXState),
+ .class_init = afx_class_init,
};
static void afx_register_devices(void)
{
- sysbus_register_withprop(&afx_info);
+ type_register_static(&afx_info);
}
device_init(afx_register_devices);
@@ -720,18 +736,29 @@
return 0;
}
-static SysBusDeviceInfo prom_info = {
- .init = prom_init1,
- .qdev.name = "openprom",
- .qdev.size = sizeof(PROMState),
- .qdev.props = (Property[]) {
- {/* end of property list */}
- }
+static Property prom_properties[] = {
+ {/* end of property list */},
+};
+
+static void prom_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = prom_init1;
+ dc->props = prom_properties;
+}
+
+static TypeInfo prom_info = {
+ .name = "openprom",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PROMState),
+ .class_init = prom_class_init,
};
static void prom_register_devices(void)
{
- sysbus_register_withprop(&prom_info);
+ type_register_static(&prom_info);
}
device_init(prom_register_devices);
@@ -779,19 +806,30 @@
sysbus_mmio_map(s, 0, addr);
}
-static SysBusDeviceInfo ram_info = {
- .init = ram_init1,
- .qdev.name = "memory",
- .qdev.size = sizeof(RamDevice),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT64("size", RamDevice, size, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ram_properties[] = {
+ DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ram_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ram_init1;
+ dc->props = ram_properties;
+}
+
+static TypeInfo ram_info = {
+ .name = "memory",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RamDevice),
+ .class_init = ram_class_init,
};
static void ram_register_devices(void)
{
- sysbus_register_withprop(&ram_info);
+ type_register_static(&ram_info);
}
device_init(ram_register_devices);
diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c
index ef7627c..727532c 100644
--- a/hw/sun4m_iommu.c
+++ b/hw/sun4m_iommu.c
@@ -357,21 +357,32 @@
return 0;
}
-static SysBusDeviceInfo iommu_info = {
- .init = iommu_init1,
- .qdev.name = "iommu",
- .qdev.size = sizeof(IOMMUState),
- .qdev.vmsd = &vmstate_iommu,
- .qdev.reset = iommu_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property iommu_properties[] = {
+ DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void iommu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = iommu_init1;
+ dc->reset = iommu_reset;
+ dc->vmsd = &vmstate_iommu;
+ dc->props = iommu_properties;
+}
+
+static TypeInfo iommu_info = {
+ .name = "iommu",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IOMMUState),
+ .class_init = iommu_class_init,
};
static void iommu_register_devices(void)
{
- sysbus_register_withprop(&iommu_info);
+ type_register_static(&iommu_info);
}
device_init(iommu_register_devices)
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 2dc3d04..79bbd49 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -562,19 +562,27 @@
return 0;
}
-static PCIDeviceInfo ebus_info = {
- .qdev.name = "ebus",
- .qdev.size = sizeof(EbusState),
- .init = pci_ebus_init1,
- .vendor_id = PCI_VENDOR_ID_SUN,
- .device_id = PCI_DEVICE_ID_SUN_EBUS,
- .revision = 0x01,
- .class_id = PCI_CLASS_BRIDGE_OTHER,
+static void ebus_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_ebus_init1;
+ k->vendor_id = PCI_VENDOR_ID_SUN;
+ k->device_id = PCI_DEVICE_ID_SUN_EBUS;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static TypeInfo ebus_info = {
+ .name = "ebus",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EbusState),
+ .class_init = ebus_class_init,
};
static void pci_ebus_register(void)
{
- pci_qdev_register(&ebus_info);
+ type_register_static(&ebus_info);
}
device_init(pci_ebus_register);
@@ -636,18 +644,29 @@
return 0;
}
-static SysBusDeviceInfo prom_info = {
- .init = prom_init1,
- .qdev.name = "openprom",
- .qdev.size = sizeof(PROMState),
- .qdev.props = (Property[]) {
- {/* end of property list */}
- }
+static Property prom_properties[] = {
+ {/* end of property list */},
+};
+
+static void prom_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = prom_init1;
+ dc->props = prom_properties;
+}
+
+static TypeInfo prom_info = {
+ .name = "openprom",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PROMState),
+ .class_init = prom_class_init,
};
static void prom_register_devices(void)
{
- sysbus_register_withprop(&prom_info);
+ type_register_static(&prom_info);
}
device_init(prom_register_devices);
@@ -688,19 +707,30 @@
sysbus_mmio_map(s, 0, addr);
}
-static SysBusDeviceInfo ram_info = {
- .init = ram_init1,
- .qdev.name = "memory",
- .qdev.size = sizeof(RamDevice),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT64("size", RamDevice, size, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ram_properties[] = {
+ DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ram_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ram_init1;
+ dc->props = ram_properties;
+}
+
+static TypeInfo ram_info = {
+ .name = "memory",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RamDevice),
+ .class_init = ram_class_init,
};
static void ram_register_devices(void)
{
- sysbus_register_withprop(&ram_info);
+ type_register_static(&ram_info);
}
device_init(ram_register_devices);
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 2e06fe8..282060a 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -105,31 +105,12 @@
}
}
-static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
+static int sysbus_device_init(DeviceState *dev)
{
- SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
+ SysBusDevice *sd = SYS_BUS_DEVICE(dev);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
- return info->init(sysbus_from_qdev(dev));
-}
-
-void sysbus_register_withprop(SysBusDeviceInfo *info)
-{
- info->qdev.init = sysbus_device_init;
- info->qdev.bus_info = &system_bus_info;
-
- assert(info->qdev.size >= sizeof(SysBusDevice));
- qdev_register(&info->qdev);
-}
-
-void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
-{
- SysBusDeviceInfo *info;
-
- info = g_malloc0(sizeof(*info));
- info->qdev.name = g_strdup(name);
- info->qdev.size = size;
- info->init = init;
- sysbus_register_withprop(info);
+ return sbc->init(sd);
}
DeviceState *sysbus_create_varargs(const char *name,
@@ -258,3 +239,26 @@
{
return get_system_memory();
}
+
+static void sysbus_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = sysbus_device_init;
+ k->bus_info = &system_bus_info;
+}
+
+static TypeInfo sysbus_device_type_info = {
+ .name = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .abstract = true,
+ .class_size = sizeof(SysBusDeviceClass),
+ .class_init = sysbus_device_class_init,
+};
+
+static void sysbus_register(void)
+{
+ type_register_static(&sysbus_device_type_info);
+}
+
+device_init(sysbus_register);
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 7b8ca23..22555cd 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -12,6 +12,20 @@
typedef struct SysBusDevice SysBusDevice;
+#define TYPE_SYS_BUS_DEVICE "sys-bus-device"
+#define SYS_BUS_DEVICE(obj) \
+ OBJECT_CHECK(SysBusDevice, (obj), TYPE_SYS_BUS_DEVICE)
+#define SYS_BUS_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SysBusDeviceClass, (klass), TYPE_SYS_BUS_DEVICE)
+#define SYS_BUS_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SysBusDeviceClass, (obj), TYPE_SYS_BUS_DEVICE)
+
+typedef struct SysBusDeviceClass {
+ DeviceClass parent_class;
+
+ int (*init)(SysBusDevice *dev);
+} SysBusDeviceClass;
+
struct SysBusDevice {
DeviceState qdev;
int num_irq;
@@ -26,19 +40,10 @@
pio_addr_t pio[QDEV_MAX_PIO];
};
-typedef int (*sysbus_initfn)(SysBusDevice *dev);
-
/* Macros to compensate for lack of type inheritance in C. */
#define sysbus_from_qdev(dev) ((SysBusDevice *)(dev))
#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
-typedef struct {
- DeviceInfo qdev;
- sysbus_initfn init;
-} SysBusDeviceInfo;
-
-void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
-void sysbus_register_withprop(SysBusDeviceInfo *info);
void *sysbus_new(void);
void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory);
MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
diff --git a/hw/tcx.c b/hw/tcx.c
index 75a28f2..ceb94c7 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -61,21 +61,13 @@
static void tcx_set_dirty(TCXState *s)
{
- unsigned int i;
-
- for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
- memory_region_set_dirty(&s->vram_mem, i);
- }
+ memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
}
static void tcx24_set_dirty(TCXState *s)
{
- unsigned int i;
-
- for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
- memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
- memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
- }
+ memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4);
+ memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4);
}
static void update_palette_entries(TCXState *s, int start, int end)
@@ -186,15 +178,13 @@
ram_addr_t cpage)
{
int ret;
- unsigned int off;
- ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
- for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
- ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
- DIRTY_MEMORY_VGA);
- ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
- DIRTY_MEMORY_VGA);
- }
+ ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
+ ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
+ DIRTY_MEMORY_VGA);
+ ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
+ DIRTY_MEMORY_VGA);
return ret;
}
@@ -253,7 +243,8 @@
}
for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
- if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
+ if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA)) {
if (y_start < 0)
y_start = y;
if (page < page_min)
@@ -646,25 +637,36 @@
return;
}
-static SysBusDeviceInfo tcx_info = {
- .init = tcx_init1,
- .qdev.name = "SUNW,tcx",
- .qdev.size = sizeof(TCXState),
- .qdev.reset = tcx_reset,
- .qdev.vmsd = &vmstate_tcx,
- .qdev.props = (Property[]) {
- DEFINE_PROP_TADDR("addr", TCXState, addr, -1),
- DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
- DEFINE_PROP_UINT16("width", TCXState, width, -1),
- DEFINE_PROP_UINT16("height", TCXState, height, -1),
- DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property tcx_properties[] = {
+ DEFINE_PROP_TADDR("addr", TCXState, addr, -1),
+ DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
+ DEFINE_PROP_UINT16("width", TCXState, width, -1),
+ DEFINE_PROP_UINT16("height", TCXState, height, -1),
+ DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tcx_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = tcx_init1;
+ dc->reset = tcx_reset;
+ dc->vmsd = &vmstate_tcx;
+ dc->props = tcx_properties;
+}
+
+static TypeInfo tcx_info = {
+ .name = "SUNW,tcx",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TCXState),
+ .class_init = tcx_class_init,
};
static void tcx_register_devices(void)
{
- sysbus_register_withprop(&tcx_info);
+ type_register_static(&tcx_info);
}
device_init(tcx_register_devices)
diff --git a/hw/tmp105.c b/hw/tmp105.c
index f7e6f2b..a3bdd91 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -22,7 +22,7 @@
#include "i2c.h"
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
uint8_t len;
uint8_t buf[2];
qemu_irq pin;
@@ -65,7 +65,7 @@
}
/* Units are 0.001 centigrades relative to 0 C. */
-void tmp105_set(i2c_slave *i2c, int temp)
+void tmp105_set(I2CSlave *i2c, int temp)
{
TMP105State *s = (TMP105State *) i2c;
@@ -138,7 +138,7 @@
}
}
-static int tmp105_rx(i2c_slave *i2c)
+static int tmp105_rx(I2CSlave *i2c)
{
TMP105State *s = (TMP105State *) i2c;
@@ -148,7 +148,7 @@
return 0xff;
}
-static int tmp105_tx(i2c_slave *i2c, uint8_t data)
+static int tmp105_tx(I2CSlave *i2c, uint8_t data)
{
TMP105State *s = (TMP105State *) i2c;
@@ -163,7 +163,7 @@
return 0;
}
-static void tmp105_event(i2c_slave *i2c, enum i2c_event event)
+static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
{
TMP105State *s = (TMP105State *) i2c;
@@ -202,7 +202,7 @@
}
};
-static void tmp105_reset(i2c_slave *i2c)
+static void tmp105_reset(I2CSlave *i2c)
{
TMP105State *s = (TMP105State *) i2c;
@@ -215,7 +215,7 @@
tmp105_interrupt_update(s);
}
-static int tmp105_init(i2c_slave *i2c)
+static int tmp105_init(I2CSlave *i2c)
{
TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c);
@@ -226,19 +226,28 @@
return 0;
}
-static I2CSlaveInfo tmp105_info = {
- .qdev.name = "tmp105",
- .qdev.size = sizeof(TMP105State),
- .qdev.vmsd = &vmstate_tmp105,
- .init = tmp105_init,
- .event = tmp105_event,
- .recv = tmp105_rx,
- .send = tmp105_tx
+static void tmp105_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = tmp105_init;
+ k->event = tmp105_event;
+ k->recv = tmp105_rx;
+ k->send = tmp105_tx;
+ dc->vmsd = &vmstate_tmp105;
+}
+
+static TypeInfo tmp105_info = {
+ .name = "tmp105",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(TMP105State),
+ .class_init = tmp105_class_init,
};
static void tmp105_register_devices(void)
{
- i2c_register_slave(&tmp105_info);
+ type_register_static(&tmp105_info);
}
device_init(tmp105_register_devices)
diff --git a/hw/tosa.c b/hw/tosa.c
index 0caba79..c0d4017 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -133,12 +133,12 @@
}
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
int len;
char buf[3];
} TosaDACState;
-static int tosa_dac_send(i2c_slave *i2c, uint8_t data)
+static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
{
TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
s->buf[s->len] = data;
@@ -157,7 +157,7 @@
return 0;
}
-static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event)
+static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
{
TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
s->len = 0;
@@ -180,13 +180,13 @@
}
}
-static int tosa_dac_recv(i2c_slave *s)
+static int tosa_dac_recv(I2CSlave *s)
{
printf("%s: recv not supported!!!\n", __FUNCTION__);
return -1;
}
-static int tosa_dac_init(i2c_slave *i2c)
+static int tosa_dac_init(I2CSlave *i2c)
{
/* Nothing to do. */
return 0;
@@ -259,26 +259,42 @@
machine_init(tosapda_machine_init);
-static I2CSlaveInfo tosa_dac_info = {
- .qdev.name = "tosa_dac",
- .qdev.size = sizeof(TosaDACState),
- .init = tosa_dac_init,
- .event = tosa_dac_event,
- .recv = tosa_dac_recv,
- .send = tosa_dac_send
+static void tosa_dac_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = tosa_dac_init;
+ k->event = tosa_dac_event;
+ k->recv = tosa_dac_recv;
+ k->send = tosa_dac_send;
+}
+
+static TypeInfo tosa_dac_info = {
+ .name = "tosa_dac",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(TosaDACState),
+ .class_init = tosa_dac_class_init,
};
-static SSISlaveInfo tosa_ssp_info = {
- .qdev.name = "tosa-ssp",
- .qdev.size = sizeof(SSISlave),
- .init = tosa_ssp_init,
- .transfer = tosa_ssp_tansfer
+static void tosa_ssp_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = tosa_ssp_init;
+ k->transfer = tosa_ssp_tansfer;
+}
+
+static TypeInfo tosa_ssp_info = {
+ .name = "tosa-ssp",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(SSISlave),
+ .class_init = tosa_ssp_class_init,
};
static void tosa_register_devices(void)
{
- i2c_register_slave(&tosa_dac_info);
- ssi_register_slave(&tosa_ssp_info);
+ type_register_static(&tosa_dac_info);
+ type_register_static(&tosa_ssp_info);
}
device_init(tosa_register_devices)
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 276300a..0ade670 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -789,16 +789,25 @@
return 0;
}
-static SysBusDeviceInfo tusb6010_info = {
- .init = tusb6010_init,
- .qdev.name = "tusb6010",
- .qdev.size = sizeof(TUSBState),
- .qdev.reset = tusb6010_reset,
+static void tusb6010_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = tusb6010_init;
+ dc->reset = tusb6010_reset;
+}
+
+static TypeInfo tusb6010_info = {
+ .name = "tusb6010",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TUSBState),
+ .class_init = tusb6010_class_init,
};
static void tusb6010_register_device(void)
{
- sysbus_register_withprop(&tusb6010_info);
+ type_register_static(&tusb6010_info);
}
device_init(tusb6010_register_device)
diff --git a/hw/twl92230.c b/hw/twl92230.c
index a75448f..03fdccc 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -27,7 +27,7 @@
#define VERBOSE 1
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
int firstbyte;
uint8_t reg;
@@ -126,7 +126,7 @@
menelaus_update(s);
}
-static void menelaus_reset(i2c_slave *i2c)
+static void menelaus_reset(I2CSlave *i2c)
{
MenelausState *s = (MenelausState *) i2c;
s->reg = 0x00;
@@ -709,7 +709,7 @@
}
}
-static void menelaus_event(i2c_slave *i2c, enum i2c_event event)
+static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
{
MenelausState *s = (MenelausState *) i2c;
@@ -717,7 +717,7 @@
s->firstbyte = 1;
}
-static int menelaus_tx(i2c_slave *i2c, uint8_t data)
+static int menelaus_tx(I2CSlave *i2c, uint8_t data)
{
MenelausState *s = (MenelausState *) i2c;
/* Interpret register address byte */
@@ -730,7 +730,7 @@
return 0;
}
-static int menelaus_rx(i2c_slave *i2c)
+static int menelaus_rx(I2CSlave *i2c)
{
MenelausState *s = (MenelausState *) i2c;
@@ -842,7 +842,7 @@
}
};
-static int twl92230_init(i2c_slave *i2c)
+static int twl92230_init(I2CSlave *i2c)
{
MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c);
@@ -857,19 +857,28 @@
return 0;
}
-static I2CSlaveInfo twl92230_info = {
- .qdev.name ="twl92230",
- .qdev.size = sizeof(MenelausState),
- .qdev.vmsd = &vmstate_menelaus,
- .init = twl92230_init,
- .event = menelaus_event,
- .recv = menelaus_rx,
- .send = menelaus_tx
+static void twl92230_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+ sc->init = twl92230_init;
+ sc->event = menelaus_event;
+ sc->recv = menelaus_rx;
+ sc->send = menelaus_tx;
+ dc->vmsd = &vmstate_menelaus;
+}
+
+static TypeInfo twl92230_info = {
+ .name = "twl92230",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(MenelausState),
+ .class_init = twl92230_class_init,
};
static void twl92230_register_devices(void)
{
- i2c_register_slave(&twl92230_info);
+ type_register_static(&twl92230_info);
}
device_init(twl92230_register_devices)
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 14d9914..17d86aa 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -39,7 +39,6 @@
static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
typedef struct UNINState {
- SysBusDevice busdev;
PCIHostState host_state;
MemoryRegion pci_mmio;
MemoryRegion pci_hole;
@@ -64,10 +63,6 @@
qemu_set_irq(pic[unin_irq_line[irq_num]], level);
}
-static void pci_unin_reset(void *opaque)
-{
-}
-
static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
{
uint32_t retval;
@@ -134,11 +129,13 @@
static int pci_unin_main_init_device(SysBusDevice *dev)
{
+ PCIHostState *h;
UNINState *s;
/* Use values found on a real PowerMac */
/* Uninorth main bus */
- s = FROM_SYSBUS(UNINState, dev);
+ h = FROM_SYSBUS(PCIHostState, dev);
+ s = DO_UPCAST(UNINState, host_state, h);
memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
&s->host_state, "pci-conf-idx", 0x1000);
@@ -147,17 +144,18 @@
sysbus_init_mmio(dev, &s->host_state.conf_mem);
sysbus_init_mmio(dev, &s->host_state.data_mem);
- qemu_register_reset(pci_unin_reset, &s->host_state);
return 0;
}
static int pci_u3_agp_init_device(SysBusDevice *dev)
{
+ PCIHostState *h;
UNINState *s;
/* Uninorth U3 AGP bus */
- s = FROM_SYSBUS(UNINState, dev);
+ h = FROM_SYSBUS(PCIHostState, dev);
+ s = DO_UPCAST(UNINState, host_state, h);
memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
&s->host_state, "pci-conf-idx", 0x1000);
@@ -166,17 +164,17 @@
sysbus_init_mmio(dev, &s->host_state.conf_mem);
sysbus_init_mmio(dev, &s->host_state.data_mem);
- qemu_register_reset(pci_unin_reset, &s->host_state);
-
return 0;
}
static int pci_unin_agp_init_device(SysBusDevice *dev)
{
+ PCIHostState *h;
UNINState *s;
/* Uninorth AGP bus */
- s = FROM_SYSBUS(UNINState, dev);
+ h = FROM_SYSBUS(PCIHostState, dev);
+ s = DO_UPCAST(UNINState, host_state, h);
memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
&s->host_state, "pci-conf-idx", 0x1000);
@@ -189,10 +187,12 @@
static int pci_unin_internal_init_device(SysBusDevice *dev)
{
+ PCIHostState *h;
UNINState *s;
/* Uninorth internal bus */
- s = FROM_SYSBUS(UNINState, dev);
+ h = FROM_SYSBUS(PCIHostState, dev);
+ s = DO_UPCAST(UNINState, host_state, h);
memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
&s->host_state, "pci-conf-idx", 0x1000);
@@ -209,21 +209,23 @@
{
DeviceState *dev;
SysBusDevice *s;
+ PCIHostState *h;
UNINState *d;
/* Use values found on a real PowerMac */
/* Uninorth main bus */
- dev = qdev_create(NULL, "uni-north");
+ dev = qdev_create(NULL, "uni-north-pci-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
- d = FROM_SYSBUS(UNINState, s);
+ h = FROM_SYSBUS(PCIHostState, s);
+ d = DO_UPCAST(UNINState, host_state, h);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
0x80000000ULL, 0x70000000ULL);
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+ d->host_state.bus = pci_register_bus(dev, "pci",
pci_unin_set_irq, pci_unin_map_irq,
pic,
&d->pci_mmio,
@@ -245,7 +247,7 @@
/* Uninorth AGP bus */
pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp");
- dev = qdev_create(NULL, "uni-north-agp");
+ dev = qdev_create(NULL, "uni-north-agp-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
sysbus_mmio_map(s, 0, 0xf0800000);
@@ -254,8 +256,9 @@
/* Uninorth internal bus */
#if 0
/* XXX: not needed for now */
- pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), "uni-north-pci");
- dev = qdev_create(NULL, "uni-north-pci");
+ pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0),
+ "uni-north-internal-pci");
+ dev = qdev_create(NULL, "uni-north-internal-pci-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
sysbus_mmio_map(s, 0, 0xf4800000);
@@ -271,14 +274,16 @@
{
DeviceState *dev;
SysBusDevice *s;
+ PCIHostState *h;
UNINState *d;
/* Uninorth AGP bus */
- dev = qdev_create(NULL, "u3-agp");
+ dev = qdev_create(NULL, "u3-agp-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
- d = FROM_SYSBUS(UNINState, s);
+ h = FROM_SYSBUS(PCIHostState, s);
+ d = DO_UPCAST(UNINState, host_state, h);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
@@ -286,7 +291,7 @@
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+ d->host_state.bus = pci_register_bus(dev, "pci",
pci_unin_set_irq, pci_unin_map_irq,
pic,
&d->pci_mmio,
@@ -334,60 +339,145 @@
return 0;
}
-static PCIDeviceInfo unin_main_pci_host_info = {
- .qdev.name = "uni-north",
- .qdev.size = sizeof(PCIDevice),
- .init = unin_main_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = unin_main_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_main_pci_host_info = {
+ .name = "uni-north-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = unin_main_pci_host_class_init,
};
-static PCIDeviceInfo u3_agp_pci_host_info = {
- .qdev.name = "u3-agp",
- .qdev.size = sizeof(PCIDevice),
- .init = u3_agp_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = u3_agp_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo u3_agp_pci_host_info = {
+ .name = "u3-agp",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = u3_agp_pci_host_class_init,
};
-static PCIDeviceInfo unin_agp_pci_host_info = {
- .qdev.name = "uni-north-agp",
- .qdev.size = sizeof(PCIDevice),
- .init = unin_agp_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = unin_agp_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_agp_pci_host_info = {
+ .name = "uni-north-agp",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = unin_agp_pci_host_class_init,
};
-static PCIDeviceInfo unin_internal_pci_host_info = {
- .qdev.name = "uni-north-pci",
- .qdev.size = sizeof(PCIDevice),
- .init = unin_internal_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = unin_internal_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_internal_pci_host_info = {
+ .name = "uni-north-internal-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = unin_internal_pci_host_class_init,
+};
+
+static void pci_unin_main_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = pci_unin_main_init_device;
+}
+
+static TypeInfo pci_unin_main_info = {
+ .name = "uni-north-pci-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .class_init = pci_unin_main_class_init,
+};
+
+static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = pci_u3_agp_init_device;
+}
+
+static TypeInfo pci_u3_agp_info = {
+ .name = "u3-agp-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .class_init = pci_u3_agp_class_init,
+};
+
+static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = pci_unin_agp_init_device;
+}
+
+static TypeInfo pci_unin_agp_info = {
+ .name = "uni-north-agp-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .class_init = pci_unin_agp_class_init,
+};
+
+static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = pci_unin_internal_init_device;
+}
+
+static TypeInfo pci_unin_internal_info = {
+ .name = "uni-north-internal-pci-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .class_init = pci_unin_internal_class_init,
};
static void unin_register_devices(void)
{
- sysbus_register_dev("uni-north", sizeof(UNINState),
- pci_unin_main_init_device);
- pci_qdev_register(&unin_main_pci_host_info);
- sysbus_register_dev("u3-agp", sizeof(UNINState),
- pci_u3_agp_init_device);
- pci_qdev_register(&u3_agp_pci_host_info);
- sysbus_register_dev("uni-north-agp", sizeof(UNINState),
- pci_unin_agp_init_device);
- pci_qdev_register(&unin_agp_pci_host_info);
- sysbus_register_dev("uni-north-pci", sizeof(UNINState),
- pci_unin_internal_init_device);
- pci_qdev_register(&unin_internal_pci_host_info);
+ type_register_static(&unin_main_pci_host_info);
+ type_register_static(&u3_agp_pci_host_info);
+ type_register_static(&unin_agp_pci_host_info);
+ type_register_static(&unin_internal_pci_host_info);
+
+ type_register_static(&pci_unin_main_info);
+ type_register_static(&pci_u3_agp_info);
+ type_register_static(&pci_unin_agp_info);
+ type_register_static(&pci_unin_internal_info);
}
device_init(unin_register_devices)
diff --git a/hw/usb-audio.c b/hw/usb-audio.c
new file mode 100644
index 0000000..cd589b7
--- /dev/null
+++ b/hw/usb-audio.c
@@ -0,0 +1,715 @@
+/*
+ * QEMU USB audio device
+ *
+ * written by:
+ * H. Peter Anvin <hpa@linux.intel.com>
+ * Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * lousely based on usb net device code which is:
+ *
+ * Copyright (c) 2006 Thomas Sailer
+ * Copyright (c) 2008 Andrzej Zaborowski
+ *
+ * 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-common.h"
+#include "usb.h"
+#include "usb-desc.h"
+#include "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+
+#define USBAUDIO_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */
+#define USBAUDIO_PRODUCT_NUM 0x0002
+
+#define DEV_CONFIG_VALUE 1 /* The one and only */
+
+/* Descriptor subtypes for AC interfaces */
+#define DST_AC_HEADER 1
+#define DST_AC_INPUT_TERMINAL 2
+#define DST_AC_OUTPUT_TERMINAL 3
+#define DST_AC_FEATURE_UNIT 6
+/* Descriptor subtypes for AS interfaces */
+#define DST_AS_GENERAL 1
+#define DST_AS_FORMAT_TYPE 2
+/* Descriptor subtypes for endpoints */
+#define DST_EP_GENERAL 1
+
+enum usb_audio_strings {
+ STRING_NULL,
+ STRING_MANUFACTURER,
+ STRING_PRODUCT,
+ STRING_SERIALNUMBER,
+ STRING_CONFIG,
+ STRING_USBAUDIO_CONTROL,
+ STRING_INPUT_TERMINAL,
+ STRING_FEATURE_UNIT,
+ STRING_OUTPUT_TERMINAL,
+ STRING_NULL_STREAM,
+ STRING_REAL_STREAM,
+};
+
+static const USBDescStrings usb_audio_stringtable = {
+ [STRING_MANUFACTURER] = "QEMU",
+ [STRING_PRODUCT] = "QEMU USB Audio",
+ [STRING_SERIALNUMBER] = "1",
+ [STRING_CONFIG] = "Audio Configuration",
+ [STRING_USBAUDIO_CONTROL] = "Audio Device",
+ [STRING_INPUT_TERMINAL] = "Audio Output Pipe",
+ [STRING_FEATURE_UNIT] = "Audio Output Volume Control",
+ [STRING_OUTPUT_TERMINAL] = "Audio Output Terminal",
+ [STRING_NULL_STREAM] = "Audio Output - Disabled",
+ [STRING_REAL_STREAM] = "Audio Output - 48 kHz Stereo",
+};
+
+#define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff)
+#define U24(x) U16(x), (((x) >> 16) & 0xff)
+#define U32(x) U24(x), (((x) >> 24) & 0xff)
+
+/*
+ * A Basic Audio Device uses these specific values
+ */
+#define USBAUDIO_PACKET_SIZE 192
+#define USBAUDIO_SAMPLE_RATE 48000
+#define USBAUDIO_PACKET_INTERVAL 1
+
+static const USBDescIface desc_iface[] = {
+ {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL,
+ .bInterfaceProtocol = 0x04,
+ .iInterface = STRING_USBAUDIO_CONTROL,
+ .ndesc = 4,
+ .descs = (USBDescOther[]) {
+ {
+ /* Headphone Class-Specific AC Interface Header Descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AC_HEADER, /* u8 bDescriptorSubtype */
+ U16(0x0100), /* u16 bcdADC */
+ U16(0x2b), /* u16 wTotalLength */
+ 0x01, /* u8 bInCollection */
+ 0x01, /* u8 baInterfaceNr */
+ }
+ },{
+ /* Generic Stereo Input Terminal ID1 Descriptor */
+ .data = (uint8_t[]) {
+ 0x0c, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AC_INPUT_TERMINAL, /* u8 bDescriptorSubtype */
+ 0x01, /* u8 bTerminalID */
+ U16(0x0101), /* u16 wTerminalType */
+ 0x00, /* u8 bAssocTerminal */
+ 0x02, /* u16 bNrChannels */
+ U16(0x0003), /* u16 wChannelConfig */
+ 0x00, /* u8 iChannelNames */
+ STRING_INPUT_TERMINAL, /* u8 iTerminal */
+ }
+ },{
+ /* Generic Stereo Feature Unit ID2 Descriptor */
+ .data = (uint8_t[]) {
+ 0x0d, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AC_FEATURE_UNIT, /* u8 bDescriptorSubtype */
+ 0x02, /* u8 bUnitID */
+ 0x01, /* u8 bSourceID */
+ 0x02, /* u8 bControlSize */
+ U16(0x0001), /* u16 bmaControls(0) */
+ U16(0x0002), /* u16 bmaControls(1) */
+ U16(0x0002), /* u16 bmaControls(2) */
+ STRING_FEATURE_UNIT, /* u8 iFeature */
+ }
+ },{
+ /* Headphone Ouptut Terminal ID3 Descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AC_OUTPUT_TERMINAL, /* u8 bDescriptorSubtype */
+ 0x03, /* u8 bUnitID */
+ U16(0x0301), /* u16 wTerminalType (SPK) */
+ 0x00, /* u8 bAssocTerminal */
+ 0x02, /* u8 bSourceID */
+ STRING_OUTPUT_TERMINAL, /* u8 iTerminal */
+ }
+ }
+ },
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
+ .iInterface = STRING_NULL_STREAM,
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
+ .iInterface = STRING_REAL_STREAM,
+ .ndesc = 2,
+ .descs = (USBDescOther[]) {
+ {
+ /* Headphone Class-specific AS General Interface Descriptor */
+ .data = (uint8_t[]) {
+ 0x07, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AS_GENERAL, /* u8 bDescriptorSubtype */
+ 0x01, /* u8 bTerminalLink */
+ 0x00, /* u8 bDelay */
+ 0x01, 0x00, /* u16 wFormatTag */
+ }
+ },{
+ /* Headphone Type I Format Type Descriptor */
+ .data = (uint8_t[]) {
+ 0x0b, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */
+ 0x01, /* u8 bFormatType */
+ 0x02, /* u8 bNrChannels */
+ 0x02, /* u8 bSubFrameSize */
+ 0x10, /* u8 bBitResolution */
+ 0x01, /* u8 bSamFreqType */
+ U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */
+ }
+ }
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | 0x01,
+ .bmAttributes = 0x0d,
+ .wMaxPacketSize = USBAUDIO_PACKET_SIZE,
+ .bInterval = 1,
+ .is_audio = 1,
+ /* Stereo Headphone Class-specific
+ AS Audio Data Endpoint Descriptor */
+ .extra = (uint8_t[]) {
+ 0x07, /* u8 bLength */
+ USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */
+ DST_EP_GENERAL, /* u8 bDescriptorSubtype */
+ 0x00, /* u8 bmAttributes */
+ 0x00, /* u8 bLockDelayUnits */
+ U16(0x0000), /* u16 wLockDelay */
+ },
+ },
+ }
+ }
+};
+
+static const USBDescDevice desc_device = {
+ .bcdUSB = 0x0200,
+ .bMaxPacketSize0 = 64,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 2,
+ .bConfigurationValue = DEV_CONFIG_VALUE,
+ .iConfiguration = STRING_CONFIG,
+ .bmAttributes = 0xc0,
+ .bMaxPower = 0x32,
+ .nif = ARRAY_SIZE(desc_iface),
+ .ifs = desc_iface,
+ },
+ },
+};
+
+static const USBDesc desc_audio = {
+ .id = {
+ .idVendor = USBAUDIO_VENDOR_NUM,
+ .idProduct = USBAUDIO_PRODUCT_NUM,
+ .bcdDevice = 0,
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .iSerialNumber = STRING_SERIALNUMBER,
+ },
+ .full = &desc_device,
+ .str = usb_audio_stringtable,
+};
+
+/*
+ * A USB audio device supports an arbitrary number of alternate
+ * interface settings for each interface. Each corresponds to a block
+ * diagram of parameterized blocks. This can thus refer to things like
+ * number of channels, data rates, or in fact completely different
+ * block diagrams. Alternative setting 0 is always the null block diagram,
+ * which is used by a disabled device.
+ */
+enum usb_audio_altset {
+ ALTSET_OFF = 0x00, /* No endpoint */
+ ALTSET_ON = 0x01, /* Single endpoint */
+};
+
+/*
+ * Class-specific control requests
+ */
+#define CR_SET_CUR 0x01
+#define CR_GET_CUR 0x81
+#define CR_SET_MIN 0x02
+#define CR_GET_MIN 0x82
+#define CR_SET_MAX 0x03
+#define CR_GET_MAX 0x83
+#define CR_SET_RES 0x04
+#define CR_GET_RES 0x84
+#define CR_SET_MEM 0x05
+#define CR_GET_MEM 0x85
+#define CR_GET_STAT 0xff
+
+/*
+ * Feature Unit Control Selectors
+ */
+#define MUTE_CONTROL 0x01
+#define VOLUME_CONTROL 0x02
+#define BASS_CONTROL 0x03
+#define MID_CONTROL 0x04
+#define TREBLE_CONTROL 0x05
+#define GRAPHIC_EQUALIZER_CONTROL 0x06
+#define AUTOMATIC_GAIN_CONTROL 0x07
+#define DELAY_CONTROL 0x08
+#define BASS_BOOST_CONTROL 0x09
+#define LOUDNESS_CONTROL 0x0a
+
+/*
+ * buffering
+ */
+
+struct streambuf {
+ uint8_t *data;
+ uint32_t size;
+ uint32_t prod;
+ uint32_t cons;
+};
+
+static void streambuf_init(struct streambuf *buf, uint32_t size)
+{
+ g_free(buf->data);
+ buf->size = size - (size % USBAUDIO_PACKET_SIZE);
+ buf->data = g_malloc(buf->size);
+ buf->prod = 0;
+ buf->cons = 0;
+}
+
+static void streambuf_fini(struct streambuf *buf)
+{
+ g_free(buf->data);
+ buf->data = NULL;
+}
+
+static int streambuf_put(struct streambuf *buf, USBPacket *p)
+{
+ uint32_t free = buf->size - (buf->prod - buf->cons);
+
+ if (!free) {
+ return 0;
+ }
+ assert(free >= USBAUDIO_PACKET_SIZE);
+ usb_packet_copy(p, buf->data + (buf->prod % buf->size),
+ USBAUDIO_PACKET_SIZE);
+ buf->prod += USBAUDIO_PACKET_SIZE;
+ return USBAUDIO_PACKET_SIZE;
+}
+
+static uint8_t *streambuf_get(struct streambuf *buf)
+{
+ uint32_t used = buf->prod - buf->cons;
+ uint8_t *data;
+
+ if (!used) {
+ return NULL;
+ }
+ assert(used >= USBAUDIO_PACKET_SIZE);
+ data = buf->data + (buf->cons % buf->size);
+ buf->cons += USBAUDIO_PACKET_SIZE;
+ return data;
+}
+
+typedef struct USBAudioState {
+ /* qemu interfaces */
+ USBDevice dev;
+ QEMUSoundCard card;
+
+ /* state */
+ struct {
+ enum usb_audio_altset altset;
+ struct audsettings as;
+ SWVoiceOut *voice;
+ bool mute;
+ uint8_t vol[2];
+ struct streambuf buf;
+ } out;
+
+ /* properties */
+ uint32_t debug;
+ uint32_t buffer;
+} USBAudioState;
+
+static void output_callback(void *opaque, int avail)
+{
+ USBAudioState *s = opaque;
+ uint8_t *data;
+
+ for (;;) {
+ if (avail < USBAUDIO_PACKET_SIZE) {
+ return;
+ }
+ data = streambuf_get(&s->out.buf);
+ if (NULL == data) {
+ return;
+ }
+ AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
+ avail -= USBAUDIO_PACKET_SIZE;
+ }
+}
+
+static int usb_audio_set_output_altset(USBAudioState *s, int altset)
+{
+ switch (altset) {
+ case ALTSET_OFF:
+ streambuf_init(&s->out.buf, s->buffer);
+ AUD_set_active_out(s->out.voice, false);
+ break;
+ case ALTSET_ON:
+ AUD_set_active_out(s->out.voice, true);
+ break;
+ default:
+ return -1;
+ }
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: set interface %d\n", altset);
+ }
+ s->out.altset = altset;
+ return 0;
+}
+
+/*
+ * Note: we arbitrarily map the volume control range onto -inf..+8 dB
+ */
+#define ATTRIB_ID(cs, attrib, idif) \
+ (((cs) << 24) | ((attrib) << 16) | (idif))
+
+static int usb_audio_get_control(USBAudioState *s, uint8_t attrib,
+ uint16_t cscn, uint16_t idif,
+ int length, uint8_t *data)
+{
+ uint8_t cs = cscn >> 8;
+ uint8_t cn = cscn - 1; /* -1 for the non-present master control */
+ uint32_t aid = ATTRIB_ID(cs, attrib, idif);
+ int ret = USB_RET_STALL;
+
+ switch (aid) {
+ case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200):
+ data[0] = s->out.mute;
+ ret = 1;
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200):
+ if (cn < 2) {
+ uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
+ data[0] = vol;
+ data[1] = vol >> 8;
+ ret = 2;
+ }
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200):
+ if (cn < 2) {
+ data[0] = 0x01;
+ data[1] = 0x80;
+ ret = 2;
+ }
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200):
+ if (cn < 2) {
+ data[0] = 0x00;
+ data[1] = 0x08;
+ ret = 2;
+ }
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200):
+ if (cn < 2) {
+ data[0] = 0x88;
+ data[1] = 0x00;
+ ret = 2;
+ }
+ break;
+ }
+
+ return ret;
+}
+static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
+ uint16_t cscn, uint16_t idif,
+ int length, uint8_t *data)
+{
+ uint8_t cs = cscn >> 8;
+ uint8_t cn = cscn - 1; /* -1 for the non-present master control */
+ uint32_t aid = ATTRIB_ID(cs, attrib, idif);
+ int ret = USB_RET_STALL;
+ bool set_vol = false;
+
+ switch (aid) {
+ case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200):
+ s->out.mute = data[0] & 1;
+ set_vol = true;
+ ret = 0;
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200):
+ if (cn < 2) {
+ uint16_t vol = data[0] + (data[1] << 8);
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol);
+ }
+
+ vol -= 0x8000;
+ vol = (vol * 255 + 0x4400) / 0x8800;
+ if (vol > 255) {
+ vol = 255;
+ }
+
+ s->out.vol[cn] = vol;
+ set_vol = true;
+ ret = 0;
+ }
+ break;
+ }
+
+ if (set_vol) {
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n",
+ s->out.mute, s->out.vol[0], s->out.vol[1]);
+ }
+ AUD_set_volume_out(s->out.voice, s->out.mute,
+ s->out.vol[0], s->out.vol[1]);
+ }
+
+ return ret;
+}
+
+static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
+ int request, int value, int index,
+ int length, uint8_t *data)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+ int ret = 0;
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: control transaction: "
+ "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
+ request, value, index, length);
+ }
+
+ ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+ if (ret >= 0) {
+ return ret;
+ }
+
+ switch (request) {
+ case ClassInterfaceRequest | CR_GET_CUR:
+ case ClassInterfaceRequest | CR_GET_MIN:
+ case ClassInterfaceRequest | CR_GET_MAX:
+ case ClassInterfaceRequest | CR_GET_RES:
+ ret = usb_audio_get_control(s, request & 0xff, value, index,
+ length, data);
+ if (ret < 0) {
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: fail: get control\n");
+ }
+ goto fail;
+ }
+ break;
+
+ case ClassInterfaceOutRequest | CR_SET_CUR:
+ case ClassInterfaceOutRequest | CR_SET_MIN:
+ case ClassInterfaceOutRequest | CR_SET_MAX:
+ case ClassInterfaceOutRequest | CR_SET_RES:
+ ret = usb_audio_set_control(s, request & 0xff, value, index,
+ length, data);
+ if (ret < 0) {
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: fail: set control\n");
+ }
+ goto fail;
+ }
+ break;
+
+ default:
+fail:
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: failed control transaction: "
+ "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
+ request, value, index, length);
+ }
+ ret = USB_RET_STALL;
+ break;
+ }
+ return ret;
+}
+
+static void usb_audio_set_interface(USBDevice *dev, int iface,
+ int old, int value)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+ if (iface == 1) {
+ usb_audio_set_output_altset(s, value);
+ }
+}
+
+static void usb_audio_handle_reset(USBDevice *dev)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: reset\n");
+ }
+ usb_audio_set_output_altset(s, ALTSET_OFF);
+}
+
+static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
+{
+ int rc;
+
+ if (s->out.altset == ALTSET_OFF) {
+ return USB_RET_STALL;
+ }
+
+ rc = streambuf_put(&s->out.buf, p);
+ if (rc < p->iov.size && s->debug > 1) {
+ fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
+ p->iov.size - rc);
+ }
+
+ return 0;
+}
+
+static int usb_audio_handle_data(USBDevice *dev, USBPacket *p)
+{
+ USBAudioState *s = (USBAudioState *) dev;
+ int ret = 0;
+
+ switch (p->pid) {
+ case USB_TOKEN_OUT:
+ switch (p->devep) {
+ case 1:
+ ret = usb_audio_handle_dataout(s, p);
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ default:
+fail:
+ ret = USB_RET_STALL;
+ break;
+ }
+ if (ret == USB_RET_STALL && s->debug) {
+ fprintf(stderr, "usb-audio: failed data transaction: "
+ "pid 0x%x ep 0x%x len 0x%zx\n",
+ p->pid, p->devep, p->iov.size);
+ }
+ return ret;
+}
+
+static void usb_audio_handle_destroy(USBDevice *dev)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: destroy\n");
+ }
+
+ usb_audio_set_output_altset(s, ALTSET_OFF);
+ AUD_close_out(&s->card, s->out.voice);
+ AUD_remove_card(&s->card);
+
+ streambuf_fini(&s->out.buf);
+}
+
+static int usb_audio_initfn(USBDevice *dev)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+ usb_desc_init(dev);
+ s->dev.opaque = s;
+ AUD_register_card("usb-audio", &s->card);
+
+ s->out.altset = ALTSET_OFF;
+ s->out.mute = false;
+ s->out.vol[0] = 240; /* 0 dB */
+ s->out.vol[1] = 240; /* 0 dB */
+ s->out.as.freq = USBAUDIO_SAMPLE_RATE;
+ s->out.as.nchannels = 2;
+ s->out.as.fmt = AUD_FMT_S16;
+ s->out.as.endianness = 0;
+ streambuf_init(&s->out.buf, s->buffer);
+
+ s->out.voice = AUD_open_out(&s->card, s->out.voice, "usb-audio",
+ s, output_callback, &s->out.as);
+ AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]);
+ AUD_set_active_out(s->out.voice, 0);
+ return 0;
+}
+
+static const VMStateDescription vmstate_usb_audio = {
+ .name = "usb-audio",
+ .unmigratable = 1,
+};
+
+static Property usb_audio_properties[] = {
+ DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
+ DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
+ 8 * USBAUDIO_PACKET_SIZE),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_audio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *k = USB_DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_usb_audio;
+ dc->props = usb_audio_properties;
+ k->product_desc = "QEMU USB Audio Interface";
+ k->usb_desc = &desc_audio;
+ k->init = usb_audio_initfn;
+ k->handle_packet = usb_generic_handle_packet;
+ k->handle_reset = usb_audio_handle_reset;
+ k->handle_control = usb_audio_handle_control;
+ k->handle_data = usb_audio_handle_data;
+ k->handle_destroy = usb_audio_handle_destroy;
+ k->set_interface = usb_audio_set_interface;
+}
+
+static TypeInfo usb_audio_info = {
+ .name = "usb-audio",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBAudioState),
+ .class_init = usb_audio_class_init,
+};
+
+static void usb_audio_register_devices(void)
+{
+ type_register_static(&usb_audio_info);
+ usb_legacy_register("usb-audio", "audio", NULL);
+}
+
+device_init(usb_audio_register_devices)
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index f30eec1..90c3b0e 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -28,7 +28,6 @@
USBDevice dev;
struct HCIInfo *hci;
- int altsetting;
int config;
#define CFIFO_LEN_MASK 255
@@ -362,7 +361,6 @@
s->outcmd.len = 0;
s->outacl.len = 0;
s->outsco.len = 0;
- s->altsetting = 0;
}
static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
@@ -402,26 +400,6 @@
case EndpointOutRequest | USB_REQ_SET_FEATURE:
goto fail;
break;
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- if (value != 0 || (index & ~1) || length != 1)
- goto fail;
- if (index == 1)
- data[0] = s->altsetting;
- else
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- if ((index & ~1) || length != 0 ||
- (index == 1 && (value < 0 || value > 4)) ||
- (index == 0 && value != 0)) {
- printf("%s: Wrong SET_INTERFACE request (%i, %i)\n",
- __FUNCTION__, index, value);
- goto fail;
- }
- s->altsetting = value;
- ret = 0;
- break;
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
if (s->config)
usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
@@ -549,22 +527,31 @@
.unmigratable = 1,
};
-static struct USBDeviceInfo bt_info = {
- .product_desc = "QEMU BT dongle",
- .qdev.name = "usb-bt-dongle",
- .qdev.size = sizeof(struct USBBtState),
- .qdev.vmsd = &vmstate_usb_bt,
- .usb_desc = &desc_bluetooth,
- .init = usb_bt_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_bt_handle_reset,
- .handle_control = usb_bt_handle_control,
- .handle_data = usb_bt_handle_data,
- .handle_destroy = usb_bt_handle_destroy,
+static void usb_bt_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_bt_initfn;
+ uc->product_desc = "QEMU BT dongle";
+ uc->usb_desc = &desc_bluetooth;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_bt_handle_reset;
+ uc->handle_control = usb_bt_handle_control;
+ uc->handle_data = usb_bt_handle_data;
+ uc->handle_destroy = usb_bt_handle_destroy;
+ dc->vmsd = &vmstate_usb_bt;
+}
+
+static TypeInfo bt_info = {
+ .name = "usb-bt-dongle",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(struct USBBtState),
+ .class_init = usb_bt_class_initfn,
};
static void usb_bt_register_devices(void)
{
- usb_qdev_register(&bt_info);
+ type_register_static(&bt_info);
}
device_init(usb_bt_register_devices)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index bd4afa7..b753834 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -65,21 +65,112 @@
return NULL;
}
-static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int usb_device_init(USBDevice *dev)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
- USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->init) {
+ return klass->init(dev);
+ }
+ return 0;
+}
+
+static void usb_device_handle_destroy(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_destroy) {
+ klass->handle_destroy(dev);
+ }
+}
+
+int usb_device_handle_packet(USBDevice *dev, USBPacket *p)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_packet) {
+ return klass->handle_packet(dev, p);
+ }
+ return -ENOSYS;
+}
+
+void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->cancel_packet) {
+ klass->cancel_packet(dev, p);
+ }
+}
+
+void usb_device_handle_attach(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_attach) {
+ klass->handle_attach(dev);
+ }
+}
+
+void usb_device_handle_reset(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_reset) {
+ klass->handle_reset(dev);
+ }
+}
+
+int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
+ int value, int index, int length, uint8_t *data)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_control) {
+ return klass->handle_control(dev, p, request, value, index, length,
+ data);
+ }
+ return -ENOSYS;
+}
+
+int usb_device_handle_data(USBDevice *dev, USBPacket *p)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_data) {
+ return klass->handle_data(dev, p);
+ }
+ return -ENOSYS;
+}
+
+const char *usb_device_get_product_desc(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ return klass->product_desc;
+}
+
+const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ return klass->usb_desc;
+}
+
+void usb_device_set_interface(USBDevice *dev, int interface,
+ int alt_old, int alt_new)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->set_interface) {
+ klass->set_interface(dev, interface, alt_old, alt_new);
+ }
+}
+
+static int usb_qdev_init(DeviceState *qdev)
+{
+ USBDevice *dev = USB_DEVICE(qdev);
int rc;
- pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
- dev->info = info;
+ pstrcpy(dev->product_desc, sizeof(dev->product_desc),
+ usb_device_get_product_desc(dev));
dev->auto_attach = 1;
QLIST_INIT(&dev->strings);
+ usb_ep_init(dev);
rc = usb_claim_port(dev);
if (rc != 0) {
return rc;
}
- rc = dev->info->init(dev);
+ rc = usb_device_init(dev);
if (rc != 0) {
usb_release_port(dev);
return rc;
@@ -96,34 +187,36 @@
static int usb_qdev_exit(DeviceState *qdev)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDevice *dev = USB_DEVICE(qdev);
if (dev->attached) {
usb_device_detach(dev);
}
- if (dev->info->handle_destroy) {
- dev->info->handle_destroy(dev);
- }
+ usb_device_handle_destroy(dev);
if (dev->port) {
usb_release_port(dev);
}
return 0;
}
-void usb_qdev_register(USBDeviceInfo *info)
+typedef struct LegacyUSBFactory
{
- info->qdev.bus_info = &usb_bus_info;
- info->qdev.init = usb_qdev_init;
- info->qdev.unplug = qdev_simple_unplug_cb;
- info->qdev.exit = usb_qdev_exit;
- qdev_register(&info->qdev);
-}
+ const char *name;
+ const char *usbdevice_name;
+ USBDevice *(*usbdevice_init)(const char *params);
+} LegacyUSBFactory;
-void usb_qdev_register_many(USBDeviceInfo *info)
+static GSList *legacy_usb_factory;
+
+void usb_legacy_register(const char *typename, const char *usbdevice_name,
+ USBDevice *(*usbdevice_init)(const char *params))
{
- while (info->qdev.name) {
- usb_qdev_register(info);
- info++;
+ if (usbdevice_name) {
+ LegacyUSBFactory *f = g_malloc0(sizeof(*f));
+ f->name = typename;
+ f->usbdevice_name = usbdevice_name;
+ f->usbdevice_init = usbdevice_init;
+ legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
}
}
@@ -143,7 +236,7 @@
#endif
dev = qdev_create(&bus->qbus, name);
- return DO_UPCAST(USBDevice, qdev, dev);
+ return USB_DEVICE(dev);
}
USBDevice *usb_create_simple(USBBus *bus, const char *name)
@@ -249,7 +342,7 @@
return -1;
}
} else {
- if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
+ if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
/* Create a new hub and chain it on */
usb_create_simple(bus, "usb-hub");
}
@@ -364,7 +457,7 @@
static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDevice *dev = USB_DEVICE(qdev);
USBBus *bus = usb_bus_from_device(dev);
monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
@@ -376,13 +469,13 @@
static char *usb_get_dev_path(DeviceState *qdev)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDevice *dev = USB_DEVICE(qdev);
return g_strdup(dev->port->path);
}
static char *usb_get_fw_dev_path(DeviceState *qdev)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDevice *dev = USB_DEVICE(qdev);
char *fw_path, *in;
ssize_t pos = 0, fw_len;
long nr;
@@ -433,8 +526,8 @@
USBDevice *usbdevice_create(const char *cmdline)
{
USBBus *bus = usb_bus_find(-1 /* any */);
- DeviceInfo *info;
- USBDeviceInfo *usb;
+ LegacyUSBFactory *f = NULL;
+ GSList *i;
char driver[32];
const char *params;
int len;
@@ -451,17 +544,13 @@
pstrcpy(driver, sizeof(driver), cmdline);
}
- for (info = device_info_list; info != NULL; info = info->next) {
- if (info->bus_info != &usb_bus_info)
- continue;
- usb = DO_UPCAST(USBDeviceInfo, qdev, info);
- if (usb->usbdevice_name == NULL)
- continue;
- if (strcmp(usb->usbdevice_name, driver) != 0)
- continue;
- break;
+ for (i = legacy_usb_factory; i; i = i->next) {
+ f = i->data;
+ if (strcmp(f->usbdevice_name, driver) == 0) {
+ break;
+ }
}
- if (info == NULL) {
+ if (i == NULL) {
#if 0
/* no error because some drivers are not converted (yet) */
error_report("usbdevice %s not found", driver);
@@ -469,12 +558,37 @@
return NULL;
}
- if (!usb->usbdevice_init) {
+ if (!f->usbdevice_init) {
if (*params) {
error_report("usbdevice %s accepts no params", driver);
return NULL;
}
- return usb_create_simple(bus, usb->qdev.name);
+ return usb_create_simple(bus, f->name);
}
- return usb->usbdevice_init(params);
+ return f->usbdevice_init(params);
}
+
+static void usb_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->bus_info = &usb_bus_info;
+ k->init = usb_qdev_init;
+ k->unplug = qdev_simple_unplug_cb;
+ k->exit = usb_qdev_exit;
+}
+
+static TypeInfo usb_device_type_info = {
+ .name = TYPE_USB_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(USBDevice),
+ .abstract = true,
+ .class_size = sizeof(USBDeviceClass),
+ .class_init = usb_device_class_init,
+};
+
+static void usb_register_devices(void)
+{
+ type_register_static(&usb_device_type_info);
+}
+
+device_init(usb_register_devices);
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index cd349f3..881da30 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -269,7 +269,6 @@
USBDevice dev;
CCIDBus bus;
CCIDCardState *card;
- CCIDCardInfo *cardinfo; /* caching the info pointer */
BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
uint32_t bulk_in_pending_start;
uint32_t bulk_in_pending_end; /* first free */
@@ -468,6 +467,43 @@
.str = desc_strings,
};
+static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len)
+{
+ CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+ if (cc->get_atr) {
+ return cc->get_atr(card, len);
+ }
+ return NULL;
+}
+
+static void ccid_card_apdu_from_guest(CCIDCardState *card,
+ const uint8_t *apdu,
+ uint32_t len)
+{
+ CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+ if (cc->apdu_from_guest) {
+ cc->apdu_from_guest(card, apdu, len);
+ }
+}
+
+static int ccid_card_exitfn(CCIDCardState *card)
+{
+ CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+ if (cc->exitfn) {
+ return cc->exitfn(card);
+ }
+ return 0;
+}
+
+static int ccid_card_initfn(CCIDCardState *card)
+{
+ CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+ if (cc->initfn) {
+ return cc->initfn(card);
+ }
+ return 0;
+}
+
static bool ccid_has_pending_answers(USBCCIDState *s)
{
return s->pending_answers_num > 0;
@@ -611,14 +647,6 @@
}
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
-
/* Class specific requests. */
case InterfaceOutClass | CCID_CONTROL_ABORT:
DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
@@ -749,7 +777,7 @@
uint32_t len = 0;
if (s->card) {
- atr = s->cardinfo->get_atr(s->card, &len);
+ atr = ccid_card_get_atr(s->card, &len);
}
ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
}
@@ -835,7 +863,7 @@
recv->hdr.bSeq, len);
ccid_add_pending_answer(s, (CCID_Header *)recv);
if (s->card) {
- s->cardinfo->apdu_from_guest(s->card, recv->abData, len);
+ ccid_card_apdu_from_guest(s->card, recv->abData, len);
} else {
DPRINTF(s, D_WARN, "warning: discarded apdu\n");
}
@@ -1121,26 +1149,21 @@
static int ccid_card_exit(DeviceState *qdev)
{
int ret = 0;
- CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
- CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info);
+ CCIDCardState *card = CCID_CARD(qdev);
USBCCIDState *s =
DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
if (ccid_card_inserted(s)) {
ccid_card_card_removed(card);
}
- if (info->exitfn) {
- ret = info->exitfn(card);
- }
+ ret = ccid_card_exitfn(card);
s->card = NULL;
- s->cardinfo = NULL;
return ret;
}
-static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
+static int ccid_card_init(DeviceState *qdev)
{
- CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
- CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, base);
+ CCIDCardState *card = CCID_CARD(qdev);
USBCCIDState *s =
DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
int ret = 0;
@@ -1154,22 +1177,13 @@
error_report("Warning: usb-ccid card already full, not adding");
return -1;
}
- ret = info->initfn ? info->initfn(card) : ret;
+ ret = ccid_card_initfn(card);
if (ret == 0) {
s->card = card;
- s->cardinfo = info;
}
return ret;
}
-void ccid_card_qdev_register(CCIDCardInfo *card)
-{
- card->qdev.bus_info = &ccid_bus_info;
- card->qdev.init = ccid_card_init;
- card->qdev.exit = ccid_card_exit;
- qdev_register(&card->qdev);
-}
-
static int ccid_initfn(USBDevice *dev)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
@@ -1178,7 +1192,6 @@
qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
s->bus.qbus.allow_hotplug = 1;
s->card = NULL;
- s->cardinfo = NULL;
s->migration_state = MIGRATION_NONE;
s->migration_target_ip = 0;
s->migration_target_port = 0;
@@ -1294,28 +1307,57 @@
}
};
-static struct USBDeviceInfo ccid_info = {
- .product_desc = "QEMU USB CCID",
- .qdev.name = CCID_DEV_NAME,
- .qdev.desc = "CCID Rev 1.1 smartcard reader",
- .qdev.size = sizeof(USBCCIDState),
- .init = ccid_initfn,
- .usb_desc = &desc_ccid,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = ccid_handle_reset,
- .handle_control = ccid_handle_control,
- .handle_data = ccid_handle_data,
- .handle_destroy = ccid_handle_destroy,
- .usbdevice_name = "ccid",
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.vmsd = &ccid_vmstate,
+static Property ccid_properties[] = {
+ DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ccid_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = ccid_initfn;
+ uc->product_desc = "QEMU USB CCID";
+ uc->usb_desc = &desc_ccid;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = ccid_handle_reset;
+ uc->handle_control = ccid_handle_control;
+ uc->handle_data = ccid_handle_data;
+ uc->handle_destroy = ccid_handle_destroy;
+ dc->desc = "CCID Rev 1.1 smartcard reader";
+ dc->vmsd = &ccid_vmstate;
+ dc->props = ccid_properties;
+}
+
+static TypeInfo ccid_info = {
+ .name = CCID_DEV_NAME,
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBCCIDState),
+ .class_init = ccid_class_initfn,
+};
+
+static void ccid_card_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->bus_info = &ccid_bus_info;
+ k->init = ccid_card_init;
+ k->exit = ccid_card_exit;
+}
+
+static TypeInfo ccid_card_type_info = {
+ .name = TYPE_CCID_CARD,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(CCIDCardState),
+ .abstract = true,
+ .class_size = sizeof(CCIDCardClass),
+ .class_init = ccid_card_class_init,
};
static void ccid_register_devices(void)
{
- usb_qdev_register(&ccid_info);
+ type_register_static(&ccid_card_type_info);
+ type_register_static(&ccid_info);
+ usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
}
device_init(ccid_register_devices)
diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index ae2d384..3c3ed6a 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -192,9 +192,10 @@
int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
{
- uint8_t bLength = 0x07;
+ uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
+ uint8_t extralen = ep->extra ? ep->extra[0] : 0;
- if (len < bLength) {
+ if (len < bLength + extralen) {
return -1;
}
@@ -205,8 +206,15 @@
dest[0x04] = usb_lo(ep->wMaxPacketSize);
dest[0x05] = usb_hi(ep->wMaxPacketSize);
dest[0x06] = ep->bInterval;
+ if (ep->is_audio) {
+ dest[0x07] = ep->bRefresh;
+ dest[0x08] = ep->bSynchAddress;
+ }
+ if (ep->extra) {
+ memcpy(dest + bLength, ep->extra, extralen);
+ }
- return bLength;
+ return bLength + extralen;
}
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
@@ -223,9 +231,114 @@
/* ------------------------------------------------------------------ */
+static void usb_desc_ep_init(USBDevice *dev)
+{
+ const USBDescIface *iface;
+ int i, e, pid, ep;
+
+ usb_ep_init(dev);
+ for (i = 0; i < dev->ninterfaces; i++) {
+ iface = dev->ifaces[i];
+ if (iface == NULL) {
+ continue;
+ }
+ for (e = 0; e < iface->bNumEndpoints; e++) {
+ pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ?
+ USB_TOKEN_IN : USB_TOKEN_OUT;
+ ep = iface->eps[e].bEndpointAddress & 0x0f;
+ usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
+ usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber);
+ usb_ep_set_max_packet_size(dev, pid, ep,
+ iface->eps[e].wMaxPacketSize);
+ }
+ }
+}
+
+static const USBDescIface *usb_desc_find_interface(USBDevice *dev,
+ int nif, int alt)
+{
+ const USBDescIface *iface;
+ int g, i;
+
+ if (!dev->config) {
+ return NULL;
+ }
+ for (g = 0; g < dev->config->nif_groups; g++) {
+ for (i = 0; i < dev->config->if_groups[g].nif; i++) {
+ iface = &dev->config->if_groups[g].ifs[i];
+ if (iface->bInterfaceNumber == nif &&
+ iface->bAlternateSetting == alt) {
+ return iface;
+ }
+ }
+ }
+ for (i = 0; i < dev->config->nif; i++) {
+ iface = &dev->config->ifs[i];
+ if (iface->bInterfaceNumber == nif &&
+ iface->bAlternateSetting == alt) {
+ return iface;
+ }
+ }
+ return NULL;
+}
+
+static int usb_desc_set_interface(USBDevice *dev, int index, int value)
+{
+ const USBDescIface *iface;
+ int old;
+
+ iface = usb_desc_find_interface(dev, index, value);
+ if (iface == NULL) {
+ return -1;
+ }
+
+ old = dev->altsetting[index];
+ dev->altsetting[index] = value;
+ dev->ifaces[index] = iface;
+ usb_desc_ep_init(dev);
+
+ if (old != value) {
+ usb_device_set_interface(dev, index, old, value);
+ }
+ return 0;
+}
+
+static int usb_desc_set_config(USBDevice *dev, int value)
+{
+ int i;
+
+ if (value == 0) {
+ dev->configuration = 0;
+ dev->ninterfaces = 0;
+ dev->config = NULL;
+ } else {
+ for (i = 0; i < dev->device->bNumConfigurations; i++) {
+ if (dev->device->confs[i].bConfigurationValue == value) {
+ dev->configuration = value;
+ dev->ninterfaces = dev->device->confs[i].bNumInterfaces;
+ dev->config = dev->device->confs + i;
+ assert(dev->ninterfaces <= USB_MAX_INTERFACES);
+ }
+ }
+ if (i < dev->device->bNumConfigurations) {
+ return -1;
+ }
+ }
+
+ for (i = 0; i < dev->ninterfaces; i++) {
+ usb_desc_set_interface(dev, i, 0);
+ }
+ for (; i < USB_MAX_INTERFACES; i++) {
+ dev->altsetting[i] = 0;
+ dev->ifaces[i] = NULL;
+ }
+
+ return 0;
+}
+
static void usb_desc_setdefaults(USBDevice *dev)
{
- const USBDesc *desc = dev->info->usb_desc;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
assert(desc != NULL);
switch (dev->speed) {
@@ -237,12 +350,12 @@
dev->device = desc->high;
break;
}
- dev->config = dev->device->confs;
+ usb_desc_set_config(dev, 0);
}
void usb_desc_init(USBDevice *dev)
{
- const USBDesc *desc = dev->info->usb_desc;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
assert(desc != NULL);
dev->speed = USB_SPEED_FULL;
@@ -258,7 +371,7 @@
void usb_desc_attach(USBDevice *dev)
{
- const USBDesc *desc = dev->info->usb_desc;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
assert(desc != NULL);
if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
@@ -267,7 +380,7 @@
dev->speed = USB_SPEED_FULL;
} else {
fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n",
- dev->info->product_desc);
+ usb_device_get_product_desc(dev));
return;
}
usb_desc_setdefaults(dev);
@@ -323,7 +436,7 @@
str = usb_desc_get_string(dev, index);
if (str == NULL) {
- str = dev->info->usb_desc->str[index];
+ str = usb_device_get_usb_desc(dev)->str[index];
if (str == NULL) {
return 0;
}
@@ -342,7 +455,7 @@
int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
{
- const USBDesc *desc = dev->info->usb_desc;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
const USBDescDevice *other_dev;
uint8_t buf[256];
uint8_t type = value >> 8;
@@ -350,9 +463,9 @@
int ret = -1;
if (dev->speed == USB_SPEED_HIGH) {
- other_dev = dev->info->usb_desc->full;
+ other_dev = usb_device_get_usb_desc(dev)->full;
} else {
- other_dev = dev->info->usb_desc->high;
+ other_dev = usb_device_get_usb_desc(dev)->high;
}
switch(type) {
@@ -407,8 +520,8 @@
int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
- const USBDesc *desc = dev->info->usb_desc;
- int i, ret = -1;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
+ int ret = -1;
assert(desc != NULL);
switch(request) {
@@ -427,12 +540,7 @@
ret = 1;
break;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- for (i = 0; i < dev->device->bNumConfigurations; i++) {
- if (dev->device->confs[i].bConfigurationValue == value) {
- dev->config = dev->device->confs + i;
- ret = 0;
- }
- }
+ ret = usb_desc_set_config(dev, value);
trace_usb_set_config(dev->addr, value, ret);
break;
@@ -461,6 +569,19 @@
}
trace_usb_set_device_feature(dev->addr, value, ret);
break;
+
+ case InterfaceRequest | USB_REQ_GET_INTERFACE:
+ if (index < 0 || index >= dev->ninterfaces) {
+ break;
+ }
+ data[0] = dev->altsetting[index];
+ ret = 1;
+ break;
+ case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+ ret = usb_desc_set_interface(dev, index, value);
+ trace_usb_set_interface(dev->addr, index, value, ret);
+ break;
+
}
return ret;
}
diff --git a/hw/usb-desc.h b/hw/usb-desc.h
index 5c14e4a..d6e07ea 100644
--- a/hw/usb-desc.h
+++ b/hw/usb-desc.h
@@ -71,6 +71,11 @@
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
+ uint8_t bRefresh;
+ uint8_t bSynchAddress;
+
+ uint8_t is_audio; /* has bRefresh + bSynchAddress */
+ uint8_t *extra;
};
struct USBDescOther {
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 7c926c0..75ef71e 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -715,7 +715,8 @@
EHCIQueue *q, *tmp;
QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
- if (q->packet.owner != dev) {
+ if (q->packet.owner == NULL ||
+ q->packet.owner->dev != dev) {
continue;
}
ehci_free_queue(q);
@@ -2262,30 +2263,46 @@
DEFINE_PROP_END_OF_LIST(),
};
-static PCIDeviceInfo ehci_info[] = {
- {
- .qdev.name = "usb-ehci",
- .qdev.size = sizeof(EHCIState),
- .qdev.vmsd = &vmstate_ehci,
- .init = usb_ehci_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
- .revision = 0x10,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = ehci_properties,
- },{
- .qdev.name = "ich9-usb-ehci1",
- .qdev.size = sizeof(EHCIState),
- .qdev.vmsd = &vmstate_ehci,
- .init = usb_ehci_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
- .revision = 0x03,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = ehci_properties,
- },{
- /* end of list */
- }
+static void ehci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_ehci;
+ dc->props = ehci_properties;
+}
+
+static TypeInfo ehci_info = {
+ .name = "usb-ehci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EHCIState),
+ .class_init = ehci_class_init,
+};
+
+static void ich9_ehci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_ehci;
+ dc->props = ehci_properties;
+}
+
+static TypeInfo ich9_ehci_info = {
+ .name = "ich9-usb-ehci1",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EHCIState),
+ .class_init = ich9_ehci_class_init,
};
static int usb_ehci_initfn(PCIDevice *dev)
@@ -2361,7 +2378,8 @@
static void ehci_register(void)
{
- pci_qdev_register_many(ehci_info);
+ type_register_static(&ehci_info);
+ type_register_static(&ich9_ehci_info);
}
device_init(ehci_register);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index a110c74..3c4e45d 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -384,13 +384,6 @@
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* hid specific requests */
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
switch (value >> 8) {
@@ -560,53 +553,81 @@
}
};
-static struct USBDeviceInfo hid_info[] = {
- {
- .product_desc = "QEMU USB Tablet",
- .qdev.name = "usb-tablet",
- .usbdevice_name = "tablet",
- .qdev.size = sizeof(USBHIDState),
- .qdev.vmsd = &vmstate_usb_ptr,
- .usb_desc = &desc_tablet,
- .init = usb_tablet_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_hid_handle_reset,
- .handle_control = usb_hid_handle_control,
- .handle_data = usb_hid_handle_data,
- .handle_destroy = usb_hid_handle_destroy,
- },{
- .product_desc = "QEMU USB Mouse",
- .qdev.name = "usb-mouse",
- .usbdevice_name = "mouse",
- .qdev.size = sizeof(USBHIDState),
- .qdev.vmsd = &vmstate_usb_ptr,
- .usb_desc = &desc_mouse,
- .init = usb_mouse_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_hid_handle_reset,
- .handle_control = usb_hid_handle_control,
- .handle_data = usb_hid_handle_data,
- .handle_destroy = usb_hid_handle_destroy,
- },{
- .product_desc = "QEMU USB Keyboard",
- .qdev.name = "usb-kbd",
- .usbdevice_name = "keyboard",
- .qdev.size = sizeof(USBHIDState),
- .qdev.vmsd = &vmstate_usb_kbd,
- .usb_desc = &desc_keyboard,
- .init = usb_keyboard_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_hid_handle_reset,
- .handle_control = usb_hid_handle_control,
- .handle_data = usb_hid_handle_data,
- .handle_destroy = usb_hid_handle_destroy,
- },{
- /* end of list */
- }
+static void usb_hid_class_initfn(ObjectClass *klass, void *data)
+{
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_hid_handle_reset;
+ uc->handle_control = usb_hid_handle_control;
+ uc->handle_data = usb_hid_handle_data;
+ uc->handle_destroy = usb_hid_handle_destroy;
+}
+
+static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ usb_hid_class_initfn(klass, data);
+ uc->init = usb_tablet_initfn;
+ uc->product_desc = "QEMU USB Tablet";
+ uc->usb_desc = &desc_tablet;
+ dc->vmsd = &vmstate_usb_ptr;
+}
+
+static TypeInfo usb_tablet_info = {
+ .name = "usb-tablet",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHIDState),
+ .class_init = usb_tablet_class_initfn,
+};
+
+static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ usb_hid_class_initfn(klass, data);
+ uc->init = usb_mouse_initfn;
+ uc->product_desc = "QEMU USB Mouse";
+ uc->usb_desc = &desc_mouse;
+ dc->vmsd = &vmstate_usb_ptr;
+}
+
+static TypeInfo usb_mouse_info = {
+ .name = "usb-mouse",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHIDState),
+ .class_init = usb_mouse_class_initfn,
+};
+
+static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ usb_hid_class_initfn(klass, data);
+ uc->init = usb_keyboard_initfn;
+ uc->product_desc = "QEMU USB Keyboard";
+ uc->usb_desc = &desc_keyboard;
+ dc->vmsd = &vmstate_usb_kbd;
+}
+
+static TypeInfo usb_keyboard_info = {
+ .name = "usb-kbd",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHIDState),
+ .class_init = usb_keyboard_class_initfn,
};
static void usb_hid_register_devices(void)
{
- usb_qdev_register_many(hid_info);
+ type_register_static(&usb_tablet_info);
+ usb_legacy_register("usb-tablet", "tablet", NULL);
+ type_register_static(&usb_mouse_info);
+ usb_legacy_register("usb-mouse", "mouse", NULL);
+ type_register_static(&usb_keyboard_info);
+ usb_legacy_register("usb-kbd", "keyboard", NULL);
}
device_init(usb_hid_register_devices)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index e195937..956b020 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -258,13 +258,6 @@
}
ret = 0;
break;
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* usb specific requests */
case GetHubStatus:
data[0] = 0;
@@ -540,23 +533,32 @@
}
};
-static struct USBDeviceInfo hub_info = {
- .product_desc = "QEMU USB Hub",
- .qdev.name = "usb-hub",
- .qdev.fw_name = "hub",
- .qdev.size = sizeof(USBHubState),
- .qdev.vmsd = &vmstate_usb_hub,
- .usb_desc = &desc_hub,
- .init = usb_hub_initfn,
- .handle_packet = usb_hub_handle_packet,
- .handle_reset = usb_hub_handle_reset,
- .handle_control = usb_hub_handle_control,
- .handle_data = usb_hub_handle_data,
- .handle_destroy = usb_hub_handle_destroy,
+static void usb_hub_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_hub_initfn;
+ uc->product_desc = "QEMU USB Hub";
+ uc->usb_desc = &desc_hub;
+ uc->handle_packet = usb_hub_handle_packet;
+ uc->handle_reset = usb_hub_handle_reset;
+ uc->handle_control = usb_hub_handle_control;
+ uc->handle_data = usb_hub_handle_data;
+ uc->handle_destroy = usb_hub_handle_destroy;
+ dc->fw_name = "hub";
+ dc->vmsd = &vmstate_usb_hub;
+}
+
+static TypeInfo hub_info = {
+ .name = "usb-hub",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHubState),
+ .class_init = usb_hub_class_initfn,
};
static void usb_hub_register_devices(void)
{
- usb_qdev_register(&hub_info);
+ type_register_static(&hub_info);
}
device_init(usb_hub_register_devices)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index e427296..6153376 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -306,19 +306,9 @@
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
ret = 0;
break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* Class specific requests. */
case ClassInterfaceOutRequest | MassStorageReset:
/* Reset state ready for the next CBW. */
@@ -646,32 +636,42 @@
}
};
-static struct USBDeviceInfo msd_info = {
- .product_desc = "QEMU USB MSD",
- .qdev.name = "usb-storage",
- .qdev.fw_name = "storage",
- .qdev.size = sizeof(MSDState),
- .qdev.vmsd = &vmstate_usb_msd,
- .usb_desc = &desc,
- .init = usb_msd_initfn,
- .handle_packet = usb_generic_handle_packet,
- .cancel_packet = usb_msd_cancel_io,
- .handle_attach = usb_desc_attach,
- .handle_reset = usb_msd_handle_reset,
- .handle_control = usb_msd_handle_control,
- .handle_data = usb_msd_handle_data,
- .usbdevice_name = "disk",
- .usbdevice_init = usb_msd_init,
- .qdev.props = (Property[]) {
- DEFINE_BLOCK_PROPERTIES(MSDState, conf),
- DEFINE_PROP_STRING("serial", MSDState, serial),
- DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property msd_properties[] = {
+ DEFINE_BLOCK_PROPERTIES(MSDState, conf),
+ DEFINE_PROP_STRING("serial", MSDState, serial),
+ DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_msd_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_msd_initfn;
+ uc->product_desc = "QEMU USB MSD";
+ uc->usb_desc = &desc;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->cancel_packet = usb_msd_cancel_io;
+ uc->handle_attach = usb_desc_attach;
+ uc->handle_reset = usb_msd_handle_reset;
+ uc->handle_control = usb_msd_handle_control;
+ uc->handle_data = usb_msd_handle_data;
+ dc->fw_name = "storage";
+ dc->vmsd = &vmstate_usb_msd;
+ dc->props = msd_properties;
+}
+
+static TypeInfo msd_info = {
+ .name = "usb-storage",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(MSDState),
+ .class_init = usb_msd_class_initfn,
};
static void usb_msd_register_devices(void)
{
- usb_qdev_register(&msd_info);
+ type_register_static(&msd_info);
+ usb_legacy_register("usb-storage", "disk", usb_msd_init);
}
device_init(usb_msd_register_devices)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 01e2e7c..4f528d2 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -812,7 +812,8 @@
for (ep = 0; ep < 16; ep++) {
for (dir = 0; dir < 2; dir++) {
- if (s->ep[ep].packey[dir].p.owner != dev) {
+ if (s->ep[ep].packey[dir].p.owner == NULL ||
+ s->ep[ep].packey[dir].p.owner->dev != dev) {
continue;
}
usb_cancel_packet(&s->ep[ep].packey[dir].p);
diff --git a/hw/usb-net.c b/hw/usb-net.c
index f91fa32..e211141 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -71,9 +71,6 @@
#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
-#define USB_DT_CS_INTERFACE 0x24
-#define USB_DT_CS_ENDPOINT 0x25
-
#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
#define USB_CDC_REQ_SET_LINE_CODING 0x20
@@ -1098,17 +1095,6 @@
#endif
break;
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
-
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
-
default:
fail:
fprintf(stderr, "usbnet: failed control transaction: "
@@ -1351,7 +1337,7 @@
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
- s->dev.qdev.info->name, s->dev.qdev.id, s);
+ object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
"%02x%02x%02x%02x%02x%02x",
@@ -1399,29 +1385,39 @@
.unmigratable = 1,
};
-static struct USBDeviceInfo net_info = {
- .product_desc = "QEMU USB Network Interface",
- .qdev.name = "usb-net",
- .qdev.fw_name = "network",
- .qdev.size = sizeof(USBNetState),
- .qdev.vmsd = &vmstate_usb_net,
- .usb_desc = &desc_net,
- .init = usb_net_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_net_handle_reset,
- .handle_control = usb_net_handle_control,
- .handle_data = usb_net_handle_data,
- .handle_destroy = usb_net_handle_destroy,
- .usbdevice_name = "net",
- .usbdevice_init = usb_net_init,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(USBNetState, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property net_properties[] = {
+ DEFINE_NIC_PROPERTIES(USBNetState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_net_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_net_initfn;
+ uc->product_desc = "QEMU USB Network Interface";
+ uc->usb_desc = &desc_net;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_net_handle_reset;
+ uc->handle_control = usb_net_handle_control;
+ uc->handle_data = usb_net_handle_data;
+ uc->handle_destroy = usb_net_handle_destroy;
+ dc->fw_name = "network";
+ dc->vmsd = &vmstate_usb_net;
+ dc->props = net_properties;
+}
+
+static TypeInfo net_info = {
+ .name = "usb-net",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBNetState),
+ .class_init = usb_net_class_initfn,
};
static void usb_net_register_devices(void)
{
- usb_qdev_register(&net_info);
+ type_register_static(&net_info);
+ usb_legacy_register("usb-net", "net", usb_net_init);
}
device_init(usb_net_register_devices)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 81488c4..425030f 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1707,7 +1707,9 @@
static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
{
- if (ohci->async_td && ohci->usb_packet.owner == dev) {
+ if (ohci->async_td &&
+ ohci->usb_packet.owner != NULL &&
+ ohci->usb_packet.owner->dev == dev) {
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
}
@@ -1775,7 +1777,7 @@
memory_region_init_io(&ohci->mem, &ohci_mem_ops, ohci, "ohci", 256);
ohci->localmem_base = localmem_base;
- ohci->name = dev->info->name;
+ ohci->name = object_get_typename(OBJECT(dev));
usb_packet_init(&ohci->usb_packet);
ohci->async_td = 0;
@@ -1834,37 +1836,59 @@
return 0;
}
-static PCIDeviceInfo ohci_pci_info = {
- .qdev.name = "pci-ohci",
- .qdev.desc = "Apple USB Controller",
- .qdev.size = sizeof(OHCIPCIState),
- .init = usb_ohci_initfn_pci,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_IPID_USB,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = (Property[]) {
- DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
- DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
- DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property ohci_pci_properties[] = {
+ DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
+ DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
+ DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo ohci_sysbus_info = {
- .init = ohci_init_pxa,
- .qdev.name = "sysbus-ohci",
- .qdev.desc = "OHCI USB Controller",
- .qdev.size = sizeof(OHCISysBusState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
- DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3),
- DEFINE_PROP_END_OF_LIST(),
- }
+static void ohci_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ohci_initfn_pci;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->desc = "Apple USB Controller";
+ dc->props = ohci_pci_properties;
+}
+
+static TypeInfo ohci_pci_info = {
+ .name = "pci-ohci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(OHCIPCIState),
+ .class_init = ohci_pci_class_init,
+};
+
+static Property ohci_sysbus_properties[] = {
+ DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
+ DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = ohci_init_pxa;
+ dc->desc = "OHCI USB Controller";
+ dc->props = ohci_sysbus_properties;
+}
+
+static TypeInfo ohci_sysbus_info = {
+ .name = "sysbus-ohci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(OHCISysBusState),
+ .class_init = ohci_sysbus_class_init,
};
static void ohci_register(void)
{
- pci_qdev_register(&ohci_pci_info);
- sysbus_register_withprop(&ohci_sysbus_info);
+ type_register_static(&ohci_pci_info);
+ type_register_static(&ohci_sysbus_info);
}
device_init(ohci_register);
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 7dbf6df..c2cb6d2 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -233,13 +233,6 @@
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
ret = 0;
break;
@@ -577,49 +570,69 @@
.unmigratable = 1,
};
-static struct USBDeviceInfo serial_info = {
- .product_desc = "QEMU USB Serial",
- .qdev.name = "usb-serial",
- .qdev.size = sizeof(USBSerialState),
- .qdev.vmsd = &vmstate_usb_serial,
- .usb_desc = &desc_serial,
- .init = usb_serial_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_serial_handle_reset,
- .handle_control = usb_serial_handle_control,
- .handle_data = usb_serial_handle_data,
- .handle_destroy = usb_serial_handle_destroy,
- .usbdevice_name = "serial",
- .usbdevice_init = usb_serial_init,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property serial_properties[] = {
+ DEFINE_PROP_CHR("chardev", USBSerialState, cs),
+ DEFINE_PROP_END_OF_LIST(),
};
-static struct USBDeviceInfo braille_info = {
- .product_desc = "QEMU USB Braille",
- .qdev.name = "usb-braille",
- .qdev.size = sizeof(USBSerialState),
- .qdev.vmsd = &vmstate_usb_serial,
- .usb_desc = &desc_braille,
- .init = usb_serial_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_serial_handle_reset,
- .handle_control = usb_serial_handle_control,
- .handle_data = usb_serial_handle_data,
- .handle_destroy = usb_serial_handle_destroy,
- .usbdevice_name = "braille",
- .usbdevice_init = usb_braille_init,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void usb_serial_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_serial_initfn;
+ uc->product_desc = "QEMU USB Serial";
+ uc->usb_desc = &desc_serial;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_serial_handle_reset;
+ uc->handle_control = usb_serial_handle_control;
+ uc->handle_data = usb_serial_handle_data;
+ uc->handle_destroy = usb_serial_handle_destroy;
+ dc->vmsd = &vmstate_usb_serial;
+ dc->props = serial_properties;
+}
+
+static TypeInfo serial_info = {
+ .name = "usb-serial",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBSerialState),
+ .class_init = usb_serial_class_initfn,
+};
+
+static Property braille_properties[] = {
+ DEFINE_PROP_CHR("chardev", USBSerialState, cs),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_braille_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_serial_initfn;
+ uc->product_desc = "QEMU USB Braille";
+ uc->usb_desc = &desc_braille;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_serial_handle_reset;
+ uc->handle_control = usb_serial_handle_control;
+ uc->handle_data = usb_serial_handle_data;
+ uc->handle_destroy = usb_serial_handle_destroy;
+ dc->vmsd = &vmstate_usb_serial;
+ dc->props = braille_properties;
+}
+
+static TypeInfo braille_info = {
+ .name = "usb-braille",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBSerialState),
+ .class_init = usb_braille_class_initfn,
};
static void usb_serial_register_devices(void)
{
- usb_qdev_register(&serial_info);
- usb_qdev_register(&braille_info);
+ type_register_static(&serial_info);
+ usb_legacy_register("usb-serial", "serial", usb_serial_init);
+ type_register_static(&braille_info);
+ usb_legacy_register("usb-braille", "braille", usb_braille_init);
}
device_init(usb_serial_register_devices)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index f8912e2..cddcc89 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -245,7 +245,8 @@
UHCIAsync *curr, *n;
QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
- if (curr->packet.owner != dev) {
+ if (curr->packet.owner == NULL ||
+ curr->packet.owner->dev != dev) {
continue;
}
uhci_async_unlink(s, curr);
@@ -1191,78 +1192,143 @@
DEFINE_PROP_END_OF_LIST(),
};
-static PCIDeviceInfo uhci_info[] = {
- {
- .qdev.name = "piix3-usb-uhci",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .exit = usb_uhci_exit,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
- .revision = 0x01,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "piix4-usb-uhci",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .exit = usb_uhci_exit,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
- .revision = 0x01,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "vt82c686b-usb-uhci",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_vt82c686b_initfn,
- .exit = usb_uhci_exit,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_UHCI,
- .revision = 0x01,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "ich9-usb-uhci1",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
- .revision = 0x03,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "ich9-usb-uhci2",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
- .revision = 0x03,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "ich9-usb-uhci3",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
- .revision = 0x03,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- /* end of list */
- }
+static void piix3_uhci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->exit = usb_uhci_exit;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_2;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo piix3_uhci_info = {
+ .name = "piix3-usb-uhci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = piix3_uhci_class_init,
+};
+
+static void piix4_uhci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->exit = usb_uhci_exit;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB_2;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo piix4_uhci_info = {
+ .name = "piix4-usb-uhci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = piix4_uhci_class_init,
+};
+
+static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_vt82c686b_initfn;
+ k->exit = usb_uhci_exit;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_UHCI;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo vt82c686b_uhci_info = {
+ .name = "vt82c686b-usb-uhci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = vt82c686b_uhci_class_init,
+};
+
+static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci1_info = {
+ .name = "ich9-usb-uhci1",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = ich9_uhci1_class_init,
+};
+
+static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci2_info = {
+ .name = "ich9-usb-uhci2",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = ich9_uhci2_class_init,
+};
+
+static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci3_info = {
+ .name = "ich9-usb-uhci3",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = ich9_uhci3_class_init,
};
static void uhci_register(void)
{
- pci_qdev_register_many(uhci_info);
+ type_register_static(&piix3_uhci_info);
+ type_register_static(&piix4_uhci_info);
+ type_register_static(&vt82c686b_uhci_info);
+ type_register_static(&ich9_uhci1_info);
+ type_register_static(&ich9_uhci2_info);
+ type_register_static(&ich9_uhci3_info);
}
device_init(uhci_register);
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 2558006..14de14d 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -263,13 +263,6 @@
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case WACOM_SET_REPORT:
if (s->mouse_grabbed) {
qemu_remove_mouse_event_handler(s->eh_entry);
@@ -356,24 +349,33 @@
.unmigratable = 1,
};
-static struct USBDeviceInfo wacom_info = {
- .product_desc = "QEMU PenPartner Tablet",
- .qdev.name = "usb-wacom-tablet",
- .qdev.desc = "QEMU PenPartner Tablet",
- .usbdevice_name = "wacom-tablet",
- .usb_desc = &desc_wacom,
- .qdev.size = sizeof(USBWacomState),
- .qdev.vmsd = &vmstate_usb_wacom,
- .init = usb_wacom_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_wacom_handle_reset,
- .handle_control = usb_wacom_handle_control,
- .handle_data = usb_wacom_handle_data,
- .handle_destroy = usb_wacom_handle_destroy,
+static void usb_wacom_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->product_desc = "QEMU PenPartner Tablet";
+ uc->usb_desc = &desc_wacom;
+ uc->init = usb_wacom_initfn;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_wacom_handle_reset;
+ uc->handle_control = usb_wacom_handle_control;
+ uc->handle_data = usb_wacom_handle_data;
+ uc->handle_destroy = usb_wacom_handle_destroy;
+ dc->desc = "QEMU PenPartner Tablet";
+ dc->vmsd = &vmstate_usb_wacom;
+}
+
+static TypeInfo wacom_info = {
+ .name = "usb-wacom-tablet",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBWacomState),
+ .class_init = usb_wacom_class_init,
};
static void usb_wacom_register_devices(void)
{
- usb_qdev_register(&wacom_info);
+ type_register_static(&wacom_info);
+ usb_legacy_register("usb-wacom-tablet", "wacom-tablet", NULL);
}
device_init(usb_wacom_register_devices)
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
new file mode 100644
index 0000000..37e887c
--- /dev/null
+++ b/hw/usb-xhci.c
@@ -0,0 +1,2759 @@
+/*
+ * USB xHCI controller emulation
+ *
+ * Copyright (c) 2011 Securiforest
+ * Date: 2011-05-11 ; Author: Hector Martin <hector@marcansoft.com>
+ * Based on usb-ohci.c, emulates Renesas NEC USB 3.0
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "pci.h"
+#include "qdev-addr.h"
+#include "msi.h"
+
+//#define DEBUG_XHCI
+//#define DEBUG_DATA
+
+#ifdef DEBUG_XHCI
+#define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DPRINTF(...) do {} while (0)
+#endif
+#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
+ __func__, __LINE__); abort(); } while (0)
+
+#define MAXSLOTS 8
+#define MAXINTRS 1
+
+#define USB2_PORTS 4
+#define USB3_PORTS 4
+
+#define MAXPORTS (USB2_PORTS+USB3_PORTS)
+
+#define TD_QUEUE 24
+#define BG_XFERS 8
+#define BG_PKTS 8
+
+/* Very pessimistic, let's hope it's enough for all cases */
+#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
+/* Do not deliver ER Full events. NEC's driver does some things not bound
+ * to the specs when it gets them */
+#define ER_FULL_HACK
+
+#define LEN_CAP 0x40
+#define OFF_OPER LEN_CAP
+#define LEN_OPER (0x400 + 0x10 * MAXPORTS)
+#define OFF_RUNTIME ((OFF_OPER + LEN_OPER + 0x20) & ~0x1f)
+#define LEN_RUNTIME (0x20 + MAXINTRS * 0x20)
+#define OFF_DOORBELL (OFF_RUNTIME + LEN_RUNTIME)
+#define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20)
+
+/* must be power of 2 */
+#define LEN_REGS 0x2000
+
+#if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS
+# error Increase LEN_REGS
+#endif
+
+#if MAXINTRS > 1
+# error TODO: only one interrupter supported
+#endif
+
+/* bit definitions */
+#define USBCMD_RS (1<<0)
+#define USBCMD_HCRST (1<<1)
+#define USBCMD_INTE (1<<2)
+#define USBCMD_HSEE (1<<3)
+#define USBCMD_LHCRST (1<<7)
+#define USBCMD_CSS (1<<8)
+#define USBCMD_CRS (1<<9)
+#define USBCMD_EWE (1<<10)
+#define USBCMD_EU3S (1<<11)
+
+#define USBSTS_HCH (1<<0)
+#define USBSTS_HSE (1<<2)
+#define USBSTS_EINT (1<<3)
+#define USBSTS_PCD (1<<4)
+#define USBSTS_SSS (1<<8)
+#define USBSTS_RSS (1<<9)
+#define USBSTS_SRE (1<<10)
+#define USBSTS_CNR (1<<11)
+#define USBSTS_HCE (1<<12)
+
+
+#define PORTSC_CCS (1<<0)
+#define PORTSC_PED (1<<1)
+#define PORTSC_OCA (1<<3)
+#define PORTSC_PR (1<<4)
+#define PORTSC_PLS_SHIFT 5
+#define PORTSC_PLS_MASK 0xf
+#define PORTSC_PP (1<<9)
+#define PORTSC_SPEED_SHIFT 10
+#define PORTSC_SPEED_MASK 0xf
+#define PORTSC_SPEED_FULL (1<<10)
+#define PORTSC_SPEED_LOW (2<<10)
+#define PORTSC_SPEED_HIGH (3<<10)
+#define PORTSC_SPEED_SUPER (4<<10)
+#define PORTSC_PIC_SHIFT 14
+#define PORTSC_PIC_MASK 0x3
+#define PORTSC_LWS (1<<16)
+#define PORTSC_CSC (1<<17)
+#define PORTSC_PEC (1<<18)
+#define PORTSC_WRC (1<<19)
+#define PORTSC_OCC (1<<20)
+#define PORTSC_PRC (1<<21)
+#define PORTSC_PLC (1<<22)
+#define PORTSC_CEC (1<<23)
+#define PORTSC_CAS (1<<24)
+#define PORTSC_WCE (1<<25)
+#define PORTSC_WDE (1<<26)
+#define PORTSC_WOE (1<<27)
+#define PORTSC_DR (1<<30)
+#define PORTSC_WPR (1<<31)
+
+#define CRCR_RCS (1<<0)
+#define CRCR_CS (1<<1)
+#define CRCR_CA (1<<2)
+#define CRCR_CRR (1<<3)
+
+#define IMAN_IP (1<<0)
+#define IMAN_IE (1<<1)
+
+#define ERDP_EHB (1<<3)
+
+#define TRB_SIZE 16
+typedef struct XHCITRB {
+ uint64_t parameter;
+ uint32_t status;
+ uint32_t control;
+ target_phys_addr_t addr;
+ bool ccs;
+} XHCITRB;
+
+
+typedef enum TRBType {
+ TRB_RESERVED = 0,
+ TR_NORMAL,
+ TR_SETUP,
+ TR_DATA,
+ TR_STATUS,
+ TR_ISOCH,
+ TR_LINK,
+ TR_EVDATA,
+ TR_NOOP,
+ CR_ENABLE_SLOT,
+ CR_DISABLE_SLOT,
+ CR_ADDRESS_DEVICE,
+ CR_CONFIGURE_ENDPOINT,
+ CR_EVALUATE_CONTEXT,
+ CR_RESET_ENDPOINT,
+ CR_STOP_ENDPOINT,
+ CR_SET_TR_DEQUEUE,
+ CR_RESET_DEVICE,
+ CR_FORCE_EVENT,
+ CR_NEGOTIATE_BW,
+ CR_SET_LATENCY_TOLERANCE,
+ CR_GET_PORT_BANDWIDTH,
+ CR_FORCE_HEADER,
+ CR_NOOP,
+ ER_TRANSFER = 32,
+ ER_COMMAND_COMPLETE,
+ ER_PORT_STATUS_CHANGE,
+ ER_BANDWIDTH_REQUEST,
+ ER_DOORBELL,
+ ER_HOST_CONTROLLER,
+ ER_DEVICE_NOTIFICATION,
+ ER_MFINDEX_WRAP,
+ /* vendor specific bits */
+ CR_VENDOR_VIA_CHALLENGE_RESPONSE = 48,
+ CR_VENDOR_NEC_FIRMWARE_REVISION = 49,
+ CR_VENDOR_NEC_CHALLENGE_RESPONSE = 50,
+} TRBType;
+
+#define CR_LINK TR_LINK
+
+typedef enum TRBCCode {
+ CC_INVALID = 0,
+ CC_SUCCESS,
+ CC_DATA_BUFFER_ERROR,
+ CC_BABBLE_DETECTED,
+ CC_USB_TRANSACTION_ERROR,
+ CC_TRB_ERROR,
+ CC_STALL_ERROR,
+ CC_RESOURCE_ERROR,
+ CC_BANDWIDTH_ERROR,
+ CC_NO_SLOTS_ERROR,
+ CC_INVALID_STREAM_TYPE_ERROR,
+ CC_SLOT_NOT_ENABLED_ERROR,
+ CC_EP_NOT_ENABLED_ERROR,
+ CC_SHORT_PACKET,
+ CC_RING_UNDERRUN,
+ CC_RING_OVERRUN,
+ CC_VF_ER_FULL,
+ CC_PARAMETER_ERROR,
+ CC_BANDWIDTH_OVERRUN,
+ CC_CONTEXT_STATE_ERROR,
+ CC_NO_PING_RESPONSE_ERROR,
+ CC_EVENT_RING_FULL_ERROR,
+ CC_INCOMPATIBLE_DEVICE_ERROR,
+ CC_MISSED_SERVICE_ERROR,
+ CC_COMMAND_RING_STOPPED,
+ CC_COMMAND_ABORTED,
+ CC_STOPPED,
+ CC_STOPPED_LENGTH_INVALID,
+ CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
+ CC_ISOCH_BUFFER_OVERRUN = 31,
+ CC_EVENT_LOST_ERROR,
+ CC_UNDEFINED_ERROR,
+ CC_INVALID_STREAM_ID_ERROR,
+ CC_SECONDARY_BANDWIDTH_ERROR,
+ CC_SPLIT_TRANSACTION_ERROR
+} TRBCCode;
+
+#define TRB_C (1<<0)
+#define TRB_TYPE_SHIFT 10
+#define TRB_TYPE_MASK 0x3f
+#define TRB_TYPE(t) (((t).control >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK)
+
+#define TRB_EV_ED (1<<2)
+
+#define TRB_TR_ENT (1<<1)
+#define TRB_TR_ISP (1<<2)
+#define TRB_TR_NS (1<<3)
+#define TRB_TR_CH (1<<4)
+#define TRB_TR_IOC (1<<5)
+#define TRB_TR_IDT (1<<6)
+#define TRB_TR_TBC_SHIFT 7
+#define TRB_TR_TBC_MASK 0x3
+#define TRB_TR_BEI (1<<9)
+#define TRB_TR_TLBPC_SHIFT 16
+#define TRB_TR_TLBPC_MASK 0xf
+#define TRB_TR_FRAMEID_SHIFT 20
+#define TRB_TR_FRAMEID_MASK 0x7ff
+#define TRB_TR_SIA (1<<31)
+
+#define TRB_TR_DIR (1<<16)
+
+#define TRB_CR_SLOTID_SHIFT 24
+#define TRB_CR_SLOTID_MASK 0xff
+#define TRB_CR_EPID_SHIFT 16
+#define TRB_CR_EPID_MASK 0x1f
+
+#define TRB_CR_BSR (1<<9)
+#define TRB_CR_DC (1<<9)
+
+#define TRB_LK_TC (1<<1)
+
+#define EP_TYPE_MASK 0x7
+#define EP_TYPE_SHIFT 3
+
+#define EP_STATE_MASK 0x7
+#define EP_DISABLED (0<<0)
+#define EP_RUNNING (1<<0)
+#define EP_HALTED (2<<0)
+#define EP_STOPPED (3<<0)
+#define EP_ERROR (4<<0)
+
+#define SLOT_STATE_MASK 0x1f
+#define SLOT_STATE_SHIFT 27
+#define SLOT_STATE(s) (((s)>>SLOT_STATE_SHIFT)&SLOT_STATE_MASK)
+#define SLOT_ENABLED 0
+#define SLOT_DEFAULT 1
+#define SLOT_ADDRESSED 2
+#define SLOT_CONFIGURED 3
+
+#define SLOT_CONTEXT_ENTRIES_MASK 0x1f
+#define SLOT_CONTEXT_ENTRIES_SHIFT 27
+
+typedef enum EPType {
+ ET_INVALID = 0,
+ ET_ISO_OUT,
+ ET_BULK_OUT,
+ ET_INTR_OUT,
+ ET_CONTROL,
+ ET_ISO_IN,
+ ET_BULK_IN,
+ ET_INTR_IN,
+} EPType;
+
+typedef struct XHCIRing {
+ target_phys_addr_t base;
+ target_phys_addr_t dequeue;
+ bool ccs;
+} XHCIRing;
+
+typedef struct XHCIPort {
+ USBPort port;
+ uint32_t portsc;
+} XHCIPort;
+
+struct XHCIState;
+typedef struct XHCIState XHCIState;
+
+typedef struct XHCITransfer {
+ XHCIState *xhci;
+ USBPacket packet;
+ bool running;
+ bool cancelled;
+ bool complete;
+ bool backgrounded;
+ unsigned int iso_pkts;
+ unsigned int slotid;
+ unsigned int epid;
+ bool in_xfer;
+ bool iso_xfer;
+ bool bg_xfer;
+
+ unsigned int trb_count;
+ unsigned int trb_alloced;
+ XHCITRB *trbs;
+
+ unsigned int data_length;
+ unsigned int data_alloced;
+ uint8_t *data;
+
+ TRBCCode status;
+
+ unsigned int pkts;
+ unsigned int pktsize;
+ unsigned int cur_pkt;
+} XHCITransfer;
+
+typedef struct XHCIEPContext {
+ XHCIRing ring;
+ unsigned int next_xfer;
+ unsigned int comp_xfer;
+ XHCITransfer transfers[TD_QUEUE];
+ bool bg_running;
+ bool bg_updating;
+ unsigned int next_bg;
+ XHCITransfer bg_transfers[BG_XFERS];
+ EPType type;
+ target_phys_addr_t pctx;
+ unsigned int max_psize;
+ bool has_bg;
+ uint32_t state;
+} XHCIEPContext;
+
+typedef struct XHCISlot {
+ bool enabled;
+ target_phys_addr_t ctx;
+ unsigned int port;
+ unsigned int devaddr;
+ XHCIEPContext * eps[31];
+} XHCISlot;
+
+typedef struct XHCIEvent {
+ TRBType type;
+ TRBCCode ccode;
+ uint64_t ptr;
+ uint32_t length;
+ uint32_t flags;
+ uint8_t slotid;
+ uint8_t epid;
+} XHCIEvent;
+
+struct XHCIState {
+ PCIDevice pci_dev;
+ USBBus bus;
+ qemu_irq irq;
+ MemoryRegion mem;
+ const char *name;
+ uint32_t msi;
+ unsigned int devaddr;
+
+ /* Operational Registers */
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ uint32_t dnctrl;
+ uint32_t crcr_low;
+ uint32_t crcr_high;
+ uint32_t dcbaap_low;
+ uint32_t dcbaap_high;
+ uint32_t config;
+
+ XHCIPort ports[MAXPORTS];
+ XHCISlot slots[MAXSLOTS];
+
+ /* Runtime Registers */
+ uint32_t mfindex;
+ /* note: we only support one interrupter */
+ uint32_t iman;
+ uint32_t imod;
+ uint32_t erstsz;
+ uint32_t erstba_low;
+ uint32_t erstba_high;
+ uint32_t erdp_low;
+ uint32_t erdp_high;
+
+ target_phys_addr_t er_start;
+ uint32_t er_size;
+ bool er_pcs;
+ unsigned int er_ep_idx;
+ bool er_full;
+
+ XHCIEvent ev_buffer[EV_QUEUE];
+ unsigned int ev_buffer_put;
+ unsigned int ev_buffer_get;
+
+ XHCIRing cmd_ring;
+};
+
+typedef struct XHCIEvRingSeg {
+ uint32_t addr_low;
+ uint32_t addr_high;
+ uint32_t size;
+ uint32_t rsvd;
+} XHCIEvRingSeg;
+
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid);
+
+static inline target_phys_addr_t xhci_addr64(uint32_t low, uint32_t high)
+{
+#if TARGET_PHYS_ADDR_BITS > 32
+ return low | ((target_phys_addr_t)high << 32);
+#else
+ return low;
+#endif
+}
+
+static inline target_phys_addr_t xhci_mask64(uint64_t addr)
+{
+#if TARGET_PHYS_ADDR_BITS > 32
+ return addr;
+#else
+ return addr & 0xffffffff;
+#endif
+}
+
+static void xhci_irq_update(XHCIState *xhci)
+{
+ int level = 0;
+
+ if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE &&
+ xhci->usbcmd && USBCMD_INTE) {
+ level = 1;
+ }
+
+ DPRINTF("xhci_irq_update(): %d\n", level);
+
+ if (xhci->msi && msi_enabled(&xhci->pci_dev)) {
+ if (level) {
+ DPRINTF("xhci_irq_update(): MSI signal\n");
+ msi_notify(&xhci->pci_dev, 0);
+ }
+ } else {
+ qemu_set_irq(xhci->irq, level);
+ }
+}
+
+static inline int xhci_running(XHCIState *xhci)
+{
+ return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full;
+}
+
+static void xhci_die(XHCIState *xhci)
+{
+ xhci->usbsts |= USBSTS_HCE;
+ fprintf(stderr, "xhci: asserted controller error\n");
+}
+
+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
+{
+ XHCITRB ev_trb;
+ target_phys_addr_t addr;
+
+ ev_trb.parameter = cpu_to_le64(event->ptr);
+ ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24));
+ ev_trb.control = (event->slotid << 24) | (event->epid << 16) |
+ event->flags | (event->type << TRB_TYPE_SHIFT);
+ if (xhci->er_pcs) {
+ ev_trb.control |= TRB_C;
+ }
+ ev_trb.control = cpu_to_le32(ev_trb.control);
+
+ DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x\n",
+ xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control);
+
+ addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
+ cpu_physical_memory_write(addr, (uint8_t *) &ev_trb, TRB_SIZE);
+
+ xhci->er_ep_idx++;
+ if (xhci->er_ep_idx >= xhci->er_size) {
+ xhci->er_ep_idx = 0;
+ xhci->er_pcs = !xhci->er_pcs;
+ }
+}
+
+static void xhci_events_update(XHCIState *xhci)
+{
+ target_phys_addr_t erdp;
+ unsigned int dp_idx;
+ bool do_irq = 0;
+
+ if (xhci->usbsts & USBSTS_HCH) {
+ return;
+ }
+
+ erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
+ if (erdp < xhci->er_start ||
+ erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
+ fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp);
+ fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n",
+ xhci->er_start, xhci->er_size);
+ xhci_die(xhci);
+ return;
+ }
+ dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
+ assert(dp_idx < xhci->er_size);
+
+ /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus
+ * deadlocks when the ER is full. Hack it by holding off events until
+ * the driver decides to free at least half of the ring */
+ if (xhci->er_full) {
+ int er_free = dp_idx - xhci->er_ep_idx;
+ if (er_free <= 0) {
+ er_free += xhci->er_size;
+ }
+ if (er_free < (xhci->er_size/2)) {
+ DPRINTF("xhci_events_update(): event ring still "
+ "more than half full (hack)\n");
+ return;
+ }
+ }
+
+ while (xhci->ev_buffer_put != xhci->ev_buffer_get) {
+ assert(xhci->er_full);
+ if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) {
+ DPRINTF("xhci_events_update(): event ring full again\n");
+#ifndef ER_FULL_HACK
+ XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
+ xhci_write_event(xhci, &full);
+#endif
+ do_irq = 1;
+ break;
+ }
+ XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get];
+ xhci_write_event(xhci, event);
+ xhci->ev_buffer_get++;
+ do_irq = 1;
+ if (xhci->ev_buffer_get == EV_QUEUE) {
+ xhci->ev_buffer_get = 0;
+ }
+ }
+
+ if (do_irq) {
+ xhci->erdp_low |= ERDP_EHB;
+ xhci->iman |= IMAN_IP;
+ xhci->usbsts |= USBSTS_EINT;
+ xhci_irq_update(xhci);
+ }
+
+ if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) {
+ DPRINTF("xhci_events_update(): event ring no longer full\n");
+ xhci->er_full = 0;
+ }
+ return;
+}
+
+static void xhci_event(XHCIState *xhci, XHCIEvent *event)
+{
+ target_phys_addr_t erdp;
+ unsigned int dp_idx;
+
+ if (xhci->er_full) {
+ DPRINTF("xhci_event(): ER full, queueing\n");
+ if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
+ fprintf(stderr, "xhci: event queue full, dropping event!\n");
+ return;
+ }
+ xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
+ if (xhci->ev_buffer_put == EV_QUEUE) {
+ xhci->ev_buffer_put = 0;
+ }
+ return;
+ }
+
+ erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
+ if (erdp < xhci->er_start ||
+ erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
+ fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp);
+ fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n",
+ xhci->er_start, xhci->er_size);
+ xhci_die(xhci);
+ return;
+ }
+
+ dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
+ assert(dp_idx < xhci->er_size);
+
+ if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) {
+ DPRINTF("xhci_event(): ER full, queueing\n");
+#ifndef ER_FULL_HACK
+ XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
+ xhci_write_event(xhci, &full);
+#endif
+ xhci->er_full = 1;
+ if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
+ fprintf(stderr, "xhci: event queue full, dropping event!\n");
+ return;
+ }
+ xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
+ if (xhci->ev_buffer_put == EV_QUEUE) {
+ xhci->ev_buffer_put = 0;
+ }
+ } else {
+ xhci_write_event(xhci, event);
+ }
+
+ xhci->erdp_low |= ERDP_EHB;
+ xhci->iman |= IMAN_IP;
+ xhci->usbsts |= USBSTS_EINT;
+
+ xhci_irq_update(xhci);
+}
+
+static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
+ target_phys_addr_t base)
+{
+ ring->base = base;
+ ring->dequeue = base;
+ ring->ccs = 1;
+}
+
+static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
+ target_phys_addr_t *addr)
+{
+ while (1) {
+ TRBType type;
+ cpu_physical_memory_read(ring->dequeue, (uint8_t *) trb, TRB_SIZE);
+ trb->addr = ring->dequeue;
+ trb->ccs = ring->ccs;
+ le64_to_cpus(&trb->parameter);
+ le32_to_cpus(&trb->status);
+ le32_to_cpus(&trb->control);
+
+ DPRINTF("xhci: TRB fetched [" TARGET_FMT_plx "]: "
+ "%016" PRIx64 " %08x %08x\n",
+ ring->dequeue, trb->parameter, trb->status, trb->control);
+
+ if ((trb->control & TRB_C) != ring->ccs) {
+ return 0;
+ }
+
+ type = TRB_TYPE(*trb);
+
+ if (type != TR_LINK) {
+ if (addr) {
+ *addr = ring->dequeue;
+ }
+ ring->dequeue += TRB_SIZE;
+ return type;
+ } else {
+ ring->dequeue = xhci_mask64(trb->parameter);
+ if (trb->control & TRB_LK_TC) {
+ ring->ccs = !ring->ccs;
+ }
+ }
+ }
+}
+
+static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
+{
+ XHCITRB trb;
+ int length = 0;
+ target_phys_addr_t dequeue = ring->dequeue;
+ bool ccs = ring->ccs;
+ /* hack to bundle together the two/three TDs that make a setup transfer */
+ bool control_td_set = 0;
+
+ while (1) {
+ TRBType type;
+ cpu_physical_memory_read(dequeue, (uint8_t *) &trb, TRB_SIZE);
+ le64_to_cpus(&trb.parameter);
+ le32_to_cpus(&trb.status);
+ le32_to_cpus(&trb.control);
+
+ DPRINTF("xhci: TRB peeked [" TARGET_FMT_plx "]: "
+ "%016" PRIx64 " %08x %08x\n",
+ dequeue, trb.parameter, trb.status, trb.control);
+
+ if ((trb.control & TRB_C) != ccs) {
+ return -length;
+ }
+
+ type = TRB_TYPE(trb);
+
+ if (type == TR_LINK) {
+ dequeue = xhci_mask64(trb.parameter);
+ if (trb.control & TRB_LK_TC) {
+ ccs = !ccs;
+ }
+ continue;
+ }
+
+ length += 1;
+ dequeue += TRB_SIZE;
+
+ if (type == TR_SETUP) {
+ control_td_set = 1;
+ } else if (type == TR_STATUS) {
+ control_td_set = 0;
+ }
+
+ if (!control_td_set && !(trb.control & TRB_TR_CH)) {
+ return length;
+ }
+ }
+}
+
+static void xhci_er_reset(XHCIState *xhci)
+{
+ XHCIEvRingSeg seg;
+
+ /* cache the (sole) event ring segment location */
+ if (xhci->erstsz != 1) {
+ fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz);
+ xhci_die(xhci);
+ return;
+ }
+ target_phys_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high);
+ cpu_physical_memory_read(erstba, (uint8_t *) &seg, sizeof(seg));
+ le32_to_cpus(&seg.addr_low);
+ le32_to_cpus(&seg.addr_high);
+ le32_to_cpus(&seg.size);
+ if (seg.size < 16 || seg.size > 4096) {
+ fprintf(stderr, "xhci: invalid value for segment size: %d\n", seg.size);
+ xhci_die(xhci);
+ return;
+ }
+ xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
+ xhci->er_size = seg.size;
+
+ xhci->er_ep_idx = 0;
+ xhci->er_pcs = 1;
+ xhci->er_full = 0;
+
+ DPRINTF("xhci: event ring:" TARGET_FMT_plx " [%d]\n",
+ xhci->er_start, xhci->er_size);
+}
+
+static void xhci_run(XHCIState *xhci)
+{
+ DPRINTF("xhci_run()\n");
+
+ xhci->usbsts &= ~USBSTS_HCH;
+}
+
+static void xhci_stop(XHCIState *xhci)
+{
+ DPRINTF("xhci_stop()\n");
+ xhci->usbsts |= USBSTS_HCH;
+ xhci->crcr_low &= ~CRCR_CRR;
+}
+
+static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
+ uint32_t state)
+{
+ uint32_t ctx[5];
+ if (epctx->state == state) {
+ return;
+ }
+
+ cpu_physical_memory_read(epctx->pctx, (uint8_t *) ctx, sizeof(ctx));
+ ctx[0] &= ~EP_STATE_MASK;
+ ctx[0] |= state;
+ ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
+ ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
+ DPRINTF("xhci: set epctx: " TARGET_FMT_plx " state=%d dequeue=%08x%08x\n",
+ epctx->pctx, state, ctx[3], ctx[2]);
+ cpu_physical_memory_write(epctx->pctx, (uint8_t *) ctx, sizeof(ctx));
+ epctx->state = state;
+}
+
+static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid, target_phys_addr_t pctx,
+ uint32_t *ctx)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+ target_phys_addr_t dequeue;
+ int i;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ assert(epid >= 1 && epid <= 31);
+
+ DPRINTF("xhci_enable_ep(%d, %d)\n", slotid, epid);
+
+ slot = &xhci->slots[slotid-1];
+ if (slot->eps[epid-1]) {
+ fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid);
+ return CC_TRB_ERROR;
+ }
+
+ epctx = g_malloc(sizeof(XHCIEPContext));
+ memset(epctx, 0, sizeof(XHCIEPContext));
+
+ slot->eps[epid-1] = epctx;
+
+ dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
+ xhci_ring_init(xhci, &epctx->ring, dequeue);
+ epctx->ring.ccs = ctx[2] & 1;
+
+ epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
+ DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type);
+ epctx->pctx = pctx;
+ epctx->max_psize = ctx[1]>>16;
+ epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
+ epctx->has_bg = false;
+ if (epctx->type == ET_ISO_IN) {
+ epctx->has_bg = true;
+ }
+ DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
+ epid/2, epid%2, epctx->max_psize);
+ for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
+ usb_packet_init(&epctx->transfers[i].packet);
+ }
+
+ epctx->state = EP_RUNNING;
+ ctx[0] &= ~EP_STATE_MASK;
+ ctx[0] |= EP_RUNNING;
+
+ return CC_SUCCESS;
+}
+
+static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+ int i, xferi, killed = 0;
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ assert(epid >= 1 && epid <= 31);
+
+ DPRINTF("xhci_ep_nuke_xfers(%d, %d)\n", slotid, epid);
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ return 0;
+ }
+
+ epctx = slot->eps[epid-1];
+
+ xferi = epctx->next_xfer;
+ for (i = 0; i < TD_QUEUE; i++) {
+ XHCITransfer *t = &epctx->transfers[xferi];
+ if (t->running) {
+ t->cancelled = 1;
+ /* libusb_cancel_transfer(t->usbxfer) */
+ DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i);
+ killed++;
+ }
+ if (t->backgrounded) {
+ t->backgrounded = 0;
+ }
+ if (t->trbs) {
+ g_free(t->trbs);
+ }
+ if (t->data) {
+ g_free(t->data);
+ }
+
+ t->trbs = NULL;
+ t->data = NULL;
+ t->trb_count = t->trb_alloced = 0;
+ t->data_length = t->data_alloced = 0;
+ xferi = (xferi + 1) % TD_QUEUE;
+ }
+ if (epctx->has_bg) {
+ xferi = epctx->next_bg;
+ for (i = 0; i < BG_XFERS; i++) {
+ XHCITransfer *t = &epctx->bg_transfers[xferi];
+ if (t->running) {
+ t->cancelled = 1;
+ /* libusb_cancel_transfer(t->usbxfer); */
+ DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i);
+ killed++;
+ }
+ if (t->data) {
+ g_free(t->data);
+ }
+
+ t->data = NULL;
+ xferi = (xferi + 1) % BG_XFERS;
+ }
+ }
+ return killed;
+}
+
+static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ assert(epid >= 1 && epid <= 31);
+
+ DPRINTF("xhci_disable_ep(%d, %d)\n", slotid, epid);
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ DPRINTF("xhci: slot %d ep %d already disabled\n", slotid, epid);
+ return CC_SUCCESS;
+ }
+
+ xhci_ep_nuke_xfers(xhci, slotid, epid);
+
+ epctx = slot->eps[epid-1];
+
+ xhci_set_ep_state(xhci, epctx, EP_DISABLED);
+
+ g_free(epctx);
+ slot->eps[epid-1] = NULL;
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+
+ DPRINTF("xhci_stop_ep(%d, %d)\n", slotid, epid);
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+ if (epid < 1 || epid > 31) {
+ fprintf(stderr, "xhci: bad ep %d\n", epid);
+ return CC_TRB_ERROR;
+ }
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+ return CC_EP_NOT_ENABLED_ERROR;
+ }
+
+ if (xhci_ep_nuke_xfers(xhci, slotid, epid) > 0) {
+ fprintf(stderr, "xhci: FIXME: endpoint stopped w/ xfers running, "
+ "data might be lost\n");
+ }
+
+ epctx = slot->eps[epid-1];
+
+ xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+ USBDevice *dev;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+ DPRINTF("xhci_reset_ep(%d, %d)\n", slotid, epid);
+
+ if (epid < 1 || epid > 31) {
+ fprintf(stderr, "xhci: bad ep %d\n", epid);
+ return CC_TRB_ERROR;
+ }
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+ return CC_EP_NOT_ENABLED_ERROR;
+ }
+
+ epctx = slot->eps[epid-1];
+
+ if (epctx->state != EP_HALTED) {
+ fprintf(stderr, "xhci: reset EP while EP %d not halted (%d)\n",
+ epid, epctx->state);
+ return CC_CONTEXT_STATE_ERROR;
+ }
+
+ if (xhci_ep_nuke_xfers(xhci, slotid, epid) > 0) {
+ fprintf(stderr, "xhci: FIXME: endpoint reset w/ xfers running, "
+ "data might be lost\n");
+ }
+
+ uint8_t ep = epid>>1;
+
+ if (epid & 1) {
+ ep |= 0x80;
+ }
+
+ dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev;
+ if (!dev) {
+ return CC_USB_TRANSACTION_ERROR;
+ }
+
+ xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid, uint64_t pdequeue)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+ target_phys_addr_t dequeue;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+ if (epid < 1 || epid > 31) {
+ fprintf(stderr, "xhci: bad ep %d\n", epid);
+ return CC_TRB_ERROR;
+ }
+
+ DPRINTF("xhci_set_ep_dequeue(%d, %d, %016"PRIx64")\n", slotid, epid, pdequeue);
+ dequeue = xhci_mask64(pdequeue);
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+ return CC_EP_NOT_ENABLED_ERROR;
+ }
+
+ epctx = slot->eps[epid-1];
+
+
+ if (epctx->state != EP_STOPPED) {
+ fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
+ return CC_CONTEXT_STATE_ERROR;
+ }
+
+ xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
+ epctx->ring.ccs = dequeue & 1;
+
+ xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+ return CC_SUCCESS;
+}
+
+static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
+ unsigned int length, bool in_xfer, bool out_xfer,
+ bool report)
+{
+ int i;
+ uint32_t edtla = 0;
+ unsigned int transferred = 0;
+ unsigned int left = length;
+ bool reported = 0;
+ bool shortpkt = 0;
+ XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
+ XHCIState *xhci = xfer->xhci;
+
+ DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n",
+ length, in_xfer, out_xfer, report);
+
+ assert(!(in_xfer && out_xfer));
+
+ for (i = 0; i < xfer->trb_count; i++) {
+ XHCITRB *trb = &xfer->trbs[i];
+ target_phys_addr_t addr;
+ unsigned int chunk = 0;
+
+ switch (TRB_TYPE(*trb)) {
+ case TR_DATA:
+ if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
+ fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
+ xhci_die(xhci);
+ return transferred;
+ }
+ /* fallthrough */
+ case TR_NORMAL:
+ case TR_ISOCH:
+ addr = xhci_mask64(trb->parameter);
+ chunk = trb->status & 0x1ffff;
+ if (chunk > left) {
+ chunk = left;
+ shortpkt = 1;
+ }
+ if (in_xfer || out_xfer) {
+ if (trb->control & TRB_TR_IDT) {
+ uint64_t idata;
+ if (chunk > 8 || in_xfer) {
+ fprintf(stderr, "xhci: invalid immediate data TRB\n");
+ xhci_die(xhci);
+ return transferred;
+ }
+ idata = le64_to_cpu(trb->parameter);
+ memcpy(data, &idata, chunk);
+ } else {
+ DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at "
+ TARGET_FMT_plx "\n", in_xfer, chunk, addr);
+ if (in_xfer) {
+ cpu_physical_memory_write(addr, data, chunk);
+ } else {
+ cpu_physical_memory_read(addr, data, chunk);
+ }
+#ifdef DEBUG_DATA
+ unsigned int count = chunk;
+ int i;
+ if (count > 16) {
+ count = 16;
+ }
+ DPRINTF(" ::");
+ for (i = 0; i < count; i++) {
+ DPRINTF(" %02x", data[i]);
+ }
+ DPRINTF("\n");
+#endif
+ }
+ }
+ left -= chunk;
+ data += chunk;
+ edtla += chunk;
+ transferred += chunk;
+ break;
+ case TR_STATUS:
+ reported = 0;
+ shortpkt = 0;
+ break;
+ }
+
+ if (report && !reported && (trb->control & TRB_TR_IOC ||
+ (shortpkt && (trb->control & TRB_TR_ISP)))) {
+ event.slotid = xfer->slotid;
+ event.epid = xfer->epid;
+ event.length = (trb->status & 0x1ffff) - chunk;
+ event.flags = 0;
+ event.ptr = trb->addr;
+ if (xfer->status == CC_SUCCESS) {
+ event.ccode = shortpkt ? CC_SHORT_PACKET : CC_SUCCESS;
+ } else {
+ event.ccode = xfer->status;
+ }
+ if (TRB_TYPE(*trb) == TR_EVDATA) {
+ event.ptr = trb->parameter;
+ event.flags |= TRB_EV_ED;
+ event.length = edtla & 0xffffff;
+ DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length);
+ edtla = 0;
+ }
+ xhci_event(xhci, &event);
+ reported = 1;
+ }
+ }
+ return transferred;
+}
+
+static void xhci_stall_ep(XHCITransfer *xfer)
+{
+ XHCIState *xhci = xfer->xhci;
+ XHCISlot *slot = &xhci->slots[xfer->slotid-1];
+ XHCIEPContext *epctx = slot->eps[xfer->epid-1];
+
+ epctx->ring.dequeue = xfer->trbs[0].addr;
+ epctx->ring.ccs = xfer->trbs[0].ccs;
+ xhci_set_ep_state(xhci, epctx, EP_HALTED);
+ DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid);
+ DPRINTF("xhci: will continue at "TARGET_FMT_plx"\n", epctx->ring.dequeue);
+}
+
+static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
+ XHCIEPContext *epctx);
+
+static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx)
+{
+ if (epctx->bg_updating) {
+ return;
+ }
+ DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx);
+ assert(epctx->has_bg);
+ DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg);
+ epctx->bg_updating = 1;
+ while (epctx->transfers[epctx->comp_xfer].backgrounded &&
+ epctx->bg_transfers[epctx->next_bg].complete) {
+ XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer];
+ XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg];
+#if 0
+ DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n",
+ epctx->comp_xfer, epctx->next_bg, bg->cur_pkt,
+ bg->usbxfer->iso_packet_desc[bg->cur_pkt].status
+ );
+#endif
+ assert(epctx->type == ET_ISO_IN);
+ assert(bg->iso_xfer);
+ assert(bg->in_xfer);
+ uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize;
+#if 0
+ int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length;
+ fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status);
+#else
+ int len = 0;
+ FIXME();
+#endif
+ fg->complete = 1;
+ fg->backgrounded = 0;
+
+ if (fg->status == CC_STALL_ERROR) {
+ xhci_stall_ep(fg);
+ }
+
+ xhci_xfer_data(fg, p, len, 1, 0, 1);
+
+ epctx->comp_xfer++;
+ if (epctx->comp_xfer == TD_QUEUE) {
+ epctx->comp_xfer = 0;
+ }
+ DPRINTF("next fg xfer: %d\n", epctx->comp_xfer);
+ bg->cur_pkt++;
+ if (bg->cur_pkt == bg->pkts) {
+ bg->complete = 0;
+ if (xhci_submit(xhci, bg, epctx) < 0) {
+ fprintf(stderr, "xhci: bg resubmit failed\n");
+ }
+ epctx->next_bg++;
+ if (epctx->next_bg == BG_XFERS) {
+ epctx->next_bg = 0;
+ }
+ DPRINTF("next bg xfer: %d\n", epctx->next_bg);
+
+ xhci_kick_ep(xhci, fg->slotid, fg->epid);
+ }
+ }
+ epctx->bg_updating = 0;
+}
+
+#if 0
+static void xhci_xfer_cb(struct libusb_transfer *transfer)
+{
+ XHCIState *xhci;
+ XHCITransfer *xfer;
+
+ xfer = (XHCITransfer *)transfer->user_data;
+ xhci = xfer->xhci;
+
+ DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid,
+ xfer->epid, transfer->status);
+
+ assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS);
+ assert(xfer->epid >= 1 && xfer->epid <= 31);
+
+ if (xfer->cancelled) {
+ DPRINTF("xhci: transfer cancelled, not reporting anything\n");
+ xfer->running = 0;
+ return;
+ }
+
+ XHCIEPContext *epctx;
+ XHCISlot *slot;
+ slot = &xhci->slots[xfer->slotid-1];
+ assert(slot->eps[xfer->epid-1]);
+ epctx = slot->eps[xfer->epid-1];
+
+ if (xfer->bg_xfer) {
+ DPRINTF("xhci: background transfer, updating\n");
+ xfer->complete = 1;
+ xfer->running = 0;
+ xhci_bg_update(xhci, epctx);
+ return;
+ }
+
+ if (xfer->iso_xfer) {
+ transfer->status = transfer->iso_packet_desc[0].status;
+ transfer->actual_length = transfer->iso_packet_desc[0].actual_length;
+ }
+
+ xfer->status = libusb_to_ccode(transfer->status);
+
+ xfer->complete = 1;
+ xfer->running = 0;
+
+ if (transfer->status == LIBUSB_TRANSFER_STALL)
+ xhci_stall_ep(xhci, epctx, xfer);
+
+ DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length);
+
+ if (xfer->in_xfer) {
+ if (xfer->epid == 1) {
+ xhci_xfer_data(xhci, xfer, xfer->data + 8,
+ transfer->actual_length, 1, 0, 1);
+ } else {
+ xhci_xfer_data(xhci, xfer, xfer->data,
+ transfer->actual_length, 1, 0, 1);
+ }
+ } else {
+ xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1);
+ }
+
+ xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+}
+
+static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer,
+ uint8_t bmRequestType, uint8_t bRequest,
+ uint16_t wValue, uint16_t wIndex, uint16_t wLength)
+{
+ uint16_t type_req = (bmRequestType << 8) | bRequest;
+
+ switch (type_req) {
+ case 0x0000 | USB_REQ_SET_CONFIGURATION:
+ DPRINTF("xhci: HLE switch configuration\n");
+ return xhci_switch_config(xhci, xfer->slotid, wValue) == 0;
+ case 0x0100 | USB_REQ_SET_INTERFACE:
+ DPRINTF("xhci: HLE set interface altsetting\n");
+ return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0;
+ case 0x0200 | USB_REQ_CLEAR_FEATURE:
+ if (wValue == 0) { // endpoint halt
+ DPRINTF("xhci: HLE clear halt\n");
+ return xhci_clear_halt(xhci, xfer->slotid, wIndex);
+ }
+ case 0x0000 | USB_REQ_SET_ADDRESS:
+ fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n");
+ return 0;
+ default:
+ return 0;
+ }
+}
+#endif
+
+static int xhci_setup_packet(XHCITransfer *xfer, XHCIPort *port, int ep)
+{
+ usb_packet_setup(&xfer->packet,
+ xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT,
+ xfer->xhci->slots[xfer->slotid-1].devaddr,
+ ep & 0x7f);
+ usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
+ DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
+ xfer->packet.pid, xfer->packet.devaddr, xfer->packet.devep);
+ return 0;
+}
+
+static int xhci_complete_packet(XHCITransfer *xfer, int ret)
+{
+ if (ret == USB_RET_ASYNC) {
+ xfer->running = 1;
+ xfer->complete = 0;
+ xfer->cancelled = 0;
+ return 0;
+ } else {
+ xfer->running = 0;
+ xfer->complete = 1;
+ }
+
+ if (ret >= 0) {
+ xfer->status = CC_SUCCESS;
+ xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1);
+ return 0;
+ }
+
+ /* error */
+ switch (ret) {
+ case USB_RET_NODEV:
+ xfer->status = CC_USB_TRANSACTION_ERROR;
+ xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
+ xhci_stall_ep(xfer);
+ break;
+ case USB_RET_STALL:
+ xfer->status = CC_STALL_ERROR;
+ xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
+ xhci_stall_ep(xfer);
+ break;
+ default:
+ fprintf(stderr, "%s: FIXME: ret = %d\n", __FUNCTION__, ret);
+ FIXME();
+ }
+ return 0;
+}
+
+static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
+{
+ XHCITRB *trb_setup, *trb_status;
+ uint8_t bmRequestType, bRequest;
+ uint16_t wValue, wLength, wIndex;
+ XHCIPort *port;
+ USBDevice *dev;
+ int ret;
+
+ DPRINTF("xhci_fire_ctl_transfer(slot=%d)\n", xfer->slotid);
+
+ trb_setup = &xfer->trbs[0];
+ trb_status = &xfer->trbs[xfer->trb_count-1];
+
+ /* at most one Event Data TRB allowed after STATUS */
+ if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
+ trb_status--;
+ }
+
+ /* do some sanity checks */
+ if (TRB_TYPE(*trb_setup) != TR_SETUP) {
+ fprintf(stderr, "xhci: ep0 first TD not SETUP: %d\n",
+ TRB_TYPE(*trb_setup));
+ return -1;
+ }
+ if (TRB_TYPE(*trb_status) != TR_STATUS) {
+ fprintf(stderr, "xhci: ep0 last TD not STATUS: %d\n",
+ TRB_TYPE(*trb_status));
+ return -1;
+ }
+ if (!(trb_setup->control & TRB_TR_IDT)) {
+ fprintf(stderr, "xhci: Setup TRB doesn't have IDT set\n");
+ return -1;
+ }
+ if ((trb_setup->status & 0x1ffff) != 8) {
+ fprintf(stderr, "xhci: Setup TRB has bad length (%d)\n",
+ (trb_setup->status & 0x1ffff));
+ return -1;
+ }
+
+ bmRequestType = trb_setup->parameter;
+ bRequest = trb_setup->parameter >> 8;
+ wValue = trb_setup->parameter >> 16;
+ wIndex = trb_setup->parameter >> 32;
+ wLength = trb_setup->parameter >> 48;
+
+ if (xfer->data && xfer->data_alloced < wLength) {
+ xfer->data_alloced = 0;
+ g_free(xfer->data);
+ xfer->data = NULL;
+ }
+ if (!xfer->data) {
+ DPRINTF("xhci: alloc %d bytes data\n", wLength);
+ xfer->data = g_malloc(wLength+1);
+ xfer->data_alloced = wLength;
+ }
+ xfer->data_length = wLength;
+
+ port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
+ dev = port->port.dev;
+ if (!dev) {
+ fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
+ xhci->slots[xfer->slotid-1].port);
+ return -1;
+ }
+
+ xfer->in_xfer = bmRequestType & USB_DIR_IN;
+ xfer->iso_xfer = false;
+
+ xhci_setup_packet(xfer, port, 0);
+ if (!xfer->in_xfer) {
+ xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
+ }
+ ret = usb_device_handle_control(dev, &xfer->packet,
+ (bmRequestType << 8) | bRequest,
+ wValue, wIndex, wLength, xfer->data);
+
+ xhci_complete_packet(xfer, ret);
+ if (!xfer->running) {
+ xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+ }
+ return 0;
+}
+
+static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
+{
+ XHCIPort *port;
+ USBDevice *dev;
+ int ret;
+
+ DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
+ uint8_t ep = xfer->epid>>1;
+
+ xfer->in_xfer = epctx->type>>2;
+ if (xfer->in_xfer) {
+ ep |= 0x80;
+ }
+
+ if (xfer->data && xfer->data_alloced < xfer->data_length) {
+ xfer->data_alloced = 0;
+ g_free(xfer->data);
+ xfer->data = NULL;
+ }
+ if (!xfer->data && xfer->data_length) {
+ DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length);
+ xfer->data = g_malloc(xfer->data_length);
+ xfer->data_alloced = xfer->data_length;
+ }
+ if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
+ if (!xfer->bg_xfer) {
+ xfer->pkts = 1;
+ }
+ } else {
+ xfer->pkts = 0;
+ }
+
+ port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
+ dev = port->port.dev;
+ if (!dev) {
+ fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
+ xhci->slots[xfer->slotid-1].port);
+ return -1;
+ }
+
+ xhci_setup_packet(xfer, port, ep);
+
+ switch(epctx->type) {
+ case ET_INTR_OUT:
+ case ET_INTR_IN:
+ case ET_BULK_OUT:
+ case ET_BULK_IN:
+ break;
+ case ET_ISO_OUT:
+ case ET_ISO_IN:
+ FIXME();
+ break;
+ default:
+ fprintf(stderr, "xhci: unknown or unhandled EP type %d (ep %02x)\n",
+ epctx->type, ep);
+ return -1;
+ }
+
+ if (!xfer->in_xfer) {
+ xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0);
+ }
+ ret = usb_handle_packet(dev, &xfer->packet);
+
+ xhci_complete_packet(xfer, ret);
+ if (!xfer->running) {
+ xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+ }
+ return 0;
+}
+
+static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
+{
+ int i;
+ unsigned int length = 0;
+ XHCITRB *trb;
+
+ DPRINTF("xhci_fire_transfer(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
+
+ for (i = 0; i < xfer->trb_count; i++) {
+ trb = &xfer->trbs[i];
+ if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) {
+ length += trb->status & 0x1ffff;
+ }
+ }
+ DPRINTF("xhci: total TD length=%d\n", length);
+
+ if (!epctx->has_bg) {
+ xfer->data_length = length;
+ xfer->backgrounded = 0;
+ return xhci_submit(xhci, xfer, epctx);
+ } else {
+ if (!epctx->bg_running) {
+ for (i = 0; i < BG_XFERS; i++) {
+ XHCITransfer *t = &epctx->bg_transfers[i];
+ t->xhci = xhci;
+ t->epid = xfer->epid;
+ t->slotid = xfer->slotid;
+ t->pkts = BG_PKTS;
+ t->pktsize = epctx->max_psize;
+ t->data_length = t->pkts * t->pktsize;
+ t->bg_xfer = 1;
+ if (xhci_submit(xhci, t, epctx) < 0) {
+ fprintf(stderr, "xhci: bg submit failed\n");
+ return -1;
+ }
+ }
+ epctx->bg_running = 1;
+ }
+ xfer->backgrounded = 1;
+ xhci_bg_update(xhci, epctx);
+ return 0;
+ }
+}
+
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
+{
+ XHCIEPContext *epctx;
+ int length;
+ int i;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ assert(epid >= 1 && epid <= 31);
+ DPRINTF("xhci_kick_ep(%d, %d)\n", slotid, epid);
+
+ if (!xhci->slots[slotid-1].enabled) {
+ fprintf(stderr, "xhci: xhci_kick_ep for disabled slot %d\n", slotid);
+ return;
+ }
+ epctx = xhci->slots[slotid-1].eps[epid-1];
+ if (!epctx) {
+ fprintf(stderr, "xhci: xhci_kick_ep for disabled endpoint %d,%d\n",
+ epid, slotid);
+ return;
+ }
+
+ if (epctx->state == EP_HALTED) {
+ DPRINTF("xhci: ep halted, not running schedule\n");
+ return;
+ }
+
+ xhci_set_ep_state(xhci, epctx, EP_RUNNING);
+
+ while (1) {
+ XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
+ if (xfer->running || xfer->backgrounded) {
+ DPRINTF("xhci: ep is busy\n");
+ break;
+ }
+ length = xhci_ring_chain_length(xhci, &epctx->ring);
+ if (length < 0) {
+ DPRINTF("xhci: incomplete TD (%d TRBs)\n", -length);
+ break;
+ } else if (length == 0) {
+ break;
+ }
+ DPRINTF("xhci: fetching %d-TRB TD\n", length);
+ if (xfer->trbs && xfer->trb_alloced < length) {
+ xfer->trb_count = 0;
+ xfer->trb_alloced = 0;
+ g_free(xfer->trbs);
+ xfer->trbs = NULL;
+ }
+ if (!xfer->trbs) {
+ xfer->trbs = g_malloc(sizeof(XHCITRB) * length);
+ xfer->trb_alloced = length;
+ }
+ xfer->trb_count = length;
+
+ for (i = 0; i < length; i++) {
+ assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL));
+ }
+ xfer->xhci = xhci;
+ xfer->epid = epid;
+ xfer->slotid = slotid;
+
+ if (epid == 1) {
+ if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
+ epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
+ } else {
+ fprintf(stderr, "xhci: error firing CTL transfer\n");
+ }
+ } else {
+ if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
+ epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
+ } else {
+ fprintf(stderr, "xhci: error firing data transfer\n");
+ }
+ }
+
+ /*
+ * Qemu usb can't handle multiple in-flight xfers.
+ * Also xfers might be finished here already,
+ * possibly with an error. Stop here for now.
+ */
+ break;
+ }
+}
+
+static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
+{
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_enable_slot(%d)\n", slotid);
+ xhci->slots[slotid-1].enabled = 1;
+ xhci->slots[slotid-1].port = 0;
+ memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31);
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
+{
+ int i;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_disable_slot(%d)\n", slotid);
+
+ for (i = 1; i <= 31; i++) {
+ if (xhci->slots[slotid-1].eps[i-1]) {
+ xhci_disable_ep(xhci, slotid, i);
+ }
+ }
+
+ xhci->slots[slotid-1].enabled = 0;
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
+ uint64_t pictx, bool bsr)
+{
+ XHCISlot *slot;
+ USBDevice *dev;
+ target_phys_addr_t ictx, octx, dcbaap;
+ uint64_t poctx;
+ uint32_t ictl_ctx[2];
+ uint32_t slot_ctx[4];
+ uint32_t ep0_ctx[5];
+ unsigned int port;
+ int i;
+ TRBCCode res;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_address_slot(%d)\n", slotid);
+
+ dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
+ cpu_physical_memory_read(dcbaap + 8*slotid,
+ (uint8_t *) &poctx, sizeof(poctx));
+ ictx = xhci_mask64(pictx);
+ octx = xhci_mask64(le64_to_cpu(poctx));
+
+ DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+ DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+ cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+ if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
+ fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+ ictl_ctx[0], ictl_ctx[1]);
+ return CC_TRB_ERROR;
+ }
+
+ cpu_physical_memory_read(ictx+32, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ cpu_physical_memory_read(ictx+64, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+ DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+ DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
+ ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+ port = (slot_ctx[1]>>16) & 0xFF;
+ dev = xhci->ports[port-1].port.dev;
+
+ if (port < 1 || port > MAXPORTS) {
+ fprintf(stderr, "xhci: bad port %d\n", port);
+ return CC_TRB_ERROR;
+ } else if (!dev) {
+ fprintf(stderr, "xhci: port %d not connected\n", port);
+ return CC_USB_TRANSACTION_ERROR;
+ }
+
+ for (i = 0; i < MAXSLOTS; i++) {
+ if (xhci->slots[i].port == port) {
+ fprintf(stderr, "xhci: port %d already assigned to slot %d\n",
+ port, i+1);
+ return CC_TRB_ERROR;
+ }
+ }
+
+ slot = &xhci->slots[slotid-1];
+ slot->port = port;
+ slot->ctx = octx;
+
+ if (bsr) {
+ slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
+ } else {
+ slot->devaddr = xhci->devaddr++;
+ slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr;
+ DPRINTF("xhci: device address is %d\n", slot->devaddr);
+ usb_device_handle_control(dev, NULL,
+ DeviceOutRequest | USB_REQ_SET_ADDRESS,
+ slot->devaddr, 0, 0, NULL);
+ }
+
+ res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx);
+
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+ DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
+ ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ cpu_physical_memory_write(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+ return res;
+}
+
+
+static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
+ uint64_t pictx, bool dc)
+{
+ target_phys_addr_t ictx, octx;
+ uint32_t ictl_ctx[2];
+ uint32_t slot_ctx[4];
+ uint32_t islot_ctx[4];
+ uint32_t ep_ctx[5];
+ int i;
+ TRBCCode res;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_configure_slot(%d)\n", slotid);
+
+ ictx = xhci_mask64(pictx);
+ octx = xhci->slots[slotid-1].ctx;
+
+ DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+ DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+ if (dc) {
+ for (i = 2; i <= 31; i++) {
+ if (xhci->slots[slotid-1].eps[i-1]) {
+ xhci_disable_ep(xhci, slotid, i);
+ }
+ }
+
+ cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+ slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ return CC_SUCCESS;
+ }
+
+ cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+ if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
+ fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+ ictl_ctx[0], ictl_ctx[1]);
+ return CC_TRB_ERROR;
+ }
+
+ cpu_physical_memory_read(ictx+32, (uint8_t *) islot_ctx, sizeof(islot_ctx));
+ cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
+ fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]);
+ return CC_CONTEXT_STATE_ERROR;
+ }
+
+ for (i = 2; i <= 31; i++) {
+ if (ictl_ctx[0] & (1<<i)) {
+ xhci_disable_ep(xhci, slotid, i);
+ }
+ if (ictl_ctx[1] & (1<<i)) {
+ cpu_physical_memory_read(ictx+32+(32*i),
+ (uint8_t *) ep_ctx, sizeof(ep_ctx));
+ DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
+ i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
+ ep_ctx[3], ep_ctx[4]);
+ xhci_disable_ep(xhci, slotid, i);
+ res = xhci_enable_ep(xhci, slotid, i, octx+(32*i), ep_ctx);
+ if (res != CC_SUCCESS) {
+ return res;
+ }
+ DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
+ i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
+ ep_ctx[3], ep_ctx[4]);
+ cpu_physical_memory_write(octx+(32*i),
+ (uint8_t *) ep_ctx, sizeof(ep_ctx));
+ }
+ }
+
+ slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+ slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT;
+ slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT);
+ slot_ctx[0] |= islot_ctx[0] & (SLOT_CONTEXT_ENTRIES_MASK <<
+ SLOT_CONTEXT_ENTRIES_SHIFT);
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ return CC_SUCCESS;
+}
+
+
+static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
+ uint64_t pictx)
+{
+ target_phys_addr_t ictx, octx;
+ uint32_t ictl_ctx[2];
+ uint32_t iep0_ctx[5];
+ uint32_t ep0_ctx[5];
+ uint32_t islot_ctx[4];
+ uint32_t slot_ctx[4];
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_evaluate_slot(%d)\n", slotid);
+
+ ictx = xhci_mask64(pictx);
+ octx = xhci->slots[slotid-1].ctx;
+
+ DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+ DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+ cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+ if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
+ fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+ ictl_ctx[0], ictl_ctx[1]);
+ return CC_TRB_ERROR;
+ }
+
+ if (ictl_ctx[1] & 0x1) {
+ cpu_physical_memory_read(ictx+32,
+ (uint8_t *) islot_ctx, sizeof(islot_ctx));
+
+ DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
+ islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
+
+ cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ slot_ctx[1] &= ~0xFFFF; /* max exit latency */
+ slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
+ slot_ctx[2] &= ~0xFF00000; /* interrupter target */
+ slot_ctx[2] |= islot_ctx[2] & 0xFF000000;
+
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ }
+
+ if (ictl_ctx[1] & 0x2) {
+ cpu_physical_memory_read(ictx+64,
+ (uint8_t *) iep0_ctx, sizeof(iep0_ctx));
+
+ DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
+ iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
+ iep0_ctx[3], iep0_ctx[4]);
+
+ cpu_physical_memory_read(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+ ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
+ ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
+
+ DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
+ ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+ cpu_physical_memory_write(octx+32,
+ (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+ }
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
+{
+ uint32_t slot_ctx[4];
+ target_phys_addr_t octx;
+ int i;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_reset_slot(%d)\n", slotid);
+
+ octx = xhci->slots[slotid-1].ctx;
+
+ DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+ for (i = 2; i <= 31; i++) {
+ if (xhci->slots[slotid-1].eps[i-1]) {
+ xhci_disable_ep(xhci, slotid, i);
+ }
+ }
+
+ cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+ slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ return CC_SUCCESS;
+}
+
+static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *trb)
+{
+ unsigned int slotid;
+ slotid = (trb->control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK;
+ if (slotid < 1 || slotid > MAXSLOTS) {
+ fprintf(stderr, "xhci: bad slot id %d\n", slotid);
+ event->ccode = CC_TRB_ERROR;
+ return 0;
+ } else if (!xhci->slots[slotid-1].enabled) {
+ fprintf(stderr, "xhci: slot id %d not enabled\n", slotid);
+ event->ccode = CC_SLOT_NOT_ENABLED_ERROR;
+ return 0;
+ }
+ return slotid;
+}
+
+static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
+{
+ target_phys_addr_t ctx;
+ uint8_t bw_ctx[MAXPORTS+1];
+
+ DPRINTF("xhci_get_port_bandwidth()\n");
+
+ ctx = xhci_mask64(pctx);
+
+ DPRINTF("xhci: bandwidth context at "TARGET_FMT_plx"\n", ctx);
+
+ /* TODO: actually implement real values here */
+ bw_ctx[0] = 0;
+ memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */
+ cpu_physical_memory_write(ctx, bw_ctx, sizeof(bw_ctx));
+
+ return CC_SUCCESS;
+}
+
+static uint32_t rotl(uint32_t v, unsigned count)
+{
+ count &= 31;
+ return (v << count) | (v >> (32 - count));
+}
+
+
+static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo)
+{
+ uint32_t val;
+ val = rotl(lo - 0x49434878, 32 - ((hi>>8) & 0x1F));
+ val += rotl(lo + 0x49434878, hi & 0x1F);
+ val -= rotl(hi ^ 0x49434878, (lo >> 16) & 0x1F);
+ return ~val;
+}
+
+static void xhci_via_challenge(uint64_t addr)
+{
+ uint32_t buf[8];
+ uint32_t obuf[8];
+ target_phys_addr_t paddr = xhci_mask64(addr);
+
+ cpu_physical_memory_read(paddr, (uint8_t *) &buf, 32);
+
+ memcpy(obuf, buf, sizeof(obuf));
+
+ if ((buf[0] & 0xff) == 2) {
+ obuf[0] = 0x49932000 + 0x54dc200 * buf[2] + 0x7429b578 * buf[3];
+ obuf[0] |= (buf[2] * buf[3]) & 0xff;
+ obuf[1] = 0x0132bb37 + 0xe89 * buf[2] + 0xf09 * buf[3];
+ obuf[2] = 0x0066c2e9 + 0x2091 * buf[2] + 0x19bd * buf[3];
+ obuf[3] = 0xd5281342 + 0x2cc9691 * buf[2] + 0x2367662 * buf[3];
+ obuf[4] = 0x0123c75c + 0x1595 * buf[2] + 0x19ec * buf[3];
+ obuf[5] = 0x00f695de + 0x26fd * buf[2] + 0x3e9 * buf[3];
+ obuf[6] = obuf[2] ^ obuf[3] ^ 0x29472956;
+ obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593;
+ }
+
+ cpu_physical_memory_write(paddr, (uint8_t *) &obuf, 32);
+}
+
+static void xhci_process_commands(XHCIState *xhci)
+{
+ XHCITRB trb;
+ TRBType type;
+ XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
+ target_phys_addr_t addr;
+ unsigned int i, slotid = 0;
+
+ DPRINTF("xhci_process_commands()\n");
+ if (!xhci_running(xhci)) {
+ DPRINTF("xhci_process_commands() called while xHC stopped or paused\n");
+ return;
+ }
+
+ xhci->crcr_low |= CRCR_CRR;
+
+ while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) {
+ event.ptr = addr;
+ switch (type) {
+ case CR_ENABLE_SLOT:
+ for (i = 0; i < MAXSLOTS; i++) {
+ if (!xhci->slots[i].enabled) {
+ break;
+ }
+ }
+ if (i >= MAXSLOTS) {
+ fprintf(stderr, "xhci: no device slots available\n");
+ event.ccode = CC_NO_SLOTS_ERROR;
+ } else {
+ slotid = i+1;
+ event.ccode = xhci_enable_slot(xhci, slotid);
+ }
+ break;
+ case CR_DISABLE_SLOT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_disable_slot(xhci, slotid);
+ }
+ break;
+ case CR_ADDRESS_DEVICE:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_address_slot(xhci, slotid, trb.parameter,
+ trb.control & TRB_CR_BSR);
+ }
+ break;
+ case CR_CONFIGURE_ENDPOINT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_configure_slot(xhci, slotid, trb.parameter,
+ trb.control & TRB_CR_DC);
+ }
+ break;
+ case CR_EVALUATE_CONTEXT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_evaluate_slot(xhci, slotid, trb.parameter);
+ }
+ break;
+ case CR_STOP_ENDPOINT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+ & TRB_CR_EPID_MASK;
+ event.ccode = xhci_stop_ep(xhci, slotid, epid);
+ }
+ break;
+ case CR_RESET_ENDPOINT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+ & TRB_CR_EPID_MASK;
+ event.ccode = xhci_reset_ep(xhci, slotid, epid);
+ }
+ break;
+ case CR_SET_TR_DEQUEUE:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+ & TRB_CR_EPID_MASK;
+ event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid,
+ trb.parameter);
+ }
+ break;
+ case CR_RESET_DEVICE:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_reset_slot(xhci, slotid);
+ }
+ break;
+ case CR_GET_PORT_BANDWIDTH:
+ event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
+ break;
+ case CR_VENDOR_VIA_CHALLENGE_RESPONSE:
+ xhci_via_challenge(trb.parameter);
+ break;
+ case CR_VENDOR_NEC_FIRMWARE_REVISION:
+ event.type = 48; /* NEC reply */
+ event.length = 0x3025;
+ break;
+ case CR_VENDOR_NEC_CHALLENGE_RESPONSE:
+ {
+ uint32_t chi = trb.parameter >> 32;
+ uint32_t clo = trb.parameter;
+ uint32_t val = xhci_nec_challenge(chi, clo);
+ event.length = val & 0xFFFF;
+ event.epid = val >> 16;
+ slotid = val >> 24;
+ event.type = 48; /* NEC reply */
+ }
+ break;
+ default:
+ fprintf(stderr, "xhci: unimplemented command %d\n", type);
+ event.ccode = CC_TRB_ERROR;
+ break;
+ }
+ event.slotid = slotid;
+ xhci_event(xhci, &event);
+ }
+}
+
+static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
+{
+ int nr = port->port.index + 1;
+
+ port->portsc = PORTSC_PP;
+ if (port->port.dev && !is_detach) {
+ port->portsc |= PORTSC_CCS;
+ switch (port->port.dev->speed) {
+ case USB_SPEED_LOW:
+ port->portsc |= PORTSC_SPEED_LOW;
+ break;
+ case USB_SPEED_FULL:
+ port->portsc |= PORTSC_SPEED_FULL;
+ break;
+ case USB_SPEED_HIGH:
+ port->portsc |= PORTSC_SPEED_HIGH;
+ break;
+ }
+ }
+
+ if (xhci_running(xhci)) {
+ port->portsc |= PORTSC_CSC;
+ XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
+ xhci_event(xhci, &ev);
+ DPRINTF("xhci: port change event for port %d\n", nr);
+ }
+}
+
+static void xhci_reset(void *opaque)
+{
+ XHCIState *xhci = opaque;
+ int i;
+
+ DPRINTF("xhci: full reset\n");
+ if (!(xhci->usbsts & USBSTS_HCH)) {
+ fprintf(stderr, "xhci: reset while running!\n");
+ }
+
+ xhci->usbcmd = 0;
+ xhci->usbsts = USBSTS_HCH;
+ xhci->dnctrl = 0;
+ xhci->crcr_low = 0;
+ xhci->crcr_high = 0;
+ xhci->dcbaap_low = 0;
+ xhci->dcbaap_high = 0;
+ xhci->config = 0;
+ xhci->devaddr = 2;
+
+ for (i = 0; i < MAXSLOTS; i++) {
+ xhci_disable_slot(xhci, i+1);
+ }
+
+ for (i = 0; i < MAXPORTS; i++) {
+ xhci_update_port(xhci, xhci->ports + i, 0);
+ }
+
+ xhci->mfindex = 0;
+ xhci->iman = 0;
+ xhci->imod = 0;
+ xhci->erstsz = 0;
+ xhci->erstba_low = 0;
+ xhci->erstba_high = 0;
+ xhci->erdp_low = 0;
+ xhci->erdp_high = 0;
+
+ xhci->er_ep_idx = 0;
+ xhci->er_pcs = 1;
+ xhci->er_full = 0;
+ xhci->ev_buffer_put = 0;
+ xhci->ev_buffer_get = 0;
+}
+
+static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
+{
+ DPRINTF("xhci_cap_read(0x%x)\n", reg);
+
+ switch (reg) {
+ case 0x00: /* HCIVERSION, CAPLENGTH */
+ return 0x01000000 | LEN_CAP;
+ case 0x04: /* HCSPARAMS 1 */
+ return (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS;
+ case 0x08: /* HCSPARAMS 2 */
+ return 0x0000000f;
+ case 0x0c: /* HCSPARAMS 3 */
+ return 0x00000000;
+ case 0x10: /* HCCPARAMS */
+#if TARGET_PHYS_ADDR_BITS > 32
+ return 0x00081001;
+#else
+ return 0x00081000;
+#endif
+ case 0x14: /* DBOFF */
+ return OFF_DOORBELL;
+ case 0x18: /* RTSOFF */
+ return OFF_RUNTIME;
+
+ /* extended capabilities */
+ case 0x20: /* Supported Protocol:00 */
+#if USB3_PORTS > 0
+ return 0x02000402; /* USB 2.0 */
+#else
+ return 0x02000002; /* USB 2.0 */
+#endif
+ case 0x24: /* Supported Protocol:04 */
+ return 0x20425455; /* "USB " */
+ case 0x28: /* Supported Protocol:08 */
+ return 0x00000001 | (USB2_PORTS<<8);
+ case 0x2c: /* Supported Protocol:0c */
+ return 0x00000000; /* reserved */
+#if USB3_PORTS > 0
+ case 0x30: /* Supported Protocol:00 */
+ return 0x03000002; /* USB 3.0 */
+ case 0x34: /* Supported Protocol:04 */
+ return 0x20425455; /* "USB " */
+ case 0x38: /* Supported Protocol:08 */
+ return 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8);
+ case 0x3c: /* Supported Protocol:0c */
+ return 0x00000000; /* reserved */
+#endif
+ default:
+ fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg);
+ }
+ return 0;
+}
+
+static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg)
+{
+ uint32_t port = reg >> 4;
+ if (port >= MAXPORTS) {
+ fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
+ return 0;
+ }
+
+ switch (reg & 0xf) {
+ case 0x00: /* PORTSC */
+ return xhci->ports[port].portsc;
+ case 0x04: /* PORTPMSC */
+ case 0x08: /* PORTLI */
+ return 0;
+ case 0x0c: /* reserved */
+ default:
+ fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
+ port, reg);
+ return 0;
+ }
+}
+
+static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+ uint32_t port = reg >> 4;
+ uint32_t portsc;
+
+ if (port >= MAXPORTS) {
+ fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
+ return;
+ }
+
+ switch (reg & 0xf) {
+ case 0x00: /* PORTSC */
+ portsc = xhci->ports[port].portsc;
+ /* write-1-to-clear bits*/
+ portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC|
+ PORTSC_PRC|PORTSC_PLC|PORTSC_CEC));
+ if (val & PORTSC_LWS) {
+ /* overwrite PLS only when LWS=1 */
+ portsc &= ~(PORTSC_PLS_MASK << PORTSC_PLS_SHIFT);
+ portsc |= val & (PORTSC_PLS_MASK << PORTSC_PLS_SHIFT);
+ }
+ /* read/write bits */
+ portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE);
+ portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE));
+ /* write-1-to-start bits */
+ if (val & PORTSC_PR) {
+ DPRINTF("xhci: port %d reset\n", port);
+ if (xhci->ports[port].port.dev) {
+ usb_send_msg(xhci->ports[port].port.dev, USB_MSG_RESET);
+ }
+ portsc |= PORTSC_PRC | PORTSC_PED;
+ }
+ xhci->ports[port].portsc = portsc;
+ break;
+ case 0x04: /* PORTPMSC */
+ case 0x08: /* PORTLI */
+ default:
+ fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n",
+ port, reg);
+ }
+}
+
+static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg)
+{
+ DPRINTF("xhci_oper_read(0x%x)\n", reg);
+
+ if (reg >= 0x400) {
+ return xhci_port_read(xhci, reg - 0x400);
+ }
+
+ switch (reg) {
+ case 0x00: /* USBCMD */
+ return xhci->usbcmd;
+ case 0x04: /* USBSTS */
+ return xhci->usbsts;
+ case 0x08: /* PAGESIZE */
+ return 1; /* 4KiB */
+ case 0x14: /* DNCTRL */
+ return xhci->dnctrl;
+ case 0x18: /* CRCR low */
+ return xhci->crcr_low & ~0xe;
+ case 0x1c: /* CRCR high */
+ return xhci->crcr_high;
+ case 0x30: /* DCBAAP low */
+ return xhci->dcbaap_low;
+ case 0x34: /* DCBAAP high */
+ return xhci->dcbaap_high;
+ case 0x38: /* CONFIG */
+ return xhci->config;
+ default:
+ fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg);
+ }
+ return 0;
+}
+
+static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+ DPRINTF("xhci_oper_write(0x%x, 0x%08x)\n", reg, val);
+
+ if (reg >= 0x400) {
+ xhci_port_write(xhci, reg - 0x400, val);
+ return;
+ }
+
+ switch (reg) {
+ case 0x00: /* USBCMD */
+ if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) {
+ xhci_run(xhci);
+ } else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) {
+ xhci_stop(xhci);
+ }
+ xhci->usbcmd = val & 0xc0f;
+ if (val & USBCMD_HCRST) {
+ xhci_reset(xhci);
+ }
+ xhci_irq_update(xhci);
+ break;
+
+ case 0x04: /* USBSTS */
+ /* these bits are write-1-to-clear */
+ xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE));
+ xhci_irq_update(xhci);
+ break;
+
+ case 0x14: /* DNCTRL */
+ xhci->dnctrl = val & 0xffff;
+ break;
+ case 0x18: /* CRCR low */
+ xhci->crcr_low = (val & 0xffffffcf) | (xhci->crcr_low & CRCR_CRR);
+ break;
+ case 0x1c: /* CRCR high */
+ xhci->crcr_high = val;
+ if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) {
+ XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED};
+ xhci->crcr_low &= ~CRCR_CRR;
+ xhci_event(xhci, &event);
+ DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
+ } else {
+ target_phys_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
+ xhci_ring_init(xhci, &xhci->cmd_ring, base);
+ }
+ xhci->crcr_low &= ~(CRCR_CA | CRCR_CS);
+ break;
+ case 0x30: /* DCBAAP low */
+ xhci->dcbaap_low = val & 0xffffffc0;
+ break;
+ case 0x34: /* DCBAAP high */
+ xhci->dcbaap_high = val;
+ break;
+ case 0x38: /* CONFIG */
+ xhci->config = val & 0xff;
+ break;
+ default:
+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
+ }
+}
+
+static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
+{
+ DPRINTF("xhci_runtime_read(0x%x)\n", reg);
+
+ switch (reg) {
+ case 0x00: /* MFINDEX */
+ fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n");
+ return xhci->mfindex;
+ case 0x20: /* IMAN */
+ return xhci->iman;
+ case 0x24: /* IMOD */
+ return xhci->imod;
+ case 0x28: /* ERSTSZ */
+ return xhci->erstsz;
+ case 0x30: /* ERSTBA low */
+ return xhci->erstba_low;
+ case 0x34: /* ERSTBA high */
+ return xhci->erstba_high;
+ case 0x38: /* ERDP low */
+ return xhci->erdp_low;
+ case 0x3c: /* ERDP high */
+ return xhci->erdp_high;
+ default:
+ fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
+ }
+ return 0;
+}
+
+static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+ DPRINTF("xhci_runtime_write(0x%x, 0x%08x)\n", reg, val);
+
+ switch (reg) {
+ case 0x20: /* IMAN */
+ if (val & IMAN_IP) {
+ xhci->iman &= ~IMAN_IP;
+ }
+ xhci->iman &= ~IMAN_IE;
+ xhci->iman |= val & IMAN_IE;
+ xhci_irq_update(xhci);
+ break;
+ case 0x24: /* IMOD */
+ xhci->imod = val;
+ break;
+ case 0x28: /* ERSTSZ */
+ xhci->erstsz = val & 0xffff;
+ break;
+ case 0x30: /* ERSTBA low */
+ /* XXX NEC driver bug: it doesn't align this to 64 bytes
+ xhci->erstba_low = val & 0xffffffc0; */
+ xhci->erstba_low = val & 0xfffffff0;
+ break;
+ case 0x34: /* ERSTBA high */
+ xhci->erstba_high = val;
+ xhci_er_reset(xhci);
+ break;
+ case 0x38: /* ERDP low */
+ if (val & ERDP_EHB) {
+ xhci->erdp_low &= ~ERDP_EHB;
+ }
+ xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB);
+ break;
+ case 0x3c: /* ERDP high */
+ xhci->erdp_high = val;
+ xhci_events_update(xhci);
+ break;
+ default:
+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
+ }
+}
+
+static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg)
+{
+ DPRINTF("xhci_doorbell_read(0x%x)\n", reg);
+ /* doorbells always read as 0 */
+ return 0;
+}
+
+static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+ DPRINTF("xhci_doorbell_write(0x%x, 0x%08x)\n", reg, val);
+
+ if (!xhci_running(xhci)) {
+ fprintf(stderr, "xhci: wrote doorbell while xHC stopped or paused\n");
+ return;
+ }
+
+ reg >>= 2;
+
+ if (reg == 0) {
+ if (val == 0) {
+ xhci_process_commands(xhci);
+ } else {
+ fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", val);
+ }
+ } else {
+ if (reg > MAXSLOTS) {
+ fprintf(stderr, "xhci: bad doorbell %d\n", reg);
+ } else if (val > 31) {
+ fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", reg, val);
+ } else {
+ xhci_kick_ep(xhci, reg, val);
+ }
+ }
+}
+
+static uint64_t xhci_mem_read(void *ptr, target_phys_addr_t addr,
+ unsigned size)
+{
+ XHCIState *xhci = ptr;
+
+ /* Only aligned reads are allowed on xHCI */
+ if (addr & 3) {
+ fprintf(stderr, "xhci_mem_read: Mis-aligned read\n");
+ return 0;
+ }
+
+ if (addr < LEN_CAP) {
+ return xhci_cap_read(xhci, addr);
+ } else if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) {
+ return xhci_oper_read(xhci, addr - OFF_OPER);
+ } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) {
+ return xhci_runtime_read(xhci, addr - OFF_RUNTIME);
+ } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) {
+ return xhci_doorbell_read(xhci, addr - OFF_DOORBELL);
+ } else {
+ fprintf(stderr, "xhci_mem_read: Bad offset %x\n", (int)addr);
+ return 0;
+ }
+}
+
+static void xhci_mem_write(void *ptr, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
+{
+ XHCIState *xhci = ptr;
+
+ /* Only aligned writes are allowed on xHCI */
+ if (addr & 3) {
+ fprintf(stderr, "xhci_mem_write: Mis-aligned write\n");
+ return;
+ }
+
+ if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) {
+ xhci_oper_write(xhci, addr - OFF_OPER, val);
+ } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) {
+ xhci_runtime_write(xhci, addr - OFF_RUNTIME, val);
+ } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) {
+ xhci_doorbell_write(xhci, addr - OFF_DOORBELL, val);
+ } else {
+ fprintf(stderr, "xhci_mem_write: Bad offset %x\n", (int)addr);
+ }
+}
+
+static const MemoryRegionOps xhci_mem_ops = {
+ .read = xhci_mem_read,
+ .write = xhci_mem_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void xhci_attach(USBPort *usbport)
+{
+ XHCIState *xhci = usbport->opaque;
+ XHCIPort *port = &xhci->ports[usbport->index];
+
+ xhci_update_port(xhci, port, 0);
+}
+
+static void xhci_detach(USBPort *usbport)
+{
+ XHCIState *xhci = usbport->opaque;
+ XHCIPort *port = &xhci->ports[usbport->index];
+
+ xhci_update_port(xhci, port, 1);
+}
+
+static void xhci_complete(USBPort *port, USBPacket *packet)
+{
+ XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
+
+ xhci_complete_packet(xfer, packet->result);
+ xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
+}
+
+static void xhci_child_detach(USBPort *port, USBDevice *child)
+{
+ FIXME();
+}
+
+static USBPortOps xhci_port_ops = {
+ .attach = xhci_attach,
+ .detach = xhci_detach,
+ .complete = xhci_complete,
+ .child_detach = xhci_child_detach,
+};
+
+static USBBusOps xhci_bus_ops = {
+};
+
+static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
+{
+ int i;
+
+ xhci->usbsts = USBSTS_HCH;
+
+ usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev);
+
+ for (i = 0; i < MAXPORTS; i++) {
+ memset(&xhci->ports[i], 0, sizeof(xhci->ports[i]));
+ usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i,
+ &xhci_port_ops, USB_SPEED_MASK_HIGH);
+ }
+ for (i = 0; i < MAXSLOTS; i++) {
+ xhci->slots[i].enabled = 0;
+ }
+
+ qemu_register_reset(xhci_reset, xhci);
+}
+
+static int usb_xhci_initfn(struct PCIDevice *dev)
+{
+ int ret;
+
+ XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
+
+ xhci->pci_dev.config[PCI_CLASS_PROG] = 0x30; /* xHCI */
+ xhci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
+ xhci->pci_dev.config[PCI_CACHE_LINE_SIZE] = 0x10;
+ xhci->pci_dev.config[0x60] = 0x30; /* release number */
+
+ usb_xhci_init(xhci, &dev->qdev);
+
+ xhci->irq = xhci->pci_dev.irq[0];
+
+ memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci,
+ "xhci", LEN_REGS);
+ pci_register_bar(&xhci->pci_dev, 0,
+ PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &xhci->mem);
+
+ ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0);
+ assert(ret >= 0);
+
+ if (xhci->msi) {
+ ret = msi_init(&xhci->pci_dev, 0x70, 1, true, false);
+ assert(ret >= 0);
+ }
+
+ return 0;
+}
+
+static void xhci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
+ int len)
+{
+ XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
+
+ pci_default_write_config(dev, addr, val, len);
+ if (xhci->msi) {
+ msi_write_config(dev, addr, val, len);
+ }
+}
+
+static const VMStateDescription vmstate_xhci = {
+ .name = "xhci",
+ .unmigratable = 1,
+};
+
+static Property xhci_properties[] = {
+ DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xhci_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_xhci;
+ dc->props = xhci_properties;
+ k->init = usb_xhci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_NEC;
+ k->device_id = PCI_DEVICE_ID_NEC_UPD720200;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ k->revision = 0x03;
+ k->is_express = 1;
+ k->config_write = xhci_write_config;
+}
+
+static TypeInfo xhci_info = {
+ .name = "nec-usb-xhci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(XHCIState),
+ .class_init = xhci_class_init,
+};
+
+static void xhci_register(void)
+{
+ type_register_static(&xhci_info);
+}
+device_init(xhci_register);
diff --git a/hw/usb.c b/hw/usb.c
index 2216efe..c3ff5b7 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -95,8 +95,8 @@
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
if (s->setup_buf[0] & USB_DIR_IN) {
- ret = s->info->handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
+ ret = usb_device_handle_control(s, p, request, value, index,
+ s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
s->setup_state = SETUP_STATE_SETUP;
return USB_RET_ASYNC;
@@ -129,7 +129,7 @@
int ret = 0;
if (p->devep != 0)
- return s->info->handle_data(s, p);
+ return usb_device_handle_data(s, p);
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
@@ -138,8 +138,8 @@
switch(s->setup_state) {
case SETUP_STATE_ACK:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
- ret = s->info->handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
+ ret = usb_device_handle_control(s, p, request, value, index,
+ s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
return USB_RET_ASYNC;
}
@@ -176,7 +176,7 @@
static int do_token_out(USBDevice *s, USBPacket *p)
{
if (p->devep != 0)
- return s->info->handle_data(s, p);
+ return usb_device_handle_data(s, p);
switch(s->setup_state) {
case SETUP_STATE_ACK:
@@ -220,9 +220,7 @@
switch(p->pid) {
case USB_MSG_ATTACH:
s->state = USB_STATE_ATTACHED;
- if (s->info->handle_attach) {
- s->info->handle_attach(s);
- }
+ usb_device_handle_attach(s);
return 0;
case USB_MSG_DETACH:
@@ -233,9 +231,7 @@
s->remote_wakeup = 0;
s->addr = 0;
s->state = USB_STATE_DEFAULT;
- if (s->info->handle_reset) {
- s->info->handle_reset(s);
- }
+ usb_device_handle_reset(s);
return 0;
}
@@ -326,10 +322,10 @@
int ret;
assert(p->owner == NULL);
- ret = dev->info->handle_packet(dev, p);
+ ret = usb_device_handle_packet(dev, p);
if (ret == USB_RET_ASYNC) {
if (p->owner == NULL) {
- p->owner = dev;
+ p->owner = usb_ep_get(dev, p->pid, p->devep);
} else {
/* We'll end up here when usb_handle_packet is called
* recursively due to a hub being in the chain. Nothing
@@ -357,7 +353,7 @@
void usb_cancel_packet(USBPacket * p)
{
assert(p->owner != NULL);
- p->owner->info->cancel_packet(p->owner, p);
+ usb_device_cancel_packet(p->owner->dev, p);
p->owner = NULL;
}
@@ -414,3 +410,124 @@
{
qemu_iovec_destroy(&p->iov);
}
+
+void usb_ep_init(USBDevice *dev)
+{
+ int ep;
+
+ dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
+ dev->ep_ctl.ifnum = 0;
+ dev->ep_ctl.dev = dev;
+ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
+ dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
+ dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
+ dev->ep_in[ep].ifnum = 0;
+ dev->ep_out[ep].ifnum = 0;
+ dev->ep_in[ep].dev = dev;
+ dev->ep_out[ep].dev = dev;
+ }
+}
+
+void usb_ep_dump(USBDevice *dev)
+{
+ static const char *tname[] = {
+ [USB_ENDPOINT_XFER_CONTROL] = "control",
+ [USB_ENDPOINT_XFER_ISOC] = "isoc",
+ [USB_ENDPOINT_XFER_BULK] = "bulk",
+ [USB_ENDPOINT_XFER_INT] = "int",
+ };
+ int ifnum, ep, first;
+
+ fprintf(stderr, "Device \"%s\", config %d\n",
+ dev->product_desc, dev->configuration);
+ for (ifnum = 0; ifnum < 16; ifnum++) {
+ first = 1;
+ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
+ if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID &&
+ dev->ep_in[ep].ifnum == ifnum) {
+ if (first) {
+ first = 0;
+ fprintf(stderr, " Interface %d, alternative %d\n",
+ ifnum, dev->altsetting[ifnum]);
+ }
+ fprintf(stderr, " Endpoint %d, IN, %s, %d max\n", ep,
+ tname[dev->ep_in[ep].type],
+ dev->ep_in[ep].max_packet_size);
+ }
+ if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID &&
+ dev->ep_out[ep].ifnum == ifnum) {
+ if (first) {
+ first = 0;
+ fprintf(stderr, " Interface %d, alternative %d\n",
+ ifnum, dev->altsetting[ifnum]);
+ }
+ fprintf(stderr, " Endpoint %d, OUT, %s, %d max\n", ep,
+ tname[dev->ep_out[ep].type],
+ dev->ep_out[ep].max_packet_size);
+ }
+ }
+ }
+ fprintf(stderr, "--\n");
+}
+
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
+{
+ struct USBEndpoint *eps = pid == USB_TOKEN_IN ? dev->ep_in : dev->ep_out;
+ if (ep == 0) {
+ return &dev->ep_ctl;
+ }
+ assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
+ assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
+ return eps + ep - 1;
+}
+
+uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ return uep->type;
+}
+
+void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ uep->type = type;
+}
+
+uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ return uep->ifnum;
+}
+
+void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ uep->ifnum = ifnum;
+}
+
+void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
+ uint16_t raw)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ int size, microframes;
+
+ size = raw & 0x7ff;
+ switch ((raw >> 11) & 3) {
+ case 1:
+ microframes = 2;
+ break;
+ case 2:
+ microframes = 3;
+ break;
+ default:
+ microframes = 1;
+ break;
+ }
+ uep->max_packet_size = size * microframes;
+}
+
+int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ return uep->max_packet_size;
+}
diff --git a/hw/usb.h b/hw/usb.h
index 7ea90e4..13e7c8e 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -1,3 +1,6 @@
+#ifndef QEMU_USB_H
+#define QEMU_USB_H
+
/*
* QEMU USB API
*
@@ -79,6 +82,11 @@
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
+#define USB_SUBCLASS_UNDEFINED 0
+#define USB_SUBCLASS_AUDIO_CONTROL 1
+#define USB_SUBCLASS_AUDIO_STREAMING 2
+#define USB_SUBCLASS_AUDIO_MIDISTREAMING 3
+
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
@@ -132,18 +140,21 @@
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_DEBUG 0x0A
#define USB_DT_INTERFACE_ASSOC 0x0B
+#define USB_DT_CS_INTERFACE 0x24
+#define USB_DT_CS_ENDPOINT 0x25
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
+#define USB_ENDPOINT_XFER_INVALID 255
typedef struct USBBus USBBus;
typedef struct USBBusOps USBBusOps;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
-typedef struct USBDeviceInfo USBDeviceInfo;
typedef struct USBPacket USBPacket;
+typedef struct USBEndpoint USBEndpoint;
typedef struct USBDesc USBDesc;
typedef struct USBDescID USBDescID;
@@ -161,10 +172,19 @@
QLIST_ENTRY(USBDescString) next;
};
+#define USB_MAX_ENDPOINTS 15
+#define USB_MAX_INTERFACES 16
+
+struct USBEndpoint {
+ uint8_t type;
+ uint8_t ifnum;
+ int max_packet_size;
+ USBDevice *dev;
+};
+
/* definition of a USB device */
struct USBDevice {
DeviceState qdev;
- USBDeviceInfo *info;
USBPort *port;
char *port_path;
void *opaque;
@@ -186,13 +206,31 @@
int32_t setup_len;
int32_t setup_index;
+ USBEndpoint ep_ctl;
+ USBEndpoint ep_in[USB_MAX_ENDPOINTS];
+ USBEndpoint ep_out[USB_MAX_ENDPOINTS];
+
QLIST_HEAD(, USBDescString) strings;
const USBDescDevice *device;
+
+ int configuration;
+ int ninterfaces;
+ int altsetting[USB_MAX_INTERFACES];
const USBDescConfig *config;
+ const USBDescIface *ifaces[USB_MAX_INTERFACES];
};
-struct USBDeviceInfo {
- DeviceInfo qdev;
+#define TYPE_USB_DEVICE "usb-device"
+#define USB_DEVICE(obj) \
+ OBJECT_CHECK(USBDevice, (obj), TYPE_USB_DEVICE)
+#define USB_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(USBDeviceClass, (klass), TYPE_USB_DEVICE)
+#define USB_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(USBDeviceClass, (obj), TYPE_USB_DEVICE)
+
+typedef struct USBDeviceClass {
+ DeviceClass parent_class;
+
int (*init)(USBDevice *dev);
/*
@@ -241,13 +279,12 @@
*/
int (*handle_data)(USBDevice *dev, USBPacket *p);
+ void (*set_interface)(USBDevice *dev, int interface,
+ int alt_old, int alt_new);
+
const char *product_desc;
const USBDesc *usb_desc;
-
- /* handle legacy -usbdevice command line options */
- const char *usbdevice_name;
- USBDevice *(*usbdevice_init)(const char *params);
-};
+} USBDeviceClass;
typedef struct USBPortOps {
void (*attach)(USBPort *port);
@@ -288,7 +325,7 @@
QEMUIOVector iov;
int result; /* transfer length or USB_RET_* status code */
/* Internal use by the USB layer. */
- USBDevice *owner;
+ USBEndpoint *owner;
};
void usb_packet_init(USBPacket *p);
@@ -304,6 +341,17 @@
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
+void usb_ep_init(USBDevice *dev);
+void usb_ep_dump(USBDevice *dev);
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep);
+void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type);
+void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum);
+void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
+ uint16_t raw);
+int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
+
void usb_attach(USBPort *port);
void usb_detach(USBPort *port);
void usb_reset(USBPort *port);
@@ -370,8 +418,8 @@
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
USBBus *usb_bus_find(int busnr);
-void usb_qdev_register(USBDeviceInfo *info);
-void usb_qdev_register_many(USBDeviceInfo *info);
+void usb_legacy_register(const char *typename, const char *usbdevice_name,
+ USBDevice *(*usbdevice_init)(const char *params));
USBDevice *usb_create(USBBus *bus, const char *name);
USBDevice *usb_create_simple(USBBus *bus, const char *name);
USBDevice *usbdevice_create(const char *cmdline);
@@ -403,4 +451,25 @@
.offset = vmstate_offset_value(_state, _field, USBDevice), \
}
+int usb_device_handle_packet(USBDevice *dev, USBPacket *p);
+
+void usb_device_cancel_packet(USBDevice *dev, USBPacket *p);
+
+void usb_device_handle_attach(USBDevice *dev);
+
+void usb_device_handle_reset(USBDevice *dev);
+
+int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value,
+ int index, int length, uint8_t *data);
+
+int usb_device_handle_data(USBDevice *dev, USBPacket *p);
+
+void usb_device_set_interface(USBDevice *dev, int interface,
+ int alt_old, int alt_new);
+
+const char *usb_device_get_product_desc(USBDevice *dev);
+
+const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
+
+#endif
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index a285f7f..c4105e9 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -109,22 +109,56 @@
return 0;
}
-static PCIDeviceInfo versatile_pci_host_info = {
- .qdev.name = "versatile_pci_host",
- .qdev.size = sizeof(PCIDevice),
- .init = versatile_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_XILINX,
- /* Both boards have the same device ID. Oh well. */
- .device_id = PCI_DEVICE_ID_XILINX_XC2VP30,
- .class_id = PCI_CLASS_PROCESSOR_CO,
+static void versatile_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = versatile_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_XILINX;
+ k->device_id = PCI_DEVICE_ID_XILINX_XC2VP30;
+ k->class_id = PCI_CLASS_PROCESSOR_CO;
+}
+
+static TypeInfo versatile_pci_host_info = {
+ .name = "versatile_pci_host",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = versatile_pci_host_class_init,
+};
+
+static void pci_vpb_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pci_vpb_init;
+}
+
+static TypeInfo pci_vpb_info = {
+ .name = "versatile_pci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PCIVPBState),
+ .class_init = pci_vpb_class_init,
+};
+
+static void pci_realview_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pci_realview_init;
+}
+
+static TypeInfo pci_realview_info = {
+ .name = "realview_pci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PCIVPBState),
+ .class_init = pci_realview_class_init,
};
static void versatile_pci_register_devices(void)
{
- sysbus_register_dev("versatile_pci", sizeof(PCIVPBState), pci_vpb_init);
- sysbus_register_dev("realview_pci", sizeof(PCIVPBState),
- pci_realview_init);
- pci_qdev_register(&versatile_pci_host_info);
+ type_register_static(&pci_vpb_info);
+ type_register_static(&pci_realview_info);
+ type_register_static(&versatile_pci_host_info);
}
device_init(versatile_pci_register_devices)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 0312b75..6e28e78 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -365,17 +365,26 @@
machine_init(versatile_machine_init);
-static SysBusDeviceInfo vpb_sic_info = {
- .init = vpb_sic_init,
- .qdev.name = "versatilepb_sic",
- .qdev.size = sizeof(vpb_sic_state),
- .qdev.vmsd = &vmstate_vpb_sic,
- .qdev.no_user = 1,
+static void vpb_sic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = vpb_sic_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_vpb_sic;
+}
+
+static TypeInfo vpb_sic_info = {
+ .name = "versatilepb_sic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(vpb_sic_state),
+ .class_init = vpb_sic_class_init,
};
static void versatilepb_register_devices(void)
{
- sysbus_register_withprop(&vpb_sic_info);
+ type_register_static(&vpb_sic_info);
}
device_init(versatilepb_register_devices)
diff --git a/hw/vexpress.c b/hw/vexpress.c
index 7111556..64fab45 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -182,6 +182,7 @@
/* 0x100ec000 TrustZone Address Space Controller */
/* 0x10200000 CoreSight debug APB */
/* 0x1e00a000 PL310 L2 Cache Controller */
+ sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
/* CS0: NOR0 flash : 0x40000000 .. 0x44000000 */
/* CS4: NOR1 flash : 0x44000000 .. 0x48000000 */
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 4825313..8d3ff0d 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -69,16 +69,24 @@
return 0;
}
-static ISADeviceInfo vga_info = {
- .qdev.name = "isa-vga",
- .qdev.size = sizeof(ISAVGAState),
- .qdev.vmsd = &vmstate_vga_common,
- .qdev.reset = vga_reset_isa,
- .init = vga_initfn,
+static void vga_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = vga_initfn;
+ dc->reset = vga_reset_isa;
+ dc->vmsd = &vmstate_vga_common;
+}
+
+static TypeInfo vga_info = {
+ .name = "isa-vga",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAVGAState),
+ .class_init = vga_class_initfn,
};
static void vga_register(void)
{
- isa_qdev_register(&vga_info);
+ type_register_static(&vga_info);
}
device_init(vga_register)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index a75dbf3..974a7a9 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -75,22 +75,29 @@
return &pci_create_simple(bus, -1, "VGA")->qdev;
}
-static PCIDeviceInfo vga_info = {
- .qdev.name = "VGA",
- .qdev.size = sizeof(PCIVGAState),
- .qdev.vmsd = &vmstate_vga_pci,
- .no_hotplug = 1,
- .init = pci_vga_initfn,
- .romfile = "vgabios-stdvga.bin",
+static void vga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- /* dummy VGA (same as Bochs ID) */
- .vendor_id = PCI_VENDOR_ID_QEMU,
- .device_id = PCI_DEVICE_ID_QEMU_VGA,
- .class_id = PCI_CLASS_DISPLAY_VGA,
+ k->no_hotplug = 1;
+ k->init = pci_vga_initfn;
+ k->romfile = "vgabios-stdvga.bin";
+ k->vendor_id = PCI_VENDOR_ID_QEMU;
+ k->device_id = PCI_DEVICE_ID_QEMU_VGA;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ dc->vmsd = &vmstate_vga_pci;
+}
+
+static TypeInfo vga_info = {
+ .name = "VGA",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIVGAState),
+ .class_init = vga_class_init,
};
static void vga_register(void)
{
- pci_qdev_register(&vga_info);
+ type_register_static(&vga_info);
}
device_init(vga_register);
diff --git a/hw/vga.c b/hw/vga.c
index 950f97e..d87c4f9 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "hw.h"
+#include "vga.h"
#include "console.h"
#include "pc.h"
#include "pci.h"
@@ -36,6 +37,18 @@
//#define DEBUG_BOCHS_VBE
+/*
+ * Video Graphics Array (VGA)
+ *
+ * Chipset docs for original IBM VGA:
+ * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
+ *
+ * FreeVGA site:
+ * http://www.osdever.net/FreeVGA/home.htm
+ *
+ * Standard VGA features and Bochs VBE extensions are implemented.
+ */
+
/* force some bits to zero */
const uint8_t sr_mask[8] = {
0x03,
@@ -160,9 +173,10 @@
s->chain4_alias = NULL;
- if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
+ if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
+ VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
offset = 0;
- switch ((s->gr[6] >> 2) & 3) {
+ switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
case 0:
base = 0xa0000;
size = 0x20000;
@@ -223,22 +237,20 @@
int64_t chars_per_sec;
struct vga_precise_retrace *r = &s->retrace_info.precise;
- htotal_chars = s->cr[0x00] + 5;
- hretr_start_char = s->cr[0x04];
- hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
- hretr_end_char = s->cr[0x05] & 0x1f;
+ htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
+ hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
+ hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
+ hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
- vtotal_lines = (s->cr[0x06]
- | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
- ;
- vretr_start_line = s->cr[0x10]
- | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
- ;
- vretr_end_line = s->cr[0x11] & 0xf;
+ vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
+ (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
+ ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
+ vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
+ ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
+ ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
+ vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
-
-
- clocking_mode = (s->sr[0x01] >> 3) & 1;
+ clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
clock_sel = (s->msr >> 2) & 3;
dots = (s->msr & 1) ? 8 : 9;
@@ -261,8 +273,8 @@
r->htotal = htotal_chars;
#if 0
- div2 = (s->cr[0x17] >> 2) & 1;
- sldiv2 = (s->cr[0x17] >> 3) & 1;
+ div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
+ sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
printf (
"hz=%f\n"
"htotal = %d\n"
@@ -332,7 +344,7 @@
int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
{
- if (s->msr & MSR_COLOR_EMULATION) {
+ if (s->msr & VGA_MIS_COLOR) {
/* Color */
return (addr >= 0x3b0 && addr <= 0x3bf);
} else {
@@ -350,73 +362,74 @@
val = 0xff;
} else {
switch(addr) {
- case 0x3c0:
+ case VGA_ATT_W:
if (s->ar_flip_flop == 0) {
val = s->ar_index;
} else {
val = 0;
}
break;
- case 0x3c1:
+ case VGA_ATT_R:
index = s->ar_index & 0x1f;
- if (index < 21)
+ if (index < VGA_ATT_C) {
val = s->ar[index];
- else
+ } else {
val = 0;
+ }
break;
- case 0x3c2:
+ case VGA_MIS_W:
val = s->st00;
break;
- case 0x3c4:
+ case VGA_SEQ_I:
val = s->sr_index;
break;
- case 0x3c5:
+ case VGA_SEQ_D:
val = s->sr[s->sr_index];
#ifdef DEBUG_VGA_REG
printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
#endif
break;
- case 0x3c7:
+ case VGA_PEL_IR:
val = s->dac_state;
break;
- case 0x3c8:
+ case VGA_PEL_IW:
val = s->dac_write_index;
break;
- case 0x3c9:
+ case VGA_PEL_D:
val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
if (++s->dac_sub_index == 3) {
s->dac_sub_index = 0;
s->dac_read_index++;
}
break;
- case 0x3ca:
+ case VGA_FTC_R:
val = s->fcr;
break;
- case 0x3cc:
+ case VGA_MIS_R:
val = s->msr;
break;
- case 0x3ce:
+ case VGA_GFX_I:
val = s->gr_index;
break;
- case 0x3cf:
+ case VGA_GFX_D:
val = s->gr[s->gr_index];
#ifdef DEBUG_VGA_REG
printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
#endif
break;
- case 0x3b4:
- case 0x3d4:
+ case VGA_CRT_IM:
+ case VGA_CRT_IC:
val = s->cr_index;
break;
- case 0x3b5:
- case 0x3d5:
+ case VGA_CRT_DM:
+ case VGA_CRT_DC:
val = s->cr[s->cr_index];
#ifdef DEBUG_VGA_REG
printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
#endif
break;
- case 0x3ba:
- case 0x3da:
+ case VGA_IS1_RM:
+ case VGA_IS1_RC:
/* just toggle to fool polling */
val = s->st01 = s->retrace(s);
s->ar_flip_flop = 0;
@@ -446,29 +459,29 @@
#endif
switch(addr) {
- case 0x3c0:
+ case VGA_ATT_W:
if (s->ar_flip_flop == 0) {
val &= 0x3f;
s->ar_index = val;
} else {
index = s->ar_index & 0x1f;
switch(index) {
- case 0x00 ... 0x0f:
+ case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
s->ar[index] = val & 0x3f;
break;
- case 0x10:
+ case VGA_ATC_MODE:
s->ar[index] = val & ~0x10;
break;
- case 0x11:
+ case VGA_ATC_OVERSCAN:
s->ar[index] = val;
break;
- case 0x12:
+ case VGA_ATC_PLANE_ENABLE:
s->ar[index] = val & ~0xc0;
break;
- case 0x13:
+ case VGA_ATC_PEL:
s->ar[index] = val & ~0xf0;
break;
- case 0x14:
+ case VGA_ATC_COLOR_PAGE:
s->ar[index] = val & ~0xf0;
break;
default:
@@ -477,32 +490,34 @@
}
s->ar_flip_flop ^= 1;
break;
- case 0x3c2:
+ case VGA_MIS_W:
s->msr = val & ~0x10;
s->update_retrace_info(s);
break;
- case 0x3c4:
+ case VGA_SEQ_I:
s->sr_index = val & 7;
break;
- case 0x3c5:
+ case VGA_SEQ_D:
#ifdef DEBUG_VGA_REG
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
- if (s->sr_index == 1) s->update_retrace_info(s);
+ if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
+ s->update_retrace_info(s);
+ }
vga_update_memory_access(s);
break;
- case 0x3c7:
+ case VGA_PEL_IR:
s->dac_read_index = val;
s->dac_sub_index = 0;
s->dac_state = 3;
break;
- case 0x3c8:
+ case VGA_PEL_IW:
s->dac_write_index = val;
s->dac_sub_index = 0;
s->dac_state = 0;
break;
- case 0x3c9:
+ case VGA_PEL_D:
s->dac_cache[s->dac_sub_index] = val;
if (++s->dac_sub_index == 3) {
memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
@@ -510,48 +525,51 @@
s->dac_write_index++;
}
break;
- case 0x3ce:
+ case VGA_GFX_I:
s->gr_index = val & 0x0f;
break;
- case 0x3cf:
+ case VGA_GFX_D:
#ifdef DEBUG_VGA_REG
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
vga_update_memory_access(s);
break;
- case 0x3b4:
- case 0x3d4:
+ case VGA_CRT_IM:
+ case VGA_CRT_IC:
s->cr_index = val;
break;
- case 0x3b5:
- case 0x3d5:
+ case VGA_CRT_DM:
+ case VGA_CRT_DC:
#ifdef DEBUG_VGA_REG
printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
#endif
/* handle CR0-7 protection */
- if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
+ if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
+ s->cr_index <= VGA_CRTC_OVERFLOW) {
/* can always write bit 4 of CR7 */
- if (s->cr_index == 7)
- s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
+ if (s->cr_index == VGA_CRTC_OVERFLOW) {
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
+ (val & 0x10);
+ }
return;
}
s->cr[s->cr_index] = val;
switch(s->cr_index) {
- case 0x00:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x11:
- case 0x17:
+ case VGA_CRTC_H_TOTAL:
+ case VGA_CRTC_H_SYNC_START:
+ case VGA_CRTC_H_SYNC_END:
+ case VGA_CRTC_V_TOTAL:
+ case VGA_CRTC_OVERFLOW:
+ case VGA_CRTC_V_SYNC_END:
+ case VGA_CRTC_MODE:
s->update_retrace_info(s);
break;
}
break;
- case 0x3ba:
- case 0x3da:
+ case VGA_IS1_RM:
+ case VGA_IS1_RC:
s->fcr = val & 0x10;
break;
}
@@ -681,31 +699,37 @@
/* we initialize the VGA graphic mode (should be done
in BIOS) */
- s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
- s->cr[0x17] |= 3; /* no CGA modes */
- s->cr[0x13] = s->vbe_line_offset >> 3;
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
/* width */
- s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
/* height (only meaningful if < 1024) */
h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[0x12] = h;
- s->cr[0x07] = (s->cr[0x07] & ~0x42) |
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
((h >> 7) & 0x02) | ((h >> 3) & 0x40);
/* line compare to 1023 */
- s->cr[0x18] = 0xff;
- s->cr[0x07] |= 0x10;
- s->cr[0x09] |= 0x40;
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
shift_control = 0;
- s->sr[0x01] &= ~8; /* no double line */
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
} else {
shift_control = 2;
- s->sr[4] |= 0x08; /* set chain 4 mode */
- s->sr[2] |= 0x0f; /* activate all planes */
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
}
- s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
- s->cr[0x09] &= ~0x9f; /* no double scan */
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
@@ -762,7 +786,7 @@
uint32_t ret;
/* convert to VGA memory offset */
- memory_map_mode = (s->gr[6] >> 2) & 3;
+ memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
addr &= 0x1ffff;
switch(memory_map_mode) {
case 0:
@@ -785,24 +809,25 @@
break;
}
- if (s->sr[4] & 0x08) {
+ if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
ret = s->vram_ptr[addr];
- } else if (s->gr[5] & 0x10) {
+ } else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
- plane = (s->gr[4] & 2) | (addr & 1);
+ plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
ret = s->vram_ptr[((addr & ~1) << 1) | plane];
} else {
/* standard VGA latched access */
s->latch = ((uint32_t *)s->vram_ptr)[addr];
- if (!(s->gr[5] & 0x08)) {
+ if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
/* read mode 0 */
- plane = s->gr[4];
+ plane = s->gr[VGA_GFX_PLANE_READ];
ret = GET_PLANE(s->latch, plane);
} else {
/* read mode 1 */
- ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
+ ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
+ mask16[s->gr[VGA_GFX_COMPARE_MASK]];
ret |= ret >> 16;
ret |= ret >> 8;
ret = (~ret) & 0xff;
@@ -821,7 +846,7 @@
printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
#endif
/* convert to VGA memory offset */
- memory_map_mode = (s->gr[6] >> 2) & 3;
+ memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
addr &= 0x1ffff;
switch(memory_map_mode) {
case 0:
@@ -844,67 +869,68 @@
break;
}
- if (s->sr[4] & 0x08) {
+ if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
plane = addr & 3;
mask = (1 << plane);
- if (s->sr[2] & mask) {
+ if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
- memory_region_set_dirty(&s->vram, addr);
+ memory_region_set_dirty(&s->vram, addr, 1);
}
- } else if (s->gr[5] & 0x10) {
+ } else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
- plane = (s->gr[4] & 2) | (addr & 1);
+ plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
mask = (1 << plane);
- if (s->sr[2] & mask) {
+ if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
- memory_region_set_dirty(&s->vram, addr);
+ memory_region_set_dirty(&s->vram, addr, 1);
}
} else {
/* standard VGA latched access */
- write_mode = s->gr[5] & 3;
+ write_mode = s->gr[VGA_GFX_MODE] & 3;
switch(write_mode) {
default:
case 0:
/* rotate */
- b = s->gr[3] & 7;
+ b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
val = ((val >> b) | (val << (8 - b))) & 0xff;
val |= val << 8;
val |= val << 16;
/* apply set/reset mask */
- set_mask = mask16[s->gr[1]];
- val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
- bit_mask = s->gr[8];
+ set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
+ val = (val & ~set_mask) |
+ (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
+ bit_mask = s->gr[VGA_GFX_BIT_MASK];
break;
case 1:
val = s->latch;
goto do_write;
case 2:
val = mask16[val & 0x0f];
- bit_mask = s->gr[8];
+ bit_mask = s->gr[VGA_GFX_BIT_MASK];
break;
case 3:
/* rotate */
- b = s->gr[3] & 7;
+ b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
val = (val >> b) | (val << (8 - b));
- bit_mask = s->gr[8] & val;
- val = mask16[s->gr[0]];
+ bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
+ val = mask16[s->gr[VGA_GFX_SR_VALUE]];
break;
}
/* apply logical operation */
- func_select = s->gr[3] >> 3;
+ func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
switch(func_select) {
case 0:
default:
@@ -931,7 +957,7 @@
do_write:
/* mask data according to sr[2] */
- mask = s->sr[2];
+ mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
((uint32_t *)s->vram_ptr)[addr] =
@@ -941,7 +967,7 @@
printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
addr * 4, write_mask, val);
#endif
- memory_region_set_dirty(&s->vram, addr << 2);
+ memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
}
}
@@ -1045,10 +1071,11 @@
palette = s->last_palette;
for(i = 0; i < 16; i++) {
v = s->ar[i];
- if (s->ar[0x10] & 0x80)
- v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
- else
- v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
+ if (s->ar[VGA_ATC_MODE] & 0x80) {
+ v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
+ } else {
+ v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
+ }
v = v * 3;
col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
c6_to_8(s->palette[v + 1]),
@@ -1104,16 +1131,17 @@
#endif
{
/* compute line_offset in bytes */
- line_offset = s->cr[0x13];
+ line_offset = s->cr[VGA_CRTC_OFFSET];
line_offset <<= 3;
/* starting address */
- start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
+ start_addr = s->cr[VGA_CRTC_START_LO] |
+ (s->cr[VGA_CRTC_START_HI] << 8);
/* line compare */
- line_compare = s->cr[0x18] |
- ((s->cr[0x07] & 0x10) << 4) |
- ((s->cr[0x09] & 0x40) << 3);
+ line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
+ ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
}
*pline_offset = line_offset;
*pstart_addr = start_addr;
@@ -1216,20 +1244,22 @@
int width, cwidth, height, cheight;
/* total width & height */
- cheight = (s->cr[9] & 0x1f) + 1;
+ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
cwidth = 8;
- if (!(s->sr[1] & 0x01))
+ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
cwidth = 9;
- if (s->sr[1] & 0x08)
+ }
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
cwidth = 16; /* NOTE: no 18 pixel wide */
- width = (s->cr[0x01] + 1);
- if (s->cr[0x06] == 100) {
+ }
+ width = (s->cr[VGA_CRTC_H_DISP] + 1);
+ if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
/* ugly hack for CGA 160x100x16 - explain me the logic */
height = 100;
} else {
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
height = (height + 1) / cheight;
}
@@ -1273,7 +1303,7 @@
vga_draw_glyph9_func *vga_draw_glyph9;
/* compute font data address (in plane 2) */
- v = s->sr[3];
+ v = s->sr[VGA_SEQ_CHARACTER_MAP];
offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
if (offset != s->font_offsets[0]) {
s->font_offsets[0] = offset;
@@ -1321,10 +1351,11 @@
palette = s->last_palette;
x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
- cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
if (cursor_offset != s->cursor_offset ||
- s->cr[0xa] != s->cursor_start ||
- s->cr[0xb] != s->cursor_end) {
+ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
/* if the cursor position changed, we update the old and new
chars */
if (s->cursor_offset < CH_ATTR_SIZE)
@@ -1332,8 +1363,8 @@
if (cursor_offset < CH_ATTR_SIZE)
s->last_ch_attr[cursor_offset] = -1;
s->cursor_offset = cursor_offset;
- s->cursor_start = s->cr[0xa];
- s->cursor_end = s->cr[0xb];
+ s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+ s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
}
cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
@@ -1378,17 +1409,19 @@
font_ptr, cheight, fgcol, bgcol);
} else {
dup9 = 0;
- if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
+ if (ch >= 0xb0 && ch <= 0xdf &&
+ (s->ar[VGA_ATC_MODE] & 0x04)) {
dup9 = 1;
+ }
vga_draw_glyph9(d1, linesize,
font_ptr, cheight, fgcol, bgcol, dup9);
}
if (src == cursor_ptr &&
- !(s->cr[0x0a] & 0x20)) {
+ !(s->cr[VGA_CRTC_CURSOR_START] & 0x20)) {
int line_start, line_last, h;
/* draw the cursor */
- line_start = s->cr[0x0a] & 0x1f;
- line_last = s->cr[0x0b] & 0x1f;
+ line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
+ line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
/* XXX: check that */
if (line_last > cheight - 1)
line_last = cheight - 1;
@@ -1544,10 +1577,10 @@
} else
#endif
{
- width = (s->cr[0x01] + 1) * 8;
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
+ width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
height = (height + 1);
}
*pwidth = width;
@@ -1602,10 +1635,11 @@
s->get_resolution(s, &width, &height);
disp_width = width;
- shift_control = (s->gr[0x05] >> 5) & 3;
- double_scan = (s->cr[0x09] >> 7);
+ shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
+ double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
if (shift_control != 1) {
- multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
+ multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
+ - 1;
} else {
/* in CGA modes, multi_scan is ignored */
/* XXX: is it correct ? */
@@ -1620,11 +1654,11 @@
}
if (shift_control == 0) {
- if (s->sr[0x01] & 8) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
disp_width <<= 1;
}
} else if (shift_control == 1) {
- if (s->sr[0x01] & 8) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
disp_width <<= 1;
}
}
@@ -1668,7 +1702,7 @@
if (shift_control == 0) {
full_update |= update_palette16(s);
- if (s->sr[0x01] & 8) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
v = VGA_DRAW_LINE4D2;
} else {
v = VGA_DRAW_LINE4;
@@ -1676,7 +1710,7 @@
bits = 4;
} else if (shift_control == 1) {
full_update |= update_palette16(s);
- if (s->sr[0x01] & 8) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
v = VGA_DRAW_LINE2D2;
} else {
v = VGA_DRAW_LINE2;
@@ -1721,7 +1755,8 @@
line_offset = s->line_offset;
#if 0
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
- width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
+ width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
+ s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
#endif
addr1 = (s->start_addr * 4);
bwidth = (width * bits + 7) / 8;
@@ -1733,26 +1768,19 @@
y1 = 0;
for(y = 0; y < height; y++) {
addr = addr1;
- if (!(s->cr[0x17] & 1)) {
+ if (!(s->cr[VGA_CRTC_MODE] & 1)) {
int shift;
/* CGA compatibility handling */
- shift = 14 + ((s->cr[0x17] >> 6) & 1);
+ shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
}
- if (!(s->cr[0x17] & 2)) {
+ if (!(s->cr[VGA_CRTC_MODE] & 2)) {
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
}
- page0 = addr & TARGET_PAGE_MASK;
- page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
- update = full_update |
- memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
- memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
- if ((page1 - page0) > TARGET_PAGE_SIZE) {
- /* if wide line, can use another page */
- update |= memory_region_get_dirty(&s->vram,
- page0 + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- }
+ page0 = addr;
+ page1 = addr + bwidth - 1;
+ update = memory_region_get_dirty(&s->vram, page0, page1,
+ DIRTY_MEMORY_VGA);
/* explicit invalidation for the hardware cursor */
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
if (update) {
@@ -1776,7 +1804,7 @@
}
}
if (!multi_run) {
- mask = (s->cr[0x17] & 3) ^ 3;
+ mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
if ((y1 & mask) == mask)
addr1 += line_offset;
y1++;
@@ -1798,7 +1826,7 @@
if (page_max >= page_min) {
memory_region_reset_dirty(&s->vram,
page_min,
- page_max + TARGET_PAGE_SIZE - page_min,
+ page_max - page_min,
DIRTY_MEMORY_VGA);
}
memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
@@ -1848,7 +1876,7 @@
if (!(s->ar_index & 0x20)) {
graphic_mode = GMODE_BLANK;
} else {
- graphic_mode = s->gr[6] & 1;
+ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
}
if (graphic_mode != s->graphic_mode) {
s->graphic_mode = graphic_mode;
@@ -1966,7 +1994,7 @@
if (!(s->ar_index & 0x20)) {
graphic_mode = GMODE_BLANK;
} else {
- graphic_mode = s->gr[6] & 1;
+ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
}
if (graphic_mode != s->graphic_mode) {
s->graphic_mode = graphic_mode;
@@ -1983,20 +2011,22 @@
full_update |= update_basic_params(s);
/* total width & height */
- cheight = (s->cr[9] & 0x1f) + 1;
+ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
cw = 8;
- if (!(s->sr[1] & 0x01))
+ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
cw = 9;
- if (s->sr[1] & 0x08)
+ }
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
cw = 16; /* NOTE: no 18 pixel wide */
- width = (s->cr[0x01] + 1);
- if (s->cr[0x06] == 100) {
+ }
+ width = (s->cr[VGA_CRTC_H_DISP] + 1);
+ if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
/* ugly hack for CGA 160x100x16 - explain me the logic */
height = 100;
} else {
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
height = (height + 1) / cheight;
}
@@ -2025,11 +2055,12 @@
}
/* Update "hardware" cursor */
- cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
if (cursor_offset != s->cursor_offset ||
- s->cr[0xa] != s->cursor_start ||
- s->cr[0xb] != s->cursor_end || full_update) {
- cursor_visible = !(s->cr[0xa] & 0x20);
+ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
+ cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
dpy_cursor(s->ds,
TEXTMODE_X(cursor_offset),
@@ -2037,8 +2068,8 @@
else
dpy_cursor(s->ds, -1, -1);
s->cursor_offset = cursor_offset;
- s->cursor_start = s->cr[0xa];
- s->cursor_end = s->cr[0xb];
+ s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+ s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
}
src = (uint32_t *) s->vram_ptr + s->start_addr;
diff --git a/hw/vga.h b/hw/vga.h
new file mode 100644
index 0000000..d917046
--- /dev/null
+++ b/hw/vga.h
@@ -0,0 +1,159 @@
+/*
+ * linux/include/video/vga.h -- standard VGA chipset interaction
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ *
+ * Copyright history from vga16fb.c:
+ * Copyright 1999 Ben Pfaff and Petr Vandrovec
+ * Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
+ * Based on VESA framebuffer (c) 1998 Gerd Knorr
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ */
+
+#ifndef __linux_video_vga_h__
+#define __linux_video_vga_h__
+
+/* Some of the code below is taken from SVGAlib. The original,
+ unmodified copyright notice for that code is below. */
+/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */
+/* */
+/* This library is free software; you can redistribute it and/or */
+/* modify it without any restrictions. This library is distributed */
+/* in the hope that it will be useful, but without any warranty. */
+
+/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
+/* partially copyrighted (C) 1993 by Hartmut Schirmer */
+
+/* VGA data register ports */
+#define VGA_CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */
+#define VGA_CRT_DM 0x3B5 /* CRT Controller Data Register - mono emulation */
+#define VGA_ATT_R 0x3C1 /* Attribute Controller Data Read Register */
+#define VGA_ATT_W 0x3C0 /* Attribute Controller Data Write Register */
+#define VGA_GFX_D 0x3CF /* Graphics Controller Data Register */
+#define VGA_SEQ_D 0x3C5 /* Sequencer Data Register */
+#define VGA_MIS_R 0x3CC /* Misc Output Read Register */
+#define VGA_MIS_W 0x3C2 /* Misc Output Write Register */
+#define VGA_FTC_R 0x3CA /* Feature Control Read Register */
+#define VGA_IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
+#define VGA_IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
+#define VGA_PEL_D 0x3C9 /* PEL Data Register */
+#define VGA_PEL_MSK 0x3C6 /* PEL mask register */
+
+/* EGA-specific registers */
+#define EGA_GFX_E0 0x3CC /* Graphics enable processor 0 */
+#define EGA_GFX_E1 0x3CA /* Graphics enable processor 1 */
+
+/* VGA index register ports */
+#define VGA_CRT_IC 0x3D4 /* CRT Controller Index - color emulation */
+#define VGA_CRT_IM 0x3B4 /* CRT Controller Index - mono emulation */
+#define VGA_ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
+#define VGA_GFX_I 0x3CE /* Graphics Controller Index */
+#define VGA_SEQ_I 0x3C4 /* Sequencer Index */
+#define VGA_PEL_IW 0x3C8 /* PEL Write Index */
+#define VGA_PEL_IR 0x3C7 /* PEL Read Index */
+
+/* standard VGA indexes max counts */
+#define VGA_CRT_C 0x19 /* Number of CRT Controller Registers */
+#define VGA_ATT_C 0x15 /* Number of Attribute Controller Registers */
+#define VGA_GFX_C 0x09 /* Number of Graphics Controller Registers */
+#define VGA_SEQ_C 0x05 /* Number of Sequencer Registers */
+#define VGA_MIS_C 0x01 /* Number of Misc Output Register */
+
+/* VGA misc register bit masks */
+#define VGA_MIS_COLOR 0x01
+#define VGA_MIS_ENB_MEM_ACCESS 0x02
+#define VGA_MIS_DCLK_28322_720 0x04
+#define VGA_MIS_ENB_PLL_LOAD (0x04 | 0x08)
+#define VGA_MIS_SEL_HIGH_PAGE 0x20
+
+/* VGA CRT controller register indices */
+#define VGA_CRTC_H_TOTAL 0
+#define VGA_CRTC_H_DISP 1
+#define VGA_CRTC_H_BLANK_START 2
+#define VGA_CRTC_H_BLANK_END 3
+#define VGA_CRTC_H_SYNC_START 4
+#define VGA_CRTC_H_SYNC_END 5
+#define VGA_CRTC_V_TOTAL 6
+#define VGA_CRTC_OVERFLOW 7
+#define VGA_CRTC_PRESET_ROW 8
+#define VGA_CRTC_MAX_SCAN 9
+#define VGA_CRTC_CURSOR_START 0x0A
+#define VGA_CRTC_CURSOR_END 0x0B
+#define VGA_CRTC_START_HI 0x0C
+#define VGA_CRTC_START_LO 0x0D
+#define VGA_CRTC_CURSOR_HI 0x0E
+#define VGA_CRTC_CURSOR_LO 0x0F
+#define VGA_CRTC_V_SYNC_START 0x10
+#define VGA_CRTC_V_SYNC_END 0x11
+#define VGA_CRTC_V_DISP_END 0x12
+#define VGA_CRTC_OFFSET 0x13
+#define VGA_CRTC_UNDERLINE 0x14
+#define VGA_CRTC_V_BLANK_START 0x15
+#define VGA_CRTC_V_BLANK_END 0x16
+#define VGA_CRTC_MODE 0x17
+#define VGA_CRTC_LINE_COMPARE 0x18
+#define VGA_CRTC_REGS VGA_CRT_C
+
+/* VGA CRT controller bit masks */
+#define VGA_CR11_LOCK_CR0_CR7 0x80 /* lock writes to CR0 - CR7 */
+#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
+
+/* VGA attribute controller register indices */
+#define VGA_ATC_PALETTE0 0x00
+#define VGA_ATC_PALETTE1 0x01
+#define VGA_ATC_PALETTE2 0x02
+#define VGA_ATC_PALETTE3 0x03
+#define VGA_ATC_PALETTE4 0x04
+#define VGA_ATC_PALETTE5 0x05
+#define VGA_ATC_PALETTE6 0x06
+#define VGA_ATC_PALETTE7 0x07
+#define VGA_ATC_PALETTE8 0x08
+#define VGA_ATC_PALETTE9 0x09
+#define VGA_ATC_PALETTEA 0x0A
+#define VGA_ATC_PALETTEB 0x0B
+#define VGA_ATC_PALETTEC 0x0C
+#define VGA_ATC_PALETTED 0x0D
+#define VGA_ATC_PALETTEE 0x0E
+#define VGA_ATC_PALETTEF 0x0F
+#define VGA_ATC_MODE 0x10
+#define VGA_ATC_OVERSCAN 0x11
+#define VGA_ATC_PLANE_ENABLE 0x12
+#define VGA_ATC_PEL 0x13
+#define VGA_ATC_COLOR_PAGE 0x14
+
+#define VGA_AR_ENABLE_DISPLAY 0x20
+
+/* VGA sequencer register indices */
+#define VGA_SEQ_RESET 0x00
+#define VGA_SEQ_CLOCK_MODE 0x01
+#define VGA_SEQ_PLANE_WRITE 0x02
+#define VGA_SEQ_CHARACTER_MAP 0x03
+#define VGA_SEQ_MEMORY_MODE 0x04
+
+/* VGA sequencer register bit masks */
+#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */
+#define VGA_SR01_SCREEN_OFF 0x20 /* bit 5: Screen is off */
+#define VGA_SR02_ALL_PLANES 0x0F /* bits 3-0: enable access to all planes */
+#define VGA_SR04_EXT_MEM 0x02 /* bit 1: allows complete mem access to 256K */
+#define VGA_SR04_SEQ_MODE 0x04 /* bit 2: directs system to use a sequential addressing mode */
+#define VGA_SR04_CHN_4M 0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
+
+/* VGA graphics controller register indices */
+#define VGA_GFX_SR_VALUE 0x00
+#define VGA_GFX_SR_ENABLE 0x01
+#define VGA_GFX_COMPARE_VALUE 0x02
+#define VGA_GFX_DATA_ROTATE 0x03
+#define VGA_GFX_PLANE_READ 0x04
+#define VGA_GFX_MODE 0x05
+#define VGA_GFX_MISC 0x06
+#define VGA_GFX_COMPARE_MASK 0x07
+#define VGA_GFX_BIT_MASK 0x08
+
+/* VGA graphics controller bit masks */
+#define VGA_GR06_GRAPHICS_MODE 0x01
+
+#endif /* __linux_video_vga_h__ */
diff --git a/hw/vga_int.h b/hw/vga_int.h
index c1e700f..7685b2b 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -25,9 +25,6 @@
#include <hw/hw.h>
#include "memory.h"
-#define MSR_COLOR_EMULATION 0x01
-#define MSR_PAGE_SELECT 0x20
-
#define ST01_V_RETRACE 0x08
#define ST01_DISP_ENABLE 0x01
@@ -205,19 +202,6 @@
void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
int ppm_save(const char *filename, struct DisplaySurface *ds);
-void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-
int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
diff --git a/hw/vga_template.h b/hw/vga_template.h
index 681425f..f6f6a01 100644
--- a/hw/vga_template.h
+++ b/hw/vga_template.h
@@ -161,7 +161,7 @@
int x;
palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
+ plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
@@ -203,7 +203,7 @@
int x;
palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
+ plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
@@ -236,7 +236,7 @@
int x;
palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
+ plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
@@ -268,7 +268,7 @@
int x;
palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
+ plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
@@ -340,72 +340,6 @@
}
}
-void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
- const uint8_t *src1,
- int poffset, int w,
- unsigned int color0,
- unsigned int color1,
- unsigned int color_xor)
-{
- const uint8_t *plane0, *plane1;
- int x, b0, b1;
- uint8_t *d;
-
- d = d1;
- plane0 = src1;
- plane1 = src1 + poffset;
- for(x = 0; x < w; x++) {
- b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
- b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
-#if DEPTH == 8
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- d[0] ^= color_xor;
- break;
- case 2:
- d[0] = color0;
- break;
- case 3:
- d[0] = color1;
- break;
- }
-#elif DEPTH == 16
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint16_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint16_t *)d)[0] = color0;
- break;
- case 3:
- ((uint16_t *)d)[0] = color1;
- break;
- }
-#elif DEPTH == 32
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint32_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint32_t *)d)[0] = color0;
- break;
- case 3:
- ((uint32_t *)d)[0] = color1;
- break;
- }
-#else
-#error unsupported depth
-#endif
- d += BPP;
- }
-}
-
#endif /* DEPTH != 15 */
diff --git a/hw/vhost.c b/hw/vhost.c
index 4778521..5ece659 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -55,7 +55,7 @@
ram_addr_t ram_addr;
bit -= 1;
ram_addr = section->offset_within_region + bit * VHOST_LOG_PAGE;
- memory_region_set_dirty(section->mr, ram_addr);
+ memory_region_set_dirty(section->mr, ram_addr, VHOST_LOG_PAGE);
log &= ~(0x1ull << bit);
}
addr += VHOST_LOG_CHUNK;
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index bd16b97..f8d2b1b 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -38,7 +38,6 @@
#include "ppc.h"
#include "ppc4xx.h"
-#include "ppc440.h"
#include "ppc405.h"
#include "blockdev.h"
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 5b416c3..a5a4396 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -346,6 +346,8 @@
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
+ trace_virtio_blk_handle_read(req, sector, req->qiov.size / 512);
+
if (sector & req->dev->sector_mask) {
virtio_blk_rw_complete(req, -EIO);
return;
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 0b28a30..4f2c3e4 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -109,10 +109,9 @@
static int virtconsole_initfn(VirtIOSerialPort *port)
{
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
- VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
- vcon->port.dev.info);
+ VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
- if (port->id == 0 && !info->is_console) {
+ if (port->id == 0 && !k->is_console) {
error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
return -1;
}
@@ -125,41 +124,63 @@
return 0;
}
-static VirtIOSerialPortInfo virtconsole_info = {
- .qdev.name = "virtconsole",
- .qdev.size = sizeof(VirtConsole),
- .is_console = true,
- .init = virtconsole_initfn,
- .have_data = flush_buf,
- .guest_open = guest_open,
- .guest_close = guest_close,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property virtconsole_properties[] = {
+ DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtconsole_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
+
+ k->is_console = true;
+ k->init = virtconsole_initfn;
+ k->have_data = flush_buf;
+ k->guest_open = guest_open;
+ k->guest_close = guest_close;
+ dc->props = virtconsole_properties;
+}
+
+static TypeInfo virtconsole_info = {
+ .name = "virtconsole",
+ .parent = TYPE_VIRTIO_SERIAL_PORT,
+ .instance_size = sizeof(VirtConsole),
+ .class_init = virtconsole_class_init,
};
static void virtconsole_register(void)
{
- virtio_serial_port_qdev_register(&virtconsole_info);
+ type_register_static(&virtconsole_info);
}
device_init(virtconsole_register)
-static VirtIOSerialPortInfo virtserialport_info = {
- .qdev.name = "virtserialport",
- .qdev.size = sizeof(VirtConsole),
- .init = virtconsole_initfn,
- .have_data = flush_buf,
- .guest_open = guest_open,
- .guest_close = guest_close,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property virtserialport_properties[] = {
+ DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtserialport_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
+
+ k->init = virtconsole_initfn;
+ k->have_data = flush_buf;
+ k->guest_open = guest_open;
+ k->guest_close = guest_close;
+ dc->props = virtserialport_properties;
+}
+
+static TypeInfo virtserialport_info = {
+ .name = "virtserialport",
+ .parent = TYPE_VIRTIO_SERIAL_PORT,
+ .instance_size = sizeof(VirtConsole),
+ .class_init = virtserialport_class_init,
};
static void virtserialport_register(void)
{
- virtio_serial_port_qdev_register(&virtserialport_info);
+ type_register_static(&virtserialport_info);
}
device_init(virtserialport_register)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 8c2f460..bc5e3a8 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -1030,7 +1030,7 @@
memcpy(&n->mac[0], &conf->macaddr, sizeof(n->mac));
n->status = VIRTIO_NET_S_LINK_UP;
- n->nic = qemu_new_nic(&net_virtio_info, conf, dev->info->name, dev->id, n);
+ n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n);
qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a);
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index caff0aa..93fff54 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -91,6 +91,9 @@
*/
#define wmb() do { } while (0)
+/* HACK for virtio to determine if it's running a big endian guest */
+bool virtio_is_big_endian(void);
+
/* virtio device */
static void virtio_pci_notify(void *opaque, uint16_t vector)
@@ -414,20 +417,35 @@
{
VirtIOPCIProxy *proxy = opaque;
uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+ uint16_t val;
if (addr < config)
return virtio_ioport_read(proxy, addr);
addr -= config;
- return virtio_config_readw(proxy->vdev, addr);
+ val = virtio_config_readw(proxy->vdev, addr);
+ if (virtio_is_big_endian()) {
+ /*
+ * virtio is odd, ioports are LE but config space is target native
+ * endian. However, in qemu, all PIO is LE, so we need to re-swap
+ * on BE targets
+ */
+ val = bswap16(val);
+ }
+ return val;
}
static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr)
{
VirtIOPCIProxy *proxy = opaque;
uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+ uint32_t val;
if (addr < config)
return virtio_ioport_read(proxy, addr);
addr -= config;
- return virtio_config_readl(proxy->vdev, addr);
+ val = virtio_config_readl(proxy->vdev, addr);
+ if (virtio_is_big_endian()) {
+ val = bswap32(val);
+ }
+ return val;
}
static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val)
@@ -451,6 +469,9 @@
return;
}
addr -= config;
+ if (virtio_is_big_endian()) {
+ val = bswap16(val);
+ }
virtio_config_writew(proxy->vdev, addr, val);
}
@@ -463,6 +484,9 @@
return;
}
addr -= config;
+ if (virtio_is_big_endian()) {
+ val = bswap32(val);
+ }
virtio_config_writel(proxy->vdev, addr, val);
}
@@ -782,98 +806,136 @@
return virtio_exit_pci(pci_dev);
}
-static PCIDeviceInfo virtio_info[] = {
- {
- .qdev.name = "virtio-blk-pci",
- .qdev.alias = "virtio-blk",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_blk_init_pci,
- .exit = virtio_blk_exit_pci,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_BLOCK,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = PCI_CLASS_STORAGE_SCSI,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
- DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
- },{
- .qdev.name = "virtio-net-pci",
- .qdev.alias = "virtio-net",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_net_init_pci,
- .exit = virtio_net_exit_pci,
- .romfile = "pxe-virtio.rom",
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_NET,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
- DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
- DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
- net.txtimer, TX_TIMER_INTERVAL),
- DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
- net.txburst, TX_BURST),
- DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
- },{
- .qdev.name = "virtio-serial-pci",
- .qdev.alias = "virtio-serial",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_serial_init_pci,
- .exit = virtio_serial_exit_pci,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = PCI_CLASS_COMMUNICATION_OTHER,
- .qdev.props = (Property[]) {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
- DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy,
- serial.max_virtserial_ports, 31),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
- },{
- .qdev.name = "virtio-balloon-pci",
- .qdev.alias = "virtio-balloon",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_balloon_init_pci,
- .exit = virtio_balloon_exit_pci,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = PCI_CLASS_MEMORY_RAM,
- .qdev.props = (Property[]) {
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
- },{
- /* end of list */
- }
+static Property virtio_blk_properties[] = {
+ DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
+ DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_blk_init_pci;
+ k->exit = virtio_blk_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_STORAGE_SCSI;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_blk_properties;
+}
+
+static TypeInfo virtio_blk_info = {
+ .name = "virtio-blk-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_blk_class_init,
+};
+
+static Property virtio_net_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+ DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
+ DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy, net.txtimer, TX_TIMER_INTERVAL),
+ DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy, net.txburst, TX_BURST),
+ DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_net_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_net_init_pci;
+ k->exit = virtio_net_exit_pci;
+ k->romfile = "pxe-virtio.rom";
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_net_properties;
+}
+
+static TypeInfo virtio_net_info = {
+ .name = "virtio-net-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_net_class_init,
+};
+
+static Property virtio_serial_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_serial_init_pci;
+ k->exit = virtio_serial_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_serial_properties;
+}
+
+static TypeInfo virtio_serial_info = {
+ .name = "virtio-serial-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_serial_class_init,
+};
+
+static Property virtio_balloon_properties[] = {
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_balloon_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_balloon_init_pci;
+ k->exit = virtio_balloon_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_MEMORY_RAM;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_balloon_properties;
+}
+
+static TypeInfo virtio_balloon_info = {
+ .name = "virtio-balloon-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_balloon_class_init,
};
static void virtio_pci_register_devices(void)
{
- pci_qdev_register_many(virtio_info);
+ type_register_static(&virtio_blk_info);
+ type_register_static(&virtio_net_info);
+ type_register_static(&virtio_serial_info);
+ type_register_static(&virtio_balloon_info);
}
device_init(virtio_pci_register_devices)
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 32e46e9..6117629 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -133,12 +133,12 @@
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
VirtIODevice *vdev)
{
- VirtIOSerialPortInfo *info;
+ VirtIOSerialPortClass *vsc;
assert(port);
assert(virtio_queue_ready(vq));
- info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+ vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
while (!port->throttled) {
unsigned int i;
@@ -157,7 +157,7 @@
ssize_t ret;
buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
- ret = info->have_data(port,
+ ret = vsc->have_data(port,
port->elem.out_sg[i].iov_base
+ port->iov_offset,
buf_size);
@@ -176,7 +176,7 @@
* 1: chardevs can notify frondends
* 2: the guest driver does not spin in these cases
*/
- if (!info->is_console) {
+ if (!vsc->is_console) {
virtio_serial_throttle_port(port, true);
}
port->iov_idx = i;
@@ -331,7 +331,7 @@
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
{
struct VirtIOSerialPort *port;
- struct VirtIOSerialPortInfo *info;
+ VirtIOSerialPortClass *vsc;
struct virtio_console_control cpkt, *gcpkt;
uint8_t *buffer;
size_t buffer_len;
@@ -373,7 +373,7 @@
trace_virtio_serial_handle_control_message_port(port->id);
- info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+ vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
switch(cpkt.event) {
case VIRTIO_CONSOLE_PORT_READY:
@@ -389,7 +389,7 @@
* this port is a console port so that the guest can hook it
* up to hvc.
*/
- if (info->is_console) {
+ if (vsc->is_console) {
send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
}
@@ -418,21 +418,21 @@
* initialised. If some app is interested in knowing about
* this event, let it know.
*/
- if (info->guest_ready) {
- info->guest_ready(port);
+ if (vsc->guest_ready) {
+ vsc->guest_ready(port);
}
break;
case VIRTIO_CONSOLE_PORT_OPEN:
port->guest_connected = cpkt.value;
- if (cpkt.value && info->guest_open) {
+ if (cpkt.value && vsc->guest_open) {
/* Send the guest opened notification if an app is interested */
- info->guest_open(port);
+ vsc->guest_open(port);
}
- if (!cpkt.value && info->guest_close) {
+ if (!cpkt.value && vsc->guest_close) {
/* Send the guest closed notification if an app is interested */
- info->guest_close(port);
+ vsc->guest_close(port);
}
break;
}
@@ -748,10 +748,10 @@
send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
}
-static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int virtser_port_qdev_init(DeviceState *qdev)
{
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
- VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
+ VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
int ret, max_nr_ports;
bool plugging_port0;
@@ -759,14 +759,14 @@
port->vser = bus->vser;
port->bh = qemu_bh_new(flush_queued_data_bh, port);
- assert(info->have_data);
+ assert(vsc->have_data);
/*
* Is the first console port we're seeing? If so, put it up at
* location 0. This is done for backward compatibility (old
* kernel, new qemu).
*/
- plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0);
+ plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0);
if (find_port_by_id(port->vser, port->id)) {
error_report("virtio-serial-bus: A port already exists at id %u",
@@ -793,7 +793,7 @@
return -1;
}
- ret = info->init(port);
+ ret = vsc->init(port);
if (ret) {
return ret;
}
@@ -823,8 +823,7 @@
static int virtser_port_qdev_exit(DeviceState *qdev)
{
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
- VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
- port->dev.info);
+ VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
VirtIOSerial *vser = port->vser;
qemu_bh_delete(port->bh);
@@ -832,21 +831,12 @@
QTAILQ_REMOVE(&vser->ports, port, next);
- if (info->exit) {
- info->exit(port);
+ if (vsc->exit) {
+ vsc->exit(port);
}
return 0;
}
-void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
-{
- info->qdev.init = virtser_port_qdev_init;
- info->qdev.bus_info = &virtser_bus_info;
- info->qdev.exit = virtser_port_qdev_exit;
- info->qdev.unplug = qdev_simple_unplug_cb;
- qdev_register(&info->qdev);
-}
-
VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
{
VirtIOSerial *vser;
@@ -940,3 +930,28 @@
virtio_cleanup(vdev);
}
+
+static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = virtser_port_qdev_init;
+ k->bus_info = &virtser_bus_info;
+ k->exit = virtser_port_qdev_exit;
+ k->unplug = qdev_simple_unplug_cb;
+}
+
+static TypeInfo virtio_serial_port_type_info = {
+ .name = TYPE_VIRTIO_SERIAL_PORT,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(VirtIOSerialPort),
+ .abstract = true,
+ .class_size = sizeof(VirtIOSerialPortClass),
+ .class_init = virtio_serial_port_class_init,
+};
+
+static void virtio_serial_register_devices(void)
+{
+ type_register_static(&virtio_serial_port_type_info);
+}
+
+device_init(virtio_serial_register_devices);
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
index ab13803..16e3982 100644
--- a/hw/virtio-serial.h
+++ b/hw/virtio-serial.h
@@ -62,10 +62,52 @@
/* == In-qemu interface == */
+#define TYPE_VIRTIO_SERIAL_PORT "virtio-serial-port"
+#define VIRTIO_SERIAL_PORT(obj) \
+ OBJECT_CHECK(VirtIOSerialPort, (obj), TYPE_VIRTIO_SERIAL_PORT)
+#define VIRTIO_SERIAL_PORT_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VirtIOSerialPortClass, (klass), TYPE_VIRTIO_SERIAL_PORT)
+#define VIRTIO_SERIAL_PORT_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VirtIOSerialPortClass, (obj), TYPE_VIRTIO_SERIAL_PORT)
+
typedef struct VirtIOSerial VirtIOSerial;
typedef struct VirtIOSerialBus VirtIOSerialBus;
typedef struct VirtIOSerialPort VirtIOSerialPort;
-typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
+
+typedef struct VirtIOSerialPortClass {
+ DeviceClass parent_class;
+
+ /* Is this a device that binds with hvc in the guest? */
+ bool is_console;
+
+ /*
+ * The per-port (or per-app) init function that's called when a
+ * new device is found on the bus.
+ */
+ int (*init)(VirtIOSerialPort *port);
+ /*
+ * Per-port exit function that's called when a port gets
+ * hot-unplugged or removed.
+ */
+ int (*exit)(VirtIOSerialPort *port);
+
+ /* Callbacks for guest events */
+ /* Guest opened device. */
+ void (*guest_open)(VirtIOSerialPort *port);
+ /* Guest closed device. */
+ void (*guest_close)(VirtIOSerialPort *port);
+
+ /* Guest is now ready to accept data (virtqueues set up). */
+ void (*guest_ready)(VirtIOSerialPort *port);
+
+ /*
+ * Guest wrote some data to the port. This data is handed over to
+ * the app via this callback. The app can return a size less than
+ * 'len'. In this case, throttling will be enabled for this port.
+ */
+ ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
+ size_t len);
+} VirtIOSerialPortClass;
/*
* This is the state that's shared between all the ports. Some of the
@@ -131,50 +173,9 @@
bool throttled;
};
-struct VirtIOSerialPortInfo {
- DeviceInfo qdev;
-
- /* Is this a device that binds with hvc in the guest? */
- bool is_console;
-
- /*
- * The per-port (or per-app) init function that's called when a
- * new device is found on the bus.
- */
- int (*init)(VirtIOSerialPort *port);
- /*
- * Per-port exit function that's called when a port gets
- * hot-unplugged or removed.
- */
- int (*exit)(VirtIOSerialPort *port);
-
- /* Callbacks for guest events */
- /* Guest opened device. */
- void (*guest_open)(VirtIOSerialPort *port);
- /* Guest closed device. */
- void (*guest_close)(VirtIOSerialPort *port);
-
- /* Guest is now ready to accept data (virtqueues set up). */
- void (*guest_ready)(VirtIOSerialPort *port);
-
- /*
- * Guest wrote some data to the port. This data is handed over to
- * the app via this callback. The app can return a size less than
- * 'len'. In this case, throttling will be enabled for this port.
- */
- ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
- size_t len);
-};
-
/* Interface to the virtio-serial bus */
/*
- * Individual ports/apps should call this function to register the port
- * with the virtio-serial bus
- */
-void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info);
-
-/*
* Open a connection to the port
* Returns 0 on success (always).
*/
diff --git a/hw/virtio.c b/hw/virtio.c
index 81ecc40..74cc038 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -539,7 +539,7 @@
if (addr > (vdev->config_len - sizeof(val)))
return (uint32_t)-1;
- memcpy(&val, vdev->config + addr, sizeof(val));
+ val = ldub_p(vdev->config + addr);
return val;
}
@@ -552,7 +552,7 @@
if (addr > (vdev->config_len - sizeof(val)))
return (uint32_t)-1;
- memcpy(&val, vdev->config + addr, sizeof(val));
+ val = lduw_p(vdev->config + addr);
return val;
}
@@ -565,7 +565,7 @@
if (addr > (vdev->config_len - sizeof(val)))
return (uint32_t)-1;
- memcpy(&val, vdev->config + addr, sizeof(val));
+ val = ldl_p(vdev->config + addr);
return val;
}
@@ -576,7 +576,7 @@
if (addr > (vdev->config_len - sizeof(val)))
return;
- memcpy(vdev->config + addr, &val, sizeof(val));
+ stb_p(vdev->config + addr, val);
if (vdev->set_config)
vdev->set_config(vdev, vdev->config);
@@ -589,7 +589,7 @@
if (addr > (vdev->config_len - sizeof(val)))
return;
- memcpy(vdev->config + addr, &val, sizeof(val));
+ stw_p(vdev->config + addr, val);
if (vdev->set_config)
vdev->set_config(vdev, vdev->config);
@@ -602,7 +602,7 @@
if (addr > (vdev->config_len - sizeof(val)))
return;
- memcpy(vdev->config + addr, &val, sizeof(val));
+ stl_p(vdev->config + addr, val);
if (vdev->set_config)
vdev->set_config(vdev, vdev->config);
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index 1113f33..fda4f89 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -254,6 +254,8 @@
s->status = 0xffff;
s->queue_size = VMMOUSE_QUEUE_SIZE;
+
+ vmmouse_disable(s);
}
static int vmmouse_initfn(ISADevice *dev)
@@ -269,21 +271,31 @@
return 0;
}
-static ISADeviceInfo vmmouse_info = {
- .init = vmmouse_initfn,
- .qdev.name = "vmmouse",
- .qdev.size = sizeof(VMMouseState),
- .qdev.vmsd = &vmstate_vmmouse,
- .qdev.no_user = 1,
- .qdev.reset = vmmouse_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property vmmouse_properties[] = {
+ DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmmouse_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = vmmouse_initfn;
+ dc->no_user = 1;
+ dc->reset = vmmouse_reset;
+ dc->vmsd = &vmstate_vmmouse;
+ dc->props = vmmouse_properties;
+}
+
+static TypeInfo vmmouse_info = {
+ .name = "vmmouse",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(VMMouseState),
+ .class_init = vmmouse_class_initfn,
};
static void vmmouse_dev_register(void)
{
- isa_qdev_register(&vmmouse_info);
+ type_register_static(&vmmouse_info);
}
device_init(vmmouse_dev_register)
diff --git a/hw/vmport.c b/hw/vmport.c
index 0a3dbc5..a2c45e1 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -144,15 +144,23 @@
return 0;
}
-static ISADeviceInfo vmport_info = {
- .qdev.name = "vmport",
- .qdev.size = sizeof(VMPortState),
- .qdev.no_user = 1,
- .init = vmport_initfn,
+static void vmport_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = vmport_initfn;
+ dc->no_user = 1;
+}
+
+static TypeInfo vmport_info = {
+ .name = "vmport",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(VMPortState),
+ .class_init = vmport_class_initfn,
};
static void vmport_dev_register(void)
{
- isa_qdev_register(&vmport_info);
+ type_register_static(&vmport_info);
}
device_init(vmport_dev_register)
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index b1885c3..3f3eb21 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1199,24 +1199,32 @@
return 0;
}
-static PCIDeviceInfo vmsvga_info = {
- .qdev.name = "vmware-svga",
- .qdev.size = sizeof(struct pci_vmsvga_state_s),
- .qdev.vmsd = &vmstate_vmware_vga,
- .qdev.reset = vmsvga_reset,
- .no_hotplug = 1,
- .init = pci_vmsvga_initfn,
- .romfile = "vgabios-vmware.bin",
+static void vmsvga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- .vendor_id = PCI_VENDOR_ID_VMWARE,
- .device_id = SVGA_PCI_DEVICE_ID,
- .class_id = PCI_CLASS_DISPLAY_VGA,
- .subsystem_vendor_id = PCI_VENDOR_ID_VMWARE,
- .subsystem_id = SVGA_PCI_DEVICE_ID,
+ k->no_hotplug = 1;
+ k->init = pci_vmsvga_initfn;
+ k->romfile = "vgabios-vmware.bin";
+ k->vendor_id = PCI_VENDOR_ID_VMWARE;
+ k->device_id = SVGA_PCI_DEVICE_ID;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
+ k->subsystem_id = SVGA_PCI_DEVICE_ID;
+ dc->reset = vmsvga_reset;
+ dc->vmsd = &vmstate_vmware_vga;
+}
+
+static TypeInfo vmsvga_info = {
+ .name = "vmware-svga",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(struct pci_vmsvga_state_s),
+ .class_init = vmsvga_class_init,
};
static void vmsvga_register(void)
{
- pci_qdev_register(&vmsvga_info);
+ type_register_static(&vmsvga_info);
}
device_init(vmsvga_register);
diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h
index db11cbf..000fbdd 100644
--- a/hw/vmware_vga.h
+++ b/hw/vmware_vga.h
@@ -8,12 +8,8 @@
{
PCIDevice *dev;
- dev = pci_try_create(bus, -1, "vmware-svga");
- if (!dev || qdev_init(&dev->qdev) < 0) {
- return NULL;
- } else {
- return &dev->qdev;
- }
+ dev = pci_create_simple(bus, -1, "vmware-svga");
+ return &dev->qdev;
}
#endif
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 7fb88a5..aa0954f 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -346,20 +346,29 @@
qdev_init_nofail(&dev->qdev);
}
-static PCIDeviceInfo via_ac97_info = {
- .qdev.name = "VT82C686B_AC97",
- .qdev.desc = "AC97",
- .qdev.size = sizeof(VT686AC97State),
- .init = vt82c686b_ac97_initfn,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_AC97,
- .revision = 0x50,
- .class_id = PCI_CLASS_MULTIMEDIA_AUDIO,
+static void via_ac97_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_ac97_initfn;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_AC97;
+ k->revision = 0x50;
+ k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+ dc->desc = "AC97";
+}
+
+static TypeInfo via_ac97_info = {
+ .name = "VT82C686B_AC97",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VT686AC97State),
+ .class_init = via_ac97_class_init,
};
static void vt82c686b_ac97_register(void)
{
- pci_qdev_register(&via_ac97_info);
+ type_register_static(&via_ac97_info);
}
device_init(vt82c686b_ac97_register);
@@ -385,20 +394,29 @@
qdev_init_nofail(&dev->qdev);
}
-static PCIDeviceInfo via_mc97_info = {
- .qdev.name = "VT82C686B_MC97",
- .qdev.desc = "MC97",
- .qdev.size = sizeof(VT686MC97State),
- .init = vt82c686b_mc97_initfn,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_MC97,
- .class_id = PCI_CLASS_COMMUNICATION_OTHER,
- .revision = 0x30,
+static void via_mc97_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_mc97_initfn;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_MC97;
+ k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+ k->revision = 0x30;
+ dc->desc = "MC97";
+}
+
+static TypeInfo via_mc97_info = {
+ .name = "VT82C686B_MC97",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VT686MC97State),
+ .class_init = via_mc97_class_init,
};
static void vt82c686b_mc97_register(void)
{
- pci_qdev_register(&via_mc97_info);
+ type_register_static(&via_mc97_info);
}
device_init(vt82c686b_mc97_register);
@@ -451,26 +469,37 @@
return s->smb.smbus;
}
-static PCIDeviceInfo via_pm_info = {
- .qdev.name = "VT82C686B_PM",
- .qdev.desc = "PM",
- .qdev.size = sizeof(VT686PMState),
- .qdev.vmsd = &vmstate_acpi,
- .init = vt82c686b_pm_initfn,
- .config_write = pm_write_config,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_ACPI,
- .class_id = PCI_CLASS_BRIDGE_OTHER,
- .revision = 0x40,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property via_pm_properties[] = {
+ DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void via_pm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_pm_initfn;
+ k->config_write = pm_write_config;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_ACPI;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+ k->revision = 0x40;
+ dc->desc = "PM";
+ dc->vmsd = &vmstate_acpi;
+ dc->props = via_pm_properties;
+}
+
+static TypeInfo via_pm_info = {
+ .name = "VT82C686B_PM",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VT686PMState),
+ .class_init = via_pm_class_init,
};
static void vt82c686b_pm_register(void)
{
- pci_qdev_register(&via_pm_info);
+ type_register_static(&via_pm_info);
}
device_init(vt82c686b_pm_register);
@@ -519,22 +548,31 @@
return DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0"));
}
-static PCIDeviceInfo via_info = {
- .qdev.name = "VT82C686B",
- .qdev.desc = "ISA bridge",
- .qdev.size = sizeof(VT82C686BState),
- .qdev.vmsd = &vmstate_via,
- .qdev.no_user = 1,
- .init = vt82c686b_initfn,
- .config_write = vt82c686b_write_config,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE,
- .class_id = PCI_CLASS_BRIDGE_ISA,
- .revision = 0x40,
+static void via_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_initfn;
+ k->config_write = vt82c686b_write_config;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+ k->revision = 0x40;
+ dc->desc = "ISA bridge";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_via;
+}
+
+static TypeInfo via_info = {
+ .name = "VT82C686B",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VT82C686BState),
+ .class_init = via_class_init,
};
static void vt82c686b_register(void)
{
- pci_qdev_register(&via_info);
+ type_register_static(&via_info);
}
device_init(vt82c686b_register);
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 20d8673..41325f0 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -143,7 +143,7 @@
static void i6300esb_reset(DeviceState *dev)
{
- PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
+ PCIDevice *pdev = PCI_DEVICE(dev);
I6300State *d = DO_UPCAST(I6300State, dev, pdev);
i6300esb_debug("I6300State = %p\n", d);
@@ -425,24 +425,33 @@
.wdt_description = "Intel 6300ESB",
};
-static PCIDeviceInfo i6300esb_info = {
- .qdev.name = "i6300esb",
- .qdev.size = sizeof(I6300State),
- .qdev.vmsd = &vmstate_i6300esb,
- .qdev.reset = i6300esb_reset,
- .config_read = i6300esb_config_read,
- .config_write = i6300esb_config_write,
- .init = i6300esb_init,
- .exit = i6300esb_exit,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_ESB_9,
- .class_id = PCI_CLASS_SYSTEM_OTHER,
+static void i6300esb_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->config_read = i6300esb_config_read;
+ k->config_write = i6300esb_config_write;
+ k->init = i6300esb_init;
+ k->exit = i6300esb_exit;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
+ k->class_id = PCI_CLASS_SYSTEM_OTHER;
+ dc->reset = i6300esb_reset;
+ dc->vmsd = &vmstate_i6300esb;
+}
+
+static TypeInfo i6300esb_info = {
+ .name = "i6300esb",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(I6300State),
+ .class_init = i6300esb_class_init,
};
static void i6300esb_register_devices(void)
{
watchdog_add_model(&model);
- pci_qdev_register(&i6300esb_info);
+ type_register_static(&i6300esb_info);
}
device_init(i6300esb_register_devices);
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
index ba1d92d..8faa231 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -120,18 +120,26 @@
.wdt_description = "iBASE 700",
};
-static ISADeviceInfo wdt_ib700_info = {
- .qdev.name = "ib700",
- .qdev.size = sizeof(IB700State),
- .qdev.vmsd = &vmstate_ib700,
- .qdev.reset = wdt_ib700_reset,
- .init = wdt_ib700_init,
+static void wdt_ib700_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = wdt_ib700_init;
+ dc->reset = wdt_ib700_reset;
+ dc->vmsd = &vmstate_ib700;
+}
+
+static TypeInfo wdt_ib700_info = {
+ .name = "ib700",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(IB700State),
+ .class_init = wdt_ib700_class_init,
};
static void wdt_ib700_register_devices(void)
{
watchdog_add_model(&model);
- isa_qdev_register(&wdt_ib700_info);
+ type_register_static(&wdt_ib700_info);
}
device_init(wdt_ib700_register_devices);
diff --git a/hw/wm8750.c b/hw/wm8750.c
index 9fbdf3d..18afa4c 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -24,7 +24,7 @@
} WMRate;
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
uint8_t i2c_data[2];
int i2c_len;
QEMUSoundCard card;
@@ -254,7 +254,7 @@
}
}
-static void wm8750_reset(i2c_slave *i2c)
+static void wm8750_reset(I2CSlave *i2c)
{
WM8750State *s = (WM8750State *) i2c;
s->rate = &wm_rate_table[0];
@@ -297,7 +297,7 @@
s->i2c_len = 0;
}
-static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
+static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
{
WM8750State *s = (WM8750State *) i2c;
@@ -354,7 +354,7 @@
#define WM8750_ROUT2V 0x29
#define WM8750_MOUTV 0x2a
-static int wm8750_tx(i2c_slave *i2c, uint8_t data)
+static int wm8750_tx(I2CSlave *i2c, uint8_t data)
{
WM8750State *s = (WM8750State *) i2c;
uint8_t cmd;
@@ -554,7 +554,7 @@
return 0;
}
-static int wm8750_rx(i2c_slave *i2c)
+static int wm8750_rx(I2CSlave *i2c)
{
return 0x00;
}
@@ -609,7 +609,7 @@
}
};
-static int wm8750_init(i2c_slave *i2c)
+static int wm8750_init(I2CSlave *i2c)
{
WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
@@ -620,7 +620,7 @@
}
#if 0
-static void wm8750_fini(i2c_slave *i2c)
+static void wm8750_fini(I2CSlave *i2c)
{
WM8750State *s = (WM8750State *) i2c;
wm8750_reset(&s->i2c);
@@ -689,19 +689,28 @@
wm8750_clk_update(s, 1);
}
-static I2CSlaveInfo wm8750_info = {
- .qdev.name = "wm8750",
- .qdev.size = sizeof(WM8750State),
- .qdev.vmsd = &vmstate_wm8750,
- .init = wm8750_init,
- .event = wm8750_event,
- .recv = wm8750_rx,
- .send = wm8750_tx
+static void wm8750_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+ sc->init = wm8750_init;
+ sc->event = wm8750_event;
+ sc->recv = wm8750_rx;
+ sc->send = wm8750_tx;
+ dc->vmsd = &vmstate_wm8750;
+}
+
+static TypeInfo wm8750_info = {
+ .name = "wm8750",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(WM8750State),
+ .class_init = wm8750_class_init,
};
static void wm8750_register_devices(void)
{
- i2c_register_slave(&wm8750_info);
+ type_register_static(&wm8750_info);
}
device_init(wm8750_register_devices)
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index e62eaef..e757102 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -372,25 +372,33 @@
platform_fixed_ioport_reset(s);
}
-static PCIDeviceInfo xen_platform_info = {
- .init = xen_platform_initfn,
- .qdev.name = "xen-platform",
- .qdev.desc = "XEN platform pci device",
- .qdev.size = sizeof(PCIXenPlatformState),
- .qdev.vmsd = &vmstate_xen_platform,
- .qdev.reset = platform_reset,
+static void xen_platform_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- .vendor_id = PCI_VENDOR_ID_XEN,
- .device_id = PCI_DEVICE_ID_XEN_PLATFORM,
- .class_id = PCI_CLASS_OTHERS << 8 | 0x80,
- .subsystem_vendor_id = PCI_VENDOR_ID_XEN,
- .subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM,
- .revision = 1,
+ k->init = xen_platform_initfn;
+ k->vendor_id = PCI_VENDOR_ID_XEN;
+ k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
+ k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
+ k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
+ k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
+ k->revision = 1;
+ dc->desc = "XEN platform pci device";
+ dc->reset = platform_reset;
+ dc->vmsd = &vmstate_xen_platform;
+}
+
+static TypeInfo xen_platform_info = {
+ .name = "xen-platform",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIXenPlatformState),
+ .class_init = xen_platform_class_init,
};
static void xen_platform_register(void)
{
- pci_qdev_register(&xen_platform_info);
+ type_register_static(&xen_platform_info);
}
device_init(xen_platform_register);
diff --git a/hw/xgmac.c b/hw/xgmac.c
new file mode 100644
index 0000000..d395b1c
--- /dev/null
+++ b/hw/xgmac.c
@@ -0,0 +1,433 @@
+/*
+ * QEMU model of XGMAC Ethernet.
+ *
+ * derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias.
+ *
+ * Copyright (c) 2011 Calxeda, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-char.h"
+#include "qemu-log.h"
+#include "net.h"
+#include "net/checksum.h"
+
+#ifdef DEBUG_XGMAC
+#define DEBUGF_BRK(message, args...) do { \
+ fprintf(stderr, (message), ## args); \
+ } while (0)
+#else
+#define DEBUGF_BRK(message, args...) do { } while (0)
+#endif
+
+#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */
+#define XGMAC_FRAME_FILTER 0x00000001 /* MAC Frame Filter */
+#define XGMAC_FLOW_CTRL 0x00000006 /* MAC Flow Control */
+#define XGMAC_VLAN_TAG 0x00000007 /* VLAN Tags */
+#define XGMAC_VERSION 0x00000008 /* Version */
+/* VLAN tag for insertion or replacement into tx frames */
+#define XGMAC_VLAN_INCL 0x00000009
+#define XGMAC_LPI_CTRL 0x0000000a /* LPI Control and Status */
+#define XGMAC_LPI_TIMER 0x0000000b /* LPI Timers Control */
+#define XGMAC_TX_PACE 0x0000000c /* Transmit Pace and Stretch */
+#define XGMAC_VLAN_HASH 0x0000000d /* VLAN Hash Table */
+#define XGMAC_DEBUG 0x0000000e /* Debug */
+#define XGMAC_INT_STATUS 0x0000000f /* Interrupt and Control */
+/* HASH table registers */
+#define XGMAC_HASH(n) ((0x00000300/4) + (n))
+#define XGMAC_NUM_HASH 16
+/* Operation Mode */
+#define XGMAC_OPMODE (0x00000400/4)
+/* Remote Wake-Up Frame Filter */
+#define XGMAC_REMOTE_WAKE (0x00000700/4)
+/* PMT Control and Status */
+#define XGMAC_PMT (0x00000704/4)
+
+#define XGMAC_ADDR_HIGH(reg) (0x00000010+((reg) * 2))
+#define XGMAC_ADDR_LOW(reg) (0x00000011+((reg) * 2))
+
+#define DMA_BUS_MODE 0x000003c0 /* Bus Mode */
+#define DMA_XMT_POLL_DEMAND 0x000003c1 /* Transmit Poll Demand */
+#define DMA_RCV_POLL_DEMAND 0x000003c2 /* Received Poll Demand */
+#define DMA_RCV_BASE_ADDR 0x000003c3 /* Receive List Base */
+#define DMA_TX_BASE_ADDR 0x000003c4 /* Transmit List Base */
+#define DMA_STATUS 0x000003c5 /* Status Register */
+#define DMA_CONTROL 0x000003c6 /* Ctrl (Operational Mode) */
+#define DMA_INTR_ENA 0x000003c7 /* Interrupt Enable */
+#define DMA_MISSED_FRAME_CTR 0x000003c8 /* Missed Frame Counter */
+/* Receive Interrupt Watchdog Timer */
+#define DMA_RI_WATCHDOG_TIMER 0x000003c9
+#define DMA_AXI_BUS 0x000003ca /* AXI Bus Mode */
+#define DMA_AXI_STATUS 0x000003cb /* AXI Status */
+#define DMA_CUR_TX_DESC_ADDR 0x000003d2 /* Current Host Tx Descriptor */
+#define DMA_CUR_RX_DESC_ADDR 0x000003d3 /* Current Host Rx Descriptor */
+#define DMA_CUR_TX_BUF_ADDR 0x000003d4 /* Current Host Tx Buffer */
+#define DMA_CUR_RX_BUF_ADDR 0x000003d5 /* Current Host Rx Buffer */
+#define DMA_HW_FEATURE 0x000003d6 /* Enabled Hardware Features */
+
+/* DMA Status register defines */
+#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
+#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
+#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
+#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
+#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
+#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
+#define DMA_STATUS_TS_SHIFT 20
+#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
+#define DMA_STATUS_RS_SHIFT 17
+#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
+#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
+#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
+#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
+#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
+#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
+#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
+#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
+#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
+#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
+#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
+#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
+#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
+#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
+#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
+
+/* DMA Control register defines */
+#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
+#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
+#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */
+
+struct desc {
+ uint32_t ctl_stat;
+ uint16_t buffer1_size;
+ uint16_t buffer2_size;
+ uint32_t buffer1_addr;
+ uint32_t buffer2_addr;
+ uint32_t ext_stat;
+ uint32_t res[3];
+};
+
+#define R_MAX 0x400
+
+typedef struct RxTxStats {
+ uint64_t rx_bytes;
+ uint64_t tx_bytes;
+
+ uint64_t rx;
+ uint64_t rx_bcast;
+ uint64_t rx_mcast;
+} RxTxStats;
+
+typedef struct XgmacState {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq sbd_irq;
+ qemu_irq pmt_irq;
+ qemu_irq mci_irq;
+ NICState *nic;
+ NICConf conf;
+
+ struct RxTxStats stats;
+ uint32_t regs[R_MAX];
+} XgmacState;
+
+const VMStateDescription vmstate_rxtx_stats = {
+ .name = "xgmac_stats",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(rx_bytes, RxTxStats),
+ VMSTATE_UINT64(tx_bytes, RxTxStats),
+ VMSTATE_UINT64(rx, RxTxStats),
+ VMSTATE_UINT64(rx_bcast, RxTxStats),
+ VMSTATE_UINT64(rx_mcast, RxTxStats),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_xgmac = {
+ .name = "xgmac",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(stats, XgmacState, 0, vmstate_rxtx_stats, RxTxStats),
+ VMSTATE_UINT32_ARRAY(regs, XgmacState, R_MAX),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void xgmac_read_desc(struct XgmacState *s, struct desc *d, int rx)
+{
+ uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] :
+ s->regs[DMA_CUR_TX_DESC_ADDR];
+ cpu_physical_memory_read(addr, d, sizeof(*d));
+}
+
+static void xgmac_write_desc(struct XgmacState *s, struct desc *d, int rx)
+{
+ int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR;
+ uint32_t addr = s->regs[reg];
+
+ if (!rx && (d->ctl_stat & 0x00200000)) {
+ s->regs[reg] = s->regs[DMA_TX_BASE_ADDR];
+ } else if (rx && (d->buffer1_size & 0x8000)) {
+ s->regs[reg] = s->regs[DMA_RCV_BASE_ADDR];
+ } else {
+ s->regs[reg] += sizeof(*d);
+ }
+ cpu_physical_memory_write(addr, d, sizeof(*d));
+}
+
+static void xgmac_enet_send(struct XgmacState *s)
+{
+ struct desc bd;
+ int frame_size;
+ int len;
+ uint8_t frame[8192];
+ uint8_t *ptr;
+
+ ptr = frame;
+ frame_size = 0;
+ while (1) {
+ xgmac_read_desc(s, &bd, 0);
+ if ((bd.ctl_stat & 0x80000000) == 0) {
+ /* Run out of descriptors to transmit. */
+ break;
+ }
+ len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff);
+
+ if ((bd.buffer1_size & 0xfff) > 2048) {
+ DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
+ "xgmac buffer 1 len on send > 2048 (0x%x)\n",
+ __func__, bd.buffer1_size & 0xfff);
+ }
+ if ((bd.buffer2_size & 0xfff) != 0) {
+ DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
+ "xgmac buffer 2 len on send != 0 (0x%x)\n",
+ __func__, bd.buffer2_size & 0xfff);
+ }
+ if (len >= sizeof(frame)) {
+ DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu "
+ "buffer\n" , __func__, len, sizeof(frame));
+ DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n",
+ __func__, bd.buffer1_size, bd.buffer2_size);
+ }
+
+ cpu_physical_memory_read(bd.buffer1_addr, ptr, len);
+ ptr += len;
+ frame_size += len;
+ if (bd.ctl_stat & 0x20000000) {
+ /* Last buffer in frame. */
+ qemu_send_packet(&s->nic->nc, frame, len);
+ ptr = frame;
+ frame_size = 0;
+ s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS;
+ }
+ bd.ctl_stat &= ~0x80000000;
+ /* Write back the modified descriptor. */
+ xgmac_write_desc(s, &bd, 0);
+ }
+}
+
+static void enet_update_irq(struct XgmacState *s)
+{
+ int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA];
+ qemu_set_irq(s->sbd_irq, !!stat);
+}
+
+static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+ struct XgmacState *s = opaque;
+ uint64_t r = 0;
+ addr >>= 2;
+
+ switch (addr) {
+ case XGMAC_VERSION:
+ r = 0x1012;
+ break;
+ default:
+ if (addr < ARRAY_SIZE(s->regs)) {
+ r = s->regs[addr];
+ }
+ break;
+ }
+ return r;
+}
+
+static void enet_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
+{
+ struct XgmacState *s = opaque;
+
+ addr >>= 2;
+ switch (addr) {
+ case DMA_BUS_MODE:
+ s->regs[DMA_BUS_MODE] = value & ~0x1;
+ break;
+ case DMA_XMT_POLL_DEMAND:
+ xgmac_enet_send(s);
+ break;
+ case DMA_STATUS:
+ s->regs[DMA_STATUS] = s->regs[DMA_STATUS] & ~value;
+ break;
+ case DMA_RCV_BASE_ADDR:
+ s->regs[DMA_RCV_BASE_ADDR] = s->regs[DMA_CUR_RX_DESC_ADDR] = value;
+ break;
+ case DMA_TX_BASE_ADDR:
+ s->regs[DMA_TX_BASE_ADDR] = s->regs[DMA_CUR_TX_DESC_ADDR] = value;
+ break;
+ default:
+ if (addr < ARRAY_SIZE(s->regs)) {
+ s->regs[addr] = value;
+ }
+ break;
+ }
+ enet_update_irq(s);
+}
+
+static const MemoryRegionOps enet_mem_ops = {
+ .read = enet_read,
+ .write = enet_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int eth_can_rx(VLANClientState *nc)
+{
+ struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+ /* RX enabled? */
+ return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
+}
+
+static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+ struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff};
+ int unicast, broadcast, multicast;
+ struct desc bd;
+ ssize_t ret;
+
+ unicast = ~buf[0] & 0x1;
+ broadcast = memcmp(buf, sa_bcast, 6) == 0;
+ multicast = !unicast && !broadcast;
+ if (size < 12) {
+ s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
+ ret = -1;
+ goto out;
+ }
+
+ xgmac_read_desc(s, &bd, 1);
+ if ((bd.ctl_stat & 0x80000000) == 0) {
+ s->regs[DMA_STATUS] |= DMA_STATUS_RU | DMA_STATUS_AIS;
+ ret = size;
+ goto out;
+ }
+
+ cpu_physical_memory_write(bd.buffer1_addr, buf, size);
+
+ /* Add in the 4 bytes for crc (the real hw returns length incl crc) */
+ size += 4;
+ bd.ctl_stat = (size << 16) | 0x300;
+ xgmac_write_desc(s, &bd, 1);
+
+ s->stats.rx_bytes += size;
+ s->stats.rx++;
+ if (multicast) {
+ s->stats.rx_mcast++;
+ } else if (broadcast) {
+ s->stats.rx_bcast++;
+ }
+
+ s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
+ ret = size;
+
+out:
+ enet_update_irq(s);
+ return ret;
+}
+
+static void eth_cleanup(VLANClientState *nc)
+{
+ struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ s->nic = NULL;
+}
+
+static NetClientInfo net_xgmac_enet_info = {
+ .type = NET_CLIENT_TYPE_NIC,
+ .size = sizeof(NICState),
+ .can_receive = eth_can_rx,
+ .receive = eth_rx,
+ .cleanup = eth_cleanup,
+};
+
+static int xgmac_enet_init(SysBusDevice *dev)
+{
+ struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev);
+
+ memory_region_init_io(&s->iomem, &enet_mem_ops, s, "xgmac", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->sbd_irq);
+ sysbus_init_irq(dev, &s->pmt_irq);
+ sysbus_init_irq(dev, &s->mci_irq);
+
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+ s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+ qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+ s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) |
+ s->conf.macaddr.a[4];
+ s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) |
+ (s->conf.macaddr.a[2] << 16) |
+ (s->conf.macaddr.a[1] << 8) |
+ s->conf.macaddr.a[0];
+
+ return 0;
+}
+
+static Property xgmac_properties[] = {
+ DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xgmac_enet_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ sbc->init = xgmac_enet_init;
+ dc->vmsd = &vmstate_xgmac;
+ dc->props = xgmac_properties;
+}
+
+static TypeInfo xgmac_enet_info = {
+ .name = "xgmac",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct XgmacState),
+ .class_init = xgmac_enet_class_init,
+};
+
+static void xgmac_enet_register(void)
+{
+ type_register_static(&xgmac_enet_info);
+}
+
+device_init(xgmac_enet_register)
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index 0da20d9..e8a5312 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -486,20 +486,31 @@
return 0;
}
-static SysBusDeviceInfo axidma_info = {
- .init = xilinx_axidma_init,
- .qdev.name = "xilinx,axidma",
- .qdev.size = sizeof(struct XilinxAXIDMA),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property axidma_properties[] = {
+ DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
+ DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void axidma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_axidma_init;
+ dc->props = axidma_properties;
+}
+
+static TypeInfo axidma_info = {
+ .name = "xilinx,axidma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct XilinxAXIDMA),
+ .class_init = axidma_class_init,
};
static void xilinx_axidma_register(void)
{
- sysbus_register_withprop(&axidma_info);
+ type_register_static(&axidma_info);
}
device_init(xilinx_axidma_register)
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index a2eb3e6..1ce2db4 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -856,7 +856,7 @@
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
tdk_init(&s->TEMAC.phy);
@@ -870,22 +870,33 @@
return 0;
}
-static SysBusDeviceInfo xilinx_enet_info = {
- .init = xilinx_enet_init,
- .qdev.name = "xilinx,axienet",
- .qdev.size = sizeof(struct XilinxAXIEnet),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
- DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
- DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
- DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xilinx_enet_properties[] = {
+ DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
+ DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
+ DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
+ DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
+ DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_enet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_enet_init;
+ dc->props = xilinx_enet_properties;
+}
+
+static TypeInfo xilinx_enet_info = {
+ .name = "xilinx,axienet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct XilinxAXIEnet),
+ .class_init = xilinx_enet_class_init,
};
static void xilinx_enet_register(void)
{
- sysbus_register_withprop(&xilinx_enet_info);
+ type_register_static(&xilinx_enet_info);
}
device_init(xilinx_enet_register)
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index 6777254..499feef 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -221,26 +221,37 @@
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
return 0;
}
-static SysBusDeviceInfo xilinx_ethlite_info = {
- .init = xilinx_ethlite_init,
- .qdev.name = "xilinx,ethlite",
- .qdev.size = sizeof(struct xlx_ethlite),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1),
- DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1),
- DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xilinx_ethlite_properties[] = {
+ DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1),
+ DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1),
+ DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_ethlite_init;
+ dc->props = xilinx_ethlite_properties;
+}
+
+static TypeInfo xilinx_ethlite_info = {
+ .name = "xilinx,ethlite",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct xlx_ethlite),
+ .class_init = xilinx_ethlite_class_init,
};
static void xilinx_ethlite_register(void)
{
- sysbus_register_withprop(&xilinx_ethlite_info);
+ type_register_static(&xilinx_ethlite_info);
}
device_init(xilinx_ethlite_register)
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
index c567885..73eed6d 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -161,19 +161,30 @@
return 0;
}
-static SysBusDeviceInfo xilinx_intc_info = {
- .init = xilinx_intc_init,
- .qdev.name = "xilinx,intc",
- .qdev.size = sizeof(struct xlx_pic),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xilinx_intc_properties[] = {
+ DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_intc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_intc_init;
+ dc->props = xilinx_intc_properties;
+}
+
+static TypeInfo xilinx_intc_info = {
+ .name = "xilinx,intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct xlx_pic),
+ .class_init = xilinx_intc_class_init,
};
static void xilinx_intc_register(void)
{
- sysbus_register_withprop(&xilinx_intc_info);
+ type_register_static(&xilinx_intc_info);
}
device_init(xilinx_intc_register)
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index adca53b..c8236d2 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -219,20 +219,31 @@
return 0;
}
-static SysBusDeviceInfo xilinx_timer_info = {
- .init = xilinx_timer_init,
- .qdev.name = "xilinx,timer",
- .qdev.size = sizeof(struct timerblock),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 0),
- DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xilinx_timer_properties[] = {
+ DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 0),
+ DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_timer_init;
+ dc->props = xilinx_timer_properties;
+}
+
+static TypeInfo xilinx_timer_info = {
+ .name = "xilinx,timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct timerblock),
+ .class_init = xilinx_timer_class_init,
};
static void xilinx_timer_register(void)
{
- sysbus_register_withprop(&xilinx_timer_info);
+ type_register_static(&xilinx_timer_info);
}
device_init(xilinx_timer_register)
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 6533df9..1c2b908 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -205,16 +205,29 @@
memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4);
sysbus_init_mmio(dev, &s->mmio);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr)
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
return 0;
}
+static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = xilinx_uartlite_init;
+}
+
+static TypeInfo xilinx_uartlite_info = {
+ .name = "xilinx,uartlite",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof (struct xlx_uartlite),
+ .class_init = xilinx_uartlite_class_init,
+};
+
static void xilinx_uart_register(void)
{
- sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite),
- xilinx_uartlite_init);
+ type_register_static(&xilinx_uartlite_info);
}
device_init(xilinx_uart_register)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index d3c387d..07e4fc1 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -47,7 +47,7 @@
static void xio3130_downstream_reset(DeviceState *qdev)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *d = PCI_DEVICE(qdev);
msi_reset(d);
pcie_cap_deverr_reset(d);
pcie_cap_slot_reset(d);
@@ -167,36 +167,45 @@
}
};
-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,
+static Property xio3130_downstream_properties[] = {
+ DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+ DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+ DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+ DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+ port.br.dev.exp.aer_log.log_max,
+ PCIE_AER_LOG_MAX_DEFAULT),
+ DEFINE_PROP_END_OF_LIST(),
+};
- .is_express = 1,
- .is_bridge = 1,
- .config_write = xio3130_downstream_write_config,
- .init = xio3130_downstream_initfn,
- .exit = xio3130_downstream_exitfn,
- .vendor_id = PCI_VENDOR_ID_TI,
- .device_id = PCI_DEVICE_ID_TI_XIO3130D,
- .revision = XIO3130_REVISION,
+static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- .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),
- DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
- port.br.dev.exp.aer_log.log_max,
- PCIE_AER_LOG_MAX_DEFAULT),
- DEFINE_PROP_END_OF_LIST(),
- }
+ k->is_express = 1;
+ k->is_bridge = 1;
+ k->config_write = xio3130_downstream_write_config;
+ k->init = xio3130_downstream_initfn;
+ k->exit = xio3130_downstream_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TI;
+ k->device_id = PCI_DEVICE_ID_TI_XIO3130D;
+ k->revision = XIO3130_REVISION;
+ dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
+ dc->reset = xio3130_downstream_reset;
+ dc->vmsd = &vmstate_xio3130_downstream;
+ dc->props = xio3130_downstream_properties;
+}
+
+static TypeInfo xio3130_downstream_info = {
+ .name = "xio3130-downstream",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIESlot),
+ .class_init = xio3130_downstream_class_init,
};
static void xio3130_downstream_register(void)
{
- pci_qdev_register(&xio3130_downstream_info);
+ type_register_static(&xio3130_downstream_info);
}
device_init(xio3130_downstream_register);
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 8283695..7887c92 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -46,7 +46,7 @@
static void xio3130_upstream_reset(DeviceState *qdev)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *d = PCI_DEVICE(qdev);
msi_reset(d);
pci_bridge_reset(qdev);
pcie_cap_deverr_reset(d);
@@ -144,33 +144,42 @@
}
};
-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,
+static Property xio3130_upstream_properties[] = {
+ DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
+ DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
+ PCIE_AER_LOG_MAX_DEFAULT),
+ DEFINE_PROP_END_OF_LIST(),
+};
- .is_express = 1,
- .is_bridge = 1,
- .config_write = xio3130_upstream_write_config,
- .init = xio3130_upstream_initfn,
- .exit = xio3130_upstream_exitfn,
- .vendor_id = PCI_VENDOR_ID_TI,
- .device_id = PCI_DEVICE_ID_TI_XIO3130U,
- .revision = XIO3130_REVISION,
+static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
- DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
- PCIE_AER_LOG_MAX_DEFAULT),
- DEFINE_PROP_END_OF_LIST(),
- }
+ k->is_express = 1;
+ k->is_bridge = 1;
+ k->config_write = xio3130_upstream_write_config;
+ k->init = xio3130_upstream_initfn;
+ k->exit = xio3130_upstream_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TI;
+ k->device_id = PCI_DEVICE_ID_TI_XIO3130U;
+ k->revision = XIO3130_REVISION;
+ dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
+ dc->reset = xio3130_upstream_reset;
+ dc->vmsd = &vmstate_xio3130_upstream;
+ dc->props = xio3130_upstream_properties;
+}
+
+static TypeInfo xio3130_upstream_info = {
+ .name = "x3130-upstream",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIEPort),
+ .class_init = xio3130_upstream_class_init,
};
static void xio3130_upstream_register(void)
{
- pci_qdev_register(&xio3130_upstream_info);
+ type_register_static(&xio3130_upstream_info);
}
device_init(xio3130_upstream_register);
diff --git a/hw/z2.c b/hw/z2.c
index 8d48488..654ac55 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -174,21 +174,30 @@
}
};
-static SSISlaveInfo zipit_lcd_info = {
- .qdev.name = "zipit-lcd",
- .qdev.size = sizeof(ZipitLCD),
- .qdev.vmsd = &vmstate_zipit_lcd_state,
- .init = zipit_lcd_init,
- .transfer = zipit_lcd_transfer
+static void zipit_lcd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = zipit_lcd_init;
+ k->transfer = zipit_lcd_transfer;
+ dc->vmsd = &vmstate_zipit_lcd_state;
+}
+
+static TypeInfo zipit_lcd_info = {
+ .name = "zipit-lcd",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(ZipitLCD),
+ .class_init = zipit_lcd_class_init,
};
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
int len;
uint8_t buf[3];
} AER915State;
-static int aer915_send(i2c_slave *i2c, uint8_t data)
+static int aer915_send(I2CSlave *i2c, uint8_t data)
{
AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
s->buf[s->len] = data;
@@ -206,7 +215,7 @@
return 0;
}
-static void aer915_event(i2c_slave *i2c, enum i2c_event event)
+static void aer915_event(I2CSlave *i2c, enum i2c_event event)
{
AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
switch (event) {
@@ -225,7 +234,7 @@
}
}
-static int aer915_recv(i2c_slave *slave)
+static int aer915_recv(I2CSlave *slave)
{
int retval = 0x00;
AER915State *s = FROM_I2C_SLAVE(AER915State, slave);
@@ -248,7 +257,7 @@
return retval;
}
-static int aer915_init(i2c_slave *i2c)
+static int aer915_init(I2CSlave *i2c)
{
/* Nothing to do. */
return 0;
@@ -266,14 +275,23 @@
}
};
-static I2CSlaveInfo aer915_info = {
- .qdev.name = "aer915",
- .qdev.size = sizeof(AER915State),
- .qdev.vmsd = &vmstate_aer915_state,
- .init = aer915_init,
- .event = aer915_event,
- .recv = aer915_recv,
- .send = aer915_send
+static void aer915_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = aer915_init;
+ k->event = aer915_event;
+ k->recv = aer915_recv;
+ k->send = aer915_send;
+ dc->vmsd = &vmstate_aer915_state;
+}
+
+static TypeInfo aer915_info = {
+ .name = "aer915",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(AER915State),
+ .class_init = aer915_class_init,
};
static void z2_init(ram_addr_t ram_size,
@@ -326,8 +344,8 @@
NULL,
qdev_get_gpio_in(cpu->gpio, Z2_GPIO_SD_DETECT));
- ssi_register_slave(&zipit_lcd_info);
- i2c_register_slave(&aer915_info);
+ type_register_static(&zipit_lcd_info);
+ type_register_static(&aer915_info);
z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd");
bus = pxa2xx_i2c_bus(cpu->i2c[0]);
i2c_create_slave(bus, "aer915", 0x55);
diff --git a/hw/zaurus.c b/hw/zaurus.c
index c4bcd29..055df9b 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -221,20 +221,31 @@
},
};
-static SysBusDeviceInfo scoop_sysbus_info = {
- .init = scoop_init,
- .qdev.name = "scoop",
- .qdev.desc = "Scoop2 Sharp custom ASIC",
- .qdev.size = sizeof(ScoopInfo),
- .qdev.vmsd = &vmstate_scoop_regs,
- .qdev.props = (Property[]) {
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property scoop_sysbus_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = scoop_init;
+ dc->desc = "Scoop2 Sharp custom ASIC";
+ dc->vmsd = &vmstate_scoop_regs;
+ dc->props = scoop_sysbus_properties;
+}
+
+static TypeInfo scoop_sysbus_info = {
+ .name = "scoop",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ScoopInfo),
+ .class_init = scoop_sysbus_class_init,
};
static void scoop_register(void)
{
- sysbus_register_withprop(&scoop_sysbus_info);
+ type_register_static(&scoop_sysbus_info);
}
device_init(scoop_register);
diff --git a/include/qemu/object.h b/include/qemu/object.h
new file mode 100644
index 0000000..9d0251d
--- /dev/null
+++ b/include/qemu/object.h
@@ -0,0 +1,662 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 QEMU_OBJECT_H
+#define QEMU_OBJECT_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "qemu-queue.h"
+
+struct Visitor;
+struct Error;
+
+struct TypeImpl;
+typedef struct TypeImpl *Type;
+
+typedef struct ObjectClass ObjectClass;
+typedef struct Object Object;
+
+typedef struct TypeInfo TypeInfo;
+
+typedef struct InterfaceClass InterfaceClass;
+typedef struct InterfaceInfo InterfaceInfo;
+
+#define TYPE_OBJECT NULL
+
+/**
+ * SECTION:object.h
+ * @title:Base Object Type System
+ * @short_description: interfaces for creating new types and objects
+ *
+ * The QEMU Object Model provides a framework for registering user creatable
+ * types and instantiating objects from those types. QOM provides the following
+ * features:
+ *
+ * - System for dynamically registering types
+ * - Support for single-inheritance of types
+ * - Multiple inheritance of stateless interfaces
+ *
+ * <example>
+ * <title>Creating a minimal type</title>
+ * <programlisting>
+ * #include "qdev.h"
+ *
+ * #define TYPE_MY_DEVICE "my-device"
+ *
+ * typedef struct MyDevice
+ * {
+ * DeviceState parent;
+ *
+ * int reg0, reg1, reg2;
+ * } MyDevice;
+ *
+ * static TypeInfo my_device_info = {
+ * .name = TYPE_MY_DEVICE,
+ * .parent = TYPE_DEVICE,
+ * .instance_size = sizeof(MyDevice),
+ * };
+ *
+ * static void my_device_module_init(void)
+ * {
+ * type_register_static(&my_device_info);
+ * }
+ *
+ * device_init(my_device_module_init);
+ * </programlisting>
+ * </example>
+ *
+ * In the above example, we create a simple type that is described by #TypeInfo.
+ * #TypeInfo describes information about the type including what it inherits
+ * from, the instance and class size, and constructor/destructor hooks.
+ *
+ * Every type has an #ObjectClass associated with it. #ObjectClass derivatives
+ * are instantiated dynamically but there is only ever one instance for any
+ * given type. The #ObjectClass typically holds a table of function pointers
+ * for the virtual methods implemented by this type.
+ *
+ * Using object_new(), a new #Object derivative will be instantiated. You can
+ * cast an #Object to a subclass (or base-class) type using
+ * object_dynamic_cast(). You typically want to define a macro wrapper around
+ * object_dynamic_cast_assert() to make it easier to convert to a specific type.
+ *
+ * # Class Initialization #
+ *
+ * Before an object is initialized, the class for the object must be
+ * initialized. There is only one class object for all instance objects
+ * that is created lazily.
+ *
+ * Classes are initialized by first initializing any parent classes (if
+ * necessary). After the parent class object has initialized, it will be
+ * copied into the current class object and any additional storage in the
+ * class object is zero filled.
+ *
+ * The effect of this is that classes automatically inherit any virtual
+ * function pointers that the parent class has already initialized. All
+ * other fields will be zero filled.
+ *
+ * Once all of the parent classes have been initialized, #TypeInfo::class_init
+ * is called to let the class being instantiated provide default initialize for
+ * it's virtual functions.
+ *
+ * # Interfaces #
+ *
+ * Interfaces allow a limited form of multiple inheritance. Instances are
+ * similar to normal types except for the fact that are only defined by
+ * their classes and never carry any state. You can dynamically cast an object
+ * to one of its #Interface types and vice versa.
+ */
+
+
+/**
+ * ObjectPropertyAccessor:
+ * @obj: the object that owns the property
+ * @v: the visitor that contains the property data
+ * @opaque: the object property opaque
+ * @name: the name of the property
+ * @errp: a pointer to an Error that is filled if getting/setting fails.
+ *
+ * Called when trying to get/set a property.
+ */
+typedef void (ObjectPropertyAccessor)(Object *obj,
+ struct Visitor *v,
+ void *opaque,
+ const char *name,
+ struct Error **errp);
+
+/**
+ * ObjectPropertyRelease:
+ * @obj: the object that owns the property
+ * @name: the name of the property
+ * @opaque: the opaque registered with the property
+ *
+ * Called when a property is removed from a object.
+ */
+typedef void (ObjectPropertyRelease)(Object *obj,
+ const char *name,
+ void *opaque);
+
+typedef struct ObjectProperty
+{
+ gchar *name;
+ gchar *type;
+ ObjectPropertyAccessor *get;
+ ObjectPropertyAccessor *set;
+ ObjectPropertyRelease *release;
+ void *opaque;
+
+ QTAILQ_ENTRY(ObjectProperty) node;
+} ObjectProperty;
+
+/**
+ * ObjectClass:
+ *
+ * The base for all classes. The only thing that #ObjectClass contains is an
+ * integer type handle.
+ */
+struct ObjectClass
+{
+ /*< private >*/
+ Type type;
+};
+
+/**
+ * Object:
+ *
+ * The base for all objects. The first member of this object is a pointer to
+ * a #ObjectClass. Since C guarantees that the first member of a structure
+ * always begins at byte 0 of that structure, as long as any sub-object places
+ * its parent as the first member, we can cast directly to a #Object.
+ *
+ * As a result, #Object contains a reference to the objects type as its
+ * first member. This allows identification of the real type of the object at
+ * run time.
+ *
+ * #Object also contains a list of #Interfaces that this object
+ * implements.
+ */
+struct Object
+{
+ /*< private >*/
+ ObjectClass *class;
+ GSList *interfaces;
+ QTAILQ_HEAD(, ObjectProperty) properties;
+ uint32_t ref;
+ Object *parent;
+};
+
+/**
+ * TypeInfo:
+ * @name: The name of the type.
+ * @parent: The name of the parent type.
+ * @instance_size: The size of the object (derivative of #Object). If
+ * @instance_size is 0, then the size of the object will be the size of the
+ * parent object.
+ * @instance_init: This function is called to initialize an object. The parent
+ * class will have already been initialized so the type is only responsible
+ * for initializing its own members.
+ * @instance_finalize: This function is called during object destruction. This
+ * is called before the parent @instance_finalize function has been called.
+ * An object should only free the members that are unique to its type in this
+ * function.
+ * @abstract: If this field is true, then the class is considered abstract and
+ * cannot be directly instantiated.
+ * @class_size: The size of the class object (derivative of #ObjectClass)
+ * for this object. If @class_size is 0, then the size of the class will be
+ * assumed to be the size of the parent class. This allows a type to avoid
+ * implementing an explicit class type if they are not adding additional
+ * virtual functions.
+ * @class_init: This function is called after all parent class initialization
+ * has occured to allow a class to set its default virtual method pointers.
+ * This is also the function to use to override virtual methods from a parent
+ * class.
+ * @class_finalize: This function is called during class destruction and is
+ * meant to release and dynamic parameters allocated by @class_init.
+ * @class_data: Data to pass to the @class_init and @class_finalize functions.
+ * This can be useful when building dynamic classes.
+ * @interfaces: The list of interfaces associated with this type. This
+ * should point to a static array that's terminated with a zero filled
+ * element.
+ */
+struct TypeInfo
+{
+ const char *name;
+ const char *parent;
+
+ size_t instance_size;
+ void (*instance_init)(Object *obj);
+ void (*instance_finalize)(Object *obj);
+
+ bool abstract;
+ size_t class_size;
+
+ void (*class_init)(ObjectClass *klass, void *data);
+ void (*class_finalize)(ObjectClass *klass, void *data);
+ void *class_data;
+
+ InterfaceInfo *interfaces;
+};
+
+/**
+ * OBJECT:
+ * @obj: A derivative of #Object
+ *
+ * Converts an object to a #Object. Since all objects are #Objects,
+ * this function will always succeed.
+ */
+#define OBJECT(obj) \
+ ((Object *)(obj))
+
+/**
+ * OBJECT_CHECK:
+ * @type: The C type to use for the return value.
+ * @obj: A derivative of @type to cast.
+ * @name: The QOM typename of @type
+ *
+ * A type safe version of @object_dynamic_cast_assert. Typically each class
+ * will define a macro based on this type to perform type safe dynamic_casts to
+ * this object type.
+ *
+ * If an invalid object is passed to this function, a run time assert will be
+ * generated.
+ */
+#define OBJECT_CHECK(type, obj, name) \
+ ((type *)object_dynamic_cast_assert((Object *)(obj), (name)))
+
+/**
+ * OBJECT_CLASS_CHECK:
+ * @class: The C type to use for the return value.
+ * @obj: A derivative of @type to cast.
+ * @name: the QOM typename of @class.
+ *
+ * A type safe version of @object_check_class. This macro is typically wrapped
+ * by each type to perform type safe casts of a class to a specific class type.
+ */
+#define OBJECT_CLASS_CHECK(class, obj, name) \
+ ((class *)object_class_dynamic_cast_assert((ObjectClass *)(obj), (name)))
+
+/**
+ * OBJECT_GET_CLASS:
+ * @class: The C type to use for the return value.
+ * @obj: The object to obtain the class for.
+ * @name: The QOM typename of @obj.
+ *
+ * This function will return a specific class for a given object. Its generally
+ * used by each type to provide a type safe macro to get a specific class type
+ * from an object.
+ */
+#define OBJECT_GET_CLASS(class, obj, name) \
+ OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
+
+#define OBJECT_CLASS(class) \
+ ((ObjectClass *)(class))
+
+/**
+ * InterfaceClass:
+ * @parent_class: the base class
+ *
+ * The class for all interfaces. Subclasses of this class should only add
+ * virtual methods.
+ */
+struct InterfaceClass
+{
+ ObjectClass parent_class;
+};
+
+/**
+ * InterfaceInfo:
+ * @type: The name of the interface.
+ * @interface_initfn: This method is called during class initialization and is
+ * used to initialize an interface associated with a class. This function
+ * should initialize any default virtual functions for a class and/or override
+ * virtual functions in a parent class.
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo
+{
+ const char *type;
+
+ void (*interface_initfn)(ObjectClass *class, void *data);
+};
+
+#define TYPE_INTERFACE "interface"
+
+/**
+ * object_new:
+ * @typename: The name of the type of the object to instantiate.
+ *
+ * This function will initialize a new object using heap allocated memory. This
+ * function should be paired with object_delete() to free the resources
+ * associated with the object.
+ *
+ * Returns: The newly allocated and instantiated object.
+ */
+Object *object_new(const char *typename);
+
+/**
+ * object_new_with_type:
+ * @type: The type of the object to instantiate.
+ *
+ * This function will initialize a new object using heap allocated memory. This
+ * function should be paired with object_delete() to free the resources
+ * associated with the object.
+ *
+ * Returns: The newly allocated and instantiated object.
+ */
+Object *object_new_with_type(Type type);
+
+/**
+ * object_delete:
+ * @obj: The object to free.
+ *
+ * Finalize an object and then free the memory associated with it. This should
+ * be paired with object_new() to free the resources associated with an object.
+ */
+void object_delete(Object *obj);
+
+/**
+ * object_initialize_with_type:
+ * @obj: A pointer to the memory to be used for the object.
+ * @type: The type of the object to instantiate.
+ *
+ * This function will initialize an object. The memory for the object should
+ * have already been allocated.
+ */
+void object_initialize_with_type(void *data, Type type);
+
+/**
+ * object_initialize:
+ * @obj: A pointer to the memory to be used for the object.
+ * @typename: The name of the type of the object to instantiate.
+ *
+ * This function will initialize an object. The memory for the object should
+ * have already been allocated.
+ */
+void object_initialize(void *obj, const char *typename);
+
+/**
+ * object_finalize:
+ * @obj: The object to finalize.
+ *
+ * This function destroys and object without freeing the memory associated with
+ * it.
+ */
+void object_finalize(void *obj);
+
+/**
+ * object_dynamic_cast:
+ * @obj: The object to cast.
+ * @typename: The @typename to cast to.
+ *
+ * This function will determine if @obj is-a @typename. @obj can refer to an
+ * object or an interface associated with an object.
+ *
+ * Returns: This function returns @obj on success or #NULL on failure.
+ */
+Object *object_dynamic_cast(Object *obj, const char *typename);
+
+/**
+ * @object_dynamic_cast_assert:
+ *
+ * See object_dynamic_cast() for a description of the parameters of this
+ * function. The only difference in behavior is that this function asserts
+ * instead of returning #NULL on failure.
+ */
+Object *object_dynamic_cast_assert(Object *obj, const char *typename);
+
+/**
+ * object_get_class:
+ * @obj: A derivative of #Object
+ *
+ * Returns: The #ObjectClass of the type associated with @obj.
+ */
+ObjectClass *object_get_class(Object *obj);
+
+/**
+ * object_get_typename:
+ * @obj: A derivative of #Object.
+ *
+ * Returns: The QOM typename of @obj.
+ */
+const char *object_get_typename(Object *obj);
+
+/**
+ * type_register_static:
+ * @info: The #TypeInfo of the new type.
+ *
+ * @info and all of the strings it points to should exist for the life time
+ * that the type is registered.
+ *
+ * Returns: 0 on failure, the new #Type on success.
+ */
+Type type_register_static(const TypeInfo *info);
+
+#define type_register_static_alias(info, name) do { } while (0)
+
+/**
+ * type_register:
+ * @info: The #TypeInfo of the new type
+ *
+ * Unlike type_register_static(), this call does not require @info or it's
+ * string members to continue to exist after the call returns.
+ *
+ * Returns: 0 on failure, the new #Type on success.
+ */
+Type type_register(const TypeInfo *info);
+
+/**
+ * object_class_dynamic_cast_assert:
+ * @klass: The #ObjectClass to attempt to cast.
+ * @typename: The QOM typename of the class to cast to.
+ *
+ * Returns: This function always returns @klass and asserts on failure.
+ */
+ObjectClass *object_class_dynamic_cast_assert(ObjectClass *klass,
+ const char *typename);
+
+ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
+ const char *typename);
+
+/**
+ * object_class_get_name:
+ * @klass: The class to obtain the QOM typename for.
+ *
+ * Returns: The QOM typename for @klass.
+ */
+const char *object_class_get_name(ObjectClass *klass);
+
+ObjectClass *object_class_by_name(const char *typename);
+
+void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+ const char *implements_type, bool include_abstract,
+ void *opaque);
+/**
+ * object_ref:
+ * @obj: the object
+ *
+ * Increase the reference count of a object. A object cannot be freed as long
+ * as its reference count is greater than zero.
+ */
+void object_ref(Object *obj);
+
+/**
+ * qdef_unref:
+ * @obj: the object
+ *
+ * Decrease the reference count of a object. A object cannot be freed as long
+ * as its reference count is greater than zero.
+ */
+void object_unref(Object *obj);
+
+/**
+ * object_property_add:
+ * @obj: the object to add a property to
+ * @name: the name of the property. This can contain any character except for
+ * a forward slash. In general, you should use hyphens '-' instead of
+ * underscores '_' when naming properties.
+ * @type: the type name of the property. This namespace is pretty loosely
+ * defined. Sub namespaces are constructed by using a prefix and then
+ * to angle brackets. For instance, the type 'virtio-net-pci' in the
+ * 'link' namespace would be 'link<virtio-net-pci>'.
+ * @get: The getter to be called to read a property. If this is NULL, then
+ * the property cannot be read.
+ * @set: the setter to be called to write a property. If this is NULL,
+ * then the property cannot be written.
+ * @release: called when the property is removed from the object. This is
+ * meant to allow a property to free its opaque upon object
+ * destruction. This may be NULL.
+ * @opaque: an opaque pointer to pass to the callbacks for the property
+ * @errp: returns an error if this function fails
+ */
+void object_property_add(Object *obj, const char *name, const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, struct Error **errp);
+
+void object_property_del(Object *obj, const char *name, struct Error **errp);
+
+void object_unparent(Object *obj);
+
+/**
+ * object_property_get:
+ * @obj: the object
+ * @v: the visitor that will receive the property value. This should be an
+ * Output visitor and the data will be written with @name as the name.
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Reads a property from a object.
+ */
+void object_property_get(Object *obj, struct Visitor *v, const char *name,
+ struct Error **errp);
+
+/**
+ * object_property_set:
+ * @obj: the object
+ * @v: the visitor that will be used to write the property value. This should
+ * be an Input visitor and the data will be first read with @name as the
+ * name and then written as the property value.
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Writes a property to a object.
+ */
+void object_property_set(Object *obj, struct Visitor *v, const char *name,
+ struct Error **errp);
+
+/**
+ * @object_property_get_type:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns: The type name of the property.
+ */
+const char *object_property_get_type(Object *obj, const char *name,
+ struct Error **errp);
+
+/**
+ * object_get_root:
+ *
+ * Returns: the root object of the composition tree
+ */
+Object *object_get_root(void);
+
+/**
+ * object_get_canonical_path:
+ *
+ * Returns: The canonical path for a object. This is the path within the
+ * composition tree starting from the root.
+ */
+gchar *object_get_canonical_path(Object *obj);
+
+/**
+ * object_resolve_path:
+ * @path: the path to resolve
+ * @ambiguous: returns true if the path resolution failed because of an
+ * ambiguous match
+ *
+ * There are two types of supported paths--absolute paths and partial paths.
+ *
+ * Absolute paths are derived from the root object and can follow child<> or
+ * link<> properties. Since they can follow link<> properties, they can be
+ * arbitrarily long. Absolute paths look like absolute filenames and are
+ * prefixed with a leading slash.
+ *
+ * Partial paths look like relative filenames. They do not begin with a
+ * prefix. The matching rules for partial paths are subtle but designed to make
+ * specifying objects easy. At each level of the composition tree, the partial
+ * path is matched as an absolute path. The first match is not returned. At
+ * least two matches are searched for. A successful result is only returned if
+ * only one match is founded. If more than one match is found, a flag is
+ * return to indicate that the match was ambiguous.
+ *
+ * Returns: The matched object or NULL on path lookup failure.
+ */
+Object *object_resolve_path(const char *path, bool *ambiguous);
+
+/**
+ * object_property_add_child:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @child: the child object
+ * @errp: if an error occurs, a pointer to an area to store the area
+ *
+ * Child properties form the composition tree. All objects need to be a child
+ * of another object. Objects can only be a child of one object.
+ *
+ * There is no way for a child to determine what its parent is. It is not
+ * a bidirectional relationship. This is by design.
+ */
+void object_property_add_child(Object *obj, const char *name,
+ Object *child, struct Error **errp);
+
+/**
+ * object_property_add_link:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @type: the qobj type of the link
+ * @child: a pointer to where the link object reference is stored
+ * @errp: if an error occurs, a pointer to an area to store the area
+ *
+ * Links establish relationships between objects. Links are unidirectional
+ * although two links can be combined to form a bidirectional relationship
+ * between objects.
+ *
+ * Links form the graph in the object model.
+ */
+void object_property_add_link(Object *obj, const char *name,
+ const char *type, Object **child,
+ struct Error **errp);
+
+/**
+ * object_property_add_str:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @get: the getter or NULL if the property is write-only. This function must
+ * return a string to be freed by g_free().
+ * @set: the setter or NULL if the property is read-only
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Add a string property using getters/setters. This function will add a
+ * property of type 'string'.
+ */
+void object_property_add_str(Object *obj, const char *name,
+ char *(*get)(Object *, struct Error **),
+ void (*set)(Object *, const char *, struct Error **),
+ struct Error **errp);
+
+#endif
diff --git a/kvm-all.c b/kvm-all.c
index 2cc4562..0b87658 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -78,6 +78,13 @@
int pit_in_kernel;
int xsave, xcrs;
int many_ioeventfds;
+ int irqchip_inject_ioctl;
+#ifdef KVM_CAP_IRQ_ROUTING
+ struct kvm_irq_routing *irq_routes;
+ int nr_allocated_irq_routes;
+ uint32_t *used_gsi_bitmap;
+ unsigned int max_gsi;
+#endif
};
KVMState *kvm_state;
@@ -344,7 +351,8 @@
unsigned long *bitmap)
{
unsigned int i, j;
- unsigned long page_number, addr, addr1, c;
+ unsigned long page_number, c;
+ target_phys_addr_t addr, addr1;
unsigned int len = ((section->size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
/*
@@ -360,7 +368,7 @@
page_number = i * HOST_LONG_BITS + j;
addr1 = page_number * TARGET_PAGE_SIZE;
addr = section->offset_within_region + addr1;
- memory_region_set_dirty(section->mr, addr);
+ memory_region_set_dirty(section->mr, addr, TARGET_PAGE_SIZE);
} while (c != 0);
}
}
@@ -371,8 +379,9 @@
/**
* kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
- * This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty().
- * This means all bits are set to dirty.
+ * This function updates qemu's dirty bitmap using
+ * memory_region_set_dirty(). This means all bits are set
+ * to dirty.
*
* @start_add: start of logged region.
* @end_addr: end of logged region.
@@ -728,6 +737,138 @@
}
}
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level)
+{
+ struct kvm_irq_level event;
+ int ret;
+
+ assert(s->irqchip_in_kernel);
+
+ event.level = level;
+ event.irq = irq;
+ ret = kvm_vm_ioctl(s, s->irqchip_inject_ioctl, &event);
+ if (ret < 0) {
+ perror("kvm_set_irqchip_line");
+ abort();
+ }
+
+ return (s->irqchip_inject_ioctl == KVM_IRQ_LINE) ? 1 : event.status;
+}
+
+#ifdef KVM_CAP_IRQ_ROUTING
+static void set_gsi(KVMState *s, unsigned int gsi)
+{
+ assert(gsi < s->max_gsi);
+
+ s->used_gsi_bitmap[gsi / 32] |= 1U << (gsi % 32);
+}
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+ int gsi_count;
+
+ gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING);
+ if (gsi_count > 0) {
+ unsigned int gsi_bits, i;
+
+ /* Round up so we can search ints using ffs */
+ gsi_bits = (gsi_count + 31) / 32;
+ s->used_gsi_bitmap = g_malloc0(gsi_bits / 8);
+ s->max_gsi = gsi_bits;
+
+ /* Mark any over-allocated bits as already in use */
+ for (i = gsi_count; i < gsi_bits; i++) {
+ set_gsi(s, i);
+ }
+ }
+
+ s->irq_routes = g_malloc0(sizeof(*s->irq_routes));
+ s->nr_allocated_irq_routes = 0;
+
+ kvm_arch_init_irq_routing(s);
+}
+
+static void kvm_add_routing_entry(KVMState *s,
+ struct kvm_irq_routing_entry *entry)
+{
+ struct kvm_irq_routing_entry *new;
+ int n, size;
+
+ if (s->irq_routes->nr == s->nr_allocated_irq_routes) {
+ n = s->nr_allocated_irq_routes * 2;
+ if (n < 64) {
+ n = 64;
+ }
+ size = sizeof(struct kvm_irq_routing);
+ size += n * sizeof(*new);
+ s->irq_routes = g_realloc(s->irq_routes, size);
+ s->nr_allocated_irq_routes = n;
+ }
+ n = s->irq_routes->nr++;
+ new = &s->irq_routes->entries[n];
+ memset(new, 0, sizeof(*new));
+ new->gsi = entry->gsi;
+ new->type = entry->type;
+ new->flags = entry->flags;
+ new->u = entry->u;
+
+ set_gsi(s, entry->gsi);
+}
+
+void kvm_irqchip_add_route(KVMState *s, int irq, int irqchip, int pin)
+{
+ struct kvm_irq_routing_entry e;
+
+ e.gsi = irq;
+ e.type = KVM_IRQ_ROUTING_IRQCHIP;
+ e.flags = 0;
+ e.u.irqchip.irqchip = irqchip;
+ e.u.irqchip.pin = pin;
+ kvm_add_routing_entry(s, &e);
+}
+
+int kvm_irqchip_commit_routes(KVMState *s)
+{
+ s->irq_routes->flags = 0;
+ return kvm_vm_ioctl(s, KVM_SET_GSI_ROUTING, s->irq_routes);
+}
+
+#else /* !KVM_CAP_IRQ_ROUTING */
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+}
+#endif /* !KVM_CAP_IRQ_ROUTING */
+
+static int kvm_irqchip_create(KVMState *s)
+{
+ QemuOptsList *list = qemu_find_opts("machine");
+ int ret;
+
+ if (QTAILQ_EMPTY(&list->head) ||
+ !qemu_opt_get_bool(QTAILQ_FIRST(&list->head),
+ "kernel_irqchip", false) ||
+ !kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
+ return 0;
+ }
+
+ ret = kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP);
+ if (ret < 0) {
+ fprintf(stderr, "Create kernel irqchip failed\n");
+ return ret;
+ }
+
+ s->irqchip_inject_ioctl = KVM_IRQ_LINE;
+ if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) {
+ s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
+ }
+ s->irqchip_in_kernel = 1;
+
+ kvm_init_irq_routing(s);
+
+ return 0;
+}
+
int kvm_init(void)
{
static const char upgrade_note[] =
@@ -823,6 +964,11 @@
goto err;
}
+ ret = kvm_irqchip_create(s);
+ if (ret < 0) {
+ goto err;
+ }
+
kvm_state = s;
memory_listener_register(&kvm_memory_listener);
@@ -1158,6 +1304,20 @@
return kvm_state->many_ioeventfds;
}
+int kvm_has_gsi_routing(void)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+ return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
+#else
+ return false;
+#endif
+}
+
+int kvm_allows_irq0_override(void)
+{
+ return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+}
+
void kvm_setup_guest_memory(void *start, size_t size)
{
if (!kvm_has_sync_mmu()) {
diff --git a/kvm-stub.c b/kvm-stub.c
index 06064b9..6c2b06b 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -78,6 +78,11 @@
return 0;
}
+int kvm_allows_irq0_override(void)
+{
+ return 1;
+}
+
void kvm_setup_guest_memory(void *start, size_t size)
{
}
diff --git a/kvm.h b/kvm.h
index c1de81a..40b5ffc 100644
--- a/kvm.h
+++ b/kvm.h
@@ -31,6 +31,7 @@
#endif
struct kvm_run;
+struct kvm_lapic_state;
typedef struct KVMCapabilityInfo {
const char *name;
@@ -51,6 +52,9 @@
int kvm_has_xsave(void);
int kvm_has_xcrs(void);
int kvm_has_many_ioeventfds(void);
+int kvm_has_gsi_routing(void);
+
+int kvm_allows_irq0_override(void);
#ifdef NEED_CPU_H
int kvm_init_vcpu(CPUState *env);
@@ -124,6 +128,16 @@
int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr);
int kvm_arch_on_sigbus(int code, void *addr);
+void kvm_arch_init_irq_routing(KVMState *s);
+
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
+
+void kvm_irqchip_add_route(KVMState *s, int gsi, int irqchip, int pin);
+int kvm_irqchip_commit_routes(KVMState *s);
+
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+
struct kvm_guest_debug;
struct kvm_debug_exit_arch;
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index fb3fddc..b921c3f 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -265,12 +265,9 @@
struct kvm_guest_debug_arch {
};
-#define KVM_REG_MASK 0x001f
-#define KVM_REG_EXT_MASK 0xffe0
-#define KVM_REG_GPR 0x0000
-#define KVM_REG_FPR 0x0020
-#define KVM_REG_QPR 0x0040
-#define KVM_REG_FQPR 0x0060
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
#define KVM_INTERRUPT_SET -1U
#define KVM_INTERRUPT_UNSET -2U
@@ -327,6 +324,6 @@
__u32 reserved[8];
};
-#define KVM_ONE_REG_PPC_HIOR KVM_ONE_REG_PPC | 0x100
+#define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h
index ad58c90..c047a84 100644
--- a/linux-headers/asm-powerpc/kvm_para.h
+++ b/linux-headers/asm-powerpc/kvm_para.h
@@ -22,6 +22,16 @@
#include <linux/types.h>
+/*
+ * Additions to this struct must only occur at the end, and should be
+ * accompanied by a KVM_MAGIC_FEAT flag to advertise that they are present
+ * (albeit not necessarily relevant to the current target hardware platform).
+ *
+ * Struct fields are always 32 or 64 bit aligned, depending on them being 32
+ * or 64 bit wide respectively.
+ *
+ * See Documentation/virtual/kvm/ppc-pv.txt
+ */
struct kvm_vcpu_arch_shared {
__u64 scratch1;
__u64 scratch2;
@@ -33,11 +43,35 @@
__u64 sprg3;
__u64 srr0;
__u64 srr1;
- __u64 dar;
+ __u64 dar; /* dear on BookE */
__u64 msr;
__u32 dsisr;
__u32 int_pending; /* Tells the guest if we have an interrupt */
__u32 sr[16];
+ __u32 mas0;
+ __u32 mas1;
+ __u64 mas7_3;
+ __u64 mas2;
+ __u32 mas4;
+ __u32 mas6;
+ __u32 esr;
+ __u32 pir;
+
+ /*
+ * SPRG4-7 are user-readable, so we can only keep these consistent
+ * between the shared area and the real registers when there's an
+ * intervening exit to KVM. This also applies to SPRG3 on some
+ * chips.
+ *
+ * This suffices for access by guest userspace, since in PR-mode
+ * KVM, an exit must occur when changing the guest's MSR[PR].
+ * If the guest kernel writes to SPRG3-7 via the shared area, it
+ * must also use the shared area for reading while in kernel space.
+ */
+ __u64 sprg4;
+ __u64 sprg5;
+ __u64 sprg6;
+ __u64 sprg7;
};
#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
@@ -47,7 +81,10 @@
#define KVM_FEATURE_MAGIC_PAGE 1
-#define KVM_MAGIC_FEAT_SR (1 << 0)
+#define KVM_MAGIC_FEAT_SR (1 << 0)
+
+/* MASn, ESR, PIR, and high SPRGs */
+#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
#endif /* __POWERPC_KVM_PARA_H__ */
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index 82b32a1..9acbde4 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -41,4 +41,13 @@
struct kvm_guest_debug_arch {
};
+#define KVM_SYNC_PREFIX (1UL << 0)
+#define KVM_SYNC_GPRS (1UL << 1)
+#define KVM_SYNC_ACRS (1UL << 2)
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+ __u64 prefix; /* prefix register */
+ __u64 gprs[16]; /* general purpose registers */
+ __u32 acrs[16]; /* access registers */
+};
#endif
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
index 5df477a..b80420b 100644
--- a/linux-headers/asm-x86/hyperv.h
+++ b/linux-headers/asm-x86/hyperv.h
@@ -189,5 +189,6 @@
#define HV_STATUS_INVALID_HYPERCALL_CODE 2
#define HV_STATUS_INVALID_HYPERCALL_INPUT 3
#define HV_STATUS_INVALID_ALIGNMENT 4
+#define HV_STATUS_INSUFFICIENT_BUFFERS 19
#endif
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 4d8dcbd..e7d1c19 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -321,4 +321,8 @@
__u64 padding[16];
};
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
#endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index a8761d3..f6b5343 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -162,6 +162,7 @@
#define KVM_EXIT_INTERNAL_ERROR 17
#define KVM_EXIT_OSI 18
#define KVM_EXIT_PAPR_HCALL 19
+#define KVM_EXIT_S390_UCONTROL 20
/* For KVM_EXIT_INTERNAL_ERROR */
#define KVM_INTERNAL_ERROR_EMULATION 1
@@ -249,6 +250,11 @@
#define KVM_S390_RESET_CPU_INIT 8
#define KVM_S390_RESET_IPL 16
__u64 s390_reset_flags;
+ /* KVM_EXIT_S390_UCONTROL */
+ struct {
+ __u64 trans_exc_code;
+ __u32 pgm_code;
+ } s390_ucontrol;
/* KVM_EXIT_DCR */
struct {
__u32 dcrn;
@@ -273,6 +279,20 @@
/* Fix the size of the union. */
char padding[256];
};
+
+ /*
+ * shared registers between kvm and userspace.
+ * kvm_valid_regs specifies the register classes set by the host
+ * kvm_dirty_regs specified the register classes dirtied by userspace
+ * struct kvm_sync_regs is architecture specific, as well as the
+ * bits for kvm_valid_regs and kvm_dirty_regs
+ */
+ __u64 kvm_valid_regs;
+ __u64 kvm_dirty_regs;
+ union {
+ struct kvm_sync_regs regs;
+ char padding[1024];
+ } s;
};
/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
@@ -371,6 +391,7 @@
#define KVM_S390_INT_VIRTIO 0xffff2603u
#define KVM_S390_INT_SERVICE 0xffff2401u
#define KVM_S390_INT_EMERGENCY 0xffff1201u
+#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u
struct kvm_s390_interrupt {
__u32 type;
@@ -430,6 +451,11 @@
#define KVMIO 0xAE
+/* machine type bits, to be used as argument to KVM_CREATE_VM */
+#define KVM_VM_S390_UCONTROL 1
+
+#define KVM_S390_SIE_PAGE_OFFSET 1
+
/*
* ioctls for /dev/kvm fds:
*/
@@ -558,6 +584,10 @@
#define KVM_CAP_PPC_PAPR 68
#define KVM_CAP_SW_TLB 69
#define KVM_CAP_ONE_REG 70
+#define KVM_CAP_S390_GMAP 71
+#define KVM_CAP_TSC_DEADLINE_TIMER 72
+#define KVM_CAP_S390_UCONTROL 73
+#define KVM_CAP_SYNC_REGS 74
#ifdef KVM_CAP_IRQ_ROUTING
@@ -654,30 +684,33 @@
/* Available with KVM_CAP_ONE_REG */
-#define KVM_ONE_REG_GENERIC 0x0000000000000000ULL
+#define KVM_REG_ARCH_MASK 0xff00000000000000ULL
+#define KVM_REG_GENERIC 0x0000000000000000ULL
/*
* Architecture specific registers are to be defined in arch headers and
* ORed with the arch identifier.
*/
-#define KVM_ONE_REG_PPC 0x1000000000000000ULL
-#define KVM_ONE_REG_X86 0x2000000000000000ULL
-#define KVM_ONE_REG_IA64 0x3000000000000000ULL
-#define KVM_ONE_REG_ARM 0x4000000000000000ULL
-#define KVM_ONE_REG_S390 0x5000000000000000ULL
+#define KVM_REG_PPC 0x1000000000000000ULL
+#define KVM_REG_X86 0x2000000000000000ULL
+#define KVM_REG_IA64 0x3000000000000000ULL
+#define KVM_REG_ARM 0x4000000000000000ULL
+#define KVM_REG_S390 0x5000000000000000ULL
+
+#define KVM_REG_SIZE_SHIFT 52
+#define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
+#define KVM_REG_SIZE_U8 0x0000000000000000ULL
+#define KVM_REG_SIZE_U16 0x0010000000000000ULL
+#define KVM_REG_SIZE_U32 0x0020000000000000ULL
+#define KVM_REG_SIZE_U64 0x0030000000000000ULL
+#define KVM_REG_SIZE_U128 0x0040000000000000ULL
+#define KVM_REG_SIZE_U256 0x0050000000000000ULL
+#define KVM_REG_SIZE_U512 0x0060000000000000ULL
+#define KVM_REG_SIZE_U1024 0x0070000000000000ULL
struct kvm_one_reg {
__u64 id;
- union {
- __u8 reg8;
- __u16 reg16;
- __u32 reg32;
- __u64 reg64;
- __u8 reg128[16];
- __u8 reg256[32];
- __u8 reg512[64];
- __u8 reg1024[128];
- } u;
+ __u64 addr;
};
/*
@@ -698,6 +731,17 @@
struct kvm_userspace_memory_region)
#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47)
#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64)
+
+/* enable ucontrol for s390 */
+struct kvm_s390_ucas_mapping {
+ __u64 user_addr;
+ __u64 vcpu_addr;
+ __u64 length;
+};
+#define KVM_S390_UCAS_MAP _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping)
+#define KVM_S390_UCAS_UNMAP _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping)
+#define KVM_S390_VCPU_FAULT _IOW(KVMIO, 0x52, unsigned long)
+
/* Device model IOC */
#define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60)
#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
@@ -809,7 +853,7 @@
/* Available with KVM_CAP_SW_TLB */
#define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb)
/* Available with KVM_CAP_ONE_REG */
-#define KVM_GET_ONE_REG _IOWR(KVMIO, 0xab, struct kvm_one_reg)
+#define KVM_GET_ONE_REG _IOW(KVMIO, 0xab, struct kvm_one_reg)
#define KVM_SET_ONE_REG _IOW(KVMIO, 0xac, struct kvm_one_reg)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h
index b315e27..7bdcf93 100644
--- a/linux-headers/linux/kvm_para.h
+++ b/linux-headers/linux/kvm_para.h
@@ -26,4 +26,3 @@
#include <asm/kvm_para.h>
#endif /* __LINUX_KVM_PARA_H */
-
diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h
index 78289ee..1b333e2 100644
--- a/linux-headers/linux/virtio_ring.h
+++ b/linux-headers/linux/virtio_ring.h
@@ -135,13 +135,13 @@
vr->num = num;
vr->desc = p;
vr->avail = p + num*sizeof(struct vring_desc);
- vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
- & ~(align - 1));
+ vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(__u16)
+ + align-1) & ~(align - 1));
}
static __inline__ unsigned vring_size(unsigned int num, unsigned long align)
{
- return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
+ return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num)
+ align - 1) & ~(align - 1))
+ sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
}
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 845be8b..2fd4a93 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1245,6 +1245,7 @@
struct image_info *interp_info)
{
abi_ulong sp;
+ abi_ulong sp_auxv;
int size;
int i;
abi_ulong u_rand_bytes;
@@ -1316,6 +1317,7 @@
sp -= n; put_user_ual(id, sp); \
} while(0)
+ sp_auxv = sp;
NEW_AUX_ENT (AT_NULL, 0);
/* There must be exactly DLINFO_ITEMS entries here. */
@@ -1346,6 +1348,7 @@
#undef NEW_AUX_ENT
info->saved_auxv = sp;
+ info->auxv_len = sp_auxv - sp;
sp = loader_build_argptr(envc, argc, sp, p, 0);
return sp;
@@ -2326,9 +2329,8 @@
{
elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
elf_addr_t orig_auxv = auxv;
- abi_ulong val;
void *ptr;
- int i, len;
+ int len = ts->info->auxv_len;
/*
* Auxiliary vector is stored in target process stack. It contains
@@ -2336,15 +2338,6 @@
* strictly necessary but we do it here for sake of completeness.
*/
- /* find out length of the vector, AT_NULL is terminator */
- i = len = 0;
- do {
- get_user_ual(val, auxv);
- i += 2;
- auxv += 2 * sizeof (elf_addr_t);
- } while (val != AT_NULL);
- len = i * sizeof (elf_addr_t);
-
/* read in whole auxv vector and copy it to memelfnote */
ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
if (ptr != NULL) {
diff --git a/linux-user/main.c b/linux-user/main.c
index 64d2208..14bf5f0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2945,6 +2945,11 @@
cpu_set_log(mask);
}
+static void handle_arg_log_filename(const char *arg)
+{
+ cpu_set_log_filename(arg);
+}
+
static void handle_arg_set_env(const char *arg)
{
char *r, *p, *token;
@@ -3125,6 +3130,8 @@
#endif
{"d", "QEMU_LOG", true, handle_arg_log,
"options", "activate log"},
+ {"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
+ "logfile", "override default logfile location"},
{"p", "QEMU_PAGESIZE", true, handle_arg_pagesize,
"pagesize", "set the host page size to 'pagesize'"},
{"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep,
diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
index 668a2b9..e436ea5 100644
--- a/linux-user/mips64/syscall.h
+++ b/linux-user/mips64/syscall.h
@@ -218,4 +218,7 @@
+/* Nasty hack: define a fake errno value for use by sigreturn. */
+#define TARGET_QEMU_ESIGRETURN 255
+
#define UNAME_MACHINE "mips64"
diff --git a/linux-user/mipsn32/syscall.h b/linux-user/mipsn32/syscall.h
index 4ec506c..ebe98f2 100644
--- a/linux-user/mipsn32/syscall.h
+++ b/linux-user/mipsn32/syscall.h
@@ -218,4 +218,7 @@
+/* Nasty hack: define a fake errno value for use by sigreturn. */
+#define TARGET_QEMU_ESIGRETURN 255
+
#define UNAME_MACHINE "mips64"
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 55ad9d8..308dbc0 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -48,6 +48,7 @@
abi_ulong code_offset;
abi_ulong data_offset;
abi_ulong saved_auxv;
+ abi_ulong auxv_len;
abi_ulong arg_start;
abi_ulong arg_end;
int personality;
@@ -123,10 +124,10 @@
#endif
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
/* Extra fields for semihosted binaries. */
- uint32_t stack_base;
uint32_t heap_base;
uint32_t heap_limit;
#endif
+ uint32_t stack_base;
int used; /* non zero if used */
struct image_info *info;
struct linux_binprm *bprm;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index ded12ca..79a39dc 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -587,7 +587,11 @@
#endif
if (oact) {
oact->_sa_handler = tswapal(k->_sa_handler);
+#if defined(TARGET_MIPS) || defined (TARGET_ALPHA)
+ oact->sa_flags = bswap32(k->sa_flags);
+#else
oact->sa_flags = tswapal(k->sa_flags);
+#endif
#if !defined(TARGET_MIPS)
oact->sa_restorer = tswapal(k->sa_restorer);
#endif
@@ -596,7 +600,11 @@
if (act) {
/* FIXME: This is not threadsafe. */
k->_sa_handler = tswapal(act->_sa_handler);
+#if defined(TARGET_MIPS) || defined (TARGET_ALPHA)
+ k->sa_flags = bswap32(act->sa_flags);
+#else
k->sa_flags = tswapal(act->sa_flags);
+#endif
#if !defined(TARGET_MIPS)
k->sa_restorer = tswapal(act->sa_restorer);
#endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 90027a1..05a0d3e 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1,5 +1,4 @@
#include <stdio.h>
-#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
@@ -284,8 +283,13 @@
static void
print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
{
-if( ret == -1 ) {
- gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno));
+ char *errstr = NULL;
+
+ if (ret < 0) {
+ errstr = target_strerror(-ret);
+ }
+ if (errstr) {
+ gemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr);
} else {
gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
}
@@ -1515,14 +1519,19 @@
print_syscall_ret(int num, abi_long ret)
{
int i;
+ char *errstr = NULL;
for(i=0;i<nsyscalls;i++)
if( scnames[i].nr == num ) {
if( scnames[i].result != NULL ) {
scnames[i].result(&scnames[i],ret);
} else {
- if( ret < 0 ) {
- gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, target_strerror(-ret));
+ if (ret < 0) {
+ errstr = target_strerror(-ret);
+ }
+ if (errstr) {
+ gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n",
+ -ret, errstr);
} else {
gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 2bf9e7e..ee8899e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -731,6 +731,9 @@
char *target_strerror(int err)
{
+ if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
+ return NULL;
+ }
return strerror(target_to_host_errno(err));
}
@@ -1530,9 +1533,41 @@
case TARGET_SO_LINGER:
case TARGET_SO_RCVTIMEO:
case TARGET_SO_SNDTIMEO:
- case TARGET_SO_PEERCRED:
case TARGET_SO_PEERNAME:
goto unimplemented;
+ case TARGET_SO_PEERCRED: {
+ struct ucred cr;
+ socklen_t crlen;
+ struct target_ucred *tcr;
+
+ if (get_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ if (len < 0) {
+ return -TARGET_EINVAL;
+ }
+
+ crlen = sizeof(cr);
+ ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
+ &cr, &crlen));
+ if (ret < 0) {
+ return ret;
+ }
+ if (len > crlen) {
+ len = crlen;
+ }
+ if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+ __put_user(cr.pid, &tcr->pid);
+ __put_user(cr.uid, &tcr->uid);
+ __put_user(cr.gid, &tcr->gid);
+ unlock_user_struct(tcr, optval_addr, 1);
+ if (put_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ break;
+ }
/* Options with 'int' argument. */
case TARGET_SO_DEBUG:
optname = SO_DEBUG;
@@ -4600,6 +4635,123 @@
return osversion;
}
+
+static int open_self_maps(void *cpu_env, int fd)
+{
+ TaskState *ts = ((CPUState *)cpu_env)->opaque;
+
+ dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
+ (unsigned long long)ts->info->stack_limit,
+ (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1))
+ & TARGET_PAGE_MASK,
+ (unsigned long long)ts->stack_base);
+
+ return 0;
+}
+
+static int open_self_stat(void *cpu_env, int fd)
+{
+ TaskState *ts = ((CPUState *)cpu_env)->opaque;
+ abi_ulong start_stack = ts->info->start_stack;
+ int i;
+
+ for (i = 0; i < 44; i++) {
+ char buf[128];
+ int len;
+ uint64_t val = 0;
+
+ if (i == 27) {
+ /* stack bottom */
+ val = start_stack;
+ }
+ snprintf(buf, sizeof(buf), "%"PRId64 "%c", val, i == 43 ? '\n' : ' ');
+ len = strlen(buf);
+ if (write(fd, buf, len) != len) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int open_self_auxv(void *cpu_env, int fd)
+{
+ TaskState *ts = ((CPUState *)cpu_env)->opaque;
+ abi_ulong auxv = ts->info->saved_auxv;
+ abi_ulong len = ts->info->auxv_len;
+ char *ptr;
+
+ /*
+ * Auxiliary vector is stored in target process stack.
+ * read in whole auxv vector and copy it to file
+ */
+ ptr = lock_user(VERIFY_READ, auxv, len, 0);
+ if (ptr != NULL) {
+ while (len > 0) {
+ ssize_t r;
+ r = write(fd, ptr, len);
+ if (r <= 0) {
+ break;
+ }
+ len -= r;
+ ptr += r;
+ }
+ lseek(fd, 0, SEEK_SET);
+ unlock_user(ptr, auxv, len);
+ }
+
+ return 0;
+}
+
+static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
+{
+ struct fake_open {
+ const char *filename;
+ int (*fill)(void *cpu_env, int fd);
+ };
+ const struct fake_open *fake_open;
+ static const struct fake_open fakes[] = {
+ { "/proc/self/maps", open_self_maps },
+ { "/proc/self/stat", open_self_stat },
+ { "/proc/self/auxv", open_self_auxv },
+ { NULL, NULL }
+ };
+
+ for (fake_open = fakes; fake_open->filename; fake_open++) {
+ if (!strncmp(pathname, fake_open->filename,
+ strlen(fake_open->filename))) {
+ break;
+ }
+ }
+
+ if (fake_open->filename) {
+ const char *tmpdir;
+ char filename[PATH_MAX];
+ int fd, r;
+
+ /* create temporary file to map stat to */
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir)
+ tmpdir = "/tmp";
+ snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ return fd;
+ }
+ unlink(filename);
+
+ if ((r = fake_open->fill(cpu_env, fd))) {
+ close(fd);
+ return r;
+ }
+ lseek(fd, 0, SEEK_SET);
+
+ return fd;
+ }
+
+ return get_errno(open(path(pathname), flags, mode));
+}
+
/* do_syscall() should always have a single exit point at the end so
that actions, such as logging of syscall results, can be performed.
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -4685,9 +4837,9 @@
case TARGET_NR_open:
if (!(p = lock_user_string(arg1)))
goto efault;
- ret = get_errno(open(path(p),
- target_to_host_bitmask(arg2, fcntl_flags_tbl),
- arg3));
+ ret = get_errno(do_open(cpu_env, p,
+ target_to_host_bitmask(arg2, fcntl_flags_tbl),
+ arg3));
unlock_user(p, arg1, 0);
break;
#if defined(TARGET_NR_openat) && defined(__NR_openat)
@@ -4715,7 +4867,7 @@
{
int status;
ret = get_errno(waitpid(arg1, &status, arg3));
- if (!is_error(ret) && arg2
+ if (!is_error(ret) && arg2 && ret
&& put_user_s32(host_to_target_waitstatus(status), arg2))
goto efault;
}
@@ -6271,7 +6423,7 @@
rusage_ptr = NULL;
ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
if (!is_error(ret)) {
- if (status_ptr) {
+ if (status_ptr && ret) {
status = host_to_target_waitstatus(status);
if (put_user_s32(status, status_ptr))
goto efault;
@@ -7644,25 +7796,64 @@
#endif
#ifdef CONFIG_ATTR
#ifdef TARGET_NR_setxattr
- case TARGET_NR_lsetxattr:
- case TARGET_NR_fsetxattr:
- case TARGET_NR_lgetxattr:
- case TARGET_NR_fgetxattr:
case TARGET_NR_listxattr:
case TARGET_NR_llistxattr:
- case TARGET_NR_flistxattr:
- case TARGET_NR_lremovexattr:
- case TARGET_NR_fremovexattr:
- ret = -TARGET_EOPNOTSUPP;
+ {
+ void *p, *b = 0;
+ if (arg2) {
+ b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+ if (!b) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
+ p = lock_user_string(arg1);
+ if (p) {
+ if (num == TARGET_NR_listxattr) {
+ ret = get_errno(listxattr(p, b, arg3));
+ } else {
+ ret = get_errno(llistxattr(p, b, arg3));
+ }
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(p, arg1, 0);
+ unlock_user(b, arg2, arg3);
break;
+ }
+ case TARGET_NR_flistxattr:
+ {
+ void *b = 0;
+ if (arg2) {
+ b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+ if (!b) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
+ ret = get_errno(flistxattr(arg1, b, arg3));
+ unlock_user(b, arg2, arg3);
+ break;
+ }
case TARGET_NR_setxattr:
+ case TARGET_NR_lsetxattr:
{
- void *p, *n, *v;
+ void *p, *n, *v = 0;
+ if (arg3) {
+ v = lock_user(VERIFY_READ, arg3, arg4, 1);
+ if (!v) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
p = lock_user_string(arg1);
n = lock_user_string(arg2);
- v = lock_user(VERIFY_READ, arg3, arg4, 1);
- if (p && n && v) {
- ret = get_errno(setxattr(p, n, v, arg4, arg5));
+ if (p && n) {
+ if (num == TARGET_NR_setxattr) {
+ ret = get_errno(setxattr(p, n, v, arg4, arg5));
+ } else {
+ ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
+ }
} else {
ret = -TARGET_EFAULT;
}
@@ -7671,14 +7862,45 @@
unlock_user(v, arg3, 0);
}
break;
- case TARGET_NR_getxattr:
+ case TARGET_NR_fsetxattr:
{
- void *p, *n, *v;
+ void *n, *v = 0;
+ if (arg3) {
+ v = lock_user(VERIFY_READ, arg3, arg4, 1);
+ if (!v) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
+ n = lock_user_string(arg2);
+ if (n) {
+ ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(n, arg2, 0);
+ unlock_user(v, arg3, 0);
+ }
+ break;
+ case TARGET_NR_getxattr:
+ case TARGET_NR_lgetxattr:
+ {
+ void *p, *n, *v = 0;
+ if (arg3) {
+ v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+ if (!v) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
p = lock_user_string(arg1);
n = lock_user_string(arg2);
- v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
- if (p && n && v) {
- ret = get_errno(getxattr(p, n, v, arg4));
+ if (p && n) {
+ if (num == TARGET_NR_getxattr) {
+ ret = get_errno(getxattr(p, n, v, arg4));
+ } else {
+ ret = get_errno(lgetxattr(p, n, v, arg4));
+ }
} else {
ret = -TARGET_EFAULT;
}
@@ -7687,13 +7909,38 @@
unlock_user(v, arg3, arg4);
}
break;
+ case TARGET_NR_fgetxattr:
+ {
+ void *n, *v = 0;
+ if (arg3) {
+ v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+ if (!v) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
+ n = lock_user_string(arg2);
+ if (n) {
+ ret = get_errno(fgetxattr(arg1, n, v, arg4));
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(n, arg2, 0);
+ unlock_user(v, arg3, arg4);
+ }
+ break;
case TARGET_NR_removexattr:
+ case TARGET_NR_lremovexattr:
{
void *p, *n;
p = lock_user_string(arg1);
n = lock_user_string(arg2);
if (p && n) {
- ret = get_errno(removexattr(p, n));
+ if (num == TARGET_NR_removexattr) {
+ ret = get_errno(removexattr(p, n));
+ } else {
+ ret = get_errno(lremovexattr(p, n));
+ }
} else {
ret = -TARGET_EFAULT;
}
@@ -7701,6 +7948,18 @@
unlock_user(n, arg2, 0);
}
break;
+ case TARGET_NR_fremovexattr:
+ {
+ void *n;
+ n = lock_user_string(arg2);
+ if (n) {
+ ret = get_errno(fremovexattr(arg1, n));
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(n, arg2, 0);
+ }
+ break;
#endif
#endif /* CONFIG_ATTR */
#ifdef TARGET_NR_set_thread_area
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 2857805..41f0ff8 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2336,3 +2336,9 @@
uint64_t rlim_cur;
uint64_t rlim_max;
};
+
+struct target_ucred {
+ uint32_t pid;
+ uint32_t uid;
+ uint32_t gid;
+};
diff --git a/main-loop.c b/main-loop.c
index 692381c..db23de0 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -164,7 +164,7 @@
#else /* _WIN32 */
-HANDLE qemu_event_handle;
+HANDLE qemu_event_handle = NULL;
static void dummy_event_handler(void *opaque)
{
@@ -183,6 +183,9 @@
void qemu_notify_event(void)
{
+ if (!qemu_event_handle) {
+ return;
+ }
if (!SetEvent(qemu_event_handle)) {
fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
GetLastError());
@@ -196,7 +199,7 @@
}
#endif
-int qemu_init_main_loop(void)
+int main_loop_init(void)
{
int ret;
diff --git a/main-loop.h b/main-loop.h
index f971013..4987041 100644
--- a/main-loop.h
+++ b/main-loop.h
@@ -41,10 +41,22 @@
* SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
* signals if available. Remember that Windows in practice does not have
* signals, though.
+ *
+ * In the case of QEMU tools, this will also start/initialize timers.
*/
int qemu_init_main_loop(void);
/**
+ * main_loop_init: Initializes main loop
+ *
+ * Internal (but shared for compatibility reasons) initialization routine
+ * for the main loop. This should not be used by applications directly,
+ * use qemu_init_main_loop() instead.
+ *
+ */
+int main_loop_init(void);
+
+/**
* main_loop_wait: Run one iteration of the main loop.
*
* If @nonblocking is true, poll for events, otherwise suspend until
diff --git a/memory.c b/memory.c
index 6201a37..5e77d8a 100644
--- a/memory.c
+++ b/memory.c
@@ -1049,6 +1049,42 @@
mr->ram_addr |= cpu_register_io_memory(mr);
}
+static uint64_t invalid_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ MemoryRegion *mr = opaque;
+
+ if (!mr->warning_printed) {
+ fprintf(stderr, "Invalid read from memory region %s\n", mr->name);
+ mr->warning_printed = true;
+ }
+ return -1U;
+}
+
+static void invalid_write(void *opaque, target_phys_addr_t addr, uint64_t data,
+ unsigned size)
+{
+ MemoryRegion *mr = opaque;
+
+ if (!mr->warning_printed) {
+ fprintf(stderr, "Invalid write to memory region %s\n", mr->name);
+ mr->warning_printed = true;
+ }
+}
+
+static const MemoryRegionOps reservation_ops = {
+ .read = invalid_read,
+ .write = invalid_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void memory_region_init_reservation(MemoryRegion *mr,
+ const char *name,
+ uint64_t size)
+{
+ memory_region_init_io(mr, &reservation_ops, mr, name, size);
+}
+
void memory_region_destroy(MemoryRegion *mr)
{
assert(QTAILQ_EMPTY(&mr->subregions));
@@ -1100,16 +1136,18 @@
}
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
- unsigned client)
+ target_phys_addr_t size, unsigned client)
{
assert(mr->terminates);
- return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
+ return cpu_physical_memory_get_dirty(mr->ram_addr + addr, size,
+ 1 << client);
}
-void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr)
+void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+ target_phys_addr_t size)
{
assert(mr->terminates);
- return cpu_physical_memory_set_dirty(mr->ram_addr + addr);
+ return cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size, -1);
}
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
diff --git a/memory.h b/memory.h
index d48b08b..4cf8d2f 100644
--- a/memory.h
+++ b/memory.h
@@ -126,6 +126,7 @@
bool readonly; /* For RAM regions */
bool enabled;
bool rom_device;
+ bool warning_printed; /* For reservations */
MemoryRegion *alias;
target_phys_addr_t alias_offset;
unsigned priority;
@@ -280,6 +281,21 @@
uint64_t size);
/**
+ * memory_region_init_reservation: Initialize a memory region that reserves
+ * I/O space.
+ *
+ * A reservation region primariy serves debugging purposes. It claims I/O
+ * space that is not supposed to be handled by QEMU itself. Any access via
+ * the memory API will cause an abort().
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @name: used for debugging; not visible to the user or ABI
+ * @size: size of the region.
+ */
+void memory_region_init_reservation(MemoryRegion *mr,
+ const char *name,
+ uint64_t size);
+/**
* memory_region_destroy: Destroy a memory region and reclaim all resources.
*
* @mr: the region to be destroyed. May not currently be a subregion
@@ -364,30 +380,34 @@
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
/**
- * memory_region_get_dirty: Check whether a page is dirty for a specified
- * client.
+ * memory_region_get_dirty: Check whether a range of bytes is dirty
+ * for a specified client.
*
- * Checks whether a page has been written to since the last
+ * Checks whether a range of bytes has been written to since the last
* call to memory_region_reset_dirty() with the same @client. Dirty logging
* must be enabled.
*
* @mr: the memory region being queried.
* @addr: the address (relative to the start of the region) being queried.
+ * @size: the size of the range being queried.
* @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
* %DIRTY_MEMORY_VGA.
*/
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
- unsigned client);
+ target_phys_addr_t size, unsigned client);
/**
- * memory_region_set_dirty: Mark a page as dirty in a memory region.
+ * memory_region_set_dirty: Mark a range of bytes as dirty in a memory region.
*
- * Marks a page as dirty, after it has been dirtied outside guest code.
+ * Marks a range of bytes as dirty, after it has been dirtied outside
+ * guest code.
*
- * @mr: the memory region being queried.
+ * @mr: the memory region being dirtied.
* @addr: the address (relative to the start of the region) being dirtied.
+ * @size: size of the range being dirtied.
*/
-void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr);
+void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+ target_phys_addr_t size);
/**
* memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
diff --git a/monitor.c b/monitor.c
index 7334401..aadbdcb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -227,7 +227,7 @@
return cur_mon && monitor_ctrl_mode(cur_mon);
}
-static void monitor_read_command(Monitor *mon, int show_prompt)
+void monitor_read_command(Monitor *mon, int show_prompt)
{
if (!mon->rs)
return;
@@ -237,8 +237,8 @@
readline_show_prompt(mon->rs);
}
-static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
- void *opaque)
+int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+ void *opaque)
{
if (monitor_ctrl_mode(mon)) {
qerror_report(QERR_MISSING_PARAMETER, "password");
@@ -479,6 +479,12 @@
case QEVENT_SPICE_DISCONNECTED:
event_name = "SPICE_DISCONNECTED";
break;
+ case QEVENT_BLOCK_JOB_COMPLETED:
+ event_name = "BLOCK_JOB_COMPLETED";
+ break;
+ case QEVENT_BLOCK_JOB_CANCELLED:
+ event_name = "BLOCK_JOB_CANCELLED";
+ break;
default:
abort();
break;
@@ -810,171 +816,6 @@
trace_print_events((FILE *)mon, &monitor_fprintf);
}
-#ifdef CONFIG_VNC
-static int change_vnc_password(const char *password)
-{
- if (!password || !password[0]) {
- if (vnc_display_disable_login(NULL)) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- return -1;
- }
- return 0;
- }
-
- if (vnc_display_password(NULL, password) < 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- return -1;
- }
-
- return 0;
-}
-
-static void change_vnc_password_cb(Monitor *mon, const char *password,
- void *opaque)
-{
- change_vnc_password(password);
- monitor_read_command(mon, 1);
-}
-
-static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
-{
- if (strcmp(target, "passwd") == 0 ||
- strcmp(target, "password") == 0) {
- if (arg) {
- char password[9];
- strncpy(password, arg, sizeof(password));
- password[sizeof(password) - 1] = '\0';
- return change_vnc_password(password);
- } else {
- return monitor_read_password(mon, change_vnc_password_cb, NULL);
- }
- } else {
- if (vnc_display_open(NULL, target) < 0) {
- qerror_report(QERR_VNC_SERVER_FAILED, target);
- return -1;
- }
- }
-
- return 0;
-}
-#else
-static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
-{
- qerror_report(QERR_FEATURE_DISABLED, "vnc");
- return -ENODEV;
-}
-#endif
-
-/**
- * do_change(): Change a removable medium, or VNC configuration
- */
-static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *device = qdict_get_str(qdict, "device");
- const char *target = qdict_get_str(qdict, "target");
- const char *arg = qdict_get_try_str(qdict, "arg");
- int ret;
-
- if (strcmp(device, "vnc") == 0) {
- ret = do_change_vnc(mon, target, arg);
- } else {
- ret = do_change_block(mon, device, target, arg);
- }
-
- return ret;
-}
-
-static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *protocol = qdict_get_str(qdict, "protocol");
- const char *password = qdict_get_str(qdict, "password");
- const char *connected = qdict_get_try_str(qdict, "connected");
- int disconnect_if_connected = 0;
- int fail_if_connected = 0;
- int rc;
-
- if (connected) {
- if (strcmp(connected, "fail") == 0) {
- fail_if_connected = 1;
- } else if (strcmp(connected, "disconnect") == 0) {
- disconnect_if_connected = 1;
- } else if (strcmp(connected, "keep") == 0) {
- /* nothing */
- } else {
- qerror_report(QERR_INVALID_PARAMETER, "connected");
- return -1;
- }
- }
-
- if (strcmp(protocol, "spice") == 0) {
- if (!using_spice) {
- /* correct one? spice isn't a device ,,, */
- qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
- return -1;
- }
- rc = qemu_spice_set_passwd(password, fail_if_connected,
- disconnect_if_connected);
- if (rc != 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- return -1;
- }
- return 0;
- }
-
- if (strcmp(protocol, "vnc") == 0) {
- if (fail_if_connected || disconnect_if_connected) {
- /* vnc supports "connected=keep" only */
- qerror_report(QERR_INVALID_PARAMETER, "connected");
- return -1;
- }
- /* Note that setting an empty password will not disable login through
- * this interface. */
- return vnc_display_password(NULL, password);
- }
-
- qerror_report(QERR_INVALID_PARAMETER, "protocol");
- return -1;
-}
-
-static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *protocol = qdict_get_str(qdict, "protocol");
- const char *whenstr = qdict_get_str(qdict, "time");
- time_t when;
- int rc;
-
- if (strcmp(whenstr, "now") == 0) {
- when = 0;
- } else if (strcmp(whenstr, "never") == 0) {
- when = TIME_MAX;
- } else if (whenstr[0] == '+') {
- when = time(NULL) + strtoull(whenstr+1, NULL, 10);
- } else {
- when = strtoull(whenstr, NULL, 10);
- }
-
- if (strcmp(protocol, "spice") == 0) {
- if (!using_spice) {
- /* correct one? spice isn't a device ,,, */
- qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
- return -1;
- }
- rc = qemu_spice_set_pw_expire(when);
- if (rc != 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- return -1;
- }
- return 0;
- }
-
- if (strcmp(protocol, "vnc") == 0) {
- return vnc_display_pw_expire(NULL, when);
- }
-
- qerror_report(QERR_INVALID_PARAMETER, "protocol");
- return -1;
-}
-
static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *protocol = qdict_get_str(qdict, "protocol");
@@ -2477,6 +2318,13 @@
.mhandler.info = hmp_info_blockstats,
},
{
+ .name = "block-jobs",
+ .args_type = "",
+ .params = "",
+ .help = "show progress of ongoing block device operations",
+ .mhandler.info = hmp_info_block_jobs,
+ },
+ {
.name = "registers",
.args_type = "",
.params = "",
@@ -4755,6 +4603,11 @@
monitor_read_command(mon, 1);
}
+ReadLineState *monitor_get_rs(Monitor *mon)
+{
+ return mon->rs;
+}
+
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
BlockDriverCompletionFunc *completion_cb,
void *opaque)
@@ -4768,7 +4621,8 @@
}
if (monitor_ctrl_mode(mon)) {
- qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+ qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+ bdrv_get_encrypted_filename(bs));
return -1;
}
diff --git a/monitor.h b/monitor.h
index cfa2f67..b72ea07 100644
--- a/monitor.h
+++ b/monitor.h
@@ -6,6 +6,7 @@
#include "qerror.h"
#include "qdict.h"
#include "block.h"
+#include "readline.h"
extern Monitor *cur_mon;
extern Monitor *default_mon;
@@ -35,6 +36,8 @@
QEVENT_SPICE_CONNECTED,
QEVENT_SPICE_INITIALIZED,
QEVENT_SPICE_DISCONNECTED,
+ QEVENT_BLOCK_JOB_COMPLETED,
+ QEVENT_BLOCK_JOB_CANCELLED,
QEVENT_MAX,
} MonitorEvent;
@@ -66,6 +69,10 @@
typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
void monitor_set_error(Monitor *mon, QError *qerror);
+void monitor_read_command(Monitor *mon, int show_prompt);
+ReadLineState *monitor_get_rs(Monitor *mon);
+int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+ void *opaque);
int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
diff --git a/net.c b/net.c
index 2b0f766..c34474f 100644
--- a/net.c
+++ b/net.c
@@ -38,6 +38,11 @@
#include "hw/qdev.h"
#include "iov.h"
+/* Net bridge is currently not supported for W32. */
+#if !defined(_WIN32)
+# define CONFIG_NET_BRIDGE
+#endif
+
static QTAILQ_HEAD(, VLANState) vlans;
static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
@@ -952,6 +957,12 @@
.type = QEMU_OPT_STRING,
.help = "script to shut down the interface",
}, {
+#ifdef CONFIG_NET_BRIDGE
+ .name = "helper",
+ .type = QEMU_OPT_STRING,
+ .help = "command to execute to configure bridge",
+ }, {
+#endif
.name = "sndbuf",
.type = QEMU_OPT_SIZE,
.help = "send buffer limit"
@@ -1053,6 +1064,25 @@
{ /* end of list */ }
},
},
+#ifdef CONFIG_NET_BRIDGE
+ [NET_CLIENT_TYPE_BRIDGE] = {
+ .type = "bridge",
+ .init = net_init_bridge,
+ .desc = {
+ NET_COMMON_PARAMS_DESC,
+ {
+ .name = "br",
+ .type = QEMU_OPT_STRING,
+ .help = "bridge name",
+ }, {
+ .name = "helper",
+ .type = QEMU_OPT_STRING,
+ .help = "command to execute to configure bridge",
+ },
+ { /* end of list */ }
+ },
+ },
+#endif /* CONFIG_NET_BRIDGE */
};
int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
@@ -1069,6 +1099,9 @@
if (is_netdev) {
if (strcmp(type, "tap") != 0 &&
+#ifdef CONFIG_NET_BRIDGE
+ strcmp(type, "bridge") != 0 &&
+#endif
#ifdef CONFIG_SLIRP
strcmp(type, "user") != 0 &&
#endif
@@ -1139,6 +1172,9 @@
{
int i;
const char *valid_param_list[] = { "tap", "socket", "dump"
+#ifdef CONFIG_NET_BRIDGE
+ , "bridge"
+#endif
#ifdef CONFIG_SLIRP
,"user"
#endif
diff --git a/net.h b/net.h
index eab089d..75a8c15 100644
--- a/net.h
+++ b/net.h
@@ -37,6 +37,7 @@
NET_CLIENT_TYPE_SOCKET,
NET_CLIENT_TYPE_VDE,
NET_CLIENT_TYPE_DUMP,
+ NET_CLIENT_TYPE_BRIDGE,
NET_CLIENT_TYPE_MAX
} net_client_type;
@@ -174,6 +175,8 @@
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
+#define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper"
+#define DEFAULT_BRIDGE_INTERFACE "br0"
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
diff --git a/net/checksum.c b/net/checksum.c
index 264c23f..9919b2e 100644
--- a/net/checksum.c
+++ b/net/checksum.c
@@ -4,7 +4,7 @@
*
* 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; under version 2 of the License.
+ * the Free Software Foundation; under version 2 or later 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
@@ -13,9 +13,6 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
*/
#include "net/checksum.h"
diff --git a/net/tap.c b/net/tap.c
index 6c27a94..f240028 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -382,6 +382,171 @@
return -1;
}
+static int recv_fd(int c)
+{
+ int fd;
+ uint8_t msgbuf[CMSG_SPACE(sizeof(fd))];
+ struct msghdr msg = {
+ .msg_control = msgbuf,
+ .msg_controllen = sizeof(msgbuf),
+ };
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ uint8_t req[1];
+ ssize_t len;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ iov.iov_base = req;
+ iov.iov_len = sizeof(req);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ len = recvmsg(c, &msg, 0);
+ if (len > 0) {
+ memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
+ return fd;
+ }
+
+ return len;
+}
+
+static int net_bridge_run_helper(const char *helper, const char *bridge)
+{
+ sigset_t oldmask, mask;
+ int pid, status;
+ char *args[5];
+ char **parg;
+ int sv[2];
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &mask, &oldmask);
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
+ return -1;
+ }
+
+ /* try to launch bridge helper */
+ pid = fork();
+ if (pid == 0) {
+ int open_max = sysconf(_SC_OPEN_MAX), i;
+ char fd_buf[6+10];
+ char br_buf[6+IFNAMSIZ] = {0};
+ char helper_cmd[PATH_MAX + sizeof(fd_buf) + sizeof(br_buf) + 15];
+
+ for (i = 0; i < open_max; i++) {
+ if (i != STDIN_FILENO &&
+ i != STDOUT_FILENO &&
+ i != STDERR_FILENO &&
+ i != sv[1]) {
+ close(i);
+ }
+ }
+
+ snprintf(fd_buf, sizeof(fd_buf), "%s%d", "--fd=", sv[1]);
+
+ if (strrchr(helper, ' ') || strrchr(helper, '\t')) {
+ /* assume helper is a command */
+
+ if (strstr(helper, "--br=") == NULL) {
+ snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
+ }
+
+ snprintf(helper_cmd, sizeof(helper_cmd), "%s %s %s %s",
+ helper, "--use-vnet", fd_buf, br_buf);
+
+ parg = args;
+ *parg++ = (char *)"sh";
+ *parg++ = (char *)"-c";
+ *parg++ = helper_cmd;
+ *parg++ = NULL;
+
+ execv("/bin/sh", args);
+ } else {
+ /* assume helper is just the executable path name */
+
+ snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
+
+ parg = args;
+ *parg++ = (char *)helper;
+ *parg++ = (char *)"--use-vnet";
+ *parg++ = fd_buf;
+ *parg++ = br_buf;
+ *parg++ = NULL;
+
+ execv(helper, args);
+ }
+ _exit(1);
+
+ } else if (pid > 0) {
+ int fd;
+
+ close(sv[1]);
+
+ do {
+ fd = recv_fd(sv[0]);
+ } while (fd == -1 && errno == EINTR);
+
+ close(sv[0]);
+
+ while (waitpid(pid, &status, 0) != pid) {
+ /* loop */
+ }
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ if (fd < 0) {
+ fprintf(stderr, "failed to recv file descriptor\n");
+ return -1;
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ return fd;
+ }
+ }
+ fprintf(stderr, "failed to launch bridge helper\n");
+ return -1;
+}
+
+int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name,
+ VLANState *vlan)
+{
+ TAPState *s;
+ int fd, vnet_hdr;
+
+ if (!qemu_opt_get(opts, "br")) {
+ qemu_opt_set(opts, "br", DEFAULT_BRIDGE_INTERFACE);
+ }
+ if (!qemu_opt_get(opts, "helper")) {
+ qemu_opt_set(opts, "helper", DEFAULT_BRIDGE_HELPER);
+ }
+
+ fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"),
+ qemu_opt_get(opts, "br"));
+ if (fd == -1) {
+ return -1;
+ }
+
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ vnet_hdr = tap_probe_vnet_hdr(fd);
+
+ s = net_tap_fd_init(vlan, "bridge", name, fd, vnet_hdr);
+ if (!s) {
+ close(fd);
+ return -1;
+ }
+
+ snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s",
+ qemu_opt_get(opts, "helper"), qemu_opt_get(opts, "br"));
+
+ return 0;
+}
+
static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
{
int fd, vnet_hdr_required;
@@ -422,13 +587,16 @@
{
TAPState *s;
int fd, vnet_hdr = 0;
+ const char *model;
if (qemu_opt_get(opts, "fd")) {
if (qemu_opt_get(opts, "ifname") ||
qemu_opt_get(opts, "script") ||
qemu_opt_get(opts, "downscript") ||
- qemu_opt_get(opts, "vnet_hdr")) {
- error_report("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=");
+ qemu_opt_get(opts, "vnet_hdr") ||
+ qemu_opt_get(opts, "helper")) {
+ error_report("ifname=, script=, downscript=, vnet_hdr=, "
+ "and helper= are invalid with fd=");
return -1;
}
@@ -440,6 +608,31 @@
fcntl(fd, F_SETFL, O_NONBLOCK);
vnet_hdr = tap_probe_vnet_hdr(fd);
+
+ model = "tap";
+
+ } else if (qemu_opt_get(opts, "helper")) {
+ if (qemu_opt_get(opts, "ifname") ||
+ qemu_opt_get(opts, "script") ||
+ qemu_opt_get(opts, "downscript") ||
+ qemu_opt_get(opts, "vnet_hdr")) {
+ error_report("ifname=, script=, downscript=, and vnet_hdr= "
+ "are invalid with helper=");
+ return -1;
+ }
+
+ fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"),
+ DEFAULT_BRIDGE_INTERFACE);
+ if (fd == -1) {
+ return -1;
+ }
+
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ vnet_hdr = tap_probe_vnet_hdr(fd);
+
+ model = "bridge";
+
} else {
if (!qemu_opt_get(opts, "script")) {
qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
@@ -453,9 +646,11 @@
if (fd == -1) {
return -1;
}
+
+ model = "tap";
}
- s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
+ s = net_tap_fd_init(vlan, model, name, fd, vnet_hdr);
if (!s) {
close(fd);
return -1;
@@ -467,6 +662,9 @@
if (qemu_opt_get(opts, "fd")) {
snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
+ } else if (qemu_opt_get(opts, "helper")) {
+ snprintf(s->nc.info_str, sizeof(s->nc.info_str),
+ "helper=%s", qemu_opt_get(opts, "helper"));
} else {
const char *ifname, *script, *downscript;
diff --git a/net/tap.h b/net/tap.h
index e44bd2b..56c591f 100644
--- a/net/tap.h
+++ b/net/tap.h
@@ -57,4 +57,7 @@
struct vhost_net;
struct vhost_net *tap_get_vhost_net(VLANClientState *vc);
+int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name,
+ VLANState *vlan);
+
#endif /* QEMU_NET_TAP_H */
diff --git a/os-posix.c b/os-posix.c
index 5c437ca..e3ed497 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -348,6 +348,6 @@
return -1;
}
- close(fd);
+ /* keep pidfile open & locked forever */
return 0;
}
diff --git a/pc-bios/README b/pc-bios/README
index 1cebbbc..5dce355 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/dgibson/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20111013.
+ built from git tag qemu-slof-20120111.1.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/bamboo.dtb b/pc-bios/bamboo.dtb
index c78e254..d12e201 100644
--- a/pc-bios/bamboo.dtb
+++ b/pc-bios/bamboo.dtb
Binary files differ
diff --git a/pc-bios/bamboo.dts b/pc-bios/bamboo.dts
index 655442c..62fabcc 100644
--- a/pc-bios/bamboo.dts
+++ b/pc-bios/bamboo.dts
@@ -9,12 +9,14 @@
* any warranty of any kind, whether express or implied.
*/
+/dts-v1/;
+
/ {
#address-cells = <2>;
#size-cells = <1>;
model = "amcc,bamboo";
compatible = "amcc,bamboo";
- dcr-parent = <&/cpus/cpu@0>;
+ dcr-parent = <&{/cpus/cpu@0}>;
aliases {
serial0 = &UART0;
@@ -29,12 +31,12 @@
device_type = "cpu";
model = "PowerPC,440EP";
reg = <0>;
- clock-frequency = <1fca0550>;
- timebase-frequency = <017d7840>;
- i-cache-line-size = <20>;
- d-cache-line-size = <20>;
- i-cache-size = <8000>;
- d-cache-size = <8000>;
+ clock-frequency = <0x1fca0550>;
+ timebase-frequency = <0x017d7840>;
+ i-cache-line-size = <0x20>;
+ d-cache-line-size = <0x20>;
+ i-cache-size = <0x8000>;
+ d-cache-size = <0x8000>;
dcr-controller;
dcr-access-method = "native";
};
@@ -42,40 +44,27 @@
memory {
device_type = "memory";
- reg = <0 0 9000000>;
+ reg = <0x0 0x0 0x9000000>;
};
UIC0: interrupt-controller0 {
compatible = "ibm,uic-440ep","ibm,uic";
interrupt-controller;
- cell-index = <0>;
- dcr-reg = <0c0 009>;
- #address-cells = <0>;
- #size-cells = <0>;
- #interrupt-cells = <2>;
+ cell-index = <0x0>;
+ dcr-reg = <0x0c0 0x009>;
+ #address-cells = <0x0>;
+ #size-cells = <0x0>;
+ #interrupt-cells = <0x2>;
};
-/*
- UIC1: interrupt-controller1 {
- compatible = "ibm,uic-440ep","ibm,uic";
- interrupt-controller;
- cell-index = <1>;
- dcr-reg = <0d0 009>;
- #address-cells = <0>;
- #size-cells = <0>;
- #interrupt-cells = <2>;
- interrupts = <1e 4 1f 4>;
- interrupt-parent = <&UIC0>;
- };
-*/
SDR0: sdr {
compatible = "ibm,sdr-440ep";
- dcr-reg = <00e 002>;
+ dcr-reg = <0x00e 0x002>;
};
CPR0: cpr {
compatible = "ibm,cpr-440ep";
- dcr-reg = <00c 002>;
+ dcr-reg = <0x00c 0x002>;
};
plb {
@@ -83,16 +72,16 @@
#address-cells = <2>;
#size-cells = <1>;
ranges;
- clock-frequency = <07f28154>;
+ clock-frequency = <0x07f28154>;
SDRAM0: sdram {
compatible = "ibm,sdram-440ep", "ibm,sdram-405gp";
- dcr-reg = <010 2>;
+ dcr-reg = <0x010 0x2>;
};
DMA0: dma {
compatible = "ibm,dma-440ep", "ibm,dma-440gp";
- dcr-reg = <100 027>;
+ dcr-reg = <0x100 0x027>;
};
POB0: opb {
@@ -102,18 +91,18 @@
/* Bamboo is oddball in the 44x world and doesn't use the ERPN
* bits.
*/
- ranges = <00000000 0 00000000 80000000
- 80000000 0 80000000 80000000>;
+ ranges = <0x00000000 0x0 0x00000000 0x80000000
+ 0x80000000 0x0 0x80000000 0x80000000>;
/* interrupt-parent = <&UIC1>; */
interrupts = <7 4>;
- clock-frequency = <03f940aa>;
+ clock-frequency = <0x03f940aa>;
EBC0: ebc {
compatible = "ibm,ebc-440ep", "ibm,ebc-440gp", "ibm,ebc";
- dcr-reg = <012 2>;
+ dcr-reg = <0x012 2>;
#address-cells = <2>;
#size-cells = <1>;
- clock-frequency = <03f940aa>;
+ clock-frequency = <0x03f940aa>;
interrupts = <5 1>;
/* interrupt-parent = <&UIC1>; */
};
@@ -121,10 +110,10 @@
UART0: serial@ef600300 {
device_type = "serial";
compatible = "ns16550";
- reg = <ef600300 8>;
- virtual-reg = <ef600300>;
- clock-frequency = <00a8c000>;
- current-speed = <1c200>;
+ reg = <0xef600300 8>;
+ virtual-reg = <0xef600300>;
+ clock-frequency = <0x00a8c000>;
+ current-speed = <0x1c200>;
interrupt-parent = <&UIC0>;
interrupts = <0 4>;
};
@@ -132,41 +121,18 @@
UART1: serial@ef600400 {
device_type = "serial";
compatible = "ns16550";
- reg = <ef600400 8>;
- virtual-reg = <ef600400>;
- clock-frequency = <00a8c000>;
+ reg = <0xef600400 8>;
+ virtual-reg = <0xef600400>;
+ clock-frequency = <0x00a8c000>;
current-speed = <0>;
interrupt-parent = <&UIC0>;
interrupts = <1 4>;
};
-/*
- UART2: serial@ef600500 {
- device_type = "serial";
- compatible = "ns16550";
- reg = <ef600500 8>;
- virtual-reg = <ef600500>;
- clock-frequency = <0>;
- current-speed = <0>;
- interrupt-parent = <&UIC0>;
- interrupts = <3 4>;
- };
- UART3: serial@ef600600 {
- device_type = "serial";
- compatible = "ns16550";
- reg = <ef600600 8>;
- virtual-reg = <ef600600>;
- clock-frequency = <0>;
- current-speed = <0>;
- interrupt-parent = <&UIC0>;
- interrupts = <4 4>;
- };
-
-*/
IIC0: i2c@ef600700 {
device_type = "i2c";
compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
- reg = <ef600700 14>;
+ reg = <0xef600700 0x14>;
interrupt-parent = <&UIC0>;
interrupts = <2 4>;
};
@@ -174,7 +140,7 @@
IIC1: i2c@ef600800 {
device_type = "i2c";
compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
- reg = <ef600800 14>;
+ reg = <0xef600800 14>;
interrupt-parent = <&UIC0>;
interrupts = <7 4>;
};
@@ -182,7 +148,7 @@
ZMII0: emac-zmii@ef600d00 {
device_type = "zmii-interface";
compatible = "ibm,zmii-440ep", "ibm,zmii-440gp", "ibm,zmii";
- reg = <ef600d00 c>;
+ reg = <0xef600d00 0xc>;
};
};
@@ -194,35 +160,35 @@
#address-cells = <3>;
compatible = "ibm,plb440ep-pci", "ibm,plb-pci";
primary;
- reg = <0 eec00000 8 /* Config space access */
- 0 eed00000 4 /* IACK */
- 0 eed00000 4 /* Special cycle */
- 0 ef400000 40>; /* Internal registers */
+ reg = <0 0xeec00000 8 /* Config space access */
+ 0 0xeed00000 4 /* IACK */
+ 0 0xeed00000 4 /* Special cycle */
+ 0 0xef400000 0x40>; /* Internal registers */
/* Outbound ranges, one memory and one IO,
* later cannot be changed. Chip supports a second
* IO range but we don't use it for now
*/
- ranges = <02000000 0 a0000000 0 a0000000 0 20000000
- 01000000 0 00000000 0 e8000000 0 00010000>;
+ ranges = <0x02000000 0 0xa0000000 0 0xa0000000 0 0x20000000
+ 0x01000000 0 0x00000000 0 0xe8000000 0 0x00010000>;
/* Inbound 2GB range starting at 0 */
- dma-ranges = <42000000 0 0 0 0 0 80000000>;
+ dma-ranges = <0x42000000 0 0 0 0 0 0x80000000>;
/* Bamboo has all 4 IRQ pins tied together per slot */
- interrupt-map-mask = <f800 0 0 0>;
+ interrupt-map-mask = <0xf800 0 0 0>;
interrupt-map = <
/* IDSEL 1 */
- 0800 0 0 0 &UIC0 1c 8
+ 0x0800 0 0 0 &UIC0 0x1c 8
/* IDSEL 2 */
- 1000 0 0 0 &UIC0 1b 8
+ 0x1000 0 0 0 &UIC0 0x1b 8
/* IDSEL 3 */
- 1800 0 0 0 &UIC0 1a 8
+ 0x1800 0 0 0 &UIC0 0x1a 8
/* IDSEL 4 */
- 2000 0 0 0 &UIC0 19 8
+ 0x2000 0 0 0 &UIC0 0x19 8
>;
};
diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
index 51da288..2caf7e6 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -16,6 +16,9 @@
build-all: multiboot.bin linuxboot.bin
+# suppress auto-removal of intermediate files
+.SECONDARY:
+
%.img: %.o
$(call quiet-command,$(LD) -Ttext 0 -e _start -s -o $@ $<," Building $(TARGET_DIR)$@")
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 1e84582..8554f54 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/qapi-schema.json b/qapi-schema.json
index 44cf764..d02ee86 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -845,6 +845,38 @@
{ 'command': 'query-pci', 'returns': ['PciInfo'] }
##
+# @BlockJobInfo:
+#
+# Information about a long-running block device operation.
+#
+# @type: the job type ('stream' for image streaming)
+#
+# @device: the block device name
+#
+# @len: the maximum progress value
+#
+# @offset: the current progress value
+#
+# @speed: the rate limit, bytes per second
+#
+# Since: 1.1
+##
+{ 'type': 'BlockJobInfo',
+ 'data': {'type': 'str', 'device': 'str', 'len': 'int',
+ 'offset': 'int', 'speed': 'int'} }
+
+##
+# @query-block-jobs:
+#
+# Return information about long-running block device operations.
+#
+# Returns: a list of @BlockJobInfo for each active block job
+#
+# Since: 1.1
+##
+{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'] }
+
+##
# @quit:
#
# This command will cause the QEMU process to exit gracefully. While every
@@ -1064,8 +1096,11 @@
#
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
-#
-# Notes: This command returns UndefinedError in a number of error conditions.
+# If @size is negative, InvalidParameterValue
+# If the block device has no medium inserted, DeviceHasNoMedium
+# If the block device does not support resize, Unsupported
+# If the block device is read-only, DeviceIsReadOnly
+# If a long-running operation is using the device, DeviceInUse
#
# Since: 0.14.0
##
@@ -1193,20 +1228,20 @@
#
# Notes: This type is experimental. Its syntax may change in future releases.
##
-{ 'type': 'DevicePropertyInfo',
+{ 'type': 'ObjectPropertyInfo',
'data': { 'name': 'str', 'type': 'str' } }
##
# @qom-list:
#
-# This command will list any properties of a device given a path in the device
+# This command will list any properties of a object given a path in the object
# model.
#
-# @path: the path within the device model. See @qom-get for a description of
+# @path: the path within the object model. See @qom-get for a description of
# this parameter.
#
-# Returns: a list of @DevicePropertyInfo that describe the properties of the
-# device.
+# Returns: a list of @ObjectPropertyInfo that describe the properties of the
+# object.
#
# Since: 1.1
#
@@ -1215,25 +1250,25 @@
##
{ 'command': 'qom-list',
'data': { 'path': 'str' },
- 'returns': [ 'DevicePropertyInfo' ] }
+ 'returns': [ 'ObjectPropertyInfo' ] }
##
# @qom-get:
#
-# This command will get a property from a device model path and return the
+# This command will get a property from a object model path and return the
# value.
#
-# @path: The path within the device model. There are two forms of supported
+# @path: The path within the object model. There are two forms of supported
# paths--absolute and partial paths.
#
-# Absolute paths are derived from the root device and can follow child<>
+# Absolute paths are derived from the root object and can follow child<>
# or link<> properties. Since they can follow link<> properties, they
# can be arbitrarily long. Absolute paths look like absolute filenames
# and are prefixed with a leading slash.
#
# Partial paths look like relative filenames. They do not begin
# with a prefix. The matching rules for partial paths are subtle but
-# designed to make specifying devices easy. At each level of the
+# designed to make specifying objects easy. At each level of the
# composition tree, the partial path is matched as an absolute path.
# The first match is not returned. At least two matches are searched
# for. A successful result is only returned if only one match is
@@ -1259,7 +1294,7 @@
##
# @qom-set:
#
-# This command will set a property from a device model path.
+# This command will set a property from a object model path.
#
# @path: see @qom-get for a description of this parameter
#
@@ -1275,3 +1310,275 @@
{ 'command': 'qom-set',
'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
'gen': 'no' }
+
+##
+# @set_password:
+#
+# Sets the password of a remote display session.
+#
+# @protocol: `vnc' to modify the VNC server password
+# `spice' to modify the Spice server password
+#
+# @password: the new password
+#
+# @connected: #optional how to handle existing clients when changing the
+# password. If nothing is specified, defaults to `keep'
+# `fail' to fail the command if clients are connected
+# `disconnect' to disconnect existing clients
+# `keep' to maintain existing clients
+#
+# Returns: Nothing on success
+# If Spice is not enabled, DeviceNotFound
+# If @protocol does not support connected, InvalidParameter
+# If @protocol is invalid, InvalidParameter
+# If any other error occurs, SetPasswdFailed
+#
+# Notes: If VNC is not enabled, SetPasswdFailed is returned.
+#
+# Since: 0.14.0
+##
+{ 'command': 'set_password',
+ 'data': {'protocol': 'str', 'password': 'str', '*connected': 'str'} }
+
+##
+# @expire_password:
+#
+# Expire the password of a remote display server.
+#
+# @protocol: the name of the remote display protocol `vnc' or `spice'
+#
+# @time: when to expire the password.
+# `now' to expire the password immediately
+# `never' to cancel password expiration
+# `+INT' where INT is the number of seconds from now (integer)
+# `INT' where INT is the absolute time in seconds
+#
+# Returns: Nothing on success
+# If @protocol is `spice' and Spice is not active, DeviceNotFound
+# If an error occurs setting password expiration, SetPasswdFailed
+# If @protocol is not `spice' or 'vnc', InvalidParameter
+#
+# Since: 0.14.0
+#
+# Notes: Time is relative to the server and currently there is no way to
+# coordinate server time with client time. It is not recommended to
+# use the absolute time version of the @time parameter unless you're
+# sure you are on the same machine as the QEMU instance.
+##
+{ 'command': 'expire_password', 'data': {'protocol': 'str', 'time': 'str'} }
+
+##
+# @eject:
+#
+# Ejects a device from a removable drive.
+#
+# @device: The name of the device
+#
+# @force: @optional If true, eject regardless of whether the drive is locked.
+# If not specified, the default value is false.
+#
+# Returns: Nothing on success
+# If @device is not a valid block device, DeviceNotFound
+# If @device is not removable and @force is false, DeviceNotRemovable
+# If @force is false and @device is locked, DeviceLocked
+#
+# Notes: Ejecting a device will no media results in success
+#
+# Since: 0.14.0
+##
+{ 'command': 'eject', 'data': {'device': 'str', '*force': 'bool'} }
+
+##
+# @change-vnc-password:
+#
+# Change the VNC server password.
+#
+# @target: the new password to use with VNC authentication
+#
+# Since: 1.1
+#
+# Notes: An empty password in this command will set the password to the empty
+# string. Existing clients are unaffected by executing this command.
+##
+{ 'command': 'change-vnc-password', 'data': {'password': 'str'} }
+
+##
+# @change:
+#
+# This command is multiple commands multiplexed together.
+#
+# @device: This is normally the name of a block device but it may also be 'vnc'.
+# when it's 'vnc', then sub command depends on @target
+#
+# @target: If @device is a block device, then this is the new filename.
+# If @device is 'vnc', then if the value 'password' selects the vnc
+# change password command. Otherwise, this specifies a new server URI
+# address to listen to for VNC connections.
+#
+# @arg: If @device is a block device, then this is an optional format to open
+# the device with.
+# If @device is 'vnc' and @target is 'password', this is the new VNC
+# password to set. If this argument is an empty string, then no future
+# logins will be allowed.
+#
+# Returns: Nothing on success.
+# If @device is not a valid block device, DeviceNotFound
+# If @format is not a valid block format, InvalidBlockFormat
+# If the new block device is encrypted, DeviceEncrypted. Note that
+# if this error is returned, the device has been opened successfully
+# and an additional call to @block_passwd is required to set the
+# device's password. The behavior of reads and writes to the block
+# device between when these calls are executed is undefined.
+#
+# Notes: It is strongly recommended that this interface is not used especially
+# for changing block devices.
+#
+# Since: 0.14.0
+##
+{ 'command': 'change',
+ 'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
+
+##
+# @block_set_io_throttle:
+#
+# Change I/O throttle limits for a block drive.
+#
+# @device: The name of the device
+#
+# @bps: total throughput limit in bytes per second
+#
+# @bps_rd: read throughput limit in bytes per second
+#
+# @bps_wr: write throughput limit in bytes per second
+#
+# @iops: total I/O operations per second
+#
+# @ops_rd: read I/O operations per second
+#
+# @iops_wr: write I/O operations per second
+#
+# Returns: Nothing on success
+# If @device is not a valid block device, DeviceNotFound
+# If the argument combination is invalid, InvalidParameterCombination
+#
+# Since: 1.1
+##
+{ 'command': 'block_set_io_throttle',
+ 'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
+ 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
+
+# @block_stream:
+#
+# Copy data from a backing file into a block device.
+#
+# The block streaming operation is performed in the background until the entire
+# backing file has been copied. This command returns immediately once streaming
+# has started. The status of ongoing block streaming operations can be checked
+# with query-block-jobs. The operation can be stopped before it has completed
+# using the block_job_cancel command.
+#
+# If a base file is specified then sectors are not copied from that base file and
+# its backing chain. When streaming completes the image file will have the base
+# file as its backing file. This can be used to stream a subset of the backing
+# file chain instead of flattening the entire image.
+#
+# On successful completion the image file is updated to drop the backing file
+# and the BLOCK_JOB_COMPLETED event is emitted.
+#
+# @device: the device name
+#
+# @base: #optional the common backing file name
+#
+# Returns: Nothing on success
+# If streaming is already active on this device, DeviceInUse
+# If @device does not exist, DeviceNotFound
+# If image streaming is not supported by this device, NotSupported
+# If @base does not exist, BaseNotFound
+#
+# Since: 1.1
+##
+{ 'command': 'block_stream', 'data': { 'device': 'str', '*base': 'str' } }
+
+##
+# @block_job_set_speed:
+#
+# Set maximum speed for a background block operation.
+#
+# This command can only be issued when there is an active block job.
+#
+# Throttling can be disabled by setting the speed to 0.
+#
+# @device: the device name
+#
+# @value: the maximum speed, in bytes per second
+#
+# Returns: Nothing on success
+# If the job type does not support throttling, NotSupported
+# If streaming is not active on this device, DeviceNotActive
+#
+# Since: 1.1
+##
+{ 'command': 'block_job_set_speed',
+ 'data': { 'device': 'str', 'value': 'int' } }
+
+##
+# @block_job_cancel:
+#
+# Stop an active block streaming operation.
+#
+# This command returns immediately after marking the active block streaming
+# operation for cancellation. It is an error to call this command if no
+# operation is in progress.
+#
+# The operation will cancel as soon as possible and then emit the
+# BLOCK_JOB_CANCELLED event. Before that happens the job is still visible when
+# enumerated using query-block-jobs.
+#
+# The image file retains its backing file unless the streaming operation happens
+# to complete just as it is being cancelled.
+#
+# A new block streaming operation can be started at a later time to finish
+# copying all data from the backing file.
+#
+# @device: the device name
+#
+# Returns: Nothing on success
+# If streaming is not active on this device, DeviceNotActive
+# If cancellation already in progress, DeviceInUse
+#
+# Since: 1.1
+##
+{ 'command': 'block_job_cancel', 'data': { 'device': 'str' } }
+
+##
+# @ObjectTypeInfo:
+#
+# This structure describes a search result from @qom-list-types
+#
+# @name: the type name found in the search
+#
+# Since: 1.1
+#
+# Notes: This command is experimental and may change syntax in future releases.
+##
+{ 'type': 'ObjectTypeInfo',
+ 'data': { 'name': 'str' } }
+
+##
+# @qom-list-types:
+#
+# This command will return a list of types given search parameters
+#
+# @implements: if specified, only return types that implement this type name
+#
+# @abstract: if true, include abstract types in the results
+#
+# Returns: a list of @ObjectTypeInfo or an empty list if no results are found
+#
+# Since: 1.1
+#
+# Notes: This command is experimental and may change syntax in future releases.
+##
+{ 'command': 'qom-list-types',
+ 'data': { '*implements': 'str', '*abstract': 'bool' },
+ 'returns': [ 'ObjectTypeInfo' ] }
diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c
new file mode 100644
index 0000000..aec5008
--- /dev/null
+++ b/qemu-bridge-helper.c
@@ -0,0 +1,410 @@
+/*
+ * QEMU Bridge Helper
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Richa Marwaha <rmarwah@linux.vnet.ibm.com>
+ * Corey Bryant <coreyb@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 "config-host.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <glib.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/prctl.h>
+
+#include <net/if.h>
+
+#include <linux/sockios.h>
+
+#include "qemu-queue.h"
+
+#include "net/tap-linux.h"
+
+#ifdef CONFIG_LIBCAP
+#include <cap-ng.h>
+#endif
+
+#define DEFAULT_ACL_FILE CONFIG_QEMU_CONFDIR "/bridge.conf"
+
+enum {
+ ACL_ALLOW = 0,
+ ACL_ALLOW_ALL,
+ ACL_DENY,
+ ACL_DENY_ALL,
+};
+
+typedef struct ACLRule {
+ int type;
+ char iface[IFNAMSIZ];
+ QSIMPLEQ_ENTRY(ACLRule) entry;
+} ACLRule;
+
+typedef QSIMPLEQ_HEAD(ACLList, ACLRule) ACLList;
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: qemu-bridge-helper [--use-vnet] --br=bridge --fd=unixfd\n");
+}
+
+static int parse_acl_file(const char *filename, ACLList *acl_list)
+{
+ FILE *f;
+ char line[4096];
+ ACLRule *acl_rule;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ return -1;
+ }
+
+ while (fgets(line, sizeof(line), f) != NULL) {
+ char *ptr = line;
+ char *cmd, *arg, *argend;
+
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+
+ /* skip comments and empty lines */
+ if (*ptr == '#' || *ptr == 0) {
+ continue;
+ }
+
+ cmd = ptr;
+ arg = strchr(cmd, ' ');
+ if (arg == NULL) {
+ arg = strchr(cmd, '\t');
+ }
+
+ if (arg == NULL) {
+ fprintf(stderr, "Invalid config line:\n %s\n", line);
+ fclose(f);
+ errno = EINVAL;
+ return -1;
+ }
+
+ *arg = 0;
+ arg++;
+ while (isspace(*arg)) {
+ arg++;
+ }
+
+ argend = arg + strlen(arg);
+ while (arg != argend && isspace(*(argend - 1))) {
+ argend--;
+ }
+ *argend = 0;
+
+ if (strcmp(cmd, "deny") == 0) {
+ acl_rule = g_malloc(sizeof(*acl_rule));
+ if (strcmp(arg, "all") == 0) {
+ acl_rule->type = ACL_DENY_ALL;
+ } else {
+ acl_rule->type = ACL_DENY;
+ snprintf(acl_rule->iface, IFNAMSIZ, "%s", arg);
+ }
+ QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
+ } else if (strcmp(cmd, "allow") == 0) {
+ acl_rule = g_malloc(sizeof(*acl_rule));
+ if (strcmp(arg, "all") == 0) {
+ acl_rule->type = ACL_ALLOW_ALL;
+ } else {
+ acl_rule->type = ACL_ALLOW;
+ snprintf(acl_rule->iface, IFNAMSIZ, "%s", arg);
+ }
+ QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
+ } else if (strcmp(cmd, "include") == 0) {
+ /* ignore errors */
+ parse_acl_file(arg, acl_list);
+ } else {
+ fprintf(stderr, "Unknown command `%s'\n", cmd);
+ fclose(f);
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static bool has_vnet_hdr(int fd)
+{
+ unsigned int features = 0;
+
+ if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
+ return false;
+ }
+
+ if (!(features & IFF_VNET_HDR)) {
+ return false;
+ }
+
+ return true;
+}
+
+static void prep_ifreq(struct ifreq *ifr, const char *ifname)
+{
+ memset(ifr, 0, sizeof(*ifr));
+ snprintf(ifr->ifr_name, IFNAMSIZ, "%s", ifname);
+}
+
+static int send_fd(int c, int fd)
+{
+ char msgbuf[CMSG_SPACE(sizeof(fd))];
+ struct msghdr msg = {
+ .msg_control = msgbuf,
+ .msg_controllen = sizeof(msgbuf),
+ };
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ char req[1] = { 0x00 };
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ iov.iov_base = req;
+ iov.iov_len = sizeof(req);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+
+ return sendmsg(c, &msg, 0);
+}
+
+#ifdef CONFIG_LIBCAP
+static int drop_privileges(void)
+{
+ /* clear all capabilities */
+ capng_clear(CAPNG_SELECT_BOTH);
+
+ if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+ CAP_NET_ADMIN) < 0) {
+ return -1;
+ }
+
+ /* change to calling user's real uid and gid, retaining supplemental
+ * groups and CAP_NET_ADMIN */
+ if (capng_change_id(getuid(), getgid(), CAPNG_CLEAR_BOUNDING)) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+ struct ifreq ifr;
+ int fd, ctlfd, unixfd = -1;
+ int use_vnet = 0;
+ int mtu;
+ const char *bridge = NULL;
+ char iface[IFNAMSIZ];
+ int index;
+ ACLRule *acl_rule;
+ ACLList acl_list;
+ int access_allowed, access_denied;
+ int ret = EXIT_SUCCESS;
+
+#ifdef CONFIG_LIBCAP
+ /* if we're run from an suid binary, immediately drop privileges preserving
+ * cap_net_admin */
+ if (geteuid() == 0 && getuid() != geteuid()) {
+ if (drop_privileges() == -1) {
+ fprintf(stderr, "failed to drop privileges\n");
+ return 1;
+ }
+ }
+#endif
+
+ /* parse arguments */
+ for (index = 1; index < argc; index++) {
+ if (strcmp(argv[index], "--use-vnet") == 0) {
+ use_vnet = 1;
+ } else if (strncmp(argv[index], "--br=", 5) == 0) {
+ bridge = &argv[index][5];
+ } else if (strncmp(argv[index], "--fd=", 5) == 0) {
+ unixfd = atoi(&argv[index][5]);
+ } else {
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (bridge == NULL || unixfd == -1) {
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ /* parse default acl file */
+ QSIMPLEQ_INIT(&acl_list);
+ if (parse_acl_file(DEFAULT_ACL_FILE, &acl_list) == -1) {
+ fprintf(stderr, "failed to parse default acl file `%s'\n",
+ DEFAULT_ACL_FILE);
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* validate bridge against acl -- default policy is to deny
+ * according acl policy if we have a deny and allow both
+ * then deny should always win over allow
+ */
+ access_allowed = 0;
+ access_denied = 0;
+ QSIMPLEQ_FOREACH(acl_rule, &acl_list, entry) {
+ switch (acl_rule->type) {
+ case ACL_ALLOW_ALL:
+ access_allowed = 1;
+ break;
+ case ACL_ALLOW:
+ if (strcmp(bridge, acl_rule->iface) == 0) {
+ access_allowed = 1;
+ }
+ break;
+ case ACL_DENY_ALL:
+ access_denied = 1;
+ break;
+ case ACL_DENY:
+ if (strcmp(bridge, acl_rule->iface) == 0) {
+ access_denied = 1;
+ }
+ break;
+ }
+ }
+
+ if ((access_allowed == 0) || (access_denied == 1)) {
+ fprintf(stderr, "access denied by acl file\n");
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* open a socket to use to control the network interfaces */
+ ctlfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (ctlfd == -1) {
+ fprintf(stderr, "failed to open control socket: %s\n", strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* open the tap device */
+ fd = open("/dev/net/tun", O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "failed to open /dev/net/tun: %s\n", strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* request a tap device, disable PI, and add vnet header support if
+ * requested and it's available. */
+ prep_ifreq(&ifr, "tap%d");
+ ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+ if (use_vnet && has_vnet_hdr(fd)) {
+ ifr.ifr_flags |= IFF_VNET_HDR;
+ }
+
+ if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
+ fprintf(stderr, "failed to create tun device: %s\n", strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* save tap device name */
+ snprintf(iface, sizeof(iface), "%s", ifr.ifr_name);
+
+ /* get the mtu of the bridge */
+ prep_ifreq(&ifr, bridge);
+ if (ioctl(ctlfd, SIOCGIFMTU, &ifr) == -1) {
+ fprintf(stderr, "failed to get mtu of bridge `%s': %s\n",
+ bridge, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* save mtu */
+ mtu = ifr.ifr_mtu;
+
+ /* set the mtu of the interface based on the bridge */
+ prep_ifreq(&ifr, iface);
+ ifr.ifr_mtu = mtu;
+ if (ioctl(ctlfd, SIOCSIFMTU, &ifr) == -1) {
+ fprintf(stderr, "failed to set mtu of device `%s' to %d: %s\n",
+ iface, mtu, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* add the interface to the bridge */
+ prep_ifreq(&ifr, bridge);
+ ifr.ifr_ifindex = if_nametoindex(iface);
+
+ if (ioctl(ctlfd, SIOCBRADDIF, &ifr) == -1) {
+ fprintf(stderr, "failed to add interface `%s' to bridge `%s': %s\n",
+ iface, bridge, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* bring the interface up */
+ prep_ifreq(&ifr, iface);
+ if (ioctl(ctlfd, SIOCGIFFLAGS, &ifr) == -1) {
+ fprintf(stderr, "failed to get interface flags for `%s': %s\n",
+ iface, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(ctlfd, SIOCSIFFLAGS, &ifr) == -1) {
+ fprintf(stderr, "failed to bring up interface `%s': %s\n",
+ iface, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* write fd to the domain socket */
+ if (send_fd(unixfd, fd) == -1) {
+ fprintf(stderr, "failed to write fd to unix socket: %s\n",
+ strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* ... */
+
+ /* profit! */
+
+cleanup:
+
+ while ((acl_rule = QSIMPLEQ_FIRST(&acl_list)) != NULL) {
+ QSIMPLEQ_REMOVE_HEAD(&acl_list, entry);
+ g_free(acl_rule);
+ }
+
+ return ret;
+}
diff --git a/qemu-char.c b/qemu-char.c
index 27abcb9..b1d80dd 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2903,3 +2903,13 @@
}
return NULL;
}
+
+/* Get a character (serial) device interface. */
+CharDriverState *qemu_char_get_next_serial(void)
+{
+ static int next_serial;
+
+ /* FIXME: This function needs to go away: use chardev properties! */
+ return serial_hds[next_serial++];
+}
+
diff --git a/qemu-char.h b/qemu-char.h
index 8ca1e2d..486644b 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -248,4 +248,6 @@
QString *qemu_chr_mem_to_qs(CharDriverState *chr);
size_t qemu_chr_mem_osize(const CharDriverState *chr);
+CharDriverState *qemu_char_get_next_serial(void);
+
#endif
diff --git a/qemu-common.h b/qemu-common.h
index 6ab7dfb..8b69a9e 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -250,6 +250,13 @@
typedef uint64_t pcibus_t;
+typedef enum LostTickPolicy {
+ LOST_TICK_DISCARD,
+ LOST_TICK_DELAY,
+ LOST_TICK_MERGE,
+ LOST_TICK_SLEW,
+} LostTickPolicy;
+
void tcg_exec_init(unsigned long tb_size);
bool tcg_enabled(void);
diff --git a/qemu-config.c b/qemu-config.c
index ecc88e8..b030205 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -531,6 +531,10 @@
.name = "accel",
.type = QEMU_OPT_STRING,
.help = "accelerator list",
+ }, {
+ .name = "kernel_irqchip",
+ .type = QEMU_OPT_BOOL,
+ .help = "use KVM in-kernel irqchip",
},
{ /* End of list */ }
},
diff --git a/qemu-coroutine-sleep.c b/qemu-coroutine-sleep.c
new file mode 100644
index 0000000..fd65274
--- /dev/null
+++ b/qemu-coroutine-sleep.c
@@ -0,0 +1,38 @@
+/*
+ * QEMU coroutine sleep
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-coroutine.h"
+#include "qemu-timer.h"
+
+typedef struct CoSleepCB {
+ QEMUTimer *ts;
+ Coroutine *co;
+} CoSleepCB;
+
+static void co_sleep_cb(void *opaque)
+{
+ CoSleepCB *sleep_cb = opaque;
+
+ qemu_free_timer(sleep_cb->ts);
+ qemu_coroutine_enter(sleep_cb->co, NULL);
+}
+
+void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns)
+{
+ CoSleepCB sleep_cb = {
+ .co = qemu_coroutine_self(),
+ };
+ sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb);
+ qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns);
+ qemu_coroutine_yield();
+}
diff --git a/qemu-coroutine.h b/qemu-coroutine.h
index 8a55fe1..34c15d4 100644
--- a/qemu-coroutine.h
+++ b/qemu-coroutine.h
@@ -17,6 +17,7 @@
#include <stdbool.h>
#include "qemu-queue.h"
+#include "qemu-timer.h"
/**
* Coroutines are a mechanism for stack switching and can be used for
@@ -199,4 +200,12 @@
*/
void qemu_co_rwlock_unlock(CoRwlock *lock);
+/**
+ * Yield the coroutine for a given duration
+ *
+ * Note this function uses timers and hence only works when a main loop is in
+ * use. See main-loop.h and do not use from qemu-tool programs.
+ */
+void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns);
+
#endif /* QEMU_COROUTINE_H */
diff --git a/qemu-io.c b/qemu-io.c
index ffa62fb..d4a5fcb 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -130,7 +130,7 @@
static void *
create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
{
- size_t *sizes = calloc(nr_iov, sizeof(size_t));
+ size_t *sizes = g_new0(size_t, nr_iov);
size_t count = 0;
void *buf = NULL;
void *p;
@@ -172,7 +172,7 @@
}
fail:
- free(sizes);
+ g_free(sizes);
return buf;
}
@@ -471,14 +471,14 @@
}
if (Pflag) {
- void *cmp_buf = malloc(pattern_count);
+ void *cmp_buf = g_malloc(pattern_count);
memset(cmp_buf, pattern, pattern_count);
if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
printf("Pattern verification failed at offset %"
PRId64 ", %d bytes\n",
offset + pattern_offset, pattern_count);
}
- free(cmp_buf);
+ g_free(cmp_buf);
}
if (qflag) {
@@ -601,13 +601,13 @@
}
if (Pflag) {
- void *cmp_buf = malloc(qiov.size);
+ void *cmp_buf = g_malloc(qiov.size);
memset(cmp_buf, pattern, qiov.size);
if (memcmp(buf, cmp_buf, qiov.size)) {
printf("Pattern verification failed at offset %"
PRId64 ", %zd bytes\n", offset, qiov.size);
}
- free(cmp_buf);
+ g_free(cmp_buf);
}
if (qflag) {
@@ -1063,7 +1063,7 @@
ctx->qiov.size, 1, ctx->Cflag);
out:
qemu_io_free(ctx->buf);
- free(ctx);
+ g_free(ctx);
}
static void aio_read_done(void *opaque, int ret)
@@ -1079,14 +1079,14 @@
}
if (ctx->Pflag) {
- void *cmp_buf = malloc(ctx->qiov.size);
+ void *cmp_buf = g_malloc(ctx->qiov.size);
memset(cmp_buf, ctx->pattern, ctx->qiov.size);
if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
printf("Pattern verification failed at offset %"
PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
}
- free(cmp_buf);
+ g_free(cmp_buf);
}
if (ctx->qflag) {
@@ -1103,7 +1103,7 @@
ctx->qiov.size, 1, ctx->Cflag);
out:
qemu_io_free(ctx->buf);
- free(ctx);
+ g_free(ctx);
}
static void aio_read_help(void)
@@ -1118,7 +1118,7 @@
" Reads a segment of the currently open file, optionally dumping it to the\n"
" standard output stream (with -v option) for subsequent inspection.\n"
" The read is performed asynchronously and the aio_flush command must be\n"
-" used to ensure all outstanding aio requests have been completed\n"
+" used to ensure all outstanding aio requests have been completed.\n"
" -C, -- report statistics in a machine parsable format\n"
" -P, -- use a pattern to verify read data\n"
" -v, -- dump buffer to standard output\n"
@@ -1141,7 +1141,7 @@
static int aio_read_f(int argc, char **argv)
{
int nr_iov, c;
- struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+ struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
switch (c) {
@@ -1152,7 +1152,7 @@
ctx->Pflag = 1;
ctx->pattern = parse_pattern(optarg);
if (ctx->pattern < 0) {
- free(ctx);
+ g_free(ctx);
return 0;
}
break;
@@ -1163,20 +1163,20 @@
ctx->vflag = 1;
break;
default:
- free(ctx);
+ g_free(ctx);
return command_usage(&aio_read_cmd);
}
}
if (optind > argc - 2) {
- free(ctx);
+ g_free(ctx);
return command_usage(&aio_read_cmd);
}
ctx->offset = cvtnum(argv[optind]);
if (ctx->offset < 0) {
printf("non-numeric length argument -- %s\n", argv[optind]);
- free(ctx);
+ g_free(ctx);
return 0;
}
optind++;
@@ -1184,14 +1184,14 @@
if (ctx->offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
ctx->offset);
- free(ctx);
+ g_free(ctx);
return 0;
}
nr_iov = argc - optind;
ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
if (ctx->buf == NULL) {
- free(ctx);
+ g_free(ctx);
return 0;
}
@@ -1214,7 +1214,7 @@
" Writes into a segment of the currently open file, using a buffer\n"
" filled with a set pattern (0xcdcdcdcd).\n"
" The write is performed asynchronously and the aio_flush command must be\n"
-" used to ensure all outstanding aio requests have been completed\n"
+" used to ensure all outstanding aio requests have been completed.\n"
" -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n"
" -q, -- quiet mode, do not show I/O statistics\n"
@@ -1237,7 +1237,7 @@
{
int nr_iov, c;
int pattern = 0xcd;
- struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+ struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
while ((c = getopt(argc, argv, "CqP:")) != EOF) {
switch (c) {
@@ -1250,25 +1250,25 @@
case 'P':
pattern = parse_pattern(optarg);
if (pattern < 0) {
- free(ctx);
+ g_free(ctx);
return 0;
}
break;
default:
- free(ctx);
+ g_free(ctx);
return command_usage(&aio_write_cmd);
}
}
if (optind > argc - 2) {
- free(ctx);
+ g_free(ctx);
return command_usage(&aio_write_cmd);
}
ctx->offset = cvtnum(argv[optind]);
if (ctx->offset < 0) {
printf("non-numeric length argument -- %s\n", argv[optind]);
- free(ctx);
+ g_free(ctx);
return 0;
}
optind++;
@@ -1276,14 +1276,14 @@
if (ctx->offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
ctx->offset);
- free(ctx);
+ g_free(ctx);
return 0;
}
nr_iov = argc - optind;
ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
if (ctx->buf == NULL) {
- free(ctx);
+ g_free(ctx);
return 0;
}
diff --git a/qemu-option.c b/qemu-option.c
index a303f87..4626ccf 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -603,7 +603,8 @@
g_free(opt);
}
-int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+static int opt_set(QemuOpts *opts, const char *name, const char *value,
+ bool prepend)
{
QemuOpt *opt;
const QemuOptDesc *desc = opts->list->desc;
@@ -626,7 +627,11 @@
opt = g_malloc0(sizeof(*opt));
opt->name = g_strdup(name);
opt->opts = opts;
- QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+ if (prepend) {
+ QTAILQ_INSERT_HEAD(&opts->head, opt, next);
+ } else {
+ QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+ }
if (desc[i].name != NULL) {
opt->desc = desc+i;
}
@@ -640,6 +645,11 @@
return 0;
}
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+{
+ return opt_set(opts, name, value, false);
+}
+
int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
{
QemuOpt *opt;
@@ -691,6 +701,9 @@
QTAILQ_FOREACH(opts, &list->head, next) {
if (!opts->id) {
+ if (!id) {
+ return opts;
+ }
continue;
}
if (strcmp(opts->id, id) != 0) {
@@ -806,7 +819,8 @@
return 0;
}
-int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+static int opts_do_parse(QemuOpts *opts, const char *params,
+ const char *firstname, bool prepend)
{
char option[128], value[1024];
const char *p,*pe,*pc;
@@ -841,7 +855,7 @@
}
if (strcmp(option, "id") != 0) {
/* store and parse */
- if (qemu_opt_set(opts, option, value) == -1) {
+ if (opt_set(opts, option, value, prepend) == -1) {
return -1;
}
}
@@ -852,8 +866,13 @@
return 0;
}
-QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
- int permit_abbrev)
+int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+{
+ return opts_do_parse(opts, params, firstname, false);
+}
+
+static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
+ int permit_abbrev, bool defaults)
{
const char *firstname;
char value[1024], *id = NULL;
@@ -870,11 +889,19 @@
get_opt_value(value, sizeof(value), p+4);
id = value;
}
- opts = qemu_opts_create(list, id, 1);
+ if (defaults) {
+ if (!id && !QTAILQ_EMPTY(&list->head)) {
+ opts = qemu_opts_find(list, NULL);
+ } else {
+ opts = qemu_opts_create(list, id, 0);
+ }
+ } else {
+ opts = qemu_opts_create(list, id, 1);
+ }
if (opts == NULL)
return NULL;
- if (qemu_opts_do_parse(opts, params, firstname) != 0) {
+ if (opts_do_parse(opts, params, firstname, defaults) != 0) {
qemu_opts_del(opts);
return NULL;
}
@@ -882,6 +909,21 @@
return opts;
}
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
+ int permit_abbrev)
+{
+ return opts_parse(list, params, permit_abbrev, false);
+}
+
+void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
+ int permit_abbrev)
+{
+ QemuOpts *opts;
+
+ opts = opts_parse(list, params, permit_abbrev, true);
+ assert(opts);
+}
+
static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
{
char buf[32];
diff --git a/qemu-option.h b/qemu-option.h
index 07958e4..e6f61e6 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -125,6 +125,8 @@
int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc);
int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev);
+void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
+ int permit_abbrev);
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict);
QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
diff --git a/qemu-options.hx b/qemu-options.hx
index 0cefd18..f577cc8 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -31,7 +31,8 @@
"-machine [type=]name[,prop[=value][,...]]\n"
" selects emulated machine (-machine ? for list)\n"
" property accel=accel1[:accel2[:...]] selects accelerator\n"
- " supported accelerators are kvm, xen, tcg (default: tcg)\n",
+ " supported accelerators are kvm, xen, tcg (default: tcg)\n"
+ " kernel_irqchip=on|off controls accelerated irqchip support\n",
QEMU_ARCH_ALL)
STEXI
@item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -44,6 +45,8 @@
kvm, xen, or tcg can be available. By default, tcg is used. If there is more
than one accelerator specified, the next one is used if the previous one fails
to initialize.
+@item kernel_irqchip=on|off
+Enables in-kernel irqchip support for the chosen accelerator when available.
@end table
ETEXI
@@ -1221,11 +1224,14 @@
"-net tap[,vlan=n][,name=str],ifname=name\n"
" connect the host TAP network interface to VLAN 'n'\n"
#else
- "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
- " connect the host TAP network interface to VLAN 'n' and use the\n"
- " network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
- " and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
+ "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
+ " connect the host TAP network interface to VLAN 'n' \n"
+ " use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
+ " to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
+ " to deconfigure it\n"
" use '[down]script=no' to disable script execution\n"
+ " use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n"
+ " configure it\n"
" use 'fd=h' to connect to an already opened TAP interface\n"
" use 'sndbuf=nbytes' to limit the size of the send buffer (the\n"
" default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576')\n"
@@ -1235,6 +1241,10 @@
" (only has effect for virtio guests which use MSIX)\n"
" use vhostforce=on to force vhost on for non-MSIX virtio guests\n"
" use 'vhostfd=h' to connect to an already opened vhost net device\n"
+ "-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper]\n"
+ " connects a host TAP network interface to a host bridge device 'br'\n"
+ " (default=" DEFAULT_BRIDGE_INTERFACE ") using the program 'helper'\n"
+ " (default=" DEFAULT_BRIDGE_HELPER ")\n"
#endif
"-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
" connect the vlan 'n' to another VLAN using a socket connection\n"
@@ -1260,6 +1270,7 @@
"user|"
#endif
"tap|"
+ "bridge|"
#ifdef CONFIG_VDE
"vde|"
#endif
@@ -1396,26 +1407,65 @@
syntax gives undefined results. Their use for new applications is discouraged
as they will be removed from future versions.
-@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}] [,script=@var{file}][,downscript=@var{dfile}]
-Connect the host TAP network interface @var{name} to VLAN @var{n}, use
-the network script @var{file} to configure it and the network script
+@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}]
+Connect the host TAP network interface @var{name} to VLAN @var{n}.
+
+Use the network script @var{file} to configure it and the network script
@var{dfile} to deconfigure it. If @var{name} is not provided, the OS
-automatically provides one. @option{fd}=@var{h} can be used to specify
-the handle of an already opened host TAP interface. The default network
-configure script is @file{/etc/qemu-ifup} and the default network
-deconfigure script is @file{/etc/qemu-ifdown}. Use @option{script=no}
-or @option{downscript=no} to disable script execution. Example:
+automatically provides one. The default network configure script is
+@file{/etc/qemu-ifup} and the default network deconfigure script is
+@file{/etc/qemu-ifdown}. Use @option{script=no} or @option{downscript=no}
+to disable script execution.
+
+If running QEMU as an unprivileged user, use the network helper
+@var{helper} to configure the TAP interface. The default network
+helper executable is @file{/usr/local/libexec/qemu-bridge-helper}.
+
+@option{fd}=@var{h} can be used to specify the handle of an already
+opened host TAP interface.
+
+Examples:
@example
+#launch a QEMU instance with the default network script
qemu linux.img -net nic -net tap
@end example
-More complicated example (two NICs, each one connected to a TAP device)
@example
+#launch a QEMU instance with two NICs, each one connected
+#to a TAP device
qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
-net nic,vlan=1 -net tap,vlan=1,ifname=tap1
@end example
+@example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge br0
+qemu linux.img -net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper"
+@end example
+
+@item -net bridge[,vlan=@var{n}][,name=@var{name}][,br=@var{bridge}][,helper=@var{helper}]
+Connect a host TAP network interface to a host bridge device.
+
+Use the network helper @var{helper} to configure the TAP interface and
+attach it to the bridge. The default network helper executable is
+@file{/usr/local/libexec/qemu-bridge-helper} and the default bridge
+device is @file{br0}.
+
+Examples:
+
+@example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge br0
+qemu linux.img -net bridge -net nic,model=virtio
+@end example
+
+@example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge qemubr0
+qemu linux.img -net bridge,br=qemubr0 -net nic,model=virtio
+@end example
+
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
index fe9b931..3524c8b 100644
--- a/qemu-thread-win32.c
+++ b/qemu-thread-win32.c
@@ -215,8 +215,6 @@
if (data->mode == QEMU_THREAD_DETACHED) {
g_free(data);
data = NULL;
- } else {
- InitializeCriticalSection(&data->cs);
}
TlsSetValue(qemu_thread_tls_index, data);
qemu_thread_exit(start_routine(thread_arg));
@@ -227,6 +225,7 @@
{
QemuThreadData *data = TlsGetValue(qemu_thread_tls_index);
if (data) {
+ assert(data->mode != QEMU_THREAD_DETACHED);
data->ret = arg;
EnterCriticalSection(&data->cs);
data->exited = true;
@@ -258,6 +257,7 @@
CloseHandle(handle);
}
ret = data->ret;
+ assert(data->mode != QEMU_THREAD_DETACHED);
DeleteCriticalSection(&data->cs);
g_free(data);
return ret;
@@ -288,6 +288,10 @@
data->mode = mode;
data->exited = false;
+ if (data->mode != QEMU_THREAD_DETACHED) {
+ InitializeCriticalSection(&data->cs);
+ }
+
hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
data, 0, &thread->tid);
if (!hThread) {
@@ -314,6 +318,7 @@
return NULL;
}
+ assert(data->mode != QEMU_THREAD_DETACHED);
EnterCriticalSection(&data->cs);
if (!data->exited) {
handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
diff --git a/qemu-timer.c b/qemu-timer.c
index cd026c6..a22f27e 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -494,35 +494,6 @@
if (!t)
return;
-#if 0
-#define DISP_FREQ 1000
- {
- static int64_t delta_min = INT64_MAX;
- static int64_t delta_max, delta_cum, last_clock, delta, ti;
- static int count;
- ti = qemu_get_clock_ns(vm_clock);
- if (last_clock != 0) {
- delta = ti - last_clock;
- if (delta < delta_min)
- delta_min = delta;
- if (delta > delta_max)
- delta_max = delta;
- delta_cum += delta;
- if (++count == DISP_FREQ) {
- printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
- muldiv64(delta_min, 1000000, get_ticks_per_sec()),
- muldiv64(delta_max, 1000000, get_ticks_per_sec()),
- muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()),
- (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ));
- count = 0;
- delta_min = INT64_MAX;
- delta_max = 0;
- delta_cum = 0;
- }
- }
- last_clock = ti;
- }
-#endif
if (alarm_has_dynticks(t) ||
qemu_next_alarm_deadline () <= 0) {
t->expired = alarm_has_dynticks(t);
diff --git a/qemu-tool.c b/qemu-tool.c
index c73bf71..183a583 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -59,12 +59,12 @@
{
}
-int64 cpu_get_clock(void)
+int64_t cpu_get_clock(void)
{
abort();
}
-int64 cpu_get_icount(void)
+int64_t cpu_get_icount(void)
{
abort();
}
@@ -83,11 +83,12 @@
{
}
-static void __attribute__((constructor)) init_main_loop(void)
+int qemu_init_main_loop(void)
{
init_clocks();
init_timer_alarm();
qemu_clock_enable(vm_clock, false);
+ return main_loop_init();
}
void slirp_select_fill(int *pnfds, fd_set *readfds,
diff --git a/qerror.c b/qerror.c
index 9a75d06..3d179c8 100644
--- a/qerror.c
+++ b/qerror.c
@@ -40,39 +40,54 @@
* "running out of foo: %(foo)%%"
*
* Please keep the entries in alphabetical order.
- * Use "sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c | sort -c"
- * to check.
+ * Use scripts/check-qerror.sh to check.
*/
static const QErrorStringTable qerror_table[] = {
{
+ .error_fmt = QERR_ADD_CLIENT_FAILED,
+ .desc = "Could not add client",
+ },
+ {
.error_fmt = QERR_BAD_BUS_FOR_DEVICE,
.desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
},
{
+ .error_fmt = QERR_BASE_NOT_FOUND,
+ .desc = "Base '%(base)' not found",
+ },
+ {
.error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
.desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
},
{
- .error_fmt = QERR_BUS_NOT_FOUND,
- .desc = "Bus '%(bus)' not found",
- },
- {
.error_fmt = QERR_BUS_NO_HOTPLUG,
.desc = "Bus '%(bus)' does not support hotplugging",
},
{
- .error_fmt = QERR_COMMAND_NOT_FOUND,
- .desc = "The command %(name) has not been found",
+ .error_fmt = QERR_BUS_NOT_FOUND,
+ .desc = "Bus '%(bus)' not found",
},
{
.error_fmt = QERR_COMMAND_DISABLED,
.desc = "The command %(name) has been disabled for this instance",
},
{
+ .error_fmt = QERR_COMMAND_NOT_FOUND,
+ .desc = "The command %(name) has not been found",
+ },
+ {
.error_fmt = QERR_DEVICE_ENCRYPTED,
.desc = "Device '%(device)' is encrypted",
},
{
+ .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+ .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+ },
+ {
+ .error_fmt = QERR_DEVICE_HAS_NO_MEDIUM,
+ .desc = "Device '%(device)' has no medium",
+ },
+ {
.error_fmt = QERR_DEVICE_INIT_FAILED,
.desc = "Device '%(device)' could not be initialized",
},
@@ -81,8 +96,8 @@
.desc = "Device '%(device)' is in use",
},
{
- .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
- .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+ .error_fmt = QERR_DEVICE_IS_READ_ONLY,
+ .desc = "Device '%(device)' is read only",
},
{
.error_fmt = QERR_DEVICE_LOCKED,
@@ -93,6 +108,14 @@
.desc = "Device '%(device)' has multiple child busses",
},
{
+ .error_fmt = QERR_DEVICE_NO_BUS,
+ .desc = "Device '%(device)' has no child bus",
+ },
+ {
+ .error_fmt = QERR_DEVICE_NO_HOTPLUG,
+ .desc = "Device '%(device)' does not support hotplugging",
+ },
+ {
.error_fmt = QERR_DEVICE_NOT_ACTIVE,
.desc = "Device '%(device)' has not been activated",
},
@@ -109,14 +132,6 @@
.desc = "Device '%(device)' is not removable",
},
{
- .error_fmt = QERR_DEVICE_NO_BUS,
- .desc = "Device '%(device)' has no child bus",
- },
- {
- .error_fmt = QERR_DEVICE_NO_HOTPLUG,
- .desc = "Device '%(device)' does not support hotplugging",
- },
- {
.error_fmt = QERR_DUPLICATE_ID,
.desc = "Duplicate ID '%(id)' for %(object)",
},
@@ -141,8 +156,12 @@
.desc = "Invalid parameter '%(name)'",
},
{
+ .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
+ .desc = "Invalid parameter combination",
+ },
+ {
.error_fmt = QERR_INVALID_PARAMETER_TYPE,
- .desc = "Invalid parameter type, expected: %(expected)",
+ .desc = "Invalid parameter type for '%(name)', expected: %(expected)",
},
{
.error_fmt = QERR_INVALID_PARAMETER_VALUE,
@@ -157,15 +176,15 @@
.desc = "An IO error has occurred",
},
{
- .error_fmt = QERR_JSON_PARSING,
- .desc = "Invalid JSON syntax",
- },
- {
.error_fmt = QERR_JSON_PARSE_ERROR,
.desc = "JSON parse error, %(message)",
},
{
+ .error_fmt = QERR_JSON_PARSING,
+ .desc = "Invalid JSON syntax",
+ },
+ {
.error_fmt = QERR_KVM_MISSING_CAP,
.desc = "Using KVM without %(capability), %(feature) unavailable",
},
@@ -182,6 +201,10 @@
.desc = "No '%(bus)' bus found for device '%(device)'",
},
{
+ .error_fmt = QERR_NOT_SUPPORTED,
+ .desc = "Not supported",
+ },
+ {
.error_fmt = QERR_OPEN_FILE_FAILED,
.desc = "Could not open '%(filename)'",
},
@@ -211,6 +234,14 @@
"value %(value) (minimum: %(min), maximum: %(max)'",
},
{
+ .error_fmt = QERR_QGA_COMMAND_FAILED,
+ .desc = "Guest agent command failed, error was '%(message)'",
+ },
+ {
+ .error_fmt = QERR_QGA_LOGGING_FAILED,
+ .desc = "Guest agent failed to log non-optional log statement",
+ },
+ {
.error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
.desc = "Expected '%(expected)' in QMP input",
},
@@ -231,10 +262,6 @@
.desc = "Could not set password",
},
{
- .error_fmt = QERR_ADD_CLIENT_FAILED,
- .desc = "Could not add client",
- },
- {
.error_fmt = QERR_TOO_MANY_FILES,
.desc = "Too many open files",
},
@@ -243,15 +270,15 @@
.desc = "An undefined error has occurred",
},
{
- .error_fmt = QERR_UNSUPPORTED,
- .desc = "this feature or command is not currently supported",
- },
- {
.error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
.desc = "'%(device)' uses a %(format) feature which is not "
"supported by this qemu version: %(feature)",
},
{
+ .error_fmt = QERR_UNSUPPORTED,
+ .desc = "this feature or command is not currently supported",
+ },
+ {
.error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
.desc = "Migration is disabled when VirtFS export path '%(path)' "
"is mounted in the guest using mount_tag '%(tag)'",
@@ -260,18 +287,6 @@
.error_fmt = QERR_VNC_SERVER_FAILED,
.desc = "Could not start VNC server on %(target)",
},
- {
- .error_fmt = QERR_QGA_LOGGING_FAILED,
- .desc = "Guest agent failed to log non-optional log statement",
- },
- {
- .error_fmt = QERR_QGA_COMMAND_FAILED,
- .desc = "Guest agent command failed, error was '%(message)'",
- },
- {
- .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
- .desc = "Invalid parameter combination",
- },
{}
};
diff --git a/qerror.h b/qerror.h
index efda232..8c36ddb 100644
--- a/qerror.h
+++ b/qerror.h
@@ -49,28 +49,43 @@
/*
* QError class list
* Please keep the definitions in alphabetical order.
- * Use "grep '^#define QERR_' qerror.h | sort -c" to check.
+ * Use scripts/check-qerror.sh to check.
*/
+#define QERR_ADD_CLIENT_FAILED \
+ "{ 'class': 'AddClientFailed', 'data': {} }"
+
#define QERR_BAD_BUS_FOR_DEVICE \
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+#define QERR_BASE_NOT_FOUND \
+ "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
+
#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
"{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
-#define QERR_BUS_NOT_FOUND \
- "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+#define QERR_BUFFER_OVERRUN \
+ "{ 'class': 'BufferOverrun', 'data': {} }"
#define QERR_BUS_NO_HOTPLUG \
"{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
-#define QERR_COMMAND_NOT_FOUND \
- "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+#define QERR_BUS_NOT_FOUND \
+ "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
#define QERR_COMMAND_DISABLED \
"{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+#define QERR_COMMAND_NOT_FOUND \
+ "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+
#define QERR_DEVICE_ENCRYPTED \
- "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }"
+ "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
+
+#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
+ "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+
+#define QERR_DEVICE_HAS_NO_MEDIUM \
+ "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
#define QERR_DEVICE_INIT_FAILED \
"{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
@@ -78,8 +93,8 @@
#define QERR_DEVICE_IN_USE \
"{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
-#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
- "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+#define QERR_DEVICE_IS_READ_ONLY \
+ "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
#define QERR_DEVICE_LOCKED \
"{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
@@ -87,6 +102,12 @@
#define QERR_DEVICE_MULTIPLE_BUSSES \
"{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
+#define QERR_DEVICE_NO_BUS \
+ "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NO_HOTPLUG \
+ "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+
#define QERR_DEVICE_NOT_ACTIVE \
"{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
@@ -99,12 +120,6 @@
#define QERR_DEVICE_NOT_REMOVABLE \
"{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
-#define QERR_DEVICE_NO_BUS \
- "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
-
-#define QERR_DEVICE_NO_HOTPLUG \
- "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
-
#define QERR_DUPLICATE_ID \
"{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
@@ -114,12 +129,18 @@
#define QERR_FD_NOT_SUPPLIED \
"{ 'class': 'FdNotSupplied', 'data': {} }"
+#define QERR_FEATURE_DISABLED \
+ "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+
#define QERR_INVALID_BLOCK_FORMAT \
"{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
#define QERR_INVALID_PARAMETER \
"{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+#define QERR_INVALID_PARAMETER_COMBINATION \
+ "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+
#define QERR_INVALID_PARAMETER_TYPE \
"{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
@@ -132,14 +153,11 @@
#define QERR_IO_ERROR \
"{ 'class': 'IOError', 'data': {} }"
-#define QERR_JSON_PARSING \
- "{ 'class': 'JSONParsing', 'data': {} }"
-
#define QERR_JSON_PARSE_ERROR \
"{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
-#define QERR_BUFFER_OVERRUN \
- "{ 'class': 'BufferOverrun', 'data': {} }"
+#define QERR_JSON_PARSING \
+ "{ 'class': 'JSONParsing', 'data': {} }"
#define QERR_KVM_MISSING_CAP \
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
@@ -153,6 +171,9 @@
#define QERR_NO_BUS_FOR_DEVICE \
"{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
+#define QERR_NOT_SUPPORTED \
+ "{ 'class': 'NotSupported', 'data': {} }"
+
#define QERR_OPEN_FILE_FAILED \
"{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
@@ -174,6 +195,12 @@
#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
"{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
+#define QERR_QGA_COMMAND_FAILED \
+ "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+
+#define QERR_QGA_LOGGING_FAILED \
+ "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+
#define QERR_QMP_BAD_INPUT_OBJECT \
"{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
@@ -189,37 +216,22 @@
#define QERR_SET_PASSWD_FAILED \
"{ 'class': 'SetPasswdFailed', 'data': {} }"
-#define QERR_ADD_CLIENT_FAILED \
- "{ 'class': 'AddClientFailed', 'data': {} }"
-
#define QERR_TOO_MANY_FILES \
"{ 'class': 'TooManyFiles', 'data': {} }"
#define QERR_UNDEFINED_ERROR \
"{ 'class': 'UndefinedError', 'data': {} }"
-#define QERR_UNSUPPORTED \
- "{ 'class': 'Unsupported', 'data': {} }"
-
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+#define QERR_UNSUPPORTED \
+ "{ 'class': 'Unsupported', 'data': {} }"
+
#define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
"{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
#define QERR_VNC_SERVER_FAILED \
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
-#define QERR_FEATURE_DISABLED \
- "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
-
-#define QERR_QGA_LOGGING_FAILED \
- "{ 'class': 'QgaLoggingFailed', 'data': {} }"
-
-#define QERR_QGA_COMMAND_FAILED \
- "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
-
-#define QERR_INVALID_PARAMETER_COMBINATION \
- "{ 'class': 'InvalidParameterCombination', 'data': {} }"
-
#endif /* QERROR_H */
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7e3f4b9..b5e2ab8 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -84,10 +84,7 @@
{
.name = "eject",
.args_type = "force:-f,device:B",
- .params = "[-f] device",
- .help = "eject a removable medium (use -f to force it)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_eject,
+ .mhandler.cmd_new = qmp_marshal_input_eject,
},
SQMP
@@ -113,10 +110,7 @@
{
.name = "change",
.args_type = "device:B,target:F,arg:s?",
- .params = "device filename [format]",
- .help = "change a removable medium, optional format",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_change,
+ .mhandler.cmd_new = qmp_marshal_input_change,
},
SQMP
@@ -655,6 +649,24 @@
EQMP
{
+ .name = "block_stream",
+ .args_type = "device:B,base:s?",
+ .mhandler.cmd_new = qmp_marshal_input_block_stream,
+ },
+
+ {
+ .name = "block_job_set_speed",
+ .args_type = "device:B,value:o",
+ .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
+ },
+
+ {
+ .name = "block_job_cancel",
+ .args_type = "device:B",
+ .mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
+ },
+
+ {
.name = "blockdev-snapshot-sync",
.args_type = "device:B,snapshot-file:s,format:s?",
.mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
@@ -813,10 +825,7 @@
{
.name = "block_set_io_throttle",
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
- .params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
- .help = "change I/O throttle limits for a block drive",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_set_io_throttle,
+ .mhandler.cmd_new = qmp_marshal_input_block_set_io_throttle,
},
SQMP
@@ -851,10 +860,7 @@
{
.name = "set_password",
.args_type = "protocol:s,password:s,connected:s?",
- .params = "protocol password action-if-connected",
- .help = "set spice/vnc password",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = set_password,
+ .mhandler.cmd_new = qmp_marshal_input_set_password,
},
SQMP
@@ -880,10 +886,7 @@
{
.name = "expire_password",
.args_type = "protocol:s,time:s",
- .params = "protocol time",
- .help = "set spice/vnc password expire-time",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = expire_password,
+ .mhandler.cmd_new = qmp_marshal_input_expire_password,
},
SQMP
@@ -2011,6 +2014,12 @@
},
{
+ .name = "query-block-jobs",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_block_jobs,
+ },
+
+ {
.name = "qom-list",
.args_type = "path:s",
.mhandler.cmd_new = qmp_marshal_input_qom_list,
@@ -2027,3 +2036,14 @@
.args_type = "path:s,property:s",
.mhandler.cmd_new = qmp_qom_get,
},
+
+ {
+ .name = "change-vnc-password",
+ .args_type = "password:s",
+ .mhandler.cmd_new = qmp_marshal_input_change_vnc_password,
+ },
+ {
+ .name = "qom-list-types",
+ .args_type = "implements:s?,abstract:b?",
+ .mhandler.cmd_new = qmp_marshal_input_qom_list_types,
+ },
diff --git a/qmp.c b/qmp.c
index c74dde6..45052cc 100644
--- a/qmp.c
+++ b/qmp.c
@@ -16,11 +16,14 @@
#include "qemu-common.h"
#include "sysemu.h"
#include "qmp-commands.h"
+#include "ui/qemu-spice.h"
+#include "ui/vnc.h"
#include "kvm.h"
#include "arch_init.h"
#include "hw/qdev.h"
#include "qapi/qmp-input-visitor.h"
#include "qapi/qmp-output-visitor.h"
+#include "blockdev.h"
NameInfo *qmp_query_name(Error **errp)
{
@@ -133,7 +136,8 @@
Error **err = opaque;
if (!error_is_set(err) && bdrv_key_required(bs)) {
- error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+ error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+ bdrv_get_encrypted_filename(bs));
}
}
@@ -160,23 +164,23 @@
vm_start();
}
-DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp)
+ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
{
- DeviceState *dev;
+ Object *obj;
bool ambiguous = false;
- DevicePropertyInfoList *props = NULL;
- DeviceProperty *prop;
+ ObjectPropertyInfoList *props = NULL;
+ ObjectProperty *prop;
- dev = qdev_resolve_path(path, &ambiguous);
- if (dev == NULL) {
+ obj = object_resolve_path(path, &ambiguous);
+ if (obj == NULL) {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
return NULL;
}
- QTAILQ_FOREACH(prop, &dev->properties, node) {
- DevicePropertyInfoList *entry = g_malloc0(sizeof(*entry));
+ QTAILQ_FOREACH(prop, &obj->properties, node) {
+ ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
- entry->value = g_malloc0(sizeof(DevicePropertyInfo));
+ entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
entry->next = props;
props = entry;
@@ -195,16 +199,16 @@
QObject *value = qdict_get(qdict, "value");
Error *local_err = NULL;
QmpInputVisitor *mi;
- DeviceState *dev;
+ Object *obj;
- dev = qdev_resolve_path(path, NULL);
- if (!dev) {
+ obj = object_resolve_path(path, NULL);
+ if (!obj) {
error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
goto out;
}
mi = qmp_input_visitor_new(value);
- qdev_property_set(dev, qmp_input_get_visitor(mi), property, &local_err);
+ object_property_set(obj, qmp_input_get_visitor(mi), property, &local_err);
qmp_input_visitor_cleanup(mi);
@@ -224,16 +228,16 @@
const char *property = qdict_get_str(qdict, "property");
Error *local_err = NULL;
QmpOutputVisitor *mo;
- DeviceState *dev;
+ Object *obj;
- dev = qdev_resolve_path(path, NULL);
- if (!dev) {
+ obj = object_resolve_path(path, NULL);
+ if (!obj) {
error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
goto out;
}
mo = qmp_output_visitor_new();
- qdev_property_get(dev, qmp_output_get_visitor(mo), property, &local_err);
+ object_property_get(obj, qmp_output_get_visitor(mo), property, &local_err);
if (!local_err) {
*ret = qmp_output_get_qobject(mo);
}
@@ -249,3 +253,172 @@
return 0;
}
+
+void qmp_set_password(const char *protocol, const char *password,
+ bool has_connected, const char *connected, Error **errp)
+{
+ int disconnect_if_connected = 0;
+ int fail_if_connected = 0;
+ int rc;
+
+ if (has_connected) {
+ if (strcmp(connected, "fail") == 0) {
+ fail_if_connected = 1;
+ } else if (strcmp(connected, "disconnect") == 0) {
+ disconnect_if_connected = 1;
+ } else if (strcmp(connected, "keep") == 0) {
+ /* nothing */
+ } else {
+ error_set(errp, QERR_INVALID_PARAMETER, "connected");
+ return;
+ }
+ }
+
+ if (strcmp(protocol, "spice") == 0) {
+ if (!using_spice) {
+ /* correct one? spice isn't a device ,,, */
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
+ return;
+ }
+ rc = qemu_spice_set_passwd(password, fail_if_connected,
+ disconnect_if_connected);
+ if (rc != 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+ return;
+ }
+
+ if (strcmp(protocol, "vnc") == 0) {
+ if (fail_if_connected || disconnect_if_connected) {
+ /* vnc supports "connected=keep" only */
+ error_set(errp, QERR_INVALID_PARAMETER, "connected");
+ return;
+ }
+ /* Note that setting an empty password will not disable login through
+ * this interface. */
+ rc = vnc_display_password(NULL, password);
+ if (rc < 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+ return;
+ }
+
+ error_set(errp, QERR_INVALID_PARAMETER, "protocol");
+}
+
+void qmp_expire_password(const char *protocol, const char *whenstr,
+ Error **errp)
+{
+ time_t when;
+ int rc;
+
+ if (strcmp(whenstr, "now") == 0) {
+ when = 0;
+ } else if (strcmp(whenstr, "never") == 0) {
+ when = TIME_MAX;
+ } else if (whenstr[0] == '+') {
+ when = time(NULL) + strtoull(whenstr+1, NULL, 10);
+ } else {
+ when = strtoull(whenstr, NULL, 10);
+ }
+
+ if (strcmp(protocol, "spice") == 0) {
+ if (!using_spice) {
+ /* correct one? spice isn't a device ,,, */
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
+ return;
+ }
+ rc = qemu_spice_set_pw_expire(when);
+ if (rc != 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+ return;
+ }
+
+ if (strcmp(protocol, "vnc") == 0) {
+ rc = vnc_display_pw_expire(NULL, when);
+ if (rc != 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+ return;
+ }
+
+ error_set(errp, QERR_INVALID_PARAMETER, "protocol");
+}
+
+#ifdef CONFIG_VNC
+void qmp_change_vnc_password(const char *password, Error **errp)
+{
+ if (vnc_display_password(NULL, password) < 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+}
+
+static void qmp_change_vnc_listen(const char *target, Error **err)
+{
+ if (vnc_display_open(NULL, target) < 0) {
+ error_set(err, QERR_VNC_SERVER_FAILED, target);
+ }
+}
+
+static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
+ Error **errp)
+{
+ if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
+ if (!has_arg) {
+ error_set(errp, QERR_MISSING_PARAMETER, "password");
+ } else {
+ qmp_change_vnc_password(arg, errp);
+ }
+ } else {
+ qmp_change_vnc_listen(target, errp);
+ }
+}
+#else
+void qmp_change_vnc_password(const char *password, Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+}
+static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
+ Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+}
+#endif /* !CONFIG_VNC */
+
+void qmp_change(const char *device, const char *target,
+ bool has_arg, const char *arg, Error **err)
+{
+ if (strcmp(device, "vnc") == 0) {
+ qmp_change_vnc(target, has_arg, arg, err);
+ } else {
+ qmp_change_blockdev(device, target, has_arg, arg, err);
+ }
+}
+
+static void qom_list_types_tramp(ObjectClass *klass, void *data)
+{
+ ObjectTypeInfoList *e, **pret = data;
+ ObjectTypeInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(object_class_get_name(klass));
+
+ e = g_malloc0(sizeof(*e));
+ e->value = info;
+ e->next = *pret;
+ *pret = e;
+}
+
+ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
+ const char *implements,
+ bool has_abstract,
+ bool abstract,
+ Error **errp)
+{
+ ObjectTypeInfoList *ret = NULL;
+
+ object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
+
+ return ret;
+}
diff --git a/qom/Makefile b/qom/Makefile
new file mode 100644
index 0000000..f33f0be
--- /dev/null
+++ b/qom/Makefile
@@ -0,0 +1 @@
+qom-y = object.o container.o
diff --git a/qom/container.c b/qom/container.c
new file mode 100644
index 0000000..946cbff
--- /dev/null
+++ b/qom/container.c
@@ -0,0 +1,27 @@
+/*
+ * Device Container
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * 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.
+ */
+
+#include "qemu/object.h"
+#include "module.h"
+
+static TypeInfo container_info = {
+ .name = "container",
+ .instance_size = sizeof(Object),
+ .parent = TYPE_OBJECT,
+};
+
+static void container_init(void)
+{
+ type_register_static(&container_info);
+}
+
+device_init(container_init);
diff --git a/qom/object.c b/qom/object.c
new file mode 100644
index 0000000..4261944
--- /dev/null
+++ b/qom/object.c
@@ -0,0 +1,984 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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.
+ */
+
+#include "qemu/object.h"
+#include "qemu-common.h"
+#include "qapi/qapi-visit-core.h"
+#include "hw/qdev.h"
+// FIXME remove above
+
+#define MAX_INTERFACES 32
+
+typedef struct InterfaceImpl InterfaceImpl;
+typedef struct TypeImpl TypeImpl;
+
+struct InterfaceImpl
+{
+ const char *parent;
+ void (*interface_initfn)(ObjectClass *class, void *data);
+ TypeImpl *type;
+};
+
+struct TypeImpl
+{
+ const char *name;
+
+ size_t class_size;
+
+ size_t instance_size;
+
+ void (*class_init)(ObjectClass *klass, void *data);
+ void (*class_finalize)(ObjectClass *klass, void *data);
+
+ void *class_data;
+
+ void (*instance_init)(Object *obj);
+ void (*instance_finalize)(Object *obj);
+
+ bool abstract;
+
+ const char *parent;
+ TypeImpl *parent_type;
+
+ ObjectClass *class;
+
+ int num_interfaces;
+ InterfaceImpl interfaces[MAX_INTERFACES];
+};
+
+typedef struct Interface
+{
+ Object parent;
+ Object *obj;
+} Interface;
+
+#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
+
+static GHashTable *type_table_get(void)
+{
+ static GHashTable *type_table;
+
+ if (type_table == NULL) {
+ type_table = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ return type_table;
+}
+
+static void type_table_add(TypeImpl *ti)
+{
+ g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
+}
+
+static TypeImpl *type_table_lookup(const char *name)
+{
+ return g_hash_table_lookup(type_table_get(), name);
+}
+
+TypeImpl *type_register(const TypeInfo *info)
+{
+ TypeImpl *ti = g_malloc0(sizeof(*ti));
+
+ g_assert(info->name != NULL);
+
+ if (type_table_lookup(info->name) != NULL) {
+ fprintf(stderr, "Registering `%s' which already exists\n", info->name);
+ abort();
+ }
+
+ ti->name = g_strdup(info->name);
+ ti->parent = g_strdup(info->parent);
+
+ ti->class_size = info->class_size;
+ ti->instance_size = info->instance_size;
+
+ ti->class_init = info->class_init;
+ ti->class_finalize = info->class_finalize;
+ ti->class_data = info->class_data;
+
+ ti->instance_init = info->instance_init;
+ ti->instance_finalize = info->instance_finalize;
+
+ ti->abstract = info->abstract;
+
+ if (info->interfaces) {
+ int i;
+
+ for (i = 0; info->interfaces[i].type; i++) {
+ ti->interfaces[i].parent = info->interfaces[i].type;
+ ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
+ ti->num_interfaces++;
+ }
+ }
+
+ type_table_add(ti);
+
+ return ti;
+}
+
+TypeImpl *type_register_static(const TypeInfo *info)
+{
+ return type_register(info);
+}
+
+static TypeImpl *type_get_by_name(const char *name)
+{
+ if (name == NULL) {
+ return NULL;
+ }
+
+ return type_table_lookup(name);
+}
+
+static TypeImpl *type_get_parent(TypeImpl *type)
+{
+ if (!type->parent_type && type->parent) {
+ type->parent_type = type_get_by_name(type->parent);
+ g_assert(type->parent_type != NULL);
+ }
+
+ return type->parent_type;
+}
+
+static bool type_has_parent(TypeImpl *type)
+{
+ return (type->parent != NULL);
+}
+
+static size_t type_class_get_size(TypeImpl *ti)
+{
+ if (ti->class_size) {
+ return ti->class_size;
+ }
+
+ if (type_has_parent(ti)) {
+ return type_class_get_size(type_get_parent(ti));
+ }
+
+ return sizeof(ObjectClass);
+}
+
+static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
+{
+ TypeInfo info = {
+ .instance_size = sizeof(Interface),
+ .parent = iface->parent,
+ .class_size = sizeof(InterfaceClass),
+ .class_init = iface->interface_initfn,
+ .abstract = true,
+ };
+ char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
+
+ info.name = name;
+ iface->type = type_register(&info);
+ g_free(name);
+}
+
+static void type_class_init(TypeImpl *ti)
+{
+ size_t class_size = sizeof(ObjectClass);
+ int i;
+
+ if (ti->class) {
+ return;
+ }
+
+ ti->class_size = type_class_get_size(ti);
+
+ ti->class = g_malloc0(ti->class_size);
+ ti->class->type = ti;
+
+ if (type_has_parent(ti)) {
+ TypeImpl *parent = type_get_parent(ti);
+
+ type_class_init(parent);
+
+ class_size = parent->class_size;
+ g_assert(parent->class_size <= ti->class_size);
+
+ memcpy((void *)ti->class + sizeof(ObjectClass),
+ (void *)parent->class + sizeof(ObjectClass),
+ parent->class_size - sizeof(ObjectClass));
+ }
+
+ memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
+
+ for (i = 0; i < ti->num_interfaces; i++) {
+ type_class_interface_init(ti, &ti->interfaces[i]);
+ }
+
+ if (ti->class_init) {
+ ti->class_init(ti->class, ti->class_data);
+ }
+}
+
+static void object_interface_init(Object *obj, InterfaceImpl *iface)
+{
+ TypeImpl *ti = iface->type;
+ Interface *iface_obj;
+
+ iface_obj = INTERFACE(object_new(ti->name));
+ iface_obj->obj = obj;
+
+ obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
+}
+
+static void object_init_with_type(Object *obj, TypeImpl *ti)
+{
+ int i;
+
+ if (type_has_parent(ti)) {
+ object_init_with_type(obj, type_get_parent(ti));
+ }
+
+ for (i = 0; i < ti->num_interfaces; i++) {
+ object_interface_init(obj, &ti->interfaces[i]);
+ }
+
+ if (ti->instance_init) {
+ ti->instance_init(obj);
+ }
+}
+
+void object_initialize_with_type(void *data, TypeImpl *type)
+{
+ Object *obj = data;
+
+ g_assert(type != NULL);
+ g_assert(type->instance_size >= sizeof(ObjectClass));
+
+ type_class_init(type);
+ g_assert(type->abstract == false);
+
+ memset(obj, 0, type->instance_size);
+ obj->class = type->class;
+ QTAILQ_INIT(&obj->properties);
+ object_init_with_type(obj, type);
+}
+
+void object_initialize(void *data, const char *typename)
+{
+ TypeImpl *type = type_get_by_name(typename);
+
+ object_initialize_with_type(data, type);
+}
+
+static void object_property_del_all(Object *obj)
+{
+ while (!QTAILQ_EMPTY(&obj->properties)) {
+ ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
+
+ QTAILQ_REMOVE(&obj->properties, prop, node);
+
+ if (prop->release) {
+ prop->release(obj, prop->name, prop->opaque);
+ }
+
+ g_free(prop->name);
+ g_free(prop->type);
+ g_free(prop);
+ }
+}
+
+static void object_property_del_child(Object *obj, Object *child, Error **errp)
+{
+ ObjectProperty *prop;
+
+ QTAILQ_FOREACH(prop, &obj->properties, node) {
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ if (prop->opaque == child) {
+ object_property_del(obj, prop->name, errp);
+ }
+ }
+}
+
+void object_unparent(Object *obj)
+{
+ if (obj->parent) {
+ object_property_del_child(obj->parent, obj, NULL);
+ }
+}
+
+static void object_deinit(Object *obj, TypeImpl *type)
+{
+ if (type->instance_finalize) {
+ type->instance_finalize(obj);
+ }
+
+ while (obj->interfaces) {
+ Interface *iface_obj = obj->interfaces->data;
+ obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
+ object_delete(OBJECT(iface_obj));
+ }
+
+ if (type_has_parent(type)) {
+ object_deinit(obj, type_get_parent(type));
+ }
+
+ object_unparent(obj);
+}
+
+void object_finalize(void *data)
+{
+ Object *obj = data;
+ TypeImpl *ti = obj->class->type;
+
+ object_deinit(obj, ti);
+ object_property_del_all(obj);
+
+ g_assert(obj->ref == 0);
+}
+
+Object *object_new_with_type(Type type)
+{
+ Object *obj;
+
+ g_assert(type != NULL);
+
+ obj = g_malloc(type->instance_size);
+ object_initialize_with_type(obj, type);
+ object_ref(obj);
+
+ return obj;
+}
+
+Object *object_new(const char *typename)
+{
+ TypeImpl *ti = type_get_by_name(typename);
+
+ return object_new_with_type(ti);
+}
+
+void object_delete(Object *obj)
+{
+ object_unref(obj);
+ g_assert(obj->ref == 0);
+ g_free(obj);
+}
+
+static bool object_is_type(Object *obj, const char *typename)
+{
+ TypeImpl *target_type = type_get_by_name(typename);
+ TypeImpl *type = obj->class->type;
+ GSList *i;
+
+ /* Check if typename is a direct ancestor of type */
+ while (type) {
+ if (type == target_type) {
+ return true;
+ }
+
+ type = type_get_parent(type);
+ }
+
+ /* Check if obj has an interface of typename */
+ for (i = obj->interfaces; i; i = i->next) {
+ Interface *iface = i->data;
+
+ if (object_is_type(OBJECT(iface), typename)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Object *object_dynamic_cast(Object *obj, const char *typename)
+{
+ GSList *i;
+
+ /* Check if typename is a direct ancestor */
+ if (object_is_type(obj, typename)) {
+ return obj;
+ }
+
+ /* Check if obj has an interface of typename */
+ for (i = obj->interfaces; i; i = i->next) {
+ Interface *iface = i->data;
+
+ if (object_is_type(OBJECT(iface), typename)) {
+ return OBJECT(iface);
+ }
+ }
+
+ /* Check if obj is an interface and its containing object is a direct
+ * ancestor of typename */
+ if (object_is_type(obj, TYPE_INTERFACE)) {
+ Interface *iface = INTERFACE(obj);
+
+ if (object_is_type(iface->obj, typename)) {
+ return iface->obj;
+ }
+ }
+
+ return NULL;
+}
+
+
+static void register_interface(void)
+{
+ static TypeInfo interface_info = {
+ .name = TYPE_INTERFACE,
+ .instance_size = sizeof(Interface),
+ .abstract = true,
+ };
+
+ type_register_static(&interface_info);
+}
+
+device_init(register_interface);
+
+Object *object_dynamic_cast_assert(Object *obj, const char *typename)
+{
+ Object *inst;
+
+ inst = object_dynamic_cast(obj, typename);
+
+ if (!inst) {
+ fprintf(stderr, "Object %p is not an instance of type %s\n",
+ obj, typename);
+ abort();
+ }
+
+ return inst;
+}
+
+ObjectClass *object_class_dynamic_cast(ObjectClass *class,
+ const char *typename)
+{
+ TypeImpl *target_type = type_get_by_name(typename);
+ TypeImpl *type = class->type;
+
+ while (type) {
+ if (type == target_type) {
+ return class;
+ }
+
+ type = type_get_parent(type);
+ }
+
+ return NULL;
+}
+
+ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
+ const char *typename)
+{
+ ObjectClass *ret = object_class_dynamic_cast(class, typename);
+
+ if (!ret) {
+ fprintf(stderr, "Object %p is not an instance of type %s\n",
+ class, typename);
+ abort();
+ }
+
+ return ret;
+}
+
+const char *object_get_typename(Object *obj)
+{
+ return obj->class->type->name;
+}
+
+ObjectClass *object_get_class(Object *obj)
+{
+ return obj->class;
+}
+
+const char *object_class_get_name(ObjectClass *klass)
+{
+ return klass->type->name;
+}
+
+ObjectClass *object_class_by_name(const char *typename)
+{
+ TypeImpl *type = type_get_by_name(typename);
+
+ if (!type) {
+ return NULL;
+ }
+
+ type_class_init(type);
+
+ return type->class;
+}
+
+typedef struct OCFData
+{
+ void (*fn)(ObjectClass *klass, void *opaque);
+ const char *implements_type;
+ bool include_abstract;
+ void *opaque;
+} OCFData;
+
+static void object_class_foreach_tramp(gpointer key, gpointer value,
+ gpointer opaque)
+{
+ OCFData *data = opaque;
+ TypeImpl *type = value;
+ ObjectClass *k;
+
+ type_class_init(type);
+ k = type->class;
+
+ if (!data->include_abstract && type->abstract) {
+ return;
+ }
+
+ if (data->implements_type &&
+ !object_class_dynamic_cast(k, data->implements_type)) {
+ return;
+ }
+
+ data->fn(k, data->opaque);
+}
+
+void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+ const char *implements_type, bool include_abstract,
+ void *opaque)
+{
+ OCFData data = { fn, implements_type, include_abstract, opaque };
+
+ g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
+}
+
+void object_ref(Object *obj)
+{
+ obj->ref++;
+}
+
+void object_unref(Object *obj)
+{
+ g_assert(obj->ref > 0);
+ obj->ref--;
+
+ /* parent always holds a reference to its children */
+ if (obj->ref == 0) {
+ object_finalize(obj);
+ }
+}
+
+void object_property_add(Object *obj, const char *name, const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, Error **errp)
+{
+ ObjectProperty *prop = g_malloc0(sizeof(*prop));
+
+ prop->name = g_strdup(name);
+ prop->type = g_strdup(type);
+
+ prop->get = get;
+ prop->set = set;
+ prop->release = release;
+ prop->opaque = opaque;
+
+ QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
+}
+
+static ObjectProperty *object_property_find(Object *obj, const char *name)
+{
+ ObjectProperty *prop;
+
+ QTAILQ_FOREACH(prop, &obj->properties, node) {
+ if (strcmp(prop->name, name) == 0) {
+ return prop;
+ }
+ }
+
+ return NULL;
+}
+
+void object_property_del(Object *obj, const char *name, Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ QTAILQ_REMOVE(&obj->properties, prop, node);
+
+ prop->release(obj, prop->name, prop->opaque);
+
+ g_free(prop->name);
+ g_free(prop->type);
+ g_free(prop);
+}
+
+void object_property_get(Object *obj, Visitor *v, const char *name,
+ Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return;
+ }
+
+ if (!prop->get) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ } else {
+ prop->get(obj, v, prop->opaque, name, errp);
+ }
+}
+
+void object_property_set(Object *obj, Visitor *v, const char *name,
+ Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return;
+ }
+
+ if (!prop->set) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ } else {
+ prop->set(obj, v, prop->opaque, name, errp);
+ }
+}
+
+const char *object_property_get_type(Object *obj, const char *name, Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return NULL;
+ }
+
+ return prop->type;
+}
+
+Object *object_get_root(void)
+{
+ static Object *root;
+
+ if (!root) {
+ root = object_new("container");
+ }
+
+ return root;
+}
+
+static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object *child = opaque;
+ gchar *path;
+
+ path = object_get_canonical_path(child);
+ visit_type_str(v, &path, name, errp);
+ g_free(path);
+}
+
+static void object_finalize_child_property(Object *obj, const char *name,
+ void *opaque)
+{
+ Object *child = opaque;
+
+ object_unref(child);
+}
+
+void object_property_add_child(Object *obj, const char *name,
+ Object *child, Error **errp)
+{
+ gchar *type;
+
+ type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
+
+ object_property_add(obj, name, type, object_get_child_property,
+ NULL, object_finalize_child_property, child, errp);
+
+ object_ref(child);
+ g_assert(child->parent == NULL);
+ child->parent = obj;
+
+ g_free(type);
+}
+
+static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object **child = opaque;
+ gchar *path;
+
+ if (*child) {
+ path = object_get_canonical_path(*child);
+ visit_type_str(v, &path, name, errp);
+ g_free(path);
+ } else {
+ path = (gchar *)"";
+ visit_type_str(v, &path, name, errp);
+ }
+}
+
+static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object **child = opaque;
+ bool ambiguous = false;
+ const char *type;
+ char *path;
+
+ type = object_property_get_type(obj, name, NULL);
+
+ visit_type_str(v, &path, name, errp);
+
+ if (*child) {
+ object_unref(*child);
+ }
+
+ if (strcmp(path, "") != 0) {
+ Object *target;
+
+ target = object_resolve_path(path, &ambiguous);
+ if (target) {
+ gchar *target_type;
+
+ target_type = g_strdup(&type[5]);
+ target_type[strlen(target_type) - 2] = 0;
+
+ if (object_dynamic_cast(target, target_type)) {
+ object_ref(target);
+ *child = target;
+ } else {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
+ }
+
+ g_free(target_type);
+ } else {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+ }
+ } else {
+ *child = NULL;
+ }
+
+ g_free(path);
+}
+
+void object_property_add_link(Object *obj, const char *name,
+ const char *type, Object **child,
+ Error **errp)
+{
+ gchar *full_type;
+
+ full_type = g_strdup_printf("link<%s>", type);
+
+ object_property_add(obj, name, full_type,
+ object_get_link_property,
+ object_set_link_property,
+ NULL, child, errp);
+
+ g_free(full_type);
+}
+
+gchar *object_get_canonical_path(Object *obj)
+{
+ Object *root = object_get_root();
+ char *newpath = NULL, *path = NULL;
+
+ while (obj != root) {
+ ObjectProperty *prop = NULL;
+
+ g_assert(obj->parent != NULL);
+
+ QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ if (prop->opaque == obj) {
+ if (path) {
+ newpath = g_strdup_printf("%s/%s", prop->name, path);
+ g_free(path);
+ path = newpath;
+ } else {
+ path = g_strdup(prop->name);
+ }
+ break;
+ }
+ }
+
+ g_assert(prop != NULL);
+
+ obj = obj->parent;
+ }
+
+ newpath = g_strdup_printf("/%s", path);
+ g_free(path);
+
+ return newpath;
+}
+
+static Object *object_resolve_abs_path(Object *parent,
+ gchar **parts,
+ int index)
+{
+ ObjectProperty *prop;
+ Object *child;
+
+ if (parts[index] == NULL) {
+ return parent;
+ }
+
+ if (strcmp(parts[index], "") == 0) {
+ return object_resolve_abs_path(parent, parts, index + 1);
+ }
+
+ prop = object_property_find(parent, parts[index]);
+ if (prop == NULL) {
+ return NULL;
+ }
+
+ child = NULL;
+ if (strstart(prop->type, "link<", NULL)) {
+ Object **pchild = prop->opaque;
+ if (*pchild) {
+ child = *pchild;
+ }
+ } else if (strstart(prop->type, "child<", NULL)) {
+ child = prop->opaque;
+ }
+
+ if (!child) {
+ return NULL;
+ }
+
+ return object_resolve_abs_path(child, parts, index + 1);
+}
+
+static Object *object_resolve_partial_path(Object *parent,
+ gchar **parts,
+ bool *ambiguous)
+{
+ Object *obj;
+ ObjectProperty *prop;
+
+ obj = object_resolve_abs_path(parent, parts, 0);
+
+ QTAILQ_FOREACH(prop, &parent->properties, node) {
+ Object *found;
+
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
+ if (found) {
+ if (obj) {
+ if (ambiguous) {
+ *ambiguous = true;
+ }
+ return NULL;
+ }
+ obj = found;
+ }
+
+ if (ambiguous && *ambiguous) {
+ return NULL;
+ }
+ }
+
+ return obj;
+}
+
+Object *object_resolve_path(const char *path, bool *ambiguous)
+{
+ bool partial_path = true;
+ Object *obj;
+ gchar **parts;
+
+ parts = g_strsplit(path, "/", 0);
+ if (parts == NULL || parts[0] == NULL) {
+ g_strfreev(parts);
+ return object_get_root();
+ }
+
+ if (strcmp(parts[0], "") == 0) {
+ partial_path = false;
+ }
+
+ if (partial_path) {
+ if (ambiguous) {
+ *ambiguous = false;
+ }
+ obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
+ } else {
+ obj = object_resolve_abs_path(object_get_root(), parts, 1);
+ }
+
+ g_strfreev(parts);
+
+ return obj;
+}
+
+typedef struct StringProperty
+{
+ char *(*get)(Object *, Error **);
+ void (*set)(Object *, const char *, Error **);
+} StringProperty;
+
+static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ StringProperty *prop = opaque;
+ char *value;
+
+ value = prop->get(obj, errp);
+ if (value) {
+ visit_type_str(v, &value, name, errp);
+ g_free(value);
+ }
+}
+
+static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ StringProperty *prop = opaque;
+ char *value;
+ Error *local_err = NULL;
+
+ visit_type_str(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ prop->set(obj, value, errp);
+ g_free(value);
+}
+
+static void object_property_release_str(Object *obj, const char *name,
+ void *opaque)
+{
+ StringProperty *prop = opaque;
+ g_free(prop);
+}
+
+void object_property_add_str(Object *obj, const char *name,
+ char *(*get)(Object *, Error **),
+ void (*set)(Object *, const char *, Error **),
+ Error **errp)
+{
+ StringProperty *prop = g_malloc0(sizeof(*prop));
+
+ prop->get = get;
+ prop->set = set;
+
+ object_property_add(obj, name, "string",
+ get ? object_property_get_str : NULL,
+ set ? object_property_set_str : NULL,
+ object_property_release_str,
+ prop, errp);
+}
diff --git a/roms/SLOF b/roms/SLOF
index 32e3430..ab062ff 160000
--- a/roms/SLOF
+++ b/roms/SLOF
@@ -1 +1 @@
-Subproject commit 32e3430c018ceb8413cb808477449d1968c42497
+Subproject commit ab062ff3b37c39649f2b0d94ed607adc6f6b3c7d
diff --git a/scripts/check-qerror.sh b/scripts/check-qerror.sh
new file mode 100755
index 0000000..af7fbd5
--- /dev/null
+++ b/scripts/check-qerror.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# This script verifies that qerror definitions and table entries are
+# alphabetically ordered.
+
+check_order() {
+ errmsg=$1
+ shift
+
+ # sort -C verifies order but does not print a message. sort -c does print a
+ # message. These options are both in POSIX.
+ if ! "$@" | sort -C; then
+ echo "$errmsg"
+ "$@" | sort -c
+ exit 1
+ fi
+ return 0
+}
+
+check_order 'Definitions in qerror.h must be in alphabetical order:' \
+ grep '^#define QERR_' qerror.h
+check_order 'Entries in qerror.c:qerror_table must be in alphabetical order:' \
+ sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c
diff --git a/sysemu.h b/sysemu.h
index ddef2bb..9d5ce33 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -102,11 +102,9 @@
extern int graphic_width;
extern int graphic_height;
extern int graphic_depth;
-extern uint8_t irq0override;
extern DisplayType display_type;
extern const char *keyboard_layout;
extern int win2k_install_hack;
-extern int rtc_td_hack;
extern int alt_grab;
extern int ctrl_grab;
extern int usb_enabled;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 42c53a7..0d9b39c 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -382,6 +382,7 @@
ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */
ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */
+ ARM_FEATURE_GENERIC_TIMER,
};
static inline int arm_feature(CPUARMState *env, int feature)
@@ -432,6 +433,7 @@
#define ARM_CPUID_ARM11MPCORE 0x410fb022
#define ARM_CPUID_CORTEXA8 0x410fc080
#define ARM_CPUID_CORTEXA9 0x410fc090
+#define ARM_CPUID_CORTEXA15 0x412fc0f1
#define ARM_CPUID_CORTEXM3 0x410fc231
#define ARM_CPUID_ANY 0xffffffff
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 00458fc..ea4f35f 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -10,6 +10,16 @@
#if !defined(CONFIG_USER_ONLY)
#include "hw/loader.h"
#endif
+#include "sysemu.h"
+
+static uint32_t cortexa15_cp15_c0_c1[8] = {
+ 0x00001131, 0x00011011, 0x02010555, 0x00000000,
+ 0x10201105, 0x20000000, 0x01240000, 0x02102211
+};
+
+static uint32_t cortexa15_cp15_c0_c2[8] = {
+ 0x02101110, 0x13112111, 0x21232041, 0x11112131, 0x10011142, 0, 0, 0
+};
static uint32_t cortexa9_cp15_c0_c1[8] =
{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
@@ -158,6 +168,27 @@
env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
env->cp15.c1_sys = 0x00c50078;
break;
+ case ARM_CPUID_CORTEXA15:
+ set_feature(env, ARM_FEATURE_V7);
+ set_feature(env, ARM_FEATURE_VFP4);
+ set_feature(env, ARM_FEATURE_VFP_FP16);
+ set_feature(env, ARM_FEATURE_NEON);
+ set_feature(env, ARM_FEATURE_THUMB2EE);
+ set_feature(env, ARM_FEATURE_ARM_DIV);
+ set_feature(env, ARM_FEATURE_V7MP);
+ set_feature(env, ARM_FEATURE_GENERIC_TIMER);
+ env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
+ env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
+ env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
+ memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
+ memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
+ env->cp15.c0_cachetype = 0x8444c004;
+ env->cp15.c0_clid = 0x0a200023;
+ env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
+ env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
+ env->cp15.c0_ccsid[2] = 0x711fe07a; /* 4096K L2 unified cache */
+ env->cp15.c1_sys = 0x00c50078;
+ break;
case ARM_CPUID_CORTEXM3:
set_feature(env, ARM_FEATURE_V7);
set_feature(env, ARM_FEATURE_M);
@@ -255,6 +286,7 @@
void cpu_reset(CPUARMState *env)
{
uint32_t id;
+ uint32_t tmp = 0;
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
@@ -262,9 +294,11 @@
}
id = env->cp15.c0_cpuid;
+ tmp = env->cp15.c15_config_base_address;
memset(env, 0, offsetof(CPUARMState, breakpoints));
if (id)
cpu_reset_model_id(env, id);
+ env->cp15.c15_config_base_address = tmp;
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
/* For user mode we must enable access to coprocessors */
@@ -413,6 +447,7 @@
{ ARM_CPUID_CORTEXM3, "cortex-m3"},
{ ARM_CPUID_CORTEXA8, "cortex-a8"},
{ ARM_CPUID_CORTEXA9, "cortex-a9"},
+ { ARM_CPUID_CORTEXA15, "cortex-a15" },
{ ARM_CPUID_TI925T, "ti925t" },
{ ARM_CPUID_PXA250, "pxa250" },
{ ARM_CPUID_SA1100, "sa1100" },
@@ -667,8 +702,6 @@
#else
-extern int semihosting_enabled;
-
/* Map CPU modes onto saved register banks. */
static inline int bank_number(CPUState *env, int mode)
{
@@ -1610,18 +1643,17 @@
break;
case 8: /* MMU TLB control. */
switch (op2) {
- case 0: /* Invalidate all. */
- tlb_flush(env, 0);
+ case 0: /* Invalidate all (TLBIALL) */
+ tlb_flush(env, 1);
break;
- case 1: /* Invalidate single TLB entry. */
+ case 1: /* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
tlb_flush_page(env, val & TARGET_PAGE_MASK);
break;
- case 2: /* Invalidate on ASID. */
+ case 2: /* Invalidate by ASID (TLBIASID) */
tlb_flush(env, val == 0);
break;
- case 3: /* Invalidate single entry on MVA. */
- /* ??? This is like case 1, but ignores ASID. */
- tlb_flush(env, 1);
+ case 3: /* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
+ tlb_flush_page(env, val & TARGET_PAGE_MASK);
break;
default:
goto bad_reg;
@@ -1762,7 +1794,11 @@
goto bad_reg;
}
break;
- case 14: /* Reserved. */
+ case 14: /* Generic timer */
+ if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
+ /* Dummy implementation: RAZ/WI for all */
+ break;
+ }
goto bad_reg;
case 15: /* Implementation specific. */
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
@@ -1939,6 +1975,7 @@
case ARM_CPUID_CORTEXA8:
return 2;
case ARM_CPUID_CORTEXA9:
+ case ARM_CPUID_CORTEXA15:
return 0;
default:
goto bad_reg;
@@ -2059,11 +2096,26 @@
goto bad_reg;
}
case 1: /* L2 cache */
- if (crm != 0) {
+ /* L2 Lockdown and Auxiliary control. */
+ switch (op2) {
+ case 0:
+ /* L2 cache lockdown (A8 only) */
+ return 0;
+ case 2:
+ /* L2 cache auxiliary control (A8) or control (A15) */
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA15) {
+ /* Linux wants the number of processors from here.
+ * Might as well set the interrupt-controller bit too.
+ */
+ return ((smp_cpus - 1) << 24) | (1 << 23);
+ }
+ return 0;
+ case 3:
+ /* L2 cache extended control (A15) */
+ return 0;
+ default:
goto bad_reg;
}
- /* L2 Lockdown and Auxiliary control. */
- return 0;
default:
goto bad_reg;
}
@@ -2132,7 +2184,11 @@
default:
goto bad_reg;
}
- case 14: /* Reserved. */
+ case 14: /* Generic timer */
+ if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
+ /* Dummy implementation: RAZ/WI for all */
+ return 0;
+ }
goto bad_reg;
case 15: /* Implementation specific. */
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
@@ -2786,7 +2842,7 @@
float##fsz HELPER(name)(uint32_t x, void *fpstp) \
{ \
float_status *fpst = fpstp; \
- return sign##int32_to_##float##fsz(x, fpst); \
+ return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \
}
#define CONV_FTOI(name, fsz, sign, round) \
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 91a104b..b9bfeaf 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -27,6 +27,8 @@
#include "qemu-option.h"
#include "qemu-config.h"
+#include "hyperv.h"
+
/* feature flags taken from "Intel Processor Identification and the CPUID
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
* between feature naming conventions, aliases may be added.
@@ -716,6 +718,14 @@
goto error;
}
x86_cpu_def->tsc_khz = tsc_freq / 1000;
+ } else if (!strcmp(featurestr, "hv_spinlocks")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ hyperv_set_spinlock_retries(numvalue);
} else {
fprintf(stderr, "unrecognized feature %s\n", featurestr);
goto error;
@@ -724,6 +734,10 @@
check_cpuid = 1;
} else if (!strcmp(featurestr, "enforce")) {
check_cpuid = enforce_cpuid = 1;
+ } else if (!strcmp(featurestr, "hv_relaxed")) {
+ hyperv_enable_relaxed_timing(true);
+ } else if (!strcmp(featurestr, "hv_vapic")) {
+ hyperv_enable_vapic_recommended(true);
} else {
fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
goto error;
diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c
new file mode 100644
index 0000000..f284e99
--- /dev/null
+++ b/target-i386/hyperv.c
@@ -0,0 +1,64 @@
+/*
+ * QEMU Hyper-V support
+ *
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Author: Vadim Rozenfeld <vrozenfe@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hyperv.h"
+
+static bool hyperv_vapic;
+static bool hyperv_relaxed_timing;
+static int hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
+
+void hyperv_enable_vapic_recommended(bool val)
+{
+ hyperv_vapic = val;
+}
+
+void hyperv_enable_relaxed_timing(bool val)
+{
+ hyperv_relaxed_timing = val;
+}
+
+void hyperv_set_spinlock_retries(int val)
+{
+ hyperv_spinlock_attempts = val;
+ if (hyperv_spinlock_attempts < 0xFFF) {
+ hyperv_spinlock_attempts = 0xFFF;
+ }
+}
+
+bool hyperv_enabled(void)
+{
+ return hyperv_hypercall_available() || hyperv_relaxed_timing_enabled();
+}
+
+bool hyperv_hypercall_available(void)
+{
+ if (hyperv_vapic ||
+ (hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY)) {
+ return true;
+ }
+ return false;
+}
+
+bool hyperv_vapic_recommended(void)
+{
+ return hyperv_vapic;
+}
+
+bool hyperv_relaxed_timing_enabled(void)
+{
+ return hyperv_relaxed_timing;
+}
+
+int hyperv_get_spinlock_retries(void)
+{
+ return hyperv_spinlock_attempts;
+}
diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h
new file mode 100644
index 0000000..bacb1d4
--- /dev/null
+++ b/target-i386/hyperv.h
@@ -0,0 +1,45 @@
+/*
+ * QEMU Hyper-V support
+ *
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Author: Vadim Rozenfeld <vrozenfe@redhat.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 QEMU_HW_HYPERV_H
+#define QEMU_HW_HYPERV_H 1
+
+#include "qemu-common.h"
+#ifdef CONFIG_KVM
+#include <asm/hyperv.h>
+#endif
+
+#ifndef HYPERV_SPINLOCK_NEVER_RETRY
+#define HYPERV_SPINLOCK_NEVER_RETRY 0xFFFFFFFF
+#endif
+
+#ifndef KVM_CPUID_SIGNATURE_NEXT
+#define KVM_CPUID_SIGNATURE_NEXT 0x40000100
+#endif
+
+#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_KVM)
+void hyperv_enable_vapic_recommended(bool val);
+void hyperv_enable_relaxed_timing(bool val);
+void hyperv_set_spinlock_retries(int val);
+#else
+static inline void hyperv_enable_vapic_recommended(bool val) { }
+static inline void hyperv_enable_relaxed_timing(bool val) { }
+static inline void hyperv_set_spinlock_retries(int val) { }
+#endif
+
+bool hyperv_enabled(void);
+bool hyperv_hypercall_available(void);
+bool hyperv_vapic_recommended(void);
+bool hyperv_relaxed_timing_enabled(void);
+int hyperv_get_spinlock_retries(void);
+
+#endif /* QEMU_HW_HYPERV_H */
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 04e65c5..e41de39 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -29,6 +29,7 @@
#include "hw/pc.h"
#include "hw/apic.h"
#include "ioport.h"
+#include "hyperv.h"
//#define DEBUG_KVM
@@ -373,11 +374,16 @@
cpuid_i = 0;
/* Paravirtualization CPUIDs */
- memcpy(signature, "KVMKVMKVM\0\0\0", 12);
c = &cpuid_data.entries[cpuid_i++];
memset(c, 0, sizeof(*c));
c->function = KVM_CPUID_SIGNATURE;
- c->eax = 0;
+ if (!hyperv_enabled()) {
+ memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+ c->eax = 0;
+ } else {
+ memcpy(signature, "Microsoft Hv", 12);
+ c->eax = HYPERV_CPUID_MIN;
+ }
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];
@@ -388,6 +394,54 @@
c->eax = env->cpuid_kvm_features &
kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
+ if (hyperv_enabled()) {
+ memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
+ c->eax = signature[0];
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = HYPERV_CPUID_VERSION;
+ c->eax = 0x00001bbc;
+ c->ebx = 0x00060001;
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = HYPERV_CPUID_FEATURES;
+ if (hyperv_relaxed_timing_enabled()) {
+ c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+ }
+ if (hyperv_vapic_recommended()) {
+ c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+ c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
+ }
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
+ if (hyperv_relaxed_timing_enabled()) {
+ c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED;
+ }
+ if (hyperv_vapic_recommended()) {
+ c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED;
+ }
+ c->ebx = hyperv_get_spinlock_retries();
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = HYPERV_CPUID_IMPLEMENT_LIMITS;
+ c->eax = 0x40;
+ c->ebx = 0x40;
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = KVM_CPUID_SIGNATURE_NEXT;
+ memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+ c->eax = 0;
+ c->ebx = signature[0];
+ c->ecx = signature[1];
+ c->edx = signature[2];
+ }
+
has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
@@ -933,6 +987,13 @@
kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN,
env->async_pf_en_msr);
}
+ if (hyperv_hypercall_available()) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
+ }
+ if (hyperv_vapic_recommended()) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0);
+ }
}
if (env->mcg_cap) {
int i;
@@ -1276,6 +1337,36 @@
return 0;
}
+static int kvm_get_apic(CPUState *env)
+{
+ DeviceState *apic = env->apic_state;
+ struct kvm_lapic_state kapic;
+ int ret;
+
+ if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+ ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic);
+ if (ret < 0) {
+ return ret;
+ }
+
+ kvm_get_apic_state(apic, &kapic);
+ }
+ return 0;
+}
+
+static int kvm_put_apic(CPUState *env)
+{
+ DeviceState *apic = env->apic_state;
+ struct kvm_lapic_state kapic;
+
+ if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+ kvm_put_apic_state(apic, &kapic);
+
+ return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic);
+ }
+ return 0;
+}
+
static int kvm_put_vcpu_events(CPUState *env, int level)
{
struct kvm_vcpu_events events;
@@ -1449,6 +1540,10 @@
if (ret < 0) {
return ret;
}
+ ret = kvm_put_apic(env);
+ if (ret < 0) {
+ return ret;
+ }
}
ret = kvm_put_vcpu_events(env, level);
if (ret < 0) {
@@ -1496,6 +1591,10 @@
if (ret < 0) {
return ret;
}
+ ret = kvm_get_apic(env);
+ if (ret < 0) {
+ return ret;
+ }
ret = kvm_get_vcpu_events(env);
if (ret < 0) {
return ret;
@@ -1878,3 +1977,14 @@
return !(env->cr[0] & CR0_PE_MASK) ||
((env->segs[R_CS].selector & 3) != 3);
}
+
+void kvm_arch_init_irq_routing(KVMState *s)
+{
+ if (!kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+ /* If kernel can't do irq routing, interrupt source
+ * override 0->2 cannot be set up as required by HPET.
+ * So we have to disable it.
+ */
+ no_hpet = 1;
+ }
+}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2d67d1f..fbcf488 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -187,7 +187,10 @@
POWERPC_EXCP_EPERFM = 35, /* Embedded performance monitor interrupt */
POWERPC_EXCP_DOORI = 36, /* Embedded doorbell interrupt */
POWERPC_EXCP_DOORCI = 37, /* Embedded doorbell critical interrupt */
- /* Vectors 38 to 63 are reserved */
+ POWERPC_EXCP_GDOORI = 38, /* Embedded guest doorbell interrupt */
+ POWERPC_EXCP_GDOORCI = 39, /* Embedded guest doorbell critical interrupt*/
+ POWERPC_EXCP_HYPPRIV = 41, /* Embedded hypervisor priv instruction */
+ /* Vectors 42 to 63 are reserved */
/* Exceptions defined in the PowerPC server specification */
POWERPC_EXCP_RESET = 64, /* System reset exception */
POWERPC_EXCP_DSEG = 65, /* Data segment exception */
@@ -855,6 +858,22 @@
#define BOOKE206_MAX_TLBN 4
/*****************************************************************************/
+/* Embedded.Processor Control */
+
+#define DBELL_TYPE_SHIFT 27
+#define DBELL_TYPE_MASK (0x1f << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_DBELL (0x00 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_DBELL_CRIT (0x01 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL (0x02 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL_CRIT (0x03 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL_MC (0x04 << DBELL_TYPE_SHIFT)
+
+#define DBELL_BRDCAST (1 << 26)
+#define DBELL_LPIDTAG_SHIFT 14
+#define DBELL_LPIDTAG_MASK (0xfff << DBELL_LPIDTAG_SHIFT)
+#define DBELL_PIRTAG_MASK 0x3fff
+
+/*****************************************************************************/
/* The whole PowerPC CPU context */
#define NB_MMU_MODES 3
@@ -1355,6 +1374,10 @@
#define SPR_BOOKE_DVC2 (0x13F)
#define SPR_BOOKE_TSR (0x150)
#define SPR_BOOKE_TCR (0x154)
+#define SPR_BOOKE_TLB0PS (0x158)
+#define SPR_BOOKE_TLB1PS (0x159)
+#define SPR_BOOKE_TLB2PS (0x15A)
+#define SPR_BOOKE_TLB3PS (0x15B)
#define SPR_BOOKE_IVOR0 (0x190)
#define SPR_BOOKE_IVOR1 (0x191)
#define SPR_BOOKE_IVOR2 (0x192)
@@ -1371,6 +1394,11 @@
#define SPR_BOOKE_IVOR13 (0x19D)
#define SPR_BOOKE_IVOR14 (0x19E)
#define SPR_BOOKE_IVOR15 (0x19F)
+#define SPR_BOOKE_IVOR38 (0x1B0)
+#define SPR_BOOKE_IVOR39 (0x1B1)
+#define SPR_BOOKE_IVOR40 (0x1B2)
+#define SPR_BOOKE_IVOR41 (0x1B3)
+#define SPR_BOOKE_IVOR42 (0x1B4)
#define SPR_BOOKE_SPEFSCR (0x200)
#define SPR_Exxx_BBEAR (0x201)
#define SPR_Exxx_BBTAR (0x202)
@@ -1888,8 +1916,10 @@
PPC2_VSX = 0x0000000000000002ULL,
/* Decimal Floating Point (DFP) */
PPC2_DFP = 0x0000000000000004ULL,
+ /* Embedded.Processor Control */
+ PPC2_PRCNTL = 0x0000000000000008ULL,
-#define PPC_TCG_INSNS2 (PPC2_BOOKE206)
+#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL)
};
/*****************************************************************************/
@@ -2103,6 +2133,10 @@
ea &= (1 << (tlb_bits - ways_bits)) - 1;
r = (ea << ways_bits) | way;
+ if (r >= booke206_tlb_size(env, tlbn)) {
+ return NULL;
+ }
+
/* bump up to tlbn index */
for (i = 0; i < tlbn; i++) {
r += booke206_tlb_size(env, i);
@@ -2111,6 +2145,27 @@
return &env->tlb.tlbm[r];
}
+/* returns bitmap of supported page sizes for a given TLB */
+static inline uint32_t booke206_tlbnps(CPUState *env, const int tlbn)
+{
+ bool mav2 = false;
+ uint32_t ret = 0;
+
+ if (mav2) {
+ ret = env->spr[SPR_BOOKE_TLB0PS + tlbn];
+ } else {
+ uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+ uint32_t min = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+ uint32_t max = (tlbncfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT;
+ int i;
+ for (i = min; i <= max; i++) {
+ ret |= (1 << (i << 1));
+ }
+ }
+
+ return ret;
+}
+
#endif
extern void (*cpu_ppc_hypercall)(CPUState *);
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 5847453..e56fac8 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1298,13 +1298,7 @@
int tlbm_size;
tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
-
- if (tlbncfg & TLBnCFG_AVAIL) {
- tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
- } else {
- tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
- tlbm_size <<= 1;
- }
+ tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
return 1024ULL << tlbm_size;
}
@@ -1338,7 +1332,10 @@
if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
return -1;
}
- *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+
+ if (raddrp) {
+ *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+ }
return 0;
}
@@ -1445,6 +1442,9 @@
for (j = 0; j < ways; j++) {
tlb = booke206_get_tlbm(env, i, address, j);
+ if (!tlb) {
+ continue;
+ }
ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
rw, access_type);
if (ret != -1) {
@@ -2698,22 +2698,10 @@
"Performance counter exception is not implemented yet !\n");
goto store_next;
case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
- /* XXX: TODO */
- cpu_abort(env,
- "Embedded doorbell interrupt is not implemented yet !\n");
goto store_next;
case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
- switch (excp_model) {
- case POWERPC_EXCP_BOOKE:
- srr0 = SPR_BOOKE_CSRR0;
- srr1 = SPR_BOOKE_CSRR1;
- break;
- default:
- break;
- }
- /* XXX: TODO */
- cpu_abort(env, "Embedded doorbell critical interrupt "
- "is not implemented yet !\n");
+ srr0 = SPR_BOOKE_CSRR0;
+ srr1 = SPR_BOOKE_CSRR1;
goto store_next;
case POWERPC_EXCP_RESET: /* System reset exception */
if (msr_pow) {
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 470e42f..148543a 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -336,6 +336,9 @@
DEF_HELPER_0(booke206_tlbwe, void)
DEF_HELPER_1(booke206_tlbsx, void, tl)
DEF_HELPER_1(booke206_tlbivax, void, tl)
+DEF_HELPER_1(booke206_tlbilx0, void, tl)
+DEF_HELPER_1(booke206_tlbilx1, void, tl)
+DEF_HELPER_1(booke206_tlbilx3, void, tl)
DEF_HELPER_1(booke206_tlbflush, void, i32)
DEF_HELPER_2(booke_setpid, void, i32, tl)
DEF_HELPER_1(6xx_tlbd, void, tl)
@@ -355,6 +358,8 @@
DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl)
DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_1(msgsnd, void, tl)
+DEF_HELPER_1(msgclr, void, tl)
#endif
DEF_HELPER_3(dlmzb, tl, tl, tl, i32)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index ce8ac5b..50cfa02 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -740,6 +740,7 @@
struct kvm_one_reg reg = {};
struct kvm_sregs sregs = {};
int ret;
+ uint64_t hior = env->spr[SPR_HIOR];
cap.cap = KVM_CAP_PPC_PAPR;
ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap);
@@ -755,11 +756,14 @@
* Once we have qdev CPUs, move HIOR to a qdev property and
* remove this chunk.
*/
- reg.id = KVM_ONE_REG_PPC_HIOR;
- reg.u.reg64 = env->spr[SPR_HIOR];
+ reg.id = KVM_REG_PPC_HIOR;
+ reg.addr = (uintptr_t)&hior;
ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®);
if (ret) {
- goto fail;
+ fprintf(stderr, "Couldn't set HIOR. Maybe you're running an old \n"
+ "kernel with support for HV KVM but no PAPR PR \n"
+ "KVM in which case things will work. If they don't \n"
+ "please update your host kernel!\n");
}
/* Set SDR1 so kernel space finds the HTAB */
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 6339c95..3f4e067 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4228,6 +4228,7 @@
{
uint32_t tlbncfg, tlbn;
ppcmas_tlb_t *tlb;
+ uint32_t size_tlb, size_ps;
switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
case MAS0_WQ_ALWAYS:
@@ -4259,12 +4260,37 @@
tlb = booke206_cur_tlb(env);
+ if (!tlb) {
+ helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ }
+
+ /* check that we support the targeted size */
+ size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+ size_ps = booke206_tlbnps(env, tlbn);
+ if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
+ !(size_ps & (1 << size_tlb))) {
+ helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ }
+
if (msr_gs) {
cpu_abort(env, "missing HV implementation\n");
}
tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
env->spr[SPR_BOOKE_MAS3];
tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
+
+ /* MAV 1.0 only */
+ if (!(tlbncfg & TLBnCFG_AVAIL)) {
+ /* force !AVAIL TLB entries to correct page size */
+ tlb->mas1 &= ~MAS1_TSIZE_MASK;
+ /* XXX can be configured in MMUCSR0 */
+ tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
+ }
+
/* XXX needs to change when supporting 64-bit e500 */
tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
@@ -4300,7 +4326,11 @@
ppcmas_tlb_t *tlb = NULL;
tlb = booke206_cur_tlb(env);
- booke206_tlb_to_mas(env, tlb);
+ if (!tlb) {
+ env->spr[SPR_BOOKE_MAS1] = 0;
+ } else {
+ booke206_tlb_to_mas(env, tlb);
+ }
}
void helper_booke206_tlbsx(target_ulong address)
@@ -4319,6 +4349,10 @@
for (j = 0; j < ways; j++) {
tlb = booke206_get_tlbm(env, i, address, j);
+ if (!tlb) {
+ continue;
+ }
+
if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
continue;
}
@@ -4362,6 +4396,9 @@
for (i = 0; i < ways; i++) {
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
+ if (!tlb) {
+ continue;
+ }
mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
!(tlb->mas1 & MAS1_IPROT)) {
@@ -4395,6 +4432,73 @@
}
}
+void helper_booke206_tlbilx0(target_ulong address)
+{
+ /* XXX missing LPID handling */
+ booke206_flush_tlb(env, -1, 1);
+}
+
+void helper_booke206_tlbilx1(target_ulong address)
+{
+ int i, j;
+ int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+ ppcmas_tlb_t *tlb = env->tlb.tlbm;
+ int tlb_size;
+
+ /* XXX missing LPID handling */
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ tlb_size = booke206_tlb_size(env, i);
+ for (j = 0; j < tlb_size; j++) {
+ if (!(tlb[j].mas1 & MAS1_IPROT) &&
+ ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
+ tlb[j].mas1 &= ~MAS1_VALID;
+ }
+ }
+ tlb += booke206_tlb_size(env, i);
+ }
+ tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbilx3(target_ulong address)
+{
+ int i, j;
+ ppcmas_tlb_t *tlb;
+ int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+ int pid = tid >> MAS6_SPID_SHIFT;
+ int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
+ int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
+ /* XXX check for unsupported isize and raise an invalid opcode then */
+ int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
+ /* XXX implement MAV2 handling */
+ bool mav2 = false;
+
+ /* XXX missing LPID handling */
+ /* flush by pid and ea */
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ int ways = booke206_tlb_ways(env, i);
+
+ for (j = 0; j < ways; j++) {
+ tlb = booke206_get_tlbm(env, i, address, j);
+ if (!tlb) {
+ continue;
+ }
+ if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
+ (tlb->mas1 & MAS1_IPROT) ||
+ ((tlb->mas1 & MAS1_IND) != ind) ||
+ ((tlb->mas8 & MAS8_TGS) != sgs)) {
+ continue;
+ }
+ if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
+ /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
+ continue;
+ }
+ /* XXX e500mc doesn't match SAS, but other cores might */
+ tlb->mas1 &= ~MAS1_VALID;
+ }
+ }
+ tlb_flush(env, 1);
+}
+
void helper_booke206_tlbflush(uint32_t type)
{
int flags = 0;
@@ -4410,4 +4514,57 @@
booke206_flush_tlb(env, flags, 1);
}
+/* Embedded.Processor Control */
+static int dbell2irq(target_ulong rb)
+{
+ int msg = rb & DBELL_TYPE_MASK;
+ int irq = -1;
+
+ switch (msg) {
+ case DBELL_TYPE_DBELL:
+ irq = PPC_INTERRUPT_DOORBELL;
+ break;
+ case DBELL_TYPE_DBELL_CRIT:
+ irq = PPC_INTERRUPT_CDOORBELL;
+ break;
+ case DBELL_TYPE_G_DBELL:
+ case DBELL_TYPE_G_DBELL_CRIT:
+ case DBELL_TYPE_G_DBELL_MC:
+ /* XXX implement */
+ default:
+ break;
+ }
+
+ return irq;
+}
+
+void helper_msgclr(target_ulong rb)
+{
+ int irq = dbell2irq(rb);
+
+ if (irq < 0) {
+ return;
+ }
+
+ env->pending_interrupts &= ~(1 << irq);
+}
+
+void helper_msgsnd(target_ulong rb)
+{
+ int irq = dbell2irq(rb);
+ int pir = rb & DBELL_PIRTAG_MASK;
+ CPUState *cenv;
+
+ if (irq < 0) {
+ return;
+ }
+
+ for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
+ if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
+ cenv->pending_interrupts |= 1 << irq;
+ cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
+ }
+ }
+}
+
#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 66eae30..b2780db 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6088,6 +6088,7 @@
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
+ gen_update_nip(ctx, ctx->nip - 4);
gen_helper_booke206_tlbwe();
#endif
}
@@ -6110,6 +6111,39 @@
#endif
}
+static void gen_tlbilx_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+ TCGv t0;
+ if (unlikely(!ctx->mem_idx)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ return;
+ }
+
+ t0 = tcg_temp_new();
+ gen_addr_reg_index(ctx, t0);
+
+ switch((ctx->opcode >> 21) & 0x3) {
+ case 0:
+ gen_helper_booke206_tlbilx0(t0);
+ break;
+ case 1:
+ gen_helper_booke206_tlbilx1(t0);
+ break;
+ case 3:
+ gen_helper_booke206_tlbilx3(t0);
+ break;
+ default:
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+ break;
+ }
+
+ tcg_temp_free(t0);
+#endif
+}
+
/* wrtee */
static void gen_wrtee(DisasContext *ctx)
@@ -6172,7 +6206,7 @@
}
/* msync replaces sync on 440 */
-static void gen_msync(DisasContext *ctx)
+static void gen_msync_4xx(DisasContext *ctx)
{
/* interpreted as no-op */
}
@@ -6186,6 +6220,36 @@
*/
}
+/* Embedded.Processor Control */
+
+static void gen_msgclr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+ if (unlikely(ctx->mem_idx == 0)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ return;
+ }
+
+ gen_helper_msgclr(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+static void gen_msgsnd(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+ if (unlikely(ctx->mem_idx == 0)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ return;
+ }
+
+ gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
/*** Altivec vector extension ***/
/* Altivec registers moves */
@@ -8574,13 +8638,18 @@
PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001,
+ PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001,
+ PPC_NONE, PPC2_PRCNTL),
+GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001,
+ PPC_NONE, PPC2_PRCNTL),
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
PPC_BOOKE, PPC2_BOOKE206),
-GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801,
- PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER(msync_4xx, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
PPC_BOOKE, PPC2_BOOKE206),
GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 47d73a6..6253076 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -526,26 +526,27 @@
static void spr_write_excp_vector (void *opaque, int sprn, int gprn)
{
DisasContext *ctx = opaque;
+ int sprn_offs;
if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
- TCGv t0 = tcg_temp_new();
- tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
- tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR0]));
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
+ sprn_offs = sprn - SPR_BOOKE_IVOR0;
} else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
- TCGv t0 = tcg_temp_new();
- tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
- tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR32 + 32]));
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
+ sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32;
+ } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) {
+ sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38;
} else {
printf("Trying to write an unknown exception vector %d %03x\n",
sprn, sprn);
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ return;
}
+
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
+ tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn_offs]));
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
}
#endif
@@ -1434,8 +1435,8 @@
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVOR32, SPR_BOOKE_IVOR33, SPR_BOOKE_IVOR34, SPR_BOOKE_IVOR35,
- SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
- SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+ SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVOR38, SPR_BOOKE_IVOR39,
+ SPR_BOOKE_IVOR40, SPR_BOOKE_IVOR41, SPR_BOOKE_IVOR42, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
@@ -3516,6 +3517,9 @@
/* PowerPC 440 EP */
#define POWERPC_INSNS_440EP (PPC_INSNS_BASE | PPC_STRING | \
+ PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | \
+ PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \
+ PPC_FLOAT_STFIWX | \
PPC_DCR | PPC_WRTEE | PPC_RFMCI | \
PPC_CACHE | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
@@ -3523,7 +3527,7 @@
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \
PPC_440_SPEC)
#define POWERPC_INSNS2_440EP (PPC_NONE)
-#define POWERPC_MSRM_440EP (0x000000000006D630ULL)
+#define POWERPC_MSRM_440EP (0x000000000006FF30ULL)
#define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE)
#define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE)
#define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE)
@@ -3532,7 +3536,6 @@
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
#define check_pow_440EP check_pow_nocheck
-__attribute__ (( unused ))
static void init_proc_440EP (CPUPPCState *env)
{
/* Time base */
@@ -3593,7 +3596,7 @@
init_excp_BookE(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
- /* XXX: TODO: allocate internal IRQ controller */
+ ppc40x_irq_init(env);
SET_FIT_PERIOD(12, 16, 20, 24);
SET_WDT_PERIOD(20, 24, 28, 32);
@@ -4368,7 +4371,7 @@
PPC_WRTEE | PPC_RFDI | \
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
- PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+ PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
#define POWERPC_INSNS2_e500v1 (PPC2_BOOKE206)
#define POWERPC_MSRM_e500v1 (0x000000000606FF30ULL)
#define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE206)
@@ -4387,7 +4390,7 @@
PPC_WRTEE | PPC_RFDI | \
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
- PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+ PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
#define POWERPC_INSNS2_e500v2 (PPC2_BOOKE206)
#define POWERPC_MSRM_e500v2 (0x000000000606FF30ULL)
#define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE206)
@@ -4408,8 +4411,8 @@
PPC_FLOAT | PPC_FLOAT_FRES | \
PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \
PPC_FLOAT_STFIWX | PPC_WAIT | \
- PPC_MEM_TLBSYNC | PPC_TLBIVAX)
-#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206)
+ PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
+#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206 | PPC2_PRCNTL)
#define POWERPC_MSRM_e500mc (0x000000001402FB36ULL)
#define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206)
#define POWERPC_EXCP_e500mc (POWERPC_EXCP_BOOKE)
@@ -4430,6 +4433,9 @@
static void init_proc_e500 (CPUPPCState *env, int version)
{
uint32_t tlbncfg[2];
+ uint64_t ivor_mask = 0x0000000F0000FFFFULL;
+ uint32_t l1cfg0 = 0x3800 /* 8 ways */
+ | 0x0020; /* 32 kb */
#if !defined(CONFIG_USER_ONLY)
int i;
#endif
@@ -4441,7 +4447,10 @@
* complain when accessing them.
* gen_spr_BookE(env, 0x0000000F0000FD7FULL);
*/
- gen_spr_BookE(env, 0x0000000F0000FFFFULL);
+ if (version == fsl_e500mc) {
+ ivor_mask = 0x000003FE0000FFFFULL;
+ }
+ gen_spr_BookE(env, ivor_mask);
/* Processor identification */
spr_register(env, SPR_BOOKE_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -4478,6 +4487,7 @@
tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
env->dcache_line_size = 64;
env->icache_line_size = 64;
+ l1cfg0 |= 0x1000000; /* 64 byte cache block size */
break;
default:
cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
@@ -4528,7 +4538,7 @@
spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
- 0x00000000);
+ l1cfg0);
/* XXX : not implemented */
spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
SPR_NOACCESS, SPR_NOACCESS,
@@ -7869,22 +7879,14 @@
POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5),
#endif
/* PowerPC 440 microcontrolers */
-#if defined(TODO_USER_ONLY)
/* PowerPC 440 EP */
POWERPC_DEF("440EP", CPU_POWERPC_440EP, 440EP),
-#endif
-#if defined(TODO_USER_ONLY)
/* PowerPC 440 EPa */
POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP),
-#endif
-#if defined(TODO_USER_ONLY)
/* PowerPC 440 EPb */
POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP),
-#endif
-#if defined(TODO_USER_ONLY)
/* PowerPC 440 EPX */
POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP),
-#endif
#if defined(TODO_USER_ONLY)
/* PowerPC 440 GP */
POWERPC_DEF("440GP", CPU_POWERPC_440GP, 440GP),
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index a992c29..9d2edb0 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -459,7 +459,7 @@
return ret;
}
-uint64 helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
+uint64_t helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
{
union {
uint64_t ll[2];
diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
index 1f3ab03..926db5c 100644
--- a/test-qmp-input-visitor.c
+++ b/test-qmp-input-visitor.c
@@ -38,8 +38,9 @@
/* This is provided instead of a test setup function so that the JSON
string used by the tests are kept in the test functions (and not
int main()) */
-static Visitor *visitor_input_test_init(TestInputVisitorData *data,
- const char *json_string, ...)
+static GCC_FMT_ATTR(2, 3)
+Visitor *visitor_input_test_init(TestInputVisitorData *data,
+ const char *json_string, ...)
{
Visitor *v;
va_list ap;
@@ -66,7 +67,7 @@
Error *errp = NULL;
Visitor *v;
- v = visitor_input_test_init(data, "%d", value);
+ v = visitor_input_test_init(data, "%" PRId64, value);
visit_type_int(v, &res, NULL, &errp);
g_assert(!error_is_set(&errp));
diff --git a/tests/Makefile b/tests/Makefile
index efde63a..55e8eb0 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -36,4 +36,4 @@
.PHONY: check
check: $(CHECKS)
- gtester $(CHECKS)
+ $(call quiet-command, gtester $(CHECKS), " CHECK")
diff --git a/trace-events b/trace-events
index c18435b..5d05749 100644
--- a/trace-events
+++ b/trace-events
@@ -65,14 +65,25 @@
bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
-bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
+bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
+
+# block/stream.c
+stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
+stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
+
+# blockdev.c
+qmp_block_job_cancel(void *job) "job %p"
+block_stream_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
+qmp_block_stream(void *bs, void *job) "bs %p job %p"
# hw/virtio-blk.c
virtio_blk_req_complete(void *req, int status) "req %p status %d"
virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
+virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
# posix-aio-compat.c
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"
@@ -95,9 +106,9 @@
apic_mem_readl(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
# coalescing
+apic_report_irq_delivered(int apic_irq_delivered) "coalescing %d"
apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
-apic_set_irq(int apic_irq_delivered) "coalescing %d"
# hw/cs4231.c
cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
@@ -246,6 +257,7 @@
usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
usb_set_addr(int addr) "dev %d"
usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
+usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d"
usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
@@ -339,6 +351,7 @@
# hw/grlib_apbuart.c
grlib_apbuart_event(int event) "event:%d"
grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
+grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64""
# hw/leon3.c
leon3_set_irq(int intno) "Set CPU IRQ %d"
diff --git a/ui/sdl.c b/ui/sdl.c
index 8cafc44..6f8091c 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -461,18 +461,23 @@
static void sdl_grab_start(void)
{
+ /*
+ * If the application is not active, do not try to enter grab state. This
+ * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
+ * application (SDL bug).
+ */
+ if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) {
+ return;
+ }
if (guest_cursor) {
SDL_SetCursor(guest_sprite);
if (!kbd_mouse_is_absolute() && !absolute_enabled)
SDL_WarpMouse(guest_x, guest_y);
} else
sdl_hide_cursor();
-
- if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
- gui_grab = 1;
- sdl_update_caption();
- } else
- sdl_show_cursor();
+ SDL_WM_GrabInput(SDL_GRAB_ON);
+ gui_grab = 1;
+ sdl_update_caption();
}
static void sdl_grab_end(void)
@@ -483,12 +488,25 @@
sdl_update_caption();
}
+static void absolute_mouse_grab(void)
+{
+ int mouse_x, mouse_y;
+
+ SDL_GetMouseState(&mouse_x, &mouse_y);
+ if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
+ mouse_y > 0 && mouse_y < real_screen->h - 1) {
+ sdl_grab_start();
+ }
+}
+
static void sdl_mouse_mode_change(Notifier *notify, void *data)
{
if (kbd_mouse_is_absolute()) {
if (!absolute_enabled) {
- sdl_grab_start();
absolute_enabled = 1;
+ if (is_graphic_console()) {
+ absolute_mouse_grab();
+ }
}
} else if (absolute_enabled) {
if (!gui_fullscreen) {
@@ -571,19 +589,6 @@
vga_hw_update();
}
-static void absolute_mouse_grab(void)
-{
- int mouse_x, mouse_y;
-
- if (SDL_GetAppState() & SDL_APPINPUTFOCUS) {
- SDL_GetMouseState(&mouse_x, &mouse_y);
- if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
- mouse_y > 0 && mouse_y < real_screen->h - 1) {
- sdl_grab_start();
- }
- }
-}
-
static void handle_keydown(DisplayState *ds, SDL_Event *ev)
{
int mod_state;
@@ -743,11 +748,7 @@
if (gui_keysym == 0) {
/* exit/enter grab if pressing Ctrl-Alt */
if (!gui_grab) {
- /* If the application is not active, do not try to enter grab
- * state. It prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from
- * blocking all the application (SDL bug). */
- if (is_graphic_console() &&
- SDL_GetAppState() & SDL_APPACTIVE) {
+ if (is_graphic_console()) {
sdl_grab_start();
}
} else if (!gui_fullscreen) {
@@ -777,7 +778,7 @@
ev->motion.x == max_x || ev->motion.y == max_y)) {
sdl_grab_end();
}
- if (!gui_grab && SDL_GetAppState() & SDL_APPINPUTFOCUS &&
+ if (!gui_grab &&
(ev->motion.x > 0 && ev->motion.x < max_x &&
ev->motion.y > 0 && ev->motion.y < max_y)) {
sdl_grab_start();
@@ -801,8 +802,7 @@
bev = &ev->button;
if (!gui_grab && !kbd_mouse_is_absolute()) {
- if (ev->type == SDL_MOUSEBUTTONDOWN &&
- (bev->button == SDL_BUTTON_LEFT)) {
+ if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
/* start grabbing all events */
sdl_grab_start();
}
@@ -828,10 +828,14 @@
static void handle_activation(DisplayState *ds, SDL_Event *ev)
{
+#ifdef _WIN32
+ /* Disable grab if the window no longer has the focus
+ * (Windows-only workaround) */
if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
!ev->active.gain && !gui_fullscreen) {
sdl_grab_end();
}
+#endif
if (!gui_grab && ev->active.gain && is_graphic_console() &&
(kbd_mouse_is_absolute() || absolute_enabled)) {
absolute_mouse_grab();
diff --git a/ui/vnc.c b/ui/vnc.c
index 1869a7a..16b79ec 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2686,19 +2686,16 @@
int vnc_display_password(DisplayState *ds, const char *password)
{
- int ret = 0;
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
if (!vs) {
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (!password) {
/* This is not the intention of this interface but err on the side
of being safe */
- ret = vnc_display_disable_login(ds);
- goto out;
+ return vnc_display_disable_login(ds);
}
if (vs->password) {
@@ -2707,11 +2704,8 @@
}
vs->password = g_strdup(password);
vs->auth = VNC_AUTH_VNC;
-out:
- if (ret != 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- }
- return ret;
+
+ return 0;
}
int vnc_display_pw_expire(DisplayState *ds, time_t expires)
diff --git a/usb-bsd.c b/usb-bsd.c
index 1187552..fc722b3 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -397,21 +397,29 @@
return ret;
}
-static struct USBDeviceInfo usb_host_dev_info = {
- .product_desc = "USB Host Device",
- .qdev.name = "usb-host",
- .qdev.size = sizeof(USBHostDevice),
- .init = usb_host_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_host_handle_reset,
- .handle_control = usb_host_handle_control,
- .handle_data = usb_host_handle_data,
- .handle_destroy = usb_host_handle_destroy,
+static void usb_host_class_initfn(ObjectClass *klass, void *data)
+{
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->product_desc = "USB Host Device";
+ uc->init = usb_host_initfn;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_host_handle_reset;
+ uc->handle_control = usb_host_handle_control;
+ uc->handle_data = usb_host_handle_data;
+ uc->handle_destroy = usb_host_handle_destroy;
+}
+
+static TypeInfo usb_host_dev_info = {
+ .name = "usb-host",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHostDevice),
+ .class_init = usb_host_class_initfn,
};
static void usb_host_register_devices(void)
{
- usb_qdev_register(&usb_host_dev_info);
+ type_register_static(&usb_host_dev_info);
}
device_init(usb_host_register_devices)
diff --git a/usb-linux.c b/usb-linux.c
index 749ce71..e7fc9ec 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -66,27 +66,11 @@
#define DPRINTF(...)
#endif
-#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
-
-#define USBPROCBUS_PATH "/proc/bus/usb"
#define PRODUCT_NAME_SZ 32
-#define MAX_ENDPOINTS 15
#define MAX_PORTLEN 16
-#define USBDEVBUS_PATH "/dev/bus/usb"
-#define USBSYSBUS_PATH "/sys/bus/usb"
-
-static char *usb_host_device_path;
-
-#define USB_FS_NONE 0
-#define USB_FS_PROC 1
-#define USB_FS_DEV 2
-#define USB_FS_SYS 3
-
-static int usb_fs_type;
/* endpoint association data */
#define ISO_FRAME_DESC_PER_URB 32
-#define INVALID_EP_TYPE 255
/* devio.c limits single requests to 16k */
#define MAX_USBFS_BUFFER_SIZE 16384
@@ -94,13 +78,11 @@
typedef struct AsyncURB AsyncURB;
struct endp_data {
- uint8_t type;
uint8_t halted;
uint8_t iso_started;
AsyncURB *iso_urb;
int iso_urb_idx;
int iso_buffer_used;
- int max_packet_size;
int inflight;
};
@@ -120,14 +102,12 @@
uint8_t descr[8192];
int descr_len;
- int configuration;
- int ninterfaces;
int closing;
uint32_t iso_urb_count;
Notifier exit;
- struct endp_data ep_in[MAX_ENDPOINTS];
- struct endp_data ep_out[MAX_ENDPOINTS];
+ struct endp_data ep_in[USB_MAX_ENDPOINTS];
+ struct endp_data ep_out[USB_MAX_ENDPOINTS];
QLIST_HEAD(, AsyncURB) aurbs;
/* Host side address */
@@ -149,6 +129,19 @@
const char *device_file, const char *device_name);
static int usb_linux_update_endp_table(USBHostDevice *s);
+static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
+{
+ static const int usbfs[] = {
+ [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL,
+ [USB_ENDPOINT_XFER_ISOC] = USBDEVFS_URB_TYPE_ISO,
+ [USB_ENDPOINT_XFER_BULK] = USBDEVFS_URB_TYPE_BULK,
+ [USB_ENDPOINT_XFER_INT] = USBDEVFS_URB_TYPE_INTERRUPT,
+ };
+ uint8_t type = usb_ep_get_type(&s->dev, p->pid, p->devep);
+ assert(type < ARRAY_SIZE(usbfs));
+ return usbfs[type];
+}
+
static int usb_host_do_reset(USBHostDevice *dev)
{
struct timeval s, e;
@@ -172,18 +165,18 @@
{
struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
- assert(ep > 0 && ep <= MAX_ENDPOINTS);
+ assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
return eps + ep - 1;
}
static int is_isoc(USBHostDevice *s, int pid, int ep)
{
- return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
+ return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC;
}
static int is_valid(USBHostDevice *s, int pid, int ep)
{
- return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
+ return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID;
}
static int is_halted(USBHostDevice *s, int pid, int ep)
@@ -265,26 +258,6 @@
return get_endp(s, pid, ep)->iso_buffer_used;
}
-static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
- uint8_t *descriptor)
-{
- int raw = descriptor[4] + (descriptor[5] << 8);
- int size, microframes;
-
- size = raw & 0x7ff;
- switch ((raw >> 11) & 3) {
- case 1: microframes = 2; break;
- case 2: microframes = 3; break;
- default: microframes = 1; break;
- }
- get_endp(s, pid, ep)->max_packet_size = size * microframes;
-}
-
-static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
-{
- return get_endp(s, pid, ep)->max_packet_size;
-}
-
/*
* Async URB state.
* We always allocate iso packet descriptors even for bulk transfers
@@ -431,6 +404,31 @@
}
}
+static int usb_host_open_device(int bus, int addr)
+{
+ const char *usbfs = NULL;
+ char filename[32];
+ struct stat st;
+ int fd, rc;
+
+ rc = stat("/dev/bus/usb", &st);
+ if (rc == 0 && S_ISDIR(st.st_mode)) {
+ /* udev-created device nodes available */
+ usbfs = "/dev/bus/usb";
+ } else {
+ /* fallback: usbfs mounted below /proc */
+ usbfs = "/proc/bus/usb";
+ }
+
+ snprintf(filename, sizeof(filename), "%s/%03d/%03d",
+ usbfs, bus, addr);
+ fd = open(filename, O_RDWR | O_NONBLOCK);
+ if (fd < 0) {
+ fprintf(stderr, "husb: open %s: %s\n", filename, strerror(errno));
+ }
+ return fd;
+}
+
static int usb_host_claim_port(USBHostDevice *s)
{
#ifdef USBDEVFS_CLAIM_PORT
@@ -460,12 +458,7 @@
return -1;
}
- if (!usb_host_device_path) {
- return -1;
- }
- snprintf(line, sizeof(line), "%s/%03d/%03d",
- usb_host_device_path, s->match.bus_num, hub_addr);
- s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
+ s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr);
if (s->hub_fd < 0) {
return -1;
}
@@ -522,10 +515,6 @@
char device_name[64], line[1024];
int num_interfaces = 0;
- if (usb_fs_type != USB_FS_SYS) {
- return -1;
- }
-
sprintf(device_name, "%d-%s", s->bus_num, s->port);
if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
device_name)) {
@@ -544,9 +533,13 @@
int interface, nb_interfaces;
int ret, i;
+ for (i = 0; i < USB_MAX_INTERFACES; i++) {
+ dev->dev.altsetting[i] = 0;
+ }
+
if (configuration == 0) { /* address state - ignore */
- dev->ninterfaces = 0;
- dev->configuration = 0;
+ dev->dev.ninterfaces = 0;
+ dev->dev.configuration = 0;
return 1;
}
@@ -604,8 +597,8 @@
trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
nb_interfaces, configuration);
- dev->ninterfaces = nb_interfaces;
- dev->configuration = configuration;
+ dev->dev.ninterfaces = nb_interfaces;
+ dev->dev.configuration = configuration;
return 1;
fail:
@@ -622,7 +615,7 @@
trace_usb_host_release_interfaces(s->bus_num, s->addr);
- for (i = 0; i < s->ninterfaces; i++) {
+ for (i = 0; i < s->dev.ninterfaces; i++) {
ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
if (ret < 0) {
perror("USBDEVFS_RELEASEINTERFACE");
@@ -660,7 +653,7 @@
static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
{
AsyncURB *aurb;
- int i, j, len = get_max_packet_size(s, pid, ep);
+ int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep);
aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
for (i = 0; i < s->iso_urb_count; i++) {
@@ -740,7 +733,7 @@
int i, j, ret, max_packet_size, offset, len = 0;
uint8_t *buf;
- max_packet_size = get_max_packet_size(s, p->pid, p->devep);
+ max_packet_size = usb_ep_get_max_packet_size(&s->dev, p->pid, p->devep);
if (max_packet_size == 0)
return USB_RET_NAK;
@@ -892,7 +885,7 @@
urb = &aurb->urb;
urb->endpoint = ep;
- urb->type = USBDEVFS_URB_TYPE_BULK;
+ urb->type = usb_host_usbfs_type(s, p);
urb->usercontext = s;
urb->buffer = pbuf;
urb->buffer_length = prem;
@@ -988,7 +981,7 @@
trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
- for (i = 1; i <= MAX_ENDPOINTS; i++) {
+ for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
if (is_isoc(s, USB_TOKEN_IN, i)) {
usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
}
@@ -997,6 +990,10 @@
}
}
+ if (iface >= USB_MAX_INTERFACES) {
+ return USB_RET_STALL;
+ }
+
si.interface = iface;
si.altsetting = alt;
ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
@@ -1007,6 +1004,8 @@
if (ret < 0) {
return ctrl_error();
}
+
+ s->dev.altsetting[iface] = alt;
usb_linux_update_endp_table(s);
return 0;
}
@@ -1090,41 +1089,21 @@
static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
uint8_t configuration, uint8_t interface)
{
- uint8_t alt_setting;
- struct usb_ctrltransfer ct;
- int ret;
+ char device_name[64], line[1024];
+ int alt_setting;
- if (usb_fs_type == USB_FS_SYS) {
- char device_name[64], line[1024];
- int alt_setting;
+ sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
+ (int)configuration, (int)interface);
- sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
- (int)configuration, (int)interface);
-
- if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
- device_name)) {
- goto usbdevfs;
- }
- if (sscanf(line, "%d", &alt_setting) != 1) {
- goto usbdevfs;
- }
- return alt_setting;
- }
-
-usbdevfs:
- ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
- ct.bRequest = USB_REQ_GET_INTERFACE;
- ct.wValue = 0;
- ct.wIndex = interface;
- ct.wLength = 1;
- ct.data = &alt_setting;
- ct.timeout = 50;
- ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
- if (ret < 0) {
+ if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
+ device_name)) {
/* Assume alt 0 on error */
return 0;
}
-
+ if (sscanf(line, "%d", &alt_setting) != 1) {
+ /* Assume alt 0 on error */
+ return 0;
+ }
return alt_setting;
}
@@ -1133,15 +1112,13 @@
{
uint8_t *descriptors;
uint8_t devep, type, alt_interface;
+ uint16_t raw;
int interface, length, i, ep, pid;
struct endp_data *epd;
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- s->ep_in[i].type = INVALID_EP_TYPE;
- s->ep_out[i].type = INVALID_EP_TYPE;
- }
+ usb_ep_init(&s->dev);
- if (s->configuration == 0) {
+ if (s->dev.configuration == 0) {
/* not configured yet -- leave all endpoints disabled */
return 0;
}
@@ -1156,12 +1133,11 @@
if (descriptors[i + 1] != USB_DT_CONFIG) {
fprintf(stderr, "invalid descriptor data\n");
return 1;
- } else if (descriptors[i + 5] != s->configuration) {
- DPRINTF("not requested configuration %d\n", s->configuration);
+ } else if (descriptors[i + 5] != s->dev.configuration) {
+ DPRINTF("not requested configuration %d\n", s->dev.configuration);
i += (descriptors[i + 3] << 8) + descriptors[i + 2];
continue;
}
-
i += descriptors[i];
if (descriptors[i + 1] != USB_DT_INTERFACE ||
@@ -1172,7 +1148,7 @@
}
interface = descriptors[i + 2];
- alt_interface = usb_linux_get_alt_setting(s, s->configuration,
+ alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
interface);
/* the current interface descriptor is the active interface
@@ -1203,32 +1179,23 @@
return 1;
}
- switch (descriptors[i + 3] & 0x3) {
- case 0x00:
- type = USBDEVFS_URB_TYPE_CONTROL;
- break;
- case 0x01:
- type = USBDEVFS_URB_TYPE_ISO;
- set_max_packet_size(s, pid, ep, descriptors + i);
- break;
- case 0x02:
- type = USBDEVFS_URB_TYPE_BULK;
- break;
- case 0x03:
- type = USBDEVFS_URB_TYPE_INTERRUPT;
- break;
- default:
- DPRINTF("usb_host: malformed endpoint type\n");
- type = USBDEVFS_URB_TYPE_BULK;
- }
+ type = descriptors[i + 3] & 0x3;
+ raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
+ usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
+ assert(usb_ep_get_type(&s->dev, pid, ep) ==
+ USB_ENDPOINT_XFER_INVALID);
+ usb_ep_set_type(&s->dev, pid, ep, type);
+ usb_ep_set_ifnum(&s->dev, pid, ep, interface);
+
epd = get_endp(s, pid, ep);
- assert(epd->type == INVALID_EP_TYPE);
- epd->type = type;
epd->halted = 0;
i += descriptors[i];
}
}
+#ifdef DEBUG
+ usb_ep_dump(&s->dev);
+#endif
return 0;
}
@@ -1273,7 +1240,6 @@
const char *prod_name, int speed)
{
int fd = -1, ret;
- char buf[1024];
trace_usb_host_open_started(bus_num, addr);
@@ -1281,15 +1247,8 @@
goto fail;
}
- if (!usb_host_device_path) {
- perror("husb: USB Host Device Path not set");
- goto fail;
- }
- snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
- bus_num, addr);
- fd = open(buf, O_RDWR | O_NONBLOCK);
+ fd = usb_host_open_device(bus_num, addr);
if (fd < 0) {
- perror(buf);
goto fail;
}
DPRINTF("husb: opened %s\n", buf);
@@ -1390,7 +1349,7 @@
qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
dev->closing = 1;
- for (i = 1; i <= MAX_ENDPOINTS; i++) {
+ for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
if (is_isoc(dev, USB_TOKEN_IN, i)) {
usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
}
@@ -1443,34 +1402,44 @@
.unmigratable = 1,
};
-static struct USBDeviceInfo usb_host_dev_info = {
- .product_desc = "USB Host Device",
- .qdev.name = "usb-host",
- .qdev.size = sizeof(USBHostDevice),
- .qdev.vmsd = &vmstate_usb_host,
- .init = usb_host_initfn,
- .handle_packet = usb_generic_handle_packet,
- .cancel_packet = usb_host_async_cancel,
- .handle_data = usb_host_handle_data,
- .handle_control = usb_host_handle_control,
- .handle_reset = usb_host_handle_reset,
- .handle_destroy = usb_host_handle_destroy,
- .usbdevice_name = "host",
- .usbdevice_init = usb_host_device_open,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
- DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
- DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
- DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
- DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
- DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property usb_host_dev_properties[] = {
+ DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
+ DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
+ DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
+ DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
+ DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
+ DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_host_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_host_initfn;
+ uc->product_desc = "USB Host Device";
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->cancel_packet = usb_host_async_cancel;
+ uc->handle_data = usb_host_handle_data;
+ uc->handle_control = usb_host_handle_control;
+ uc->handle_reset = usb_host_handle_reset;
+ uc->handle_destroy = usb_host_handle_destroy;
+ dc->vmsd = &vmstate_usb_host;
+ dc->props = usb_host_dev_properties;
+}
+
+static TypeInfo usb_host_dev_info = {
+ .name = "usb-host",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHostDevice),
+ .class_init = usb_host_class_initfn,
};
static void usb_host_register_devices(void)
{
- usb_qdev_register(&usb_host_dev_info);
+ type_register_static(&usb_host_dev_info);
+ usb_legacy_register("usb-host", "host", usb_host_device_open);
}
device_init(usb_host_register_devices)
@@ -1538,149 +1507,6 @@
return -1;
}
-static int get_tag_value(char *buf, int buf_size,
- const char *str, const char *tag,
- const char *stopchars)
-{
- const char *p;
- char *q;
- p = strstr(str, tag);
- if (!p) {
- return -1;
- }
- p += strlen(tag);
- while (qemu_isspace(*p)) {
- p++;
- }
- q = buf;
- while (*p != '\0' && !strchr(stopchars, *p)) {
- if ((q - buf) < (buf_size - 1)) {
- *q++ = *p;
- }
- p++;
- }
- *q = '\0';
- return q - buf;
-}
-
-/*
- * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
- * host's USB devices. This is legacy support since many distributions
- * are moving to /sys/bus/usb
- */
-static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
-{
- FILE *f = NULL;
- char line[1024];
- char buf[1024];
- int bus_num, addr, speed, device_count;
- int class_id, product_id, vendor_id, port;
- char product_name[512];
- int ret = 0;
-
- if (!usb_host_device_path) {
- perror("husb: USB Host Device Path not set");
- goto the_end;
- }
- snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
- f = fopen(line, "r");
- if (!f) {
- perror("husb: cannot open devices file");
- goto the_end;
- }
-
- device_count = 0;
- bus_num = addr = class_id = product_id = vendor_id = port = 0;
- speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
- for(;;) {
- if (fgets(line, sizeof(line), f) == NULL) {
- break;
- }
- if (strlen(line) > 0) {
- line[strlen(line) - 1] = '\0';
- }
- if (line[0] == 'T' && line[1] == ':') {
- if (device_count && (vendor_id || product_id)) {
- /* New device. Add the previously discovered device. */
- if (port > 0) {
- snprintf(buf, sizeof(buf), "%d", port);
- } else {
- snprintf(buf, sizeof(buf), "?");
- }
- ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
- product_id, product_name, speed);
- if (ret) {
- goto the_end;
- }
- }
- if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
- goto fail;
- }
- bus_num = atoi(buf);
- if (get_tag_value(buf, sizeof(buf), line, "Port=", " ") < 0) {
- goto fail;
- }
- port = atoi(buf);
- if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
- goto fail;
- }
- addr = atoi(buf);
- if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
- goto fail;
- }
- if (!strcmp(buf, "5000")) {
- speed = USB_SPEED_SUPER;
- } else if (!strcmp(buf, "480")) {
- speed = USB_SPEED_HIGH;
- } else if (!strcmp(buf, "1.5")) {
- speed = USB_SPEED_LOW;
- } else {
- speed = USB_SPEED_FULL;
- }
- product_name[0] = '\0';
- class_id = 0xff;
- device_count++;
- product_id = 0;
- vendor_id = 0;
- } else if (line[0] == 'P' && line[1] == ':') {
- if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
- goto fail;
- }
- vendor_id = strtoul(buf, NULL, 16);
- if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
- goto fail;
- }
- product_id = strtoul(buf, NULL, 16);
- } else if (line[0] == 'S' && line[1] == ':') {
- if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
- goto fail;
- }
- pstrcpy(product_name, sizeof(product_name), buf);
- } else if (line[0] == 'D' && line[1] == ':') {
- if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
- goto fail;
- }
- class_id = strtoul(buf, NULL, 16);
- }
- fail: ;
- }
- if (device_count && (vendor_id || product_id)) {
- /* Add the last device. */
- if (port > 0) {
- snprintf(buf, sizeof(buf), "%d", port);
- } else {
- snprintf(buf, sizeof(buf), "?");
- }
- ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
- product_id, product_name, speed);
- }
- the_end:
- if (f) {
- fclose(f);
- }
- return ret;
-}
-
/*
* Read sys file-system device file
*
@@ -1698,7 +1524,7 @@
int ret = 0;
char filename[PATH_MAX];
- snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
+ snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name,
device_file);
f = fopen(filename, "r");
if (f) {
@@ -1716,7 +1542,7 @@
* This code is based on Robert Schiele's original patches posted to
* the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
*/
-static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
+static int usb_host_scan(void *opaque, USBScanFunc *func)
{
DIR *dir = NULL;
char line[1024];
@@ -1726,9 +1552,10 @@
char product_name[512];
struct dirent *de;
- dir = opendir(USBSYSBUS_PATH "/devices");
+ dir = opendir("/sys/bus/usb/devices");
if (!dir) {
- perror("husb: cannot open devices directory");
+ perror("husb: opendir /sys/bus/usb/devices");
+ fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n");
goto the_end;
}
@@ -1803,81 +1630,6 @@
return ret;
}
-/*
- * Determine how to access the host's USB devices and call the
- * specific support function.
- */
-static int usb_host_scan(void *opaque, USBScanFunc *func)
-{
- Monitor *mon = cur_mon;
- FILE *f = NULL;
- DIR *dir = NULL;
- int ret = 0;
- const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
- char devpath[PATH_MAX];
-
- /* only check the host once */
- if (!usb_fs_type) {
- dir = opendir(USBSYSBUS_PATH "/devices");
- if (dir) {
- /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
- strcpy(devpath, USBDEVBUS_PATH);
- usb_fs_type = USB_FS_SYS;
- closedir(dir);
- DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
- goto found_devices;
- }
- f = fopen(USBPROCBUS_PATH "/devices", "r");
- if (f) {
- /* devices found in /proc/bus/usb/ */
- strcpy(devpath, USBPROCBUS_PATH);
- usb_fs_type = USB_FS_PROC;
- fclose(f);
- DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
- goto found_devices;
- }
- /* try additional methods if an access method hasn't been found yet */
- f = fopen(USBDEVBUS_PATH "/devices", "r");
- if (f) {
- /* devices found in /dev/bus/usb/ */
- strcpy(devpath, USBDEVBUS_PATH);
- usb_fs_type = USB_FS_DEV;
- fclose(f);
- DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
- goto found_devices;
- }
- found_devices:
- if (!usb_fs_type) {
- if (mon) {
- monitor_printf(mon, "husb: unable to access USB devices\n");
- }
- return -ENOENT;
- }
-
- /* the module setting (used later for opening devices) */
- usb_host_device_path = g_malloc0(strlen(devpath)+1);
- strcpy(usb_host_device_path, devpath);
- if (mon) {
- monitor_printf(mon, "husb: using %s file-system with %s\n",
- fs_type[usb_fs_type], usb_host_device_path);
- }
- }
-
- switch (usb_fs_type) {
- case USB_FS_PROC:
- case USB_FS_DEV:
- ret = usb_host_scan_dev(opaque, func);
- break;
- case USB_FS_SYS:
- ret = usb_host_scan_sys(opaque, func);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
static QEMUTimer *usb_auto_timer;
static int usb_host_auto_scan(void *opaque, int bus_num,
diff --git a/usb-redir.c b/usb-redir.c
index 2b53cf3..303292a 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -60,7 +60,11 @@
uint8_t iso_error; /* For reporting iso errors to the HC */
uint8_t interrupt_started;
uint8_t interrupt_error;
+ uint8_t bufpq_prefilled;
+ uint8_t bufpq_dropping_packets;
QTAILQ_HEAD(, buf_packet) bufpq;
+ int bufpq_size;
+ int bufpq_target_size;
};
struct USBRedirDevice {
@@ -287,21 +291,41 @@
}
}
-static struct buf_packet *bufp_alloc(USBRedirDevice *dev,
+static void bufp_alloc(USBRedirDevice *dev,
uint8_t *data, int len, int status, uint8_t ep)
{
- struct buf_packet *bufp = g_malloc(sizeof(struct buf_packet));
+ struct buf_packet *bufp;
+
+ if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets &&
+ dev->endpoint[EP2I(ep)].bufpq_size >
+ 2 * dev->endpoint[EP2I(ep)].bufpq_target_size) {
+ DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep);
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1;
+ }
+ /* Since we're interupting the stream anyways, drop enough packets to get
+ back to our target buffer size */
+ if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) {
+ if (dev->endpoint[EP2I(ep)].bufpq_size >
+ dev->endpoint[EP2I(ep)].bufpq_target_size) {
+ free(data);
+ return;
+ }
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
+ }
+
+ bufp = g_malloc(sizeof(struct buf_packet));
bufp->data = data;
bufp->len = len;
bufp->status = status;
QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
- return bufp;
+ dev->endpoint[EP2I(ep)].bufpq_size++;
}
static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
uint8_t ep)
{
QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+ dev->endpoint[EP2I(ep)].bufpq_size--;
free(bufp->data);
g_free(bufp);
}
@@ -332,35 +356,77 @@
uint8_t ep)
{
int status, len;
-
if (!dev->endpoint[EP2I(ep)].iso_started &&
!dev->endpoint[EP2I(ep)].iso_error) {
struct usb_redir_start_iso_stream_header start_iso = {
.endpoint = ep,
- /* TODO maybe do something with these depending on ep interval? */
- .pkts_per_urb = 32,
- .no_urbs = 3,
};
+ int pkts_per_sec;
+
+ if (dev->dev.speed == USB_SPEED_HIGH) {
+ pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval;
+ } else {
+ pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval;
+ }
+ /* Testing has shown that we need circa 60 ms buffer */
+ dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000;
+
+ /* Aim for approx 100 interrupts / second on the client to
+ balance latency and interrupt load */
+ start_iso.pkts_per_urb = pkts_per_sec / 100;
+ if (start_iso.pkts_per_urb < 1) {
+ start_iso.pkts_per_urb = 1;
+ } else if (start_iso.pkts_per_urb > 32) {
+ start_iso.pkts_per_urb = 32;
+ }
+
+ start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size +
+ start_iso.pkts_per_urb - 1) /
+ start_iso.pkts_per_urb;
+ /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest
+ as overflow buffer. Also see the usbredir protocol documentation */
+ if (!(ep & USB_DIR_IN)) {
+ start_iso.no_urbs *= 2;
+ }
+ if (start_iso.no_urbs > 16) {
+ start_iso.no_urbs = 16;
+ }
+
/* No id, we look at the ep when receiving a status back */
usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
usbredirparser_do_write(dev->parser);
- DPRINTF("iso stream started ep %02X\n", ep);
+ DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n",
+ pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep);
dev->endpoint[EP2I(ep)].iso_started = 1;
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
}
if (ep & USB_DIR_IN) {
struct buf_packet *isop;
+ if (dev->endpoint[EP2I(ep)].iso_started &&
+ !dev->endpoint[EP2I(ep)].bufpq_prefilled) {
+ if (dev->endpoint[EP2I(ep)].bufpq_size <
+ dev->endpoint[EP2I(ep)].bufpq_target_size) {
+ return usbredir_handle_status(dev, 0, 0);
+ }
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
+ }
+
isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
if (isop == NULL) {
- DPRINTF2("iso-token-in ep %02X, no isop\n", ep);
+ DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n",
+ ep, dev->endpoint[EP2I(ep)].iso_error);
+ /* Re-fill the buffer */
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
/* Check iso_error for stream errors, otherwise its an underrun */
status = dev->endpoint[EP2I(ep)].iso_error;
dev->endpoint[EP2I(ep)].iso_error = 0;
return usbredir_handle_status(dev, status, 0);
}
- DPRINTF2("iso-token-in ep %02X status %d len %d\n", ep, isop->status,
- isop->len);
+ DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
+ isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
status = isop->status;
if (status != usb_redir_success) {
@@ -370,7 +436,8 @@
len = isop->len;
if (len > p->iov.size) {
- ERROR("received iso data is larger then packet ep %02X\n", ep);
+ ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
+ ep, len, (int)p->iov.size);
bufp_free(dev, isop, ep);
return USB_RET_NAK;
}
@@ -410,6 +477,7 @@
DPRINTF("iso stream stopped ep %02X\n", ep);
dev->endpoint[EP2I(ep)].iso_started = 0;
}
+ dev->endpoint[EP2I(ep)].iso_error = 0;
usbredir_free_bufpq(dev, ep);
}
@@ -460,6 +528,10 @@
usbredirparser_do_write(dev->parser);
DPRINTF("interrupt recv started ep %02X\n", ep);
dev->endpoint[EP2I(ep)].interrupt_started = 1;
+ /* We don't really want to drop interrupt packets ever, but
+ having some upper limit to how much we buffer is good. */
+ dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
}
intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
@@ -522,6 +594,7 @@
DPRINTF("interrupt recv stopped ep %02X\n", ep);
dev->endpoint[EP2I(ep)].interrupt_started = 0;
}
+ dev->endpoint[EP2I(ep)].interrupt_error = 0;
usbredir_free_bufpq(dev, ep);
}
@@ -959,9 +1032,24 @@
dev->endpoint[i].type = ep_info->type[i];
dev->endpoint[i].interval = ep_info->interval[i];
dev->endpoint[i].interface = ep_info->interface[i];
- if (dev->endpoint[i].type != usb_redir_type_invalid) {
+ switch (dev->endpoint[i].type) {
+ case usb_redir_type_invalid:
+ break;
+ case usb_redir_type_iso:
+ case usb_redir_type_interrupt:
+ if (dev->endpoint[i].interval == 0) {
+ ERROR("Received 0 interval for isoc or irq endpoint\n");
+ usbredir_device_disconnect(dev);
+ }
+ /* Fall through */
+ case usb_redir_type_control:
+ case usb_redir_type_bulk:
DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
dev->endpoint[i].type, dev->endpoint[i].interface);
+ break;
+ default:
+ ERROR("Received invalid endpoint type\n");
+ usbredir_device_disconnect(dev);
}
}
}
@@ -1029,7 +1117,7 @@
DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status,
ep, id);
- if (!dev->dev.attached) {
+ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) {
return;
}
@@ -1050,7 +1138,7 @@
DPRINTF("interrupt recv status %d ep %02X id %u\n",
interrupt_receiving_status->status, ep, id);
- if (!dev->dev.attached) {
+ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) {
return;
}
@@ -1227,26 +1315,37 @@
}
}
-static struct USBDeviceInfo usbredir_dev_info = {
- .product_desc = "USB Redirection Device",
- .qdev.name = "usb-redir",
- .qdev.size = sizeof(USBRedirDevice),
- .init = usbredir_initfn,
- .handle_destroy = usbredir_handle_destroy,
- .handle_packet = usb_generic_handle_packet,
- .cancel_packet = usbredir_cancel_packet,
- .handle_reset = usbredir_handle_reset,
- .handle_data = usbredir_handle_data,
- .handle_control = usbredir_handle_control,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
- DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property usbredir_properties[] = {
+ DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
+ DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usbredir_class_initfn(ObjectClass *klass, void *data)
+{
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ uc->init = usbredir_initfn;
+ uc->product_desc = "USB Redirection Device";
+ uc->handle_destroy = usbredir_handle_destroy;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->cancel_packet = usbredir_cancel_packet;
+ uc->handle_reset = usbredir_handle_reset;
+ uc->handle_data = usbredir_handle_data;
+ uc->handle_control = usbredir_handle_control;
+ dc->props = usbredir_properties;
+}
+
+static TypeInfo usbredir_dev_info = {
+ .name = "usb-redir",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBRedirDevice),
+ .class_init = usbredir_class_initfn,
};
static void usbredir_register_devices(void)
{
- usb_qdev_register(&usbredir_dev_info);
+ type_register_static(&usbredir_dev_info);
}
device_init(usbredir_register_devices);
diff --git a/vl.c b/vl.c
index ba55b35..63dd725 100644
--- a/vl.c
+++ b/vl.c
@@ -201,7 +201,6 @@
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
int win2k_install_hack = 0;
-int rtc_td_hack = 0;
int usb_enabled = 0;
int singlestep = 0;
int smp_cpus = 1;
@@ -218,7 +217,6 @@
int no_shutdown = 0;
int cursor_hide = 1;
int graphic_rotate = 0;
-uint8_t irq0override = 1;
const char *watchdog;
QEMUOptionRom option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
@@ -271,7 +269,6 @@
static int default_parallel = 1;
static int default_virtcon = 1;
static int default_monitor = 1;
-static int default_vga = 1;
static int default_floppy = 1;
static int default_cdrom = 1;
static int default_sdcard = 1;
@@ -290,11 +287,6 @@
{ .driver = "virtio-serial-pci", .flag = &default_virtcon },
{ .driver = "virtio-serial-s390", .flag = &default_virtcon },
{ .driver = "virtio-serial", .flag = &default_virtcon },
- { .driver = "VGA", .flag = &default_vga },
- { .driver = "cirrus-vga", .flag = &default_vga },
- { .driver = "vmware-svga", .flag = &default_vga },
- { .driver = "isa-vga", .flag = &default_vga },
- { .driver = "qxl-vga", .flag = &default_vga },
};
static void res_free(void)
@@ -547,9 +539,18 @@
value = qemu_opt_get(opts, "driftfix");
if (value) {
if (!strcmp(value, "slew")) {
- rtc_td_hack = 1;
+ static GlobalProperty slew_lost_ticks[] = {
+ {
+ .driver = "mc146818rtc",
+ .property = "lost_tick_policy",
+ .value = "slew",
+ },
+ { /* end of list */ }
+ };
+
+ qdev_prop_register_global_list(slew_lost_ticks);
} else if (!strcmp(value, "none")) {
- rtc_td_hack = 0;
+ /* discard is default */
} else {
fprintf(stderr, "qemu: invalid option value '%s'\n", value);
exit(1);
@@ -1525,18 +1526,48 @@
#include "qemu-options-wrapper.h"
{ NULL },
};
+
+static bool vga_available(void)
+{
+ return qdev_exists("VGA") || qdev_exists("isa-vga");
+}
+
+static bool cirrus_vga_available(void)
+{
+ return qdev_exists("cirrus-vga") || qdev_exists("isa-cirrus-vga");
+}
+
+static bool vmware_vga_available(void)
+{
+ return qdev_exists("vmware-svga");
+}
+
static void select_vgahw (const char *p)
{
const char *opts;
- default_vga = 0;
vga_interface_type = VGA_NONE;
if (strstart(p, "std", &opts)) {
- vga_interface_type = VGA_STD;
+ if (vga_available()) {
+ vga_interface_type = VGA_STD;
+ } else {
+ fprintf(stderr, "Error: standard VGA not available\n");
+ exit(0);
+ }
} else if (strstart(p, "cirrus", &opts)) {
- vga_interface_type = VGA_CIRRUS;
+ if (cirrus_vga_available()) {
+ vga_interface_type = VGA_CIRRUS;
+ } else {
+ fprintf(stderr, "Error: Cirrus VGA not available\n");
+ exit(0);
+ }
} else if (strstart(p, "vmware", &opts)) {
- vga_interface_type = VGA_VMWARE;
+ if (vmware_vga_available()) {
+ vga_interface_type = VGA_VMWARE;
+ } else {
+ fprintf(stderr, "Error: VMWare SVGA not available\n");
+ exit(0);
+ }
} else if (strstart(p, "xenfb", &opts)) {
vga_interface_type = VGA_XENFB;
} else if (strstart(p, "qxl", &opts)) {
@@ -1916,7 +1947,11 @@
}
bus_opts = qemu_opts_create(device, NULL, 0);
- qemu_opt_set(bus_opts, "driver", "virtio-serial");
+ if (arch_type == QEMU_ARCH_S390X) {
+ qemu_opt_set(bus_opts, "driver", "virtio-serial-s390");
+ } else {
+ qemu_opt_set(bus_opts, "driver", "virtio-serial-pci");
+ }
dev_opts = qemu_opts_create(device, NULL, 0);
qemu_opt_set(dev_opts, "driver", "virtconsole");
@@ -2136,6 +2171,11 @@
free(mem);
}
+int qemu_init_main_loop(void)
+{
+ return main_loop_init();
+}
+
int main(int argc, char **argv, char **envp)
{
const char *gdbstub_dev = NULL;
@@ -2155,6 +2195,7 @@
const char *loadvm = NULL;
QEMUMachine *machine;
const char *cpu_model;
+ const char *vga_model = NULL;
const char *pid_file = NULL;
const char *incoming = NULL;
#ifdef CONFIG_VNC
@@ -2581,7 +2622,7 @@
rtc_utc = 0;
break;
case QEMU_OPTION_vga:
- select_vgahw (optarg);
+ vga_model = optarg;
break;
case QEMU_OPTION_g:
{
@@ -2812,9 +2853,19 @@
case QEMU_OPTION_win2k_hack:
win2k_install_hack = 1;
break;
- case QEMU_OPTION_rtc_td_hack:
- rtc_td_hack = 1;
+ case QEMU_OPTION_rtc_td_hack: {
+ static GlobalProperty slew_lost_ticks[] = {
+ {
+ .driver = "mc146818rtc",
+ .property = "lost_tick_policy",
+ .value = "slew",
+ },
+ { /* end of list */ }
+ };
+
+ qdev_prop_register_global_list(slew_lost_ticks);
break;
+ }
case QEMU_OPTION_acpitable:
do_acpitable_option(optarg);
break;
@@ -2978,11 +3029,11 @@
default_parallel = 0;
default_virtcon = 0;
default_monitor = 0;
- default_vga = 0;
default_net = 0;
default_floppy = 0;
default_cdrom = 0;
default_sdcard = 0;
+ vga_model = "none";
break;
case QEMU_OPTION_xen_domid:
if (!(xen_available())) {
@@ -3111,21 +3162,8 @@
* specified either by the configuration file or by the command line.
*/
if (machine->default_machine_opts) {
- QemuOptsList *list = qemu_find_opts("machine");
- const char *p = NULL;
-
- if (!QTAILQ_EMPTY(&list->head)) {
- p = qemu_opt_get(QTAILQ_FIRST(&list->head), "accel");
- }
- if (p == NULL) {
- qemu_opts_reset(list);
- opts = qemu_opts_parse(list, machine->default_machine_opts, 0);
- if (!opts) {
- fprintf(stderr, "parse error for machine %s: %s\n",
- machine->name, machine->default_machine_opts);
- exit(1);
- }
- }
+ qemu_opts_set_defaults(qemu_find_opts("machine"),
+ machine->default_machine_opts, 0);
}
qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0);
@@ -3140,9 +3178,6 @@
if (!machine->use_virtcon) {
default_virtcon = 0;
}
- if (machine->no_vga) {
- default_vga = 0;
- }
if (machine->no_floppy) {
default_floppy = 0;
}
@@ -3178,8 +3213,6 @@
if (default_virtcon)
add_device_config(DEV_VIRTCON, "vc:80Cx24C");
}
- if (default_vga)
- vga_interface_type = VGA_CIRRUS;
socket_init();
@@ -3330,6 +3363,15 @@
module_call_init(MODULE_INIT_DEVICE);
+ /* must be after qdev registration but before machine init */
+ if (vga_model) {
+ select_vgahw(vga_model);
+ } else if (cirrus_vga_available()) {
+ select_vgahw("cirrus");
+ } else {
+ select_vgahw("none");
+ }
+
if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
exit(0);
diff --git a/xen-all.c b/xen-all.c
index d1fc597..fd39168 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -447,7 +447,8 @@
j = ffsl(map) - 1;
map &= ~(1ul << j);
memory_region_set_dirty(framebuffer,
- (i * width + j) * TARGET_PAGE_SIZE);
+ (i * width + j) * TARGET_PAGE_SIZE,
+ TARGET_PAGE_SIZE);
};
}
}