Compare commits
331 Commits
pull-conso
...
pull-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50c6617fcb | ||
|
|
e37f202450 | ||
|
|
29429c7244 | ||
|
|
70d3a7a7b8 | ||
|
|
136e67e9b5 | ||
|
|
041c96666d | ||
|
|
e0d6e6a5e7 | ||
|
|
607d98b81e | ||
|
|
35979d71c4 | ||
|
|
2dd081ae76 | ||
|
|
dfafd09088 | ||
|
|
043b7f8d12 | ||
|
|
9e729b57ac | ||
|
|
64e0e2de0c | ||
|
|
f149e3e847 | ||
|
|
c0f4af1719 | ||
|
|
f59492b984 | ||
|
|
6ac285b824 | ||
|
|
93c9aea9b4 | ||
|
|
65731d1c3e | ||
|
|
8f95ce2e4c | ||
|
|
0eacea7060 | ||
|
|
46747d1508 | ||
|
|
b60a7726cc | ||
|
|
70556264a8 | ||
|
|
e8c81b4d8a | ||
|
|
ed9114356b | ||
|
|
0ebcc56453 | ||
|
|
151623353f | ||
|
|
1c1f949844 | ||
|
|
e80084d352 | ||
|
|
a631892f9d | ||
|
|
235256a2bd | ||
|
|
e5048d15ce | ||
|
|
97699eff3a | ||
|
|
63ce8e150c | ||
|
|
dbe2a7a62a | ||
|
|
59a2c4ce2b | ||
|
|
597db727cc | ||
|
|
04404c21cc | ||
|
|
fe509ee237 | ||
|
|
cb55111b4e | ||
|
|
146db9f919 | ||
|
|
cee2dedb85 | ||
|
|
1f9296b51a | ||
|
|
e5554e2015 | ||
|
|
c5d1e2cce3 | ||
|
|
ed173cb704 | ||
|
|
cb021cfee7 | ||
|
|
eebf29401a | ||
|
|
10905cb26a | ||
|
|
2b8419cb49 | ||
|
|
81ab11a7a5 | ||
|
|
541be9274e | ||
|
|
a697d240ff | ||
|
|
5a6e8ba64f | ||
|
|
da1c4ec88a | ||
|
|
15124e1420 | ||
|
|
bc0d104c6a | ||
|
|
3af8f177fa | ||
|
|
931f53e184 | ||
|
|
89ae5831a5 | ||
|
|
40893768df | ||
|
|
4d249a2074 | ||
|
|
8a55acb1e0 | ||
|
|
88ed34ff5e | ||
|
|
f9bbba9569 | ||
|
|
44e7ebb8bb | ||
|
|
f4026f269a | ||
|
|
0bc375eb51 | ||
|
|
14101d028d | ||
|
|
1dde0f48d5 | ||
|
|
60e17d2822 | ||
|
|
2321442920 | ||
|
|
6a0fcbdf2d | ||
|
|
42f53fea9f | ||
|
|
458dd76656 | ||
|
|
e9854c3945 | ||
|
|
29cd33d3c7 | ||
|
|
fa4faba448 | ||
|
|
dfdb483454 | ||
|
|
fbb96c4b7f | ||
|
|
87afe467e2 | ||
|
|
e8925712e6 | ||
|
|
d8bb915972 | ||
|
|
f47ede195b | ||
|
|
dde7c241e3 | ||
|
|
5a1f7f44cf | ||
|
|
ab409bb3fe | ||
|
|
02bb9bbf1d | ||
|
|
37f3616aa8 | ||
|
|
9585db68c7 | ||
|
|
774f0abeae | ||
|
|
00f3fd63e1 | ||
|
|
374e0cd4db | ||
|
|
1039e1290f | ||
|
|
cffe7b3249 | ||
|
|
1ba50f4ea0 | ||
|
|
c9d17ad0dd | ||
|
|
9aebf3b892 | ||
|
|
a4127c428e | ||
|
|
f9d7b4b3b4 | ||
|
|
5abbf0ee4d | ||
|
|
247147fbc1 | ||
|
|
d224469d87 | ||
|
|
e5d7bbeb10 | ||
|
|
3ae59580a0 | ||
|
|
a0f1eab157 | ||
|
|
d4362d642e | ||
|
|
1862ed02df | ||
|
|
4f2280b219 | ||
|
|
c0f896810b | ||
|
|
ca976d1803 | ||
|
|
55d7bfe229 | ||
|
|
01f7cecf00 | ||
|
|
769188d3bb | ||
|
|
cad684c538 | ||
|
|
e8601dd5d0 | ||
|
|
a327c9215d | ||
|
|
450749141e | ||
|
|
380f649e02 | ||
|
|
ec56214f6f | ||
|
|
638ca939d8 | ||
|
|
3533c3d2bf | ||
|
|
7334d6507a | ||
|
|
594a53607e | ||
|
|
bd2ba2752d | ||
|
|
df9bb6660d | ||
|
|
77e35b4bbe | ||
|
|
5450eeaaad | ||
|
|
27107d416e | ||
|
|
276b7ac8e9 | ||
|
|
0b8b863fb2 | ||
|
|
38fff2c9f4 | ||
|
|
63cdca364c | ||
|
|
6b7afb7f0b | ||
|
|
b89dc7e33f | ||
|
|
f5dc597878 | ||
|
|
5a882e40d5 | ||
|
|
f3f8c45972 | ||
|
|
2e6a0dd1ac | ||
|
|
2aa76dc18c | ||
|
|
d73ad35990 | ||
|
|
7d553f27fc | ||
|
|
dc1f598845 | ||
|
|
17336812c7 | ||
|
|
f0bc7fe3b7 | ||
|
|
75bd0c7253 | ||
|
|
6758008e2c | ||
|
|
52b53c04fa | ||
|
|
032f8b8158 | ||
|
|
d9612b43dd | ||
|
|
2f78e491d7 | ||
|
|
e91a8b2fef | ||
|
|
550830f935 | ||
|
|
3e7e6f186f | ||
|
|
0fa781e3d5 | ||
|
|
dbc180e572 | ||
|
|
c2f3029fbc | ||
|
|
fac7aa7fc2 | ||
|
|
96d6d3bad9 | ||
|
|
8840a843dc | ||
|
|
c8b5b20f81 | ||
|
|
1cd1031ddc | ||
|
|
1e8fd8d44d | ||
|
|
2e5be6b77e | ||
|
|
56271efdea | ||
|
|
f658581130 | ||
|
|
ee42b5ce0b | ||
|
|
e775ba7721 | ||
|
|
7b17ce60cc | ||
|
|
93bb131525 | ||
|
|
407ba0844d | ||
|
|
5b0ed2be88 | ||
|
|
a97c67ee6c | ||
|
|
adb435522b | ||
|
|
85186ebdac | ||
|
|
9bf040b962 | ||
|
|
db866be982 | ||
|
|
e8712cea6a | ||
|
|
e819ab2277 | ||
|
|
a90d411e63 | ||
|
|
0722eba945 | ||
|
|
8007429a99 | ||
|
|
ca5fd113b8 | ||
|
|
e551c999bc | ||
|
|
5da91e4ef4 | ||
|
|
6d24b4df38 | ||
|
|
7691e24dbe | ||
|
|
7940e5056b | ||
|
|
997dd8df3e | ||
|
|
533ffb17a5 | ||
|
|
facb5539d6 | ||
|
|
9784e70f3d | ||
|
|
4c781717c5 | ||
|
|
4743b42a1b | ||
|
|
722d93335f | ||
|
|
9bb9da46d6 | ||
|
|
771b64daf9 | ||
|
|
3391f5e51c | ||
|
|
f600ac1902 | ||
|
|
3acabd685e | ||
|
|
02c50efe08 | ||
|
|
f197fe2b2c | ||
|
|
0d910cfeaf | ||
|
|
6698c5bed2 | ||
|
|
d735b620b5 | ||
|
|
c2ebb05e25 | ||
|
|
7e3d523883 | ||
|
|
e0bcc42ee7 | ||
|
|
a011898d25 | ||
|
|
31376776d0 | ||
|
|
4d63322cd4 | ||
|
|
2d5361f2a9 | ||
|
|
6c5b0c0ac0 | ||
|
|
971ae6ef47 | ||
|
|
9d632f5f68 | ||
|
|
c88930a686 | ||
|
|
07e2863d02 | ||
|
|
4852ee95f3 | ||
|
|
a30cf8760f | ||
|
|
4df7961faa | ||
|
|
10e11f4d2b | ||
|
|
438f92ee9f | ||
|
|
4d43d3f3c8 | ||
|
|
d8e80ae37a | ||
|
|
e43c0b2ea5 | ||
|
|
9e8e8c4865 | ||
|
|
131c5221fe | ||
|
|
abb4d5f2e2 | ||
|
|
b3ce84fea4 | ||
|
|
d828c430eb | ||
|
|
08ac80cd61 | ||
|
|
45de81735b | ||
|
|
2177801a48 | ||
|
|
9d41401b90 | ||
|
|
bb26a1e80b | ||
|
|
5bde14078d | ||
|
|
9d64fab422 | ||
|
|
86152436eb | ||
|
|
e4d50d47a9 | ||
|
|
a61ae7f88c | ||
|
|
90a14bfe52 | ||
|
|
8287fea321 | ||
|
|
dafd325dbb | ||
|
|
8af47027eb | ||
|
|
5f3fb5a2e2 | ||
|
|
7dbb4c49bf | ||
|
|
9a48bcd1b8 | ||
|
|
317b0a6d8b | ||
|
|
de9d61e83d | ||
|
|
be894f51b6 | ||
|
|
07d49a53b6 | ||
|
|
0d61f7dcc6 | ||
|
|
4f36e42ee9 | ||
|
|
cc35a44cf7 | ||
|
|
f2bcdc8de0 | ||
|
|
16ab5046c4 | ||
|
|
70e98b230f | ||
|
|
556068eed0 | ||
|
|
2b31cd4e08 | ||
|
|
e4d9df4fb1 | ||
|
|
5fb9b5b9cb | ||
|
|
4c24f40040 | ||
|
|
0e4271b711 | ||
|
|
06247428be | ||
|
|
ffeaac9b4e | ||
|
|
180e95265e | ||
|
|
c2eb918e32 | ||
|
|
92df845070 | ||
|
|
69e7f76f6a | ||
|
|
fee8ea12eb | ||
|
|
4c4bf65474 | ||
|
|
0be969a2d9 | ||
|
|
fa439fc5d7 | ||
|
|
995939a650 | ||
|
|
5e8b12ffbb | ||
|
|
17a9eb53a9 | ||
|
|
16a906fd6e | ||
|
|
3ff6fc9148 | ||
|
|
73c5211ba9 | ||
|
|
9ee98ce810 | ||
|
|
86025ee443 | ||
|
|
08225676b2 | ||
|
|
3ee887e8ff | ||
|
|
05068c0dfb | ||
|
|
acf82361c6 | ||
|
|
34bf774485 | ||
|
|
6e3cf5df01 | ||
|
|
bfb27e6042 | ||
|
|
c3c8d6b3dd | ||
|
|
f022b8e953 | ||
|
|
6cd14054b6 | ||
|
|
be2bfb9dbd | ||
|
|
48f364dd0b | ||
|
|
624ff5736e | ||
|
|
745a9bb9cd | ||
|
|
462efe9e53 | ||
|
|
a28fe7e3f6 | ||
|
|
0b102153e0 | ||
|
|
2c9ecdeb9f | ||
|
|
7385b275d9 | ||
|
|
461a2753a1 | ||
|
|
c0b92f3037 | ||
|
|
4603ea0105 | ||
|
|
a6dead43e6 | ||
|
|
9b10ac869d | ||
|
|
466c80f21f | ||
|
|
94c80a438c | ||
|
|
5366d0c8bc | ||
|
|
28298fd3d9 | ||
|
|
5e5a94b605 | ||
|
|
0ddd0ad96a | ||
|
|
1a7044bb62 | ||
|
|
a31e69cf00 | ||
|
|
7ca9b7c035 | ||
|
|
cedccf1381 | ||
|
|
dbb651c46c | ||
|
|
0d4cc3e715 | ||
|
|
c7c2ff0c7e | ||
|
|
fc7a5800ad | ||
|
|
557529dd60 | ||
|
|
d42e2de7bc | ||
|
|
33e0eb5297 | ||
|
|
49946538d2 | ||
|
|
ef701d7b6f | ||
|
|
c261d774fb | ||
|
|
2ceee4b052 | ||
|
|
f6e0830298 | ||
|
|
ddbc41de38 | ||
|
|
a85e130e01 |
55
.travis.yml
55
.travis.yml
@@ -12,7 +12,7 @@ notifications:
|
|||||||
on_failure: always
|
on_failure: always
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- TEST_CMD="make check"
|
- TEST_CMD=""
|
||||||
- EXTRA_CONFIG=""
|
- EXTRA_CONFIG=""
|
||||||
# Development packages, EXTRA_PKGS saved for additional builds
|
# Development packages, EXTRA_PKGS saved for additional builds
|
||||||
- CORE_PKGS="libusb-1.0-0-dev libiscsi-dev librados-dev libncurses5-dev"
|
- CORE_PKGS="libusb-1.0-0-dev libiscsi-dev librados-dev libncurses5-dev"
|
||||||
@@ -20,31 +20,51 @@ env:
|
|||||||
- GUI_PKGS="libgtk-3-dev libvte-2.90-dev libsdl1.2-dev libpng12-dev libpixman-1-dev"
|
- GUI_PKGS="libgtk-3-dev libvte-2.90-dev libsdl1.2-dev libpng12-dev libpixman-1-dev"
|
||||||
- EXTRA_PKGS=""
|
- EXTRA_PKGS=""
|
||||||
matrix:
|
matrix:
|
||||||
|
# Group major targets together with their linux-user counterparts
|
||||||
- TARGETS=alpha-softmmu,alpha-linux-user
|
- TARGETS=alpha-softmmu,alpha-linux-user
|
||||||
- TARGETS=arm-softmmu,arm-linux-user
|
- TARGETS=arm-softmmu,arm-linux-user,armeb-linux-user,aarch64-softmmu,aarch64-linux-user
|
||||||
- TARGETS=aarch64-softmmu,aarch64-linux-user
|
- TARGETS=cris-softmmu,cris-linux-user
|
||||||
- TARGETS=cris-softmmu
|
- TARGETS=i386-softmmu,i386-linux-user,x86_64-softmmu,x86_64-linux-user
|
||||||
- TARGETS=i386-softmmu,x86_64-softmmu
|
- TARGETS=m68k-softmmu,m68k-linux-user
|
||||||
- TARGETS=lm32-softmmu
|
- TARGETS=microblaze-softmmu,microblazeel-softmmu,microblaze-linux-user,microblazeel-linux-user
|
||||||
- TARGETS=m68k-softmmu
|
|
||||||
- TARGETS=microblaze-softmmu,microblazeel-softmmu
|
|
||||||
- TARGETS=mips-softmmu,mips64-softmmu,mips64el-softmmu,mipsel-softmmu
|
- TARGETS=mips-softmmu,mips64-softmmu,mips64el-softmmu,mipsel-softmmu
|
||||||
- TARGETS=moxie-softmmu
|
- TARGETS=mips-linux-user,mips64-linux-user,mips64el-linux-user,mipsel-linux-user,mipsn32-linux-user,mipsn32el-linux-user
|
||||||
- TARGETS=or32-softmmu,
|
- TARGETS=or32-softmmu,or32-linux-user
|
||||||
- TARGETS=ppc-softmmu,ppc64-softmmu,ppcemb-softmmu
|
- TARGETS=ppc-softmmu,ppc64-softmmu,ppcemb-softmmu,ppc-linux-user,ppc64-linux-user,ppc64abi32-linux-user,ppc64le-linux-user
|
||||||
- TARGETS=s390x-softmmu
|
- TARGETS=s390x-softmmu,s390x-linux-user
|
||||||
- TARGETS=sh4-softmmu,sh4eb-softmmu
|
- TARGETS=sh4-softmmu,sh4eb-softmmu,sh4-linux-user sh4eb-linux-user
|
||||||
- TARGETS=sparc-softmmu,sparc64-softmmu
|
- TARGETS=sparc-softmmu,sparc64-softmmu,sparc-linux-user,sparc32plus-linux-user,sparc64-linux-user
|
||||||
- TARGETS=unicore32-softmmu
|
- TARGETS=unicore32-softmmu,unicore32-linux-user
|
||||||
- TARGETS=xtensa-softmmu,xtensaeb-softmmu
|
# Group remaining softmmu only targets into one build
|
||||||
|
- TARGETS=lm32-softmmu,moxie-softmmu,tricore-softmmu,xtensa-softmmu,xtensaeb-softmmu
|
||||||
|
git:
|
||||||
|
# we want to do this ourselves
|
||||||
|
submodules: false
|
||||||
before_install:
|
before_install:
|
||||||
|
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
- sudo apt-get install -qq ${CORE_PKGS} ${NET_PKGS} ${GUI_PKGS} ${EXTRA_PKGS}
|
- sudo apt-get install -qq ${CORE_PKGS} ${NET_PKGS} ${GUI_PKGS} ${EXTRA_PKGS}
|
||||||
script: "./configure --target-list=${TARGETS} ${EXTRA_CONFIG} && make && ${TEST_CMD}"
|
before_script:
|
||||||
|
- ./configure --target-list=${TARGETS} --enable-debug-tcg ${EXTRA_CONFIG}
|
||||||
|
script:
|
||||||
|
- make -j2 && ${TEST_CMD}
|
||||||
matrix:
|
matrix:
|
||||||
# We manually include a number of additional build for non-standard bits
|
# We manually include a number of additional build for non-standard bits
|
||||||
include:
|
include:
|
||||||
|
# Make check target (we only do this once)
|
||||||
|
- env:
|
||||||
|
- TARGETS=alpha-softmmu,arm-softmmu,aarch64-softmmu,cris-softmmu,
|
||||||
|
i386-softmmu,x86_64-softmmu,m68k-softmmu,microblaze-softmmu,
|
||||||
|
microblazeel-softmmu,mips-softmmu,mips64-softmmu,
|
||||||
|
mips64el-softmmu,mipsel-softmmu,or32-softmmu,ppc-softmmu,
|
||||||
|
ppc64-softmmu,ppcemb-softmmu,s390x-softmmu,sh4-softmmu,
|
||||||
|
sh4eb-softmmu,sparc-softmmu,sparc64-softmmu,
|
||||||
|
unicore32-softmmu,unicore32-linux-user,
|
||||||
|
lm32-softmmu,moxie-softmmu,tricore-softmmu,xtensa-softmmu,
|
||||||
|
xtensaeb-softmmu
|
||||||
|
TEST_CMD="make check"
|
||||||
|
compiler: gcc
|
||||||
# Debug related options
|
# Debug related options
|
||||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||||
EXTRA_CONFIG="--enable-debug"
|
EXTRA_CONFIG="--enable-debug"
|
||||||
@@ -73,7 +93,6 @@ matrix:
|
|||||||
compiler: gcc
|
compiler: gcc
|
||||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||||
EXTRA_CONFIG="--enable-trace-backends=ftrace"
|
EXTRA_CONFIG="--enable-trace-backends=ftrace"
|
||||||
TEST_CMD=""
|
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||||
EXTRA_PKGS="liblttng-ust-dev liburcu-dev"
|
EXTRA_PKGS="liblttng-ust-dev liburcu-dev"
|
||||||
|
|||||||
1
Makefile
1
Makefile
@@ -418,6 +418,7 @@ endif
|
|||||||
set -e; for x in $(KEYMAPS); do \
|
set -e; for x in $(KEYMAPS); do \
|
||||||
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
|
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
|
||||||
done
|
done
|
||||||
|
$(INSTALL_DATA) $(SRC_PATH)/trace-events "$(DESTDIR)$(qemu_datadir)/trace-events"
|
||||||
for d in $(TARGET_DIRS); do \
|
for d in $(TARGET_DIRS); do \
|
||||||
$(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \
|
$(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -283,9 +283,9 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
|||||||
int count;
|
int count;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
if (aio_prepare(ctx)) {
|
have_select_revents = aio_prepare(ctx);
|
||||||
|
if (have_select_revents) {
|
||||||
blocking = false;
|
blocking = false;
|
||||||
have_select_revents = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
was_dispatching = ctx->dispatching;
|
was_dispatching = ctx->dispatching;
|
||||||
@@ -335,6 +335,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
|||||||
event = NULL;
|
event = NULL;
|
||||||
if ((DWORD) (ret - WAIT_OBJECT_0) < count) {
|
if ((DWORD) (ret - WAIT_OBJECT_0) < count) {
|
||||||
event = events[ret - WAIT_OBJECT_0];
|
event = events[ret - WAIT_OBJECT_0];
|
||||||
|
events[ret - WAIT_OBJECT_0] = events[--count];
|
||||||
} else if (!have_select_revents) {
|
} else if (!have_select_revents) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -343,9 +344,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
|||||||
blocking = false;
|
blocking = false;
|
||||||
|
|
||||||
progress |= aio_dispatch_handlers(ctx, event);
|
progress |= aio_dispatch_handlers(ctx, event);
|
||||||
|
|
||||||
/* Try again, but only call each handler once. */
|
|
||||||
events[ret - WAIT_OBJECT_0] = events[--count];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
progress |= timerlistgroup_run_timers(&ctx->tlg);
|
progress |= timerlistgroup_run_timers(&ctx->tlg);
|
||||||
|
|||||||
16
async.c
16
async.c
@@ -289,18 +289,24 @@ static void aio_rfifolock_cb(void *opaque)
|
|||||||
aio_notify(opaque);
|
aio_notify(opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
AioContext *aio_context_new(void)
|
AioContext *aio_context_new(Error **errp)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
AioContext *ctx;
|
AioContext *ctx;
|
||||||
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
|
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
|
||||||
|
ret = event_notifier_init(&ctx->notifier, false);
|
||||||
|
if (ret < 0) {
|
||||||
|
g_source_destroy(&ctx->source);
|
||||||
|
error_setg_errno(errp, -ret, "Failed to initialize event notifier");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
aio_set_event_notifier(ctx, &ctx->notifier,
|
||||||
|
(EventNotifierHandler *)
|
||||||
|
event_notifier_test_and_clear);
|
||||||
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
|
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
|
||||||
ctx->thread_pool = NULL;
|
ctx->thread_pool = NULL;
|
||||||
qemu_mutex_init(&ctx->bh_lock);
|
qemu_mutex_init(&ctx->bh_lock);
|
||||||
rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
|
rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
|
||||||
event_notifier_init(&ctx->notifier, false);
|
|
||||||
aio_set_event_notifier(ctx, &ctx->notifier,
|
|
||||||
(EventNotifierHandler *)
|
|
||||||
event_notifier_test_and_clear);
|
|
||||||
timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);
|
timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
|
|||||||
@@ -629,7 +629,7 @@ fail_handle:
|
|||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
register_char_driver_qapi("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL);
|
register_char_driver("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
|||||||
|
|
||||||
path = object_get_canonical_path_component(OBJECT(backend));
|
path = object_get_canonical_path_component(OBJECT(backend));
|
||||||
memory_region_init_ram(&backend->mr, OBJECT(backend), path,
|
memory_region_init_ram(&backend->mr, OBJECT(backend), path,
|
||||||
backend->size);
|
backend->size, errp);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ CharDriverState *qemu_chr_open_msmouse(void)
|
|||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
register_char_driver_qapi("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL);
|
register_char_driver("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
|
|||||||
if (b->opened) {
|
if (b->opened) {
|
||||||
error_set(errp, QERR_PERMISSION_DENIED);
|
error_set(errp, QERR_PERMISSION_DENIED);
|
||||||
} else {
|
} else {
|
||||||
|
g_free(s->chr_name);
|
||||||
s->chr_name = g_strdup(value);
|
s->chr_name = g_strdup(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ CharDriverState *chr_testdev_init(void)
|
|||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
register_char_driver_qapi("testdev", CHARDEV_BACKEND_KIND_TESTDEV, NULL);
|
register_char_driver("testdev", CHARDEV_BACKEND_KIND_TESTDEV, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
|||||||
153
block.c
153
block.c
@@ -29,6 +29,7 @@
|
|||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qapi/qmp/qjson.h"
|
#include "qapi/qmp/qjson.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "sysemu/blockdev.h" /* FIXME layering violation */
|
||||||
#include "qemu/notify.h"
|
#include "qemu/notify.h"
|
||||||
#include "block/coroutine.h"
|
#include "block/coroutine.h"
|
||||||
#include "block/qapi.h"
|
#include "block/qapi.h"
|
||||||
@@ -334,19 +335,30 @@ void bdrv_register(BlockDriver *bdrv)
|
|||||||
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
|
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool bdrv_is_valid_name(const char *name)
|
||||||
|
{
|
||||||
|
return qemu_opts_id_wellformed(name);
|
||||||
|
}
|
||||||
|
|
||||||
/* create a new block device (by default it is empty) */
|
/* create a new block device (by default it is empty) */
|
||||||
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
|
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (*device_name && !bdrv_is_valid_name(device_name)) {
|
||||||
|
error_setg(errp, "Invalid device name");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (bdrv_find(device_name)) {
|
if (bdrv_find(device_name)) {
|
||||||
error_setg(errp, "Device with id '%s' already exists",
|
error_setg(errp, "Device with id '%s' already exists",
|
||||||
device_name);
|
device_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (bdrv_find_node(device_name)) {
|
if (bdrv_find_node(device_name)) {
|
||||||
error_setg(errp, "Device with node-name '%s' already exists",
|
error_setg(errp,
|
||||||
|
"Device name '%s' conflicts with an existing node name",
|
||||||
device_name);
|
device_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -861,9 +873,9 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* empty string node name is invalid */
|
/* Check for empty string or invalid characters */
|
||||||
if (node_name[0] == '\0') {
|
if (!bdrv_is_valid_name(node_name)) {
|
||||||
error_setg(errp, "Empty node name");
|
error_setg(errp, "Invalid node name");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2110,6 +2122,7 @@ static void bdrv_delete(BlockDriverState *bs)
|
|||||||
/* remove from list, if necessary */
|
/* remove from list, if necessary */
|
||||||
bdrv_make_anon(bs);
|
bdrv_make_anon(bs);
|
||||||
|
|
||||||
|
drive_info_del(drive_get_by_blockdev(bs));
|
||||||
g_free(bs);
|
g_free(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3363,9 +3376,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
|||||||
|
|
||||||
bdrv_set_dirty(bs, sector_num, nb_sectors);
|
bdrv_set_dirty(bs, sector_num, nb_sectors);
|
||||||
|
|
||||||
if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
|
block_acct_highest_sector(&bs->stats, sector_num, nb_sectors);
|
||||||
bs->wr_highest_sector = sector_num + nb_sectors - 1;
|
|
||||||
}
|
|
||||||
if (bs->growable && ret >= 0) {
|
if (bs->growable && ret >= 0) {
|
||||||
bs->total_sectors = MAX(bs->total_sectors, sector_num + nb_sectors);
|
bs->total_sectors = MAX(bs->total_sectors, sector_num + nb_sectors);
|
||||||
}
|
}
|
||||||
@@ -3639,6 +3651,19 @@ BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void send_qmp_error_event(BlockDriverState *bs,
|
||||||
|
BlockErrorAction action,
|
||||||
|
bool is_read, int error)
|
||||||
|
{
|
||||||
|
BlockErrorAction ac;
|
||||||
|
|
||||||
|
ac = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
|
||||||
|
qapi_event_send_block_io_error(bdrv_get_device_name(bs), ac, action,
|
||||||
|
bdrv_iostatus_is_enabled(bs),
|
||||||
|
error == ENOSPC, strerror(error),
|
||||||
|
&error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
/* This is done by device models because, while the block layer knows
|
/* This is done by device models because, while the block layer knows
|
||||||
* about the error, it does not know whether an operation comes from
|
* about the error, it does not know whether an operation comes from
|
||||||
* the device or the block layer (from a job, for example).
|
* the device or the block layer (from a job, for example).
|
||||||
@@ -3664,16 +3689,10 @@ void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
|
|||||||
* also ensures that the STOP/RESUME pair of events is emitted.
|
* also ensures that the STOP/RESUME pair of events is emitted.
|
||||||
*/
|
*/
|
||||||
qemu_system_vmstop_request_prepare();
|
qemu_system_vmstop_request_prepare();
|
||||||
qapi_event_send_block_io_error(bdrv_get_device_name(bs),
|
send_qmp_error_event(bs, action, is_read, error);
|
||||||
is_read ? IO_OPERATION_TYPE_READ :
|
|
||||||
IO_OPERATION_TYPE_WRITE,
|
|
||||||
action, &error_abort);
|
|
||||||
qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
|
qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
|
||||||
} else {
|
} else {
|
||||||
qapi_event_send_block_io_error(bdrv_get_device_name(bs),
|
send_qmp_error_event(bs, action, is_read, error);
|
||||||
is_read ? IO_OPERATION_TYPE_READ :
|
|
||||||
IO_OPERATION_TYPE_WRITE,
|
|
||||||
action, &error_abort);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4634,7 +4653,28 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
|||||||
|
|
||||||
void bdrv_aio_cancel(BlockDriverAIOCB *acb)
|
void bdrv_aio_cancel(BlockDriverAIOCB *acb)
|
||||||
{
|
{
|
||||||
acb->aiocb_info->cancel(acb);
|
qemu_aio_ref(acb);
|
||||||
|
bdrv_aio_cancel_async(acb);
|
||||||
|
while (acb->refcnt > 1) {
|
||||||
|
if (acb->aiocb_info->get_aio_context) {
|
||||||
|
aio_poll(acb->aiocb_info->get_aio_context(acb), true);
|
||||||
|
} else if (acb->bs) {
|
||||||
|
aio_poll(bdrv_get_aio_context(acb->bs), true);
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qemu_aio_unref(acb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Async version of aio cancel. The caller is not blocked if the acb implements
|
||||||
|
* cancel_async, otherwise we do nothing and let the request normally complete.
|
||||||
|
* In either case the completion callback must be called. */
|
||||||
|
void bdrv_aio_cancel_async(BlockDriverAIOCB *acb)
|
||||||
|
{
|
||||||
|
if (acb->aiocb_info->cancel_async) {
|
||||||
|
acb->aiocb_info->cancel_async(acb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
@@ -4650,18 +4690,8 @@ typedef struct BlockDriverAIOCBSync {
|
|||||||
int is_write;
|
int is_write;
|
||||||
} BlockDriverAIOCBSync;
|
} BlockDriverAIOCBSync;
|
||||||
|
|
||||||
static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
BlockDriverAIOCBSync *acb =
|
|
||||||
container_of(blockacb, BlockDriverAIOCBSync, common);
|
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
acb->bh = NULL;
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo bdrv_em_aiocb_info = {
|
static const AIOCBInfo bdrv_em_aiocb_info = {
|
||||||
.aiocb_size = sizeof(BlockDriverAIOCBSync),
|
.aiocb_size = sizeof(BlockDriverAIOCBSync),
|
||||||
.cancel = bdrv_aio_cancel_em,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_aio_bh_cb(void *opaque)
|
static void bdrv_aio_bh_cb(void *opaque)
|
||||||
@@ -4675,7 +4705,7 @@ static void bdrv_aio_bh_cb(void *opaque)
|
|||||||
acb->common.cb(acb->common.opaque, acb->ret);
|
acb->common.cb(acb->common.opaque, acb->ret);
|
||||||
qemu_bh_delete(acb->bh);
|
qemu_bh_delete(acb->bh);
|
||||||
acb->bh = NULL;
|
acb->bh = NULL;
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
|
static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
|
||||||
@@ -4732,22 +4762,8 @@ typedef struct BlockDriverAIOCBCoroutine {
|
|||||||
QEMUBH* bh;
|
QEMUBH* bh;
|
||||||
} BlockDriverAIOCBCoroutine;
|
} BlockDriverAIOCBCoroutine;
|
||||||
|
|
||||||
static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
AioContext *aio_context = bdrv_get_aio_context(blockacb->bs);
|
|
||||||
BlockDriverAIOCBCoroutine *acb =
|
|
||||||
container_of(blockacb, BlockDriverAIOCBCoroutine, common);
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
acb->done = &done;
|
|
||||||
while (!done) {
|
|
||||||
aio_poll(aio_context, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo bdrv_em_co_aiocb_info = {
|
static const AIOCBInfo bdrv_em_co_aiocb_info = {
|
||||||
.aiocb_size = sizeof(BlockDriverAIOCBCoroutine),
|
.aiocb_size = sizeof(BlockDriverAIOCBCoroutine),
|
||||||
.cancel = bdrv_aio_co_cancel_em,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_co_em_bh(void *opaque)
|
static void bdrv_co_em_bh(void *opaque)
|
||||||
@@ -4756,12 +4772,8 @@ static void bdrv_co_em_bh(void *opaque)
|
|||||||
|
|
||||||
acb->common.cb(acb->common.opaque, acb->req.error);
|
acb->common.cb(acb->common.opaque, acb->req.error);
|
||||||
|
|
||||||
if (acb->done) {
|
|
||||||
*acb->done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_bh_delete(acb->bh);
|
qemu_bh_delete(acb->bh);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke bdrv_co_do_readv/bdrv_co_do_writev */
|
/* Invoke bdrv_co_do_readv/bdrv_co_do_writev */
|
||||||
@@ -4800,7 +4812,6 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
|||||||
acb->req.qiov = qiov;
|
acb->req.qiov = qiov;
|
||||||
acb->req.flags = flags;
|
acb->req.flags = flags;
|
||||||
acb->is_write = is_write;
|
acb->is_write = is_write;
|
||||||
acb->done = NULL;
|
|
||||||
|
|
||||||
co = qemu_coroutine_create(bdrv_co_do_rw);
|
co = qemu_coroutine_create(bdrv_co_do_rw);
|
||||||
qemu_coroutine_enter(co, acb);
|
qemu_coroutine_enter(co, acb);
|
||||||
@@ -4827,7 +4838,6 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
|
|||||||
BlockDriverAIOCBCoroutine *acb;
|
BlockDriverAIOCBCoroutine *acb;
|
||||||
|
|
||||||
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
||||||
acb->done = NULL;
|
|
||||||
|
|
||||||
co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
|
co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
|
||||||
qemu_coroutine_enter(co, acb);
|
qemu_coroutine_enter(co, acb);
|
||||||
@@ -4857,7 +4867,6 @@ BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
|
|||||||
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
||||||
acb->req.sector = sector_num;
|
acb->req.sector = sector_num;
|
||||||
acb->req.nb_sectors = nb_sectors;
|
acb->req.nb_sectors = nb_sectors;
|
||||||
acb->done = NULL;
|
|
||||||
co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
|
co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
|
||||||
qemu_coroutine_enter(co, acb);
|
qemu_coroutine_enter(co, acb);
|
||||||
|
|
||||||
@@ -4885,13 +4894,23 @@ void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
|
|||||||
acb->bs = bs;
|
acb->bs = bs;
|
||||||
acb->cb = cb;
|
acb->cb = cb;
|
||||||
acb->opaque = opaque;
|
acb->opaque = opaque;
|
||||||
|
acb->refcnt = 1;
|
||||||
return acb;
|
return acb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_aio_release(void *p)
|
void qemu_aio_ref(void *p)
|
||||||
{
|
{
|
||||||
BlockDriverAIOCB *acb = p;
|
BlockDriverAIOCB *acb = p;
|
||||||
g_slice_free1(acb->aiocb_info->aiocb_size, acb);
|
acb->refcnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_aio_unref(void *p)
|
||||||
|
{
|
||||||
|
BlockDriverAIOCB *acb = p;
|
||||||
|
assert(acb->refcnt > 0);
|
||||||
|
if (--acb->refcnt == 0) {
|
||||||
|
g_slice_free1(acb->aiocb_info->aiocb_size, acb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
@@ -5566,27 +5585,6 @@ void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, int64_t bytes,
|
|
||||||
enum BlockAcctType type)
|
|
||||||
{
|
|
||||||
assert(type < BDRV_MAX_IOTYPE);
|
|
||||||
|
|
||||||
cookie->bytes = bytes;
|
|
||||||
cookie->start_time_ns = get_clock();
|
|
||||||
cookie->type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
|
|
||||||
{
|
|
||||||
assert(cookie->type < BDRV_MAX_IOTYPE);
|
|
||||||
|
|
||||||
bs->nr_bytes[cookie->type] += cookie->bytes;
|
|
||||||
bs->nr_ops[cookie->type]++;
|
|
||||||
bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bdrv_img_create(const char *filename, const char *fmt,
|
void bdrv_img_create(const char *filename, const char *fmt,
|
||||||
const char *base_filename, const char *base_fmt,
|
const char *base_filename, const char *base_fmt,
|
||||||
char *options, uint64_t img_size, int flags,
|
char *options, uint64_t img_size, int flags,
|
||||||
@@ -6103,3 +6101,14 @@ void bdrv_refresh_filename(BlockDriverState *bs)
|
|||||||
QDECREF(json);
|
QDECREF(json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This accessor function purpose is to allow the device models to access the
|
||||||
|
* BlockAcctStats structure embedded inside a BlockDriverState without being
|
||||||
|
* aware of the BlockDriverState structure layout.
|
||||||
|
* It will go away when the BlockAcctStats structure will be moved inside
|
||||||
|
* the device models.
|
||||||
|
*/
|
||||||
|
BlockAcctStats *bdrv_get_stats(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
return &bs->stats;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
block-obj-y += raw_bsd.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
|
block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
|
||||||
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
|
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
|
||||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||||
block-obj-y += qed-check.o
|
block-obj-y += qed-check.o
|
||||||
@@ -9,6 +9,7 @@ block-obj-y += snapshot.o qapi.o
|
|||||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
||||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||||
|
block-obj-y += null.o
|
||||||
|
|
||||||
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
||||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||||
@@ -18,6 +19,7 @@ block-obj-$(CONFIG_RBD) += rbd.o
|
|||||||
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
|
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
|
||||||
block-obj-$(CONFIG_ARCHIPELAGO) += archipelago.o
|
block-obj-$(CONFIG_ARCHIPELAGO) += archipelago.o
|
||||||
block-obj-$(CONFIG_LIBSSH2) += ssh.o
|
block-obj-$(CONFIG_LIBSSH2) += ssh.o
|
||||||
|
block-obj-y += accounting.o
|
||||||
|
|
||||||
common-obj-y += stream.o
|
common-obj-y += stream.o
|
||||||
common-obj-y += commit.o
|
common-obj-y += commit.o
|
||||||
|
|||||||
54
block/accounting.c
Normal file
54
block/accounting.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator block accounting
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 Christoph Hellwig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "block/accounting.h"
|
||||||
|
#include "block/block_int.h"
|
||||||
|
|
||||||
|
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
||||||
|
int64_t bytes, enum BlockAcctType type)
|
||||||
|
{
|
||||||
|
assert(type < BLOCK_MAX_IOTYPE);
|
||||||
|
|
||||||
|
cookie->bytes = bytes;
|
||||||
|
cookie->start_time_ns = get_clock();
|
||||||
|
cookie->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||||
|
{
|
||||||
|
assert(cookie->type < BLOCK_MAX_IOTYPE);
|
||||||
|
|
||||||
|
stats->nr_bytes[cookie->type] += cookie->bytes;
|
||||||
|
stats->nr_ops[cookie->type]++;
|
||||||
|
stats->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void block_acct_highest_sector(BlockAcctStats *stats, int64_t sector_num,
|
||||||
|
unsigned int nb_sectors)
|
||||||
|
{
|
||||||
|
if (stats->wr_highest_sector < sector_num + nb_sectors - 1) {
|
||||||
|
stats->wr_highest_sector = sector_num + nb_sectors - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,8 +63,6 @@
|
|||||||
#include <xseg/xseg.h>
|
#include <xseg/xseg.h>
|
||||||
#include <xseg/protocol.h>
|
#include <xseg/protocol.h>
|
||||||
|
|
||||||
#define ARCHIP_FD_READ 0
|
|
||||||
#define ARCHIP_FD_WRITE 1
|
|
||||||
#define MAX_REQUEST_SIZE 524288
|
#define MAX_REQUEST_SIZE 524288
|
||||||
|
|
||||||
#define ARCHIPELAGO_OPT_VOLUME "volume"
|
#define ARCHIPELAGO_OPT_VOLUME "volume"
|
||||||
@@ -84,6 +82,7 @@ typedef enum {
|
|||||||
ARCHIP_OP_WRITE,
|
ARCHIP_OP_WRITE,
|
||||||
ARCHIP_OP_FLUSH,
|
ARCHIP_OP_FLUSH,
|
||||||
ARCHIP_OP_VOLINFO,
|
ARCHIP_OP_VOLINFO,
|
||||||
|
ARCHIP_OP_TRUNCATE,
|
||||||
} ARCHIPCmd;
|
} ARCHIPCmd;
|
||||||
|
|
||||||
typedef struct ArchipelagoAIOCB {
|
typedef struct ArchipelagoAIOCB {
|
||||||
@@ -92,7 +91,6 @@ typedef struct ArchipelagoAIOCB {
|
|||||||
struct BDRVArchipelagoState *s;
|
struct BDRVArchipelagoState *s;
|
||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
ARCHIPCmd cmd;
|
ARCHIPCmd cmd;
|
||||||
bool cancelled;
|
|
||||||
int status;
|
int status;
|
||||||
int64_t size;
|
int64_t size;
|
||||||
int64_t ret;
|
int64_t ret;
|
||||||
@@ -248,6 +246,7 @@ static void xseg_request_handler(void *state)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARCHIP_OP_VOLINFO:
|
case ARCHIP_OP_VOLINFO:
|
||||||
|
case ARCHIP_OP_TRUNCATE:
|
||||||
s->is_signaled = true;
|
s->is_signaled = true;
|
||||||
qemu_cond_signal(&s->archip_cond);
|
qemu_cond_signal(&s->archip_cond);
|
||||||
break;
|
break;
|
||||||
@@ -318,9 +317,7 @@ static void qemu_archipelago_complete_aio(void *opaque)
|
|||||||
aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
|
aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
|
||||||
aio_cb->status = 0;
|
aio_cb->status = 0;
|
||||||
|
|
||||||
if (!aio_cb->cancelled) {
|
qemu_aio_unref(aio_cb);
|
||||||
qemu_aio_release(aio_cb);
|
|
||||||
}
|
|
||||||
g_free(reqdata);
|
g_free(reqdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,7 +705,8 @@ static int qemu_archipelago_create(const char *filename,
|
|||||||
|
|
||||||
parse_filename_opts(filename, errp, &volname, &segment_name, &mport,
|
parse_filename_opts(filename, errp, &volname, &segment_name, &mport,
|
||||||
&vport);
|
&vport);
|
||||||
total_size = qemu_opt_get_size_del(options, BLOCK_OPT_SIZE, 0);
|
total_size = ROUND_UP(qemu_opt_get_size_del(options, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
if (segment_name == NULL) {
|
if (segment_name == NULL) {
|
||||||
segment_name = g_strdup("archipelago");
|
segment_name = g_strdup("archipelago");
|
||||||
@@ -724,19 +722,8 @@ static int qemu_archipelago_create(const char *filename,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_archipelago_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) blockacb;
|
|
||||||
aio_cb->cancelled = true;
|
|
||||||
while (aio_cb->status == -EINPROGRESS) {
|
|
||||||
aio_poll(bdrv_get_aio_context(aio_cb->common.bs), true);
|
|
||||||
}
|
|
||||||
qemu_aio_release(aio_cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo archipelago_aiocb_info = {
|
static const AIOCBInfo archipelago_aiocb_info = {
|
||||||
.aiocb_size = sizeof(ArchipelagoAIOCB),
|
.aiocb_size = sizeof(ArchipelagoAIOCB),
|
||||||
.cancel = qemu_archipelago_aio_cancel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int archipelago_submit_request(BDRVArchipelagoState *s,
|
static int archipelago_submit_request(BDRVArchipelagoState *s,
|
||||||
@@ -888,7 +875,6 @@ static BlockDriverAIOCB *qemu_archipelago_aio_rw(BlockDriverState *bs,
|
|||||||
|
|
||||||
aio_cb->ret = 0;
|
aio_cb->ret = 0;
|
||||||
aio_cb->s = s;
|
aio_cb->s = s;
|
||||||
aio_cb->cancelled = false;
|
|
||||||
aio_cb->status = -EINPROGRESS;
|
aio_cb->status = -EINPROGRESS;
|
||||||
|
|
||||||
off = sector_num * BDRV_SECTOR_SIZE;
|
off = sector_num * BDRV_SECTOR_SIZE;
|
||||||
@@ -904,7 +890,7 @@ static BlockDriverAIOCB *qemu_archipelago_aio_rw(BlockDriverState *bs,
|
|||||||
|
|
||||||
err_exit:
|
err_exit:
|
||||||
error_report("qemu_archipelago_aio_rw(): I/O Error\n");
|
error_report("qemu_archipelago_aio_rw(): I/O Error\n");
|
||||||
qemu_aio_release(aio_cb);
|
qemu_aio_unref(aio_cb);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -995,6 +981,64 @@ static int64_t qemu_archipelago_getlength(BlockDriverState *bs)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qemu_archipelago_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
|
{
|
||||||
|
int ret, targetlen;
|
||||||
|
struct xseg_request *req;
|
||||||
|
BDRVArchipelagoState *s = bs->opaque;
|
||||||
|
AIORequestData *reqdata = g_new(AIORequestData, 1);
|
||||||
|
|
||||||
|
const char *volname = s->volname;
|
||||||
|
targetlen = strlen(volname);
|
||||||
|
req = xseg_get_request(s->xseg, s->srcport, s->mportno, X_ALLOC);
|
||||||
|
if (!req) {
|
||||||
|
archipelagolog("Cannot get XSEG request\n");
|
||||||
|
goto err_exit2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = xseg_prep_request(s->xseg, req, targetlen, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
archipelagolog("Cannot prepare XSEG request\n");
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
char *target = xseg_get_target(s->xseg, req);
|
||||||
|
if (!target) {
|
||||||
|
archipelagolog("Cannot get XSEG target\n");
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
memcpy(target, volname, targetlen);
|
||||||
|
req->offset = offset;
|
||||||
|
req->op = X_TRUNCATE;
|
||||||
|
|
||||||
|
reqdata->op = ARCHIP_OP_TRUNCATE;
|
||||||
|
reqdata->volname = volname;
|
||||||
|
|
||||||
|
xseg_set_req_data(s->xseg, req, reqdata);
|
||||||
|
|
||||||
|
xport p = xseg_submit(s->xseg, req, s->srcport, X_ALLOC);
|
||||||
|
if (p == NoPort) {
|
||||||
|
archipelagolog("Cannot submit XSEG request\n");
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
xseg_signal(s->xseg, p);
|
||||||
|
qemu_mutex_lock(&s->archip_mutex);
|
||||||
|
while (!s->is_signaled) {
|
||||||
|
qemu_cond_wait(&s->archip_cond, &s->archip_mutex);
|
||||||
|
}
|
||||||
|
s->is_signaled = false;
|
||||||
|
qemu_mutex_unlock(&s->archip_mutex);
|
||||||
|
xseg_put_request(s->xseg, req, s->srcport);
|
||||||
|
g_free(reqdata);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
xseg_put_request(s->xseg, req, s->srcport);
|
||||||
|
err_exit2:
|
||||||
|
g_free(reqdata);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
static QemuOptsList qemu_archipelago_create_opts = {
|
static QemuOptsList qemu_archipelago_create_opts = {
|
||||||
.name = "archipelago-create-opts",
|
.name = "archipelago-create-opts",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_archipelago_create_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(qemu_archipelago_create_opts.head),
|
||||||
@@ -1024,6 +1068,7 @@ static BlockDriver bdrv_archipelago = {
|
|||||||
.bdrv_close = qemu_archipelago_close,
|
.bdrv_close = qemu_archipelago_close,
|
||||||
.bdrv_create = qemu_archipelago_create,
|
.bdrv_create = qemu_archipelago_create,
|
||||||
.bdrv_getlength = qemu_archipelago_getlength,
|
.bdrv_getlength = qemu_archipelago_getlength,
|
||||||
|
.bdrv_truncate = qemu_archipelago_truncate,
|
||||||
.bdrv_aio_readv = qemu_archipelago_aio_readv,
|
.bdrv_aio_readv = qemu_archipelago_aio_readv,
|
||||||
.bdrv_aio_writev = qemu_archipelago_aio_writev,
|
.bdrv_aio_writev = qemu_archipelago_aio_writev,
|
||||||
.bdrv_aio_flush = qemu_archipelago_aio_flush,
|
.bdrv_aio_flush = qemu_archipelago_aio_flush,
|
||||||
|
|||||||
@@ -52,11 +52,8 @@ typedef struct BlkdebugSuspendedReq {
|
|||||||
QLIST_ENTRY(BlkdebugSuspendedReq) next;
|
QLIST_ENTRY(BlkdebugSuspendedReq) next;
|
||||||
} BlkdebugSuspendedReq;
|
} BlkdebugSuspendedReq;
|
||||||
|
|
||||||
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
|
|
||||||
|
|
||||||
static const AIOCBInfo blkdebug_aiocb_info = {
|
static const AIOCBInfo blkdebug_aiocb_info = {
|
||||||
.aiocb_size = sizeof(BlkdebugAIOCB),
|
.aiocb_size = sizeof(BlkdebugAIOCB),
|
||||||
.cancel = blkdebug_aio_cancel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -217,6 +214,7 @@ static int get_event_by_name(const char *name, BlkDebugEvent *event)
|
|||||||
struct add_rule_data {
|
struct add_rule_data {
|
||||||
BDRVBlkdebugState *s;
|
BDRVBlkdebugState *s;
|
||||||
int action;
|
int action;
|
||||||
|
Error **errp;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int add_rule(QemuOpts *opts, void *opaque)
|
static int add_rule(QemuOpts *opts, void *opaque)
|
||||||
@@ -229,7 +227,11 @@ static int add_rule(QemuOpts *opts, void *opaque)
|
|||||||
|
|
||||||
/* Find the right event for the rule */
|
/* Find the right event for the rule */
|
||||||
event_name = qemu_opt_get(opts, "event");
|
event_name = qemu_opt_get(opts, "event");
|
||||||
if (!event_name || get_event_by_name(event_name, &event) < 0) {
|
if (!event_name) {
|
||||||
|
error_setg(d->errp, "Missing event name for rule");
|
||||||
|
return -1;
|
||||||
|
} else if (get_event_by_name(event_name, &event) < 0) {
|
||||||
|
error_setg(d->errp, "Invalid event name \"%s\"", event_name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,10 +317,21 @@ static int read_config(BDRVBlkdebugState *s, const char *filename,
|
|||||||
|
|
||||||
d.s = s;
|
d.s = s;
|
||||||
d.action = ACTION_INJECT_ERROR;
|
d.action = ACTION_INJECT_ERROR;
|
||||||
qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
|
d.errp = &local_err;
|
||||||
|
qemu_opts_foreach(&inject_error_opts, add_rule, &d, 1);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
d.action = ACTION_SET_STATE;
|
d.action = ACTION_SET_STATE;
|
||||||
qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
|
qemu_opts_foreach(&set_state_opts, add_rule, &d, 1);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
@@ -447,17 +460,7 @@ static void error_callback_bh(void *opaque)
|
|||||||
struct BlkdebugAIOCB *acb = opaque;
|
struct BlkdebugAIOCB *acb = opaque;
|
||||||
qemu_bh_delete(acb->bh);
|
qemu_bh_delete(acb->bh);
|
||||||
acb->common.cb(acb->common.opaque, acb->ret);
|
acb->common.cb(acb->common.opaque, acb->ret);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
|
||||||
|
|
||||||
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
|
|
||||||
if (acb->bh) {
|
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
acb->bh = NULL;
|
|
||||||
}
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ struct BlkverifyAIOCB {
|
|||||||
|
|
||||||
int ret; /* first completed request's result */
|
int ret; /* first completed request's result */
|
||||||
unsigned int done; /* completion counter */
|
unsigned int done; /* completion counter */
|
||||||
bool *finished; /* completion signal for cancel */
|
|
||||||
|
|
||||||
QEMUIOVector *qiov; /* user I/O vector */
|
QEMUIOVector *qiov; /* user I/O vector */
|
||||||
QEMUIOVector raw_qiov; /* cloned I/O vector for raw file */
|
QEMUIOVector raw_qiov; /* cloned I/O vector for raw file */
|
||||||
@@ -38,22 +37,8 @@ struct BlkverifyAIOCB {
|
|||||||
void (*verify)(BlkverifyAIOCB *acb);
|
void (*verify)(BlkverifyAIOCB *acb);
|
||||||
};
|
};
|
||||||
|
|
||||||
static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
BlkverifyAIOCB *acb = (BlkverifyAIOCB *)blockacb;
|
|
||||||
AioContext *aio_context = bdrv_get_aio_context(blockacb->bs);
|
|
||||||
bool finished = false;
|
|
||||||
|
|
||||||
/* Wait until request completes, invokes its callback, and frees itself */
|
|
||||||
acb->finished = &finished;
|
|
||||||
while (!finished) {
|
|
||||||
aio_poll(aio_context, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo blkverify_aiocb_info = {
|
static const AIOCBInfo blkverify_aiocb_info = {
|
||||||
.aiocb_size = sizeof(BlkverifyAIOCB),
|
.aiocb_size = sizeof(BlkverifyAIOCB),
|
||||||
.cancel = blkverify_aio_cancel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
|
static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
|
||||||
@@ -194,7 +179,6 @@ static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
|
|||||||
acb->qiov = qiov;
|
acb->qiov = qiov;
|
||||||
acb->buf = NULL;
|
acb->buf = NULL;
|
||||||
acb->verify = NULL;
|
acb->verify = NULL;
|
||||||
acb->finished = NULL;
|
|
||||||
return acb;
|
return acb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,10 +192,7 @@ static void blkverify_aio_bh(void *opaque)
|
|||||||
qemu_vfree(acb->buf);
|
qemu_vfree(acb->buf);
|
||||||
}
|
}
|
||||||
acb->common.cb(acb->common.opaque, acb->ret);
|
acb->common.cb(acb->common.opaque, acb->ret);
|
||||||
if (acb->finished) {
|
qemu_aio_unref(acb);
|
||||||
*acb->finished = true;
|
|
||||||
}
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blkverify_aio_cb(void *opaque, int ret)
|
static void blkverify_aio_cb(void *opaque, int ret)
|
||||||
|
|||||||
432
block/cow.c
432
block/cow.c
@@ -1,432 +0,0 @@
|
|||||||
/*
|
|
||||||
* Block driver for the COW format
|
|
||||||
*
|
|
||||||
* Copyright (c) 2004 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "qemu-common.h"
|
|
||||||
#include "block/block_int.h"
|
|
||||||
#include "qemu/module.h"
|
|
||||||
|
|
||||||
/**************************************************************/
|
|
||||||
/* COW block driver using file system holes */
|
|
||||||
|
|
||||||
/* user mode linux compatible COW file */
|
|
||||||
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
|
|
||||||
#define COW_VERSION 2
|
|
||||||
|
|
||||||
struct cow_header_v2 {
|
|
||||||
uint32_t magic;
|
|
||||||
uint32_t version;
|
|
||||||
char backing_file[1024];
|
|
||||||
int32_t mtime;
|
|
||||||
uint64_t size;
|
|
||||||
uint32_t sectorsize;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct BDRVCowState {
|
|
||||||
CoMutex lock;
|
|
||||||
int64_t cow_sectors_offset;
|
|
||||||
} BDRVCowState;
|
|
||||||
|
|
||||||
static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|
||||||
{
|
|
||||||
const struct cow_header_v2 *cow_header = (const void *)buf;
|
|
||||||
|
|
||||||
if (buf_size >= sizeof(struct cow_header_v2) &&
|
|
||||||
be32_to_cpu(cow_header->magic) == COW_MAGIC &&
|
|
||||||
be32_to_cpu(cow_header->version) == COW_VERSION)
|
|
||||||
return 100;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
BDRVCowState *s = bs->opaque;
|
|
||||||
struct cow_header_v2 cow_header;
|
|
||||||
int bitmap_size;
|
|
||||||
int64_t size;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* see if it is a cow image */
|
|
||||||
ret = bdrv_pread(bs->file, 0, &cow_header, sizeof(cow_header));
|
|
||||||
if (ret < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (be32_to_cpu(cow_header.magic) != COW_MAGIC) {
|
|
||||||
error_setg(errp, "Image not in COW format");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
|
||||||
char version[64];
|
|
||||||
snprintf(version, sizeof(version),
|
|
||||||
"COW version %" PRIu32, cow_header.version);
|
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
|
||||||
bs->device_name, "cow", version);
|
|
||||||
ret = -ENOTSUP;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cow image found */
|
|
||||||
size = be64_to_cpu(cow_header.size);
|
|
||||||
bs->total_sectors = size / 512;
|
|
||||||
|
|
||||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
|
||||||
cow_header.backing_file);
|
|
||||||
|
|
||||||
bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
|
||||||
s->cow_sectors_offset = (bitmap_size + 511) & ~511;
|
|
||||||
qemu_co_mutex_init(&s->lock);
|
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void cow_set_bits(uint8_t *bitmap, int start, int64_t nb_sectors)
|
|
||||||
{
|
|
||||||
int64_t bitnum = start, last = start + nb_sectors;
|
|
||||||
while (bitnum < last) {
|
|
||||||
if ((bitnum & 7) == 0 && bitnum + 8 <= last) {
|
|
||||||
bitmap[bitnum / 8] = 0xFF;
|
|
||||||
bitnum += 8;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bitmap[bitnum/8] |= (1 << (bitnum % 8));
|
|
||||||
bitnum++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BITS_PER_BITMAP_SECTOR (512 * 8)
|
|
||||||
|
|
||||||
/* Cannot use bitmap.c on big-endian machines. */
|
|
||||||
static int cow_test_bit(int64_t bitnum, const uint8_t *bitmap)
|
|
||||||
{
|
|
||||||
return (bitmap[bitnum / 8] & (1 << (bitnum & 7))) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cow_find_streak(const uint8_t *bitmap, int value, int start, int nb_sectors)
|
|
||||||
{
|
|
||||||
int streak_value = value ? 0xFF : 0;
|
|
||||||
int last = MIN(start + nb_sectors, BITS_PER_BITMAP_SECTOR);
|
|
||||||
int bitnum = start;
|
|
||||||
while (bitnum < last) {
|
|
||||||
if ((bitnum & 7) == 0 && bitmap[bitnum / 8] == streak_value) {
|
|
||||||
bitnum += 8;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (cow_test_bit(bitnum, bitmap) == value) {
|
|
||||||
bitnum++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return MIN(bitnum, last) - start;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if first block has been changed (ie. current version is
|
|
||||||
* in COW file). Set the number of continuous blocks for which that
|
|
||||||
* is true. */
|
|
||||||
static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, int nb_sectors, int *num_same)
|
|
||||||
{
|
|
||||||
int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8;
|
|
||||||
uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
|
|
||||||
bool first = true;
|
|
||||||
int changed = 0, same = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
int ret;
|
|
||||||
uint8_t bitmap[BDRV_SECTOR_SIZE];
|
|
||||||
|
|
||||||
bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
|
||||||
int sector_bits = MIN(nb_sectors, BITS_PER_BITMAP_SECTOR - bitnum);
|
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
changed = cow_test_bit(bitnum, bitmap);
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
same += cow_find_streak(bitmap, changed, bitnum, nb_sectors);
|
|
||||||
|
|
||||||
bitnum += sector_bits;
|
|
||||||
nb_sectors -= sector_bits;
|
|
||||||
offset += BDRV_SECTOR_SIZE;
|
|
||||||
} while (nb_sectors);
|
|
||||||
|
|
||||||
*num_same = same;
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t coroutine_fn cow_co_get_block_status(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, int nb_sectors, int *num_same)
|
|
||||||
{
|
|
||||||
BDRVCowState *s = bs->opaque;
|
|
||||||
int ret = cow_co_is_allocated(bs, sector_num, nb_sectors, num_same);
|
|
||||||
int64_t offset = s->cow_sectors_offset + (sector_num << BDRV_SECTOR_BITS);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return (ret ? BDRV_BLOCK_DATA : 0) | offset | BDRV_BLOCK_OFFSET_VALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
|
|
||||||
int nb_sectors)
|
|
||||||
{
|
|
||||||
int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8;
|
|
||||||
uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
|
|
||||||
bool first = true;
|
|
||||||
int sector_bits;
|
|
||||||
|
|
||||||
for ( ; nb_sectors;
|
|
||||||
bitnum += sector_bits,
|
|
||||||
nb_sectors -= sector_bits,
|
|
||||||
offset += BDRV_SECTOR_SIZE) {
|
|
||||||
int ret, set;
|
|
||||||
uint8_t bitmap[BDRV_SECTOR_SIZE];
|
|
||||||
|
|
||||||
bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
|
||||||
sector_bits = MIN(nb_sectors, BITS_PER_BITMAP_SECTOR - bitnum);
|
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip over any already set bits */
|
|
||||||
set = cow_find_streak(bitmap, 1, bitnum, sector_bits);
|
|
||||||
bitnum += set;
|
|
||||||
sector_bits -= set;
|
|
||||||
nb_sectors -= set;
|
|
||||||
if (!sector_bits) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
ret = bdrv_flush(bs->file);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cow_set_bits(bitmap, bitnum, sector_bits);
|
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap));
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num,
|
|
||||||
uint8_t *buf, int nb_sectors)
|
|
||||||
{
|
|
||||||
BDRVCowState *s = bs->opaque;
|
|
||||||
int ret, n;
|
|
||||||
|
|
||||||
while (nb_sectors > 0) {
|
|
||||||
ret = cow_co_is_allocated(bs, sector_num, nb_sectors, &n);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (ret) {
|
|
||||||
ret = bdrv_pread(bs->file,
|
|
||||||
s->cow_sectors_offset + sector_num * 512,
|
|
||||||
buf, n * 512);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (bs->backing_hd) {
|
|
||||||
/* read from the base image */
|
|
||||||
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
memset(buf, 0, n * 512);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nb_sectors -= n;
|
|
||||||
sector_num += n;
|
|
||||||
buf += n * 512;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num,
|
|
||||||
uint8_t *buf, int nb_sectors)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
BDRVCowState *s = bs->opaque;
|
|
||||||
qemu_co_mutex_lock(&s->lock);
|
|
||||||
ret = cow_read(bs, sector_num, buf, nb_sectors);
|
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cow_write(BlockDriverState *bs, int64_t sector_num,
|
|
||||||
const uint8_t *buf, int nb_sectors)
|
|
||||||
{
|
|
||||||
BDRVCowState *s = bs->opaque;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512,
|
|
||||||
buf, nb_sectors * 512);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cow_update_bitmap(bs, sector_num, nb_sectors);
|
|
||||||
}
|
|
||||||
|
|
||||||
static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num,
|
|
||||||
const uint8_t *buf, int nb_sectors)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
BDRVCowState *s = bs->opaque;
|
|
||||||
qemu_co_mutex_lock(&s->lock);
|
|
||||||
ret = cow_write(bs, sector_num, buf, nb_sectors);
|
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cow_close(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cow_create(const char *filename, QemuOpts *opts, Error **errp)
|
|
||||||
{
|
|
||||||
struct cow_header_v2 cow_header;
|
|
||||||
struct stat st;
|
|
||||||
int64_t image_sectors = 0;
|
|
||||||
char *image_filename = NULL;
|
|
||||||
Error *local_err = NULL;
|
|
||||||
int ret;
|
|
||||||
BlockDriverState *cow_bs = NULL;
|
|
||||||
|
|
||||||
/* Read out options */
|
|
||||||
image_sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
|
|
||||||
image_filename = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
|
||||||
|
|
||||||
ret = bdrv_create_file(filename, opts, &local_err);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_propagate(errp, local_err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bdrv_open(&cow_bs, filename, NULL, NULL,
|
|
||||||
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_propagate(errp, local_err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&cow_header, 0, sizeof(cow_header));
|
|
||||||
cow_header.magic = cpu_to_be32(COW_MAGIC);
|
|
||||||
cow_header.version = cpu_to_be32(COW_VERSION);
|
|
||||||
if (image_filename) {
|
|
||||||
/* Note: if no file, we put a dummy mtime */
|
|
||||||
cow_header.mtime = cpu_to_be32(0);
|
|
||||||
|
|
||||||
if (stat(image_filename, &st) != 0) {
|
|
||||||
goto mtime_fail;
|
|
||||||
}
|
|
||||||
cow_header.mtime = cpu_to_be32(st.st_mtime);
|
|
||||||
mtime_fail:
|
|
||||||
pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
|
|
||||||
image_filename);
|
|
||||||
}
|
|
||||||
cow_header.sectorsize = cpu_to_be32(512);
|
|
||||||
cow_header.size = cpu_to_be64(image_sectors * 512);
|
|
||||||
ret = bdrv_pwrite(cow_bs, 0, &cow_header, sizeof(cow_header));
|
|
||||||
if (ret < 0) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* resize to include at least all the bitmap */
|
|
||||||
ret = bdrv_truncate(cow_bs,
|
|
||||||
sizeof(cow_header) + ((image_sectors + 7) >> 3));
|
|
||||||
if (ret < 0) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
g_free(image_filename);
|
|
||||||
if (cow_bs) {
|
|
||||||
bdrv_unref(cow_bs);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QemuOptsList cow_create_opts = {
|
|
||||||
.name = "cow-create-opts",
|
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(cow_create_opts.head),
|
|
||||||
.desc = {
|
|
||||||
{
|
|
||||||
.name = BLOCK_OPT_SIZE,
|
|
||||||
.type = QEMU_OPT_SIZE,
|
|
||||||
.help = "Virtual disk size"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = BLOCK_OPT_BACKING_FILE,
|
|
||||||
.type = QEMU_OPT_STRING,
|
|
||||||
.help = "File name of a base image"
|
|
||||||
},
|
|
||||||
{ /* end of list */ }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static BlockDriver bdrv_cow = {
|
|
||||||
.format_name = "cow",
|
|
||||||
.instance_size = sizeof(BDRVCowState),
|
|
||||||
|
|
||||||
.bdrv_probe = cow_probe,
|
|
||||||
.bdrv_open = cow_open,
|
|
||||||
.bdrv_close = cow_close,
|
|
||||||
.bdrv_create = cow_create,
|
|
||||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
|
||||||
.supports_backing = true,
|
|
||||||
|
|
||||||
.bdrv_read = cow_co_read,
|
|
||||||
.bdrv_write = cow_co_write,
|
|
||||||
.bdrv_co_get_block_status = cow_co_get_block_status,
|
|
||||||
|
|
||||||
.create_opts = &cow_create_opts,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void bdrv_cow_init(void)
|
|
||||||
{
|
|
||||||
bdrv_register(&bdrv_cow);
|
|
||||||
}
|
|
||||||
|
|
||||||
block_init(bdrv_cow_init);
|
|
||||||
16
block/curl.c
16
block/curl.c
@@ -212,7 +212,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|||||||
qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
|
qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
|
||||||
acb->end - acb->start);
|
acb->end - acb->start);
|
||||||
acb->common.cb(acb->common.opaque, 0);
|
acb->common.cb(acb->common.opaque, 0);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
s->acb[i] = NULL;
|
s->acb[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,7 +304,7 @@ static void curl_multi_check_completion(BDRVCURLState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
acb->common.cb(acb->common.opaque, -EIO);
|
acb->common.cb(acb->common.opaque, -EIO);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
state->acb[i] = NULL;
|
state->acb[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -613,14 +613,8 @@ out_noclean:
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
// Do we have to implement canceling? Seems to work without...
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo curl_aiocb_info = {
|
static const AIOCBInfo curl_aiocb_info = {
|
||||||
.aiocb_size = sizeof(CURLAIOCB),
|
.aiocb_size = sizeof(CURLAIOCB),
|
||||||
.cancel = curl_aio_cancel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -642,7 +636,7 @@ static void curl_readv_bh_cb(void *p)
|
|||||||
// we can just call the callback and be done.
|
// we can just call the callback and be done.
|
||||||
switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
|
switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
|
||||||
case FIND_RET_OK:
|
case FIND_RET_OK:
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
// fall through
|
// fall through
|
||||||
case FIND_RET_WAIT:
|
case FIND_RET_WAIT:
|
||||||
return;
|
return;
|
||||||
@@ -654,7 +648,7 @@ static void curl_readv_bh_cb(void *p)
|
|||||||
state = curl_init_state(acb->common.bs, s);
|
state = curl_init_state(acb->common.bs, s);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
acb->common.cb(acb->common.opaque, -EIO);
|
acb->common.cb(acb->common.opaque, -EIO);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,7 +664,7 @@ static void curl_readv_bh_cb(void *p)
|
|||||||
if (state->buf_len && state->orig_buf == NULL) {
|
if (state->buf_len && state->orig_buf == NULL) {
|
||||||
curl_clean_state(state);
|
curl_clean_state(state);
|
||||||
acb->common.cb(acb->common.opaque, -ENOMEM);
|
acb->common.cb(acb->common.opaque, -ENOMEM);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state->acb[0] = acb;
|
state->acb[0] = acb;
|
||||||
|
|||||||
@@ -494,8 +494,8 @@ static int qemu_gluster_create(const char *filename,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_size =
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
|
BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
||||||
if (!tmp || !strcmp(tmp, "off")) {
|
if (!tmp || !strcmp(tmp, "off")) {
|
||||||
@@ -516,9 +516,8 @@ static int qemu_gluster_create(const char *filename,
|
|||||||
if (!fd) {
|
if (!fd) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
} else {
|
} else {
|
||||||
if (!glfs_ftruncate(fd, total_size * BDRV_SECTOR_SIZE)) {
|
if (!glfs_ftruncate(fd, total_size)) {
|
||||||
if (prealloc && qemu_gluster_zerofill(fd, 0,
|
if (prealloc && qemu_gluster_zerofill(fd, 0, total_size)) {
|
||||||
total_size * BDRV_SECTOR_SIZE)) {
|
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
#include "qemu/bitmap.h"
|
#include "qemu/bitmap.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "trace.h"
|
|
||||||
#include "block/scsi.h"
|
#include "block/scsi.h"
|
||||||
#include "qemu/iov.h"
|
#include "qemu/iov.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
@@ -88,7 +87,6 @@ typedef struct IscsiAIOCB {
|
|||||||
struct scsi_task *task;
|
struct scsi_task *task;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
int status;
|
int status;
|
||||||
int canceled;
|
|
||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
int nb_sectors;
|
int nb_sectors;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@@ -120,16 +118,14 @@ iscsi_bh_cb(void *p)
|
|||||||
g_free(acb->buf);
|
g_free(acb->buf);
|
||||||
acb->buf = NULL;
|
acb->buf = NULL;
|
||||||
|
|
||||||
if (acb->canceled == 0) {
|
acb->common.cb(acb->common.opaque, acb->status);
|
||||||
acb->common.cb(acb->common.opaque, acb->status);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acb->task != NULL) {
|
if (acb->task != NULL) {
|
||||||
scsi_free_scsi_task(acb->task);
|
scsi_free_scsi_task(acb->task);
|
||||||
acb->task = NULL;
|
acb->task = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -240,20 +236,15 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
acb->canceled = 1;
|
|
||||||
|
|
||||||
/* send a task mgmt call to the target to cancel the task on the target */
|
/* send a task mgmt call to the target to cancel the task on the target */
|
||||||
iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
|
iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
|
||||||
iscsi_abort_task_cb, acb);
|
iscsi_abort_task_cb, acb);
|
||||||
|
|
||||||
while (acb->status == -EINPROGRESS) {
|
|
||||||
aio_poll(iscsilun->aio_context, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AIOCBInfo iscsi_aiocb_info = {
|
static const AIOCBInfo iscsi_aiocb_info = {
|
||||||
.aiocb_size = sizeof(IscsiAIOCB),
|
.aiocb_size = sizeof(IscsiAIOCB),
|
||||||
.cancel = iscsi_aio_cancel,
|
.cancel_async = iscsi_aio_cancel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -638,10 +629,6 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
|
|||||||
g_free(acb->buf);
|
g_free(acb->buf);
|
||||||
acb->buf = NULL;
|
acb->buf = NULL;
|
||||||
|
|
||||||
if (acb->canceled != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
acb->status = 0;
|
acb->status = 0;
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
error_report("Failed to ioctl(SG_IO) to iSCSI lun. %s",
|
error_report("Failed to ioctl(SG_IO) to iSCSI lun. %s",
|
||||||
@@ -683,7 +670,6 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
|||||||
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
|
||||||
|
|
||||||
acb->iscsilun = iscsilun;
|
acb->iscsilun = iscsilun;
|
||||||
acb->canceled = 0;
|
|
||||||
acb->bh = NULL;
|
acb->bh = NULL;
|
||||||
acb->status = -EINPROGRESS;
|
acb->status = -EINPROGRESS;
|
||||||
acb->buf = NULL;
|
acb->buf = NULL;
|
||||||
@@ -693,7 +679,7 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
|||||||
if (acb->task == NULL) {
|
if (acb->task == NULL) {
|
||||||
error_report("iSCSI: Failed to allocate task for scsi command. %s",
|
error_report("iSCSI: Failed to allocate task for scsi command. %s",
|
||||||
iscsi_get_error(iscsi));
|
iscsi_get_error(iscsi));
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(acb->task, 0, sizeof(struct scsi_task));
|
memset(acb->task, 0, sizeof(struct scsi_task));
|
||||||
@@ -731,7 +717,7 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
|||||||
(data.size > 0) ? &data : NULL,
|
(data.size > 0) ? &data : NULL,
|
||||||
acb) != 0) {
|
acb) != 0) {
|
||||||
scsi_free_scsi_task(acb->task);
|
scsi_free_scsi_task(acb->task);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1531,8 +1517,8 @@ static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
bs = bdrv_new("", &error_abort);
|
bs = bdrv_new("", &error_abort);
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
total_size =
|
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
|
BDRV_SECTOR_SIZE);
|
||||||
bs->opaque = g_new0(struct IscsiLun, 1);
|
bs->opaque = g_new0(struct IscsiLun, 1);
|
||||||
iscsilun = bs->opaque;
|
iscsilun = bs->opaque;
|
||||||
|
|
||||||
|
|||||||
@@ -85,11 +85,10 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
laiocb->common.cb(laiocb->common.opaque, ret);
|
|
||||||
}
|
}
|
||||||
|
laiocb->common.cb(laiocb->common.opaque, ret);
|
||||||
|
|
||||||
qemu_aio_release(laiocb);
|
qemu_aio_unref(laiocb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The completion BH fetches completed I/O requests and invokes their
|
/* The completion BH fetches completed I/O requests and invokes their
|
||||||
@@ -153,35 +152,22 @@ static void laio_cancel(BlockDriverAIOCB *blockacb)
|
|||||||
struct io_event event;
|
struct io_event event;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (laiocb->ret != -EINPROGRESS)
|
if (laiocb->ret != -EINPROGRESS) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
/*
|
|
||||||
* Note that as of Linux 2.6.31 neither the block device code nor any
|
|
||||||
* filesystem implements cancellation of AIO request.
|
|
||||||
* Thus the polling loop below is the normal code path.
|
|
||||||
*/
|
|
||||||
ret = io_cancel(laiocb->ctx->ctx, &laiocb->iocb, &event);
|
ret = io_cancel(laiocb->ctx->ctx, &laiocb->iocb, &event);
|
||||||
if (ret == 0) {
|
laiocb->ret = -ECANCELED;
|
||||||
laiocb->ret = -ECANCELED;
|
if (ret != 0) {
|
||||||
|
/* iocb is not cancelled, cb will be called by the event loop later */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
laiocb->common.cb(laiocb->common.opaque, laiocb->ret);
|
||||||
* We have to wait for the iocb to finish.
|
|
||||||
*
|
|
||||||
* The only way to get the iocb status update is by polling the io context.
|
|
||||||
* We might be able to do this slightly more optimal by removing the
|
|
||||||
* O_NONBLOCK flag.
|
|
||||||
*/
|
|
||||||
while (laiocb->ret == -EINPROGRESS) {
|
|
||||||
qemu_laio_completion_cb(&laiocb->ctx->e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AIOCBInfo laio_aiocb_info = {
|
static const AIOCBInfo laio_aiocb_info = {
|
||||||
.aiocb_size = sizeof(struct qemu_laiocb),
|
.aiocb_size = sizeof(struct qemu_laiocb),
|
||||||
.cancel = laio_cancel,
|
.cancel_async = laio_cancel,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ioq_init(LaioQueue *io_q)
|
static void ioq_init(LaioQueue *io_q)
|
||||||
@@ -300,7 +286,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
|||||||
return &laiocb->common;
|
return &laiocb->common;
|
||||||
|
|
||||||
out_free_aiocb:
|
out_free_aiocb:
|
||||||
qemu_aio_release(laiocb);
|
qemu_aio_unref(laiocb);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -418,7 +418,8 @@ static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
|
|||||||
client->aio_context = qemu_get_aio_context();
|
client->aio_context = qemu_get_aio_context();
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
ret = nfs_client_open(client, url, O_CREAT, errp);
|
ret = nfs_client_open(client, url, O_CREAT, errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
168
block/null.c
Normal file
168
block/null.c
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Null block driver
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Fam Zheng <famz@redhat.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "block/block_int.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int64_t length;
|
||||||
|
} BDRVNullState;
|
||||||
|
|
||||||
|
static QemuOptsList runtime_opts = {
|
||||||
|
.name = "null",
|
||||||
|
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||||
|
.desc = {
|
||||||
|
{
|
||||||
|
.name = "filename",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = BLOCK_OPT_SIZE,
|
||||||
|
.type = QEMU_OPT_SIZE,
|
||||||
|
.help = "size of the null block",
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QemuOpts *opts;
|
||||||
|
BDRVNullState *s = bs->opaque;
|
||||||
|
|
||||||
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
|
qemu_opts_absorb_qdict(opts, options, &error_abort);
|
||||||
|
s->length =
|
||||||
|
qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
|
||||||
|
qemu_opts_del(opts);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void null_close(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t null_getlength(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVNullState *s = bs->opaque;
|
||||||
|
return s->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static coroutine_fn int null_co_readv(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors,
|
||||||
|
QEMUIOVector *qiov)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static coroutine_fn int null_co_writev(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors,
|
||||||
|
QEMUIOVector *qiov)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static coroutine_fn int null_co_flush(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BlockDriverAIOCB common;
|
||||||
|
QEMUBH *bh;
|
||||||
|
} NullAIOCB;
|
||||||
|
|
||||||
|
static const AIOCBInfo null_aiocb_info = {
|
||||||
|
.aiocb_size = sizeof(NullAIOCB),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void null_bh_cb(void *opaque)
|
||||||
|
{
|
||||||
|
NullAIOCB *acb = opaque;
|
||||||
|
acb->common.cb(acb->common.opaque, 0);
|
||||||
|
qemu_bh_delete(acb->bh);
|
||||||
|
qemu_aio_unref(acb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BlockDriverAIOCB *null_aio_common(BlockDriverState *bs,
|
||||||
|
BlockDriverCompletionFunc *cb,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
NullAIOCB *acb;
|
||||||
|
|
||||||
|
acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
|
||||||
|
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
|
||||||
|
qemu_bh_schedule(acb->bh);
|
||||||
|
return &acb->common;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockDriverAIOCB *null_aio_readv(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, QEMUIOVector *qiov,
|
||||||
|
int nb_sectors,
|
||||||
|
BlockDriverCompletionFunc *cb,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
return null_aio_common(bs, cb, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockDriverAIOCB *null_aio_writev(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, QEMUIOVector *qiov,
|
||||||
|
int nb_sectors,
|
||||||
|
BlockDriverCompletionFunc *cb,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
return null_aio_common(bs, cb, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockDriverAIOCB *null_aio_flush(BlockDriverState *bs,
|
||||||
|
BlockDriverCompletionFunc *cb,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
return null_aio_common(bs, cb, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockDriver bdrv_null_co = {
|
||||||
|
.format_name = "null-co",
|
||||||
|
.protocol_name = "null-co",
|
||||||
|
.instance_size = sizeof(BDRVNullState),
|
||||||
|
|
||||||
|
.bdrv_file_open = null_file_open,
|
||||||
|
.bdrv_close = null_close,
|
||||||
|
.bdrv_getlength = null_getlength,
|
||||||
|
|
||||||
|
.bdrv_co_readv = null_co_readv,
|
||||||
|
.bdrv_co_writev = null_co_writev,
|
||||||
|
.bdrv_co_flush_to_disk = null_co_flush,
|
||||||
|
};
|
||||||
|
|
||||||
|
static BlockDriver bdrv_null_aio = {
|
||||||
|
.format_name = "null-aio",
|
||||||
|
.protocol_name = "null-aio",
|
||||||
|
.instance_size = sizeof(BDRVNullState),
|
||||||
|
|
||||||
|
.bdrv_file_open = null_file_open,
|
||||||
|
.bdrv_close = null_close,
|
||||||
|
.bdrv_getlength = null_getlength,
|
||||||
|
|
||||||
|
.bdrv_aio_readv = null_aio_readv,
|
||||||
|
.bdrv_aio_writev = null_aio_writev,
|
||||||
|
.bdrv_aio_flush = null_aio_flush,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void bdrv_null_init(void)
|
||||||
|
{
|
||||||
|
bdrv_register(&bdrv_null_co);
|
||||||
|
bdrv_register(&bdrv_null_aio);
|
||||||
|
}
|
||||||
|
|
||||||
|
block_init(bdrv_null_init);
|
||||||
19
block/qapi.c
19
block/qapi.c
@@ -333,15 +333,16 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->stats = g_malloc0(sizeof(*s->stats));
|
s->stats = g_malloc0(sizeof(*s->stats));
|
||||||
s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ];
|
s->stats->rd_bytes = bs->stats.nr_bytes[BLOCK_ACCT_READ];
|
||||||
s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE];
|
s->stats->wr_bytes = bs->stats.nr_bytes[BLOCK_ACCT_WRITE];
|
||||||
s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ];
|
s->stats->rd_operations = bs->stats.nr_ops[BLOCK_ACCT_READ];
|
||||||
s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE];
|
s->stats->wr_operations = bs->stats.nr_ops[BLOCK_ACCT_WRITE];
|
||||||
s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE;
|
s->stats->wr_highest_offset =
|
||||||
s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH];
|
bs->stats.wr_highest_sector * BDRV_SECTOR_SIZE;
|
||||||
s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE];
|
s->stats->flush_operations = bs->stats.nr_ops[BLOCK_ACCT_FLUSH];
|
||||||
s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ];
|
s->stats->wr_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_WRITE];
|
||||||
s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH];
|
s->stats->rd_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_READ];
|
||||||
|
s->stats->flush_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_FLUSH];
|
||||||
|
|
||||||
if (bs->file) {
|
if (bs->file) {
|
||||||
s->has_parent = true;
|
s->has_parent = true;
|
||||||
|
|||||||
@@ -725,7 +725,8 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
BlockDriverState *qcow_bs;
|
BlockDriverState *qcow_bs;
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
||||||
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
|
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
|
||||||
flags |= BLOCK_FLAG_ENCRYPT;
|
flags |= BLOCK_FLAG_ENCRYPT;
|
||||||
@@ -753,7 +754,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
header.magic = cpu_to_be32(QCOW_MAGIC);
|
header.magic = cpu_to_be32(QCOW_MAGIC);
|
||||||
header.version = cpu_to_be32(QCOW_VERSION);
|
header.version = cpu_to_be32(QCOW_VERSION);
|
||||||
header.size = cpu_to_be64(total_size * 512);
|
header.size = cpu_to_be64(total_size);
|
||||||
header_size = sizeof(header);
|
header_size = sizeof(header);
|
||||||
backing_filename_len = 0;
|
backing_filename_len = 0;
|
||||||
if (backing_file) {
|
if (backing_file) {
|
||||||
@@ -775,7 +776,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
}
|
}
|
||||||
header_size = (header_size + 7) & ~7;
|
header_size = (header_size + 7) & ~7;
|
||||||
shift = header.cluster_bits + header.l2_bits;
|
shift = header.cluster_bits + header.l2_bits;
|
||||||
l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
|
l1_size = (total_size + (1LL << shift) - 1) >> shift;
|
||||||
|
|
||||||
header.l1_table_offset = cpu_to_be64(header_size);
|
header.l1_table_offset = cpu_to_be64(header_size);
|
||||||
if (flags & BLOCK_FLAG_ENCRYPT) {
|
if (flags & BLOCK_FLAG_ENCRYPT) {
|
||||||
|
|||||||
@@ -486,6 +486,13 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (offset_into_cluster(s, l2_offset)) {
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#" PRIx64
|
||||||
|
" unaligned (L1 index: %#" PRIx64 ")",
|
||||||
|
l2_offset, l1_index);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
/* load the l2 table in memory */
|
/* load the l2 table in memory */
|
||||||
|
|
||||||
ret = l2_load(bs, l2_offset, &l2_table);
|
ret = l2_load(bs, l2_offset, &l2_table);
|
||||||
@@ -508,8 +515,11 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
break;
|
break;
|
||||||
case QCOW2_CLUSTER_ZERO:
|
case QCOW2_CLUSTER_ZERO:
|
||||||
if (s->qcow_version < 3) {
|
if (s->qcow_version < 3) {
|
||||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"
|
||||||
return -EIO;
|
" in pre-v3 image (L2 offset: %#" PRIx64
|
||||||
|
", L2 index: %#x)", l2_offset, l2_index);
|
||||||
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||||
&l2_table[l2_index], QCOW_OFLAG_ZERO);
|
&l2_table[l2_index], QCOW_OFLAG_ZERO);
|
||||||
@@ -525,6 +535,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||||
&l2_table[l2_index], QCOW_OFLAG_ZERO);
|
&l2_table[l2_index], QCOW_OFLAG_ZERO);
|
||||||
*cluster_offset &= L2E_OFFSET_MASK;
|
*cluster_offset &= L2E_OFFSET_MASK;
|
||||||
|
if (offset_into_cluster(s, *cluster_offset)) {
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset %#"
|
||||||
|
PRIx64 " unaligned (L2 offset: %#" PRIx64
|
||||||
|
", L2 index: %#x)", *cluster_offset,
|
||||||
|
l2_offset, l2_index);
|
||||||
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
@@ -541,6 +559,10 @@ out:
|
|||||||
*num = nb_available - index_in_cluster;
|
*num = nb_available - index_in_cluster;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -576,6 +598,12 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
|||||||
|
|
||||||
assert(l1_index < s->l1_size);
|
assert(l1_index < s->l1_size);
|
||||||
l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
|
l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
|
||||||
|
if (offset_into_cluster(s, l2_offset)) {
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#" PRIx64
|
||||||
|
" unaligned (L1 index: %#" PRIx64 ")",
|
||||||
|
l2_offset, l1_index);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
/* seek the l2 table of the given l2 offset */
|
/* seek the l2 table of the given l2 offset */
|
||||||
|
|
||||||
@@ -948,6 +976,15 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
|
|||||||
bool offset_matches =
|
bool offset_matches =
|
||||||
(cluster_offset & L2E_OFFSET_MASK) == *host_offset;
|
(cluster_offset & L2E_OFFSET_MASK) == *host_offset;
|
||||||
|
|
||||||
|
if (offset_into_cluster(s, cluster_offset & L2E_OFFSET_MASK)) {
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset "
|
||||||
|
"%#llx unaligned (guest offset: %#" PRIx64
|
||||||
|
")", cluster_offset & L2E_OFFSET_MASK,
|
||||||
|
guest_offset);
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (*host_offset != 0 && !offset_matches) {
|
if (*host_offset != 0 && !offset_matches) {
|
||||||
*bytes = 0;
|
*bytes = 0;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -979,7 +1016,7 @@ out:
|
|||||||
|
|
||||||
/* Only return a host offset if we actually made progress. Otherwise we
|
/* Only return a host offset if we actually made progress. Otherwise we
|
||||||
* would make requirements for handle_alloc() that it can't fulfill */
|
* would make requirements for handle_alloc() that it can't fulfill */
|
||||||
if (ret) {
|
if (ret > 0) {
|
||||||
*host_offset = (cluster_offset & L2E_OFFSET_MASK)
|
*host_offset = (cluster_offset & L2E_OFFSET_MASK)
|
||||||
+ offset_into_cluster(s, guest_offset);
|
+ offset_into_cluster(s, guest_offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,6 @@
|
|||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "block/qcow2.h"
|
#include "block/qcow2.h"
|
||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
#include "qapi/qmp/types.h"
|
|
||||||
#include "qapi-event.h"
|
|
||||||
|
|
||||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
|
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
|
||||||
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||||
@@ -110,6 +108,13 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
|||||||
if (!refcount_block_offset)
|
if (!refcount_block_offset)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (offset_into_cluster(s, refcount_block_offset)) {
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1, "Refblock offset %#" PRIx64
|
||||||
|
" unaligned (reftable index: %#" PRIx64 ")",
|
||||||
|
refcount_block_offset, refcount_table_index);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
ret = qcow2_cache_get(bs, s->refcount_block_cache, refcount_block_offset,
|
ret = qcow2_cache_get(bs, s->refcount_block_cache, refcount_block_offset,
|
||||||
(void**) &refcount_block);
|
(void**) &refcount_block);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -183,6 +188,14 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
|
|
||||||
/* If it's already there, we're done */
|
/* If it's already there, we're done */
|
||||||
if (refcount_block_offset) {
|
if (refcount_block_offset) {
|
||||||
|
if (offset_into_cluster(s, refcount_block_offset)) {
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1, "Refblock offset %#"
|
||||||
|
PRIx64 " unaligned (reftable index: "
|
||||||
|
"%#x)", refcount_block_offset,
|
||||||
|
refcount_table_index);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
return load_refcount_block(bs, refcount_block_offset,
|
return load_refcount_block(bs, refcount_block_offset,
|
||||||
(void**) refcount_block);
|
(void**) refcount_block);
|
||||||
}
|
}
|
||||||
@@ -838,8 +851,14 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
|
|||||||
case QCOW2_CLUSTER_NORMAL:
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
case QCOW2_CLUSTER_ZERO:
|
case QCOW2_CLUSTER_ZERO:
|
||||||
if (l2_entry & L2E_OFFSET_MASK) {
|
if (l2_entry & L2E_OFFSET_MASK) {
|
||||||
qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
|
if (offset_into_cluster(s, l2_entry & L2E_OFFSET_MASK)) {
|
||||||
nb_clusters << s->cluster_bits, type);
|
qcow2_signal_corruption(bs, false, -1, -1,
|
||||||
|
"Cannot free unaligned cluster %#llx",
|
||||||
|
l2_entry & L2E_OFFSET_MASK);
|
||||||
|
} else {
|
||||||
|
qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
|
||||||
|
nb_clusters << s->cluster_bits, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QCOW2_CLUSTER_UNALLOCATED:
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
@@ -903,6 +922,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
old_l2_offset = l2_offset;
|
old_l2_offset = l2_offset;
|
||||||
l2_offset &= L1E_OFFSET_MASK;
|
l2_offset &= L1E_OFFSET_MASK;
|
||||||
|
|
||||||
|
if (offset_into_cluster(s, l2_offset)) {
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#"
|
||||||
|
PRIx64 " unaligned (L1 index: %#x)",
|
||||||
|
l2_offset, i);
|
||||||
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
|
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
|
||||||
(void**) &l2_table);
|
(void**) &l2_table);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -935,6 +962,17 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
|
|
||||||
case QCOW2_CLUSTER_NORMAL:
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
case QCOW2_CLUSTER_ZERO:
|
case QCOW2_CLUSTER_ZERO:
|
||||||
|
if (offset_into_cluster(s, offset & L2E_OFFSET_MASK)) {
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1, "Data "
|
||||||
|
"cluster offset %#llx "
|
||||||
|
"unaligned (L2 offset: %#"
|
||||||
|
PRIx64 ", L2 index: %#x)",
|
||||||
|
offset & L2E_OFFSET_MASK,
|
||||||
|
l2_offset, j);
|
||||||
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
|
cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
|
||||||
if (!cluster_index) {
|
if (!cluster_index) {
|
||||||
/* unallocated */
|
/* unallocated */
|
||||||
@@ -1838,26 +1876,11 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
|
|||||||
return ret;
|
return ret;
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
int metadata_ol_bitnr = ffs(ret) - 1;
|
int metadata_ol_bitnr = ffs(ret) - 1;
|
||||||
char *message;
|
|
||||||
|
|
||||||
assert(metadata_ol_bitnr < QCOW2_OL_MAX_BITNR);
|
assert(metadata_ol_bitnr < QCOW2_OL_MAX_BITNR);
|
||||||
|
|
||||||
fprintf(stderr, "qcow2: Preventing invalid write on metadata (overlaps "
|
qcow2_signal_corruption(bs, true, offset, size, "Preventing invalid "
|
||||||
"with %s); image marked as corrupt.\n",
|
"write on metadata (overlaps with %s)",
|
||||||
metadata_ol_names[metadata_ol_bitnr]);
|
metadata_ol_names[metadata_ol_bitnr]);
|
||||||
message = g_strdup_printf("Prevented %s overwrite",
|
|
||||||
metadata_ol_names[metadata_ol_bitnr]);
|
|
||||||
qapi_event_send_block_image_corrupted(bdrv_get_device_name(bs),
|
|
||||||
message,
|
|
||||||
true,
|
|
||||||
offset,
|
|
||||||
true,
|
|
||||||
size,
|
|
||||||
&error_abort);
|
|
||||||
g_free(message);
|
|
||||||
|
|
||||||
qcow2_mark_corrupt(bs);
|
|
||||||
bs->drv = NULL; /* make BDS unusable */
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
159
block/qcow2.c
159
block/qcow2.c
@@ -30,6 +30,9 @@
|
|||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qapi/qmp/qbool.h"
|
#include "qapi/qmp/qbool.h"
|
||||||
|
#include "qapi/util.h"
|
||||||
|
#include "qapi/qmp/types.h"
|
||||||
|
#include "qapi-event.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "qemu/option_int.h"
|
#include "qemu/option_int.h"
|
||||||
|
|
||||||
@@ -402,6 +405,12 @@ static QemuOptsList qcow2_runtime_opts = {
|
|||||||
.help = "Selects which overlap checks to perform from a range of "
|
.help = "Selects which overlap checks to perform from a range of "
|
||||||
"templates (none, constant, cached, all)",
|
"templates (none, constant, cached, all)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = QCOW2_OPT_OVERLAP_TEMPLATE,
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "Selects which overlap checks to perform from a range of "
|
||||||
|
"templates (none, constant, cached, all)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = QCOW2_OPT_OVERLAP_MAIN_HEADER,
|
.name = QCOW2_OPT_OVERLAP_MAIN_HEADER,
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
@@ -535,11 +544,11 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
unsigned int len, i;
|
unsigned int len, i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
QCowHeader header;
|
QCowHeader header;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
uint64_t ext_end;
|
uint64_t ext_end;
|
||||||
uint64_t l1_vm_state_index;
|
uint64_t l1_vm_state_index;
|
||||||
const char *opt_overlap_check;
|
const char *opt_overlap_check, *opt_overlap_check_template;
|
||||||
int overlap_check_template = 0;
|
int overlap_check_template = 0;
|
||||||
uint64_t l2_cache_size, refcount_cache_size;
|
uint64_t l2_cache_size, refcount_cache_size;
|
||||||
|
|
||||||
@@ -919,7 +928,21 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->discard_passthrough[QCOW2_DISCARD_OTHER] =
|
s->discard_passthrough[QCOW2_DISCARD_OTHER] =
|
||||||
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
|
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
|
||||||
|
|
||||||
opt_overlap_check = qemu_opt_get(opts, "overlap-check") ?: "cached";
|
opt_overlap_check = qemu_opt_get(opts, QCOW2_OPT_OVERLAP);
|
||||||
|
opt_overlap_check_template = qemu_opt_get(opts, QCOW2_OPT_OVERLAP_TEMPLATE);
|
||||||
|
if (opt_overlap_check_template && opt_overlap_check &&
|
||||||
|
strcmp(opt_overlap_check_template, opt_overlap_check))
|
||||||
|
{
|
||||||
|
error_setg(errp, "Conflicting values for qcow2 options '"
|
||||||
|
QCOW2_OPT_OVERLAP "' ('%s') and '" QCOW2_OPT_OVERLAP_TEMPLATE
|
||||||
|
"' ('%s')", opt_overlap_check, opt_overlap_check_template);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!opt_overlap_check) {
|
||||||
|
opt_overlap_check = opt_overlap_check_template ?: "cached";
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(opt_overlap_check, "none")) {
|
if (!strcmp(opt_overlap_check, "none")) {
|
||||||
overlap_check_template = 0;
|
overlap_check_template = 0;
|
||||||
} else if (!strcmp(opt_overlap_check, "constant")) {
|
} else if (!strcmp(opt_overlap_check, "constant")) {
|
||||||
@@ -932,7 +955,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
error_setg(errp, "Unsupported value '%s' for qcow2 option "
|
error_setg(errp, "Unsupported value '%s' for qcow2 option "
|
||||||
"'overlap-check'. Allowed are either of the following: "
|
"'overlap-check'. Allowed are either of the following: "
|
||||||
"none, constant, cached, all", opt_overlap_check);
|
"none, constant, cached, all", opt_overlap_check);
|
||||||
qemu_opts_del(opts);
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -947,6 +969,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
|
opts = NULL;
|
||||||
|
|
||||||
if (s->use_lazy_refcounts && s->qcow_version < 3) {
|
if (s->use_lazy_refcounts && s->qcow_version < 3) {
|
||||||
error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
|
error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
|
||||||
@@ -964,6 +987,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
qemu_opts_del(opts);
|
||||||
g_free(s->unknown_header_fields);
|
g_free(s->unknown_header_fields);
|
||||||
cleanup_unknown_header_ext(bs);
|
cleanup_unknown_header_ext(bs);
|
||||||
qcow2_free_snapshots(bs);
|
qcow2_free_snapshots(bs);
|
||||||
@@ -1738,7 +1762,7 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
|
|
||||||
static int qcow2_create2(const char *filename, int64_t total_size,
|
static int qcow2_create2(const char *filename, int64_t total_size,
|
||||||
const char *backing_file, const char *backing_format,
|
const char *backing_file, const char *backing_format,
|
||||||
int flags, size_t cluster_size, int prealloc,
|
int flags, size_t cluster_size, PreallocMode prealloc,
|
||||||
QemuOpts *opts, int version,
|
QemuOpts *opts, int version,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@@ -1771,6 +1795,56 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
|
||||||
|
int64_t meta_size = 0;
|
||||||
|
uint64_t nreftablee, nrefblocke, nl1e, nl2e;
|
||||||
|
int64_t aligned_total_size = align_offset(total_size, cluster_size);
|
||||||
|
|
||||||
|
/* header: 1 cluster */
|
||||||
|
meta_size += cluster_size;
|
||||||
|
|
||||||
|
/* total size of L2 tables */
|
||||||
|
nl2e = aligned_total_size / cluster_size;
|
||||||
|
nl2e = align_offset(nl2e, cluster_size / sizeof(uint64_t));
|
||||||
|
meta_size += nl2e * sizeof(uint64_t);
|
||||||
|
|
||||||
|
/* total size of L1 tables */
|
||||||
|
nl1e = nl2e * sizeof(uint64_t) / cluster_size;
|
||||||
|
nl1e = align_offset(nl1e, cluster_size / sizeof(uint64_t));
|
||||||
|
meta_size += nl1e * sizeof(uint64_t);
|
||||||
|
|
||||||
|
/* total size of refcount blocks
|
||||||
|
*
|
||||||
|
* note: every host cluster is reference-counted, including metadata
|
||||||
|
* (even refcount blocks are recursively included).
|
||||||
|
* Let:
|
||||||
|
* a = total_size (this is the guest disk size)
|
||||||
|
* m = meta size not including refcount blocks and refcount tables
|
||||||
|
* c = cluster size
|
||||||
|
* y1 = number of refcount blocks entries
|
||||||
|
* y2 = meta size including everything
|
||||||
|
* then,
|
||||||
|
* y1 = (y2 + a)/c
|
||||||
|
* y2 = y1 * sizeof(u16) + y1 * sizeof(u16) * sizeof(u64) / c + m
|
||||||
|
* we can get y1:
|
||||||
|
* y1 = (a + m) / (c - sizeof(u16) - sizeof(u16) * sizeof(u64) / c)
|
||||||
|
*/
|
||||||
|
nrefblocke = (aligned_total_size + meta_size + cluster_size) /
|
||||||
|
(cluster_size - sizeof(uint16_t) -
|
||||||
|
1.0 * sizeof(uint16_t) * sizeof(uint64_t) / cluster_size);
|
||||||
|
nrefblocke = align_offset(nrefblocke, cluster_size / sizeof(uint16_t));
|
||||||
|
meta_size += nrefblocke * sizeof(uint16_t);
|
||||||
|
|
||||||
|
/* total size of refcount tables */
|
||||||
|
nreftablee = nrefblocke * sizeof(uint16_t) / cluster_size;
|
||||||
|
nreftablee = align_offset(nreftablee, cluster_size / sizeof(uint64_t));
|
||||||
|
meta_size += nreftablee * sizeof(uint64_t);
|
||||||
|
|
||||||
|
qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
|
||||||
|
aligned_total_size + meta_size);
|
||||||
|
qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_lookup[prealloc]);
|
||||||
|
}
|
||||||
|
|
||||||
ret = bdrv_create_file(filename, opts, &local_err);
|
ret = bdrv_create_file(filename, opts, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
@@ -1859,7 +1933,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Okay, now that we have a valid image, let's give it the right size */
|
/* Okay, now that we have a valid image, let's give it the right size */
|
||||||
ret = bdrv_truncate(bs, total_size * BDRV_SECTOR_SIZE);
|
ret = bdrv_truncate(bs, total_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not resize image");
|
error_setg_errno(errp, -ret, "Could not resize image");
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1876,7 +1950,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* And if we're supposed to preallocate metadata, do that now */
|
/* And if we're supposed to preallocate metadata, do that now */
|
||||||
if (prealloc) {
|
if (prealloc != PREALLOC_MODE_OFF) {
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
ret = preallocate(bs);
|
ret = preallocate(bs);
|
||||||
@@ -1912,16 +1986,17 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
char *backing_file = NULL;
|
char *backing_file = NULL;
|
||||||
char *backing_fmt = NULL;
|
char *backing_fmt = NULL;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
uint64_t sectors = 0;
|
uint64_t size = 0;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
size_t cluster_size = DEFAULT_CLUSTER_SIZE;
|
size_t cluster_size = DEFAULT_CLUSTER_SIZE;
|
||||||
int prealloc = 0;
|
PreallocMode prealloc;
|
||||||
int version = 3;
|
int version = 3;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
|
size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
||||||
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
|
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
|
||||||
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
|
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
|
||||||
@@ -1930,12 +2005,11 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
|
cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
|
||||||
DEFAULT_CLUSTER_SIZE);
|
DEFAULT_CLUSTER_SIZE);
|
||||||
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
||||||
if (!buf || !strcmp(buf, "off")) {
|
prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
|
||||||
prealloc = 0;
|
PREALLOC_MODE_MAX, PREALLOC_MODE_OFF,
|
||||||
} else if (!strcmp(buf, "metadata")) {
|
&local_err);
|
||||||
prealloc = 1;
|
if (local_err) {
|
||||||
} else {
|
error_propagate(errp, local_err);
|
||||||
error_setg(errp, "Invalid preallocation mode: '%s'", buf);
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
@@ -1957,7 +2031,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
|
flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backing_file && prealloc) {
|
if (backing_file && prealloc != PREALLOC_MODE_OFF) {
|
||||||
error_setg(errp, "Backing file and preallocation cannot be used at "
|
error_setg(errp, "Backing file and preallocation cannot be used at "
|
||||||
"the same time");
|
"the same time");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@@ -1971,7 +2045,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
|
ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags,
|
||||||
cluster_size, prealloc, opts, version, &local_err);
|
cluster_size, prealloc, opts, version, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
@@ -2478,6 +2552,52 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If offset or size are negative, respectively, they will not be included in
|
||||||
|
* the BLOCK_IMAGE_CORRUPTED event emitted.
|
||||||
|
* fatal will be ignored for read-only BDS; corruptions found there will always
|
||||||
|
* be considered non-fatal.
|
||||||
|
*/
|
||||||
|
void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
|
||||||
|
int64_t size, const char *message_format, ...)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
char *message;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
fatal = fatal && !bs->read_only;
|
||||||
|
|
||||||
|
if (s->signaled_corruption &&
|
||||||
|
(!fatal || (s->incompatible_features & QCOW2_INCOMPAT_CORRUPT)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(ap, message_format);
|
||||||
|
message = g_strdup_vprintf(message_format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (fatal) {
|
||||||
|
fprintf(stderr, "qcow2: Marking image as corrupt: %s; further "
|
||||||
|
"corruption events will be suppressed\n", message);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "qcow2: Image is corrupt: %s; further non-fatal "
|
||||||
|
"corruption events will be suppressed\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
qapi_event_send_block_image_corrupted(bdrv_get_device_name(bs), message,
|
||||||
|
offset >= 0, offset, size >= 0, size,
|
||||||
|
fatal, &error_abort);
|
||||||
|
g_free(message);
|
||||||
|
|
||||||
|
if (fatal) {
|
||||||
|
qcow2_mark_corrupt(bs);
|
||||||
|
bs->drv = NULL; /* make BDS unusable */
|
||||||
|
}
|
||||||
|
|
||||||
|
s->signaled_corruption = true;
|
||||||
|
}
|
||||||
|
|
||||||
static QemuOptsList qcow2_create_opts = {
|
static QemuOptsList qcow2_create_opts = {
|
||||||
.name = "qcow2-create-opts",
|
.name = "qcow2-create-opts",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
|
||||||
@@ -2517,7 +2637,8 @@ static QemuOptsList qcow2_create_opts = {
|
|||||||
{
|
{
|
||||||
.name = BLOCK_OPT_PREALLOC,
|
.name = BLOCK_OPT_PREALLOC,
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "Preallocation mode (allowed values: off, metadata)"
|
.help = "Preallocation mode (allowed values: off, metadata, "
|
||||||
|
"falloc, full)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = BLOCK_OPT_LAZY_REFCOUNTS,
|
.name = BLOCK_OPT_LAZY_REFCOUNTS,
|
||||||
|
|||||||
@@ -83,6 +83,7 @@
|
|||||||
#define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot"
|
#define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot"
|
||||||
#define QCOW2_OPT_DISCARD_OTHER "pass-discard-other"
|
#define QCOW2_OPT_DISCARD_OTHER "pass-discard-other"
|
||||||
#define QCOW2_OPT_OVERLAP "overlap-check"
|
#define QCOW2_OPT_OVERLAP "overlap-check"
|
||||||
|
#define QCOW2_OPT_OVERLAP_TEMPLATE "overlap-check.template"
|
||||||
#define QCOW2_OPT_OVERLAP_MAIN_HEADER "overlap-check.main-header"
|
#define QCOW2_OPT_OVERLAP_MAIN_HEADER "overlap-check.main-header"
|
||||||
#define QCOW2_OPT_OVERLAP_ACTIVE_L1 "overlap-check.active-l1"
|
#define QCOW2_OPT_OVERLAP_ACTIVE_L1 "overlap-check.active-l1"
|
||||||
#define QCOW2_OPT_OVERLAP_ACTIVE_L2 "overlap-check.active-l2"
|
#define QCOW2_OPT_OVERLAP_ACTIVE_L2 "overlap-check.active-l2"
|
||||||
@@ -261,6 +262,7 @@ typedef struct BDRVQcowState {
|
|||||||
bool discard_passthrough[QCOW2_DISCARD_MAX];
|
bool discard_passthrough[QCOW2_DISCARD_MAX];
|
||||||
|
|
||||||
int overlap_check; /* bitmask of Qcow2MetadataOverlap values */
|
int overlap_check; /* bitmask of Qcow2MetadataOverlap values */
|
||||||
|
bool signaled_corruption;
|
||||||
|
|
||||||
uint64_t incompatible_features;
|
uint64_t incompatible_features;
|
||||||
uint64_t compatible_features;
|
uint64_t compatible_features;
|
||||||
@@ -477,6 +479,10 @@ int qcow2_mark_corrupt(BlockDriverState *bs);
|
|||||||
int qcow2_mark_consistent(BlockDriverState *bs);
|
int qcow2_mark_consistent(BlockDriverState *bs);
|
||||||
int qcow2_update_header(BlockDriverState *bs);
|
int qcow2_update_header(BlockDriverState *bs);
|
||||||
|
|
||||||
|
void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
|
||||||
|
int64_t size, const char *message_format, ...)
|
||||||
|
GCC_FMT_ATTR(5, 6);
|
||||||
|
|
||||||
/* qcow2-refcount.c functions */
|
/* qcow2-refcount.c functions */
|
||||||
int qcow2_refcount_init(BlockDriverState *bs);
|
int qcow2_refcount_init(BlockDriverState *bs);
|
||||||
void qcow2_refcount_close(BlockDriverState *bs);
|
void qcow2_refcount_close(BlockDriverState *bs);
|
||||||
|
|||||||
26
block/qed.c
26
block/qed.c
@@ -18,22 +18,8 @@
|
|||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "migration/migration.h"
|
#include "migration/migration.h"
|
||||||
|
|
||||||
static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
QEDAIOCB *acb = (QEDAIOCB *)blockacb;
|
|
||||||
AioContext *aio_context = bdrv_get_aio_context(blockacb->bs);
|
|
||||||
bool finished = false;
|
|
||||||
|
|
||||||
/* Wait for the request to finish */
|
|
||||||
acb->finished = &finished;
|
|
||||||
while (!finished) {
|
|
||||||
aio_poll(aio_context, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo qed_aiocb_info = {
|
static const AIOCBInfo qed_aiocb_info = {
|
||||||
.aiocb_size = sizeof(QEDAIOCB),
|
.aiocb_size = sizeof(QEDAIOCB),
|
||||||
.cancel = qed_aio_cancel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
|
static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
|
||||||
@@ -648,7 +634,8 @@ static int bdrv_qed_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
char *backing_fmt = NULL;
|
char *backing_fmt = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
image_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
image_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
||||||
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
|
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
|
||||||
cluster_size = qemu_opt_get_size_del(opts,
|
cluster_size = qemu_opt_get_size_del(opts,
|
||||||
@@ -918,18 +905,12 @@ static void qed_aio_complete_bh(void *opaque)
|
|||||||
BlockDriverCompletionFunc *cb = acb->common.cb;
|
BlockDriverCompletionFunc *cb = acb->common.cb;
|
||||||
void *user_opaque = acb->common.opaque;
|
void *user_opaque = acb->common.opaque;
|
||||||
int ret = acb->bh_ret;
|
int ret = acb->bh_ret;
|
||||||
bool *finished = acb->finished;
|
|
||||||
|
|
||||||
qemu_bh_delete(acb->bh);
|
qemu_bh_delete(acb->bh);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
|
|
||||||
/* Invoke callback */
|
/* Invoke callback */
|
||||||
cb(user_opaque, ret);
|
cb(user_opaque, ret);
|
||||||
|
|
||||||
/* Signal cancel completion */
|
|
||||||
if (finished) {
|
|
||||||
*finished = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qed_aio_complete(QEDAIOCB *acb, int ret)
|
static void qed_aio_complete(QEDAIOCB *acb, int ret)
|
||||||
@@ -1396,7 +1377,6 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
|
|||||||
opaque, flags);
|
opaque, flags);
|
||||||
|
|
||||||
acb->flags = flags;
|
acb->flags = flags;
|
||||||
acb->finished = NULL;
|
|
||||||
acb->qiov = qiov;
|
acb->qiov = qiov;
|
||||||
acb->qiov_offset = 0;
|
acb->qiov_offset = 0;
|
||||||
acb->cur_pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
|
acb->cur_pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
|
||||||
|
|||||||
@@ -138,16 +138,15 @@ static void quorum_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||||||
|
|
||||||
/* cancel all callbacks */
|
/* cancel all callbacks */
|
||||||
for (i = 0; i < s->num_children; i++) {
|
for (i = 0; i < s->num_children; i++) {
|
||||||
bdrv_aio_cancel(acb->qcrs[i].aiocb);
|
if (acb->qcrs[i].aiocb) {
|
||||||
|
bdrv_aio_cancel_async(acb->qcrs[i].aiocb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(acb->qcrs);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static AIOCBInfo quorum_aiocb_info = {
|
static AIOCBInfo quorum_aiocb_info = {
|
||||||
.aiocb_size = sizeof(QuorumAIOCB),
|
.aiocb_size = sizeof(QuorumAIOCB),
|
||||||
.cancel = quorum_aio_cancel,
|
.cancel_async = quorum_aio_cancel,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void quorum_aio_finalize(QuorumAIOCB *acb)
|
static void quorum_aio_finalize(QuorumAIOCB *acb)
|
||||||
@@ -169,7 +168,7 @@ static void quorum_aio_finalize(QuorumAIOCB *acb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_free(acb->qcrs);
|
g_free(acb->qcrs);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool quorum_sha256_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
static bool quorum_sha256_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "block/thread-pool.h"
|
#include "block/thread-pool.h"
|
||||||
#include "qemu/iov.h"
|
#include "qemu/iov.h"
|
||||||
#include "raw-aio.h"
|
#include "raw-aio.h"
|
||||||
|
#include "qapi/util.h"
|
||||||
|
|
||||||
#if defined(__APPLE__) && (__MACH__)
|
#if defined(__APPLE__) && (__MACH__)
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
@@ -1365,44 +1366,102 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
int result = 0;
|
int result = 0;
|
||||||
int64_t total_size = 0;
|
int64_t total_size = 0;
|
||||||
bool nocow = false;
|
bool nocow = false;
|
||||||
|
PreallocMode prealloc;
|
||||||
|
char *buf = NULL;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
strstart(filename, "file:", &filename);
|
strstart(filename, "file:", &filename);
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
total_size =
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
|
BDRV_SECTOR_SIZE);
|
||||||
nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
|
nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
|
||||||
|
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
||||||
|
prealloc = qapi_enum_parse(PreallocMode_lookup, buf,
|
||||||
|
PREALLOC_MODE_MAX, PREALLOC_MODE_OFF,
|
||||||
|
&local_err);
|
||||||
|
g_free(buf);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
result = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||||
0644);
|
0644);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
error_setg_errno(errp, -result, "Could not create file");
|
error_setg_errno(errp, -result, "Could not create file");
|
||||||
} else {
|
goto out;
|
||||||
if (nocow) {
|
|
||||||
#ifdef __linux__
|
|
||||||
/* Set NOCOW flag to solve performance issue on fs like btrfs.
|
|
||||||
* This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
|
|
||||||
* will be ignored since any failure of this operation should not
|
|
||||||
* block the left work.
|
|
||||||
*/
|
|
||||||
int attr;
|
|
||||||
if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
|
|
||||||
attr |= FS_NOCOW_FL;
|
|
||||||
ioctl(fd, FS_IOC_SETFLAGS, &attr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
|
|
||||||
result = -errno;
|
|
||||||
error_setg_errno(errp, -result, "Could not resize file");
|
|
||||||
}
|
|
||||||
if (qemu_close(fd) != 0) {
|
|
||||||
result = -errno;
|
|
||||||
error_setg_errno(errp, -result, "Could not close the new file");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nocow) {
|
||||||
|
#ifdef __linux__
|
||||||
|
/* Set NOCOW flag to solve performance issue on fs like btrfs.
|
||||||
|
* This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
|
||||||
|
* will be ignored since any failure of this operation should not
|
||||||
|
* block the left work.
|
||||||
|
*/
|
||||||
|
int attr;
|
||||||
|
if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
|
||||||
|
attr |= FS_NOCOW_FL;
|
||||||
|
ioctl(fd, FS_IOC_SETFLAGS, &attr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftruncate(fd, total_size) != 0) {
|
||||||
|
result = -errno;
|
||||||
|
error_setg_errno(errp, -result, "Could not resize file");
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (prealloc) {
|
||||||
|
#ifdef CONFIG_POSIX_FALLOCATE
|
||||||
|
case PREALLOC_MODE_FALLOC:
|
||||||
|
/* posix_fallocate() doesn't set errno. */
|
||||||
|
result = -posix_fallocate(fd, 0, total_size);
|
||||||
|
if (result != 0) {
|
||||||
|
error_setg_errno(errp, -result,
|
||||||
|
"Could not preallocate data for the new file");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case PREALLOC_MODE_FULL:
|
||||||
|
{
|
||||||
|
int64_t num = 0, left = total_size;
|
||||||
|
buf = g_malloc0(65536);
|
||||||
|
|
||||||
|
while (left > 0) {
|
||||||
|
num = MIN(left, 65536);
|
||||||
|
result = write(fd, buf, num);
|
||||||
|
if (result < 0) {
|
||||||
|
result = -errno;
|
||||||
|
error_setg_errno(errp, -result,
|
||||||
|
"Could not write to the new file");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
left -= num;
|
||||||
|
}
|
||||||
|
fsync(fd);
|
||||||
|
g_free(buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PREALLOC_MODE_OFF:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = -EINVAL;
|
||||||
|
error_setg(errp, "Unsupported preallocation mode: %s",
|
||||||
|
PreallocMode_lookup[prealloc]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
if (qemu_close(fd) != 0 && result == 0) {
|
||||||
|
result = -errno;
|
||||||
|
error_setg_errno(errp, -result, "Could not close the new file");
|
||||||
|
}
|
||||||
|
out:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1585,6 +1644,11 @@ static QemuOptsList raw_create_opts = {
|
|||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
.help = "Turn off copy-on-write (valid only on btrfs)"
|
.help = "Turn off copy-on-write (valid only on btrfs)"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = BLOCK_OPT_PREALLOC,
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "Preallocation mode (allowed values: off, falloc, full)"
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1966,8 +2030,8 @@ static int hdev_create(const char *filename, QemuOpts *opts,
|
|||||||
(void)has_prefix;
|
(void)has_prefix;
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
total_size =
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
|
BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
fd = qemu_open(filename, O_WRONLY | O_BINARY);
|
fd = qemu_open(filename, O_WRONLY | O_BINARY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
@@ -1983,7 +2047,7 @@ static int hdev_create(const char *filename, QemuOpts *opts,
|
|||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"The given file is neither a block nor a character device");
|
"The given file is neither a block nor a character device");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
} else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE) {
|
} else if (lseek(fd, 0, SEEK_END) < total_size) {
|
||||||
error_setg(errp, "Device is too small");
|
error_setg(errp, "Device is too small");
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -511,8 +511,8 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
strstart(filename, "file:", &filename);
|
strstart(filename, "file:", &filename);
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
total_size =
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
|
BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||||
0644);
|
0644);
|
||||||
@@ -521,7 +521,7 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
set_sparse(fd);
|
set_sparse(fd);
|
||||||
ftruncate(fd, total_size * 512);
|
ftruncate(fd, total_size);
|
||||||
qemu_close(fd);
|
qemu_close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
28
block/rbd.c
28
block/rbd.c
@@ -77,7 +77,6 @@ typedef struct RBDAIOCB {
|
|||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
int error;
|
int error;
|
||||||
struct BDRVRBDState *s;
|
struct BDRVRBDState *s;
|
||||||
int cancelled;
|
|
||||||
int status;
|
int status;
|
||||||
} RBDAIOCB;
|
} RBDAIOCB;
|
||||||
|
|
||||||
@@ -314,7 +313,8 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
bytes = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
objsize = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
|
objsize = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
|
||||||
if (objsize) {
|
if (objsize) {
|
||||||
if ((objsize - 1) & objsize) { /* not a power of 2? */
|
if ((objsize - 1) & objsize) { /* not a power of 2? */
|
||||||
@@ -407,9 +407,7 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
|||||||
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
||||||
acb->status = 0;
|
acb->status = 0;
|
||||||
|
|
||||||
if (!acb->cancelled) {
|
qemu_aio_unref(acb);
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Convert to fine grained options */
|
/* TODO Convert to fine grained options */
|
||||||
@@ -538,25 +536,8 @@ static void qemu_rbd_close(BlockDriverState *bs)
|
|||||||
rados_shutdown(s->cluster);
|
rados_shutdown(s->cluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Cancel aio. Since we don't reference acb in a non qemu threads,
|
|
||||||
* it is safe to access it here.
|
|
||||||
*/
|
|
||||||
static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
RBDAIOCB *acb = (RBDAIOCB *) blockacb;
|
|
||||||
acb->cancelled = 1;
|
|
||||||
|
|
||||||
while (acb->status == -EINPROGRESS) {
|
|
||||||
aio_poll(bdrv_get_aio_context(acb->common.bs), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo rbd_aiocb_info = {
|
static const AIOCBInfo rbd_aiocb_info = {
|
||||||
.aiocb_size = sizeof(RBDAIOCB),
|
.aiocb_size = sizeof(RBDAIOCB),
|
||||||
.cancel = qemu_rbd_aio_cancel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void rbd_finish_bh(void *opaque)
|
static void rbd_finish_bh(void *opaque)
|
||||||
@@ -639,7 +620,6 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
|||||||
acb->ret = 0;
|
acb->ret = 0;
|
||||||
acb->error = 0;
|
acb->error = 0;
|
||||||
acb->s = s;
|
acb->s = s;
|
||||||
acb->cancelled = 0;
|
|
||||||
acb->bh = NULL;
|
acb->bh = NULL;
|
||||||
acb->status = -EINPROGRESS;
|
acb->status = -EINPROGRESS;
|
||||||
|
|
||||||
@@ -691,7 +671,7 @@ failed_completion:
|
|||||||
failed:
|
failed:
|
||||||
g_free(rcb);
|
g_free(rcb);
|
||||||
qemu_vfree(acb->bounce);
|
qemu_vfree(acb->bounce);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -315,7 +315,6 @@ struct SheepdogAIOCB {
|
|||||||
void (*aio_done_func)(SheepdogAIOCB *);
|
void (*aio_done_func)(SheepdogAIOCB *);
|
||||||
|
|
||||||
bool cancelable;
|
bool cancelable;
|
||||||
bool *finished;
|
|
||||||
int nr_pending;
|
int nr_pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -446,10 +445,7 @@ static inline void free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
|
|||||||
static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb)
|
static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb)
|
||||||
{
|
{
|
||||||
qemu_coroutine_enter(acb->coroutine, NULL);
|
qemu_coroutine_enter(acb->coroutine, NULL);
|
||||||
if (acb->finished) {
|
qemu_aio_unref(acb);
|
||||||
*acb->finished = true;
|
|
||||||
}
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -482,36 +478,33 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
|
|||||||
SheepdogAIOCB *acb = (SheepdogAIOCB *)blockacb;
|
SheepdogAIOCB *acb = (SheepdogAIOCB *)blockacb;
|
||||||
BDRVSheepdogState *s = acb->common.bs->opaque;
|
BDRVSheepdogState *s = acb->common.bs->opaque;
|
||||||
AIOReq *aioreq, *next;
|
AIOReq *aioreq, *next;
|
||||||
bool finished = false;
|
|
||||||
|
|
||||||
acb->finished = &finished;
|
if (sd_acb_cancelable(acb)) {
|
||||||
while (!finished) {
|
/* Remove outstanding requests from pending and failed queues. */
|
||||||
if (sd_acb_cancelable(acb)) {
|
QLIST_FOREACH_SAFE(aioreq, &s->pending_aio_head, aio_siblings,
|
||||||
/* Remove outstanding requests from pending and failed queues. */
|
next) {
|
||||||
QLIST_FOREACH_SAFE(aioreq, &s->pending_aio_head, aio_siblings,
|
if (aioreq->aiocb == acb) {
|
||||||
next) {
|
free_aio_req(s, aioreq);
|
||||||
if (aioreq->aiocb == acb) {
|
|
||||||
free_aio_req(s, aioreq);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
QLIST_FOREACH_SAFE(aioreq, &s->failed_aio_head, aio_siblings,
|
|
||||||
next) {
|
|
||||||
if (aioreq->aiocb == acb) {
|
|
||||||
free_aio_req(s, aioreq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(acb->nr_pending == 0);
|
|
||||||
sd_finish_aiocb(acb);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
aio_poll(s->aio_context, true);
|
QLIST_FOREACH_SAFE(aioreq, &s->failed_aio_head, aio_siblings,
|
||||||
|
next) {
|
||||||
|
if (aioreq->aiocb == acb) {
|
||||||
|
free_aio_req(s, aioreq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(acb->nr_pending == 0);
|
||||||
|
if (acb->common.cb) {
|
||||||
|
acb->common.cb(acb->common.opaque, -ECANCELED);
|
||||||
|
}
|
||||||
|
sd_finish_aiocb(acb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AIOCBInfo sd_aiocb_info = {
|
static const AIOCBInfo sd_aiocb_info = {
|
||||||
.aiocb_size = sizeof(SheepdogAIOCB),
|
.aiocb_size = sizeof(SheepdogAIOCB),
|
||||||
.cancel = sd_aio_cancel,
|
.cancel_async = sd_aio_cancel,
|
||||||
};
|
};
|
||||||
|
|
||||||
static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||||
@@ -528,7 +521,6 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
|||||||
|
|
||||||
acb->aio_done_func = NULL;
|
acb->aio_done_func = NULL;
|
||||||
acb->cancelable = true;
|
acb->cancelable = true;
|
||||||
acb->finished = NULL;
|
|
||||||
acb->coroutine = qemu_coroutine_self();
|
acb->coroutine = qemu_coroutine_self();
|
||||||
acb->ret = 0;
|
acb->ret = 0;
|
||||||
acb->nr_pending = 0;
|
acb->nr_pending = 0;
|
||||||
@@ -1702,7 +1694,8 @@ static int sd_create(const char *filename, QemuOpts *opts,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->inode.vdi_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
s->inode.vdi_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
||||||
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
|
||||||
if (!buf || !strcmp(buf, "off")) {
|
if (!buf || !strcmp(buf, "off")) {
|
||||||
@@ -2137,7 +2130,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
ret = sd_co_rw_vector(acb);
|
ret = sd_co_rw_vector(acb);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2158,7 +2151,7 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
ret = sd_co_rw_vector(acb);
|
ret = sd_co_rw_vector(acb);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2517,7 +2510,7 @@ static coroutine_fn int sd_co_discard(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
ret = sd_co_rw_vector(acb);
|
ret = sd_co_rw_vector(acb);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
qemu_aio_release(acb);
|
qemu_aio_unref(acb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -700,7 +700,8 @@ static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
ssh_state_init(&s);
|
ssh_state_init(&s);
|
||||||
|
|
||||||
/* Get desired file size. */
|
/* Get desired file size. */
|
||||||
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
DPRINTF("total_size=%" PRIi64, total_size);
|
DPRINTF("total_size=%" PRIi64, total_size);
|
||||||
|
|
||||||
uri_options = qdict_new();
|
uri_options = qdict_new();
|
||||||
|
|||||||
@@ -700,7 +700,8 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
logout("\n");
|
logout("\n");
|
||||||
|
|
||||||
/* Read out options. */
|
/* Read out options. */
|
||||||
bytes = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
#if defined(CONFIG_VDI_BLOCK_SIZE)
|
#if defined(CONFIG_VDI_BLOCK_SIZE)
|
||||||
/* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
|
/* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
|
||||||
block_size = qemu_opt_get_size_del(opts,
|
block_size = qemu_opt_get_size_del(opts,
|
||||||
|
|||||||
24
block/vhdx.c
24
block/vhdx.c
@@ -99,7 +99,8 @@ static const MSGUID logical_sector_guid = { .data1 = 0x8141bf1d,
|
|||||||
/* Each parent type must have a valid GUID; this is for parent images
|
/* Each parent type must have a valid GUID; this is for parent images
|
||||||
* of type 'VHDX'. If we were to allow e.g. a QCOW2 parent, we would
|
* of type 'VHDX'. If we were to allow e.g. a QCOW2 parent, we would
|
||||||
* need to make up our own QCOW2 GUID type */
|
* need to make up our own QCOW2 GUID type */
|
||||||
static const MSGUID parent_vhdx_guid = { .data1 = 0xb04aefb7,
|
static const MSGUID parent_vhdx_guid __attribute__((unused))
|
||||||
|
= { .data1 = 0xb04aefb7,
|
||||||
.data2 = 0xd19e,
|
.data2 = 0xd19e,
|
||||||
.data3 = 0x4a81,
|
.data3 = 0x4a81,
|
||||||
.data4 = { 0xb7, 0x89, 0x25, 0xb8,
|
.data4 = { 0xb7, 0x89, 0x25, 0xb8,
|
||||||
@@ -1407,6 +1408,12 @@ exit:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VHDX_METADATA_ENTRY_BUFFER_SIZE \
|
||||||
|
(sizeof(VHDXFileParameters) +\
|
||||||
|
sizeof(VHDXVirtualDiskSize) +\
|
||||||
|
sizeof(VHDXPage83Data) +\
|
||||||
|
sizeof(VHDXVirtualDiskLogicalSectorSize) +\
|
||||||
|
sizeof(VHDXVirtualDiskPhysicalSectorSize))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the Metadata entries.
|
* Create the Metadata entries.
|
||||||
@@ -1445,11 +1452,7 @@ static int vhdx_create_new_metadata(BlockDriverState *bs,
|
|||||||
VHDXVirtualDiskLogicalSectorSize *mt_log_sector_size;
|
VHDXVirtualDiskLogicalSectorSize *mt_log_sector_size;
|
||||||
VHDXVirtualDiskPhysicalSectorSize *mt_phys_sector_size;
|
VHDXVirtualDiskPhysicalSectorSize *mt_phys_sector_size;
|
||||||
|
|
||||||
entry_buffer = g_malloc0(sizeof(VHDXFileParameters) +
|
entry_buffer = g_malloc0(VHDX_METADATA_ENTRY_BUFFER_SIZE);
|
||||||
sizeof(VHDXVirtualDiskSize) +
|
|
||||||
sizeof(VHDXPage83Data) +
|
|
||||||
sizeof(VHDXVirtualDiskLogicalSectorSize) +
|
|
||||||
sizeof(VHDXVirtualDiskPhysicalSectorSize));
|
|
||||||
|
|
||||||
mt_file_params = entry_buffer;
|
mt_file_params = entry_buffer;
|
||||||
offset += sizeof(VHDXFileParameters);
|
offset += sizeof(VHDXFileParameters);
|
||||||
@@ -1530,7 +1533,7 @@ static int vhdx_create_new_metadata(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs, metadata_offset + (64 * KiB), entry_buffer,
|
ret = bdrv_pwrite(bs, metadata_offset + (64 * KiB), entry_buffer,
|
||||||
VHDX_HEADER_BLOCK_SIZE);
|
VHDX_METADATA_ENTRY_BUFFER_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1593,7 +1596,7 @@ static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
bdrv_has_zero_init(bs) == 0) {
|
bdrv_has_zero_init(bs) == 0) {
|
||||||
/* for a fixed file, the default BAT entry is not zero */
|
/* for a fixed file, the default BAT entry is not zero */
|
||||||
s->bat = g_try_malloc0(length);
|
s->bat = g_try_malloc0(length);
|
||||||
if (length && s->bat != NULL) {
|
if (length && s->bat == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1725,7 +1728,6 @@ static int vhdx_create_new_region_table(BlockDriverState *bs,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
g_free(s);
|
g_free(s);
|
||||||
g_free(buffer);
|
g_free(buffer);
|
||||||
@@ -1766,7 +1768,8 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
VHDXImageType image_type;
|
VHDXImageType image_type;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
image_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
image_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0);
|
log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0);
|
||||||
block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0);
|
block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0);
|
||||||
type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
|
type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
|
||||||
@@ -1875,7 +1878,6 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
delete_and_exit:
|
delete_and_exit:
|
||||||
bdrv_unref(bs);
|
bdrv_unref(bs);
|
||||||
exit:
|
exit:
|
||||||
|
|||||||
@@ -1807,7 +1807,8 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE);
|
adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE);
|
||||||
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
|
||||||
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) {
|
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) {
|
||||||
|
|||||||
55
block/vpc.c
55
block/vpc.c
@@ -207,7 +207,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
"incorrect.\n", bs->filename);
|
"incorrect.\n", bs->filename);
|
||||||
|
|
||||||
/* Write 'checksum' back to footer, or else will leave it with zero. */
|
/* Write 'checksum' back to footer, or else will leave it with zero. */
|
||||||
footer->checksum = be32_to_cpu(checksum);
|
footer->checksum = cpu_to_be32(checksum);
|
||||||
|
|
||||||
// The visible size of a image in Virtual PC depends on the geometry
|
// The visible size of a image in Virtual PC depends on the geometry
|
||||||
// rather than on the size stored in the footer (the size in the footer
|
// rather than on the size stored in the footer (the size in the footer
|
||||||
@@ -472,7 +472,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
|
|||||||
|
|
||||||
// Write BAT entry to disk
|
// Write BAT entry to disk
|
||||||
bat_offset = s->bat_offset + (4 * index);
|
bat_offset = s->bat_offset + (4 * index);
|
||||||
bat_value = be32_to_cpu(s->pagetable[index]);
|
bat_value = cpu_to_be32(s->pagetable[index]);
|
||||||
ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
|
ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -489,7 +489,7 @@ static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|||||||
BDRVVPCState *s = (BDRVVPCState *)bs->opaque;
|
BDRVVPCState *s = (BDRVVPCState *)bs->opaque;
|
||||||
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
||||||
|
|
||||||
if (cpu_to_be32(footer->type) != VHD_FIXED) {
|
if (be32_to_cpu(footer->type) != VHD_FIXED) {
|
||||||
bdi->cluster_size = s->block_size;
|
bdi->cluster_size = s->block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,7 +506,7 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
int64_t sectors, sectors_per_block;
|
int64_t sectors, sectors_per_block;
|
||||||
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
||||||
|
|
||||||
if (cpu_to_be32(footer->type) == VHD_FIXED) {
|
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
||||||
return bdrv_read(bs->file, sector_num, buf, nb_sectors);
|
return bdrv_read(bs->file, sector_num, buf, nb_sectors);
|
||||||
}
|
}
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
@@ -555,7 +555,7 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
int ret;
|
int ret;
|
||||||
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
||||||
|
|
||||||
if (cpu_to_be32(footer->type) == VHD_FIXED) {
|
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
||||||
return bdrv_write(bs->file, sector_num, buf, nb_sectors);
|
return bdrv_write(bs->file, sector_num, buf, nb_sectors);
|
||||||
}
|
}
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
@@ -699,13 +699,13 @@ static int create_dynamic_disk(BlockDriverState *bs, uint8_t *buf,
|
|||||||
* Note: The spec is actually wrong here for data_offset, it says
|
* Note: The spec is actually wrong here for data_offset, it says
|
||||||
* 0xFFFFFFFF, but MS tools expect all 64 bits to be set.
|
* 0xFFFFFFFF, but MS tools expect all 64 bits to be set.
|
||||||
*/
|
*/
|
||||||
dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
|
dyndisk_header->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
|
||||||
dyndisk_header->table_offset = be64_to_cpu(3 * 512);
|
dyndisk_header->table_offset = cpu_to_be64(3 * 512);
|
||||||
dyndisk_header->version = be32_to_cpu(0x00010000);
|
dyndisk_header->version = cpu_to_be32(0x00010000);
|
||||||
dyndisk_header->block_size = be32_to_cpu(block_size);
|
dyndisk_header->block_size = cpu_to_be32(block_size);
|
||||||
dyndisk_header->max_table_entries = be32_to_cpu(num_bat_entries);
|
dyndisk_header->max_table_entries = cpu_to_be32(num_bat_entries);
|
||||||
|
|
||||||
dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
|
dyndisk_header->checksum = cpu_to_be32(vpc_checksum(buf, 1024));
|
||||||
|
|
||||||
// Write the header
|
// Write the header
|
||||||
offset = 512;
|
offset = 512;
|
||||||
@@ -757,7 +757,8 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
BlockDriverState *bs = NULL;
|
BlockDriverState *bs = NULL;
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||||
|
BDRV_SECTOR_SIZE);
|
||||||
disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
|
disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
|
||||||
if (disk_type_param) {
|
if (disk_type_param) {
|
||||||
if (!strcmp(disk_type_param, "dynamic")) {
|
if (!strcmp(disk_type_param, "dynamic")) {
|
||||||
@@ -809,36 +810,36 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
memcpy(footer->creator_app, "qemu", 4);
|
memcpy(footer->creator_app, "qemu", 4);
|
||||||
memcpy(footer->creator_os, "Wi2k", 4);
|
memcpy(footer->creator_os, "Wi2k", 4);
|
||||||
|
|
||||||
footer->features = be32_to_cpu(0x02);
|
footer->features = cpu_to_be32(0x02);
|
||||||
footer->version = be32_to_cpu(0x00010000);
|
footer->version = cpu_to_be32(0x00010000);
|
||||||
if (disk_type == VHD_DYNAMIC) {
|
if (disk_type == VHD_DYNAMIC) {
|
||||||
footer->data_offset = be64_to_cpu(HEADER_SIZE);
|
footer->data_offset = cpu_to_be64(HEADER_SIZE);
|
||||||
} else {
|
} else {
|
||||||
footer->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
|
footer->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
|
||||||
}
|
}
|
||||||
footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
|
footer->timestamp = cpu_to_be32(time(NULL) - VHD_TIMESTAMP_BASE);
|
||||||
|
|
||||||
/* Version of Virtual PC 2007 */
|
/* Version of Virtual PC 2007 */
|
||||||
footer->major = be16_to_cpu(0x0005);
|
footer->major = cpu_to_be16(0x0005);
|
||||||
footer->minor = be16_to_cpu(0x0003);
|
footer->minor = cpu_to_be16(0x0003);
|
||||||
if (disk_type == VHD_DYNAMIC) {
|
if (disk_type == VHD_DYNAMIC) {
|
||||||
footer->orig_size = be64_to_cpu(total_sectors * 512);
|
footer->orig_size = cpu_to_be64(total_sectors * 512);
|
||||||
footer->size = be64_to_cpu(total_sectors * 512);
|
footer->size = cpu_to_be64(total_sectors * 512);
|
||||||
} else {
|
} else {
|
||||||
footer->orig_size = be64_to_cpu(total_size);
|
footer->orig_size = cpu_to_be64(total_size);
|
||||||
footer->size = be64_to_cpu(total_size);
|
footer->size = cpu_to_be64(total_size);
|
||||||
}
|
}
|
||||||
footer->cyls = be16_to_cpu(cyls);
|
footer->cyls = cpu_to_be16(cyls);
|
||||||
footer->heads = heads;
|
footer->heads = heads;
|
||||||
footer->secs_per_cyl = secs_per_cyl;
|
footer->secs_per_cyl = secs_per_cyl;
|
||||||
|
|
||||||
footer->type = be32_to_cpu(disk_type);
|
footer->type = cpu_to_be32(disk_type);
|
||||||
|
|
||||||
#if defined(CONFIG_UUID)
|
#if defined(CONFIG_UUID)
|
||||||
uuid_generate(footer->uuid);
|
uuid_generate(footer->uuid);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
|
footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE));
|
||||||
|
|
||||||
if (disk_type == VHD_DYNAMIC) {
|
if (disk_type == VHD_DYNAMIC) {
|
||||||
ret = create_dynamic_disk(bs, buf, total_sectors);
|
ret = create_dynamic_disk(bs, buf, total_sectors);
|
||||||
@@ -857,7 +858,7 @@ static int vpc_has_zero_init(BlockDriverState *bs)
|
|||||||
BDRVVPCState *s = bs->opaque;
|
BDRVVPCState *s = bs->opaque;
|
||||||
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
||||||
|
|
||||||
if (cpu_to_be32(footer->type) == VHD_FIXED) {
|
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
||||||
return bdrv_has_zero_init(bs->file);
|
return bdrv_has_zero_init(bs->file);
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ static void win32_aio_process_completion(QEMUWin32AIOState *s,
|
|||||||
|
|
||||||
|
|
||||||
waiocb->common.cb(waiocb->common.opaque, ret);
|
waiocb->common.cb(waiocb->common.opaque, ret);
|
||||||
qemu_aio_release(waiocb);
|
qemu_aio_unref(waiocb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void win32_aio_completion_cb(EventNotifier *e)
|
static void win32_aio_completion_cb(EventNotifier *e)
|
||||||
@@ -106,22 +106,8 @@ static void win32_aio_completion_cb(EventNotifier *e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void win32_aio_cancel(BlockDriverAIOCB *blockacb)
|
|
||||||
{
|
|
||||||
QEMUWin32AIOCB *waiocb = (QEMUWin32AIOCB *)blockacb;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CancelIoEx is only supported in Vista and newer. For now, just
|
|
||||||
* wait for completion.
|
|
||||||
*/
|
|
||||||
while (!HasOverlappedIoCompleted(&waiocb->ov)) {
|
|
||||||
aio_poll(bdrv_get_aio_context(blockacb->bs), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo win32_aiocb_info = {
|
static const AIOCBInfo win32_aiocb_info = {
|
||||||
.aiocb_size = sizeof(QEMUWin32AIOCB),
|
.aiocb_size = sizeof(QEMUWin32AIOCB),
|
||||||
.cancel = win32_aio_cancel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
||||||
@@ -172,7 +158,7 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
|||||||
out_dec_count:
|
out_dec_count:
|
||||||
aio->count--;
|
aio->count--;
|
||||||
out:
|
out:
|
||||||
qemu_aio_release(waiocb);
|
qemu_aio_unref(waiocb);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
113
blockdev.c
113
blockdev.c
@@ -216,11 +216,17 @@ static void bdrv_format_print(void *opaque, const char *name)
|
|||||||
|
|
||||||
void drive_del(DriveInfo *dinfo)
|
void drive_del(DriveInfo *dinfo)
|
||||||
{
|
{
|
||||||
|
bdrv_unref(dinfo->bdrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drive_info_del(DriveInfo *dinfo)
|
||||||
|
{
|
||||||
|
if (!dinfo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (dinfo->opts) {
|
if (dinfo->opts) {
|
||||||
qemu_opts_del(dinfo->opts);
|
qemu_opts_del(dinfo->opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_unref(dinfo->bdrv);
|
|
||||||
g_free(dinfo->id);
|
g_free(dinfo->id);
|
||||||
QTAILQ_REMOVE(&drives, dinfo, next);
|
QTAILQ_REMOVE(&drives, dinfo, next);
|
||||||
g_free(dinfo->serial);
|
g_free(dinfo->serial);
|
||||||
@@ -301,6 +307,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
int ro = 0;
|
int ro = 0;
|
||||||
int bdrv_flags = 0;
|
int bdrv_flags = 0;
|
||||||
int on_read_error, on_write_error;
|
int on_read_error, on_write_error;
|
||||||
|
BlockDriverState *bs;
|
||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
ThrottleConfig cfg;
|
ThrottleConfig cfg;
|
||||||
int snapshot = 0;
|
int snapshot = 0;
|
||||||
@@ -456,26 +463,27 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
dinfo = g_malloc0(sizeof(*dinfo));
|
bs = bdrv_new(qemu_opts_id(opts), errp);
|
||||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
if (!bs) {
|
||||||
dinfo->bdrv = bdrv_new(dinfo->id, &error);
|
goto early_err;
|
||||||
if (error) {
|
|
||||||
error_propagate(errp, error);
|
|
||||||
goto bdrv_new_err;
|
|
||||||
}
|
}
|
||||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||||
dinfo->bdrv->read_only = ro;
|
bs->read_only = ro;
|
||||||
dinfo->bdrv->detect_zeroes = detect_zeroes;
|
bs->detect_zeroes = detect_zeroes;
|
||||||
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
|
|
||||||
|
|
||||||
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
|
bdrv_set_on_error(bs, on_read_error, on_write_error);
|
||||||
|
|
||||||
/* disk I/O throttling */
|
/* disk I/O throttling */
|
||||||
if (throttle_enabled(&cfg)) {
|
if (throttle_enabled(&cfg)) {
|
||||||
bdrv_io_limits_enable(dinfo->bdrv);
|
bdrv_io_limits_enable(bs);
|
||||||
bdrv_set_io_limits(dinfo->bdrv, &cfg);
|
bdrv_set_io_limits(bs, &cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dinfo = g_malloc0(sizeof(*dinfo));
|
||||||
|
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||||
|
dinfo->bdrv = bs;
|
||||||
|
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
|
||||||
|
|
||||||
if (!file || !*file) {
|
if (!file || !*file) {
|
||||||
if (has_driver_specific_opts) {
|
if (has_driver_specific_opts) {
|
||||||
file = NULL;
|
file = NULL;
|
||||||
@@ -502,7 +510,8 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
|
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
|
||||||
|
|
||||||
QINCREF(bs_opts);
|
QINCREF(bs_opts);
|
||||||
ret = bdrv_open(&dinfo->bdrv, file, NULL, bs_opts, bdrv_flags, drv, &error);
|
ret = bdrv_open(&bs, file, NULL, bs_opts, bdrv_flags, drv, &error);
|
||||||
|
assert(bs == dinfo->bdrv);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "could not open disk image %s: %s",
|
error_setg(errp, "could not open disk image %s: %s",
|
||||||
@@ -511,8 +520,9 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_key_required(dinfo->bdrv))
|
if (bdrv_key_required(bs)) {
|
||||||
autostart = 0;
|
autostart = 0;
|
||||||
|
}
|
||||||
|
|
||||||
QDECREF(bs_opts);
|
QDECREF(bs_opts);
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
@@ -520,11 +530,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
return dinfo;
|
return dinfo;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
bdrv_unref(dinfo->bdrv);
|
bdrv_unref(bs);
|
||||||
QTAILQ_REMOVE(&drives, dinfo, next);
|
|
||||||
bdrv_new_err:
|
|
||||||
g_free(dinfo->id);
|
|
||||||
g_free(dinfo);
|
|
||||||
early_err:
|
early_err:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
err_no_opts:
|
err_no_opts:
|
||||||
@@ -532,12 +538,18 @@ err_no_opts:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to)
|
static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
const char *value;
|
const char *value;
|
||||||
|
|
||||||
value = qemu_opt_get(opts, from);
|
value = qemu_opt_get(opts, from);
|
||||||
if (value) {
|
if (value) {
|
||||||
|
if (qemu_opt_find(opts, to)) {
|
||||||
|
error_setg(errp, "'%s' and its alias '%s' can't be used at the "
|
||||||
|
"same time", to, from);
|
||||||
|
return;
|
||||||
|
}
|
||||||
qemu_opt_set(opts, to, value);
|
qemu_opt_set(opts, to, value);
|
||||||
qemu_opt_unset(opts, from);
|
qemu_opt_unset(opts, from);
|
||||||
}
|
}
|
||||||
@@ -641,28 +653,43 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
|||||||
const char *serial;
|
const char *serial;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Change legacy command line options into QMP ones */
|
/* Change legacy command line options into QMP ones */
|
||||||
qemu_opt_rename(all_opts, "iops", "throttling.iops-total");
|
static const struct {
|
||||||
qemu_opt_rename(all_opts, "iops_rd", "throttling.iops-read");
|
const char *from;
|
||||||
qemu_opt_rename(all_opts, "iops_wr", "throttling.iops-write");
|
const char *to;
|
||||||
|
} opt_renames[] = {
|
||||||
|
{ "iops", "throttling.iops-total" },
|
||||||
|
{ "iops_rd", "throttling.iops-read" },
|
||||||
|
{ "iops_wr", "throttling.iops-write" },
|
||||||
|
|
||||||
qemu_opt_rename(all_opts, "bps", "throttling.bps-total");
|
{ "bps", "throttling.bps-total" },
|
||||||
qemu_opt_rename(all_opts, "bps_rd", "throttling.bps-read");
|
{ "bps_rd", "throttling.bps-read" },
|
||||||
qemu_opt_rename(all_opts, "bps_wr", "throttling.bps-write");
|
{ "bps_wr", "throttling.bps-write" },
|
||||||
|
|
||||||
qemu_opt_rename(all_opts, "iops_max", "throttling.iops-total-max");
|
{ "iops_max", "throttling.iops-total-max" },
|
||||||
qemu_opt_rename(all_opts, "iops_rd_max", "throttling.iops-read-max");
|
{ "iops_rd_max", "throttling.iops-read-max" },
|
||||||
qemu_opt_rename(all_opts, "iops_wr_max", "throttling.iops-write-max");
|
{ "iops_wr_max", "throttling.iops-write-max" },
|
||||||
|
|
||||||
qemu_opt_rename(all_opts, "bps_max", "throttling.bps-total-max");
|
{ "bps_max", "throttling.bps-total-max" },
|
||||||
qemu_opt_rename(all_opts, "bps_rd_max", "throttling.bps-read-max");
|
{ "bps_rd_max", "throttling.bps-read-max" },
|
||||||
qemu_opt_rename(all_opts, "bps_wr_max", "throttling.bps-write-max");
|
{ "bps_wr_max", "throttling.bps-write-max" },
|
||||||
|
|
||||||
qemu_opt_rename(all_opts,
|
{ "iops_size", "throttling.iops-size" },
|
||||||
"iops_size", "throttling.iops-size");
|
|
||||||
|
|
||||||
qemu_opt_rename(all_opts, "readonly", "read-only");
|
{ "readonly", "read-only" },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(opt_renames); i++) {
|
||||||
|
qemu_opt_rename(all_opts, opt_renames[i].from, opt_renames[i].to,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report("%s", error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
value = qemu_opt_get(all_opts, "cache");
|
value = qemu_opt_get(all_opts, "cache");
|
||||||
if (value) {
|
if (value) {
|
||||||
@@ -1739,6 +1766,7 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
{
|
{
|
||||||
const char *id = qdict_get_str(qdict, "id");
|
const char *id = qdict_get_str(qdict, "id");
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
DriveInfo *dinfo;
|
||||||
AioContext *aio_context;
|
AioContext *aio_context;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
@@ -1748,6 +1776,13 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dinfo = drive_get_by_blockdev(bs);
|
||||||
|
if (dinfo && !dinfo->enable_auto_del) {
|
||||||
|
error_report("Deleting device added with blockdev-add"
|
||||||
|
" is not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
aio_context = bdrv_get_aio_context(bs);
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
aio_context_acquire(aio_context);
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
@@ -1775,7 +1810,7 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
|
bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
|
||||||
BLOCKDEV_ON_ERROR_REPORT);
|
BLOCKDEV_ON_ERROR_REPORT);
|
||||||
} else {
|
} else {
|
||||||
drive_del(drive_get_by_blockdev(bs));
|
drive_del(dinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
|
|||||||
61
configure
vendored
61
configure
vendored
@@ -327,7 +327,6 @@ glusterfs=""
|
|||||||
glusterfs_discard="no"
|
glusterfs_discard="no"
|
||||||
glusterfs_zerofill="no"
|
glusterfs_zerofill="no"
|
||||||
archipelago=""
|
archipelago=""
|
||||||
virtio_blk_data_plane=""
|
|
||||||
gtk=""
|
gtk=""
|
||||||
gtkabi=""
|
gtkabi=""
|
||||||
vte=""
|
vte=""
|
||||||
@@ -389,6 +388,7 @@ cpp="${CPP-$cc -E}"
|
|||||||
objcopy="${OBJCOPY-${cross_prefix}objcopy}"
|
objcopy="${OBJCOPY-${cross_prefix}objcopy}"
|
||||||
ld="${LD-${cross_prefix}ld}"
|
ld="${LD-${cross_prefix}ld}"
|
||||||
libtool="${LIBTOOL-${cross_prefix}libtool}"
|
libtool="${LIBTOOL-${cross_prefix}libtool}"
|
||||||
|
nm="${NM-${cross_prefix}nm}"
|
||||||
strip="${STRIP-${cross_prefix}strip}"
|
strip="${STRIP-${cross_prefix}strip}"
|
||||||
windres="${WINDRES-${cross_prefix}windres}"
|
windres="${WINDRES-${cross_prefix}windres}"
|
||||||
pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}"
|
pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}"
|
||||||
@@ -1092,9 +1092,8 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-archipelago) archipelago="yes"
|
--enable-archipelago) archipelago="yes"
|
||||||
;;
|
;;
|
||||||
--disable-virtio-blk-data-plane) virtio_blk_data_plane="no"
|
--disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane)
|
||||||
;;
|
echo "$0: $opt is obsolete, virtio-blk data-plane is always on" >&2
|
||||||
--enable-virtio-blk-data-plane) virtio_blk_data_plane="yes"
|
|
||||||
;;
|
;;
|
||||||
--disable-gtk) gtk="no"
|
--disable-gtk) gtk="no"
|
||||||
;;
|
;;
|
||||||
@@ -1349,7 +1348,7 @@ Advanced options (experts only):
|
|||||||
--enable-linux-aio enable Linux AIO support
|
--enable-linux-aio enable Linux AIO support
|
||||||
--disable-cap-ng disable libcap-ng support
|
--disable-cap-ng disable libcap-ng support
|
||||||
--enable-cap-ng enable libcap-ng support
|
--enable-cap-ng enable libcap-ng support
|
||||||
--disable-attr disables attr and xattr support
|
--disable-attr disable attr and xattr support
|
||||||
--enable-attr enable attr and xattr support
|
--enable-attr enable attr and xattr support
|
||||||
--disable-blobs disable installing provided firmware blobs
|
--disable-blobs disable installing provided firmware blobs
|
||||||
--enable-docs enable documentation build
|
--enable-docs enable documentation build
|
||||||
@@ -1380,7 +1379,7 @@ Advanced options (experts only):
|
|||||||
--with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent
|
--with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent
|
||||||
--with-win-sdk=SDK-path path to Windows Platform SDK (to build VSS .tlb)
|
--with-win-sdk=SDK-path path to Windows Platform SDK (to build VSS .tlb)
|
||||||
--disable-seccomp disable seccomp support
|
--disable-seccomp disable seccomp support
|
||||||
--enable-seccomp enables seccomp support
|
--enable-seccomp enable seccomp support
|
||||||
--with-coroutine=BACKEND coroutine backend. Supported options:
|
--with-coroutine=BACKEND coroutine backend. Supported options:
|
||||||
gthread, ucontext, sigaltstack, windows
|
gthread, ucontext, sigaltstack, windows
|
||||||
--disable-coroutine-pool disable coroutine freelist (worse performance)
|
--disable-coroutine-pool disable coroutine freelist (worse performance)
|
||||||
@@ -1395,7 +1394,7 @@ Advanced options (experts only):
|
|||||||
--enable-tpm enable TPM support
|
--enable-tpm enable TPM support
|
||||||
--disable-libssh2 disable ssh block device support
|
--disable-libssh2 disable ssh block device support
|
||||||
--enable-libssh2 enable ssh block device support
|
--enable-libssh2 enable ssh block device support
|
||||||
--disable-vhdx disables support for the Microsoft VHDX image format
|
--disable-vhdx disable support for the Microsoft VHDX image format
|
||||||
--enable-vhdx enable support for the Microsoft VHDX image format
|
--enable-vhdx enable support for the Microsoft VHDX image format
|
||||||
--disable-quorum disable quorum block filter support
|
--disable-quorum disable quorum block filter support
|
||||||
--enable-quorum enable quorum block filter support
|
--enable-quorum enable quorum block filter support
|
||||||
@@ -2716,6 +2715,12 @@ for i in $glib_modules; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# g_test_trap_subprocess added in 2.38. Used by some tests.
|
||||||
|
glib_subprocess=yes
|
||||||
|
if ! $pkg_config --atleast-version=2.38 glib-2.0; then
|
||||||
|
glib_subprocess=no
|
||||||
|
fi
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# SHA command probe for modules
|
# SHA command probe for modules
|
||||||
if test "$modules" = yes; then
|
if test "$modules" = yes; then
|
||||||
@@ -2936,16 +2941,6 @@ else
|
|||||||
tpm_passthrough=no
|
tpm_passthrough=no
|
||||||
fi
|
fi
|
||||||
|
|
||||||
##########################################
|
|
||||||
# adjust virtio-blk-data-plane based on linux-aio
|
|
||||||
|
|
||||||
if test "$virtio_blk_data_plane" = "yes" -a \
|
|
||||||
"$linux_aio" != "yes" ; then
|
|
||||||
error_exit "virtio-blk-data-plane requires Linux AIO, please try --enable-linux-aio"
|
|
||||||
elif test -z "$virtio_blk_data_plane" ; then
|
|
||||||
virtio_blk_data_plane=$linux_aio
|
|
||||||
fi
|
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# attr probe
|
# attr probe
|
||||||
|
|
||||||
@@ -3313,6 +3308,21 @@ if compile_prog "" "" ; then
|
|||||||
fallocate_punch_hole=yes
|
fallocate_punch_hole=yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# check for posix_fallocate
|
||||||
|
posix_fallocate=no
|
||||||
|
cat > $TMPC << EOF
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
posix_fallocate(0, 0, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
if compile_prog "" "" ; then
|
||||||
|
posix_fallocate=yes
|
||||||
|
fi
|
||||||
|
|
||||||
# check for sync_file_range
|
# check for sync_file_range
|
||||||
sync_file_range=no
|
sync_file_range=no
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
@@ -3961,12 +3971,11 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# check if we have valgrind/valgrind.h and valgrind/memcheck.h
|
# check if we have valgrind/valgrind.h
|
||||||
|
|
||||||
valgrind_h=no
|
valgrind_h=no
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
#include <valgrind/valgrind.h>
|
#include <valgrind/valgrind.h>
|
||||||
#include <valgrind/memcheck.h>
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -4320,7 +4329,6 @@ echo "coroutine backend $coroutine"
|
|||||||
echo "coroutine pool $coroutine_pool"
|
echo "coroutine pool $coroutine_pool"
|
||||||
echo "GlusterFS support $glusterfs"
|
echo "GlusterFS support $glusterfs"
|
||||||
echo "Archipelago support $archipelago"
|
echo "Archipelago support $archipelago"
|
||||||
echo "virtio-blk-data-plane $virtio_blk_data_plane"
|
|
||||||
echo "gcov $gcov_tool"
|
echo "gcov $gcov_tool"
|
||||||
echo "gcov enabled $gcov"
|
echo "gcov enabled $gcov"
|
||||||
echo "TPM support $tpm"
|
echo "TPM support $tpm"
|
||||||
@@ -4529,6 +4537,9 @@ fi
|
|||||||
if test "$fallocate_punch_hole" = "yes" ; then
|
if test "$fallocate_punch_hole" = "yes" ; then
|
||||||
echo "CONFIG_FALLOCATE_PUNCH_HOLE=y" >> $config_host_mak
|
echo "CONFIG_FALLOCATE_PUNCH_HOLE=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$posix_fallocate" = "yes" ; then
|
||||||
|
echo "CONFIG_POSIX_FALLOCATE=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
if test "$sync_file_range" = "yes" ; then
|
if test "$sync_file_range" = "yes" ; then
|
||||||
echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
|
echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -4586,6 +4597,9 @@ if test "$bluez" = "yes" ; then
|
|||||||
echo "CONFIG_BLUEZ=y" >> $config_host_mak
|
echo "CONFIG_BLUEZ=y" >> $config_host_mak
|
||||||
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
|
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "glib_subprocess" = "yes" ; then
|
||||||
|
echo "CONFIG_HAS_GLIB_SUBPROCESS_TESTS=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
||||||
if test "$gtk" = "yes" ; then
|
if test "$gtk" = "yes" ; then
|
||||||
echo "CONFIG_GTK=y" >> $config_host_mak
|
echo "CONFIG_GTK=y" >> $config_host_mak
|
||||||
@@ -4779,10 +4793,6 @@ if test "$quorum" = "yes" ; then
|
|||||||
echo "CONFIG_QUORUM=y" >> $config_host_mak
|
echo "CONFIG_QUORUM=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$virtio_blk_data_plane" = "yes" ; then
|
|
||||||
echo 'CONFIG_VIRTIO_BLK_DATA_PLANE=$(CONFIG_VIRTIO)' >> $config_host_mak
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$vhdx" = "yes" ; then
|
if test "$vhdx" = "yes" ; then
|
||||||
echo "CONFIG_VHDX=y" >> $config_host_mak
|
echo "CONFIG_VHDX=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -4889,6 +4899,7 @@ echo "AS=$as" >> $config_host_mak
|
|||||||
echo "CPP=$cpp" >> $config_host_mak
|
echo "CPP=$cpp" >> $config_host_mak
|
||||||
echo "OBJCOPY=$objcopy" >> $config_host_mak
|
echo "OBJCOPY=$objcopy" >> $config_host_mak
|
||||||
echo "LD=$ld" >> $config_host_mak
|
echo "LD=$ld" >> $config_host_mak
|
||||||
|
echo "NM=$nm" >> $config_host_mak
|
||||||
echo "WINDRES=$windres" >> $config_host_mak
|
echo "WINDRES=$windres" >> $config_host_mak
|
||||||
echo "LIBTOOL=$libtool" >> $config_host_mak
|
echo "LIBTOOL=$libtool" >> $config_host_mak
|
||||||
echo "CFLAGS=$CFLAGS" >> $config_host_mak
|
echo "CFLAGS=$CFLAGS" >> $config_host_mak
|
||||||
@@ -5017,7 +5028,7 @@ case "$target_name" in
|
|||||||
aarch64)
|
aarch64)
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
bflt="yes"
|
bflt="yes"
|
||||||
gdb_xml_files="aarch64-core.xml aarch64-fpu.xml"
|
gdb_xml_files="aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
|
||||||
;;
|
;;
|
||||||
cris)
|
cris)
|
||||||
;;
|
;;
|
||||||
|
|||||||
342
cpu-exec.c
342
cpu-exec.c
@@ -295,16 +295,10 @@ static inline TranslationBlock *tb_find_fast(CPUArchState *env)
|
|||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CPUDebugExcpHandler *debug_excp_handler;
|
|
||||||
|
|
||||||
void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
|
|
||||||
{
|
|
||||||
debug_excp_handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cpu_handle_debug_exception(CPUArchState *env)
|
static void cpu_handle_debug_exception(CPUArchState *env)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
CPUState *cpu = ENV_GET_CPU(env);
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
CPUWatchpoint *wp;
|
CPUWatchpoint *wp;
|
||||||
|
|
||||||
if (!cpu->watchpoint_hit) {
|
if (!cpu->watchpoint_hit) {
|
||||||
@@ -312,9 +306,8 @@ static void cpu_handle_debug_exception(CPUArchState *env)
|
|||||||
wp->flags &= ~BP_WATCHPOINT_HIT;
|
wp->flags &= ~BP_WATCHPOINT_HIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (debug_excp_handler) {
|
|
||||||
debug_excp_handler(env);
|
cc->debug_excp_handler(cpu);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* main execution loop */
|
/* main execution loop */
|
||||||
@@ -324,10 +317,7 @@ volatile sig_atomic_t exit_request;
|
|||||||
int cpu_exec(CPUArchState *env)
|
int cpu_exec(CPUArchState *env)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
CPUState *cpu = ENV_GET_CPU(env);
|
||||||
#if !(defined(CONFIG_USER_ONLY) && \
|
|
||||||
(defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
|
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
#endif
|
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||||
#endif
|
#endif
|
||||||
@@ -362,36 +352,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
cpu->exit_request = 1;
|
cpu->exit_request = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
cc->cpu_exec_enter(cpu);
|
||||||
/* put eflags in CPU temporary format */
|
|
||||||
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
|
||||||
env->df = 1 - (2 * ((env->eflags >> 10) & 1));
|
|
||||||
CC_OP = CC_OP_EFLAGS;
|
|
||||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
|
||||||
#elif defined(TARGET_SPARC)
|
|
||||||
#elif defined(TARGET_M68K)
|
|
||||||
env->cc_op = CC_OP_FLAGS;
|
|
||||||
env->cc_dest = env->sr & 0xf;
|
|
||||||
env->cc_x = (env->sr >> 4) & 1;
|
|
||||||
#elif defined(TARGET_ALPHA)
|
|
||||||
#elif defined(TARGET_ARM)
|
|
||||||
#elif defined(TARGET_UNICORE32)
|
|
||||||
#elif defined(TARGET_PPC)
|
|
||||||
env->reserve_addr = -1;
|
|
||||||
#elif defined(TARGET_LM32)
|
|
||||||
#elif defined(TARGET_MICROBLAZE)
|
|
||||||
#elif defined(TARGET_MIPS)
|
|
||||||
#elif defined(TARGET_MOXIE)
|
|
||||||
#elif defined(TARGET_OPENRISC)
|
|
||||||
#elif defined(TARGET_SH4)
|
|
||||||
#elif defined(TARGET_CRIS)
|
|
||||||
#elif defined(TARGET_S390X)
|
|
||||||
#elif defined(TARGET_XTENSA)
|
|
||||||
#elif defined(TARGET_TRICORE)
|
|
||||||
/* XXXXX */
|
|
||||||
#else
|
|
||||||
#error unsupported target CPU
|
|
||||||
#endif
|
|
||||||
cpu->exception_index = -1;
|
cpu->exception_index = -1;
|
||||||
|
|
||||||
/* Calculate difference between guest clock and host clock.
|
/* Calculate difference between guest clock and host clock.
|
||||||
@@ -443,17 +404,12 @@ int cpu_exec(CPUArchState *env)
|
|||||||
cpu->exception_index = EXCP_DEBUG;
|
cpu->exception_index = EXCP_DEBUG;
|
||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
|
|
||||||
defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
|
|
||||||
defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || \
|
|
||||||
defined(TARGET_UNICORE32) || defined(TARGET_TRICORE)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HALT) {
|
if (interrupt_request & CPU_INTERRUPT_HALT) {
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
|
cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
|
||||||
cpu->halted = 1;
|
cpu->halted = 1;
|
||||||
cpu->exception_index = EXCP_HLT;
|
cpu->exception_index = EXCP_HLT;
|
||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
||||||
@@ -466,257 +422,15 @@ int cpu_exec(CPUArchState *env)
|
|||||||
cpu_reset(cpu);
|
cpu_reset(cpu);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(TARGET_I386)
|
/* The target hook has 3 exit conditions:
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
False when the interrupt isn't processed,
|
||||||
if (interrupt_request & CPU_INTERRUPT_POLL) {
|
True when it is, and we should restart on a new TB,
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
|
and via longjmp via cpu_loop_exit. */
|
||||||
apic_poll_irq(x86_cpu->apic_state);
|
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_SIPI) {
|
|
||||||
do_cpu_sipi(x86_cpu);
|
|
||||||
} else if (env->hflags2 & HF2_GIF_MASK) {
|
|
||||||
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
|
|
||||||
!(env->hflags & HF_SMM_MASK)) {
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI,
|
|
||||||
0);
|
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
|
|
||||||
do_smm_enter(x86_cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
} else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
|
|
||||||
!(env->hflags2 & HF2_NMI_MASK)) {
|
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
|
|
||||||
env->hflags2 |= HF2_NMI_MASK;
|
|
||||||
do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
|
|
||||||
next_tb = 0;
|
|
||||||
} else if (interrupt_request & CPU_INTERRUPT_MCE) {
|
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_MCE;
|
|
||||||
do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
|
|
||||||
next_tb = 0;
|
|
||||||
} else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
|
||||||
(((env->hflags2 & HF2_VINTR_MASK) &&
|
|
||||||
(env->hflags2 & HF2_HIF_MASK)) ||
|
|
||||||
(!(env->hflags2 & HF2_VINTR_MASK) &&
|
|
||||||
(env->eflags & IF_MASK &&
|
|
||||||
!(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
|
|
||||||
int intno;
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INTR,
|
|
||||||
0);
|
|
||||||
cpu->interrupt_request &= ~(CPU_INTERRUPT_HARD |
|
|
||||||
CPU_INTERRUPT_VIRQ);
|
|
||||||
intno = cpu_get_pic_interrupt(env);
|
|
||||||
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
|
|
||||||
do_interrupt_x86_hardirq(env, intno, 1);
|
|
||||||
/* ensure that no TB jump will be modified as
|
|
||||||
the program flow was changed */
|
|
||||||
next_tb = 0;
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
} else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
|
|
||||||
(env->eflags & IF_MASK) &&
|
|
||||||
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
|
|
||||||
int intno;
|
|
||||||
/* FIXME: this should respect TPR */
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR,
|
|
||||||
0);
|
|
||||||
intno = ldl_phys(cpu->as,
|
|
||||||
env->vm_vmcb
|
|
||||||
+ offsetof(struct vmcb,
|
|
||||||
control.int_vector));
|
|
||||||
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
|
|
||||||
do_interrupt_x86_hardirq(env, intno, 1);
|
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
|
|
||||||
next_tb = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_PPC)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
|
||||||
ppc_hw_interrupt(env);
|
|
||||||
if (env->pending_interrupts == 0) {
|
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
|
||||||
}
|
|
||||||
next_tb = 0;
|
next_tb = 0;
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_LM32)
|
/* Don't use the cached interrupt_request value,
|
||||||
if ((interrupt_request & CPU_INTERRUPT_HARD)
|
do_interrupt may have updated the EXITTB flag. */
|
||||||
&& (env->ie & IE_IE)) {
|
|
||||||
cpu->exception_index = EXCP_IRQ;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_MICROBLAZE)
|
|
||||||
if ((interrupt_request & CPU_INTERRUPT_HARD)
|
|
||||||
&& (env->sregs[SR_MSR] & MSR_IE)
|
|
||||||
&& !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
|
|
||||||
&& !(env->iflags & (D_FLAG | IMM_FLAG))) {
|
|
||||||
cpu->exception_index = EXCP_IRQ;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_MIPS)
|
|
||||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
|
||||||
cpu_mips_hw_interrupts_pending(env)) {
|
|
||||||
/* Raise it */
|
|
||||||
cpu->exception_index = EXCP_EXT_INTERRUPT;
|
|
||||||
env->error_code = 0;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_TRICORE)
|
|
||||||
if ((interrupt_request & CPU_INTERRUPT_HARD)) {
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(TARGET_OPENRISC)
|
|
||||||
{
|
|
||||||
int idx = -1;
|
|
||||||
if ((interrupt_request & CPU_INTERRUPT_HARD)
|
|
||||||
&& (env->sr & SR_IEE)) {
|
|
||||||
idx = EXCP_INT;
|
|
||||||
}
|
|
||||||
if ((interrupt_request & CPU_INTERRUPT_TIMER)
|
|
||||||
&& (env->sr & SR_TEE)) {
|
|
||||||
idx = EXCP_TICK;
|
|
||||||
}
|
|
||||||
if (idx >= 0) {
|
|
||||||
cpu->exception_index = idx;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_SPARC)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
|
||||||
if (cpu_interrupts_enabled(env) &&
|
|
||||||
env->interrupt_index > 0) {
|
|
||||||
int pil = env->interrupt_index & 0xf;
|
|
||||||
int type = env->interrupt_index & 0xf0;
|
|
||||||
|
|
||||||
if (((type == TT_EXTINT) &&
|
|
||||||
cpu_pil_allowed(env, pil)) ||
|
|
||||||
type != TT_EXTINT) {
|
|
||||||
cpu->exception_index = env->interrupt_index;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_ARM)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_FIQ
|
|
||||||
&& !(env->daif & PSTATE_F)) {
|
|
||||||
cpu->exception_index = EXCP_FIQ;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
/* ARMv7-M interrupt return works by loading a magic value
|
|
||||||
into the PC. On real hardware the load causes the
|
|
||||||
return to occur. The qemu implementation performs the
|
|
||||||
jump normally, then does the exception return when the
|
|
||||||
CPU tries to execute code at the magic address.
|
|
||||||
This will cause the magic PC value to be pushed to
|
|
||||||
the stack if an interrupt occurred at the wrong time.
|
|
||||||
We avoid this by disabling interrupts when
|
|
||||||
pc contains a magic address. */
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
|
||||||
&& ((IS_M(env) && env->regs[15] < 0xfffffff0)
|
|
||||||
|| !(env->daif & PSTATE_I))) {
|
|
||||||
cpu->exception_index = EXCP_IRQ;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_UNICORE32)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
|
||||||
&& !(env->uncached_asr & ASR_I)) {
|
|
||||||
cpu->exception_index = UC32_EXCP_INTR;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_SH4)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_ALPHA)
|
|
||||||
{
|
|
||||||
int idx = -1;
|
|
||||||
/* ??? This hard-codes the OSF/1 interrupt levels. */
|
|
||||||
switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
|
|
||||||
case 0 ... 3:
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
|
||||||
idx = EXCP_DEV_INTERRUPT;
|
|
||||||
}
|
|
||||||
/* FALLTHRU */
|
|
||||||
case 4:
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_TIMER) {
|
|
||||||
idx = EXCP_CLK_INTERRUPT;
|
|
||||||
}
|
|
||||||
/* FALLTHRU */
|
|
||||||
case 5:
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_SMP) {
|
|
||||||
idx = EXCP_SMP_INTERRUPT;
|
|
||||||
}
|
|
||||||
/* FALLTHRU */
|
|
||||||
case 6:
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_MCHK) {
|
|
||||||
idx = EXCP_MCHK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (idx >= 0) {
|
|
||||||
cpu->exception_index = idx;
|
|
||||||
env->error_code = 0;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_CRIS)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
|
||||||
&& (env->pregs[PR_CCS] & I_FLAG)
|
|
||||||
&& !env->locked_irq) {
|
|
||||||
cpu->exception_index = EXCP_IRQ;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_NMI) {
|
|
||||||
unsigned int m_flag_archval;
|
|
||||||
if (env->pregs[PR_VR] < 32) {
|
|
||||||
m_flag_archval = M_FLAG_V10;
|
|
||||||
} else {
|
|
||||||
m_flag_archval = M_FLAG_V32;
|
|
||||||
}
|
|
||||||
if ((env->pregs[PR_CCS] & m_flag_archval)) {
|
|
||||||
cpu->exception_index = EXCP_NMI;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_M68K)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
|
||||||
&& ((env->sr & SR_I) >> SR_I_SHIFT)
|
|
||||||
< env->pending_level) {
|
|
||||||
/* Real hardware gets the interrupt vector via an
|
|
||||||
IACK cycle at this point. Current emulated
|
|
||||||
hardware doesn't rely on this, so we
|
|
||||||
provide/save the vector when the interrupt is
|
|
||||||
first signalled. */
|
|
||||||
cpu->exception_index = env->pending_vector;
|
|
||||||
do_interrupt_m68k_hardirq(env);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
|
|
||||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
|
||||||
(env->psw.mask & PSW_MASK_EXT)) {
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#elif defined(TARGET_XTENSA)
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
|
||||||
cpu->exception_index = EXC_IRQ;
|
|
||||||
cc->do_interrupt(cpu);
|
|
||||||
next_tb = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* Don't use the cached interrupt_request value,
|
|
||||||
do_interrupt may have updated the EXITTB flag. */
|
|
||||||
if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) {
|
if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
||||||
/* ensure that no TB jump will be modified as
|
/* ensure that no TB jump will be modified as
|
||||||
@@ -822,10 +536,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
* local variables as longjmp is marked 'noreturn'. */
|
* local variables as longjmp is marked 'noreturn'. */
|
||||||
cpu = current_cpu;
|
cpu = current_cpu;
|
||||||
env = cpu->env_ptr;
|
env = cpu->env_ptr;
|
||||||
#if !(defined(CONFIG_USER_ONLY) && \
|
|
||||||
(defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
|
|
||||||
cc = CPU_GET_CLASS(cpu);
|
cc = CPU_GET_CLASS(cpu);
|
||||||
#endif
|
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
x86_cpu = X86_CPU(cpu);
|
x86_cpu = X86_CPU(cpu);
|
||||||
#endif
|
#endif
|
||||||
@@ -836,36 +547,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
}
|
}
|
||||||
} /* for(;;) */
|
} /* for(;;) */
|
||||||
|
|
||||||
|
cc->cpu_exec_exit(cpu);
|
||||||
#if defined(TARGET_I386)
|
|
||||||
/* restore flags in standard format */
|
|
||||||
env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
|
|
||||||
| (env->df & DF_MASK);
|
|
||||||
#elif defined(TARGET_ARM)
|
|
||||||
/* XXX: Save/restore host fpu exception state?. */
|
|
||||||
#elif defined(TARGET_UNICORE32)
|
|
||||||
#elif defined(TARGET_SPARC)
|
|
||||||
#elif defined(TARGET_PPC)
|
|
||||||
#elif defined(TARGET_LM32)
|
|
||||||
#elif defined(TARGET_M68K)
|
|
||||||
cpu_m68k_flush_flags(env, env->cc_op);
|
|
||||||
env->cc_op = CC_OP_FLAGS;
|
|
||||||
env->sr = (env->sr & 0xffe0)
|
|
||||||
| env->cc_dest | (env->cc_x << 4);
|
|
||||||
#elif defined(TARGET_MICROBLAZE)
|
|
||||||
#elif defined(TARGET_MIPS)
|
|
||||||
#elif defined(TARGET_TRICORE)
|
|
||||||
#elif defined(TARGET_MOXIE)
|
|
||||||
#elif defined(TARGET_OPENRISC)
|
|
||||||
#elif defined(TARGET_SH4)
|
|
||||||
#elif defined(TARGET_ALPHA)
|
|
||||||
#elif defined(TARGET_CRIS)
|
|
||||||
#elif defined(TARGET_S390X)
|
|
||||||
#elif defined(TARGET_XTENSA)
|
|
||||||
/* XXXXX */
|
|
||||||
#else
|
|
||||||
#error unsupported target CPU
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* fail safe : never use current_cpu outside cpu_exec() */
|
/* fail safe : never use current_cpu outside cpu_exec() */
|
||||||
current_cpu = NULL;
|
current_cpu = NULL;
|
||||||
|
|||||||
17
cpus.c
17
cpus.c
@@ -493,13 +493,17 @@ static const VMStateDescription vmstate_timers = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void cpu_ticks_init(void)
|
||||||
|
{
|
||||||
|
seqlock_init(&timers_state.vm_clock_seqlock, NULL);
|
||||||
|
vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
|
||||||
|
}
|
||||||
|
|
||||||
void configure_icount(QemuOpts *opts, Error **errp)
|
void configure_icount(QemuOpts *opts, Error **errp)
|
||||||
{
|
{
|
||||||
const char *option;
|
const char *option;
|
||||||
char *rem_str = NULL;
|
char *rem_str = NULL;
|
||||||
|
|
||||||
seqlock_init(&timers_state.vm_clock_seqlock, NULL);
|
|
||||||
vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
|
|
||||||
option = qemu_opt_get(opts, "shift");
|
option = qemu_opt_get(opts, "shift");
|
||||||
if (!option) {
|
if (!option) {
|
||||||
if (qemu_opt_get(opts, "align") != NULL) {
|
if (qemu_opt_get(opts, "align") != NULL) {
|
||||||
@@ -589,6 +593,15 @@ void cpu_synchronize_all_post_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_clean_all_dirty(void)
|
||||||
|
{
|
||||||
|
CPUState *cpu;
|
||||||
|
|
||||||
|
CPU_FOREACH(cpu) {
|
||||||
|
cpu_clean_state(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int do_vm_stop(RunState state)
|
static int do_vm_stop(RunState state)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ typedef struct {
|
|||||||
QEMUSGList *sg;
|
QEMUSGList *sg;
|
||||||
uint64_t sector_num;
|
uint64_t sector_num;
|
||||||
DMADirection dir;
|
DMADirection dir;
|
||||||
bool in_cancel;
|
|
||||||
int sg_cur_index;
|
int sg_cur_index;
|
||||||
dma_addr_t sg_cur_byte;
|
dma_addr_t sg_cur_byte;
|
||||||
QEMUIOVector iov;
|
QEMUIOVector iov;
|
||||||
@@ -125,12 +124,7 @@ static void dma_complete(DMAAIOCB *dbs, int ret)
|
|||||||
qemu_bh_delete(dbs->bh);
|
qemu_bh_delete(dbs->bh);
|
||||||
dbs->bh = NULL;
|
dbs->bh = NULL;
|
||||||
}
|
}
|
||||||
if (!dbs->in_cancel) {
|
qemu_aio_unref(dbs);
|
||||||
/* Requests may complete while dma_aio_cancel is in progress. In
|
|
||||||
* this case, the AIOCB should not be released because it is still
|
|
||||||
* referenced by dma_aio_cancel. */
|
|
||||||
qemu_aio_release(dbs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dma_bdrv_cb(void *opaque, int ret)
|
static void dma_bdrv_cb(void *opaque, int ret)
|
||||||
@@ -186,19 +180,14 @@ static void dma_aio_cancel(BlockDriverAIOCB *acb)
|
|||||||
trace_dma_aio_cancel(dbs);
|
trace_dma_aio_cancel(dbs);
|
||||||
|
|
||||||
if (dbs->acb) {
|
if (dbs->acb) {
|
||||||
BlockDriverAIOCB *acb = dbs->acb;
|
bdrv_aio_cancel_async(dbs->acb);
|
||||||
dbs->acb = NULL;
|
|
||||||
dbs->in_cancel = true;
|
|
||||||
bdrv_aio_cancel(acb);
|
|
||||||
dbs->in_cancel = false;
|
|
||||||
}
|
}
|
||||||
dbs->common.cb = NULL;
|
|
||||||
dma_complete(dbs, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const AIOCBInfo dma_aiocb_info = {
|
static const AIOCBInfo dma_aiocb_info = {
|
||||||
.aiocb_size = sizeof(DMAAIOCB),
|
.aiocb_size = sizeof(DMAAIOCB),
|
||||||
.cancel = dma_aio_cancel,
|
.cancel_async = dma_aio_cancel,
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDriverAIOCB *dma_bdrv_io(
|
BlockDriverAIOCB *dma_bdrv_io(
|
||||||
@@ -217,7 +206,6 @@ BlockDriverAIOCB *dma_bdrv_io(
|
|||||||
dbs->sg_cur_index = 0;
|
dbs->sg_cur_index = 0;
|
||||||
dbs->sg_cur_byte = 0;
|
dbs->sg_cur_byte = 0;
|
||||||
dbs->dir = dir;
|
dbs->dir = dir;
|
||||||
dbs->in_cancel = false;
|
|
||||||
dbs->io_func = io_func;
|
dbs->io_func = io_func;
|
||||||
dbs->bh = NULL;
|
dbs->bh = NULL;
|
||||||
qemu_iovec_init(&dbs->iov, sg->nsg);
|
qemu_iovec_init(&dbs->iov, sg->nsg);
|
||||||
@@ -277,5 +265,5 @@ uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg)
|
|||||||
void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
|
void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
|
||||||
QEMUSGList *sg, enum BlockAcctType type)
|
QEMUSGList *sg, enum BlockAcctType type)
|
||||||
{
|
{
|
||||||
bdrv_acct_start(bs, cookie, sg->size, type);
|
block_acct_start(bdrv_get_stats(bs), cookie, sg->size, type);
|
||||||
}
|
}
|
||||||
|
|||||||
161
docs/blkdebug.txt
Normal file
161
docs/blkdebug.txt
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
Block I/O error injection using blkdebug
|
||||||
|
----------------------------------------
|
||||||
|
Copyright (C) 2014 Red Hat Inc
|
||||||
|
|
||||||
|
This work is licensed under the terms of the GNU GPL, version 2 or later. See
|
||||||
|
the COPYING file in the top-level directory.
|
||||||
|
|
||||||
|
The blkdebug block driver is a rule-based error injection engine. It can be
|
||||||
|
used to exercise error code paths in block drivers including ENOSPC (out of
|
||||||
|
space) and EIO.
|
||||||
|
|
||||||
|
This document gives an overview of the features available in blkdebug.
|
||||||
|
|
||||||
|
Background
|
||||||
|
----------
|
||||||
|
Block drivers have many error code paths that handle I/O errors. Image formats
|
||||||
|
are especially complex since metadata I/O errors during cluster allocation or
|
||||||
|
while updating tables happen halfway through request processing and require
|
||||||
|
discipline to keep image files consistent.
|
||||||
|
|
||||||
|
Error injection allows test cases to trigger I/O errors at specific points.
|
||||||
|
This way, all error paths can be tested to make sure they are correct.
|
||||||
|
|
||||||
|
Rules
|
||||||
|
-----
|
||||||
|
The blkdebug block driver takes a list of "rules" that tell the error injection
|
||||||
|
engine when to fail an I/O request.
|
||||||
|
|
||||||
|
Each I/O request is evaluated against the rules. If a rule matches the request
|
||||||
|
then its "action" is executed.
|
||||||
|
|
||||||
|
Rules can be placed in a configuration file; the configuration file
|
||||||
|
follows the same .ini-like format used by QEMU's -readconfig option, and
|
||||||
|
each section of the file represents a rule.
|
||||||
|
|
||||||
|
The following configuration file defines a single rule:
|
||||||
|
|
||||||
|
$ cat blkdebug.conf
|
||||||
|
[inject-error]
|
||||||
|
event = "read_aio"
|
||||||
|
errno = "28"
|
||||||
|
|
||||||
|
This rule fails all aio read requests with ENOSPC (28). Note that the errno
|
||||||
|
value depends on the host. On Linux, see
|
||||||
|
/usr/include/asm-generic/errno-base.h for errno values.
|
||||||
|
|
||||||
|
Invoke QEMU as follows:
|
||||||
|
|
||||||
|
$ qemu-system-x86_64
|
||||||
|
-drive if=none,cache=none,file=blkdebug:blkdebug.conf:test.img,id=drive0 \
|
||||||
|
-device virtio-blk-pci,drive=drive0,id=virtio-blk-pci0
|
||||||
|
|
||||||
|
Rules support the following attributes:
|
||||||
|
|
||||||
|
event - which type of operation to match (e.g. read_aio, write_aio,
|
||||||
|
flush_to_os, flush_to_disk). See the "Events" section for
|
||||||
|
information on events.
|
||||||
|
|
||||||
|
state - (optional) the engine must be in this state number in order for this
|
||||||
|
rule to match. See the "State transitions" section for information
|
||||||
|
on states.
|
||||||
|
|
||||||
|
errno - the numeric errno value to return when a request matches this rule.
|
||||||
|
The errno values depend on the host since the numeric values are not
|
||||||
|
standarized in the POSIX specification.
|
||||||
|
|
||||||
|
sector - (optional) a sector number that the request must overlap in order to
|
||||||
|
match this rule
|
||||||
|
|
||||||
|
once - (optional, default "off") only execute this action on the first
|
||||||
|
matching request
|
||||||
|
|
||||||
|
immediately - (optional, default "off") return a NULL BlockDriverAIOCB
|
||||||
|
pointer and fail without an errno instead. This exercises the
|
||||||
|
code path where BlockDriverAIOCB fails and the caller's
|
||||||
|
BlockDriverCompletionFunc is not invoked.
|
||||||
|
|
||||||
|
Events
|
||||||
|
------
|
||||||
|
Block drivers provide information about the type of I/O request they are about
|
||||||
|
to make so rules can match specific types of requests. For example, the qcow2
|
||||||
|
block driver tells blkdebug when it accesses the L1 table so rules can match
|
||||||
|
only L1 table accesses and not other metadata or guest data requests.
|
||||||
|
|
||||||
|
The core events are:
|
||||||
|
|
||||||
|
read_aio - guest data read
|
||||||
|
|
||||||
|
write_aio - guest data write
|
||||||
|
|
||||||
|
flush_to_os - write out unwritten block driver state (e.g. cached metadata)
|
||||||
|
|
||||||
|
flush_to_disk - flush the host block device's disk cache
|
||||||
|
|
||||||
|
See block/blkdebug.c:event_names[] for the full list of events. You may need
|
||||||
|
to grep block driver source code to understand the meaning of specific events.
|
||||||
|
|
||||||
|
State transitions
|
||||||
|
-----------------
|
||||||
|
There are cases where more power is needed to match a particular I/O request in
|
||||||
|
a longer sequence of requests. For example:
|
||||||
|
|
||||||
|
write_aio
|
||||||
|
flush_to_disk
|
||||||
|
write_aio
|
||||||
|
|
||||||
|
How do we match the 2nd write_aio but not the first? This is where state
|
||||||
|
transitions come in.
|
||||||
|
|
||||||
|
The error injection engine has an integer called the "state" that always starts
|
||||||
|
initialized to 1. The state integer is internal to blkdebug and cannot be
|
||||||
|
observed from outside but rules can interact with it for powerful matching
|
||||||
|
behavior.
|
||||||
|
|
||||||
|
Rules can be conditional on the current state and they can transition to a new
|
||||||
|
state.
|
||||||
|
|
||||||
|
When a rule's "state" attribute is non-zero then the current state must equal
|
||||||
|
the attribute in order for the rule to match.
|
||||||
|
|
||||||
|
For example, to match the 2nd write_aio:
|
||||||
|
|
||||||
|
[set-state]
|
||||||
|
event = "write_aio"
|
||||||
|
state = "1"
|
||||||
|
new_state = "2"
|
||||||
|
|
||||||
|
[inject-error]
|
||||||
|
event = "write_aio"
|
||||||
|
state = "2"
|
||||||
|
errno = "5"
|
||||||
|
|
||||||
|
The first write_aio request matches the set-state rule and transitions from
|
||||||
|
state 1 to state 2. Once state 2 has been entered, the set-state rule no
|
||||||
|
longer matches since it requires state 1. But the inject-error rule now
|
||||||
|
matches the next write_aio request and injects EIO (5).
|
||||||
|
|
||||||
|
State transition rules support the following attributes:
|
||||||
|
|
||||||
|
event - which type of operation to match (e.g. read_aio, write_aio,
|
||||||
|
flush_to_os, flush_to_disk). See the "Events" section for
|
||||||
|
information on events.
|
||||||
|
|
||||||
|
state - (optional) the engine must be in this state number in order for this
|
||||||
|
rule to match
|
||||||
|
|
||||||
|
new_state - transition to this state number
|
||||||
|
|
||||||
|
Suspend and resume
|
||||||
|
------------------
|
||||||
|
Exercising code paths in block drivers may require specific ordering amongst
|
||||||
|
concurrent requests. The "breakpoint" feature allows requests to be halted on
|
||||||
|
a blkdebug event and resumed later. This makes it possible to achieve
|
||||||
|
deterministic ordering when multiple requests are in flight.
|
||||||
|
|
||||||
|
Breakpoints on blkdebug events are associated with a user-defined "tag" string.
|
||||||
|
This tag serves as an identifier by which the request can be resumed at a later
|
||||||
|
point.
|
||||||
|
|
||||||
|
See the qemu-io(1) break, resume, remove_break, and wait_break commands for
|
||||||
|
details.
|
||||||
@@ -125,7 +125,8 @@ If a fuzzer configuration is specified, then it has the next interpretation:
|
|||||||
will be always fuzzed for every test. This case is useful for regression
|
will be always fuzzed for every test. This case is useful for regression
|
||||||
testing.
|
testing.
|
||||||
|
|
||||||
For now only header fields, header extensions and L1/L2 tables are generated.
|
The generator can create header fields, header extensions, L1/L2 tables and
|
||||||
|
refcount table and blocks.
|
||||||
|
|
||||||
Module interfaces
|
Module interfaces
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
= How to use the QAPI code generator =
|
= How to use the QAPI code generator =
|
||||||
|
|
||||||
* Note: as of this writing, QMP does not use QAPI. Eventually QMP
|
|
||||||
commands will be converted to use QAPI internally. The following
|
|
||||||
information describes QMP/QAPI as it will exist after the
|
|
||||||
conversion.
|
|
||||||
|
|
||||||
QAPI is a native C API within QEMU which provides management-level
|
QAPI is a native C API within QEMU which provides management-level
|
||||||
functionality to internal/external users. For external
|
functionality to internal/external users. For external
|
||||||
users/processes, this interface is made available by a JSON-based
|
users/processes, this interface is made available by a JSON-based
|
||||||
@@ -19,7 +14,7 @@ marshaling/dispatch code for the guest agent server running in the
|
|||||||
guest.
|
guest.
|
||||||
|
|
||||||
This document will describe how the schemas, scripts, and resulting
|
This document will describe how the schemas, scripts, and resulting
|
||||||
code is used.
|
code are used.
|
||||||
|
|
||||||
|
|
||||||
== QMP/Guest agent schema ==
|
== QMP/Guest agent schema ==
|
||||||
@@ -234,6 +229,7 @@ Resulting in this JSON object:
|
|||||||
"data": { "b": "test string" },
|
"data": { "b": "test string" },
|
||||||
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
|
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
|
||||||
|
|
||||||
|
|
||||||
== Code generation ==
|
== Code generation ==
|
||||||
|
|
||||||
Schemas are fed into 3 scripts to generate all the code/files that, paired
|
Schemas are fed into 3 scripts to generate all the code/files that, paired
|
||||||
@@ -256,6 +252,8 @@ command which takes that type as a parameter and returns the same type:
|
|||||||
'data': {'arg1': 'UserDefOne'},
|
'data': {'arg1': 'UserDefOne'},
|
||||||
'returns': 'UserDefOne' }
|
'returns': 'UserDefOne' }
|
||||||
|
|
||||||
|
{ 'event': 'MY_EVENT' }
|
||||||
|
|
||||||
=== scripts/qapi-types.py ===
|
=== scripts/qapi-types.py ===
|
||||||
|
|
||||||
Used to generate the C types defined by a schema. The following files are
|
Used to generate the C types defined by a schema. The following files are
|
||||||
@@ -277,7 +275,7 @@ Example:
|
|||||||
$ cat qapi-generated/example-qapi-types.c
|
$ cat qapi-generated/example-qapi-types.c
|
||||||
[Uninteresting stuff omitted...]
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
void qapi_free_UserDefOneList(UserDefOneList * obj)
|
void qapi_free_UserDefOneList(UserDefOneList *obj)
|
||||||
{
|
{
|
||||||
QapiDeallocVisitor *md;
|
QapiDeallocVisitor *md;
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
@@ -292,7 +290,7 @@ Example:
|
|||||||
qapi_dealloc_visitor_cleanup(md);
|
qapi_dealloc_visitor_cleanup(md);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qapi_free_UserDefOne(UserDefOne * obj)
|
void qapi_free_UserDefOne(UserDefOne *obj)
|
||||||
{
|
{
|
||||||
QapiDeallocVisitor *md;
|
QapiDeallocVisitor *md;
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
@@ -331,11 +329,11 @@ Example:
|
|||||||
struct UserDefOne
|
struct UserDefOne
|
||||||
{
|
{
|
||||||
int64_t integer;
|
int64_t integer;
|
||||||
char * string;
|
char *string;
|
||||||
};
|
};
|
||||||
|
|
||||||
void qapi_free_UserDefOneList(UserDefOneList * obj);
|
void qapi_free_UserDefOneList(UserDefOneList *obj);
|
||||||
void qapi_free_UserDefOne(UserDefOne * obj);
|
void qapi_free_UserDefOne(UserDefOne *obj);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -364,7 +362,7 @@ Example:
|
|||||||
$ cat qapi-generated/example-qapi-visit.c
|
$ cat qapi-generated/example-qapi-visit.c
|
||||||
[Uninteresting stuff omitted...]
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
|
static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne **obj, Error **errp)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
visit_type_int(m, &(*obj)->integer, "integer", &err);
|
visit_type_int(m, &(*obj)->integer, "integer", &err);
|
||||||
@@ -380,7 +378,7 @@ Example:
|
|||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
|
void visit_type_UserDefOne(Visitor *m, UserDefOne **obj, const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
@@ -394,7 +392,7 @@ Example:
|
|||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
|
void visit_type_UserDefOneList(Visitor *m, UserDefOneList **obj, const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
GenericList *i, **prev;
|
GenericList *i, **prev;
|
||||||
@@ -427,8 +425,8 @@ Example:
|
|||||||
|
|
||||||
[Visitors for builtin types omitted...]
|
[Visitors for builtin types omitted...]
|
||||||
|
|
||||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
|
void visit_type_UserDefOne(Visitor *m, UserDefOne **obj, const char *name, Error **errp);
|
||||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
|
void visit_type_UserDefOneList(Visitor *m, UserDefOneList **obj, const char *name, Error **errp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -451,10 +449,12 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
$ python scripts/qapi-commands.py --output-dir="qapi-generated"
|
||||||
|
--prefix="example-" --input-file=example-schema.json
|
||||||
$ cat qapi-generated/example-qmp-marshal.c
|
$ cat qapi-generated/example-qmp-marshal.c
|
||||||
[Uninteresting stuff omitted...]
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
|
static void qmp_marshal_output_my_command(UserDefOne *ret_in, QObject **ret_out, Error **errp)
|
||||||
{
|
{
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
||||||
@@ -480,11 +480,11 @@ Example:
|
|||||||
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
|
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
|
||||||
{
|
{
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
UserDefOne * retval = NULL;
|
UserDefOne *retval = NULL;
|
||||||
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
|
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
|
||||||
QapiDeallocVisitor *md;
|
QapiDeallocVisitor *md;
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
UserDefOne * arg1 = NULL;
|
UserDefOne *arg1 = NULL;
|
||||||
|
|
||||||
v = qmp_input_get_visitor(mi);
|
v = qmp_input_get_visitor(mi);
|
||||||
visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
|
visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
|
||||||
@@ -525,6 +525,66 @@ Example:
|
|||||||
#include "qapi/qmp/qdict.h"
|
#include "qapi/qmp/qdict.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
|
||||||
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
|
UserDefOne *qmp_my_command(UserDefOne *arg1, Error **errp);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
=== scripts/qapi-event.py ===
|
||||||
|
|
||||||
|
Used to generate the event-related C code defined by a schema. The
|
||||||
|
following files are created:
|
||||||
|
|
||||||
|
$(prefix)qapi-event.h - Function prototypes for each event type, plus an
|
||||||
|
enumeration of all event names
|
||||||
|
$(prefix)qapi-event.c - Implementation of functions to send an event
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
$ python scripts/qapi-event.py --output-dir="qapi-generated"
|
||||||
|
--prefix="example-" --input-file=example-schema.json
|
||||||
|
$ cat qapi-generated/example-qapi-event.c
|
||||||
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
|
void qapi_event_send_my_event(Error **errp)
|
||||||
|
{
|
||||||
|
QDict *qmp;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
QMPEventFuncEmit emit;
|
||||||
|
emit = qmp_event_get_func_emit();
|
||||||
|
if (!emit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmp = qmp_event_build_dict("MY_EVENT");
|
||||||
|
|
||||||
|
emit(EXAMPLE_QAPI_EVENT_MY_EVENT, qmp, &local_err);
|
||||||
|
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
QDECREF(qmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *EXAMPLE_QAPIEvent_lookup[] = {
|
||||||
|
"MY_EVENT",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
$ cat qapi-generated/example-qapi-event.h
|
||||||
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
|
#ifndef EXAMPLE_QAPI_EVENT_H
|
||||||
|
#define EXAMPLE_QAPI_EVENT_H
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qapi/qmp/qdict.h"
|
||||||
|
#include "example-qapi-types.h"
|
||||||
|
|
||||||
|
|
||||||
|
void qapi_event_send_my_event(Error **errp);
|
||||||
|
|
||||||
|
extern const char *EXAMPLE_QAPIEvent_lookup[];
|
||||||
|
typedef enum EXAMPLE_QAPIEvent
|
||||||
|
{
|
||||||
|
EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
|
||||||
|
EXAMPLE_QAPI_EVENT_MAX = 1,
|
||||||
|
} EXAMPLE_QAPIEvent;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Contents:
|
|||||||
* RDMA Migration Protocol Description
|
* RDMA Migration Protocol Description
|
||||||
* Versioning and Capabilities
|
* Versioning and Capabilities
|
||||||
* QEMUFileRDMA Interface
|
* QEMUFileRDMA Interface
|
||||||
* Migration of pc.ram
|
* Migration of VM's ram
|
||||||
* Error handling
|
* Error handling
|
||||||
* TODO
|
* TODO
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ The only difference between a SEND message and an RDMA
|
|||||||
message is that SEND messages cause notifications
|
message is that SEND messages cause notifications
|
||||||
to be posted to the completion queue (CQ) on the
|
to be posted to the completion queue (CQ) on the
|
||||||
infiniband receiver side, whereas RDMA messages (used
|
infiniband receiver side, whereas RDMA messages (used
|
||||||
for pc.ram) do not (to behave like an actual DMA).
|
for VM's ram) do not (to behave like an actual DMA).
|
||||||
|
|
||||||
Messages in infiniband require two things:
|
Messages in infiniband require two things:
|
||||||
|
|
||||||
@@ -355,7 +355,7 @@ If the buffer is empty, then we follow the same steps
|
|||||||
listed above and issue another "QEMU File" protocol command,
|
listed above and issue another "QEMU File" protocol command,
|
||||||
asking for a new SEND message to re-fill the buffer.
|
asking for a new SEND message to re-fill the buffer.
|
||||||
|
|
||||||
Migration of pc.ram:
|
Migration of VM's ram:
|
||||||
====================
|
====================
|
||||||
|
|
||||||
At the beginning of the migration, (migration-rdma.c),
|
At the beginning of the migration, (migration-rdma.c),
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ for debugging, profiling, and observing execution.
|
|||||||
|
|
||||||
4. Pretty-print the binary trace file:
|
4. Pretty-print the binary trace file:
|
||||||
|
|
||||||
./scripts/simpletrace.py trace-events trace-*
|
./scripts/simpletrace.py trace-events trace-* # Override * with QEMU <pid>
|
||||||
|
|
||||||
== Trace events ==
|
== Trace events ==
|
||||||
|
|
||||||
|
|||||||
118
exec.c
118
exec.c
@@ -572,6 +572,16 @@ void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
||||||
int flags, CPUWatchpoint **watchpoint)
|
int flags, CPUWatchpoint **watchpoint)
|
||||||
{
|
{
|
||||||
@@ -582,12 +592,10 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
|||||||
int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
||||||
int flags, CPUWatchpoint **watchpoint)
|
int flags, CPUWatchpoint **watchpoint)
|
||||||
{
|
{
|
||||||
vaddr len_mask = ~(len - 1);
|
|
||||||
CPUWatchpoint *wp;
|
CPUWatchpoint *wp;
|
||||||
|
|
||||||
/* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
|
/* forbid ranges which are empty or run off the end of the address space */
|
||||||
if ((len & (len - 1)) || (addr & ~len_mask) ||
|
if (len == 0 || (addr + len - 1) < addr) {
|
||||||
len == 0 || len > TARGET_PAGE_SIZE) {
|
|
||||||
error_report("tried to set invalid watchpoint at %"
|
error_report("tried to set invalid watchpoint at %"
|
||||||
VADDR_PRIx ", len=%" VADDR_PRIu, addr, len);
|
VADDR_PRIx ", len=%" VADDR_PRIu, addr, len);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -595,7 +603,7 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
|||||||
wp = g_malloc(sizeof(*wp));
|
wp = g_malloc(sizeof(*wp));
|
||||||
|
|
||||||
wp->vaddr = addr;
|
wp->vaddr = addr;
|
||||||
wp->len_mask = len_mask;
|
wp->len = len;
|
||||||
wp->flags = flags;
|
wp->flags = flags;
|
||||||
|
|
||||||
/* keep all GDB-injected watchpoints in front */
|
/* keep all GDB-injected watchpoints in front */
|
||||||
@@ -616,11 +624,10 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
|||||||
int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len,
|
int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
vaddr len_mask = ~(len - 1);
|
|
||||||
CPUWatchpoint *wp;
|
CPUWatchpoint *wp;
|
||||||
|
|
||||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||||
if (addr == wp->vaddr && len_mask == wp->len_mask
|
if (addr == wp->vaddr && len == wp->len
|
||||||
&& flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
|
&& flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
|
||||||
cpu_watchpoint_remove_by_ref(cpu, wp);
|
cpu_watchpoint_remove_by_ref(cpu, wp);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -650,6 +657,27 @@ void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if this watchpoint address matches the specified
|
||||||
|
* access (ie the address range covered by the watchpoint overlaps
|
||||||
|
* partially or completely with the address range covered by the
|
||||||
|
* access).
|
||||||
|
*/
|
||||||
|
static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
|
||||||
|
vaddr addr,
|
||||||
|
vaddr len)
|
||||||
|
{
|
||||||
|
/* We know the lengths are non-zero, but a little caution is
|
||||||
|
* required to avoid errors in the case where the range ends
|
||||||
|
* exactly at the top of the address space and so addr + len
|
||||||
|
* wraps round to zero.
|
||||||
|
*/
|
||||||
|
vaddr wpend = wp->vaddr + wp->len - 1;
|
||||||
|
vaddr addrend = addr + len - 1;
|
||||||
|
|
||||||
|
return !(addr > wpend || wp->vaddr > addrend);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Add a breakpoint. */
|
/* Add a breakpoint. */
|
||||||
@@ -861,7 +889,7 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
|||||||
/* Make accesses to pages with watchpoints go via the
|
/* Make accesses to pages with watchpoints go via the
|
||||||
watchpoint trap routines. */
|
watchpoint trap routines. */
|
||||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||||
if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
|
if (cpu_watchpoint_address_matches(wp, vaddr, TARGET_PAGE_SIZE)) {
|
||||||
/* Avoid trapping reads of pages with a write breakpoint. */
|
/* Avoid trapping reads of pages with a write breakpoint. */
|
||||||
if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
|
if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
|
||||||
iotlb = PHYS_SECTION_WATCH + paddr;
|
iotlb = PHYS_SECTION_WATCH + paddr;
|
||||||
@@ -1031,7 +1059,7 @@ void qemu_mutex_unlock_ramlist(void)
|
|||||||
|
|
||||||
#define HUGETLBFS_MAGIC 0x958458f6
|
#define HUGETLBFS_MAGIC 0x958458f6
|
||||||
|
|
||||||
static long gethugepagesize(const char *path)
|
static long gethugepagesize(const char *path, Error **errp)
|
||||||
{
|
{
|
||||||
struct statfs fs;
|
struct statfs fs;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1041,7 +1069,8 @@ static long gethugepagesize(const char *path)
|
|||||||
} while (ret != 0 && errno == EINTR);
|
} while (ret != 0 && errno == EINTR);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
perror(path);
|
error_setg_errno(errp, errno, "failed to get page size of file %s",
|
||||||
|
path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,17 +1088,22 @@ static void *file_ram_alloc(RAMBlock *block,
|
|||||||
char *filename;
|
char *filename;
|
||||||
char *sanitized_name;
|
char *sanitized_name;
|
||||||
char *c;
|
char *c;
|
||||||
void *area;
|
void *area = NULL;
|
||||||
int fd;
|
int fd;
|
||||||
unsigned long hpagesize;
|
uint64_t hpagesize;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
hpagesize = gethugepagesize(path);
|
hpagesize = gethugepagesize(path, &local_err);
|
||||||
if (!hpagesize) {
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memory < hpagesize) {
|
if (memory < hpagesize) {
|
||||||
return NULL;
|
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
|
||||||
|
"or larger than huge page size 0x%" PRIx64,
|
||||||
|
memory, hpagesize);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||||
@@ -1130,6 +1164,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
if (mem_prealloc) {
|
if (mem_prealloc) {
|
||||||
|
error_report("%s\n", error_get_pretty(*errp));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1259,7 +1294,7 @@ static int memory_try_enable_merging(void *addr, size_t len)
|
|||||||
return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
|
return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ram_addr_t ram_block_add(RAMBlock *new_block)
|
static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
||||||
{
|
{
|
||||||
RAMBlock *block;
|
RAMBlock *block;
|
||||||
ram_addr_t old_ram_size, new_ram_size;
|
ram_addr_t old_ram_size, new_ram_size;
|
||||||
@@ -1276,9 +1311,11 @@ static ram_addr_t ram_block_add(RAMBlock *new_block)
|
|||||||
} else {
|
} else {
|
||||||
new_block->host = phys_mem_alloc(new_block->length);
|
new_block->host = phys_mem_alloc(new_block->length);
|
||||||
if (!new_block->host) {
|
if (!new_block->host) {
|
||||||
fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
|
error_setg_errno(errp, errno,
|
||||||
memory_region_name(new_block->mr), strerror(errno));
|
"cannot set up guest memory '%s'",
|
||||||
exit(1);
|
memory_region_name(new_block->mr));
|
||||||
|
qemu_mutex_unlock_ramlist();
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
memory_try_enable_merging(new_block->host, new_block->length);
|
memory_try_enable_merging(new_block->host, new_block->length);
|
||||||
}
|
}
|
||||||
@@ -1329,6 +1366,8 @@ ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
RAMBlock *new_block;
|
RAMBlock *new_block;
|
||||||
|
ram_addr_t addr;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
if (xen_enabled()) {
|
if (xen_enabled()) {
|
||||||
error_setg(errp, "-mem-path not supported with Xen");
|
error_setg(errp, "-mem-path not supported with Xen");
|
||||||
@@ -1358,14 +1397,22 @@ ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ram_block_add(new_block);
|
addr = ram_block_add(new_block, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
g_free(new_block);
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
||||||
MemoryRegion *mr)
|
MemoryRegion *mr, Error **errp)
|
||||||
{
|
{
|
||||||
RAMBlock *new_block;
|
RAMBlock *new_block;
|
||||||
|
ram_addr_t addr;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
size = TARGET_PAGE_ALIGN(size);
|
size = TARGET_PAGE_ALIGN(size);
|
||||||
new_block = g_malloc0(sizeof(*new_block));
|
new_block = g_malloc0(sizeof(*new_block));
|
||||||
@@ -1376,12 +1423,18 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
|||||||
if (host) {
|
if (host) {
|
||||||
new_block->flags |= RAM_PREALLOC;
|
new_block->flags |= RAM_PREALLOC;
|
||||||
}
|
}
|
||||||
return ram_block_add(new_block);
|
addr = ram_block_add(new_block, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
g_free(new_block);
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr)
|
ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp)
|
||||||
{
|
{
|
||||||
return qemu_ram_alloc_from_ptr(size, NULL, mr);
|
return qemu_ram_alloc_from_ptr(size, NULL, mr, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_ram_free_from_ptr(ram_addr_t addr)
|
void qemu_ram_free_from_ptr(ram_addr_t addr)
|
||||||
@@ -1625,7 +1678,7 @@ static const MemoryRegionOps notdirty_mem_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Generate a debug exception if a watchpoint has been hit. */
|
/* Generate a debug exception if a watchpoint has been hit. */
|
||||||
static void check_watchpoint(int offset, int len_mask, int flags)
|
static void check_watchpoint(int offset, int len, int flags)
|
||||||
{
|
{
|
||||||
CPUState *cpu = current_cpu;
|
CPUState *cpu = current_cpu;
|
||||||
CPUArchState *env = cpu->env_ptr;
|
CPUArchState *env = cpu->env_ptr;
|
||||||
@@ -1643,9 +1696,14 @@ static void check_watchpoint(int offset, int len_mask, int flags)
|
|||||||
}
|
}
|
||||||
vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
|
vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
|
||||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||||
if ((vaddr == (wp->vaddr & len_mask) ||
|
if (cpu_watchpoint_address_matches(wp, vaddr, len)
|
||||||
(vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
|
&& (wp->flags & flags)) {
|
||||||
wp->flags |= BP_WATCHPOINT_HIT;
|
if (flags == BP_MEM_READ) {
|
||||||
|
wp->flags |= BP_WATCHPOINT_HIT_READ;
|
||||||
|
} else {
|
||||||
|
wp->flags |= BP_WATCHPOINT_HIT_WRITE;
|
||||||
|
}
|
||||||
|
wp->hitaddr = vaddr;
|
||||||
if (!cpu->watchpoint_hit) {
|
if (!cpu->watchpoint_hit) {
|
||||||
cpu->watchpoint_hit = wp;
|
cpu->watchpoint_hit = wp;
|
||||||
tb_check_watchpoint(cpu);
|
tb_check_watchpoint(cpu);
|
||||||
@@ -1670,7 +1728,7 @@ static void check_watchpoint(int offset, int len_mask, int flags)
|
|||||||
static uint64_t watch_mem_read(void *opaque, hwaddr addr,
|
static uint64_t watch_mem_read(void *opaque, hwaddr addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_READ);
|
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, BP_MEM_READ);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1: return ldub_phys(&address_space_memory, addr);
|
case 1: return ldub_phys(&address_space_memory, addr);
|
||||||
case 2: return lduw_phys(&address_space_memory, addr);
|
case 2: return lduw_phys(&address_space_memory, addr);
|
||||||
@@ -1682,7 +1740,7 @@ static uint64_t watch_mem_read(void *opaque, hwaddr addr,
|
|||||||
static void watch_mem_write(void *opaque, hwaddr addr,
|
static void watch_mem_write(void *opaque, hwaddr addr,
|
||||||
uint64_t val, unsigned size)
|
uint64_t val, unsigned size)
|
||||||
{
|
{
|
||||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_WRITE);
|
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, BP_MEM_WRITE);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
stb_phys(&address_space_memory, addr, val);
|
stb_phys(&address_space_memory, addr, val);
|
||||||
|
|||||||
@@ -1707,7 +1707,7 @@ int gdbserver_start(const char *device)
|
|||||||
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
|
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
|
||||||
|
|
||||||
/* Initialize a monitor terminal for gdb */
|
/* Initialize a monitor terminal for gdb */
|
||||||
mon_chr = g_malloc0(sizeof(*mon_chr));
|
mon_chr = qemu_chr_alloc();
|
||||||
mon_chr->chr_write = gdb_monitor_write;
|
mon_chr->chr_write = gdb_monitor_write;
|
||||||
monitor_init(mon_chr, 0);
|
monitor_init(mon_chr, 0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1778,6 +1778,8 @@ show qdev device model list
|
|||||||
show roms
|
show roms
|
||||||
@item info tpm
|
@item info tpm
|
||||||
show the TPM device
|
show the TPM device
|
||||||
|
@item info memory-devices
|
||||||
|
show the memory devices
|
||||||
@end table
|
@end table
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
|
|||||||
40
hmp.c
40
hmp.c
@@ -679,6 +679,8 @@ void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
list = list->next;
|
list = list->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qapi_free_BlockJobInfoList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_info_tpm(Monitor *mon, const QDict *qdict)
|
void hmp_info_tpm(Monitor *mon, const QDict *qdict)
|
||||||
@@ -1718,3 +1720,41 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
|
|||||||
|
|
||||||
qapi_free_MemdevList(memdev_list);
|
qapi_free_MemdevList(memdev_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err);
|
||||||
|
MemoryDeviceInfoList *info;
|
||||||
|
MemoryDeviceInfo *value;
|
||||||
|
PCDIMMDeviceInfo *di;
|
||||||
|
|
||||||
|
for (info = info_list; info; info = info->next) {
|
||||||
|
value = info->value;
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
switch (value->kind) {
|
||||||
|
case MEMORY_DEVICE_INFO_KIND_DIMM:
|
||||||
|
di = value->dimm;
|
||||||
|
|
||||||
|
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
||||||
|
MemoryDeviceInfoKind_lookup[value->kind],
|
||||||
|
di->id ? di->id : "");
|
||||||
|
monitor_printf(mon, " addr: 0x%" PRIx64 "\n", di->addr);
|
||||||
|
monitor_printf(mon, " slot: %" PRId64 "\n", di->slot);
|
||||||
|
monitor_printf(mon, " node: %" PRId64 "\n", di->node);
|
||||||
|
monitor_printf(mon, " size: %" PRIu64 "\n", di->size);
|
||||||
|
monitor_printf(mon, " memdev: %s\n", di->memdev);
|
||||||
|
monitor_printf(mon, " hotplugged: %s\n",
|
||||||
|
di->hotplugged ? "true" : "false");
|
||||||
|
monitor_printf(mon, " hotpluggable: %s\n",
|
||||||
|
di->hotpluggable ? "true" : "false");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qapi_free_MemoryDeviceInfoList(info_list);
|
||||||
|
}
|
||||||
|
|||||||
1
hmp.h
1
hmp.h
@@ -94,6 +94,7 @@ void hmp_cpu_add(Monitor *mon, const QDict *qdict);
|
|||||||
void hmp_object_add(Monitor *mon, const QDict *qdict);
|
void hmp_object_add(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_info_memdev(Monitor *mon, const QDict *qdict);
|
void hmp_info_memdev(Monitor *mon, const QDict *qdict);
|
||||||
|
void hmp_info_memory_devices(Monitor *mon, const QDict *qdict);
|
||||||
void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
|||||||
@@ -844,7 +844,8 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
|
|||||||
|
|
||||||
/* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
|
/* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
|
||||||
but the address space hole reserved at this point is 8TB. */
|
but the address space hole reserved at this point is 8TB. */
|
||||||
memory_region_init_ram(&s->ram_region, OBJECT(s), "ram", ram_size);
|
memory_region_init_ram(&s->ram_region, OBJECT(s), "ram", ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->ram_region);
|
vmstate_register_ram_global(&s->ram_region);
|
||||||
memory_region_add_subregion(addr_space, 0, &s->ram_region);
|
memory_region_add_subregion(addr_space, 0, &s->ram_region);
|
||||||
|
|
||||||
|
|||||||
@@ -210,11 +210,12 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Flash programming is done via the SCU, so pretend it is ROM. */
|
/* Flash programming is done via the SCU, so pretend it is ROM. */
|
||||||
memory_region_init_ram(flash, NULL, "armv7m.flash", flash_size);
|
memory_region_init_ram(flash, NULL, "armv7m.flash", flash_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(flash);
|
vmstate_register_ram_global(flash);
|
||||||
memory_region_set_readonly(flash, true);
|
memory_region_set_readonly(flash, true);
|
||||||
memory_region_add_subregion(system_memory, 0, flash);
|
memory_region_add_subregion(system_memory, 0, flash);
|
||||||
memory_region_init_ram(sram, NULL, "armv7m.sram", sram_size);
|
memory_region_init_ram(sram, NULL, "armv7m.sram", sram_size, &error_abort);
|
||||||
vmstate_register_ram_global(sram);
|
vmstate_register_ram_global(sram);
|
||||||
memory_region_add_subregion(system_memory, 0x20000000, sram);
|
memory_region_add_subregion(system_memory, 0x20000000, sram);
|
||||||
armv7m_bitband_init();
|
armv7m_bitband_init();
|
||||||
@@ -255,7 +256,7 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory,
|
|||||||
/* Hack to map an additional page of ram at the top of the address
|
/* Hack to map an additional page of ram at the top of the address
|
||||||
space. This stops qemu complaining about executing code outside RAM
|
space. This stops qemu complaining about executing code outside RAM
|
||||||
when returning from an exception. */
|
when returning from an exception. */
|
||||||
memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000);
|
memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_abort);
|
||||||
vmstate_register_ram_global(hack);
|
vmstate_register_ram_global(hack);
|
||||||
memory_region_add_subregion(system_memory, 0xfffff000, hack);
|
memory_region_add_subregion(system_memory, 0xfffff000, hack);
|
||||||
|
|
||||||
|
|||||||
@@ -312,7 +312,26 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
|
/**
|
||||||
|
* load_dtb() - load a device tree binary image into memory
|
||||||
|
* @addr: the address to load the image at
|
||||||
|
* @binfo: struct describing the boot environment
|
||||||
|
* @addr_limit: upper limit of the available memory area at @addr
|
||||||
|
*
|
||||||
|
* Load a device tree supplied by the machine or by the user with the
|
||||||
|
* '-dtb' command line option, and put it at offset @addr in target
|
||||||
|
* memory.
|
||||||
|
*
|
||||||
|
* If @addr_limit contains a meaningful value (i.e., it is strictly greater
|
||||||
|
* than @addr), the device tree is only loaded if its size does not exceed
|
||||||
|
* the limit.
|
||||||
|
*
|
||||||
|
* Returns: the size of the device tree image on success,
|
||||||
|
* 0 if the image size exceeds the limit,
|
||||||
|
* -1 on errors.
|
||||||
|
*/
|
||||||
|
static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
||||||
|
hwaddr addr_limit)
|
||||||
{
|
{
|
||||||
void *fdt = NULL;
|
void *fdt = NULL;
|
||||||
int size, rc;
|
int size, rc;
|
||||||
@@ -341,6 +360,15 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addr_limit > addr && size > (addr_limit - addr)) {
|
||||||
|
/* Installing the device tree blob at addr would exceed addr_limit.
|
||||||
|
* Whether this constitutes failure is up to the caller to decide,
|
||||||
|
* so just return 0 as size, i.e., no error.
|
||||||
|
*/
|
||||||
|
g_free(fdt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells");
|
acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells");
|
||||||
scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells");
|
scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells");
|
||||||
if (acells == 0 || scells == 0) {
|
if (acells == 0 || scells == 0) {
|
||||||
@@ -396,11 +424,14 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
|
|||||||
|
|
||||||
qemu_fdt_dumpdtb(fdt, size);
|
qemu_fdt_dumpdtb(fdt, size);
|
||||||
|
|
||||||
cpu_physical_memory_write(addr, fdt, size);
|
/* Put the DTB into the memory map as a ROM image: this will ensure
|
||||||
|
* the DTB is copied again upon reset, even if addr points into RAM.
|
||||||
|
*/
|
||||||
|
rom_add_blob_fixed("dtb", fdt, size, addr);
|
||||||
|
|
||||||
g_free(fdt);
|
g_free(fdt);
|
||||||
|
|
||||||
return 0;
|
return size;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
g_free(fdt);
|
g_free(fdt);
|
||||||
@@ -451,7 +482,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
int kernel_size;
|
int kernel_size;
|
||||||
int initrd_size;
|
int initrd_size;
|
||||||
int is_linux = 0;
|
int is_linux = 0;
|
||||||
uint64_t elf_entry;
|
uint64_t elf_entry, elf_low_addr, elf_high_addr;
|
||||||
int elf_machine;
|
int elf_machine;
|
||||||
hwaddr entry, kernel_load_offset;
|
hwaddr entry, kernel_load_offset;
|
||||||
int big_endian;
|
int big_endian;
|
||||||
@@ -459,6 +490,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
|
|
||||||
/* Load the kernel. */
|
/* Load the kernel. */
|
||||||
if (!info->kernel_filename) {
|
if (!info->kernel_filename) {
|
||||||
|
|
||||||
|
if (have_dtb(info)) {
|
||||||
|
/* If we have a device tree blob, but no kernel to supply it to,
|
||||||
|
* copy it to the base of RAM for a bootloader to pick up.
|
||||||
|
*/
|
||||||
|
if (load_dtb(info->loader_start, info, 0) < 0) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If no kernel specified, do nothing; we will start from address 0
|
/* If no kernel specified, do nothing; we will start from address 0
|
||||||
* (typically a boot ROM image) in the same way as hardware.
|
* (typically a boot ROM image) in the same way as hardware.
|
||||||
*/
|
*/
|
||||||
@@ -508,7 +549,25 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
|
|
||||||
/* Assume that raw images are linux kernels, and ELF images are not. */
|
/* Assume that raw images are linux kernels, and ELF images are not. */
|
||||||
kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
|
kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
|
||||||
NULL, NULL, big_endian, elf_machine, 1);
|
&elf_low_addr, &elf_high_addr, big_endian,
|
||||||
|
elf_machine, 1);
|
||||||
|
if (kernel_size > 0 && have_dtb(info)) {
|
||||||
|
/* If there is still some room left at the base of RAM, try and put
|
||||||
|
* the DTB there like we do for images loaded with -bios or -pflash.
|
||||||
|
*/
|
||||||
|
if (elf_low_addr > info->loader_start
|
||||||
|
|| elf_high_addr < info->loader_start) {
|
||||||
|
/* Pass elf_low_addr as address limit to load_dtb if it may be
|
||||||
|
* pointing into RAM, otherwise pass '0' (no limit)
|
||||||
|
*/
|
||||||
|
if (elf_low_addr < info->loader_start) {
|
||||||
|
elf_low_addr = 0;
|
||||||
|
}
|
||||||
|
if (load_dtb(info->loader_start, info, elf_low_addr) < 0) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
entry = elf_entry;
|
entry = elf_entry;
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
|
kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
|
||||||
@@ -569,7 +628,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
*/
|
*/
|
||||||
hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size,
|
hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size,
|
||||||
4096);
|
4096);
|
||||||
if (load_dtb(dtb_start, info)) {
|
if (load_dtb(dtb_start, info, 0) < 0) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fixupcontext[FIXUP_ARGPTR] = dtb_start;
|
fixupcontext[FIXUP_ARGPTR] = dtb_start;
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ static void cubieboard_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram",
|
memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram",
|
||||||
machine->ram_size);
|
machine->ram_size, &error_abort);
|
||||||
vmstate_register_ram_global(&s->sdram);
|
vmstate_register_ram_global(&s->sdram);
|
||||||
memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE,
|
memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE,
|
||||||
&s->sdram);
|
&s->sdram);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ typedef struct DigicBoard {
|
|||||||
|
|
||||||
static void digic4_board_setup_ram(DigicBoardState *s, hwaddr ram_size)
|
static void digic4_board_setup_ram(DigicBoardState *s, hwaddr ram_size)
|
||||||
{
|
{
|
||||||
memory_region_init_ram(&s->ram, NULL, "ram", ram_size);
|
memory_region_init_ram(&s->ram, NULL, "ram", ram_size, &error_abort);
|
||||||
memory_region_add_subregion(get_system_memory(), 0, &s->ram);
|
memory_region_add_subregion(get_system_memory(), 0, &s->ram);
|
||||||
vmstate_register_ram_global(&s->ram);
|
vmstate_register_ram_global(&s->ram);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
|||||||
|
|
||||||
/* Internal ROM */
|
/* Internal ROM */
|
||||||
memory_region_init_ram(&s->irom_mem, NULL, "exynos4210.irom",
|
memory_region_init_ram(&s->irom_mem, NULL, "exynos4210.irom",
|
||||||
EXYNOS4210_IROM_SIZE);
|
EXYNOS4210_IROM_SIZE, &error_abort);
|
||||||
vmstate_register_ram_global(&s->irom_mem);
|
vmstate_register_ram_global(&s->irom_mem);
|
||||||
memory_region_set_readonly(&s->irom_mem, true);
|
memory_region_set_readonly(&s->irom_mem, true);
|
||||||
memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
|
memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
|
||||||
@@ -264,7 +264,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
|||||||
|
|
||||||
/* Internal RAM */
|
/* Internal RAM */
|
||||||
memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram",
|
memory_region_init_ram(&s->iram_mem, NULL, "exynos4210.iram",
|
||||||
EXYNOS4210_IRAM_SIZE);
|
EXYNOS4210_IRAM_SIZE, &error_abort);
|
||||||
vmstate_register_ram_global(&s->iram_mem);
|
vmstate_register_ram_global(&s->iram_mem);
|
||||||
memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
|
memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
|
||||||
&s->iram_mem);
|
&s->iram_mem);
|
||||||
@@ -273,13 +273,14 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
|||||||
mem_size = ram_size;
|
mem_size = ram_size;
|
||||||
if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) {
|
if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) {
|
||||||
memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1",
|
memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1",
|
||||||
mem_size - EXYNOS4210_DRAM_MAX_SIZE);
|
mem_size - EXYNOS4210_DRAM_MAX_SIZE, &error_abort);
|
||||||
vmstate_register_ram_global(&s->dram1_mem);
|
vmstate_register_ram_global(&s->dram1_mem);
|
||||||
memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR,
|
memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR,
|
||||||
&s->dram1_mem);
|
&s->dram1_mem);
|
||||||
mem_size = EXYNOS4210_DRAM_MAX_SIZE;
|
mem_size = EXYNOS4210_DRAM_MAX_SIZE;
|
||||||
}
|
}
|
||||||
memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size);
|
memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->dram0_mem);
|
vmstate_register_ram_global(&s->dram0_mem);
|
||||||
memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
|
memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
|
||||||
&s->dram0_mem);
|
&s->dram0_mem);
|
||||||
|
|||||||
@@ -255,12 +255,13 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
|||||||
|
|
||||||
sysmem = get_system_memory();
|
sysmem = get_system_memory();
|
||||||
dram = g_new(MemoryRegion, 1);
|
dram = g_new(MemoryRegion, 1);
|
||||||
memory_region_init_ram(dram, NULL, "highbank.dram", ram_size);
|
memory_region_init_ram(dram, NULL, "highbank.dram", ram_size, &error_abort);
|
||||||
/* SDRAM at address zero. */
|
/* SDRAM at address zero. */
|
||||||
memory_region_add_subregion(sysmem, 0, dram);
|
memory_region_add_subregion(sysmem, 0, dram);
|
||||||
|
|
||||||
sysram = g_new(MemoryRegion, 1);
|
sysram = g_new(MemoryRegion, 1);
|
||||||
memory_region_init_ram(sysram, NULL, "highbank.sysram", 0x8000);
|
memory_region_init_ram(sysram, NULL, "highbank.sysram", 0x8000,
|
||||||
|
&error_abort);
|
||||||
memory_region_add_subregion(sysmem, 0xfff88000, sysram);
|
memory_region_add_subregion(sysmem, 0xfff88000, sysram);
|
||||||
if (bios_name != NULL) {
|
if (bios_name != NULL) {
|
||||||
sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||||
|
|||||||
@@ -264,7 +264,8 @@ static int integratorcm_init(SysBusDevice *dev)
|
|||||||
s->cm_init = 0x00000112;
|
s->cm_init = 0x00000112;
|
||||||
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
||||||
1000);
|
1000);
|
||||||
memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000);
|
memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->flash);
|
vmstate_register_ram_global(&s->flash);
|
||||||
|
|
||||||
memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
|
memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
|
||||||
@@ -485,7 +486,7 @@ static void integratorcp_init(MachineState *machine)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size);
|
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
|
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
|
||||||
/* ??? RAM should repeat to fill physical memory space. */
|
/* ??? RAM should repeat to fill physical memory space. */
|
||||||
|
|||||||
@@ -97,14 +97,14 @@ static void kzm_init(MachineState *machine)
|
|||||||
|
|
||||||
/* On a real system, the first 16k is a `secure boot rom' */
|
/* On a real system, the first 16k is a `secure boot rom' */
|
||||||
|
|
||||||
memory_region_init_ram(ram, NULL, "kzm.ram", ram_size);
|
memory_region_init_ram(ram, NULL, "kzm.ram", ram_size, &error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram);
|
memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram);
|
||||||
|
|
||||||
memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
|
memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
|
||||||
memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias);
|
memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias);
|
||||||
|
|
||||||
memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000);
|
memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000, &error_abort);
|
||||||
memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
|
memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
|
||||||
|
|
||||||
dev = sysbus_create_varargs("imx_avic", 0x68000000,
|
dev = sysbus_create_varargs("imx_avic", 0x68000000,
|
||||||
|
|||||||
@@ -123,7 +123,8 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
|
|||||||
|
|
||||||
/* Setup CPU & memory */
|
/* Setup CPU & memory */
|
||||||
mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model);
|
mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model);
|
||||||
memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM);
|
memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(rom);
|
vmstate_register_ram_global(rom);
|
||||||
memory_region_set_readonly(rom, true);
|
memory_region_set_readonly(rom, true);
|
||||||
memory_region_add_subregion(address_space_mem, 0, rom);
|
memory_region_add_subregion(address_space_mem, 0, rom);
|
||||||
|
|||||||
@@ -1601,11 +1601,13 @@ static void musicpal_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* For now we use a fixed - the original - RAM size */
|
/* For now we use a fixed - the original - RAM size */
|
||||||
memory_region_init_ram(ram, NULL, "musicpal.ram", MP_RAM_DEFAULT_SIZE);
|
memory_region_init_ram(ram, NULL, "musicpal.ram", MP_RAM_DEFAULT_SIZE,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
memory_region_add_subregion(address_space_mem, 0, ram);
|
memory_region_add_subregion(address_space_mem, 0, ram);
|
||||||
|
|
||||||
memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE);
|
memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(sram);
|
vmstate_register_ram_global(sram);
|
||||||
memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
|
memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
|
||||||
|
|
||||||
|
|||||||
@@ -3854,10 +3854,12 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
|||||||
omap_clk_init(s);
|
omap_clk_init(s);
|
||||||
|
|
||||||
/* Memory-mapped stuff */
|
/* Memory-mapped stuff */
|
||||||
memory_region_init_ram(&s->emiff_ram, NULL, "omap1.dram", s->sdram_size);
|
memory_region_init_ram(&s->emiff_ram, NULL, "omap1.dram", s->sdram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->emiff_ram);
|
vmstate_register_ram_global(&s->emiff_ram);
|
||||||
memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram);
|
memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram);
|
||||||
memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size);
|
memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->imif_ram);
|
vmstate_register_ram_global(&s->imif_ram);
|
||||||
memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram);
|
memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram);
|
||||||
|
|
||||||
|
|||||||
@@ -2266,10 +2266,12 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
|
|||||||
omap_clk_init(s);
|
omap_clk_init(s);
|
||||||
|
|
||||||
/* Memory-mapped stuff */
|
/* Memory-mapped stuff */
|
||||||
memory_region_init_ram(&s->sdram, NULL, "omap2.dram", s->sdram_size);
|
memory_region_init_ram(&s->sdram, NULL, "omap2.dram", s->sdram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->sdram);
|
vmstate_register_ram_global(&s->sdram);
|
||||||
memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram);
|
memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram);
|
||||||
memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size);
|
memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->sram);
|
vmstate_register_ram_global(&s->sram);
|
||||||
memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram);
|
memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram);
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ static void sx1_init(MachineState *machine, const int version)
|
|||||||
machine->cpu_model);
|
machine->cpu_model);
|
||||||
|
|
||||||
/* External Flash (EMIFS) */
|
/* External Flash (EMIFS) */
|
||||||
memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size);
|
memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(flash);
|
vmstate_register_ram_global(flash);
|
||||||
memory_region_set_readonly(flash, true);
|
memory_region_set_readonly(flash, true);
|
||||||
memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash);
|
memory_region_add_subregion(address_space, OMAP_CS0_BASE, flash);
|
||||||
@@ -164,7 +165,8 @@ static void sx1_init(MachineState *machine, const int version)
|
|||||||
|
|
||||||
if ((version == 1) &&
|
if ((version == 1) &&
|
||||||
(dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
|
(dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
|
||||||
memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size);
|
memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(flash_1);
|
vmstate_register_ram_global(flash_1);
|
||||||
memory_region_set_readonly(flash_1, true);
|
memory_region_set_readonly(flash_1, true);
|
||||||
memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1);
|
memory_region_add_subregion(address_space, OMAP_CS1_BASE, flash_1);
|
||||||
|
|||||||
@@ -212,7 +212,8 @@ static void palmte_init(MachineState *machine)
|
|||||||
mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model);
|
mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model);
|
||||||
|
|
||||||
/* External Flash (EMIFS) */
|
/* External Flash (EMIFS) */
|
||||||
memory_region_init_ram(flash, NULL, "palmte.flash", flash_size);
|
memory_region_init_ram(flash, NULL, "palmte.flash", flash_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(flash);
|
vmstate_register_ram_global(flash);
|
||||||
memory_region_set_readonly(flash, true);
|
memory_region_set_readonly(flash, true);
|
||||||
memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
|
memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
|
||||||
|
|||||||
@@ -2055,10 +2055,12 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
|
|||||||
s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
|
s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
|
||||||
|
|
||||||
/* SDRAM & Internal Memory Storage */
|
/* SDRAM & Internal Memory Storage */
|
||||||
memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size);
|
memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->sdram);
|
vmstate_register_ram_global(&s->sdram);
|
||||||
memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
|
memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
|
||||||
memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000);
|
memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->internal);
|
vmstate_register_ram_global(&s->internal);
|
||||||
memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
|
memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
|
||||||
&s->internal);
|
&s->internal);
|
||||||
@@ -2186,11 +2188,12 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
|
|||||||
s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
|
s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
|
||||||
|
|
||||||
/* SDRAM & Internal Memory Storage */
|
/* SDRAM & Internal Memory Storage */
|
||||||
memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size);
|
memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->sdram);
|
vmstate_register_ram_global(&s->sdram);
|
||||||
memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
|
memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
|
||||||
memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
|
memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
|
||||||
PXA2XX_INTERNAL_SIZE);
|
PXA2XX_INTERNAL_SIZE, &error_abort);
|
||||||
vmstate_register_ram_global(&s->internal);
|
vmstate_register_ram_global(&s->internal);
|
||||||
memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
|
memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
|
||||||
&s->internal);
|
&s->internal);
|
||||||
|
|||||||
@@ -137,12 +137,14 @@ static void realview_init(MachineState *machine,
|
|||||||
/* Core tile RAM. */
|
/* Core tile RAM. */
|
||||||
low_ram_size = ram_size - 0x20000000;
|
low_ram_size = ram_size - 0x20000000;
|
||||||
ram_size = 0x20000000;
|
ram_size = 0x20000000;
|
||||||
memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size);
|
memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram_lo);
|
vmstate_register_ram_global(ram_lo);
|
||||||
memory_region_add_subregion(sysmem, 0x20000000, ram_lo);
|
memory_region_add_subregion(sysmem, 0x20000000, ram_lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size);
|
memory_region_init_ram(ram_hi, NULL, "realview.highmem", ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram_hi);
|
vmstate_register_ram_global(ram_hi);
|
||||||
low_ram_size = ram_size;
|
low_ram_size = ram_size;
|
||||||
if (low_ram_size > 0x10000000)
|
if (low_ram_size > 0x10000000)
|
||||||
@@ -337,7 +339,8 @@ static void realview_init(MachineState *machine,
|
|||||||
startup code. I guess this works on real hardware because the
|
startup code. I guess this works on real hardware because the
|
||||||
BootROM happens to be in ROM/flash or in memory that isn't clobbered
|
BootROM happens to be in ROM/flash or in memory that isn't clobbered
|
||||||
until after Linux boots the secondary CPUs. */
|
until after Linux boots the secondary CPUs. */
|
||||||
memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000);
|
memory_region_init_ram(ram_hack, NULL, "realview.hack", 0x1000,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram_hack);
|
vmstate_register_ram_global(ram_hack);
|
||||||
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
|
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
|
||||||
|
|
||||||
|
|||||||
@@ -912,7 +912,7 @@ static void spitz_common_init(MachineState *machine,
|
|||||||
|
|
||||||
sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
|
sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
|
||||||
|
|
||||||
memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM);
|
memory_region_init_ram(rom, NULL, "spitz.rom", SPITZ_ROM, &error_abort);
|
||||||
vmstate_register_ram_global(rom);
|
vmstate_register_ram_global(rom);
|
||||||
memory_region_set_readonly(rom, true);
|
memory_region_set_readonly(rom, true);
|
||||||
memory_region_add_subregion(address_space_mem, 0, rom);
|
memory_region_add_subregion(address_space_mem, 0, rom);
|
||||||
|
|||||||
@@ -1604,7 +1604,8 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init_ram(&s->sdram, NULL, "strongarm.sdram", sdram_size);
|
memory_region_init_ram(&s->sdram, NULL, "strongarm.sdram", sdram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->sdram);
|
vmstate_register_ram_global(&s->sdram);
|
||||||
memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
|
memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
|
||||||
|
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ static void tosa_init(MachineState *machine)
|
|||||||
|
|
||||||
mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size);
|
mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size);
|
||||||
|
|
||||||
memory_region_init_ram(rom, NULL, "tosa.rom", TOSA_ROM);
|
memory_region_init_ram(rom, NULL, "tosa.rom", TOSA_ROM, &error_abort);
|
||||||
vmstate_register_ram_global(rom);
|
vmstate_register_ram_global(rom);
|
||||||
memory_region_set_readonly(rom, true);
|
memory_region_set_readonly(rom, true);
|
||||||
memory_region_add_subregion(address_space_mem, 0, rom);
|
memory_region_add_subregion(address_space_mem, 0, rom);
|
||||||
|
|||||||
@@ -198,7 +198,8 @@ static void versatile_init(MachineState *machine, int board_id)
|
|||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
fprintf(stderr, "Unable to find CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size);
|
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
/* ??? RAM should repeat to fill physical memory space. */
|
/* ??? RAM should repeat to fill physical memory space. */
|
||||||
/* SDRAM at address zero. */
|
/* SDRAM at address zero. */
|
||||||
|
|||||||
@@ -252,7 +252,8 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init_ram(ram, NULL, "vexpress.highmem", ram_size);
|
memory_region_init_ram(ram, NULL, "vexpress.highmem", ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
low_ram_size = ram_size;
|
low_ram_size = ram_size;
|
||||||
if (low_ram_size > 0x4000000) {
|
if (low_ram_size > 0x4000000) {
|
||||||
@@ -346,7 +347,8 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init_ram(ram, NULL, "vexpress.highmem", ram_size);
|
memory_region_init_ram(ram, NULL, "vexpress.highmem", ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
/* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */
|
/* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */
|
||||||
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
||||||
@@ -364,7 +366,8 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
/* 0x2b060000: SP805 watchdog: not modelled */
|
/* 0x2b060000: SP805 watchdog: not modelled */
|
||||||
/* 0x2b0a0000: PL341 dynamic memory controller: not modelled */
|
/* 0x2b0a0000: PL341 dynamic memory controller: not modelled */
|
||||||
/* 0x2e000000: system SRAM */
|
/* 0x2e000000: system SRAM */
|
||||||
memory_region_init_ram(sram, NULL, "vexpress.a15sram", 0x10000);
|
memory_region_init_ram(sram, NULL, "vexpress.a15sram", 0x10000,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(sram);
|
vmstate_register_ram_global(sram);
|
||||||
memory_region_add_subregion(sysmem, 0x2e000000, sram);
|
memory_region_add_subregion(sysmem, 0x2e000000, sram);
|
||||||
|
|
||||||
@@ -634,12 +637,14 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sram_size = 0x2000000;
|
sram_size = 0x2000000;
|
||||||
memory_region_init_ram(sram, NULL, "vexpress.sram", sram_size);
|
memory_region_init_ram(sram, NULL, "vexpress.sram", sram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(sram);
|
vmstate_register_ram_global(sram);
|
||||||
memory_region_add_subregion(sysmem, map[VE_SRAM], sram);
|
memory_region_add_subregion(sysmem, map[VE_SRAM], sram);
|
||||||
|
|
||||||
vram_size = 0x800000;
|
vram_size = 0x800000;
|
||||||
memory_region_init_ram(vram, NULL, "vexpress.vram", vram_size);
|
memory_region_init_ram(vram, NULL, "vexpress.vram", vram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(vram);
|
vmstate_register_ram_global(vram);
|
||||||
memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram);
|
memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram);
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
|
#include "hw/loader.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
@@ -371,11 +372,13 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
|||||||
2, base, 2, size);
|
2, base, 2, size);
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
|
||||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||||
GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks",
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks",
|
||||||
vbi->clock_phandle, vbi->clock_phandle);
|
vbi->clock_phandle, vbi->clock_phandle);
|
||||||
qemu_fdt_setprop(vbi->fdt, nodename, "clock-names",
|
qemu_fdt_setprop(vbi->fdt, nodename, "clock-names",
|
||||||
clocknames, sizeof(clocknames));
|
clocknames, sizeof(clocknames));
|
||||||
|
|
||||||
|
qemu_fdt_setprop_string(vbi->fdt, "/chosen", "linux,stdout-path", nodename);
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +399,7 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
|
|||||||
2, base, 2, size);
|
2, base, 2, size);
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
|
||||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||||
GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
|
qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
|
||||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
|
qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
@@ -437,6 +440,73 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_one_flash(const char *name, hwaddr flashbase,
|
||||||
|
hwaddr flashsize)
|
||||||
|
{
|
||||||
|
/* Create and map a single flash device. We use the same
|
||||||
|
* parameters as the flash devices on the Versatile Express board.
|
||||||
|
*/
|
||||||
|
DriveInfo *dinfo = drive_get_next(IF_PFLASH);
|
||||||
|
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
|
||||||
|
const uint64_t sectorlength = 256 * 1024;
|
||||||
|
|
||||||
|
if (dinfo && qdev_prop_set_drive(dev, "drive", dinfo->bdrv)) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
qdev_prop_set_uint32(dev, "num-blocks", flashsize / sectorlength);
|
||||||
|
qdev_prop_set_uint64(dev, "sector-length", sectorlength);
|
||||||
|
qdev_prop_set_uint8(dev, "width", 4);
|
||||||
|
qdev_prop_set_uint8(dev, "device-width", 2);
|
||||||
|
qdev_prop_set_uint8(dev, "big-endian", 0);
|
||||||
|
qdev_prop_set_uint16(dev, "id0", 0x89);
|
||||||
|
qdev_prop_set_uint16(dev, "id1", 0x18);
|
||||||
|
qdev_prop_set_uint16(dev, "id2", 0x00);
|
||||||
|
qdev_prop_set_uint16(dev, "id3", 0x00);
|
||||||
|
qdev_prop_set_string(dev, "name", name);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, flashbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_flash(const VirtBoardInfo *vbi)
|
||||||
|
{
|
||||||
|
/* Create two flash devices to fill the VIRT_FLASH space in the memmap.
|
||||||
|
* Any file passed via -bios goes in the first of these.
|
||||||
|
*/
|
||||||
|
hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2;
|
||||||
|
hwaddr flashbase = vbi->memmap[VIRT_FLASH].base;
|
||||||
|
char *nodename;
|
||||||
|
|
||||||
|
if (bios_name) {
|
||||||
|
const char *fn;
|
||||||
|
|
||||||
|
if (drive_get(IF_PFLASH, 0, 0)) {
|
||||||
|
error_report("The contents of the first flash device may be "
|
||||||
|
"specified with -bios or with -drive if=pflash... "
|
||||||
|
"but you cannot use both options at once");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||||
|
if (!fn || load_image_targphys(fn, flashbase, flashsize) < 0) {
|
||||||
|
error_report("Could not load ROM image '%s'", bios_name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create_one_flash("virt.flash0", flashbase, flashsize);
|
||||||
|
create_one_flash("virt.flash1", flashbase + flashsize, flashsize);
|
||||||
|
|
||||||
|
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||||||
|
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||||
|
qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash");
|
||||||
|
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||||
|
2, flashbase, 2, flashsize,
|
||||||
|
2, flashbase + flashsize, 2, flashsize);
|
||||||
|
qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4);
|
||||||
|
g_free(nodename);
|
||||||
|
}
|
||||||
|
|
||||||
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||||
{
|
{
|
||||||
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
||||||
@@ -510,10 +580,13 @@ static void machvirt_init(MachineState *machine)
|
|||||||
fdt_add_cpu_nodes(vbi);
|
fdt_add_cpu_nodes(vbi);
|
||||||
fdt_add_psci_node(vbi);
|
fdt_add_psci_node(vbi);
|
||||||
|
|
||||||
memory_region_init_ram(ram, NULL, "mach-virt.ram", machine->ram_size);
|
memory_region_init_ram(ram, NULL, "mach-virt.ram", machine->ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
||||||
|
|
||||||
|
create_flash(vbi);
|
||||||
|
|
||||||
create_gic(vbi, pic);
|
create_gic(vbi, pic);
|
||||||
|
|
||||||
create_uart(vbi, pic);
|
create_uart(vbi, pic);
|
||||||
|
|||||||
@@ -149,12 +149,14 @@ static void zynq_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* DDR remapped to address zero. */
|
/* DDR remapped to address zero. */
|
||||||
memory_region_init_ram(ext_ram, NULL, "zynq.ext_ram", ram_size);
|
memory_region_init_ram(ext_ram, NULL, "zynq.ext_ram", ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ext_ram);
|
vmstate_register_ram_global(ext_ram);
|
||||||
memory_region_add_subregion(address_space_mem, 0, ext_ram);
|
memory_region_add_subregion(address_space_mem, 0, ext_ram);
|
||||||
|
|
||||||
/* 256K of on-chip memory */
|
/* 256K of on-chip memory */
|
||||||
memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10);
|
memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(ocm_ram);
|
vmstate_register_ram_global(ocm_ram);
|
||||||
memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
|
memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
|
||||||
|
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ common-obj-$(CONFIG_NVME_PCI) += nvme.o
|
|||||||
obj-$(CONFIG_SH4) += tc58128.o
|
obj-$(CONFIG_SH4) += tc58128.o
|
||||||
|
|
||||||
obj-$(CONFIG_VIRTIO) += virtio-blk.o
|
obj-$(CONFIG_VIRTIO) += virtio-blk.o
|
||||||
obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += dataplane/
|
obj-$(CONFIG_VIRTIO) += dataplane/
|
||||||
|
|||||||
@@ -164,8 +164,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
|||||||
* block jobs that can conflict.
|
* block jobs that can conflict.
|
||||||
*/
|
*/
|
||||||
if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) {
|
if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) {
|
||||||
error_report("cannot start dataplane thread: %s",
|
error_setg(errp, "cannot start dataplane thread: %s",
|
||||||
error_get_pretty(local_err));
|
error_get_pretty(local_err));
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -695,10 +695,34 @@ static const VMStateDescription vmstate_fdrive_media_rate = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool fdrive_perpendicular_needed(void *opaque)
|
||||||
|
{
|
||||||
|
FDrive *drive = opaque;
|
||||||
|
|
||||||
|
return drive->perpendicular != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_fdrive_perpendicular = {
|
||||||
|
.name = "fdrive/perpendicular",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT8(perpendicular, FDrive),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int fdrive_post_load(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
fd_revalidate(opaque);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_fdrive = {
|
static const VMStateDescription vmstate_fdrive = {
|
||||||
.name = "fdrive",
|
.name = "fdrive",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
|
.post_load = fdrive_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT8(head, FDrive),
|
VMSTATE_UINT8(head, FDrive),
|
||||||
VMSTATE_UINT8(track, FDrive),
|
VMSTATE_UINT8(track, FDrive),
|
||||||
@@ -712,6 +736,9 @@ static const VMStateDescription vmstate_fdrive = {
|
|||||||
} , {
|
} , {
|
||||||
.vmsd = &vmstate_fdrive_media_rate,
|
.vmsd = &vmstate_fdrive_media_rate,
|
||||||
.needed = &fdrive_media_rate_needed,
|
.needed = &fdrive_media_rate_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_fdrive_perpendicular,
|
||||||
|
.needed = &fdrive_perpendicular_needed,
|
||||||
} , {
|
} , {
|
||||||
/* empty */
|
/* empty */
|
||||||
}
|
}
|
||||||
@@ -734,6 +761,40 @@ static int fdc_post_load(void *opaque, int version_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool fdc_reset_sensei_needed(void *opaque)
|
||||||
|
{
|
||||||
|
FDCtrl *s = opaque;
|
||||||
|
|
||||||
|
return s->reset_sensei != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_fdc_reset_sensei = {
|
||||||
|
.name = "fdc/reset_sensei",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_INT32(reset_sensei, FDCtrl),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool fdc_result_timer_needed(void *opaque)
|
||||||
|
{
|
||||||
|
FDCtrl *s = opaque;
|
||||||
|
|
||||||
|
return timer_pending(s->result_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_fdc_result_timer = {
|
||||||
|
.name = "fdc/result_timer",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_TIMER(result_timer, FDCtrl),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static const VMStateDescription vmstate_fdc = {
|
static const VMStateDescription vmstate_fdc = {
|
||||||
.name = "fdc",
|
.name = "fdc",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
@@ -770,6 +831,17 @@ static const VMStateDescription vmstate_fdc = {
|
|||||||
VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
|
VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
|
||||||
vmstate_fdrive, FDrive),
|
vmstate_fdrive, FDrive),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
.subsections = (VMStateSubsection[]) {
|
||||||
|
{
|
||||||
|
.vmsd = &vmstate_fdc_reset_sensei,
|
||||||
|
.needed = fdc_reset_sensei_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_fdc_result_timer,
|
||||||
|
.needed = fdc_result_timer_needed,
|
||||||
|
} , {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -844,6 +916,8 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
|
|||||||
fdctrl->dor = FD_DOR_nRESET;
|
fdctrl->dor = FD_DOR_nRESET;
|
||||||
fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
|
fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
|
||||||
fdctrl->msr = FD_MSR_RQM;
|
fdctrl->msr = FD_MSR_RQM;
|
||||||
|
fdctrl->reset_sensei = 0;
|
||||||
|
timer_del(fdctrl->result_timer);
|
||||||
/* FIFO state */
|
/* FIFO state */
|
||||||
fdctrl->data_pos = 0;
|
fdctrl->data_pos = 0;
|
||||||
fdctrl->data_len = 0;
|
fdctrl->data_len = 0;
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ static void nvme_rw_cb(void *opaque, int ret)
|
|||||||
NvmeCtrl *n = sq->ctrl;
|
NvmeCtrl *n = sq->ctrl;
|
||||||
NvmeCQueue *cq = n->cq[sq->cqid];
|
NvmeCQueue *cq = n->cq[sq->cqid];
|
||||||
|
|
||||||
bdrv_acct_done(n->conf.bs, &req->acct);
|
block_acct_done(bdrv_get_stats(n->conf.bs), &req->acct);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
req->status = NVME_SUCCESS;
|
req->status = NVME_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
@@ -232,7 +232,7 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
|||||||
assert((nlb << data_shift) == req->qsg.size);
|
assert((nlb << data_shift) == req->qsg.size);
|
||||||
|
|
||||||
dma_acct_start(n->conf.bs, &req->acct, &req->qsg, is_write ?
|
dma_acct_start(n->conf.bs, &req->acct, &req->qsg, is_write ?
|
||||||
BDRV_ACCT_WRITE : BDRV_ACCT_READ);
|
BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
||||||
req->aiocb = is_write ?
|
req->aiocb = is_write ?
|
||||||
dma_bdrv_write(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req) :
|
dma_bdrv_write(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req) :
|
||||||
dma_bdrv_read(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req);
|
dma_bdrv_read(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req);
|
||||||
|
|||||||
@@ -789,7 +789,7 @@ static int onenand_initfn(SysBusDevice *sbd)
|
|||||||
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
|
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
|
||||||
0xff, (64 + 2) << PAGE_SHIFT);
|
0xff, (64 + 2) << PAGE_SHIFT);
|
||||||
memory_region_init_ram(&s->ram, OBJECT(s), "onenand.ram",
|
memory_region_init_ram(&s->ram, OBJECT(s), "onenand.ram",
|
||||||
0xc000 << s->shift);
|
0xc000 << s->shift, &error_abort);
|
||||||
vmstate_register_ram_global(&s->ram);
|
vmstate_register_ram_global(&s->ram);
|
||||||
ram = memory_region_get_ram_ptr(&s->ram);
|
ram = memory_region_get_ram_ptr(&s->ram);
|
||||||
s->boot[0] = ram + (0x0000 << s->shift);
|
s->boot[0] = ram + (0x0000 << s->shift);
|
||||||
|
|||||||
@@ -753,6 +753,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
|||||||
int ret;
|
int ret;
|
||||||
uint64_t blocks_per_device, device_len;
|
uint64_t blocks_per_device, device_len;
|
||||||
int num_devices;
|
int num_devices;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
total_len = pfl->sector_len * pfl->nb_blocs;
|
total_len = pfl->sector_len * pfl->nb_blocs;
|
||||||
|
|
||||||
@@ -773,7 +774,12 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
|||||||
memory_region_init_rom_device(
|
memory_region_init_rom_device(
|
||||||
&pfl->mem, OBJECT(dev),
|
&pfl->mem, OBJECT(dev),
|
||||||
pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
||||||
pfl->name, total_len);
|
pfl->name, total_len, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
vmstate_register_ram(&pfl->mem, DEVICE(pfl));
|
vmstate_register_ram(&pfl->mem, DEVICE(pfl));
|
||||||
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
|
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
|
||||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
|
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
|
||||||
|
|||||||
@@ -597,6 +597,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
|
|||||||
pflash_t *pfl = CFI_PFLASH02(dev);
|
pflash_t *pfl = CFI_PFLASH02(dev);
|
||||||
uint32_t chip_len;
|
uint32_t chip_len;
|
||||||
int ret;
|
int ret;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
chip_len = pfl->sector_len * pfl->nb_blocs;
|
chip_len = pfl->sector_len * pfl->nb_blocs;
|
||||||
/* XXX: to be fixed */
|
/* XXX: to be fixed */
|
||||||
@@ -608,7 +609,12 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl), pfl->be ?
|
memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl), pfl->be ?
|
||||||
&pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
|
&pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
|
||||||
pfl, pfl->name, chip_len);
|
pfl, pfl->name, chip_len, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
|
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
|
||||||
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
|
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
|
||||||
pfl->chip_len = chip_len;
|
pfl->chip_len = chip_len;
|
||||||
|
|||||||
@@ -18,10 +18,8 @@
|
|||||||
#include "hw/block/block.h"
|
#include "hw/block/block.h"
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
#include "hw/virtio/virtio-blk.h"
|
#include "hw/virtio/virtio-blk.h"
|
||||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
#include "dataplane/virtio-blk.h"
|
||||||
# include "dataplane/virtio-blk.h"
|
#include "migration/migration.h"
|
||||||
# include "migration/migration.h"
|
|
||||||
#endif
|
|
||||||
#include "block/scsi.h"
|
#include "block/scsi.h"
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
# include <scsi/sg.h>
|
# include <scsi/sg.h>
|
||||||
@@ -74,7 +72,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
|
|||||||
s->rq = req;
|
s->rq = req;
|
||||||
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
|
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
|
||||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
||||||
bdrv_acct_done(s->bs, &req->acct);
|
block_acct_done(bdrv_get_stats(s->bs), &req->acct);
|
||||||
virtio_blk_free_request(req);
|
virtio_blk_free_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +94,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
||||||
bdrv_acct_done(req->dev->bs, &req->acct);
|
block_acct_done(bdrv_get_stats(req->dev->bs), &req->acct);
|
||||||
virtio_blk_free_request(req);
|
virtio_blk_free_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +109,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
||||||
bdrv_acct_done(req->dev->bs, &req->acct);
|
block_acct_done(bdrv_get_stats(req->dev->bs), &req->acct);
|
||||||
virtio_blk_free_request(req);
|
virtio_blk_free_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +277,8 @@ void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
|
|||||||
|
|
||||||
static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||||
{
|
{
|
||||||
bdrv_acct_start(req->dev->bs, &req->acct, 0, BDRV_ACCT_FLUSH);
|
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, 0,
|
||||||
|
BLOCK_ACCT_FLUSH);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure all outstanding writes are posted to the backing device.
|
* Make sure all outstanding writes are posted to the backing device.
|
||||||
@@ -322,7 +321,8 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);
|
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, req->qiov.size,
|
||||||
|
BLOCK_ACCT_WRITE);
|
||||||
|
|
||||||
if (mrb->num_writes == 32) {
|
if (mrb->num_writes == 32) {
|
||||||
virtio_submit_multiwrite(req->dev->bs, mrb);
|
virtio_submit_multiwrite(req->dev->bs, mrb);
|
||||||
@@ -353,7 +353,8 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
|
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, req->qiov.size,
|
||||||
|
BLOCK_ACCT_READ);
|
||||||
bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
|
bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
|
||||||
req->qiov.size / BDRV_SECTOR_SIZE,
|
req->qiov.size / BDRV_SECTOR_SIZE,
|
||||||
virtio_blk_rw_complete, req);
|
virtio_blk_rw_complete, req);
|
||||||
@@ -432,7 +433,6 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
.num_writes = 0,
|
.num_writes = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
||||||
/* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
|
/* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
|
||||||
* dataplane here instead of waiting for .set_status().
|
* dataplane here instead of waiting for .set_status().
|
||||||
*/
|
*/
|
||||||
@@ -440,7 +440,6 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
virtio_blk_data_plane_start(s->dataplane);
|
virtio_blk_data_plane_start(s->dataplane);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
while ((req = virtio_blk_get_request(s))) {
|
while ((req = virtio_blk_get_request(s))) {
|
||||||
virtio_blk_handle_request(req, &mrb);
|
virtio_blk_handle_request(req, &mrb);
|
||||||
@@ -497,11 +496,9 @@ static void virtio_blk_reset(VirtIODevice *vdev)
|
|||||||
{
|
{
|
||||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||||
|
|
||||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
||||||
if (s->dataplane) {
|
if (s->dataplane) {
|
||||||
virtio_blk_data_plane_stop(s->dataplane);
|
virtio_blk_data_plane_stop(s->dataplane);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This should cancel pending requests, but can't do nicely until there
|
* This should cancel pending requests, but can't do nicely until there
|
||||||
@@ -591,12 +588,10 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
|||||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||||
uint32_t features;
|
uint32_t features;
|
||||||
|
|
||||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
||||||
if (s->dataplane && !(status & (VIRTIO_CONFIG_S_DRIVER |
|
if (s->dataplane && !(status & (VIRTIO_CONFIG_S_DRIVER |
|
||||||
VIRTIO_CONFIG_S_DRIVER_OK))) {
|
VIRTIO_CONFIG_S_DRIVER_OK))) {
|
||||||
virtio_blk_data_plane_stop(s->dataplane);
|
virtio_blk_data_plane_stop(s->dataplane);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
||||||
return;
|
return;
|
||||||
@@ -691,7 +686,6 @@ static const BlockDevOps virtio_block_ops = {
|
|||||||
.resize_cb = virtio_blk_resize,
|
.resize_cb = virtio_blk_resize,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
||||||
/* Disable dataplane thread during live migration since it does not
|
/* Disable dataplane thread during live migration since it does not
|
||||||
* update the dirty memory bitmap yet.
|
* update the dirty memory bitmap yet.
|
||||||
*/
|
*/
|
||||||
@@ -722,7 +716,6 @@ static void virtio_blk_migration_state_changed(Notifier *notifier, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_VIRTIO_BLK_DATA_PLANE */
|
|
||||||
|
|
||||||
static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -759,7 +752,6 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
|
s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
|
||||||
s->complete_request = virtio_blk_complete_request;
|
s->complete_request = virtio_blk_complete_request;
|
||||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
||||||
virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
|
virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
@@ -768,7 +760,6 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
s->migration_state_notifier.notify = virtio_blk_migration_state_changed;
|
s->migration_state_notifier.notify = virtio_blk_migration_state_changed;
|
||||||
add_migration_state_change_notifier(&s->migration_state_notifier);
|
add_migration_state_change_notifier(&s->migration_state_notifier);
|
||||||
#endif
|
|
||||||
|
|
||||||
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
|
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
|
||||||
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
||||||
@@ -786,11 +777,9 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
|
|||||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||||
VirtIOBlock *s = VIRTIO_BLK(dev);
|
VirtIOBlock *s = VIRTIO_BLK(dev);
|
||||||
|
|
||||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
||||||
remove_migration_state_change_notifier(&s->migration_state_notifier);
|
remove_migration_state_change_notifier(&s->migration_state_notifier);
|
||||||
virtio_blk_data_plane_destroy(s->dataplane);
|
virtio_blk_data_plane_destroy(s->dataplane);
|
||||||
s->dataplane = NULL;
|
s->dataplane = NULL;
|
||||||
#endif
|
|
||||||
qemu_del_vm_change_state_handler(s->change);
|
qemu_del_vm_change_state_handler(s->change);
|
||||||
unregister_savevm(dev, "virtio-blk", s);
|
unregister_savevm(dev, "virtio-blk", s);
|
||||||
blockdev_mark_auto_del(s->bs);
|
blockdev_mark_auto_del(s->bs);
|
||||||
@@ -815,9 +804,7 @@ static Property virtio_blk_properties[] = {
|
|||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
DEFINE_PROP_BIT("scsi", VirtIOBlock, blk.scsi, 0, true),
|
DEFINE_PROP_BIT("scsi", VirtIOBlock, blk.scsi, 0, true),
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
|
||||||
DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, blk.data_plane, 0, false),
|
DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, blk.data_plane, 0, false),
|
||||||
#endif
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ static void qemu_aio_complete(void *opaque, int ret)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BLKIF_OP_READ:
|
case BLKIF_OP_READ:
|
||||||
bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
|
block_acct_done(bdrv_get_stats(ioreq->blkdev->bs), &ioreq->acct);
|
||||||
break;
|
break;
|
||||||
case BLKIF_OP_DISCARD:
|
case BLKIF_OP_DISCARD:
|
||||||
default:
|
default:
|
||||||
@@ -518,7 +518,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
|||||||
|
|
||||||
switch (ioreq->req.operation) {
|
switch (ioreq->req.operation) {
|
||||||
case BLKIF_OP_READ:
|
case BLKIF_OP_READ:
|
||||||
bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_READ);
|
block_acct_start(bdrv_get_stats(blkdev->bs), &ioreq->acct,
|
||||||
|
ioreq->v.size, BLOCK_ACCT_READ);
|
||||||
ioreq->aio_inflight++;
|
ioreq->aio_inflight++;
|
||||||
bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
|
bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
|
||||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||||
@@ -530,7 +531,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_WRITE);
|
block_acct_start(bdrv_get_stats(blkdev->bs), &ioreq->acct,
|
||||||
|
ioreq->v.size, BLOCK_ACCT_WRITE);
|
||||||
ioreq->aio_inflight++;
|
ioreq->aio_inflight++;
|
||||||
bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
|
bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
|
||||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||||
@@ -852,28 +854,25 @@ static int blk_connect(struct XenDevice *xendev)
|
|||||||
blkdev->dinfo = drive_get(IF_XEN, 0, index);
|
blkdev->dinfo = drive_get(IF_XEN, 0, index);
|
||||||
if (!blkdev->dinfo) {
|
if (!blkdev->dinfo) {
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
BlockDriver *drv;
|
||||||
|
|
||||||
/* setup via xenbus -> create new block driver instance */
|
/* setup via xenbus -> create new block driver instance */
|
||||||
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
||||||
blkdev->bs = bdrv_new(blkdev->dev, &local_err);
|
blkdev->bs = bdrv_new(blkdev->dev, NULL);
|
||||||
if (local_err) {
|
|
||||||
blkdev->bs = NULL;
|
|
||||||
}
|
|
||||||
if (blkdev->bs) {
|
|
||||||
BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto,
|
|
||||||
readonly);
|
|
||||||
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
|
|
||||||
drv, &local_err) != 0)
|
|
||||||
{
|
|
||||||
xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
|
|
||||||
error_get_pretty(local_err));
|
|
||||||
error_free(local_err);
|
|
||||||
bdrv_unref(blkdev->bs);
|
|
||||||
blkdev->bs = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!blkdev->bs) {
|
if (!blkdev->bs) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drv = bdrv_find_whitelisted_format(blkdev->fileproto, readonly);
|
||||||
|
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
|
||||||
|
drv, &local_err) != 0) {
|
||||||
|
xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
|
||||||
|
error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
bdrv_unref(blkdev->bs);
|
||||||
|
blkdev->bs = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* setup via qemu cmdline -> already setup for us */
|
/* setup via qemu cmdline -> already setup for us */
|
||||||
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
|
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
|
||||||
|
|||||||
@@ -477,6 +477,23 @@ static const MemoryRegionPortio isa_parallel_portio_sw_list[] = {
|
|||||||
PORTIO_END_OF_LIST(),
|
PORTIO_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_parallel_isa = {
|
||||||
|
.name = "parallel_isa",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT8(state.dataw, ISAParallelState),
|
||||||
|
VMSTATE_UINT8(state.datar, ISAParallelState),
|
||||||
|
VMSTATE_UINT8(state.status, ISAParallelState),
|
||||||
|
VMSTATE_UINT8(state.control, ISAParallelState),
|
||||||
|
VMSTATE_INT32(state.irq_pending, ISAParallelState),
|
||||||
|
VMSTATE_INT32(state.epp_timeout, ISAParallelState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
|
static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
static int index;
|
static int index;
|
||||||
@@ -606,6 +623,7 @@ static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
|
|||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
dc->realize = parallel_isa_realizefn;
|
dc->realize = parallel_isa_realizefn;
|
||||||
|
dc->vmsd = &vmstate_parallel_isa;
|
||||||
dc->props = parallel_isa_properties;
|
dc->props = parallel_isa_properties;
|
||||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||||
}
|
}
|
||||||
|
|||||||
231
hw/char/serial.c
231
hw/char/serial.c
@@ -272,6 +272,36 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Setter for FCR.
|
||||||
|
is_load flag means, that value is set while loading VM state
|
||||||
|
and interrupt should not be invoked */
|
||||||
|
static void serial_write_fcr(SerialState *s, uint8_t val)
|
||||||
|
{
|
||||||
|
/* Set fcr - val only has the bits that are supposed to "stick" */
|
||||||
|
s->fcr = val;
|
||||||
|
|
||||||
|
if (val & UART_FCR_FE) {
|
||||||
|
s->iir |= UART_IIR_FE;
|
||||||
|
/* Set recv_fifo trigger Level */
|
||||||
|
switch (val & 0xC0) {
|
||||||
|
case UART_FCR_ITL_1:
|
||||||
|
s->recv_fifo_itl = 1;
|
||||||
|
break;
|
||||||
|
case UART_FCR_ITL_2:
|
||||||
|
s->recv_fifo_itl = 4;
|
||||||
|
break;
|
||||||
|
case UART_FCR_ITL_3:
|
||||||
|
s->recv_fifo_itl = 8;
|
||||||
|
break;
|
||||||
|
case UART_FCR_ITL_4:
|
||||||
|
s->recv_fifo_itl = 14;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s->iir &= ~UART_IIR_FE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
@@ -327,20 +357,16 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
val = val & 0xFF;
|
|
||||||
|
|
||||||
if (s->fcr == val)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
|
/* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
|
||||||
if ((val ^ s->fcr) & UART_FCR_FE)
|
if ((val ^ s->fcr) & UART_FCR_FE) {
|
||||||
val |= UART_FCR_XFR | UART_FCR_RFR;
|
val |= UART_FCR_XFR | UART_FCR_RFR;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIFO clear */
|
/* FIFO clear */
|
||||||
|
|
||||||
if (val & UART_FCR_RFR) {
|
if (val & UART_FCR_RFR) {
|
||||||
timer_del(s->fifo_timeout_timer);
|
timer_del(s->fifo_timeout_timer);
|
||||||
s->timeout_ipending=0;
|
s->timeout_ipending = 0;
|
||||||
fifo8_reset(&s->recv_fifo);
|
fifo8_reset(&s->recv_fifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,28 +374,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
fifo8_reset(&s->xmit_fifo);
|
fifo8_reset(&s->xmit_fifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val & UART_FCR_FE) {
|
serial_write_fcr(s, val & 0xC9);
|
||||||
s->iir |= UART_IIR_FE;
|
|
||||||
/* Set recv_fifo trigger Level */
|
|
||||||
switch (val & 0xC0) {
|
|
||||||
case UART_FCR_ITL_1:
|
|
||||||
s->recv_fifo_itl = 1;
|
|
||||||
break;
|
|
||||||
case UART_FCR_ITL_2:
|
|
||||||
s->recv_fifo_itl = 4;
|
|
||||||
break;
|
|
||||||
case UART_FCR_ITL_3:
|
|
||||||
s->recv_fifo_itl = 8;
|
|
||||||
break;
|
|
||||||
case UART_FCR_ITL_4:
|
|
||||||
s->recv_fifo_itl = 14;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
s->iir &= ~UART_IIR_FE;
|
|
||||||
|
|
||||||
/* Set fcr - or at least the bits in it that are supposed to "stick" */
|
|
||||||
s->fcr = val & 0xC9;
|
|
||||||
serial_update_irq(s);
|
serial_update_irq(s);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
@@ -590,6 +595,14 @@ static void serial_pre_save(void *opaque)
|
|||||||
s->fcr_vmstate = s->fcr;
|
s->fcr_vmstate = s->fcr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int serial_pre_load(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = opaque;
|
||||||
|
s->thr_ipending = -1;
|
||||||
|
s->poll_msl = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int serial_post_load(void *opaque, int version_id)
|
static int serial_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
SerialState *s = opaque;
|
SerialState *s = opaque;
|
||||||
@@ -597,17 +610,139 @@ static int serial_post_load(void *opaque, int version_id)
|
|||||||
if (version_id < 3) {
|
if (version_id < 3) {
|
||||||
s->fcr_vmstate = 0;
|
s->fcr_vmstate = 0;
|
||||||
}
|
}
|
||||||
|
if (s->thr_ipending == -1) {
|
||||||
|
s->thr_ipending = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
|
||||||
|
}
|
||||||
|
s->last_break_enable = (s->lcr >> 6) & 1;
|
||||||
/* Initialize fcr via setter to perform essential side-effects */
|
/* Initialize fcr via setter to perform essential side-effects */
|
||||||
serial_ioport_write(s, 0x02, s->fcr_vmstate, 1);
|
serial_write_fcr(s, s->fcr_vmstate);
|
||||||
serial_update_parameters(s);
|
serial_update_parameters(s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool serial_thr_ipending_needed(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = opaque;
|
||||||
|
bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
|
||||||
|
return s->thr_ipending != expected_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_serial_thr_ipending = {
|
||||||
|
.name = "serial/thr_ipending",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_INT32(thr_ipending, SerialState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool serial_tsr_needed(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = (SerialState *)opaque;
|
||||||
|
return s->tsr_retry != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_serial_tsr = {
|
||||||
|
.name = "serial/tsr",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_INT32(tsr_retry, SerialState),
|
||||||
|
VMSTATE_UINT8(thr, SerialState),
|
||||||
|
VMSTATE_UINT8(tsr, SerialState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool serial_recv_fifo_needed(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = (SerialState *)opaque;
|
||||||
|
return !fifo8_is_empty(&s->recv_fifo);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_serial_recv_fifo = {
|
||||||
|
.name = "serial/recv_fifo",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_STRUCT(recv_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool serial_xmit_fifo_needed(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = (SerialState *)opaque;
|
||||||
|
return !fifo8_is_empty(&s->xmit_fifo);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_serial_xmit_fifo = {
|
||||||
|
.name = "serial/xmit_fifo",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_STRUCT(xmit_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool serial_fifo_timeout_timer_needed(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = (SerialState *)opaque;
|
||||||
|
return timer_pending(s->fifo_timeout_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_serial_fifo_timeout_timer = {
|
||||||
|
.name = "serial/fifo_timeout_timer",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_TIMER(fifo_timeout_timer, SerialState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool serial_timeout_ipending_needed(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = (SerialState *)opaque;
|
||||||
|
return s->timeout_ipending != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_serial_timeout_ipending = {
|
||||||
|
.name = "serial/timeout_ipending",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_INT32(timeout_ipending, SerialState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool serial_poll_needed(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = (SerialState *)opaque;
|
||||||
|
return s->poll_msl >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_serial_poll = {
|
||||||
|
.name = "serial/poll",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_INT32(poll_msl, SerialState),
|
||||||
|
VMSTATE_TIMER(modem_status_poll, SerialState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_serial = {
|
const VMStateDescription vmstate_serial = {
|
||||||
.name = "serial",
|
.name = "serial",
|
||||||
.version_id = 3,
|
.version_id = 3,
|
||||||
.minimum_version_id = 2,
|
.minimum_version_id = 2,
|
||||||
.pre_save = serial_pre_save,
|
.pre_save = serial_pre_save,
|
||||||
|
.pre_load = serial_pre_load,
|
||||||
.post_load = serial_post_load,
|
.post_load = serial_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT16_V(divider, SerialState, 2),
|
VMSTATE_UINT16_V(divider, SerialState, 2),
|
||||||
@@ -621,6 +756,32 @@ const VMStateDescription vmstate_serial = {
|
|||||||
VMSTATE_UINT8(scr, SerialState),
|
VMSTATE_UINT8(scr, SerialState),
|
||||||
VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
|
VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
.subsections = (VMStateSubsection[]) {
|
||||||
|
{
|
||||||
|
.vmsd = &vmstate_serial_thr_ipending,
|
||||||
|
.needed = &serial_thr_ipending_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_serial_tsr,
|
||||||
|
.needed = &serial_tsr_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_serial_recv_fifo,
|
||||||
|
.needed = &serial_recv_fifo_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_serial_xmit_fifo,
|
||||||
|
.needed = &serial_xmit_fifo_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_serial_fifo_timeout_timer,
|
||||||
|
.needed = &serial_fifo_timeout_timer_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_serial_timeout_ipending,
|
||||||
|
.needed = &serial_timeout_ipending_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_serial_poll,
|
||||||
|
.needed = &serial_poll_needed,
|
||||||
|
} , {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -642,6 +803,10 @@ static void serial_reset(void *opaque)
|
|||||||
s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10;
|
s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10;
|
||||||
s->poll_msl = 0;
|
s->poll_msl = 0;
|
||||||
|
|
||||||
|
s->timeout_ipending = 0;
|
||||||
|
timer_del(s->fifo_timeout_timer);
|
||||||
|
timer_del(s->modem_status_poll);
|
||||||
|
|
||||||
fifo8_reset(&s->recv_fifo);
|
fifo8_reset(&s->recv_fifo);
|
||||||
fifo8_reset(&s->xmit_fifo);
|
fifo8_reset(&s->xmit_fifo);
|
||||||
|
|
||||||
@@ -650,6 +815,9 @@ static void serial_reset(void *opaque)
|
|||||||
s->thr_ipending = 0;
|
s->thr_ipending = 0;
|
||||||
s->last_break_enable = 0;
|
s->last_break_enable = 0;
|
||||||
qemu_irq_lower(s->irq);
|
qemu_irq_lower(s->irq);
|
||||||
|
|
||||||
|
serial_update_msl(s);
|
||||||
|
s->msr &= ~UART_MSR_ANY_DELTA;
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_realize_core(SerialState *s, Error **errp)
|
void serial_realize_core(SerialState *s, Error **errp)
|
||||||
@@ -668,6 +836,7 @@ void serial_realize_core(SerialState *s, Error **errp)
|
|||||||
serial_event, s);
|
serial_event, s);
|
||||||
fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
|
fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
|
||||||
fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
|
fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
|
||||||
|
serial_reset(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_exit_core(SerialState *s)
|
void serial_exit_core(SerialState *s)
|
||||||
@@ -779,7 +948,5 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
|
|||||||
memory_region_init_io(&s->io, NULL, &serial_mm_ops[end], s,
|
memory_region_init_io(&s->io, NULL, &serial_mm_ops[end], s,
|
||||||
"serial", 8 << it_shift);
|
"serial", 8 << it_shift);
|
||||||
memory_region_add_subregion(address_space, base, &s->io);
|
memory_region_add_subregion(address_space, base, &s->io);
|
||||||
|
|
||||||
serial_update_msl(s);
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -701,7 +701,7 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
|
|||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
rom->mr = g_malloc(sizeof(*rom->mr));
|
rom->mr = g_malloc(sizeof(*rom->mr));
|
||||||
memory_region_init_ram(rom->mr, owner, name, rom->datasize);
|
memory_region_init_ram(rom->mr, owner, name, rom->datasize, &error_abort);
|
||||||
memory_region_set_readonly(rom->mr, true);
|
memory_region_set_readonly(rom->mr, true);
|
||||||
vmstate_register_ram_global(rom->mr);
|
vmstate_register_ram_global(rom->mr);
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ static void machine_set_accel(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->accel);
|
||||||
ms->accel = g_strdup(value);
|
ms->accel = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->kernel_filename);
|
||||||
ms->kernel_filename = g_strdup(value);
|
ms->kernel_filename = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +95,7 @@ static void machine_set_initrd(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->initrd_filename);
|
||||||
ms->initrd_filename = g_strdup(value);
|
ms->initrd_filename = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +110,7 @@ static void machine_set_append(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->kernel_cmdline);
|
||||||
ms->kernel_cmdline = g_strdup(value);
|
ms->kernel_cmdline = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +125,7 @@ static void machine_set_dtb(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->dtb);
|
||||||
ms->dtb = g_strdup(value);
|
ms->dtb = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +140,7 @@ static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->dumpdtb);
|
||||||
ms->dumpdtb = g_strdup(value);
|
ms->dumpdtb = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +182,7 @@ static void machine_set_dt_compatible(Object *obj, const char *value, Error **er
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->dt_compatible);
|
||||||
ms->dt_compatible = g_strdup(value);
|
ms->dt_compatible = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,6 +239,7 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp)
|
|||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
g_free(ms->firmware);
|
||||||
ms->firmware = g_strdup(value);
|
ms->firmware = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -388,28 +388,12 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
|
|||||||
static int qdev_add_one_global(QemuOpts *opts, void *opaque)
|
static int qdev_add_one_global(QemuOpts *opts, void *opaque)
|
||||||
{
|
{
|
||||||
GlobalProperty *g;
|
GlobalProperty *g;
|
||||||
ObjectClass *oc;
|
|
||||||
|
|
||||||
g = g_malloc0(sizeof(*g));
|
g = g_malloc0(sizeof(*g));
|
||||||
g->driver = qemu_opt_get(opts, "driver");
|
g->driver = qemu_opt_get(opts, "driver");
|
||||||
g->property = qemu_opt_get(opts, "property");
|
g->property = qemu_opt_get(opts, "property");
|
||||||
g->value = qemu_opt_get(opts, "value");
|
g->value = qemu_opt_get(opts, "value");
|
||||||
oc = object_class_dynamic_cast(object_class_by_name(g->driver),
|
g->user_provided = true;
|
||||||
TYPE_DEVICE);
|
|
||||||
if (oc) {
|
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
||||||
|
|
||||||
if (dc->hotpluggable) {
|
|
||||||
/* If hotpluggable then skip not_used checking. */
|
|
||||||
g->not_used = false;
|
|
||||||
} else {
|
|
||||||
/* Maybe a typo. */
|
|
||||||
g->not_used = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Maybe a typo. */
|
|
||||||
g->not_used = true;
|
|
||||||
}
|
|
||||||
qdev_prop_register_global(g);
|
qdev_prop_register_global(g);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -955,19 +955,35 @@ void qdev_prop_register_global_list(GlobalProperty *props)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int qdev_prop_check_global(void)
|
int qdev_prop_check_globals(void)
|
||||||
{
|
{
|
||||||
GlobalProperty *prop;
|
GlobalProperty *prop;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
QTAILQ_FOREACH(prop, &global_props, next) {
|
QTAILQ_FOREACH(prop, &global_props, next) {
|
||||||
if (!prop->not_used) {
|
ObjectClass *oc;
|
||||||
|
DeviceClass *dc;
|
||||||
|
if (prop->used) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!prop->user_provided) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
oc = object_class_by_name(prop->driver);
|
||||||
|
oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
|
||||||
|
if (!oc) {
|
||||||
|
error_report("Warning: global %s.%s has invalid class name",
|
||||||
|
prop->driver, prop->property);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dc = DEVICE_CLASS(oc);
|
||||||
|
if (!dc->hotpluggable && !prop->used) {
|
||||||
|
error_report("Warning: global %s.%s=%s not used",
|
||||||
|
prop->driver, prop->property, prop->value);
|
||||||
|
ret = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ret = 1;
|
|
||||||
error_report("Warning: \"-global %s.%s=%s\" not used",
|
|
||||||
prop->driver, prop->property, prop->value);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -983,7 +999,7 @@ void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
|
|||||||
if (strcmp(typename, prop->driver) != 0) {
|
if (strcmp(typename, prop->driver) != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
prop->not_used = false;
|
prop->used = true;
|
||||||
object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
|
object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
|
|||||||
@@ -270,13 +270,15 @@ void axisdev88_init(MachineState *machine)
|
|||||||
env = &cpu->env;
|
env = &cpu->env;
|
||||||
|
|
||||||
/* allocate RAM */
|
/* allocate RAM */
|
||||||
memory_region_init_ram(phys_ram, NULL, "axisdev88.ram", ram_size);
|
memory_region_init_ram(phys_ram, NULL, "axisdev88.ram", ram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(phys_ram);
|
vmstate_register_ram_global(phys_ram);
|
||||||
memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
|
memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
|
||||||
|
|
||||||
/* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the
|
/* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the
|
||||||
internal memory. */
|
internal memory. */
|
||||||
memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram", INTMEM_SIZE);
|
memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram", INTMEM_SIZE,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(phys_intmem);
|
vmstate_register_ram_global(phys_intmem);
|
||||||
memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
|
memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
|
||||||
|
|
||||||
|
|||||||
@@ -134,14 +134,6 @@ static const int blizzard_iformat_bpp[0x10] = {
|
|||||||
0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void blizzard_rgb2yuv(int r, int g, int b,
|
|
||||||
int *y, int *u, int *v)
|
|
||||||
{
|
|
||||||
*y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13);
|
|
||||||
*u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13);
|
|
||||||
*v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void blizzard_window(BlizzardState *s)
|
static void blizzard_window(BlizzardState *s)
|
||||||
{
|
{
|
||||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||||
|
|||||||
@@ -279,7 +279,8 @@ static void cg3_initfn(Object *obj)
|
|||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
CG3State *s = CG3(obj);
|
CG3State *s = CG3(obj);
|
||||||
|
|
||||||
memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
|
memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE,
|
||||||
|
&error_abort);
|
||||||
memory_region_set_readonly(&s->rom, true);
|
memory_region_set_readonly(&s->rom, true);
|
||||||
sysbus_init_mmio(sbd, &s->rom);
|
sysbus_init_mmio(sbd, &s->rom);
|
||||||
|
|
||||||
@@ -306,7 +307,8 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size);
|
memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size,
|
||||||
|
&error_abort);
|
||||||
vmstate_register_ram_global(&s->vram_mem);
|
vmstate_register_ram_global(&s->vram_mem);
|
||||||
sysbus_init_mmio(sbd, &s->vram_mem);
|
sysbus_init_mmio(sbd, &s->vram_mem);
|
||||||
|
|
||||||
|
|||||||
@@ -279,14 +279,6 @@ static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
|
|||||||
s->liidr = s->dma_ch[ch].id;
|
s->liidr = s->dma_ch[ch].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set Read Status interrupt high and poke associated registers */
|
|
||||||
static inline void pxa2xx_dma_rdst_set(PXA2xxLCDState *s)
|
|
||||||
{
|
|
||||||
s->status[0] |= LCSR0_RDST;
|
|
||||||
if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
|
|
||||||
s->status[0] |= LCSR0_SINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load new Frame Descriptors from DMA */
|
/* Load new Frame Descriptors from DMA */
|
||||||
static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
|
static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
|
|||||||
static void qxl_reset_surfaces(PCIQXLDevice *d);
|
static void qxl_reset_surfaces(PCIQXLDevice *d);
|
||||||
static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
|
static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
|
||||||
|
|
||||||
|
static void qxl_hw_update(void *opaque);
|
||||||
|
|
||||||
void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
|
void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
|
||||||
{
|
{
|
||||||
trace_qxl_set_guest_bug(qxl->id);
|
trace_qxl_set_guest_bug(qxl->id);
|
||||||
@@ -1076,6 +1078,10 @@ static const QXLInterface qxl_interface = {
|
|||||||
.client_monitors_config = interface_client_monitors_config,
|
.client_monitors_config = interface_client_monitors_config,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const GraphicHwOps qxl_ops = {
|
||||||
|
.gfx_update = qxl_hw_update,
|
||||||
|
};
|
||||||
|
|
||||||
static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
||||||
{
|
{
|
||||||
if (d->mode == QXL_MODE_VGA) {
|
if (d->mode == QXL_MODE_VGA) {
|
||||||
@@ -1085,6 +1091,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
|||||||
#if SPICE_SERVER_VERSION >= 0x000c03 /* release 0.12.3 */
|
#if SPICE_SERVER_VERSION >= 0x000c03 /* release 0.12.3 */
|
||||||
spice_qxl_driver_unload(&d->ssd.qxl);
|
spice_qxl_driver_unload(&d->ssd.qxl);
|
||||||
#endif
|
#endif
|
||||||
|
graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga);
|
||||||
qemu_spice_create_host_primary(&d->ssd);
|
qemu_spice_create_host_primary(&d->ssd);
|
||||||
d->mode = QXL_MODE_VGA;
|
d->mode = QXL_MODE_VGA;
|
||||||
vga_dirty_log_start(&d->vga);
|
vga_dirty_log_start(&d->vga);
|
||||||
@@ -1097,6 +1104,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
trace_qxl_exit_vga_mode(d->id);
|
trace_qxl_exit_vga_mode(d->id);
|
||||||
|
graphic_console_set_hwops(d->ssd.dcl.con, &qxl_ops, d);
|
||||||
vga_dirty_log_stop(&d->vga);
|
vga_dirty_log_stop(&d->vga);
|
||||||
qxl_destroy_primary(d, QXL_SYNC);
|
qxl_destroy_primary(d, QXL_SYNC);
|
||||||
}
|
}
|
||||||
@@ -1756,41 +1764,8 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
|
|||||||
static void qxl_hw_update(void *opaque)
|
static void qxl_hw_update(void *opaque)
|
||||||
{
|
{
|
||||||
PCIQXLDevice *qxl = opaque;
|
PCIQXLDevice *qxl = opaque;
|
||||||
VGACommonState *vga = &qxl->vga;
|
|
||||||
|
|
||||||
switch (qxl->mode) {
|
qxl_render_update(qxl);
|
||||||
case QXL_MODE_VGA:
|
|
||||||
vga->hw_ops->gfx_update(vga);
|
|
||||||
break;
|
|
||||||
case QXL_MODE_COMPAT:
|
|
||||||
case QXL_MODE_NATIVE:
|
|
||||||
qxl_render_update(qxl);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qxl_hw_invalidate(void *opaque)
|
|
||||||
{
|
|
||||||
PCIQXLDevice *qxl = opaque;
|
|
||||||
VGACommonState *vga = &qxl->vga;
|
|
||||||
|
|
||||||
if (qxl->mode == QXL_MODE_VGA) {
|
|
||||||
vga->hw_ops->invalidate(vga);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
|
|
||||||
{
|
|
||||||
PCIQXLDevice *qxl = opaque;
|
|
||||||
VGACommonState *vga = &qxl->vga;
|
|
||||||
|
|
||||||
if (qxl->mode == QXL_MODE_VGA) {
|
|
||||||
vga->hw_ops->text_update(vga, chardata);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
|
static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
|
||||||
@@ -1979,14 +1954,14 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
|||||||
|
|
||||||
qxl->rom_size = qxl_rom_size();
|
qxl->rom_size = qxl_rom_size();
|
||||||
memory_region_init_ram(&qxl->rom_bar, OBJECT(qxl), "qxl.vrom",
|
memory_region_init_ram(&qxl->rom_bar, OBJECT(qxl), "qxl.vrom",
|
||||||
qxl->rom_size);
|
qxl->rom_size, &error_abort);
|
||||||
vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev);
|
vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev);
|
||||||
init_qxl_rom(qxl);
|
init_qxl_rom(qxl);
|
||||||
init_qxl_ram(qxl);
|
init_qxl_ram(qxl);
|
||||||
|
|
||||||
qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
|
qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
|
||||||
memory_region_init_ram(&qxl->vram_bar, OBJECT(qxl), "qxl.vram",
|
memory_region_init_ram(&qxl->vram_bar, OBJECT(qxl), "qxl.vram",
|
||||||
qxl->vram_size);
|
qxl->vram_size, &error_abort);
|
||||||
vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
|
vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
|
||||||
memory_region_init_alias(&qxl->vram32_bar, OBJECT(qxl), "qxl.vram32",
|
memory_region_init_alias(&qxl->vram32_bar, OBJECT(qxl), "qxl.vram32",
|
||||||
&qxl->vram_bar, 0, qxl->vram32_size);
|
&qxl->vram_bar, 0, qxl->vram32_size);
|
||||||
@@ -2049,12 +2024,6 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const GraphicHwOps qxl_ops = {
|
|
||||||
.invalidate = qxl_hw_invalidate,
|
|
||||||
.gfx_update = qxl_hw_update,
|
|
||||||
.text_update = qxl_hw_text_update,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int qxl_init_primary(PCIDevice *dev)
|
static int qxl_init_primary(PCIDevice *dev)
|
||||||
{
|
{
|
||||||
PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
|
PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
|
||||||
@@ -2095,7 +2064,7 @@ static int qxl_init_secondary(PCIDevice *dev)
|
|||||||
qxl->id = device_id++;
|
qxl->id = device_id++;
|
||||||
qxl_init_ramsize(qxl);
|
qxl_init_ramsize(qxl);
|
||||||
memory_region_init_ram(&qxl->vga.vram, OBJECT(dev), "qxl.vgavram",
|
memory_region_init_ram(&qxl->vga.vram, OBJECT(dev), "qxl.vgavram",
|
||||||
qxl->vga.vram_size);
|
qxl->vga.vram_size, &error_abort);
|
||||||
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
|
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
|
||||||
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
|
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
|
||||||
qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
|
qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
|
||||||
|
|||||||
@@ -1410,7 +1410,7 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
|
|||||||
|
|
||||||
/* allocate local memory */
|
/* allocate local memory */
|
||||||
memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
|
memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
|
||||||
local_mem_bytes);
|
local_mem_bytes, &error_abort);
|
||||||
vmstate_register_ram_global(&s->local_mem_region);
|
vmstate_register_ram_global(&s->local_mem_region);
|
||||||
s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
|
s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
|
||||||
memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
|
memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user