Compare commits
310 Commits
pull-audio
...
pull-input
Author | SHA1 | Date | |
---|---|---|---|
|
47c03744b3 | ||
|
6f90f3d786 | ||
|
5643706a09 | ||
|
5c07d00f1b | ||
|
70b52f62b8 | ||
|
e842c68d44 | ||
|
a8dfb1c34f | ||
|
4a33f45e2e | ||
|
4798648e32 | ||
|
2d0755d21c | ||
|
16b0ecd168 | ||
|
faecd955ce | ||
|
c43ce5512f | ||
|
21bae11a39 | ||
|
2e08c665cc | ||
|
c751a74afe | ||
|
f100db385d | ||
|
14768eba46 | ||
|
3ab193e662 | ||
|
192f81bfce | ||
|
edd85a3d9e | ||
|
502c8db5b4 | ||
|
d3535431e8 | ||
|
43579403a3 | ||
|
cd10032888 | ||
|
de8f580b23 | ||
|
8d447d10b7 | ||
|
a25f545d68 | ||
|
af98ba92ac | ||
|
d2a9260335 | ||
|
9784e57930 | ||
|
6567147588 | ||
|
c8b405b679 | ||
|
8b6b0c59a6 | ||
|
bbd1b1cc25 | ||
|
031fa96439 | ||
|
7ad95ff76c | ||
|
d4c8533755 | ||
|
f55ea6297c | ||
|
ac458e121c | ||
|
e00ef747f0 | ||
|
4a29420ea1 | ||
|
4fd42afe61 | ||
|
c2cb92f9ea | ||
|
739aa555b8 | ||
|
d47e95c0c8 | ||
|
57f45b6207 | ||
|
b774539743 | ||
|
25a7017555 | ||
|
949ceeb31b | ||
|
56bed4135f | ||
|
a105acbce3 | ||
|
678e48a2e4 | ||
|
2fc0043283 | ||
|
7ad993b480 | ||
|
aabbd472a0 | ||
|
2c38b60010 | ||
|
c2216a8a7a | ||
|
ab22ad96ce | ||
|
357765fed5 | ||
|
25254a7191 | ||
|
cae8a9289b | ||
|
67d065c3db | ||
|
777872e5c6 | ||
|
cc99c6f5ff | ||
|
aa830cdc28 | ||
|
7edd9ddc97 | ||
|
8ead601883 | ||
|
c5d3c49896 | ||
|
55e7c29e46 | ||
|
0064aceb29 | ||
|
de580dafad | ||
|
1c884abede | ||
|
de92f3f86a | ||
|
ffe9fe3a25 | ||
|
4864512389 | ||
|
3eba13ec25 | ||
|
9147d019f3 | ||
|
69bef7931e | ||
|
4b350f1de1 | ||
|
0c762736df | ||
|
a9e6a0cbe2 | ||
|
adccfbcd60 | ||
|
1b37b3442f | ||
|
9a05feabd5 | ||
|
7d6dc7f30c | ||
|
4ab23a9182 | ||
|
b53ccc30c4 | ||
|
d12f57ec66 | ||
|
64cfba6a47 | ||
|
d0686c7291 | ||
|
298f116827 | ||
|
7aad248d35 | ||
|
607dacd0a0 | ||
|
4835ef7784 | ||
|
5d31babe5c | ||
|
fda053875e | ||
|
6a519918b3 | ||
|
b5ba1cc626 | ||
|
cb48da7f81 | ||
|
4e47e39ab0 | ||
|
d2fe51bda8 | ||
|
fbb0621a0f | ||
|
cd159d0954 | ||
|
d844a7b656 | ||
|
9fbee91a13 | ||
|
73795cea96 | ||
|
af87bf290f | ||
|
9eb08a435a | ||
|
ead4cf04f8 | ||
|
f9681f116c | ||
|
7f00eb30fe | ||
|
1eecf41b3e | ||
|
04c2b5168e | ||
|
f7d3e46676 | ||
|
49f5c9e98a | ||
|
0ca3611221 | ||
|
5d739a4787 | ||
|
d1028f1b5b | ||
|
c804c2a717 | ||
|
6fbef18a4c | ||
|
477a72a1ef | ||
|
65e526c24e | ||
|
e8803d93df | ||
|
6e25280216 | ||
|
a0fa2cb8cc | ||
|
9da45bb217 | ||
|
77319f2263 | ||
|
f2c55d1735 | ||
|
0788082a4b | ||
|
819bd3091e | ||
|
3a553fc658 | ||
|
216db403d0 | ||
|
2ce5868ca1 | ||
|
6f6831f61a | ||
|
bc3fbad816 | ||
|
28c05edff5 | ||
|
4b9430294e | ||
|
52aa17cbd8 | ||
|
82d0794565 | ||
|
13665a2d2f | ||
|
c04018e933 | ||
|
a5ae7e3984 | ||
|
432a0a130e | ||
|
1c8be73d4e | ||
|
c3143ba877 | ||
|
024c6e2ea5 | ||
|
63a31905cb | ||
|
eb0ecd5ad9 | ||
|
0956ff5a4e | ||
|
1f79ee32b5 | ||
|
34222fb810 | ||
|
9cfa0b4e4c | ||
|
4cc35614a0 | ||
|
1ed69e82b8 | ||
|
d9ea7d290b | ||
|
cd5c11b84b | ||
|
0b45451e58 | ||
|
e60cef860f | ||
|
a7adc4b779 | ||
|
4b7fff2fab | ||
|
327ed10fa2 | ||
|
a505d7fe5f | ||
|
cb2e37dffa | ||
|
5ebafdf31a | ||
|
b0fe242751 | ||
|
91e240698f | ||
|
168aa23bb0 | ||
|
8af35c37d2 | ||
|
cd4da63177 | ||
|
0eef9d9833 | ||
|
7da845b0f4 | ||
|
67ed771ded | ||
|
855011be05 | ||
|
1da41cc1c6 | ||
|
0a6a7ccaae | ||
|
d6032e06d1 | ||
|
876074c228 | ||
|
6453fa998a | ||
|
c10f7fc3d1 | ||
|
cf143ad350 | ||
|
fce0a82608 | ||
|
775fda92a1 | ||
|
cba933b225 | ||
|
106a73b6d2 | ||
|
ec1efab957 | ||
|
d5001cf787 | ||
|
d91a68a73b | ||
|
b8d4e1c43b | ||
|
29873712e6 | ||
|
13c9bfbfbb | ||
|
8174196b7f | ||
|
81cce07ec6 | ||
|
05a738c4ec | ||
|
aa0d1f4488 | ||
|
a89d97df1f | ||
|
ad37bb3b00 | ||
|
e3e48565c1 | ||
|
d6085e3ace | ||
|
41310c6878 | ||
|
6d3cb1f970 | ||
|
24a370ef23 | ||
|
aded6539d9 | ||
|
0459650d94 | ||
|
05fd3bf2a1 | ||
|
0a985b3727 | ||
|
f6c65bfb93 | ||
|
3bac80d31a | ||
|
cf528b8958 | ||
|
2e753bcc7d | ||
|
1f55ac4586 | ||
|
e96dfd110e | ||
|
6e50d18847 | ||
|
e7a1d6c52a | ||
|
c58e291591 | ||
|
6dedf0522c | ||
|
98b21dcdb3 | ||
|
9c70434f82 | ||
|
604e1f9cd0 | ||
|
676056d4f1 | ||
|
2c09eee112 | ||
|
a2e67072b7 | ||
|
d0fa1f0df3 | ||
|
e848dd4248 | ||
|
7c84259019 | ||
|
6502668237 | ||
|
b807b5ff89 | ||
|
e0db904d1d | ||
|
a749f42da5 | ||
|
10b7c5dd0d | ||
|
2c958923bc | ||
|
d9e1f574cb | ||
|
ff8adbcfdb | ||
|
4c1b8f1e83 | ||
|
d9738fd246 | ||
|
64cc22841e | ||
|
24d3bd67ac | ||
|
837c390137 | ||
|
7ef8cf9a08 | ||
|
703dd81aca | ||
|
c5f52875b9 | ||
|
6141f3bd69 | ||
|
8a87f3d722 | ||
|
c7fc5bc2a4 | ||
|
c88a1de51a | ||
|
98a7a38f81 | ||
|
1c508d174d | ||
|
a28e4c408b | ||
|
d55dee2044 | ||
|
95c6bff356 | ||
|
7db6982a19 | ||
|
f70d7f7e4d | ||
|
13e7956e31 | ||
|
cadebd7a2a | ||
|
27cec15e4e | ||
|
64757582da | ||
|
7841c76884 | ||
|
bae3f92a01 | ||
|
ae39c4b201 | ||
|
a33cc31d08 | ||
|
a283cb6e58 | ||
|
626f84f39d | ||
|
2dc8328b4c | ||
|
77386bf6eb | ||
|
7cc07ab8da | ||
|
5b7aa9b56d | ||
|
76abe4071d | ||
|
89ac8480a8 | ||
|
37f09e5e3d | ||
|
d1833ef52b | ||
|
a8842e6d2a | ||
|
c0f92b526d | ||
|
6890aad46b | ||
|
0fea6b7972 | ||
|
b6d5066d32 | ||
|
2a94fee3f6 | ||
|
f8d924e481 | ||
|
a7451cb850 | ||
|
24897a767b | ||
|
f2917853f7 | ||
|
35cb1748d5 | ||
|
537b41f501 | ||
|
c06b72781d | ||
|
77e8b9ca64 | ||
|
a69d9af449 | ||
|
f7d9fd8c72 | ||
|
5acd9d81e1 | ||
|
5469a2a688 | ||
|
d4446eae63 | ||
|
5d12aa63c7 | ||
|
2e40134bfd | ||
|
ddf5636dc9 | ||
|
f67503e5bd | ||
|
e6dc8a1f83 | ||
|
a71835a0cc | ||
|
521f438e36 | ||
|
58da5b1e01 | ||
|
15e8159e76 | ||
|
f966f9ddd1 | ||
|
66518bf668 | ||
|
d3399d7cf8 | ||
|
cc47569881 | ||
|
e3be6f0ecc | ||
|
e26110cfc6 | ||
|
17969268f5 | ||
|
13b6ce0ec9 | ||
|
6ebc91e5d0 | ||
|
5c0d52bcd3 | ||
|
ba1183da9a | ||
|
10f5bff622 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -66,6 +66,9 @@ libuser
|
||||
*.cp
|
||||
*.dvi
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.mo
|
||||
*.fn
|
||||
*.ky
|
||||
*.log
|
||||
|
@@ -726,7 +726,7 @@ F: vl.c
|
||||
|
||||
Human Monitor (HMP)
|
||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||
S: Supported
|
||||
S: Maintained
|
||||
F: monitor.c
|
||||
F: hmp.c
|
||||
F: hmp-commands.hx
|
||||
@@ -758,7 +758,7 @@ T: git git://github.com/bonzini/qemu.git nbd-next
|
||||
QAPI
|
||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
S: Supported
|
||||
S: Maintained
|
||||
F: qapi/
|
||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
||||
|
||||
@@ -772,7 +772,7 @@ T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
||||
|
||||
QMP
|
||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||
S: Supported
|
||||
S: Maintained
|
||||
F: qmp.c
|
||||
F: monitor.c
|
||||
F: qmp-commands.hx
|
||||
|
32
Makefile
32
Makefile
@@ -127,13 +127,29 @@ defconfig:
|
||||
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
endif
|
||||
|
||||
dummy := $(call unnest-vars,, \
|
||||
stub-obj-y \
|
||||
util-obj-y \
|
||||
qga-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
common-obj-y \
|
||||
common-obj-m)
|
||||
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
include $(SRC_PATH)/tests/Makefile
|
||||
endif
|
||||
ifeq ($(CONFIG_SMARTCARD_NSS),y)
|
||||
include $(SRC_PATH)/libcacard/Makefile
|
||||
endif
|
||||
|
||||
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
|
||||
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
|
||||
|
||||
config-host.h: config-host.h-timestamp
|
||||
config-host.h-timestamp: config-host.mak
|
||||
@@ -143,6 +159,7 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx
|
||||
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
|
||||
|
||||
$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
|
||||
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
|
||||
|
||||
subdir-%:
|
||||
@@ -192,6 +209,9 @@ Makefile: $(version-obj-y) $(version-lobj-y)
|
||||
libqemustub.a: $(stub-obj-y)
|
||||
libqemuutil.a: $(util-obj-y) qapi-types.o qapi-visit.o
|
||||
|
||||
block-modules = $(foreach o,$(block-obj-m),"$(basename $(subst /,-,$o))",) NULL
|
||||
util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)'
|
||||
|
||||
######################################################################
|
||||
|
||||
qemu-img.o: qemu-img-cmds.h
|
||||
@@ -247,6 +267,8 @@ clean:
|
||||
rm -f qemu-options.def
|
||||
find . -name '*.[oda]' -type f -exec rm -f {} +
|
||||
find . -name '*.l[oa]' -type f -exec rm -f {} +
|
||||
find . -name '*$(DSOSUF)' -type f -exec rm -f {} +
|
||||
find . -name '*.mo' -type f -exec rm -f {} +
|
||||
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||
rm -f fsdev/*.pod
|
||||
rm -rf .libs */.libs
|
||||
@@ -298,7 +320,7 @@ ifdef INSTALL_BLOBS
|
||||
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
|
||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
|
||||
acpi-dsdt.aml q35-acpi-dsdt.aml \
|
||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \
|
||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
|
||||
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
|
||||
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
|
||||
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
|
||||
@@ -354,6 +376,12 @@ install-datadir install-localstatedir
|
||||
ifneq ($(TOOLS),)
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||
endif
|
||||
ifneq ($(CONFIG_MODULES),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
||||
for s in $(patsubst %.mo,%$(DSOSUF),$(modules-m)); do \
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$${s//\//-}"; \
|
||||
done
|
||||
endif
|
||||
ifneq ($(HELPERS-y),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
|
||||
|
@@ -19,6 +19,8 @@ block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
|
||||
block-obj-y += qemu-coroutine-sleep.o
|
||||
block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o
|
||||
|
||||
block-obj-m = block/
|
||||
|
||||
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
|
||||
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
||||
# only pull in the actual virtio-9p device if we also enabled virtio.
|
||||
@@ -41,7 +43,7 @@ libcacard-y += libcacard/vcardt.o
|
||||
# single QEMU executable should support all CPUs and machines.
|
||||
|
||||
ifeq ($(CONFIG_SOFTMMU),y)
|
||||
common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
|
||||
common-obj-y = blockdev.o blockdev-nbd.o block/
|
||||
common-obj-y += net/
|
||||
common-obj-y += qdev-monitor.o device-hotplug.o
|
||||
common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
@@ -111,18 +113,3 @@ version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo
|
||||
# by libqemuutil.a. These should be moved to a separate .json schema.
|
||||
qga-obj-y = qga/ qapi-types.o qapi-visit.o
|
||||
qga-vss-dll-obj-y = qga/
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
|
||||
|
||||
QEMU_CFLAGS+=$(GLIB_CFLAGS)
|
||||
|
||||
nested-vars += \
|
||||
stub-obj-y \
|
||||
util-obj-y \
|
||||
qga-obj-y \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
common-obj-y
|
||||
dummy := $(call unnest-vars)
|
||||
|
@@ -130,8 +130,6 @@ else
|
||||
obj-y += hw/$(TARGET_BASE_ARCH)/
|
||||
endif
|
||||
|
||||
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
GENERATED_HEADERS += hmp-commands.h qmp-commands-old.h
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
@@ -139,13 +137,26 @@ endif # CONFIG_SOFTMMU
|
||||
# Workaround for http://gcc.gnu.org/PR55489, see configure.
|
||||
%/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS)
|
||||
|
||||
nested-vars += obj-y
|
||||
dummy := $(call unnest-vars,,obj-y)
|
||||
|
||||
# This resolves all nested paths, so it must come last
|
||||
# we are making another call to unnest-vars with different vars, protect obj-y,
|
||||
# it can be overriden in subdir Makefile.objs
|
||||
obj-y-save := $(obj-y)
|
||||
|
||||
block-obj-y :=
|
||||
common-obj-y :=
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
dummy := $(call unnest-vars,.., \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
common-obj-y \
|
||||
common-obj-m)
|
||||
|
||||
all-obj-y = $(obj-y)
|
||||
all-obj-y += $(addprefix ../, $(common-obj-y))
|
||||
# Now restore obj-y
|
||||
obj-y := $(obj-y-save)
|
||||
|
||||
all-obj-y = $(obj-y) $(common-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
|
||||
|
||||
ifndef CONFIG_HAIKU
|
||||
LIBS+=-lm
|
||||
|
64
arch_init.c
64
arch_init.c
@@ -122,7 +122,6 @@ static void check_guest_throttling(void);
|
||||
#define RAM_SAVE_FLAG_XBZRLE 0x40
|
||||
/* 0x80 is reserved in migration.h start with 0x100 next */
|
||||
|
||||
|
||||
static struct defconfig_file {
|
||||
const char *filename;
|
||||
/* Indicates it is an user config file (disabled by -no-user-config) */
|
||||
@@ -133,6 +132,7 @@ static struct defconfig_file {
|
||||
{ NULL }, /* end of list */
|
||||
};
|
||||
|
||||
static const uint8_t ZERO_TARGET_PAGE[TARGET_PAGE_SIZE];
|
||||
|
||||
int qemu_read_default_config_files(bool userconfig)
|
||||
{
|
||||
@@ -273,6 +273,34 @@ static size_t save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
|
||||
return size;
|
||||
}
|
||||
|
||||
/* This is the last block that we have visited serching for dirty pages
|
||||
*/
|
||||
static RAMBlock *last_seen_block;
|
||||
/* This is the last block from where we have sent data */
|
||||
static RAMBlock *last_sent_block;
|
||||
static ram_addr_t last_offset;
|
||||
static unsigned long *migration_bitmap;
|
||||
static uint64_t migration_dirty_pages;
|
||||
static uint32_t last_version;
|
||||
static bool ram_bulk_stage;
|
||||
|
||||
/* Update the xbzrle cache to reflect a page that's been sent as all 0.
|
||||
* The important thing is that a stale (not-yet-0'd) page be replaced
|
||||
* by the new data.
|
||||
* As a bonus, if the page wasn't in the cache it gets added so that
|
||||
* when a small write is made into the 0'd page it gets XBZRLE sent
|
||||
*/
|
||||
static void xbzrle_cache_zero_page(ram_addr_t current_addr)
|
||||
{
|
||||
if (ram_bulk_stage || !migrate_use_xbzrle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We don't care if this fails to allocate a new cache page
|
||||
* as long as it updated an old one */
|
||||
cache_insert(XBZRLE.cache, current_addr, ZERO_TARGET_PAGE);
|
||||
}
|
||||
|
||||
#define ENCODING_FLAG_XBZRLE 0x1
|
||||
|
||||
static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
||||
@@ -329,18 +357,6 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
|
||||
/* This is the last block that we have visited serching for dirty pages
|
||||
*/
|
||||
static RAMBlock *last_seen_block;
|
||||
/* This is the last block from where we have sent data */
|
||||
static RAMBlock *last_sent_block;
|
||||
static ram_addr_t last_offset;
|
||||
static unsigned long *migration_bitmap;
|
||||
static uint64_t migration_dirty_pages;
|
||||
static uint32_t last_version;
|
||||
static bool ram_bulk_stage;
|
||||
|
||||
static inline
|
||||
ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
|
||||
ram_addr_t start)
|
||||
@@ -512,6 +528,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
|
||||
} else {
|
||||
int ret;
|
||||
uint8_t *p;
|
||||
bool send_async = true;
|
||||
int cont = (block == last_sent_block) ?
|
||||
RAM_SAVE_FLAG_CONTINUE : 0;
|
||||
|
||||
@@ -522,6 +539,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
|
||||
ret = ram_control_save_page(f, block->offset,
|
||||
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
||||
|
||||
current_addr = block->offset + offset;
|
||||
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
||||
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
||||
if (bytes_sent > 0) {
|
||||
@@ -536,19 +554,35 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
|
||||
RAM_SAVE_FLAG_COMPRESS);
|
||||
qemu_put_byte(f, 0);
|
||||
bytes_sent++;
|
||||
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
||||
* page would be stale
|
||||
*/
|
||||
xbzrle_cache_zero_page(current_addr);
|
||||
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
||||
current_addr = block->offset + offset;
|
||||
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
|
||||
offset, cont, last_stage);
|
||||
if (!last_stage) {
|
||||
/* We must send exactly what's in the xbzrle cache
|
||||
* even if the page wasn't xbzrle compressed, so that
|
||||
* it's right next time.
|
||||
*/
|
||||
p = get_cached_data(XBZRLE.cache, current_addr);
|
||||
|
||||
/* Can't send this cached data async, since the cache page
|
||||
* might get updated before it gets to the wire
|
||||
*/
|
||||
send_async = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* XBZRLE overflow or normal page */
|
||||
if (bytes_sent == -1) {
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
||||
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
||||
if (send_async) {
|
||||
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
||||
} else {
|
||||
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
||||
}
|
||||
bytes_sent += TARGET_PAGE_SIZE;
|
||||
acct_info.norm_pages++;
|
||||
}
|
||||
|
@@ -566,7 +566,7 @@ CharDriverState *chr_baum_init(void)
|
||||
BaumDriverState *baum;
|
||||
CharDriverState *chr;
|
||||
brlapi_handle_t *handle;
|
||||
#ifdef CONFIG_SDL
|
||||
#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||
SDL_SysWMinfo info;
|
||||
#endif
|
||||
int tty;
|
||||
@@ -595,7 +595,7 @@ CharDriverState *chr_baum_init(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SDL
|
||||
#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||
memset(&info, 0, sizeof(info));
|
||||
SDL_VERSION(&info.version);
|
||||
if (SDL_GetWMInfo(&info))
|
||||
|
237
block.c
237
block.c
@@ -547,8 +547,9 @@ int get_tmp_filename(char *filename, int size)
|
||||
int fd;
|
||||
const char *tmpdir;
|
||||
tmpdir = getenv("TMPDIR");
|
||||
if (!tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
if (!tmpdir) {
|
||||
tmpdir = "/var/tmp";
|
||||
}
|
||||
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
@@ -955,53 +956,27 @@ free_and_fail:
|
||||
/*
|
||||
* Opens a file using a protocol (file, host_device, nbd, ...)
|
||||
*
|
||||
* options is a QDict of options to pass to the block drivers, or NULL for an
|
||||
* empty set of options. The reference to the QDict belongs to the block layer
|
||||
* after the call (even on failure), so if the caller intends to reuse the
|
||||
* dictionary, it needs to use QINCREF() before calling bdrv_file_open.
|
||||
* options is an indirect pointer to a QDict of options to pass to the block
|
||||
* drivers, or pointer to NULL for an empty set of options. If this function
|
||||
* takes ownership of the QDict reference, it will set *options to NULL;
|
||||
* otherwise, it will contain unused/unrecognized options after this function
|
||||
* returns. Then, the caller is responsible for freeing it. If it intends to
|
||||
* reuse the QDict, QINCREF() should be called beforehand.
|
||||
*/
|
||||
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
|
||||
const char *reference, QDict *options, int flags,
|
||||
Error **errp)
|
||||
static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
||||
QDict **options, int flags, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockDriver *drv;
|
||||
const char *drvname;
|
||||
bool allow_protocol_prefix = false;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
/* NULL means an empty set of options */
|
||||
if (options == NULL) {
|
||||
options = qdict_new();
|
||||
}
|
||||
|
||||
if (reference) {
|
||||
if (filename || qdict_size(options)) {
|
||||
error_setg(errp, "Cannot reference an existing block device with "
|
||||
"additional options or a new filename");
|
||||
return -EINVAL;
|
||||
}
|
||||
QDECREF(options);
|
||||
|
||||
bs = bdrv_lookup_bs(reference, reference, errp);
|
||||
if (!bs) {
|
||||
return -ENODEV;
|
||||
}
|
||||
bdrv_ref(bs);
|
||||
*pbs = bs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bs = bdrv_new("");
|
||||
bs->options = options;
|
||||
options = qdict_clone_shallow(options);
|
||||
|
||||
/* Fetch the file name from the options QDict if necessary */
|
||||
if (!filename) {
|
||||
filename = qdict_get_try_str(options, "filename");
|
||||
} else if (filename && !qdict_haskey(options, "filename")) {
|
||||
qdict_put(options, "filename", qstring_from_str(filename));
|
||||
filename = qdict_get_try_str(*options, "filename");
|
||||
} else if (filename && !qdict_haskey(*options, "filename")) {
|
||||
qdict_put(*options, "filename", qstring_from_str(filename));
|
||||
allow_protocol_prefix = true;
|
||||
} else {
|
||||
error_setg(errp, "Can't specify 'file' and 'filename' options at the "
|
||||
@@ -1011,13 +986,13 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
|
||||
}
|
||||
|
||||
/* Find the right block driver */
|
||||
drvname = qdict_get_try_str(options, "driver");
|
||||
drvname = qdict_get_try_str(*options, "driver");
|
||||
if (drvname) {
|
||||
drv = bdrv_find_format(drvname);
|
||||
if (!drv) {
|
||||
error_setg(errp, "Unknown driver '%s'", drvname);
|
||||
}
|
||||
qdict_del(options, "driver");
|
||||
qdict_del(*options, "driver");
|
||||
} else if (filename) {
|
||||
drv = bdrv_find_protocol(filename, allow_protocol_prefix);
|
||||
if (!drv) {
|
||||
@@ -1036,46 +1011,30 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
|
||||
|
||||
/* Parse the filename and open it */
|
||||
if (drv->bdrv_parse_filename && filename) {
|
||||
drv->bdrv_parse_filename(filename, options, &local_err);
|
||||
drv->bdrv_parse_filename(filename, *options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
qdict_del(options, "filename");
|
||||
qdict_del(*options, "filename");
|
||||
}
|
||||
|
||||
if (!drv->bdrv_file_open) {
|
||||
ret = bdrv_open(bs, filename, options, flags, drv, &local_err);
|
||||
options = NULL;
|
||||
ret = bdrv_open(&bs, filename, NULL, *options, flags, drv, &local_err);
|
||||
*options = NULL;
|
||||
} else {
|
||||
ret = bdrv_open_common(bs, NULL, options, flags, drv, &local_err);
|
||||
ret = bdrv_open_common(bs, NULL, *options, flags, drv, &local_err);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check if any unknown options were used */
|
||||
if (options && (qdict_size(options) != 0)) {
|
||||
const QDictEntry *entry = qdict_first(options);
|
||||
error_setg(errp, "Block protocol '%s' doesn't support the option '%s'",
|
||||
drv->format_name, entry->key);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
QDECREF(options);
|
||||
|
||||
bs->growable = 1;
|
||||
*pbs = bs;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
QDECREF(options);
|
||||
if (!bs->drv) {
|
||||
QDECREF(bs->options);
|
||||
}
|
||||
bdrv_unref(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1115,8 +1074,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
sizeof(backing_filename));
|
||||
}
|
||||
|
||||
bs->backing_hd = bdrv_new("");
|
||||
|
||||
if (bs->backing_format[0] != '\0') {
|
||||
back_drv = bdrv_find_format(bs->backing_format);
|
||||
}
|
||||
@@ -1125,11 +1082,11 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT |
|
||||
BDRV_O_COPY_ON_READ);
|
||||
|
||||
ret = bdrv_open(bs->backing_hd,
|
||||
*backing_filename ? backing_filename : NULL, options,
|
||||
assert(bs->backing_hd == NULL);
|
||||
ret = bdrv_open(&bs->backing_hd,
|
||||
*backing_filename ? backing_filename : NULL, NULL, options,
|
||||
back_flags, back_drv, &local_err);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(bs->backing_hd);
|
||||
bs->backing_hd = NULL;
|
||||
bs->open_flags |= BDRV_O_NO_BACKING;
|
||||
error_setg(errp, "Could not open backing file: %s",
|
||||
@@ -1153,10 +1110,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
* Opens a disk image whose options are given as BlockdevRef in another block
|
||||
* device's options.
|
||||
*
|
||||
* If force_raw is true, bdrv_file_open() will be used, thereby preventing any
|
||||
* image format auto-detection. If it is false and a filename is given,
|
||||
* bdrv_open() will be used for auto-detection.
|
||||
*
|
||||
* If allow_none is true, no image will be opened if filename is false and no
|
||||
* BlockdevRef is given. *pbs will remain unchanged and 0 will be returned.
|
||||
*
|
||||
@@ -1166,16 +1119,21 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
* BlockdevRef.
|
||||
*
|
||||
* The BlockdevRef will be removed from the options QDict.
|
||||
*
|
||||
* To conform with the behavior of bdrv_open(), *pbs has to be NULL.
|
||||
*/
|
||||
int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
||||
QDict *options, const char *bdref_key, int flags,
|
||||
bool force_raw, bool allow_none, Error **errp)
|
||||
bool allow_none, Error **errp)
|
||||
{
|
||||
QDict *image_options;
|
||||
int ret;
|
||||
char *bdref_key_dot;
|
||||
const char *reference;
|
||||
|
||||
assert(pbs);
|
||||
assert(*pbs == NULL);
|
||||
|
||||
bdref_key_dot = g_strdup_printf("%s.", bdref_key);
|
||||
qdict_extract_subqdict(options, &image_options, bdref_key_dot);
|
||||
g_free(bdref_key_dot);
|
||||
@@ -1192,30 +1150,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (filename && !force_raw) {
|
||||
/* If a filename is given and the block driver should be detected
|
||||
automatically (instead of using none), use bdrv_open() in order to do
|
||||
that auto-detection. */
|
||||
BlockDriverState *bs;
|
||||
|
||||
if (reference) {
|
||||
error_setg(errp, "Cannot reference an existing block device while "
|
||||
"giving a filename");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
bs = bdrv_new("");
|
||||
ret = bdrv_open(bs, filename, image_options, flags, NULL, errp);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(bs);
|
||||
} else {
|
||||
*pbs = bs;
|
||||
}
|
||||
} else {
|
||||
ret = bdrv_file_open(pbs, filename, reference, image_options, flags,
|
||||
errp);
|
||||
}
|
||||
ret = bdrv_open(pbs, filename, reference, image_options, flags, NULL, errp);
|
||||
|
||||
done:
|
||||
qdict_del(options, bdref_key);
|
||||
@@ -1229,17 +1164,58 @@ done:
|
||||
* empty set of options. The reference to the QDict belongs to the block layer
|
||||
* after the call (even on failure), so if the caller intends to reuse the
|
||||
* dictionary, it needs to use QINCREF() before calling bdrv_open.
|
||||
*
|
||||
* If *pbs is NULL, a new BDS will be created with a pointer to it stored there.
|
||||
* If it is not NULL, the referenced BDS will be reused.
|
||||
*
|
||||
* The reference parameter may be used to specify an existing block device which
|
||||
* should be opened. If specified, neither options nor a filename may be given,
|
||||
* nor can an existing BDS be reused (that is, *pbs has to be NULL).
|
||||
*/
|
||||
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
int flags, BlockDriver *drv, Error **errp)
|
||||
int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
const char *reference, QDict *options, int flags,
|
||||
BlockDriver *drv, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||
char tmp_filename[PATH_MAX + 1];
|
||||
BlockDriverState *file = NULL;
|
||||
BlockDriverState *file = NULL, *bs;
|
||||
const char *drvname;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(pbs);
|
||||
|
||||
if (reference) {
|
||||
bool options_non_empty = options ? qdict_size(options) : false;
|
||||
QDECREF(options);
|
||||
|
||||
if (*pbs) {
|
||||
error_setg(errp, "Cannot reuse an existing BDS when referencing "
|
||||
"another block device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (filename || options_non_empty) {
|
||||
error_setg(errp, "Cannot reference an existing block device with "
|
||||
"additional options or a new filename");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bs = bdrv_lookup_bs(reference, reference, errp);
|
||||
if (!bs) {
|
||||
return -ENODEV;
|
||||
}
|
||||
bdrv_ref(bs);
|
||||
*pbs = bs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*pbs) {
|
||||
bs = *pbs;
|
||||
} else {
|
||||
bs = bdrv_new("");
|
||||
}
|
||||
|
||||
/* NULL means an empty set of options */
|
||||
if (options == NULL) {
|
||||
options = qdict_new();
|
||||
@@ -1248,6 +1224,19 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
bs->options = options;
|
||||
options = qdict_clone_shallow(options);
|
||||
|
||||
if (flags & BDRV_O_PROTOCOL) {
|
||||
assert(!drv);
|
||||
ret = bdrv_file_open(bs, filename, &options, flags & ~BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (!ret) {
|
||||
goto done;
|
||||
} else if (bs->drv) {
|
||||
goto close_and_fail;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* For snapshot=on, create a temporary qcow2 overlay */
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
BlockDriverState *bs1;
|
||||
@@ -1260,12 +1249,11 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
instead of opening 'filename' directly */
|
||||
|
||||
/* Get the required size from the image */
|
||||
bs1 = bdrv_new("");
|
||||
QINCREF(options);
|
||||
ret = bdrv_open(bs1, filename, options, BDRV_O_NO_BACKING,
|
||||
bs1 = NULL;
|
||||
ret = bdrv_open(&bs1, filename, NULL, options, BDRV_O_NO_BACKING,
|
||||
drv, &local_err);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(bs1);
|
||||
goto fail;
|
||||
}
|
||||
total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
|
||||
@@ -1322,9 +1310,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
flags |= BDRV_O_ALLOW_RDWR;
|
||||
}
|
||||
|
||||
assert(file == NULL);
|
||||
ret = bdrv_open_image(&file, filename, options, "file",
|
||||
bdrv_open_flags(bs, flags | BDRV_O_UNMAP), true, true,
|
||||
&local_err);
|
||||
bdrv_open_flags(bs, flags | BDRV_O_UNMAP) |
|
||||
BDRV_O_PROTOCOL, true, &local_err);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -1377,12 +1366,18 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
/* Check if any unknown options were used */
|
||||
if (qdict_size(options) != 0) {
|
||||
if (options && (qdict_size(options) != 0)) {
|
||||
const QDictEntry *entry = qdict_first(options);
|
||||
error_setg(errp, "Block format '%s' used by device '%s' doesn't "
|
||||
"support the option '%s'", drv->format_name, bs->device_name,
|
||||
entry->key);
|
||||
if (flags & BDRV_O_PROTOCOL) {
|
||||
error_setg(errp, "Block protocol '%s' doesn't support the option "
|
||||
"'%s'", drv->format_name, entry->key);
|
||||
} else {
|
||||
error_setg(errp, "Block format '%s' used by device '%s' doesn't "
|
||||
"support the option '%s'", drv->format_name,
|
||||
bs->device_name, entry->key);
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
goto close_and_fail;
|
||||
@@ -1393,6 +1388,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
bdrv_dev_change_media_cb(bs, true);
|
||||
}
|
||||
|
||||
*pbs = bs;
|
||||
return 0;
|
||||
|
||||
unlink_and_fail:
|
||||
@@ -1406,13 +1402,24 @@ fail:
|
||||
QDECREF(bs->options);
|
||||
QDECREF(options);
|
||||
bs->options = NULL;
|
||||
if (!*pbs) {
|
||||
/* If *pbs is NULL, a new BDS has been created in this function and
|
||||
needs to be freed now. Otherwise, it does not need to be closed,
|
||||
since it has not really been opened yet. */
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
return ret;
|
||||
|
||||
close_and_fail:
|
||||
bdrv_close(bs);
|
||||
/* See fail path, but now the BDS has to be always closed */
|
||||
if (*pbs) {
|
||||
bdrv_close(bs);
|
||||
} else {
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
QDECREF(options);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -5290,9 +5297,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
back_flags =
|
||||
flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
|
||||
|
||||
bs = bdrv_new("");
|
||||
|
||||
ret = bdrv_open(bs, backing_file->value.s, NULL, back_flags,
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file->value.s, NULL, NULL, back_flags,
|
||||
backing_drv, &local_err);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not open '%s': %s",
|
||||
@@ -5300,7 +5306,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
bdrv_unref(bs);
|
||||
goto out;
|
||||
}
|
||||
bdrv_get_geometry(bs, &size);
|
||||
@@ -5416,11 +5421,7 @@ bool bdrv_is_first_non_filter(BlockDriverState *candidate)
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
bool perm;
|
||||
|
||||
if (!bs->file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
perm = bdrv_recurse_is_first_non_filter(bs->file, candidate);
|
||||
perm = bdrv_recurse_is_first_non_filter(bs, candidate);
|
||||
|
||||
/* candidate is the first non filter */
|
||||
if (perm) {
|
||||
|
@@ -3,6 +3,7 @@ block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-c
|
||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||
block-obj-y += qed-check.o
|
||||
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
|
||||
block-obj-$(CONFIG_QUORUM) += quorum.o
|
||||
block-obj-y += parallels.o blkdebug.o blkverify.o
|
||||
block-obj-y += snapshot.o qapi.o
|
||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||
@@ -24,4 +25,15 @@ common-obj-y += commit.o
|
||||
common-obj-y += mirror.o
|
||||
common-obj-y += backup.o
|
||||
|
||||
$(obj)/curl.o: QEMU_CFLAGS+=$(CURL_CFLAGS)
|
||||
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||
iscsi.o-libs := $(LIBISCSI_LIBS)
|
||||
curl.o-cflags := $(CURL_CFLAGS)
|
||||
curl.o-libs := $(CURL_LIBS)
|
||||
rbd.o-cflags := $(RBD_CFLAGS)
|
||||
rbd.o-libs := $(RBD_LIBS)
|
||||
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
|
||||
gluster.o-libs := $(GLUSTERFS_LIBS)
|
||||
ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
||||
ssh.o-libs := $(LIBSSH2_LIBS)
|
||||
qcow.o-libs := -lz
|
||||
linux-aio.o-libs := -laio
|
||||
|
@@ -410,8 +410,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->state = 1;
|
||||
|
||||
/* Open the backing file */
|
||||
assert(bs->file == NULL);
|
||||
ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
|
||||
flags, true, false, &local_err);
|
||||
flags | BDRV_O_PROTOCOL, false, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
|
@@ -135,16 +135,18 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* Open the raw file */
|
||||
assert(bs->file == NULL);
|
||||
ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options,
|
||||
"raw", flags, true, false, &local_err);
|
||||
"raw", flags | BDRV_O_PROTOCOL, false, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Open the test file */
|
||||
assert(s->test_file == NULL);
|
||||
ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), options,
|
||||
"test", flags, false, false, &local_err);
|
||||
"test", flags, false, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
s->test_file = NULL;
|
||||
@@ -171,110 +173,6 @@ static int64_t blkverify_getlength(BlockDriverState *bs)
|
||||
return bdrv_getlength(s->test_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that I/O vector contents are identical
|
||||
*
|
||||
* @a: I/O vector
|
||||
* @b: I/O vector
|
||||
* @ret: Offset to first mismatching byte or -1 if match
|
||||
*/
|
||||
static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
|
||||
{
|
||||
int i;
|
||||
ssize_t offset = 0;
|
||||
|
||||
assert(a->niov == b->niov);
|
||||
for (i = 0; i < a->niov; i++) {
|
||||
size_t len = 0;
|
||||
uint8_t *p = (uint8_t *)a->iov[i].iov_base;
|
||||
uint8_t *q = (uint8_t *)b->iov[i].iov_base;
|
||||
|
||||
assert(a->iov[i].iov_len == b->iov[i].iov_len);
|
||||
while (len < a->iov[i].iov_len && *p++ == *q++) {
|
||||
len++;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
|
||||
if (len != a->iov[i].iov_len) {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int src_index;
|
||||
struct iovec *src_iov;
|
||||
void *dest_base;
|
||||
} IOVectorSortElem;
|
||||
|
||||
static int sortelem_cmp_src_base(const void *a, const void *b)
|
||||
{
|
||||
const IOVectorSortElem *elem_a = a;
|
||||
const IOVectorSortElem *elem_b = b;
|
||||
|
||||
/* Don't overflow */
|
||||
if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
|
||||
return -1;
|
||||
} else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int sortelem_cmp_src_index(const void *a, const void *b)
|
||||
{
|
||||
const IOVectorSortElem *elem_a = a;
|
||||
const IOVectorSortElem *elem_b = b;
|
||||
|
||||
return elem_a->src_index - elem_b->src_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy contents of I/O vector
|
||||
*
|
||||
* The relative relationships of overlapping iovecs are preserved. This is
|
||||
* necessary to ensure identical semantics in the cloned I/O vector.
|
||||
*/
|
||||
static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src,
|
||||
void *buf)
|
||||
{
|
||||
IOVectorSortElem sortelems[src->niov];
|
||||
void *last_end;
|
||||
int i;
|
||||
|
||||
/* Sort by source iovecs by base address */
|
||||
for (i = 0; i < src->niov; i++) {
|
||||
sortelems[i].src_index = i;
|
||||
sortelems[i].src_iov = &src->iov[i];
|
||||
}
|
||||
qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base);
|
||||
|
||||
/* Allocate buffer space taking into account overlapping iovecs */
|
||||
last_end = NULL;
|
||||
for (i = 0; i < src->niov; i++) {
|
||||
struct iovec *cur = sortelems[i].src_iov;
|
||||
ptrdiff_t rewind = 0;
|
||||
|
||||
/* Detect overlap */
|
||||
if (last_end && last_end > cur->iov_base) {
|
||||
rewind = last_end - cur->iov_base;
|
||||
}
|
||||
|
||||
sortelems[i].dest_base = buf - rewind;
|
||||
buf += cur->iov_len - MIN(rewind, cur->iov_len);
|
||||
last_end = MAX(cur->iov_base + cur->iov_len, last_end);
|
||||
}
|
||||
|
||||
/* Sort by source iovec index and build destination iovec */
|
||||
qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index);
|
||||
for (i = 0; i < src->niov; i++) {
|
||||
qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len);
|
||||
}
|
||||
}
|
||||
|
||||
static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
|
||||
int64_t sector_num, QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
@@ -338,7 +236,7 @@ static void blkverify_aio_cb(void *opaque, int ret)
|
||||
|
||||
static void blkverify_verify_readv(BlkverifyAIOCB *acb)
|
||||
{
|
||||
ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
|
||||
ssize_t offset = qemu_iovec_compare(acb->qiov, &acb->raw_qiov);
|
||||
if (offset != -1) {
|
||||
blkverify_err(acb, "contents mismatch in sector %" PRId64,
|
||||
acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
|
||||
@@ -356,7 +254,7 @@ static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
|
||||
acb->verify = blkverify_verify_readv;
|
||||
acb->buf = qemu_blockalign(bs->file, qiov->size);
|
||||
qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
|
||||
blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
|
||||
qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
|
||||
|
||||
bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
|
@@ -129,7 +129,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
strcmp(bochs.subtype, GROWING_TYPE) ||
|
||||
((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
|
||||
(le32_to_cpu(bochs.version) != HEADER_V1))) {
|
||||
return -EMEDIUMTYPE;
|
||||
error_setg(errp, "Image not in Bochs format");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(bochs.version) == HEADER_V1) {
|
||||
|
16
block/cow.c
16
block/cow.c
@@ -74,7 +74,8 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (be32_to_cpu(cow_header.magic) != COW_MAGIC) {
|
||||
ret = -EMEDIUMTYPE;
|
||||
error_setg(errp, "Image not in COW format");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
char version[64];
|
||||
snprintf(version, sizeof(version),
|
||||
"COW version %d", cow_header.version);
|
||||
qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "cow", version);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
@@ -346,16 +347,15 @@ static int cow_create(const char *filename, QEMUOptionParameter *options,
|
||||
|
||||
ret = bdrv_create_file(filename, options, &local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&cow_bs, filename, NULL, NULL, BDRV_O_RDWR,
|
||||
&local_err);
|
||||
cow_bs = NULL;
|
||||
ret = bdrv_open(&cow_bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
13
block/curl.c
13
block/curl.c
@@ -456,30 +456,27 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
static int inited = 0;
|
||||
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
qerror_report(ERROR_CLASS_GENERIC_ERROR,
|
||||
"curl block device does not support writes");
|
||||
error_setg(errp, "curl block device does not support writes");
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
|
||||
if ((s->readahead_size & 0x1ff) != 0) {
|
||||
fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n",
|
||||
s->readahead_size);
|
||||
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
|
||||
s->readahead_size);
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
file = qemu_opt_get(opts, "url");
|
||||
if (file == NULL) {
|
||||
qerror_report(ERROR_CLASS_GENERIC_ERROR, "curl block driver requires "
|
||||
"an 'url' option");
|
||||
error_setg(errp, "curl block driver requires an 'url' option");
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
|
171
block/gluster.c
171
block/gluster.c
@@ -45,11 +45,13 @@ typedef struct GlusterConf {
|
||||
|
||||
static void qemu_gluster_gconf_free(GlusterConf *gconf)
|
||||
{
|
||||
g_free(gconf->server);
|
||||
g_free(gconf->volname);
|
||||
g_free(gconf->image);
|
||||
g_free(gconf->transport);
|
||||
g_free(gconf);
|
||||
if (gconf) {
|
||||
g_free(gconf->server);
|
||||
g_free(gconf->volname);
|
||||
g_free(gconf->image);
|
||||
g_free(gconf->transport);
|
||||
g_free(gconf);
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_volume_options(GlusterConf *gconf, char *path)
|
||||
@@ -127,7 +129,7 @@ static int qemu_gluster_parseuri(GlusterConf *gconf, const char *filename)
|
||||
}
|
||||
|
||||
/* transport */
|
||||
if (!strcmp(uri->scheme, "gluster")) {
|
||||
if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
|
||||
gconf->transport = g_strdup("tcp");
|
||||
} else if (!strcmp(uri->scheme, "gluster+tcp")) {
|
||||
gconf->transport = g_strdup("tcp");
|
||||
@@ -163,7 +165,7 @@ static int qemu_gluster_parseuri(GlusterConf *gconf, const char *filename)
|
||||
}
|
||||
gconf->server = g_strdup(qp->p[0].value);
|
||||
} else {
|
||||
gconf->server = g_strdup(uri->server);
|
||||
gconf->server = g_strdup(uri->server ? uri->server : "localhost");
|
||||
gconf->port = uri->port;
|
||||
}
|
||||
|
||||
@@ -175,7 +177,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename)
|
||||
static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
|
||||
Error **errp)
|
||||
{
|
||||
struct glfs *glfs = NULL;
|
||||
int ret;
|
||||
@@ -183,8 +186,8 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename)
|
||||
|
||||
ret = qemu_gluster_parseuri(gconf, filename);
|
||||
if (ret < 0) {
|
||||
error_report("Usage: file=gluster[+transport]://[server[:port]]/"
|
||||
"volname/image[?socket=...]");
|
||||
error_setg(errp, "Usage: file=gluster[+transport]://[server[:port]]/"
|
||||
"volname/image[?socket=...]");
|
||||
errno = -ret;
|
||||
goto out;
|
||||
}
|
||||
@@ -211,9 +214,11 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename)
|
||||
|
||||
ret = glfs_init(glfs);
|
||||
if (ret) {
|
||||
error_report("Gluster connection failed for server=%s port=%d "
|
||||
"volume=%s image=%s transport=%s", gconf->server, gconf->port,
|
||||
gconf->volname, gconf->image, gconf->transport);
|
||||
error_setg_errno(errp, errno,
|
||||
"Gluster connection failed for server=%s port=%d "
|
||||
"volume=%s image=%s transport=%s", gconf->server,
|
||||
gconf->port, gconf->volname, gconf->image,
|
||||
gconf->transport);
|
||||
goto out;
|
||||
}
|
||||
return glfs;
|
||||
@@ -269,11 +274,28 @@ static QemuOptsList runtime_opts = {
|
||||
},
|
||||
};
|
||||
|
||||
static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
|
||||
{
|
||||
assert(open_flags != NULL);
|
||||
|
||||
*open_flags |= O_BINARY;
|
||||
|
||||
if (bdrv_flags & BDRV_O_RDWR) {
|
||||
*open_flags |= O_RDWR;
|
||||
} else {
|
||||
*open_flags |= O_RDONLY;
|
||||
}
|
||||
|
||||
if ((bdrv_flags & BDRV_O_NOCACHE)) {
|
||||
*open_flags |= O_DIRECT;
|
||||
}
|
||||
}
|
||||
|
||||
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
||||
int bdrv_flags, Error **errp)
|
||||
{
|
||||
BDRVGlusterState *s = bs->opaque;
|
||||
int open_flags = O_BINARY;
|
||||
int open_flags = 0;
|
||||
int ret = 0;
|
||||
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
|
||||
QemuOpts *opts;
|
||||
@@ -283,29 +305,20 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
filename = qemu_opt_get(opts, "filename");
|
||||
|
||||
s->glfs = qemu_gluster_init(gconf, filename);
|
||||
s->glfs = qemu_gluster_init(gconf, filename, errp);
|
||||
if (!s->glfs) {
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bdrv_flags & BDRV_O_RDWR) {
|
||||
open_flags |= O_RDWR;
|
||||
} else {
|
||||
open_flags |= O_RDONLY;
|
||||
}
|
||||
|
||||
if ((bdrv_flags & BDRV_O_NOCACHE)) {
|
||||
open_flags |= O_DIRECT;
|
||||
}
|
||||
qemu_gluster_parse_flags(bdrv_flags, &open_flags);
|
||||
|
||||
s->fd = glfs_open(s->glfs, gconf->image, open_flags);
|
||||
if (!s->fd) {
|
||||
@@ -327,6 +340,96 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct BDRVGlusterReopenState {
|
||||
struct glfs *glfs;
|
||||
struct glfs_fd *fd;
|
||||
} BDRVGlusterReopenState;
|
||||
|
||||
|
||||
static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
||||
BlockReopenQueue *queue, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
BDRVGlusterReopenState *reop_s;
|
||||
GlusterConf *gconf = NULL;
|
||||
int open_flags = 0;
|
||||
|
||||
assert(state != NULL);
|
||||
assert(state->bs != NULL);
|
||||
|
||||
state->opaque = g_malloc0(sizeof(BDRVGlusterReopenState));
|
||||
reop_s = state->opaque;
|
||||
|
||||
qemu_gluster_parse_flags(state->flags, &open_flags);
|
||||
|
||||
gconf = g_malloc0(sizeof(GlusterConf));
|
||||
|
||||
reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, errp);
|
||||
if (reop_s->glfs == NULL) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
reop_s->fd = glfs_open(reop_s->glfs, gconf->image, open_flags);
|
||||
if (reop_s->fd == NULL) {
|
||||
/* reops->glfs will be cleaned up in _abort */
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
/* state->opaque will be freed in either the _abort or _commit */
|
||||
qemu_gluster_gconf_free(gconf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qemu_gluster_reopen_commit(BDRVReopenState *state)
|
||||
{
|
||||
BDRVGlusterReopenState *reop_s = state->opaque;
|
||||
BDRVGlusterState *s = state->bs->opaque;
|
||||
|
||||
|
||||
/* close the old */
|
||||
if (s->fd) {
|
||||
glfs_close(s->fd);
|
||||
}
|
||||
if (s->glfs) {
|
||||
glfs_fini(s->glfs);
|
||||
}
|
||||
|
||||
/* use the newly opened image / connection */
|
||||
s->fd = reop_s->fd;
|
||||
s->glfs = reop_s->glfs;
|
||||
|
||||
g_free(state->opaque);
|
||||
state->opaque = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void qemu_gluster_reopen_abort(BDRVReopenState *state)
|
||||
{
|
||||
BDRVGlusterReopenState *reop_s = state->opaque;
|
||||
|
||||
if (reop_s == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reop_s->fd) {
|
||||
glfs_close(reop_s->fd);
|
||||
}
|
||||
|
||||
if (reop_s->glfs) {
|
||||
glfs_fini(reop_s->glfs);
|
||||
}
|
||||
|
||||
g_free(state->opaque);
|
||||
state->opaque = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||
static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||
@@ -389,9 +492,9 @@ static int qemu_gluster_create(const char *filename,
|
||||
int64_t total_size = 0;
|
||||
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
|
||||
|
||||
glfs = qemu_gluster_init(gconf, filename);
|
||||
glfs = qemu_gluster_init(gconf, filename, errp);
|
||||
if (!glfs) {
|
||||
ret = -errno;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -617,6 +720,9 @@ static BlockDriver bdrv_gluster = {
|
||||
.instance_size = sizeof(BDRVGlusterState),
|
||||
.bdrv_needs_filename = true,
|
||||
.bdrv_file_open = qemu_gluster_open,
|
||||
.bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
|
||||
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
|
||||
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
|
||||
.bdrv_close = qemu_gluster_close,
|
||||
.bdrv_create = qemu_gluster_create,
|
||||
.bdrv_getlength = qemu_gluster_getlength,
|
||||
@@ -641,6 +747,9 @@ static BlockDriver bdrv_gluster_tcp = {
|
||||
.instance_size = sizeof(BDRVGlusterState),
|
||||
.bdrv_needs_filename = true,
|
||||
.bdrv_file_open = qemu_gluster_open,
|
||||
.bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
|
||||
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
|
||||
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
|
||||
.bdrv_close = qemu_gluster_close,
|
||||
.bdrv_create = qemu_gluster_create,
|
||||
.bdrv_getlength = qemu_gluster_getlength,
|
||||
@@ -665,6 +774,9 @@ static BlockDriver bdrv_gluster_unix = {
|
||||
.instance_size = sizeof(BDRVGlusterState),
|
||||
.bdrv_needs_filename = true,
|
||||
.bdrv_file_open = qemu_gluster_open,
|
||||
.bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
|
||||
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
|
||||
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
|
||||
.bdrv_close = qemu_gluster_close,
|
||||
.bdrv_create = qemu_gluster_create,
|
||||
.bdrv_getlength = qemu_gluster_getlength,
|
||||
@@ -689,6 +801,9 @@ static BlockDriver bdrv_gluster_rdma = {
|
||||
.instance_size = sizeof(BDRVGlusterState),
|
||||
.bdrv_needs_filename = true,
|
||||
.bdrv_file_open = qemu_gluster_open,
|
||||
.bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
|
||||
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
|
||||
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
|
||||
.bdrv_close = qemu_gluster_close,
|
||||
.bdrv_create = qemu_gluster_create,
|
||||
.bdrv_getlength = qemu_gluster_getlength,
|
||||
|
263
block/iscsi.c
263
block/iscsi.c
@@ -145,12 +145,13 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
|
||||
if (iTask->retries-- > 0 && status == SCSI_STATUS_CHECK_CONDITION
|
||||
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
|
||||
error_report("iSCSI CheckCondition: %s", iscsi_get_error(iscsi));
|
||||
iTask->do_retry = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI: Failure. %s", iscsi_get_error(iscsi));
|
||||
error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -325,6 +326,7 @@ retry:
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -399,6 +401,7 @@ retry:
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -433,6 +436,7 @@ retry:
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -683,6 +687,7 @@ retry:
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -767,6 +772,7 @@ retry:
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -830,24 +836,26 @@ retry:
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
||||
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
||||
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
||||
/* WRITE SAME is not supported by the target */
|
||||
iscsilun->has_write_same = false;
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
||||
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
||||
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
||||
/* WRITE SAME is not supported by the target */
|
||||
iscsilun->has_write_same = false;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -856,7 +864,8 @@ retry:
|
||||
|
||||
#endif /* SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED */
|
||||
|
||||
static int parse_chap(struct iscsi_context *iscsi, const char *target)
|
||||
static void parse_chap(struct iscsi_context *iscsi, const char *target,
|
||||
Error **errp)
|
||||
{
|
||||
QemuOptsList *list;
|
||||
QemuOpts *opts;
|
||||
@@ -865,37 +874,35 @@ static int parse_chap(struct iscsi_context *iscsi, const char *target)
|
||||
|
||||
list = qemu_find_opts("iscsi");
|
||||
if (!list) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
opts = qemu_opts_find(list, target);
|
||||
if (opts == NULL) {
|
||||
opts = QTAILQ_FIRST(&list->head);
|
||||
if (!opts) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
user = qemu_opt_get(opts, "user");
|
||||
if (!user) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
password = qemu_opt_get(opts, "password");
|
||||
if (!password) {
|
||||
error_report("CHAP username specified but no password was given");
|
||||
return -1;
|
||||
error_setg(errp, "CHAP username specified but no password was given");
|
||||
return;
|
||||
}
|
||||
|
||||
if (iscsi_set_initiator_username_pwd(iscsi, user, password)) {
|
||||
error_report("Failed to set initiator username and password");
|
||||
return -1;
|
||||
error_setg(errp, "Failed to set initiator username and password");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_header_digest(struct iscsi_context *iscsi, const char *target)
|
||||
static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
|
||||
Error **errp)
|
||||
{
|
||||
QemuOptsList *list;
|
||||
QemuOpts *opts;
|
||||
@@ -928,7 +935,7 @@ static void parse_header_digest(struct iscsi_context *iscsi, const char *target)
|
||||
} else if (!strcmp(digest, "NONE-CRC32C")) {
|
||||
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
|
||||
} else {
|
||||
error_report("Invalid header-digest setting : %s", digest);
|
||||
error_setg(errp, "Invalid header-digest setting : %s", digest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -986,12 +993,11 @@ static void iscsi_nop_timed_event(void *opaque)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
|
||||
static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
|
||||
{
|
||||
struct scsi_task *task = NULL;
|
||||
struct scsi_readcapacity10 *rc10 = NULL;
|
||||
struct scsi_readcapacity16 *rc16 = NULL;
|
||||
int ret = 0;
|
||||
int retries = ISCSI_CMD_RETRIES;
|
||||
|
||||
do {
|
||||
@@ -1006,8 +1012,7 @@ static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
|
||||
if (task != NULL && task->status == SCSI_STATUS_GOOD) {
|
||||
rc16 = scsi_datain_unmarshall(task);
|
||||
if (rc16 == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
|
||||
ret = -EINVAL;
|
||||
error_setg(errp, "iSCSI: Failed to unmarshall readcapacity16 data.");
|
||||
} else {
|
||||
iscsilun->block_size = rc16->block_length;
|
||||
iscsilun->num_blocks = rc16->returned_lba + 1;
|
||||
@@ -1021,8 +1026,7 @@ static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
|
||||
if (task != NULL && task->status == SCSI_STATUS_GOOD) {
|
||||
rc10 = scsi_datain_unmarshall(task);
|
||||
if (rc10 == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
||||
ret = -EINVAL;
|
||||
error_setg(errp, "iSCSI: Failed to unmarshall readcapacity10 data.");
|
||||
} else {
|
||||
iscsilun->block_size = rc10->block_size;
|
||||
if (rc10->lba == 0) {
|
||||
@@ -1035,20 +1039,18 @@ static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
} while (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION
|
||||
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION
|
||||
&& retries-- > 0);
|
||||
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI: failed to send readcapacity10 command.");
|
||||
ret = -EINVAL;
|
||||
error_setg(errp, "iSCSI: failed to send readcapacity10 command.");
|
||||
}
|
||||
if (task) {
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO Convert to fine grained options */
|
||||
@@ -1065,35 +1067,41 @@ static QemuOptsList runtime_opts = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi,
|
||||
int lun, int evpd, int pc) {
|
||||
int full_size;
|
||||
struct scsi_task *task = NULL;
|
||||
task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, 64);
|
||||
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
||||
int evpd, int pc, void **inq, Error **errp)
|
||||
{
|
||||
int full_size;
|
||||
struct scsi_task *task = NULL;
|
||||
task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, 64);
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
goto fail;
|
||||
}
|
||||
full_size = scsi_datain_getfullsize(task);
|
||||
if (full_size > task->datain.size) {
|
||||
scsi_free_scsi_task(task);
|
||||
|
||||
/* we need more data for the full list */
|
||||
task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, full_size);
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
goto fail;
|
||||
}
|
||||
full_size = scsi_datain_getfullsize(task);
|
||||
if (full_size > task->datain.size) {
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
|
||||
/* we need more data for the full list */
|
||||
task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, full_size);
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
*inq = scsi_datain_unmarshall(task);
|
||||
if (*inq == NULL) {
|
||||
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return task;
|
||||
return task;
|
||||
|
||||
fail:
|
||||
error_report("iSCSI: Inquiry command failed : %s",
|
||||
iscsi_get_error(iscsi));
|
||||
if (task) {
|
||||
scsi_free_scsi_task(task);
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
||||
iscsi_get_error(iscsi));
|
||||
if (task != NULL) {
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1112,34 +1120,33 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
struct iscsi_url *iscsi_url = NULL;
|
||||
struct scsi_task *task = NULL;
|
||||
struct scsi_inquiry_standard *inq = NULL;
|
||||
struct scsi_inquiry_supported_pages *inq_vpd;
|
||||
char *initiator_name = NULL;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename;
|
||||
int ret;
|
||||
int i, ret;
|
||||
|
||||
if ((BDRV_SECTOR_SIZE % 512) != 0) {
|
||||
error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
|
||||
"BDRV_SECTOR_SIZE(%lld) is not a multiple "
|
||||
"of 512", BDRV_SECTOR_SIZE);
|
||||
error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
|
||||
"BDRV_SECTOR_SIZE(%lld) is not a multiple "
|
||||
"of 512", BDRV_SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
filename = qemu_opt_get(opts, "filename");
|
||||
|
||||
|
||||
iscsi_url = iscsi_parse_full_url(iscsi, filename);
|
||||
if (iscsi_url == NULL) {
|
||||
error_report("Failed to parse URL : %s", filename);
|
||||
error_setg(errp, "Failed to parse URL : %s", filename);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1150,13 +1157,13 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
iscsi = iscsi_create_context(initiator_name);
|
||||
if (iscsi == NULL) {
|
||||
error_report("iSCSI: Failed to create iSCSI context.");
|
||||
error_setg(errp, "iSCSI: Failed to create iSCSI context.");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
|
||||
error_report("iSCSI: Failed to set target name.");
|
||||
error_setg(errp, "iSCSI: Failed to set target name.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1165,21 +1172,22 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
|
||||
iscsi_url->passwd);
|
||||
if (ret != 0) {
|
||||
error_report("Failed to set initiator username and password");
|
||||
error_setg(errp, "Failed to set initiator username and password");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we got CHAP username/password via the options */
|
||||
if (parse_chap(iscsi, iscsi_url->target) != 0) {
|
||||
error_report("iSCSI: Failed to set CHAP user/password");
|
||||
parse_chap(iscsi, iscsi_url->target, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
|
||||
error_report("iSCSI: Failed to set session type to normal.");
|
||||
error_setg(errp, "iSCSI: Failed to set session type to normal.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1187,10 +1195,15 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
|
||||
|
||||
/* check if we got HEADER_DIGEST via the options */
|
||||
parse_header_digest(iscsi, iscsi_url->target);
|
||||
parse_header_digest(iscsi, iscsi_url->target, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
|
||||
error_report("iSCSI: Failed to connect to LUN : %s",
|
||||
error_setg(errp, "iSCSI: Failed to connect to LUN : %s",
|
||||
iscsi_get_error(iscsi));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@@ -1198,26 +1211,21 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
iscsilun->iscsi = iscsi;
|
||||
iscsilun->lun = iscsi_url->lun;
|
||||
|
||||
task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
|
||||
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI: failed to send inquiry command.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
inq = scsi_datain_unmarshall(task);
|
||||
if (inq == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall inquiry data.");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
iscsilun->type = inq->periperal_device_type;
|
||||
iscsilun->has_write_same = true;
|
||||
|
||||
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
|
||||
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 0, 0,
|
||||
(void **) &inq, errp);
|
||||
if (task == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
iscsilun->type = inq->periperal_device_type;
|
||||
scsi_free_scsi_task(task);
|
||||
task = NULL;
|
||||
|
||||
iscsi_readcapacity_sync(iscsilun, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
}
|
||||
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
||||
@@ -1232,45 +1240,48 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
bs->sg = 1;
|
||||
}
|
||||
|
||||
if (iscsilun->lbpme) {
|
||||
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||
SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES,
|
||||
(void **) &inq_vpd, errp);
|
||||
if (task == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < inq_vpd->num_pages; i++) {
|
||||
struct scsi_task *inq_task;
|
||||
struct scsi_inquiry_logical_block_provisioning *inq_lbp;
|
||||
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||
SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING);
|
||||
if (task == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
inq_lbp = scsi_datain_unmarshall(task);
|
||||
if (inq_lbp == NULL) {
|
||||
error_report("iSCSI: failed to unmarshall inquiry datain blob");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(&iscsilun->lbp, inq_lbp,
|
||||
sizeof(struct scsi_inquiry_logical_block_provisioning));
|
||||
scsi_free_scsi_task(task);
|
||||
task = NULL;
|
||||
}
|
||||
|
||||
if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
|
||||
struct scsi_inquiry_block_limits *inq_bl;
|
||||
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||
SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS);
|
||||
if (task == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
switch (inq_vpd->pages[i]) {
|
||||
case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
|
||||
inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||
SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
|
||||
(void **) &inq_lbp, errp);
|
||||
if (inq_task == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(&iscsilun->lbp, inq_lbp,
|
||||
sizeof(struct scsi_inquiry_logical_block_provisioning));
|
||||
scsi_free_scsi_task(inq_task);
|
||||
break;
|
||||
case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
|
||||
inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||
SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS,
|
||||
(void **) &inq_bl, errp);
|
||||
if (inq_task == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(&iscsilun->bl, inq_bl,
|
||||
sizeof(struct scsi_inquiry_block_limits));
|
||||
scsi_free_scsi_task(inq_task);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
inq_bl = scsi_datain_unmarshall(task);
|
||||
if (inq_bl == NULL) {
|
||||
error_report("iSCSI: failed to unmarshall inquiry datain blob");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(&iscsilun->bl, inq_bl,
|
||||
sizeof(struct scsi_inquiry_block_limits));
|
||||
scsi_free_scsi_task(task);
|
||||
task = NULL;
|
||||
}
|
||||
scsi_free_scsi_task(task);
|
||||
task = NULL;
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||
/* Set up a timer for sending out iSCSI NOPs */
|
||||
@@ -1353,14 +1364,16 @@ static int iscsi_reopen_prepare(BDRVReopenState *state,
|
||||
static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
int ret = 0;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (iscsilun->type != TYPE_DISK) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
|
||||
return ret;
|
||||
iscsi_readcapacity_sync(iscsilun, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_free(local_err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (offset > iscsi_getlength(bs)) {
|
||||
|
43
block/nbd.c
43
block/nbd.c
@@ -188,31 +188,28 @@ out:
|
||||
g_free(file);
|
||||
}
|
||||
|
||||
static int nbd_config(BDRVNBDState *s, QDict *options, char **export)
|
||||
static void nbd_config(BDRVNBDState *s, QDict *options, char **export,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (qdict_haskey(options, "path")) {
|
||||
if (qdict_haskey(options, "host")) {
|
||||
qerror_report(ERROR_CLASS_GENERIC_ERROR, "path and host may not "
|
||||
"be used at the same time.");
|
||||
return -EINVAL;
|
||||
if (qdict_haskey(options, "path") == qdict_haskey(options, "host")) {
|
||||
if (qdict_haskey(options, "path")) {
|
||||
error_setg(errp, "path and host may not be used at the same time.");
|
||||
} else {
|
||||
error_setg(errp, "one of path and host must be specified.");
|
||||
}
|
||||
s->client.is_unix = true;
|
||||
} else if (qdict_haskey(options, "host")) {
|
||||
s->client.is_unix = false;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
s->client.is_unix = qdict_haskey(options, "path");
|
||||
s->socket_opts = qemu_opts_create(&socket_optslist, NULL, 0,
|
||||
&error_abort);
|
||||
|
||||
qemu_opts_absorb_qdict(s->socket_opts, options, &local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
return -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qemu_opt_get(s->socket_opts, "port")) {
|
||||
@@ -223,19 +220,17 @@ static int nbd_config(BDRVNBDState *s, QDict *options, char **export)
|
||||
if (*export) {
|
||||
qdict_del(options, "export");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nbd_establish_connection(BlockDriverState *bs)
|
||||
static int nbd_establish_connection(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
int sock;
|
||||
|
||||
if (s->client.is_unix) {
|
||||
sock = unix_socket_outgoing(qemu_opt_get(s->socket_opts, "path"));
|
||||
sock = unix_connect_opts(s->socket_opts, errp, NULL, NULL);
|
||||
} else {
|
||||
sock = tcp_socket_outgoing_opts(s->socket_opts);
|
||||
sock = inet_connect_opts(s->socket_opts, errp, NULL, NULL);
|
||||
if (sock >= 0) {
|
||||
socket_set_nodelay(sock);
|
||||
}
|
||||
@@ -256,17 +251,19 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
char *export = NULL;
|
||||
int result, sock;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* Pop the config into our state object. Exit if invalid. */
|
||||
result = nbd_config(s, options, &export);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
nbd_config(s, options, &export, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* establish TCP connection, return error if it fails
|
||||
* TODO: Configurable retry-until-timeout behaviour.
|
||||
*/
|
||||
sock = nbd_establish_connection(bs);
|
||||
sock = nbd_establish_connection(bs, errp);
|
||||
if (sock < 0) {
|
||||
return sock;
|
||||
}
|
||||
|
@@ -85,7 +85,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
|
||||
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
|
||||
ret = -EMEDIUMTYPE;
|
||||
error_setg(errp, "Image not in Parallels format");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
20
block/qcow.c
20
block/qcow.c
@@ -113,23 +113,26 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
be64_to_cpus(&header.l1_table_offset);
|
||||
|
||||
if (header.magic != QCOW_MAGIC) {
|
||||
ret = -EMEDIUMTYPE;
|
||||
error_setg(errp, "Image not in qcow format");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
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);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "qcow", version);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.size <= 1 || header.cluster_bits < 9) {
|
||||
error_setg(errp, "invalid value in qcow header");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
error_setg(errp, "invalid encryption method in qcow header");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -686,16 +689,15 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options,
|
||||
|
||||
ret = bdrv_create_file(filename, options, &local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&qcow_bs, filename, NULL, NULL, BDRV_O_RDWR,
|
||||
&local_err);
|
||||
qcow_bs = NULL;
|
||||
ret = bdrv_open(&qcow_bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -1367,13 +1367,31 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t old_offset;
|
||||
|
||||
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
||||
if ((old_offset & L2E_OFFSET_MASK) == 0) {
|
||||
|
||||
/*
|
||||
* Make sure that a discarded area reads back as zeroes for v3 images
|
||||
* (we cannot do it for v2 without actually writing a zero-filled
|
||||
* buffer). We can skip the operation if the cluster is already marked
|
||||
* as zero, or if it's unallocated and we don't have a backing file.
|
||||
*
|
||||
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
||||
* holding s->lock, so that doesn't work today.
|
||||
*/
|
||||
if (old_offset & QCOW_OFLAG_ZERO) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((old_offset & L2E_OFFSET_MASK) == 0 && !bs->backing_hd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* First remove L2 entries */
|
||||
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
|
||||
l2_table[l2_index + i] = cpu_to_be64(0);
|
||||
if (s->qcow_version >= 3) {
|
||||
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
|
||||
} else {
|
||||
l2_table[l2_index + i] = cpu_to_be64(0);
|
||||
}
|
||||
|
||||
/* Then decrease the refcount */
|
||||
qcow2_free_any_clusters(bs, old_offset, 1, type);
|
||||
|
@@ -449,7 +449,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
if (header.magic != QCOW_MAGIC) {
|
||||
error_setg(errp, "Image is not in qcow2 format");
|
||||
ret = -EMEDIUMTYPE;
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (header.version < 2 || header.version > 3) {
|
||||
@@ -1493,7 +1493,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
|
||||
NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
@@ -1543,7 +1545,8 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
goto out;
|
||||
}
|
||||
|
||||
bdrv_close(bs);
|
||||
bdrv_unref(bs);
|
||||
bs = NULL;
|
||||
|
||||
/*
|
||||
* And now open the image and make it consistent first (i.e. increase the
|
||||
@@ -1552,7 +1555,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
*/
|
||||
BlockDriver* drv = bdrv_find_format("qcow2");
|
||||
assert(drv != NULL);
|
||||
ret = bdrv_open(bs, filename, NULL,
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -1599,10 +1602,11 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_close(bs);
|
||||
bdrv_unref(bs);
|
||||
bs = NULL;
|
||||
|
||||
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
|
||||
ret = bdrv_open(bs, filename, NULL,
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
||||
drv, &local_err);
|
||||
if (local_err) {
|
||||
@@ -1612,7 +1616,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
bdrv_unref(bs);
|
||||
if (bs) {
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
24
block/qed.c
24
block/qed.c
@@ -391,14 +391,15 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
qed_header_le_to_cpu(&le_header, &s->header);
|
||||
|
||||
if (s->header.magic != QED_MAGIC) {
|
||||
return -EMEDIUMTYPE;
|
||||
error_setg(errp, "Image not in QED format");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (s->header.features & ~QED_FEATURE_MASK) {
|
||||
/* image uses unsupported feature bits */
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "%" PRIx64,
|
||||
s->header.features & ~QED_FEATURE_MASK);
|
||||
qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "QED", buf);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
@@ -545,7 +546,8 @@ static void bdrv_qed_close(BlockDriverState *bs)
|
||||
|
||||
static int qed_create(const char *filename, uint32_t cluster_size,
|
||||
uint64_t image_size, uint32_t table_size,
|
||||
const char *backing_file, const char *backing_fmt)
|
||||
const char *backing_file, const char *backing_fmt,
|
||||
Error **errp)
|
||||
{
|
||||
QEDHeader header = {
|
||||
.magic = QED_MAGIC,
|
||||
@@ -562,20 +564,20 @@ static int qed_create(const char *filename, uint32_t cluster_size,
|
||||
size_t l1_size = header.cluster_size * header.table_size;
|
||||
Error *local_err = NULL;
|
||||
int ret = 0;
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockDriverState *bs;
|
||||
|
||||
ret = bdrv_create_file(filename, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB, &local_err);
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, NULL,
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -665,7 +667,7 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
|
||||
return qed_create(filename, cluster_size, image_size, table_size,
|
||||
backing_file, backing_fmt);
|
||||
backing_file, backing_fmt, errp);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
873
block/quorum.c
Normal file
873
block/quorum.c
Normal file
@@ -0,0 +1,873 @@
|
||||
/*
|
||||
* Quorum Block filter
|
||||
*
|
||||
* Copyright (C) 2012-2014 Nodalink, EURL.
|
||||
*
|
||||
* Author:
|
||||
* Benoît Canet <benoit.canet@irqsave.net>
|
||||
*
|
||||
* Based on the design and code of blkverify.c (Copyright (C) 2010 IBM, Corp)
|
||||
* and blkmirror.c (Copyright (C) 2011 Red Hat, Inc).
|
||||
*
|
||||
* 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 <gnutls/gnutls.h>
|
||||
#include <gnutls/crypto.h>
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
#define HASH_LENGTH 32
|
||||
|
||||
#define QUORUM_OPT_VOTE_THRESHOLD "vote-threshold"
|
||||
#define QUORUM_OPT_BLKVERIFY "blkverify"
|
||||
|
||||
/* This union holds a vote hash value */
|
||||
typedef union QuorumVoteValue {
|
||||
char h[HASH_LENGTH]; /* SHA-256 hash */
|
||||
int64_t l; /* simpler 64 bits hash */
|
||||
} QuorumVoteValue;
|
||||
|
||||
/* A vote item */
|
||||
typedef struct QuorumVoteItem {
|
||||
int index;
|
||||
QLIST_ENTRY(QuorumVoteItem) next;
|
||||
} QuorumVoteItem;
|
||||
|
||||
/* this structure is a vote version. A version is the set of votes sharing the
|
||||
* same vote value.
|
||||
* The set of votes will be tracked with the items field and its cardinality is
|
||||
* vote_count.
|
||||
*/
|
||||
typedef struct QuorumVoteVersion {
|
||||
QuorumVoteValue value;
|
||||
int index;
|
||||
int vote_count;
|
||||
QLIST_HEAD(, QuorumVoteItem) items;
|
||||
QLIST_ENTRY(QuorumVoteVersion) next;
|
||||
} QuorumVoteVersion;
|
||||
|
||||
/* this structure holds a group of vote versions together */
|
||||
typedef struct QuorumVotes {
|
||||
QLIST_HEAD(, QuorumVoteVersion) vote_list;
|
||||
bool (*compare)(QuorumVoteValue *a, QuorumVoteValue *b);
|
||||
} QuorumVotes;
|
||||
|
||||
/* the following structure holds the state of one quorum instance */
|
||||
typedef struct BDRVQuorumState {
|
||||
BlockDriverState **bs; /* children BlockDriverStates */
|
||||
int num_children; /* children count */
|
||||
int threshold; /* if less than threshold children reads gave the
|
||||
* same result a quorum error occurs.
|
||||
*/
|
||||
bool is_blkverify; /* true if the driver is in blkverify mode
|
||||
* Writes are mirrored on two children devices.
|
||||
* On reads the two children devices' contents are
|
||||
* compared and if a difference is spotted its
|
||||
* location is printed and the code aborts.
|
||||
* It is useful to debug other block drivers by
|
||||
* comparing them with a reference one.
|
||||
*/
|
||||
} BDRVQuorumState;
|
||||
|
||||
typedef struct QuorumAIOCB QuorumAIOCB;
|
||||
|
||||
/* Quorum will create one instance of the following structure per operation it
|
||||
* performs on its children.
|
||||
* So for each read/write operation coming from the upper layer there will be
|
||||
* $children_count QuorumChildRequest.
|
||||
*/
|
||||
typedef struct QuorumChildRequest {
|
||||
BlockDriverAIOCB *aiocb;
|
||||
QEMUIOVector qiov;
|
||||
uint8_t *buf;
|
||||
int ret;
|
||||
QuorumAIOCB *parent;
|
||||
} QuorumChildRequest;
|
||||
|
||||
/* Quorum will use the following structure to track progress of each read/write
|
||||
* operation received by the upper layer.
|
||||
* This structure hold pointers to the QuorumChildRequest structures instances
|
||||
* used to do operations on each children and track overall progress.
|
||||
*/
|
||||
struct QuorumAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
|
||||
/* Request metadata */
|
||||
uint64_t sector_num;
|
||||
int nb_sectors;
|
||||
|
||||
QEMUIOVector *qiov; /* calling IOV */
|
||||
|
||||
QuorumChildRequest *qcrs; /* individual child requests */
|
||||
int count; /* number of completed AIOCB */
|
||||
int success_count; /* number of successfully completed AIOCB */
|
||||
|
||||
QuorumVotes votes;
|
||||
|
||||
bool is_read;
|
||||
int vote_ret;
|
||||
};
|
||||
|
||||
static void quorum_vote(QuorumAIOCB *acb);
|
||||
|
||||
static void quorum_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
QuorumAIOCB *acb = container_of(blockacb, QuorumAIOCB, common);
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int i;
|
||||
|
||||
/* cancel all callbacks */
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_aio_cancel(acb->qcrs[i].aiocb);
|
||||
}
|
||||
|
||||
g_free(acb->qcrs);
|
||||
qemu_aio_release(acb);
|
||||
}
|
||||
|
||||
static AIOCBInfo quorum_aiocb_info = {
|
||||
.aiocb_size = sizeof(QuorumAIOCB),
|
||||
.cancel = quorum_aio_cancel,
|
||||
};
|
||||
|
||||
static void quorum_aio_finalize(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int i, ret = 0;
|
||||
|
||||
if (acb->vote_ret) {
|
||||
ret = acb->vote_ret;
|
||||
}
|
||||
|
||||
acb->common.cb(acb->common.opaque, ret);
|
||||
|
||||
if (acb->is_read) {
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
qemu_vfree(acb->qcrs[i].buf);
|
||||
qemu_iovec_destroy(&acb->qcrs[i].qiov);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(acb->qcrs);
|
||||
qemu_aio_release(acb);
|
||||
}
|
||||
|
||||
static bool quorum_sha256_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
||||
{
|
||||
return !memcmp(a->h, b->h, HASH_LENGTH);
|
||||
}
|
||||
|
||||
static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
||||
{
|
||||
return a->l == b->l;
|
||||
}
|
||||
|
||||
static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s,
|
||||
BlockDriverState *bs,
|
||||
QEMUIOVector *qiov,
|
||||
uint64_t sector_num,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
QuorumAIOCB *acb = qemu_aio_get(&quorum_aiocb_info, bs, cb, opaque);
|
||||
int i;
|
||||
|
||||
acb->common.bs->opaque = s;
|
||||
acb->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
acb->qiov = qiov;
|
||||
acb->qcrs = g_new0(QuorumChildRequest, s->num_children);
|
||||
acb->count = 0;
|
||||
acb->success_count = 0;
|
||||
acb->votes.compare = quorum_sha256_compare;
|
||||
QLIST_INIT(&acb->votes.vote_list);
|
||||
acb->is_read = false;
|
||||
acb->vote_ret = 0;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].buf = NULL;
|
||||
acb->qcrs[i].ret = 0;
|
||||
acb->qcrs[i].parent = acb;
|
||||
}
|
||||
|
||||
return acb;
|
||||
}
|
||||
|
||||
static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret)
|
||||
{
|
||||
QObject *data;
|
||||
assert(node_name);
|
||||
data = qobject_from_jsonf("{ 'node-name': %s"
|
||||
", 'sector-num': %" PRId64
|
||||
", 'sectors-count': %d }",
|
||||
node_name, acb->sector_num, acb->nb_sectors);
|
||||
if (ret < 0) {
|
||||
QDict *dict = qobject_to_qdict(data);
|
||||
qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
|
||||
}
|
||||
monitor_protocol_event(QEVENT_QUORUM_REPORT_BAD, data);
|
||||
qobject_decref(data);
|
||||
}
|
||||
|
||||
static void quorum_report_failure(QuorumAIOCB *acb)
|
||||
{
|
||||
QObject *data;
|
||||
const char *reference = acb->common.bs->device_name[0] ?
|
||||
acb->common.bs->device_name :
|
||||
acb->common.bs->node_name;
|
||||
data = qobject_from_jsonf("{ 'reference': %s"
|
||||
", 'sector-num': %" PRId64
|
||||
", 'sectors-count': %d }",
|
||||
reference, acb->sector_num, acb->nb_sectors);
|
||||
monitor_protocol_event(QEVENT_QUORUM_FAILURE, data);
|
||||
qobject_decref(data);
|
||||
}
|
||||
|
||||
static int quorum_vote_error(QuorumAIOCB *acb);
|
||||
|
||||
static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
|
||||
if (acb->success_count < s->threshold) {
|
||||
acb->vote_ret = quorum_vote_error(acb);
|
||||
quorum_report_failure(acb);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void quorum_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
QuorumChildRequest *sacb = opaque;
|
||||
QuorumAIOCB *acb = sacb->parent;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
|
||||
sacb->ret = ret;
|
||||
acb->count++;
|
||||
if (ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
quorum_report_bad(acb, sacb->aiocb->bs->node_name, ret);
|
||||
}
|
||||
assert(acb->count <= s->num_children);
|
||||
assert(acb->success_count <= s->num_children);
|
||||
if (acb->count < s->num_children) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do the vote on read */
|
||||
if (acb->is_read) {
|
||||
quorum_vote(acb);
|
||||
} else {
|
||||
quorum_has_too_much_io_failed(acb);
|
||||
}
|
||||
|
||||
quorum_aio_finalize(acb);
|
||||
}
|
||||
|
||||
static void quorum_report_bad_versions(BDRVQuorumState *s,
|
||||
QuorumAIOCB *acb,
|
||||
QuorumVoteValue *value)
|
||||
{
|
||||
QuorumVoteVersion *version;
|
||||
QuorumVoteItem *item;
|
||||
|
||||
QLIST_FOREACH(version, &acb->votes.vote_list, next) {
|
||||
if (acb->votes.compare(&version->value, value)) {
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(item, &version->items, next) {
|
||||
quorum_report_bad(acb, s->bs[item->index]->node_name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source)
|
||||
{
|
||||
int i;
|
||||
assert(dest->niov == source->niov);
|
||||
assert(dest->size == source->size);
|
||||
for (i = 0; i < source->niov; i++) {
|
||||
assert(dest->iov[i].iov_len == source->iov[i].iov_len);
|
||||
memcpy(dest->iov[i].iov_base,
|
||||
source->iov[i].iov_base,
|
||||
source->iov[i].iov_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void quorum_count_vote(QuorumVotes *votes,
|
||||
QuorumVoteValue *value,
|
||||
int index)
|
||||
{
|
||||
QuorumVoteVersion *v = NULL, *version = NULL;
|
||||
QuorumVoteItem *item;
|
||||
|
||||
/* look if we have something with this hash */
|
||||
QLIST_FOREACH(v, &votes->vote_list, next) {
|
||||
if (votes->compare(&v->value, value)) {
|
||||
version = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* It's a version not yet in the list add it */
|
||||
if (!version) {
|
||||
version = g_new0(QuorumVoteVersion, 1);
|
||||
QLIST_INIT(&version->items);
|
||||
memcpy(&version->value, value, sizeof(version->value));
|
||||
version->index = index;
|
||||
version->vote_count = 0;
|
||||
QLIST_INSERT_HEAD(&votes->vote_list, version, next);
|
||||
}
|
||||
|
||||
version->vote_count++;
|
||||
|
||||
item = g_new0(QuorumVoteItem, 1);
|
||||
item->index = index;
|
||||
QLIST_INSERT_HEAD(&version->items, item, next);
|
||||
}
|
||||
|
||||
static void quorum_free_vote_list(QuorumVotes *votes)
|
||||
{
|
||||
QuorumVoteVersion *version, *next_version;
|
||||
QuorumVoteItem *item, *next_item;
|
||||
|
||||
QLIST_FOREACH_SAFE(version, &votes->vote_list, next, next_version) {
|
||||
QLIST_REMOVE(version, next);
|
||||
QLIST_FOREACH_SAFE(item, &version->items, next, next_item) {
|
||||
QLIST_REMOVE(item, next);
|
||||
g_free(item);
|
||||
}
|
||||
g_free(version);
|
||||
}
|
||||
}
|
||||
|
||||
static int quorum_compute_hash(QuorumAIOCB *acb, int i, QuorumVoteValue *hash)
|
||||
{
|
||||
int j, ret;
|
||||
gnutls_hash_hd_t dig;
|
||||
QEMUIOVector *qiov = &acb->qcrs[i].qiov;
|
||||
|
||||
ret = gnutls_hash_init(&dig, GNUTLS_DIG_SHA256);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (j = 0; j < qiov->niov; j++) {
|
||||
ret = gnutls_hash(dig, qiov->iov[j].iov_base, qiov->iov[j].iov_len);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gnutls_hash_deinit(dig, (void *) hash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QuorumVoteVersion *quorum_get_vote_winner(QuorumVotes *votes)
|
||||
{
|
||||
int max = 0;
|
||||
QuorumVoteVersion *candidate, *winner = NULL;
|
||||
|
||||
QLIST_FOREACH(candidate, &votes->vote_list, next) {
|
||||
if (candidate->vote_count > max) {
|
||||
max = candidate->vote_count;
|
||||
winner = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return winner;
|
||||
}
|
||||
|
||||
/* qemu_iovec_compare is handy for blkverify mode because it returns the first
|
||||
* differing byte location. Yet it is handcoded to compare vectors one byte
|
||||
* after another so it does not benefit from the libc SIMD optimizations.
|
||||
* quorum_iovec_compare is written for speed and should be used in the non
|
||||
* blkverify mode of quorum.
|
||||
*/
|
||||
static bool quorum_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
|
||||
{
|
||||
int i;
|
||||
int result;
|
||||
|
||||
assert(a->niov == b->niov);
|
||||
for (i = 0; i < a->niov; i++) {
|
||||
assert(a->iov[i].iov_len == b->iov[i].iov_len);
|
||||
result = memcmp(a->iov[i].iov_base,
|
||||
b->iov[i].iov_base,
|
||||
a->iov[i].iov_len);
|
||||
if (result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "quorum: sector_num=%" PRId64 " nb_sectors=%d ",
|
||||
acb->sector_num, acb->nb_sectors);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static bool quorum_compare(QuorumAIOCB *acb,
|
||||
QEMUIOVector *a,
|
||||
QEMUIOVector *b)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
ssize_t offset;
|
||||
|
||||
/* This driver will replace blkverify in this particular case */
|
||||
if (s->is_blkverify) {
|
||||
offset = qemu_iovec_compare(a, b);
|
||||
if (offset != -1) {
|
||||
quorum_err(acb, "contents mismatch in sector %" PRId64,
|
||||
acb->sector_num +
|
||||
(uint64_t)(offset / BDRV_SECTOR_SIZE));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return quorum_iovec_compare(a, b);
|
||||
}
|
||||
|
||||
/* Do a vote to get the error code */
|
||||
static int quorum_vote_error(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
QuorumVoteVersion *winner = NULL;
|
||||
QuorumVotes error_votes;
|
||||
QuorumVoteValue result_value;
|
||||
int i, ret = 0;
|
||||
bool error = false;
|
||||
|
||||
QLIST_INIT(&error_votes.vote_list);
|
||||
error_votes.compare = quorum_64bits_compare;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
ret = acb->qcrs[i].ret;
|
||||
if (ret) {
|
||||
error = true;
|
||||
result_value.l = ret;
|
||||
quorum_count_vote(&error_votes, &result_value, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
winner = quorum_get_vote_winner(&error_votes);
|
||||
ret = winner->value.l;
|
||||
}
|
||||
|
||||
quorum_free_vote_list(&error_votes);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void quorum_vote(QuorumAIOCB *acb)
|
||||
{
|
||||
bool quorum = true;
|
||||
int i, j, ret;
|
||||
QuorumVoteValue hash;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
QuorumVoteVersion *winner;
|
||||
|
||||
if (quorum_has_too_much_io_failed(acb)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the index of the first successful read */
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
if (!acb->qcrs[i].ret) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(i < s->num_children);
|
||||
|
||||
/* compare this read with all other successful reads stopping at quorum
|
||||
* failure
|
||||
*/
|
||||
for (j = i + 1; j < s->num_children; j++) {
|
||||
if (acb->qcrs[j].ret) {
|
||||
continue;
|
||||
}
|
||||
quorum = quorum_compare(acb, &acb->qcrs[i].qiov, &acb->qcrs[j].qiov);
|
||||
if (!quorum) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Every successful read agrees */
|
||||
if (quorum) {
|
||||
quorum_copy_qiov(acb->qiov, &acb->qcrs[i].qiov);
|
||||
return;
|
||||
}
|
||||
|
||||
/* compute hashes for each successful read, also store indexes */
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
if (acb->qcrs[i].ret) {
|
||||
continue;
|
||||
}
|
||||
ret = quorum_compute_hash(acb, i, &hash);
|
||||
/* if ever the hash computation failed */
|
||||
if (ret < 0) {
|
||||
acb->vote_ret = ret;
|
||||
goto free_exit;
|
||||
}
|
||||
quorum_count_vote(&acb->votes, &hash, i);
|
||||
}
|
||||
|
||||
/* vote to select the most represented version */
|
||||
winner = quorum_get_vote_winner(&acb->votes);
|
||||
|
||||
/* if the winner count is smaller than threshold the read fails */
|
||||
if (winner->vote_count < s->threshold) {
|
||||
quorum_report_failure(acb);
|
||||
acb->vote_ret = -EIO;
|
||||
goto free_exit;
|
||||
}
|
||||
|
||||
/* we have a winner: copy it */
|
||||
quorum_copy_qiov(acb->qiov, &acb->qcrs[winner->index].qiov);
|
||||
|
||||
/* some versions are bad print them */
|
||||
quorum_report_bad_versions(s, acb, &winner->value);
|
||||
|
||||
free_exit:
|
||||
/* free lists */
|
||||
quorum_free_vote_list(&acb->votes);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *quorum_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num,
|
||||
nb_sectors, cb, opaque);
|
||||
int i;
|
||||
|
||||
acb->is_read = true;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].buf = qemu_blockalign(s->bs[i], qiov->size);
|
||||
qemu_iovec_init(&acb->qcrs[i].qiov, qiov->niov);
|
||||
qemu_iovec_clone(&acb->qcrs[i].qiov, qiov, acb->qcrs[i].buf);
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_aio_readv(s->bs[i], sector_num, &acb->qcrs[i].qiov, nb_sectors,
|
||||
quorum_aio_cb, &acb->qcrs[i]);
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *quorum_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num, nb_sectors,
|
||||
cb, opaque);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].aiocb = bdrv_aio_writev(s->bs[i], sector_num, qiov,
|
||||
nb_sectors, &quorum_aio_cb,
|
||||
&acb->qcrs[i]);
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static int64_t quorum_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
int64_t result;
|
||||
int i;
|
||||
|
||||
/* check that all file have the same length */
|
||||
result = bdrv_getlength(s->bs[0]);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
for (i = 1; i < s->num_children; i++) {
|
||||
int64_t value = bdrv_getlength(s->bs[i]);
|
||||
if (value < 0) {
|
||||
return value;
|
||||
}
|
||||
if (value != result) {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void quorum_invalidate_cache(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_invalidate_cache(s->bs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static coroutine_fn int quorum_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumVoteVersion *winner = NULL;
|
||||
QuorumVotes error_votes;
|
||||
QuorumVoteValue result_value;
|
||||
int i;
|
||||
int result = 0;
|
||||
|
||||
QLIST_INIT(&error_votes.vote_list);
|
||||
error_votes.compare = quorum_64bits_compare;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
result = bdrv_co_flush(s->bs[i]);
|
||||
result_value.l = result;
|
||||
quorum_count_vote(&error_votes, &result_value, i);
|
||||
}
|
||||
|
||||
winner = quorum_get_vote_winner(&error_votes);
|
||||
result = winner->value.l;
|
||||
|
||||
quorum_free_vote_list(&error_votes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool quorum_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bool perm = bdrv_recurse_is_first_non_filter(s->bs[i],
|
||||
candidate);
|
||||
if (perm) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int quorum_valid_threshold(int threshold, int num_children, Error **errp)
|
||||
{
|
||||
|
||||
if (threshold < 1) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
|
||||
"vote-threshold", "value >= 1");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (threshold > num_children) {
|
||||
error_setg(errp, "threshold may not exceed children count");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QemuOptsList quorum_runtime_opts = {
|
||||
.name = "quorum",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(quorum_runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = QUORUM_OPT_VOTE_THRESHOLD,
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "The number of vote needed for reaching quorum",
|
||||
},
|
||||
{
|
||||
.name = QUORUM_OPT_BLKVERIFY,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Trigger block verify mode if set",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
Error *local_err = NULL;
|
||||
QemuOpts *opts;
|
||||
bool *opened;
|
||||
QDict *sub = NULL;
|
||||
QList *list = NULL;
|
||||
const QListEntry *lentry;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
qdict_flatten(options);
|
||||
qdict_extract_subqdict(options, &sub, "children.");
|
||||
qdict_array_split(sub, &list);
|
||||
|
||||
if (qdict_size(sub)) {
|
||||
error_setg(&local_err, "Invalid option children.%s",
|
||||
qdict_first(sub)->key);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* count how many different children are present */
|
||||
s->num_children = qlist_size(list);
|
||||
if (s->num_children < 2) {
|
||||
error_setg(&local_err,
|
||||
"Number of provided children must be greater than 1");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
opts = qemu_opts_create(&quorum_runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s->threshold = qemu_opt_get_number(opts, QUORUM_OPT_VOTE_THRESHOLD, 0);
|
||||
|
||||
/* and validate it against s->num_children */
|
||||
ret = quorum_valid_threshold(s->threshold, s->num_children, &local_err);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* is the driver in blkverify mode */
|
||||
if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false) &&
|
||||
s->num_children == 2 && s->threshold == 2) {
|
||||
s->is_blkverify = true;
|
||||
} else if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false)) {
|
||||
fprintf(stderr, "blkverify mode is set by setting blkverify=on "
|
||||
"and using two files with vote_threshold=2\n");
|
||||
}
|
||||
|
||||
/* allocate the children BlockDriverState array */
|
||||
s->bs = g_new0(BlockDriverState *, s->num_children);
|
||||
opened = g_new0(bool, s->num_children);
|
||||
|
||||
for (i = 0, lentry = qlist_first(list); lentry;
|
||||
lentry = qlist_next(lentry), i++) {
|
||||
QDict *d;
|
||||
QString *string;
|
||||
|
||||
switch (qobject_type(lentry->value))
|
||||
{
|
||||
/* List of options */
|
||||
case QTYPE_QDICT:
|
||||
d = qobject_to_qdict(lentry->value);
|
||||
QINCREF(d);
|
||||
ret = bdrv_open(&s->bs[i], NULL, NULL, d, flags, NULL,
|
||||
&local_err);
|
||||
break;
|
||||
|
||||
/* QMP reference */
|
||||
case QTYPE_QSTRING:
|
||||
string = qobject_to_qstring(lentry->value);
|
||||
ret = bdrv_open(&s->bs[i], NULL, qstring_get_str(string), NULL,
|
||||
flags, NULL, &local_err);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(&local_err, "Specification of child block device %i "
|
||||
"is invalid", i);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
goto close_exit;
|
||||
}
|
||||
opened[i] = true;
|
||||
}
|
||||
|
||||
g_free(opened);
|
||||
goto exit;
|
||||
|
||||
close_exit:
|
||||
/* cleanup on error */
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
if (!opened[i]) {
|
||||
continue;
|
||||
}
|
||||
bdrv_unref(s->bs[i]);
|
||||
}
|
||||
g_free(s->bs);
|
||||
g_free(opened);
|
||||
exit:
|
||||
/* propagate error */
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
QDECREF(list);
|
||||
QDECREF(sub);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void quorum_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_unref(s->bs[i]);
|
||||
}
|
||||
|
||||
g_free(s->bs);
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_quorum = {
|
||||
.format_name = "quorum",
|
||||
.protocol_name = "quorum",
|
||||
|
||||
.instance_size = sizeof(BDRVQuorumState),
|
||||
|
||||
.bdrv_file_open = quorum_open,
|
||||
.bdrv_close = quorum_close,
|
||||
|
||||
.authorizations = { true, true },
|
||||
|
||||
.bdrv_co_flush_to_disk = quorum_co_flush,
|
||||
|
||||
.bdrv_getlength = quorum_getlength,
|
||||
|
||||
.bdrv_aio_readv = quorum_aio_readv,
|
||||
.bdrv_aio_writev = quorum_aio_writev,
|
||||
.bdrv_invalidate_cache = quorum_invalidate_cache,
|
||||
|
||||
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
|
||||
};
|
||||
|
||||
static void bdrv_quorum_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_quorum);
|
||||
}
|
||||
|
||||
block_init(bdrv_quorum_init);
|
@@ -1534,7 +1534,8 @@ static int sd_prealloc(const char *filename)
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
|
||||
NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
@@ -1695,7 +1696,9 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&bs, backing_file, NULL, NULL, 0, &local_err);
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_PROTOCOL, NULL,
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
|
29
block/vdi.c
29
block/vdi.c
@@ -395,43 +395,50 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (header.signature != VDI_SIGNATURE) {
|
||||
logout("bad vdi signature %08x\n", header.signature);
|
||||
ret = -EMEDIUMTYPE;
|
||||
error_setg(errp, "Image not in VDI format (bad signature %08x)", header.signature);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else if (header.version != VDI_VERSION_1_1) {
|
||||
logout("unsupported version %u.%u\n",
|
||||
header.version >> 16, header.version & 0xffff);
|
||||
error_setg(errp, "unsupported VDI image (version %u.%u)",
|
||||
header.version >> 16, header.version & 0xffff);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
||||
/* We only support block maps which start on a sector boundary. */
|
||||
logout("unsupported block map offset 0x%x B\n", header.offset_bmap);
|
||||
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
||||
"0x%x)", header.offset_bmap);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
||||
/* We only support data blocks which start on a sector boundary. */
|
||||
logout("unsupported data offset 0x%x B\n", header.offset_data);
|
||||
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%x)",
|
||||
header.offset_data);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.sector_size != SECTOR_SIZE) {
|
||||
logout("unsupported sector size %u B\n", header.sector_size);
|
||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
||||
header.sector_size, SECTOR_SIZE);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.block_size != 1 * MiB) {
|
||||
logout("unsupported block size %u B\n", header.block_size);
|
||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
||||
header.block_size, 1 * MiB);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.disk_size >
|
||||
(uint64_t)header.blocks_in_image * header.block_size) {
|
||||
logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
|
||||
error_setg(errp, "unsupported VDI image (disk size %" PRIu64 ", "
|
||||
"image bitmap has room for %" PRIu64 ")",
|
||||
header.disk_size,
|
||||
(uint64_t)header.blocks_in_image * header.block_size);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (!uuid_is_null(header.uuid_link)) {
|
||||
logout("link uuid != 0, unsupported\n");
|
||||
error_setg(errp, "unsupported VDI image (non-NULL link UUID)");
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (!uuid_is_null(header.uuid_parent)) {
|
||||
logout("parent uuid != 0, unsupported\n");
|
||||
error_setg(errp, "unsupported VDI image (non-NULL parent UUID)");
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
25
block/vhdx.c
25
block/vhdx.c
@@ -402,9 +402,10 @@ int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
}
|
||||
|
||||
/* opens the specified header block from the VHDX file header section */
|
||||
static int vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s)
|
||||
static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
VHDXHeader *header1;
|
||||
VHDXHeader *header2;
|
||||
bool h1_valid = false;
|
||||
@@ -462,7 +463,6 @@ static int vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s)
|
||||
} else if (!h1_valid && h2_valid) {
|
||||
s->curr_header = 1;
|
||||
} else if (!h1_valid && !h2_valid) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else {
|
||||
/* If both headers are valid, then we choose the active one by the
|
||||
@@ -473,27 +473,22 @@ static int vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s)
|
||||
} else if (h2_seq > h1_seq) {
|
||||
s->curr_header = 1;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
vhdx_region_register(s, s->headers[s->curr_header]->log_offset,
|
||||
s->headers[s->curr_header]->log_length);
|
||||
|
||||
ret = 0;
|
||||
|
||||
goto exit;
|
||||
|
||||
fail:
|
||||
qerror_report(ERROR_CLASS_GENERIC_ERROR, "No valid VHDX header found");
|
||||
error_setg_errno(errp, -ret, "No valid VHDX header found");
|
||||
qemu_vfree(header1);
|
||||
qemu_vfree(header2);
|
||||
s->headers[0] = NULL;
|
||||
s->headers[1] = NULL;
|
||||
exit:
|
||||
qemu_vfree(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -878,7 +873,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret = 0;
|
||||
uint32_t i;
|
||||
uint64_t signature;
|
||||
|
||||
Error *local_err = NULL;
|
||||
|
||||
s->bat = NULL;
|
||||
s->first_visible_write = true;
|
||||
@@ -901,8 +896,10 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
* header update */
|
||||
vhdx_guid_generate(&s->session_guid);
|
||||
|
||||
ret = vhdx_parse_header(bs, s);
|
||||
if (ret < 0) {
|
||||
vhdx_parse_header(bs, s, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -1797,7 +1794,9 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
|
||||
NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto exit;
|
||||
|
144
block/vmdk.c
144
block/vmdk.c
@@ -526,8 +526,34 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
|
||||
uint64_t desc_offset, Error **errp);
|
||||
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
|
||||
Error **errp);
|
||||
|
||||
static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
|
||||
Error **errp)
|
||||
{
|
||||
int64_t size;
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
size = bdrv_getlength(file);
|
||||
if (size < 0) {
|
||||
error_setg_errno(errp, -size, "Could not access file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = MIN(size, 1 << 20); /* avoid unbounded allocation */
|
||||
buf = g_malloc0(size + 1);
|
||||
|
||||
ret = bdrv_pread(file, desc_offset, buf, size);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not read from file");
|
||||
g_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
BlockDriverState *file,
|
||||
@@ -546,11 +572,18 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
error_setg_errno(errp, -ret,
|
||||
"Could not read header from file '%s'",
|
||||
file->filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (header.capacity == 0) {
|
||||
uint64_t desc_offset = le64_to_cpu(header.desc_offset);
|
||||
if (desc_offset) {
|
||||
return vmdk_open_desc_file(bs, flags, desc_offset << 9, errp);
|
||||
char *buf = vmdk_read_desc(file, desc_offset << 9, errp);
|
||||
if (!buf) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = vmdk_open_desc_file(bs, flags, buf, errp);
|
||||
g_free(buf);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,8 +642,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "VMDK version %d",
|
||||
le32_to_cpu(header.version));
|
||||
qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "vmdk", buf);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "vmdk", buf);
|
||||
return -ENOTSUP;
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) {
|
||||
/* VMware KB 2064959 explains that version 3 added support for
|
||||
@@ -622,7 +655,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
if (le32_to_cpu(header.num_gtes_per_gt) > 512) {
|
||||
error_report("L2 table size too big");
|
||||
error_setg(errp, "L2 table size too big");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -638,8 +671,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
}
|
||||
if (bdrv_getlength(file) <
|
||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) {
|
||||
error_report("File truncated, expecting at least %lld bytes",
|
||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE);
|
||||
error_setg(errp, "File truncated, expecting at least %lld bytes",
|
||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -701,16 +734,12 @@ static int vmdk_parse_description(const char *desc, const char *opt_name,
|
||||
|
||||
/* Open an extent file and append to bs array */
|
||||
static int vmdk_open_sparse(BlockDriverState *bs,
|
||||
BlockDriverState *file,
|
||||
int flags, Error **errp)
|
||||
BlockDriverState *file, int flags,
|
||||
char *buf, Error **errp)
|
||||
{
|
||||
uint32_t magic;
|
||||
|
||||
if (bdrv_pread(file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
magic = be32_to_cpu(magic);
|
||||
magic = ldl_be_p(buf);
|
||||
switch (magic) {
|
||||
case VMDK3_MAGIC:
|
||||
return vmdk_open_vmfs_sparse(bs, file, flags, errp);
|
||||
@@ -719,7 +748,8 @@ static int vmdk_open_sparse(BlockDriverState *bs,
|
||||
return vmdk_open_vmdk4(bs, file, flags, errp);
|
||||
break;
|
||||
default:
|
||||
return -EMEDIUMTYPE;
|
||||
error_setg(errp, "Image not in VMDK format");
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -776,8 +806,9 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
||||
|
||||
path_combine(extent_path, sizeof(extent_path),
|
||||
desc_file_path, fname);
|
||||
ret = bdrv_file_open(&extent_file, extent_path, NULL, NULL,
|
||||
bs->open_flags, errp);
|
||||
extent_file = NULL;
|
||||
ret = bdrv_open(&extent_file, extent_path, NULL, NULL,
|
||||
bs->open_flags | BDRV_O_PROTOCOL, NULL, errp);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@@ -794,8 +825,14 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
||||
extent->flat_start_offset = flat_offset << 9;
|
||||
} else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) {
|
||||
/* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/
|
||||
ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, errp);
|
||||
char *buf = vmdk_read_desc(extent_file, 0, errp);
|
||||
if (!buf) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf, errp);
|
||||
}
|
||||
if (ret) {
|
||||
g_free(buf);
|
||||
bdrv_unref(extent_file);
|
||||
return ret;
|
||||
}
|
||||
@@ -818,29 +855,16 @@ next_line:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
|
||||
uint64_t desc_offset, Error **errp)
|
||||
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
char *buf = NULL;
|
||||
char ct[128];
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int64_t size;
|
||||
|
||||
size = bdrv_getlength(bs->file);
|
||||
if (size < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = MIN(size, 1 << 20); /* avoid unbounded allocation */
|
||||
buf = g_malloc0(size + 1);
|
||||
|
||||
ret = bdrv_pread(bs->file, desc_offset, buf, size);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
|
||||
ret = -EMEDIUMTYPE;
|
||||
error_setg(errp, "invalid VMDK image descriptor");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
if (strcmp(ct, "monolithicFlat") &&
|
||||
@@ -856,24 +880,37 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
|
||||
s->desc_offset = 0;
|
||||
ret = vmdk_parse_extents(buf, bs, bs->file->filename, errp);
|
||||
exit:
|
||||
g_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
char *buf = NULL;
|
||||
int ret;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
uint32_t magic;
|
||||
|
||||
if (vmdk_open_sparse(bs, bs->file, flags, errp) == 0) {
|
||||
s->desc_offset = 0x200;
|
||||
} else {
|
||||
ret = vmdk_open_desc_file(bs, flags, 0, errp);
|
||||
if (ret) {
|
||||
goto fail;
|
||||
}
|
||||
buf = vmdk_read_desc(bs->file, 0, errp);
|
||||
if (!buf) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
magic = ldl_be_p(buf);
|
||||
switch (magic) {
|
||||
case VMDK3_MAGIC:
|
||||
case VMDK4_MAGIC:
|
||||
ret = vmdk_open_sparse(bs, bs->file, flags, buf, errp);
|
||||
s->desc_offset = 0x200;
|
||||
break;
|
||||
default:
|
||||
ret = vmdk_open_desc_file(bs, flags, buf, errp);
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* try to open parent images, if exist */
|
||||
ret = vmdk_parent_open(bs);
|
||||
if (ret) {
|
||||
@@ -888,10 +925,11 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vmdk", bs->device_name, "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
g_free(buf);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
g_free(buf);
|
||||
g_free(s->create_type);
|
||||
s->create_type = NULL;
|
||||
vmdk_free_extents(bs);
|
||||
@@ -1146,7 +1184,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
|
||||
break;
|
||||
case VMDK_OK:
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
if (extent->file == bs->file) {
|
||||
if (extent->file == bs->file && !extent->compressed) {
|
||||
ret |= BDRV_BLOCK_OFFSET_VALID | offset;
|
||||
}
|
||||
|
||||
@@ -1493,7 +1531,9 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||
assert(bs == NULL);
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
|
||||
NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto exit;
|
||||
@@ -1755,10 +1795,10 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
goto exit;
|
||||
}
|
||||
if (backing_file) {
|
||||
BlockDriverState *bs = bdrv_new("");
|
||||
ret = bdrv_open(bs, backing_file, NULL, BDRV_O_NO_BACKING, NULL, errp);
|
||||
BlockDriverState *bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_NO_BACKING, NULL,
|
||||
errp);
|
||||
if (ret != 0) {
|
||||
bdrv_unref(bs);
|
||||
goto exit;
|
||||
}
|
||||
if (strcmp(bs->drv->format_name, "vmdk")) {
|
||||
@@ -1831,7 +1871,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
ret = bdrv_file_open(&new_bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||
assert(new_bs == NULL);
|
||||
ret = bdrv_open(&new_bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not write description");
|
||||
goto exit;
|
||||
|
@@ -190,7 +190,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
if (strncmp(footer->creator, "conectix", 8)) {
|
||||
ret = -EMEDIUMTYPE;
|
||||
error_setg(errp, "invalid VPC image");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
disk_type = VHD_FIXED;
|
||||
|
@@ -1086,16 +1086,14 @@ DLOG(if (stderr == NULL) {
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dirname = qemu_opt_get(opts, "dir");
|
||||
if (!dirname) {
|
||||
qerror_report(ERROR_CLASS_GENERIC_ERROR, "vvfat block driver requires "
|
||||
"a 'dir' option");
|
||||
error_setg(errp, "vvfat block driver requires a 'dir' option");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -1135,8 +1133,7 @@ DLOG(if (stderr == NULL) {
|
||||
case 12:
|
||||
break;
|
||||
default:
|
||||
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Valid FAT types are only "
|
||||
"12, 16 and 32");
|
||||
error_setg(errp, "Valid FAT types are only 12, 16 and 32");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -2936,15 +2933,13 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
goto err;
|
||||
}
|
||||
|
||||
s->qcow = bdrv_new("");
|
||||
|
||||
ret = bdrv_open(s->qcow, s->qcow_filename, NULL,
|
||||
s->qcow = NULL;
|
||||
ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow,
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
bdrv_unref(s->qcow);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
22
blockdev.c
22
blockdev.c
@@ -504,7 +504,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
|
||||
|
||||
QINCREF(bs_opts);
|
||||
ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv, &error);
|
||||
ret = bdrv_open(&dinfo->bdrv, file, NULL, bs_opts, bdrv_flags, drv, &error);
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "could not open disk image %s: %s",
|
||||
@@ -1330,12 +1330,12 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
||||
qstring_from_str(snapshot_node_name));
|
||||
}
|
||||
|
||||
/* We will manually add the backing_hd field to the bs later */
|
||||
state->new_bs = bdrv_new("");
|
||||
/* TODO Inherit bs->options or only take explicit options with an
|
||||
* extended QMP command? */
|
||||
ret = bdrv_open(state->new_bs, new_image_file, options,
|
||||
assert(state->new_bs == NULL);
|
||||
ret = bdrv_open(&state->new_bs, new_image_file, NULL, options,
|
||||
flags | BDRV_O_NO_BACKING, drv, &local_err);
|
||||
/* We will manually add the backing_hd field to the bs later */
|
||||
if (ret != 0) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
@@ -1582,7 +1582,7 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
ret = bdrv_open(bs, filename, NULL, bdrv_flags, drv, &local_err);
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL, bdrv_flags, drv, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
@@ -2018,10 +2018,9 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
return;
|
||||
}
|
||||
|
||||
target_bs = bdrv_new("");
|
||||
ret = bdrv_open(target_bs, target, NULL, flags, drv, &local_err);
|
||||
target_bs = NULL;
|
||||
ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(target_bs);
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
@@ -2162,11 +2161,10 @@ void qmp_drive_mirror(const char *device, const char *target,
|
||||
/* Mirroring takes care of copy-on-write using the source's backing
|
||||
* file.
|
||||
*/
|
||||
target_bs = bdrv_new("");
|
||||
ret = bdrv_open(target_bs, target, NULL, flags | BDRV_O_NO_BACKING, drv,
|
||||
&local_err);
|
||||
target_bs = NULL;
|
||||
ret = bdrv_open(&target_bs, target, NULL, NULL, flags | BDRV_O_NO_BACKING,
|
||||
drv, &local_err);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(target_bs);
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
317
configure
vendored
317
configure
vendored
@@ -12,7 +12,10 @@ else
|
||||
fi
|
||||
|
||||
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
||||
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
|
||||
TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}"
|
||||
TMPO="${TMPDIR1}/${TMPB}.o"
|
||||
TMPL="${TMPDIR1}/${TMPB}.lo"
|
||||
TMPA="${TMPDIR1}/lib${TMPB}.la"
|
||||
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
|
||||
|
||||
# NB: do not call "exit" in the trap handler; this is buggy with some shells;
|
||||
@@ -86,6 +89,38 @@ compile_prog() {
|
||||
do_cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags
|
||||
}
|
||||
|
||||
do_libtool() {
|
||||
local mode=$1
|
||||
shift
|
||||
# Run the compiler, capturing its output to the log.
|
||||
echo $libtool $mode --tag=CC $cc "$@" >> config.log
|
||||
$libtool $mode --tag=CC $cc "$@" >> config.log 2>&1 || return $?
|
||||
# Test passed. If this is an --enable-werror build, rerun
|
||||
# the test with -Werror and bail out if it fails. This
|
||||
# makes warning-generating-errors in configure test code
|
||||
# obvious to developers.
|
||||
if test "$werror" != "yes"; then
|
||||
return 0
|
||||
fi
|
||||
# Don't bother rerunning the compile if we were already using -Werror
|
||||
case "$*" in
|
||||
*-Werror*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
echo $libtool $mode --tag=CC $cc -Werror "$@" >> config.log
|
||||
$libtool $mode --tag=CC $cc -Werror "$@" >> config.log 2>&1 && return $?
|
||||
error_exit "configure test passed without -Werror but failed with -Werror." \
|
||||
"This is probably a bug in the configure script. The failing command" \
|
||||
"will be at the bottom of config.log." \
|
||||
"You can run configure with --disable-werror to bypass this check."
|
||||
}
|
||||
|
||||
libtool_prog() {
|
||||
do_libtool --mode=compile $QEMU_CFLAGS -c -fPIE -DPIE -o $TMPO $TMPC || return $?
|
||||
do_libtool --mode=link $LDFLAGS -o $TMPA $TMPL -rpath /usr/local/lib
|
||||
}
|
||||
|
||||
# symbolically link $1 to $2. Portable version of "ln -sf".
|
||||
symlink() {
|
||||
rm -rf "$2"
|
||||
@@ -172,6 +207,7 @@ fdt=""
|
||||
netmap="no"
|
||||
pixman=""
|
||||
sdl=""
|
||||
sdlabi="1.2"
|
||||
virtfs=""
|
||||
vnc="yes"
|
||||
sparse="no"
|
||||
@@ -205,6 +241,9 @@ mingw32="no"
|
||||
gcov="no"
|
||||
gcov_tool="gcov"
|
||||
EXESUF=""
|
||||
DSOSUF=".so"
|
||||
LDFLAGS_SHARED="-shared"
|
||||
modules="no"
|
||||
prefix="/usr/local"
|
||||
mandir="\${prefix}/share/man"
|
||||
datadir="\${prefix}/share"
|
||||
@@ -245,6 +284,8 @@ libusb=""
|
||||
usb_redir=""
|
||||
glx=""
|
||||
zlib="yes"
|
||||
lzo="no"
|
||||
snappy="no"
|
||||
guest_agent=""
|
||||
guest_agent_with_vss="no"
|
||||
vss_win32_sdk=""
|
||||
@@ -264,6 +305,7 @@ gtkabi="2.0"
|
||||
tpm="no"
|
||||
libssh2=""
|
||||
vhdx=""
|
||||
quorum="no"
|
||||
|
||||
# parse CC options first
|
||||
for opt do
|
||||
@@ -325,6 +367,7 @@ query_pkg_config() {
|
||||
}
|
||||
pkg_config=query_pkg_config
|
||||
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
|
||||
sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
|
||||
|
||||
# If the user hasn't specified ARFLAGS, default to 'rv', just as make does.
|
||||
ARFLAGS="${ARFLAGS-rv}"
|
||||
@@ -515,11 +558,10 @@ OpenBSD)
|
||||
Darwin)
|
||||
bsd="yes"
|
||||
darwin="yes"
|
||||
LDFLAGS_SHARED="-bundle -undefined dynamic_lookup"
|
||||
if [ "$cpu" = "x86_64" ] ; then
|
||||
QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
|
||||
LDFLAGS="-arch x86_64 $LDFLAGS"
|
||||
else
|
||||
QEMU_CFLAGS="-mdynamic-no-pic $QEMU_CFLAGS"
|
||||
fi
|
||||
cocoa="yes"
|
||||
audio_drv_list="coreaudio"
|
||||
@@ -610,6 +652,7 @@ fi
|
||||
|
||||
if test "$mingw32" = "yes" ; then
|
||||
EXESUF=".exe"
|
||||
DSOSUF=".dll"
|
||||
QEMU_CFLAGS="-DWIN32_LEAN_AND_MEAN -DWINVER=0x501 $QEMU_CFLAGS"
|
||||
# enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later)
|
||||
QEMU_CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $QEMU_CFLAGS"
|
||||
@@ -676,6 +719,9 @@ for opt do
|
||||
;;
|
||||
--disable-debug-info)
|
||||
;;
|
||||
--enable-modules)
|
||||
modules="yes"
|
||||
;;
|
||||
--cpu=*)
|
||||
;;
|
||||
--target-list=*) target_list="$optarg"
|
||||
@@ -731,6 +777,8 @@ for opt do
|
||||
;;
|
||||
--enable-sdl) sdl="yes"
|
||||
;;
|
||||
--with-sdlabi=*) sdlabi="$optarg"
|
||||
;;
|
||||
--disable-qom-cast-debug) qom_cast_debug="no"
|
||||
;;
|
||||
--enable-qom-cast-debug) qom_cast_debug="yes"
|
||||
@@ -953,6 +1001,10 @@ for opt do
|
||||
;;
|
||||
--disable-zlib-test) zlib="no"
|
||||
;;
|
||||
--enable-lzo) lzo="yes"
|
||||
;;
|
||||
--enable-snappy) snappy="yes"
|
||||
;;
|
||||
--enable-guest-agent) guest_agent="yes"
|
||||
;;
|
||||
--disable-guest-agent) guest_agent="no"
|
||||
@@ -1005,6 +1057,10 @@ for opt do
|
||||
;;
|
||||
--disable-vhdx) vhdx="no"
|
||||
;;
|
||||
--disable-quorum) quorum="no"
|
||||
;;
|
||||
--enable-quorum) quorum="yes"
|
||||
;;
|
||||
*) echo "ERROR: unknown option $opt"; show_help="yes"
|
||||
;;
|
||||
esac
|
||||
@@ -1131,7 +1187,8 @@ Advanced options (experts only):
|
||||
--libdir=PATH install libraries in PATH
|
||||
--sysconfdir=PATH install config in PATH$confsuffix
|
||||
--localstatedir=PATH install local state in PATH (set at runtime on win32)
|
||||
--with-confsuffix=SUFFIX suffix for QEMU data inside datadir and sysconfdir [$confsuffix]
|
||||
--with-confsuffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir [$confsuffix]
|
||||
--enable-modules enable modules support
|
||||
--enable-debug-tcg enable TCG debugging
|
||||
--disable-debug-tcg disable TCG debugging (default)
|
||||
--enable-debug-info enable debugging information (default)
|
||||
@@ -1143,6 +1200,7 @@ Advanced options (experts only):
|
||||
--disable-werror disable compilation abort on warning
|
||||
--disable-sdl disable SDL
|
||||
--enable-sdl enable SDL
|
||||
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
||||
--disable-gtk disable gtk UI
|
||||
--enable-gtk enable gtk UI
|
||||
--disable-virtfs disable VirtFS
|
||||
@@ -1242,6 +1300,8 @@ Advanced options (experts only):
|
||||
--enable-libusb enable libusb (for usb passthrough)
|
||||
--disable-usb-redir disable usb network redirection support
|
||||
--enable-usb-redir enable usb network redirection support
|
||||
--enable-lzo enable the support of lzo compression library
|
||||
--enable-snappy enable the support of snappy compression library
|
||||
--disable-guest-agent disable building of the QEMU Guest Agent
|
||||
--enable-guest-agent enable building of the QEMU Guest Agent
|
||||
--with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent
|
||||
@@ -1261,6 +1321,8 @@ Advanced options (experts only):
|
||||
--enable-libssh2 enable ssh block device support
|
||||
--disable-vhdx disables support for the Microsoft VHDX image format
|
||||
--enable-vhdx enable support for the Microsoft VHDX image format
|
||||
--disable-quorum disable quorum block filter support
|
||||
--enable-quorum enable quorum block filter support
|
||||
|
||||
NOTE: The object files are built at the place where configure is launched
|
||||
EOF
|
||||
@@ -1289,6 +1351,35 @@ else
|
||||
error_exit "\"$cc\" either does not exist or does not work"
|
||||
fi
|
||||
|
||||
# Check that the C++ compiler exists and works with the C compiler
|
||||
if has $cxx; then
|
||||
cat > $TMPC <<EOF
|
||||
int c_function(void);
|
||||
int main(void) { return c_function(); }
|
||||
EOF
|
||||
|
||||
compile_object
|
||||
|
||||
cat > $TMPC <<EOF
|
||||
extern "C" {
|
||||
int c_function(void);
|
||||
}
|
||||
int c_function(void) { return 42; }
|
||||
EOF
|
||||
|
||||
if (cc=$cxx do_cc $QEMU_CFLAGS -o $TMPE $TMPC $TMPO $LDFLAGS); then
|
||||
# C++ compiler $cxx works ok with C compiler $cc
|
||||
:
|
||||
else
|
||||
echo "C++ compiler $cxx does not work with C compiler $cc"
|
||||
echo "Disabling C++ specific optional code"
|
||||
cxx=
|
||||
fi
|
||||
else
|
||||
echo "No C++ compiler available; disabling C++ specific optional code"
|
||||
cxx=
|
||||
fi
|
||||
|
||||
# Consult white-list to determine whether to enable werror
|
||||
# by default. Only enable by default for git builds
|
||||
z_version=`cut -f3 -d. $source_path/VERSION`
|
||||
@@ -1346,6 +1437,9 @@ if compile_prog "-Werror -fno-gcse" "" ; then
|
||||
fi
|
||||
|
||||
if test "$static" = "yes" ; then
|
||||
if test "$modules" = "yes" ; then
|
||||
error_exit "static and modules are mutually incompatible"
|
||||
fi
|
||||
if test "$pie" = "yes" ; then
|
||||
error_exit "static and pie are mutually incompatible"
|
||||
else
|
||||
@@ -1399,6 +1493,32 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# check for broken gcc and libtool in RHEL5
|
||||
if test -n "$libtool" -a "$pie" != "no" ; then
|
||||
cat > $TMPC <<EOF
|
||||
|
||||
void *f(unsigned char *buf, int len);
|
||||
void *g(unsigned char *buf, int len);
|
||||
|
||||
void *
|
||||
f(unsigned char *buf, int len)
|
||||
{
|
||||
return (void*)0L;
|
||||
}
|
||||
|
||||
void *
|
||||
g(unsigned char *buf, int len)
|
||||
{
|
||||
return f(buf, len);
|
||||
}
|
||||
|
||||
EOF
|
||||
if ! libtool_prog; then
|
||||
echo "Disabling libtool due to broken toolchain support"
|
||||
libtool=
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# __sync_fetch_and_and requires at least -march=i486. Many toolchains
|
||||
# use i686 as default anyway, but for those that don't, an explicit
|
||||
@@ -1550,7 +1670,43 @@ EOF
|
||||
"Make sure to have the zlib libs and headers installed."
|
||||
fi
|
||||
fi
|
||||
libs_softmmu="$libs_softmmu -lz"
|
||||
LIBS="$LIBS -lz"
|
||||
|
||||
##########################################
|
||||
# lzo check
|
||||
|
||||
if test "$lzo" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <lzo/lzo1x.h>
|
||||
int main(void) { lzo_version(); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "-llzo2" ; then
|
||||
:
|
||||
else
|
||||
error_exit "lzo check failed" \
|
||||
"Make sure to have the lzo libs and headers installed."
|
||||
fi
|
||||
|
||||
libs_softmmu="$libs_softmmu -llzo2"
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# snappy check
|
||||
|
||||
if test "$snappy" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <snappy-c.h>
|
||||
int main(void) { snappy_max_compressed_length(4096); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "-lsnappy" ; then
|
||||
:
|
||||
else
|
||||
error_exit "snappy check failed" \
|
||||
"Make sure to have the snappy libs and headers installed."
|
||||
fi
|
||||
|
||||
libs_softmmu="$libs_softmmu -lsnappy"
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# libseccomp check
|
||||
@@ -1804,12 +1960,22 @@ fi
|
||||
|
||||
# Look for sdl configuration program (pkg-config or sdl-config). Try
|
||||
# sdl-config even without cross prefix, and favour pkg-config over sdl-config.
|
||||
if test "`basename $sdl_config`" != sdl-config && ! has ${sdl_config}; then
|
||||
sdl_config=sdl-config
|
||||
|
||||
if test $sdlabi = "2.0"; then
|
||||
sdl_config=$sdl2_config
|
||||
sdlname=sdl2
|
||||
sdlconfigname=sdl2_config
|
||||
else
|
||||
sdlname=sdl
|
||||
sdlconfigname=sdl_config
|
||||
fi
|
||||
|
||||
if $pkg_config sdl --exists; then
|
||||
sdlconfig="$pkg_config sdl"
|
||||
if test "`basename $sdl_config`" != $sdlconfigname && ! has ${sdl_config}; then
|
||||
sdl_config=$sdlconfigname
|
||||
fi
|
||||
|
||||
if $pkg_config $sdlname --exists; then
|
||||
sdlconfig="$pkg_config $sdlname"
|
||||
_sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
|
||||
elif has ${sdl_config}; then
|
||||
sdlconfig="$sdl_config"
|
||||
@@ -1936,6 +2102,30 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Quorum probe (check for gnutls)
|
||||
if test "$quorum" != "no" ; then
|
||||
cat > $TMPC <<EOF
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/crypto.h>
|
||||
int main(void) {char data[4096], digest[32];
|
||||
gnutls_hash_fast(GNUTLS_DIG_SHA256, data, 4096, digest);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
quorum_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null`
|
||||
quorum_tls_libs=`$pkg_config --libs gnutls 2> /dev/null`
|
||||
if compile_prog "$quorum_tls_cflags" "$quorum_tls_libs" ; then
|
||||
qcow_tls=yes
|
||||
libs_softmmu="$quorum_tls_libs $libs_softmmu"
|
||||
libs_tools="$quorum_tls_libs $libs_softmmu"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $quorum_tls_cflags"
|
||||
else
|
||||
echo "gnutls > 2.10.0 required to compile Quorum"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# VNC SASL detection
|
||||
if test "$vnc" = "yes" -a "$vnc_sasl" != "no" ; then
|
||||
@@ -2118,13 +2308,21 @@ EOF
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# netmap headers probe
|
||||
# netmap support probe
|
||||
# Apart from looking for netmap headers, we make sure that the host API version
|
||||
# supports the netmap backend (>=11). The upper bound (15) is meant to simulate
|
||||
# a minor/major version number. Minor new features will be marked with values up
|
||||
# to 15, and if something happens that requires a change to the backend we will
|
||||
# move above 15, submit the backend fixes and modify this two bounds.
|
||||
if test "$netmap" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <inttypes.h>
|
||||
#include <net/if.h>
|
||||
#include <net/netmap.h>
|
||||
#include <net/netmap_user.h>
|
||||
#if (NETMAP_API < 11) || (NETMAP_API > 15)
|
||||
#error
|
||||
#endif
|
||||
int main(void) { return 0; }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
@@ -2318,8 +2516,6 @@ EOF
|
||||
curl_libs=`$curlconfig --libs 2>/dev/null`
|
||||
if compile_prog "$curl_cflags" "$curl_libs" ; then
|
||||
curl=yes
|
||||
libs_tools="$curl_libs $libs_tools"
|
||||
libs_softmmu="$curl_libs $libs_softmmu"
|
||||
else
|
||||
if test "$curl" = "yes" ; then
|
||||
feature_not_found "curl" "Install libcurl devel"
|
||||
@@ -2357,13 +2553,36 @@ if test "$mingw32" = yes; then
|
||||
else
|
||||
glib_req_ver=2.12
|
||||
fi
|
||||
if $pkg_config --atleast-version=$glib_req_ver gthread-2.0; then
|
||||
glib_cflags=`$pkg_config --cflags gthread-2.0`
|
||||
glib_libs=`$pkg_config --libs gthread-2.0`
|
||||
LIBS="$glib_libs $LIBS"
|
||||
libs_qga="$glib_libs $libs_qga"
|
||||
else
|
||||
error_exit "glib-$glib_req_ver required to compile QEMU"
|
||||
glib_modules=gthread-2.0
|
||||
if test "$modules" = yes; then
|
||||
glib_modules="$glib_modules gmodule-2.0"
|
||||
fi
|
||||
|
||||
for i in $glib_modules; do
|
||||
if $pkg_config --atleast-version=$glib_req_ver $i; then
|
||||
glib_cflags=`$pkg_config --cflags $i`
|
||||
glib_libs=`$pkg_config --libs $i`
|
||||
CFLAGS="$glib_cflags $CFLAGS"
|
||||
LIBS="$glib_libs $LIBS"
|
||||
libs_qga="$glib_libs $libs_qga"
|
||||
else
|
||||
error_exit "glib-$glib_req_ver $i is required to compile QEMU"
|
||||
fi
|
||||
done
|
||||
|
||||
##########################################
|
||||
# SHA command probe for modules
|
||||
if test "$modules" = yes; then
|
||||
shacmd_probe="sha1sum sha1 shasum"
|
||||
for c in $shacmd_probe; do
|
||||
if which $c &>/dev/null; then
|
||||
shacmd="$c"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "$shacmd" = ""; then
|
||||
error_exit "one of the checksum commands is required to enable modules: $shacmd_probe"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
@@ -2474,8 +2693,6 @@ EOF
|
||||
rbd_libs="-lrbd -lrados"
|
||||
if compile_prog "" "$rbd_libs" ; then
|
||||
rbd=yes
|
||||
libs_tools="$rbd_libs $libs_tools"
|
||||
libs_softmmu="$rbd_libs $libs_softmmu"
|
||||
else
|
||||
if test "$rbd" = "yes" ; then
|
||||
feature_not_found "rados block device" "Install librbd/ceph devel"
|
||||
@@ -2492,9 +2709,6 @@ if test "$libssh2" != "no" ; then
|
||||
libssh2_cflags=`$pkg_config libssh2 --cflags`
|
||||
libssh2_libs=`$pkg_config libssh2 --libs`
|
||||
libssh2=yes
|
||||
libs_tools="$libssh2_libs $libs_tools"
|
||||
libs_softmmu="$libssh2_libs $libs_softmmu"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $libssh2_cflags"
|
||||
else
|
||||
if test "$libssh2" = "yes" ; then
|
||||
error_exit "libssh2 >= $min_libssh2_version required for --enable-libssh2"
|
||||
@@ -2540,8 +2754,6 @@ int main(void) { io_setup(0, NULL); io_set_eventfd(NULL, 0); eventfd(0, 0); retu
|
||||
EOF
|
||||
if compile_prog "" "-laio" ; then
|
||||
linux_aio=yes
|
||||
libs_softmmu="$libs_softmmu -laio"
|
||||
libs_tools="$libs_tools -laio"
|
||||
else
|
||||
if test "$linux_aio" = "yes" ; then
|
||||
feature_not_found "linux AIO" "Install libaio devel"
|
||||
@@ -2710,9 +2922,6 @@ if test "$glusterfs" != "no" ; then
|
||||
glusterfs="yes"
|
||||
glusterfs_cflags=`$pkg_config --cflags glusterfs-api`
|
||||
glusterfs_libs=`$pkg_config --libs glusterfs-api`
|
||||
CFLAGS="$CFLAGS $glusterfs_cflags"
|
||||
libs_tools="$glusterfs_libs $libs_tools"
|
||||
libs_softmmu="$glusterfs_libs $libs_softmmu"
|
||||
if $pkg_config --atleast-version=5 glusterfs-api; then
|
||||
glusterfs_discard="yes"
|
||||
fi
|
||||
@@ -3083,11 +3292,9 @@ EOF
|
||||
libiscsi="yes"
|
||||
libiscsi_cflags=$($pkg_config --cflags libiscsi)
|
||||
libiscsi_libs=$($pkg_config --libs libiscsi)
|
||||
CFLAGS="$CFLAGS $libiscsi_cflags"
|
||||
LIBS="$LIBS $libiscsi_libs"
|
||||
elif compile_prog "" "-liscsi" ; then
|
||||
libiscsi="yes"
|
||||
LIBS="$LIBS -liscsi"
|
||||
libiscsi_libs="-liscsi"
|
||||
else
|
||||
if test "$libiscsi" = "yes" ; then
|
||||
feature_not_found "libiscsi" "Install libiscsi devel"
|
||||
@@ -3688,6 +3895,7 @@ if test "$mingw32" = "yes" ; then
|
||||
fi
|
||||
|
||||
qemu_confdir=$sysconfdir$confsuffix
|
||||
qemu_moddir=$libdir$confsuffix
|
||||
qemu_datadir=$datadir$confsuffix
|
||||
qemu_localedir="$datadir/locale"
|
||||
|
||||
@@ -3778,6 +3986,7 @@ echo "Install prefix $prefix"
|
||||
echo "BIOS directory `eval echo $qemu_datadir`"
|
||||
echo "binary directory `eval echo $bindir`"
|
||||
echo "library directory `eval echo $libdir`"
|
||||
echo "module directory `eval echo $qemu_moddir`"
|
||||
echo "libexec directory `eval echo $libexecdir`"
|
||||
echo "include directory `eval echo $includedir`"
|
||||
echo "config directory `eval echo $sysconfdir`"
|
||||
@@ -3804,6 +4013,7 @@ echo "python $python"
|
||||
if test "$slirp" = "yes" ; then
|
||||
echo "smbd $smbd"
|
||||
fi
|
||||
echo "module support $modules"
|
||||
echo "host CPU $cpu"
|
||||
echo "host big endian $bigendian"
|
||||
echo "target list $target_list"
|
||||
@@ -3893,6 +4103,9 @@ echo "libssh2 support $libssh2"
|
||||
echo "TPM passthrough $tpm_passthrough"
|
||||
echo "QOM debugging $qom_cast_debug"
|
||||
echo "vhdx $vhdx"
|
||||
echo "Quorum $quorum"
|
||||
echo "lzo support $lzo"
|
||||
echo "snappy support $snappy"
|
||||
|
||||
if test "$sdl_too_old" = "yes"; then
|
||||
echo "-> Your SDL version is too old - please upgrade to have SDL support"
|
||||
@@ -3916,6 +4129,7 @@ echo "sysconfdir=$sysconfdir" >> $config_host_mak
|
||||
echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
|
||||
echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
|
||||
echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
|
||||
echo "qemu_moddir=$qemu_moddir" >> $config_host_mak
|
||||
if test "$mingw32" = "no" ; then
|
||||
echo "qemu_localstatedir=$local_statedir" >> $config_host_mak
|
||||
fi
|
||||
@@ -4048,6 +4262,12 @@ echo "TARGET_DIRS=$target_list" >> $config_host_mak
|
||||
if [ "$docs" = "yes" ] ; then
|
||||
echo "BUILD_DOCS=yes" >> $config_host_mak
|
||||
fi
|
||||
if test "$modules" = "yes"; then
|
||||
# $shacmd can generate a hash started with digit, which the compiler doesn't
|
||||
# like as an symbol. So prefix it with an underscore
|
||||
echo "CONFIG_STAMP=_`(echo $qemu_version; echo $pkgversion; cat $0) | $shacmd - | cut -f1 -d\ `" >> $config_host_mak
|
||||
echo "CONFIG_MODULES=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$sdl" = "yes" ; then
|
||||
echo "CONFIG_SDL=y" >> $config_host_mak
|
||||
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
|
||||
@@ -4119,8 +4339,9 @@ if test "$bswap_h" = "yes" ; then
|
||||
echo "CONFIG_MACHINE_BSWAP_H=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$curl" = "yes" ; then
|
||||
echo "CONFIG_CURL=y" >> $config_host_mak
|
||||
echo "CONFIG_CURL=m" >> $config_host_mak
|
||||
echo "CURL_CFLAGS=$curl_cflags" >> $config_host_mak
|
||||
echo "CURL_LIBS=$curl_libs" >> $config_host_mak
|
||||
fi
|
||||
if test "$brlapi" = "yes" ; then
|
||||
echo "CONFIG_BRLAPI=y" >> $config_host_mak
|
||||
@@ -4208,11 +4429,21 @@ if test "$glx" = "yes" ; then
|
||||
echo "GLX_LIBS=$glx_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$lzo" = "yes" ; then
|
||||
echo "CONFIG_LZO=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$snappy" = "yes" ; then
|
||||
echo "CONFIG_SNAPPY=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$libiscsi" = "yes" ; then
|
||||
echo "CONFIG_LIBISCSI=y" >> $config_host_mak
|
||||
echo "CONFIG_LIBISCSI=m" >> $config_host_mak
|
||||
if test "$libiscsi_version" = "1.4.0"; then
|
||||
echo "CONFIG_LIBISCSI_1_4=y" >> $config_host_mak
|
||||
fi
|
||||
echo "LIBISCSI_CFLAGS=$libiscsi_cflags" >> $config_host_mak
|
||||
echo "LIBISCSI_LIBS=$libiscsi_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$libnfs" = "yes" ; then
|
||||
@@ -4237,7 +4468,9 @@ if test "$qom_cast_debug" = "yes" ; then
|
||||
echo "CONFIG_QOM_CAST_DEBUG=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$rbd" = "yes" ; then
|
||||
echo "CONFIG_RBD=y" >> $config_host_mak
|
||||
echo "CONFIG_RBD=m" >> $config_host_mak
|
||||
echo "RBD_CFLAGS=$rbd_cflags" >> $config_host_mak
|
||||
echo "RBD_LIBS=$rbd_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak
|
||||
@@ -4280,7 +4513,9 @@ if test "$getauxval" = "yes" ; then
|
||||
fi
|
||||
|
||||
if test "$glusterfs" = "yes" ; then
|
||||
echo "CONFIG_GLUSTERFS=y" >> $config_host_mak
|
||||
echo "CONFIG_GLUSTERFS=m" >> $config_host_mak
|
||||
echo "GLUSTERFS_CFLAGS=$glusterfs_cflags" >> $config_host_mak
|
||||
echo "GLUSTERFS_LIBS=$glusterfs_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$glusterfs_discard" = "yes" ; then
|
||||
@@ -4292,7 +4527,13 @@ if test "$glusterfs_zerofill" = "yes" ; then
|
||||
fi
|
||||
|
||||
if test "$libssh2" = "yes" ; then
|
||||
echo "CONFIG_LIBSSH2=y" >> $config_host_mak
|
||||
echo "CONFIG_LIBSSH2=m" >> $config_host_mak
|
||||
echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
|
||||
echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$quorum" = "yes" ; then
|
||||
echo "CONFIG_QUORUM=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$virtio_blk_data_plane" = "yes" ; then
|
||||
@@ -4423,6 +4664,8 @@ echo "LIBTOOLFLAGS=$LIBTOOLFLAGS" >> $config_host_mak
|
||||
echo "LIBS+=$LIBS" >> $config_host_mak
|
||||
echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
|
||||
echo "EXESUF=$EXESUF" >> $config_host_mak
|
||||
echo "DSOSUF=$DSOSUF" >> $config_host_mak
|
||||
echo "LDFLAGS_SHARED=$LDFLAGS_SHARED" >> $config_host_mak
|
||||
echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
|
||||
echo "POD2MAN=$POD2MAN" >> $config_host_mak
|
||||
echo "TRANSLATE_OPT_CFLAGS=$TRANSLATE_OPT_CFLAGS" >> $config_host_mak
|
||||
|
@@ -477,7 +477,7 @@ int cpu_exec(CPUArchState *env)
|
||||
}
|
||||
#elif defined(TARGET_ARM)
|
||||
if (interrupt_request & CPU_INTERRUPT_FIQ
|
||||
&& !(env->uncached_cpsr & CPSR_F)) {
|
||||
&& !(env->daif & PSTATE_F)) {
|
||||
env->exception_index = EXCP_FIQ;
|
||||
cc->do_interrupt(cpu);
|
||||
next_tb = 0;
|
||||
@@ -493,7 +493,7 @@ int cpu_exec(CPUArchState *env)
|
||||
pc contains a magic address. */
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
||||
&& ((IS_M(env) && env->regs[15] < 0xfffffff0)
|
||||
|| !(env->uncached_cpsr & CPSR_I))) {
|
||||
|| !(env->daif & PSTATE_I))) {
|
||||
env->exception_index = EXCP_IRQ;
|
||||
cc->do_interrupt(cpu);
|
||||
next_tb = 0;
|
||||
|
@@ -1,2 +1,3 @@
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_S390_FLIC=$(CONFIG_KVM)
|
||||
|
@@ -10,6 +10,7 @@ CONFIG_EMPTY_SLOT=y
|
||||
CONFIG_PCNET_COMMON=y
|
||||
CONFIG_LANCE=y
|
||||
CONFIG_TCX=y
|
||||
CONFIG_CG3=y
|
||||
CONFIG_SLAVIO=y
|
||||
CONFIG_CS4231=y
|
||||
CONFIG_GRLIB=y
|
||||
|
@@ -225,6 +225,45 @@ Data:
|
||||
"timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
|
||||
}
|
||||
|
||||
QUORUM_FAILURE
|
||||
--------------
|
||||
|
||||
Emitted by the Quorum block driver if it fails to establish a quorum.
|
||||
|
||||
Data:
|
||||
|
||||
- "reference": device name if defined else node name.
|
||||
- "sector-num": Number of the first sector of the failed read operation.
|
||||
- "sector-count": Failed read operation sector count.
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "QUORUM_FAILURE",
|
||||
"data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
|
||||
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
||||
|
||||
QUORUM_REPORT_BAD
|
||||
-----------------
|
||||
|
||||
Emitted to report a corruption of a Quorum file.
|
||||
|
||||
Data:
|
||||
|
||||
- "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 the
|
||||
block layer reported an error and clients should not try to
|
||||
interpret the error string.
|
||||
- "node-name": The graph node name of the block driver state.
|
||||
- "sector-num": Number of the first sector of the failed read operation.
|
||||
- "sector-count": Failed read operation sector count.
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "QUORUM_REPORT_BAD",
|
||||
"data": { "node-name": "1.raw", "sector-num": 345435, "sector-count": 5 },
|
||||
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
||||
|
||||
RESET
|
||||
-----
|
||||
|
||||
|
@@ -66,7 +66,7 @@ bulk-phase round of the migration and can be enabled for extremely
|
||||
high-performance RDMA hardware using the following command:
|
||||
|
||||
QEMU Monitor Command:
|
||||
$ migrate_set_capability x-rdma-pin-all on # disabled by default
|
||||
$ migrate_set_capability rdma-pin-all on # disabled by default
|
||||
|
||||
Performing this action will cause all 8GB to be pinned, so if that's
|
||||
not what you want, then please ignore this step altogether.
|
||||
@@ -93,12 +93,12 @@ $ migrate_set_speed 40g # or whatever is the MAX of your RDMA device
|
||||
|
||||
Next, on the destination machine, add the following to the QEMU command line:
|
||||
|
||||
qemu ..... -incoming x-rdma:host:port
|
||||
qemu ..... -incoming rdma:host:port
|
||||
|
||||
Finally, perform the actual migration on the source machine:
|
||||
|
||||
QEMU Monitor Command:
|
||||
$ migrate -d x-rdma:host:port
|
||||
$ migrate -d rdma:host:port
|
||||
|
||||
PERFORMANCE
|
||||
===========
|
||||
@@ -120,8 +120,8 @@ For example, in the same 8GB RAM example with all 8GB of memory in
|
||||
active use and the VM itself is completely idle using the same 40 gbps
|
||||
infiniband link:
|
||||
|
||||
1. x-rdma-pin-all disabled total time: approximately 7.5 seconds @ 9.5 Gbps
|
||||
2. x-rdma-pin-all enabled total time: approximately 4 seconds @ 26 Gbps
|
||||
1. rdma-pin-all disabled total time: approximately 7.5 seconds @ 9.5 Gbps
|
||||
2. rdma-pin-all enabled total time: approximately 4 seconds @ 26 Gbps
|
||||
|
||||
These numbers would of course scale up to whatever size virtual machine
|
||||
you have to migrate using RDMA.
|
||||
@@ -407,18 +407,14 @@ socket is broken during a non-RDMA based migration.
|
||||
|
||||
TODO:
|
||||
=====
|
||||
1. 'migrate x-rdma:host:port' and '-incoming x-rdma' options will be
|
||||
renamed to 'rdma' after the experimental phase of this work has
|
||||
completed upstream.
|
||||
2. Currently, 'ulimit -l' mlock() limits as well as cgroups swap limits
|
||||
1. Currently, 'ulimit -l' mlock() limits as well as cgroups swap limits
|
||||
are not compatible with infinband memory pinning and will result in
|
||||
an aborted migration (but with the source VM left unaffected).
|
||||
3. Use of the recent /proc/<pid>/pagemap would likely speed up
|
||||
2. Use of the recent /proc/<pid>/pagemap would likely speed up
|
||||
the use of KSM and ballooning while using RDMA.
|
||||
4. Also, some form of balloon-device usage tracking would also
|
||||
3. Also, some form of balloon-device usage tracking would also
|
||||
help alleviate some issues.
|
||||
5. Move UNREGISTER requests to a separate thread.
|
||||
6. Use LRU to provide more fine-grained direction of UNREGISTER
|
||||
4. Use LRU to provide more fine-grained direction of UNREGISTER
|
||||
requests for unpinning memory in an overcommitted environment.
|
||||
7. Expose UNREGISTER support to the user by way of workload-specific
|
||||
5. Expose UNREGISTER support to the user by way of workload-specific
|
||||
hints about application behavior.
|
||||
|
4
exec.c
4
exec.c
@@ -17,9 +17,7 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "config.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
5
hmp.c
5
hmp.c
@@ -1311,8 +1311,11 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
||||
const char *file = qdict_get_str(qdict, "filename");
|
||||
bool has_begin = qdict_haskey(qdict, "begin");
|
||||
bool has_length = qdict_haskey(qdict, "length");
|
||||
/* kdump-compressed format is not supported for HMP */
|
||||
bool has_format = false;
|
||||
int64_t begin = 0;
|
||||
int64_t length = 0;
|
||||
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
||||
char *prot;
|
||||
|
||||
if (has_begin) {
|
||||
@@ -1325,7 +1328,7 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
||||
prot = g_strconcat("file:", file, NULL);
|
||||
|
||||
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
||||
&errp);
|
||||
has_format, dump_format, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
g_free(prot);
|
||||
}
|
||||
|
@@ -92,8 +92,6 @@
|
||||
#define MP_ETH_CRDP3 0x4AC
|
||||
#define MP_ETH_CTDP0 0x4E0
|
||||
#define MP_ETH_CTDP1 0x4E4
|
||||
#define MP_ETH_CTDP2 0x4E8
|
||||
#define MP_ETH_CTDP3 0x4EC
|
||||
|
||||
/* MII PHY access */
|
||||
#define MP_ETH_SMIR_DATA 0x0000FFFF
|
||||
@@ -308,7 +306,7 @@ static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
|
||||
case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
|
||||
return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
|
||||
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
|
||||
return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
|
||||
|
||||
default:
|
||||
@@ -362,7 +360,7 @@ static void mv88w8618_eth_write(void *opaque, hwaddr offset,
|
||||
s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
|
||||
break;
|
||||
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
|
||||
s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
|
||||
break;
|
||||
}
|
||||
@@ -632,7 +630,7 @@ static int musicpal_lcd_init(SysBusDevice *sbd)
|
||||
"musicpal-lcd", MP_LCD_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
s->con = graphic_console_init(dev, &musicpal_gfx_ops, s);
|
||||
s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
|
||||
qemu_console_resize(s->con, 128*3, 64*3);
|
||||
|
||||
qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
|
||||
|
@@ -272,11 +272,11 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
goto message;
|
||||
|
||||
case 3:
|
||||
s->cpu->env.uncached_cpsr =
|
||||
ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
|
||||
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
||||
s->cpu->env.cp15.c1_sys = 0;
|
||||
s->cpu->env.cp15.c1_coproc = 0;
|
||||
s->cpu->env.cp15.c2_base0 = 0;
|
||||
s->cpu->env.cp15.ttbr0_el1 = 0;
|
||||
s->cpu->env.cp15.c3 = 0;
|
||||
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
||||
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
||||
|
@@ -483,7 +483,18 @@ static void qemu_aio_complete(void *opaque, int ret)
|
||||
ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
||||
ioreq_unmap(ioreq);
|
||||
ioreq_finish(ioreq);
|
||||
bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
|
||||
switch (ioreq->req.operation) {
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
if (!ioreq->req.nr_segments) {
|
||||
break;
|
||||
}
|
||||
case BLKIF_OP_READ:
|
||||
bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
qemu_bh_schedule(ioreq->blkdev->bh);
|
||||
}
|
||||
|
||||
@@ -813,8 +824,8 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
Error *local_err = NULL;
|
||||
BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto,
|
||||
readonly);
|
||||
if (bdrv_open(blkdev->bs,
|
||||
blkdev->filename, NULL, qflags, drv, &local_err) != 0)
|
||||
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
|
||||
drv, &local_err) != 0)
|
||||
{
|
||||
xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
|
||||
error_get_pretty(local_err));
|
||||
|
@@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP) += omap_lcdc.o
|
||||
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
|
||||
obj-$(CONFIG_SM501) += sm501.o
|
||||
obj-$(CONFIG_TCX) += tcx.o
|
||||
obj-$(CONFIG_CG3) += cg3.o
|
||||
|
||||
obj-$(CONFIG_VGA) += vga.o
|
||||
|
||||
|
@@ -956,7 +956,7 @@ void *s1d13745_init(qemu_irq gpio_int)
|
||||
|
||||
s->fb = g_malloc(0x180000);
|
||||
|
||||
s->con = graphic_console_init(NULL, &blizzard_ops, s);
|
||||
s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
|
||||
surface = qemu_console_surface(s->con);
|
||||
|
||||
switch (surface_bits_per_pixel(surface)) {
|
||||
|
385
hw/display/cg3.c
Normal file
385
hw/display/cg3.c
Normal file
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
* QEMU CG3 Frame buffer
|
||||
*
|
||||
* Copyright (c) 2012 Bob Breuer
|
||||
* Copyright (c) 2013 Mark Cave-Ayland
|
||||
*
|
||||
* 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 "qemu/error-report.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/loader.h"
|
||||
|
||||
/* Change to 1 to enable debugging */
|
||||
#define DEBUG_CG3 0
|
||||
|
||||
#define CG3_ROM_FILE "QEMU,cgthree.bin"
|
||||
#define FCODE_MAX_ROM_SIZE 0x10000
|
||||
|
||||
#define CG3_REG_SIZE 0x20
|
||||
|
||||
#define CG3_REG_BT458_ADDR 0x0
|
||||
#define CG3_REG_BT458_COLMAP 0x4
|
||||
#define CG3_REG_FBC_CTRL 0x10
|
||||
#define CG3_REG_FBC_STATUS 0x11
|
||||
#define CG3_REG_FBC_CURSTART 0x12
|
||||
#define CG3_REG_FBC_CUREND 0x13
|
||||
#define CG3_REG_FBC_VCTRL 0x14
|
||||
|
||||
/* Control register flags */
|
||||
#define CG3_CR_ENABLE_INTS 0x80
|
||||
|
||||
/* Status register flags */
|
||||
#define CG3_SR_PENDING_INT 0x80
|
||||
#define CG3_SR_1152_900_76_B 0x60
|
||||
#define CG3_SR_ID_COLOR 0x01
|
||||
|
||||
#define CG3_VRAM_SIZE 0x100000
|
||||
#define CG3_VRAM_OFFSET 0x800000
|
||||
|
||||
#define DPRINTF(fmt, ...) do { \
|
||||
if (DEBUG_CG3) { \
|
||||
printf("CG3: " fmt , ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define TYPE_CG3 "cgthree"
|
||||
#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3)
|
||||
|
||||
typedef struct CG3State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
QemuConsole *con;
|
||||
qemu_irq irq;
|
||||
hwaddr prom_addr;
|
||||
MemoryRegion vram_mem;
|
||||
MemoryRegion rom;
|
||||
MemoryRegion reg;
|
||||
uint32_t vram_size;
|
||||
int full_update;
|
||||
uint8_t regs[16];
|
||||
uint8_t r[256], g[256], b[256];
|
||||
uint16_t width, height, depth;
|
||||
uint8_t dac_index, dac_state;
|
||||
} CG3State;
|
||||
|
||||
static void cg3_update_display(void *opaque)
|
||||
{
|
||||
CG3State *s = opaque;
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
const uint8_t *pix;
|
||||
uint32_t *data;
|
||||
uint32_t dval;
|
||||
int x, y, y_start;
|
||||
unsigned int width, height;
|
||||
ram_addr_t page, page_min, page_max;
|
||||
|
||||
if (surface_bits_per_pixel(surface) != 32) {
|
||||
return;
|
||||
}
|
||||
width = s->width;
|
||||
height = s->height;
|
||||
|
||||
y_start = -1;
|
||||
page_min = -1;
|
||||
page_max = 0;
|
||||
page = 0;
|
||||
pix = memory_region_get_ram_ptr(&s->vram_mem);
|
||||
data = (uint32_t *)surface_data(surface);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
int update = s->full_update;
|
||||
|
||||
page = (y * width) & TARGET_PAGE_MASK;
|
||||
update |= memory_region_get_dirty(&s->vram_mem, page, page + width,
|
||||
DIRTY_MEMORY_VGA);
|
||||
if (update) {
|
||||
if (y_start < 0) {
|
||||
y_start = y;
|
||||
}
|
||||
if (page < page_min) {
|
||||
page_min = page;
|
||||
}
|
||||
if (page > page_max) {
|
||||
page_max = page;
|
||||
}
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
dval = *pix++;
|
||||
dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval];
|
||||
*data++ = dval;
|
||||
}
|
||||
} else {
|
||||
if (y_start >= 0) {
|
||||
dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
|
||||
y_start = -1;
|
||||
}
|
||||
pix += width;
|
||||
data += width;
|
||||
}
|
||||
}
|
||||
s->full_update = 0;
|
||||
if (y_start >= 0) {
|
||||
dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
|
||||
}
|
||||
if (page_max >= page_min) {
|
||||
memory_region_reset_dirty(&s->vram_mem,
|
||||
page_min, page_max - page_min + TARGET_PAGE_SIZE,
|
||||
DIRTY_MEMORY_VGA);
|
||||
}
|
||||
/* vsync interrupt? */
|
||||
if (s->regs[0] & CG3_CR_ENABLE_INTS) {
|
||||
s->regs[1] |= CG3_SR_PENDING_INT;
|
||||
qemu_irq_raise(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void cg3_invalidate_display(void *opaque)
|
||||
{
|
||||
CG3State *s = opaque;
|
||||
|
||||
memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE);
|
||||
}
|
||||
|
||||
static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
CG3State *s = opaque;
|
||||
int val;
|
||||
|
||||
switch (addr) {
|
||||
case CG3_REG_BT458_ADDR:
|
||||
case CG3_REG_BT458_COLMAP:
|
||||
val = 0;
|
||||
break;
|
||||
case CG3_REG_FBC_CTRL:
|
||||
val = s->regs[0];
|
||||
break;
|
||||
case CG3_REG_FBC_STATUS:
|
||||
/* monitor ID 6, board type = 1 (color) */
|
||||
val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
|
||||
break;
|
||||
case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
|
||||
val = s->regs[addr - 0x10];
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"cg3: Unimplemented register read "
|
||||
"reg 0x%" HWADDR_PRIx " size 0x%x\n",
|
||||
addr, size);
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
CG3State *s = opaque;
|
||||
uint8_t regval;
|
||||
int i;
|
||||
|
||||
DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n",
|
||||
val, addr, size);
|
||||
|
||||
switch (addr) {
|
||||
case CG3_REG_BT458_ADDR:
|
||||
s->dac_index = val;
|
||||
s->dac_state = 0;
|
||||
break;
|
||||
case CG3_REG_BT458_COLMAP:
|
||||
/* This register can be written to as either a long word or a byte */
|
||||
if (size == 1) {
|
||||
val <<= 24;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
regval = val >> 24;
|
||||
|
||||
switch (s->dac_state) {
|
||||
case 0:
|
||||
s->r[s->dac_index] = regval;
|
||||
s->dac_state++;
|
||||
break;
|
||||
case 1:
|
||||
s->g[s->dac_index] = regval;
|
||||
s->dac_state++;
|
||||
break;
|
||||
case 2:
|
||||
s->b[s->dac_index] = regval;
|
||||
/* Index autoincrement */
|
||||
s->dac_index = (s->dac_index + 1) & 0xff;
|
||||
default:
|
||||
s->dac_state = 0;
|
||||
break;
|
||||
}
|
||||
val <<= 8;
|
||||
}
|
||||
s->full_update = 1;
|
||||
break;
|
||||
case CG3_REG_FBC_CTRL:
|
||||
s->regs[0] = val;
|
||||
break;
|
||||
case CG3_REG_FBC_STATUS:
|
||||
if (s->regs[1] & CG3_SR_PENDING_INT) {
|
||||
/* clear interrupt */
|
||||
s->regs[1] &= ~CG3_SR_PENDING_INT;
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
break;
|
||||
case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
|
||||
s->regs[addr - 0x10] = val;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"cg3: Unimplemented register write "
|
||||
"reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
|
||||
addr, size, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps cg3_reg_ops = {
|
||||
.read = cg3_reg_read,
|
||||
.write = cg3_reg_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static const GraphicHwOps cg3_ops = {
|
||||
.invalidate = cg3_invalidate_display,
|
||||
.gfx_update = cg3_update_display,
|
||||
};
|
||||
|
||||
static void cg3_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
CG3State *s = CG3(dev);
|
||||
int ret;
|
||||
char *fcode_filename;
|
||||
|
||||
/* FCode ROM */
|
||||
memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
|
||||
vmstate_register_ram_global(&s->rom);
|
||||
memory_region_set_readonly(&s->rom, true);
|
||||
sysbus_init_mmio(sbd, &s->rom);
|
||||
|
||||
fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
|
||||
if (fcode_filename) {
|
||||
ret = load_image_targphys(fcode_filename, s->prom_addr,
|
||||
FCODE_MAX_ROM_SIZE);
|
||||
if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
|
||||
error_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
|
||||
CG3_REG_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->reg);
|
||||
|
||||
memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size);
|
||||
vmstate_register_ram_global(&s->vram_mem);
|
||||
sysbus_init_mmio(sbd, &s->vram_mem);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s);
|
||||
qemu_console_resize(s->con, s->width, s->height);
|
||||
}
|
||||
|
||||
static int vmstate_cg3_post_load(void *opaque, int version_id)
|
||||
{
|
||||
CG3State *s = opaque;
|
||||
|
||||
cg3_invalidate_display(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_cg3 = {
|
||||
.name = "cg3",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = vmstate_cg3_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(height, CG3State),
|
||||
VMSTATE_UINT16(width, CG3State),
|
||||
VMSTATE_UINT16(depth, CG3State),
|
||||
VMSTATE_BUFFER(r, CG3State),
|
||||
VMSTATE_BUFFER(g, CG3State),
|
||||
VMSTATE_BUFFER(b, CG3State),
|
||||
VMSTATE_UINT8(dac_index, CG3State),
|
||||
VMSTATE_UINT8(dac_state, CG3State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void cg3_reset(DeviceState *d)
|
||||
{
|
||||
CG3State *s = CG3(d);
|
||||
|
||||
/* Initialize palette */
|
||||
memset(s->r, 0, 256);
|
||||
memset(s->g, 0, 256);
|
||||
memset(s->b, 0, 256);
|
||||
|
||||
s->dac_state = 0;
|
||||
s->full_update = 1;
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
|
||||
static Property cg3_properties[] = {
|
||||
DEFINE_PROP_UINT32("vram-size", CG3State, vram_size, -1),
|
||||
DEFINE_PROP_UINT16("width", CG3State, width, -1),
|
||||
DEFINE_PROP_UINT16("height", CG3State, height, -1),
|
||||
DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
|
||||
DEFINE_PROP_UINT64("prom-addr", CG3State, prom_addr, -1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void cg3_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = cg3_realizefn;
|
||||
dc->reset = cg3_reset;
|
||||
dc->vmsd = &vmstate_cg3;
|
||||
dc->props = cg3_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo cg3_info = {
|
||||
.name = TYPE_CG3,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(CG3State),
|
||||
.class_init = cg3_class_init,
|
||||
};
|
||||
|
||||
static void cg3_register_types(void)
|
||||
{
|
||||
type_register_static(&cg3_info);
|
||||
}
|
||||
|
||||
type_init(cg3_register_types)
|
@@ -2917,7 +2917,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
|
||||
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
|
||||
isa_address_space(isadev),
|
||||
isa_address_space_io(isadev));
|
||||
s->con = graphic_console_init(dev, s->hw_ops, s);
|
||||
s->con = graphic_console_init(dev, 0, s->hw_ops, s);
|
||||
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
|
||||
/* XXX ISA-LFB support */
|
||||
/* FIXME not qdev yet */
|
||||
@@ -2963,7 +2963,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
|
||||
vga_common_init(&s->vga, OBJECT(dev));
|
||||
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
|
||||
pci_address_space_io(dev));
|
||||
s->vga.con = graphic_console_init(DEVICE(dev), s->vga.hw_ops, &s->vga);
|
||||
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
|
||||
|
||||
/* setup PCI */
|
||||
|
||||
|
@@ -1917,7 +1917,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev)
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
|
||||
"exynos4210.fimd", FIMD_REGS_SIZE);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
s->console = graphic_console_init(DEVICE(dev), &exynos4210_fimd_ops, s);
|
||||
s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -484,7 +484,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
|
||||
{
|
||||
s->vram = g_malloc0(s->vram_size);
|
||||
|
||||
s->con = graphic_console_init(dev, &g364fb_ops, s);
|
||||
s->con = graphic_console_init(dev, 0, &g364fb_ops, s);
|
||||
|
||||
memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
|
||||
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
|
||||
|
@@ -271,7 +271,7 @@ static int jazz_led_init(SysBusDevice *dev)
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
s->con = graphic_console_init(DEVICE(dev), &jazz_led_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -290,7 +290,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev)
|
||||
"milkymist-vgafb", R_MAX * 4);
|
||||
sysbus_init_mmio(dev, &s->regs_region);
|
||||
|
||||
s->con = graphic_console_init(DEVICE(dev), &vgafb_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -406,7 +406,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
|
||||
s->con = graphic_console_init(NULL, &omap_ops, s);
|
||||
s->con = graphic_console_init(NULL, 0, &omap_ops, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@@ -464,7 +464,7 @@ static int pl110_initfn(SysBusDevice *sbd)
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
|
||||
s->con = graphic_console_init(dev, &pl110_gfx_ops, s);
|
||||
s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -1013,7 +1013,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
|
||||
"pxa2xx-lcd-controller", 0x00100000);
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
|
||||
s->con = graphic_console_init(NULL, &pxa2xx_ops, s);
|
||||
s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
|
||||
surface = qemu_console_surface(s->con);
|
||||
|
||||
switch (surface_bits_per_pixel(surface)) {
|
||||
|
@@ -1429,7 +1429,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
|
||||
static void qxl_set_mode(PCIQXLDevice *d, unsigned int modenr, int loadvm)
|
||||
{
|
||||
pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
|
||||
pcibus_t end = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
|
||||
@@ -1439,6 +1439,12 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
|
||||
.mem_start = start,
|
||||
.mem_end = end
|
||||
};
|
||||
|
||||
if (modenr >= d->modes->n_modes) {
|
||||
qxl_set_guest_bug(d, "mode number out of range");
|
||||
return;
|
||||
}
|
||||
|
||||
QXLSurfaceCreate surface = {
|
||||
.width = mode->x_res,
|
||||
.height = mode->y_res,
|
||||
@@ -2063,7 +2069,7 @@ static int qxl_init_primary(PCIDevice *dev)
|
||||
portio_list_set_flush_coalesced(qxl_vga_port_list);
|
||||
portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
|
||||
|
||||
vga->con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
|
||||
vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
|
||||
qemu_spice_display_init_common(&qxl->ssd);
|
||||
|
||||
rc = qxl_init_common(qxl);
|
||||
@@ -2088,7 +2094,7 @@ static int qxl_init_secondary(PCIDevice *dev)
|
||||
qxl->vga.vram_size);
|
||||
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
|
||||
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
|
||||
qxl->vga.con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
|
||||
qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
|
||||
|
||||
return qxl_init_common(qxl);
|
||||
}
|
||||
|
@@ -1449,5 +1449,5 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
|
||||
}
|
||||
|
||||
/* create qemu graphic console */
|
||||
s->con = graphic_console_init(DEVICE(dev), &sm501_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
|
||||
}
|
||||
|
@@ -299,7 +299,7 @@ static int ssd0303_init(I2CSlave *i2c)
|
||||
{
|
||||
ssd0303_state *s = SSD0303(i2c);
|
||||
|
||||
s->con = graphic_console_init(DEVICE(i2c), &ssd0303_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s);
|
||||
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -342,7 +342,7 @@ static int ssd0323_init(SSISlave *dev)
|
||||
|
||||
s->col_end = 63;
|
||||
s->row_end = 79;
|
||||
s->con = graphic_console_init(DEVICE(dev), &ssd0323_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s);
|
||||
qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
|
||||
|
||||
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
|
||||
|
@@ -587,7 +587,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
|
||||
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
|
||||
s->scr_width = 480;
|
||||
s->scr_height = 640;
|
||||
s->con = graphic_console_init(NULL, &tc6393xb_gfx_ops, s);
|
||||
s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@@ -602,14 +602,14 @@ static int tcx_init1(SysBusDevice *dev)
|
||||
&s->vram_mem, vram_offset, size);
|
||||
sysbus_init_mmio(dev, &s->vram_cplane);
|
||||
|
||||
s->con = graphic_console_init(DEVICE(dev), &tcx24_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s);
|
||||
} else {
|
||||
/* THC 8 bit (dummy) */
|
||||
memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8",
|
||||
TCX_THC_NREGS_8);
|
||||
sysbus_init_mmio(dev, &s->thc8);
|
||||
|
||||
s->con = graphic_console_init(DEVICE(dev), &tcx_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s);
|
||||
}
|
||||
|
||||
qemu_console_resize(s->con, s->width, s->height);
|
||||
|
@@ -135,7 +135,7 @@ int isa_vga_mm_init(hwaddr vram_base,
|
||||
vga_common_init(&s->vga, NULL);
|
||||
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
|
||||
|
||||
s->vga.con = graphic_console_init(NULL, s->vga.hw_ops, s);
|
||||
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
|
||||
|
||||
vga_init_vbe(&s->vga, NULL, address_space);
|
||||
return 0;
|
||||
|
@@ -67,7 +67,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
isa_mem_base + 0x000a0000,
|
||||
vga_io_memory, 1);
|
||||
memory_region_set_coalescing(vga_io_memory);
|
||||
s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
|
||||
|
||||
vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev));
|
||||
/* ROM BIOS */
|
||||
|
@@ -151,7 +151,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
|
||||
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
|
||||
true);
|
||||
|
||||
s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
|
||||
|
||||
/* XXX: VGA_RAM_SIZE must be a power of two */
|
||||
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
|
||||
|
@@ -1199,7 +1199,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
|
||||
s->scratch_size = SVGA_SCRATCH_SIZE;
|
||||
s->scratch = g_malloc(s->scratch_size * 4);
|
||||
|
||||
s->vga.con = graphic_console_init(dev, &vmsvga_ops, s);
|
||||
s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s);
|
||||
|
||||
s->fifo_size = SVGA_FIFO_SIZE;
|
||||
memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);
|
||||
|
@@ -227,7 +227,8 @@ static const VMStateDescription vmstate_pl330_queue = {
|
||||
};
|
||||
|
||||
struct PL330State {
|
||||
SysBusDevice busdev;
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq_abort;
|
||||
qemu_irq *irq;
|
||||
@@ -577,7 +578,7 @@ static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
|
||||
|
||||
static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
|
||||
{
|
||||
DB_PRINT("ch: %p, flags: %x\n", ch, flags);
|
||||
DB_PRINT("ch: %p, flags: %" PRIx32 "\n", ch, flags);
|
||||
ch->fault_type |= flags;
|
||||
if (ch->state == pl330_chan_fault) {
|
||||
return;
|
||||
@@ -600,10 +601,12 @@ static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
|
||||
* LEN - number of elements in ARGS array
|
||||
*/
|
||||
|
||||
static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
static void pl330_dmaadxh(PL330Chan *ch, uint8_t *args, bool ra, bool neg)
|
||||
{
|
||||
uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]);
|
||||
uint8_t ra = (opcode >> 1) & 1;
|
||||
uint32_t im = (args[1] << 8) | args[0];
|
||||
if (neg) {
|
||||
im |= 0xffffu << 16;
|
||||
}
|
||||
|
||||
if (ch->is_manager) {
|
||||
pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
|
||||
@@ -616,6 +619,16 @@ static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
}
|
||||
}
|
||||
|
||||
static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
{
|
||||
pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), false);
|
||||
}
|
||||
|
||||
static void pl330_dmaadnh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
{
|
||||
pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), true);
|
||||
}
|
||||
|
||||
static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
|
||||
uint8_t *args, int len)
|
||||
{
|
||||
@@ -723,7 +736,8 @@ static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
|
||||
size, num, inc, 0, ch->tag);
|
||||
if (!ch->stall) {
|
||||
DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
|
||||
DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
|
||||
" num:%" PRId32 " %c\n",
|
||||
ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
|
||||
ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
|
||||
}
|
||||
@@ -868,9 +882,10 @@ static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
}
|
||||
if (ch->parent->inten & (1 << ev_id)) {
|
||||
ch->parent->int_status |= (1 << ev_id);
|
||||
DB_PRINT("event interrupt raised %d\n", ev_id);
|
||||
DB_PRINT("event interrupt raised %" PRId8 "\n", ev_id);
|
||||
qemu_irq_raise(ch->parent->irq[ev_id]);
|
||||
}
|
||||
DB_PRINT("event raised %" PRId8 "\n", ev_id);
|
||||
ch->parent->ev_status |= (1 << ev_id);
|
||||
}
|
||||
|
||||
@@ -895,7 +910,8 @@ static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
|
||||
size, num, inc, 0, ch->tag);
|
||||
if (!ch->stall) {
|
||||
DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
|
||||
DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
|
||||
" num:%" PRId32 " %c\n",
|
||||
ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
|
||||
ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
|
||||
}
|
||||
@@ -972,6 +988,7 @@ static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
|
||||
}
|
||||
}
|
||||
ch->parent->ev_status &= ~(1 << ev_id);
|
||||
DB_PRINT("event lowered %" PRIx8 "\n", ev_id);
|
||||
} else {
|
||||
ch->stall = 1;
|
||||
}
|
||||
@@ -1037,6 +1054,7 @@ static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode,
|
||||
/* NULL terminated array of the instruction descriptions. */
|
||||
static const PL330InsnDesc insn_desc[] = {
|
||||
{ .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, },
|
||||
{ .opcode = 0x5c, .opmask = 0xFD, .size = 3, .exec = pl330_dmaadnh, },
|
||||
{ .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, },
|
||||
{ .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, },
|
||||
{ .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
|
||||
@@ -1108,7 +1126,6 @@ static int pl330_chan_exec(PL330Chan *ch)
|
||||
ch->state != pl330_chan_waiting_periph &&
|
||||
ch->state != pl330_chan_at_barrier &&
|
||||
ch->state != pl330_chan_waiting_event) {
|
||||
DB_PRINT("%d\n", ch->state);
|
||||
return 0;
|
||||
}
|
||||
ch->stall = 0;
|
||||
@@ -1155,7 +1172,7 @@ static int pl330_exec_cycle(PL330Chan *channel)
|
||||
|
||||
dma_memory_read(&address_space_memory, q->addr, buf, len);
|
||||
if (PL330_ERR_DEBUG > 1) {
|
||||
DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
|
||||
DB_PRINT("PL330 read from memory @%08" PRIx32 " (size = %08x):\n",
|
||||
q->addr, len);
|
||||
qemu_hexdump((char *)buf, stderr, "", len);
|
||||
}
|
||||
@@ -1187,8 +1204,8 @@ static int pl330_exec_cycle(PL330Chan *channel)
|
||||
if (fifo_res == PL330_FIFO_OK || q->z) {
|
||||
dma_memory_write(&address_space_memory, q->addr, buf, len);
|
||||
if (PL330_ERR_DEBUG > 1) {
|
||||
DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
|
||||
q->addr, len);
|
||||
DB_PRINT("PL330 read from memory @%08" PRIx32
|
||||
" (size = %08x):\n", q->addr, len);
|
||||
qemu_hexdump((char *)buf, stderr, "", len);
|
||||
}
|
||||
if (q->inc) {
|
||||
@@ -1277,7 +1294,7 @@ static void pl330_debug_exec(PL330State *s)
|
||||
args[2] = (s->dbg[1] >> 8) & 0xff;
|
||||
args[3] = (s->dbg[1] >> 16) & 0xff;
|
||||
args[4] = (s->dbg[1] >> 24) & 0xff;
|
||||
DB_PRINT("chan id: %d\n", chan_id);
|
||||
DB_PRINT("chan id: %" PRIx8 "\n", chan_id);
|
||||
if (s->dbg[0] & 1) {
|
||||
ch = &s->chan[chan_id];
|
||||
} else {
|
||||
@@ -1311,7 +1328,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PL330State *s = (PL330State *) opaque;
|
||||
uint32_t i;
|
||||
int i;
|
||||
|
||||
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
|
||||
|
||||
@@ -1467,8 +1484,8 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque,
|
||||
static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
int ret = pl330_iomem_read_imp(opaque, offset);
|
||||
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret);
|
||||
uint32_t ret = pl330_iomem_read_imp(opaque, offset);
|
||||
DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1554,7 +1571,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
||||
s->cfg[1] |= 5;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Bad value for i-cache_len property: %d\n",
|
||||
error_setg(errp, "Bad value for i-cache_len property: %" PRIx8 "\n",
|
||||
s->i_cache_len);
|
||||
return;
|
||||
}
|
||||
@@ -1589,7 +1606,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
||||
s->cfg[CFG_CRD] |= 0x4;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Bad value for data_width property: %d\n",
|
||||
error_setg(errp, "Bad value for data_width property: %" PRIx8 "\n",
|
||||
s->data_width);
|
||||
return;
|
||||
}
|
||||
@@ -1602,7 +1619,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
pl330_queue_init(&s->read_queue, s->rd_q_dep, s);
|
||||
pl330_queue_init(&s->write_queue, s->wr_q_dep, s);
|
||||
pl330_fifo_init(&s->fifo, s->data_buffer_dep);
|
||||
pl330_fifo_init(&s->fifo, s->data_width / 4 * s->data_buffer_dep);
|
||||
}
|
||||
|
||||
static Property pl330_properties[] = {
|
||||
|
@@ -743,6 +743,7 @@ static void assign_failed_examine(AssignedDevice *dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
driver[r] = 0;
|
||||
ns = strrchr(driver, '/');
|
||||
if (!ns) {
|
||||
goto fail;
|
||||
|
@@ -167,7 +167,7 @@ static int pci_piix_ide_initfn(PCIDevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
{
|
||||
PCIIDEState *pci_ide;
|
||||
DriveInfo *di;
|
||||
@@ -266,7 +266,6 @@ static void piix3_ide_xen_class_init(ObjectClass *klass, void *data)
|
||||
k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
|
||||
k->class_id = PCI_CLASS_STORAGE_IDE;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->unplug = pci_piix3_xen_ide_unplug;
|
||||
}
|
||||
|
||||
static const TypeInfo piix3_ide_xen_info = {
|
||||
|
@@ -25,3 +25,4 @@ obj-$(CONFIG_SH4) += sh_intc.o
|
||||
obj-$(CONFIG_XICS) += xics.o
|
||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
||||
obj-$(CONFIG_S390_FLIC) += s390_flic.o
|
||||
|
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2012 Linaro Limited
|
||||
* Written by Peter Maydell
|
||||
* Save/Restore logic added by Christoffer Dall.
|
||||
*
|
||||
* 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
|
||||
@@ -23,6 +24,20 @@
|
||||
#include "kvm_arm.h"
|
||||
#include "gic_internal.h"
|
||||
|
||||
//#define DEBUG_GIC_KVM
|
||||
|
||||
#ifdef DEBUG_GIC_KVM
|
||||
static const int debug_gic_kvm = 1;
|
||||
#else
|
||||
static const int debug_gic_kvm = 0;
|
||||
#endif
|
||||
|
||||
#define DPRINTF(fmt, ...) do { \
|
||||
if (debug_gic_kvm) { \
|
||||
printf("arm_gic: " fmt , ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
|
||||
#define KVM_ARM_GIC(obj) \
|
||||
OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
|
||||
@@ -72,14 +87,419 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
|
||||
kvm_set_irq(kvm_state, kvm_irq, !!level);
|
||||
}
|
||||
|
||||
static bool kvm_arm_gic_can_save_restore(GICState *s)
|
||||
{
|
||||
return s->dev_fd >= 0;
|
||||
}
|
||||
|
||||
static void kvm_gic_access(GICState *s, int group, int offset,
|
||||
int cpu, uint32_t *val, bool write)
|
||||
{
|
||||
struct kvm_device_attr attr;
|
||||
int type;
|
||||
int err;
|
||||
|
||||
cpu = cpu & 0xff;
|
||||
|
||||
attr.flags = 0;
|
||||
attr.group = group;
|
||||
attr.attr = (((uint64_t)cpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) &
|
||||
KVM_DEV_ARM_VGIC_CPUID_MASK) |
|
||||
(((uint64_t)offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) &
|
||||
KVM_DEV_ARM_VGIC_OFFSET_MASK);
|
||||
attr.addr = (uintptr_t)val;
|
||||
|
||||
if (write) {
|
||||
type = KVM_SET_DEVICE_ATTR;
|
||||
} else {
|
||||
type = KVM_GET_DEVICE_ATTR;
|
||||
}
|
||||
|
||||
err = kvm_device_ioctl(s->dev_fd, type, &attr);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n",
|
||||
strerror(-err));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_gicd_access(GICState *s, int offset, int cpu,
|
||||
uint32_t *val, bool write)
|
||||
{
|
||||
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
|
||||
offset, cpu, val, write);
|
||||
}
|
||||
|
||||
static void kvm_gicc_access(GICState *s, int offset, int cpu,
|
||||
uint32_t *val, bool write)
|
||||
{
|
||||
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
|
||||
offset, cpu, val, write);
|
||||
}
|
||||
|
||||
#define for_each_irq_reg(_ctr, _max_irq, _field_width) \
|
||||
for (_ctr = 0; _ctr < ((_max_irq) / (32 / (_field_width))); _ctr++)
|
||||
|
||||
/*
|
||||
* Translate from the in-kernel field for an IRQ value to/from the qemu
|
||||
* representation.
|
||||
*/
|
||||
typedef void (*vgic_translate_fn)(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel);
|
||||
|
||||
/* synthetic translate function used for clear/set registers to completely
|
||||
* clear a setting using a clear-register before setting the remaing bits
|
||||
* using a set-register */
|
||||
static void translate_clear(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = ~0;
|
||||
} else {
|
||||
/* does not make sense: qemu model doesn't use set/clear regs */
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_enabled(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||
|
||||
if (to_kernel) {
|
||||
*field = GIC_TEST_ENABLED(irq, cm);
|
||||
} else {
|
||||
if (*field & 1) {
|
||||
GIC_SET_ENABLED(irq, cm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_pending(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||
|
||||
if (to_kernel) {
|
||||
*field = gic_test_pending(s, irq, cm);
|
||||
} else {
|
||||
if (*field & 1) {
|
||||
GIC_SET_PENDING(irq, cm);
|
||||
/* TODO: Capture is level-line is held high in the kernel */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_active(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||
|
||||
if (to_kernel) {
|
||||
*field = GIC_TEST_ACTIVE(irq, cm);
|
||||
} else {
|
||||
if (*field & 1) {
|
||||
GIC_SET_ACTIVE(irq, cm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_trigger(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = (GIC_TEST_EDGE_TRIGGER(irq)) ? 0x2 : 0x0;
|
||||
} else {
|
||||
if (*field & 0x2) {
|
||||
GIC_SET_EDGE_TRIGGER(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_priority(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = GIC_GET_PRIORITY(irq, cpu) & 0xff;
|
||||
} else {
|
||||
gic_set_priority(s, cpu, irq, *field & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_targets(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = s->irq_target[irq] & 0xff;
|
||||
} else {
|
||||
s->irq_target[irq] = *field & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_sgisource(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = s->sgi_pending[irq][cpu] & 0xff;
|
||||
} else {
|
||||
s->sgi_pending[irq][cpu] = *field & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a register group from the kernel VGIC */
|
||||
static void kvm_dist_get(GICState *s, uint32_t offset, int width,
|
||||
int maxirq, vgic_translate_fn translate_fn)
|
||||
{
|
||||
uint32_t reg;
|
||||
int i;
|
||||
int j;
|
||||
int irq;
|
||||
int cpu;
|
||||
int regsz = 32 / width; /* irqs per kernel register */
|
||||
uint32_t field;
|
||||
|
||||
for_each_irq_reg(i, maxirq, width) {
|
||||
irq = i * regsz;
|
||||
cpu = 0;
|
||||
while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
|
||||
kvm_gicd_access(s, offset, cpu, ®, false);
|
||||
for (j = 0; j < regsz; j++) {
|
||||
field = extract32(reg, j * width, width);
|
||||
translate_fn(s, irq + j, cpu, &field, false);
|
||||
}
|
||||
|
||||
cpu++;
|
||||
}
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a register group to the kernel VGIC */
|
||||
static void kvm_dist_put(GICState *s, uint32_t offset, int width,
|
||||
int maxirq, vgic_translate_fn translate_fn)
|
||||
{
|
||||
uint32_t reg;
|
||||
int i;
|
||||
int j;
|
||||
int irq;
|
||||
int cpu;
|
||||
int regsz = 32 / width; /* irqs per kernel register */
|
||||
uint32_t field;
|
||||
|
||||
for_each_irq_reg(i, maxirq, width) {
|
||||
irq = i * regsz;
|
||||
cpu = 0;
|
||||
while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
|
||||
reg = 0;
|
||||
for (j = 0; j < regsz; j++) {
|
||||
translate_fn(s, irq + j, cpu, &field, true);
|
||||
reg = deposit32(reg, j * width, width, field);
|
||||
}
|
||||
kvm_gicd_access(s, offset, cpu, ®, true);
|
||||
|
||||
cpu++;
|
||||
}
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_put(GICState *s)
|
||||
{
|
||||
/* TODO: there isn't currently a kernel interface to set the GIC state */
|
||||
uint32_t reg;
|
||||
int i;
|
||||
int cpu;
|
||||
int num_cpu;
|
||||
int num_irq;
|
||||
|
||||
if (!kvm_arm_gic_can_save_restore(s)) {
|
||||
DPRINTF("Cannot put kernel gic state, no kernel interface");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note: We do the restore in a slightly different order than the save
|
||||
* (where the order doesn't matter and is simply ordered according to the
|
||||
* register offset values */
|
||||
|
||||
/*****************************************************************
|
||||
* Distributor State
|
||||
*/
|
||||
|
||||
/* s->enabled -> GICD_CTLR */
|
||||
reg = s->enabled;
|
||||
kvm_gicd_access(s, 0x0, 0, ®, true);
|
||||
|
||||
/* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */
|
||||
kvm_gicd_access(s, 0x4, 0, ®, false);
|
||||
num_irq = ((reg & 0x1f) + 1) * 32;
|
||||
num_cpu = ((reg & 0xe0) >> 5) + 1;
|
||||
|
||||
if (num_irq < s->num_irq) {
|
||||
fprintf(stderr, "Restoring %u IRQs, but kernel supports max %d\n",
|
||||
s->num_irq, num_irq);
|
||||
abort();
|
||||
} else if (num_cpu != s->num_cpu) {
|
||||
fprintf(stderr, "Restoring %u CPU interfaces, kernel only has %d\n",
|
||||
s->num_cpu, num_cpu);
|
||||
/* Did we not create the VCPUs in the kernel yet? */
|
||||
abort();
|
||||
}
|
||||
|
||||
/* TODO: Consider checking compatibility with the IIDR ? */
|
||||
|
||||
/* irq_state[n].enabled -> GICD_ISENABLERn */
|
||||
kvm_dist_put(s, 0x180, 1, s->num_irq, translate_clear);
|
||||
kvm_dist_put(s, 0x100, 1, s->num_irq, translate_enabled);
|
||||
|
||||
/* s->irq_target[irq] -> GICD_ITARGETSRn
|
||||
* (restore targets before pending to ensure the pending state is set on
|
||||
* the appropriate CPU interfaces in the kernel) */
|
||||
kvm_dist_put(s, 0x800, 8, s->num_irq, translate_targets);
|
||||
|
||||
/* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */
|
||||
kvm_dist_put(s, 0x280, 1, s->num_irq, translate_clear);
|
||||
kvm_dist_put(s, 0x200, 1, s->num_irq, translate_pending);
|
||||
|
||||
/* irq_state[n].active -> GICD_ISACTIVERn */
|
||||
kvm_dist_put(s, 0x380, 1, s->num_irq, translate_clear);
|
||||
kvm_dist_put(s, 0x300, 1, s->num_irq, translate_active);
|
||||
|
||||
/* irq_state[n].trigger -> GICD_ICFRn */
|
||||
kvm_dist_put(s, 0xc00, 2, s->num_irq, translate_trigger);
|
||||
|
||||
/* s->priorityX[irq] -> ICD_IPRIORITYRn */
|
||||
kvm_dist_put(s, 0x400, 8, s->num_irq, translate_priority);
|
||||
|
||||
/* s->sgi_pending -> ICD_CPENDSGIRn */
|
||||
kvm_dist_put(s, 0xf10, 8, GIC_NR_SGIS, translate_clear);
|
||||
kvm_dist_put(s, 0xf20, 8, GIC_NR_SGIS, translate_sgisource);
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* CPU Interface(s) State
|
||||
*/
|
||||
|
||||
for (cpu = 0; cpu < s->num_cpu; cpu++) {
|
||||
/* s->cpu_enabled[cpu] -> GICC_CTLR */
|
||||
reg = s->cpu_enabled[cpu];
|
||||
kvm_gicc_access(s, 0x00, cpu, ®, true);
|
||||
|
||||
/* s->priority_mask[cpu] -> GICC_PMR */
|
||||
reg = (s->priority_mask[cpu] & 0xff);
|
||||
kvm_gicc_access(s, 0x04, cpu, ®, true);
|
||||
|
||||
/* s->bpr[cpu] -> GICC_BPR */
|
||||
reg = (s->bpr[cpu] & 0x7);
|
||||
kvm_gicc_access(s, 0x08, cpu, ®, true);
|
||||
|
||||
/* s->abpr[cpu] -> GICC_ABPR */
|
||||
reg = (s->abpr[cpu] & 0x7);
|
||||
kvm_gicc_access(s, 0x1c, cpu, ®, true);
|
||||
|
||||
/* s->apr[n][cpu] -> GICC_APRn */
|
||||
for (i = 0; i < 4; i++) {
|
||||
reg = s->apr[i][cpu];
|
||||
kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_get(GICState *s)
|
||||
{
|
||||
/* TODO: there isn't currently a kernel interface to get the GIC state */
|
||||
uint32_t reg;
|
||||
int i;
|
||||
int cpu;
|
||||
|
||||
if (!kvm_arm_gic_can_save_restore(s)) {
|
||||
DPRINTF("Cannot get kernel gic state, no kernel interface");
|
||||
return;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* Distributor State
|
||||
*/
|
||||
|
||||
/* GICD_CTLR -> s->enabled */
|
||||
kvm_gicd_access(s, 0x0, 0, ®, false);
|
||||
s->enabled = reg & 1;
|
||||
|
||||
/* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */
|
||||
kvm_gicd_access(s, 0x4, 0, ®, false);
|
||||
s->num_irq = ((reg & 0x1f) + 1) * 32;
|
||||
s->num_cpu = ((reg & 0xe0) >> 5) + 1;
|
||||
|
||||
if (s->num_irq > GIC_MAXIRQ) {
|
||||
fprintf(stderr, "Too many IRQs reported from the kernel: %d\n",
|
||||
s->num_irq);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* GICD_IIDR -> ? */
|
||||
kvm_gicd_access(s, 0x8, 0, ®, false);
|
||||
|
||||
/* Verify no GROUP 1 interrupts configured in the kernel */
|
||||
for_each_irq_reg(i, s->num_irq, 1) {
|
||||
kvm_gicd_access(s, 0x80 + (i * 4), 0, ®, false);
|
||||
if (reg != 0) {
|
||||
fprintf(stderr, "Unsupported GICD_IGROUPRn value: %08x\n",
|
||||
reg);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear all the IRQ settings */
|
||||
for (i = 0; i < s->num_irq; i++) {
|
||||
memset(&s->irq_state[i], 0, sizeof(s->irq_state[0]));
|
||||
}
|
||||
|
||||
/* GICD_ISENABLERn -> irq_state[n].enabled */
|
||||
kvm_dist_get(s, 0x100, 1, s->num_irq, translate_enabled);
|
||||
|
||||
/* GICD_ISPENDRn -> irq_state[n].pending + irq_state[n].level */
|
||||
kvm_dist_get(s, 0x200, 1, s->num_irq, translate_pending);
|
||||
|
||||
/* GICD_ISACTIVERn -> irq_state[n].active */
|
||||
kvm_dist_get(s, 0x300, 1, s->num_irq, translate_active);
|
||||
|
||||
/* GICD_ICFRn -> irq_state[n].trigger */
|
||||
kvm_dist_get(s, 0xc00, 2, s->num_irq, translate_trigger);
|
||||
|
||||
/* GICD_IPRIORITYRn -> s->priorityX[irq] */
|
||||
kvm_dist_get(s, 0x400, 8, s->num_irq, translate_priority);
|
||||
|
||||
/* GICD_ITARGETSRn -> s->irq_target[irq] */
|
||||
kvm_dist_get(s, 0x800, 8, s->num_irq, translate_targets);
|
||||
|
||||
/* GICD_CPENDSGIRn -> s->sgi_pending */
|
||||
kvm_dist_get(s, 0xf10, 8, GIC_NR_SGIS, translate_sgisource);
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* CPU Interface(s) State
|
||||
*/
|
||||
|
||||
for (cpu = 0; cpu < s->num_cpu; cpu++) {
|
||||
/* GICC_CTLR -> s->cpu_enabled[cpu] */
|
||||
kvm_gicc_access(s, 0x00, cpu, ®, false);
|
||||
s->cpu_enabled[cpu] = (reg & 1);
|
||||
|
||||
/* GICC_PMR -> s->priority_mask[cpu] */
|
||||
kvm_gicc_access(s, 0x04, cpu, ®, false);
|
||||
s->priority_mask[cpu] = (reg & 0xff);
|
||||
|
||||
/* GICC_BPR -> s->bpr[cpu] */
|
||||
kvm_gicc_access(s, 0x08, cpu, ®, false);
|
||||
s->bpr[cpu] = (reg & 0x7);
|
||||
|
||||
/* GICC_ABPR -> s->abpr[cpu] */
|
||||
kvm_gicc_access(s, 0x1c, cpu, ®, false);
|
||||
s->abpr[cpu] = (reg & 0x7);
|
||||
|
||||
/* GICC_APRn -> s->apr[n][cpu] */
|
||||
for (i = 0; i < 4; i++) {
|
||||
kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, false);
|
||||
s->apr[i][cpu] = reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_reset(DeviceState *dev)
|
||||
@@ -97,6 +517,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
GICState *s = KVM_ARM_GIC(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
|
||||
int ret;
|
||||
|
||||
kgc->parent_realize(dev, errp);
|
||||
if (error_is_set(errp)) {
|
||||
@@ -119,13 +540,27 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->parent_irq[i]);
|
||||
}
|
||||
|
||||
/* Try to create the device via the device control API */
|
||||
s->dev_fd = -1;
|
||||
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false);
|
||||
if (ret >= 0) {
|
||||
s->dev_fd = ret;
|
||||
} else if (ret != -ENODEV && ret != -ENOTSUP) {
|
||||
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Distributor */
|
||||
memory_region_init_reservation(&s->iomem, OBJECT(s),
|
||||
"kvm-gic_dist", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
kvm_arm_register_device(&s->iomem,
|
||||
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
||||
| KVM_VGIC_V2_ADDR_TYPE_DIST);
|
||||
| KVM_VGIC_V2_ADDR_TYPE_DIST,
|
||||
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||
KVM_VGIC_V2_ADDR_TYPE_DIST,
|
||||
s->dev_fd);
|
||||
/* CPU interface for current core. Unlike arm_gic, we don't
|
||||
* provide the "interface for core #N" memory regions, because
|
||||
* cores with a VGIC don't have those.
|
||||
@@ -135,7 +570,10 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
|
||||
kvm_arm_register_device(&s->cpuiomem[0],
|
||||
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
||||
| KVM_VGIC_V2_ADDR_TYPE_CPU);
|
||||
| KVM_VGIC_V2_ADDR_TYPE_CPU,
|
||||
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||
KVM_VGIC_V2_ADDR_TYPE_CPU,
|
||||
s->dev_fd);
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
|
||||
|
@@ -418,7 +418,7 @@ static int exynos4210_combiner_init(SysBusDevice *sbd)
|
||||
qdev_init_gpio_in(dev, exynos4210_combiner_handler, IIC_NIRQ);
|
||||
|
||||
/* Connect SysBusDev irqs to device specific irqs */
|
||||
for (i = 0; i < IIC_NIRQ; i++) {
|
||||
for (i = 0; i < IIC_NGRP; i++) {
|
||||
sysbus_init_irq(sbd, &s->output_irq[i]);
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,7 @@
|
||||
#define GIC_SET_MODEL(irq) s->irq_state[irq].model = true
|
||||
#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false
|
||||
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
|
||||
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
|
||||
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level |= (cm)
|
||||
#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
|
||||
#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
|
||||
#define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true
|
||||
|
322
hw/intc/s390_flic.c
Normal file
322
hw/intc/s390_flic.c
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* QEMU S390x KVM floating interrupt controller (flic)
|
||||
*
|
||||
* Copyright 2014 IBM Corp.
|
||||
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/qemu-file.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define FLIC_SAVE_INITIAL_SIZE getpagesize()
|
||||
#define FLIC_FAILED (-1UL)
|
||||
#define FLIC_SAVEVM_VERSION 1
|
||||
|
||||
void s390_flic_init(void)
|
||||
{
|
||||
DeviceState *dev;
|
||||
int r;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
dev = qdev_create(NULL, "s390-flic");
|
||||
object_property_add_child(qdev_get_machine(), "s390-flic",
|
||||
OBJECT(dev), NULL);
|
||||
r = qdev_init(dev);
|
||||
if (r) {
|
||||
error_report("flic: couldn't create qdev");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* flic_get_all_irqs - store all pending irqs in buffer
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -ENOMEM if buffer is too small,
|
||||
* -EINVAL if attr.group is invalid,
|
||||
* -EFAULT if copying to userspace failed,
|
||||
* on success return number of stored interrupts
|
||||
*/
|
||||
static int flic_get_all_irqs(KVMS390FLICState *flic,
|
||||
void *buf, int len)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_GET_ALL_IRQS,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc == -1 ? -errno : rc;
|
||||
}
|
||||
|
||||
static void flic_enable_pfault(KVMS390FLICState *flic)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_ENABLE,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't enable pfault\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void flic_disable_wait_pfault(KVMS390FLICState *flic)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "flic: couldn't disable pfault\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** flic_enqueue_irqs - returns 0 on success
|
||||
* @buf: pointer to buffer which is passed to kernel
|
||||
* @len: length of buffer
|
||||
* @flic: pointer to flic device state
|
||||
*
|
||||
* Returns: -EINVAL if attr.group is unknown
|
||||
*/
|
||||
static int flic_enqueue_irqs(void *buf, uint64_t len,
|
||||
KVMS390FLICState *flic)
|
||||
{
|
||||
int rc;
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_ENQUEUE,
|
||||
.addr = (uint64_t) buf,
|
||||
.attr = len,
|
||||
};
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
||||
return rc ? -errno : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __get_all_irqs - store all pending irqs in buffer
|
||||
* @flic: pointer to flic device state
|
||||
* @buf: pointer to pointer to a buffer
|
||||
* @len: length of buffer
|
||||
*
|
||||
* Returns: return value of flic_get_all_irqs
|
||||
* Note: Retry and increase buffer size until flic_get_all_irqs
|
||||
* either returns a value >= 0 or a negative error code.
|
||||
* -ENOMEM is an exception, which means the buffer is too small
|
||||
* and we should try again. Other negative error codes can be
|
||||
* -EFAULT and -EINVAL which we ignore at this point
|
||||
*/
|
||||
static int __get_all_irqs(KVMS390FLICState *flic,
|
||||
void **buf, int len)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
/* returns -ENOMEM if buffer is too small and number
|
||||
* of queued interrupts on success */
|
||||
r = flic_get_all_irqs(flic, *buf, len);
|
||||
if (r >= 0) {
|
||||
break;
|
||||
}
|
||||
len *= 2;
|
||||
*buf = g_try_realloc(*buf, len);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
} while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_save - Save pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
*
|
||||
* Note: Pass buf and len to kernel. Start with one page and
|
||||
* increase until buffer is sufficient or maxium size is
|
||||
* reached
|
||||
*/
|
||||
static void kvm_flic_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
KVMS390FLICState *flic = opaque;
|
||||
int len = FLIC_SAVE_INITIAL_SIZE;
|
||||
void *buf;
|
||||
int count;
|
||||
|
||||
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
error_report("flic: couldn't allocate memory");
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
count = __get_all_irqs(flic, &buf, len);
|
||||
if (count < 0) {
|
||||
error_report("flic: couldn't retrieve irqs from kernel, rc %d",
|
||||
count);
|
||||
/* Storing FLIC_FAILED into the count field here will cause the
|
||||
* target system to fail when attempting to load irqs from the
|
||||
* migration state */
|
||||
qemu_put_be64(f, FLIC_FAILED);
|
||||
} else {
|
||||
qemu_put_be64(f, count);
|
||||
qemu_put_buffer(f, (uint8_t *) buf,
|
||||
count * sizeof(struct kvm_s390_irq));
|
||||
}
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_flic_load - Load pending floating interrupts
|
||||
* @f: QEMUFile containing migration state
|
||||
* @opaque: pointer to flic device state
|
||||
* @version_id: version id for migration
|
||||
*
|
||||
* Returns: value of flic_enqueue_irqs, -EINVAL on error
|
||||
* Note: Do nothing when no interrupts where stored
|
||||
* in QEMUFile
|
||||
*/
|
||||
static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
uint64_t len = 0;
|
||||
uint64_t count = 0;
|
||||
void *buf = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (version_id != FLIC_SAVEVM_VERSION) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
flic_enable_pfault((struct KVMS390FLICState *) opaque);
|
||||
|
||||
count = qemu_get_be64(f);
|
||||
len = count * sizeof(struct kvm_s390_irq);
|
||||
if (count == FLIC_FAILED) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (count == 0) {
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
buf = g_try_malloc0(len);
|
||||
if (!buf) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
|
||||
r = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
|
||||
|
||||
out_free:
|
||||
g_free(buf);
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
struct kvm_create_device cd = {0};
|
||||
int ret;
|
||||
|
||||
flic_state->fd = -1;
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
|
||||
trace_flic_no_device_api(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
cd.type = KVM_DEV_TYPE_FLIC;
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
|
||||
if (ret < 0) {
|
||||
trace_flic_create_device(errno);
|
||||
return;
|
||||
}
|
||||
flic_state->fd = cd.fd;
|
||||
|
||||
/* Register savevm handler for floating interrupts */
|
||||
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
|
||||
kvm_flic_load, (void *) flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||
|
||||
unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_reset(DeviceState *dev)
|
||||
{
|
||||
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_FLIC_CLEAR_IRQS,
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
if (flic->fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
flic_disable_wait_pfault(flic);
|
||||
|
||||
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||
if (rc) {
|
||||
trace_flic_reset_failed(errno);
|
||||
}
|
||||
|
||||
flic_enable_pfault(flic);
|
||||
}
|
||||
|
||||
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = kvm_s390_flic_realize;
|
||||
dc->unrealize = kvm_s390_flic_unrealize;
|
||||
dc->reset = kvm_s390_flic_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_s390_flic_info = {
|
||||
.name = TYPE_KVM_S390_FLIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(KVMS390FLICState),
|
||||
.class_init = kvm_s390_flic_class_init,
|
||||
};
|
||||
|
||||
static void kvm_s390_flic_register_types(void)
|
||||
{
|
||||
type_register_static(&kvm_s390_flic_info);
|
||||
}
|
||||
|
||||
type_init(kvm_s390_flic_register_types)
|
@@ -32,7 +32,6 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/devices.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/xilinx.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "exec/address-spaces.h"
|
||||
@@ -49,6 +48,7 @@
|
||||
|
||||
#define NUM_SPI_FLASHES 4
|
||||
|
||||
#define SPI_BASEADDR 0x40a00000
|
||||
#define MEMORY_BASEADDR 0x50000000
|
||||
#define FLASH_BASEADDR 0x86000000
|
||||
#define INTC_BASEADDR 0x81800000
|
||||
@@ -57,6 +57,13 @@
|
||||
#define AXIENET_BASEADDR 0x82780000
|
||||
#define AXIDMA_BASEADDR 0x84600000
|
||||
|
||||
#define AXIDMA_IRQ1 0
|
||||
#define AXIDMA_IRQ0 1
|
||||
#define TIMER_IRQ 2
|
||||
#define AXIENET_IRQ 3
|
||||
#define SPI_IRQ 4
|
||||
#define UART16550_IRQ 5
|
||||
|
||||
static void machine_cpu_reset(MicroBlazeCPU *cpu)
|
||||
{
|
||||
CPUMBState *env = &cpu->env;
|
||||
@@ -111,17 +118,27 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
|
||||
2, 0x89, 0x18, 0x0000, 0x0, 0);
|
||||
|
||||
|
||||
dev = xilinx_intc_create(INTC_BASEADDR, qdev_get_gpio_in(DEVICE(cpu),
|
||||
MB_CPU_IRQ), 4);
|
||||
dev = qdev_create(NULL, "xlnx.xps-intc");
|
||||
qdev_prop_set_uint32(dev, "kind-of-intr", 1 << TIMER_IRQ);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
||||
qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ));
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
|
||||
serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2,
|
||||
irq[5], 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN);
|
||||
irq[UART16550_IRQ], 115200, serial_hds[0],
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
/* 2 timers at irq 2 @ 100 Mhz. */
|
||||
xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000);
|
||||
dev = qdev_create(NULL, "xlnx.xps-timer");
|
||||
qdev_prop_set_uint32(dev, "one-timer-only", 0);
|
||||
qdev_prop_set_uint32(dev, "clock-frequency", 100 * 1000000);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
|
||||
|
||||
/* axi ethernet and dma initialization. */
|
||||
qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet");
|
||||
@@ -138,16 +155,30 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
|
||||
"axistream-connected-target", NULL);
|
||||
cs = object_property_get_link(OBJECT(dma),
|
||||
"axistream-control-connected-target", NULL);
|
||||
xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(ds),
|
||||
STREAM_SLAVE(cs), 0x82780000, irq[3], 0x1000,
|
||||
0x1000);
|
||||
qdev_set_nic_properties(eth0, &nd_table[0]);
|
||||
qdev_prop_set_uint32(eth0, "rxmem", 0x1000);
|
||||
qdev_prop_set_uint32(eth0, "txmem", 0x1000);
|
||||
object_property_set_link(OBJECT(eth0), OBJECT(ds),
|
||||
"axistream-connected", &error_abort);
|
||||
object_property_set_link(OBJECT(eth0), OBJECT(cs),
|
||||
"axistream-control-connected", &error_abort);
|
||||
qdev_init_nofail(eth0);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(eth0), 0, AXIENET_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(eth0), 0, irq[AXIENET_IRQ]);
|
||||
|
||||
ds = object_property_get_link(OBJECT(eth0),
|
||||
"axistream-connected-target", NULL);
|
||||
cs = object_property_get_link(OBJECT(eth0),
|
||||
"axistream-control-connected-target", NULL);
|
||||
xilinx_axidma_init(dma, STREAM_SLAVE(ds), STREAM_SLAVE(cs), 0x84600000,
|
||||
irq[1], irq[0], 100 * 1000000);
|
||||
qdev_prop_set_uint32(dma, "freqhz", 100 * 1000000);
|
||||
object_property_set_link(OBJECT(dma), OBJECT(ds),
|
||||
"axistream-connected", &error_abort);
|
||||
object_property_set_link(OBJECT(dma), OBJECT(cs),
|
||||
"axistream-control-connected", &error_abort);
|
||||
qdev_init_nofail(dma);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, AXIDMA_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dma), 0, irq[AXIDMA_IRQ0]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dma), 1, irq[AXIDMA_IRQ1]);
|
||||
|
||||
{
|
||||
SSIBus *spi;
|
||||
@@ -156,8 +187,8 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
|
||||
qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES);
|
||||
qdev_init_nofail(dev);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, 0x40a00000);
|
||||
sysbus_connect_irq(busdev, 0, irq[4]);
|
||||
sysbus_mmio_map(busdev, 0, SPI_BASEADDR);
|
||||
sysbus_connect_irq(busdev, 0, irq[SPI_IRQ]);
|
||||
|
||||
spi = (SSIBus *)qdev_get_child_bus(dev, "spi");
|
||||
|
||||
|
@@ -30,7 +30,6 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/devices.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/xilinx.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
@@ -48,6 +47,10 @@
|
||||
#define UARTLITE_BASEADDR 0x84000000
|
||||
#define ETHLITE_BASEADDR 0x81000000
|
||||
|
||||
#define TIMER_IRQ 0
|
||||
#define ETHLITE_IRQ 1
|
||||
#define UARTLITE_IRQ 3
|
||||
|
||||
static void machine_cpu_reset(MicroBlazeCPU *cpu)
|
||||
{
|
||||
CPUMBState *env = &cpu->env;
|
||||
@@ -93,16 +96,36 @@ petalogix_s3adsp1800_init(QEMUMachineInitArgs *args)
|
||||
FLASH_SIZE >> 16,
|
||||
1, 0x89, 0x18, 0x0000, 0x0, 1);
|
||||
|
||||
dev = xilinx_intc_create(INTC_BASEADDR, qdev_get_gpio_in(DEVICE(cpu),
|
||||
MB_CPU_IRQ), 0xA);
|
||||
dev = qdev_create(NULL, "xlnx.xps-intc");
|
||||
qdev_prop_set_uint32(dev, "kind-of-intr",
|
||||
1 << ETHLITE_IRQ | 1 << UARTLITE_IRQ);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
||||
qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ));
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
|
||||
sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, irq[3]);
|
||||
sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR,
|
||||
irq[UARTLITE_IRQ]);
|
||||
|
||||
/* 2 timers at irq 2 @ 62 Mhz. */
|
||||
xilinx_timer_create(TIMER_BASEADDR, irq[0], 0, 62 * 1000000);
|
||||
xilinx_ethlite_create(&nd_table[0], ETHLITE_BASEADDR, irq[1], 0, 0);
|
||||
dev = qdev_create(NULL, "xlnx.xps-timer");
|
||||
qdev_prop_set_uint32(dev, "one-timer-only", 0);
|
||||
qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
|
||||
|
||||
qemu_check_nic_model(&nd_table[0], "xlnx.xps-ethernetlite");
|
||||
dev = qdev_create(NULL, "xlnx.xps-ethernetlite");
|
||||
qdev_set_nic_properties(dev, &nd_table[0]);
|
||||
qdev_prop_set_uint32(dev, "tx-ping-pong", 0);
|
||||
qdev_prop_set_uint32(dev, "rx-ping-pong", 0);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ETHLITE_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]);
|
||||
|
||||
microblaze_load_kernel(cpu, ddr_base, ram_size,
|
||||
args->initrd_filename,
|
||||
|
@@ -276,7 +276,7 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
|
||||
}
|
||||
break;
|
||||
case SYS_CFG_OSC:
|
||||
if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
|
||||
if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
|
||||
/* motherboard clock */
|
||||
*val = s->mb_clock[device];
|
||||
return true;
|
||||
@@ -324,7 +324,7 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
|
||||
|
||||
switch (function) {
|
||||
case SYS_CFG_OSC:
|
||||
if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
|
||||
if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
|
||||
/* motherboard clock */
|
||||
s->mb_clock[device] = val;
|
||||
return true;
|
||||
|
@@ -209,6 +209,29 @@ typedef struct VFIOGroup {
|
||||
QLIST_ENTRY(VFIOGroup) container_next;
|
||||
} VFIOGroup;
|
||||
|
||||
typedef struct VFIORomBlacklistEntry {
|
||||
uint16_t vendor_id;
|
||||
uint16_t device_id;
|
||||
} VFIORomBlacklistEntry;
|
||||
|
||||
/*
|
||||
* List of device ids/vendor ids for which to disable
|
||||
* option rom loading. This avoids the guest hangs during rom
|
||||
* execution as noticed with the BCM 57810 card for lack of a
|
||||
* more better way to handle such issues.
|
||||
* The user can still override by specifying a romfile or
|
||||
* rombar=1.
|
||||
* Please see https://bugs.launchpad.net/qemu/+bug/1284874
|
||||
* for an analysis of the 57810 card hang. When adding
|
||||
* a new vendor id/device id combination below, please also add
|
||||
* your card/environment details and information that could
|
||||
* help in debugging to the bug tracking this issue
|
||||
*/
|
||||
static const VFIORomBlacklistEntry romblacklist[] = {
|
||||
/* Broadcom BCM 57810 */
|
||||
{ 0x14e4, 0x168e }
|
||||
};
|
||||
|
||||
#define MSIX_CAP_LENGTH 12
|
||||
|
||||
static QLIST_HEAD(, VFIOContainer)
|
||||
@@ -1197,13 +1220,43 @@ static const MemoryRegionOps vfio_rom_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static bool vfio_blacklist_opt_rom(VFIODevice *vdev)
|
||||
{
|
||||
PCIDevice *pdev = &vdev->pdev;
|
||||
uint16_t vendor_id, device_id;
|
||||
int count = 0;
|
||||
|
||||
vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
|
||||
device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
|
||||
|
||||
while (count < ARRAY_SIZE(romblacklist)) {
|
||||
if (romblacklist[count].vendor_id == vendor_id &&
|
||||
romblacklist[count].device_id == device_id) {
|
||||
return true;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void vfio_pci_size_rom(VFIODevice *vdev)
|
||||
{
|
||||
uint32_t orig, size = cpu_to_le32((uint32_t)PCI_ROM_ADDRESS_MASK);
|
||||
off_t offset = vdev->config_offset + PCI_ROM_ADDRESS;
|
||||
DeviceState *dev = DEVICE(vdev);
|
||||
char name[32];
|
||||
|
||||
if (vdev->pdev.romfile || !vdev->pdev.rom_bar) {
|
||||
/* Since pci handles romfile, just print a message and return */
|
||||
if (vfio_blacklist_opt_rom(vdev) && vdev->pdev.romfile) {
|
||||
error_printf("Warning : Device at %04x:%02x:%02x.%x "
|
||||
"is known to cause system instability issues during "
|
||||
"option rom execution. "
|
||||
"Proceeding anyway since user specified romfile\n",
|
||||
vdev->host.domain, vdev->host.bus, vdev->host.slot,
|
||||
vdev->host.function);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1227,6 +1280,26 @@ static void vfio_pci_size_rom(VFIODevice *vdev)
|
||||
return;
|
||||
}
|
||||
|
||||
if (vfio_blacklist_opt_rom(vdev)) {
|
||||
if (dev->opts && qemu_opt_get(dev->opts, "rombar")) {
|
||||
error_printf("Warning : Device at %04x:%02x:%02x.%x "
|
||||
"is known to cause system instability issues during "
|
||||
"option rom execution. "
|
||||
"Proceeding anyway since user specified non zero value for "
|
||||
"rombar\n",
|
||||
vdev->host.domain, vdev->host.bus, vdev->host.slot,
|
||||
vdev->host.function);
|
||||
} else {
|
||||
error_printf("Warning : Rom loading for device at "
|
||||
"%04x:%02x:%02x.%x has been disabled due to "
|
||||
"system instability issues. "
|
||||
"Specify rombar=1 or romfile to force\n",
|
||||
vdev->host.domain, vdev->host.bus, vdev->host.slot,
|
||||
vdev->host.function);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("%04x:%02x:%02x.%x ROM size 0x%x\n", vdev->host.domain,
|
||||
vdev->host.bus, vdev->host.slot, vdev->host.function, size);
|
||||
|
||||
@@ -3681,10 +3754,10 @@ static int vfio_initfn(PCIDevice *pdev)
|
||||
|
||||
strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
|
||||
|
||||
len = readlink(path, iommu_group_path, PATH_MAX);
|
||||
if (len <= 0) {
|
||||
len = readlink(path, iommu_group_path, sizeof(path));
|
||||
if (len <= 0 || len >= sizeof(path)) {
|
||||
error_report("vfio: error no iommu_group for device");
|
||||
return -errno;
|
||||
return len < 0 ? -errno : ENAMETOOLONG;
|
||||
}
|
||||
|
||||
iommu_group_path[len] = 0;
|
||||
|
@@ -169,6 +169,7 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
INT_SOURCE_BUSY = 0x10,
|
||||
INT_SOURCE_RXB = 0x4,
|
||||
INT_SOURCE_TXB = 0x1,
|
||||
};
|
||||
@@ -351,8 +352,7 @@ static int open_eth_can_receive(NetClientState *nc)
|
||||
OpenEthState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
return GET_REGBIT(s, MODER, RXEN) &&
|
||||
(s->regs[TX_BD_NUM] < 0x80) &&
|
||||
(rx_desc(s)->len_flags & RXD_E);
|
||||
(s->regs[TX_BD_NUM] < 0x80);
|
||||
}
|
||||
|
||||
static ssize_t open_eth_receive(NetClientState *nc,
|
||||
@@ -402,6 +402,12 @@ static ssize_t open_eth_receive(NetClientState *nc,
|
||||
desc *desc = rx_desc(s);
|
||||
size_t copy_size = GET_REGBIT(s, MODER, HUGEN) ? 65536 : maxfl;
|
||||
|
||||
if (!(desc->len_flags & RXD_E)) {
|
||||
open_eth_int_source_write(s,
|
||||
s->regs[INT_SOURCE] | INT_SOURCE_BUSY);
|
||||
return size;
|
||||
}
|
||||
|
||||
desc->len_flags &= ~(RXD_CF | RXD_M | RXD_OR |
|
||||
RXD_IS | RXD_DN | RXD_TL | RXD_SF | RXD_CRC | RXD_LC);
|
||||
|
||||
@@ -551,6 +557,15 @@ static uint64_t open_eth_reg_read(void *opaque,
|
||||
return v;
|
||||
}
|
||||
|
||||
static void open_eth_notify_can_receive(OpenEthState *s)
|
||||
{
|
||||
NetClientState *nc = qemu_get_queue(s->nic);
|
||||
|
||||
if (open_eth_can_receive(nc)) {
|
||||
qemu_flush_queued_packets(nc);
|
||||
}
|
||||
}
|
||||
|
||||
static void open_eth_ro(OpenEthState *s, uint32_t val)
|
||||
{
|
||||
}
|
||||
@@ -567,6 +582,7 @@ static void open_eth_moder_host_write(OpenEthState *s, uint32_t val)
|
||||
|
||||
if (set & MODER_RXEN) {
|
||||
s->rx_desc = s->regs[TX_BD_NUM];
|
||||
open_eth_notify_can_receive(s);
|
||||
}
|
||||
if (set & MODER_TXEN) {
|
||||
s->tx_desc = 0;
|
||||
@@ -592,6 +608,18 @@ static void open_eth_int_mask_host_write(OpenEthState *s, uint32_t val)
|
||||
s->regs[INT_SOURCE] & s->regs[INT_MASK]);
|
||||
}
|
||||
|
||||
static void open_eth_tx_bd_num_host_write(OpenEthState *s, uint32_t val)
|
||||
{
|
||||
if (val < 0x80) {
|
||||
bool enable = s->regs[TX_BD_NUM] == 0x80;
|
||||
|
||||
s->regs[TX_BD_NUM] = val;
|
||||
if (enable) {
|
||||
open_eth_notify_can_receive(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void open_eth_mii_command_host_write(OpenEthState *s, uint32_t val)
|
||||
{
|
||||
unsigned fiad = GET_REGFIELD(s, MIIADDRESS, FIAD);
|
||||
@@ -630,6 +658,7 @@ static void open_eth_reg_write(void *opaque,
|
||||
[MODER] = open_eth_moder_host_write,
|
||||
[INT_SOURCE] = open_eth_int_source_host_write,
|
||||
[INT_MASK] = open_eth_int_mask_host_write,
|
||||
[TX_BD_NUM] = open_eth_tx_bd_num_host_write,
|
||||
[MIICOMMAND] = open_eth_mii_command_host_write,
|
||||
[MIITX_DATA] = open_eth_mii_tx_host_write,
|
||||
[MIISTATUS] = open_eth_ro,
|
||||
|
@@ -176,7 +176,8 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
|
||||
return val;
|
||||
case 0x14: /* IA0 */
|
||||
return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
|
||||
| (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
|
||||
| (s->conf.macaddr.a[2] << 16)
|
||||
| ((uint32_t)s->conf.macaddr.a[3] << 24);
|
||||
case 0x18: /* IA1 */
|
||||
return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
|
||||
case 0x1c: /* THR */
|
||||
|
@@ -106,7 +106,7 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
|
||||
goto fail;
|
||||
}
|
||||
net->nc = backend;
|
||||
net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
|
||||
net->dev.backend_features = qemu_has_vnet_hdr(backend) ? 0 :
|
||||
(1 << VHOST_NET_F_VIRTIO_NET_HDR);
|
||||
net->backend = r;
|
||||
|
||||
@@ -117,8 +117,8 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
if (!tap_has_vnet_hdr_len(backend,
|
||||
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
|
||||
if (!qemu_has_vnet_hdr_len(backend,
|
||||
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
|
||||
net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
|
||||
}
|
||||
if (~net->dev.features & net->dev.backend_features) {
|
||||
|
@@ -325,11 +325,7 @@ static void peer_test_vnet_hdr(VirtIONet *n)
|
||||
return;
|
||||
}
|
||||
|
||||
if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
|
||||
return;
|
||||
}
|
||||
|
||||
n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer);
|
||||
n->has_vnet_hdr = qemu_has_vnet_hdr(nc->peer);
|
||||
}
|
||||
|
||||
static int peer_has_vnet_hdr(VirtIONet *n)
|
||||
@@ -342,7 +338,7 @@ static int peer_has_ufo(VirtIONet *n)
|
||||
if (!peer_has_vnet_hdr(n))
|
||||
return 0;
|
||||
|
||||
n->has_ufo = tap_has_ufo(qemu_get_queue(n->nic)->peer);
|
||||
n->has_ufo = qemu_has_ufo(qemu_get_queue(n->nic)->peer);
|
||||
|
||||
return n->has_ufo;
|
||||
}
|
||||
@@ -361,8 +357,8 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs)
|
||||
nc = qemu_get_subqueue(n->nic, i);
|
||||
|
||||
if (peer_has_vnet_hdr(n) &&
|
||||
tap_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) {
|
||||
tap_set_vnet_hdr_len(nc->peer, n->guest_hdr_len);
|
||||
qemu_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) {
|
||||
qemu_set_vnet_hdr_len(nc->peer, n->guest_hdr_len);
|
||||
n->host_hdr_len = n->guest_hdr_len;
|
||||
}
|
||||
}
|
||||
@@ -463,7 +459,7 @@ static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
|
||||
|
||||
static void virtio_net_apply_guest_offloads(VirtIONet *n)
|
||||
{
|
||||
tap_set_offload(qemu_get_subqueue(n->nic, 0)->peer,
|
||||
qemu_set_offload(qemu_get_queue(n->nic)->peer,
|
||||
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_CSUM)),
|
||||
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO4)),
|
||||
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO6)),
|
||||
@@ -1544,7 +1540,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
|
||||
peer_test_vnet_hdr(n);
|
||||
if (peer_has_vnet_hdr(n)) {
|
||||
for (i = 0; i < n->max_queues; i++) {
|
||||
tap_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true);
|
||||
qemu_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true);
|
||||
}
|
||||
n->host_hdr_len = sizeof(struct virtio_net_hdr);
|
||||
} else {
|
||||
|
@@ -1290,12 +1290,12 @@ static void vmxnet3_update_features(VMXNET3State *s)
|
||||
s->lro_supported, rxcso_supported,
|
||||
s->rx_vlan_stripping);
|
||||
if (s->peer_has_vhdr) {
|
||||
tap_set_offload(qemu_get_queue(s->nic)->peer,
|
||||
rxcso_supported,
|
||||
s->lro_supported,
|
||||
s->lro_supported,
|
||||
0,
|
||||
0);
|
||||
qemu_set_offload(qemu_get_queue(s->nic)->peer,
|
||||
rxcso_supported,
|
||||
s->lro_supported,
|
||||
s->lro_supported,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1883,11 +1883,9 @@ static NetClientInfo net_vmxnet3_info = {
|
||||
|
||||
static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s)
|
||||
{
|
||||
NetClientState *peer = qemu_get_queue(s->nic)->peer;
|
||||
NetClientState *nc = qemu_get_queue(s->nic);
|
||||
|
||||
if ((NULL != peer) &&
|
||||
(peer->info->type == NET_CLIENT_OPTIONS_KIND_TAP) &&
|
||||
tap_has_vnet_hdr(peer)) {
|
||||
if (qemu_has_vnet_hdr(nc->peer)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1935,10 +1933,10 @@ static void vmxnet3_net_init(VMXNET3State *s)
|
||||
s->lro_supported = false;
|
||||
|
||||
if (s->peer_has_vhdr) {
|
||||
tap_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer,
|
||||
qemu_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer,
|
||||
sizeof(struct virtio_net_hdr));
|
||||
|
||||
tap_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1);
|
||||
qemu_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1);
|
||||
}
|
||||
|
||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||
|
@@ -40,11 +40,19 @@
|
||||
#include "ppc405.h"
|
||||
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/xilinx.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
|
||||
#define EPAPR_MAGIC (0x45504150)
|
||||
#define FLASH_SIZE (16 * 1024 * 1024)
|
||||
|
||||
#define INTC_BASEADDR 0x81800000
|
||||
#define UART16550_BASEADDR 0x83e01003
|
||||
#define TIMER_BASEADDR 0x83c00000
|
||||
#define PFLASH_BASEADDR 0xfc000000
|
||||
|
||||
#define TIMER_IRQ 3
|
||||
#define UART16550_IRQ 9
|
||||
|
||||
static struct boot_info
|
||||
{
|
||||
uint32_t bootstrap_pc;
|
||||
@@ -204,22 +212,31 @@ static void virtex_init(QEMUMachineInitArgs *args)
|
||||
memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
pflash_cfi01_register(0xfc000000, NULL, "virtex.flash", FLASH_SIZE,
|
||||
pflash_cfi01_register(PFLASH_BASEADDR, NULL, "virtex.flash", FLASH_SIZE,
|
||||
dinfo ? dinfo->bdrv : NULL, (64 * 1024),
|
||||
FLASH_SIZE >> 16,
|
||||
1, 0x89, 0x18, 0x0000, 0x0, 1);
|
||||
|
||||
cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
|
||||
dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0);
|
||||
dev = qdev_create(NULL, "xlnx.xps-intc");
|
||||
qdev_prop_set_uint32(dev, "kind-of-intr", 0);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]);
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
|
||||
serial_mm_init(address_space_mem, 0x83e01003ULL, 2, irq[9], 115200,
|
||||
serial_hds[0], DEVICE_LITTLE_ENDIAN);
|
||||
serial_mm_init(address_space_mem, UART16550_BASEADDR, 2, irq[UART16550_IRQ],
|
||||
115200, serial_hds[0], DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
/* 2 timers at irq 2 @ 62 Mhz. */
|
||||
xilinx_timer_create(0x83c00000, irq[3], 0, 62 * 1000000);
|
||||
dev = qdev_create(NULL, "xlnx.xps-timer");
|
||||
qdev_prop_set_uint32(dev, "one-timer-only", 0);
|
||||
qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
|
||||
|
||||
if (kernel_filename) {
|
||||
uint64_t entry, low, high;
|
||||
|
@@ -21,13 +21,13 @@
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/event-facility.h"
|
||||
|
||||
typedef struct EventTypesBus {
|
||||
typedef struct SCLPEventsBus {
|
||||
BusState qbus;
|
||||
} EventTypesBus;
|
||||
} SCLPEventsBus;
|
||||
|
||||
struct SCLPEventFacility {
|
||||
EventTypesBus sbus;
|
||||
DeviceState *qdev;
|
||||
SysBusDevice parent_obj;
|
||||
SCLPEventsBus sbus;
|
||||
/* guest' receive mask */
|
||||
unsigned int receive_mask;
|
||||
};
|
||||
@@ -291,7 +291,7 @@ static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static const TypeInfo s390_sclp_events_bus_info = {
|
||||
static const TypeInfo sclp_events_bus_info = {
|
||||
.name = TYPE_SCLP_EVENTS_BUS,
|
||||
.parent = TYPE_BUS,
|
||||
.class_init = sclp_events_bus_class_init,
|
||||
@@ -299,7 +299,7 @@ static const TypeInfo s390_sclp_events_bus_info = {
|
||||
|
||||
static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
|
||||
{
|
||||
switch (code) {
|
||||
switch (code & SCLP_CMD_CODE_MASK) {
|
||||
case SCLP_CMD_READ_EVENT_DATA:
|
||||
read_event_data(ef, sccb);
|
||||
break;
|
||||
@@ -315,21 +315,26 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
|
||||
}
|
||||
}
|
||||
|
||||
static int init_event_facility(S390SCLPDevice *sdev)
|
||||
static const VMStateDescription vmstate_event_facility = {
|
||||
.name = "vmstate-event-facility",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(receive_mask, SCLPEventFacility),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static int init_event_facility(SCLPEventFacility *event_facility)
|
||||
{
|
||||
SCLPEventFacility *event_facility;
|
||||
DeviceState *sdev = DEVICE(event_facility);
|
||||
DeviceState *quiesce;
|
||||
|
||||
event_facility = g_malloc0(sizeof(SCLPEventFacility));
|
||||
sdev->ef = event_facility;
|
||||
sdev->sclp_command_handler = command_handler;
|
||||
sdev->event_pending = event_pending;
|
||||
|
||||
/* Spawn a new sclp-events facility */
|
||||
/* Spawn a new bus for SCLP events */
|
||||
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
|
||||
TYPE_SCLP_EVENTS_BUS, DEVICE(sdev), NULL);
|
||||
TYPE_SCLP_EVENTS_BUS, sdev, NULL);
|
||||
event_facility->sbus.qbus.allow_hotplug = 0;
|
||||
event_facility->qdev = (DeviceState *) sdev;
|
||||
|
||||
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
|
||||
if (!quiesce) {
|
||||
@@ -346,43 +351,57 @@ static int init_event_facility(S390SCLPDevice *sdev)
|
||||
|
||||
static void reset_event_facility(DeviceState *dev)
|
||||
{
|
||||
S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev);
|
||||
SCLPEventFacility *sdev = EVENT_FACILITY(dev);
|
||||
|
||||
sdev->ef->receive_mask = 0;
|
||||
sdev->receive_mask = 0;
|
||||
}
|
||||
|
||||
static void init_event_facility_class(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(sbdc);
|
||||
SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
|
||||
|
||||
dc->reset = reset_event_facility;
|
||||
dc->vmsd = &vmstate_event_facility;
|
||||
k->init = init_event_facility;
|
||||
k->command_handler = command_handler;
|
||||
k->event_pending = event_pending;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_sclp_event_facility_info = {
|
||||
.name = "s390-sclp-event-facility",
|
||||
.parent = TYPE_DEVICE_S390_SCLP,
|
||||
.instance_size = sizeof(S390SCLPDevice),
|
||||
static const TypeInfo sclp_event_facility_info = {
|
||||
.name = TYPE_SCLP_EVENT_FACILITY,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SCLPEventFacility),
|
||||
.class_init = init_event_facility_class,
|
||||
.class_size = sizeof(SCLPEventFacilityClass),
|
||||
};
|
||||
|
||||
static int event_qdev_init(DeviceState *qdev)
|
||||
static void event_realize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
|
||||
SCLPEvent *event = SCLP_EVENT(qdev);
|
||||
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
|
||||
|
||||
return child->init(event);
|
||||
if (child->init) {
|
||||
int rc = child->init(event);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "SCLP event initialization failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int event_qdev_exit(DeviceState *qdev)
|
||||
static void event_unrealize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
|
||||
SCLPEvent *event = SCLP_EVENT(qdev);
|
||||
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
|
||||
if (child->exit) {
|
||||
child->exit(event);
|
||||
int rc = child->exit(event);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "SCLP event exit failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void event_class_init(ObjectClass *klass, void *data)
|
||||
@@ -391,11 +410,11 @@ static void event_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
dc->bus_type = TYPE_SCLP_EVENTS_BUS;
|
||||
dc->unplug = qdev_simple_unplug_cb;
|
||||
dc->init = event_qdev_init;
|
||||
dc->exit = event_qdev_exit;
|
||||
dc->realize = event_realize;
|
||||
dc->unrealize = event_unrealize;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_sclp_event_type_info = {
|
||||
static const TypeInfo sclp_event_type_info = {
|
||||
.name = TYPE_SCLP_EVENT,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(SCLPEvent),
|
||||
@@ -406,9 +425,9 @@ static const TypeInfo s390_sclp_event_type_info = {
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&s390_sclp_events_bus_info);
|
||||
type_register_static(&s390_sclp_event_facility_info);
|
||||
type_register_static(&s390_sclp_event_type_info);
|
||||
type_register_static(&sclp_events_bus_info);
|
||||
type_register_static(&sclp_event_facility_info);
|
||||
type_register_static(&sclp_event_type_info);
|
||||
}
|
||||
|
||||
type_init(register_types)
|
||||
|
@@ -95,7 +95,8 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
|
||||
uint64_t pentry = KERN_IMAGE_START;
|
||||
kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
|
||||
NULL, 1, ELF_MACHINE, 0);
|
||||
if (kernel_size == -1) {
|
||||
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
|
||||
@@ -104,15 +105,19 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
|
||||
return -1;
|
||||
}
|
||||
/* we have to overwrite values in the kernel image, which are "rom" */
|
||||
strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
|
||||
|
||||
/*
|
||||
* we can not rely on the ELF entry point, since up to 3.2 this
|
||||
* value was 0x800 (the SALIPL loader) and it wont work. For
|
||||
* all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
|
||||
* Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
|
||||
* kernel parameters here as well. Note: For old kernels (up to 3.2)
|
||||
* we can not rely on the ELF entry point - it was 0x800 (the SALIPL
|
||||
* loader) and it won't work. For this case we force it to 0x10000, too.
|
||||
*/
|
||||
ipl->start_addr = KERN_IMAGE_START;
|
||||
if (pentry == KERN_IMAGE_START || pentry == 0x800) {
|
||||
ipl->start_addr = KERN_IMAGE_START;
|
||||
/* Overwrite parameters in the kernel image, which are "rom" */
|
||||
strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
|
||||
} else {
|
||||
ipl->start_addr = pentry;
|
||||
}
|
||||
}
|
||||
if (ipl->initrd) {
|
||||
ram_addr_t initrd_offset;
|
||||
|
@@ -13,13 +13,14 @@
|
||||
#include "exec/address-spaces.h"
|
||||
#include "s390-virtio.h"
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "ioinst.h"
|
||||
#include "css.h"
|
||||
#include "virtio-ccw.h"
|
||||
|
||||
void io_subsystem_reset(void)
|
||||
{
|
||||
DeviceState *css, *sclp;
|
||||
DeviceState *css, *sclp, *flic;
|
||||
|
||||
css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
|
||||
if (css) {
|
||||
@@ -30,6 +31,10 @@ void io_subsystem_reset(void)
|
||||
if (sclp) {
|
||||
qdev_reset_all(sclp);
|
||||
}
|
||||
flic = DEVICE(object_resolve_path_type("", "s390-flic", NULL));
|
||||
if (flic) {
|
||||
qdev_reset_all(flic);
|
||||
}
|
||||
}
|
||||
|
||||
static int virtio_ccw_hcall_notify(const uint64_t *args)
|
||||
@@ -99,6 +104,7 @@ static void ccw_init(QEMUMachineInitArgs *args)
|
||||
s390_sclp_init();
|
||||
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
|
||||
args->initrd_filename, "s390-ccw.img");
|
||||
s390_flic_init();
|
||||
|
||||
/* register hypercalls */
|
||||
virtio_ccw_register_hcalls();
|
||||
|
@@ -26,11 +26,15 @@ void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
|
||||
|
||||
int s390_virtio_hypercall(CPUS390XState *env)
|
||||
{
|
||||
s390_virtio_fn fn = s390_diag500_table[env->regs[1]];
|
||||
s390_virtio_fn fn;
|
||||
|
||||
if (!fn) {
|
||||
return -EINVAL;
|
||||
if (env->regs[1] < MAX_DIAG_SUBCODES) {
|
||||
fn = s390_diag500_table[env->regs[1]];
|
||||
if (fn) {
|
||||
env->regs[2] = fn(&env->regs[2]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return fn(&env->regs[2]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "hw/s390x/s390-virtio-bus.h"
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/s390x/s390-virtio.h"
|
||||
|
||||
//#define DEBUG_S390
|
||||
@@ -251,6 +252,7 @@ static void s390_init(QEMUMachineInitArgs *args)
|
||||
s390_sclp_init();
|
||||
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
|
||||
args->initrd_filename, ZIPL_FILENAME);
|
||||
s390_flic_init();
|
||||
|
||||
/* register hypercalls */
|
||||
s390_virtio_register_hcalls();
|
||||
|
@@ -18,11 +18,12 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/event-facility.h"
|
||||
|
||||
static inline S390SCLPDevice *get_event_facility(void)
|
||||
static inline SCLPEventFacility *get_event_facility(void)
|
||||
{
|
||||
ObjectProperty *op = object_property_find(qdev_get_machine(),
|
||||
"s390-sclp-event-facility",
|
||||
TYPE_SCLP_EVENT_FACILITY,
|
||||
NULL);
|
||||
assert(op);
|
||||
return op->opaque;
|
||||
@@ -89,9 +90,10 @@ static void sclp_read_cpu_info(SCCB *sccb)
|
||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
|
||||
}
|
||||
|
||||
static void sclp_execute(SCCB *sccb, uint64_t code)
|
||||
static void sclp_execute(SCCB *sccb, uint32_t code)
|
||||
{
|
||||
S390SCLPDevice *sdev = get_event_facility();
|
||||
SCLPEventFacility *ef = get_event_facility();
|
||||
SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
|
||||
|
||||
switch (code & SCLP_CMD_CODE_MASK) {
|
||||
case SCLP_CMDW_READ_SCP_INFO:
|
||||
@@ -102,12 +104,12 @@ static void sclp_execute(SCCB *sccb, uint64_t code)
|
||||
sclp_read_cpu_info(sccb);
|
||||
break;
|
||||
default:
|
||||
sdev->sclp_command_handler(sdev->ef, sccb, code);
|
||||
efc->command_handler(ef, sccb, code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int sclp_service_call(uint32_t sccb, uint64_t code)
|
||||
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
|
||||
{
|
||||
int r = 0;
|
||||
SCCB work_sccb;
|
||||
@@ -115,11 +117,16 @@ int sclp_service_call(uint32_t sccb, uint64_t code)
|
||||
hwaddr sccb_len = sizeof(SCCB);
|
||||
|
||||
/* first some basic checks on program checks */
|
||||
if (env->psw.mask & PSW_MASK_PSTATE) {
|
||||
r = -PGM_PRIVILEGED;
|
||||
goto out;
|
||||
}
|
||||
if (cpu_physical_memory_is_io(sccb)) {
|
||||
r = -PGM_ADDRESSING;
|
||||
goto out;
|
||||
}
|
||||
if (sccb & ~0x7ffffff8ul) {
|
||||
if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa
|
||||
|| (sccb & ~0x7ffffff8UL) != 0) {
|
||||
r = -PGM_SPECIFICATION;
|
||||
goto out;
|
||||
}
|
||||
@@ -151,11 +158,13 @@ out:
|
||||
|
||||
void sclp_service_interrupt(uint32_t sccb)
|
||||
{
|
||||
S390SCLPDevice *sdev = get_event_facility();
|
||||
SCLPEventFacility *ef = get_event_facility();
|
||||
SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
|
||||
|
||||
uint32_t param = sccb & ~3;
|
||||
|
||||
/* Indicate whether an event is still pending */
|
||||
param |= sdev->event_pending(sdev->ef) ? 1 : 0;
|
||||
param |= efc->event_pending(ef) ? 1 : 0;
|
||||
|
||||
if (!param) {
|
||||
/* No need to send an interrupt, there's nothing to be notified about */
|
||||
@@ -168,47 +177,9 @@ void sclp_service_interrupt(uint32_t sccb)
|
||||
|
||||
void s390_sclp_init(void)
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, "s390-sclp-event-facility");
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_SCLP_EVENT_FACILITY);
|
||||
|
||||
object_property_add_child(qdev_get_machine(), "s390-sclp-event-facility",
|
||||
object_property_add_child(qdev_get_machine(), TYPE_SCLP_EVENT_FACILITY,
|
||||
OBJECT(dev), NULL);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
|
||||
static int s390_sclp_dev_init(SysBusDevice *dev)
|
||||
{
|
||||
int r;
|
||||
S390SCLPDevice *sdev = (S390SCLPDevice *)dev;
|
||||
S390SCLPDeviceClass *sclp = SCLP_S390_DEVICE_GET_CLASS(dev);
|
||||
|
||||
r = sclp->init(sdev);
|
||||
if (!r) {
|
||||
assert(sdev->event_pending);
|
||||
assert(sdev->sclp_command_handler);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void s390_sclp_device_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
dc->init = s390_sclp_dev_init;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_sclp_device_info = {
|
||||
.name = TYPE_DEVICE_S390_SCLP,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(S390SCLPDevice),
|
||||
.class_init = s390_sclp_device_class_init,
|
||||
.class_size = sizeof(S390SCLPDeviceClass),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void s390_sclp_register_types(void)
|
||||
{
|
||||
type_register_static(&s390_sclp_device_info);
|
||||
}
|
||||
|
||||
type_init(s390_sclp_register_types)
|
||||
|
@@ -909,7 +909,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case VERIFY_16:
|
||||
if ((buf[1] & 2) == 0) {
|
||||
cmd->xfer = 0;
|
||||
} else if ((buf[1] & 4) == 1) {
|
||||
} else if ((buf[1] & 4) != 0) {
|
||||
cmd->xfer = 1;
|
||||
}
|
||||
cmd->xfer *= dev->blocksize;
|
||||
@@ -1367,6 +1367,11 @@ const struct SCSISense sense_code_WRITE_PROTECTED = {
|
||||
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Data Protection, Space Allocation Failed Write Protect */
|
||||
const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
|
||||
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
|
||||
};
|
||||
|
||||
/*
|
||||
* scsi_build_sense
|
||||
*
|
||||
|
@@ -75,6 +75,8 @@ struct SCSIDiskState
|
||||
bool media_event;
|
||||
bool eject_request;
|
||||
uint64_t wwn;
|
||||
uint64_t port_wwn;
|
||||
uint16_t port_index;
|
||||
uint64_t max_unmap_size;
|
||||
QEMUBH *bh;
|
||||
char *version;
|
||||
@@ -428,6 +430,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
|
||||
case EINVAL:
|
||||
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||
break;
|
||||
case ENOSPC:
|
||||
scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
|
||||
break;
|
||||
default:
|
||||
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
|
||||
break;
|
||||
@@ -617,6 +622,24 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
||||
stq_be_p(&outbuf[buflen], s->wwn);
|
||||
buflen += 8;
|
||||
}
|
||||
|
||||
if (s->port_wwn) {
|
||||
outbuf[buflen++] = 0x61; // SAS / Binary
|
||||
outbuf[buflen++] = 0x93; // PIV / Target port / NAA
|
||||
outbuf[buflen++] = 0; // reserved
|
||||
outbuf[buflen++] = 8;
|
||||
stq_be_p(&outbuf[buflen], s->port_wwn);
|
||||
buflen += 8;
|
||||
}
|
||||
|
||||
if (s->port_index) {
|
||||
outbuf[buflen++] = 0x61; // SAS / Binary
|
||||
outbuf[buflen++] = 0x94; // PIV / Target port / relative target port
|
||||
outbuf[buflen++] = 0; // reserved
|
||||
outbuf[buflen++] = 4;
|
||||
stw_be_p(&outbuf[buflen + 2], s->port_index);
|
||||
buflen += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xb0: /* block limits */
|
||||
@@ -2536,6 +2559,8 @@ static Property scsi_hd_properties[] = {
|
||||
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
|
||||
SCSI_DISK_F_DPOFUA, false),
|
||||
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
|
||||
DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
|
||||
DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
|
||||
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
|
||||
DEFAULT_MAX_UNMAP_SIZE),
|
||||
DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
|
||||
@@ -2584,6 +2609,8 @@ static const TypeInfo scsi_hd_info = {
|
||||
static Property scsi_cd_properties[] = {
|
||||
DEFINE_SCSI_DISK_PROPERTIES(),
|
||||
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
|
||||
DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
|
||||
DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -2647,6 +2674,8 @@ static Property scsi_disk_properties[] = {
|
||||
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
|
||||
SCSI_DISK_F_DPOFUA, false),
|
||||
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
|
||||
DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
|
||||
DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
|
||||
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
|
||||
DEFAULT_MAX_UNMAP_SIZE),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
@@ -37,8 +37,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#include <scsi/sg.h>
|
||||
#include "block/scsi.h"
|
||||
|
||||
#define SCSI_SENSE_BUF_SIZE 96
|
||||
|
||||
#define SG_ERR_DRIVER_TIMEOUT 0x06
|
||||
#define SG_ERR_DRIVER_SENSE 0x08
|
||||
|
||||
|
@@ -60,7 +60,6 @@
|
||||
#define VSCSI_MAX_SECTORS 4096
|
||||
#define VSCSI_REQ_LIMIT 24
|
||||
|
||||
#define SCSI_SENSE_BUF_SIZE 96
|
||||
#define SRP_RSP_SENSE_DATA_LEN 18
|
||||
|
||||
typedef union vscsi_crq {
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/sparc/sun4m.h"
|
||||
#include "hw/timer/m48t59.h"
|
||||
@@ -561,6 +562,31 @@ static void tcx_init(hwaddr addr, int vram_size, int width,
|
||||
}
|
||||
}
|
||||
|
||||
static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
|
||||
int height, int depth)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *s;
|
||||
|
||||
dev = qdev_create(NULL, "cgthree");
|
||||
qdev_prop_set_uint32(dev, "vram-size", vram_size);
|
||||
qdev_prop_set_uint16(dev, "width", width);
|
||||
qdev_prop_set_uint16(dev, "height", height);
|
||||
qdev_prop_set_uint16(dev, "depth", depth);
|
||||
qdev_prop_set_uint64(dev, "prom-addr", addr);
|
||||
qdev_init_nofail(dev);
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
|
||||
/* FCode ROM */
|
||||
sysbus_mmio_map(s, 0, addr);
|
||||
/* DAC */
|
||||
sysbus_mmio_map(s, 1, addr + 0x400000ULL);
|
||||
/* 8-bit plane */
|
||||
sysbus_mmio_map(s, 2, addr + 0x800000ULL);
|
||||
|
||||
sysbus_connect_irq(s, 0, irq);
|
||||
}
|
||||
|
||||
/* NCR89C100/MACIO Internal ID register */
|
||||
|
||||
#define TYPE_MACIO_ID_REGISTER "macio_idreg"
|
||||
@@ -914,13 +940,43 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
|
||||
slavio_irq[16], iommu, &ledma_irq, 1);
|
||||
|
||||
if (graphic_depth != 8 && graphic_depth != 24) {
|
||||
fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
|
||||
error_report("Unsupported depth: %d", graphic_depth);
|
||||
exit (1);
|
||||
}
|
||||
num_vsimms = 0;
|
||||
if (num_vsimms == 0) {
|
||||
tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
|
||||
graphic_depth);
|
||||
if (vga_interface_type == VGA_CG3) {
|
||||
if (graphic_depth != 8) {
|
||||
error_report("Unsupported depth: %d", graphic_depth);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!(graphic_width == 1024 && graphic_height == 768) &&
|
||||
!(graphic_width == 1152 && graphic_height == 900)) {
|
||||
error_report("Unsupported resolution: %d x %d", graphic_width,
|
||||
graphic_height);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* sbus irq 5 */
|
||||
cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000,
|
||||
graphic_width, graphic_height, graphic_depth);
|
||||
} else {
|
||||
/* If no display specified, default to TCX */
|
||||
if (graphic_depth != 8 && graphic_depth != 24) {
|
||||
error_report("Unsupported depth: %d", graphic_depth);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!(graphic_width == 1024 && graphic_height == 768)) {
|
||||
error_report("Unsupported resolution: %d x %d",
|
||||
graphic_width, graphic_height);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
|
||||
graphic_depth);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = num_vsimms; i < MAX_VSIMMS; i++) {
|
||||
|
@@ -320,6 +320,7 @@ static uint64_t icp_pit_read(void *opaque, hwaddr offset,
|
||||
n = offset >> 8;
|
||||
if (n > 2) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return arm_timer_read(s->timer[n], offset & 0xff);
|
||||
@@ -334,6 +335,7 @@ static void icp_pit_write(void *opaque, hwaddr offset,
|
||||
n = offset >> 8;
|
||||
if (n > 2) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||
return;
|
||||
}
|
||||
|
||||
arm_timer_write(s->timer[n], offset & 0xff, value);
|
||||
|
@@ -51,7 +51,7 @@ typedef struct CPUTimerState {
|
||||
ptimer_state *timer;
|
||||
uint32_t count, counthigh, reached;
|
||||
/* processor only */
|
||||
uint32_t running;
|
||||
uint32_t run;
|
||||
uint64_t limit;
|
||||
} CPUTimerState;
|
||||
|
||||
@@ -177,7 +177,7 @@ static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
|
||||
// only available in processor counter/timer
|
||||
// read start/stop status
|
||||
if (timer_index > 0) {
|
||||
ret = t->running;
|
||||
ret = t->run;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
@@ -260,16 +260,15 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
|
||||
case TIMER_STATUS:
|
||||
if (slavio_timer_is_user(tc)) {
|
||||
// start/stop user counter
|
||||
if ((val & 1) && !t->running) {
|
||||
if (val & 1) {
|
||||
trace_slavio_timer_mem_writel_status_start(timer_index);
|
||||
ptimer_run(t->timer, 0);
|
||||
t->running = 1;
|
||||
} else if (!(val & 1) && t->running) {
|
||||
} else {
|
||||
trace_slavio_timer_mem_writel_status_stop(timer_index);
|
||||
ptimer_stop(t->timer);
|
||||
t->running = 0;
|
||||
}
|
||||
}
|
||||
t->run = val & 1;
|
||||
break;
|
||||
case TIMER_MODE:
|
||||
if (timer_index == 0) {
|
||||
@@ -284,8 +283,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
|
||||
if (val & processor) { // counter -> user timer
|
||||
qemu_irq_lower(curr_timer->irq);
|
||||
// counters are always running
|
||||
ptimer_stop(curr_timer->timer);
|
||||
curr_timer->running = 0;
|
||||
if (!curr_timer->run) {
|
||||
ptimer_stop(curr_timer->timer);
|
||||
}
|
||||
// user timer limit is always the same
|
||||
curr_timer->limit = TIMER_MAX_COUNT64;
|
||||
ptimer_set_limit(curr_timer->timer,
|
||||
@@ -296,13 +296,8 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
|
||||
s->cputimer_mode |= processor;
|
||||
trace_slavio_timer_mem_writel_mode_user(timer_index);
|
||||
} else { // user timer -> counter
|
||||
// stop the user timer if it is running
|
||||
if (curr_timer->running) {
|
||||
ptimer_stop(curr_timer->timer);
|
||||
}
|
||||
// start the counter
|
||||
ptimer_run(curr_timer->timer, 0);
|
||||
curr_timer->running = 1;
|
||||
// clear this processors user timer bit in config
|
||||
// register
|
||||
s->cputimer_mode &= ~processor;
|
||||
@@ -340,7 +335,7 @@ static const VMStateDescription vmstate_timer = {
|
||||
VMSTATE_UINT32(count, CPUTimerState),
|
||||
VMSTATE_UINT32(counthigh, CPUTimerState),
|
||||
VMSTATE_UINT32(reached, CPUTimerState),
|
||||
VMSTATE_UINT32(running, CPUTimerState),
|
||||
VMSTATE_UINT32(run , CPUTimerState),
|
||||
VMSTATE_PTIMER(timer, CPUTimerState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@@ -373,7 +368,7 @@ static void slavio_timer_reset(DeviceState *d)
|
||||
ptimer_set_limit(curr_timer->timer,
|
||||
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
|
||||
ptimer_run(curr_timer->timer, 0);
|
||||
curr_timer->running = 1;
|
||||
curr_timer->run = 1;
|
||||
}
|
||||
}
|
||||
s->cputimer_mode = 0;
|
||||
|
@@ -98,7 +98,7 @@ static void puv3_load_kernel(const char *kernel_filename)
|
||||
}
|
||||
|
||||
/* cheat curses that we have a graphic console, only under ocd console */
|
||||
graphic_console_init(NULL, &no_ops, NULL);
|
||||
graphic_console_init(NULL, 0, &no_ops, NULL);
|
||||
}
|
||||
|
||||
static void puv3_init(QEMUMachineInitArgs *args)
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/ide.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/xen/xen_common.h"
|
||||
@@ -110,7 +111,7 @@ static void unplug_disks(PCIBus *b, PCIDevice *d, void *o)
|
||||
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
|
||||
PCI_CLASS_STORAGE_IDE
|
||||
&& strcmp(d->name, "xen-pci-passthrough") != 0) {
|
||||
qdev_unplug(DEVICE(d), NULL);
|
||||
pci_piix3_xen_ide_unplug(DEVICE(d));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "xtensa_bootparam.h"
|
||||
|
||||
typedef struct LxBoardDesc {
|
||||
hwaddr flash_base;
|
||||
size_t flash_size;
|
||||
size_t flash_sector_size;
|
||||
size_t sram_size;
|
||||
@@ -219,7 +220,7 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
if (dinfo) {
|
||||
flash = pflash_cfi01_register(0xf8000000,
|
||||
flash = pflash_cfi01_register(board->flash_base,
|
||||
NULL, "lx60.io.flash", board->flash_size,
|
||||
dinfo->bdrv, board->flash_sector_size,
|
||||
board->flash_size / board->flash_sector_size,
|
||||
@@ -265,7 +266,9 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
|
||||
MemoryRegion *flash_io = g_malloc(sizeof(*flash_io));
|
||||
|
||||
memory_region_init_alias(flash_io, NULL, "lx60.flash",
|
||||
flash_mr, 0, board->flash_size);
|
||||
flash_mr, 0,
|
||||
board->flash_size < 0x02000000 ?
|
||||
board->flash_size : 0x02000000);
|
||||
memory_region_add_subregion(system_memory, 0xfe000000,
|
||||
flash_io);
|
||||
}
|
||||
@@ -275,7 +278,8 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
|
||||
static void xtensa_lx60_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
static const LxBoardDesc lx60_board = {
|
||||
.flash_size = 0x400000,
|
||||
.flash_base = 0xf8000000,
|
||||
.flash_size = 0x00400000,
|
||||
.flash_sector_size = 0x10000,
|
||||
.sram_size = 0x20000,
|
||||
};
|
||||
@@ -285,13 +289,36 @@ static void xtensa_lx60_init(QEMUMachineInitArgs *args)
|
||||
static void xtensa_lx200_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
static const LxBoardDesc lx200_board = {
|
||||
.flash_size = 0x1000000,
|
||||
.flash_base = 0xf8000000,
|
||||
.flash_size = 0x01000000,
|
||||
.flash_sector_size = 0x20000,
|
||||
.sram_size = 0x2000000,
|
||||
};
|
||||
lx_init(&lx200_board, args);
|
||||
}
|
||||
|
||||
static void xtensa_ml605_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
static const LxBoardDesc ml605_board = {
|
||||
.flash_base = 0xf8000000,
|
||||
.flash_size = 0x02000000,
|
||||
.flash_sector_size = 0x20000,
|
||||
.sram_size = 0x2000000,
|
||||
};
|
||||
lx_init(&ml605_board, args);
|
||||
}
|
||||
|
||||
static void xtensa_kc705_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
static const LxBoardDesc kc705_board = {
|
||||
.flash_base = 0xf0000000,
|
||||
.flash_size = 0x08000000,
|
||||
.flash_sector_size = 0x20000,
|
||||
.sram_size = 0x2000000,
|
||||
};
|
||||
lx_init(&kc705_board, args);
|
||||
}
|
||||
|
||||
static QEMUMachine xtensa_lx60_machine = {
|
||||
.name = "lx60",
|
||||
.desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
|
||||
@@ -306,10 +333,26 @@ static QEMUMachine xtensa_lx200_machine = {
|
||||
.max_cpus = 4,
|
||||
};
|
||||
|
||||
static QEMUMachine xtensa_ml605_machine = {
|
||||
.name = "ml605",
|
||||
.desc = "ml605 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
|
||||
.init = xtensa_ml605_init,
|
||||
.max_cpus = 4,
|
||||
};
|
||||
|
||||
static QEMUMachine xtensa_kc705_machine = {
|
||||
.name = "kc705",
|
||||
.desc = "kc705 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
|
||||
.init = xtensa_kc705_init,
|
||||
.max_cpus = 4,
|
||||
};
|
||||
|
||||
static void xtensa_lx_machines_init(void)
|
||||
{
|
||||
qemu_register_machine(&xtensa_lx60_machine);
|
||||
qemu_register_machine(&xtensa_lx200_machine);
|
||||
qemu_register_machine(&xtensa_ml605_machine);
|
||||
qemu_register_machine(&xtensa_kc705_machine);
|
||||
}
|
||||
|
||||
machine_init(xtensa_lx_machines_init);
|
||||
|
@@ -102,6 +102,9 @@ typedef enum {
|
||||
#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
|
||||
#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */
|
||||
#define BDRV_O_UNMAP 0x4000 /* execute guest UNMAP/TRIM operations */
|
||||
#define BDRV_O_PROTOCOL 0x8000 /* if no block driver is explicitly given:
|
||||
select an appropriate protocol driver,
|
||||
ignoring the format layer */
|
||||
|
||||
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
|
||||
|
||||
@@ -183,15 +186,13 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
|
||||
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
|
||||
int bdrv_parse_cache_flags(const char *mode, int *flags);
|
||||
int bdrv_parse_discard_flags(const char *mode, int *flags);
|
||||
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
|
||||
const char *reference, QDict *options, int flags,
|
||||
Error **errp);
|
||||
int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
||||
QDict *options, const char *bdref_key, int flags,
|
||||
bool force_raw, bool allow_none, Error **errp);
|
||||
bool allow_none, Error **errp);
|
||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
|
||||
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
int flags, BlockDriver *drv, Error **errp);
|
||||
int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
const char *reference, QDict *options, int flags,
|
||||
BlockDriver *drv, Error **errp);
|
||||
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
||||
BlockDriverState *bs, int flags);
|
||||
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
|
||||
|
@@ -62,12 +62,6 @@ enum {
|
||||
#define NBD_MAX_BUFFER_SIZE (32 * 1024 * 1024)
|
||||
|
||||
ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
|
||||
int tcp_socket_incoming(const char *address, uint16_t port);
|
||||
int tcp_socket_incoming_spec(const char *address_and_port);
|
||||
int tcp_socket_outgoing_opts(QemuOpts *opts);
|
||||
int unix_socket_outgoing(const char *path);
|
||||
int unix_socket_incoming(const char *path);
|
||||
|
||||
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
||||
off_t *size, size_t *blocksize);
|
||||
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
|
||||
|
@@ -17,6 +17,7 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
|
||||
PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
|
||||
PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
|
||||
PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
|
||||
int pci_piix3_xen_ide_unplug(DeviceState *dev);
|
||||
void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
|
||||
|
||||
/* ide-mmio.c */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user