Compare commits
226 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3ffb4001c2 | ||
|
86a8d63bc1 | ||
|
102dd9167c | ||
|
d0ed2d2e8e | ||
|
d194ba1cdb | ||
|
8a0a9cf35b | ||
|
d928541b51 | ||
|
7a6d80e93c | ||
|
447a3b3473 | ||
|
e295c31e25 | ||
|
adf6c527b0 | ||
|
57ee5f77c0 | ||
|
986626efec | ||
|
85a4ca797d | ||
|
e47c212cb5 | ||
|
8afe984ef7 | ||
|
5bb37d151b | ||
|
fe5c13ebf1 | ||
|
6061f16a8a | ||
|
fbcf305e5a | ||
|
37769d2727 | ||
|
23201c64a7 | ||
|
c936f649d4 | ||
|
f63d074313 | ||
|
9b81fbdbb0 | ||
|
7e2191ae98 | ||
|
a25808dc5b | ||
|
3e8088148b | ||
|
6d450bfbc8 | ||
|
abf80f8804 | ||
|
3d3ec7b809 | ||
|
45d6cdff48 | ||
|
ed6857bf98 | ||
|
64dd41bc2d | ||
|
c554919f74 | ||
|
77a0262181 | ||
|
f03969b952 | ||
|
2061800b85 | ||
|
0b23c5d40e | ||
|
1c8a881daa | ||
|
9b12940858 | ||
|
d8e1f214a0 | ||
|
85e83264b2 | ||
|
7e62255a4b | ||
|
aea317aaa5 | ||
|
023ddd7431 | ||
|
eba90e4efc | ||
|
e36b369577 | ||
|
45009a3087 | ||
|
961b42b9dc | ||
|
c03417b438 | ||
|
8dddfb5531 | ||
|
21d4a791da | ||
|
c1b71a1df6 | ||
|
99f08100cd | ||
|
65f9d98673 | ||
|
f76e4c7f16 | ||
|
a425d23f8f | ||
|
2507718baf | ||
|
51711aee8c | ||
|
c16ada980f | ||
|
ad0c93328d | ||
|
ae0f940e6b | ||
|
13bd0b5026 | ||
|
f04303743a | ||
|
684a7a7459 | ||
|
a1fd24af4d | ||
|
bc75c9e50d | ||
|
14f40fdc98 | ||
|
61669f9a83 | ||
|
0fdd2e1d06 | ||
|
c7662daaa2 | ||
|
5bb1cbac4f | ||
|
6ac5f3881f | ||
|
3397f0cb48 | ||
|
612ff3d887 | ||
|
2bc3166c22 | ||
|
fc9d106c8d | ||
|
fd9f102c3e | ||
|
335b8d2068 | ||
|
aac882e7ce | ||
|
20d183b6f0 | ||
|
be85c90b74 | ||
|
4abf12f4ea | ||
|
be35cbbc88 | ||
|
f462141f18 | ||
|
2af2a1b8d0 | ||
|
e30e5eb613 | ||
|
c3fecea50d | ||
|
28b77657cf | ||
|
795928f61d | ||
|
ce4e7e4661 | ||
|
3a395142ba | ||
|
40897c9c16 | ||
|
3439eec34f | ||
|
40d6444e91 | ||
|
ff51a738cf | ||
|
ae392c416c | ||
|
9a93b61730 | ||
|
50322249fd | ||
|
2923d34fdc | ||
|
930b588395 | ||
|
f565403949 | ||
|
1ed520c66e | ||
|
06d9260ffa | ||
|
0f15423c32 | ||
|
38e0735eb7 | ||
|
fa2756b71b | ||
|
a3baf1be67 | ||
|
1571b6cba2 | ||
|
0cd0fd0867 | ||
|
b246721614 | ||
|
5931065907 | ||
|
414c460431 | ||
|
7b863f41de | ||
|
92a114f6f8 | ||
|
e04da7c3d1 | ||
|
bc4268998d | ||
|
725e14e91f | ||
|
96d922a654 | ||
|
9643c25f8d | ||
|
b08d26b76d | ||
|
25cc4a768d | ||
|
05a86f23e5 | ||
|
54dcd0b37e | ||
|
7197390a0b | ||
|
15d4a72338 | ||
|
1e34d859d0 | ||
|
3feef8ad17 | ||
|
5afdec404e | ||
|
57285302af | ||
|
5435352ce6 | ||
|
92c93a816a | ||
|
33ebad1263 | ||
|
f3b338ef4a | ||
|
0fd76ff40b | ||
|
06b863577e | ||
|
00a01ad47a | ||
|
2c20ae11ad | ||
|
245d004947 | ||
|
7082826eb4 | ||
|
00984e3953 | ||
|
1b14254b48 | ||
|
b1beac3db2 | ||
|
599825c565 | ||
|
611b727374 | ||
|
54d50be688 | ||
|
c951d9a675 | ||
|
e6d89f8c25 | ||
|
126197214e | ||
|
4238e26416 | ||
|
b5e4946f96 | ||
|
3f5bd4e1b8 | ||
|
3827cdb1c3 | ||
|
e1556ad5b8 | ||
|
371572dff4 | ||
|
326384d5b6 | ||
|
2a534aff30 | ||
|
771142c2a7 | ||
|
ef81522bc1 | ||
|
854e42f3e8 | ||
|
13449a6e0e | ||
|
e9d86b760c | ||
|
1864b94abb | ||
|
17bb18ce16 | ||
|
b995913853 | ||
|
09ed75f784 | ||
|
27b5979d9d | ||
|
a3efecb847 | ||
|
3fc3abf7ec | ||
|
b2887c43ee | ||
|
7c64d297f9 | ||
|
e7852674d5 | ||
|
88365e47dd | ||
|
74d33d5ce4 | ||
|
0abe905d29 | ||
|
ee71c98434 | ||
|
afd4a65225 | ||
|
b78c2b3aad | ||
|
35914dc724 | ||
|
7dd47667b9 | ||
|
096685fc2a | ||
|
1bbd1592c8 | ||
|
095ed5be7b | ||
|
9d94747262 | ||
|
f2d3476eba | ||
|
a4e2604852 | ||
|
1299c63168 | ||
|
f2338fb48a | ||
|
ee2b399463 | ||
|
9df3b45dd4 | ||
|
d43b45e220 | ||
|
d423675c94 | ||
|
ca716364f0 | ||
|
eb489bb1ec | ||
|
c68b89acd6 | ||
|
980bda8ba2 | ||
|
78439f6af1 | ||
|
802ddc375a | ||
|
f1ef5555c2 | ||
|
c1f8fdc362 | ||
|
a517e88baa | ||
|
b32f6c28d5 | ||
|
bb345110f0 | ||
|
74624688b3 | ||
|
4480de19d9 | ||
|
2df0a3a308 | ||
|
025ccaa7f9 | ||
|
7704df98b0 | ||
|
0e3b800e71 | ||
|
04c5b17a74 | ||
|
99e1dec06f | ||
|
d3c481b357 | ||
|
302d9d6fd8 | ||
|
542379f426 | ||
|
235e510cfd | ||
|
27c8efcb5d | ||
|
4f61927a41 | ||
|
c0465d1a1d | ||
|
95117be5a3 | ||
|
66e3dd9282 | ||
|
4f26f2b6f2 | ||
|
1bf6ccd372 | ||
|
bfc763fcfa | ||
|
cca5de7389 | ||
|
9770b91252 |
10
MAINTAINERS
10
MAINTAINERS
@@ -485,6 +485,11 @@ S: Maintained
|
||||
F: trace/
|
||||
T: git://repo.or.cz/qemu/stefanha.git tracing
|
||||
|
||||
Checkpatch
|
||||
M: Blue Swirl <blauwirbel@gmail.com>
|
||||
S: Odd Fixes
|
||||
F: scripts/checkpatch.pl
|
||||
|
||||
Usermode Emulation
|
||||
------------------
|
||||
BSD user
|
||||
@@ -554,3 +559,8 @@ SPARC target
|
||||
M: Blue Swirl <blauwirbel@gmail.com>
|
||||
S: Maintained
|
||||
F: tcg/sparc/
|
||||
|
||||
TCI target
|
||||
M: Stefan Weil <sw@weilnetz.de>
|
||||
S: Maintained
|
||||
F: tcg/tci
|
||||
|
49
Makefile
49
Makefile
@@ -8,6 +8,7 @@ ifeq ($(TRACE_BACKEND),dtrace)
|
||||
GENERATED_HEADERS += trace-dtrace.h
|
||||
endif
|
||||
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
|
||||
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
|
||||
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
# Put the all: rule here so that config-host.mak can contain dependencies.
|
||||
@@ -167,38 +168,38 @@ check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
|
||||
test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
|
||||
|
||||
$(qapi-obj-y): $(GENERATED_HEADERS)
|
||||
qapi-dir := qapi-generated
|
||||
qapi-dir := $(BUILD_DIR)/qapi-generated
|
||||
test-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
|
||||
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
|
||||
|
||||
$(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
|
||||
$(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
|
||||
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
|
||||
$(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
|
||||
$(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
|
||||
$(qapi-dir)/test-qapi-visit.c $(qapi-dir)/test-qapi-visit.h :\
|
||||
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
|
||||
$(qapi-dir)/test-qmp-commands.h: $(qapi-dir)/test-qmp-marshal.c
|
||||
$(qapi-dir)/test-qmp-marshal.c: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
|
||||
$(qapi-dir)/test-qmp-commands.h $(qapi-dir)/test-qmp-marshal.c :\
|
||||
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
|
||||
|
||||
$(qapi-dir)/qga-qapi-types.c: $(qapi-dir)/qga-qapi-types.h
|
||||
$(qapi-dir)/qga-qapi-types.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
$(qapi-dir)/qga-qapi-types.c $(qapi-dir)/qga-qapi-types.h :\
|
||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
|
||||
$(qapi-dir)/qga-qapi-visit.c: $(qapi-dir)/qga-qapi-visit.h
|
||||
$(qapi-dir)/qga-qapi-visit.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
|
||||
$(qapi-dir)/qga-qapi-visit.c $(qapi-dir)/qga-qapi-visit.h :\
|
||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
|
||||
$(qapi-dir)/qga-qmp-commands.h: $(qapi-dir)/qga-qmp-marshal.c
|
||||
$(qapi-dir)/qga-qmp-marshal.c: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
|
||||
$(qapi-dir)/qga-qmp-commands.h $(qapi-dir)/qga-qmp-marshal.c :\
|
||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
|
||||
|
||||
qapi-types.c: qapi-types.h
|
||||
qapi-types.h: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
qapi-types.c qapi-types.h :\
|
||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "." < $<, " GEN $@")
|
||||
qapi-visit.c: qapi-visit.h
|
||||
qapi-visit.h: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
|
||||
qapi-visit.c qapi-visit.h :\
|
||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "." < $<, " GEN $@")
|
||||
qmp-commands.h: qmp-marshal.c
|
||||
qmp-marshal.c: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
|
||||
qmp-commands.h qmp-marshal.c :\
|
||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -m -o "." < $<, " GEN $@")
|
||||
|
||||
test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
|
||||
@@ -207,11 +208,12 @@ test-visitor: test-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qap
|
||||
test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
|
||||
test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
|
||||
|
||||
QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c)
|
||||
$(QGALIB_GEN): $(GENERATED_HEADERS)
|
||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
||||
QGALIB_OBJ=$(addprefix $(qapi-dir)/, qga-qapi-types.o qga-qapi-visit.o qga-qmp-marshal.o)
|
||||
QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
||||
$(QGALIB_OBJ): $(QGALIB_GEN) $(GENERATED_HEADERS)
|
||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) $(GENERATED_HEADERS)
|
||||
|
||||
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qobject-obj-y) $(version-obj-y) $(addprefix $(qapi-dir)/, qga-qapi-visit.o qga-qapi-types.o qga-qmp-marshal.o)
|
||||
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qobject-obj-y) $(version-obj-y) $(QGALIB_OBJ)
|
||||
|
||||
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
|
||||
|
||||
@@ -227,6 +229,7 @@ clean:
|
||||
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
|
||||
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
|
||||
rm -f trace-dtrace.h trace-dtrace.h-timestamp
|
||||
rm -f $(GENERATED_SOURCES)
|
||||
rm -rf $(qapi-dir)
|
||||
$(MAKE) -C tests clean
|
||||
for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
|
||||
|
@@ -310,8 +310,8 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
|
||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
|
||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
|
||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
|
||||
9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-handle.o
|
||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-synth.o
|
||||
9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-synth.o
|
||||
9pfs-nested-$(CONFIG_OPEN_BY_HANDLE) += virtio-9p-handle.o
|
||||
|
||||
hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
|
||||
$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
|
||||
|
@@ -343,7 +343,7 @@ static void fmod_fini_out (HWVoiceOut *hw)
|
||||
|
||||
static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
|
||||
{
|
||||
int bits16, mode, channel;
|
||||
int mode, channel;
|
||||
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
|
||||
struct audsettings obt_as = *as;
|
||||
|
||||
@@ -374,7 +374,6 @@ static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
|
||||
/* FMOD always operates on little endian frames? */
|
||||
obt_as.endianness = 0;
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
bits16 = (mode & FSOUND_16BITS) != 0;
|
||||
hw->samples = conf.nb_samples;
|
||||
return 0;
|
||||
}
|
||||
@@ -405,7 +404,7 @@ static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
||||
|
||||
static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
|
||||
{
|
||||
int bits16, mode;
|
||||
int mode;
|
||||
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
|
||||
struct audsettings obt_as = *as;
|
||||
|
||||
@@ -432,7 +431,6 @@ static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
|
||||
/* FMOD always operates on little endian frames? */
|
||||
obt_as.endianness = 0;
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
bits16 = (mode & FSOUND_16BITS) != 0;
|
||||
hw->samples = conf.nb_samples;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -521,7 +521,7 @@ static int is_stage2_completed(void)
|
||||
|
||||
if ((remaining_dirty / bwidth) <=
|
||||
migrate_max_downtime()) {
|
||||
/* finish stage2 because we think that we can finish remaing work
|
||||
/* finish stage2 because we think that we can finish remaining work
|
||||
below max_downtime */
|
||||
|
||||
return 1;
|
||||
|
46
block.c
46
block.c
@@ -816,6 +816,13 @@ bool bdrv_dev_has_removable_media(BlockDriverState *bs)
|
||||
return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
|
||||
}
|
||||
|
||||
void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
|
||||
{
|
||||
if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
|
||||
bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
|
||||
}
|
||||
}
|
||||
|
||||
bool bdrv_dev_is_tray_open(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->dev_ops && bs->dev_ops->is_tray_open) {
|
||||
@@ -2782,12 +2789,27 @@ static void coroutine_fn bdrv_flush_co_entry(void *opaque)
|
||||
|
||||
int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!bs->drv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write back cached data to the OS even with cache=unsafe */
|
||||
if (bs->drv->bdrv_co_flush_to_os) {
|
||||
ret = bs->drv->bdrv_co_flush_to_os(bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* But don't actually force it to the disk with cache=unsafe */
|
||||
if (bs->open_flags & BDRV_O_NO_FLUSH) {
|
||||
return 0;
|
||||
} else if (!bs->drv) {
|
||||
return 0;
|
||||
} else if (bs->drv->bdrv_co_flush) {
|
||||
return bs->drv->bdrv_co_flush(bs);
|
||||
}
|
||||
|
||||
if (bs->drv->bdrv_co_flush_to_disk) {
|
||||
return bs->drv->bdrv_co_flush_to_disk(bs);
|
||||
} else if (bs->drv->bdrv_aio_flush) {
|
||||
BlockDriverAIOCB *acb;
|
||||
CoroutineIOCompletion co = {
|
||||
@@ -2817,6 +2839,22 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_invalidate_cache(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->drv && bs->drv->bdrv_invalidate_cache) {
|
||||
bs->drv->bdrv_invalidate_cache(bs);
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_invalidate_cache_all(void)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
||||
bdrv_invalidate_cache(bs);
|
||||
}
|
||||
}
|
||||
|
||||
int bdrv_flush(BlockDriverState *bs)
|
||||
{
|
||||
Coroutine *co;
|
||||
|
14
block.h
14
block.h
@@ -38,6 +38,15 @@ typedef struct BlockDevOps {
|
||||
* Device models with removable media must implement this callback.
|
||||
*/
|
||||
void (*change_media_cb)(void *opaque, bool load);
|
||||
/*
|
||||
* Runs when an eject request is issued from the monitor, the tray
|
||||
* is closed, and the medium is locked.
|
||||
* Device models that do not implement is_medium_locked will not need
|
||||
* this callback. Device models that can lock the medium or tray might
|
||||
* want to implement the callback and unlock the tray when "force" is
|
||||
* true, even if they do not support eject requests.
|
||||
*/
|
||||
void (*eject_request_cb)(void *opaque, bool force);
|
||||
/*
|
||||
* Is the virtual tray open?
|
||||
* Device models implement this only when the device has a tray.
|
||||
@@ -111,6 +120,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev);
|
||||
void *bdrv_get_attached_dev(BlockDriverState *bs);
|
||||
void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
|
||||
void *opaque);
|
||||
void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
|
||||
bool bdrv_dev_has_removable_media(BlockDriverState *bs);
|
||||
bool bdrv_dev_is_tray_open(BlockDriverState *bs);
|
||||
bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
|
||||
@@ -187,6 +197,10 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
|
||||
unsigned long int req, void *buf,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
|
||||
/* Invalidate any cached metadata used by image formats */
|
||||
void bdrv_invalidate_cache(BlockDriverState *bs);
|
||||
void bdrv_invalidate_cache_all(void);
|
||||
|
||||
/* Ensure contents are flushed to disk. */
|
||||
int bdrv_flush(BlockDriverState *bs);
|
||||
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
|
||||
|
22
block/cow.c
22
block/cow.c
@@ -326,16 +326,18 @@ static QEMUOptionParameter cow_create_options[] = {
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_cow = {
|
||||
.format_name = "cow",
|
||||
.instance_size = sizeof(BDRVCowState),
|
||||
.bdrv_probe = cow_probe,
|
||||
.bdrv_open = cow_open,
|
||||
.bdrv_read = cow_co_read,
|
||||
.bdrv_write = cow_co_write,
|
||||
.bdrv_close = cow_close,
|
||||
.bdrv_create = cow_create,
|
||||
.bdrv_co_flush = cow_co_flush,
|
||||
.bdrv_is_allocated = cow_is_allocated,
|
||||
.format_name = "cow",
|
||||
.instance_size = sizeof(BDRVCowState),
|
||||
|
||||
.bdrv_probe = cow_probe,
|
||||
.bdrv_open = cow_open,
|
||||
.bdrv_close = cow_close,
|
||||
.bdrv_create = cow_create,
|
||||
|
||||
.bdrv_read = cow_co_read,
|
||||
.bdrv_write = cow_co_write,
|
||||
.bdrv_co_flush_to_disk = cow_co_flush,
|
||||
.bdrv_is_allocated = cow_is_allocated,
|
||||
|
||||
.create_options = cow_create_options,
|
||||
};
|
||||
|
30
block/qcow.c
30
block/qcow.c
@@ -26,6 +26,7 @@
|
||||
#include "module.h"
|
||||
#include <zlib.h>
|
||||
#include "aes.h"
|
||||
#include "migration.h"
|
||||
|
||||
/**************************************************************/
|
||||
/* QEMU COW block driver with compression and encryption support */
|
||||
@@ -74,6 +75,7 @@ typedef struct BDRVQcowState {
|
||||
AES_KEY aes_encrypt_key;
|
||||
AES_KEY aes_decrypt_key;
|
||||
CoMutex lock;
|
||||
Error *migration_blocker;
|
||||
} BDRVQcowState;
|
||||
|
||||
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
||||
@@ -160,6 +162,12 @@ static int qcow_open(BlockDriverState *bs, int flags)
|
||||
bs->backing_file[len] = '\0';
|
||||
}
|
||||
|
||||
/* Disable migration when qcow images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"qcow", bs->device_name, "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
return 0;
|
||||
|
||||
@@ -604,10 +612,14 @@ static int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
static void qcow_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
|
||||
g_free(s->l1_table);
|
||||
g_free(s->l2_cache);
|
||||
g_free(s->cluster_cache);
|
||||
g_free(s->cluster_data);
|
||||
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
}
|
||||
|
||||
static int qcow_create(const char *filename, QEMUOptionParameter *options)
|
||||
@@ -828,14 +840,16 @@ static BlockDriver bdrv_qcow = {
|
||||
.bdrv_open = qcow_open,
|
||||
.bdrv_close = qcow_close,
|
||||
.bdrv_create = qcow_create,
|
||||
.bdrv_is_allocated = qcow_is_allocated,
|
||||
.bdrv_set_key = qcow_set_key,
|
||||
.bdrv_make_empty = qcow_make_empty,
|
||||
.bdrv_co_readv = qcow_co_readv,
|
||||
.bdrv_co_writev = qcow_co_writev,
|
||||
.bdrv_co_flush = qcow_co_flush,
|
||||
.bdrv_write_compressed = qcow_write_compressed,
|
||||
.bdrv_get_info = qcow_get_info,
|
||||
|
||||
.bdrv_co_readv = qcow_co_readv,
|
||||
.bdrv_co_writev = qcow_co_writev,
|
||||
.bdrv_co_flush_to_disk = qcow_co_flush,
|
||||
.bdrv_is_allocated = qcow_is_allocated,
|
||||
|
||||
.bdrv_set_key = qcow_set_key,
|
||||
.bdrv_make_empty = qcow_make_empty,
|
||||
.bdrv_write_compressed = qcow_write_compressed,
|
||||
.bdrv_get_info = qcow_get_info,
|
||||
|
||||
.create_options = qcow_create_options,
|
||||
};
|
||||
|
@@ -240,6 +240,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
||||
s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
|
||||
+ 512);
|
||||
s->cluster_cache_offset = -1;
|
||||
s->flags = flags;
|
||||
|
||||
ret = qcow2_refcount_init(bs);
|
||||
if (ret != 0) {
|
||||
@@ -632,6 +633,37 @@ static void qcow2_close(BlockDriverState *bs)
|
||||
qcow2_refcount_close(bs);
|
||||
}
|
||||
|
||||
static void qcow2_invalidate_cache(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int flags = s->flags;
|
||||
AES_KEY aes_encrypt_key;
|
||||
AES_KEY aes_decrypt_key;
|
||||
uint32_t crypt_method = 0;
|
||||
|
||||
/*
|
||||
* Backing files are read-only which makes all of their metadata immutable,
|
||||
* that means we don't have to worry about reopening them here.
|
||||
*/
|
||||
|
||||
if (s->crypt_method) {
|
||||
crypt_method = s->crypt_method;
|
||||
memcpy(&aes_encrypt_key, &s->aes_encrypt_key, sizeof(aes_encrypt_key));
|
||||
memcpy(&aes_decrypt_key, &s->aes_decrypt_key, sizeof(aes_decrypt_key));
|
||||
}
|
||||
|
||||
qcow2_close(bs);
|
||||
|
||||
memset(s, 0, sizeof(BDRVQcowState));
|
||||
qcow2_open(bs, flags);
|
||||
|
||||
if (crypt_method) {
|
||||
s->crypt_method = crypt_method;
|
||||
memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
|
||||
memcpy(&s->aes_decrypt_key, &aes_decrypt_key, sizeof(aes_decrypt_key));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the variable length parts of the qcow2 header, i.e. the backing file
|
||||
* name and all extensions. qcow2 was not designed to allow such changes, so if
|
||||
@@ -1105,7 +1137,7 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcow2_co_flush(BlockDriverState *bs)
|
||||
static int qcow2_co_flush_to_os(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int ret;
|
||||
@@ -1124,6 +1156,11 @@ static int qcow2_co_flush(BlockDriverState *bs)
|
||||
}
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcow2_co_flush_to_disk(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_co_flush(bs->file);
|
||||
}
|
||||
|
||||
@@ -1243,9 +1280,10 @@ static BlockDriver bdrv_qcow2 = {
|
||||
.bdrv_set_key = qcow2_set_key,
|
||||
.bdrv_make_empty = qcow2_make_empty,
|
||||
|
||||
.bdrv_co_readv = qcow2_co_readv,
|
||||
.bdrv_co_writev = qcow2_co_writev,
|
||||
.bdrv_co_flush = qcow2_co_flush,
|
||||
.bdrv_co_readv = qcow2_co_readv,
|
||||
.bdrv_co_writev = qcow2_co_writev,
|
||||
.bdrv_co_flush_to_os = qcow2_co_flush_to_os,
|
||||
.bdrv_co_flush_to_disk = qcow2_co_flush_to_disk,
|
||||
|
||||
.bdrv_co_discard = qcow2_co_discard,
|
||||
.bdrv_truncate = qcow2_truncate,
|
||||
@@ -1263,6 +1301,8 @@ static BlockDriver bdrv_qcow2 = {
|
||||
|
||||
.bdrv_change_backing_file = qcow2_change_backing_file,
|
||||
|
||||
.bdrv_invalidate_cache = qcow2_invalidate_cache,
|
||||
|
||||
.create_options = qcow2_create_options,
|
||||
.bdrv_check = qcow2_check,
|
||||
};
|
||||
|
@@ -125,6 +125,8 @@ typedef struct BDRVQcowState {
|
||||
int snapshots_size;
|
||||
int nb_snapshots;
|
||||
QCowSnapshot *snapshots;
|
||||
|
||||
int flags;
|
||||
} BDRVQcowState;
|
||||
|
||||
/* XXX: use std qcow open function ? */
|
||||
|
10
block/qed.c
10
block/qed.c
@@ -16,6 +16,7 @@
|
||||
#include "trace.h"
|
||||
#include "qed.h"
|
||||
#include "qerror.h"
|
||||
#include "migration.h"
|
||||
|
||||
static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
@@ -504,6 +505,12 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
|
||||
s->need_check_timer = qemu_new_timer_ns(vm_clock,
|
||||
qed_need_check_timer_cb, s);
|
||||
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"qed", bs->device_name, "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
|
||||
out:
|
||||
if (ret) {
|
||||
qed_free_l2_cache(&s->l2_cache);
|
||||
@@ -516,6 +523,9 @@ static void bdrv_qed_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
|
||||
qed_cancel_need_check_timer(s);
|
||||
qemu_free_timer(s->need_check_timer);
|
||||
|
||||
|
@@ -164,6 +164,8 @@ typedef struct {
|
||||
|
||||
/* Periodic flush and clear need check flag */
|
||||
QEMUTimer *need_check_timer;
|
||||
|
||||
Error *migration_blocker;
|
||||
} BDRVQEDState;
|
||||
|
||||
enum {
|
||||
|
@@ -281,9 +281,11 @@ static BlockDriver bdrv_file = {
|
||||
.bdrv_file_open = raw_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_create = raw_create,
|
||||
.bdrv_co_flush = raw_flush,
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_co_flush_to_disk = raw_flush,
|
||||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
@@ -409,11 +411,12 @@ static BlockDriver bdrv_host_device = {
|
||||
.bdrv_probe_device = hdev_probe_device,
|
||||
.bdrv_file_open = hdev_open,
|
||||
.bdrv_close = raw_close,
|
||||
.bdrv_co_flush = raw_flush,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_co_flush_to_disk = raw_flush,
|
||||
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
@@ -111,10 +111,10 @@ static BlockDriver bdrv_raw = {
|
||||
.bdrv_open = raw_open,
|
||||
.bdrv_close = raw_close,
|
||||
|
||||
.bdrv_co_readv = raw_co_readv,
|
||||
.bdrv_co_writev = raw_co_writev,
|
||||
.bdrv_co_flush = raw_co_flush,
|
||||
.bdrv_co_discard = raw_co_discard,
|
||||
.bdrv_co_readv = raw_co_readv,
|
||||
.bdrv_co_writev = raw_co_writev,
|
||||
.bdrv_co_flush_to_disk = raw_co_flush,
|
||||
.bdrv_co_discard = raw_co_discard,
|
||||
|
||||
.bdrv_probe = raw_probe,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
|
13
block/rbd.c
13
block/rbd.c
@@ -808,7 +808,7 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
|
||||
} while (snap_count == -ERANGE);
|
||||
|
||||
if (snap_count <= 0) {
|
||||
return snap_count;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sn_tab = g_malloc0(snap_count * sizeof(QEMUSnapshotInfo));
|
||||
@@ -827,6 +827,7 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
|
||||
}
|
||||
rbd_snap_list_end(snaps);
|
||||
|
||||
done:
|
||||
*psn_tab = sn_tab;
|
||||
return snap_count;
|
||||
}
|
||||
@@ -851,18 +852,18 @@ static BlockDriver bdrv_rbd = {
|
||||
.bdrv_file_open = qemu_rbd_open,
|
||||
.bdrv_close = qemu_rbd_close,
|
||||
.bdrv_create = qemu_rbd_create,
|
||||
.bdrv_co_flush = qemu_rbd_co_flush,
|
||||
.bdrv_get_info = qemu_rbd_getinfo,
|
||||
.create_options = qemu_rbd_create_options,
|
||||
.bdrv_getlength = qemu_rbd_getlength,
|
||||
.bdrv_truncate = qemu_rbd_truncate,
|
||||
.protocol_name = "rbd",
|
||||
|
||||
.bdrv_aio_readv = qemu_rbd_aio_readv,
|
||||
.bdrv_aio_writev = qemu_rbd_aio_writev,
|
||||
.bdrv_aio_readv = qemu_rbd_aio_readv,
|
||||
.bdrv_aio_writev = qemu_rbd_aio_writev,
|
||||
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
|
||||
|
||||
.bdrv_snapshot_create = qemu_rbd_snap_create,
|
||||
.bdrv_snapshot_list = qemu_rbd_snap_list,
|
||||
.bdrv_snapshot_create = qemu_rbd_snap_create,
|
||||
.bdrv_snapshot_list = qemu_rbd_snap_list,
|
||||
};
|
||||
|
||||
static void bdrv_rbd_init(void)
|
||||
|
@@ -1116,6 +1116,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
/* send a header */
|
||||
ret = do_write(s->fd, &hdr, sizeof(hdr));
|
||||
if (ret) {
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
@@ -1123,6 +1124,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
if (wlen) {
|
||||
ret = do_writev(s->fd, iov, wlen, aio_req->iov_offset);
|
||||
if (ret) {
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
error_report("failed to send a data, %s", strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
|
17
block/vdi.c
17
block/vdi.c
@@ -52,6 +52,7 @@
|
||||
#include "qemu-common.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "migration.h"
|
||||
|
||||
#if defined(CONFIG_UUID)
|
||||
#include <uuid/uuid.h>
|
||||
@@ -203,6 +204,8 @@ typedef struct {
|
||||
uint32_t bmap_sector;
|
||||
/* VDI header (converted to host endianness). */
|
||||
VdiHeader header;
|
||||
|
||||
Error *migration_blocker;
|
||||
} BDRVVdiState;
|
||||
|
||||
/* Change UUID from little endian (IPRT = VirtualBox format) to big endian
|
||||
@@ -454,6 +457,12 @@ static int vdi_open(BlockDriverState *bs, int flags)
|
||||
goto fail_free_bmap;
|
||||
}
|
||||
|
||||
/* Disable migration when vdi images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vdi", bs->device_name, "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free_bmap:
|
||||
@@ -939,6 +948,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
||||
|
||||
static void vdi_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVdiState *s = bs->opaque;
|
||||
|
||||
g_free(s->bmap);
|
||||
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
}
|
||||
|
||||
static coroutine_fn int vdi_co_flush(BlockDriverState *bs)
|
||||
@@ -980,7 +995,7 @@ static BlockDriver bdrv_vdi = {
|
||||
.bdrv_open = vdi_open,
|
||||
.bdrv_close = vdi_close,
|
||||
.bdrv_create = vdi_create,
|
||||
.bdrv_co_flush = vdi_co_flush,
|
||||
.bdrv_co_flush_to_disk = vdi_co_flush,
|
||||
.bdrv_is_allocated = vdi_is_allocated,
|
||||
.bdrv_make_empty = vdi_make_empty,
|
||||
|
||||
|
22
block/vmdk.c
22
block/vmdk.c
@@ -26,7 +26,8 @@
|
||||
#include "qemu-common.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "zlib.h"
|
||||
#include "migration.h"
|
||||
#include <zlib.h>
|
||||
|
||||
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
||||
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
|
||||
@@ -97,6 +98,7 @@ typedef struct BDRVVmdkState {
|
||||
int num_extents;
|
||||
/* Extent array with num_extents entries, ascend ordered by address */
|
||||
VmdkExtent *extents;
|
||||
Error *migration_blocker;
|
||||
} BDRVVmdkState;
|
||||
|
||||
typedef struct VmdkMetaData {
|
||||
@@ -659,7 +661,14 @@ static int vmdk_open(BlockDriverState *bs, int flags)
|
||||
}
|
||||
s->parent_cid = vmdk_read_cid(bs, 1);
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
return ret;
|
||||
|
||||
/* Disable migration when VMDK images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vmdk", bs->device_name, "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
vmdk_free_extents(bs);
|
||||
@@ -1504,7 +1513,12 @@ exit:
|
||||
|
||||
static void vmdk_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
|
||||
vmdk_free_extents(bs);
|
||||
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
}
|
||||
|
||||
static coroutine_fn int vmdk_co_flush(BlockDriverState *bs)
|
||||
@@ -1581,8 +1595,8 @@ static BlockDriver bdrv_vmdk = {
|
||||
.bdrv_write = vmdk_co_write,
|
||||
.bdrv_close = vmdk_close,
|
||||
.bdrv_create = vmdk_create,
|
||||
.bdrv_co_flush = vmdk_co_flush,
|
||||
.bdrv_is_allocated = vmdk_is_allocated,
|
||||
.bdrv_co_flush_to_disk = vmdk_co_flush,
|
||||
.bdrv_is_allocated = vmdk_is_allocated,
|
||||
.bdrv_get_allocated_file_size = vmdk_get_allocated_file_size,
|
||||
|
||||
.create_options = vmdk_create_options,
|
||||
|
32
block/vpc.c
32
block/vpc.c
@@ -25,6 +25,7 @@
|
||||
#include "qemu-common.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "migration.h"
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
@@ -128,6 +129,8 @@ typedef struct BDRVVPCState {
|
||||
|
||||
uint64_t last_bitmap;
|
||||
#endif
|
||||
|
||||
Error *migration_blocker;
|
||||
} BDRVVPCState;
|
||||
|
||||
static uint32_t vpc_checksum(uint8_t* buf, size_t size)
|
||||
@@ -228,6 +231,13 @@ static int vpc_open(BlockDriverState *bs, int flags)
|
||||
#endif
|
||||
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
|
||||
/* Disable migration when VHD images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vpc", bs->device_name, "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
return err;
|
||||
@@ -352,8 +362,11 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
|
||||
|
||||
// Initialize the block's bitmap
|
||||
memset(bitmap, 0xff, s->bitmap_size);
|
||||
bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
|
||||
ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
|
||||
s->bitmap_size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Write new footer (the old one will be overwritten)
|
||||
s->free_data_block_offset += s->block_size + s->bitmap_size;
|
||||
@@ -617,7 +630,11 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
|
||||
|
||||
memcpy(dyndisk_header->magic, "cxsparse", 8);
|
||||
|
||||
dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFF);
|
||||
/*
|
||||
* Note: The spec is actually wrong here for data_offset, it says
|
||||
* 0xFFFFFFFF, but MS tools expect all 64 bits to be set.
|
||||
*/
|
||||
dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
|
||||
dyndisk_header->table_offset = be64_to_cpu(3 * 512);
|
||||
dyndisk_header->version = be32_to_cpu(0x00010000);
|
||||
dyndisk_header->block_size = be32_to_cpu(block_size);
|
||||
@@ -647,6 +664,9 @@ static void vpc_close(BlockDriverState *bs)
|
||||
#ifdef CACHE
|
||||
g_free(s->pageentry_u8);
|
||||
#endif
|
||||
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
}
|
||||
|
||||
static QEMUOptionParameter vpc_create_options[] = {
|
||||
@@ -661,14 +681,16 @@ static QEMUOptionParameter vpc_create_options[] = {
|
||||
static BlockDriver bdrv_vpc = {
|
||||
.format_name = "vpc",
|
||||
.instance_size = sizeof(BDRVVPCState),
|
||||
|
||||
.bdrv_probe = vpc_probe,
|
||||
.bdrv_open = vpc_open,
|
||||
.bdrv_read = vpc_co_read,
|
||||
.bdrv_write = vpc_co_write,
|
||||
.bdrv_co_flush = vpc_co_flush,
|
||||
.bdrv_close = vpc_close,
|
||||
.bdrv_create = vpc_create,
|
||||
|
||||
.bdrv_read = vpc_co_read,
|
||||
.bdrv_write = vpc_co_write,
|
||||
.bdrv_co_flush_to_disk = vpc_co_flush,
|
||||
|
||||
.create_options = vpc_create_options,
|
||||
};
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "qemu-common.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "migration.h"
|
||||
|
||||
#ifndef S_IWGRP
|
||||
#define S_IWGRP 0
|
||||
@@ -350,6 +351,8 @@ typedef struct BDRVVVFATState {
|
||||
array_t commits;
|
||||
const char* path;
|
||||
int downcase_short_names;
|
||||
|
||||
Error *migration_blocker;
|
||||
} BDRVVVFATState;
|
||||
|
||||
/* take the sector position spos and convert it to Cylinder/Head/Sector position
|
||||
@@ -1073,6 +1076,15 @@ DLOG(if (stderr == NULL) {
|
||||
|
||||
// assert(is_consistent(s));
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
|
||||
/* Disable migration when vvfat is used rw */
|
||||
if (s->qcow) {
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vvfat (rw)", bs->device_name, "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1254,15 +1266,15 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
|
||||
return -1;
|
||||
if (s->qcow) {
|
||||
int n;
|
||||
if (s->qcow->drv->bdrv_is_allocated(s->qcow,
|
||||
sector_num, nb_sectors-i, &n)) {
|
||||
if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
|
||||
DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
|
||||
if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
|
||||
return -1;
|
||||
i += n - 1;
|
||||
sector_num += n - 1;
|
||||
continue;
|
||||
}
|
||||
if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
|
||||
return -1;
|
||||
}
|
||||
i += n - 1;
|
||||
sector_num += n - 1;
|
||||
continue;
|
||||
}
|
||||
DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
|
||||
}
|
||||
if(sector_num<s->faked_sectors) {
|
||||
@@ -1516,7 +1528,7 @@ static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
|
||||
return 0;
|
||||
|
||||
for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
|
||||
was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
|
||||
was_modified = bdrv_is_allocated(s->qcow,
|
||||
cluster2sector(s, cluster_num) + i, 1, &dummy);
|
||||
|
||||
return was_modified;
|
||||
@@ -1665,16 +1677,16 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
||||
int64_t offset = cluster2sector(s, cluster_num);
|
||||
|
||||
vvfat_close_current_file(s);
|
||||
for (i = 0; i < s->sectors_per_cluster; i++)
|
||||
if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
|
||||
offset + i, 1, &dummy)) {
|
||||
if (vvfat_read(s->bs,
|
||||
offset, s->cluster_buffer, 1))
|
||||
return -1;
|
||||
if (s->qcow->drv->bdrv_write(s->qcow,
|
||||
offset, s->cluster_buffer, 1))
|
||||
return -2;
|
||||
}
|
||||
for (i = 0; i < s->sectors_per_cluster; i++) {
|
||||
if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
|
||||
if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
|
||||
return -1;
|
||||
}
|
||||
if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2619,7 +2631,9 @@ static int do_commit(BDRVVVFATState* s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->qcow->drv->bdrv_make_empty(s->qcow);
|
||||
if (s->qcow->drv->bdrv_make_empty) {
|
||||
s->qcow->drv->bdrv_make_empty(s->qcow);
|
||||
}
|
||||
|
||||
memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
|
||||
|
||||
@@ -2714,7 +2728,7 @@ DLOG(checkpoint());
|
||||
* Use qcow backend. Commit later.
|
||||
*/
|
||||
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
|
||||
ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
|
||||
ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error writing to qcow backend\n");
|
||||
return ret;
|
||||
@@ -2827,6 +2841,11 @@ static void vvfat_close(BlockDriverState *bs)
|
||||
array_free(&(s->directory));
|
||||
array_free(&(s->mapping));
|
||||
g_free(s->cluster_buffer);
|
||||
|
||||
if (s->qcow) {
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_vvfat = {
|
||||
|
19
block_int.h
19
block_int.h
@@ -84,10 +84,27 @@ struct BlockDriver {
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
|
||||
int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
|
||||
int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
|
||||
int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors);
|
||||
|
||||
/*
|
||||
* Invalidate any cached meta-data.
|
||||
*/
|
||||
void (*bdrv_invalidate_cache)(BlockDriverState *bs);
|
||||
|
||||
/*
|
||||
* Flushes all data that was already written to the OS all the way down to
|
||||
* the disk (for example raw-posix calls fsync()).
|
||||
*/
|
||||
int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs);
|
||||
|
||||
/*
|
||||
* Flushes all internal caches to the OS. The data may still sit in a
|
||||
* writeback cache of the host OS, but it will survive a crash of the qemu
|
||||
* process.
|
||||
*/
|
||||
int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
|
||||
|
||||
int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
|
||||
int num_reqs);
|
||||
int (*bdrv_merge_requests)(BlockDriverState *bs, BlockRequest* a,
|
||||
|
10
blockdev.c
10
blockdev.c
@@ -635,10 +635,12 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
|
||||
qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
|
||||
return -1;
|
||||
}
|
||||
if (!force && !bdrv_dev_is_tray_open(bs)
|
||||
&& bdrv_dev_is_medium_locked(bs)) {
|
||||
qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
|
||||
return -1;
|
||||
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
|
||||
bdrv_dev_eject_request(bs, force);
|
||||
if (!force) {
|
||||
qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
bdrv_close(bs);
|
||||
return 0;
|
||||
|
102
configure
vendored
102
configure
vendored
@@ -129,6 +129,7 @@ xen=""
|
||||
xen_ctrl_version=""
|
||||
linux_aio=""
|
||||
attr=""
|
||||
libattr=""
|
||||
xfs=""
|
||||
|
||||
vhost_net="no"
|
||||
@@ -171,7 +172,7 @@ aix="no"
|
||||
blobs="yes"
|
||||
pkgversion=""
|
||||
check_utests=""
|
||||
user_pie="no"
|
||||
pie=""
|
||||
zero_malloc=""
|
||||
trace_backend="nop"
|
||||
trace_file="trace"
|
||||
@@ -568,6 +569,14 @@ for opt do
|
||||
;;
|
||||
--sysconfdir=*) sysconfdir="$optarg"
|
||||
;;
|
||||
--sbindir=*|--libexecdir=*|--sharedstatedir=*|--localstatedir=*|\
|
||||
--oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\
|
||||
--htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
|
||||
# These switches are silently ignored, for compatibility with
|
||||
# autoconf-generated configure scripts. This allows QEMU's
|
||||
# configure to be used by RPM and similar macros that set
|
||||
# lots of directory switches by default.
|
||||
;;
|
||||
--disable-sdl) sdl="no"
|
||||
;;
|
||||
--enable-sdl) sdl="yes"
|
||||
@@ -700,9 +709,9 @@ for opt do
|
||||
;;
|
||||
--disable-guest-base) guest_base="no"
|
||||
;;
|
||||
--enable-user-pie) user_pie="yes"
|
||||
--enable-pie) pie="yes"
|
||||
;;
|
||||
--disable-user-pie) user_pie="no"
|
||||
--disable-pie) pie="no"
|
||||
;;
|
||||
--enable-uname-release=*) uname_release="$optarg"
|
||||
;;
|
||||
@@ -758,8 +767,6 @@ for opt do
|
||||
;;
|
||||
--enable-opengl) opengl="yes"
|
||||
;;
|
||||
--*dir)
|
||||
;;
|
||||
--disable-rbd) rbd="no"
|
||||
;;
|
||||
--enable-rbd) rbd="yes"
|
||||
@@ -1030,12 +1037,13 @@ echo " --disable-bsd-user disable all BSD usermode emulation targets"
|
||||
echo " --enable-guest-base enable GUEST_BASE support for usermode"
|
||||
echo " emulation targets"
|
||||
echo " --disable-guest-base disable GUEST_BASE support"
|
||||
echo " --enable-user-pie build usermode emulation targets as PIE"
|
||||
echo " --disable-user-pie do not build usermode emulation targets as PIE"
|
||||
echo " --enable-pie build Position Independent Executables"
|
||||
echo " --disable-pie do not build Position Independent Executables"
|
||||
echo " --fmod-lib path to FMOD library"
|
||||
echo " --fmod-inc path to FMOD includes"
|
||||
echo " --oss-lib path to OSS library"
|
||||
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
|
||||
echo " --cpu=CPU Build for host CPU [$cpu]"
|
||||
echo " --sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
|
||||
echo " --disable-uuid disable uuid support"
|
||||
echo " --enable-uuid enable uuid support"
|
||||
@@ -1097,6 +1105,57 @@ for flag in $gcc_flags; do
|
||||
fi
|
||||
done
|
||||
|
||||
if test "$static" = "yes" ; then
|
||||
if test "$pie" = "yes" ; then
|
||||
echo "static and pie are mutually incompatible"
|
||||
exit 1
|
||||
else
|
||||
pie="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$pie" = ""; then
|
||||
case "$cpu-$targetos" in
|
||||
i386-Linux|x86_64-Linux|i386-OpenBSD|x86_64-OpenBSD)
|
||||
;;
|
||||
*)
|
||||
pie="no"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test "$pie" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
|
||||
#ifdef __linux__
|
||||
# define THREAD __thread
|
||||
#else
|
||||
# define THREAD
|
||||
#endif
|
||||
|
||||
static THREAD int tls_var;
|
||||
|
||||
int main(void) { return tls_var; }
|
||||
|
||||
EOF
|
||||
if compile_prog "-fPIE -DPIE" "-pie"; then
|
||||
QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS"
|
||||
LDFLAGS="-pie $LDFLAGS"
|
||||
pie="yes"
|
||||
if compile_prog "" "-Wl,-z,relro -Wl,-z,now" ; then
|
||||
LDFLAGS="-Wl,-z,relro -Wl,-z,now $LDFLAGS"
|
||||
fi
|
||||
else
|
||||
if test "$pie" = "yes"; then
|
||||
echo "PIE not available due to missing toolchain support"
|
||||
exit 1
|
||||
else
|
||||
echo "Disabling PIE due to missing toolchain support"
|
||||
pie="no"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Solaris specific configure tool chain decisions
|
||||
#
|
||||
@@ -1961,12 +2020,20 @@ if test "$attr" != "no" ; then
|
||||
cat > $TMPC <<EOF
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef CONFIG_LIBATTR
|
||||
#include <attr/xattr.h>
|
||||
#else
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
int main(void) { getxattr(NULL, NULL, NULL, 0); setxattr(NULL, NULL, NULL, 0, 0); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "-lattr" ; then
|
||||
if compile_prog "" "" ; then
|
||||
attr=yes
|
||||
# Older distros have <attr/xattr.h>, and need -lattr:
|
||||
elif compile_prog "-DCONFIG_LIBATTR" "-lattr" ; then
|
||||
attr=yes
|
||||
LIBS="-lattr $LIBS"
|
||||
libattr=yes
|
||||
else
|
||||
if test "$attr" = "yes" ; then
|
||||
feature_not_found "ATTR"
|
||||
@@ -2190,7 +2257,7 @@ cat > $TMPC << EOF
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int efd = eventfd(0, 0);
|
||||
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
@@ -2755,7 +2822,7 @@ echo "Documentation $docs"
|
||||
echo "uname -r $uname_release"
|
||||
echo "NPTL support $nptl"
|
||||
echo "GUEST_BASE $guest_base"
|
||||
echo "PIE user targets $user_pie"
|
||||
echo "PIE $pie"
|
||||
echo "vde support $vde"
|
||||
echo "Linux AIO support $linux_aio"
|
||||
echo "ATTR/XATTR support $attr"
|
||||
@@ -3032,6 +3099,9 @@ fi
|
||||
if test "$attr" = "yes" ; then
|
||||
echo "CONFIG_ATTR=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$libattr" = "yes" ; then
|
||||
echo "CONFIG_LIBATTR=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$linux" = "yes" ; then
|
||||
if test "$attr" = "yes" ; then
|
||||
echo "CONFIG_VIRTFS=y" >> $config_host_mak
|
||||
@@ -3212,9 +3282,6 @@ for d in libdis libdis-user; do
|
||||
symlink $source_path/Makefile.dis $d/Makefile
|
||||
echo > $d/config.mak
|
||||
done
|
||||
if test "$static" = "no" -a "$user_pie" = "yes" ; then
|
||||
echo "QEMU_CFLAGS+=-fpie" > libdis-user/config.mak
|
||||
fi
|
||||
|
||||
for target in $target_list; do
|
||||
target_dir="$target"
|
||||
@@ -3633,12 +3700,6 @@ if test "$target_softmmu" = "yes" ; then
|
||||
esac
|
||||
fi
|
||||
|
||||
if test "$target_user_only" = "yes" -a "$static" = "no" -a \
|
||||
"$user_pie" = "yes" ; then
|
||||
cflags="-fpie $cflags"
|
||||
ldflags="-pie $ldflags"
|
||||
fi
|
||||
|
||||
if test "$target_softmmu" = "yes" -a \( \
|
||||
"$TARGET_ARCH" = "microblaze" -o \
|
||||
"$TARGET_ARCH" = "cris" \) ; then
|
||||
@@ -3762,9 +3823,6 @@ d=libuser
|
||||
mkdir -p $d
|
||||
mkdir -p $d/trace
|
||||
symlink $source_path/Makefile.user $d/Makefile
|
||||
if test "$static" = "no" -a "$user_pie" = "yes" ; then
|
||||
echo "QEMU_CFLAGS+=-fpie" > $d/config.mak
|
||||
fi
|
||||
|
||||
if test "$docs" = "yes" ; then
|
||||
mkdir -p QMP
|
||||
|
@@ -186,7 +186,9 @@ void vga_hw_screen_dump(const char *filename)
|
||||
consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
|
||||
}
|
||||
|
||||
console_select(previous_active_console->index);
|
||||
if (previous_active_console) {
|
||||
console_select(previous_active_console->index);
|
||||
}
|
||||
}
|
||||
|
||||
void vga_hw_text_update(console_ch_t *chardata)
|
||||
|
@@ -35,6 +35,10 @@ enum {
|
||||
POOL_MAX_SIZE = 64,
|
||||
};
|
||||
|
||||
/** Free list to speed up creation */
|
||||
static QLIST_HEAD(, Coroutine) pool = QLIST_HEAD_INITIALIZER(pool);
|
||||
static unsigned int pool_size;
|
||||
|
||||
typedef struct {
|
||||
Coroutine base;
|
||||
void *stack;
|
||||
@@ -48,10 +52,6 @@ typedef struct {
|
||||
/** Currently executing coroutine */
|
||||
Coroutine *current;
|
||||
|
||||
/** Free list to speed up creation */
|
||||
QLIST_HEAD(, Coroutine) pool;
|
||||
unsigned int pool_size;
|
||||
|
||||
/** The default coroutine */
|
||||
CoroutineUContext leader;
|
||||
} CoroutineThreadState;
|
||||
@@ -75,7 +75,6 @@ static CoroutineThreadState *coroutine_get_thread_state(void)
|
||||
if (!s) {
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->current = &s->leader.base;
|
||||
QLIST_INIT(&s->pool);
|
||||
pthread_setspecific(thread_state_key, s);
|
||||
}
|
||||
return s;
|
||||
@@ -84,14 +83,19 @@ static CoroutineThreadState *coroutine_get_thread_state(void)
|
||||
static void qemu_coroutine_thread_cleanup(void *opaque)
|
||||
{
|
||||
CoroutineThreadState *s = opaque;
|
||||
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static void __attribute__((destructor)) coroutine_cleanup(void)
|
||||
{
|
||||
Coroutine *co;
|
||||
Coroutine *tmp;
|
||||
|
||||
QLIST_FOREACH_SAFE(co, &s->pool, pool_next, tmp) {
|
||||
QLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
|
||||
g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
|
||||
g_free(co);
|
||||
}
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) coroutine_init(void)
|
||||
@@ -169,13 +173,12 @@ static Coroutine *coroutine_new(void)
|
||||
|
||||
Coroutine *qemu_coroutine_new(void)
|
||||
{
|
||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
||||
Coroutine *co;
|
||||
|
||||
co = QLIST_FIRST(&s->pool);
|
||||
co = QLIST_FIRST(&pool);
|
||||
if (co) {
|
||||
QLIST_REMOVE(co, pool_next);
|
||||
s->pool_size--;
|
||||
pool_size--;
|
||||
} else {
|
||||
co = coroutine_new();
|
||||
}
|
||||
@@ -184,13 +187,12 @@ Coroutine *qemu_coroutine_new(void)
|
||||
|
||||
void qemu_coroutine_delete(Coroutine *co_)
|
||||
{
|
||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
||||
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
|
||||
|
||||
if (s->pool_size < POOL_MAX_SIZE) {
|
||||
QLIST_INSERT_HEAD(&s->pool, &co->base, pool_next);
|
||||
if (pool_size < POOL_MAX_SIZE) {
|
||||
QLIST_INSERT_HEAD(&pool, &co->base, pool_next);
|
||||
co->base.caller = NULL;
|
||||
s->pool_size++;
|
||||
pool_size++;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -172,6 +172,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
|
||||
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
|
||||
#define IO_MEM_NOTDIRTY (3 << IO_MEM_SHIFT)
|
||||
#define IO_MEM_SUBPAGE_RAM (4 << IO_MEM_SHIFT)
|
||||
|
||||
/* Acts like a ROM when read and like a device when written. */
|
||||
#define IO_MEM_ROMD (1)
|
||||
|
86
cutils.c
86
cutils.c
@@ -217,7 +217,10 @@ void qemu_iovec_destroy(QEMUIOVector *qiov)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
qemu_iovec_reset(qiov);
|
||||
g_free(qiov->iov);
|
||||
qiov->nalloc = 0;
|
||||
qiov->iov = NULL;
|
||||
}
|
||||
|
||||
void qemu_iovec_reset(QEMUIOVector *qiov)
|
||||
@@ -315,19 +318,34 @@ int fcntl_setfl(int fd, int flag)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int64_t suffix_mul(char suffix, int64_t unit)
|
||||
{
|
||||
switch (qemu_toupper(suffix)) {
|
||||
case STRTOSZ_DEFSUFFIX_B:
|
||||
return 1;
|
||||
case STRTOSZ_DEFSUFFIX_KB:
|
||||
return unit;
|
||||
case STRTOSZ_DEFSUFFIX_MB:
|
||||
return unit * unit;
|
||||
case STRTOSZ_DEFSUFFIX_GB:
|
||||
return unit * unit * unit;
|
||||
case STRTOSZ_DEFSUFFIX_TB:
|
||||
return unit * unit * unit * unit;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string to bytes, allowing either B/b for bytes, K/k for KB,
|
||||
* M/m for MB, G/g for GB or T/t for TB. Default without any postfix
|
||||
* is MB. End pointer will be returned in *end, if not NULL. A valid
|
||||
* value must be terminated by whitespace, ',' or '\0'. Return -1 on
|
||||
* error.
|
||||
* M/m for MB, G/g for GB or T/t for TB. End pointer will be returned
|
||||
* in *end, if not NULL. Return -1 on error.
|
||||
*/
|
||||
int64_t strtosz_suffix_unit(const char *nptr, char **end,
|
||||
const char default_suffix, int64_t unit)
|
||||
{
|
||||
int64_t retval = -1;
|
||||
char *endptr;
|
||||
unsigned char c, d;
|
||||
unsigned char c;
|
||||
int mul_required = 0;
|
||||
double val, mul, integral, fraction;
|
||||
|
||||
@@ -340,58 +358,16 @@ int64_t strtosz_suffix_unit(const char *nptr, char **end,
|
||||
if (fraction != 0) {
|
||||
mul_required = 1;
|
||||
}
|
||||
/*
|
||||
* Any whitespace character is fine for terminating the number,
|
||||
* in addition we accept ',' to handle strings where the size is
|
||||
* part of a multi token argument.
|
||||
*/
|
||||
c = *endptr;
|
||||
d = c;
|
||||
if (qemu_isspace(c) || c == '\0' || c == ',') {
|
||||
c = 0;
|
||||
if (default_suffix) {
|
||||
d = default_suffix;
|
||||
} else {
|
||||
d = c;
|
||||
}
|
||||
}
|
||||
switch (qemu_toupper(d)) {
|
||||
case STRTOSZ_DEFSUFFIX_B:
|
||||
mul = 1;
|
||||
if (mul_required) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case STRTOSZ_DEFSUFFIX_KB:
|
||||
mul = unit;
|
||||
break;
|
||||
case 0:
|
||||
if (mul_required) {
|
||||
goto fail;
|
||||
}
|
||||
case STRTOSZ_DEFSUFFIX_MB:
|
||||
mul = unit * unit;
|
||||
break;
|
||||
case STRTOSZ_DEFSUFFIX_GB:
|
||||
mul = unit * unit * unit;
|
||||
break;
|
||||
case STRTOSZ_DEFSUFFIX_TB:
|
||||
mul = unit * unit * unit * unit;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
/*
|
||||
* If not terminated by whitespace, ',', or \0, increment endptr
|
||||
* to point to next character, then check that we are terminated
|
||||
* by an appropriate separating character, ie. whitespace, ',', or
|
||||
* \0. If not, we are seeing trailing garbage, thus fail.
|
||||
*/
|
||||
if (c != 0) {
|
||||
mul = suffix_mul(c, unit);
|
||||
if (mul >= 0) {
|
||||
endptr++;
|
||||
if (!qemu_isspace(*endptr) && *endptr != ',' && *endptr != 0) {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
mul = suffix_mul(default_suffix, unit);
|
||||
assert(mul >= 0);
|
||||
}
|
||||
if (mul == 1 && mul_required) {
|
||||
goto fail;
|
||||
}
|
||||
if ((val * mul >= INT64_MAX) || val < 0) {
|
||||
goto fail;
|
||||
|
@@ -170,7 +170,7 @@ public entry point:
|
||||
int cert_count);
|
||||
|
||||
The parameters for this are:
|
||||
card - the virtual card structure which will prepresent this card.
|
||||
card - the virtual card structure which will represent this card.
|
||||
flags - option flags that may be specific to this card type.
|
||||
cert - array of binary certificates.
|
||||
cert_len - array of lengths of each of the certificates specified in cert.
|
||||
@@ -179,7 +179,7 @@ public entry point:
|
||||
cert_count - number of entries in cert, cert_len, and key arrays.
|
||||
|
||||
Any cert, cert_len, or key with the same index are matching sets. That is
|
||||
cert[0] is cert_len[0] long and has the corresponsing private key of key[0].
|
||||
cert[0] is cert_len[0] long and has the corresponding private key of key[0].
|
||||
|
||||
The card type emulator is expected to own the VCardKeys, but it should copy
|
||||
any raw cert data it wants to save. It can create new applets and add them to
|
||||
@@ -261,7 +261,7 @@ Prior to processing calling the card type emulator's VCardProcessAPDU function,
|
||||
apdu->a_Le - The expected length of any returned data.
|
||||
apdu->a_cla - The raw apdu class.
|
||||
apdu->a_channel - The channel (decoded from the class).
|
||||
apdu->a_secure_messaging_type - The decoded secure messagin type
|
||||
apdu->a_secure_messaging_type - The decoded secure messaging type
|
||||
(from class).
|
||||
apdu->a_type - The decode class type.
|
||||
apdu->a_gen_type - the generic class type (7816, PROPRIETARY, RFU, PTS).
|
||||
@@ -273,7 +273,7 @@ Creating a Response --
|
||||
|
||||
The expected result of any APDU call is a response. The card type emulator must
|
||||
set *response with an appropriate VCardResponse value if it returns VCARD_DONE.
|
||||
Reponses could be as simple as returning a 2 byte status word response, to as
|
||||
Responses could be as simple as returning a 2 byte status word response, to as
|
||||
complex as returning a block of data along with a 2 byte response. Which is
|
||||
returned will depend on the semantics of the APDU. The following functions will
|
||||
create card responses.
|
||||
@@ -281,13 +281,13 @@ create card responses.
|
||||
VCardResponse *vcard_make_response(VCard7816Status status);
|
||||
|
||||
This is the most basic function to get a response. This function will
|
||||
return a response the consists soley one 2 byte status code. If that status
|
||||
code is defined in card_7816t.h, then this function is guarrenteed to
|
||||
return a response the consists solely one 2 byte status code. If that status
|
||||
code is defined in card_7816t.h, then this function is guaranteed to
|
||||
return a response with that status. If a cart type specific status code
|
||||
is passed and vcard_make_response fails to allocate the appropriate memory
|
||||
for that response, then vcard_make_response will return a VCardResponse
|
||||
of VCARD7816_STATUS_EXC_ERROR_MEMORY. In any case, this function is
|
||||
guarrenteed to return a valid VCardResponse.
|
||||
guaranteed to return a valid VCardResponse.
|
||||
|
||||
VCardResponse *vcard_response_new(unsigned char *buf, int len,
|
||||
VCard7816Status status);
|
||||
@@ -327,7 +327,7 @@ and applet.
|
||||
|
||||
int vcard_emul_get_login_count(VCard *card);
|
||||
|
||||
This function returns the the number of remaing login attempts for this
|
||||
This function returns the the number of remaining login attempts for this
|
||||
card. If the card emulator does not know, or the card does not have a
|
||||
way of giving this information, this function returns -1.
|
||||
|
||||
@@ -373,7 +373,7 @@ functions:
|
||||
|
||||
The options structure is built by another function in the virtual card
|
||||
interface where a string of virtual card emulator specific strings are
|
||||
mapped to the options. The actual structure is defined by the virutal card
|
||||
mapped to the options. The actual structure is defined by the virtual card
|
||||
emulator and is used to determine the configuration of soft cards, or to
|
||||
determine which physical cards to present to the guest.
|
||||
|
||||
@@ -399,7 +399,7 @@ functions:
|
||||
This function will automatically generate the appropriate new reader
|
||||
events and add the reader to the list.
|
||||
|
||||
To create a new card, the virtual card emulator will call a similiar
|
||||
To create a new card, the virtual card emulator will call a similar
|
||||
function.
|
||||
|
||||
VCard *vcard_new(VCardEmul *card_emul,
|
||||
|
@@ -14,7 +14,7 @@ To map QMP-defined interfaces to the native C QAPI implementations,
|
||||
a JSON-based schema is used to define types and function
|
||||
signatures, and a set of scripts is used to generate types/signatures,
|
||||
and marshaling/dispatch code. The QEMU Guest Agent also uses these
|
||||
scripts, paired with a seperate schema, to generate
|
||||
scripts, paired with a separate schema, to generate
|
||||
marshaling/dispatch code for the guest agent server running in the
|
||||
guest.
|
||||
|
||||
|
65
exec.c
65
exec.c
@@ -3570,6 +3570,63 @@ static CPUWriteMemoryFunc * const subpage_write[] = {
|
||||
&subpage_writel,
|
||||
};
|
||||
|
||||
static uint32_t subpage_ram_readb(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
return ldub_p(ptr);
|
||||
}
|
||||
|
||||
static void subpage_ram_writeb(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
stb_p(ptr, value);
|
||||
}
|
||||
|
||||
static uint32_t subpage_ram_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
return lduw_p(ptr);
|
||||
}
|
||||
|
||||
static void subpage_ram_writew(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
stw_p(ptr, value);
|
||||
}
|
||||
|
||||
static uint32_t subpage_ram_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
return ldl_p(ptr);
|
||||
}
|
||||
|
||||
static void subpage_ram_writel(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
ram_addr_t raddr = addr;
|
||||
void *ptr = qemu_get_ram_ptr(raddr);
|
||||
stl_p(ptr, value);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc * const subpage_ram_read[] = {
|
||||
&subpage_ram_readb,
|
||||
&subpage_ram_readw,
|
||||
&subpage_ram_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc * const subpage_ram_write[] = {
|
||||
&subpage_ram_writeb,
|
||||
&subpage_ram_writew,
|
||||
&subpage_ram_writel,
|
||||
};
|
||||
|
||||
static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
|
||||
ram_addr_t memory, ram_addr_t region_offset)
|
||||
{
|
||||
@@ -3583,8 +3640,9 @@ static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
|
||||
printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__,
|
||||
mmio, start, end, idx, eidx, memory);
|
||||
#endif
|
||||
if ((memory & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
|
||||
memory = IO_MEM_UNASSIGNED;
|
||||
if ((memory & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
|
||||
memory = IO_MEM_SUBPAGE_RAM;
|
||||
}
|
||||
memory = (memory >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
for (; idx <= eidx; idx++) {
|
||||
mmio->sub_io_index[idx] = memory;
|
||||
@@ -3817,6 +3875,9 @@ static void io_mem_init(void)
|
||||
cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read,
|
||||
notdirty_mem_write, NULL,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
cpu_register_io_memory_fixed(IO_MEM_SUBPAGE_RAM, subpage_ram_read,
|
||||
subpage_ram_write, NULL,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
for (i=0; i<5; i++)
|
||||
io_mem_used[i] = 1;
|
||||
|
||||
|
@@ -74,7 +74,7 @@ typedef struct FsContext
|
||||
} FsContext;
|
||||
|
||||
typedef struct V9fsPath {
|
||||
int16_t size;
|
||||
uint16_t size;
|
||||
char *data;
|
||||
} V9fsPath;
|
||||
|
||||
@@ -112,10 +112,10 @@ typedef struct FileOperations
|
||||
ssize_t (*pwritev)(FsContext *, V9fsFidOpenState *,
|
||||
const struct iovec *, int, off_t);
|
||||
int (*mkdir)(FsContext *, V9fsPath *, const char *, FsCred *);
|
||||
int (*fstat)(FsContext *, V9fsFidOpenState *, struct stat *);
|
||||
int (*fstat)(FsContext *, int, V9fsFidOpenState *, struct stat *);
|
||||
int (*rename)(FsContext *, const char *, const char *);
|
||||
int (*truncate)(FsContext *, V9fsPath *, off_t);
|
||||
int (*fsync)(FsContext *, V9fsFidOpenState *, int);
|
||||
int (*fsync)(FsContext *, int, V9fsFidOpenState *, int);
|
||||
int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
|
||||
ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
|
||||
const char *, void *, size_t);
|
||||
|
@@ -23,7 +23,9 @@ static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries =
|
||||
|
||||
static FsDriverTable FsDrivers[] = {
|
||||
{ .name = "local", .ops = &local_ops},
|
||||
#ifdef CONFIG_OPEN_BY_HANDLE
|
||||
{ .name = "handle", .ops = &handle_ops},
|
||||
#endif
|
||||
{ .name = "synth", .ops = &synth_ops},
|
||||
};
|
||||
|
||||
|
14
gdbstub.c
14
gdbstub.c
@@ -1781,12 +1781,6 @@ void gdb_register_coprocessor(CPUState * env,
|
||||
GDBRegisterState **p;
|
||||
static int last_reg = NUM_CORE_REGS;
|
||||
|
||||
s = (GDBRegisterState *)g_malloc0(sizeof(GDBRegisterState));
|
||||
s->base_reg = last_reg;
|
||||
s->num_regs = num_regs;
|
||||
s->get_reg = get_reg;
|
||||
s->set_reg = set_reg;
|
||||
s->xml = xml;
|
||||
p = &env->gdb_regs;
|
||||
while (*p) {
|
||||
/* Check for duplicates. */
|
||||
@@ -1794,6 +1788,14 @@ void gdb_register_coprocessor(CPUState * env,
|
||||
return;
|
||||
p = &(*p)->next;
|
||||
}
|
||||
|
||||
s = g_new0(GDBRegisterState, 1);
|
||||
s->base_reg = last_reg;
|
||||
s->num_regs = num_regs;
|
||||
s->get_reg = get_reg;
|
||||
s->set_reg = set_reg;
|
||||
s->xml = xml;
|
||||
|
||||
/* Add to end of list. */
|
||||
last_reg += num_regs;
|
||||
*p = s;
|
||||
|
@@ -71,7 +71,7 @@ int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
|
||||
}
|
||||
v9fs_co_run_in_worker(
|
||||
{
|
||||
err = s->ops->fstat(&s->ctx, &fidp->fs, stbuf);
|
||||
err = s->ops->fstat(&s->ctx, fidp->fid_type, &fidp->fs, stbuf);
|
||||
if (err < 0) {
|
||||
err = -errno;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
|
||||
}
|
||||
v9fs_co_run_in_worker(
|
||||
{
|
||||
err = s->ops->fsync(&s->ctx, &fidp->fs, datasync);
|
||||
err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync);
|
||||
if (err < 0) {
|
||||
err = -errno;
|
||||
}
|
||||
|
@@ -33,13 +33,15 @@ static V9fsState *to_virtio_9p(VirtIODevice *vdev)
|
||||
|
||||
static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
|
||||
{
|
||||
int len;
|
||||
struct virtio_9p_config *cfg;
|
||||
V9fsState *s = to_virtio_9p(vdev);
|
||||
|
||||
cfg = g_malloc0(sizeof(struct virtio_9p_config) +
|
||||
s->tag_len);
|
||||
stw_raw(&cfg->tag_len, s->tag_len);
|
||||
memcpy(cfg->tag, s->tag, s->tag_len);
|
||||
len = strlen(s->tag);
|
||||
cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
|
||||
stw_raw(&cfg->tag_len, len);
|
||||
/* We don't copy the terminating null to config space */
|
||||
memcpy(cfg->tag, s->tag, len);
|
||||
memcpy(config, cfg, s->config_size);
|
||||
g_free(cfg);
|
||||
}
|
||||
@@ -96,20 +98,18 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
|
||||
}
|
||||
|
||||
len = strlen(conf->tag);
|
||||
if (len > MAX_TAG_LEN) {
|
||||
if (len > MAX_TAG_LEN - 1) {
|
||||
fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
|
||||
"maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN);
|
||||
"maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN - 1);
|
||||
exit(1);
|
||||
}
|
||||
/* s->tag is non-NULL terminated string */
|
||||
s->tag = g_malloc(len);
|
||||
memcpy(s->tag, conf->tag, len);
|
||||
s->tag_len = len;
|
||||
|
||||
s->tag = strdup(conf->tag);
|
||||
s->ctx.uid = -1;
|
||||
|
||||
s->ops = fse->ops;
|
||||
s->vdev.get_features = virtio_9p_get_features;
|
||||
s->config_size = sizeof(struct virtio_9p_config) + s->tag_len;
|
||||
s->config_size = sizeof(struct virtio_9p_config) + len;
|
||||
s->vdev.get_config = virtio_9p_get_config;
|
||||
s->fid_list = NULL;
|
||||
qemu_co_rwlock_init(&s->rename_lock);
|
||||
@@ -176,7 +176,8 @@ static PCIDeviceInfo virtio_9p_info = {
|
||||
DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
|
||||
DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
}
|
||||
},
|
||||
.qdev.reset = virtio_pci_reset,
|
||||
};
|
||||
|
||||
static void virtio_9p_register_devices(void)
|
||||
|
@@ -19,7 +19,7 @@
|
||||
#include <grp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <attr/xattr.h>
|
||||
#include "qemu-xattr.h"
|
||||
#include <unistd.h>
|
||||
#include <linux/fs.h>
|
||||
#ifdef CONFIG_LINUX_MAGIC_H
|
||||
@@ -45,7 +45,6 @@ struct handle_data {
|
||||
int handle_bytes;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OPEN_BY_HANDLE
|
||||
static inline int name_to_handle(int dirfd, const char *name,
|
||||
struct file_handle *fh, int *mnt_id, int flags)
|
||||
{
|
||||
@@ -56,34 +55,6 @@ static inline int open_by_handle(int mountfd, const char *fh, int flags)
|
||||
{
|
||||
return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
|
||||
}
|
||||
#else
|
||||
|
||||
struct file_handle {
|
||||
unsigned int handle_bytes;
|
||||
int handle_type;
|
||||
unsigned char handle[0];
|
||||
};
|
||||
|
||||
#ifndef AT_EMPTY_PATH
|
||||
#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
|
||||
#endif
|
||||
#ifndef O_PATH
|
||||
#define O_PATH 010000000
|
||||
#endif
|
||||
|
||||
static inline int name_to_handle(int dirfd, const char *name,
|
||||
struct file_handle *fh, int *mnt_id, int flags)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int open_by_handle(int mountfd, const char *fh, int flags)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
|
||||
{
|
||||
@@ -284,10 +255,17 @@ static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_fstat(FsContext *fs_ctx, V9fsFidOpenState *fs,
|
||||
struct stat *stbuf)
|
||||
static int handle_fstat(FsContext *fs_ctx, int fid_type,
|
||||
V9fsFidOpenState *fs, struct stat *stbuf)
|
||||
{
|
||||
return fstat(fs->fd, stbuf);
|
||||
int fd;
|
||||
|
||||
if (fid_type == P9_FID_DIR) {
|
||||
fd = dirfd(fs->dir);
|
||||
} else {
|
||||
fd = fs->fd;
|
||||
}
|
||||
return fstat(fd, stbuf);
|
||||
}
|
||||
|
||||
static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
|
||||
@@ -424,12 +402,21 @@ static int handle_remove(FsContext *ctx, const char *path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int handle_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
|
||||
static int handle_fsync(FsContext *ctx, int fid_type,
|
||||
V9fsFidOpenState *fs, int datasync)
|
||||
{
|
||||
if (datasync) {
|
||||
return qemu_fdatasync(fs->fd);
|
||||
int fd;
|
||||
|
||||
if (fid_type == P9_FID_DIR) {
|
||||
fd = dirfd(fs->dir);
|
||||
} else {
|
||||
return fsync(fs->fd);
|
||||
fd = fs->fd;
|
||||
}
|
||||
|
||||
if (datasync) {
|
||||
return qemu_fdatasync(fd);
|
||||
} else {
|
||||
return fsync(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,13 +561,20 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
|
||||
{
|
||||
int dirfd, ret;
|
||||
struct handle_data *data = (struct handle_data *)ctx->private;
|
||||
int rflags;
|
||||
|
||||
dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
|
||||
if (dirfd < 0) {
|
||||
return dirfd;
|
||||
}
|
||||
|
||||
ret = unlinkat(dirfd, name, flags);
|
||||
rflags = 0;
|
||||
if (flags & P9_DOTL_AT_REMOVEDIR) {
|
||||
rflags |= AT_REMOVEDIR;
|
||||
}
|
||||
|
||||
ret = unlinkat(dirfd, name, rflags);
|
||||
|
||||
close(dirfd);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
#include <grp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <attr/xattr.h>
|
||||
#include "qemu-xattr.h"
|
||||
#include <linux/fs.h>
|
||||
#ifdef CONFIG_LINUX_MAGIC_H
|
||||
#include <linux/magic.h>
|
||||
@@ -366,11 +366,18 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int local_fstat(FsContext *fs_ctx,
|
||||
static int local_fstat(FsContext *fs_ctx, int fid_type,
|
||||
V9fsFidOpenState *fs, struct stat *stbuf)
|
||||
{
|
||||
int err;
|
||||
err = fstat(fs->fd, stbuf);
|
||||
int err, fd;
|
||||
|
||||
if (fid_type == P9_FID_DIR) {
|
||||
fd = dirfd(fs->dir);
|
||||
} else {
|
||||
fd = fs->fd;
|
||||
}
|
||||
|
||||
err = fstat(fd, stbuf);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -381,19 +388,19 @@ static int local_fstat(FsContext *fs_ctx,
|
||||
mode_t tmp_mode;
|
||||
dev_t tmp_dev;
|
||||
|
||||
if (fgetxattr(fs->fd, "user.virtfs.uid",
|
||||
if (fgetxattr(fd, "user.virtfs.uid",
|
||||
&tmp_uid, sizeof(uid_t)) > 0) {
|
||||
stbuf->st_uid = tmp_uid;
|
||||
}
|
||||
if (fgetxattr(fs->fd, "user.virtfs.gid",
|
||||
if (fgetxattr(fd, "user.virtfs.gid",
|
||||
&tmp_gid, sizeof(gid_t)) > 0) {
|
||||
stbuf->st_gid = tmp_gid;
|
||||
}
|
||||
if (fgetxattr(fs->fd, "user.virtfs.mode",
|
||||
if (fgetxattr(fd, "user.virtfs.mode",
|
||||
&tmp_mode, sizeof(mode_t)) > 0) {
|
||||
stbuf->st_mode = tmp_mode;
|
||||
}
|
||||
if (fgetxattr(fs->fd, "user.virtfs.rdev",
|
||||
if (fgetxattr(fd, "user.virtfs.rdev",
|
||||
&tmp_dev, sizeof(dev_t)) > 0) {
|
||||
stbuf->st_rdev = tmp_dev;
|
||||
}
|
||||
@@ -583,8 +590,7 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path,
|
||||
char buffer[PATH_MAX];
|
||||
char *path = fs_path->data;
|
||||
|
||||
return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf,
|
||||
AT_SYMLINK_NOFOLLOW);
|
||||
return qemu_utimens(rpath(s, path, buffer), buf);
|
||||
}
|
||||
|
||||
static int local_remove(FsContext *ctx, const char *path)
|
||||
@@ -593,12 +599,21 @@ static int local_remove(FsContext *ctx, const char *path)
|
||||
return remove(rpath(ctx, path, buffer));
|
||||
}
|
||||
|
||||
static int local_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
|
||||
static int local_fsync(FsContext *ctx, int fid_type,
|
||||
V9fsFidOpenState *fs, int datasync)
|
||||
{
|
||||
if (datasync) {
|
||||
return qemu_fdatasync(fs->fd);
|
||||
int fd;
|
||||
|
||||
if (fid_type == P9_FID_DIR) {
|
||||
fd = dirfd(fs->dir);
|
||||
} else {
|
||||
return fsync(fs->fd);
|
||||
fd = fs->fd;
|
||||
}
|
||||
|
||||
if (datasync) {
|
||||
return qemu_fdatasync(fd);
|
||||
} else {
|
||||
return fsync(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,6 +709,7 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
||||
mode_t st_mode, uint64_t *st_gen)
|
||||
{
|
||||
int err;
|
||||
#ifdef FS_IOC_GETVERSION
|
||||
V9fsFidOpenState fid_open;
|
||||
|
||||
/*
|
||||
@@ -709,15 +725,22 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
||||
}
|
||||
err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
|
||||
local_close(ctx, &fid_open);
|
||||
#else
|
||||
err = -ENOTTY;
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
static int local_init(FsContext *ctx)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
struct statfs stbuf;
|
||||
|
||||
ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
|
||||
#ifdef FS_IOC_GETVERSION
|
||||
/*
|
||||
* use ioc_getversion only if the iocl is definied
|
||||
*/
|
||||
err = statfs(ctx->fs_root, &stbuf);
|
||||
if (!err) {
|
||||
switch (stbuf.f_type) {
|
||||
@@ -729,6 +752,7 @@ static int local_init(FsContext *ctx)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <attr/xattr.h>
|
||||
#include "qemu-xattr.h"
|
||||
#include "hw/virtio.h"
|
||||
#include "virtio-9p.h"
|
||||
#include "fsdev/file-op-9p.h"
|
||||
|
@@ -166,7 +166,7 @@ static int v9fs_synth_lstat(FsContext *fs_ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int v9fs_synth_fstat(FsContext *fs_ctx,
|
||||
static int v9fs_synth_fstat(FsContext *fs_ctx, int fid_type,
|
||||
V9fsFidOpenState *fs, struct stat *stbuf)
|
||||
{
|
||||
V9fsSynthOpenState *synth_open = fs->private;
|
||||
@@ -414,7 +414,8 @@ static int v9fs_synth_remove(FsContext *ctx, const char *path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int v9fs_synth_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
|
||||
static int v9fs_synth_fsync(FsContext *ctx, int fid_type,
|
||||
V9fsFidOpenState *fs, int datasync)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return 0;
|
||||
|
@@ -13,7 +13,7 @@
|
||||
#ifndef _QEMU_VIRTIO_9P_XATTR_H
|
||||
#define _QEMU_VIRTIO_9P_XATTR_H
|
||||
|
||||
#include <attr/xattr.h>
|
||||
#include "qemu-xattr.h"
|
||||
|
||||
typedef struct xattr_operations
|
||||
{
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "virtio-9p-xattr.h"
|
||||
#include "virtio-9p-coth.h"
|
||||
#include "trace.h"
|
||||
#include "migration.h"
|
||||
|
||||
int open_fd_hw;
|
||||
int total_open_fd;
|
||||
@@ -74,15 +75,6 @@ static int omode_to_uflags(int8_t mode)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dotl_to_at_flags(int flags)
|
||||
{
|
||||
int rflags = 0;
|
||||
if (flags & P9_DOTL_AT_REMOVEDIR) {
|
||||
rflags |= AT_REMOVEDIR;
|
||||
}
|
||||
return rflags;
|
||||
}
|
||||
|
||||
struct dotl_openflag_map {
|
||||
int dotl_flag;
|
||||
int open_flag;
|
||||
@@ -382,6 +374,19 @@ static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
|
||||
* Don't free the fid if it is in reclaim list
|
||||
*/
|
||||
if (!fidp->ref && fidp->clunked) {
|
||||
if (fidp->fid == pdu->s->root_fid) {
|
||||
/*
|
||||
* if the clunked fid is root fid then we
|
||||
* have unmounted the fs on the client side.
|
||||
* delete the migration blocker. Ideally, this
|
||||
* should be hooked to transport close notification
|
||||
*/
|
||||
if (pdu->s->migration_blocker) {
|
||||
migrate_del_blocker(pdu->s->migration_blocker);
|
||||
error_free(pdu->s->migration_blocker);
|
||||
pdu->s->migration_blocker = NULL;
|
||||
}
|
||||
}
|
||||
free_fid(pdu, fidp);
|
||||
}
|
||||
}
|
||||
@@ -518,6 +523,30 @@ static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtfs_reset(V9fsPDU *pdu)
|
||||
{
|
||||
V9fsState *s = pdu->s;
|
||||
V9fsFidState *fidp = NULL;
|
||||
|
||||
/* Free all fids */
|
||||
while (s->fid_list) {
|
||||
fidp = s->fid_list;
|
||||
s->fid_list = fidp->next;
|
||||
|
||||
if (fidp->ref) {
|
||||
fidp->clunked = 1;
|
||||
} else {
|
||||
free_fid(pdu, fidp);
|
||||
}
|
||||
}
|
||||
if (fidp) {
|
||||
/* One or more unclunked fids found... */
|
||||
error_report("9pfs:%s: One or more uncluncked fids "
|
||||
"found during reset", __func__);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#define P9_QID_TYPE_DIR 0x80
|
||||
#define P9_QID_TYPE_SYMLINK 0x02
|
||||
|
||||
@@ -645,40 +674,6 @@ static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
|
||||
offset, size, 1);
|
||||
}
|
||||
|
||||
static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
|
||||
{
|
||||
size_t pos = 0;
|
||||
int i, j;
|
||||
struct iovec *src_sg;
|
||||
unsigned int num;
|
||||
|
||||
if (rx) {
|
||||
src_sg = pdu->elem.in_sg;
|
||||
num = pdu->elem.in_num;
|
||||
} else {
|
||||
src_sg = pdu->elem.out_sg;
|
||||
num = pdu->elem.out_num;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i < num; i++) {
|
||||
if (offset <= pos) {
|
||||
sg[j].iov_base = src_sg[i].iov_base;
|
||||
sg[j].iov_len = src_sg[i].iov_len;
|
||||
j++;
|
||||
} else if (offset < (src_sg[i].iov_len + pos)) {
|
||||
sg[j].iov_base = src_sg[i].iov_base;
|
||||
sg[j].iov_len = src_sg[i].iov_len;
|
||||
sg[j].iov_base += (offset - pos);
|
||||
sg[j].iov_len -= (offset - pos);
|
||||
j++;
|
||||
}
|
||||
pos += src_sg[i].iov_len;
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
{
|
||||
size_t old_offset = offset;
|
||||
@@ -714,12 +709,6 @@ static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
*valp = le64_to_cpu(val);
|
||||
break;
|
||||
}
|
||||
case 'v': {
|
||||
struct iovec *iov = va_arg(ap, struct iovec *);
|
||||
int *iovcnt = va_arg(ap, int *);
|
||||
*iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
V9fsString *str = va_arg(ap, V9fsString *);
|
||||
offset += pdu_unmarshal(pdu, offset, "w", &str->size);
|
||||
@@ -798,12 +787,6 @@ static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
offset += pdu_pack(pdu, offset, &val, sizeof(val));
|
||||
break;
|
||||
}
|
||||
case 'v': {
|
||||
struct iovec *iov = va_arg(ap, struct iovec *);
|
||||
int *iovcnt = va_arg(ap, int *);
|
||||
*iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
V9fsString *str = va_arg(ap, V9fsString *);
|
||||
offset += pdu_marshal(pdu, offset, "w", str->size);
|
||||
@@ -1114,42 +1097,6 @@ static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
|
||||
stat_to_qid(stbuf, &v9lstat->qid);
|
||||
}
|
||||
|
||||
static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
|
||||
{
|
||||
while (len && *iovcnt) {
|
||||
if (len < sg->iov_len) {
|
||||
sg->iov_len -= len;
|
||||
sg->iov_base += len;
|
||||
len = 0;
|
||||
} else {
|
||||
len -= sg->iov_len;
|
||||
sg++;
|
||||
*iovcnt -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
|
||||
{
|
||||
int i;
|
||||
int total = 0;
|
||||
|
||||
for (i = 0; i < *cnt; i++) {
|
||||
if ((total + sg[i].iov_len) > cap) {
|
||||
sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
total += sg[i].iov_len;
|
||||
}
|
||||
|
||||
*cnt = i;
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
static void print_sg(struct iovec *sg, int cnt)
|
||||
{
|
||||
int i;
|
||||
@@ -1191,6 +1138,8 @@ static void v9fs_version(void *opaque)
|
||||
pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
|
||||
trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
|
||||
|
||||
virtfs_reset(pdu);
|
||||
|
||||
if (!strcmp(version.data, "9P2000.u")) {
|
||||
s->proto_version = V9FS_PROTO_2000U;
|
||||
} else if (!strcmp(version.data, "9P2000.L")) {
|
||||
@@ -1244,6 +1193,11 @@ static void v9fs_attach(void *opaque)
|
||||
err = offset;
|
||||
trace_v9fs_attach_return(pdu->tag, pdu->id,
|
||||
qid.type, qid.version, qid.path);
|
||||
s->root_fid = fid;
|
||||
/* disable migration */
|
||||
error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
|
||||
s->ctx.fs_root, s->tag);
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
out:
|
||||
put_fid(pdu, fidp);
|
||||
out_nofid:
|
||||
@@ -1740,8 +1694,8 @@ out_nofid:
|
||||
complete_pdu(s, pdu, err);
|
||||
}
|
||||
|
||||
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
|
||||
V9fsFidState *fidp, int64_t off, int32_t max_count)
|
||||
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
|
||||
uint64_t off, uint32_t max_count)
|
||||
{
|
||||
size_t offset = 7;
|
||||
int read_count;
|
||||
@@ -1765,7 +1719,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
|
||||
}
|
||||
|
||||
static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
|
||||
V9fsFidState *fidp, int32_t max_count)
|
||||
V9fsFidState *fidp, uint32_t max_count)
|
||||
{
|
||||
V9fsPath path;
|
||||
V9fsStat v9stat;
|
||||
@@ -1825,14 +1779,46 @@ out:
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a QEMUIOVector for a sub-region of PDU iovecs
|
||||
*
|
||||
* @qiov: uninitialized QEMUIOVector
|
||||
* @skip: number of bytes to skip from beginning of PDU
|
||||
* @size: number of bytes to include
|
||||
* @is_write: true - write, false - read
|
||||
*
|
||||
* The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
|
||||
* with qemu_iovec_destroy().
|
||||
*/
|
||||
static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
|
||||
uint64_t skip, size_t size,
|
||||
bool is_write)
|
||||
{
|
||||
QEMUIOVector elem;
|
||||
struct iovec *iov;
|
||||
unsigned int niov;
|
||||
|
||||
if (is_write) {
|
||||
iov = pdu->elem.out_sg;
|
||||
niov = pdu->elem.out_num;
|
||||
} else {
|
||||
iov = pdu->elem.in_sg;
|
||||
niov = pdu->elem.in_num;
|
||||
}
|
||||
|
||||
qemu_iovec_init_external(&elem, iov, niov);
|
||||
qemu_iovec_init(qiov, niov);
|
||||
qemu_iovec_copy(qiov, &elem, skip, size);
|
||||
}
|
||||
|
||||
static void v9fs_read(void *opaque)
|
||||
{
|
||||
int32_t fid;
|
||||
int64_t off;
|
||||
uint64_t off;
|
||||
ssize_t err = 0;
|
||||
int32_t count = 0;
|
||||
size_t offset = 7;
|
||||
int32_t max_count;
|
||||
uint32_t max_count;
|
||||
V9fsFidState *fidp;
|
||||
V9fsPDU *pdu = opaque;
|
||||
V9fsState *s = pdu->s;
|
||||
@@ -1859,21 +1845,21 @@ static void v9fs_read(void *opaque)
|
||||
err += pdu_marshal(pdu, offset, "d", count);
|
||||
err += count;
|
||||
} else if (fidp->fid_type == P9_FID_FILE) {
|
||||
int32_t cnt;
|
||||
QEMUIOVector qiov_full;
|
||||
QEMUIOVector qiov;
|
||||
int32_t len;
|
||||
struct iovec *sg;
|
||||
struct iovec iov[128]; /* FIXME: bad, bad, bad */
|
||||
|
||||
sg = iov;
|
||||
pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
|
||||
sg = cap_sg(sg, max_count, &cnt);
|
||||
v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
|
||||
qemu_iovec_init(&qiov, qiov_full.niov);
|
||||
do {
|
||||
qemu_iovec_reset(&qiov);
|
||||
qemu_iovec_copy(&qiov, &qiov_full, count, qiov_full.size - count);
|
||||
if (0) {
|
||||
print_sg(sg, cnt);
|
||||
print_sg(qiov.iov, qiov.niov);
|
||||
}
|
||||
/* Loop in case of EINTR */
|
||||
do {
|
||||
len = v9fs_co_preadv(pdu, fidp, sg, cnt, off);
|
||||
len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
|
||||
if (len >= 0) {
|
||||
off += len;
|
||||
count += len;
|
||||
@@ -1884,11 +1870,12 @@ static void v9fs_read(void *opaque)
|
||||
err = len;
|
||||
goto out;
|
||||
}
|
||||
sg = adjust_sg(sg, len, &cnt);
|
||||
} while (count < max_count && len > 0);
|
||||
err = offset;
|
||||
err += pdu_marshal(pdu, offset, "d", count);
|
||||
err += count;
|
||||
qemu_iovec_destroy(&qiov);
|
||||
qemu_iovec_destroy(&qiov_full);
|
||||
} else if (fidp->fid_type == P9_FID_XATTR) {
|
||||
err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
|
||||
} else {
|
||||
@@ -1975,8 +1962,9 @@ static void v9fs_readdir(void *opaque)
|
||||
V9fsFidState *fidp;
|
||||
ssize_t retval = 0;
|
||||
size_t offset = 7;
|
||||
int64_t initial_offset;
|
||||
int32_t count, max_count;
|
||||
uint64_t initial_offset;
|
||||
int32_t count;
|
||||
uint32_t max_count;
|
||||
V9fsPDU *pdu = opaque;
|
||||
V9fsState *s = pdu->s;
|
||||
|
||||
@@ -2014,7 +2002,7 @@ out_nofid:
|
||||
}
|
||||
|
||||
static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
|
||||
int64_t off, int32_t count,
|
||||
uint64_t off, uint32_t count,
|
||||
struct iovec *sg, int cnt)
|
||||
{
|
||||
int i, to_copy;
|
||||
@@ -2059,22 +2047,22 @@ out:
|
||||
|
||||
static void v9fs_write(void *opaque)
|
||||
{
|
||||
int cnt;
|
||||
ssize_t err;
|
||||
int32_t fid;
|
||||
int64_t off;
|
||||
int32_t count;
|
||||
uint64_t off;
|
||||
uint32_t count;
|
||||
int32_t len = 0;
|
||||
int32_t total = 0;
|
||||
size_t offset = 7;
|
||||
V9fsFidState *fidp;
|
||||
struct iovec iov[128]; /* FIXME: bad, bad, bad */
|
||||
struct iovec *sg = iov;
|
||||
V9fsPDU *pdu = opaque;
|
||||
V9fsState *s = pdu->s;
|
||||
QEMUIOVector qiov_full;
|
||||
QEMUIOVector qiov;
|
||||
|
||||
pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
|
||||
trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt);
|
||||
offset += pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
|
||||
v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
|
||||
trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
|
||||
|
||||
fidp = get_fid(pdu, fid);
|
||||
if (fidp == NULL) {
|
||||
@@ -2090,20 +2078,23 @@ static void v9fs_write(void *opaque)
|
||||
/*
|
||||
* setxattr operation
|
||||
*/
|
||||
err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
|
||||
err = v9fs_xattr_write(s, pdu, fidp, off, count,
|
||||
qiov_full.iov, qiov_full.niov);
|
||||
goto out;
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
sg = cap_sg(sg, count, &cnt);
|
||||
qemu_iovec_init(&qiov, qiov_full.niov);
|
||||
do {
|
||||
qemu_iovec_reset(&qiov);
|
||||
qemu_iovec_copy(&qiov, &qiov_full, total, qiov_full.size - total);
|
||||
if (0) {
|
||||
print_sg(sg, cnt);
|
||||
print_sg(qiov.iov, qiov.niov);
|
||||
}
|
||||
/* Loop in case of EINTR */
|
||||
do {
|
||||
len = v9fs_co_pwritev(pdu, fidp, sg, cnt, off);
|
||||
len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
|
||||
if (len >= 0) {
|
||||
off += len;
|
||||
total += len;
|
||||
@@ -2112,16 +2103,20 @@ static void v9fs_write(void *opaque)
|
||||
if (len < 0) {
|
||||
/* IO error return the error */
|
||||
err = len;
|
||||
goto out;
|
||||
goto out_qiov;
|
||||
}
|
||||
sg = adjust_sg(sg, len, &cnt);
|
||||
} while (total < count && len > 0);
|
||||
|
||||
offset = 7;
|
||||
offset += pdu_marshal(pdu, offset, "d", total);
|
||||
err = offset;
|
||||
trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
|
||||
out_qiov:
|
||||
qemu_iovec_destroy(&qiov);
|
||||
out:
|
||||
put_fid(pdu, fidp);
|
||||
out_nofid:
|
||||
qemu_iovec_destroy(&qiov_full);
|
||||
complete_pdu(s, pdu, err);
|
||||
}
|
||||
|
||||
@@ -2444,7 +2439,6 @@ static void v9fs_unlinkat(void *opaque)
|
||||
V9fsPDU *pdu = opaque;
|
||||
|
||||
pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
|
||||
flags = dotl_to_at_flags(flags);
|
||||
|
||||
dfidp = get_fid(pdu, dfid);
|
||||
if (dfidp == NULL) {
|
||||
|
@@ -156,7 +156,7 @@ typedef struct V9fsFidState V9fsFidState;
|
||||
|
||||
typedef struct V9fsString
|
||||
{
|
||||
int16_t size;
|
||||
uint16_t size;
|
||||
char *data;
|
||||
} V9fsString;
|
||||
|
||||
@@ -246,8 +246,7 @@ typedef struct V9fsState
|
||||
V9fsFidState *fid_list;
|
||||
FileOperations *ops;
|
||||
FsContext ctx;
|
||||
uint16_t tag_len;
|
||||
uint8_t *tag;
|
||||
char *tag;
|
||||
size_t config_size;
|
||||
enum p9_proto_version proto_version;
|
||||
int32_t msize;
|
||||
@@ -256,6 +255,8 @@ typedef struct V9fsState
|
||||
* on rename.
|
||||
*/
|
||||
CoRwlock rename_lock;
|
||||
int32_t root_fid;
|
||||
Error *migration_blocker;
|
||||
} V9fsState;
|
||||
|
||||
typedef struct V9fsStatState {
|
||||
|
@@ -231,15 +231,30 @@ static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
|
||||
s->nvflags &= ~val;
|
||||
break;
|
||||
case 0x40: /* RESETCTL */
|
||||
if (board_id(s) == BOARD_ID_VEXPRESS) {
|
||||
switch (board_id(s)) {
|
||||
case BOARD_ID_PB926:
|
||||
if (s->lockval == LOCK_VALUE) {
|
||||
s->resetlevel = val;
|
||||
if (val & 0x100) {
|
||||
qemu_system_reset_request();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BOARD_ID_PBX:
|
||||
case BOARD_ID_PBA8:
|
||||
if (s->lockval == LOCK_VALUE) {
|
||||
s->resetlevel = val;
|
||||
if (val & 0x04) {
|
||||
qemu_system_reset_request();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BOARD_ID_VEXPRESS:
|
||||
case BOARD_ID_EB:
|
||||
default:
|
||||
/* reserved: RAZ/WI */
|
||||
break;
|
||||
}
|
||||
if (s->lockval == LOCK_VALUE) {
|
||||
s->resetlevel = val;
|
||||
if (val & 0x100)
|
||||
qemu_system_reset_request ();
|
||||
}
|
||||
break;
|
||||
case 0x44: /* PCICTL */
|
||||
/* nothing to do. */
|
||||
|
@@ -269,7 +269,7 @@ static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
|
||||
|
||||
/* ??? Don't know the PrimeCell ID for this device. */
|
||||
n = offset >> 8;
|
||||
if (n > 3) {
|
||||
if (n > 2) {
|
||||
hw_error("sp804_read: Bad timer %d\n", n);
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ static void icp_pit_write(void *opaque, target_phys_addr_t offset,
|
||||
int n;
|
||||
|
||||
n = offset >> 8;
|
||||
if (n > 3) {
|
||||
if (n > 2) {
|
||||
hw_error("sp804_write: Bad timer %d\n", n);
|
||||
}
|
||||
|
||||
|
@@ -150,6 +150,7 @@ static void ccid_card_vscard_handle_message(PassthruState *card,
|
||||
error_report("ATR size exceeds spec, ignoring");
|
||||
ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
|
||||
VSC_GENERAL_ERROR);
|
||||
break;
|
||||
}
|
||||
memcpy(card->atr, data, scr_msg_header->length);
|
||||
card->atr_length = scr_msg_header->length;
|
||||
|
@@ -466,6 +466,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
bytes = split_size;
|
||||
if (tp->size + bytes > msh)
|
||||
bytes = msh - tp->size;
|
||||
|
||||
bytes = MIN(sizeof(tp->data) - tp->size, bytes);
|
||||
pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
|
||||
if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
|
||||
memmove(tp->header, tp->data, hdr);
|
||||
@@ -481,6 +483,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
// context descriptor TSE is not set, while data descriptor TSE is set
|
||||
DBGOUT(TXERR, "TCP segmentaion Error\n");
|
||||
} else {
|
||||
split_size = MIN(sizeof(tp->data) - tp->size, split_size);
|
||||
pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
|
||||
tp->size += split_size;
|
||||
}
|
||||
|
@@ -976,7 +976,15 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
|
||||
case CU_STATSADDR:
|
||||
/* Load dump counters address. */
|
||||
s->statsaddr = e100_read_reg4(s, SCBPointer);
|
||||
TRACE(OTHER, logout("val=0x%02x (status address)\n", val));
|
||||
TRACE(OTHER, logout("val=0x%02x (dump counters address)\n", val));
|
||||
if (s->statsaddr & 3) {
|
||||
/* Memory must be Dword aligned. */
|
||||
logout("unaligned dump counters address\n");
|
||||
/* Handling of misaligned addresses is undefined.
|
||||
* Here we align the address by ignoring the lower bits. */
|
||||
/* TODO: Test unaligned dump counter address on real hardware. */
|
||||
s->statsaddr &= ~3;
|
||||
}
|
||||
break;
|
||||
case CU_SHOWSTATS:
|
||||
/* Dump statistical counters. */
|
||||
|
@@ -157,14 +157,14 @@ static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
|
||||
|
||||
cmp = (uint32_t)t->cmp;
|
||||
diff = cmp - (uint32_t)current;
|
||||
diff = (int32_t)diff > 0 ? diff : (uint32_t)0;
|
||||
diff = (int32_t)diff > 0 ? diff : (uint32_t)1;
|
||||
return (uint64_t)diff;
|
||||
} else {
|
||||
uint64_t diff, cmp;
|
||||
|
||||
cmp = t->cmp;
|
||||
diff = cmp - current;
|
||||
diff = (int64_t)diff > 0 ? diff : (uint64_t)0;
|
||||
diff = (int64_t)diff > 0 ? diff : (uint64_t)1;
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
|
@@ -516,9 +516,14 @@ static unsigned int event_status_media(IDEState *s,
|
||||
|
||||
/* Event notification descriptor */
|
||||
event_code = MEC_NO_CHANGE;
|
||||
if (media_status != MS_TRAY_OPEN && s->events.new_media) {
|
||||
event_code = MEC_NEW_MEDIA;
|
||||
s->events.new_media = false;
|
||||
if (media_status != MS_TRAY_OPEN) {
|
||||
if (s->events.new_media) {
|
||||
event_code = MEC_NEW_MEDIA;
|
||||
s->events.new_media = false;
|
||||
} else if (s->events.eject_request) {
|
||||
event_code = MEC_EJECT_REQUESTED;
|
||||
s->events.eject_request = false;
|
||||
}
|
||||
}
|
||||
|
||||
buf[4] = event_code;
|
||||
@@ -690,12 +695,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
int action, code;
|
||||
int max_len;
|
||||
|
||||
if (buf[0] == GPCMD_MODE_SENSE_10) {
|
||||
max_len = ube16_to_cpu(buf + 7);
|
||||
} else {
|
||||
max_len = buf[4];
|
||||
}
|
||||
|
||||
max_len = ube16_to_cpu(buf + 7);
|
||||
action = buf[2] >> 6;
|
||||
code = buf[2] & 0x3f;
|
||||
|
||||
@@ -703,7 +703,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
case 0: /* current values */
|
||||
switch(code) {
|
||||
case MODE_PAGE_R_W_ERROR: /* error recovery */
|
||||
cpu_to_ube16(&buf[0], 16 + 6);
|
||||
cpu_to_ube16(&buf[0], 16 - 2);
|
||||
buf[2] = 0x70;
|
||||
buf[3] = 0;
|
||||
buf[4] = 0;
|
||||
@@ -722,7 +722,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
ide_atapi_cmd_reply(s, 16, max_len);
|
||||
break;
|
||||
case MODE_PAGE_AUDIO_CTL:
|
||||
cpu_to_ube16(&buf[0], 24 + 6);
|
||||
cpu_to_ube16(&buf[0], 24 - 2);
|
||||
buf[2] = 0x70;
|
||||
buf[3] = 0;
|
||||
buf[4] = 0;
|
||||
@@ -741,7 +741,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
ide_atapi_cmd_reply(s, 24, max_len);
|
||||
break;
|
||||
case MODE_PAGE_CAPABILITIES:
|
||||
cpu_to_ube16(&buf[0], 28 + 6);
|
||||
cpu_to_ube16(&buf[0], 30 - 2);
|
||||
buf[2] = 0x70;
|
||||
buf[3] = 0;
|
||||
buf[4] = 0;
|
||||
@@ -750,7 +750,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
buf[7] = 0;
|
||||
|
||||
buf[8] = MODE_PAGE_CAPABILITIES;
|
||||
buf[9] = 28 - 10;
|
||||
buf[9] = 30 - 10;
|
||||
buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
|
||||
buf[11] = 0x00;
|
||||
|
||||
@@ -772,7 +772,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
buf[25] = 0;
|
||||
buf[26] = 0;
|
||||
buf[27] = 0;
|
||||
ide_atapi_cmd_reply(s, 28, max_len);
|
||||
buf[28] = 0;
|
||||
buf[29] = 0;
|
||||
ide_atapi_cmd_reply(s, 30, max_len);
|
||||
break;
|
||||
default:
|
||||
goto error_cmd;
|
||||
@@ -1038,7 +1040,6 @@ static const struct {
|
||||
[ 0x00 ] = { cmd_test_unit_ready, CHECK_READY },
|
||||
[ 0x03 ] = { cmd_request_sense, ALLOW_UA },
|
||||
[ 0x12 ] = { cmd_inquiry, ALLOW_UA },
|
||||
[ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 },
|
||||
[ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */
|
||||
[ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 },
|
||||
[ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY },
|
||||
|
@@ -804,6 +804,18 @@ static void ide_cd_change_cb(void *opaque, bool load)
|
||||
*/
|
||||
s->cdrom_changed = 1;
|
||||
s->events.new_media = true;
|
||||
s->events.eject_request = false;
|
||||
ide_set_irq(s->bus);
|
||||
}
|
||||
|
||||
static void ide_cd_eject_request_cb(void *opaque, bool force)
|
||||
{
|
||||
IDEState *s = opaque;
|
||||
|
||||
s->events.eject_request = true;
|
||||
if (force) {
|
||||
s->tray_locked = false;
|
||||
}
|
||||
ide_set_irq(s->bus);
|
||||
}
|
||||
|
||||
@@ -1811,6 +1823,7 @@ static bool ide_cd_is_medium_locked(void *opaque)
|
||||
|
||||
static const BlockDevOps ide_cd_block_ops = {
|
||||
.change_media_cb = ide_cd_change_cb,
|
||||
.eject_request_cb = ide_cd_eject_request_cb,
|
||||
.is_tray_open = ide_cd_is_tray_open,
|
||||
.is_medium_locked = ide_cd_is_medium_locked,
|
||||
};
|
||||
|
14
hw/ivshmem.c
14
hw/ivshmem.c
@@ -18,6 +18,8 @@
|
||||
#include "pci.h"
|
||||
#include "msix.h"
|
||||
#include "kvm.h"
|
||||
#include "migration.h"
|
||||
#include "qerror.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
@@ -78,6 +80,8 @@ typedef struct IVShmemState {
|
||||
uint32_t features;
|
||||
EventfdEntry *eventfd_table;
|
||||
|
||||
Error *migration_blocker;
|
||||
|
||||
char * shmobj;
|
||||
char * sizearg;
|
||||
char * role;
|
||||
@@ -646,7 +650,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
|
||||
}
|
||||
|
||||
if (s->role_val == IVSHMEM_PEER) {
|
||||
register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
|
||||
error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "ivshmem", "peer mode");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
}
|
||||
|
||||
pci_conf = s->dev.config;
|
||||
@@ -694,7 +699,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
|
||||
s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
|
||||
|
||||
pci_register_bar(&s->dev, 2,
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem);
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
|
||||
|
||||
s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
|
||||
|
||||
@@ -741,6 +746,11 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
|
||||
{
|
||||
IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
|
||||
|
||||
if (s->migration_blocker) {
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
}
|
||||
|
||||
memory_region_destroy(&s->ivshmem_mmio);
|
||||
memory_region_del_subregion(&s->bar, &s->ivshmem);
|
||||
memory_region_destroy(&s->ivshmem);
|
||||
|
@@ -863,6 +863,7 @@ static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
|
||||
} else {
|
||||
DPRINTF("EEPROM Write All (ignored)\n");
|
||||
}
|
||||
break;
|
||||
case 5: /* ERASE */
|
||||
if (s->eeprom_writable) {
|
||||
s->eeprom[addr] = 0xff;
|
||||
|
@@ -85,11 +85,11 @@ int load_image(const char *filename, uint8_t *addr)
|
||||
}
|
||||
|
||||
/* read()-like version */
|
||||
int read_targphys(const char *name,
|
||||
int fd, target_phys_addr_t dst_addr, size_t nbytes)
|
||||
ssize_t read_targphys(const char *name,
|
||||
int fd, target_phys_addr_t dst_addr, size_t nbytes)
|
||||
{
|
||||
uint8_t *buf;
|
||||
size_t did;
|
||||
ssize_t did;
|
||||
|
||||
buf = g_malloc(nbytes);
|
||||
did = read(fd, buf, nbytes);
|
||||
@@ -176,7 +176,8 @@ static void bswap_ahdr(struct exec *e)
|
||||
int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
|
||||
int bswap_needed, target_phys_addr_t target_page_size)
|
||||
{
|
||||
int fd, size, ret;
|
||||
int fd;
|
||||
ssize_t size, ret;
|
||||
struct exec e;
|
||||
uint32_t magic;
|
||||
|
||||
|
@@ -14,8 +14,8 @@ int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
|
||||
int load_uimage(const char *filename, target_phys_addr_t *ep,
|
||||
target_phys_addr_t *loadaddr, int *is_linux);
|
||||
|
||||
int read_targphys(const char *name,
|
||||
int fd, target_phys_addr_t dst_addr, size_t nbytes);
|
||||
ssize_t read_targphys(const char *name,
|
||||
int fd, target_phys_addr_t dst_addr, size_t nbytes);
|
||||
void pstrcpy_targphys(const char *name,
|
||||
target_phys_addr_t dest, int buf_size,
|
||||
const char *source);
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include "mc146818rtc.h"
|
||||
#include "blockdev.h"
|
||||
#include "exec-memory.h"
|
||||
#include "sysbus.h" /* SysBusDevice */
|
||||
|
||||
//#define DEBUG_BOARD_INIT
|
||||
|
||||
@@ -72,6 +73,11 @@ typedef struct {
|
||||
SerialState *uart;
|
||||
} MaltaFPGAState;
|
||||
|
||||
typedef struct {
|
||||
SysBusDevice busdev;
|
||||
qemu_irq *i8259;
|
||||
} MaltaState;
|
||||
|
||||
static ISADevice *pit;
|
||||
|
||||
static struct _loaderparams {
|
||||
@@ -775,7 +781,7 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
int64_t kernel_entry;
|
||||
PCIBus *pci_bus;
|
||||
CPUState *env;
|
||||
qemu_irq *i8259 = NULL, *isa_irq;
|
||||
qemu_irq *isa_irq;
|
||||
qemu_irq *cpu_exit_irq;
|
||||
int piix4_devfn;
|
||||
i2c_bus *smbus;
|
||||
@@ -787,6 +793,11 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
int fl_sectors = 0;
|
||||
int be;
|
||||
|
||||
DeviceState *dev = qdev_create(NULL, "mips-malta");
|
||||
MaltaState *s = DO_UPCAST(MaltaState, busdev.qdev, dev);
|
||||
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* Make sure the first 3 serial ports are associated with a device. */
|
||||
for(i = 0; i < 3; i++) {
|
||||
if (!serial_hds[i]) {
|
||||
@@ -932,7 +943,7 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
* qemu_irq_proxy() adds an extra bit of indirection, allowing us
|
||||
* to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
|
||||
*/
|
||||
isa_irq = qemu_irq_proxy(&i8259, 16);
|
||||
isa_irq = qemu_irq_proxy(&s->i8259, 16);
|
||||
|
||||
/* Northbridge */
|
||||
pci_bus = gt64120_register(isa_irq);
|
||||
@@ -944,9 +955,9 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
|
||||
/* Interrupt controller */
|
||||
/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
|
||||
i8259 = i8259_init(env->irq[2]);
|
||||
s->i8259 = i8259_init(env->irq[2]);
|
||||
|
||||
isa_bus_irqs(i8259);
|
||||
isa_bus_irqs(s->i8259);
|
||||
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
|
||||
usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
|
||||
smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(9),
|
||||
@@ -990,6 +1001,20 @@ void mips_malta_init (ram_addr_t ram_size,
|
||||
}
|
||||
}
|
||||
|
||||
static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SysBusDeviceInfo mips_malta_device = {
|
||||
.init = mips_malta_sysbus_device_init,
|
||||
.qdev.name = "mips-malta",
|
||||
.qdev.size = sizeof(MaltaState),
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static QEMUMachine mips_malta_machine = {
|
||||
.name = "malta",
|
||||
.desc = "MIPS Malta Core LV",
|
||||
@@ -998,9 +1023,15 @@ static QEMUMachine mips_malta_machine = {
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
static void mips_malta_device_init(void)
|
||||
{
|
||||
sysbus_register_withprop(&mips_malta_device);
|
||||
}
|
||||
|
||||
static void mips_malta_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&mips_malta_machine);
|
||||
}
|
||||
|
||||
device_init(mips_malta_device_init);
|
||||
machine_init(mips_malta_machine_init);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* QEMU/mipssim emulation
|
||||
*
|
||||
* Emulates a very simple machine model similiar to the one use by the
|
||||
* Emulates a very simple machine model similar to the one used by the
|
||||
* proprietary MIPS emulator.
|
||||
*
|
||||
* Copyright (c) 2007 Thiemo Seufer
|
||||
|
48
hw/msix.c
48
hw/msix.c
@@ -79,6 +79,7 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
|
||||
/* Make flags bit writable. */
|
||||
pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
|
||||
MSIX_MASKALL_MASK;
|
||||
pdev->msix_function_masked = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -117,50 +118,64 @@ static void msix_clr_pending(PCIDevice *dev, int vector)
|
||||
*msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
|
||||
}
|
||||
|
||||
static int msix_function_masked(PCIDevice *dev)
|
||||
static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask)
|
||||
{
|
||||
return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK;
|
||||
unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
|
||||
return fmask || dev->msix_table_page[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
|
||||
}
|
||||
|
||||
static int msix_is_masked(PCIDevice *dev, int vector)
|
||||
static bool msix_is_masked(PCIDevice *dev, int vector)
|
||||
{
|
||||
unsigned offset =
|
||||
vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
|
||||
return msix_function_masked(dev) ||
|
||||
dev->msix_table_page[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
|
||||
return msix_vector_masked(dev, vector, dev->msix_function_masked);
|
||||
}
|
||||
|
||||
static void msix_handle_mask_update(PCIDevice *dev, int vector)
|
||||
static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked)
|
||||
{
|
||||
if (!msix_is_masked(dev, vector) && msix_is_pending(dev, vector)) {
|
||||
bool is_masked = msix_is_masked(dev, vector);
|
||||
if (is_masked == was_masked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_masked && msix_is_pending(dev, vector)) {
|
||||
msix_clr_pending(dev, vector);
|
||||
msix_notify(dev, vector);
|
||||
}
|
||||
}
|
||||
|
||||
static void msix_update_function_masked(PCIDevice *dev)
|
||||
{
|
||||
dev->msix_function_masked = !msix_enabled(dev) ||
|
||||
(dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK);
|
||||
}
|
||||
|
||||
/* Handle MSI-X capability config write. */
|
||||
void msix_write_config(PCIDevice *dev, uint32_t addr,
|
||||
uint32_t val, int len)
|
||||
{
|
||||
unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
|
||||
int vector;
|
||||
bool was_masked;
|
||||
|
||||
if (!range_covers_byte(addr, len, enable_pos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
was_masked = dev->msix_function_masked;
|
||||
msix_update_function_masked(dev);
|
||||
|
||||
if (!msix_enabled(dev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pci_device_deassert_intx(dev);
|
||||
|
||||
if (msix_function_masked(dev)) {
|
||||
if (dev->msix_function_masked == was_masked) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
|
||||
msix_handle_mask_update(dev, vector);
|
||||
msix_handle_mask_update(dev, vector,
|
||||
msix_vector_masked(dev, vector, was_masked));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,8 +185,16 @@ static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
|
||||
PCIDevice *dev = opaque;
|
||||
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
|
||||
int vector = offset / PCI_MSIX_ENTRY_SIZE;
|
||||
bool was_masked;
|
||||
|
||||
/* MSI-X page includes a read-only PBA and a writeable Vector Control. */
|
||||
if (vector >= dev->msix_entries_nr) {
|
||||
return;
|
||||
}
|
||||
|
||||
was_masked = msix_is_masked(dev, vector);
|
||||
pci_set_long(dev->msix_table_page + offset, val);
|
||||
msix_handle_mask_update(dev, vector);
|
||||
msix_handle_mask_update(dev, vector, was_masked);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps msix_mmio_ops = {
|
||||
@@ -300,6 +323,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
|
||||
msix_free_irq_entries(dev);
|
||||
qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
|
||||
qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
|
||||
msix_update_function_masked(dev);
|
||||
}
|
||||
|
||||
/* Does device support MSI-X? */
|
||||
|
22
hw/nand.c
22
hw/nand.c
@@ -19,6 +19,7 @@
|
||||
# include "flash.h"
|
||||
# include "blockdev.h"
|
||||
# include "sysbus.h"
|
||||
#include "qemu-error.h"
|
||||
|
||||
# define NAND_CMD_READ0 0x00
|
||||
# define NAND_CMD_READ1 0x01
|
||||
@@ -384,18 +385,23 @@ static int nand_device_init(SysBusDevice *dev)
|
||||
nand_init_2048(s);
|
||||
break;
|
||||
default:
|
||||
hw_error("%s: Unsupported NAND block size.\n", __func__);
|
||||
error_report("Unsupported NAND block size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pagesize = 1 << s->oob_shift;
|
||||
s->mem_oob = 1;
|
||||
if (s->bdrv && bdrv_getlength(s->bdrv) >=
|
||||
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
|
||||
pagesize = 0;
|
||||
s->mem_oob = 0;
|
||||
}
|
||||
|
||||
if (!s->bdrv) {
|
||||
if (s->bdrv) {
|
||||
if (bdrv_is_read_only(s->bdrv)) {
|
||||
error_report("Can't use a read-only drive");
|
||||
return -1;
|
||||
}
|
||||
if (bdrv_getlength(s->bdrv) >=
|
||||
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
|
||||
pagesize = 0;
|
||||
s->mem_oob = 0;
|
||||
}
|
||||
} else {
|
||||
pagesize += 1 << s->page_shift;
|
||||
}
|
||||
if (pagesize) {
|
||||
|
@@ -389,10 +389,11 @@ static void omap_disc_write(void *opaque, target_phys_addr_t addr,
|
||||
s->dig.enable = (value >> 1) & 1;
|
||||
s->lcd.enable = (value >> 0) & 1;
|
||||
if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */
|
||||
if (~((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1))
|
||||
fprintf(stderr, "%s: Overlay Optimization when no overlay "
|
||||
"region effectively exists leads to "
|
||||
"unpredictable behaviour!\n", __FUNCTION__);
|
||||
if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
|
||||
fprintf(stderr, "%s: Overlay Optimization when no overlay "
|
||||
"region effectively exists leads to "
|
||||
"unpredictable behaviour!\n", __func__);
|
||||
}
|
||||
if (value & (1 << 6)) { /* GODIGITAL */
|
||||
/* XXX: Shadowed fields are:
|
||||
* s->dispc.config
|
||||
|
@@ -510,7 +510,7 @@ static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr,
|
||||
|
||||
static uint32_t omap2_gpio_module_readp(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
return omap2_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3);
|
||||
return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
|
||||
}
|
||||
|
||||
static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr,
|
||||
|
@@ -180,6 +180,7 @@ static void omap_nand_setio(DeviceState *dev, uint64_t value,
|
||||
nand_setio(dev, (value >> 24) & 0xff);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OMAP_GPMC_16BIT:
|
||||
switch (size) {
|
||||
case 1:
|
||||
@@ -195,6 +196,7 @@ static void omap_nand_setio(DeviceState *dev, uint64_t value,
|
||||
nand_setio(dev, (value >> 16) & 0xffff);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -398,6 +398,9 @@ static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
|
||||
if (bank_no < s->nbanks) {
|
||||
offset &= ~0x60;
|
||||
bank = &s->bank[bank_no];
|
||||
} else {
|
||||
OMAP_BAD_REG(addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,6 +479,9 @@ static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
|
||||
if (bank_no < s->nbanks) {
|
||||
offset &= ~0x60;
|
||||
bank = &s->bank[bank_no];
|
||||
} else {
|
||||
OMAP_BAD_REG(addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "memory.h"
|
||||
#include "exec-memory.h"
|
||||
#include "sysbus.h"
|
||||
#include "qemu-error.h"
|
||||
|
||||
/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
|
||||
#define PAGE_SHIFT 11
|
||||
@@ -772,6 +773,10 @@ static int onenand_initfn(SysBusDevice *dev)
|
||||
s->image = memset(g_malloc(size + (size >> 5)),
|
||||
0xff, size + (size >> 5));
|
||||
} else {
|
||||
if (bdrv_is_read_only(s->bdrv)) {
|
||||
error_report("Can't use a read-only drive");
|
||||
return -1;
|
||||
}
|
||||
s->bdrv_cur = s->bdrv;
|
||||
}
|
||||
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
|
||||
|
4
hw/pc.c
4
hw/pc.c
@@ -335,7 +335,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
ISADevice *s)
|
||||
{
|
||||
int val, nb, nb_heads, max_track, last_sect, i;
|
||||
FDriveType fd_type[2];
|
||||
FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
|
||||
BlockDriverState *fd[MAX_FD];
|
||||
static pc_cmos_init_late_arg arg;
|
||||
|
||||
@@ -385,8 +385,6 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track,
|
||||
&last_sect, FDRIVE_DRV_NONE,
|
||||
&fd_type[i]);
|
||||
} else {
|
||||
fd_type[i] = FDRIVE_DRV_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
53
hw/pc_piix.c
53
hw/pc_piix.c
@@ -306,11 +306,47 @@ static QEMUMachine pc_machine_v1_0 = {
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
static QEMUMachine pc_machine_v0_15 = {
|
||||
.name = "pc-0.15",
|
||||
.desc = "Standard PC",
|
||||
.init = pc_init_pci,
|
||||
.max_cpus = 255,
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
static QEMUMachine pc_machine_v0_14 = {
|
||||
.name = "pc-0.14",
|
||||
.desc = "Standard PC",
|
||||
.init = pc_init_pci,
|
||||
.max_cpus = 255,
|
||||
.compat_props = (GlobalProperty[]) {
|
||||
{
|
||||
.driver = "qxl",
|
||||
.property = "revision",
|
||||
.value = stringify(2),
|
||||
},{
|
||||
.driver = "qxl-vga",
|
||||
.property = "revision",
|
||||
.value = stringify(2),
|
||||
},{
|
||||
.driver = "virtio-blk-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-serial-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static QEMUMachine pc_machine_v0_13 = {
|
||||
@@ -347,6 +383,10 @@ static QEMUMachine pc_machine_v0_13 = {
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "AC97",
|
||||
.property = "use_broken_id",
|
||||
@@ -394,6 +434,10 @@ static QEMUMachine pc_machine_v0_12 = {
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "AC97",
|
||||
.property = "use_broken_id",
|
||||
@@ -449,6 +493,10 @@ static QEMUMachine pc_machine_v0_11 = {
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "AC97",
|
||||
.property = "use_broken_id",
|
||||
@@ -516,6 +564,10 @@ static QEMUMachine pc_machine_v0_10 = {
|
||||
.driver = "virtio-net-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "virtio-balloon-pci",
|
||||
.property = "event_idx",
|
||||
.value = "off",
|
||||
},{
|
||||
.driver = "AC97",
|
||||
.property = "use_broken_id",
|
||||
@@ -545,6 +597,7 @@ static QEMUMachine xenfv_machine = {
|
||||
static void pc_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&pc_machine_v1_0);
|
||||
qemu_register_machine(&pc_machine_v0_15);
|
||||
qemu_register_machine(&pc_machine_v0_14);
|
||||
qemu_register_machine(&pc_machine_v0_13);
|
||||
qemu_register_machine(&pc_machine_v0_12);
|
||||
|
@@ -91,7 +91,8 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
|
||||
*/
|
||||
dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
|
||||
dinfo->bus = scsibus->busnr;
|
||||
scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, false);
|
||||
scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit,
|
||||
false, -1);
|
||||
if (!scsidev) {
|
||||
return -1;
|
||||
}
|
||||
|
2
hw/pci.h
2
hw/pci.h
@@ -178,6 +178,8 @@ struct PCIDevice {
|
||||
unsigned *msix_entry_used;
|
||||
/* Region including the MSI-X table */
|
||||
uint32_t msix_bar_size;
|
||||
/* MSIX function mask set or MSIX disabled */
|
||||
bool msix_function_masked;
|
||||
/* Version id needed for VMState */
|
||||
int32_t version_id;
|
||||
|
||||
|
@@ -103,7 +103,7 @@ static void pl061_update(pl061_state *s)
|
||||
s->old_data = out;
|
||||
for (i = 0; i < 8; i++) {
|
||||
mask = 1 << i;
|
||||
if ((changed & mask) && s->out) {
|
||||
if (changed & mask) {
|
||||
DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
|
||||
qemu_set_irq(s->out[i], (out & mask) != 0);
|
||||
}
|
||||
|
@@ -112,6 +112,7 @@ static void spin_kick(void *data)
|
||||
|
||||
env->halted = 0;
|
||||
env->exception_index = -1;
|
||||
env->stopped = 0;
|
||||
qemu_cpu_kick(env);
|
||||
}
|
||||
|
||||
|
@@ -114,7 +114,10 @@ static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
|
||||
|
||||
switch (addr) {
|
||||
case PMCR:
|
||||
s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
|
||||
/* Clear the write-one-to-clear bits... */
|
||||
s->pm_regs[addr >> 2] &= ~(value & 0x2a);
|
||||
/* ...and set the plain r/w bits */
|
||||
s->pm_regs[addr >> 2] &= ~0x15;
|
||||
s->pm_regs[addr >> 2] |= value & 0x15;
|
||||
break;
|
||||
|
||||
|
@@ -186,7 +186,7 @@ int qdev_device_help(QemuOpts *opts)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!qemu_opt_get(opts, "?")) {
|
||||
if (!driver || !qemu_opt_get(opts, "?")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
14
hw/rtl8139.c
14
hw/rtl8139.c
@@ -1971,7 +1971,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
cplus_tx_ring_desc += 16 * descriptor;
|
||||
|
||||
DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at "
|
||||
"%08x0x%08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1],
|
||||
"%08x %08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1],
|
||||
s->TxAddr[0], cplus_tx_ring_desc);
|
||||
|
||||
uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
|
||||
@@ -2713,8 +2713,6 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
|
||||
{
|
||||
RTL8139State *s = opaque;
|
||||
|
||||
addr &= 0xff;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case MAC0 ... MAC0+5:
|
||||
@@ -2800,8 +2798,6 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
|
||||
{
|
||||
RTL8139State *s = opaque;
|
||||
|
||||
addr &= 0xfe;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case IntrMask:
|
||||
@@ -2900,8 +2896,6 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
|
||||
{
|
||||
RTL8139State *s = opaque;
|
||||
|
||||
addr &= 0xfc;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case RxMissed:
|
||||
@@ -2969,8 +2963,6 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
|
||||
RTL8139State *s = opaque;
|
||||
int ret;
|
||||
|
||||
addr &= 0xff;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case MAC0 ... MAC0+5:
|
||||
@@ -3043,8 +3035,6 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
|
||||
RTL8139State *s = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
addr &= 0xfe; /* mask lower bit */
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case IntrMask:
|
||||
@@ -3120,8 +3110,6 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
|
||||
RTL8139State *s = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
addr &= 0xfc; /* also mask low 2 bits */
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case RxMissed:
|
||||
|
@@ -254,10 +254,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
|
||||
/* Update guest supported feature bitmap */
|
||||
|
||||
features = bswap32(ldl_be_phys(dev->feat_offs));
|
||||
if (vdev->set_features) {
|
||||
vdev->set_features(vdev, features);
|
||||
}
|
||||
vdev->guest_features = features;
|
||||
virtio_set_features(vdev, features);
|
||||
}
|
||||
|
||||
VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus)
|
||||
|
@@ -97,6 +97,7 @@ int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall)
|
||||
|
||||
dev = s390_virtio_bus_find_mem(s390_bus, mem);
|
||||
virtio_reset(dev->vdev);
|
||||
stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS, 0);
|
||||
s390_virtio_device_sync(dev);
|
||||
break;
|
||||
}
|
||||
@@ -120,6 +121,34 @@ int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall)
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* The number of running CPUs. On s390 a shutdown is the state of all CPUs
|
||||
* being either stopped or disabled (for interrupts) waiting. We have to
|
||||
* track this number to call the shutdown sequence accordingly. This
|
||||
* number is modified either on startup or while holding the big qemu lock.
|
||||
*/
|
||||
static unsigned s390_running_cpus;
|
||||
|
||||
void s390_add_running_cpu(CPUState *env)
|
||||
{
|
||||
if (env->halted) {
|
||||
s390_running_cpus++;
|
||||
env->halted = 0;
|
||||
env->exception_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned s390_del_running_cpu(CPUState *env)
|
||||
{
|
||||
if (env->halted == 0) {
|
||||
assert(s390_running_cpus >= 1);
|
||||
s390_running_cpus--;
|
||||
env->halted = 1;
|
||||
env->exception_index = EXCP_HLT;
|
||||
}
|
||||
return s390_running_cpus;
|
||||
}
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void s390_init(ram_addr_t my_ram_size,
|
||||
const char *boot_device,
|
||||
@@ -136,6 +165,9 @@ static void s390_init(ram_addr_t my_ram_size,
|
||||
ram_addr_t initrd_size = 0;
|
||||
int shift = 0;
|
||||
uint8_t *storage_keys;
|
||||
void *virtio_region;
|
||||
target_phys_addr_t virtio_region_len;
|
||||
target_phys_addr_t virtio_region_start;
|
||||
int i;
|
||||
|
||||
/* s390x ram size detection needs a 16bit multiplier + an increment. So
|
||||
@@ -155,6 +187,15 @@ static void s390_init(ram_addr_t my_ram_size,
|
||||
memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size);
|
||||
memory_region_add_subregion(sysmem, 0, ram);
|
||||
|
||||
/* clear virtio region */
|
||||
virtio_region_len = my_ram_size - ram_size;
|
||||
virtio_region_start = ram_size;
|
||||
virtio_region = cpu_physical_memory_map(virtio_region_start,
|
||||
&virtio_region_len, true);
|
||||
memset(virtio_region, 0, virtio_region_len);
|
||||
cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1,
|
||||
virtio_region_len);
|
||||
|
||||
/* allocate storage keys */
|
||||
storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
|
||||
|
||||
@@ -178,8 +219,8 @@ static void s390_init(ram_addr_t my_ram_size,
|
||||
tmp_env->storage_keys = storage_keys;
|
||||
}
|
||||
|
||||
env->halted = 0;
|
||||
env->exception_index = 0;
|
||||
/* One CPU has to run */
|
||||
s390_add_running_cpu(env);
|
||||
|
||||
if (kernel_filename) {
|
||||
kernel_size = load_image(kernel_filename, qemu_get_ram_ptr(0));
|
||||
@@ -229,7 +270,7 @@ static void s390_init(ram_addr_t my_ram_size,
|
||||
|
||||
if (kernel_cmdline) {
|
||||
cpu_physical_memory_write(KERN_PARM_AREA, kernel_cmdline,
|
||||
strlen(kernel_cmdline));
|
||||
strlen(kernel_cmdline) + 1);
|
||||
}
|
||||
|
||||
/* Create VirtIO network adapters */
|
||||
|
137
hw/scsi-bus.c
137
hw/scsi-bus.c
@@ -9,8 +9,6 @@
|
||||
static char *scsibus_get_fw_dev_path(DeviceState *dev);
|
||||
static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
|
||||
static void scsi_req_dequeue(SCSIRequest *req);
|
||||
static int scsi_build_sense(uint8_t *in_buf, int in_len,
|
||||
uint8_t *buf, int len, bool fixed);
|
||||
|
||||
static struct BusInfo scsi_bus_info = {
|
||||
.name = "SCSI",
|
||||
@@ -164,7 +162,7 @@ void scsi_qdev_register(SCSIDeviceInfo *info)
|
||||
|
||||
/* handle legacy '-drive if=scsi,...' cmd line args */
|
||||
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
|
||||
int unit, bool removable)
|
||||
int unit, bool removable, int bootindex)
|
||||
{
|
||||
const char *driver;
|
||||
DeviceState *dev;
|
||||
@@ -172,6 +170,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
|
||||
driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
|
||||
dev = qdev_create(&bus->qbus, driver);
|
||||
qdev_prop_set_uint32(dev, "scsi-id", unit);
|
||||
if (bootindex >= 0) {
|
||||
qdev_prop_set_int32(dev, "bootindex", bootindex);
|
||||
}
|
||||
if (qdev_prop_exists(dev, "removable")) {
|
||||
qdev_prop_set_bit(dev, "removable", removable);
|
||||
}
|
||||
@@ -197,7 +198,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
|
||||
continue;
|
||||
}
|
||||
qemu_opts_loc_restore(dinfo->opts);
|
||||
if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false)) {
|
||||
if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1)) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
@@ -502,7 +503,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
hba_private);
|
||||
} else if (lun != d->lun ||
|
||||
buf[0] == REPORT_LUNS ||
|
||||
buf[0] == REQUEST_SENSE) {
|
||||
(buf[0] == REQUEST_SENSE && (d->sense_len || cmd.xfer < 4))) {
|
||||
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
|
||||
hba_private);
|
||||
} else {
|
||||
@@ -649,6 +650,31 @@ static void scsi_req_dequeue(SCSIRequest *req)
|
||||
}
|
||||
}
|
||||
|
||||
static int scsi_get_performance_length(int num_desc, int type, int data_type)
|
||||
{
|
||||
/* MMC-6, paragraph 6.7. */
|
||||
switch (type) {
|
||||
case 0:
|
||||
if ((data_type & 3) == 0) {
|
||||
/* Each descriptor is as in Table 295 - Nominal performance. */
|
||||
return 16 * num_desc + 8;
|
||||
} else {
|
||||
/* Each descriptor is as in Table 296 - Exceptions. */
|
||||
return 6 * num_desc + 8;
|
||||
}
|
||||
case 1:
|
||||
case 4:
|
||||
case 5:
|
||||
return 8 * num_desc + 8;
|
||||
case 2:
|
||||
return 2048 * num_desc + 8;
|
||||
case 3:
|
||||
return 16 * num_desc + 8;
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
{
|
||||
switch (buf[0] >> 5) {
|
||||
@@ -666,11 +692,11 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
cmd->len = 10;
|
||||
break;
|
||||
case 4:
|
||||
cmd->xfer = ldl_be_p(&buf[10]);
|
||||
cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL;
|
||||
cmd->len = 16;
|
||||
break;
|
||||
case 5:
|
||||
cmd->xfer = ldl_be_p(&buf[6]);
|
||||
cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL;
|
||||
cmd->len = 12;
|
||||
break;
|
||||
default:
|
||||
@@ -681,8 +707,9 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case TEST_UNIT_READY:
|
||||
case REWIND:
|
||||
case START_STOP:
|
||||
case SEEK_6:
|
||||
case SET_CAPACITY:
|
||||
case WRITE_FILEMARKS:
|
||||
case WRITE_FILEMARKS_16:
|
||||
case SPACE:
|
||||
case RESERVE:
|
||||
case RELEASE:
|
||||
@@ -691,6 +718,8 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case VERIFY_10:
|
||||
case SEEK_10:
|
||||
case SYNCHRONIZE_CACHE:
|
||||
case SYNCHRONIZE_CACHE_16:
|
||||
case LOCATE_16:
|
||||
case LOCK_UNLOCK_CACHE:
|
||||
case LOAD_UNLOAD:
|
||||
case SET_CD_SPEED:
|
||||
@@ -698,6 +727,11 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case WRITE_LONG_10:
|
||||
case MOVE_MEDIUM:
|
||||
case UPDATE_BLOCK:
|
||||
case RESERVE_TRACK:
|
||||
case SET_READ_AHEAD:
|
||||
case PRE_FETCH:
|
||||
case PRE_FETCH_16:
|
||||
case ALLOW_OVERWRITE:
|
||||
cmd->xfer = 0;
|
||||
break;
|
||||
case MODE_SENSE:
|
||||
@@ -711,14 +745,13 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case READ_BLOCK_LIMITS:
|
||||
cmd->xfer = 6;
|
||||
break;
|
||||
case READ_POSITION:
|
||||
cmd->xfer = 20;
|
||||
break;
|
||||
case SEND_VOLUME_TAG:
|
||||
cmd->xfer *= 40;
|
||||
break;
|
||||
case MEDIUM_SCAN:
|
||||
cmd->xfer *= 8;
|
||||
/* GPCMD_SET_STREAMING from multimedia commands. */
|
||||
if (dev->type == TYPE_ROM) {
|
||||
cmd->xfer = buf[10] | (buf[9] << 8);
|
||||
} else {
|
||||
cmd->xfer = buf[9] | (buf[8] << 8);
|
||||
}
|
||||
break;
|
||||
case WRITE_10:
|
||||
case WRITE_VERIFY_10:
|
||||
@@ -737,9 +770,39 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case READ_16:
|
||||
cmd->xfer *= dev->blocksize;
|
||||
break;
|
||||
case FORMAT_UNIT:
|
||||
/* MMC mandates the parameter list to be 12-bytes long. Parameters
|
||||
* for block devices are restricted to the header right now. */
|
||||
if (dev->type == TYPE_ROM && (buf[1] & 16)) {
|
||||
cmd->xfer = 12;
|
||||
} else {
|
||||
cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4);
|
||||
}
|
||||
break;
|
||||
case INQUIRY:
|
||||
case RECEIVE_DIAGNOSTIC:
|
||||
case SEND_DIAGNOSTIC:
|
||||
cmd->xfer = buf[4] | (buf[3] << 8);
|
||||
break;
|
||||
case READ_CD:
|
||||
case READ_BUFFER:
|
||||
case WRITE_BUFFER:
|
||||
case SEND_CUE_SHEET:
|
||||
cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
|
||||
break;
|
||||
case PERSISTENT_RESERVE_OUT:
|
||||
cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL;
|
||||
break;
|
||||
case ERASE_12:
|
||||
if (dev->type == TYPE_ROM) {
|
||||
/* MMC command GET PERFORMANCE. */
|
||||
cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8),
|
||||
buf[10], buf[1] & 0x1f);
|
||||
}
|
||||
break;
|
||||
case MECHANISM_STATUS:
|
||||
case READ_DVD_STRUCTURE:
|
||||
case SEND_DVD_STRUCTURE:
|
||||
case MAINTENANCE_OUT:
|
||||
case MAINTENANCE_IN:
|
||||
if (dev->type == TYPE_ROM) {
|
||||
@@ -755,6 +818,10 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu
|
||||
{
|
||||
switch (buf[0]) {
|
||||
/* stream commands */
|
||||
case ERASE_12:
|
||||
case ERASE_16:
|
||||
cmd->xfer = 0;
|
||||
break;
|
||||
case READ_6:
|
||||
case READ_REVERSE:
|
||||
case RECOVER_BUFFERED_DATA:
|
||||
@@ -770,6 +837,15 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu
|
||||
cmd->len = 6;
|
||||
cmd->xfer = 0;
|
||||
break;
|
||||
case SPACE_16:
|
||||
cmd->xfer = buf[13] | (buf[12] << 8);
|
||||
break;
|
||||
case READ_POSITION:
|
||||
cmd->xfer = buf[8] | (buf[7] << 8);
|
||||
break;
|
||||
case FORMAT_UNIT:
|
||||
cmd->xfer = buf[4] | (buf[3] << 8);
|
||||
break;
|
||||
/* generic commands */
|
||||
default:
|
||||
return scsi_req_length(cmd, dev, buf);
|
||||
@@ -809,6 +885,8 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
||||
case SEARCH_LOW_12:
|
||||
case MEDIUM_SCAN:
|
||||
case SEND_VOLUME_TAG:
|
||||
case SEND_CUE_SHEET:
|
||||
case SEND_DVD_STRUCTURE:
|
||||
case PERSISTENT_RESERVE_OUT:
|
||||
case MAINTENANCE_OUT:
|
||||
cmd->mode = SCSI_XFER_TO_DEV;
|
||||
@@ -835,7 +913,7 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd)
|
||||
case 1:
|
||||
case 2:
|
||||
case 5:
|
||||
lba = ldl_be_p(&buf[2]);
|
||||
lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
|
||||
break;
|
||||
case 4:
|
||||
lba = ldq_be_p(&buf[2]);
|
||||
@@ -1036,7 +1114,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS",
|
||||
[ READ_6 ] = "READ_6",
|
||||
[ WRITE_6 ] = "WRITE_6",
|
||||
[ SEEK_6 ] = "SEEK_6",
|
||||
[ SET_CAPACITY ] = "SET_CAPACITY",
|
||||
[ READ_REVERSE ] = "READ_REVERSE",
|
||||
[ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
|
||||
[ SPACE ] = "SPACE",
|
||||
@@ -1064,7 +1142,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ SEARCH_EQUAL ] = "SEARCH_EQUAL",
|
||||
[ SEARCH_LOW ] = "SEARCH_LOW",
|
||||
[ SET_LIMITS ] = "SET_LIMITS",
|
||||
[ PRE_FETCH ] = "PRE_FETCH",
|
||||
[ PRE_FETCH ] = "PRE_FETCH/READ_POSITION",
|
||||
/* READ_POSITION and PRE_FETCH use the same operation code */
|
||||
[ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE",
|
||||
[ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE",
|
||||
@@ -1101,9 +1179,11 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ WRITE_16 ] = "WRITE_16",
|
||||
[ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
|
||||
[ VERIFY_16 ] = "VERIFY_16",
|
||||
[ SYNCHRONIZE_CACHE_16 ] = "SYNCHRONIZE_CACHE_16",
|
||||
[ PRE_FETCH_16 ] = "PRE_FETCH_16",
|
||||
[ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
|
||||
/* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
|
||||
[ LOCATE_16 ] = "LOCATE_16",
|
||||
[ WRITE_SAME_16 ] = "WRITE_SAME_16",
|
||||
[ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16",
|
||||
/* ERASE_16 and WRITE_SAME_16 use the same operation code */
|
||||
[ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
|
||||
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
||||
@@ -1113,6 +1193,8 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
||||
[ READ_12 ] = "READ_12",
|
||||
[ WRITE_12 ] = "WRITE_12",
|
||||
[ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE",
|
||||
/* ERASE_12 and GET_PERFORMANCE use the same operation code */
|
||||
[ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12",
|
||||
[ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
|
||||
[ VERIFY_12 ] = "VERIFY_12",
|
||||
@@ -1120,9 +1202,18 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
|
||||
[ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
|
||||
[ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
|
||||
[ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG",
|
||||
[ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING",
|
||||
/* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
|
||||
[ READ_CD ] = "READ_CD",
|
||||
[ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
|
||||
[ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE",
|
||||
[ RESERVE_TRACK ] = "RESERVE_TRACK",
|
||||
[ SEND_CUE_SHEET ] = "SEND_CUE_SHEET",
|
||||
[ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE",
|
||||
[ SET_CD_SPEED ] = "SET_CD_SPEED",
|
||||
[ SET_READ_AHEAD ] = "SET_READ_AHEAD",
|
||||
[ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE",
|
||||
[ MECHANISM_STATUS ] = "MECHANISM_STATUS",
|
||||
};
|
||||
|
||||
if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
|
||||
@@ -1279,8 +1370,8 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev)
|
||||
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
|
||||
char path[100];
|
||||
|
||||
snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev),
|
||||
d->channel, d->id, d->lun);
|
||||
snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel,
|
||||
qdev_fw_name(dev), d->id, d->lun);
|
||||
|
||||
return strdup(path);
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@
|
||||
#define REASSIGN_BLOCKS 0x07
|
||||
#define READ_6 0x08
|
||||
#define WRITE_6 0x0a
|
||||
#define SEEK_6 0x0b
|
||||
#define SET_CAPACITY 0x0b
|
||||
#define READ_REVERSE 0x0f
|
||||
#define WRITE_FILEMARKS 0x10
|
||||
#define SPACE 0x11
|
||||
@@ -81,14 +81,17 @@
|
||||
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
|
||||
#define LOG_SELECT 0x4c
|
||||
#define LOG_SENSE 0x4d
|
||||
#define RESERVE_TRACK 0x53
|
||||
#define MODE_SELECT_10 0x55
|
||||
#define RESERVE_10 0x56
|
||||
#define RELEASE_10 0x57
|
||||
#define MODE_SENSE_10 0x5a
|
||||
#define SEND_CUE_SHEET 0x5d
|
||||
#define PERSISTENT_RESERVE_IN 0x5e
|
||||
#define PERSISTENT_RESERVE_OUT 0x5f
|
||||
#define VARLENGTH_CDB 0x7f
|
||||
#define WRITE_FILEMARKS_16 0x80
|
||||
#define ALLOW_OVERWRITE 0x82
|
||||
#define EXTENDED_COPY 0x83
|
||||
#define ATA_PASSTHROUGH 0x85
|
||||
#define ACCESS_CONTROL_IN 0x86
|
||||
@@ -98,6 +101,8 @@
|
||||
#define WRITE_16 0x8a
|
||||
#define WRITE_VERIFY_16 0x8e
|
||||
#define VERIFY_16 0x8f
|
||||
#define PRE_FETCH_16 0x90
|
||||
#define SPACE_16 0x91
|
||||
#define SYNCHRONIZE_CACHE_16 0x91
|
||||
#define LOCATE_16 0x92
|
||||
#define WRITE_SAME_16 0x93
|
||||
@@ -110,9 +115,11 @@
|
||||
#define MAINTENANCE_OUT 0xa4
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
#define LOAD_UNLOAD 0xa6
|
||||
#define SET_READ_AHEAD 0xa7
|
||||
#define READ_12 0xa8
|
||||
#define WRITE_12 0xaa
|
||||
#define SERVICE_ACTION_IN_12 0xab
|
||||
#define ERASE_12 0xac
|
||||
#define READ_DVD_STRUCTURE 0xad
|
||||
#define WRITE_VERIFY_12 0xae
|
||||
#define VERIFY_12 0xaf
|
||||
@@ -125,6 +132,7 @@
|
||||
#define SET_CD_SPEED 0xbb
|
||||
#define MECHANISM_STATUS 0xbd
|
||||
#define READ_CD 0xbe
|
||||
#define SEND_DVD_STRUCTURE 0xbf
|
||||
|
||||
/*
|
||||
* SERVICE ACTION IN subcodes
|
||||
|
@@ -65,6 +65,7 @@ struct SCSIDiskState
|
||||
uint32_t removable;
|
||||
bool media_changed;
|
||||
bool media_event;
|
||||
bool eject_request;
|
||||
QEMUBH *bh;
|
||||
char *version;
|
||||
char *serial;
|
||||
@@ -671,9 +672,14 @@ static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
|
||||
|
||||
/* Event notification descriptor */
|
||||
event_code = MEC_NO_CHANGE;
|
||||
if (media_status != MS_TRAY_OPEN && s->media_event) {
|
||||
event_code = MEC_NEW_MEDIA;
|
||||
s->media_event = false;
|
||||
if (media_status != MS_TRAY_OPEN) {
|
||||
if (s->media_event) {
|
||||
event_code = MEC_NEW_MEDIA;
|
||||
s->media_event = false;
|
||||
} else if (s->eject_request) {
|
||||
event_code = MEC_EJECT_REQUESTED;
|
||||
s->eject_request = false;
|
||||
}
|
||||
}
|
||||
|
||||
outbuf[0] = event_code;
|
||||
@@ -791,7 +797,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
|
||||
break;
|
||||
}
|
||||
/* if a geometry hint is available, use it */
|
||||
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
|
||||
bdrv_guess_geometry(bdrv, &cylinders, &heads, &secs);
|
||||
p[2] = (cylinders >> 16) & 0xff;
|
||||
p[3] = (cylinders >> 8) & 0xff;
|
||||
p[4] = cylinders & 0xff;
|
||||
@@ -825,7 +831,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
|
||||
p[2] = 5000 >> 8;
|
||||
p[3] = 5000 & 0xff;
|
||||
/* if a geometry hint is available, use it */
|
||||
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
|
||||
bdrv_guess_geometry(bdrv, &cylinders, &heads, &secs);
|
||||
p[4] = heads & 0xff;
|
||||
p[5] = secs & 0xff;
|
||||
p[6] = s->qdev.blocksize >> 8;
|
||||
@@ -950,8 +956,9 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
|
||||
p += 8;
|
||||
}
|
||||
|
||||
/* MMC prescribes that CD/DVD drives have no block descriptors. */
|
||||
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
|
||||
if (!dbd && nb_sectors) {
|
||||
if (!dbd && s->qdev.type == TYPE_DISK && nb_sectors) {
|
||||
if (r->req.cmd.buf[0] == MODE_SENSE) {
|
||||
outbuf[3] = 8; /* Block descriptor length */
|
||||
} else { /* MODE_SENSE_10 */
|
||||
@@ -1172,6 +1179,11 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
|
||||
outbuf[7] = 0;
|
||||
buflen = 8;
|
||||
break;
|
||||
case REQUEST_SENSE:
|
||||
/* Just return "NO SENSE". */
|
||||
buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
|
||||
(req->cmd.buf[1] & 1) == 0);
|
||||
break;
|
||||
case MECHANISM_STATUS:
|
||||
buflen = scsi_emulate_mechanism_status(s, outbuf);
|
||||
if (buflen < 0) {
|
||||
@@ -1306,6 +1318,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
case GET_EVENT_STATUS_NOTIFICATION:
|
||||
case MECHANISM_STATUS:
|
||||
case SERVICE_ACTION_IN_16:
|
||||
case REQUEST_SENSE:
|
||||
case VERIFY_10:
|
||||
rc = scsi_disk_emulate_command(r);
|
||||
if (rc < 0) {
|
||||
@@ -1368,10 +1381,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case SEEK_6:
|
||||
case SEEK_10:
|
||||
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
|
||||
r->req.cmd.lba);
|
||||
DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
|
||||
if (r->req.cmd.lba > s->qdev.max_lba) {
|
||||
goto illegal_lba;
|
||||
}
|
||||
@@ -1402,8 +1413,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
}
|
||||
|
||||
break;
|
||||
case REQUEST_SENSE:
|
||||
abort();
|
||||
default:
|
||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
||||
@@ -1470,6 +1479,17 @@ static void scsi_cd_change_media_cb(void *opaque, bool load)
|
||||
s->tray_open = !load;
|
||||
s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM);
|
||||
s->media_event = true;
|
||||
s->eject_request = false;
|
||||
}
|
||||
|
||||
static void scsi_cd_eject_request_cb(void *opaque, bool force)
|
||||
{
|
||||
SCSIDiskState *s = opaque;
|
||||
|
||||
s->eject_request = true;
|
||||
if (force) {
|
||||
s->tray_locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool scsi_cd_is_tray_open(void *opaque)
|
||||
@@ -1484,6 +1504,7 @@ static bool scsi_cd_is_medium_locked(void *opaque)
|
||||
|
||||
static const BlockDevOps scsi_cd_block_ops = {
|
||||
.change_media_cb = scsi_cd_change_media_cb,
|
||||
.eject_request_cb = scsi_cd_eject_request_cb,
|
||||
.is_tray_open = scsi_cd_is_tray_open,
|
||||
.is_medium_locked = scsi_cd_is_medium_locked,
|
||||
};
|
||||
@@ -1535,7 +1556,7 @@ static int scsi_initfn(SCSIDevice *dev)
|
||||
bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
|
||||
|
||||
bdrv_iostatus_enable(s->qdev.conf.bs);
|
||||
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
|
||||
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1682,8 +1703,20 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
|
||||
case WRITE_VERIFY_10:
|
||||
case WRITE_VERIFY_12:
|
||||
case WRITE_VERIFY_16:
|
||||
return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
|
||||
hba_private);
|
||||
/* MMC writing cannot be done via pread/pwrite, because it sometimes
|
||||
* involves writing beyond the maximum LBA or to negative LBA (lead-in).
|
||||
* And once you do these writes, reading from the block device is
|
||||
* unreliable, too. It is even possible that reads deliver random data
|
||||
* from the host page cache (this is probably a Linux bug).
|
||||
*
|
||||
* We might use scsi_disk_reqops as long as no writing commands are
|
||||
* seen, but performance usually isn't paramount on optical media. So,
|
||||
* just make scsi-block operate the same as scsi-generic for them.
|
||||
*/
|
||||
if (s->qdev.type != TYPE_ROM) {
|
||||
return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
|
||||
hba_private);
|
||||
}
|
||||
}
|
||||
|
||||
return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
|
||||
|
@@ -413,6 +413,10 @@ static int scsi_generic_initfn(SCSIDevice *s)
|
||||
/* define device state */
|
||||
s->type = scsiid.scsi_type;
|
||||
DPRINTF("device type %d\n", s->type);
|
||||
if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
|
||||
add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
|
||||
}
|
||||
|
||||
switch (s->type) {
|
||||
case TYPE_TAPE:
|
||||
s->blocksize = get_stream_blocksize(s->conf.bs);
|
||||
@@ -459,6 +463,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
|
||||
static SCSIDeviceInfo scsi_generic_info = {
|
||||
.qdev.name = "scsi-generic",
|
||||
.qdev.fw_name = "disk",
|
||||
.qdev.desc = "pass through generic scsi device (/dev/sg*)",
|
||||
.qdev.size = sizeof(SCSIDevice),
|
||||
.qdev.reset = scsi_generic_reset,
|
||||
|
@@ -128,7 +128,7 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
|
||||
}
|
||||
|
||||
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
|
||||
int unit, bool removable);
|
||||
int unit, bool removable, int bootindex);
|
||||
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
|
||||
|
||||
/*
|
||||
@@ -179,6 +179,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
|
||||
#define SENSE_CODE(x) sense_code_ ## x
|
||||
|
||||
int scsi_sense_valid(SCSISense sense);
|
||||
int scsi_build_sense(uint8_t *in_buf, int in_len,
|
||||
uint8_t *buf, int len, bool fixed);
|
||||
|
||||
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
|
||||
uint32_t tag, uint32_t lun, void *hba_private);
|
||||
|
12
hw/spapr.c
12
hw/spapr.c
@@ -57,7 +57,7 @@
|
||||
#define FW_MAX_SIZE 0x400000
|
||||
#define FW_FILE_NAME "slof.bin"
|
||||
|
||||
#define MIN_RAM_SLOF 512UL
|
||||
#define MIN_RMA_SLOF 128UL
|
||||
|
||||
#define TIMEBASE_FREQ 512000000ULL
|
||||
|
||||
@@ -351,6 +351,8 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
||||
fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
|
||||
}
|
||||
|
||||
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
||||
|
||||
_FDT((fdt_pack(fdt)));
|
||||
|
||||
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
|
||||
@@ -407,7 +409,9 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
long pteg_shift = 17;
|
||||
char *filename;
|
||||
|
||||
spapr = g_malloc(sizeof(*spapr));
|
||||
spapr = g_malloc0(sizeof(*spapr));
|
||||
QLIST_INIT(&spapr->phbs);
|
||||
|
||||
cpu_ppc_hypercall = emulate_spapr_hypercall;
|
||||
|
||||
/* Allocate RMA if necessary */
|
||||
@@ -560,9 +564,9 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
|
||||
spapr->entry_point = KERNEL_LOAD_ADDR;
|
||||
} else {
|
||||
if (ram_size < (MIN_RAM_SLOF << 20)) {
|
||||
if (rma_size < (MIN_RMA_SLOF << 20)) {
|
||||
fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
|
||||
"%ldM guest RAM\n", MIN_RAM_SLOF);
|
||||
"%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
|
||||
exit(1);
|
||||
}
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
|
||||
|
@@ -454,7 +454,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
|
||||
reg[0].size = 0;
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < PCI_NUM_REGIONS; ++i) {
|
||||
for (i = 0; i < ARRAY_SIZE(bars); ++i) {
|
||||
if (0 == dev->io_regions[i].size) {
|
||||
continue;
|
||||
}
|
||||
|
124
hw/spapr_vio.c
124
hw/spapr_vio.c
@@ -66,11 +66,24 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
|
||||
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
|
||||
dev = (VIOsPAPRDevice *)qdev;
|
||||
if (dev->reg == reg) {
|
||||
break;
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
return dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *vio_format_dev_name(VIOsPAPRDevice *dev)
|
||||
{
|
||||
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
|
||||
char *name;
|
||||
|
||||
/* Device tree style name device@reg */
|
||||
if (asprintf(&name, "%s@%x", info->dt_name, dev->reg) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FDT
|
||||
@@ -78,15 +91,21 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
|
||||
void *fdt)
|
||||
{
|
||||
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
|
||||
int vdevice_off, node_off;
|
||||
int ret;
|
||||
int vdevice_off, node_off, ret;
|
||||
char *dt_name;
|
||||
|
||||
vdevice_off = fdt_path_offset(fdt, "/vdevice");
|
||||
if (vdevice_off < 0) {
|
||||
return vdevice_off;
|
||||
}
|
||||
|
||||
node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id);
|
||||
dt_name = vio_format_dev_name(dev);
|
||||
if (!dt_name) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
|
||||
free(dt_name);
|
||||
if (node_off < 0) {
|
||||
return node_off;
|
||||
}
|
||||
@@ -608,12 +627,15 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
|
||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
|
||||
char *id;
|
||||
|
||||
if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
|
||||
return -1;
|
||||
/* Don't overwrite ids assigned on the command line */
|
||||
if (!dev->qdev.id) {
|
||||
id = vio_format_dev_name(dev);
|
||||
if (!id) {
|
||||
return -1;
|
||||
}
|
||||
dev->qdev.id = id;
|
||||
}
|
||||
|
||||
dev->qdev.id = id;
|
||||
|
||||
dev->qirq = spapr_allocate_irq(dev->vio_irq_num, &dev->vio_irq_num);
|
||||
if (!dev->qirq) {
|
||||
return -1;
|
||||
@@ -727,21 +749,95 @@ static void spapr_vio_register_devices(void)
|
||||
device_init(spapr_vio_register_devices)
|
||||
|
||||
#ifdef CONFIG_FDT
|
||||
static int compare_reg(const void *p1, const void *p2)
|
||||
{
|
||||
VIOsPAPRDevice const *dev1, *dev2;
|
||||
|
||||
dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
|
||||
dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
|
||||
|
||||
if (dev1->reg < dev2->reg) {
|
||||
return -1;
|
||||
}
|
||||
if (dev1->reg == dev2->reg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dev1->reg > dev2->reg */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
|
||||
{
|
||||
DeviceState *qdev;
|
||||
int ret = 0;
|
||||
DeviceState *qdev, **qdevs;
|
||||
int i, num, ret = 0;
|
||||
|
||||
/* Count qdevs on the bus list */
|
||||
num = 0;
|
||||
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
|
||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
|
||||
num++;
|
||||
}
|
||||
|
||||
/* Copy out into an array of pointers */
|
||||
qdevs = g_malloc(sizeof(qdev) * num);
|
||||
num = 0;
|
||||
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
|
||||
qdevs[num++] = qdev;
|
||||
}
|
||||
|
||||
/* Sort the array */
|
||||
qsort(qdevs, num, sizeof(qdev), compare_reg);
|
||||
|
||||
/* Hack alert. Give the devices to libfdt in reverse order, we happen
|
||||
* to know that will mean they are in forward order in the tree. */
|
||||
for (i = num - 1; i >= 0; i--) {
|
||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
|
||||
|
||||
ret = vio_make_devnode(dev, fdt);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
out:
|
||||
free(qdevs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
|
||||
{
|
||||
VIOsPAPRDevice *dev;
|
||||
char *name, *path;
|
||||
int ret, offset;
|
||||
|
||||
dev = spapr_vty_get_default(bus);
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
offset = fdt_path_offset(fdt, "/chosen");
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
name = vio_format_dev_name(dev);
|
||||
if (!name) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (asprintf(&path, "/vdevice/%s", name) < 0) {
|
||||
path = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
|
||||
out:
|
||||
free(name);
|
||||
free(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_FDT */
|
||||
|
@@ -83,6 +83,7 @@ extern VIOsPAPRBus *spapr_vio_bus_init(void);
|
||||
extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
|
||||
extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
|
||||
extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
|
||||
extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
|
||||
|
||||
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
|
||||
|
||||
@@ -108,6 +109,8 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
|
||||
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
|
||||
void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg);
|
||||
|
||||
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
|
||||
|
||||
int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
|
||||
void spapr_vio_quiesce(void);
|
||||
|
||||
|
@@ -58,12 +58,20 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev)
|
||||
{
|
||||
VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
|
||||
|
||||
if (!dev->chardev) {
|
||||
fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
qemu_chr_add_handlers(dev->chardev, vty_can_receive,
|
||||
vty_receive, NULL, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
|
||||
|
||||
static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
@@ -71,9 +79,10 @@ static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
|
||||
target_ulong len = args[1];
|
||||
target_ulong char0_7 = args[2];
|
||||
target_ulong char8_15 = args[3];
|
||||
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
VIOsPAPRDevice *sdev;
|
||||
uint8_t buf[16];
|
||||
|
||||
sdev = vty_lookup(spapr, reg);
|
||||
if (!sdev) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
@@ -97,9 +106,10 @@ static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
|
||||
target_ulong *len = args + 0;
|
||||
target_ulong *char0_7 = args + 1;
|
||||
target_ulong *char8_15 = args + 2;
|
||||
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
VIOsPAPRDevice *sdev;
|
||||
uint8_t buf[16];
|
||||
|
||||
sdev = vty_lookup(spapr, reg);
|
||||
if (!sdev) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
@@ -140,12 +150,64 @@ static VIOsPAPRDeviceInfo spapr_vty = {
|
||||
.qdev.name = "spapr-vty",
|
||||
.qdev.size = sizeof(VIOsPAPRVTYDevice),
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, 0, 0),
|
||||
DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
|
||||
DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
|
||||
{
|
||||
VIOsPAPRDevice *sdev, *selected;
|
||||
DeviceState *iter;
|
||||
|
||||
/*
|
||||
* To avoid the console bouncing around we want one VTY to be
|
||||
* the "default". We haven't really got anything to go on, so
|
||||
* arbitrarily choose the one with the lowest reg value.
|
||||
*/
|
||||
|
||||
selected = NULL;
|
||||
QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
|
||||
/* Only look at VTY devices */
|
||||
if (iter->info != &spapr_vty.qdev) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
|
||||
|
||||
/* First VTY we've found, so it is selected for now */
|
||||
if (!selected) {
|
||||
selected = sdev;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Choose VTY with lowest reg value */
|
||||
if (sdev->reg < selected->reg) {
|
||||
selected = sdev;
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||
{
|
||||
VIOsPAPRDevice *sdev;
|
||||
|
||||
sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
if (!sdev && reg == 0) {
|
||||
/* Hack for kernel early debug, which always specifies reg==0.
|
||||
* We search all VIO devices, and grab the vty with the lowest
|
||||
* reg. This attempts to mimic existing PowerVM behaviour
|
||||
* (early debug does work there, despite having no vty with
|
||||
* reg==0. */
|
||||
return spapr_vty_get_default(spapr->vio_bus);
|
||||
}
|
||||
|
||||
return sdev;
|
||||
}
|
||||
|
||||
static void spapr_vty_register(void)
|
||||
{
|
||||
spapr_vio_bus_register_withprop(&spapr_vty);
|
||||
|
@@ -131,9 +131,7 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
|
||||
}
|
||||
switch (offset >> 2) {
|
||||
case SYBORG_VIRTIO_GUEST_FEATURES:
|
||||
if (vdev->set_features)
|
||||
vdev->set_features(vdev, value);
|
||||
vdev->guest_features = value;
|
||||
virtio_set_features(vdev, value);
|
||||
break;
|
||||
case SYBORG_VIRTIO_QUEUE_BASE:
|
||||
if (value == 0)
|
||||
|
@@ -30,12 +30,8 @@ static void init_dev(tc58128_dev * dev, const char *filename)
|
||||
int ret, blocks;
|
||||
|
||||
dev->state = WAIT;
|
||||
dev->flash_contents = g_malloc0(FLASH_SIZE);
|
||||
dev->flash_contents = g_malloc(FLASH_SIZE);
|
||||
memset(dev->flash_contents, 0xff, FLASH_SIZE);
|
||||
if (!dev->flash_contents) {
|
||||
fprintf(stderr, "could not alloc memory for flash\n");
|
||||
exit(1);
|
||||
}
|
||||
if (filename) {
|
||||
/* Load flash image skipping the first block */
|
||||
ret = load_image(filename, dev->flash_contents + 528 * 32);
|
||||
|
@@ -528,6 +528,9 @@ USBDevice *usb_bt_init(HCIInfo *hci)
|
||||
if (!hci)
|
||||
return NULL;
|
||||
dev = usb_create_simple(NULL /* FIXME */, "usb-bt-dongle");
|
||||
if (!dev) {
|
||||
return NULL;
|
||||
}
|
||||
s = DO_UPCAST(struct USBBtState, dev, dev);
|
||||
s->dev.opaque = s;
|
||||
|
||||
|
29
hw/usb-bus.c
29
hw/usb-bus.c
@@ -9,6 +9,7 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
|
||||
|
||||
static char *usb_get_dev_path(DeviceState *dev);
|
||||
static char *usb_get_fw_dev_path(DeviceState *qdev);
|
||||
static int usb_qdev_exit(DeviceState *qdev);
|
||||
|
||||
static struct BusInfo usb_bus_info = {
|
||||
.name = "USB",
|
||||
@@ -75,12 +76,23 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
||||
dev->auto_attach = 1;
|
||||
QLIST_INIT(&dev->strings);
|
||||
rc = usb_claim_port(dev);
|
||||
if (rc == 0) {
|
||||
rc = dev->info->init(dev);
|
||||
if (rc != 0) {
|
||||
goto err;
|
||||
}
|
||||
if (rc == 0 && dev->auto_attach) {
|
||||
rc = dev->info->init(dev);
|
||||
if (rc != 0) {
|
||||
goto err;
|
||||
}
|
||||
if (dev->auto_attach) {
|
||||
rc = usb_device_attach(dev);
|
||||
if (rc != 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
usb_qdev_exit(qdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -139,10 +151,17 @@ USBDevice *usb_create(USBBus *bus, const char *name)
|
||||
USBDevice *usb_create_simple(USBBus *bus, const char *name)
|
||||
{
|
||||
USBDevice *dev = usb_create(bus, name);
|
||||
int rc;
|
||||
|
||||
if (!dev) {
|
||||
hw_error("Failed to create USB device '%s'\n", name);
|
||||
error_report("Failed to create USB device '%s'\n", name);
|
||||
return NULL;
|
||||
}
|
||||
rc = qdev_init(&dev->qdev);
|
||||
if (rc < 0) {
|
||||
error_report("Failed to initialize USB device '%s'\n", name);
|
||||
return NULL;
|
||||
}
|
||||
qdev_init_nofail(&dev->qdev);
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
@@ -437,37 +437,39 @@ struct EHCIState {
|
||||
} while(0)
|
||||
|
||||
static const char *ehci_state_names[] = {
|
||||
[ EST_INACTIVE ] = "INACTIVE",
|
||||
[ EST_ACTIVE ] = "ACTIVE",
|
||||
[ EST_EXECUTING ] = "EXECUTING",
|
||||
[ EST_SLEEPING ] = "SLEEPING",
|
||||
[ EST_WAITLISTHEAD ] = "WAITLISTHEAD",
|
||||
[ EST_FETCHENTRY ] = "FETCH ENTRY",
|
||||
[ EST_FETCHQH ] = "FETCH QH",
|
||||
[ EST_FETCHITD ] = "FETCH ITD",
|
||||
[ EST_ADVANCEQUEUE ] = "ADVANCEQUEUE",
|
||||
[ EST_FETCHQTD ] = "FETCH QTD",
|
||||
[ EST_EXECUTE ] = "EXECUTE",
|
||||
[ EST_WRITEBACK ] = "WRITEBACK",
|
||||
[ EST_HORIZONTALQH ] = "HORIZONTALQH",
|
||||
[EST_INACTIVE] = "INACTIVE",
|
||||
[EST_ACTIVE] = "ACTIVE",
|
||||
[EST_EXECUTING] = "EXECUTING",
|
||||
[EST_SLEEPING] = "SLEEPING",
|
||||
[EST_WAITLISTHEAD] = "WAITLISTHEAD",
|
||||
[EST_FETCHENTRY] = "FETCH ENTRY",
|
||||
[EST_FETCHQH] = "FETCH QH",
|
||||
[EST_FETCHITD] = "FETCH ITD",
|
||||
[EST_ADVANCEQUEUE] = "ADVANCEQUEUE",
|
||||
[EST_FETCHQTD] = "FETCH QTD",
|
||||
[EST_EXECUTE] = "EXECUTE",
|
||||
[EST_WRITEBACK] = "WRITEBACK",
|
||||
[EST_HORIZONTALQH] = "HORIZONTALQH",
|
||||
};
|
||||
|
||||
static const char *ehci_mmio_names[] = {
|
||||
[ CAPLENGTH ] = "CAPLENGTH",
|
||||
[ HCIVERSION ] = "HCIVERSION",
|
||||
[ HCSPARAMS ] = "HCSPARAMS",
|
||||
[ HCCPARAMS ] = "HCCPARAMS",
|
||||
[ USBCMD ] = "USBCMD",
|
||||
[ USBSTS ] = "USBSTS",
|
||||
[ USBINTR ] = "USBINTR",
|
||||
[ FRINDEX ] = "FRINDEX",
|
||||
[ PERIODICLISTBASE ] = "P-LIST BASE",
|
||||
[ ASYNCLISTADDR ] = "A-LIST ADDR",
|
||||
[ PORTSC_BEGIN ] = "PORTSC #0",
|
||||
[ PORTSC_BEGIN + 4] = "PORTSC #1",
|
||||
[ PORTSC_BEGIN + 8] = "PORTSC #2",
|
||||
[ PORTSC_BEGIN + 12] = "PORTSC #3",
|
||||
[ CONFIGFLAG ] = "CONFIGFLAG",
|
||||
[CAPLENGTH] = "CAPLENGTH",
|
||||
[HCIVERSION] = "HCIVERSION",
|
||||
[HCSPARAMS] = "HCSPARAMS",
|
||||
[HCCPARAMS] = "HCCPARAMS",
|
||||
[USBCMD] = "USBCMD",
|
||||
[USBSTS] = "USBSTS",
|
||||
[USBINTR] = "USBINTR",
|
||||
[FRINDEX] = "FRINDEX",
|
||||
[PERIODICLISTBASE] = "P-LIST BASE",
|
||||
[ASYNCLISTADDR] = "A-LIST ADDR",
|
||||
[PORTSC_BEGIN] = "PORTSC #0",
|
||||
[PORTSC_BEGIN + 4] = "PORTSC #1",
|
||||
[PORTSC_BEGIN + 8] = "PORTSC #2",
|
||||
[PORTSC_BEGIN + 12] = "PORTSC #3",
|
||||
[PORTSC_BEGIN + 16] = "PORTSC #4",
|
||||
[PORTSC_BEGIN + 20] = "PORTSC #5",
|
||||
[CONFIGFLAG] = "CONFIGFLAG",
|
||||
};
|
||||
|
||||
static const char *nr2str(const char **n, size_t len, uint32_t nr)
|
||||
@@ -2046,6 +2048,7 @@ static void ehci_advance_state(EHCIState *ehci,
|
||||
break;
|
||||
|
||||
case EST_WRITEBACK:
|
||||
assert(q != NULL);
|
||||
again = ehci_state_writeback(q, async);
|
||||
break;
|
||||
|
||||
|
22
hw/usb-hub.c
22
hw/usb-hub.c
@@ -171,6 +171,8 @@ static void usb_hub_detach(USBPort *port1)
|
||||
USBHubState *s = port1->opaque;
|
||||
USBHubPort *port = &s->ports[port1->index];
|
||||
|
||||
usb_wakeup(&s->dev);
|
||||
|
||||
/* Let upstream know the device on this port is gone */
|
||||
s->dev.port->ops->child_detach(s->dev.port, port1->dev);
|
||||
|
||||
@@ -220,7 +222,22 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet)
|
||||
|
||||
static void usb_hub_handle_reset(USBDevice *dev)
|
||||
{
|
||||
/* XXX: do it */
|
||||
USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
|
||||
USBHubPort *port;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_PORTS; i++) {
|
||||
port = s->ports + i;
|
||||
port->wPortStatus = PORT_STAT_POWER;
|
||||
port->wPortChange = 0;
|
||||
if (port->port.dev && port->port.dev->attached) {
|
||||
port->wPortStatus |= PORT_STAT_CONNECTION;
|
||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||
if (port->port.dev->speed == USB_SPEED_LOW) {
|
||||
port->wPortStatus |= PORT_STAT_LOW_SPEED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||
@@ -495,9 +512,8 @@ static int usb_hub_initfn(USBDevice *dev)
|
||||
&port->port, s, i, &usb_hub_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
usb_port_location(&port->port, dev->port, i+1);
|
||||
port->wPortStatus = PORT_STAT_POWER;
|
||||
port->wPortChange = 0;
|
||||
}
|
||||
usb_hub_handle_reset(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
81
hw/usb-msd.c
81
hw/usb-msd.c
@@ -38,6 +38,13 @@ enum USBMSDMode {
|
||||
USB_MSDM_CSW /* Command Status. */
|
||||
};
|
||||
|
||||
struct usb_msd_csw {
|
||||
uint32_t sig;
|
||||
uint32_t tag;
|
||||
uint32_t residue;
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
USBDevice dev;
|
||||
enum USBMSDMode mode;
|
||||
@@ -45,14 +52,13 @@ typedef struct {
|
||||
uint8_t *scsi_buf;
|
||||
uint32_t data_len;
|
||||
uint32_t residue;
|
||||
uint32_t tag;
|
||||
struct usb_msd_csw csw;
|
||||
SCSIRequest *req;
|
||||
SCSIBus bus;
|
||||
BlockConf conf;
|
||||
char *serial;
|
||||
SCSIDevice *scsi_dev;
|
||||
uint32_t removable;
|
||||
int result;
|
||||
/* For async completion. */
|
||||
USBPacket *packet;
|
||||
} MSDState;
|
||||
@@ -67,13 +73,6 @@ struct usb_msd_cbw {
|
||||
uint8_t cmd[16];
|
||||
};
|
||||
|
||||
struct usb_msd_csw {
|
||||
uint32_t sig;
|
||||
uint32_t tag;
|
||||
uint32_t residue;
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
enum {
|
||||
STR_MANUFACTURER = 1,
|
||||
STR_PRODUCT,
|
||||
@@ -191,17 +190,15 @@ static void usb_msd_copy_data(MSDState *s, USBPacket *p)
|
||||
|
||||
static void usb_msd_send_status(MSDState *s, USBPacket *p)
|
||||
{
|
||||
struct usb_msd_csw csw;
|
||||
int len;
|
||||
|
||||
csw.sig = cpu_to_le32(0x53425355);
|
||||
csw.tag = cpu_to_le32(s->tag);
|
||||
csw.residue = s->residue;
|
||||
csw.status = s->result;
|
||||
DPRINTF("Command status %d tag 0x%x, len %zd\n",
|
||||
s->csw.status, s->csw.tag, p->iov.size);
|
||||
|
||||
len = MIN(sizeof(csw), p->iov.size);
|
||||
usb_packet_copy(p, &csw, len);
|
||||
p->result = len;
|
||||
assert(s->csw.sig == 0x53425355);
|
||||
len = MIN(sizeof(s->csw), p->iov.size);
|
||||
usb_packet_copy(p, &s->csw, len);
|
||||
memset(&s->csw, 0, sizeof(s->csw));
|
||||
}
|
||||
|
||||
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
|
||||
@@ -231,9 +228,14 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
|
||||
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
|
||||
USBPacket *p = s->packet;
|
||||
|
||||
DPRINTF("Command complete %d\n", status);
|
||||
DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
|
||||
s->residue = s->data_len;
|
||||
s->result = status != 0;
|
||||
|
||||
s->csw.sig = cpu_to_le32(0x53425355);
|
||||
s->csw.tag = cpu_to_le32(req->tag);
|
||||
s->csw.residue = s->residue;
|
||||
s->csw.status = status != 0;
|
||||
|
||||
if (s->packet) {
|
||||
if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
|
||||
/* A deferred packet with no write data remaining must be
|
||||
@@ -276,6 +278,18 @@ static void usb_msd_handle_reset(USBDevice *dev)
|
||||
MSDState *s = (MSDState *)dev;
|
||||
|
||||
DPRINTF("Reset\n");
|
||||
if (s->req) {
|
||||
scsi_req_cancel(s->req);
|
||||
}
|
||||
assert(s->req == NULL);
|
||||
|
||||
if (s->packet) {
|
||||
USBPacket *p = s->packet;
|
||||
s->packet = NULL;
|
||||
p->result = USB_RET_STALL;
|
||||
usb_packet_complete(dev, p);
|
||||
}
|
||||
|
||||
s->mode = USB_MSDM_CBW;
|
||||
}
|
||||
|
||||
@@ -334,6 +348,7 @@ static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
|
||||
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
MSDState *s = (MSDState *)dev;
|
||||
uint32_t tag;
|
||||
int ret = 0;
|
||||
struct usb_msd_cbw cbw;
|
||||
uint8_t devep = p->devep;
|
||||
@@ -360,7 +375,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
|
||||
goto fail;
|
||||
}
|
||||
s->tag = le32_to_cpu(cbw.tag);
|
||||
tag = le32_to_cpu(cbw.tag);
|
||||
s->data_len = le32_to_cpu(cbw.data_len);
|
||||
if (s->data_len == 0) {
|
||||
s->mode = USB_MSDM_CSW;
|
||||
@@ -370,14 +385,12 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
s->mode = USB_MSDM_DATAOUT;
|
||||
}
|
||||
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
|
||||
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
|
||||
tag, cbw.flags, cbw.cmd_len, s->data_len);
|
||||
s->residue = 0;
|
||||
s->scsi_len = 0;
|
||||
s->req = scsi_req_new(s->scsi_dev, s->tag, 0, cbw.cmd, NULL);
|
||||
s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
|
||||
scsi_req_enqueue(s->req);
|
||||
/* ??? Should check that USB and SCSI data transfer
|
||||
directions match. */
|
||||
if (s->mode != USB_MSDM_CSW && s->residue == 0) {
|
||||
if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
|
||||
scsi_req_continue(s->req);
|
||||
}
|
||||
ret = p->result;
|
||||
@@ -432,15 +445,19 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
break;
|
||||
|
||||
case USB_MSDM_CSW:
|
||||
DPRINTF("Command status %d tag 0x%x, len %zd\n",
|
||||
s->result, s->tag, p->iov.size);
|
||||
if (p->iov.size < 13) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
usb_msd_send_status(s, p);
|
||||
s->mode = USB_MSDM_CBW;
|
||||
ret = 13;
|
||||
if (s->req) {
|
||||
/* still in flight */
|
||||
s->packet = p;
|
||||
ret = USB_RET_ASYNC;
|
||||
} else {
|
||||
usb_msd_send_status(s, p);
|
||||
s->mode = USB_MSDM_CBW;
|
||||
ret = 13;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_MSDM_DATAIN:
|
||||
@@ -541,7 +558,8 @@ static int usb_msd_initfn(USBDevice *dev)
|
||||
|
||||
usb_desc_init(dev);
|
||||
scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info);
|
||||
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
|
||||
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
|
||||
s->conf.bootindex);
|
||||
if (!s->scsi_dev) {
|
||||
return -1;
|
||||
}
|
||||
@@ -557,7 +575,6 @@ static int usb_msd_initfn(USBDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
add_boot_device_path(s->conf.bootindex, &dev->qdev, "/disk@0,0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -1025,10 +1025,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
||||
if (ret == len) {
|
||||
td.cbp = 0;
|
||||
} else {
|
||||
td.cbp += ret;
|
||||
if ((td.cbp & 0xfff) + ret > 0xfff) {
|
||||
td.cbp &= 0xfff;
|
||||
td.cbp |= td.be & ~0xfff;
|
||||
td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
|
||||
} else {
|
||||
td.cbp += ret;
|
||||
}
|
||||
}
|
||||
td.flags |= OHCI_TD_T1;
|
||||
|
@@ -202,7 +202,6 @@ static void virtex_init(ram_addr_t ram_size,
|
||||
cpu_model = "440-Xilinx";
|
||||
}
|
||||
|
||||
memset(clk_setup, 0, sizeof(clk_setup));
|
||||
env = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000);
|
||||
qemu_register_reset(main_cpu_reset, env);
|
||||
|
||||
|
@@ -485,6 +485,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
|
||||
struct virtio_blk_config blkcfg;
|
||||
uint64_t capacity;
|
||||
int cylinders, heads, secs;
|
||||
int blk_size = s->conf->logical_block_size;
|
||||
|
||||
bdrv_get_geometry(s->bs, &capacity);
|
||||
bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
|
||||
@@ -492,14 +493,14 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
|
||||
stq_raw(&blkcfg.capacity, capacity);
|
||||
stl_raw(&blkcfg.seg_max, 128 - 2);
|
||||
stw_raw(&blkcfg.cylinders, cylinders);
|
||||
stl_raw(&blkcfg.blk_size, blk_size);
|
||||
stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
|
||||
stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
|
||||
blkcfg.heads = heads;
|
||||
blkcfg.sectors = secs & ~s->sector_mask;
|
||||
blkcfg.blk_size = s->conf->logical_block_size;
|
||||
blkcfg.size_max = 0;
|
||||
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
|
||||
blkcfg.alignment_offset = 0;
|
||||
blkcfg.min_io_size = s->conf->min_io_size / blkcfg.blk_size;
|
||||
blkcfg.opt_io_size = s->conf->opt_io_size / blkcfg.blk_size;
|
||||
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
|
||||
}
|
||||
|
||||
|
@@ -266,7 +266,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
|
||||
proxy->ioeventfd_started = false;
|
||||
}
|
||||
|
||||
static void virtio_pci_reset(DeviceState *d)
|
||||
void virtio_pci_reset(DeviceState *d)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
@@ -285,14 +285,9 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
case VIRTIO_PCI_GUEST_FEATURES:
|
||||
/* Guest does not negotiate properly? We have to assume nothing. */
|
||||
if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
|
||||
if (vdev->bad_features)
|
||||
val = proxy->host_features & vdev->bad_features(vdev);
|
||||
else
|
||||
val = 0;
|
||||
val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
|
||||
}
|
||||
if (vdev->set_features)
|
||||
vdev->set_features(vdev, val);
|
||||
vdev->guest_features = val;
|
||||
virtio_set_features(vdev, val);
|
||||
break;
|
||||
case VIRTIO_PCI_QUEUE_PFN:
|
||||
pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
|
||||
|
@@ -45,6 +45,7 @@ typedef struct {
|
||||
} VirtIOPCIProxy;
|
||||
|
||||
void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
|
||||
void virtio_pci_reset(DeviceState *d);
|
||||
|
||||
/* Virtio ABI version, if we increment this, we break the guest driver. */
|
||||
#define VIRTIO_PCI_ABI_VERSION 0
|
||||
|
24
hw/virtio.c
24
hw/virtio.c
@@ -763,12 +763,25 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
|
||||
}
|
||||
}
|
||||
|
||||
int virtio_set_features(VirtIODevice *vdev, uint32_t val)
|
||||
{
|
||||
uint32_t supported_features =
|
||||
vdev->binding->get_features(vdev->binding_opaque);
|
||||
bool bad = (val & ~supported_features) != 0;
|
||||
|
||||
val &= supported_features;
|
||||
if (vdev->set_features) {
|
||||
vdev->set_features(vdev, val);
|
||||
}
|
||||
vdev->guest_features = val;
|
||||
return bad ? -1 : 0;
|
||||
}
|
||||
|
||||
int virtio_load(VirtIODevice *vdev, QEMUFile *f)
|
||||
{
|
||||
int num, i, ret;
|
||||
uint32_t features;
|
||||
uint32_t supported_features =
|
||||
vdev->binding->get_features(vdev->binding_opaque);
|
||||
uint32_t supported_features;
|
||||
|
||||
if (vdev->binding->load_config) {
|
||||
ret = vdev->binding->load_config(vdev->binding_opaque, f);
|
||||
@@ -780,14 +793,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
|
||||
qemu_get_8s(f, &vdev->isr);
|
||||
qemu_get_be16s(f, &vdev->queue_sel);
|
||||
qemu_get_be32s(f, &features);
|
||||
if (features & ~supported_features) {
|
||||
|
||||
if (virtio_set_features(vdev, features) < 0) {
|
||||
supported_features = vdev->binding->get_features(vdev->binding_opaque);
|
||||
error_report("Features 0x%x unsupported. Allowed features: 0x%x",
|
||||
features, supported_features);
|
||||
return -1;
|
||||
}
|
||||
if (vdev->set_features)
|
||||
vdev->set_features(vdev, features);
|
||||
vdev->guest_features = features;
|
||||
vdev->config_len = qemu_get_be32(f);
|
||||
qemu_get_buffer(f, vdev->config, vdev->config_len);
|
||||
|
||||
|
@@ -185,6 +185,7 @@ void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector);
|
||||
void virtio_set_status(VirtIODevice *vdev, uint8_t val);
|
||||
void virtio_reset(void *opaque);
|
||||
void virtio_update_irq(VirtIODevice *vdev);
|
||||
int virtio_set_features(VirtIODevice *vdev, uint32_t val);
|
||||
|
||||
void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
|
||||
void *opaque);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user