Compare commits
498 Commits
pull-usb-2
...
pull-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e6a64cb8d | ||
|
|
2330e9e7cc | ||
|
|
d4df42c431 | ||
|
|
c80276b420 | ||
|
|
d7b7f526b1 | ||
|
|
96d7c0720e | ||
|
|
57a4e3b92b | ||
|
|
cde8dcbc92 | ||
|
|
f1ef557866 | ||
|
|
7de2cc8f78 | ||
|
|
a91a4e7d8c | ||
|
|
b3b22db69f | ||
|
|
f7d3f8c0c0 | ||
|
|
93d16d81c8 | ||
|
|
cdd85eb280 | ||
|
|
0a608a6e13 | ||
|
|
4e3bfc167d | ||
|
|
ab9746570a | ||
|
|
bd4976838d | ||
|
|
af9ed379fc | ||
|
|
bf328399da | ||
|
|
3e5cfba3ca | ||
|
|
67d5cd9722 | ||
|
|
90a0f9afec | ||
|
|
5d1abf2344 | ||
|
|
06a96dae11 | ||
|
|
c188e30315 | ||
|
|
67aad508de | ||
|
|
e7d336959b | ||
|
|
f7c40aa1e7 | ||
|
|
b804e8a62a | ||
|
|
dd70bd0d4c | ||
|
|
3f9e485964 | ||
|
|
cf2499350a | ||
|
|
bb0995468a | ||
|
|
e468b6730c | ||
|
|
07c6f329bd | ||
|
|
b39b7718dc | ||
|
|
cdbd727c20 | ||
|
|
7399a337e4 | ||
|
|
81daabaf7a | ||
|
|
a390284b80 | ||
|
|
7e9a7c50d9 | ||
|
|
4aa3f4dd5b | ||
|
|
40bfe48f1c | ||
|
|
217f1b4a72 | ||
|
|
87f8b62604 | ||
|
|
c35bd19a5c | ||
|
|
d6276d26bd | ||
|
|
6aff24c6a6 | ||
|
|
09f71b054a | ||
|
|
62a48a2a57 | ||
|
|
cf2887c973 | ||
|
|
7eb24386db | ||
|
|
fb02d56e96 | ||
|
|
adae837d40 | ||
|
|
39a3b377b8 | ||
|
|
77280adbdf | ||
|
|
8d76bfe8f8 | ||
|
|
823efc5d26 | ||
|
|
4f4a9ca4a4 | ||
|
|
66542f6399 | ||
|
|
eef9f19eea | ||
|
|
e0dadc1e9e | ||
|
|
5229f45bd9 | ||
|
|
bb14a1eda0 | ||
|
|
90e26f5aac | ||
|
|
5563168c53 | ||
|
|
69e87b3268 | ||
|
|
91d3550990 | ||
|
|
0c56c6ab68 | ||
|
|
975b1c3ac6 | ||
|
|
fc5d0a2b24 | ||
|
|
b6954712ab | ||
|
|
37f9e0a2b6 | ||
|
|
a15fcc3cf6 | ||
|
|
3b098d5697 | ||
|
|
23d1705f42 | ||
|
|
a8fff94d28 | ||
|
|
1830f22a67 | ||
|
|
e7ca565629 | ||
|
|
b70ce1018a | ||
|
|
7a0525c7be | ||
|
|
09204eac9b | ||
|
|
2c0ef9f411 | ||
|
|
1158bb2a05 | ||
|
|
911ee36d41 | ||
|
|
c7eb39cbd4 | ||
|
|
9d8256ebc0 | ||
|
|
c61d8126fc | ||
|
|
c540128f93 | ||
|
|
015e02f880 | ||
|
|
1331eab216 | ||
|
|
3cb5158f15 | ||
|
|
726bdf653a | ||
|
|
2f5ae772c6 | ||
|
|
de1b9b85ef | ||
|
|
ada03a0e84 | ||
|
|
1f00b27f17 | ||
|
|
59d7c14eef | ||
|
|
120c1084ed | ||
|
|
5f6f0e27fb | ||
|
|
07bee7f4f4 | ||
|
|
791b7d2340 | ||
|
|
b0aaca4d7f | ||
|
|
f1f7a1ddf3 | ||
|
|
a03ef88f77 | ||
|
|
e293b7a3df | ||
|
|
720ff280e7 | ||
|
|
d9ca2ea2e2 | ||
|
|
cf2ab8fc34 | ||
|
|
18d51c4bac | ||
|
|
fbcbbf4e80 | ||
|
|
f8e2bd538d | ||
|
|
83fd6dd3e7 | ||
|
|
adad6496c5 | ||
|
|
0d1049c7d1 | ||
|
|
ebb7af2173 | ||
|
|
25ec177d90 | ||
|
|
28b04a8f65 | ||
|
|
db1e80ee2e | ||
|
|
e858a9705c | ||
|
|
eecc77473b | ||
|
|
a9d52a7563 | ||
|
|
1c42f149dd | ||
|
|
5411541270 | ||
|
|
8cc9c6e92b | ||
|
|
a5b8dd2ce8 | ||
|
|
d9e0dfa246 | ||
|
|
ad82be2f4f | ||
|
|
b9f7855a50 | ||
|
|
29cc6a6834 | ||
|
|
5def6b80e1 | ||
|
|
79ba8c986a | ||
|
|
a65064816d | ||
|
|
2914a1de99 | ||
|
|
a84178ccff | ||
|
|
c8b3b998e2 | ||
|
|
835db3ee7b | ||
|
|
24ce9a2026 | ||
|
|
efaf4781a9 | ||
|
|
f9e95af0a6 | ||
|
|
202204717a | ||
|
|
476b923c32 | ||
|
|
82524274ea | ||
|
|
a604fa2ba5 | ||
|
|
cff86b38ac | ||
|
|
cfef6a45c7 | ||
|
|
60a0f1af07 | ||
|
|
269fe4c3ab | ||
|
|
66bf7d58d8 | ||
|
|
1070048eae | ||
|
|
2e2aa31674 | ||
|
|
afea4e1410 | ||
|
|
1108b2f8a9 | ||
|
|
69b205bb0b | ||
|
|
b4b4a57fa6 | ||
|
|
444dd1af1c | ||
|
|
c0f2abff73 | ||
|
|
290fd20db6 | ||
|
|
b2e1fffb5a | ||
|
|
8662d7db39 | ||
|
|
2c7ad80443 | ||
|
|
912acdf487 | ||
|
|
949868633f | ||
|
|
073de86aa9 | ||
|
|
651060aba7 | ||
|
|
1f0252e66e | ||
|
|
ae4de14cd3 | ||
|
|
2e4109de8e | ||
|
|
f4ec5e26ed | ||
|
|
318f67ce13 | ||
|
|
606b54986d | ||
|
|
c4e6c42353 | ||
|
|
7093645a84 | ||
|
|
158c87e5de | ||
|
|
600426f2df | ||
|
|
1165942311 | ||
|
|
0d7e96c9b5 | ||
|
|
3b1154fff1 | ||
|
|
a1c5e949dd | ||
|
|
13f12430d4 | ||
|
|
9164b89762 | ||
|
|
6b9c1dd2cd | ||
|
|
58eeb83cc7 | ||
|
|
6dd726a2bf | ||
|
|
a0efbf1660 | ||
|
|
58e19e6e79 | ||
|
|
5178ecd863 | ||
|
|
3173a1fd54 | ||
|
|
9b9611c85d | ||
|
|
e1ad9bc405 | ||
|
|
924ed16386 | ||
|
|
7c1c69bca4 | ||
|
|
73bce5187b | ||
|
|
b7f480c3f6 | ||
|
|
b68cb06093 | ||
|
|
cace7b801d | ||
|
|
7673bb4cd3 | ||
|
|
f4b99537f1 | ||
|
|
034c2e6902 | ||
|
|
a74229597e | ||
|
|
49e14ddbce | ||
|
|
684204593d | ||
|
|
0b73c9bb06 | ||
|
|
1599121b57 | ||
|
|
ae2923b5c2 | ||
|
|
5d636e21c4 | ||
|
|
a19861666b | ||
|
|
39e0b03dec | ||
|
|
a7aeb5f7b2 | ||
|
|
a1777f7f64 | ||
|
|
f5666418c4 | ||
|
|
d317091d5e | ||
|
|
6c6668232e | ||
|
|
62cee1a28a | ||
|
|
0830c96d70 | ||
|
|
01c9742d9d | ||
|
|
97a83ec3a9 | ||
|
|
10d01f73e3 | ||
|
|
621d983a1f | ||
|
|
bf8d492405 | ||
|
|
b86eacb804 | ||
|
|
1b04cc801a | ||
|
|
5ec7d09818 | ||
|
|
e2c8f9e44e | ||
|
|
0c16c056a4 | ||
|
|
8cbfc94269 | ||
|
|
8b7cdba386 | ||
|
|
6e03a28e1c | ||
|
|
ea996ebd65 | ||
|
|
4e04ab6a63 | ||
|
|
8692aa2979 | ||
|
|
7b143999f2 | ||
|
|
e5857062a6 | ||
|
|
f7725df387 | ||
|
|
ef763fa4bd | ||
|
|
1d17654e76 | ||
|
|
972487b878 | ||
|
|
96b39d8327 | ||
|
|
9a48e36700 | ||
|
|
b05528b533 | ||
|
|
8d85a22aab | ||
|
|
1b756f1abf | ||
|
|
8df42d855c | ||
|
|
45027808cd | ||
|
|
94e31093ff | ||
|
|
1fb4c13e4f | ||
|
|
13f5e8003e | ||
|
|
8a1eb71bd8 | ||
|
|
f11235b920 | ||
|
|
8e758dee66 | ||
|
|
470f215787 | ||
|
|
9e196938aa | ||
|
|
27f2458245 | ||
|
|
1cbd222055 | ||
|
|
9c7027ba94 | ||
|
|
161deaf225 | ||
|
|
4322e8ced5 | ||
|
|
a36848ff7c | ||
|
|
ff461b8da9 | ||
|
|
dde35bc966 | ||
|
|
6cc09e261b | ||
|
|
f2b70fded9 | ||
|
|
635dff20a3 | ||
|
|
4b236b621b | ||
|
|
b378bb0948 | ||
|
|
d1dbe37c1e | ||
|
|
4b3fc37788 | ||
|
|
88536935c0 | ||
|
|
8eeb330c69 | ||
|
|
3cb3b1549f | ||
|
|
d22d8956b1 | ||
|
|
e37dac06dc | ||
|
|
325ae8d548 | ||
|
|
4d3fc4fdc6 | ||
|
|
ddf31aa853 | ||
|
|
8a0b4de048 | ||
|
|
db486cc334 | ||
|
|
7c47959d0c | ||
|
|
fec0fc0a13 | ||
|
|
9b4e38fe6a | ||
|
|
01fb8e192d | ||
|
|
ff5394ad5b | ||
|
|
ba4dba5434 | ||
|
|
297e8005f8 | ||
|
|
8c1cd719a5 | ||
|
|
1ec20c2a3a | ||
|
|
ef8757f1fe | ||
|
|
74b6ce43e3 | ||
|
|
3fa27a9a1e | ||
|
|
c1111a24a3 | ||
|
|
25f0d2aa5e | ||
|
|
634d39b4e3 | ||
|
|
845d1e7e42 | ||
|
|
66f37d360b | ||
|
|
8f242cb724 | ||
|
|
6d356c8c9e | ||
|
|
9f34a35e00 | ||
|
|
a1df76da57 | ||
|
|
6f1de6b70d | ||
|
|
b0585e7e07 | ||
|
|
bce933b85a | ||
|
|
807464d8a7 | ||
|
|
0ead93120e | ||
|
|
8642c1b81e | ||
| be968c721e | |||
|
|
33df7bf3bf | ||
|
|
cc96677469 | ||
|
|
3638439d54 | ||
|
|
250263033c | ||
|
|
ea5d42508c | ||
|
|
f999c0de05 | ||
|
|
35a6b23c82 | ||
|
|
a94dd6a9d6 | ||
|
|
f62efcacfa | ||
|
|
f2dd8ebdf4 | ||
|
|
d812b3d68d | ||
|
|
3115b9e2d2 | ||
|
|
8d1c7158a0 | ||
|
|
401f2f3ef1 | ||
|
|
1a004c7fc8 | ||
|
|
936a6447c8 | ||
|
|
873b4d3f05 | ||
|
|
e8ad4d1680 | ||
|
|
3e904d6ade | ||
|
|
15d6729850 | ||
|
|
b48100cf07 | ||
|
|
ccee3d8f97 | ||
|
|
e4808881cb | ||
|
|
176129552f | ||
|
|
7eac868a50 | ||
|
|
ff04198bf5 | ||
|
|
d99b26c42a | ||
|
|
38f8d5e025 | ||
|
|
947eb2030e | ||
|
|
9c15e70086 | ||
|
|
06a1e0c197 | ||
|
|
10985131e3 | ||
|
|
39ca463e81 | ||
|
|
e9a80859d6 | ||
|
|
e9e0bb2af2 | ||
|
|
eeb2b8f78d | ||
|
|
e370ad9999 | ||
|
|
d7f3040357 | ||
|
|
7dd929dfdc | ||
|
|
92fe2ba8b0 | ||
|
|
b7a511248d | ||
|
|
12c8720d8f | ||
|
|
2f2705908f | ||
|
|
51b04ac5c6 | ||
|
|
30d8bf6d17 | ||
|
|
edaffd9f0b | ||
|
|
b234cdda95 | ||
|
|
e21737ab15 | ||
|
|
84419863f7 | ||
|
|
5fa78b2a1c | ||
|
|
17c42b1f6b | ||
|
|
40428feaeb | ||
|
|
aa4b04a09c | ||
|
|
dc154b1db4 | ||
|
|
c508277335 | ||
|
|
46fe8bef4d | ||
|
|
7e8449594c | ||
|
|
d88d3a0938 | ||
|
|
ca1ee3d6b5 | ||
|
|
fdc997ef54 | ||
|
|
0d0437aac6 | ||
|
|
14e60aaece | ||
|
|
7542d3e706 | ||
|
|
4071887b58 | ||
|
|
6960bfca3a | ||
|
|
4d9be25200 | ||
|
|
f12103afaa | ||
|
|
3830c7a460 | ||
|
|
dadb2f9078 | ||
|
|
cf6f1efe0b | ||
|
|
d9cc8701f1 | ||
|
|
7a69c10002 | ||
|
|
30467afe7b | ||
|
|
9964674e50 | ||
|
|
e02b3bf263 | ||
|
|
e3ba6cd67f | ||
|
|
c7cd0a6c24 | ||
|
|
87e79af074 | ||
|
|
334973bbae | ||
|
|
1c8a2388aa | ||
|
|
1f5c1cfbae | ||
|
|
cbdab58d46 | ||
|
|
f265ae8c79 | ||
|
|
f6cf41932e | ||
|
|
92b30c2f7d | ||
|
|
aa8151b7df | ||
|
|
4b86bac21c | ||
|
|
929bf947f7 | ||
|
|
27393c33d8 | ||
|
|
62c9467dff | ||
|
|
d29f086169 | ||
|
|
6d18a7a1ff | ||
|
|
4ba92cd736 | ||
|
|
c9bc3437a9 | ||
|
|
31f875f211 | ||
|
|
e942fefa6e | ||
|
|
5d3acaf89c | ||
|
|
4eed9990a0 | ||
|
|
b9403979b5 | ||
|
|
48dc0f2c3d | ||
|
|
84f34b00c8 | ||
|
|
9a6309e7fa | ||
|
|
84bd828429 | ||
|
|
8997d1bd18 | ||
|
|
fb3aabf384 | ||
|
|
7e3b92ece0 | ||
|
|
4debae6fa5 | ||
|
|
ba4537805d | ||
|
|
c5679026d5 | ||
|
|
4259a820d2 | ||
|
|
affc88cc9b | ||
|
|
997f6ed3a1 | ||
|
|
1d48fdd9d8 | ||
|
|
435da5e709 | ||
|
|
213d3e9ea2 | ||
|
|
b64d2e57e7 | ||
|
|
77be419980 | ||
|
|
599bc5e89c | ||
|
|
87552089b6 | ||
|
|
6be7748005 | ||
|
|
40bd6dd456 | ||
|
|
52d4c8ee93 | ||
|
|
c27644f0e9 | ||
|
|
a7c04d545a | ||
|
|
a59eaea646 | ||
|
|
af39bc8c49 | ||
|
|
c52125ab92 | ||
|
|
43716de6b3 | ||
|
|
1676103dc2 | ||
|
|
4d9dc8b7a8 | ||
|
|
c9c3dc5f4b | ||
|
|
ffdc5a2bce | ||
|
|
a01aef5d2f | ||
|
|
55d72a7eb3 | ||
|
|
21a4d96243 | ||
|
|
c0971bcb7c | ||
|
|
9f06e71a56 | ||
|
|
7c55f68a63 | ||
|
|
b1f0a33d80 | ||
|
|
6798e245a3 | ||
|
|
1f3aba377d | ||
|
|
d8d69e1f51 | ||
|
|
679dd1a957 | ||
|
|
76623d00ae | ||
|
|
8872c25a26 | ||
|
|
d2238cb678 | ||
|
|
ac35f13ba8 | ||
|
|
5e1b5d9388 | ||
|
|
16bcab97eb | ||
|
|
abd49bc2ed | ||
|
|
aa1dd39ca3 | ||
|
|
15b82b1dc5 | ||
|
|
14e44198ff | ||
|
|
2b9e57fc7f | ||
|
|
5797dcdc7a | ||
|
|
d15fc53f8d | ||
|
|
189f4d5635 | ||
|
|
90623ebf60 | ||
|
|
4568c94806 | ||
|
|
732b530c1b | ||
|
|
052889b8e9 | ||
|
|
b265f27c5a | ||
|
|
d6fb213a62 | ||
|
|
8df1426e44 | ||
|
|
f4eda2d429 | ||
|
|
86e91dd713 | ||
|
|
35658f6e0c | ||
|
|
0517cc9863 | ||
|
|
c728876752 | ||
|
|
c6eb076aec | ||
|
|
59a79f65ba | ||
|
|
86b50f2e1b | ||
|
|
7778a575c7 | ||
|
|
b9971cc53e | ||
|
|
5c3ae92910 | ||
|
|
b781537560 | ||
|
|
9b2fadda3e | ||
|
|
33595dc9f3 | ||
|
|
f03a1af581 | ||
|
|
6d49d6d4ed | ||
|
|
61687db252 | ||
|
|
a2e71b28e8 | ||
|
|
25f8f6b4c2 | ||
|
|
16246018d3 | ||
|
|
0d8e58942a | ||
|
|
f682e9c244 | ||
|
|
f0278900d3 | ||
|
|
820724d170 | ||
|
|
7f2b1744b3 | ||
|
|
0ccac16f59 | ||
|
|
c117590769 |
10
MAINTAINERS
10
MAINTAINERS
@@ -888,12 +888,13 @@ F: include/hw/virtio/
|
|||||||
|
|
||||||
virtio-9p
|
virtio-9p
|
||||||
M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||||
M: Greg Kurz <gkurz@linux.vnet.ibm.com>
|
M: Greg Kurz <groug@kaod.org>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: hw/9pfs/
|
F: hw/9pfs/
|
||||||
F: fsdev/
|
F: fsdev/
|
||||||
F: tests/virtio-9p-test.c
|
F: tests/virtio-9p-test.c
|
||||||
T: git git://github.com/kvaneesh/QEMU.git
|
T: git git://github.com/kvaneesh/QEMU.git
|
||||||
|
T: git git://github.com/gkurz/qemu.git 9p-next
|
||||||
|
|
||||||
virtio-blk
|
virtio-blk
|
||||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||||
@@ -1261,7 +1262,6 @@ F: docs/tracing.txt
|
|||||||
T: git git://github.com/stefanha/qemu.git tracing
|
T: git git://github.com/stefanha/qemu.git tracing
|
||||||
|
|
||||||
Checkpatch
|
Checkpatch
|
||||||
M: Blue Swirl <blauwirbel@gmail.com>
|
|
||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
F: scripts/checkpatch.pl
|
F: scripts/checkpatch.pl
|
||||||
|
|
||||||
@@ -1334,8 +1334,7 @@ F: thunk.c
|
|||||||
F: user-exec.c
|
F: user-exec.c
|
||||||
|
|
||||||
BSD user
|
BSD user
|
||||||
M: Blue Swirl <blauwirbel@gmail.com>
|
S: Orphan
|
||||||
S: Maintained
|
|
||||||
F: bsd-user/
|
F: bsd-user/
|
||||||
|
|
||||||
Linux user
|
Linux user
|
||||||
@@ -1398,8 +1397,7 @@ F: tcg/s390/
|
|||||||
F: disas/s390.c
|
F: disas/s390.c
|
||||||
|
|
||||||
SPARC target
|
SPARC target
|
||||||
M: Blue Swirl <blauwirbel@gmail.com>
|
S: Odd Fixes
|
||||||
S: Maintained
|
|
||||||
F: tcg/sparc/
|
F: tcg/sparc/
|
||||||
F: disas/sparc.c
|
F: disas/sparc.c
|
||||||
|
|
||||||
|
|||||||
10
Makefile
10
Makefile
@@ -30,7 +30,7 @@ CONFIG_ALL=y
|
|||||||
-include config-all-devices.mak
|
-include config-all-devices.mak
|
||||||
-include config-all-disas.mak
|
-include config-all-disas.mak
|
||||||
|
|
||||||
config-host.mak: $(SRC_PATH)/configure
|
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios
|
||||||
@echo $@ is out-of-date, running configure
|
@echo $@ is out-of-date, running configure
|
||||||
@# TODO: The next lines include code which supports a smooth
|
@# TODO: The next lines include code which supports a smooth
|
||||||
@# transition from old configurations without config.status.
|
@# transition from old configurations without config.status.
|
||||||
@@ -416,6 +416,7 @@ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
|
|||||||
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
|
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
|
||||||
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
|
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
|
||||||
efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \
|
efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \
|
||||||
|
efi-e1000e.rom efi-vmxnet3.rom \
|
||||||
qemu-icon.bmp qemu_logo_no_text.svg \
|
qemu-icon.bmp qemu_logo_no_text.svg \
|
||||||
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
|
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
|
||||||
multiboot.bin linuxboot.bin kvmvapic.bin \
|
multiboot.bin linuxboot.bin kvmvapic.bin \
|
||||||
@@ -564,8 +565,9 @@ qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
|
|||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
|
||||||
$(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
|
$(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
|
||||||
" GEN $@")
|
" GEN $@")
|
||||||
|
qemu.1: qemu-option-trace.texi
|
||||||
|
|
||||||
qemu-img.1: qemu-img.texi qemu-img-cmds.texi
|
qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
|
||||||
$(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \
|
$(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \
|
||||||
@@ -577,7 +579,7 @@ fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
|
|||||||
$(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
|
$(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
|
||||||
" GEN $@")
|
" GEN $@")
|
||||||
|
|
||||||
qemu-nbd.8: qemu-nbd.texi
|
qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
|
||||||
$(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
|
$(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
|
||||||
@@ -595,7 +597,7 @@ info: qemu-doc.info qemu-tech.info
|
|||||||
pdf: qemu-doc.pdf qemu-tech.pdf
|
pdf: qemu-doc.pdf qemu-tech.pdf
|
||||||
|
|
||||||
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
|
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
|
||||||
qemu-img.texi qemu-nbd.texi qemu-options.texi \
|
qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
|
||||||
qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \
|
qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \
|
||||||
qemu-monitor-info.texi
|
qemu-monitor-info.texi
|
||||||
|
|
||||||
|
|||||||
@@ -108,11 +108,8 @@ obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/dpd/decimal128.o
|
|||||||
|
|
||||||
ifdef CONFIG_LINUX_USER
|
ifdef CONFIG_LINUX_USER
|
||||||
|
|
||||||
# Note that we only add linux-user/host/$ARCH if it exists, and
|
|
||||||
# that it must come before linux-user/host/generic in the search path.
|
|
||||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
|
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
|
||||||
$(patsubst %,-I%,$(wildcard $(SRC_PATH)/linux-user/host/$(ARCH))) \
|
-I$(SRC_PATH)/linux-user/host/$(ARCH) \
|
||||||
-I$(SRC_PATH)/linux-user/host/generic \
|
|
||||||
-I$(SRC_PATH)/linux-user
|
-I$(SRC_PATH)/linux-user
|
||||||
|
|
||||||
obj-y += linux-user/
|
obj-y += linux-user/
|
||||||
|
|||||||
@@ -25,16 +25,51 @@
|
|||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "sysemu/char.h"
|
#include "sysemu/char.h"
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
|
#include "ui/input.h"
|
||||||
|
|
||||||
#define MSMOUSE_LO6(n) ((n) & 0x3f)
|
#define MSMOUSE_LO6(n) ((n) & 0x3f)
|
||||||
#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
|
#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
|
||||||
|
|
||||||
static void msmouse_event(void *opaque,
|
typedef struct {
|
||||||
int dx, int dy, int dz, int buttons_state)
|
CharDriverState *chr;
|
||||||
{
|
QemuInputHandlerState *hs;
|
||||||
CharDriverState *chr = (CharDriverState *)opaque;
|
int axis[INPUT_AXIS__MAX];
|
||||||
|
bool btns[INPUT_BUTTON__MAX];
|
||||||
|
bool btnc[INPUT_BUTTON__MAX];
|
||||||
|
uint8_t outbuf[32];
|
||||||
|
int outlen;
|
||||||
|
} MouseState;
|
||||||
|
|
||||||
|
static void msmouse_chr_accept_input(CharDriverState *chr)
|
||||||
|
{
|
||||||
|
MouseState *mouse = chr->opaque;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = qemu_chr_be_can_write(chr);
|
||||||
|
if (len > mouse->outlen) {
|
||||||
|
len = mouse->outlen;
|
||||||
|
}
|
||||||
|
if (!len) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_chr_be_write(chr, mouse->outbuf, len);
|
||||||
|
mouse->outlen -= len;
|
||||||
|
if (mouse->outlen) {
|
||||||
|
memmove(mouse->outbuf, mouse->outbuf + len, mouse->outlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msmouse_queue_event(MouseState *mouse)
|
||||||
|
{
|
||||||
unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 };
|
unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 };
|
||||||
|
int dx, dy, count = 3;
|
||||||
|
|
||||||
|
dx = mouse->axis[INPUT_AXIS_X];
|
||||||
|
mouse->axis[INPUT_AXIS_X] = 0;
|
||||||
|
|
||||||
|
dy = mouse->axis[INPUT_AXIS_Y];
|
||||||
|
mouse->axis[INPUT_AXIS_Y] = 0;
|
||||||
|
|
||||||
/* Movement deltas */
|
/* Movement deltas */
|
||||||
bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx);
|
bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx);
|
||||||
@@ -42,14 +77,54 @@ static void msmouse_event(void *opaque,
|
|||||||
bytes[2] |= MSMOUSE_LO6(dy);
|
bytes[2] |= MSMOUSE_LO6(dy);
|
||||||
|
|
||||||
/* Buttons */
|
/* Buttons */
|
||||||
bytes[0] |= (buttons_state & 0x01 ? 0x20 : 0x00);
|
bytes[0] |= (mouse->btns[INPUT_BUTTON_LEFT] ? 0x20 : 0x00);
|
||||||
bytes[0] |= (buttons_state & 0x02 ? 0x10 : 0x00);
|
bytes[0] |= (mouse->btns[INPUT_BUTTON_RIGHT] ? 0x10 : 0x00);
|
||||||
bytes[3] |= (buttons_state & 0x04 ? 0x20 : 0x00);
|
if (mouse->btns[INPUT_BUTTON_MIDDLE] ||
|
||||||
|
mouse->btnc[INPUT_BUTTON_MIDDLE]) {
|
||||||
|
bytes[3] |= (mouse->btns[INPUT_BUTTON_MIDDLE] ? 0x20 : 0x00);
|
||||||
|
mouse->btnc[INPUT_BUTTON_MIDDLE] = false;
|
||||||
|
count = 4;
|
||||||
|
}
|
||||||
|
|
||||||
/* We always send the packet of, so that we do not have to keep track
|
if (mouse->outlen <= sizeof(mouse->outbuf) - count) {
|
||||||
of previous state of the middle button. This can potentially confuse
|
memcpy(mouse->outbuf + mouse->outlen, bytes, count);
|
||||||
some very old drivers for two button mice though. */
|
mouse->outlen += count;
|
||||||
qemu_chr_be_write(chr, bytes, 4);
|
} else {
|
||||||
|
/* queue full -> drop event */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
|
||||||
|
InputEvent *evt)
|
||||||
|
{
|
||||||
|
MouseState *mouse = (MouseState *)dev;
|
||||||
|
InputMoveEvent *move;
|
||||||
|
InputBtnEvent *btn;
|
||||||
|
|
||||||
|
switch (evt->type) {
|
||||||
|
case INPUT_EVENT_KIND_REL:
|
||||||
|
move = evt->u.rel.data;
|
||||||
|
mouse->axis[move->axis] += move->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INPUT_EVENT_KIND_BTN:
|
||||||
|
btn = evt->u.btn.data;
|
||||||
|
mouse->btns[btn->button] = btn->down;
|
||||||
|
mouse->btnc[btn->button] = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* keep gcc happy */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msmouse_input_sync(DeviceState *dev)
|
||||||
|
{
|
||||||
|
MouseState *mouse = (MouseState *)dev;
|
||||||
|
|
||||||
|
msmouse_queue_event(mouse);
|
||||||
|
msmouse_chr_accept_input(mouse->chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
|
static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
|
||||||
@@ -60,26 +135,41 @@ static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int
|
|||||||
|
|
||||||
static void msmouse_chr_close (struct CharDriverState *chr)
|
static void msmouse_chr_close (struct CharDriverState *chr)
|
||||||
{
|
{
|
||||||
g_free (chr);
|
MouseState *mouse = chr->opaque;
|
||||||
|
|
||||||
|
qemu_input_handler_unregister(mouse->hs);
|
||||||
|
g_free(mouse);
|
||||||
|
g_free(chr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QemuInputHandler msmouse_handler = {
|
||||||
|
.name = "QEMU Microsoft Mouse",
|
||||||
|
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
|
||||||
|
.event = msmouse_input_event,
|
||||||
|
.sync = msmouse_input_sync,
|
||||||
|
};
|
||||||
|
|
||||||
static CharDriverState *qemu_chr_open_msmouse(const char *id,
|
static CharDriverState *qemu_chr_open_msmouse(const char *id,
|
||||||
ChardevBackend *backend,
|
ChardevBackend *backend,
|
||||||
ChardevReturn *ret,
|
ChardevReturn *ret,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ChardevCommon *common = backend->u.msmouse.data;
|
ChardevCommon *common = backend->u.msmouse.data;
|
||||||
|
MouseState *mouse;
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
|
|
||||||
chr = qemu_chr_alloc(common, errp);
|
chr = qemu_chr_alloc(common, errp);
|
||||||
if (!chr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
chr->chr_write = msmouse_chr_write;
|
chr->chr_write = msmouse_chr_write;
|
||||||
chr->chr_close = msmouse_chr_close;
|
chr->chr_close = msmouse_chr_close;
|
||||||
|
chr->chr_accept_input = msmouse_chr_accept_input;
|
||||||
chr->explicit_be_open = true;
|
chr->explicit_be_open = true;
|
||||||
|
|
||||||
qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse");
|
mouse = g_new0(MouseState, 1);
|
||||||
|
mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
|
||||||
|
&msmouse_handler);
|
||||||
|
|
||||||
|
mouse->chr = chr;
|
||||||
|
chr->opaque = mouse;
|
||||||
|
|
||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|||||||
142
block.c
142
block.c
@@ -536,9 +536,10 @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
|
|||||||
return drv;
|
return drv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_image_format(BlockDriverState *bs, const char *filename,
|
static int find_image_format(BdrvChild *file, const char *filename,
|
||||||
BlockDriver **pdrv, Error **errp)
|
BlockDriver **pdrv, Error **errp)
|
||||||
{
|
{
|
||||||
|
BlockDriverState *bs = file->bs;
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
uint8_t buf[BLOCK_PROBE_BUF_SIZE];
|
uint8_t buf[BLOCK_PROBE_BUF_SIZE];
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -549,7 +550,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs, 0, buf, sizeof(buf));
|
ret = bdrv_pread(file, 0, buf, sizeof(buf));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not read image for determining its "
|
error_setg_errno(errp, -ret, "Could not read image for determining its "
|
||||||
"format");
|
"format");
|
||||||
@@ -937,7 +938,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
|
|||||||
goto fail_opts;
|
goto fail_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->request_alignment = drv->bdrv_co_preadv ? 1 : 512;
|
|
||||||
bs->read_only = !(bs->open_flags & BDRV_O_RDWR);
|
bs->read_only = !(bs->open_flags & BDRV_O_RDWR);
|
||||||
|
|
||||||
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
|
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
|
||||||
@@ -1017,7 +1017,7 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
|
|||||||
|
|
||||||
assert(bdrv_opt_mem_align(bs) != 0);
|
assert(bdrv_opt_mem_align(bs) != 0);
|
||||||
assert(bdrv_min_mem_align(bs) != 0);
|
assert(bdrv_min_mem_align(bs) != 0);
|
||||||
assert(is_power_of_2(bs->request_alignment) || bdrv_is_sg(bs));
|
assert(is_power_of_2(bs->bl.request_alignment));
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1653,7 +1653,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
|||||||
/* Image format probing */
|
/* Image format probing */
|
||||||
bs->probed = !drv;
|
bs->probed = !drv;
|
||||||
if (!drv && file) {
|
if (!drv && file) {
|
||||||
ret = find_image_format(file->bs, filename, &drv, &local_err);
|
ret = find_image_format(file, filename, &drv, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -2184,9 +2184,9 @@ static void bdrv_close(BlockDriverState *bs)
|
|||||||
bs->backing_file[0] = '\0';
|
bs->backing_file[0] = '\0';
|
||||||
bs->backing_format[0] = '\0';
|
bs->backing_format[0] = '\0';
|
||||||
bs->total_sectors = 0;
|
bs->total_sectors = 0;
|
||||||
bs->encrypted = 0;
|
bs->encrypted = false;
|
||||||
bs->valid_key = 0;
|
bs->valid_key = false;
|
||||||
bs->sg = 0;
|
bs->sg = false;
|
||||||
QDECREF(bs->options);
|
QDECREF(bs->options);
|
||||||
QDECREF(bs->explicit_options);
|
QDECREF(bs->explicit_options);
|
||||||
bs->options = NULL;
|
bs->options = NULL;
|
||||||
@@ -2323,116 +2323,6 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
|
|||||||
return bs->drv->bdrv_check(bs, res, fix);
|
return bs->drv->bdrv_check(bs, res, fix);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define COMMIT_BUF_SECTORS 2048
|
|
||||||
|
|
||||||
/* commit COW file into the raw image */
|
|
||||||
int bdrv_commit(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
BlockDriver *drv = bs->drv;
|
|
||||||
int64_t sector, total_sectors, length, backing_length;
|
|
||||||
int n, ro, open_flags;
|
|
||||||
int ret = 0;
|
|
||||||
uint8_t *buf = NULL;
|
|
||||||
|
|
||||||
if (!drv)
|
|
||||||
return -ENOMEDIUM;
|
|
||||||
|
|
||||||
if (!bs->backing) {
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) ||
|
|
||||||
bdrv_op_is_blocked(bs->backing->bs, BLOCK_OP_TYPE_COMMIT_TARGET, NULL)) {
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
ro = bs->backing->bs->read_only;
|
|
||||||
open_flags = bs->backing->bs->open_flags;
|
|
||||||
|
|
||||||
if (ro) {
|
|
||||||
if (bdrv_reopen(bs->backing->bs, open_flags | BDRV_O_RDWR, NULL)) {
|
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
length = bdrv_getlength(bs);
|
|
||||||
if (length < 0) {
|
|
||||||
ret = length;
|
|
||||||
goto ro_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
backing_length = bdrv_getlength(bs->backing->bs);
|
|
||||||
if (backing_length < 0) {
|
|
||||||
ret = backing_length;
|
|
||||||
goto ro_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If our top snapshot is larger than the backing file image,
|
|
||||||
* grow the backing file image if possible. If not possible,
|
|
||||||
* we must return an error */
|
|
||||||
if (length > backing_length) {
|
|
||||||
ret = bdrv_truncate(bs->backing->bs, length);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto ro_cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total_sectors = length >> BDRV_SECTOR_BITS;
|
|
||||||
|
|
||||||
/* qemu_try_blockalign() for bs will choose an alignment that works for
|
|
||||||
* bs->backing->bs as well, so no need to compare the alignment manually. */
|
|
||||||
buf = qemu_try_blockalign(bs, COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
|
|
||||||
if (buf == NULL) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto ro_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (sector = 0; sector < total_sectors; sector += n) {
|
|
||||||
ret = bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto ro_cleanup;
|
|
||||||
}
|
|
||||||
if (ret) {
|
|
||||||
ret = bdrv_read(bs, sector, buf, n);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto ro_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bdrv_write(bs->backing->bs, sector, buf, n);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto ro_cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drv->bdrv_make_empty) {
|
|
||||||
ret = drv->bdrv_make_empty(bs);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto ro_cleanup;
|
|
||||||
}
|
|
||||||
bdrv_flush(bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure all data we wrote to the backing device is actually
|
|
||||||
* stable on disk.
|
|
||||||
*/
|
|
||||||
if (bs->backing) {
|
|
||||||
bdrv_flush(bs->backing->bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
ro_cleanup:
|
|
||||||
qemu_vfree(buf);
|
|
||||||
|
|
||||||
if (ro) {
|
|
||||||
/* ignoring error return here */
|
|
||||||
bdrv_reopen(bs->backing->bs, open_flags & ~BDRV_O_RDWR, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return values:
|
* Return values:
|
||||||
* 0 - success
|
* 0 - success
|
||||||
@@ -2644,30 +2534,30 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
|
|||||||
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
|
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_is_read_only(BlockDriverState *bs)
|
bool bdrv_is_read_only(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
return bs->read_only;
|
return bs->read_only;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_is_sg(BlockDriverState *bs)
|
bool bdrv_is_sg(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
return bs->sg;
|
return bs->sg;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_is_encrypted(BlockDriverState *bs)
|
bool bdrv_is_encrypted(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
if (bs->backing && bs->backing->bs->encrypted) {
|
if (bs->backing && bs->backing->bs->encrypted) {
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
return bs->encrypted;
|
return bs->encrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_key_required(BlockDriverState *bs)
|
bool bdrv_key_required(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BdrvChild *backing = bs->backing;
|
BdrvChild *backing = bs->backing;
|
||||||
|
|
||||||
if (backing && backing->bs->encrypted && !backing->bs->valid_key) {
|
if (backing && backing->bs->encrypted && !backing->bs->valid_key) {
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
return (bs->encrypted && !bs->valid_key);
|
return (bs->encrypted && !bs->valid_key);
|
||||||
}
|
}
|
||||||
@@ -2689,10 +2579,10 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
|
|||||||
}
|
}
|
||||||
ret = bs->drv->bdrv_set_key(bs, key);
|
ret = bs->drv->bdrv_set_key(bs, key);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bs->valid_key = 0;
|
bs->valid_key = false;
|
||||||
} else if (!bs->valid_key) {
|
} else if (!bs->valid_key) {
|
||||||
/* call the change callback now, we skipped it on open */
|
/* call the change callback now, we skipped it on open */
|
||||||
bs->valid_key = 1;
|
bs->valid_key = true;
|
||||||
bdrv_parent_cb_change_media(bs, true);
|
bdrv_parent_cb_change_media(bs, true);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ block-obj-y += block-backend.o 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 mirror.o io.o
|
block-obj-y += null.o mirror.o commit.o io.o
|
||||||
block-obj-y += throttle-groups.o
|
block-obj-y += throttle-groups.o
|
||||||
|
|
||||||
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
||||||
@@ -26,7 +26,6 @@ block-obj-y += write-threshold.o
|
|||||||
block-obj-y += crypto.o
|
block-obj-y += crypto.o
|
||||||
|
|
||||||
common-obj-y += stream.o
|
common-obj-y += stream.o
|
||||||
common-obj-y += commit.o
|
|
||||||
common-obj-y += backup.o
|
common-obj-y += backup.o
|
||||||
|
|
||||||
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
|
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||||
|
|||||||
@@ -489,7 +489,6 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
|||||||
|
|
||||||
assert(bs);
|
assert(bs);
|
||||||
assert(target);
|
assert(target);
|
||||||
assert(cb);
|
|
||||||
|
|
||||||
if (bs == target) {
|
if (bs == target) {
|
||||||
error_setg(errp, "Source and target cannot be the same");
|
error_setg(errp, "Source and target cannot be the same");
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
typedef struct BDRVBlkdebugState {
|
typedef struct BDRVBlkdebugState {
|
||||||
int state;
|
int state;
|
||||||
int new_state;
|
int new_state;
|
||||||
|
int align;
|
||||||
|
|
||||||
QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
|
QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
|
||||||
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
|
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
|
||||||
@@ -382,10 +383,10 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set request alignment */
|
/* Set request alignment */
|
||||||
align = qemu_opt_get_size(opts, "align", bs->request_alignment);
|
align = qemu_opt_get_size(opts, "align", 0);
|
||||||
if (align > 0 && align < INT_MAX && !(align & (align - 1))) {
|
if (align < INT_MAX && is_power_of_2(align)) {
|
||||||
bs->request_alignment = align;
|
s->align = align;
|
||||||
} else {
|
} else if (align) {
|
||||||
error_setg(errp, "Invalid alignment");
|
error_setg(errp, "Invalid alignment");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail_unref;
|
goto fail_unref;
|
||||||
@@ -456,7 +457,7 @@ static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
|||||||
return inject_error(bs, cb, opaque, rule);
|
return inject_error(bs, cb, opaque, rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bdrv_aio_readv(bs->file->bs, sector_num, qiov, nb_sectors,
|
return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
|
||||||
cb, opaque);
|
cb, opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,7 +480,7 @@ static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
|||||||
return inject_error(bs, cb, opaque, rule);
|
return inject_error(bs, cb, opaque, rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
|
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
|
||||||
cb, opaque);
|
cb, opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,6 +721,15 @@ static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
|
|||||||
bs->full_open_options = opts;
|
bs->full_open_options = opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
BDRVBlkdebugState *s = bs->opaque;
|
||||||
|
|
||||||
|
if (s->align) {
|
||||||
|
bs->bl.request_alignment = s->align;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
|
static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
|
||||||
BlockReopenQueue *queue, Error **errp)
|
BlockReopenQueue *queue, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -738,6 +748,7 @@ static BlockDriver bdrv_blkdebug = {
|
|||||||
.bdrv_getlength = blkdebug_getlength,
|
.bdrv_getlength = blkdebug_getlength,
|
||||||
.bdrv_truncate = blkdebug_truncate,
|
.bdrv_truncate = blkdebug_truncate,
|
||||||
.bdrv_refresh_filename = blkdebug_refresh_filename,
|
.bdrv_refresh_filename = blkdebug_refresh_filename,
|
||||||
|
.bdrv_refresh_limits = blkdebug_refresh_limits,
|
||||||
|
|
||||||
.bdrv_aio_readv = blkdebug_aio_readv,
|
.bdrv_aio_readv = blkdebug_aio_readv,
|
||||||
.bdrv_aio_writev = blkdebug_aio_writev,
|
.bdrv_aio_writev = blkdebug_aio_writev,
|
||||||
|
|||||||
@@ -81,22 +81,22 @@ static void block_request_create(uint64_t reqid, BlockDriverState *bs,
|
|||||||
replay_block_event(req->bh, reqid);
|
replay_block_event(req->bh, reqid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn blkreplay_co_readv(BlockDriverState *bs,
|
static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
|
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||||
{
|
{
|
||||||
uint64_t reqid = request_id++;
|
uint64_t reqid = request_id++;
|
||||||
int ret = bdrv_co_readv(bs->file->bs, sector_num, nb_sectors, qiov);
|
int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn blkreplay_co_writev(BlockDriverState *bs,
|
static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
|
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||||
{
|
{
|
||||||
uint64_t reqid = request_id++;
|
uint64_t reqid = request_id++;
|
||||||
int ret = bdrv_co_writev(bs->file->bs, sector_num, nb_sectors, qiov);
|
int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
||||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
int64_t offset, int count, BdrvRequestFlags flags)
|
int64_t offset, int count, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
uint64_t reqid = request_id++;
|
uint64_t reqid = request_id++;
|
||||||
int ret = bdrv_co_pwrite_zeroes(bs->file->bs, offset, count, flags);
|
int ret = bdrv_co_pwrite_zeroes(bs->file, offset, count, flags);
|
||||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
|
|
||||||
@@ -144,8 +144,8 @@ static BlockDriver bdrv_blkreplay = {
|
|||||||
.bdrv_close = blkreplay_close,
|
.bdrv_close = blkreplay_close,
|
||||||
.bdrv_getlength = blkreplay_getlength,
|
.bdrv_getlength = blkreplay_getlength,
|
||||||
|
|
||||||
.bdrv_co_readv = blkreplay_co_readv,
|
.bdrv_co_preadv = blkreplay_co_preadv,
|
||||||
.bdrv_co_writev = blkreplay_co_writev,
|
.bdrv_co_pwritev = blkreplay_co_pwritev,
|
||||||
|
|
||||||
.bdrv_co_pwrite_zeroes = blkreplay_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = blkreplay_co_pwrite_zeroes,
|
||||||
.bdrv_co_discard = blkreplay_co_discard,
|
.bdrv_co_discard = blkreplay_co_discard,
|
||||||
|
|||||||
@@ -247,9 +247,9 @@ static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs,
|
|||||||
qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
|
qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
|
||||||
qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
|
qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
|
||||||
|
|
||||||
bdrv_aio_readv(s->test_file->bs, sector_num, qiov, nb_sectors,
|
bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
|
||||||
blkverify_aio_cb, acb);
|
blkverify_aio_cb, acb);
|
||||||
bdrv_aio_readv(bs->file->bs, sector_num, &acb->raw_qiov, nb_sectors,
|
bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
|
||||||
blkverify_aio_cb, acb);
|
blkverify_aio_cb, acb);
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
@@ -262,9 +262,9 @@ static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs,
|
|||||||
BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
|
BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
|
||||||
nb_sectors, cb, opaque);
|
nb_sectors, cb, opaque);
|
||||||
|
|
||||||
bdrv_aio_writev(s->test_file->bs, sector_num, qiov, nb_sectors,
|
bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
|
||||||
blkverify_aio_cb, acb);
|
blkverify_aio_cb, acb);
|
||||||
bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
|
bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
|
||||||
blkverify_aio_cb, acb);
|
blkverify_aio_cb, acb);
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -760,7 +760,7 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
|
|||||||
throttle_group_co_io_limits_intercept(blk, bytes, false);
|
throttle_group_co_io_limits_intercept(blk, bytes, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bdrv_co_preadv(blk_bs(blk), offset, bytes, qiov, flags);
|
return bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
|
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
|
||||||
@@ -785,7 +785,7 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
|
|||||||
flags |= BDRV_REQ_FUA;
|
flags |= BDRV_REQ_FUA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bdrv_co_pwritev(blk_bs(blk), offset, bytes, qiov, flags);
|
return bdrv_co_pwritev(blk->root, offset, bytes, qiov, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct BlkRwCo {
|
typedef struct BlkRwCo {
|
||||||
@@ -870,6 +870,11 @@ int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset,
|
|||||||
flags | BDRV_REQ_ZERO_WRITE);
|
flags | BDRV_REQ_ZERO_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
|
||||||
|
{
|
||||||
|
return bdrv_make_zero(blk->root, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static void error_callback_bh(void *opaque)
|
static void error_callback_bh(void *opaque)
|
||||||
{
|
{
|
||||||
struct BlockBackendAIOCB *acb = opaque;
|
struct BlockBackendAIOCB *acb = opaque;
|
||||||
@@ -1303,15 +1308,16 @@ int blk_get_flags(BlockBackend *blk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int blk_get_max_transfer_length(BlockBackend *blk)
|
/* Returns the maximum transfer length, in bytes; guaranteed nonzero */
|
||||||
|
uint32_t blk_get_max_transfer(BlockBackend *blk)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = blk_bs(blk);
|
BlockDriverState *bs = blk_bs(blk);
|
||||||
|
uint32_t max = 0;
|
||||||
|
|
||||||
if (bs) {
|
if (bs) {
|
||||||
return bs->bl.max_transfer_length;
|
max = bs->bl.max_transfer;
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return MIN_NON_ZERO(max, INT_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
int blk_get_max_iov(BlockBackend *blk)
|
int blk_get_max_iov(BlockBackend *blk)
|
||||||
|
|||||||
@@ -104,10 +104,9 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
struct bochs_header bochs;
|
struct bochs_header bochs;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
bs->read_only = 1; // no write support yet
|
bs->read_only = true; /* no write support yet */
|
||||||
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
|
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 0, &bochs, sizeof(bochs));
|
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -141,7 +140,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
||||||
s->catalog_size * 4);
|
s->catalog_size * 4);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -189,6 +188,11 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bochs_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
|
||||||
|
}
|
||||||
|
|
||||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||||
{
|
{
|
||||||
BDRVBochsState *s = bs->opaque;
|
BDRVBochsState *s = bs->opaque;
|
||||||
@@ -210,7 +214,7 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
|||||||
(s->extent_blocks + s->bitmap_blocks));
|
(s->extent_blocks + s->bitmap_blocks));
|
||||||
|
|
||||||
/* read in bitmap for current extent */
|
/* read in bitmap for current extent */
|
||||||
ret = bdrv_pread(bs->file->bs, bitmap_offset + (extent_offset / 8),
|
ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||||
&bitmap_entry, 1);
|
&bitmap_entry, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -251,7 +255,7 @@ bochs_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, 512);
|
qemu_iovec_concat(&local_qiov, qiov, bytes_done, 512);
|
||||||
|
|
||||||
if (block_offset > 0) {
|
if (block_offset > 0) {
|
||||||
ret = bdrv_co_preadv(bs->file->bs, block_offset, 512,
|
ret = bdrv_co_preadv(bs->file, block_offset, 512,
|
||||||
&local_qiov, 0);
|
&local_qiov, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -283,6 +287,7 @@ static BlockDriver bdrv_bochs = {
|
|||||||
.instance_size = sizeof(BDRVBochsState),
|
.instance_size = sizeof(BDRVBochsState),
|
||||||
.bdrv_probe = bochs_probe,
|
.bdrv_probe = bochs_probe,
|
||||||
.bdrv_open = bochs_open,
|
.bdrv_open = bochs_open,
|
||||||
|
.bdrv_refresh_limits = bochs_refresh_limits,
|
||||||
.bdrv_co_preadv = bochs_co_preadv,
|
.bdrv_co_preadv = bochs_co_preadv,
|
||||||
.bdrv_close = bochs_close,
|
.bdrv_close = bochs_close,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -66,11 +66,10 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
uint32_t offsets_size, max_compressed_block_size = 1, i;
|
uint32_t offsets_size, max_compressed_block_size = 1, i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
bs->read_only = 1;
|
bs->read_only = true;
|
||||||
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
|
|
||||||
|
|
||||||
/* read header */
|
/* read header */
|
||||||
ret = bdrv_pread(bs->file->bs, 128, &s->block_size, 4);
|
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -96,7 +95,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 128 + 4, &s->n_blocks, 4);
|
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -127,7 +126,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 128 + 4 + 4, s->offsets, offsets_size);
|
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -199,6 +198,11 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cloop_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
|
||||||
|
}
|
||||||
|
|
||||||
static inline int cloop_read_block(BlockDriverState *bs, int block_num)
|
static inline int cloop_read_block(BlockDriverState *bs, int block_num)
|
||||||
{
|
{
|
||||||
BDRVCloopState *s = bs->opaque;
|
BDRVCloopState *s = bs->opaque;
|
||||||
@@ -207,7 +211,7 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
|
|||||||
int ret;
|
int ret;
|
||||||
uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
|
uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, s->offsets[block_num],
|
ret = bdrv_pread(bs->file, s->offsets[block_num],
|
||||||
s->compressed_block, bytes);
|
s->compressed_block, bytes);
|
||||||
if (ret != bytes) {
|
if (ret != bytes) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -280,6 +284,7 @@ static BlockDriver bdrv_cloop = {
|
|||||||
.instance_size = sizeof(BDRVCloopState),
|
.instance_size = sizeof(BDRVCloopState),
|
||||||
.bdrv_probe = cloop_probe,
|
.bdrv_probe = cloop_probe,
|
||||||
.bdrv_open = cloop_open,
|
.bdrv_open = cloop_open,
|
||||||
|
.bdrv_refresh_limits = cloop_refresh_limits,
|
||||||
.bdrv_co_preadv = cloop_co_preadv,
|
.bdrv_co_preadv = cloop_co_preadv,
|
||||||
.bdrv_close = cloop_close,
|
.bdrv_close = cloop_close,
|
||||||
};
|
};
|
||||||
|
|||||||
121
block/commit.c
121
block/commit.c
@@ -282,3 +282,124 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
|||||||
trace_commit_start(bs, base, top, s, s->common.co, opaque);
|
trace_commit_start(bs, base, top, s, s->common.co, opaque);
|
||||||
qemu_coroutine_enter(s->common.co, s);
|
qemu_coroutine_enter(s->common.co, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define COMMIT_BUF_SECTORS 2048
|
||||||
|
|
||||||
|
/* commit COW file into the raw image */
|
||||||
|
int bdrv_commit(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BlockBackend *src, *backing;
|
||||||
|
BlockDriver *drv = bs->drv;
|
||||||
|
int64_t sector, total_sectors, length, backing_length;
|
||||||
|
int n, ro, open_flags;
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
|
||||||
|
if (!drv)
|
||||||
|
return -ENOMEDIUM;
|
||||||
|
|
||||||
|
if (!bs->backing) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) ||
|
||||||
|
bdrv_op_is_blocked(bs->backing->bs, BLOCK_OP_TYPE_COMMIT_TARGET, NULL)) {
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ro = bs->backing->bs->read_only;
|
||||||
|
open_flags = bs->backing->bs->open_flags;
|
||||||
|
|
||||||
|
if (ro) {
|
||||||
|
if (bdrv_reopen(bs->backing->bs, open_flags | BDRV_O_RDWR, NULL)) {
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src = blk_new();
|
||||||
|
blk_insert_bs(src, bs);
|
||||||
|
|
||||||
|
backing = blk_new();
|
||||||
|
blk_insert_bs(backing, bs->backing->bs);
|
||||||
|
|
||||||
|
length = blk_getlength(src);
|
||||||
|
if (length < 0) {
|
||||||
|
ret = length;
|
||||||
|
goto ro_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
backing_length = blk_getlength(backing);
|
||||||
|
if (backing_length < 0) {
|
||||||
|
ret = backing_length;
|
||||||
|
goto ro_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If our top snapshot is larger than the backing file image,
|
||||||
|
* grow the backing file image if possible. If not possible,
|
||||||
|
* we must return an error */
|
||||||
|
if (length > backing_length) {
|
||||||
|
ret = blk_truncate(backing, length);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto ro_cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total_sectors = length >> BDRV_SECTOR_BITS;
|
||||||
|
|
||||||
|
/* blk_try_blockalign() for src will choose an alignment that works for
|
||||||
|
* backing as well, so no need to compare the alignment manually. */
|
||||||
|
buf = blk_try_blockalign(src, COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
|
||||||
|
if (buf == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto ro_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (sector = 0; sector < total_sectors; sector += n) {
|
||||||
|
ret = bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto ro_cleanup;
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
ret = blk_pread(src, sector * BDRV_SECTOR_SIZE, buf,
|
||||||
|
n * BDRV_SECTOR_SIZE);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto ro_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = blk_pwrite(backing, sector * BDRV_SECTOR_SIZE, buf,
|
||||||
|
n * BDRV_SECTOR_SIZE, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto ro_cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drv->bdrv_make_empty) {
|
||||||
|
ret = drv->bdrv_make_empty(bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto ro_cleanup;
|
||||||
|
}
|
||||||
|
blk_flush(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure all data we wrote to the backing device is actually
|
||||||
|
* stable on disk.
|
||||||
|
*/
|
||||||
|
blk_flush(backing);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
ro_cleanup:
|
||||||
|
qemu_vfree(buf);
|
||||||
|
|
||||||
|
blk_unref(src);
|
||||||
|
blk_unref(backing);
|
||||||
|
|
||||||
|
if (ro) {
|
||||||
|
/* ignoring error return here */
|
||||||
|
bdrv_reopen(bs->backing->bs, open_flags & ~BDRV_O_RDWR, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ static ssize_t block_crypto_read_func(QCryptoBlock *block,
|
|||||||
BlockDriverState *bs = opaque;
|
BlockDriverState *bs = opaque;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, offset, buf, buflen);
|
ret = bdrv_pread(bs->file, offset, buf, buflen);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not read encryption header");
|
error_setg_errno(errp, -ret, "Could not read encryption header");
|
||||||
return ret;
|
return ret;
|
||||||
@@ -193,17 +193,16 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
|
|||||||
QemuOpts *opts,
|
QemuOpts *opts,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
OptsVisitor *ov;
|
Visitor *v;
|
||||||
QCryptoBlockOpenOptions *ret = NULL;
|
QCryptoBlockOpenOptions *ret = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
ret = g_new0(QCryptoBlockOpenOptions, 1);
|
ret = g_new0(QCryptoBlockOpenOptions, 1);
|
||||||
ret->format = format;
|
ret->format = format;
|
||||||
|
|
||||||
ov = opts_visitor_new(opts);
|
v = opts_visitor_new(opts);
|
||||||
|
|
||||||
visit_start_struct(opts_get_visitor(ov),
|
visit_start_struct(v, NULL, NULL, 0, &local_err);
|
||||||
NULL, NULL, 0, &local_err);
|
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -211,7 +210,7 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
|
|||||||
switch (format) {
|
switch (format) {
|
||||||
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
|
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
|
||||||
visit_type_QCryptoBlockOptionsLUKS_members(
|
visit_type_QCryptoBlockOptionsLUKS_members(
|
||||||
opts_get_visitor(ov), &ret->u.luks, &local_err);
|
v, &ret->u.luks, &local_err);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -219,10 +218,10 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!local_err) {
|
if (!local_err) {
|
||||||
visit_check_struct(opts_get_visitor(ov), &local_err);
|
visit_check_struct(v, &local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_end_struct(opts_get_visitor(ov));
|
visit_end_struct(v, NULL);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
@@ -230,7 +229,7 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
|
|||||||
qapi_free_QCryptoBlockOpenOptions(ret);
|
qapi_free_QCryptoBlockOpenOptions(ret);
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
}
|
}
|
||||||
opts_visitor_cleanup(ov);
|
visit_free(v);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,17 +239,16 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
|
|||||||
QemuOpts *opts,
|
QemuOpts *opts,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
OptsVisitor *ov;
|
Visitor *v;
|
||||||
QCryptoBlockCreateOptions *ret = NULL;
|
QCryptoBlockCreateOptions *ret = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
ret = g_new0(QCryptoBlockCreateOptions, 1);
|
ret = g_new0(QCryptoBlockCreateOptions, 1);
|
||||||
ret->format = format;
|
ret->format = format;
|
||||||
|
|
||||||
ov = opts_visitor_new(opts);
|
v = opts_visitor_new(opts);
|
||||||
|
|
||||||
visit_start_struct(opts_get_visitor(ov),
|
visit_start_struct(v, NULL, NULL, 0, &local_err);
|
||||||
NULL, NULL, 0, &local_err);
|
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -258,7 +256,7 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
|
|||||||
switch (format) {
|
switch (format) {
|
||||||
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
|
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
|
||||||
visit_type_QCryptoBlockCreateOptionsLUKS_members(
|
visit_type_QCryptoBlockCreateOptionsLUKS_members(
|
||||||
opts_get_visitor(ov), &ret->u.luks, &local_err);
|
v, &ret->u.luks, &local_err);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -266,10 +264,10 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!local_err) {
|
if (!local_err) {
|
||||||
visit_check_struct(opts_get_visitor(ov), &local_err);
|
visit_check_struct(v, &local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_end_struct(opts_get_visitor(ov));
|
visit_end_struct(v, NULL);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
@@ -277,7 +275,7 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
|
|||||||
qapi_free_QCryptoBlockCreateOptions(ret);
|
qapi_free_QCryptoBlockCreateOptions(ret);
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
}
|
}
|
||||||
opts_visitor_cleanup(ov);
|
visit_free(v);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,8 +320,8 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->encrypted = 1;
|
bs->encrypted = true;
|
||||||
bs->valid_key = 1;
|
bs->valid_key = true;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
cleanup:
|
cleanup:
|
||||||
@@ -428,7 +426,7 @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
qemu_iovec_reset(&hd_qiov);
|
qemu_iovec_reset(&hd_qiov);
|
||||||
qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
|
qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
|
||||||
|
|
||||||
ret = bdrv_co_readv(bs->file->bs,
|
ret = bdrv_co_readv(bs->file,
|
||||||
payload_offset + sector_num,
|
payload_offset + sector_num,
|
||||||
cur_nr_sectors, &hd_qiov);
|
cur_nr_sectors, &hd_qiov);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -507,7 +505,7 @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
qemu_iovec_reset(&hd_qiov);
|
qemu_iovec_reset(&hd_qiov);
|
||||||
qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
|
qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
|
||||||
|
|
||||||
ret = bdrv_co_writev(bs->file->bs,
|
ret = bdrv_co_writev(bs->file,
|
||||||
payload_offset + sector_num,
|
payload_offset + sector_num,
|
||||||
cur_nr_sectors, &hd_qiov);
|
cur_nr_sectors, &hd_qiov);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
30
block/dmg.c
30
block/dmg.c
@@ -86,7 +86,7 @@ static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
|
|||||||
uint64_t buffer;
|
uint64_t buffer;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, offset, &buffer, 8);
|
ret = bdrv_pread(bs->file, offset, &buffer, 8);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
|
|||||||
uint32_t buffer;
|
uint32_t buffer;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, offset, &buffer, 4);
|
ret = bdrv_pread(bs->file, offset, &buffer, 4);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -153,8 +153,9 @@ static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t dmg_find_koly_offset(BlockDriverState *file_bs, Error **errp)
|
static int64_t dmg_find_koly_offset(BdrvChild *file, Error **errp)
|
||||||
{
|
{
|
||||||
|
BlockDriverState *file_bs = file->bs;
|
||||||
int64_t length;
|
int64_t length;
|
||||||
int64_t offset = 0;
|
int64_t offset = 0;
|
||||||
uint8_t buffer[515];
|
uint8_t buffer[515];
|
||||||
@@ -178,7 +179,7 @@ static int64_t dmg_find_koly_offset(BlockDriverState *file_bs, Error **errp)
|
|||||||
offset = length - 511 - 512;
|
offset = length - 511 - 512;
|
||||||
}
|
}
|
||||||
length = length < 515 ? length : 515;
|
length = length < 515 ? length : 515;
|
||||||
ret = bdrv_pread(file_bs, offset, buffer, length);
|
ret = bdrv_pread(file, offset, buffer, length);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Failed while reading UDIF trailer");
|
error_setg_errno(errp, -ret, "Failed while reading UDIF trailer");
|
||||||
return ret;
|
return ret;
|
||||||
@@ -355,7 +356,7 @@ static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
|
|||||||
offset += 4;
|
offset += 4;
|
||||||
|
|
||||||
buffer = g_realloc(buffer, count);
|
buffer = g_realloc(buffer, count);
|
||||||
ret = bdrv_pread(bs->file->bs, offset, buffer, count);
|
ret = bdrv_pread(bs->file, offset, buffer, count);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -392,7 +393,7 @@ static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds,
|
|||||||
|
|
||||||
buffer = g_malloc(info_length + 1);
|
buffer = g_malloc(info_length + 1);
|
||||||
buffer[info_length] = '\0';
|
buffer[info_length] = '\0';
|
||||||
ret = bdrv_pread(bs->file->bs, info_begin, buffer, info_length);
|
ret = bdrv_pread(bs->file, info_begin, buffer, info_length);
|
||||||
if (ret != info_length) {
|
if (ret != info_length) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -438,8 +439,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
int64_t offset;
|
int64_t offset;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
bs->read_only = 1;
|
bs->read_only = true;
|
||||||
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
|
|
||||||
|
|
||||||
s->n_chunks = 0;
|
s->n_chunks = 0;
|
||||||
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
|
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
|
||||||
@@ -449,7 +449,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
ds.max_sectors_per_chunk = 1;
|
ds.max_sectors_per_chunk = 1;
|
||||||
|
|
||||||
/* locate the UDIF trailer */
|
/* locate the UDIF trailer */
|
||||||
offset = dmg_find_koly_offset(bs->file->bs, errp);
|
offset = dmg_find_koly_offset(bs->file, errp);
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
ret = offset;
|
ret = offset;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -547,6 +547,11 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dmg_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
|
||||||
|
}
|
||||||
|
|
||||||
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
||||||
uint32_t chunk_num, uint64_t sector_num)
|
uint32_t chunk_num, uint64_t sector_num)
|
||||||
{
|
{
|
||||||
@@ -595,7 +600,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
|||||||
case 0x80000005: { /* zlib compressed */
|
case 0x80000005: { /* zlib compressed */
|
||||||
/* we need to buffer, because only the chunk as whole can be
|
/* we need to buffer, because only the chunk as whole can be
|
||||||
* inflated. */
|
* inflated. */
|
||||||
ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
s->compressed_chunk, s->lengths[chunk]);
|
s->compressed_chunk, s->lengths[chunk]);
|
||||||
if (ret != s->lengths[chunk]) {
|
if (ret != s->lengths[chunk]) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -619,7 +624,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
|||||||
case 0x80000006: /* bzip2 compressed */
|
case 0x80000006: /* bzip2 compressed */
|
||||||
/* we need to buffer, because only the chunk as whole can be
|
/* we need to buffer, because only the chunk as whole can be
|
||||||
* inflated. */
|
* inflated. */
|
||||||
ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
s->compressed_chunk, s->lengths[chunk]);
|
s->compressed_chunk, s->lengths[chunk]);
|
||||||
if (ret != s->lengths[chunk]) {
|
if (ret != s->lengths[chunk]) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -644,7 +649,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
|||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BZIP2 */
|
#endif /* CONFIG_BZIP2 */
|
||||||
case 1: /* copy */
|
case 1: /* copy */
|
||||||
ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
s->uncompressed_chunk, s->lengths[chunk]);
|
s->uncompressed_chunk, s->lengths[chunk]);
|
||||||
if (ret != s->lengths[chunk]) {
|
if (ret != s->lengths[chunk]) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -720,6 +725,7 @@ static BlockDriver bdrv_dmg = {
|
|||||||
.instance_size = sizeof(BDRVDMGState),
|
.instance_size = sizeof(BDRVDMGState),
|
||||||
.bdrv_probe = dmg_probe,
|
.bdrv_probe = dmg_probe,
|
||||||
.bdrv_open = dmg_open,
|
.bdrv_open = dmg_open,
|
||||||
|
.bdrv_refresh_limits = dmg_refresh_limits,
|
||||||
.bdrv_co_preadv = dmg_co_preadv,
|
.bdrv_co_preadv = dmg_co_preadv,
|
||||||
.bdrv_close = dmg_close,
|
.bdrv_close = dmg_close,
|
||||||
};
|
};
|
||||||
|
|||||||
230
block/gluster.c
230
block/gluster.c
@@ -24,6 +24,8 @@ typedef struct GlusterAIOCB {
|
|||||||
typedef struct BDRVGlusterState {
|
typedef struct BDRVGlusterState {
|
||||||
struct glfs *glfs;
|
struct glfs *glfs;
|
||||||
struct glfs_fd *fd;
|
struct glfs_fd *fd;
|
||||||
|
bool supports_seek_data;
|
||||||
|
int debug_level;
|
||||||
} BDRVGlusterState;
|
} BDRVGlusterState;
|
||||||
|
|
||||||
typedef struct GlusterConf {
|
typedef struct GlusterConf {
|
||||||
@@ -32,6 +34,7 @@ typedef struct GlusterConf {
|
|||||||
char *volname;
|
char *volname;
|
||||||
char *image;
|
char *image;
|
||||||
char *transport;
|
char *transport;
|
||||||
|
int debug_level;
|
||||||
} GlusterConf;
|
} GlusterConf;
|
||||||
|
|
||||||
static void qemu_gluster_gconf_free(GlusterConf *gconf)
|
static void qemu_gluster_gconf_free(GlusterConf *gconf)
|
||||||
@@ -194,11 +197,7 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ret = glfs_set_logging(glfs, "-", gconf->debug_level);
|
||||||
* TODO: Use GF_LOG_ERROR instead of hard code value of 4 here when
|
|
||||||
* GlusterFS makes GF_LOG_* macros available to libgfapi users.
|
|
||||||
*/
|
|
||||||
ret = glfs_set_logging(glfs, "-", 4);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -256,16 +255,26 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
|||||||
qemu_bh_schedule(acb->bh);
|
qemu_bh_schedule(acb->bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GLUSTER_OPT_FILENAME "filename"
|
||||||
|
#define GLUSTER_OPT_DEBUG "debug"
|
||||||
|
#define GLUSTER_DEBUG_DEFAULT 4
|
||||||
|
#define GLUSTER_DEBUG_MAX 9
|
||||||
|
|
||||||
/* TODO Convert to fine grained options */
|
/* TODO Convert to fine grained options */
|
||||||
static QemuOptsList runtime_opts = {
|
static QemuOptsList runtime_opts = {
|
||||||
.name = "gluster",
|
.name = "gluster",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||||
.desc = {
|
.desc = {
|
||||||
{
|
{
|
||||||
.name = "filename",
|
.name = GLUSTER_OPT_FILENAME,
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "URL to the gluster image",
|
.help = "URL to the gluster image",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = GLUSTER_OPT_DEBUG,
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
.help = "Gluster log level, valid range is 0-9",
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -287,6 +296,28 @@ static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do SEEK_DATA/HOLE to detect if it is functional. Older broken versions of
|
||||||
|
* gfapi incorrectly return the current offset when SEEK_DATA/HOLE is used.
|
||||||
|
* - Corrected versions return -1 and set errno to EINVAL.
|
||||||
|
* - Versions that support SEEK_DATA/HOLE correctly, will return -1 and set
|
||||||
|
* errno to ENXIO when SEEK_DATA is called with a position of EOF.
|
||||||
|
*/
|
||||||
|
static bool qemu_gluster_test_seek(struct glfs_fd *fd)
|
||||||
|
{
|
||||||
|
off_t ret, eof;
|
||||||
|
|
||||||
|
eof = glfs_lseek(fd, 0, SEEK_END);
|
||||||
|
if (eof < 0) {
|
||||||
|
/* this should never occur */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this should always fail with ENXIO if SEEK_DATA is supported */
|
||||||
|
ret = glfs_lseek(fd, eof, SEEK_DATA);
|
||||||
|
return (ret < 0) && (errno == ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
||||||
int bdrv_flags, Error **errp)
|
int bdrv_flags, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -306,8 +337,17 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = qemu_opt_get(opts, "filename");
|
filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME);
|
||||||
|
|
||||||
|
s->debug_level = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG,
|
||||||
|
GLUSTER_DEBUG_DEFAULT);
|
||||||
|
if (s->debug_level < 0) {
|
||||||
|
s->debug_level = 0;
|
||||||
|
} else if (s->debug_level > GLUSTER_DEBUG_MAX) {
|
||||||
|
s->debug_level = GLUSTER_DEBUG_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
gconf->debug_level = s->debug_level;
|
||||||
s->glfs = qemu_gluster_init(gconf, filename, errp);
|
s->glfs = qemu_gluster_init(gconf, filename, errp);
|
||||||
if (!s->glfs) {
|
if (!s->glfs) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
@@ -338,6 +378,8 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
|||||||
ret = -errno;
|
ret = -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->supports_seek_data = qemu_gluster_test_seek(s->fd);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
qemu_gluster_gconf_free(gconf);
|
qemu_gluster_gconf_free(gconf);
|
||||||
@@ -363,6 +405,7 @@ static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
|||||||
BlockReopenQueue *queue, Error **errp)
|
BlockReopenQueue *queue, Error **errp)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
BDRVGlusterState *s;
|
||||||
BDRVGlusterReopenState *reop_s;
|
BDRVGlusterReopenState *reop_s;
|
||||||
GlusterConf *gconf = NULL;
|
GlusterConf *gconf = NULL;
|
||||||
int open_flags = 0;
|
int open_flags = 0;
|
||||||
@@ -370,6 +413,8 @@ static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
|||||||
assert(state != NULL);
|
assert(state != NULL);
|
||||||
assert(state->bs != NULL);
|
assert(state->bs != NULL);
|
||||||
|
|
||||||
|
s = state->bs->opaque;
|
||||||
|
|
||||||
state->opaque = g_new0(BDRVGlusterReopenState, 1);
|
state->opaque = g_new0(BDRVGlusterReopenState, 1);
|
||||||
reop_s = state->opaque;
|
reop_s = state->opaque;
|
||||||
|
|
||||||
@@ -377,6 +422,7 @@ static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
|||||||
|
|
||||||
gconf = g_new0(GlusterConf, 1);
|
gconf = g_new0(GlusterConf, 1);
|
||||||
|
|
||||||
|
gconf->debug_level = s->debug_level;
|
||||||
reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, errp);
|
reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, errp);
|
||||||
if (reop_s->glfs == NULL) {
|
if (reop_s->glfs == NULL) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
@@ -510,6 +556,14 @@ static int qemu_gluster_create(const char *filename,
|
|||||||
char *tmp = NULL;
|
char *tmp = NULL;
|
||||||
GlusterConf *gconf = g_new0(GlusterConf, 1);
|
GlusterConf *gconf = g_new0(GlusterConf, 1);
|
||||||
|
|
||||||
|
gconf->debug_level = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
|
||||||
|
GLUSTER_DEBUG_DEFAULT);
|
||||||
|
if (gconf->debug_level < 0) {
|
||||||
|
gconf->debug_level = 0;
|
||||||
|
} else if (gconf->debug_level > GLUSTER_DEBUG_MAX) {
|
||||||
|
gconf->debug_level = GLUSTER_DEBUG_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
glfs = qemu_gluster_init(gconf, filename, errp);
|
glfs = qemu_gluster_init(gconf, filename, errp);
|
||||||
if (!glfs) {
|
if (!glfs) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
@@ -727,6 +781,159 @@ static int qemu_gluster_has_zero_init(BlockDriverState *bs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find allocation range in @bs around offset @start.
|
||||||
|
* May change underlying file descriptor's file offset.
|
||||||
|
* If @start is not in a hole, store @start in @data, and the
|
||||||
|
* beginning of the next hole in @hole, and return 0.
|
||||||
|
* If @start is in a non-trailing hole, store @start in @hole and the
|
||||||
|
* beginning of the next non-hole in @data, and return 0.
|
||||||
|
* If @start is in a trailing hole or beyond EOF, return -ENXIO.
|
||||||
|
* If we can't find out, return a negative errno other than -ENXIO.
|
||||||
|
*
|
||||||
|
* (Shamefully copied from raw-posix.c, only miniscule adaptions.)
|
||||||
|
*/
|
||||||
|
static int find_allocation(BlockDriverState *bs, off_t start,
|
||||||
|
off_t *data, off_t *hole)
|
||||||
|
{
|
||||||
|
BDRVGlusterState *s = bs->opaque;
|
||||||
|
off_t offs;
|
||||||
|
|
||||||
|
if (!s->supports_seek_data) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SEEK_DATA cases:
|
||||||
|
* D1. offs == start: start is in data
|
||||||
|
* D2. offs > start: start is in a hole, next data at offs
|
||||||
|
* D3. offs < 0, errno = ENXIO: either start is in a trailing hole
|
||||||
|
* or start is beyond EOF
|
||||||
|
* If the latter happens, the file has been truncated behind
|
||||||
|
* our back since we opened it. All bets are off then.
|
||||||
|
* Treating like a trailing hole is simplest.
|
||||||
|
* D4. offs < 0, errno != ENXIO: we learned nothing
|
||||||
|
*/
|
||||||
|
offs = glfs_lseek(s->fd, start, SEEK_DATA);
|
||||||
|
if (offs < 0) {
|
||||||
|
return -errno; /* D3 or D4 */
|
||||||
|
}
|
||||||
|
assert(offs >= start);
|
||||||
|
|
||||||
|
if (offs > start) {
|
||||||
|
/* D2: in hole, next data at offs */
|
||||||
|
*hole = start;
|
||||||
|
*data = offs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* D1: in data, end not yet known */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SEEK_HOLE cases:
|
||||||
|
* H1. offs == start: start is in a hole
|
||||||
|
* If this happens here, a hole has been dug behind our back
|
||||||
|
* since the previous lseek().
|
||||||
|
* H2. offs > start: either start is in data, next hole at offs,
|
||||||
|
* or start is in trailing hole, EOF at offs
|
||||||
|
* Linux treats trailing holes like any other hole: offs ==
|
||||||
|
* start. Solaris seeks to EOF instead: offs > start (blech).
|
||||||
|
* If that happens here, a hole has been dug behind our back
|
||||||
|
* since the previous lseek().
|
||||||
|
* H3. offs < 0, errno = ENXIO: start is beyond EOF
|
||||||
|
* If this happens, the file has been truncated behind our
|
||||||
|
* back since we opened it. Treat it like a trailing hole.
|
||||||
|
* H4. offs < 0, errno != ENXIO: we learned nothing
|
||||||
|
* Pretend we know nothing at all, i.e. "forget" about D1.
|
||||||
|
*/
|
||||||
|
offs = glfs_lseek(s->fd, start, SEEK_HOLE);
|
||||||
|
if (offs < 0) {
|
||||||
|
return -errno; /* D1 and (H3 or H4) */
|
||||||
|
}
|
||||||
|
assert(offs >= start);
|
||||||
|
|
||||||
|
if (offs > start) {
|
||||||
|
/*
|
||||||
|
* D1 and H2: either in data, next hole at offs, or it was in
|
||||||
|
* data but is now in a trailing hole. In the latter case,
|
||||||
|
* all bets are off. Treating it as if it there was data all
|
||||||
|
* the way to EOF is safe, so simply do that.
|
||||||
|
*/
|
||||||
|
*data = start;
|
||||||
|
*hole = offs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* D1 and H1 */
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the allocation status of the specified sectors.
|
||||||
|
*
|
||||||
|
* If 'sector_num' is beyond the end of the disk image the return value is 0
|
||||||
|
* and 'pnum' is set to 0.
|
||||||
|
*
|
||||||
|
* 'pnum' is set to the number of sectors (including and immediately following
|
||||||
|
* the specified sector) that are known to be in the same
|
||||||
|
* allocated/unallocated state.
|
||||||
|
*
|
||||||
|
* 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
|
||||||
|
* beyond the end of the disk image it will be clamped.
|
||||||
|
*
|
||||||
|
* (Based on raw_co_get_block_status() from raw-posix.c.)
|
||||||
|
*/
|
||||||
|
static int64_t coroutine_fn qemu_gluster_co_get_block_status(
|
||||||
|
BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
|
||||||
|
BlockDriverState **file)
|
||||||
|
{
|
||||||
|
BDRVGlusterState *s = bs->opaque;
|
||||||
|
off_t start, data = 0, hole = 0;
|
||||||
|
int64_t total_size;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (!s->fd) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = sector_num * BDRV_SECTOR_SIZE;
|
||||||
|
total_size = bdrv_getlength(bs);
|
||||||
|
if (total_size < 0) {
|
||||||
|
return total_size;
|
||||||
|
} else if (start >= total_size) {
|
||||||
|
*pnum = 0;
|
||||||
|
return 0;
|
||||||
|
} else if (start + nb_sectors * BDRV_SECTOR_SIZE > total_size) {
|
||||||
|
nb_sectors = DIV_ROUND_UP(total_size - start, BDRV_SECTOR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = find_allocation(bs, start, &data, &hole);
|
||||||
|
if (ret == -ENXIO) {
|
||||||
|
/* Trailing hole */
|
||||||
|
*pnum = nb_sectors;
|
||||||
|
ret = BDRV_BLOCK_ZERO;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
/* No info available, so pretend there are no holes */
|
||||||
|
*pnum = nb_sectors;
|
||||||
|
ret = BDRV_BLOCK_DATA;
|
||||||
|
} else if (data == start) {
|
||||||
|
/* On a data extent, compute sectors to the end of the extent,
|
||||||
|
* possibly including a partial sector at EOF. */
|
||||||
|
*pnum = MIN(nb_sectors, DIV_ROUND_UP(hole - start, BDRV_SECTOR_SIZE));
|
||||||
|
ret = BDRV_BLOCK_DATA;
|
||||||
|
} else {
|
||||||
|
/* On a hole, compute sectors to the beginning of the next extent. */
|
||||||
|
assert(hole == start);
|
||||||
|
*pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE);
|
||||||
|
ret = BDRV_BLOCK_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*file = bs;
|
||||||
|
|
||||||
|
return ret | BDRV_BLOCK_OFFSET_VALID | start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static QemuOptsList qemu_gluster_create_opts = {
|
static QemuOptsList qemu_gluster_create_opts = {
|
||||||
.name = "qemu-gluster-create-opts",
|
.name = "qemu-gluster-create-opts",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
|
||||||
@@ -741,6 +948,11 @@ static QemuOptsList qemu_gluster_create_opts = {
|
|||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "Preallocation mode (allowed values: off, full)"
|
.help = "Preallocation mode (allowed values: off, full)"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = GLUSTER_OPT_DEBUG,
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
.help = "Gluster log level, valid range is 0-9",
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -769,6 +981,7 @@ static BlockDriver bdrv_gluster = {
|
|||||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
||||||
#endif
|
#endif
|
||||||
|
.bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
|
||||||
.create_opts = &qemu_gluster_create_opts,
|
.create_opts = &qemu_gluster_create_opts,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -796,6 +1009,7 @@ static BlockDriver bdrv_gluster_tcp = {
|
|||||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
||||||
#endif
|
#endif
|
||||||
|
.bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
|
||||||
.create_opts = &qemu_gluster_create_opts,
|
.create_opts = &qemu_gluster_create_opts,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -823,6 +1037,7 @@ static BlockDriver bdrv_gluster_unix = {
|
|||||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
||||||
#endif
|
#endif
|
||||||
|
.bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
|
||||||
.create_opts = &qemu_gluster_create_opts,
|
.create_opts = &qemu_gluster_create_opts,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -850,6 +1065,7 @@ static BlockDriver bdrv_gluster_rdma = {
|
|||||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
||||||
#endif
|
#endif
|
||||||
|
.bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
|
||||||
.create_opts = &qemu_gluster_create_opts,
|
.create_opts = &qemu_gluster_create_opts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
238
block/io.c
238
block/io.c
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
||||||
|
|
||||||
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
static BlockAIOCB *bdrv_co_aio_rw_vector(BdrvChild *child,
|
||||||
int64_t sector_num,
|
int64_t sector_num,
|
||||||
QEMUIOVector *qiov,
|
QEMUIOVector *qiov,
|
||||||
int nb_sectors,
|
int nb_sectors,
|
||||||
@@ -67,6 +67,17 @@ static void bdrv_parent_drained_end(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
|
||||||
|
{
|
||||||
|
dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer);
|
||||||
|
dst->max_transfer = MIN_NON_ZERO(dst->max_transfer, src->max_transfer);
|
||||||
|
dst->opt_mem_alignment = MAX(dst->opt_mem_alignment,
|
||||||
|
src->opt_mem_alignment);
|
||||||
|
dst->min_mem_alignment = MAX(dst->min_mem_alignment,
|
||||||
|
src->min_mem_alignment);
|
||||||
|
dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov);
|
||||||
|
}
|
||||||
|
|
||||||
void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
|
void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
@@ -78,6 +89,9 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Default alignment based on whether driver has byte interface */
|
||||||
|
bs->bl.request_alignment = drv->bdrv_co_preadv ? 1 : 512;
|
||||||
|
|
||||||
/* Take some limits from the children as a default */
|
/* Take some limits from the children as a default */
|
||||||
if (bs->file) {
|
if (bs->file) {
|
||||||
bdrv_refresh_limits(bs->file->bs, &local_err);
|
bdrv_refresh_limits(bs->file->bs, &local_err);
|
||||||
@@ -85,11 +99,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bs->bl.opt_transfer_length = bs->file->bs->bl.opt_transfer_length;
|
bdrv_merge_limits(&bs->bl, &bs->file->bs->bl);
|
||||||
bs->bl.max_transfer_length = bs->file->bs->bl.max_transfer_length;
|
|
||||||
bs->bl.min_mem_alignment = bs->file->bs->bl.min_mem_alignment;
|
|
||||||
bs->bl.opt_mem_alignment = bs->file->bs->bl.opt_mem_alignment;
|
|
||||||
bs->bl.max_iov = bs->file->bs->bl.max_iov;
|
|
||||||
} else {
|
} else {
|
||||||
bs->bl.min_mem_alignment = 512;
|
bs->bl.min_mem_alignment = 512;
|
||||||
bs->bl.opt_mem_alignment = getpagesize();
|
bs->bl.opt_mem_alignment = getpagesize();
|
||||||
@@ -104,21 +114,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bs->bl.opt_transfer_length =
|
bdrv_merge_limits(&bs->bl, &bs->backing->bs->bl);
|
||||||
MAX(bs->bl.opt_transfer_length,
|
|
||||||
bs->backing->bs->bl.opt_transfer_length);
|
|
||||||
bs->bl.max_transfer_length =
|
|
||||||
MIN_NON_ZERO(bs->bl.max_transfer_length,
|
|
||||||
bs->backing->bs->bl.max_transfer_length);
|
|
||||||
bs->bl.opt_mem_alignment =
|
|
||||||
MAX(bs->bl.opt_mem_alignment,
|
|
||||||
bs->backing->bs->bl.opt_mem_alignment);
|
|
||||||
bs->bl.min_mem_alignment =
|
|
||||||
MAX(bs->bl.min_mem_alignment,
|
|
||||||
bs->backing->bs->bl.min_mem_alignment);
|
|
||||||
bs->bl.max_iov =
|
|
||||||
MIN(bs->bl.max_iov,
|
|
||||||
bs->backing->bs->bl.max_iov);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then let the driver override it */
|
/* Then let the driver override it */
|
||||||
@@ -463,7 +459,7 @@ static int bdrv_get_cluster_size(BlockDriverState *bs)
|
|||||||
|
|
||||||
ret = bdrv_get_info(bs, &bdi);
|
ret = bdrv_get_info(bs, &bdi);
|
||||||
if (ret < 0 || bdi.cluster_size == 0) {
|
if (ret < 0 || bdi.cluster_size == 0) {
|
||||||
return bs->request_alignment;
|
return bs->bl.request_alignment;
|
||||||
} else {
|
} else {
|
||||||
return bdi.cluster_size;
|
return bdi.cluster_size;
|
||||||
}
|
}
|
||||||
@@ -557,7 +553,7 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef struct RwCo {
|
typedef struct RwCo {
|
||||||
BlockDriverState *bs;
|
BdrvChild *child;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
bool is_write;
|
bool is_write;
|
||||||
@@ -570,11 +566,11 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
|
|||||||
RwCo *rwco = opaque;
|
RwCo *rwco = opaque;
|
||||||
|
|
||||||
if (!rwco->is_write) {
|
if (!rwco->is_write) {
|
||||||
rwco->ret = bdrv_co_preadv(rwco->bs, rwco->offset,
|
rwco->ret = bdrv_co_preadv(rwco->child, rwco->offset,
|
||||||
rwco->qiov->size, rwco->qiov,
|
rwco->qiov->size, rwco->qiov,
|
||||||
rwco->flags);
|
rwco->flags);
|
||||||
} else {
|
} else {
|
||||||
rwco->ret = bdrv_co_pwritev(rwco->bs, rwco->offset,
|
rwco->ret = bdrv_co_pwritev(rwco->child, rwco->offset,
|
||||||
rwco->qiov->size, rwco->qiov,
|
rwco->qiov->size, rwco->qiov,
|
||||||
rwco->flags);
|
rwco->flags);
|
||||||
}
|
}
|
||||||
@@ -583,13 +579,13 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
|
|||||||
/*
|
/*
|
||||||
* Process a vectored synchronous request using coroutines
|
* Process a vectored synchronous request using coroutines
|
||||||
*/
|
*/
|
||||||
static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset,
|
static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
|
||||||
QEMUIOVector *qiov, bool is_write,
|
QEMUIOVector *qiov, bool is_write,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
Coroutine *co;
|
Coroutine *co;
|
||||||
RwCo rwco = {
|
RwCo rwco = {
|
||||||
.bs = bs,
|
.child = child,
|
||||||
.offset = offset,
|
.offset = offset,
|
||||||
.qiov = qiov,
|
.qiov = qiov,
|
||||||
.is_write = is_write,
|
.is_write = is_write,
|
||||||
@@ -601,7 +597,7 @@ static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset,
|
|||||||
/* Fast-path if already in coroutine context */
|
/* Fast-path if already in coroutine context */
|
||||||
bdrv_rw_co_entry(&rwco);
|
bdrv_rw_co_entry(&rwco);
|
||||||
} else {
|
} else {
|
||||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
AioContext *aio_context = bdrv_get_aio_context(child->bs);
|
||||||
|
|
||||||
co = qemu_coroutine_create(bdrv_rw_co_entry);
|
co = qemu_coroutine_create(bdrv_rw_co_entry);
|
||||||
qemu_coroutine_enter(co, &rwco);
|
qemu_coroutine_enter(co, &rwco);
|
||||||
@@ -615,7 +611,7 @@ static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset,
|
|||||||
/*
|
/*
|
||||||
* Process a synchronous request using coroutines
|
* Process a synchronous request using coroutines
|
||||||
*/
|
*/
|
||||||
static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
|
static int bdrv_rw_co(BdrvChild *child, int64_t sector_num, uint8_t *buf,
|
||||||
int nb_sectors, bool is_write, BdrvRequestFlags flags)
|
int nb_sectors, bool is_write, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
@@ -629,15 +625,15 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
return bdrv_prwv_co(bs, sector_num << BDRV_SECTOR_BITS,
|
return bdrv_prwv_co(child, sector_num << BDRV_SECTOR_BITS,
|
||||||
&qiov, is_write, flags);
|
&qiov, is_write, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return < 0 if error. See bdrv_write() for the return codes */
|
/* return < 0 if error. See bdrv_write() for the return codes */
|
||||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
int bdrv_read(BdrvChild *child, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors)
|
uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false, 0);
|
return bdrv_rw_co(child, sector_num, buf, nb_sectors, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return < 0 if error. Important errors are:
|
/* Return < 0 if error. Important errors are:
|
||||||
@@ -646,13 +642,13 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
-EINVAL Invalid sector number or nb_sectors
|
-EINVAL Invalid sector number or nb_sectors
|
||||||
-EACCES Trying to write a read-only device
|
-EACCES Trying to write a read-only device
|
||||||
*/
|
*/
|
||||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
int bdrv_write(BdrvChild *child, int64_t sector_num,
|
||||||
const uint8_t *buf, int nb_sectors)
|
const uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true, 0);
|
return bdrv_rw_co(child, sector_num, (uint8_t *)buf, nb_sectors, true, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
||||||
int count, BdrvRequestFlags flags)
|
int count, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
@@ -662,7 +658,7 @@ int bdrv_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
|||||||
};
|
};
|
||||||
|
|
||||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
return bdrv_prwv_co(bs, offset, &qiov, true,
|
return bdrv_prwv_co(child, offset, &qiov, true,
|
||||||
BDRV_REQ_ZERO_WRITE | flags);
|
BDRV_REQ_ZERO_WRITE | flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -675,9 +671,10 @@ int bdrv_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
|||||||
*
|
*
|
||||||
* Returns < 0 on error, 0 on success. For error codes see bdrv_write().
|
* Returns < 0 on error, 0 on success. For error codes see bdrv_write().
|
||||||
*/
|
*/
|
||||||
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
int64_t target_sectors, ret, nb_sectors, sector_num = 0;
|
int64_t target_sectors, ret, nb_sectors, sector_num = 0;
|
||||||
|
BlockDriverState *bs = child->bs;
|
||||||
BlockDriverState *file;
|
BlockDriverState *file;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@@ -701,7 +698,7 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
|||||||
sector_num += n;
|
sector_num += n;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ret = bdrv_pwrite_zeroes(bs, sector_num << BDRV_SECTOR_BITS,
|
ret = bdrv_pwrite_zeroes(child, sector_num << BDRV_SECTOR_BITS,
|
||||||
n << BDRV_SECTOR_BITS, flags);
|
n << BDRV_SECTOR_BITS, flags);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("error writing zeroes at sector %" PRId64 ": %s",
|
error_report("error writing zeroes at sector %" PRId64 ": %s",
|
||||||
@@ -712,11 +709,11 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_preadv(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov)
|
int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bdrv_prwv_co(bs, offset, qiov, false, 0);
|
ret = bdrv_prwv_co(child, offset, qiov, false, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -724,7 +721,7 @@ int bdrv_preadv(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov)
|
|||||||
return qiov->size;
|
return qiov->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_pread(BlockDriverState *bs, int64_t offset, void *buf, int bytes)
|
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
|
||||||
{
|
{
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
@@ -737,14 +734,14 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, void *buf, int bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
return bdrv_preadv(bs, offset, &qiov);
|
return bdrv_preadv(child, offset, &qiov);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_pwritev(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov)
|
int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bdrv_prwv_co(bs, offset, qiov, true, 0);
|
ret = bdrv_prwv_co(child, offset, qiov, true, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -752,8 +749,7 @@ int bdrv_pwritev(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov)
|
|||||||
return qiov->size;
|
return qiov->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes)
|
||||||
const void *buf, int bytes)
|
|
||||||
{
|
{
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
@@ -766,7 +762,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
return bdrv_pwritev(bs, offset, &qiov);
|
return bdrv_pwritev(child, offset, &qiov);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -775,17 +771,17 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
|||||||
*
|
*
|
||||||
* Returns 0 on success, -errno in error cases.
|
* Returns 0 on success, -errno in error cases.
|
||||||
*/
|
*/
|
||||||
int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
|
int bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
|
||||||
const void *buf, int count)
|
const void *buf, int count)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs, offset, buf, count);
|
ret = bdrv_pwrite(child, offset, buf, count);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_flush(bs);
|
ret = bdrv_flush(child->bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -945,6 +941,9 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
|
|||||||
|
|
||||||
if (drv->bdrv_co_pwrite_zeroes &&
|
if (drv->bdrv_co_pwrite_zeroes &&
|
||||||
buffer_is_zero(bounce_buffer, iov.iov_len)) {
|
buffer_is_zero(bounce_buffer, iov.iov_len)) {
|
||||||
|
/* FIXME: Should we (perhaps conditionally) be setting
|
||||||
|
* BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
|
||||||
|
* that still correctly reads as zero? */
|
||||||
ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, cluster_bytes, 0);
|
ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, cluster_bytes, 0);
|
||||||
} else {
|
} else {
|
||||||
/* This does not change the data on the disk, it is not necessary
|
/* This does not change the data on the disk, it is not necessary
|
||||||
@@ -987,7 +986,12 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
|
|||||||
assert((bytes & (align - 1)) == 0);
|
assert((bytes & (align - 1)) == 0);
|
||||||
assert(!qiov || bytes == qiov->size);
|
assert(!qiov || bytes == qiov->size);
|
||||||
assert((bs->open_flags & BDRV_O_NO_IO) == 0);
|
assert((bs->open_flags & BDRV_O_NO_IO) == 0);
|
||||||
assert(!(flags & ~BDRV_REQ_MASK));
|
|
||||||
|
/* TODO: We would need a per-BDS .supported_read_flags and
|
||||||
|
* potential fallback support, if we ever implement any read flags
|
||||||
|
* to pass through to drivers. For now, there aren't any
|
||||||
|
* passthrough flags. */
|
||||||
|
assert(!(flags & ~(BDRV_REQ_NO_SERIALISING | BDRV_REQ_COPY_ON_READ)));
|
||||||
|
|
||||||
/* Handle Copy on Read and associated serialisation */
|
/* Handle Copy on Read and associated serialisation */
|
||||||
if (flags & BDRV_REQ_COPY_ON_READ) {
|
if (flags & BDRV_REQ_COPY_ON_READ) {
|
||||||
@@ -1028,7 +1032,7 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
max_bytes = ROUND_UP(MAX(0, total_bytes - offset), align);
|
max_bytes = ROUND_UP(MAX(0, total_bytes - offset), align);
|
||||||
if (bytes < max_bytes) {
|
if (bytes <= max_bytes) {
|
||||||
ret = bdrv_driver_preadv(bs, offset, bytes, qiov, 0);
|
ret = bdrv_driver_preadv(bs, offset, bytes, qiov, 0);
|
||||||
} else if (max_bytes > 0) {
|
} else if (max_bytes > 0) {
|
||||||
QEMUIOVector local_qiov;
|
QEMUIOVector local_qiov;
|
||||||
@@ -1057,14 +1061,15 @@ out:
|
|||||||
/*
|
/*
|
||||||
* Handle a read request in coroutine context
|
* Handle a read request in coroutine context
|
||||||
*/
|
*/
|
||||||
int coroutine_fn bdrv_co_preadv(BlockDriverState *bs,
|
int coroutine_fn bdrv_co_preadv(BdrvChild *child,
|
||||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
|
BlockDriverState *bs = child->bs;
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
BdrvTrackedRequest req;
|
BdrvTrackedRequest req;
|
||||||
|
|
||||||
uint64_t align = bs->request_alignment;
|
uint64_t align = bs->bl.request_alignment;
|
||||||
uint8_t *head_buf = NULL;
|
uint8_t *head_buf = NULL;
|
||||||
uint8_t *tail_buf = NULL;
|
uint8_t *tail_buf = NULL;
|
||||||
QEMUIOVector local_qiov;
|
QEMUIOVector local_qiov;
|
||||||
@@ -1125,7 +1130,7 @@ int coroutine_fn bdrv_co_preadv(BlockDriverState *bs,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
|
static int coroutine_fn bdrv_co_do_readv(BdrvChild *child,
|
||||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
|
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
@@ -1133,19 +1138,20 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bdrv_co_preadv(bs, sector_num << BDRV_SECTOR_BITS,
|
return bdrv_co_preadv(child, sector_num << BDRV_SECTOR_BITS,
|
||||||
nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
|
nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
|
int coroutine_fn bdrv_co_readv(BdrvChild *child, int64_t sector_num,
|
||||||
int nb_sectors, QEMUIOVector *qiov)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
trace_bdrv_co_readv(bs, sector_num, nb_sectors);
|
trace_bdrv_co_readv(child->bs, sector_num, nb_sectors);
|
||||||
|
|
||||||
return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, 0);
|
return bdrv_co_do_readv(child, sector_num, nb_sectors, qiov, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_WRITE_ZEROES_BOUNCE_BUFFER 32768
|
/* Maximum buffer for write zeroes fallback, in bytes */
|
||||||
|
#define MAX_WRITE_ZEROES_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
|
||||||
|
|
||||||
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||||
int64_t offset, int count, BdrvRequestFlags flags)
|
int64_t offset, int count, BdrvRequestFlags flags)
|
||||||
@@ -1159,8 +1165,8 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
int tail = 0;
|
int tail = 0;
|
||||||
|
|
||||||
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
|
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
|
||||||
int alignment = MAX(bs->bl.pwrite_zeroes_alignment ?: 1,
|
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
|
||||||
bs->request_alignment);
|
bs->bl.request_alignment);
|
||||||
|
|
||||||
assert(is_power_of_2(alignment));
|
assert(is_power_of_2(alignment));
|
||||||
head = offset & (alignment - 1);
|
head = offset & (alignment - 1);
|
||||||
@@ -1203,7 +1209,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
|
|
||||||
if (ret == -ENOTSUP) {
|
if (ret == -ENOTSUP) {
|
||||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||||
int max_xfer_len = MIN_NON_ZERO(bs->bl.max_transfer_length,
|
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
|
||||||
MAX_WRITE_ZEROES_BOUNCE_BUFFER);
|
MAX_WRITE_ZEROES_BOUNCE_BUFFER);
|
||||||
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
|
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
|
||||||
|
|
||||||
@@ -1214,7 +1220,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
write_flags &= ~BDRV_REQ_FUA;
|
write_flags &= ~BDRV_REQ_FUA;
|
||||||
need_flush = true;
|
need_flush = true;
|
||||||
}
|
}
|
||||||
num = MIN(num, max_xfer_len << BDRV_SECTOR_BITS);
|
num = MIN(num, max_transfer);
|
||||||
iov.iov_len = num;
|
iov.iov_len = num;
|
||||||
if (iov.iov_base == NULL) {
|
if (iov.iov_base == NULL) {
|
||||||
iov.iov_base = qemu_try_blockalign(bs, num);
|
iov.iov_base = qemu_try_blockalign(bs, num);
|
||||||
@@ -1231,7 +1237,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
/* Keep bounce buffer around if it is big enough for all
|
/* Keep bounce buffer around if it is big enough for all
|
||||||
* all future requests.
|
* all future requests.
|
||||||
*/
|
*/
|
||||||
if (num < max_xfer_len << BDRV_SECTOR_BITS) {
|
if (num < max_transfer) {
|
||||||
qemu_vfree(iov.iov_base);
|
qemu_vfree(iov.iov_base);
|
||||||
iov.iov_base = NULL;
|
iov.iov_base = NULL;
|
||||||
}
|
}
|
||||||
@@ -1254,7 +1260,7 @@ fail:
|
|||||||
*/
|
*/
|
||||||
static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||||
BdrvTrackedRequest *req, int64_t offset, unsigned int bytes,
|
BdrvTrackedRequest *req, int64_t offset, unsigned int bytes,
|
||||||
QEMUIOVector *qiov, int flags)
|
int64_t align, QEMUIOVector *qiov, int flags)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
bool waited;
|
bool waited;
|
||||||
@@ -1263,6 +1269,9 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
|||||||
int64_t start_sector = offset >> BDRV_SECTOR_BITS;
|
int64_t start_sector = offset >> BDRV_SECTOR_BITS;
|
||||||
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
|
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
|
assert(is_power_of_2(align));
|
||||||
|
assert((offset & (align - 1)) == 0);
|
||||||
|
assert((bytes & (align - 1)) == 0);
|
||||||
assert(!qiov || bytes == qiov->size);
|
assert(!qiov || bytes == qiov->size);
|
||||||
assert((bs->open_flags & BDRV_O_NO_IO) == 0);
|
assert((bs->open_flags & BDRV_O_NO_IO) == 0);
|
||||||
assert(!(flags & ~BDRV_REQ_MASK));
|
assert(!(flags & ~BDRV_REQ_MASK));
|
||||||
@@ -1316,7 +1325,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
|
|||||||
uint8_t *buf = NULL;
|
uint8_t *buf = NULL;
|
||||||
QEMUIOVector local_qiov;
|
QEMUIOVector local_qiov;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
uint64_t align = bs->request_alignment;
|
uint64_t align = bs->bl.request_alignment;
|
||||||
unsigned int head_padding_bytes, tail_padding_bytes;
|
unsigned int head_padding_bytes, tail_padding_bytes;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@@ -1349,7 +1358,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
|
|||||||
|
|
||||||
memset(buf + head_padding_bytes, 0, zero_bytes);
|
memset(buf + head_padding_bytes, 0, zero_bytes);
|
||||||
ret = bdrv_aligned_pwritev(bs, req, offset & ~(align - 1), align,
|
ret = bdrv_aligned_pwritev(bs, req, offset & ~(align - 1), align,
|
||||||
&local_qiov,
|
align, &local_qiov,
|
||||||
flags & ~BDRV_REQ_ZERO_WRITE);
|
flags & ~BDRV_REQ_ZERO_WRITE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -1362,7 +1371,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
|
|||||||
if (bytes >= align) {
|
if (bytes >= align) {
|
||||||
/* Write the aligned part in the middle. */
|
/* Write the aligned part in the middle. */
|
||||||
uint64_t aligned_bytes = bytes & ~(align - 1);
|
uint64_t aligned_bytes = bytes & ~(align - 1);
|
||||||
ret = bdrv_aligned_pwritev(bs, req, offset, aligned_bytes,
|
ret = bdrv_aligned_pwritev(bs, req, offset, aligned_bytes, align,
|
||||||
NULL, flags);
|
NULL, flags);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -1386,7 +1395,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
|
|||||||
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
|
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
|
||||||
|
|
||||||
memset(buf, 0, bytes);
|
memset(buf, 0, bytes);
|
||||||
ret = bdrv_aligned_pwritev(bs, req, offset, align,
|
ret = bdrv_aligned_pwritev(bs, req, offset, align, align,
|
||||||
&local_qiov, flags & ~BDRV_REQ_ZERO_WRITE);
|
&local_qiov, flags & ~BDRV_REQ_ZERO_WRITE);
|
||||||
}
|
}
|
||||||
fail:
|
fail:
|
||||||
@@ -1398,12 +1407,13 @@ fail:
|
|||||||
/*
|
/*
|
||||||
* Handle a write request in coroutine context
|
* Handle a write request in coroutine context
|
||||||
*/
|
*/
|
||||||
int coroutine_fn bdrv_co_pwritev(BlockDriverState *bs,
|
int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
|
||||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
|
BlockDriverState *bs = child->bs;
|
||||||
BdrvTrackedRequest req;
|
BdrvTrackedRequest req;
|
||||||
uint64_t align = bs->request_alignment;
|
uint64_t align = bs->bl.request_alignment;
|
||||||
uint8_t *head_buf = NULL;
|
uint8_t *head_buf = NULL;
|
||||||
uint8_t *tail_buf = NULL;
|
uint8_t *tail_buf = NULL;
|
||||||
QEMUIOVector local_qiov;
|
QEMUIOVector local_qiov;
|
||||||
@@ -1511,7 +1521,7 @@ int coroutine_fn bdrv_co_pwritev(BlockDriverState *bs,
|
|||||||
bytes = ROUND_UP(bytes, align);
|
bytes = ROUND_UP(bytes, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_aligned_pwritev(bs, &req, offset, bytes,
|
ret = bdrv_aligned_pwritev(bs, &req, offset, bytes, align,
|
||||||
use_local_qiov ? &local_qiov : qiov,
|
use_local_qiov ? &local_qiov : qiov,
|
||||||
flags);
|
flags);
|
||||||
|
|
||||||
@@ -1527,7 +1537,7 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
|
static int coroutine_fn bdrv_co_do_writev(BdrvChild *child,
|
||||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
|
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
@@ -1535,29 +1545,28 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bdrv_co_pwritev(bs, sector_num << BDRV_SECTOR_BITS,
|
return bdrv_co_pwritev(child, sector_num << BDRV_SECTOR_BITS,
|
||||||
nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
|
nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
|
int coroutine_fn bdrv_co_writev(BdrvChild *child, int64_t sector_num,
|
||||||
int nb_sectors, QEMUIOVector *qiov)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
trace_bdrv_co_writev(bs, sector_num, nb_sectors);
|
trace_bdrv_co_writev(child->bs, sector_num, nb_sectors);
|
||||||
|
|
||||||
return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov, 0);
|
return bdrv_co_do_writev(child, sector_num, nb_sectors, qiov, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int coroutine_fn bdrv_co_pwrite_zeroes(BlockDriverState *bs,
|
int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
||||||
int64_t offset, int count,
|
int count, BdrvRequestFlags flags)
|
||||||
BdrvRequestFlags flags)
|
|
||||||
{
|
{
|
||||||
trace_bdrv_co_pwrite_zeroes(bs, offset, count, flags);
|
trace_bdrv_co_pwrite_zeroes(child->bs, offset, count, flags);
|
||||||
|
|
||||||
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
if (!(child->bs->open_flags & BDRV_O_UNMAP)) {
|
||||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bdrv_co_pwritev(bs, offset, count, NULL,
|
return bdrv_co_pwritev(child, offset, count, NULL,
|
||||||
BDRV_REQ_ZERO_WRITE | flags);
|
BDRV_REQ_ZERO_WRITE | flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1954,23 +1963,23 @@ int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
|
|||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
/* async I/Os */
|
/* async I/Os */
|
||||||
|
|
||||||
BlockAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
BlockAIOCB *bdrv_aio_readv(BdrvChild *child, int64_t sector_num,
|
||||||
QEMUIOVector *qiov, int nb_sectors,
|
QEMUIOVector *qiov, int nb_sectors,
|
||||||
BlockCompletionFunc *cb, void *opaque)
|
BlockCompletionFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
|
trace_bdrv_aio_readv(child->bs, sector_num, nb_sectors, opaque);
|
||||||
|
|
||||||
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
|
return bdrv_co_aio_rw_vector(child, sector_num, qiov, nb_sectors, 0,
|
||||||
cb, opaque, false);
|
cb, opaque, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
BlockAIOCB *bdrv_aio_writev(BdrvChild *child, int64_t sector_num,
|
||||||
QEMUIOVector *qiov, int nb_sectors,
|
QEMUIOVector *qiov, int nb_sectors,
|
||||||
BlockCompletionFunc *cb, void *opaque)
|
BlockCompletionFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
|
trace_bdrv_aio_writev(child->bs, sector_num, nb_sectors, opaque);
|
||||||
|
|
||||||
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
|
return bdrv_co_aio_rw_vector(child, sector_num, qiov, nb_sectors, 0,
|
||||||
cb, opaque, true);
|
cb, opaque, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2026,6 +2035,7 @@ typedef struct BlockRequest {
|
|||||||
|
|
||||||
typedef struct BlockAIOCBCoroutine {
|
typedef struct BlockAIOCBCoroutine {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
|
BdrvChild *child;
|
||||||
BlockRequest req;
|
BlockRequest req;
|
||||||
bool is_write;
|
bool is_write;
|
||||||
bool need_bh;
|
bool need_bh;
|
||||||
@@ -2069,20 +2079,19 @@ static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb)
|
|||||||
static void coroutine_fn bdrv_co_do_rw(void *opaque)
|
static void coroutine_fn bdrv_co_do_rw(void *opaque)
|
||||||
{
|
{
|
||||||
BlockAIOCBCoroutine *acb = opaque;
|
BlockAIOCBCoroutine *acb = opaque;
|
||||||
BlockDriverState *bs = acb->common.bs;
|
|
||||||
|
|
||||||
if (!acb->is_write) {
|
if (!acb->is_write) {
|
||||||
acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
|
acb->req.error = bdrv_co_do_readv(acb->child, acb->req.sector,
|
||||||
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
|
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
|
||||||
} else {
|
} else {
|
||||||
acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
|
acb->req.error = bdrv_co_do_writev(acb->child, acb->req.sector,
|
||||||
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
|
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_co_complete(acb);
|
bdrv_co_complete(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
static BlockAIOCB *bdrv_co_aio_rw_vector(BdrvChild *child,
|
||||||
int64_t sector_num,
|
int64_t sector_num,
|
||||||
QEMUIOVector *qiov,
|
QEMUIOVector *qiov,
|
||||||
int nb_sectors,
|
int nb_sectors,
|
||||||
@@ -2094,7 +2103,8 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
|||||||
Coroutine *co;
|
Coroutine *co;
|
||||||
BlockAIOCBCoroutine *acb;
|
BlockAIOCBCoroutine *acb;
|
||||||
|
|
||||||
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, child->bs, cb, opaque);
|
||||||
|
acb->child = child;
|
||||||
acb->need_bh = true;
|
acb->need_bh = true;
|
||||||
acb->req.error = -EINPROGRESS;
|
acb->req.error = -EINPROGRESS;
|
||||||
acb->req.sector = sector_num;
|
acb->req.sector = sector_num;
|
||||||
@@ -2200,9 +2210,15 @@ void qemu_aio_unref(void *p)
|
|||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
/* Coroutine block device emulation */
|
/* Coroutine block device emulation */
|
||||||
|
|
||||||
|
typedef struct FlushCo {
|
||||||
|
BlockDriverState *bs;
|
||||||
|
int ret;
|
||||||
|
} FlushCo;
|
||||||
|
|
||||||
|
|
||||||
static void coroutine_fn bdrv_flush_co_entry(void *opaque)
|
static void coroutine_fn bdrv_flush_co_entry(void *opaque)
|
||||||
{
|
{
|
||||||
RwCo *rwco = opaque;
|
FlushCo *rwco = opaque;
|
||||||
|
|
||||||
rwco->ret = bdrv_co_flush(rwco->bs);
|
rwco->ret = bdrv_co_flush(rwco->bs);
|
||||||
}
|
}
|
||||||
@@ -2286,25 +2302,25 @@ out:
|
|||||||
int bdrv_flush(BlockDriverState *bs)
|
int bdrv_flush(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
Coroutine *co;
|
Coroutine *co;
|
||||||
RwCo rwco = {
|
FlushCo flush_co = {
|
||||||
.bs = bs,
|
.bs = bs,
|
||||||
.ret = NOT_DONE,
|
.ret = NOT_DONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (qemu_in_coroutine()) {
|
if (qemu_in_coroutine()) {
|
||||||
/* Fast-path if already in coroutine context */
|
/* Fast-path if already in coroutine context */
|
||||||
bdrv_flush_co_entry(&rwco);
|
bdrv_flush_co_entry(&flush_co);
|
||||||
} else {
|
} else {
|
||||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||||
|
|
||||||
co = qemu_coroutine_create(bdrv_flush_co_entry);
|
co = qemu_coroutine_create(bdrv_flush_co_entry);
|
||||||
qemu_coroutine_enter(co, &rwco);
|
qemu_coroutine_enter(co, &flush_co);
|
||||||
while (rwco.ret == NOT_DONE) {
|
while (flush_co.ret == NOT_DONE) {
|
||||||
aio_poll(aio_context, true);
|
aio_poll(aio_context, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rwco.ret;
|
return flush_co.ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct DiscardCo {
|
typedef struct DiscardCo {
|
||||||
@@ -2355,19 +2371,21 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
max_discard = MIN_NON_ZERO(bs->bl.max_discard, BDRV_REQUEST_MAX_SECTORS);
|
max_discard = MIN_NON_ZERO(bs->bl.max_pdiscard >> BDRV_SECTOR_BITS,
|
||||||
|
BDRV_REQUEST_MAX_SECTORS);
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
int ret;
|
int ret;
|
||||||
int num = nb_sectors;
|
int num = nb_sectors;
|
||||||
|
int discard_alignment = bs->bl.pdiscard_alignment >> BDRV_SECTOR_BITS;
|
||||||
|
|
||||||
/* align request */
|
/* align request */
|
||||||
if (bs->bl.discard_alignment &&
|
if (discard_alignment &&
|
||||||
num >= bs->bl.discard_alignment &&
|
num >= discard_alignment &&
|
||||||
sector_num % bs->bl.discard_alignment) {
|
sector_num % discard_alignment) {
|
||||||
if (num > bs->bl.discard_alignment) {
|
if (num > discard_alignment) {
|
||||||
num = bs->bl.discard_alignment;
|
num = discard_alignment;
|
||||||
}
|
}
|
||||||
num -= sector_num % bs->bl.discard_alignment;
|
num -= sector_num % discard_alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* limit request size */
|
/* limit request size */
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ static bool is_byte_request_lun_aligned(int64_t offset, int count,
|
|||||||
static bool is_sector_request_lun_aligned(int64_t sector_num, int nb_sectors,
|
static bool is_sector_request_lun_aligned(int64_t sector_num, int nb_sectors,
|
||||||
IscsiLun *iscsilun)
|
IscsiLun *iscsilun)
|
||||||
{
|
{
|
||||||
assert(nb_sectors < BDRV_REQUEST_MAX_SECTORS);
|
assert(nb_sectors <= BDRV_REQUEST_MAX_SECTORS);
|
||||||
return is_byte_request_lun_aligned(sector_num << BDRV_SECTOR_BITS,
|
return is_byte_request_lun_aligned(sector_num << BDRV_SECTOR_BITS,
|
||||||
nb_sectors << BDRV_SECTOR_BITS,
|
nb_sectors << BDRV_SECTOR_BITS,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
@@ -473,9 +473,10 @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->bl.max_transfer_length && nb_sectors > bs->bl.max_transfer_length) {
|
if (bs->bl.max_transfer &&
|
||||||
|
nb_sectors << BDRV_SECTOR_BITS > bs->bl.max_transfer) {
|
||||||
error_report("iSCSI Error: Write of %d sectors exceeds max_xfer_len "
|
error_report("iSCSI Error: Write of %d sectors exceeds max_xfer_len "
|
||||||
"of %d sectors", nb_sectors, bs->bl.max_transfer_length);
|
"of %" PRIu32 " bytes", nb_sectors, bs->bl.max_transfer);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,9 +651,10 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->bl.max_transfer_length && nb_sectors > bs->bl.max_transfer_length) {
|
if (bs->bl.max_transfer &&
|
||||||
|
nb_sectors << BDRV_SECTOR_BITS > bs->bl.max_transfer) {
|
||||||
error_report("iSCSI Error: Read of %d sectors exceeds max_xfer_len "
|
error_report("iSCSI Error: Read of %d sectors exceeds max_xfer_len "
|
||||||
"of %d sectors", nb_sectors, bs->bl.max_transfer_length);
|
"of %" PRIu32 " bytes", nb_sectors, bs->bl.max_transfer);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,7 +663,8 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
|||||||
int64_t ret;
|
int64_t ret;
|
||||||
int pnum;
|
int pnum;
|
||||||
BlockDriverState *file;
|
BlockDriverState *file;
|
||||||
ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum, &file);
|
ret = iscsi_co_get_block_status(bs, sector_num,
|
||||||
|
BDRV_REQUEST_MAX_SECTORS, &pnum, &file);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1588,14 +1591,13 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
||||||
bs->request_alignment = iscsilun->block_size;
|
|
||||||
|
|
||||||
/* We don't have any emulation for devices other than disks and CD-ROMs, so
|
/* We don't have any emulation for devices other than disks and CD-ROMs, so
|
||||||
* this must be sg ioctl compatible. We force it to be sg, otherwise qemu
|
* this must be sg ioctl compatible. We force it to be sg, otherwise qemu
|
||||||
* will try to read from the device to guess the image format.
|
* will try to read from the device to guess the image format.
|
||||||
*/
|
*/
|
||||||
if (iscsilun->type != TYPE_DISK && iscsilun->type != TYPE_ROM) {
|
if (iscsilun->type != TYPE_DISK && iscsilun->type != TYPE_ROM) {
|
||||||
bs->sg = 1;
|
bs->sg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||||
@@ -1695,34 +1697,33 @@ static void iscsi_close(BlockDriverState *bs)
|
|||||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sector_limits_lun2qemu(int64_t sector, IscsiLun *iscsilun)
|
|
||||||
{
|
|
||||||
return MIN(sector_lun2qemu(sector, iscsilun), INT_MAX / 2 + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
|
static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
/* We don't actually refresh here, but just return data queried in
|
/* We don't actually refresh here, but just return data queried in
|
||||||
* iscsi_open(): iscsi targets don't change their limits. */
|
* iscsi_open(): iscsi targets don't change their limits. */
|
||||||
|
|
||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
uint32_t max_xfer_len = iscsilun->use_16_for_rw ? 0xffffffff : 0xffff;
|
uint64_t max_xfer_len = iscsilun->use_16_for_rw ? 0xffffffff : 0xffff;
|
||||||
|
|
||||||
|
bs->bl.request_alignment = iscsilun->block_size;
|
||||||
|
|
||||||
if (iscsilun->bl.max_xfer_len) {
|
if (iscsilun->bl.max_xfer_len) {
|
||||||
max_xfer_len = MIN(max_xfer_len, iscsilun->bl.max_xfer_len);
|
max_xfer_len = MIN(max_xfer_len, iscsilun->bl.max_xfer_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->bl.max_transfer_length = sector_limits_lun2qemu(max_xfer_len, iscsilun);
|
if (max_xfer_len * iscsilun->block_size < INT_MAX) {
|
||||||
|
bs->bl.max_transfer = max_xfer_len * iscsilun->block_size;
|
||||||
|
}
|
||||||
|
|
||||||
if (iscsilun->lbp.lbpu) {
|
if (iscsilun->lbp.lbpu) {
|
||||||
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
if (iscsilun->bl.max_unmap < 0xffffffff / iscsilun->block_size) {
|
||||||
bs->bl.max_discard =
|
bs->bl.max_pdiscard =
|
||||||
sector_limits_lun2qemu(iscsilun->bl.max_unmap, iscsilun);
|
iscsilun->bl.max_unmap * iscsilun->block_size;
|
||||||
}
|
}
|
||||||
bs->bl.discard_alignment =
|
bs->bl.pdiscard_alignment =
|
||||||
sector_limits_lun2qemu(iscsilun->bl.opt_unmap_gran, iscsilun);
|
iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
||||||
} else {
|
} else {
|
||||||
bs->bl.discard_alignment = iscsilun->block_size >> BDRV_SECTOR_BITS;
|
bs->bl.pdiscard_alignment = iscsilun->block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscsilun->bl.max_ws_len < 0xffffffff / iscsilun->block_size) {
|
if (iscsilun->bl.max_ws_len < 0xffffffff / iscsilun->block_size) {
|
||||||
@@ -1735,8 +1736,11 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
} else {
|
} else {
|
||||||
bs->bl.pwrite_zeroes_alignment = iscsilun->block_size;
|
bs->bl.pwrite_zeroes_alignment = iscsilun->block_size;
|
||||||
}
|
}
|
||||||
bs->bl.opt_transfer_length =
|
if (iscsilun->bl.opt_xfer_len &&
|
||||||
sector_limits_lun2qemu(iscsilun->bl.opt_xfer_len, iscsilun);
|
iscsilun->bl.opt_xfer_len < INT_MAX / iscsilun->block_size) {
|
||||||
|
bs->bl.opt_transfer = pow2floor(iscsilun->bl.opt_xfer_len *
|
||||||
|
iscsilun->block_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note that this will not re-establish a connection with an iSCSI target - it
|
/* Note that this will not re-establish a connection with an iSCSI target - it
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
|
|||||||
qemu_iovec_memset(laiocb->qiov, ret, 0,
|
qemu_iovec_memset(laiocb->qiov, ret, 0,
|
||||||
laiocb->qiov->size - ret);
|
laiocb->qiov->size - ret);
|
||||||
} else {
|
} else {
|
||||||
ret = -EINVAL;
|
ret = -ENOSPC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,9 @@ static inline void mirror_wait_for_io(MirrorBlockJob *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Submit async read while handling COW.
|
/* Submit async read while handling COW.
|
||||||
* Returns: nb_sectors if no alignment is necessary, or
|
* Returns: The number of sectors copied after and including sector_num,
|
||||||
|
* excluding any sectors copied prior to sector_num due to alignment.
|
||||||
|
* This will be nb_sectors if no alignment is necessary, or
|
||||||
* (new_end - sector_num) if tail is rounded up or down due to
|
* (new_end - sector_num) if tail is rounded up or down due to
|
||||||
* alignment or buffer limit.
|
* alignment or buffer limit.
|
||||||
*/
|
*/
|
||||||
@@ -227,14 +229,18 @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num,
|
|||||||
{
|
{
|
||||||
BlockBackend *source = s->common.blk;
|
BlockBackend *source = s->common.blk;
|
||||||
int sectors_per_chunk, nb_chunks;
|
int sectors_per_chunk, nb_chunks;
|
||||||
int ret = nb_sectors;
|
int ret;
|
||||||
MirrorOp *op;
|
MirrorOp *op;
|
||||||
|
int max_sectors;
|
||||||
|
|
||||||
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
|
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
|
||||||
|
max_sectors = sectors_per_chunk * s->max_iov;
|
||||||
|
|
||||||
/* We can only handle as much as buf_size at a time. */
|
/* We can only handle as much as buf_size at a time. */
|
||||||
nb_sectors = MIN(s->buf_size >> BDRV_SECTOR_BITS, nb_sectors);
|
nb_sectors = MIN(s->buf_size >> BDRV_SECTOR_BITS, nb_sectors);
|
||||||
|
nb_sectors = MIN(max_sectors, nb_sectors);
|
||||||
assert(nb_sectors);
|
assert(nb_sectors);
|
||||||
|
ret = nb_sectors;
|
||||||
|
|
||||||
if (s->cow_bitmap) {
|
if (s->cow_bitmap) {
|
||||||
ret += mirror_cow_align(s, §or_num, &nb_sectors);
|
ret += mirror_cow_align(s, §or_num, &nb_sectors);
|
||||||
@@ -327,7 +333,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
|
|
||||||
first_chunk = sector_num / sectors_per_chunk;
|
first_chunk = sector_num / sectors_per_chunk;
|
||||||
while (test_bit(first_chunk, s->in_flight_bitmap)) {
|
while (test_bit(first_chunk, s->in_flight_bitmap)) {
|
||||||
trace_mirror_yield_in_flight(s, first_chunk, s->in_flight);
|
trace_mirror_yield_in_flight(s, sector_num, s->in_flight);
|
||||||
mirror_wait_for_io(s);
|
mirror_wait_for_io(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,7 +775,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check the target bs is not blocked and block all operations on it */
|
/* block all operations on to_replace bs */
|
||||||
if (s->replaces) {
|
if (s->replaces) {
|
||||||
AioContext *replace_aio_context;
|
AioContext *replace_aio_context;
|
||||||
|
|
||||||
|
|||||||
@@ -269,10 +269,6 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return -reply.error;
|
return -reply.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qemu-nbd has a limit of slightly less than 1M per request. Try to
|
|
||||||
* remain aligned to 4K. */
|
|
||||||
#define NBD_MAX_SECTORS 2040
|
|
||||||
|
|
||||||
int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
|
int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors, QEMUIOVector *qiov)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -362,8 +362,8 @@ static int nbd_co_flush(BlockDriverState *bs)
|
|||||||
|
|
||||||
static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
|
static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
bs->bl.max_discard = UINT32_MAX >> BDRV_SECTOR_BITS;
|
bs->bl.max_pdiscard = NBD_MAX_BUFFER_SIZE;
|
||||||
bs->bl.max_transfer_length = UINT32_MAX >> BDRV_SECTOR_BITS;
|
bs->bl.max_transfer = NBD_MAX_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
|
static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
|||||||
55
block/nfs.c
55
block/nfs.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* QEMU Block driver for native access to files on NFS shares
|
* QEMU Block driver for native access to files on NFS shares
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014 Peter Lieven <pl@kamp.de>
|
* Copyright (c) 2014-2016 Peter Lieven <pl@kamp.de>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
#include <nfsc/libnfs.h>
|
#include <nfsc/libnfs.h>
|
||||||
|
|
||||||
#define QEMU_NFS_MAX_READAHEAD_SIZE 1048576
|
#define QEMU_NFS_MAX_READAHEAD_SIZE 1048576
|
||||||
|
#define QEMU_NFS_MAX_PAGECACHE_SIZE (8388608 / NFS_BLKSIZE)
|
||||||
#define QEMU_NFS_MAX_DEBUG_LEVEL 2
|
#define QEMU_NFS_MAX_DEBUG_LEVEL 2
|
||||||
|
|
||||||
typedef struct NFSClient {
|
typedef struct NFSClient {
|
||||||
@@ -47,6 +48,7 @@ typedef struct NFSClient {
|
|||||||
bool has_zero_init;
|
bool has_zero_init;
|
||||||
AioContext *aio_context;
|
AioContext *aio_context;
|
||||||
blkcnt_t st_blocks;
|
blkcnt_t st_blocks;
|
||||||
|
bool cache_used;
|
||||||
} NFSClient;
|
} NFSClient;
|
||||||
|
|
||||||
typedef struct NFSRPC {
|
typedef struct NFSRPC {
|
||||||
@@ -278,7 +280,7 @@ static void nfs_file_close(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
||||||
int flags, Error **errp)
|
int flags, Error **errp, int open_flags)
|
||||||
{
|
{
|
||||||
int ret = -EINVAL, i;
|
int ret = -EINVAL, i;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -330,12 +332,38 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
|||||||
nfs_set_tcp_syncnt(client->context, val);
|
nfs_set_tcp_syncnt(client->context, val);
|
||||||
#ifdef LIBNFS_FEATURE_READAHEAD
|
#ifdef LIBNFS_FEATURE_READAHEAD
|
||||||
} else if (!strcmp(qp->p[i].name, "readahead")) {
|
} else if (!strcmp(qp->p[i].name, "readahead")) {
|
||||||
|
if (open_flags & BDRV_O_NOCACHE) {
|
||||||
|
error_setg(errp, "Cannot enable NFS readahead "
|
||||||
|
"if cache.direct = on");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
if (val > QEMU_NFS_MAX_READAHEAD_SIZE) {
|
if (val > QEMU_NFS_MAX_READAHEAD_SIZE) {
|
||||||
error_report("NFS Warning: Truncating NFS readahead"
|
error_report("NFS Warning: Truncating NFS readahead"
|
||||||
" size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
|
" size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
|
||||||
val = QEMU_NFS_MAX_READAHEAD_SIZE;
|
val = QEMU_NFS_MAX_READAHEAD_SIZE;
|
||||||
}
|
}
|
||||||
nfs_set_readahead(client->context, val);
|
nfs_set_readahead(client->context, val);
|
||||||
|
#ifdef LIBNFS_FEATURE_PAGECACHE
|
||||||
|
nfs_set_pagecache_ttl(client->context, 0);
|
||||||
|
#endif
|
||||||
|
client->cache_used = true;
|
||||||
|
#endif
|
||||||
|
#ifdef LIBNFS_FEATURE_PAGECACHE
|
||||||
|
nfs_set_pagecache_ttl(client->context, 0);
|
||||||
|
} else if (!strcmp(qp->p[i].name, "pagecache")) {
|
||||||
|
if (open_flags & BDRV_O_NOCACHE) {
|
||||||
|
error_setg(errp, "Cannot enable NFS pagecache "
|
||||||
|
"if cache.direct = on");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (val > QEMU_NFS_MAX_PAGECACHE_SIZE) {
|
||||||
|
error_report("NFS Warning: Truncating NFS pagecache"
|
||||||
|
" size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE);
|
||||||
|
val = QEMU_NFS_MAX_PAGECACHE_SIZE;
|
||||||
|
}
|
||||||
|
nfs_set_pagecache(client->context, val);
|
||||||
|
nfs_set_pagecache_ttl(client->context, 0);
|
||||||
|
client->cache_used = true;
|
||||||
#endif
|
#endif
|
||||||
#ifdef LIBNFS_FEATURE_DEBUG
|
#ifdef LIBNFS_FEATURE_DEBUG
|
||||||
} else if (!strcmp(qp->p[i].name, "debug")) {
|
} else if (!strcmp(qp->p[i].name, "debug")) {
|
||||||
@@ -418,7 +446,7 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
ret = nfs_client_open(client, qemu_opt_get(opts, "filename"),
|
ret = nfs_client_open(client, qemu_opt_get(opts, "filename"),
|
||||||
(flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
|
(flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
|
||||||
errp);
|
errp, bs->open_flags);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -454,7 +482,7 @@ static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
|
|||||||
total_size = ROUND_UP(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);
|
BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
ret = nfs_client_open(client, url, O_CREAT, errp);
|
ret = nfs_client_open(client, url, O_CREAT, errp, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -516,6 +544,12 @@ static int nfs_reopen_prepare(BDRVReopenState *state,
|
|||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((state->flags & BDRV_O_NOCACHE) && client->cache_used) {
|
||||||
|
error_setg(errp, "Cannot disable cache if libnfs readahead or"
|
||||||
|
" pagecache is enabled");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update cache for read-only reopens */
|
/* Update cache for read-only reopens */
|
||||||
if (!(state->flags & BDRV_O_RDWR)) {
|
if (!(state->flags & BDRV_O_RDWR)) {
|
||||||
ret = nfs_fstat(client->context, client->fh, &st);
|
ret = nfs_fstat(client->context, client->fh, &st);
|
||||||
@@ -530,6 +564,15 @@ static int nfs_reopen_prepare(BDRVReopenState *state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LIBNFS_FEATURE_PAGECACHE
|
||||||
|
static void nfs_invalidate_cache(BlockDriverState *bs,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
nfs_pagecache_invalidate(client->context, client->fh);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static BlockDriver bdrv_nfs = {
|
static BlockDriver bdrv_nfs = {
|
||||||
.format_name = "nfs",
|
.format_name = "nfs",
|
||||||
.protocol_name = "nfs",
|
.protocol_name = "nfs",
|
||||||
@@ -553,6 +596,10 @@ static BlockDriver bdrv_nfs = {
|
|||||||
|
|
||||||
.bdrv_detach_aio_context = nfs_detach_aio_context,
|
.bdrv_detach_aio_context = nfs_detach_aio_context,
|
||||||
.bdrv_attach_aio_context = nfs_attach_aio_context,
|
.bdrv_attach_aio_context = nfs_attach_aio_context,
|
||||||
|
|
||||||
|
#ifdef LIBNFS_FEATURE_PAGECACHE
|
||||||
|
.bdrv_invalidate_cache = nfs_invalidate_cache,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void nfs_block_init(void)
|
static void nfs_block_init(void)
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
|
|||||||
int ret;
|
int ret;
|
||||||
space += s->prealloc_size;
|
space += s->prealloc_size;
|
||||||
if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
|
if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
|
||||||
ret = bdrv_pwrite_zeroes(bs->file->bs,
|
ret = bdrv_pwrite_zeroes(bs->file,
|
||||||
s->data_end << BDRV_SECTOR_BITS,
|
s->data_end << BDRV_SECTOR_BITS,
|
||||||
space << BDRV_SECTOR_BITS, 0);
|
space << BDRV_SECTOR_BITS, 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -250,7 +250,7 @@ static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
|
|||||||
if (off + to_write > s->header_size) {
|
if (off + to_write > s->header_size) {
|
||||||
to_write = s->header_size - off;
|
to_write = s->header_size - off;
|
||||||
}
|
}
|
||||||
ret = bdrv_pwrite(bs->file->bs, off, (uint8_t *)s->header + off,
|
ret = bdrv_pwrite(bs->file, off, (uint8_t *)s->header + off,
|
||||||
to_write);
|
to_write);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
@@ -311,7 +311,7 @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
|
|||||||
qemu_iovec_reset(&hd_qiov);
|
qemu_iovec_reset(&hd_qiov);
|
||||||
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
|
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
|
||||||
|
|
||||||
ret = bdrv_co_writev(bs->file->bs, position, n, &hd_qiov);
|
ret = bdrv_co_writev(bs->file, position, n, &hd_qiov);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -351,7 +351,7 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
|
|||||||
qemu_iovec_reset(&hd_qiov);
|
qemu_iovec_reset(&hd_qiov);
|
||||||
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
|
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
|
||||||
|
|
||||||
ret = bdrv_co_readv(bs->file->bs, position, n, &hd_qiov);
|
ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -432,7 +432,7 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (flush_bat) {
|
if (flush_bat) {
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, 0, s->header, s->header_size);
|
ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
res->check_errors++;
|
res->check_errors++;
|
||||||
return ret;
|
return ret;
|
||||||
@@ -563,7 +563,7 @@ static int parallels_update_header(BlockDriverState *bs)
|
|||||||
if (size > s->header_size) {
|
if (size > s->header_size) {
|
||||||
size = s->header_size;
|
size = s->header_size;
|
||||||
}
|
}
|
||||||
return bdrv_pwrite_sync(bs->file->bs, 0, s->header, size);
|
return bdrv_pwrite_sync(bs->file, 0, s->header, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
@@ -576,7 +576,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 0, &ph, sizeof(ph));
|
ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -631,7 +631,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->header_size = size;
|
s->header_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 0, s->header, s->header_size);
|
ret = bdrv_pread(bs->file, 0, s->header, s->header_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -690,16 +690,15 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
|
|||||||
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
||||||
ImageInfoSpecific *info_spec)
|
ImageInfoSpecific *info_spec)
|
||||||
{
|
{
|
||||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
|
||||||
QObject *obj, *data;
|
QObject *obj, *data;
|
||||||
|
Visitor *v = qmp_output_visitor_new(&obj);
|
||||||
|
|
||||||
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), NULL, &info_spec,
|
visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort);
|
||||||
&error_abort);
|
visit_complete(v, &obj);
|
||||||
obj = qmp_output_get_qobject(ov);
|
|
||||||
assert(qobject_type(obj) == QTYPE_QDICT);
|
assert(qobject_type(obj) == QTYPE_QDICT);
|
||||||
data = qdict_get(qobject_to_qdict(obj), "data");
|
data = qdict_get(qobject_to_qdict(obj), "data");
|
||||||
dump_qobject(func_fprintf, f, 1, data);
|
dump_qobject(func_fprintf, f, 1, data);
|
||||||
qmp_output_visitor_cleanup(ov);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
|
void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
|
||||||
|
|||||||
78
block/qcow.c
78
block/qcow.c
@@ -105,7 +105,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
int ret;
|
int ret;
|
||||||
QCowHeader header;
|
QCowHeader header;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header));
|
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->encrypted = 1;
|
bs->encrypted = true;
|
||||||
}
|
}
|
||||||
s->cluster_bits = header.cluster_bits;
|
s->cluster_bits = header.cluster_bits;
|
||||||
s->cluster_size = 1 << s->cluster_bits;
|
s->cluster_size = 1 << s->cluster_bits;
|
||||||
@@ -208,7 +208,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table,
|
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
|
||||||
s->l1_size * sizeof(uint64_t));
|
s->l1_size * sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -239,7 +239,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file->bs, header.backing_file_offset,
|
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||||
bs->backing_file, len);
|
bs->backing_file, len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -390,7 +390,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
/* update the L1 entry */
|
/* update the L1 entry */
|
||||||
s->l1_table[l1_index] = l2_offset;
|
s->l1_table[l1_index] = l2_offset;
|
||||||
tmp = cpu_to_be64(l2_offset);
|
tmp = cpu_to_be64(l2_offset);
|
||||||
if (bdrv_pwrite_sync(bs->file->bs,
|
if (bdrv_pwrite_sync(bs->file,
|
||||||
s->l1_table_offset + l1_index * sizeof(tmp),
|
s->l1_table_offset + l1_index * sizeof(tmp),
|
||||||
&tmp, sizeof(tmp)) < 0)
|
&tmp, sizeof(tmp)) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -420,11 +420,11 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
||||||
if (new_l2_table) {
|
if (new_l2_table) {
|
||||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
||||||
if (bdrv_pwrite_sync(bs->file->bs, l2_offset, l2_table,
|
if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
|
||||||
s->l2_size * sizeof(uint64_t)) < 0)
|
s->l2_size * sizeof(uint64_t)) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (bdrv_pread(bs->file->bs, l2_offset, l2_table,
|
if (bdrv_pread(bs->file, l2_offset, l2_table,
|
||||||
s->l2_size * sizeof(uint64_t)) !=
|
s->l2_size * sizeof(uint64_t)) !=
|
||||||
s->l2_size * sizeof(uint64_t))
|
s->l2_size * sizeof(uint64_t))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -450,7 +450,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||||
~(s->cluster_size - 1);
|
~(s->cluster_size - 1);
|
||||||
/* write the cluster content */
|
/* write the cluster content */
|
||||||
if (bdrv_pwrite(bs->file->bs, cluster_offset, s->cluster_cache,
|
if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
|
||||||
s->cluster_size) !=
|
s->cluster_size) !=
|
||||||
s->cluster_size)
|
s->cluster_size)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -480,7 +480,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (bdrv_pwrite(bs->file->bs,
|
if (bdrv_pwrite(bs->file,
|
||||||
cluster_offset + i * 512,
|
cluster_offset + i * 512,
|
||||||
s->cluster_data, 512) != 512)
|
s->cluster_data, 512) != 512)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -495,7 +495,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
|||||||
/* update L2 table */
|
/* update L2 table */
|
||||||
tmp = cpu_to_be64(cluster_offset);
|
tmp = cpu_to_be64(cluster_offset);
|
||||||
l2_table[l2_index] = tmp;
|
l2_table[l2_index] = tmp;
|
||||||
if (bdrv_pwrite_sync(bs->file->bs, l2_offset + l2_index * sizeof(tmp),
|
if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
|
||||||
&tmp, sizeof(tmp)) < 0)
|
&tmp, sizeof(tmp)) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -565,7 +565,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
|||||||
if (s->cluster_cache_offset != coffset) {
|
if (s->cluster_cache_offset != coffset) {
|
||||||
csize = cluster_offset >> (63 - s->cluster_bits);
|
csize = cluster_offset >> (63 - s->cluster_bits);
|
||||||
csize &= (s->cluster_size - 1);
|
csize &= (s->cluster_size - 1);
|
||||||
ret = bdrv_pread(bs->file->bs, coffset, s->cluster_data, csize);
|
ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
|
||||||
if (ret != csize)
|
if (ret != csize)
|
||||||
return -1;
|
return -1;
|
||||||
if (decompress_buffer(s->cluster_cache, s->cluster_size,
|
if (decompress_buffer(s->cluster_cache, s->cluster_size,
|
||||||
@@ -619,8 +619,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
hd_iov.iov_len = n * 512;
|
hd_iov.iov_len = n * 512;
|
||||||
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
ret = bdrv_co_readv(bs->backing->bs, sector_num,
|
ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
|
||||||
n, &hd_qiov);
|
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -644,7 +643,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
hd_iov.iov_len = n * 512;
|
hd_iov.iov_len = n * 512;
|
||||||
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
ret = bdrv_co_readv(bs->file->bs,
|
ret = bdrv_co_readv(bs->file,
|
||||||
(cluster_offset >> 9) + index_in_cluster,
|
(cluster_offset >> 9) + index_in_cluster,
|
||||||
n, &hd_qiov);
|
n, &hd_qiov);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
@@ -746,7 +745,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
hd_iov.iov_len = n * 512;
|
hd_iov.iov_len = n * 512;
|
||||||
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
ret = bdrv_co_writev(bs->file->bs,
|
ret = bdrv_co_writev(bs->file,
|
||||||
(cluster_offset >> 9) + index_in_cluster,
|
(cluster_offset >> 9) + index_in_cluster,
|
||||||
n, &hd_qiov);
|
n, &hd_qiov);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
@@ -900,7 +899,7 @@ static int qcow_make_empty(BlockDriverState *bs)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(s->l1_table, 0, l1_length);
|
memset(s->l1_table, 0, l1_length);
|
||||||
if (bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, s->l1_table,
|
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
|
||||||
l1_length) < 0)
|
l1_length) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
ret = bdrv_truncate(bs->file->bs, s->l1_table_offset + l1_length);
|
ret = bdrv_truncate(bs->file->bs, s->l1_table_offset + l1_length);
|
||||||
@@ -914,6 +913,49 @@ static int qcow_make_empty(BlockDriverState *bs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct QcowWriteCo {
|
||||||
|
BlockDriverState *bs;
|
||||||
|
int64_t sector_num;
|
||||||
|
const uint8_t *buf;
|
||||||
|
int nb_sectors;
|
||||||
|
int ret;
|
||||||
|
} QcowWriteCo;
|
||||||
|
|
||||||
|
static void qcow_write_co_entry(void *opaque)
|
||||||
|
{
|
||||||
|
QcowWriteCo *co = opaque;
|
||||||
|
QEMUIOVector qiov;
|
||||||
|
|
||||||
|
struct iovec iov = (struct iovec) {
|
||||||
|
.iov_base = (uint8_t*) co->buf,
|
||||||
|
.iov_len = co->nb_sectors * BDRV_SECTOR_SIZE,
|
||||||
|
};
|
||||||
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
|
|
||||||
|
co->ret = qcow_co_writev(co->bs, co->sector_num, co->nb_sectors, &qiov);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper for non-coroutine contexts */
|
||||||
|
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
const uint8_t *buf, int nb_sectors)
|
||||||
|
{
|
||||||
|
Coroutine *co;
|
||||||
|
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||||
|
QcowWriteCo data = {
|
||||||
|
.bs = bs,
|
||||||
|
.sector_num = sector_num,
|
||||||
|
.buf = buf,
|
||||||
|
.nb_sectors = nb_sectors,
|
||||||
|
.ret = -EINPROGRESS,
|
||||||
|
};
|
||||||
|
co = qemu_coroutine_create(qcow_write_co_entry);
|
||||||
|
qemu_coroutine_enter(co, &data);
|
||||||
|
while (data.ret == -EINPROGRESS) {
|
||||||
|
aio_poll(aio_context, true);
|
||||||
|
}
|
||||||
|
return data.ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||||
tables to avoid losing bytes in alignment */
|
tables to avoid losing bytes in alignment */
|
||||||
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||||
@@ -970,7 +1012,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
|
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
|
||||||
/* could not compress: write normal cluster */
|
/* could not compress: write normal cluster */
|
||||||
ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
|
ret = qcow_write(bs, sector_num, buf, s->cluster_sectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -983,7 +1025,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cluster_offset &= s->cluster_offset_mask;
|
cluster_offset &= s->cluster_offset_mask;
|
||||||
ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, out_len);
|
ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
|
|||||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, c->entries[i].offset,
|
ret = bdrv_pwrite(bs->file, c->entries[i].offset,
|
||||||
qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
|
qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -357,7 +357,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
|
|||||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, offset,
|
ret = bdrv_pread(bs->file, offset,
|
||||||
qcow2_cache_get_table_addr(bs, c, i),
|
qcow2_cache_get_table_addr(bs, c, i),
|
||||||
s->cluster_size);
|
s->cluster_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
|
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
|
||||||
for(i = 0; i < s->l1_size; i++)
|
for(i = 0; i < s->l1_size; i++)
|
||||||
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
|
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, new_l1_table_offset,
|
ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset,
|
||||||
new_l1_table, new_l1_size2);
|
new_l1_table, new_l1_size2);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -117,9 +117,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
|
|
||||||
/* set new table */
|
/* set new table */
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
|
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
|
||||||
cpu_to_be32w((uint32_t*)data, new_l1_size);
|
stl_be_p(data, new_l1_size);
|
||||||
stq_be_p(data + 4, new_l1_table_offset);
|
stq_be_p(data + 4, new_l1_table_offset);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_size),
|
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size),
|
||||||
data, sizeof(data));
|
data, sizeof(data));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -185,7 +185,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs,
|
ret = bdrv_pwrite_sync(bs->file,
|
||||||
s->l1_table_offset + 8 * l1_start_index,
|
s->l1_table_offset + 8 * l1_start_index,
|
||||||
buf, sizeof(buf));
|
buf, sizeof(buf));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -446,7 +446,7 @@ static int coroutine_fn do_perform_cow(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
|
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
|
||||||
ret = bdrv_co_pwritev(bs->file->bs, cluster_offset + offset_in_cluster,
|
ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
|
||||||
bytes, &qiov, 0);
|
bytes, &qiov, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1408,7 +1408,7 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
|||||||
sector_offset = coffset & 511;
|
sector_offset = coffset & 511;
|
||||||
csize = nb_csectors * 512 - sector_offset;
|
csize = nb_csectors * 512 - sector_offset;
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
|
||||||
ret = bdrv_read(bs->file->bs, coffset >> 9, s->cluster_data,
|
ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data,
|
||||||
nb_csectors);
|
nb_csectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1677,7 +1677,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
|
|||||||
(void **)&l2_table);
|
(void **)&l2_table);
|
||||||
} else {
|
} else {
|
||||||
/* load inactive L2 tables from disk */
|
/* load inactive L2 tables from disk */
|
||||||
ret = bdrv_read(bs->file->bs, l2_offset / BDRV_SECTOR_SIZE,
|
ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
|
||||||
(void *)l2_table, s->cluster_sectors);
|
(void *)l2_table, s->cluster_sectors);
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1752,7 +1752,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite_zeroes(bs->file->bs, offset, s->cluster_size, 0);
|
ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (!preallocated) {
|
if (!preallocated) {
|
||||||
qcow2_free_clusters(bs, offset, s->cluster_size,
|
qcow2_free_clusters(bs, offset, s->cluster_size,
|
||||||
@@ -1784,7 +1784,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_write(bs->file->bs, l2_offset / BDRV_SECTOR_SIZE,
|
ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
|
||||||
(void *)l2_table, s->cluster_sectors);
|
(void *)l2_table, s->cluster_sectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -1859,7 +1859,7 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
|
|||||||
|
|
||||||
l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
|
l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
ret = bdrv_read(bs->file->bs,
|
ret = bdrv_read(bs->file,
|
||||||
s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,
|
s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,
|
||||||
(void *)l1_table, l1_sectors);
|
(void *)l1_table, l1_sectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ int qcow2_refcount_init(BlockDriverState *bs)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
|
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
|
||||||
ret = bdrv_pread(bs->file->bs, s->refcount_table_offset,
|
ret = bdrv_pread(bs->file, s->refcount_table_offset,
|
||||||
s->refcount_table, refcount_table_size2);
|
s->refcount_table, refcount_table_size2);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -431,7 +431,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
if (refcount_table_index < s->refcount_table_size) {
|
if (refcount_table_index < s->refcount_table_size) {
|
||||||
uint64_t data64 = cpu_to_be64(new_block);
|
uint64_t data64 = cpu_to_be64(new_block);
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
|
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs,
|
ret = bdrv_pwrite_sync(bs->file,
|
||||||
s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
|
s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
|
||||||
&data64, sizeof(data64));
|
&data64, sizeof(data64));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -533,7 +533,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
|
|
||||||
/* Write refcount blocks to disk */
|
/* Write refcount blocks to disk */
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
|
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, meta_offset, new_blocks,
|
ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
|
||||||
blocks_clusters * s->cluster_size);
|
blocks_clusters * s->cluster_size);
|
||||||
g_free(new_blocks);
|
g_free(new_blocks);
|
||||||
new_blocks = NULL;
|
new_blocks = NULL;
|
||||||
@@ -547,7 +547,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
|
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, table_offset, new_table,
|
ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
|
||||||
table_size * sizeof(uint64_t));
|
table_size * sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail_table;
|
goto fail_table;
|
||||||
@@ -562,10 +562,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
uint64_t d64;
|
uint64_t d64;
|
||||||
uint32_t d32;
|
uint32_t d32;
|
||||||
} data;
|
} data;
|
||||||
cpu_to_be64w(&data.d64, table_offset);
|
data.d64 = cpu_to_be64(table_offset);
|
||||||
cpu_to_be32w(&data.d32, table_clusters);
|
data.d32 = cpu_to_be32(table_clusters);
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
|
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs,
|
ret = bdrv_pwrite_sync(bs->file,
|
||||||
offsetof(QCowHeader, refcount_table_offset),
|
offsetof(QCowHeader, refcount_table_offset),
|
||||||
&data, sizeof(data));
|
&data, sizeof(data));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1070,7 +1070,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
l1_allocated = true;
|
l1_allocated = true;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, l1_table_offset, l1_table, l1_size2);
|
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -1223,7 +1223,7 @@ fail:
|
|||||||
cpu_to_be64s(&l1_table[i]);
|
cpu_to_be64s(&l1_table[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, l1_table_offset,
|
ret = bdrv_pwrite_sync(bs->file, l1_table_offset,
|
||||||
l1_table, l1_size2);
|
l1_table, l1_size2);
|
||||||
|
|
||||||
for (i = 0; i < l1_size; i++) {
|
for (i = 0; i < l1_size; i++) {
|
||||||
@@ -1382,7 +1382,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
l2_size = s->l2_size * sizeof(uint64_t);
|
l2_size = s->l2_size * sizeof(uint64_t);
|
||||||
l2_table = g_malloc(l2_size);
|
l2_table = g_malloc(l2_size);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, l2_offset, l2_table, l2_size);
|
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
|
fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
|
||||||
res->check_errors++;
|
res->check_errors++;
|
||||||
@@ -1514,7 +1514,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
res->check_errors++;
|
res->check_errors++;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file->bs, l1_table_offset, l1_table, l1_size2);
|
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
|
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
|
||||||
res->check_errors++;
|
res->check_errors++;
|
||||||
@@ -1612,7 +1612,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, l2_offset, l2_table,
|
ret = bdrv_pread(bs->file, l2_offset, l2_table,
|
||||||
s->l2_size * sizeof(uint64_t));
|
s->l2_size * sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "ERROR: Could not read L2 table: %s\n",
|
fprintf(stderr, "ERROR: Could not read L2 table: %s\n",
|
||||||
@@ -1664,7 +1664,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, l2_offset, l2_table,
|
ret = bdrv_pwrite(bs->file, l2_offset, l2_table,
|
||||||
s->cluster_size);
|
s->cluster_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "ERROR: Could not write L2 table: %s\n",
|
fprintf(stderr, "ERROR: Could not write L2 table: %s\n",
|
||||||
@@ -2098,7 +2098,7 @@ write_refblocks:
|
|||||||
on_disk_refblock = (void *)((char *) *refcount_table +
|
on_disk_refblock = (void *)((char *) *refcount_table +
|
||||||
refblock_index * s->cluster_size);
|
refblock_index * s->cluster_size);
|
||||||
|
|
||||||
ret = bdrv_write(bs->file->bs, refblock_offset / BDRV_SECTOR_SIZE,
|
ret = bdrv_write(bs->file, refblock_offset / BDRV_SECTOR_SIZE,
|
||||||
on_disk_refblock, s->cluster_sectors);
|
on_disk_refblock, s->cluster_sectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret));
|
fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret));
|
||||||
@@ -2147,7 +2147,7 @@ write_refblocks:
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(reftable_size < INT_MAX / sizeof(uint64_t));
|
assert(reftable_size < INT_MAX / sizeof(uint64_t));
|
||||||
ret = bdrv_pwrite(bs->file->bs, reftable_offset, on_disk_reftable,
|
ret = bdrv_pwrite(bs->file, reftable_offset, on_disk_reftable,
|
||||||
reftable_size * sizeof(uint64_t));
|
reftable_size * sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret));
|
fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret));
|
||||||
@@ -2155,12 +2155,11 @@ write_refblocks:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enter new reftable into the image header */
|
/* Enter new reftable into the image header */
|
||||||
cpu_to_be64w(&reftable_offset_and_clusters.reftable_offset,
|
reftable_offset_and_clusters.reftable_offset = cpu_to_be64(reftable_offset);
|
||||||
reftable_offset);
|
reftable_offset_and_clusters.reftable_clusters =
|
||||||
cpu_to_be32w(&reftable_offset_and_clusters.reftable_clusters,
|
cpu_to_be32(size_to_clusters(s, reftable_size * sizeof(uint64_t)));
|
||||||
size_to_clusters(s, reftable_size * sizeof(uint64_t)));
|
ret = bdrv_pwrite_sync(bs->file,
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader,
|
offsetof(QCowHeader, refcount_table_offset),
|
||||||
refcount_table_offset),
|
|
||||||
&reftable_offset_and_clusters,
|
&reftable_offset_and_clusters,
|
||||||
sizeof(reftable_offset_and_clusters));
|
sizeof(reftable_offset_and_clusters));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -2407,7 +2406,7 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, l1_ofs, l1, l1_sz2);
|
ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
g_free(l1);
|
g_free(l1);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2560,7 +2559,7 @@ static int flush_refblock(BlockDriverState *bs, uint64_t **reftable,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, offset, refblock, s->cluster_size);
|
ret = bdrv_pwrite(bs->file, offset, refblock, s->cluster_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Failed to write refblock");
|
error_setg_errno(errp, -ret, "Failed to write refblock");
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2830,7 +2829,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
|
|||||||
cpu_to_be64s(&new_reftable[i]);
|
cpu_to_be64s(&new_reftable[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, new_reftable_offset, new_reftable,
|
ret = bdrv_pwrite(bs->file, new_reftable_offset, new_reftable,
|
||||||
new_reftable_size * sizeof(uint64_t));
|
new_reftable_size * sizeof(uint64_t));
|
||||||
|
|
||||||
for (i = 0; i < new_reftable_size; i++) {
|
for (i = 0; i < new_reftable_size; i++) {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
|||||||
for(i = 0; i < s->nb_snapshots; i++) {
|
for(i = 0; i < s->nb_snapshots; i++) {
|
||||||
/* Read statically sized part of the snapshot header */
|
/* Read statically sized part of the snapshot header */
|
||||||
offset = align_offset(offset, 8);
|
offset = align_offset(offset, 8);
|
||||||
ret = bdrv_pread(bs->file->bs, offset, &h, sizeof(h));
|
ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
|||||||
name_size = be16_to_cpu(h.name_size);
|
name_size = be16_to_cpu(h.name_size);
|
||||||
|
|
||||||
/* Read extra data */
|
/* Read extra data */
|
||||||
ret = bdrv_pread(bs->file->bs, offset, &extra,
|
ret = bdrv_pread(bs->file, offset, &extra,
|
||||||
MIN(sizeof(extra), extra_data_size));
|
MIN(sizeof(extra), extra_data_size));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -105,7 +105,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
|||||||
|
|
||||||
/* Read snapshot ID */
|
/* Read snapshot ID */
|
||||||
sn->id_str = g_malloc(id_str_size + 1);
|
sn->id_str = g_malloc(id_str_size + 1);
|
||||||
ret = bdrv_pread(bs->file->bs, offset, sn->id_str, id_str_size);
|
ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
|||||||
|
|
||||||
/* Read snapshot name */
|
/* Read snapshot name */
|
||||||
sn->name = g_malloc(name_size + 1);
|
sn->name = g_malloc(name_size + 1);
|
||||||
ret = bdrv_pread(bs->file->bs, offset, sn->name, name_size);
|
ret = bdrv_pread(bs->file, offset, sn->name, name_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -217,25 +217,25 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
|||||||
h.name_size = cpu_to_be16(name_size);
|
h.name_size = cpu_to_be16(name_size);
|
||||||
offset = align_offset(offset, 8);
|
offset = align_offset(offset, 8);
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, offset, &h, sizeof(h));
|
ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
offset += sizeof(h);
|
offset += sizeof(h);
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, offset, &extra, sizeof(extra));
|
ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
offset += sizeof(extra);
|
offset += sizeof(extra);
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, offset, sn->id_str, id_str_size);
|
ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
offset += id_str_size;
|
offset += id_str_size;
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, offset, sn->name, name_size);
|
ret = bdrv_pwrite(bs->file, offset, sn->name, name_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -257,7 +257,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
|||||||
header_data.nb_snapshots = cpu_to_be32(s->nb_snapshots);
|
header_data.nb_snapshots = cpu_to_be32(s->nb_snapshots);
|
||||||
header_data.snapshots_offset = cpu_to_be64(snapshots_offset);
|
header_data.snapshots_offset = cpu_to_be64(snapshots_offset);
|
||||||
|
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, nb_snapshots),
|
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
|
||||||
&header_data, sizeof(header_data));
|
&header_data, sizeof(header_data));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -399,7 +399,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs->file->bs, sn->l1_table_offset, l1_table,
|
ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
|
||||||
s->l1_size * sizeof(uint64_t));
|
s->l1_size * sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -512,7 +512,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, sn->l1_table_offset,
|
ret = bdrv_pread(bs->file, sn->l1_table_offset,
|
||||||
sn_l1_table, sn_l1_bytes);
|
sn_l1_table, sn_l1_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -530,7 +530,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, sn_l1_table,
|
ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
|
||||||
cur_l1_bytes);
|
cur_l1_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -716,7 +716,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, sn->l1_table_offset,
|
ret = bdrv_pread(bs->file, sn->l1_table_offset,
|
||||||
new_l1_table, new_l1_bytes);
|
new_l1_table, new_l1_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Failed to read l1 table for snapshot");
|
error_setg(errp, "Failed to read l1 table for snapshot");
|
||||||
|
|||||||
102
block/qcow2.c
102
block/qcow2.c
@@ -107,7 +107,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
|||||||
printf("attempting to read extended header in offset %lu\n", offset);
|
printf("attempting to read extended header in offset %lu\n", offset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, offset, &ext, sizeof(ext));
|
ret = bdrv_pread(bs->file, offset, &ext, sizeof(ext));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: "
|
error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: "
|
||||||
"pread fail from offset %" PRIu64, offset);
|
"pread fail from offset %" PRIu64, offset);
|
||||||
@@ -135,7 +135,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
|||||||
sizeof(bs->backing_format));
|
sizeof(bs->backing_format));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file->bs, offset, bs->backing_format, ext.len);
|
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "ERROR: ext_backing_format: "
|
error_setg_errno(errp, -ret, "ERROR: ext_backing_format: "
|
||||||
"Could not read format name");
|
"Could not read format name");
|
||||||
@@ -151,7 +151,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
|||||||
case QCOW2_EXT_MAGIC_FEATURE_TABLE:
|
case QCOW2_EXT_MAGIC_FEATURE_TABLE:
|
||||||
if (p_feature_table != NULL) {
|
if (p_feature_table != NULL) {
|
||||||
void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
|
void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
|
||||||
ret = bdrv_pread(bs->file->bs, offset , feature_table, ext.len);
|
ret = bdrv_pread(bs->file, offset , feature_table, ext.len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "ERROR: ext_feature_table: "
|
error_setg_errno(errp, -ret, "ERROR: ext_feature_table: "
|
||||||
"Could not read table");
|
"Could not read table");
|
||||||
@@ -172,7 +172,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
|||||||
uext->len = ext.len;
|
uext->len = ext.len;
|
||||||
QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
|
QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, offset , uext->data, uext->len);
|
ret = bdrv_pread(bs->file, offset , uext->data, uext->len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "ERROR: unknown extension: "
|
error_setg_errno(errp, -ret, "ERROR: unknown extension: "
|
||||||
"Could not read data");
|
"Could not read data");
|
||||||
@@ -249,7 +249,7 @@ int qcow2_mark_dirty(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
val = cpu_to_be64(s->incompatible_features | QCOW2_INCOMPAT_DIRTY);
|
val = cpu_to_be64(s->incompatible_features | QCOW2_INCOMPAT_DIRTY);
|
||||||
ret = bdrv_pwrite(bs->file->bs, offsetof(QCowHeader, incompatible_features),
|
ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, incompatible_features),
|
||||||
&val, sizeof(val));
|
&val, sizeof(val));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -817,7 +817,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
uint64_t ext_end;
|
uint64_t ext_end;
|
||||||
uint64_t l1_vm_state_index;
|
uint64_t l1_vm_state_index;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header));
|
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not read qcow2 header");
|
error_setg_errno(errp, -ret, "Could not read qcow2 header");
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -892,7 +892,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
if (header.header_length > sizeof(header)) {
|
if (header.header_length > sizeof(header)) {
|
||||||
s->unknown_header_fields_size = header.header_length - sizeof(header);
|
s->unknown_header_fields_size = header.header_length - sizeof(header);
|
||||||
s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
|
s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
|
||||||
ret = bdrv_pread(bs->file->bs, sizeof(header), s->unknown_header_fields,
|
ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields,
|
||||||
s->unknown_header_fields_size);
|
s->unknown_header_fields_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not read unknown qcow2 header "
|
error_setg_errno(errp, -ret, "Could not read unknown qcow2 header "
|
||||||
@@ -980,10 +980,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->encrypted = 1;
|
bs->encrypted = true;
|
||||||
|
|
||||||
/* Encryption works on a sector granularity */
|
|
||||||
bs->request_alignment = BDRV_SECTOR_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
||||||
@@ -1069,7 +1066,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table,
|
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
|
||||||
s->l1_size * sizeof(uint64_t));
|
s->l1_size * sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not read L1 table");
|
error_setg_errno(errp, -ret, "Could not read L1 table");
|
||||||
@@ -1125,7 +1122,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file->bs, header.backing_file_offset,
|
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||||
bs->backing_file, len);
|
bs->backing_file, len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not read backing file name");
|
error_setg_errno(errp, -ret, "Could not read backing file name");
|
||||||
@@ -1202,6 +1199,10 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
|
|
||||||
|
if (bs->encrypted) {
|
||||||
|
/* Encryption works on a sector granularity */
|
||||||
|
bs->bl.request_alignment = BDRV_SECTOR_SIZE;
|
||||||
|
}
|
||||||
bs->bl.pwrite_zeroes_alignment = s->cluster_size;
|
bs->bl.pwrite_zeroes_alignment = s->cluster_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1442,7 +1443,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
|
|||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
ret = bdrv_co_preadv(bs->backing->bs, offset, n1,
|
ret = bdrv_co_preadv(bs->backing, offset, n1,
|
||||||
&local_qiov, 0);
|
&local_qiov, 0);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
|
|
||||||
@@ -1505,7 +1506,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
|
|||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
ret = bdrv_co_preadv(bs->file->bs,
|
ret = bdrv_co_preadv(bs->file,
|
||||||
cluster_offset + offset_in_cluster,
|
cluster_offset + offset_in_cluster,
|
||||||
cur_bytes, &hd_qiov, 0);
|
cur_bytes, &hd_qiov, 0);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
@@ -1636,7 +1637,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
|||||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||||
trace_qcow2_writev_data(qemu_coroutine_self(),
|
trace_qcow2_writev_data(qemu_coroutine_self(),
|
||||||
cluster_offset + offset_in_cluster);
|
cluster_offset + offset_in_cluster);
|
||||||
ret = bdrv_co_pwritev(bs->file->bs,
|
ret = bdrv_co_pwritev(bs->file,
|
||||||
cluster_offset + offset_in_cluster,
|
cluster_offset + offset_in_cluster,
|
||||||
cur_bytes, &hd_qiov, 0);
|
cur_bytes, &hd_qiov, 0);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
@@ -1975,7 +1976,7 @@ int qcow2_update_header(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write the new header */
|
/* Write the new header */
|
||||||
ret = bdrv_pwrite(bs->file->bs, 0, header, s->cluster_size);
|
ret = bdrv_pwrite(bs->file, 0, header, s->cluster_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -2058,7 +2059,7 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
*/
|
*/
|
||||||
if (host_offset != 0) {
|
if (host_offset != 0) {
|
||||||
uint8_t data = 0;
|
uint8_t data = 0;
|
||||||
ret = bdrv_pwrite(bs->file->bs, (host_offset + cur_bytes) - 1,
|
ret = bdrv_pwrite(bs->file, (host_offset + cur_bytes) - 1,
|
||||||
&data, 1);
|
&data, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2522,7 +2523,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
|
|||||||
|
|
||||||
/* write updated header.size */
|
/* write updated header.size */
|
||||||
offset = cpu_to_be64(offset);
|
offset = cpu_to_be64(offset);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, size),
|
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
|
||||||
&offset, sizeof(uint64_t));
|
&offset, sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2532,6 +2533,51 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct Qcow2WriteCo {
|
||||||
|
BlockDriverState *bs;
|
||||||
|
int64_t sector_num;
|
||||||
|
const uint8_t *buf;
|
||||||
|
int nb_sectors;
|
||||||
|
int ret;
|
||||||
|
} Qcow2WriteCo;
|
||||||
|
|
||||||
|
static void qcow2_write_co_entry(void *opaque)
|
||||||
|
{
|
||||||
|
Qcow2WriteCo *co = opaque;
|
||||||
|
QEMUIOVector qiov;
|
||||||
|
uint64_t offset = co->sector_num * BDRV_SECTOR_SIZE;
|
||||||
|
uint64_t bytes = co->nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
|
struct iovec iov = (struct iovec) {
|
||||||
|
.iov_base = (uint8_t*) co->buf,
|
||||||
|
.iov_len = bytes,
|
||||||
|
};
|
||||||
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
|
|
||||||
|
co->ret = qcow2_co_pwritev(co->bs, offset, bytes, &qiov, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper for non-coroutine contexts */
|
||||||
|
static int qcow2_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
const uint8_t *buf, int nb_sectors)
|
||||||
|
{
|
||||||
|
Coroutine *co;
|
||||||
|
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||||
|
Qcow2WriteCo data = {
|
||||||
|
.bs = bs,
|
||||||
|
.sector_num = sector_num,
|
||||||
|
.buf = buf,
|
||||||
|
.nb_sectors = nb_sectors,
|
||||||
|
.ret = -EINPROGRESS,
|
||||||
|
};
|
||||||
|
co = qemu_coroutine_create(qcow2_write_co_entry);
|
||||||
|
qemu_coroutine_enter(co, &data);
|
||||||
|
while (data.ret == -EINPROGRESS) {
|
||||||
|
aio_poll(aio_context, true);
|
||||||
|
}
|
||||||
|
return data.ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||||
tables to avoid losing bytes in alignment */
|
tables to avoid losing bytes in alignment */
|
||||||
static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||||
@@ -2595,7 +2641,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
|
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
|
||||||
/* could not compress: write normal cluster */
|
/* could not compress: write normal cluster */
|
||||||
ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
|
ret = qcow2_write(bs, sector_num, buf, s->cluster_sectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -2614,7 +2660,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
|
||||||
ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, out_len);
|
ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -2663,7 +2709,7 @@ static int make_completely_empty(BlockDriverState *bs)
|
|||||||
/* After this call, neither the in-memory nor the on-disk refcount
|
/* After this call, neither the in-memory nor the on-disk refcount
|
||||||
* information accurately describe the actual references */
|
* information accurately describe the actual references */
|
||||||
|
|
||||||
ret = bdrv_pwrite_zeroes(bs->file->bs, s->l1_table_offset,
|
ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset,
|
||||||
l1_clusters * s->cluster_size, 0);
|
l1_clusters * s->cluster_size, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail_broken_refcounts;
|
goto fail_broken_refcounts;
|
||||||
@@ -2677,7 +2723,7 @@ static int make_completely_empty(BlockDriverState *bs)
|
|||||||
* overwrite parts of the existing refcount and L1 table, which is not
|
* overwrite parts of the existing refcount and L1 table, which is not
|
||||||
* an issue because the dirty flag is set, complete data loss is in fact
|
* an issue because the dirty flag is set, complete data loss is in fact
|
||||||
* desired and partial data loss is consequently fine as well */
|
* desired and partial data loss is consequently fine as well */
|
||||||
ret = bdrv_pwrite_zeroes(bs->file->bs, s->cluster_size,
|
ret = bdrv_pwrite_zeroes(bs->file, s->cluster_size,
|
||||||
(2 + l1_clusters) * s->cluster_size, 0);
|
(2 + l1_clusters) * s->cluster_size, 0);
|
||||||
/* This call (even if it failed overall) may have overwritten on-disk
|
/* This call (even if it failed overall) may have overwritten on-disk
|
||||||
* refcount structures; in that case, the in-memory refcount information
|
* refcount structures; in that case, the in-memory refcount information
|
||||||
@@ -2693,10 +2739,10 @@ static int make_completely_empty(BlockDriverState *bs)
|
|||||||
/* "Create" an empty reftable (one cluster) directly after the image
|
/* "Create" an empty reftable (one cluster) directly after the image
|
||||||
* header and an empty L1 table three clusters after the image header;
|
* header and an empty L1 table three clusters after the image header;
|
||||||
* the cluster between those two will be used as the first refblock */
|
* the cluster between those two will be used as the first refblock */
|
||||||
cpu_to_be64w(&l1_ofs_rt_ofs_cls.l1_offset, 3 * s->cluster_size);
|
l1_ofs_rt_ofs_cls.l1_offset = cpu_to_be64(3 * s->cluster_size);
|
||||||
cpu_to_be64w(&l1_ofs_rt_ofs_cls.reftable_offset, s->cluster_size);
|
l1_ofs_rt_ofs_cls.reftable_offset = cpu_to_be64(s->cluster_size);
|
||||||
cpu_to_be32w(&l1_ofs_rt_ofs_cls.reftable_clusters, 1);
|
l1_ofs_rt_ofs_cls.reftable_clusters = cpu_to_be32(1);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_table_offset),
|
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_table_offset),
|
||||||
&l1_ofs_rt_ofs_cls, sizeof(l1_ofs_rt_ofs_cls));
|
&l1_ofs_rt_ofs_cls, sizeof(l1_ofs_rt_ofs_cls));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail_broken_refcounts;
|
goto fail_broken_refcounts;
|
||||||
@@ -2727,7 +2773,7 @@ static int make_completely_empty(BlockDriverState *bs)
|
|||||||
|
|
||||||
/* Enter the first refblock into the reftable */
|
/* Enter the first refblock into the reftable */
|
||||||
rt_entry = cpu_to_be64(2 * s->cluster_size);
|
rt_entry = cpu_to_be64(2 * s->cluster_size);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, s->cluster_size,
|
ret = bdrv_pwrite_sync(bs->file, s->cluster_size,
|
||||||
&rt_entry, sizeof(rt_entry));
|
&rt_entry, sizeof(rt_entry));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail_broken_refcounts;
|
goto fail_broken_refcounts;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
|
|||||||
read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size,
|
read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size,
|
||||||
|
|
||||||
qemu_iovec_init_external(qiov, &read_table_cb->iov, 1);
|
qemu_iovec_init_external(qiov, &read_table_cb->iov, 1);
|
||||||
bdrv_aio_readv(s->bs->file->bs, offset / BDRV_SECTOR_SIZE, qiov,
|
bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov,
|
||||||
qiov->size / BDRV_SECTOR_SIZE,
|
qiov->size / BDRV_SECTOR_SIZE,
|
||||||
qed_read_table_cb, read_table_cb);
|
qed_read_table_cb, read_table_cb);
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
|
|||||||
/* Adjust for offset into table */
|
/* Adjust for offset into table */
|
||||||
offset += start * sizeof(uint64_t);
|
offset += start * sizeof(uint64_t);
|
||||||
|
|
||||||
bdrv_aio_writev(s->bs->file->bs, offset / BDRV_SECTOR_SIZE,
|
bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
|
||||||
&write_table_cb->qiov,
|
&write_table_cb->qiov,
|
||||||
write_table_cb->qiov.size / BDRV_SECTOR_SIZE,
|
write_table_cb->qiov.size / BDRV_SECTOR_SIZE,
|
||||||
qed_write_table_cb, write_table_cb);
|
qed_write_table_cb, write_table_cb);
|
||||||
|
|||||||
22
block/qed.c
22
block/qed.c
@@ -86,7 +86,7 @@ int qed_write_header_sync(BDRVQEDState *s)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
qed_header_cpu_to_le(&s->header, &le);
|
qed_header_cpu_to_le(&s->header, &le);
|
||||||
ret = bdrv_pwrite(s->bs->file->bs, 0, &le, sizeof(le));
|
ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le));
|
||||||
if (ret != sizeof(le)) {
|
if (ret != sizeof(le)) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ static void qed_write_header_read_cb(void *opaque, int ret)
|
|||||||
/* Update header */
|
/* Update header */
|
||||||
qed_header_cpu_to_le(&s->header, (QEDHeader *)write_header_cb->buf);
|
qed_header_cpu_to_le(&s->header, (QEDHeader *)write_header_cb->buf);
|
||||||
|
|
||||||
bdrv_aio_writev(s->bs->file->bs, 0, &write_header_cb->qiov,
|
bdrv_aio_writev(s->bs->file, 0, &write_header_cb->qiov,
|
||||||
write_header_cb->nsectors, qed_write_header_cb,
|
write_header_cb->nsectors, qed_write_header_cb,
|
||||||
write_header_cb);
|
write_header_cb);
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
|
|||||||
write_header_cb->iov.iov_len = len;
|
write_header_cb->iov.iov_len = len;
|
||||||
qemu_iovec_init_external(&write_header_cb->qiov, &write_header_cb->iov, 1);
|
qemu_iovec_init_external(&write_header_cb->qiov, &write_header_cb->iov, 1);
|
||||||
|
|
||||||
bdrv_aio_readv(s->bs->file->bs, 0, &write_header_cb->qiov, nsectors,
|
bdrv_aio_readv(s->bs->file, 0, &write_header_cb->qiov, nsectors,
|
||||||
qed_write_header_read_cb, write_header_cb);
|
qed_write_header_read_cb, write_header_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ static bool qed_is_image_size_valid(uint64_t image_size, uint32_t cluster_size,
|
|||||||
*
|
*
|
||||||
* The string is NUL-terminated.
|
* The string is NUL-terminated.
|
||||||
*/
|
*/
|
||||||
static int qed_read_string(BlockDriverState *file, uint64_t offset, size_t n,
|
static int qed_read_string(BdrvChild *file, uint64_t offset, size_t n,
|
||||||
char *buf, size_t buflen)
|
char *buf, size_t buflen)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -389,7 +389,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->bs = bs;
|
s->bs = bs;
|
||||||
QSIMPLEQ_INIT(&s->allocating_write_reqs);
|
QSIMPLEQ_INIT(&s->allocating_write_reqs);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 0, &le_header, sizeof(le_header));
|
ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -446,7 +446,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qed_read_string(bs->file->bs, s->header.backing_filename_offset,
|
ret = qed_read_string(bs->file, s->header.backing_filename_offset,
|
||||||
s->header.backing_filename_size, bs->backing_file,
|
s->header.backing_filename_size, bs->backing_file,
|
||||||
sizeof(bs->backing_file));
|
sizeof(bs->backing_file));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -800,7 +800,7 @@ static void qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
|
|||||||
qemu_iovec_concat(*backing_qiov, qiov, 0, size);
|
qemu_iovec_concat(*backing_qiov, qiov, 0, size);
|
||||||
|
|
||||||
BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
|
BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
|
||||||
bdrv_aio_readv(s->bs->backing->bs, pos / BDRV_SECTOR_SIZE,
|
bdrv_aio_readv(s->bs->backing, pos / BDRV_SECTOR_SIZE,
|
||||||
*backing_qiov, size / BDRV_SECTOR_SIZE, cb, opaque);
|
*backing_qiov, size / BDRV_SECTOR_SIZE, cb, opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,7 +837,7 @@ static void qed_copy_from_backing_file_write(void *opaque, int ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
|
BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
|
||||||
bdrv_aio_writev(s->bs->file->bs, copy_cb->offset / BDRV_SECTOR_SIZE,
|
bdrv_aio_writev(s->bs->file, copy_cb->offset / BDRV_SECTOR_SIZE,
|
||||||
©_cb->qiov, copy_cb->qiov.size / BDRV_SECTOR_SIZE,
|
©_cb->qiov, copy_cb->qiov.size / BDRV_SECTOR_SIZE,
|
||||||
qed_copy_from_backing_file_cb, copy_cb);
|
qed_copy_from_backing_file_cb, copy_cb);
|
||||||
}
|
}
|
||||||
@@ -1087,7 +1087,7 @@ static void qed_aio_write_main(void *opaque, int ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
|
BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
|
||||||
bdrv_aio_writev(s->bs->file->bs, offset / BDRV_SECTOR_SIZE,
|
bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
|
||||||
&acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
|
&acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
|
||||||
next_fn, acb);
|
next_fn, acb);
|
||||||
}
|
}
|
||||||
@@ -1319,7 +1319,7 @@ static void qed_aio_read_data(void *opaque, int ret,
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
||||||
bdrv_aio_readv(bs->file->bs, offset / BDRV_SECTOR_SIZE,
|
bdrv_aio_readv(bs->file, offset / BDRV_SECTOR_SIZE,
|
||||||
&acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
|
&acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
|
||||||
qed_aio_next_io, acb);
|
qed_aio_next_io, acb);
|
||||||
return;
|
return;
|
||||||
@@ -1575,7 +1575,7 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write new header */
|
/* Write new header */
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, 0, buffer, buffer_len);
|
ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len);
|
||||||
g_free(buffer);
|
g_free(buffer);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
memcpy(&s->header, &new_header, sizeof(new_header));
|
memcpy(&s->header, &new_header, sizeof(new_header));
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QLIST_FOREACH(item, &version->items, next) {
|
QLIST_FOREACH(item, &version->items, next) {
|
||||||
bdrv_aio_writev(s->children[item->index]->bs, acb->sector_num,
|
bdrv_aio_writev(s->children[item->index], acb->sector_num,
|
||||||
acb->qiov, acb->nb_sectors, quorum_rewrite_aio_cb,
|
acb->qiov, acb->nb_sectors, quorum_rewrite_aio_cb,
|
||||||
acb);
|
acb);
|
||||||
}
|
}
|
||||||
@@ -660,7 +660,7 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < s->num_children; i++) {
|
for (i = 0; i < s->num_children; i++) {
|
||||||
acb->qcrs[i].aiocb = bdrv_aio_readv(s->children[i]->bs, acb->sector_num,
|
acb->qcrs[i].aiocb = bdrv_aio_readv(s->children[i], acb->sector_num,
|
||||||
&acb->qcrs[i].qiov, acb->nb_sectors,
|
&acb->qcrs[i].qiov, acb->nb_sectors,
|
||||||
quorum_aio_cb, &acb->qcrs[i]);
|
quorum_aio_cb, &acb->qcrs[i]);
|
||||||
}
|
}
|
||||||
@@ -678,7 +678,7 @@ static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb)
|
|||||||
qemu_iovec_clone(&acb->qcrs[acb->child_iter].qiov, acb->qiov,
|
qemu_iovec_clone(&acb->qcrs[acb->child_iter].qiov, acb->qiov,
|
||||||
acb->qcrs[acb->child_iter].buf);
|
acb->qcrs[acb->child_iter].buf);
|
||||||
acb->qcrs[acb->child_iter].aiocb =
|
acb->qcrs[acb->child_iter].aiocb =
|
||||||
bdrv_aio_readv(s->children[acb->child_iter]->bs, acb->sector_num,
|
bdrv_aio_readv(s->children[acb->child_iter], acb->sector_num,
|
||||||
&acb->qcrs[acb->child_iter].qiov, acb->nb_sectors,
|
&acb->qcrs[acb->child_iter].qiov, acb->nb_sectors,
|
||||||
quorum_aio_cb, &acb->qcrs[acb->child_iter]);
|
quorum_aio_cb, &acb->qcrs[acb->child_iter]);
|
||||||
|
|
||||||
@@ -719,7 +719,7 @@ static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < s->num_children; i++) {
|
for (i = 0; i < s->num_children; i++) {
|
||||||
acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i]->bs, sector_num,
|
acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i], sector_num,
|
||||||
qiov, nb_sectors, &quorum_aio_cb,
|
qiov, nb_sectors, &quorum_aio_cb,
|
||||||
&acb->qcrs[i]);
|
&acb->qcrs[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -302,22 +302,22 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
|
|||||||
/* For SCSI generic devices the alignment is not really used.
|
/* For SCSI generic devices the alignment is not really used.
|
||||||
With buffered I/O, we don't have any restrictions. */
|
With buffered I/O, we don't have any restrictions. */
|
||||||
if (bdrv_is_sg(bs) || !s->needs_alignment) {
|
if (bdrv_is_sg(bs) || !s->needs_alignment) {
|
||||||
bs->request_alignment = 1;
|
bs->bl.request_alignment = 1;
|
||||||
s->buf_align = 1;
|
s->buf_align = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->request_alignment = 0;
|
bs->bl.request_alignment = 0;
|
||||||
s->buf_align = 0;
|
s->buf_align = 0;
|
||||||
/* Let's try to use the logical blocksize for the alignment. */
|
/* Let's try to use the logical blocksize for the alignment. */
|
||||||
if (probe_logical_blocksize(fd, &bs->request_alignment) < 0) {
|
if (probe_logical_blocksize(fd, &bs->bl.request_alignment) < 0) {
|
||||||
bs->request_alignment = 0;
|
bs->bl.request_alignment = 0;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_XFS
|
#ifdef CONFIG_XFS
|
||||||
if (s->is_xfs) {
|
if (s->is_xfs) {
|
||||||
struct dioattr da;
|
struct dioattr da;
|
||||||
if (xfsctl(NULL, fd, XFS_IOC_DIOINFO, &da) >= 0) {
|
if (xfsctl(NULL, fd, XFS_IOC_DIOINFO, &da) >= 0) {
|
||||||
bs->request_alignment = da.d_miniosz;
|
bs->bl.request_alignment = da.d_miniosz;
|
||||||
/* The kernel returns wrong information for d_mem */
|
/* The kernel returns wrong information for d_mem */
|
||||||
/* s->buf_align = da.d_mem; */
|
/* s->buf_align = da.d_mem; */
|
||||||
}
|
}
|
||||||
@@ -337,21 +337,21 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
|
|||||||
qemu_vfree(buf);
|
qemu_vfree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bs->request_alignment) {
|
if (!bs->bl.request_alignment) {
|
||||||
size_t align;
|
size_t align;
|
||||||
buf = qemu_memalign(s->buf_align, max_align);
|
buf = qemu_memalign(s->buf_align, max_align);
|
||||||
for (align = 512; align <= max_align; align <<= 1) {
|
for (align = 512; align <= max_align; align <<= 1) {
|
||||||
if (raw_is_io_aligned(fd, buf, align)) {
|
if (raw_is_io_aligned(fd, buf, align)) {
|
||||||
bs->request_alignment = align;
|
bs->bl.request_alignment = align;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qemu_vfree(buf);
|
qemu_vfree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s->buf_align || !bs->request_alignment) {
|
if (!s->buf_align || !bs->bl.request_alignment) {
|
||||||
error_setg(errp, "Could not find working O_DIRECT alignment. "
|
error_setg(errp, "Could not find working O_DIRECT alignment");
|
||||||
"Try cache.direct=off.");
|
error_append_hint(errp, "Try cache.direct=off\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,8 +745,8 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
if (!fstat(s->fd, &st)) {
|
if (!fstat(s->fd, &st)) {
|
||||||
if (S_ISBLK(st.st_mode)) {
|
if (S_ISBLK(st.st_mode)) {
|
||||||
int ret = hdev_get_max_transfer_length(s->fd);
|
int ret = hdev_get_max_transfer_length(s->fd);
|
||||||
if (ret >= 0) {
|
if (ret > 0 && ret <= BDRV_REQUEST_MAX_SECTORS) {
|
||||||
bs->bl.max_transfer_length = ret;
|
bs->bl.max_transfer = pow2floor(ret << BDRV_SECTOR_BITS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ static void raw_attach_aio_context(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raw_probe_alignment(BlockDriverState *bs)
|
static void raw_probe_alignment(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
DWORD sectorsPerCluster, freeClusters, totalClusters, count;
|
DWORD sectorsPerCluster, freeClusters, totalClusters, count;
|
||||||
@@ -230,14 +230,14 @@ static void raw_probe_alignment(BlockDriverState *bs)
|
|||||||
BOOL status;
|
BOOL status;
|
||||||
|
|
||||||
if (s->type == FTYPE_CD) {
|
if (s->type == FTYPE_CD) {
|
||||||
bs->request_alignment = 2048;
|
bs->bl.request_alignment = 2048;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (s->type == FTYPE_HARDDISK) {
|
if (s->type == FTYPE_HARDDISK) {
|
||||||
status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||||
NULL, 0, &dg, sizeof(dg), &count, NULL);
|
NULL, 0, &dg, sizeof(dg), &count, NULL);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
bs->request_alignment = dg.Geometry.BytesPerSector;
|
bs->bl.request_alignment = dg.Geometry.BytesPerSector;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* try GetDiskFreeSpace too */
|
/* try GetDiskFreeSpace too */
|
||||||
@@ -247,7 +247,7 @@ static void raw_probe_alignment(BlockDriverState *bs)
|
|||||||
GetDiskFreeSpace(s->drive_path, §orsPerCluster,
|
GetDiskFreeSpace(s->drive_path, §orsPerCluster,
|
||||||
&dg.Geometry.BytesPerSector,
|
&dg.Geometry.BytesPerSector,
|
||||||
&freeClusters, &totalClusters);
|
&freeClusters, &totalClusters);
|
||||||
bs->request_alignment = dg.Geometry.BytesPerSector;
|
bs->bl.request_alignment = dg.Geometry.BytesPerSector;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +365,6 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs));
|
win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs));
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_probe_alignment(bs);
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
@@ -550,6 +549,7 @@ BlockDriver bdrv_file = {
|
|||||||
.bdrv_needs_filename = true,
|
.bdrv_needs_filename = true,
|
||||||
.bdrv_parse_filename = raw_parse_filename,
|
.bdrv_parse_filename = raw_parse_filename,
|
||||||
.bdrv_file_open = raw_open,
|
.bdrv_file_open = raw_open,
|
||||||
|
.bdrv_refresh_limits = raw_probe_alignment,
|
||||||
.bdrv_close = raw_close,
|
.bdrv_close = raw_close,
|
||||||
.bdrv_create = raw_create,
|
.bdrv_create = raw_create,
|
||||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* BlockDriver implementation for "raw"
|
/* BlockDriver implementation for "raw"
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2013, Red Hat, Inc.
|
* Copyright (C) 2010-2016 Red Hat, Inc.
|
||||||
* Copyright (C) 2010, Blue Swirl <blauwirbel@gmail.com>
|
* Copyright (C) 2010, Blue Swirl <blauwirbel@gmail.com>
|
||||||
* Copyright (C) 2009, Anthony Liguori <aliguori@us.ibm.com>
|
* Copyright (C) 2009, Anthony Liguori <aliguori@us.ibm.com>
|
||||||
*
|
*
|
||||||
@@ -54,7 +54,7 @@ static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
int nb_sectors, QEMUIOVector *qiov)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
||||||
return bdrv_co_readv(bs->file->bs, sector_num, nb_sectors, qiov);
|
return bdrv_co_readv(bs->file, sector_num, nb_sectors, qiov);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn
|
static int coroutine_fn
|
||||||
@@ -105,7 +105,7 @@ raw_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
|||||||
}
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||||
ret = bdrv_co_pwritev(bs->file->bs, sector_num * BDRV_SECTOR_SIZE,
|
ret = bdrv_co_pwritev(bs->file, sector_num * BDRV_SECTOR_SIZE,
|
||||||
nb_sectors * BDRV_SECTOR_SIZE, qiov, flags);
|
nb_sectors * BDRV_SECTOR_SIZE, qiov, flags);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@@ -131,7 +131,7 @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
int64_t offset, int count,
|
int64_t offset, int count,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
return bdrv_co_pwrite_zeroes(bs->file->bs, offset, count, flags);
|
return bdrv_co_pwrite_zeroes(bs->file, offset, count, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn raw_co_discard(BlockDriverState *bs,
|
static int coroutine_fn raw_co_discard(BlockDriverState *bs,
|
||||||
@@ -150,11 +150,6 @@ static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|||||||
return bdrv_get_info(bs->file->bs, bdi);
|
return bdrv_get_info(bs->file->bs, bdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
|
||||||
{
|
|
||||||
bs->bl = bs->file->bs->bl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
{
|
{
|
||||||
return bdrv_truncate(bs->file->bs, offset);
|
return bdrv_truncate(bs->file->bs, offset);
|
||||||
@@ -252,7 +247,6 @@ BlockDriver bdrv_raw = {
|
|||||||
.bdrv_getlength = &raw_getlength,
|
.bdrv_getlength = &raw_getlength,
|
||||||
.has_variable_length = true,
|
.has_variable_length = true,
|
||||||
.bdrv_get_info = &raw_get_info,
|
.bdrv_get_info = &raw_get_info,
|
||||||
.bdrv_refresh_limits = &raw_refresh_limits,
|
|
||||||
.bdrv_probe_blocksizes = &raw_probe_blocksizes,
|
.bdrv_probe_blocksizes = &raw_probe_blocksizes,
|
||||||
.bdrv_probe_geometry = &raw_probe_geometry,
|
.bdrv_probe_geometry = &raw_probe_geometry,
|
||||||
.bdrv_media_changed = &raw_media_changed,
|
.bdrv_media_changed = &raw_media_changed,
|
||||||
|
|||||||
14
block/vdi.c
14
block/vdi.c
@@ -403,7 +403,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
logout("\n");
|
logout("\n");
|
||||||
|
|
||||||
ret = bdrv_read(bs->file->bs, 0, (uint8_t *)&header, 1);
|
ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -500,7 +500,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_read(bs->file->bs, s->bmap_sector, (uint8_t *)s->bmap,
|
ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap,
|
||||||
bmap_size);
|
bmap_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail_free_bmap;
|
goto fail_free_bmap;
|
||||||
@@ -597,7 +597,7 @@ vdi_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
qemu_iovec_reset(&local_qiov);
|
qemu_iovec_reset(&local_qiov);
|
||||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||||
|
|
||||||
ret = bdrv_co_preadv(bs->file->bs, data_offset, n_bytes,
|
ret = bdrv_co_preadv(bs->file, data_offset, n_bytes,
|
||||||
&local_qiov, 0);
|
&local_qiov, 0);
|
||||||
}
|
}
|
||||||
logout("%u bytes read\n", n_bytes);
|
logout("%u bytes read\n", n_bytes);
|
||||||
@@ -670,7 +670,7 @@ vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
* acquire the lock and thus the padded cluster is written before
|
* acquire the lock and thus the padded cluster is written before
|
||||||
* the other coroutines can write to the affected area. */
|
* the other coroutines can write to the affected area. */
|
||||||
qemu_co_mutex_lock(&s->write_lock);
|
qemu_co_mutex_lock(&s->write_lock);
|
||||||
ret = bdrv_pwrite(bs->file->bs, data_offset, block, s->block_size);
|
ret = bdrv_pwrite(bs->file, data_offset, block, s->block_size);
|
||||||
qemu_co_mutex_unlock(&s->write_lock);
|
qemu_co_mutex_unlock(&s->write_lock);
|
||||||
} else {
|
} else {
|
||||||
uint64_t data_offset = s->header.offset_data +
|
uint64_t data_offset = s->header.offset_data +
|
||||||
@@ -690,7 +690,7 @@ vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
qemu_iovec_reset(&local_qiov);
|
qemu_iovec_reset(&local_qiov);
|
||||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||||
|
|
||||||
ret = bdrv_co_pwritev(bs->file->bs, data_offset, n_bytes,
|
ret = bdrv_co_pwritev(bs->file, data_offset, n_bytes,
|
||||||
&local_qiov, 0);
|
&local_qiov, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,7 +719,7 @@ vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
assert(VDI_IS_ALLOCATED(bmap_first));
|
assert(VDI_IS_ALLOCATED(bmap_first));
|
||||||
*header = s->header;
|
*header = s->header;
|
||||||
vdi_header_to_le(header);
|
vdi_header_to_le(header);
|
||||||
ret = bdrv_write(bs->file->bs, 0, block, 1);
|
ret = bdrv_write(bs->file, 0, block, 1);
|
||||||
g_free(block);
|
g_free(block);
|
||||||
block = NULL;
|
block = NULL;
|
||||||
|
|
||||||
@@ -737,7 +737,7 @@ vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
|
base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
|
||||||
logout("will write %u block map sectors starting from entry %u\n",
|
logout("will write %u block map sectors starting from entry %u\n",
|
||||||
n_sectors, bmap_first);
|
n_sectors, bmap_first);
|
||||||
ret = bdrv_write(bs->file->bs, offset, base, n_sectors);
|
ret = bdrv_write(bs->file, offset, base, n_sectors);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log,
|
|||||||
|
|
||||||
offset = log->offset + read;
|
offset = log->offset + read;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, offset, hdr, sizeof(VHDXLogEntryHeader));
|
ret = bdrv_pread(bs->file, offset, hdr, sizeof(VHDXLogEntryHeader));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ static int vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log,
|
|||||||
}
|
}
|
||||||
offset = log->offset + read;
|
offset = log->offset + read;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, offset, buffer, VHDX_LOG_SECTOR_SIZE);
|
ret = bdrv_pread(bs->file, offset, buffer, VHDX_LOG_SECTOR_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -194,7 +194,7 @@ static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
|
|||||||
/* full */
|
/* full */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret = bdrv_pwrite(bs->file->bs, offset, buffer_tmp,
|
ret = bdrv_pwrite(bs->file, offset, buffer_tmp,
|
||||||
VHDX_LOG_SECTOR_SIZE);
|
VHDX_LOG_SECTOR_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -466,7 +466,7 @@ static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
|
|||||||
|
|
||||||
/* count is only > 1 if we are writing zeroes */
|
/* count is only > 1 if we are writing zeroes */
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, file_offset, buffer,
|
ret = bdrv_pwrite_sync(bs->file, file_offset, buffer,
|
||||||
VHDX_LOG_SECTOR_SIZE);
|
VHDX_LOG_SECTOR_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -945,7 +945,7 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
|
|
||||||
if (i == 0 && leading_length) {
|
if (i == 0 && leading_length) {
|
||||||
/* partial sector at the front of the buffer */
|
/* partial sector at the front of the buffer */
|
||||||
ret = bdrv_pread(bs->file->bs, file_offset, merged_sector,
|
ret = bdrv_pread(bs->file, file_offset, merged_sector,
|
||||||
VHDX_LOG_SECTOR_SIZE);
|
VHDX_LOG_SECTOR_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -955,7 +955,7 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
sector_write = merged_sector;
|
sector_write = merged_sector;
|
||||||
} else if (i == sectors - 1 && trailing_length) {
|
} else if (i == sectors - 1 && trailing_length) {
|
||||||
/* partial sector at the end of the buffer */
|
/* partial sector at the end of the buffer */
|
||||||
ret = bdrv_pread(bs->file->bs,
|
ret = bdrv_pread(bs->file,
|
||||||
file_offset,
|
file_offset,
|
||||||
merged_sector + trailing_length,
|
merged_sector + trailing_length,
|
||||||
VHDX_LOG_SECTOR_SIZE - trailing_length);
|
VHDX_LOG_SECTOR_SIZE - trailing_length);
|
||||||
|
|||||||
85
block/vhdx.c
85
block/vhdx.c
@@ -298,9 +298,10 @@ static int vhdx_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|||||||
* and then update the header checksum. Header is converted to proper
|
* and then update the header checksum. Header is converted to proper
|
||||||
* endianness before being written to the specified file offset
|
* endianness before being written to the specified file offset
|
||||||
*/
|
*/
|
||||||
static int vhdx_write_header(BlockDriverState *bs_file, VHDXHeader *hdr,
|
static int vhdx_write_header(BdrvChild *file, VHDXHeader *hdr,
|
||||||
uint64_t offset, bool read)
|
uint64_t offset, bool read)
|
||||||
{
|
{
|
||||||
|
BlockDriverState *bs_file = file->bs;
|
||||||
uint8_t *buffer = NULL;
|
uint8_t *buffer = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
VHDXHeader *header_le;
|
VHDXHeader *header_le;
|
||||||
@@ -315,7 +316,7 @@ static int vhdx_write_header(BlockDriverState *bs_file, VHDXHeader *hdr,
|
|||||||
buffer = qemu_blockalign(bs_file, VHDX_HEADER_SIZE);
|
buffer = qemu_blockalign(bs_file, VHDX_HEADER_SIZE);
|
||||||
if (read) {
|
if (read) {
|
||||||
/* if true, we can't assume the extra reserved bytes are 0 */
|
/* if true, we can't assume the extra reserved bytes are 0 */
|
||||||
ret = bdrv_pread(bs_file, offset, buffer, VHDX_HEADER_SIZE);
|
ret = bdrv_pread(file, offset, buffer, VHDX_HEADER_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -329,7 +330,7 @@ static int vhdx_write_header(BlockDriverState *bs_file, VHDXHeader *hdr,
|
|||||||
vhdx_header_le_export(hdr, header_le);
|
vhdx_header_le_export(hdr, header_le);
|
||||||
vhdx_update_checksum(buffer, VHDX_HEADER_SIZE,
|
vhdx_update_checksum(buffer, VHDX_HEADER_SIZE,
|
||||||
offsetof(VHDXHeader, checksum));
|
offsetof(VHDXHeader, checksum));
|
||||||
ret = bdrv_pwrite_sync(bs_file, offset, header_le, sizeof(VHDXHeader));
|
ret = bdrv_pwrite_sync(file, offset, header_le, sizeof(VHDXHeader));
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
qemu_vfree(buffer);
|
qemu_vfree(buffer);
|
||||||
@@ -378,7 +379,7 @@ static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
inactive_header->log_guid = *log_guid;
|
inactive_header->log_guid = *log_guid;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = vhdx_write_header(bs->file->bs, inactive_header, header_offset, true);
|
ret = vhdx_write_header(bs->file, inactive_header, header_offset, true);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -430,7 +431,7 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
/* We have to read the whole VHDX_HEADER_SIZE instead of
|
/* We have to read the whole VHDX_HEADER_SIZE instead of
|
||||||
* sizeof(VHDXHeader), because the checksum is over the whole
|
* sizeof(VHDXHeader), because the checksum is over the whole
|
||||||
* region */
|
* region */
|
||||||
ret = bdrv_pread(bs->file->bs, VHDX_HEADER1_OFFSET, buffer,
|
ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, buffer,
|
||||||
VHDX_HEADER_SIZE);
|
VHDX_HEADER_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -447,7 +448,7 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, VHDX_HEADER2_OFFSET, buffer,
|
ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, buffer,
|
||||||
VHDX_HEADER_SIZE);
|
VHDX_HEADER_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -521,7 +522,7 @@ static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
|
|||||||
* whole block */
|
* whole block */
|
||||||
buffer = qemu_blockalign(bs, VHDX_HEADER_BLOCK_SIZE);
|
buffer = qemu_blockalign(bs, VHDX_HEADER_BLOCK_SIZE);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, VHDX_REGION_TABLE_OFFSET, buffer,
|
ret = bdrv_pread(bs->file, VHDX_REGION_TABLE_OFFSET, buffer,
|
||||||
VHDX_HEADER_BLOCK_SIZE);
|
VHDX_HEADER_BLOCK_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -634,7 +635,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
|||||||
|
|
||||||
buffer = qemu_blockalign(bs, VHDX_METADATA_TABLE_MAX_SIZE);
|
buffer = qemu_blockalign(bs, VHDX_METADATA_TABLE_MAX_SIZE);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, s->metadata_rt.file_offset, buffer,
|
ret = bdrv_pread(bs->file, s->metadata_rt.file_offset, buffer,
|
||||||
VHDX_METADATA_TABLE_MAX_SIZE);
|
VHDX_METADATA_TABLE_MAX_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -737,7 +738,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs,
|
ret = bdrv_pread(bs->file,
|
||||||
s->metadata_entries.file_parameters_entry.offset
|
s->metadata_entries.file_parameters_entry.offset
|
||||||
+ s->metadata_rt.file_offset,
|
+ s->metadata_rt.file_offset,
|
||||||
&s->params,
|
&s->params,
|
||||||
@@ -772,7 +773,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
|||||||
/* determine virtual disk size, logical sector size,
|
/* determine virtual disk size, logical sector size,
|
||||||
* and phys sector size */
|
* and phys sector size */
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs,
|
ret = bdrv_pread(bs->file,
|
||||||
s->metadata_entries.virtual_disk_size_entry.offset
|
s->metadata_entries.virtual_disk_size_entry.offset
|
||||||
+ s->metadata_rt.file_offset,
|
+ s->metadata_rt.file_offset,
|
||||||
&s->virtual_disk_size,
|
&s->virtual_disk_size,
|
||||||
@@ -780,7 +781,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file->bs,
|
ret = bdrv_pread(bs->file,
|
||||||
s->metadata_entries.logical_sector_size_entry.offset
|
s->metadata_entries.logical_sector_size_entry.offset
|
||||||
+ s->metadata_rt.file_offset,
|
+ s->metadata_rt.file_offset,
|
||||||
&s->logical_sector_size,
|
&s->logical_sector_size,
|
||||||
@@ -788,7 +789,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file->bs,
|
ret = bdrv_pread(bs->file,
|
||||||
s->metadata_entries.phys_sector_size_entry.offset
|
s->metadata_entries.phys_sector_size_entry.offset
|
||||||
+ s->metadata_rt.file_offset,
|
+ s->metadata_rt.file_offset,
|
||||||
&s->physical_sector_size,
|
&s->physical_sector_size,
|
||||||
@@ -905,7 +906,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
QLIST_INIT(&s->regions);
|
QLIST_INIT(&s->regions);
|
||||||
|
|
||||||
/* validate the file signature */
|
/* validate the file signature */
|
||||||
ret = bdrv_pread(bs->file->bs, 0, &signature, sizeof(uint64_t));
|
ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -964,7 +965,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, s->bat_offset, s->bat, s->bat_rt.length);
|
ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -1117,7 +1118,7 @@ static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
break;
|
break;
|
||||||
case PAYLOAD_BLOCK_FULLY_PRESENT:
|
case PAYLOAD_BLOCK_FULLY_PRESENT:
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
ret = bdrv_co_readv(bs->file->bs,
|
ret = bdrv_co_readv(bs->file,
|
||||||
sinfo.file_offset >> BDRV_SECTOR_BITS,
|
sinfo.file_offset >> BDRV_SECTOR_BITS,
|
||||||
sinfo.sectors_avail, &hd_qiov);
|
sinfo.sectors_avail, &hd_qiov);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
@@ -1326,7 +1327,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
/* block exists, so we can just overwrite it */
|
/* block exists, so we can just overwrite it */
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
ret = bdrv_co_writev(bs->file->bs,
|
ret = bdrv_co_writev(bs->file,
|
||||||
sinfo.file_offset >> BDRV_SECTOR_BITS,
|
sinfo.file_offset >> BDRV_SECTOR_BITS,
|
||||||
sectors_to_write, &hd_qiov);
|
sectors_to_write, &hd_qiov);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
@@ -1387,9 +1388,11 @@ exit:
|
|||||||
* There are 2 headers, and the highest sequence number will represent
|
* There are 2 headers, and the highest sequence number will represent
|
||||||
* the active header
|
* the active header
|
||||||
*/
|
*/
|
||||||
static int vhdx_create_new_headers(BlockDriverState *bs, uint64_t image_size,
|
static int vhdx_create_new_headers(BlockBackend *blk, uint64_t image_size,
|
||||||
uint32_t log_size)
|
uint32_t log_size)
|
||||||
{
|
{
|
||||||
|
BlockDriverState *bs = blk_bs(blk);
|
||||||
|
BdrvChild *child;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
VHDXHeader *hdr = NULL;
|
VHDXHeader *hdr = NULL;
|
||||||
|
|
||||||
@@ -1404,12 +1407,18 @@ static int vhdx_create_new_headers(BlockDriverState *bs, uint64_t image_size,
|
|||||||
vhdx_guid_generate(&hdr->file_write_guid);
|
vhdx_guid_generate(&hdr->file_write_guid);
|
||||||
vhdx_guid_generate(&hdr->data_write_guid);
|
vhdx_guid_generate(&hdr->data_write_guid);
|
||||||
|
|
||||||
ret = vhdx_write_header(bs, hdr, VHDX_HEADER1_OFFSET, false);
|
/* XXX Ugly way to get blk->root, but that's a feature, not a bug. This
|
||||||
|
* hack makes it obvious that vhdx_write_header() bypasses the BlockBackend
|
||||||
|
* here, which it really shouldn't be doing. */
|
||||||
|
child = QLIST_FIRST(&bs->parents);
|
||||||
|
assert(!QLIST_NEXT(child, next_parent));
|
||||||
|
|
||||||
|
ret = vhdx_write_header(child, hdr, VHDX_HEADER1_OFFSET, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
hdr->sequence_number++;
|
hdr->sequence_number++;
|
||||||
ret = vhdx_write_header(bs, hdr, VHDX_HEADER2_OFFSET, false);
|
ret = vhdx_write_header(child, hdr, VHDX_HEADER2_OFFSET, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1442,7 +1451,7 @@ exit:
|
|||||||
* The first 64KB of the Metadata section is reserved for the metadata
|
* The first 64KB of the Metadata section is reserved for the metadata
|
||||||
* header and entries; beyond that, the metadata items themselves reside.
|
* header and entries; beyond that, the metadata items themselves reside.
|
||||||
*/
|
*/
|
||||||
static int vhdx_create_new_metadata(BlockDriverState *bs,
|
static int vhdx_create_new_metadata(BlockBackend *blk,
|
||||||
uint64_t image_size,
|
uint64_t image_size,
|
||||||
uint32_t block_size,
|
uint32_t block_size,
|
||||||
uint32_t sector_size,
|
uint32_t sector_size,
|
||||||
@@ -1538,13 +1547,13 @@ static int vhdx_create_new_metadata(BlockDriverState *bs,
|
|||||||
VHDX_META_FLAGS_IS_VIRTUAL_DISK;
|
VHDX_META_FLAGS_IS_VIRTUAL_DISK;
|
||||||
vhdx_metadata_entry_le_export(&md_table_entry[4]);
|
vhdx_metadata_entry_le_export(&md_table_entry[4]);
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs, metadata_offset, buffer, VHDX_HEADER_BLOCK_SIZE);
|
ret = blk_pwrite(blk, metadata_offset, buffer, VHDX_HEADER_BLOCK_SIZE, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs, metadata_offset + (64 * KiB), entry_buffer,
|
ret = blk_pwrite(blk, metadata_offset + (64 * KiB), entry_buffer,
|
||||||
VHDX_METADATA_ENTRY_BUFFER_SIZE);
|
VHDX_METADATA_ENTRY_BUFFER_SIZE, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1564,7 +1573,7 @@ exit:
|
|||||||
* Fixed images: default state of the BAT is fully populated, with
|
* Fixed images: default state of the BAT is fully populated, with
|
||||||
* file offsets and state PAYLOAD_BLOCK_FULLY_PRESENT.
|
* file offsets and state PAYLOAD_BLOCK_FULLY_PRESENT.
|
||||||
*/
|
*/
|
||||||
static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
|
static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
|
||||||
uint64_t image_size, VHDXImageType type,
|
uint64_t image_size, VHDXImageType type,
|
||||||
bool use_zero_blocks, uint64_t file_offset,
|
bool use_zero_blocks, uint64_t file_offset,
|
||||||
uint32_t length)
|
uint32_t length)
|
||||||
@@ -1588,12 +1597,12 @@ static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
if (type == VHDX_TYPE_DYNAMIC) {
|
if (type == VHDX_TYPE_DYNAMIC) {
|
||||||
/* All zeroes, so we can just extend the file - the end of the BAT
|
/* All zeroes, so we can just extend the file - the end of the BAT
|
||||||
* is the furthest thing we have written yet */
|
* is the furthest thing we have written yet */
|
||||||
ret = bdrv_truncate(bs, data_file_offset);
|
ret = blk_truncate(blk, data_file_offset);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
} else if (type == VHDX_TYPE_FIXED) {
|
} else if (type == VHDX_TYPE_FIXED) {
|
||||||
ret = bdrv_truncate(bs, data_file_offset + image_size);
|
ret = blk_truncate(blk, data_file_offset + image_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1604,7 +1613,7 @@ static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
|
|
||||||
if (type == VHDX_TYPE_FIXED ||
|
if (type == VHDX_TYPE_FIXED ||
|
||||||
use_zero_blocks ||
|
use_zero_blocks ||
|
||||||
bdrv_has_zero_init(bs) == 0) {
|
bdrv_has_zero_init(blk_bs(blk)) == 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) {
|
||||||
@@ -1620,12 +1629,12 @@ static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
sinfo.file_offset = data_file_offset +
|
sinfo.file_offset = data_file_offset +
|
||||||
(sector_num << s->logical_sector_size_bits);
|
(sector_num << s->logical_sector_size_bits);
|
||||||
sinfo.file_offset = ROUND_UP(sinfo.file_offset, MiB);
|
sinfo.file_offset = ROUND_UP(sinfo.file_offset, MiB);
|
||||||
vhdx_update_bat_table_entry(bs, s, &sinfo, &unused, &unused,
|
vhdx_update_bat_table_entry(blk_bs(blk), s, &sinfo, &unused, &unused,
|
||||||
block_state);
|
block_state);
|
||||||
cpu_to_le64s(&s->bat[sinfo.bat_idx]);
|
cpu_to_le64s(&s->bat[sinfo.bat_idx]);
|
||||||
sector_num += s->sectors_per_block;
|
sector_num += s->sectors_per_block;
|
||||||
}
|
}
|
||||||
ret = bdrv_pwrite(bs, file_offset, s->bat, length);
|
ret = blk_pwrite(blk, file_offset, s->bat, length, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1645,7 +1654,7 @@ exit:
|
|||||||
* to create the BAT itself, we will also cause the BAT to be
|
* to create the BAT itself, we will also cause the BAT to be
|
||||||
* created.
|
* created.
|
||||||
*/
|
*/
|
||||||
static int vhdx_create_new_region_table(BlockDriverState *bs,
|
static int vhdx_create_new_region_table(BlockBackend *blk,
|
||||||
uint64_t image_size,
|
uint64_t image_size,
|
||||||
uint32_t block_size,
|
uint32_t block_size,
|
||||||
uint32_t sector_size,
|
uint32_t sector_size,
|
||||||
@@ -1720,21 +1729,21 @@ static int vhdx_create_new_region_table(BlockDriverState *bs,
|
|||||||
|
|
||||||
/* The region table gives us the data we need to create the BAT,
|
/* The region table gives us the data we need to create the BAT,
|
||||||
* so do that now */
|
* so do that now */
|
||||||
ret = vhdx_create_bat(bs, s, image_size, type, use_zero_blocks,
|
ret = vhdx_create_bat(blk, s, image_size, type, use_zero_blocks,
|
||||||
bat_file_offset, bat_length);
|
bat_file_offset, bat_length);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now write out the region headers to disk */
|
/* Now write out the region headers to disk */
|
||||||
ret = bdrv_pwrite(bs, VHDX_REGION_TABLE_OFFSET, buffer,
|
ret = blk_pwrite(blk, VHDX_REGION_TABLE_OFFSET, buffer,
|
||||||
VHDX_HEADER_BLOCK_SIZE);
|
VHDX_HEADER_BLOCK_SIZE, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs, VHDX_REGION_TABLE2_OFFSET, buffer,
|
ret = blk_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, buffer,
|
||||||
VHDX_HEADER_BLOCK_SIZE);
|
VHDX_HEADER_BLOCK_SIZE, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1871,13 +1880,13 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
|
|
||||||
|
|
||||||
/* Creates (B),(C) */
|
/* Creates (B),(C) */
|
||||||
ret = vhdx_create_new_headers(blk_bs(blk), image_size, log_size);
|
ret = vhdx_create_new_headers(blk, image_size, log_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto delete_and_exit;
|
goto delete_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creates (D),(E),(G) explicitly. (F) created as by-product */
|
/* Creates (D),(E),(G) explicitly. (F) created as by-product */
|
||||||
ret = vhdx_create_new_region_table(blk_bs(blk), image_size, block_size, 512,
|
ret = vhdx_create_new_region_table(blk, image_size, block_size, 512,
|
||||||
log_size, use_zero_blocks, image_type,
|
log_size, use_zero_blocks, image_type,
|
||||||
&metadata_offset);
|
&metadata_offset);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1885,7 +1894,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Creates (H) */
|
/* Creates (H) */
|
||||||
ret = vhdx_create_new_metadata(blk_bs(blk), image_size, block_size, 512,
|
ret = vhdx_create_new_metadata(blk, image_size, block_size, 512,
|
||||||
metadata_offset, image_type);
|
metadata_offset, image_type);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto delete_and_exit;
|
goto delete_and_exit;
|
||||||
|
|||||||
54
block/vmdk.c
54
block/vmdk.c
@@ -252,7 +252,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
desc = g_malloc0(DESC_SIZE);
|
desc = g_malloc0(DESC_SIZE);
|
||||||
ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
|
ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
g_free(desc);
|
g_free(desc);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -286,7 +286,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
|||||||
|
|
||||||
desc = g_malloc0(DESC_SIZE);
|
desc = g_malloc0(DESC_SIZE);
|
||||||
tmp_desc = g_malloc0(DESC_SIZE);
|
tmp_desc = g_malloc0(DESC_SIZE);
|
||||||
ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
|
ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -306,7 +306,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
|||||||
pstrcat(desc, DESC_SIZE, tmp_desc);
|
pstrcat(desc, DESC_SIZE, tmp_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
|
ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
g_free(desc);
|
g_free(desc);
|
||||||
@@ -350,7 +350,7 @@ static int vmdk_parent_open(BlockDriverState *bs)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
desc = g_malloc0(DESC_SIZE + 1);
|
desc = g_malloc0(DESC_SIZE + 1);
|
||||||
ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
|
ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -454,7 +454,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(extent->file->bs,
|
ret = bdrv_pread(extent->file,
|
||||||
extent->l1_table_offset,
|
extent->l1_table_offset,
|
||||||
extent->l1_table,
|
extent->l1_table,
|
||||||
l1_size);
|
l1_size);
|
||||||
@@ -474,7 +474,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
|
|||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto fail_l1;
|
goto fail_l1;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(extent->file->bs,
|
ret = bdrv_pread(extent->file,
|
||||||
extent->l1_backup_table_offset,
|
extent->l1_backup_table_offset,
|
||||||
extent->l1_backup_table,
|
extent->l1_backup_table,
|
||||||
l1_size);
|
l1_size);
|
||||||
@@ -508,7 +508,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
|
|||||||
VMDK3Header header;
|
VMDK3Header header;
|
||||||
VmdkExtent *extent;
|
VmdkExtent *extent;
|
||||||
|
|
||||||
ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header));
|
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret,
|
error_setg_errno(errp, -ret,
|
||||||
"Could not read header from file '%s'",
|
"Could not read header from file '%s'",
|
||||||
@@ -538,14 +538,13 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
|
|||||||
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
|
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
|
||||||
QDict *options, Error **errp);
|
QDict *options, Error **errp);
|
||||||
|
|
||||||
static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
|
static char *vmdk_read_desc(BdrvChild *file, uint64_t desc_offset, Error **errp)
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
int64_t size;
|
int64_t size;
|
||||||
char *buf;
|
char *buf;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size = bdrv_getlength(file);
|
size = bdrv_getlength(file->bs);
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
error_setg_errno(errp, -size, "Could not access file");
|
error_setg_errno(errp, -size, "Could not access file");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -586,7 +585,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
int64_t l1_backup_offset = 0;
|
int64_t l1_backup_offset = 0;
|
||||||
bool compressed;
|
bool compressed;
|
||||||
|
|
||||||
ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header));
|
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret,
|
error_setg_errno(errp, -ret,
|
||||||
"Could not read header from file '%s'",
|
"Could not read header from file '%s'",
|
||||||
@@ -596,7 +595,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
if (header.capacity == 0) {
|
if (header.capacity == 0) {
|
||||||
uint64_t desc_offset = le64_to_cpu(header.desc_offset);
|
uint64_t desc_offset = le64_to_cpu(header.desc_offset);
|
||||||
if (desc_offset) {
|
if (desc_offset) {
|
||||||
char *buf = vmdk_read_desc(file->bs, desc_offset << 9, errp);
|
char *buf = vmdk_read_desc(file, desc_offset << 9, errp);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -636,7 +635,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
} QEMU_PACKED eos_marker;
|
} QEMU_PACKED eos_marker;
|
||||||
} QEMU_PACKED footer;
|
} QEMU_PACKED footer;
|
||||||
|
|
||||||
ret = bdrv_pread(file->bs,
|
ret = bdrv_pread(file,
|
||||||
bs->file->bs->total_sectors * 512 - 1536,
|
bs->file->bs->total_sectors * 512 - 1536,
|
||||||
&footer, sizeof(footer));
|
&footer, sizeof(footer));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -874,7 +873,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
|||||||
extent->flat_start_offset = flat_offset << 9;
|
extent->flat_start_offset = flat_offset << 9;
|
||||||
} else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) {
|
} else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) {
|
||||||
/* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/
|
/* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/
|
||||||
char *buf = vmdk_read_desc(extent_file->bs, 0, errp);
|
char *buf = vmdk_read_desc(extent_file, 0, errp);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
} else {
|
} else {
|
||||||
@@ -943,7 +942,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
|
||||||
buf = vmdk_read_desc(bs->file->bs, 0, errp);
|
buf = vmdk_read_desc(bs->file, 0, errp);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -1046,14 +1045,14 @@ static int get_whole_cluster(BlockDriverState *bs,
|
|||||||
/* Read backing data before skip range */
|
/* Read backing data before skip range */
|
||||||
if (skip_start_bytes > 0) {
|
if (skip_start_bytes > 0) {
|
||||||
if (bs->backing) {
|
if (bs->backing) {
|
||||||
ret = bdrv_pread(bs->backing->bs, offset, whole_grain,
|
ret = bdrv_pread(bs->backing, offset, whole_grain,
|
||||||
skip_start_bytes);
|
skip_start_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = VMDK_ERROR;
|
ret = VMDK_ERROR;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = bdrv_pwrite(extent->file->bs, cluster_offset, whole_grain,
|
ret = bdrv_pwrite(extent->file, cluster_offset, whole_grain,
|
||||||
skip_start_bytes);
|
skip_start_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = VMDK_ERROR;
|
ret = VMDK_ERROR;
|
||||||
@@ -1063,7 +1062,7 @@ static int get_whole_cluster(BlockDriverState *bs,
|
|||||||
/* Read backing data after skip range */
|
/* Read backing data after skip range */
|
||||||
if (skip_end_bytes < cluster_bytes) {
|
if (skip_end_bytes < cluster_bytes) {
|
||||||
if (bs->backing) {
|
if (bs->backing) {
|
||||||
ret = bdrv_pread(bs->backing->bs, offset + skip_end_bytes,
|
ret = bdrv_pread(bs->backing, offset + skip_end_bytes,
|
||||||
whole_grain + skip_end_bytes,
|
whole_grain + skip_end_bytes,
|
||||||
cluster_bytes - skip_end_bytes);
|
cluster_bytes - skip_end_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1071,7 +1070,7 @@ static int get_whole_cluster(BlockDriverState *bs,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = bdrv_pwrite(extent->file->bs, cluster_offset + skip_end_bytes,
|
ret = bdrv_pwrite(extent->file, cluster_offset + skip_end_bytes,
|
||||||
whole_grain + skip_end_bytes,
|
whole_grain + skip_end_bytes,
|
||||||
cluster_bytes - skip_end_bytes);
|
cluster_bytes - skip_end_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1091,8 +1090,7 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
|
|||||||
{
|
{
|
||||||
offset = cpu_to_le32(offset);
|
offset = cpu_to_le32(offset);
|
||||||
/* update L2 table */
|
/* update L2 table */
|
||||||
if (bdrv_pwrite_sync(
|
if (bdrv_pwrite_sync(extent->file,
|
||||||
extent->file->bs,
|
|
||||||
((int64_t)m_data->l2_offset * 512)
|
((int64_t)m_data->l2_offset * 512)
|
||||||
+ (m_data->l2_index * sizeof(offset)),
|
+ (m_data->l2_index * sizeof(offset)),
|
||||||
&offset, sizeof(offset)) < 0) {
|
&offset, sizeof(offset)) < 0) {
|
||||||
@@ -1101,8 +1099,7 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
|
|||||||
/* update backup L2 table */
|
/* update backup L2 table */
|
||||||
if (extent->l1_backup_table_offset != 0) {
|
if (extent->l1_backup_table_offset != 0) {
|
||||||
m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
|
m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
|
||||||
if (bdrv_pwrite_sync(
|
if (bdrv_pwrite_sync(extent->file,
|
||||||
extent->file->bs,
|
|
||||||
((int64_t)m_data->l2_offset * 512)
|
((int64_t)m_data->l2_offset * 512)
|
||||||
+ (m_data->l2_index * sizeof(offset)),
|
+ (m_data->l2_index * sizeof(offset)),
|
||||||
&offset, sizeof(offset)) < 0) {
|
&offset, sizeof(offset)) < 0) {
|
||||||
@@ -1191,8 +1188,7 @@ static int get_cluster_offset(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
l2_table = extent->l2_cache + (min_index * extent->l2_size);
|
l2_table = extent->l2_cache + (min_index * extent->l2_size);
|
||||||
if (bdrv_pread(
|
if (bdrv_pread(extent->file,
|
||||||
extent->file->bs,
|
|
||||||
(int64_t)l2_offset * 512,
|
(int64_t)l2_offset * 512,
|
||||||
l2_table,
|
l2_table,
|
||||||
extent->l2_size * sizeof(uint32_t)
|
extent->l2_size * sizeof(uint32_t)
|
||||||
@@ -1373,7 +1369,7 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
write_offset = cluster_offset + offset_in_cluster,
|
write_offset = cluster_offset + offset_in_cluster,
|
||||||
ret = bdrv_co_pwritev(extent->file->bs, write_offset, n_bytes,
|
ret = bdrv_co_pwritev(extent->file, write_offset, n_bytes,
|
||||||
&local_qiov, 0);
|
&local_qiov, 0);
|
||||||
|
|
||||||
write_end_sector = DIV_ROUND_UP(write_offset + n_bytes, BDRV_SECTOR_SIZE);
|
write_end_sector = DIV_ROUND_UP(write_offset + n_bytes, BDRV_SECTOR_SIZE);
|
||||||
@@ -1411,7 +1407,7 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
|||||||
|
|
||||||
|
|
||||||
if (!extent->compressed) {
|
if (!extent->compressed) {
|
||||||
ret = bdrv_co_preadv(extent->file->bs,
|
ret = bdrv_co_preadv(extent->file,
|
||||||
cluster_offset + offset_in_cluster, bytes,
|
cluster_offset + offset_in_cluster, bytes,
|
||||||
qiov, 0);
|
qiov, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1424,7 +1420,7 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
|||||||
buf_bytes = cluster_bytes * 2;
|
buf_bytes = cluster_bytes * 2;
|
||||||
cluster_buf = g_malloc(buf_bytes);
|
cluster_buf = g_malloc(buf_bytes);
|
||||||
uncomp_buf = g_malloc(cluster_bytes);
|
uncomp_buf = g_malloc(cluster_bytes);
|
||||||
ret = bdrv_pread(extent->file->bs,
|
ret = bdrv_pread(extent->file,
|
||||||
cluster_offset,
|
cluster_offset,
|
||||||
cluster_buf, buf_bytes);
|
cluster_buf, buf_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1501,7 +1497,7 @@ vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
qemu_iovec_reset(&local_qiov);
|
qemu_iovec_reset(&local_qiov);
|
||||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||||
|
|
||||||
ret = bdrv_co_preadv(bs->backing->bs, offset, n_bytes,
|
ret = bdrv_co_preadv(bs->backing, offset, n_bytes,
|
||||||
&local_qiov, 0);
|
&local_qiov, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
24
block/vpc.c
24
block/vpc.c
@@ -237,7 +237,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, 0, s->footer_buf, HEADER_SIZE);
|
ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Unable to read VHD header");
|
error_setg(errp, "Unable to read VHD header");
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -257,7 +257,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If a fixed disk, the footer is found only at the end of the file */
|
/* If a fixed disk, the footer is found only at the end of the file */
|
||||||
ret = bdrv_pread(bs->file->bs, offset-HEADER_SIZE, s->footer_buf,
|
ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
|
||||||
HEADER_SIZE);
|
HEADER_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -328,7 +328,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (disk_type == VHD_DYNAMIC) {
|
if (disk_type == VHD_DYNAMIC) {
|
||||||
ret = bdrv_pread(bs->file->bs, be64_to_cpu(footer->data_offset), buf,
|
ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
|
||||||
HEADER_SIZE);
|
HEADER_SIZE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Error reading dynamic VHD header");
|
error_setg(errp, "Error reading dynamic VHD header");
|
||||||
@@ -385,7 +385,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file->bs, s->bat_offset, s->pagetable,
|
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
|
||||||
pagetable_size);
|
pagetable_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Error reading pagetable");
|
error_setg(errp, "Error reading pagetable");
|
||||||
@@ -481,7 +481,7 @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
|
|
||||||
s->last_bitmap_offset = bitmap_offset;
|
s->last_bitmap_offset = bitmap_offset;
|
||||||
memset(bitmap, 0xff, s->bitmap_size);
|
memset(bitmap, 0xff, s->bitmap_size);
|
||||||
bdrv_pwrite_sync(bs->file->bs, bitmap_offset, bitmap, s->bitmap_size);
|
bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return block_offset;
|
return block_offset;
|
||||||
@@ -505,7 +505,7 @@ static int rewrite_footer(BlockDriverState* bs)
|
|||||||
BDRVVPCState *s = bs->opaque;
|
BDRVVPCState *s = bs->opaque;
|
||||||
int64_t offset = s->free_data_block_offset;
|
int64_t offset = s->free_data_block_offset;
|
||||||
|
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, offset, s->footer_buf, HEADER_SIZE);
|
ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -539,7 +539,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t offset)
|
|||||||
|
|
||||||
/* Initialize the block's bitmap */
|
/* Initialize the block's bitmap */
|
||||||
memset(bitmap, 0xff, s->bitmap_size);
|
memset(bitmap, 0xff, s->bitmap_size);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, s->free_data_block_offset, bitmap,
|
ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
|
||||||
s->bitmap_size);
|
s->bitmap_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -554,7 +554,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t offset)
|
|||||||
/* 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 = cpu_to_be32(s->pagetable[index]);
|
bat_value = cpu_to_be32(s->pagetable[index]);
|
||||||
ret = bdrv_pwrite_sync(bs->file->bs, 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;
|
||||||
|
|
||||||
@@ -591,7 +591,7 @@ vpc_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
QEMUIOVector local_qiov;
|
QEMUIOVector local_qiov;
|
||||||
|
|
||||||
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
||||||
return bdrv_co_preadv(bs->file->bs, offset, bytes, qiov, 0);
|
return bdrv_co_preadv(bs->file, offset, bytes, qiov, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
@@ -607,7 +607,7 @@ vpc_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
qemu_iovec_reset(&local_qiov);
|
qemu_iovec_reset(&local_qiov);
|
||||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||||
|
|
||||||
ret = bdrv_co_preadv(bs->file->bs, image_offset, n_bytes,
|
ret = bdrv_co_preadv(bs->file, image_offset, n_bytes,
|
||||||
&local_qiov, 0);
|
&local_qiov, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -640,7 +640,7 @@ vpc_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
QEMUIOVector local_qiov;
|
QEMUIOVector local_qiov;
|
||||||
|
|
||||||
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
||||||
return bdrv_co_pwritev(bs->file->bs, offset, bytes, qiov, 0);
|
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
@@ -661,7 +661,7 @@ vpc_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
qemu_iovec_reset(&local_qiov);
|
qemu_iovec_reset(&local_qiov);
|
||||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||||
|
|
||||||
ret = bdrv_co_pwritev(bs->file->bs, image_offset, n_bytes,
|
ret = bdrv_co_pwritev(bs->file, image_offset, n_bytes,
|
||||||
&local_qiov, 0);
|
&local_qiov, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
@@ -341,9 +341,8 @@ typedef struct BDRVVVFATState {
|
|||||||
unsigned int current_cluster;
|
unsigned int current_cluster;
|
||||||
|
|
||||||
/* write support */
|
/* write support */
|
||||||
BlockDriverState* write_target;
|
|
||||||
char* qcow_filename;
|
char* qcow_filename;
|
||||||
BlockDriverState* qcow;
|
BdrvChild* qcow;
|
||||||
void* fat2;
|
void* fat2;
|
||||||
char* used_clusters;
|
char* used_clusters;
|
||||||
array_t commits;
|
array_t commits;
|
||||||
@@ -981,7 +980,7 @@ static int init_directories(BDRVVVFATState* s,
|
|||||||
static BDRVVVFATState *vvv = NULL;
|
static BDRVVVFATState *vvv = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int enable_write_target(BDRVVVFATState *s, Error **errp);
|
static int enable_write_target(BlockDriverState *bs, Error **errp);
|
||||||
static int is_consistent(BDRVVVFATState *s);
|
static int is_consistent(BDRVVVFATState *s);
|
||||||
|
|
||||||
static QemuOptsList runtime_opts = {
|
static QemuOptsList runtime_opts = {
|
||||||
@@ -1158,8 +1157,8 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->current_cluster=0xffffffff;
|
s->current_cluster=0xffffffff;
|
||||||
|
|
||||||
/* read only is the default for safety */
|
/* read only is the default for safety */
|
||||||
bs->read_only = 1;
|
bs->read_only = true;
|
||||||
s->qcow = s->write_target = NULL;
|
s->qcow = NULL;
|
||||||
s->qcow_filename = NULL;
|
s->qcow_filename = NULL;
|
||||||
s->fat2 = NULL;
|
s->fat2 = NULL;
|
||||||
s->downcase_short_names = 1;
|
s->downcase_short_names = 1;
|
||||||
@@ -1170,14 +1169,13 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
|
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
|
||||||
|
|
||||||
if (qemu_opt_get_bool(opts, "rw", false)) {
|
if (qemu_opt_get_bool(opts, "rw", false)) {
|
||||||
ret = enable_write_target(s, errp);
|
ret = enable_write_target(bs, errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
bs->read_only = 0;
|
bs->read_only = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
|
|
||||||
bs->total_sectors = cyls * heads * secs;
|
bs->total_sectors = cyls * heads * secs;
|
||||||
|
|
||||||
if (init_directories(s, dirname, heads, secs, errp)) {
|
if (init_directories(s, dirname, heads, secs, errp)) {
|
||||||
@@ -1209,6 +1207,11 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
|
||||||
|
}
|
||||||
|
|
||||||
static inline void vvfat_close_current_file(BDRVVVFATState *s)
|
static inline void vvfat_close_current_file(BDRVVVFATState *s)
|
||||||
{
|
{
|
||||||
if(s->current_mapping) {
|
if(s->current_mapping) {
|
||||||
@@ -1387,9 +1390,10 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return -1;
|
return -1;
|
||||||
if (s->qcow) {
|
if (s->qcow) {
|
||||||
int n;
|
int n;
|
||||||
if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
|
if (bdrv_is_allocated(s->qcow->bs, sector_num, nb_sectors-i, &n)) {
|
||||||
DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
|
DLOG(fprintf(stderr, "sectors %d+%d allocated\n",
|
||||||
if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
|
(int)sector_num, n));
|
||||||
|
if (bdrv_read(s->qcow, sector_num, buf + i * 0x200, n)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
i += n - 1;
|
i += n - 1;
|
||||||
@@ -1665,12 +1669,15 @@ static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
|
|||||||
int was_modified = 0;
|
int was_modified = 0;
|
||||||
int i, dummy;
|
int i, dummy;
|
||||||
|
|
||||||
if (s->qcow == NULL)
|
if (s->qcow == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
|
for (i = 0; !was_modified && i < s->sectors_per_cluster; i++) {
|
||||||
was_modified = bdrv_is_allocated(s->qcow,
|
was_modified = bdrv_is_allocated(s->qcow->bs,
|
||||||
cluster2sector(s, cluster_num) + i, 1, &dummy);
|
cluster2sector(s, cluster_num) + i,
|
||||||
|
1, &dummy);
|
||||||
|
}
|
||||||
|
|
||||||
return was_modified;
|
return was_modified;
|
||||||
}
|
}
|
||||||
@@ -1819,11 +1826,16 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
|||||||
|
|
||||||
vvfat_close_current_file(s);
|
vvfat_close_current_file(s);
|
||||||
for (i = 0; i < s->sectors_per_cluster; i++) {
|
for (i = 0; i < s->sectors_per_cluster; i++) {
|
||||||
if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
|
int res;
|
||||||
if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
|
|
||||||
|
res = bdrv_is_allocated(s->qcow->bs, offset + i, 1, &dummy);
|
||||||
|
if (!res) {
|
||||||
|
res = vvfat_read(s->bs, offset, s->cluster_buffer, 1);
|
||||||
|
if (res) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
|
res = bdrv_write(s->qcow, offset, s->cluster_buffer, 1);
|
||||||
|
if (res) {
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2779,8 +2791,8 @@ static int do_commit(BDRVVVFATState* s)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->qcow->drv->bdrv_make_empty) {
|
if (s->qcow->bs->drv->bdrv_make_empty) {
|
||||||
s->qcow->drv->bdrv_make_empty(s->qcow);
|
s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
|
memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
|
||||||
@@ -2946,7 +2958,7 @@ write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
|||||||
|
|
||||||
static void write_target_close(BlockDriverState *bs) {
|
static void write_target_close(BlockDriverState *bs) {
|
||||||
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
|
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
|
||||||
bdrv_unref(s->qcow);
|
bdrv_unref_child(s->bs, s->qcow);
|
||||||
g_free(s->qcow_filename);
|
g_free(s->qcow_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2956,8 +2968,19 @@ static BlockDriver vvfat_write_target = {
|
|||||||
.bdrv_close = write_target_close,
|
.bdrv_close = write_target_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
static void vvfat_qcow_options(int *child_flags, QDict *child_options,
|
||||||
|
int parent_flags, QDict *parent_options)
|
||||||
{
|
{
|
||||||
|
*child_flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const BdrvChildRole child_vvfat_qcow = {
|
||||||
|
.inherit_options = vvfat_qcow_options,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int enable_write_target(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
BDRVVVFATState *s = bs->opaque;
|
||||||
BlockDriver *bdrv_qcow = NULL;
|
BlockDriver *bdrv_qcow = NULL;
|
||||||
BlockDriverState *backing;
|
BlockDriverState *backing;
|
||||||
QemuOpts *opts = NULL;
|
QemuOpts *opts = NULL;
|
||||||
@@ -2996,8 +3019,8 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
|||||||
|
|
||||||
options = qdict_new();
|
options = qdict_new();
|
||||||
qdict_put(options, "driver", qstring_from_str("qcow"));
|
qdict_put(options, "driver", qstring_from_str("qcow"));
|
||||||
s->qcow = bdrv_open(s->qcow_filename, NULL, options,
|
s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
|
||||||
BDRV_O_RDWR | BDRV_O_NO_FLUSH, errp);
|
&child_vvfat_qcow, false, errp);
|
||||||
if (!s->qcow) {
|
if (!s->qcow) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err;
|
goto err;
|
||||||
@@ -3046,6 +3069,7 @@ static BlockDriver bdrv_vvfat = {
|
|||||||
|
|
||||||
.bdrv_parse_filename = vvfat_parse_filename,
|
.bdrv_parse_filename = vvfat_parse_filename,
|
||||||
.bdrv_file_open = vvfat_open,
|
.bdrv_file_open = vvfat_open,
|
||||||
|
.bdrv_refresh_limits = vvfat_refresh_limits,
|
||||||
.bdrv_close = vvfat_close,
|
.bdrv_close = vvfat_close,
|
||||||
|
|
||||||
.bdrv_co_preadv = vvfat_co_preadv,
|
.bdrv_co_preadv = vvfat_co_preadv,
|
||||||
|
|||||||
@@ -3950,10 +3950,10 @@ out:
|
|||||||
|
|
||||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||||
{
|
{
|
||||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
BlockBackend *blk = NULL;
|
BlockBackend *blk = NULL;
|
||||||
QObject *obj;
|
QObject *obj;
|
||||||
|
Visitor *v = qmp_output_visitor_new(&obj);
|
||||||
QDict *qdict;
|
QDict *qdict;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
@@ -3972,14 +3972,13 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_type_BlockdevOptions(qmp_output_get_visitor(ov), NULL, &options,
|
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
|
||||||
&local_err);
|
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = qmp_output_get_qobject(ov);
|
visit_complete(v, &obj);
|
||||||
qdict = qobject_to_qdict(obj);
|
qdict = qobject_to_qdict(obj);
|
||||||
|
|
||||||
qdict_flatten(qdict);
|
qdict_flatten(qdict);
|
||||||
@@ -4020,7 +4019,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
qmp_output_visitor_cleanup(ov);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_x_blockdev_del(bool has_id, const char *id,
|
void qmp_x_blockdev_del(bool has_id, const char *id,
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
|||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
BlockJob *job;
|
BlockJob *job;
|
||||||
|
|
||||||
|
assert(cb);
|
||||||
if (bs->job) {
|
if (bs->job) {
|
||||||
error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
|
error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -315,12 +315,14 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
|
|||||||
abi_long arg5, abi_long arg6, abi_long arg7,
|
abi_long arg5, abi_long arg6, abi_long arg7,
|
||||||
abi_long arg8)
|
abi_long arg8)
|
||||||
{
|
{
|
||||||
|
CPUState *cpu = ENV_GET_CPU(cpu_env);
|
||||||
abi_long ret;
|
abi_long ret;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
gemu_log("freebsd syscall %d\n", num);
|
gemu_log("freebsd syscall %d\n", num);
|
||||||
#endif
|
#endif
|
||||||
|
trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||||
if(do_strace)
|
if(do_strace)
|
||||||
print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
|
print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||||
|
|
||||||
@@ -400,6 +402,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
|
|||||||
#endif
|
#endif
|
||||||
if (do_strace)
|
if (do_strace)
|
||||||
print_freebsd_syscall_ret(num, ret);
|
print_freebsd_syscall_ret(num, ret);
|
||||||
|
trace_guest_user_syscall_ret(cpu, num, ret);
|
||||||
return ret;
|
return ret;
|
||||||
efault:
|
efault:
|
||||||
ret = -TARGET_EFAULT;
|
ret = -TARGET_EFAULT;
|
||||||
@@ -410,12 +413,14 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
|
|||||||
abi_long arg2, abi_long arg3, abi_long arg4,
|
abi_long arg2, abi_long arg3, abi_long arg4,
|
||||||
abi_long arg5, abi_long arg6)
|
abi_long arg5, abi_long arg6)
|
||||||
{
|
{
|
||||||
|
CPUState *cpu = ENV_GET_CPU(cpu_env);
|
||||||
abi_long ret;
|
abi_long ret;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
gemu_log("netbsd syscall %d\n", num);
|
gemu_log("netbsd syscall %d\n", num);
|
||||||
#endif
|
#endif
|
||||||
|
trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
|
||||||
if(do_strace)
|
if(do_strace)
|
||||||
print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
|
print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||||
|
|
||||||
@@ -472,6 +477,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
|
|||||||
#endif
|
#endif
|
||||||
if (do_strace)
|
if (do_strace)
|
||||||
print_netbsd_syscall_ret(num, ret);
|
print_netbsd_syscall_ret(num, ret);
|
||||||
|
trace_guest_user_syscall_ret(cpu, num, ret);
|
||||||
return ret;
|
return ret;
|
||||||
efault:
|
efault:
|
||||||
ret = -TARGET_EFAULT;
|
ret = -TARGET_EFAULT;
|
||||||
@@ -482,12 +488,14 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
|
|||||||
abi_long arg2, abi_long arg3, abi_long arg4,
|
abi_long arg2, abi_long arg3, abi_long arg4,
|
||||||
abi_long arg5, abi_long arg6)
|
abi_long arg5, abi_long arg6)
|
||||||
{
|
{
|
||||||
|
CPUState *cpu = ENV_GET_CPU(cpu_env);
|
||||||
abi_long ret;
|
abi_long ret;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
gemu_log("openbsd syscall %d\n", num);
|
gemu_log("openbsd syscall %d\n", num);
|
||||||
#endif
|
#endif
|
||||||
|
trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
|
||||||
if(do_strace)
|
if(do_strace)
|
||||||
print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
|
print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||||
|
|
||||||
@@ -544,6 +552,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
|
|||||||
#endif
|
#endif
|
||||||
if (do_strace)
|
if (do_strace)
|
||||||
print_openbsd_syscall_ret(num, ret);
|
print_openbsd_syscall_ret(num, ret);
|
||||||
|
trace_guest_user_syscall_ret(cpu, num, ret);
|
||||||
return ret;
|
return ret;
|
||||||
efault:
|
efault:
|
||||||
ret = -TARGET_EFAULT;
|
ret = -TARGET_EFAULT;
|
||||||
|
|||||||
49
configure
vendored
49
configure
vendored
@@ -305,8 +305,8 @@ archipelago="no"
|
|||||||
gtk=""
|
gtk=""
|
||||||
gtkabi=""
|
gtkabi=""
|
||||||
gtk_gl="no"
|
gtk_gl="no"
|
||||||
|
tls_priority="NORMAL"
|
||||||
gnutls=""
|
gnutls=""
|
||||||
gnutls_hash=""
|
|
||||||
gnutls_rnd=""
|
gnutls_rnd=""
|
||||||
nettle=""
|
nettle=""
|
||||||
nettle_kdf="no"
|
nettle_kdf="no"
|
||||||
@@ -369,6 +369,7 @@ fi
|
|||||||
|
|
||||||
ar="${AR-${cross_prefix}ar}"
|
ar="${AR-${cross_prefix}ar}"
|
||||||
as="${AS-${cross_prefix}as}"
|
as="${AS-${cross_prefix}as}"
|
||||||
|
ccas="${CCAS-$cc}"
|
||||||
cpp="${CPP-$cc -E}"
|
cpp="${CPP-$cc -E}"
|
||||||
objcopy="${OBJCOPY-${cross_prefix}objcopy}"
|
objcopy="${OBJCOPY-${cross_prefix}objcopy}"
|
||||||
ld="${LD-${cross_prefix}ld}"
|
ld="${LD-${cross_prefix}ld}"
|
||||||
@@ -1097,6 +1098,8 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-gtk) gtk="yes"
|
--enable-gtk) gtk="yes"
|
||||||
;;
|
;;
|
||||||
|
--tls-priority=*) tls_priority="$optarg"
|
||||||
|
;;
|
||||||
--disable-gnutls) gnutls="no"
|
--disable-gnutls) gnutls="no"
|
||||||
;;
|
;;
|
||||||
--enable-gnutls) gnutls="yes"
|
--enable-gnutls) gnutls="yes"
|
||||||
@@ -1216,6 +1219,13 @@ esac
|
|||||||
QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS"
|
QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS"
|
||||||
EXTRA_CFLAGS="$CPU_CFLAGS $EXTRA_CFLAGS"
|
EXTRA_CFLAGS="$CPU_CFLAGS $EXTRA_CFLAGS"
|
||||||
|
|
||||||
|
# For user-mode emulation the host arch has to be one we explicitly
|
||||||
|
# support, even if we're using TCI.
|
||||||
|
if [ "$ARCH" = "unknown" ]; then
|
||||||
|
bsd_user="no"
|
||||||
|
linux_user="no"
|
||||||
|
fi
|
||||||
|
|
||||||
default_target_list=""
|
default_target_list=""
|
||||||
|
|
||||||
mak_wilds=""
|
mak_wilds=""
|
||||||
@@ -1301,6 +1311,7 @@ Advanced options (experts only):
|
|||||||
--disable-blobs disable installing provided firmware blobs
|
--disable-blobs disable installing provided firmware blobs
|
||||||
--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)
|
||||||
|
--tls-priority default TLS protocol/cipher priority string
|
||||||
|
|
||||||
Optional features, enabled with --enable-FEATURE and
|
Optional features, enabled with --enable-FEATURE and
|
||||||
disabled with --disable-FEATURE, default is enabled if available:
|
disabled with --disable-FEATURE, default is enabled if available:
|
||||||
@@ -1380,7 +1391,6 @@ fi
|
|||||||
if test "$ARCH" = "unknown"; then
|
if test "$ARCH" = "unknown"; then
|
||||||
if test "$tcg_interpreter" = "yes" ; then
|
if test "$tcg_interpreter" = "yes" ; then
|
||||||
echo "Unsupported CPU = $cpu, will use TCG with TCI (experimental)"
|
echo "Unsupported CPU = $cpu, will use TCG with TCI (experimental)"
|
||||||
ARCH=tci
|
|
||||||
else
|
else
|
||||||
error_exit "Unsupported CPU = $cpu, try --enable-tcg-interpreter"
|
error_exit "Unsupported CPU = $cpu, try --enable-tcg-interpreter"
|
||||||
fi
|
fi
|
||||||
@@ -1792,8 +1802,10 @@ int foo(void *a) __attribute__((ifunc("bar_ifunc")));
|
|||||||
int main(int argc, char *argv[]) { return foo(argv[0]);}
|
int main(int argc, char *argv[]) { return foo(argv[0]);}
|
||||||
EOF
|
EOF
|
||||||
if compile_object "" ; then
|
if compile_object "" ; then
|
||||||
if readelf --syms $TMPO |grep "IFUNC.*foo" >/dev/null 2>&1; then
|
if has readelf; then
|
||||||
avx2_opt="yes"
|
if readelf --syms $TMPO 2>/dev/null |grep -q "IFUNC.*foo"; then
|
||||||
|
avx2_opt="yes"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -2210,13 +2222,6 @@ if test "$gnutls" != "no"; then
|
|||||||
QEMU_CFLAGS="$QEMU_CFLAGS $gnutls_cflags"
|
QEMU_CFLAGS="$QEMU_CFLAGS $gnutls_cflags"
|
||||||
gnutls="yes"
|
gnutls="yes"
|
||||||
|
|
||||||
# gnutls_hash_init requires >= 2.9.10
|
|
||||||
if $pkg_config --exists "gnutls >= 2.9.10"; then
|
|
||||||
gnutls_hash="yes"
|
|
||||||
else
|
|
||||||
gnutls_hash="no"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# gnutls_rnd requires >= 2.11.0
|
# gnutls_rnd requires >= 2.11.0
|
||||||
if $pkg_config --exists "gnutls >= 2.11.0"; then
|
if $pkg_config --exists "gnutls >= 2.11.0"; then
|
||||||
gnutls_rnd="yes"
|
gnutls_rnd="yes"
|
||||||
@@ -2250,11 +2255,9 @@ if test "$gnutls" != "no"; then
|
|||||||
feature_not_found "gnutls" "Install gnutls devel"
|
feature_not_found "gnutls" "Install gnutls devel"
|
||||||
else
|
else
|
||||||
gnutls="no"
|
gnutls="no"
|
||||||
gnutls_hash="no"
|
|
||||||
gnutls_rnd="no"
|
gnutls_rnd="no"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
gnutls_hash="no"
|
|
||||||
gnutls_rnd="no"
|
gnutls_rnd="no"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -4703,7 +4706,7 @@ if test "$cpu" = "s390x" ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Probe for the need for relocating the user-only binary.
|
# Probe for the need for relocating the user-only binary.
|
||||||
if test "$pie" = "no" ; then
|
if ( [ "$linux_user" = yes ] || [ "$bsd_user" = yes ] ) && [ "$pie" = no ]; then
|
||||||
textseg_addr=
|
textseg_addr=
|
||||||
case "$cpu" in
|
case "$cpu" in
|
||||||
arm | i386 | ppc* | s390* | sparc* | x86_64 | x32)
|
arm | i386 | ppc* | s390* | sparc* | x86_64 | x32)
|
||||||
@@ -4725,6 +4728,16 @@ EOF
|
|||||||
# In case ld does not support -Ttext-segment, edit the default linker
|
# In case ld does not support -Ttext-segment, edit the default linker
|
||||||
# script via sed to set the .text start addr. This is needed on FreeBSD
|
# script via sed to set the .text start addr. This is needed on FreeBSD
|
||||||
# at least.
|
# at least.
|
||||||
|
if ! $ld --verbose >/dev/null 2>&1; then
|
||||||
|
error_exit \
|
||||||
|
"We need to link the QEMU user mode binaries at a" \
|
||||||
|
"specific text address. Unfortunately your linker" \
|
||||||
|
"doesn't support either the -Ttext-segment option or" \
|
||||||
|
"printing the default linker script with --verbose." \
|
||||||
|
"If you don't want the user mode binaries, pass the" \
|
||||||
|
"--disable-user option to configure."
|
||||||
|
fi
|
||||||
|
|
||||||
$ld --verbose | sed \
|
$ld --verbose | sed \
|
||||||
-e '1,/==================================================/d' \
|
-e '1,/==================================================/d' \
|
||||||
-e '/==================================================/,$d' \
|
-e '/==================================================/,$d' \
|
||||||
@@ -4794,8 +4807,8 @@ echo "SDL support $sdl $(echo_version $sdl $sdlversion)"
|
|||||||
echo "GTK support $gtk $(echo_version $gtk $gtk_version)"
|
echo "GTK support $gtk $(echo_version $gtk $gtk_version)"
|
||||||
echo "GTK GL support $gtk_gl"
|
echo "GTK GL support $gtk_gl"
|
||||||
echo "VTE support $vte $(echo_version $vte $vteversion)"
|
echo "VTE support $vte $(echo_version $vte $vteversion)"
|
||||||
|
echo "TLS priority $tls_priority"
|
||||||
echo "GNUTLS support $gnutls"
|
echo "GNUTLS support $gnutls"
|
||||||
echo "GNUTLS hash $gnutls_hash"
|
|
||||||
echo "GNUTLS rnd $gnutls_rnd"
|
echo "GNUTLS rnd $gnutls_rnd"
|
||||||
echo "libgcrypt $gcrypt"
|
echo "libgcrypt $gcrypt"
|
||||||
echo "libgcrypt kdf $gcrypt_kdf"
|
echo "libgcrypt kdf $gcrypt_kdf"
|
||||||
@@ -5158,12 +5171,10 @@ if test "$gtk" = "yes" ; then
|
|||||||
echo "CONFIG_GTK_GL=y" >> $config_host_mak
|
echo "CONFIG_GTK_GL=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak
|
||||||
if test "$gnutls" = "yes" ; then
|
if test "$gnutls" = "yes" ; then
|
||||||
echo "CONFIG_GNUTLS=y" >> $config_host_mak
|
echo "CONFIG_GNUTLS=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$gnutls_hash" = "yes" ; then
|
|
||||||
echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
|
|
||||||
fi
|
|
||||||
if test "$gnutls_rnd" = "yes" ; then
|
if test "$gnutls_rnd" = "yes" ; then
|
||||||
echo "CONFIG_GNUTLS_RND=y" >> $config_host_mak
|
echo "CONFIG_GNUTLS_RND=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -5499,6 +5510,7 @@ echo "OBJCC=$objcc" >> $config_host_mak
|
|||||||
echo "AR=$ar" >> $config_host_mak
|
echo "AR=$ar" >> $config_host_mak
|
||||||
echo "ARFLAGS=$ARFLAGS" >> $config_host_mak
|
echo "ARFLAGS=$ARFLAGS" >> $config_host_mak
|
||||||
echo "AS=$as" >> $config_host_mak
|
echo "AS=$as" >> $config_host_mak
|
||||||
|
echo "CCAS=$ccas" >> $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
|
||||||
@@ -5972,6 +5984,7 @@ for rom in seabios vgabios ; do
|
|||||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||||
echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak
|
echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak
|
||||||
echo "AS=$as" >> $config_mak
|
echo "AS=$as" >> $config_mak
|
||||||
|
echo "CCAS=$ccas" >> $config_mak
|
||||||
echo "CC=$cc" >> $config_mak
|
echo "CC=$cc" >> $config_mak
|
||||||
echo "BCC=bcc" >> $config_mak
|
echo "BCC=bcc" >> $config_mak
|
||||||
echo "CPP=$cpp" >> $config_mak
|
echo "CPP=$cpp" >> $config_mak
|
||||||
|
|||||||
68
cputlb.c
68
cputlb.c
@@ -30,6 +30,8 @@
|
|||||||
#include "exec/ram_addr.h"
|
#include "exec/ram_addr.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "exec/log.h"
|
||||||
|
|
||||||
/* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */
|
/* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */
|
||||||
/* #define DEBUG_TLB */
|
/* #define DEBUG_TLB */
|
||||||
@@ -427,6 +429,39 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
|||||||
prot, mmu_idx, size);
|
prot, mmu_idx, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void report_bad_exec(CPUState *cpu, target_ulong addr)
|
||||||
|
{
|
||||||
|
/* Accidentally executing outside RAM or ROM is quite common for
|
||||||
|
* several user-error situations, so report it in a way that
|
||||||
|
* makes it clear that this isn't a QEMU bug and provide suggestions
|
||||||
|
* about what a user could do to fix things.
|
||||||
|
*/
|
||||||
|
error_report("Trying to execute code outside RAM or ROM at 0x"
|
||||||
|
TARGET_FMT_lx, addr);
|
||||||
|
error_printf("This usually means one of the following happened:\n\n"
|
||||||
|
"(1) You told QEMU to execute a kernel for the wrong machine "
|
||||||
|
"type, and it crashed on startup (eg trying to run a "
|
||||||
|
"raspberry pi kernel on a versatilepb QEMU machine)\n"
|
||||||
|
"(2) You didn't give QEMU a kernel or BIOS filename at all, "
|
||||||
|
"and QEMU executed a ROM full of no-op instructions until "
|
||||||
|
"it fell off the end\n"
|
||||||
|
"(3) Your guest kernel has a bug and crashed by jumping "
|
||||||
|
"off into nowhere\n\n"
|
||||||
|
"This is almost always one of the first two, so check your "
|
||||||
|
"command line and that you are using the right type of kernel "
|
||||||
|
"for this machine.\n"
|
||||||
|
"If you think option (3) is likely then you can try debugging "
|
||||||
|
"your guest with the -d debug options; in particular "
|
||||||
|
"-d guest_errors will cause the log to include a dump of the "
|
||||||
|
"guest register state at this point.\n\n"
|
||||||
|
"Execution cannot continue; stopping here.\n\n");
|
||||||
|
|
||||||
|
/* Report also to the logs, with more detail including register dump */
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "qemu: fatal: Trying to execute code "
|
||||||
|
"outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
|
||||||
|
log_cpu_state_mask(LOG_GUEST_ERROR, cpu, CPU_DUMP_FPU | CPU_DUMP_CCOP);
|
||||||
|
}
|
||||||
|
|
||||||
/* NOTE: this function can trigger an exception */
|
/* NOTE: this function can trigger an exception */
|
||||||
/* NOTE2: the returned address is not exactly the physical address: it
|
/* NOTE2: the returned address is not exactly the physical address: it
|
||||||
* is actually a ram_addr_t (in system mode; the user mode emulation
|
* is actually a ram_addr_t (in system mode; the user mode emulation
|
||||||
@@ -455,14 +490,43 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
|||||||
if (cc->do_unassigned_access) {
|
if (cc->do_unassigned_access) {
|
||||||
cc->do_unassigned_access(cpu, addr, false, true, 0, 4);
|
cc->do_unassigned_access(cpu, addr, false, true, 0, 4);
|
||||||
} else {
|
} else {
|
||||||
cpu_abort(cpu, "Trying to execute code outside RAM or ROM at 0x"
|
report_bad_exec(cpu, addr);
|
||||||
TARGET_FMT_lx "\n", addr);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);
|
p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);
|
||||||
return qemu_ram_addr_from_host_nofail(p);
|
return qemu_ram_addr_from_host_nofail(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if ADDR is present in the victim tlb, and has been copied
|
||||||
|
back to the main tlb. */
|
||||||
|
static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
|
||||||
|
size_t elt_ofs, target_ulong page)
|
||||||
|
{
|
||||||
|
size_t vidx;
|
||||||
|
for (vidx = 0; vidx < CPU_VTLB_SIZE; ++vidx) {
|
||||||
|
CPUTLBEntry *vtlb = &env->tlb_v_table[mmu_idx][vidx];
|
||||||
|
target_ulong cmp = *(target_ulong *)((uintptr_t)vtlb + elt_ofs);
|
||||||
|
|
||||||
|
if (cmp == page) {
|
||||||
|
/* Found entry in victim tlb, swap tlb and iotlb. */
|
||||||
|
CPUTLBEntry tmptlb, *tlb = &env->tlb_table[mmu_idx][index];
|
||||||
|
CPUIOTLBEntry tmpio, *io = &env->iotlb[mmu_idx][index];
|
||||||
|
CPUIOTLBEntry *vio = &env->iotlb_v[mmu_idx][vidx];
|
||||||
|
|
||||||
|
tmptlb = *tlb; *tlb = *vtlb; *vtlb = tmptlb;
|
||||||
|
tmpio = *io; *io = *vio; *vio = tmpio;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Macro to call the above, with local variables from the use context. */
|
||||||
|
#define VICTIM_TLB_HIT(TY, ADDR) \
|
||||||
|
victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \
|
||||||
|
(ADDR) & TARGET_PAGE_MASK)
|
||||||
|
|
||||||
#define MMUSUFFIX _mmu
|
#define MMUSUFFIX _mmu
|
||||||
|
|
||||||
#define SHIFT 0
|
#define SHIFT 0
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
crypto-obj-y = init.o
|
crypto-obj-y = init.o
|
||||||
crypto-obj-y += hash.o
|
crypto-obj-y += hash.o
|
||||||
|
crypto-obj-$(CONFIG_NETTLE) += hash-nettle.o
|
||||||
|
crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT)) += hash-gcrypt.o
|
||||||
crypto-obj-y += aes.o
|
crypto-obj-y += aes.o
|
||||||
crypto-obj-y += desrfb.o
|
crypto-obj-y += desrfb.o
|
||||||
crypto-obj-y += cipher.o
|
crypto-obj-y += cipher.o
|
||||||
@@ -28,3 +30,4 @@ crypto-aes-obj-y = aes.o
|
|||||||
|
|
||||||
stub-obj-y += random-stub.o
|
stub-obj-y += random-stub.o
|
||||||
stub-obj-y += pbkdf-stub.o
|
stub-obj-y += pbkdf-stub.o
|
||||||
|
stub-obj-y += hash-stub.o
|
||||||
|
|||||||
@@ -776,6 +776,11 @@ qcrypto_block_luks_open(QCryptoBlock *block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ivalg == QCRYPTO_IVGEN_ALG_ESSIV) {
|
if (ivalg == QCRYPTO_IVGEN_ALG_ESSIV) {
|
||||||
|
if (!ivhash_name) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
error_setg(errp, "Missing IV generator hash specification");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
ivcipheralg = qcrypto_block_luks_essiv_cipher(cipheralg,
|
ivcipheralg = qcrypto_block_luks_essiv_cipher(cipheralg,
|
||||||
ivhash,
|
ivhash,
|
||||||
&local_err);
|
&local_err);
|
||||||
@@ -785,6 +790,13 @@ qcrypto_block_luks_open(QCryptoBlock *block,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* Note we parsed the ivhash_name earlier in the cipher_mode
|
||||||
|
* spec string even with plain/plain64 ivgens, but we
|
||||||
|
* will ignore it, since it is irrelevant for these ivgens.
|
||||||
|
* This is for compat with dm-crypt which will silently
|
||||||
|
* ignore hash names with these ivgens rather than report
|
||||||
|
* an error about the invalid usage
|
||||||
|
*/
|
||||||
ivcipheralg = cipheralg;
|
ivcipheralg = cipheralg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,6 +916,15 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
|||||||
if (!luks_opts.has_hash_alg) {
|
if (!luks_opts.has_hash_alg) {
|
||||||
luks_opts.hash_alg = QCRYPTO_HASH_ALG_SHA256;
|
luks_opts.hash_alg = QCRYPTO_HASH_ALG_SHA256;
|
||||||
}
|
}
|
||||||
|
if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
|
||||||
|
if (!luks_opts.has_ivgen_hash_alg) {
|
||||||
|
luks_opts.ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256;
|
||||||
|
luks_opts.has_ivgen_hash_alg = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Note we're allowing ivgen_hash_alg to be set even for
|
||||||
|
* non-essiv iv generators that don't need a hash. It will
|
||||||
|
* be silently ignored, for compatibility with dm-crypt */
|
||||||
|
|
||||||
if (!options->u.luks.key_secret) {
|
if (!options->u.luks.key_secret) {
|
||||||
error_setg(errp, "Parameter 'key-secret' is required for cipher");
|
error_setg(errp, "Parameter 'key-secret' is required for cipher");
|
||||||
|
|||||||
110
crypto/hash-gcrypt.c
Normal file
110
crypto/hash-gcrypt.c
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto hash algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
#include "gcrypt.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||||
|
[QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA224] = GCRY_MD_SHA224,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512,
|
||||||
|
[QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160,
|
||||||
|
};
|
||||||
|
|
||||||
|
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
|
||||||
|
{
|
||||||
|
if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) &&
|
||||||
|
qcrypto_hash_alg_map[alg] != GCRY_MD_NONE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *resultlen,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
gcry_md_hd_t md;
|
||||||
|
unsigned char *digest;
|
||||||
|
|
||||||
|
if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map) ||
|
||||||
|
qcrypto_hash_alg_map[alg] == GCRY_MD_NONE) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unknown hash algorithm %d",
|
||||||
|
alg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gcry_md_open(&md, qcrypto_hash_alg_map[alg], 0);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unable to initialize hash algorithm: %s",
|
||||||
|
gcry_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < niov; i++) {
|
||||||
|
gcry_md_write(md, iov[i].iov_base, iov[i].iov_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[alg]);
|
||||||
|
if (ret <= 0) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unable to get hash length: %s",
|
||||||
|
gcry_strerror(ret));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (*resultlen == 0) {
|
||||||
|
*resultlen = ret;
|
||||||
|
*result = g_new0(uint8_t, *resultlen);
|
||||||
|
} else if (*resultlen != ret) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Result buffer size %zu is smaller than hash %d",
|
||||||
|
*resultlen, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
digest = gcry_md_read(md, 0);
|
||||||
|
if (!digest) {
|
||||||
|
error_setg(errp,
|
||||||
|
"No digest produced");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
memcpy(*result, digest, *resultlen);
|
||||||
|
|
||||||
|
gcry_md_close(md);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
gcry_md_close(md);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
155
crypto/hash-nettle.c
Normal file
155
crypto/hash-nettle.c
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto hash algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
#include <nettle/md5.h>
|
||||||
|
#include <nettle/sha.h>
|
||||||
|
#include <nettle/ripemd160.h>
|
||||||
|
|
||||||
|
typedef void (*qcrypto_nettle_init)(void *ctx);
|
||||||
|
typedef void (*qcrypto_nettle_write)(void *ctx,
|
||||||
|
unsigned int len,
|
||||||
|
const uint8_t *buf);
|
||||||
|
typedef void (*qcrypto_nettle_result)(void *ctx,
|
||||||
|
unsigned int len,
|
||||||
|
uint8_t *buf);
|
||||||
|
|
||||||
|
union qcrypto_hash_ctx {
|
||||||
|
struct md5_ctx md5;
|
||||||
|
struct sha1_ctx sha1;
|
||||||
|
struct sha224_ctx sha224;
|
||||||
|
struct sha256_ctx sha256;
|
||||||
|
struct sha384_ctx sha384;
|
||||||
|
struct sha512_ctx sha512;
|
||||||
|
struct ripemd160_ctx ripemd160;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qcrypto_hash_alg {
|
||||||
|
qcrypto_nettle_init init;
|
||||||
|
qcrypto_nettle_write write;
|
||||||
|
qcrypto_nettle_result result;
|
||||||
|
size_t len;
|
||||||
|
} qcrypto_hash_alg_map[] = {
|
||||||
|
[QCRYPTO_HASH_ALG_MD5] = {
|
||||||
|
.init = (qcrypto_nettle_init)md5_init,
|
||||||
|
.write = (qcrypto_nettle_write)md5_update,
|
||||||
|
.result = (qcrypto_nettle_result)md5_digest,
|
||||||
|
.len = MD5_DIGEST_SIZE,
|
||||||
|
},
|
||||||
|
[QCRYPTO_HASH_ALG_SHA1] = {
|
||||||
|
.init = (qcrypto_nettle_init)sha1_init,
|
||||||
|
.write = (qcrypto_nettle_write)sha1_update,
|
||||||
|
.result = (qcrypto_nettle_result)sha1_digest,
|
||||||
|
.len = SHA1_DIGEST_SIZE,
|
||||||
|
},
|
||||||
|
[QCRYPTO_HASH_ALG_SHA224] = {
|
||||||
|
.init = (qcrypto_nettle_init)sha224_init,
|
||||||
|
.write = (qcrypto_nettle_write)sha224_update,
|
||||||
|
.result = (qcrypto_nettle_result)sha224_digest,
|
||||||
|
.len = SHA224_DIGEST_SIZE,
|
||||||
|
},
|
||||||
|
[QCRYPTO_HASH_ALG_SHA256] = {
|
||||||
|
.init = (qcrypto_nettle_init)sha256_init,
|
||||||
|
.write = (qcrypto_nettle_write)sha256_update,
|
||||||
|
.result = (qcrypto_nettle_result)sha256_digest,
|
||||||
|
.len = SHA256_DIGEST_SIZE,
|
||||||
|
},
|
||||||
|
[QCRYPTO_HASH_ALG_SHA384] = {
|
||||||
|
.init = (qcrypto_nettle_init)sha384_init,
|
||||||
|
.write = (qcrypto_nettle_write)sha384_update,
|
||||||
|
.result = (qcrypto_nettle_result)sha384_digest,
|
||||||
|
.len = SHA384_DIGEST_SIZE,
|
||||||
|
},
|
||||||
|
[QCRYPTO_HASH_ALG_SHA512] = {
|
||||||
|
.init = (qcrypto_nettle_init)sha512_init,
|
||||||
|
.write = (qcrypto_nettle_write)sha512_update,
|
||||||
|
.result = (qcrypto_nettle_result)sha512_digest,
|
||||||
|
.len = SHA512_DIGEST_SIZE,
|
||||||
|
},
|
||||||
|
[QCRYPTO_HASH_ALG_RIPEMD160] = {
|
||||||
|
.init = (qcrypto_nettle_init)ripemd160_init,
|
||||||
|
.write = (qcrypto_nettle_write)ripemd160_update,
|
||||||
|
.result = (qcrypto_nettle_result)ripemd160_digest,
|
||||||
|
.len = RIPEMD160_DIGEST_SIZE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
|
||||||
|
{
|
||||||
|
if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) &&
|
||||||
|
qcrypto_hash_alg_map[alg].init != NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
||||||
|
const struct iovec *iov,
|
||||||
|
size_t niov,
|
||||||
|
uint8_t **result,
|
||||||
|
size_t *resultlen,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
union qcrypto_hash_ctx ctx;
|
||||||
|
|
||||||
|
if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map) ||
|
||||||
|
qcrypto_hash_alg_map[alg].init == NULL) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Unknown hash algorithm %d",
|
||||||
|
alg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qcrypto_hash_alg_map[alg].init(&ctx);
|
||||||
|
|
||||||
|
for (i = 0; i < niov; i++) {
|
||||||
|
/* Some versions of nettle have functions
|
||||||
|
* declared with 'int' instead of 'size_t'
|
||||||
|
* so to be safe avoid writing more than
|
||||||
|
* UINT_MAX bytes at a time
|
||||||
|
*/
|
||||||
|
size_t len = iov[i].iov_len;
|
||||||
|
uint8_t *base = iov[i].iov_base;
|
||||||
|
while (len) {
|
||||||
|
size_t shortlen = MIN(len, UINT_MAX);
|
||||||
|
qcrypto_hash_alg_map[alg].write(&ctx, len, base);
|
||||||
|
len -= shortlen;
|
||||||
|
base += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*resultlen == 0) {
|
||||||
|
*resultlen = qcrypto_hash_alg_map[alg].len;
|
||||||
|
*result = g_new0(uint8_t, *resultlen);
|
||||||
|
} else if (*resultlen != qcrypto_hash_alg_map[alg].len) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Result buffer size %zu is smaller than hash %zu",
|
||||||
|
*resultlen, qcrypto_hash_alg_map[alg].len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qcrypto_hash_alg_map[alg].result(&ctx, *resultlen, *result);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
41
crypto/hash-stub.c
Normal file
41
crypto/hash-stub.c
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Crypto hash algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
|
||||||
|
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
||||||
|
const struct iovec *iov G_GNUC_UNUSED,
|
||||||
|
size_t niov G_GNUC_UNUSED,
|
||||||
|
uint8_t **result G_GNUC_UNUSED,
|
||||||
|
size_t *resultlen G_GNUC_UNUSED,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
error_setg(errp,
|
||||||
|
"Hash algorithm %d not supported without GNUTLS",
|
||||||
|
alg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
109
crypto/hash.c
109
crypto/hash.c
@@ -22,16 +22,14 @@
|
|||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
|
|
||||||
#ifdef CONFIG_GNUTLS_HASH
|
|
||||||
#include <gnutls/gnutls.h>
|
|
||||||
#include <gnutls/crypto.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALG__MAX] = {
|
static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALG__MAX] = {
|
||||||
[QCRYPTO_HASH_ALG_MD5] = 16,
|
[QCRYPTO_HASH_ALG_MD5] = 16,
|
||||||
[QCRYPTO_HASH_ALG_SHA1] = 20,
|
[QCRYPTO_HASH_ALG_SHA1] = 20,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA224] = 28,
|
||||||
[QCRYPTO_HASH_ALG_SHA256] = 32,
|
[QCRYPTO_HASH_ALG_SHA256] = 32,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA384] = 48,
|
||||||
|
[QCRYPTO_HASH_ALG_SHA512] = 64,
|
||||||
|
[QCRYPTO_HASH_ALG_RIPEMD160] = 20,
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg)
|
size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg)
|
||||||
@@ -41,105 +39,6 @@ size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_GNUTLS_HASH
|
|
||||||
static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
|
|
||||||
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
|
|
||||||
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
|
|
||||||
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
|
|
||||||
};
|
|
||||||
|
|
||||||
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
|
|
||||||
{
|
|
||||||
if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
|
||||||
const struct iovec *iov,
|
|
||||||
size_t niov,
|
|
||||||
uint8_t **result,
|
|
||||||
size_t *resultlen,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
gnutls_hash_hd_t dig;
|
|
||||||
|
|
||||||
if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map)) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Unknown hash algorithm %d",
|
|
||||||
alg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gnutls_hash_init(&dig, qcrypto_hash_alg_map[alg]);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Unable to initialize hash algorithm: %s",
|
|
||||||
gnutls_strerror(ret));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < niov; i++) {
|
|
||||||
ret = gnutls_hash(dig, iov[i].iov_base, iov[i].iov_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Unable process hash data: %s",
|
|
||||||
gnutls_strerror(ret));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]);
|
|
||||||
if (ret <= 0) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Unable to get hash length: %s",
|
|
||||||
gnutls_strerror(ret));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (*resultlen == 0) {
|
|
||||||
*resultlen = ret;
|
|
||||||
*result = g_new0(uint8_t, *resultlen);
|
|
||||||
} else if (*resultlen != ret) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Result buffer size %zu is smaller than hash %d",
|
|
||||||
*resultlen, ret);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
gnutls_hash_deinit(dig, *result);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
gnutls_hash_deinit(dig, NULL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* ! CONFIG_GNUTLS_HASH */
|
|
||||||
|
|
||||||
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg G_GNUC_UNUSED)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
|
||||||
const struct iovec *iov G_GNUC_UNUSED,
|
|
||||||
size_t niov G_GNUC_UNUSED,
|
|
||||||
uint8_t **result G_GNUC_UNUSED,
|
|
||||||
size_t *resultlen G_GNUC_UNUSED,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
error_setg(errp,
|
|
||||||
"Hash algorithm %d not supported without GNUTLS",
|
|
||||||
alg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* ! CONFIG_GNUTLS_HASH */
|
|
||||||
|
|
||||||
int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
|
int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
|
|||||||
@@ -178,6 +178,27 @@ qcrypto_tls_creds_prop_get_dir(Object *obj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
qcrypto_tls_creds_prop_set_priority(Object *obj,
|
||||||
|
const char *value,
|
||||||
|
Error **errp G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
|
||||||
|
|
||||||
|
creds->priority = g_strdup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
qcrypto_tls_creds_prop_get_priority(Object *obj,
|
||||||
|
Error **errp G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
|
||||||
|
|
||||||
|
return g_strdup(creds->priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qcrypto_tls_creds_prop_set_endpoint(Object *obj,
|
qcrypto_tls_creds_prop_set_endpoint(Object *obj,
|
||||||
int value,
|
int value,
|
||||||
@@ -216,6 +237,10 @@ qcrypto_tls_creds_class_init(ObjectClass *oc, void *data)
|
|||||||
qcrypto_tls_creds_prop_get_endpoint,
|
qcrypto_tls_creds_prop_get_endpoint,
|
||||||
qcrypto_tls_creds_prop_set_endpoint,
|
qcrypto_tls_creds_prop_set_endpoint,
|
||||||
NULL);
|
NULL);
|
||||||
|
object_class_property_add_str(oc, "priority",
|
||||||
|
qcrypto_tls_creds_prop_get_priority,
|
||||||
|
qcrypto_tls_creds_prop_set_priority,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -234,6 +259,7 @@ qcrypto_tls_creds_finalize(Object *obj)
|
|||||||
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
|
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
|
||||||
|
|
||||||
g_free(creds->dir);
|
g_free(creds->dir);
|
||||||
|
g_free(creds->priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -132,14 +132,22 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
|||||||
if (object_dynamic_cast(OBJECT(creds),
|
if (object_dynamic_cast(OBJECT(creds),
|
||||||
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
|
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
|
||||||
QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds);
|
QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds);
|
||||||
|
char *prio;
|
||||||
|
|
||||||
ret = gnutls_priority_set_direct(session->handle,
|
if (creds->priority != NULL) {
|
||||||
"NORMAL:+ANON-DH", NULL);
|
prio = g_strdup_printf("%s:+ANON-DH", creds->priority);
|
||||||
|
} else {
|
||||||
|
prio = g_strdup(CONFIG_TLS_PRIORITY ":+ANON-DH");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gnutls_priority_set_direct(session->handle, prio, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Unable to set TLS session priority: %s",
|
error_setg(errp, "Unable to set TLS session priority %s: %s",
|
||||||
gnutls_strerror(ret));
|
prio, gnutls_strerror(ret));
|
||||||
|
g_free(prio);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
g_free(prio);
|
||||||
if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||||
ret = gnutls_credentials_set(session->handle,
|
ret = gnutls_credentials_set(session->handle,
|
||||||
GNUTLS_CRD_ANON,
|
GNUTLS_CRD_ANON,
|
||||||
@@ -157,11 +165,15 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
|||||||
} else if (object_dynamic_cast(OBJECT(creds),
|
} else if (object_dynamic_cast(OBJECT(creds),
|
||||||
TYPE_QCRYPTO_TLS_CREDS_X509)) {
|
TYPE_QCRYPTO_TLS_CREDS_X509)) {
|
||||||
QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds);
|
QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds);
|
||||||
|
const char *prio = creds->priority;
|
||||||
|
if (!prio) {
|
||||||
|
prio = CONFIG_TLS_PRIORITY;
|
||||||
|
}
|
||||||
|
|
||||||
ret = gnutls_set_default_priority(session->handle);
|
ret = gnutls_priority_set_direct(session->handle, prio, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Cannot set default TLS session priority: %s",
|
error_setg(errp, "Cannot set default TLS session priority %s: %s",
|
||||||
gnutls_strerror(ret));
|
prio, gnutls_strerror(ret));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
ret = gnutls_credentials_set(session->handle,
|
ret = gnutls_credentials_set(session->handle,
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ CONFIG_PXA2XX=y
|
|||||||
CONFIG_BITBANG_I2C=y
|
CONFIG_BITBANG_I2C=y
|
||||||
CONFIG_FRAMEBUFFER=y
|
CONFIG_FRAMEBUFFER=y
|
||||||
CONFIG_XILINX_SPIPS=y
|
CONFIG_XILINX_SPIPS=y
|
||||||
|
CONFIG_ZYNQ_DEVCFG=y
|
||||||
|
|
||||||
CONFIG_ARM11SCU=y
|
CONFIG_ARM11SCU=y
|
||||||
CONFIG_A9SCU=y
|
CONFIG_A9SCU=y
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ CONFIG_ETSEC=y
|
|||||||
CONFIG_LIBDECNUMBER=y
|
CONFIG_LIBDECNUMBER=y
|
||||||
# For pSeries
|
# For pSeries
|
||||||
CONFIG_XICS=$(CONFIG_PSERIES)
|
CONFIG_XICS=$(CONFIG_PSERIES)
|
||||||
|
CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
|
||||||
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||||
# For PReP
|
# For PReP
|
||||||
CONFIG_MC146818RTC=y
|
CONFIG_MC146818RTC=y
|
||||||
|
|||||||
@@ -185,10 +185,17 @@ static void dma_aio_cancel(BlockAIOCB *acb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AioContext *dma_get_aio_context(BlockAIOCB *acb)
|
||||||
|
{
|
||||||
|
DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
|
||||||
|
|
||||||
|
return dbs->ctx;
|
||||||
|
}
|
||||||
|
|
||||||
static const AIOCBInfo dma_aiocb_info = {
|
static const AIOCBInfo dma_aiocb_info = {
|
||||||
.aiocb_size = sizeof(DMAAIOCB),
|
.aiocb_size = sizeof(DMAAIOCB),
|
||||||
.cancel_async = dma_aio_cancel,
|
.cancel_async = dma_aio_cancel,
|
||||||
|
.get_aio_context = dma_get_aio_context,
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockAIOCB *dma_blk_io(AioContext *ctx,
|
BlockAIOCB *dma_blk_io(AioContext *ctx,
|
||||||
|
|||||||
@@ -41,8 +41,13 @@ MemoryRegion):
|
|||||||
MemoryRegionOps structure describing the callbacks.
|
MemoryRegionOps structure describing the callbacks.
|
||||||
|
|
||||||
- ROM: a ROM memory region works like RAM for reads (directly accessing
|
- ROM: a ROM memory region works like RAM for reads (directly accessing
|
||||||
a region of host memory), but like MMIO for writes (invoking a callback).
|
a region of host memory), and forbids writes. You initialize these with
|
||||||
You initialize these with memory_region_init_rom_device().
|
memory_region_init_rom().
|
||||||
|
|
||||||
|
- ROM device: a ROM device memory region works like RAM for reads
|
||||||
|
(directly accessing a region of host memory), but like MMIO for
|
||||||
|
writes (invoking a callback). You initialize these with
|
||||||
|
memory_region_init_rom_device().
|
||||||
|
|
||||||
- IOMMU region: an IOMMU region translates addresses of accesses made to it
|
- IOMMU region: an IOMMU region translates addresses of accesses made to it
|
||||||
and forwards them to some other target memory region. As the name suggests,
|
and forwards them to some other target memory region. As the name suggests,
|
||||||
|
|||||||
@@ -802,32 +802,28 @@ Example:
|
|||||||
|
|
||||||
void qapi_free_UserDefOne(UserDefOne *obj)
|
void qapi_free_UserDefOne(UserDefOne *obj)
|
||||||
{
|
{
|
||||||
QapiDeallocVisitor *qdv;
|
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qdv = qapi_dealloc_visitor_new();
|
v = qapi_dealloc_visitor_new();
|
||||||
v = qapi_dealloc_get_visitor(qdv);
|
|
||||||
visit_type_UserDefOne(v, NULL, &obj, NULL);
|
visit_type_UserDefOne(v, NULL, &obj, NULL);
|
||||||
qapi_dealloc_visitor_cleanup(qdv);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qapi_free_UserDefOneList(UserDefOneList *obj)
|
void qapi_free_UserDefOneList(UserDefOneList *obj)
|
||||||
{
|
{
|
||||||
QapiDeallocVisitor *qdv;
|
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qdv = qapi_dealloc_visitor_new();
|
v = qapi_dealloc_visitor_new();
|
||||||
v = qapi_dealloc_get_visitor(qdv);
|
|
||||||
visit_type_UserDefOneList(v, NULL, &obj, NULL);
|
visit_type_UserDefOneList(v, NULL, &obj, NULL);
|
||||||
qapi_dealloc_visitor_cleanup(qdv);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
=== scripts/qapi-visit.py ===
|
=== scripts/qapi-visit.py ===
|
||||||
@@ -904,7 +900,7 @@ Example:
|
|||||||
}
|
}
|
||||||
visit_check_struct(v, &err);
|
visit_check_struct(v, &err);
|
||||||
out_obj:
|
out_obj:
|
||||||
visit_end_struct(v);
|
visit_end_struct(v, (void **)obj);
|
||||||
if (err && visit_is_input(v)) {
|
if (err && visit_is_input(v)) {
|
||||||
qapi_free_UserDefOne(*obj);
|
qapi_free_UserDefOne(*obj);
|
||||||
*obj = NULL;
|
*obj = NULL;
|
||||||
@@ -932,7 +928,7 @@ Example:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_end_list(v);
|
visit_end_list(v, (void **)obj);
|
||||||
if (err && visit_is_input(v)) {
|
if (err && visit_is_input(v)) {
|
||||||
qapi_free_UserDefOneList(*obj);
|
qapi_free_UserDefOneList(*obj);
|
||||||
*obj = NULL;
|
*obj = NULL;
|
||||||
@@ -984,36 +980,28 @@ Example:
|
|||||||
static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp)
|
static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
QmpOutputVisitor *qov = qmp_output_visitor_new();
|
|
||||||
QapiDeallocVisitor *qdv;
|
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
|
|
||||||
v = qmp_output_get_visitor(qov);
|
v = qmp_output_visitor_new(ret_out);
|
||||||
visit_type_UserDefOne(v, "unused", &ret_in, &err);
|
visit_type_UserDefOne(v, "unused", &ret_in, &err);
|
||||||
if (err) {
|
if (!err) {
|
||||||
goto out;
|
visit_complete(v, ret_out);
|
||||||
}
|
}
|
||||||
*ret_out = qmp_output_get_qobject(qov);
|
|
||||||
|
|
||||||
out:
|
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
qmp_output_visitor_cleanup(qov);
|
visit_free(v);
|
||||||
qdv = qapi_dealloc_visitor_new();
|
v = qapi_dealloc_visitor_new();
|
||||||
v = qapi_dealloc_get_visitor(qdv);
|
|
||||||
visit_type_UserDefOne(v, "unused", &ret_in, NULL);
|
visit_type_UserDefOne(v, "unused", &ret_in, NULL);
|
||||||
qapi_dealloc_visitor_cleanup(qdv);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp)
|
static void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
UserDefOne *retval;
|
UserDefOne *retval;
|
||||||
QmpInputVisitor *qiv = qmp_input_visitor_new(QOBJECT(args), true);
|
|
||||||
QapiDeallocVisitor *qdv;
|
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
UserDefOneList *arg1 = NULL;
|
UserDefOneList *arg1 = NULL;
|
||||||
|
|
||||||
v = qmp_input_get_visitor(qiv);
|
v = qmp_input_visitor_new(QOBJECT(args), true);
|
||||||
visit_start_struct(v, NULL, NULL, 0, &err);
|
visit_start_struct(v, NULL, NULL, 0, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1022,7 +1010,7 @@ Example:
|
|||||||
if (!err) {
|
if (!err) {
|
||||||
visit_check_struct(v, &err);
|
visit_check_struct(v, &err);
|
||||||
}
|
}
|
||||||
visit_end_struct(v);
|
visit_end_struct(v, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -1036,13 +1024,12 @@ Example:
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
qmp_input_visitor_cleanup(qiv);
|
visit_free(v);
|
||||||
qdv = qapi_dealloc_visitor_new();
|
v = qapi_dealloc_visitor_new();
|
||||||
v = qapi_dealloc_get_visitor(qdv);
|
|
||||||
visit_start_struct(v, NULL, NULL, 0, NULL);
|
visit_start_struct(v, NULL, NULL, 0, NULL);
|
||||||
visit_type_UserDefOneList(v, "arg1", &arg1, NULL);
|
visit_type_UserDefOneList(v, "arg1", &arg1, NULL);
|
||||||
visit_end_struct(v);
|
visit_end_struct(v, NULL);
|
||||||
qapi_dealloc_visitor_cleanup(qdv);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmp_init_marshal(void)
|
static void qmp_init_marshal(void)
|
||||||
|
|||||||
@@ -4,21 +4,91 @@ QEMU<->ACPI BIOS CPU hotplug interface
|
|||||||
QEMU supports CPU hotplug via ACPI. This document
|
QEMU supports CPU hotplug via ACPI. This document
|
||||||
describes the interface between QEMU and the ACPI BIOS.
|
describes the interface between QEMU and the ACPI BIOS.
|
||||||
|
|
||||||
ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
|
ACPI BIOS GPE.2 handler is dedicated for notifying OS about CPU hot-add
|
||||||
-----------------------------------------
|
and hot-remove events.
|
||||||
|
|
||||||
Generic ACPI GPE block. Bit 2 (GPE.2) used to notify CPU
|
|
||||||
hot-add/remove event to ACPI BIOS, via SCI interrupt.
|
|
||||||
|
|
||||||
|
============================================
|
||||||
|
Legacy ACPI CPU hotplug interface registers:
|
||||||
|
--------------------------------------------
|
||||||
CPU present bitmap for:
|
CPU present bitmap for:
|
||||||
ICH9-LPC (IO port 0x0cd8-0xcf7, 1-byte access)
|
ICH9-LPC (IO port 0x0cd8-0xcf7, 1-byte access)
|
||||||
PIIX-PM (IO port 0xaf00-0xaf1f, 1-byte access)
|
PIIX-PM (IO port 0xaf00-0xaf1f, 1-byte access)
|
||||||
|
One bit per CPU. Bit position reflects corresponding CPU APIC ID. Read-only.
|
||||||
|
The first DWORD in bitmap is used in write mode to switch from legacy
|
||||||
|
to new CPU hotplug interface, write 0 into it to do switch.
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
One bit per CPU. Bit position reflects corresponding CPU APIC ID.
|
QEMU sets corresponding CPU bit on hot-add event and issues SCI
|
||||||
Read-only.
|
with GPE.2 event set. CPU present map is read by ACPI BIOS GPE.2 handler
|
||||||
|
to notify OS about CPU hot-add events. CPU hot-remove isn't supported.
|
||||||
|
|
||||||
CPU hot-add/remove notification:
|
=====================================
|
||||||
-----------------------------------------------------
|
ACPI CPU hotplug interface registers:
|
||||||
QEMU sets/clears corresponding CPU bit on hot-add/remove event.
|
-------------------------------------
|
||||||
CPU present map read by ACPI BIOS GPE.2 handler to notify OS of CPU
|
Register block base address:
|
||||||
hot-(un)plug events.
|
ICH9-LPC IO port 0x0cd8
|
||||||
|
PIIX-PM IO port 0xaf00
|
||||||
|
Register block size:
|
||||||
|
ACPI_CPU_HOTPLUG_REG_LEN = 12
|
||||||
|
|
||||||
|
read access:
|
||||||
|
offset:
|
||||||
|
[0x0-0x3] reserved
|
||||||
|
[0x4] CPU device status fields: (1 byte access)
|
||||||
|
bits:
|
||||||
|
0: Device is enabled and may be used by guest
|
||||||
|
1: Device insert event, used to distinguish device for which
|
||||||
|
no device check event to OSPM was issued.
|
||||||
|
It's valid only when bit 0 is set.
|
||||||
|
2: Device remove event, used to distinguish device for which
|
||||||
|
no device eject request to OSPM was issued.
|
||||||
|
3-7: reserved and should be ignored by OSPM
|
||||||
|
[0x5-0x7] reserved
|
||||||
|
[0x8] Command data: (DWORD access)
|
||||||
|
in case of error or unsupported command reads is 0xFFFFFFFF
|
||||||
|
current 'Command field' value:
|
||||||
|
0: returns PXM value corresponding to device
|
||||||
|
|
||||||
|
write access:
|
||||||
|
offset:
|
||||||
|
[0x0-0x3] CPU selector: (DWORD access)
|
||||||
|
selects active CPU device. All following accesses to other
|
||||||
|
registers will read/store data from/to selected CPU.
|
||||||
|
[0x4] CPU device control fields: (1 byte access)
|
||||||
|
bits:
|
||||||
|
0: reserved, OSPM must clear it before writing to register.
|
||||||
|
1: if set to 1 clears device insert event, set by OSPM
|
||||||
|
after it has emitted device check event for the
|
||||||
|
selected CPU device
|
||||||
|
2: if set to 1 clears device remove event, set by OSPM
|
||||||
|
after it has emitted device eject request for the
|
||||||
|
selected CPU device
|
||||||
|
3: if set to 1 initiates device eject, set by OSPM when it
|
||||||
|
triggers CPU device removal and calls _EJ0 method
|
||||||
|
4-7: reserved, OSPM must clear them before writing to register
|
||||||
|
[0x5] Command field: (1 byte access)
|
||||||
|
value:
|
||||||
|
0: selects a CPU device with inserting/removing events and
|
||||||
|
following reads from 'Command data' register return
|
||||||
|
selected CPU (CPU selector value). If no CPU with events
|
||||||
|
found, the current CPU selector doesn't change and
|
||||||
|
corresponding insert/remove event flags are not set.
|
||||||
|
1: following writes to 'Command data' register set OST event
|
||||||
|
register in QEMU
|
||||||
|
2: following writes to 'Command data' register set OST status
|
||||||
|
register in QEMU
|
||||||
|
other values: reserved
|
||||||
|
[0x6-0x7] reserved
|
||||||
|
[0x8] Command data: (DWORD access)
|
||||||
|
current 'Command field' value:
|
||||||
|
0: OSPM reads value of CPU selector
|
||||||
|
1: stores value into OST event register
|
||||||
|
2: stores value into OST status register, triggers
|
||||||
|
ACPI_DEVICE_OST QMP event from QEMU to external applications
|
||||||
|
with current values of OST event and status registers.
|
||||||
|
other values: reserved
|
||||||
|
|
||||||
|
Selecting CPU device beyond possible range has no effect on platform:
|
||||||
|
- write accesses to CPU hot-plug registers not documented above are
|
||||||
|
ignored
|
||||||
|
- read accesses to CPU hot-plug registers not documented above return
|
||||||
|
all bits set to 0.
|
||||||
|
|||||||
132
docs/specs/acpi_nvdimm.txt
Normal file
132
docs/specs/acpi_nvdimm.txt
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
QEMU<->ACPI BIOS NVDIMM interface
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
QEMU supports NVDIMM via ACPI. This document describes the basic concepts of
|
||||||
|
NVDIMM ACPI and the interface between QEMU and the ACPI BIOS.
|
||||||
|
|
||||||
|
NVDIMM ACPI Background
|
||||||
|
----------------------
|
||||||
|
NVDIMM is introduced in ACPI 6.0 which defines an NVDIMM root device under
|
||||||
|
_SB scope with a _HID of “ACPI0012”. For each NVDIMM present or intended
|
||||||
|
to be supported by platform, platform firmware also exposes an ACPI
|
||||||
|
Namespace Device under the root device.
|
||||||
|
|
||||||
|
The NVDIMM child devices under the NVDIMM root device are defined with _ADR
|
||||||
|
corresponding to the NFIT device handle. The NVDIMM root device and the
|
||||||
|
NVDIMM devices can have device specific methods (_DSM) to provide additional
|
||||||
|
functions specific to a particular NVDIMM implementation.
|
||||||
|
|
||||||
|
This is an example from ACPI 6.0, a platform contains one NVDIMM:
|
||||||
|
|
||||||
|
Scope (\_SB){
|
||||||
|
Device (NVDR) // Root device
|
||||||
|
{
|
||||||
|
Name (_HID, “ACPI0012”)
|
||||||
|
Method (_STA) {...}
|
||||||
|
Method (_FIT) {...}
|
||||||
|
Method (_DSM, ...) {...}
|
||||||
|
Device (NVD)
|
||||||
|
{
|
||||||
|
Name(_ADR, h) //where h is NFIT Device Handle for this NVDIMM
|
||||||
|
Method (_DSM, ...) {...}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Method supported on both NVDIMM root device and NVDIMM device
|
||||||
|
_DSM (Device Specific Method)
|
||||||
|
It is a control method that enables devices to provide device specific
|
||||||
|
control functions that are consumed by the device driver.
|
||||||
|
The NVDIMM DSM specification can be found at:
|
||||||
|
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
Arg0 – A Buffer containing a UUID (16 Bytes)
|
||||||
|
Arg1 – An Integer containing the Revision ID (4 Bytes)
|
||||||
|
Arg2 – An Integer containing the Function Index (4 Bytes)
|
||||||
|
Arg3 – A package containing parameters for the function specified by the
|
||||||
|
UUID, Revision ID, and Function Index
|
||||||
|
|
||||||
|
Return Value:
|
||||||
|
If Function Index = 0, a Buffer containing a function index bitfield.
|
||||||
|
Otherwise, the return value and type depends on the UUID, revision ID
|
||||||
|
and function index which are described in the DSM specification.
|
||||||
|
|
||||||
|
Methods on NVDIMM ROOT Device
|
||||||
|
_FIT(Firmware Interface Table)
|
||||||
|
It evaluates to a buffer returning data in the format of a series of NFIT
|
||||||
|
Type Structure.
|
||||||
|
|
||||||
|
Arguments: None
|
||||||
|
|
||||||
|
Return Value:
|
||||||
|
A Buffer containing a list of NFIT Type structure entries.
|
||||||
|
|
||||||
|
The detailed definition of the structure can be found at ACPI 6.0: 5.2.25
|
||||||
|
NVDIMM Firmware Interface Table (NFIT).
|
||||||
|
|
||||||
|
QEMU NVDIMM Implemention
|
||||||
|
========================
|
||||||
|
QEMU uses 4 bytes IO Port starting from 0x0a18 and a RAM-based memory page
|
||||||
|
for NVDIMM ACPI.
|
||||||
|
|
||||||
|
Memory:
|
||||||
|
QEMU uses BIOS Linker/loader feature to ask BIOS to allocate a memory
|
||||||
|
page and dynamically patch its into a int32 object named "MEMA" in ACPI.
|
||||||
|
|
||||||
|
This page is RAM-based and it is used to transfer data between _DSM
|
||||||
|
method and QEMU. If ACPI has control, this pages is owned by ACPI which
|
||||||
|
writes _DSM input data to it, otherwise, it is owned by QEMU which
|
||||||
|
emulates _DSM access and writes the output data to it.
|
||||||
|
|
||||||
|
ACPI writes _DSM Input Data (based on the offset in the page):
|
||||||
|
[0x0 - 0x3]: 4 bytes, NVDIMM Device Handle, 0 is reserved for NVDIMM
|
||||||
|
Root device.
|
||||||
|
[0x4 - 0x7]: 4 bytes, Revision ID, that is the Arg1 of _DSM method.
|
||||||
|
[0x8 - 0xB]: 4 bytes. Function Index, that is the Arg2 of _DSM method.
|
||||||
|
[0xC - 0xFFF]: 4084 bytes, the Arg3 of _DSM method.
|
||||||
|
|
||||||
|
QEMU Writes Output Data (based on the offset in the page):
|
||||||
|
[0x0 - 0x3]: 4 bytes, the length of result
|
||||||
|
[0x4 - 0xFFF]: 4092 bytes, the DSM result filled by QEMU
|
||||||
|
|
||||||
|
IO Port 0x0a18 - 0xa1b:
|
||||||
|
ACPI writes the address of the memory page allocated by BIOS to this
|
||||||
|
port then QEMU gets the control and fills the result in the memory page.
|
||||||
|
|
||||||
|
write Access:
|
||||||
|
[0x0a18 - 0xa1b]: 4 bytes, the address of the memory page allocated
|
||||||
|
by BIOS.
|
||||||
|
|
||||||
|
_DSM process diagram:
|
||||||
|
---------------------
|
||||||
|
"MEMA" indicates the address of memory page allocated by BIOS.
|
||||||
|
|
||||||
|
+----------------------+ +-----------------------+
|
||||||
|
| 1. OSPM | | 2. OSPM |
|
||||||
|
| save _DSM input data | | write "MEMA" to | Exit to QEMU
|
||||||
|
| to the page +----->| IO port 0x0a18 +------------+
|
||||||
|
| indicated by "MEMA" | | | |
|
||||||
|
+----------------------+ +-----------------------+ |
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+------------- ----+ +-----------+ +------------------+--------+
|
||||||
|
| 5 QEMU | | 4 QEMU | | 3. QEMU |
|
||||||
|
| write _DSM result | | emulate | | get _DSM input data from |
|
||||||
|
| to the page +<------+ _DSM +<-----+ the page indicated by the |
|
||||||
|
| | | | | value from the IO port |
|
||||||
|
+--------+-----------+ +-----------+ +---------------------------+
|
||||||
|
|
|
||||||
|
| Enter Guest
|
||||||
|
|
|
||||||
|
v
|
||||||
|
+--------------------------+ +--------------+
|
||||||
|
| 6 OSPM | | 7 OSPM |
|
||||||
|
| result size is returned | | _DSM return |
|
||||||
|
| by reading DSM +----->+ |
|
||||||
|
| result from the page | | |
|
||||||
|
+--------------------------+ +--------------+
|
||||||
|
|
||||||
|
_FIT implementation
|
||||||
|
-------------------
|
||||||
|
TODO (will fill it when nvdimm hotplug is introduced)
|
||||||
File diff suppressed because it is too large
Load Diff
172
fpu/softfloat.c
172
fpu/softfloat.c
@@ -2105,7 +2105,7 @@ static float32 subFloat32Sigs(float32 a, float32 b, flag zSign,
|
|||||||
return propagateFloat32NaN(a, b, status);
|
return propagateFloat32NaN(a, b, status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( aExp == 0 ) {
|
if ( aExp == 0 ) {
|
||||||
aExp = 1;
|
aExp = 1;
|
||||||
@@ -2234,7 +2234,7 @@ float32 float32_mul(float32 a, float32 b, float_status *status)
|
|||||||
}
|
}
|
||||||
if ( ( bExp | bSig ) == 0 ) {
|
if ( ( bExp | bSig ) == 0 ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
return packFloat32( zSign, 0xFF, 0 );
|
return packFloat32( zSign, 0xFF, 0 );
|
||||||
}
|
}
|
||||||
@@ -2244,7 +2244,7 @@ float32 float32_mul(float32 a, float32 b, float_status *status)
|
|||||||
}
|
}
|
||||||
if ( ( aExp | aSig ) == 0 ) {
|
if ( ( aExp | aSig ) == 0 ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
return packFloat32( zSign, 0xFF, 0 );
|
return packFloat32( zSign, 0xFF, 0 );
|
||||||
}
|
}
|
||||||
@@ -2299,7 +2299,7 @@ float32 float32_div(float32 a, float32 b, float_status *status)
|
|||||||
return propagateFloat32NaN(a, b, status);
|
return propagateFloat32NaN(a, b, status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
return packFloat32( zSign, 0xFF, 0 );
|
return packFloat32( zSign, 0xFF, 0 );
|
||||||
}
|
}
|
||||||
@@ -2313,7 +2313,7 @@ float32 float32_div(float32 a, float32 b, float_status *status)
|
|||||||
if ( bSig == 0 ) {
|
if ( bSig == 0 ) {
|
||||||
if ( ( aExp | aSig ) == 0 ) {
|
if ( ( aExp | aSig ) == 0 ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_divbyzero, status);
|
float_raise(float_flag_divbyzero, status);
|
||||||
return packFloat32( zSign, 0xFF, 0 );
|
return packFloat32( zSign, 0xFF, 0 );
|
||||||
@@ -2367,7 +2367,7 @@ float32 float32_rem(float32 a, float32 b, float_status *status)
|
|||||||
return propagateFloat32NaN(a, b, status);
|
return propagateFloat32NaN(a, b, status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( bExp == 0xFF ) {
|
if ( bExp == 0xFF ) {
|
||||||
if (bSig) {
|
if (bSig) {
|
||||||
@@ -2378,7 +2378,7 @@ float32 float32_rem(float32 a, float32 b, float_status *status)
|
|||||||
if ( bExp == 0 ) {
|
if ( bExp == 0 ) {
|
||||||
if ( bSig == 0 ) {
|
if ( bSig == 0 ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
|
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
|
||||||
}
|
}
|
||||||
@@ -2493,7 +2493,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags,
|
|||||||
|
|
||||||
if (infzero) {
|
if (infzero) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & float_muladd_negate_c) {
|
if (flags & float_muladd_negate_c) {
|
||||||
@@ -2514,7 +2514,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags,
|
|||||||
if (pInf && (pSign ^ cSign)) {
|
if (pInf && (pSign ^ cSign)) {
|
||||||
/* addition of opposite-signed infinities => InvalidOperation */
|
/* addition of opposite-signed infinities => InvalidOperation */
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
/* Otherwise generate an infinity of the same sign */
|
/* Otherwise generate an infinity of the same sign */
|
||||||
return packFloat32(cSign ^ signflip, 0xff, 0);
|
return packFloat32(cSign ^ signflip, 0xff, 0);
|
||||||
@@ -2690,12 +2690,12 @@ float32 float32_sqrt(float32 a, float_status *status)
|
|||||||
}
|
}
|
||||||
if ( ! aSign ) return a;
|
if ( ! aSign ) return a;
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( aSign ) {
|
if ( aSign ) {
|
||||||
if ( ( aExp | aSig ) == 0 ) return a;
|
if ( ( aExp | aSig ) == 0 ) return a;
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( aExp == 0 ) {
|
if ( aExp == 0 ) {
|
||||||
if ( aSig == 0 ) return float32_zero;
|
if ( aSig == 0 ) return float32_zero;
|
||||||
@@ -2828,7 +2828,7 @@ float32 float32_log2(float32 a, float_status *status)
|
|||||||
}
|
}
|
||||||
if ( aSign ) {
|
if ( aSign ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float32_default_nan;
|
return float32_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( aExp == 0xFF ) {
|
if ( aExp == 0xFF ) {
|
||||||
if (aSig) {
|
if (aSig) {
|
||||||
@@ -2974,7 +2974,8 @@ int float32_eq_quiet(float32 a, float32 b, float_status *status)
|
|||||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||||
) {
|
) {
|
||||||
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
|
if (float32_is_signaling_nan(a, status)
|
||||||
|
|| float32_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3000,7 +3001,8 @@ int float32_le_quiet(float32 a, float32 b, float_status *status)
|
|||||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||||
) {
|
) {
|
||||||
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
|
if (float32_is_signaling_nan(a, status)
|
||||||
|
|| float32_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3031,7 +3033,8 @@ int float32_lt_quiet(float32 a, float32 b, float_status *status)
|
|||||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||||
) {
|
) {
|
||||||
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
|
if (float32_is_signaling_nan(a, status)
|
||||||
|
|| float32_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3060,7 +3063,8 @@ int float32_unordered_quiet(float32 a, float32 b, float_status *status)
|
|||||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||||
) {
|
) {
|
||||||
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
|
if (float32_is_signaling_nan(a, status)
|
||||||
|
|| float32_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -3896,7 +3900,7 @@ static float64 subFloat64Sigs(float64 a, float64 b, flag zSign,
|
|||||||
return propagateFloat64NaN(a, b, status);
|
return propagateFloat64NaN(a, b, status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( aExp == 0 ) {
|
if ( aExp == 0 ) {
|
||||||
aExp = 1;
|
aExp = 1;
|
||||||
@@ -4023,7 +4027,7 @@ float64 float64_mul(float64 a, float64 b, float_status *status)
|
|||||||
}
|
}
|
||||||
if ( ( bExp | bSig ) == 0 ) {
|
if ( ( bExp | bSig ) == 0 ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
return packFloat64( zSign, 0x7FF, 0 );
|
return packFloat64( zSign, 0x7FF, 0 );
|
||||||
}
|
}
|
||||||
@@ -4033,7 +4037,7 @@ float64 float64_mul(float64 a, float64 b, float_status *status)
|
|||||||
}
|
}
|
||||||
if ( ( aExp | aSig ) == 0 ) {
|
if ( ( aExp | aSig ) == 0 ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
return packFloat64( zSign, 0x7FF, 0 );
|
return packFloat64( zSign, 0x7FF, 0 );
|
||||||
}
|
}
|
||||||
@@ -4090,7 +4094,7 @@ float64 float64_div(float64 a, float64 b, float_status *status)
|
|||||||
return propagateFloat64NaN(a, b, status);
|
return propagateFloat64NaN(a, b, status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
return packFloat64( zSign, 0x7FF, 0 );
|
return packFloat64( zSign, 0x7FF, 0 );
|
||||||
}
|
}
|
||||||
@@ -4104,7 +4108,7 @@ float64 float64_div(float64 a, float64 b, float_status *status)
|
|||||||
if ( bSig == 0 ) {
|
if ( bSig == 0 ) {
|
||||||
if ( ( aExp | aSig ) == 0 ) {
|
if ( ( aExp | aSig ) == 0 ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_divbyzero, status);
|
float_raise(float_flag_divbyzero, status);
|
||||||
return packFloat64( zSign, 0x7FF, 0 );
|
return packFloat64( zSign, 0x7FF, 0 );
|
||||||
@@ -4162,7 +4166,7 @@ float64 float64_rem(float64 a, float64 b, float_status *status)
|
|||||||
return propagateFloat64NaN(a, b, status);
|
return propagateFloat64NaN(a, b, status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( bExp == 0x7FF ) {
|
if ( bExp == 0x7FF ) {
|
||||||
if (bSig) {
|
if (bSig) {
|
||||||
@@ -4173,7 +4177,7 @@ float64 float64_rem(float64 a, float64 b, float_status *status)
|
|||||||
if ( bExp == 0 ) {
|
if ( bExp == 0 ) {
|
||||||
if ( bSig == 0 ) {
|
if ( bSig == 0 ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
normalizeFloat64Subnormal( bSig, &bExp, &bSig );
|
normalizeFloat64Subnormal( bSig, &bExp, &bSig );
|
||||||
}
|
}
|
||||||
@@ -4275,7 +4279,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags,
|
|||||||
|
|
||||||
if (infzero) {
|
if (infzero) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & float_muladd_negate_c) {
|
if (flags & float_muladd_negate_c) {
|
||||||
@@ -4296,7 +4300,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags,
|
|||||||
if (pInf && (pSign ^ cSign)) {
|
if (pInf && (pSign ^ cSign)) {
|
||||||
/* addition of opposite-signed infinities => InvalidOperation */
|
/* addition of opposite-signed infinities => InvalidOperation */
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
/* Otherwise generate an infinity of the same sign */
|
/* Otherwise generate an infinity of the same sign */
|
||||||
return packFloat64(cSign ^ signflip, 0x7ff, 0);
|
return packFloat64(cSign ^ signflip, 0x7ff, 0);
|
||||||
@@ -4494,12 +4498,12 @@ float64 float64_sqrt(float64 a, float_status *status)
|
|||||||
}
|
}
|
||||||
if ( ! aSign ) return a;
|
if ( ! aSign ) return a;
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( aSign ) {
|
if ( aSign ) {
|
||||||
if ( ( aExp | aSig ) == 0 ) return a;
|
if ( ( aExp | aSig ) == 0 ) return a;
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( aExp == 0 ) {
|
if ( aExp == 0 ) {
|
||||||
if ( aSig == 0 ) return float64_zero;
|
if ( aSig == 0 ) return float64_zero;
|
||||||
@@ -4547,7 +4551,7 @@ float64 float64_log2(float64 a, float_status *status)
|
|||||||
}
|
}
|
||||||
if ( aSign ) {
|
if ( aSign ) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
return float64_default_nan;
|
return float64_default_nan(status);
|
||||||
}
|
}
|
||||||
if ( aExp == 0x7FF ) {
|
if ( aExp == 0x7FF ) {
|
||||||
if (aSig) {
|
if (aSig) {
|
||||||
@@ -4694,7 +4698,8 @@ int float64_eq_quiet(float64 a, float64 b, float_status *status)
|
|||||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||||
) {
|
) {
|
||||||
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
|
if (float64_is_signaling_nan(a, status)
|
||||||
|
|| float64_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4722,7 +4727,8 @@ int float64_le_quiet(float64 a, float64 b, float_status *status)
|
|||||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||||
) {
|
) {
|
||||||
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
|
if (float64_is_signaling_nan(a, status)
|
||||||
|
|| float64_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4753,7 +4759,8 @@ int float64_lt_quiet(float64 a, float64 b, float_status *status)
|
|||||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||||
) {
|
) {
|
||||||
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
|
if (float64_is_signaling_nan(a, status)
|
||||||
|
|| float64_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4782,7 +4789,8 @@ int float64_unordered_quiet(float64 a, float64 b, float_status *status)
|
|||||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||||
) {
|
) {
|
||||||
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
|
if (float64_is_signaling_nan(a, status)
|
||||||
|
|| float64_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -5207,7 +5215,6 @@ static floatx80 subFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
|
|||||||
int32_t aExp, bExp, zExp;
|
int32_t aExp, bExp, zExp;
|
||||||
uint64_t aSig, bSig, zSig0, zSig1;
|
uint64_t aSig, bSig, zSig0, zSig1;
|
||||||
int32_t expDiff;
|
int32_t expDiff;
|
||||||
floatx80 z;
|
|
||||||
|
|
||||||
aSig = extractFloatx80Frac( a );
|
aSig = extractFloatx80Frac( a );
|
||||||
aExp = extractFloatx80Exp( a );
|
aExp = extractFloatx80Exp( a );
|
||||||
@@ -5221,9 +5228,7 @@ static floatx80 subFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
|
|||||||
return propagateFloatx80NaN(a, b, status);
|
return propagateFloatx80NaN(a, b, status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = floatx80_default_nan_low;
|
return floatx80_default_nan(status);
|
||||||
z.high = floatx80_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
if ( aExp == 0 ) {
|
if ( aExp == 0 ) {
|
||||||
aExp = 1;
|
aExp = 1;
|
||||||
@@ -5317,7 +5322,6 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status)
|
|||||||
flag aSign, bSign, zSign;
|
flag aSign, bSign, zSign;
|
||||||
int32_t aExp, bExp, zExp;
|
int32_t aExp, bExp, zExp;
|
||||||
uint64_t aSig, bSig, zSig0, zSig1;
|
uint64_t aSig, bSig, zSig0, zSig1;
|
||||||
floatx80 z;
|
|
||||||
|
|
||||||
aSig = extractFloatx80Frac( a );
|
aSig = extractFloatx80Frac( a );
|
||||||
aExp = extractFloatx80Exp( a );
|
aExp = extractFloatx80Exp( a );
|
||||||
@@ -5341,9 +5345,7 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status)
|
|||||||
if ( ( aExp | aSig ) == 0 ) {
|
if ( ( aExp | aSig ) == 0 ) {
|
||||||
invalid:
|
invalid:
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = floatx80_default_nan_low;
|
return floatx80_default_nan(status);
|
||||||
z.high = floatx80_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
|
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
|
||||||
}
|
}
|
||||||
@@ -5377,7 +5379,6 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status)
|
|||||||
int32_t aExp, bExp, zExp;
|
int32_t aExp, bExp, zExp;
|
||||||
uint64_t aSig, bSig, zSig0, zSig1;
|
uint64_t aSig, bSig, zSig0, zSig1;
|
||||||
uint64_t rem0, rem1, rem2, term0, term1, term2;
|
uint64_t rem0, rem1, rem2, term0, term1, term2;
|
||||||
floatx80 z;
|
|
||||||
|
|
||||||
aSig = extractFloatx80Frac( a );
|
aSig = extractFloatx80Frac( a );
|
||||||
aExp = extractFloatx80Exp( a );
|
aExp = extractFloatx80Exp( a );
|
||||||
@@ -5409,9 +5410,7 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status)
|
|||||||
if ( ( aExp | aSig ) == 0 ) {
|
if ( ( aExp | aSig ) == 0 ) {
|
||||||
invalid:
|
invalid:
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = floatx80_default_nan_low;
|
return floatx80_default_nan(status);
|
||||||
z.high = floatx80_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
float_raise(float_flag_divbyzero, status);
|
float_raise(float_flag_divbyzero, status);
|
||||||
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
|
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
|
||||||
@@ -5461,7 +5460,6 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
|
|||||||
int32_t aExp, bExp, expDiff;
|
int32_t aExp, bExp, expDiff;
|
||||||
uint64_t aSig0, aSig1, bSig;
|
uint64_t aSig0, aSig1, bSig;
|
||||||
uint64_t q, term0, term1, alternateASig0, alternateASig1;
|
uint64_t q, term0, term1, alternateASig0, alternateASig1;
|
||||||
floatx80 z;
|
|
||||||
|
|
||||||
aSig0 = extractFloatx80Frac( a );
|
aSig0 = extractFloatx80Frac( a );
|
||||||
aExp = extractFloatx80Exp( a );
|
aExp = extractFloatx80Exp( a );
|
||||||
@@ -5485,9 +5483,7 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
|
|||||||
if ( bSig == 0 ) {
|
if ( bSig == 0 ) {
|
||||||
invalid:
|
invalid:
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = floatx80_default_nan_low;
|
return floatx80_default_nan(status);
|
||||||
z.high = floatx80_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
|
normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
|
||||||
}
|
}
|
||||||
@@ -5559,7 +5555,6 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status)
|
|||||||
int32_t aExp, zExp;
|
int32_t aExp, zExp;
|
||||||
uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0;
|
uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0;
|
||||||
uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
|
uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
|
||||||
floatx80 z;
|
|
||||||
|
|
||||||
aSig0 = extractFloatx80Frac( a );
|
aSig0 = extractFloatx80Frac( a );
|
||||||
aExp = extractFloatx80Exp( a );
|
aExp = extractFloatx80Exp( a );
|
||||||
@@ -5575,9 +5570,7 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status)
|
|||||||
if ( ( aExp | aSig0 ) == 0 ) return a;
|
if ( ( aExp | aSig0 ) == 0 ) return a;
|
||||||
invalid:
|
invalid:
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = floatx80_default_nan_low;
|
return floatx80_default_nan(status);
|
||||||
z.high = floatx80_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
if ( aExp == 0 ) {
|
if ( aExp == 0 ) {
|
||||||
if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 );
|
if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 );
|
||||||
@@ -5745,8 +5738,8 @@ int floatx80_eq_quiet(floatx80 a, floatx80 b, float_status *status)
|
|||||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||||
) {
|
) {
|
||||||
if ( floatx80_is_signaling_nan( a )
|
if (floatx80_is_signaling_nan(a, status)
|
||||||
|| floatx80_is_signaling_nan( b ) ) {
|
|| floatx80_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5776,8 +5769,8 @@ int floatx80_le_quiet(floatx80 a, floatx80 b, float_status *status)
|
|||||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||||
) {
|
) {
|
||||||
if ( floatx80_is_signaling_nan( a )
|
if (floatx80_is_signaling_nan(a, status)
|
||||||
|| floatx80_is_signaling_nan( b ) ) {
|
|| floatx80_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5812,8 +5805,8 @@ int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status)
|
|||||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||||
) {
|
) {
|
||||||
if ( floatx80_is_signaling_nan( a )
|
if (floatx80_is_signaling_nan(a, status)
|
||||||
|| floatx80_is_signaling_nan( b ) ) {
|
|| floatx80_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5845,8 +5838,8 @@ int floatx80_unordered_quiet(floatx80 a, floatx80 b, float_status *status)
|
|||||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||||
) {
|
) {
|
||||||
if ( floatx80_is_signaling_nan( a )
|
if (floatx80_is_signaling_nan(a, status)
|
||||||
|| floatx80_is_signaling_nan( b ) ) {
|
|| floatx80_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -6385,7 +6378,6 @@ static float128 subFloat128Sigs(float128 a, float128 b, flag zSign,
|
|||||||
int32_t aExp, bExp, zExp;
|
int32_t aExp, bExp, zExp;
|
||||||
uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
|
uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
|
||||||
int32_t expDiff;
|
int32_t expDiff;
|
||||||
float128 z;
|
|
||||||
|
|
||||||
aSig1 = extractFloat128Frac1( a );
|
aSig1 = extractFloat128Frac1( a );
|
||||||
aSig0 = extractFloat128Frac0( a );
|
aSig0 = extractFloat128Frac0( a );
|
||||||
@@ -6403,9 +6395,7 @@ static float128 subFloat128Sigs(float128 a, float128 b, flag zSign,
|
|||||||
return propagateFloat128NaN(a, b, status);
|
return propagateFloat128NaN(a, b, status);
|
||||||
}
|
}
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = float128_default_nan_low;
|
return float128_default_nan(status);
|
||||||
z.high = float128_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
if ( aExp == 0 ) {
|
if ( aExp == 0 ) {
|
||||||
aExp = 1;
|
aExp = 1;
|
||||||
@@ -6515,7 +6505,6 @@ float128 float128_mul(float128 a, float128 b, float_status *status)
|
|||||||
flag aSign, bSign, zSign;
|
flag aSign, bSign, zSign;
|
||||||
int32_t aExp, bExp, zExp;
|
int32_t aExp, bExp, zExp;
|
||||||
uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
|
uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
|
||||||
float128 z;
|
|
||||||
|
|
||||||
aSig1 = extractFloat128Frac1( a );
|
aSig1 = extractFloat128Frac1( a );
|
||||||
aSig0 = extractFloat128Frac0( a );
|
aSig0 = extractFloat128Frac0( a );
|
||||||
@@ -6541,9 +6530,7 @@ float128 float128_mul(float128 a, float128 b, float_status *status)
|
|||||||
if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
|
if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
|
||||||
invalid:
|
invalid:
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = float128_default_nan_low;
|
return float128_default_nan(status);
|
||||||
z.high = float128_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
return packFloat128( zSign, 0x7FFF, 0, 0 );
|
return packFloat128( zSign, 0x7FFF, 0, 0 );
|
||||||
}
|
}
|
||||||
@@ -6582,7 +6569,6 @@ float128 float128_div(float128 a, float128 b, float_status *status)
|
|||||||
int32_t aExp, bExp, zExp;
|
int32_t aExp, bExp, zExp;
|
||||||
uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
|
uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
|
||||||
uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
|
uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
|
||||||
float128 z;
|
|
||||||
|
|
||||||
aSig1 = extractFloat128Frac1( a );
|
aSig1 = extractFloat128Frac1( a );
|
||||||
aSig0 = extractFloat128Frac0( a );
|
aSig0 = extractFloat128Frac0( a );
|
||||||
@@ -6616,9 +6602,7 @@ float128 float128_div(float128 a, float128 b, float_status *status)
|
|||||||
if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
|
if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
|
||||||
invalid:
|
invalid:
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = float128_default_nan_low;
|
return float128_default_nan(status);
|
||||||
z.high = float128_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
float_raise(float_flag_divbyzero, status);
|
float_raise(float_flag_divbyzero, status);
|
||||||
return packFloat128( zSign, 0x7FFF, 0, 0 );
|
return packFloat128( zSign, 0x7FFF, 0, 0 );
|
||||||
@@ -6673,7 +6657,6 @@ float128 float128_rem(float128 a, float128 b, float_status *status)
|
|||||||
uint64_t aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
|
uint64_t aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
|
||||||
uint64_t allZero, alternateASig0, alternateASig1, sigMean1;
|
uint64_t allZero, alternateASig0, alternateASig1, sigMean1;
|
||||||
int64_t sigMean0;
|
int64_t sigMean0;
|
||||||
float128 z;
|
|
||||||
|
|
||||||
aSig1 = extractFloat128Frac1( a );
|
aSig1 = extractFloat128Frac1( a );
|
||||||
aSig0 = extractFloat128Frac0( a );
|
aSig0 = extractFloat128Frac0( a );
|
||||||
@@ -6699,9 +6682,7 @@ float128 float128_rem(float128 a, float128 b, float_status *status)
|
|||||||
if ( ( bSig0 | bSig1 ) == 0 ) {
|
if ( ( bSig0 | bSig1 ) == 0 ) {
|
||||||
invalid:
|
invalid:
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = float128_default_nan_low;
|
return float128_default_nan(status);
|
||||||
z.high = float128_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
|
normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
|
||||||
}
|
}
|
||||||
@@ -6782,7 +6763,6 @@ float128 float128_sqrt(float128 a, float_status *status)
|
|||||||
int32_t aExp, zExp;
|
int32_t aExp, zExp;
|
||||||
uint64_t aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
|
uint64_t aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
|
||||||
uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
|
uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
|
||||||
float128 z;
|
|
||||||
|
|
||||||
aSig1 = extractFloat128Frac1( a );
|
aSig1 = extractFloat128Frac1( a );
|
||||||
aSig0 = extractFloat128Frac0( a );
|
aSig0 = extractFloat128Frac0( a );
|
||||||
@@ -6799,9 +6779,7 @@ float128 float128_sqrt(float128 a, float_status *status)
|
|||||||
if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
|
if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
|
||||||
invalid:
|
invalid:
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
z.low = float128_default_nan_low;
|
return float128_default_nan(status);
|
||||||
z.high = float128_default_nan_high;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
if ( aExp == 0 ) {
|
if ( aExp == 0 ) {
|
||||||
if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
|
if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
|
||||||
@@ -6969,8 +6947,8 @@ int float128_eq_quiet(float128 a, float128 b, float_status *status)
|
|||||||
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
|
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
|
||||||
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
|
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
|
||||||
) {
|
) {
|
||||||
if ( float128_is_signaling_nan( a )
|
if (float128_is_signaling_nan(a, status)
|
||||||
|| float128_is_signaling_nan( b ) ) {
|
|| float128_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -7000,8 +6978,8 @@ int float128_le_quiet(float128 a, float128 b, float_status *status)
|
|||||||
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
|
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
|
||||||
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
|
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
|
||||||
) {
|
) {
|
||||||
if ( float128_is_signaling_nan( a )
|
if (float128_is_signaling_nan(a, status)
|
||||||
|| float128_is_signaling_nan( b ) ) {
|
|| float128_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -7036,8 +7014,8 @@ int float128_lt_quiet(float128 a, float128 b, float_status *status)
|
|||||||
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
|
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
|
||||||
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
|
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
|
||||||
) {
|
) {
|
||||||
if ( float128_is_signaling_nan( a )
|
if (float128_is_signaling_nan(a, status)
|
||||||
|| float128_is_signaling_nan( b ) ) {
|
|| float128_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -7070,8 +7048,8 @@ int float128_unordered_quiet(float128 a, float128 b, float_status *status)
|
|||||||
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
|
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
|
||||||
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
|
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
|
||||||
) {
|
) {
|
||||||
if ( float128_is_signaling_nan( a )
|
if (float128_is_signaling_nan(a, status)
|
||||||
|| float128_is_signaling_nan( b ) ) {
|
|| float128_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -7351,8 +7329,8 @@ static inline int float ## s ## _compare_internal(float ## s a, float ## s b,\
|
|||||||
( ( extractFloat ## s ## Exp( b ) == nan_exp ) && \
|
( ( extractFloat ## s ## Exp( b ) == nan_exp ) && \
|
||||||
extractFloat ## s ## Frac( b ) )) { \
|
extractFloat ## s ## Frac( b ) )) { \
|
||||||
if (!is_quiet || \
|
if (!is_quiet || \
|
||||||
float ## s ## _is_signaling_nan( a ) || \
|
float ## s ## _is_signaling_nan(a, status) || \
|
||||||
float ## s ## _is_signaling_nan( b ) ) { \
|
float ## s ## _is_signaling_nan(b, status)) { \
|
||||||
float_raise(float_flag_invalid, status); \
|
float_raise(float_flag_invalid, status); \
|
||||||
} \
|
} \
|
||||||
return float_relation_unordered; \
|
return float_relation_unordered; \
|
||||||
@@ -7401,8 +7379,8 @@ static inline int floatx80_compare_internal(floatx80 a, floatx80 b,
|
|||||||
( ( extractFloatx80Exp( b ) == 0x7fff ) &&
|
( ( extractFloatx80Exp( b ) == 0x7fff ) &&
|
||||||
( extractFloatx80Frac( b )<<1 ) )) {
|
( extractFloatx80Frac( b )<<1 ) )) {
|
||||||
if (!is_quiet ||
|
if (!is_quiet ||
|
||||||
floatx80_is_signaling_nan( a ) ||
|
floatx80_is_signaling_nan(a, status) ||
|
||||||
floatx80_is_signaling_nan( b ) ) {
|
floatx80_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return float_relation_unordered;
|
return float_relation_unordered;
|
||||||
@@ -7447,8 +7425,8 @@ static inline int float128_compare_internal(float128 a, float128 b,
|
|||||||
( ( extractFloat128Exp( b ) == 0x7fff ) &&
|
( ( extractFloat128Exp( b ) == 0x7fff ) &&
|
||||||
( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) {
|
( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) {
|
||||||
if (!is_quiet ||
|
if (!is_quiet ||
|
||||||
float128_is_signaling_nan( a ) ||
|
float128_is_signaling_nan(a, status) ||
|
||||||
float128_is_signaling_nan( b ) ) {
|
float128_is_signaling_nan(b, status)) {
|
||||||
float_raise(float_flag_invalid, status);
|
float_raise(float_flag_invalid, status);
|
||||||
}
|
}
|
||||||
return float_relation_unordered;
|
return float_relation_unordered;
|
||||||
@@ -7508,11 +7486,11 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
|
|||||||
if (float ## s ## _is_any_nan(a) || \
|
if (float ## s ## _is_any_nan(a) || \
|
||||||
float ## s ## _is_any_nan(b)) { \
|
float ## s ## _is_any_nan(b)) { \
|
||||||
if (isieee) { \
|
if (isieee) { \
|
||||||
if (float ## s ## _is_quiet_nan(a) && \
|
if (float ## s ## _is_quiet_nan(a, status) && \
|
||||||
!float ## s ##_is_any_nan(b)) { \
|
!float ## s ##_is_any_nan(b)) { \
|
||||||
return b; \
|
return b; \
|
||||||
} else if (float ## s ## _is_quiet_nan(b) && \
|
} else if (float ## s ## _is_quiet_nan(b, status) && \
|
||||||
!float ## s ## _is_any_nan(a)) { \
|
!float ## s ## _is_any_nan(a)) { \
|
||||||
return a; \
|
return a; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include <glib/gprintf.h>
|
#include <glib/gprintf.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#include <sys/uio.h>
|
|
||||||
|
|
||||||
#include "9p-iov-marshal.h"
|
#include "9p-iov-marshal.h"
|
||||||
#include "qemu/bswap.h"
|
#include "qemu/bswap.h"
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include <glib/gprintf.h>
|
#include <glib/gprintf.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#include <sys/uio.h>
|
|
||||||
|
|
||||||
#include "9p-marshal.h"
|
#include "9p-marshal.h"
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#define _FILEOP_H
|
#define _FILEOP_H
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <sys/vfs.h>
|
#include <sys/vfs.h>
|
||||||
|
|
||||||
#define SM_LOCAL_MODE_BITS 0600
|
#define SM_LOCAL_MODE_BITS 0600
|
||||||
|
|||||||
35
hmp.c
35
hmp.c
@@ -1722,7 +1722,7 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
OptsVisitor *ov;
|
Visitor *v;
|
||||||
Object *obj = NULL;
|
Object *obj = NULL;
|
||||||
|
|
||||||
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
||||||
@@ -1731,9 +1731,9 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ov = opts_visitor_new(opts);
|
v = opts_visitor_new(opts);
|
||||||
obj = user_creatable_add(qdict, opts_get_visitor(ov), &err);
|
obj = user_creatable_add(qdict, v, &err);
|
||||||
opts_visitor_cleanup(ov);
|
visit_free(v);
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -1983,15 +1983,14 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
|
|||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
MemdevList *memdev_list = qmp_query_memdev(&err);
|
MemdevList *memdev_list = qmp_query_memdev(&err);
|
||||||
MemdevList *m = memdev_list;
|
MemdevList *m = memdev_list;
|
||||||
StringOutputVisitor *ov;
|
Visitor *v;
|
||||||
char *str;
|
char *str;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
|
||||||
while (m) {
|
while (m) {
|
||||||
ov = string_output_visitor_new(false);
|
v = string_output_visitor_new(false, &str);
|
||||||
visit_type_uint16List(string_output_get_visitor(ov), NULL,
|
visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL);
|
||||||
&m->value->host_nodes, NULL);
|
|
||||||
monitor_printf(mon, "memory backend: %d\n", i);
|
monitor_printf(mon, "memory backend: %d\n", i);
|
||||||
monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
|
monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
|
||||||
monitor_printf(mon, " merge: %s\n",
|
monitor_printf(mon, " merge: %s\n",
|
||||||
@@ -2002,11 +2001,11 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
|
|||||||
m->value->prealloc ? "true" : "false");
|
m->value->prealloc ? "true" : "false");
|
||||||
monitor_printf(mon, " policy: %s\n",
|
monitor_printf(mon, " policy: %s\n",
|
||||||
HostMemPolicy_lookup[m->value->policy]);
|
HostMemPolicy_lookup[m->value->policy]);
|
||||||
str = string_output_get_string(ov);
|
visit_complete(v, &str);
|
||||||
monitor_printf(mon, " host nodes: %s\n", str);
|
monitor_printf(mon, " host nodes: %s\n", str);
|
||||||
|
|
||||||
g_free(str);
|
g_free(str);
|
||||||
string_output_visitor_cleanup(ov);
|
visit_free(v);
|
||||||
m = m->next;
|
m = m->next;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@@ -2457,17 +2456,17 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict)
|
|||||||
|
|
||||||
c = l->value->props;
|
c = l->value->props;
|
||||||
monitor_printf(mon, " CPUInstance Properties:\n");
|
monitor_printf(mon, " CPUInstance Properties:\n");
|
||||||
if (c->has_node) {
|
if (c->has_node_id) {
|
||||||
monitor_printf(mon, " node: \"%" PRIu64 "\"\n", c->node);
|
monitor_printf(mon, " node-id: \"%" PRIu64 "\"\n", c->node_id);
|
||||||
}
|
}
|
||||||
if (c->has_socket) {
|
if (c->has_socket_id) {
|
||||||
monitor_printf(mon, " socket: \"%" PRIu64 "\"\n", c->socket);
|
monitor_printf(mon, " socket-id: \"%" PRIu64 "\"\n", c->socket_id);
|
||||||
}
|
}
|
||||||
if (c->has_core) {
|
if (c->has_core_id) {
|
||||||
monitor_printf(mon, " core: \"%" PRIu64 "\"\n", c->core);
|
monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id);
|
||||||
}
|
}
|
||||||
if (c->has_thread) {
|
if (c->has_thread_id) {
|
||||||
monitor_printf(mon, " thread: \"%" PRIu64 "\"\n", c->thread);
|
monitor_printf(mon, " thread-id: \"%" PRIu64 "\"\n", c->thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
l = l->next;
|
l = l->next;
|
||||||
|
|||||||
@@ -21,19 +21,19 @@
|
|||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
|
|
||||||
/* Root node for synth file system */
|
/* Root node for synth file system */
|
||||||
static V9fsSynthNode v9fs_synth_root = {
|
static V9fsSynthNode synth_root = {
|
||||||
.name = "/",
|
.name = "/",
|
||||||
.actual_attr = {
|
.actual_attr = {
|
||||||
.mode = 0555 | S_IFDIR,
|
.mode = 0555 | S_IFDIR,
|
||||||
.nlink = 1,
|
.nlink = 1,
|
||||||
},
|
},
|
||||||
.attr = &v9fs_synth_root.actual_attr,
|
.attr = &synth_root.actual_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
static QemuMutex v9fs_synth_mutex;
|
static QemuMutex synth_mutex;
|
||||||
static int v9fs_synth_node_count;
|
static int synth_node_count;
|
||||||
/* set to 1 when the synth fs is ready */
|
/* set to 1 when the synth fs is ready */
|
||||||
static int v9fs_synth_fs;
|
static int synth_fs;
|
||||||
|
|
||||||
static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
|
static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
|
||||||
const char *name,
|
const char *name,
|
||||||
@@ -69,16 +69,16 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
|
|||||||
int ret;
|
int ret;
|
||||||
V9fsSynthNode *node, *tmp;
|
V9fsSynthNode *node, *tmp;
|
||||||
|
|
||||||
if (!v9fs_synth_fs) {
|
if (!synth_fs) {
|
||||||
return EAGAIN;
|
return EAGAIN;
|
||||||
}
|
}
|
||||||
if (!name || (strlen(name) >= NAME_MAX)) {
|
if (!name || (strlen(name) >= NAME_MAX)) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
parent = &v9fs_synth_root;
|
parent = &synth_root;
|
||||||
}
|
}
|
||||||
qemu_mutex_lock(&v9fs_synth_mutex);
|
qemu_mutex_lock(&synth_mutex);
|
||||||
QLIST_FOREACH(tmp, &parent->child, sibling) {
|
QLIST_FOREACH(tmp, &parent->child, sibling) {
|
||||||
if (!strcmp(tmp->name, name)) {
|
if (!strcmp(tmp->name, name)) {
|
||||||
ret = EEXIST;
|
ret = EEXIST;
|
||||||
@@ -86,7 +86,7 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Add the name */
|
/* Add the name */
|
||||||
node = v9fs_add_dir_node(parent, mode, name, NULL, v9fs_synth_node_count++);
|
node = v9fs_add_dir_node(parent, mode, name, NULL, synth_node_count++);
|
||||||
v9fs_add_dir_node(node, parent->attr->mode, "..",
|
v9fs_add_dir_node(node, parent->attr->mode, "..",
|
||||||
parent->attr, parent->attr->inode);
|
parent->attr, parent->attr->inode);
|
||||||
v9fs_add_dir_node(node, node->attr->mode, ".",
|
v9fs_add_dir_node(node, node->attr->mode, ".",
|
||||||
@@ -94,7 +94,7 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
|
|||||||
*result = node;
|
*result = node;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
err_out:
|
err_out:
|
||||||
qemu_mutex_unlock(&v9fs_synth_mutex);
|
qemu_mutex_unlock(&synth_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,17 +105,17 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
|
|||||||
int ret;
|
int ret;
|
||||||
V9fsSynthNode *node, *tmp;
|
V9fsSynthNode *node, *tmp;
|
||||||
|
|
||||||
if (!v9fs_synth_fs) {
|
if (!synth_fs) {
|
||||||
return EAGAIN;
|
return EAGAIN;
|
||||||
}
|
}
|
||||||
if (!name || (strlen(name) >= NAME_MAX)) {
|
if (!name || (strlen(name) >= NAME_MAX)) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
parent = &v9fs_synth_root;
|
parent = &synth_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_mutex_lock(&v9fs_synth_mutex);
|
qemu_mutex_lock(&synth_mutex);
|
||||||
QLIST_FOREACH(tmp, &parent->child, sibling) {
|
QLIST_FOREACH(tmp, &parent->child, sibling) {
|
||||||
if (!strcmp(tmp->name, name)) {
|
if (!strcmp(tmp->name, name)) {
|
||||||
ret = EEXIST;
|
ret = EEXIST;
|
||||||
@@ -126,7 +126,7 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
|
|||||||
mode = ((mode & 0777) | S_IFREG);
|
mode = ((mode & 0777) | S_IFREG);
|
||||||
node = g_malloc0(sizeof(V9fsSynthNode));
|
node = g_malloc0(sizeof(V9fsSynthNode));
|
||||||
node->attr = &node->actual_attr;
|
node->attr = &node->actual_attr;
|
||||||
node->attr->inode = v9fs_synth_node_count++;
|
node->attr->inode = synth_node_count++;
|
||||||
node->attr->nlink = 1;
|
node->attr->nlink = 1;
|
||||||
node->attr->read = read;
|
node->attr->read = read;
|
||||||
node->attr->write = write;
|
node->attr->write = write;
|
||||||
@@ -136,11 +136,11 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
|
|||||||
QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
|
QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
err_out:
|
err_out:
|
||||||
qemu_mutex_unlock(&v9fs_synth_mutex);
|
qemu_mutex_unlock(&synth_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
|
static void synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
|
||||||
{
|
{
|
||||||
stbuf->st_dev = 0;
|
stbuf->st_dev = 0;
|
||||||
stbuf->st_ino = node->attr->inode;
|
stbuf->st_ino = node->attr->inode;
|
||||||
@@ -157,24 +157,24 @@ static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
|
|||||||
stbuf->st_ctime = 0;
|
stbuf->st_ctime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_lstat(FsContext *fs_ctx,
|
static int synth_lstat(FsContext *fs_ctx,
|
||||||
V9fsPath *fs_path, struct stat *stbuf)
|
V9fsPath *fs_path, struct stat *stbuf)
|
||||||
{
|
{
|
||||||
V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
|
V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
|
||||||
|
|
||||||
v9fs_synth_fill_statbuf(node, stbuf);
|
synth_fill_statbuf(node, stbuf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_fstat(FsContext *fs_ctx, int fid_type,
|
static int synth_fstat(FsContext *fs_ctx, int fid_type,
|
||||||
V9fsFidOpenState *fs, struct stat *stbuf)
|
V9fsFidOpenState *fs, struct stat *stbuf)
|
||||||
{
|
{
|
||||||
V9fsSynthOpenState *synth_open = fs->private;
|
V9fsSynthOpenState *synth_open = fs->private;
|
||||||
v9fs_synth_fill_statbuf(synth_open->node, stbuf);
|
synth_fill_statbuf(synth_open->node, stbuf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_opendir(FsContext *ctx,
|
static int synth_opendir(FsContext *ctx,
|
||||||
V9fsPath *fs_path, V9fsFidOpenState *fs)
|
V9fsPath *fs_path, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
V9fsSynthOpenState *synth_open;
|
V9fsSynthOpenState *synth_open;
|
||||||
@@ -187,7 +187,7 @@ static int v9fs_synth_opendir(FsContext *ctx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
|
static int synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
V9fsSynthOpenState *synth_open = fs->private;
|
V9fsSynthOpenState *synth_open = fs->private;
|
||||||
V9fsSynthNode *node = synth_open->node;
|
V9fsSynthNode *node = synth_open->node;
|
||||||
@@ -198,24 +198,24 @@ static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static off_t v9fs_synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
|
static off_t synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
V9fsSynthOpenState *synth_open = fs->private;
|
V9fsSynthOpenState *synth_open = fs->private;
|
||||||
return synth_open->offset;
|
return synth_open->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void v9fs_synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
|
static void synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
|
||||||
{
|
{
|
||||||
V9fsSynthOpenState *synth_open = fs->private;
|
V9fsSynthOpenState *synth_open = fs->private;
|
||||||
synth_open->offset = off;
|
synth_open->offset = off;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
|
static void synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
v9fs_synth_seekdir(ctx, fs, 0);
|
synth_seekdir(ctx, fs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void v9fs_synth_direntry(V9fsSynthNode *node,
|
static void synth_direntry(V9fsSynthNode *node,
|
||||||
struct dirent *entry, off_t off)
|
struct dirent *entry, off_t off)
|
||||||
{
|
{
|
||||||
strcpy(entry->d_name, node->name);
|
strcpy(entry->d_name, node->name);
|
||||||
@@ -223,7 +223,7 @@ static void v9fs_synth_direntry(V9fsSynthNode *node,
|
|||||||
entry->d_off = off + 1;
|
entry->d_off = off + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dirent *v9fs_synth_get_dentry(V9fsSynthNode *dir,
|
static struct dirent *synth_get_dentry(V9fsSynthNode *dir,
|
||||||
struct dirent *entry, off_t off)
|
struct dirent *entry, off_t off)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -242,23 +242,23 @@ static struct dirent *v9fs_synth_get_dentry(V9fsSynthNode *dir,
|
|||||||
/* end of directory */
|
/* end of directory */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
v9fs_synth_direntry(node, entry, off);
|
synth_direntry(node, entry, off);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dirent *v9fs_synth_readdir(FsContext *ctx, V9fsFidOpenState *fs)
|
static struct dirent *synth_readdir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
V9fsSynthOpenState *synth_open = fs->private;
|
V9fsSynthOpenState *synth_open = fs->private;
|
||||||
V9fsSynthNode *node = synth_open->node;
|
V9fsSynthNode *node = synth_open->node;
|
||||||
entry = v9fs_synth_get_dentry(node, &synth_open->dent, synth_open->offset);
|
entry = synth_get_dentry(node, &synth_open->dent, synth_open->offset);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
synth_open->offset++;
|
synth_open->offset++;
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path,
|
static int synth_open(FsContext *ctx, V9fsPath *fs_path,
|
||||||
int flags, V9fsFidOpenState *fs)
|
int flags, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
V9fsSynthOpenState *synth_open;
|
V9fsSynthOpenState *synth_open;
|
||||||
@@ -271,7 +271,7 @@ static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
|
static int synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||||
const char *name, int flags,
|
const char *name, int flags,
|
||||||
FsCred *credp, V9fsFidOpenState *fs)
|
FsCred *credp, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
@@ -279,7 +279,7 @@ static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs)
|
static int synth_close(FsContext *ctx, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
V9fsSynthOpenState *synth_open = fs->private;
|
V9fsSynthOpenState *synth_open = fs->private;
|
||||||
V9fsSynthNode *node = synth_open->node;
|
V9fsSynthNode *node = synth_open->node;
|
||||||
@@ -290,7 +290,7 @@ static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
|
static ssize_t synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
int iovcnt, off_t offset)
|
int iovcnt, off_t offset)
|
||||||
{
|
{
|
||||||
@@ -314,7 +314,7 @@ static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
|
static ssize_t synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
int iovcnt, off_t offset)
|
int iovcnt, off_t offset)
|
||||||
{
|
{
|
||||||
@@ -338,112 +338,112 @@ static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
|
static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
|
||||||
{
|
{
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
|
static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_mknod(FsContext *fs_ctx, V9fsPath *path,
|
static int synth_mknod(FsContext *fs_ctx, V9fsPath *path,
|
||||||
const char *buf, FsCred *credp)
|
const char *buf, FsCred *credp)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
|
static int synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
|
||||||
const char *buf, FsCred *credp)
|
const char *buf, FsCred *credp)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t v9fs_synth_readlink(FsContext *fs_ctx, V9fsPath *path,
|
static ssize_t synth_readlink(FsContext *fs_ctx, V9fsPath *path,
|
||||||
char *buf, size_t bufsz)
|
char *buf, size_t bufsz)
|
||||||
{
|
{
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_symlink(FsContext *fs_ctx, const char *oldpath,
|
static int synth_symlink(FsContext *fs_ctx, const char *oldpath,
|
||||||
V9fsPath *newpath, const char *buf, FsCred *credp)
|
V9fsPath *newpath, const char *buf, FsCred *credp)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
|
static int synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
|
||||||
V9fsPath *newpath, const char *buf)
|
V9fsPath *newpath, const char *buf)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_rename(FsContext *ctx, const char *oldpath,
|
static int synth_rename(FsContext *ctx, const char *oldpath,
|
||||||
const char *newpath)
|
const char *newpath)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
|
static int synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
|
static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
|
||||||
const struct timespec *buf)
|
const struct timespec *buf)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_remove(FsContext *ctx, const char *path)
|
static int synth_remove(FsContext *ctx, const char *path)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_fsync(FsContext *ctx, int fid_type,
|
static int synth_fsync(FsContext *ctx, int fid_type,
|
||||||
V9fsFidOpenState *fs, int datasync)
|
V9fsFidOpenState *fs, int datasync)
|
||||||
{
|
{
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_statfs(FsContext *s, V9fsPath *fs_path,
|
static int synth_statfs(FsContext *s, V9fsPath *fs_path,
|
||||||
struct statfs *stbuf)
|
struct statfs *stbuf)
|
||||||
{
|
{
|
||||||
stbuf->f_type = 0xABCD;
|
stbuf->f_type = 0xABCD;
|
||||||
stbuf->f_bsize = 512;
|
stbuf->f_bsize = 512;
|
||||||
stbuf->f_blocks = 0;
|
stbuf->f_blocks = 0;
|
||||||
stbuf->f_files = v9fs_synth_node_count;
|
stbuf->f_files = synth_node_count;
|
||||||
stbuf->f_namelen = NAME_MAX;
|
stbuf->f_namelen = NAME_MAX;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t v9fs_synth_lgetxattr(FsContext *ctx, V9fsPath *path,
|
static ssize_t synth_lgetxattr(FsContext *ctx, V9fsPath *path,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t v9fs_synth_llistxattr(FsContext *ctx, V9fsPath *path,
|
static ssize_t synth_llistxattr(FsContext *ctx, V9fsPath *path,
|
||||||
void *value, size_t size)
|
void *value, size_t size)
|
||||||
{
|
{
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path,
|
static int synth_lsetxattr(FsContext *ctx, V9fsPath *path,
|
||||||
const char *name, void *value,
|
const char *name, void *value,
|
||||||
size_t size, int flags)
|
size_t size, int flags)
|
||||||
{
|
{
|
||||||
@@ -451,14 +451,14 @@ static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_lremovexattr(FsContext *ctx,
|
static int synth_lremovexattr(FsContext *ctx,
|
||||||
V9fsPath *path, const char *name)
|
V9fsPath *path, const char *name)
|
||||||
{
|
{
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
static int synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
||||||
const char *name, V9fsPath *target)
|
const char *name, V9fsPath *target)
|
||||||
{
|
{
|
||||||
V9fsSynthNode *node;
|
V9fsSynthNode *node;
|
||||||
@@ -471,7 +471,7 @@ static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
|||||||
|
|
||||||
}
|
}
|
||||||
if (!dir_path) {
|
if (!dir_path) {
|
||||||
dir_node = &v9fs_synth_root;
|
dir_node = &synth_root;
|
||||||
} else {
|
} else {
|
||||||
dir_node = *(V9fsSynthNode **)dir_path->data;
|
dir_node = *(V9fsSynthNode **)dir_path->data;
|
||||||
}
|
}
|
||||||
@@ -500,7 +500,7 @@ out:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir,
|
static int synth_renameat(FsContext *ctx, V9fsPath *olddir,
|
||||||
const char *old_name, V9fsPath *newdir,
|
const char *old_name, V9fsPath *newdir,
|
||||||
const char *new_name)
|
const char *new_name)
|
||||||
{
|
{
|
||||||
@@ -508,62 +508,62 @@ static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir,
|
static int synth_unlinkat(FsContext *ctx, V9fsPath *dir,
|
||||||
const char *name, int flags)
|
const char *name, int flags)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_synth_init(FsContext *ctx)
|
static int synth_init(FsContext *ctx)
|
||||||
{
|
{
|
||||||
QLIST_INIT(&v9fs_synth_root.child);
|
QLIST_INIT(&synth_root.child);
|
||||||
qemu_mutex_init(&v9fs_synth_mutex);
|
qemu_mutex_init(&synth_mutex);
|
||||||
|
|
||||||
/* Add "." and ".." entries for root */
|
/* Add "." and ".." entries for root */
|
||||||
v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
|
v9fs_add_dir_node(&synth_root, synth_root.attr->mode,
|
||||||
"..", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
|
"..", synth_root.attr, synth_root.attr->inode);
|
||||||
v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode,
|
v9fs_add_dir_node(&synth_root, synth_root.attr->mode,
|
||||||
".", v9fs_synth_root.attr, v9fs_synth_root.attr->inode);
|
".", synth_root.attr, synth_root.attr->inode);
|
||||||
|
|
||||||
/* Mark the subsystem is ready for use */
|
/* Mark the subsystem is ready for use */
|
||||||
v9fs_synth_fs = 1;
|
synth_fs = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileOperations synth_ops = {
|
FileOperations synth_ops = {
|
||||||
.init = v9fs_synth_init,
|
.init = synth_init,
|
||||||
.lstat = v9fs_synth_lstat,
|
.lstat = synth_lstat,
|
||||||
.readlink = v9fs_synth_readlink,
|
.readlink = synth_readlink,
|
||||||
.close = v9fs_synth_close,
|
.close = synth_close,
|
||||||
.closedir = v9fs_synth_closedir,
|
.closedir = synth_closedir,
|
||||||
.open = v9fs_synth_open,
|
.open = synth_open,
|
||||||
.opendir = v9fs_synth_opendir,
|
.opendir = synth_opendir,
|
||||||
.rewinddir = v9fs_synth_rewinddir,
|
.rewinddir = synth_rewinddir,
|
||||||
.telldir = v9fs_synth_telldir,
|
.telldir = synth_telldir,
|
||||||
.readdir = v9fs_synth_readdir,
|
.readdir = synth_readdir,
|
||||||
.seekdir = v9fs_synth_seekdir,
|
.seekdir = synth_seekdir,
|
||||||
.preadv = v9fs_synth_preadv,
|
.preadv = synth_preadv,
|
||||||
.pwritev = v9fs_synth_pwritev,
|
.pwritev = synth_pwritev,
|
||||||
.chmod = v9fs_synth_chmod,
|
.chmod = synth_chmod,
|
||||||
.mknod = v9fs_synth_mknod,
|
.mknod = synth_mknod,
|
||||||
.mkdir = v9fs_synth_mkdir,
|
.mkdir = synth_mkdir,
|
||||||
.fstat = v9fs_synth_fstat,
|
.fstat = synth_fstat,
|
||||||
.open2 = v9fs_synth_open2,
|
.open2 = synth_open2,
|
||||||
.symlink = v9fs_synth_symlink,
|
.symlink = synth_symlink,
|
||||||
.link = v9fs_synth_link,
|
.link = synth_link,
|
||||||
.truncate = v9fs_synth_truncate,
|
.truncate = synth_truncate,
|
||||||
.rename = v9fs_synth_rename,
|
.rename = synth_rename,
|
||||||
.chown = v9fs_synth_chown,
|
.chown = synth_chown,
|
||||||
.utimensat = v9fs_synth_utimensat,
|
.utimensat = synth_utimensat,
|
||||||
.remove = v9fs_synth_remove,
|
.remove = synth_remove,
|
||||||
.fsync = v9fs_synth_fsync,
|
.fsync = synth_fsync,
|
||||||
.statfs = v9fs_synth_statfs,
|
.statfs = synth_statfs,
|
||||||
.lgetxattr = v9fs_synth_lgetxattr,
|
.lgetxattr = synth_lgetxattr,
|
||||||
.llistxattr = v9fs_synth_llistxattr,
|
.llistxattr = synth_llistxattr,
|
||||||
.lsetxattr = v9fs_synth_lsetxattr,
|
.lsetxattr = synth_lsetxattr,
|
||||||
.lremovexattr = v9fs_synth_lremovexattr,
|
.lremovexattr = synth_lremovexattr,
|
||||||
.name_to_path = v9fs_synth_name_to_path,
|
.name_to_path = synth_name_to_path,
|
||||||
.renameat = v9fs_synth_renameat,
|
.renameat = synth_renameat,
|
||||||
.unlinkat = v9fs_synth_unlinkat,
|
.unlinkat = synth_unlinkat,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o
|
|||||||
common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
|
common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
|
||||||
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
|
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
|
||||||
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o
|
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o
|
||||||
|
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
|
||||||
obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
|
obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
|
||||||
common-obj-$(CONFIG_ACPI) += acpi_interface.o
|
common-obj-$(CONFIG_ACPI) += acpi_interface.o
|
||||||
common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
|
common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
|
||||||
common-obj-$(CONFIG_ACPI) += aml-build.o
|
common-obj-$(CONFIG_ACPI) += aml-build.o
|
||||||
|
common-obj-$(call land,$(CONFIG_ACPI),$(CONFIG_IPMI)) += ipmi.o
|
||||||
|
|||||||
@@ -660,6 +660,20 @@ Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4)
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* helper to call method with 5 arguments */
|
||||||
|
Aml *aml_call5(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4,
|
||||||
|
Aml *arg5)
|
||||||
|
{
|
||||||
|
Aml *var = aml_alloc();
|
||||||
|
build_append_namestring(var->buf, "%s", method);
|
||||||
|
aml_append(var, arg1);
|
||||||
|
aml_append(var, arg2);
|
||||||
|
aml_append(var, arg3);
|
||||||
|
aml_append(var, arg4);
|
||||||
|
aml_append(var, arg5);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor
|
* ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor
|
||||||
* Type 1, Large Item Name 0xC
|
* Type 1, Large Item Name 0xC
|
||||||
@@ -1481,6 +1495,14 @@ Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target)
|
|||||||
target);
|
target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefObjectType */
|
||||||
|
Aml *aml_object_type(Aml *object)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x8E /* ObjectTypeOp */);
|
||||||
|
aml_append(var, object);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
build_header(BIOSLinker *linker, GArray *table_data,
|
build_header(BIOSLinker *linker, GArray *table_data,
|
||||||
AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
|
AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
|
||||||
|
|||||||
@@ -239,11 +239,11 @@ void acpi_table_add(const QemuOpts *opts, Error **errp)
|
|||||||
char unsigned *blob = NULL;
|
char unsigned *blob = NULL;
|
||||||
|
|
||||||
{
|
{
|
||||||
OptsVisitor *ov;
|
Visitor *v;
|
||||||
|
|
||||||
ov = opts_visitor_new(opts);
|
v = opts_visitor_new(opts);
|
||||||
visit_type_AcpiTableOptions(opts_get_visitor(ov), NULL, &hdrs, &err);
|
visit_type_AcpiTableOptions(v, NULL, &hdrs, &err);
|
||||||
opts_visitor_cleanup(ov);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
561
hw/acpi/cpu.c
Normal file
561
hw/acpi/cpu.c
Normal file
@@ -0,0 +1,561 @@
|
|||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/boards.h"
|
||||||
|
#include "hw/acpi/cpu.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qapi-event.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
#define ACPI_CPU_HOTPLUG_REG_LEN 12
|
||||||
|
#define ACPI_CPU_SELECTOR_OFFSET_WR 0
|
||||||
|
#define ACPI_CPU_FLAGS_OFFSET_RW 4
|
||||||
|
#define ACPI_CPU_CMD_OFFSET_WR 5
|
||||||
|
#define ACPI_CPU_CMD_DATA_OFFSET_RW 8
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CPHP_GET_NEXT_CPU_WITH_EVENT_CMD = 0,
|
||||||
|
CPHP_OST_EVENT_CMD = 1,
|
||||||
|
CPHP_OST_STATUS_CMD = 2,
|
||||||
|
CPHP_CMD_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
static ACPIOSTInfo *acpi_cpu_device_status(int idx, AcpiCpuStatus *cdev)
|
||||||
|
{
|
||||||
|
ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1);
|
||||||
|
|
||||||
|
info->slot_type = ACPI_SLOT_TYPE_CPU;
|
||||||
|
info->slot = g_strdup_printf("%d", idx);
|
||||||
|
info->source = cdev->ost_event;
|
||||||
|
info->status = cdev->ost_status;
|
||||||
|
if (cdev->cpu) {
|
||||||
|
DeviceState *dev = DEVICE(cdev->cpu);
|
||||||
|
if (dev->id) {
|
||||||
|
info->device = g_strdup(dev->id);
|
||||||
|
info->has_device = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cpu_st->dev_count; i++) {
|
||||||
|
ACPIOSTInfoList *elem = g_new0(ACPIOSTInfoList, 1);
|
||||||
|
elem->value = acpi_cpu_device_status(i, &cpu_st->devs[i]);
|
||||||
|
elem->next = NULL;
|
||||||
|
**list = elem;
|
||||||
|
*list = &elem->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
|
||||||
|
{
|
||||||
|
uint64_t val = 0;
|
||||||
|
CPUHotplugState *cpu_st = opaque;
|
||||||
|
AcpiCpuStatus *cdev;
|
||||||
|
|
||||||
|
if (cpu_st->selector >= cpu_st->dev_count) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdev = &cpu_st->devs[cpu_st->selector];
|
||||||
|
switch (addr) {
|
||||||
|
case ACPI_CPU_FLAGS_OFFSET_RW: /* pack and return is_* fields */
|
||||||
|
val |= cdev->cpu ? 1 : 0;
|
||||||
|
val |= cdev->is_inserting ? 2 : 0;
|
||||||
|
val |= cdev->is_removing ? 4 : 0;
|
||||||
|
trace_cpuhp_acpi_read_flags(cpu_st->selector, val);
|
||||||
|
break;
|
||||||
|
case ACPI_CPU_CMD_DATA_OFFSET_RW:
|
||||||
|
switch (cpu_st->command) {
|
||||||
|
case CPHP_GET_NEXT_CPU_WITH_EVENT_CMD:
|
||||||
|
val = cpu_st->selector;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
trace_cpuhp_acpi_read_cmd_data(cpu_st->selector, val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
CPUHotplugState *cpu_st = opaque;
|
||||||
|
AcpiCpuStatus *cdev;
|
||||||
|
ACPIOSTInfo *info;
|
||||||
|
|
||||||
|
assert(cpu_st->dev_count);
|
||||||
|
|
||||||
|
if (addr) {
|
||||||
|
if (cpu_st->selector >= cpu_st->dev_count) {
|
||||||
|
trace_cpuhp_acpi_invalid_idx_selected(cpu_st->selector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case ACPI_CPU_SELECTOR_OFFSET_WR: /* current CPU selector */
|
||||||
|
cpu_st->selector = data;
|
||||||
|
trace_cpuhp_acpi_write_idx(cpu_st->selector);
|
||||||
|
break;
|
||||||
|
case ACPI_CPU_FLAGS_OFFSET_RW: /* set is_* fields */
|
||||||
|
cdev = &cpu_st->devs[cpu_st->selector];
|
||||||
|
if (data & 2) { /* clear insert event */
|
||||||
|
cdev->is_inserting = false;
|
||||||
|
trace_cpuhp_acpi_clear_inserting_evt(cpu_st->selector);
|
||||||
|
} else if (data & 4) { /* clear remove event */
|
||||||
|
cdev->is_removing = false;
|
||||||
|
trace_cpuhp_acpi_clear_remove_evt(cpu_st->selector);
|
||||||
|
} else if (data & 8) {
|
||||||
|
DeviceState *dev = NULL;
|
||||||
|
HotplugHandler *hotplug_ctrl = NULL;
|
||||||
|
|
||||||
|
if (!cdev->cpu) {
|
||||||
|
trace_cpuhp_acpi_ejecting_invalid_cpu(cpu_st->selector);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_cpuhp_acpi_ejecting_cpu(cpu_st->selector);
|
||||||
|
dev = DEVICE(cdev->cpu);
|
||||||
|
hotplug_ctrl = qdev_get_hotplug_handler(dev);
|
||||||
|
hotplug_handler_unplug(hotplug_ctrl, dev, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACPI_CPU_CMD_OFFSET_WR:
|
||||||
|
trace_cpuhp_acpi_write_cmd(cpu_st->selector, data);
|
||||||
|
if (data < CPHP_CMD_MAX) {
|
||||||
|
cpu_st->command = data;
|
||||||
|
if (cpu_st->command == CPHP_GET_NEXT_CPU_WITH_EVENT_CMD) {
|
||||||
|
uint32_t iter = cpu_st->selector;
|
||||||
|
|
||||||
|
do {
|
||||||
|
cdev = &cpu_st->devs[iter];
|
||||||
|
if (cdev->is_inserting || cdev->is_removing) {
|
||||||
|
cpu_st->selector = iter;
|
||||||
|
trace_cpuhp_acpi_cpu_has_events(cpu_st->selector,
|
||||||
|
cdev->is_inserting, cdev->is_removing);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iter = iter + 1 < cpu_st->dev_count ? iter + 1 : 0;
|
||||||
|
} while (iter != cpu_st->selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACPI_CPU_CMD_DATA_OFFSET_RW:
|
||||||
|
switch (cpu_st->command) {
|
||||||
|
case CPHP_OST_EVENT_CMD: {
|
||||||
|
cdev = &cpu_st->devs[cpu_st->selector];
|
||||||
|
cdev->ost_event = data;
|
||||||
|
trace_cpuhp_acpi_write_ost_ev(cpu_st->selector, cdev->ost_event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CPHP_OST_STATUS_CMD: {
|
||||||
|
cdev = &cpu_st->devs[cpu_st->selector];
|
||||||
|
cdev->ost_status = data;
|
||||||
|
info = acpi_cpu_device_status(cpu_st->selector, cdev);
|
||||||
|
qapi_event_send_acpi_device_ost(info, &error_abort);
|
||||||
|
qapi_free_ACPIOSTInfo(info);
|
||||||
|
trace_cpuhp_acpi_write_ost_status(cpu_st->selector,
|
||||||
|
cdev->ost_status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps cpu_hotplug_ops = {
|
||||||
|
.read = cpu_hotplug_rd,
|
||||||
|
.write = cpu_hotplug_wr,
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
.valid = {
|
||||||
|
.min_access_size = 1,
|
||||||
|
.max_access_size = 4,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
|
||||||
|
CPUHotplugState *state, hwaddr base_addr)
|
||||||
|
{
|
||||||
|
MachineState *machine = MACHINE(qdev_get_machine());
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||||
|
CPUArchIdList *id_list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert(mc->possible_cpu_arch_ids);
|
||||||
|
id_list = mc->possible_cpu_arch_ids(machine);
|
||||||
|
state->dev_count = id_list->len;
|
||||||
|
state->devs = g_new0(typeof(*state->devs), state->dev_count);
|
||||||
|
for (i = 0; i < id_list->len; i++) {
|
||||||
|
state->devs[i].cpu = id_list->cpus[i].cpu;
|
||||||
|
state->devs[i].arch_id = id_list->cpus[i].arch_id;
|
||||||
|
}
|
||||||
|
g_free(id_list);
|
||||||
|
memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state,
|
||||||
|
"acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN);
|
||||||
|
memory_region_add_subregion(as, base_addr, &state->ctrl_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev)
|
||||||
|
{
|
||||||
|
CPUClass *k = CPU_GET_CLASS(dev);
|
||||||
|
uint64_t cpu_arch_id = k->get_arch_id(CPU(dev));
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cpu_st->dev_count; i++) {
|
||||||
|
if (cpu_arch_id == cpu_st->devs[i].arch_id) {
|
||||||
|
return &cpu_st->devs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
|
||||||
|
CPUHotplugState *cpu_st, DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
AcpiCpuStatus *cdev;
|
||||||
|
|
||||||
|
cdev = get_cpu_status(cpu_st, dev);
|
||||||
|
if (!cdev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdev->cpu = CPU(dev);
|
||||||
|
if (dev->hotplugged) {
|
||||||
|
cdev->is_inserting = true;
|
||||||
|
acpi_send_event(DEVICE(hotplug_dev), ACPI_CPU_HOTPLUG_STATUS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||||
|
CPUHotplugState *cpu_st,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
AcpiCpuStatus *cdev;
|
||||||
|
|
||||||
|
cdev = get_cpu_status(cpu_st, dev);
|
||||||
|
if (!cdev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdev->is_removing = true;
|
||||||
|
acpi_send_event(DEVICE(hotplug_dev), ACPI_CPU_HOTPLUG_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
AcpiCpuStatus *cdev;
|
||||||
|
|
||||||
|
cdev = get_cpu_status(cpu_st, dev);
|
||||||
|
if (!cdev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdev->cpu = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_cpuhp_sts = {
|
||||||
|
.name = "CPU hotplug device state",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_BOOL(is_inserting, AcpiCpuStatus),
|
||||||
|
VMSTATE_BOOL(is_removing, AcpiCpuStatus),
|
||||||
|
VMSTATE_UINT32(ost_event, AcpiCpuStatus),
|
||||||
|
VMSTATE_UINT32(ost_status, AcpiCpuStatus),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_cpu_hotplug = {
|
||||||
|
.name = "CPU hotplug state",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(selector, CPUHotplugState),
|
||||||
|
VMSTATE_UINT8(command, CPUHotplugState),
|
||||||
|
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, CPUHotplugState, dev_count,
|
||||||
|
vmstate_cpuhp_sts, AcpiCpuStatus),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CPU_NAME_FMT "C%.03X"
|
||||||
|
#define CPUHP_RES_DEVICE "PRES"
|
||||||
|
#define CPU_LOCK "CPLK"
|
||||||
|
#define CPU_STS_METHOD "CSTA"
|
||||||
|
#define CPU_SCAN_METHOD "CSCN"
|
||||||
|
#define CPU_NOTIFY_METHOD "CTFY"
|
||||||
|
#define CPU_EJECT_METHOD "CEJ0"
|
||||||
|
#define CPU_OST_METHOD "COST"
|
||||||
|
|
||||||
|
#define CPU_ENABLED "CPEN"
|
||||||
|
#define CPU_SELECTOR "CSEL"
|
||||||
|
#define CPU_COMMAND "CCMD"
|
||||||
|
#define CPU_DATA "CDAT"
|
||||||
|
#define CPU_INSERT_EVENT "CINS"
|
||||||
|
#define CPU_REMOVE_EVENT "CRMV"
|
||||||
|
#define CPU_EJECT_EVENT "CEJ0"
|
||||||
|
|
||||||
|
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||||
|
hwaddr io_base,
|
||||||
|
const char *res_root,
|
||||||
|
const char *event_handler_method)
|
||||||
|
{
|
||||||
|
Aml *ifctx;
|
||||||
|
Aml *field;
|
||||||
|
Aml *method;
|
||||||
|
Aml *cpu_ctrl_dev;
|
||||||
|
Aml *cpus_dev;
|
||||||
|
Aml *zero = aml_int(0);
|
||||||
|
Aml *one = aml_int(1);
|
||||||
|
Aml *sb_scope = aml_scope("_SB");
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||||
|
CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
|
||||||
|
char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root);
|
||||||
|
Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
|
||||||
|
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
|
||||||
|
AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);
|
||||||
|
|
||||||
|
cpu_ctrl_dev = aml_device("%s", cphp_res_path);
|
||||||
|
{
|
||||||
|
Aml *crs;
|
||||||
|
|
||||||
|
aml_append(cpu_ctrl_dev,
|
||||||
|
aml_name_decl("_HID", aml_eisaid("PNP0A06")));
|
||||||
|
aml_append(cpu_ctrl_dev,
|
||||||
|
aml_name_decl("_UID", aml_string("CPU Hotplug resources")));
|
||||||
|
aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0));
|
||||||
|
|
||||||
|
crs = aml_resource_template();
|
||||||
|
aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1,
|
||||||
|
ACPI_CPU_HOTPLUG_REG_LEN));
|
||||||
|
aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs));
|
||||||
|
|
||||||
|
/* declare CPU hotplug MMIO region with related access fields */
|
||||||
|
aml_append(cpu_ctrl_dev,
|
||||||
|
aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base),
|
||||||
|
ACPI_CPU_HOTPLUG_REG_LEN));
|
||||||
|
|
||||||
|
field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK,
|
||||||
|
AML_WRITE_AS_ZEROS);
|
||||||
|
aml_append(field, aml_reserved_field(ACPI_CPU_FLAGS_OFFSET_RW * 8));
|
||||||
|
/* 1 if enabled, read only */
|
||||||
|
aml_append(field, aml_named_field(CPU_ENABLED, 1));
|
||||||
|
/* (read) 1 if has a insert event. (write) 1 to clear event */
|
||||||
|
aml_append(field, aml_named_field(CPU_INSERT_EVENT, 1));
|
||||||
|
/* (read) 1 if has a remove event. (write) 1 to clear event */
|
||||||
|
aml_append(field, aml_named_field(CPU_REMOVE_EVENT, 1));
|
||||||
|
/* initiates device eject, write only */
|
||||||
|
aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1));
|
||||||
|
aml_append(field, aml_reserved_field(4));
|
||||||
|
aml_append(field, aml_named_field(CPU_COMMAND, 8));
|
||||||
|
aml_append(cpu_ctrl_dev, field);
|
||||||
|
|
||||||
|
field = aml_field("PRST", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE);
|
||||||
|
/* CPU selector, write only */
|
||||||
|
aml_append(field, aml_named_field(CPU_SELECTOR, 32));
|
||||||
|
/* flags + cmd + 2byte align */
|
||||||
|
aml_append(field, aml_reserved_field(4 * 8));
|
||||||
|
aml_append(field, aml_named_field(CPU_DATA, 32));
|
||||||
|
aml_append(cpu_ctrl_dev, field);
|
||||||
|
|
||||||
|
if (opts.has_legacy_cphp) {
|
||||||
|
method = aml_method("_INI", 0, AML_SERIALIZED);
|
||||||
|
/* switch off legacy CPU hotplug HW and use new one,
|
||||||
|
* on reboot system is in new mode and writing 0
|
||||||
|
* in CPU_SELECTOR selects BSP, which is NOP at
|
||||||
|
* the time _INI is called */
|
||||||
|
aml_append(method, aml_store(zero, aml_name(CPU_SELECTOR)));
|
||||||
|
aml_append(cpu_ctrl_dev, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aml_append(sb_scope, cpu_ctrl_dev);
|
||||||
|
|
||||||
|
cpus_dev = aml_device("\\_SB.CPUS");
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK);
|
||||||
|
Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR);
|
||||||
|
Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED);
|
||||||
|
Aml *cpu_cmd = aml_name("%s.%s", cphp_res_path, CPU_COMMAND);
|
||||||
|
Aml *cpu_data = aml_name("%s.%s", cphp_res_path, CPU_DATA);
|
||||||
|
Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT);
|
||||||
|
Aml *rm_evt = aml_name("%s.%s", cphp_res_path, CPU_REMOVE_EVENT);
|
||||||
|
Aml *ej_evt = aml_name("%s.%s", cphp_res_path, CPU_EJECT_EVENT);
|
||||||
|
|
||||||
|
aml_append(cpus_dev, aml_name_decl("_HID", aml_string("ACPI0010")));
|
||||||
|
aml_append(cpus_dev, aml_name_decl("_CID", aml_eisaid("PNP0A05")));
|
||||||
|
|
||||||
|
method = aml_method(CPU_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
|
||||||
|
for (i = 0; i < arch_ids->len; i++) {
|
||||||
|
Aml *cpu = aml_name(CPU_NAME_FMT, i);
|
||||||
|
Aml *uid = aml_arg(0);
|
||||||
|
Aml *event = aml_arg(1);
|
||||||
|
|
||||||
|
ifctx = aml_if(aml_equal(uid, aml_int(i)));
|
||||||
|
{
|
||||||
|
aml_append(ifctx, aml_notify(cpu, event));
|
||||||
|
}
|
||||||
|
aml_append(method, ifctx);
|
||||||
|
}
|
||||||
|
aml_append(cpus_dev, method);
|
||||||
|
|
||||||
|
method = aml_method(CPU_STS_METHOD, 1, AML_SERIALIZED);
|
||||||
|
{
|
||||||
|
Aml *idx = aml_arg(0);
|
||||||
|
Aml *sta = aml_local(0);
|
||||||
|
|
||||||
|
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||||
|
aml_append(method, aml_store(idx, cpu_selector));
|
||||||
|
aml_append(method, aml_store(zero, sta));
|
||||||
|
ifctx = aml_if(aml_equal(is_enabled, one));
|
||||||
|
{
|
||||||
|
aml_append(ifctx, aml_store(aml_int(0xF), sta));
|
||||||
|
}
|
||||||
|
aml_append(method, ifctx);
|
||||||
|
aml_append(method, aml_release(ctrl_lock));
|
||||||
|
aml_append(method, aml_return(sta));
|
||||||
|
}
|
||||||
|
aml_append(cpus_dev, method);
|
||||||
|
|
||||||
|
method = aml_method(CPU_EJECT_METHOD, 1, AML_SERIALIZED);
|
||||||
|
{
|
||||||
|
Aml *idx = aml_arg(0);
|
||||||
|
|
||||||
|
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||||
|
aml_append(method, aml_store(idx, cpu_selector));
|
||||||
|
aml_append(method, aml_store(one, ej_evt));
|
||||||
|
aml_append(method, aml_release(ctrl_lock));
|
||||||
|
}
|
||||||
|
aml_append(cpus_dev, method);
|
||||||
|
|
||||||
|
method = aml_method(CPU_SCAN_METHOD, 0, AML_SERIALIZED);
|
||||||
|
{
|
||||||
|
Aml *else_ctx;
|
||||||
|
Aml *while_ctx;
|
||||||
|
Aml *has_event = aml_local(0);
|
||||||
|
Aml *dev_chk = aml_int(1);
|
||||||
|
Aml *eject_req = aml_int(3);
|
||||||
|
Aml *next_cpu_cmd = aml_int(CPHP_GET_NEXT_CPU_WITH_EVENT_CMD);
|
||||||
|
|
||||||
|
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||||
|
aml_append(method, aml_store(one, has_event));
|
||||||
|
while_ctx = aml_while(aml_equal(has_event, one));
|
||||||
|
{
|
||||||
|
/* clear loop exit condition, ins_evt/rm_evt checks
|
||||||
|
* will set it to 1 while next_cpu_cmd returns a CPU
|
||||||
|
* with events */
|
||||||
|
aml_append(while_ctx, aml_store(zero, has_event));
|
||||||
|
aml_append(while_ctx, aml_store(next_cpu_cmd, cpu_cmd));
|
||||||
|
ifctx = aml_if(aml_equal(ins_evt, one));
|
||||||
|
{
|
||||||
|
aml_append(ifctx,
|
||||||
|
aml_call2(CPU_NOTIFY_METHOD, cpu_data, dev_chk));
|
||||||
|
aml_append(ifctx, aml_store(one, ins_evt));
|
||||||
|
aml_append(ifctx, aml_store(one, has_event));
|
||||||
|
}
|
||||||
|
aml_append(while_ctx, ifctx);
|
||||||
|
else_ctx = aml_else();
|
||||||
|
ifctx = aml_if(aml_equal(rm_evt, one));
|
||||||
|
{
|
||||||
|
aml_append(ifctx,
|
||||||
|
aml_call2(CPU_NOTIFY_METHOD, cpu_data, eject_req));
|
||||||
|
aml_append(ifctx, aml_store(one, rm_evt));
|
||||||
|
aml_append(ifctx, aml_store(one, has_event));
|
||||||
|
}
|
||||||
|
aml_append(else_ctx, ifctx);
|
||||||
|
aml_append(while_ctx, else_ctx);
|
||||||
|
}
|
||||||
|
aml_append(method, while_ctx);
|
||||||
|
aml_append(method, aml_release(ctrl_lock));
|
||||||
|
}
|
||||||
|
aml_append(cpus_dev, method);
|
||||||
|
|
||||||
|
method = aml_method(CPU_OST_METHOD, 4, AML_SERIALIZED);
|
||||||
|
{
|
||||||
|
Aml *uid = aml_arg(0);
|
||||||
|
Aml *ev_cmd = aml_int(CPHP_OST_EVENT_CMD);
|
||||||
|
Aml *st_cmd = aml_int(CPHP_OST_STATUS_CMD);
|
||||||
|
|
||||||
|
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||||
|
aml_append(method, aml_store(uid, cpu_selector));
|
||||||
|
aml_append(method, aml_store(ev_cmd, cpu_cmd));
|
||||||
|
aml_append(method, aml_store(aml_arg(1), cpu_data));
|
||||||
|
aml_append(method, aml_store(st_cmd, cpu_cmd));
|
||||||
|
aml_append(method, aml_store(aml_arg(2), cpu_data));
|
||||||
|
aml_append(method, aml_release(ctrl_lock));
|
||||||
|
}
|
||||||
|
aml_append(cpus_dev, method);
|
||||||
|
|
||||||
|
/* build Processor object for each processor */
|
||||||
|
for (i = 0; i < arch_ids->len; i++) {
|
||||||
|
Aml *dev;
|
||||||
|
Aml *uid = aml_int(i);
|
||||||
|
GArray *madt_buf = g_array_new(0, 1, 1);
|
||||||
|
int arch_id = arch_ids->cpus[i].arch_id;
|
||||||
|
|
||||||
|
if (opts.apci_1_compatible && arch_id < 255) {
|
||||||
|
dev = aml_processor(i, 0, 0, CPU_NAME_FMT, i);
|
||||||
|
} else {
|
||||||
|
dev = aml_device(CPU_NAME_FMT, i);
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
method = aml_method("_STA", 0, AML_SERIALIZED);
|
||||||
|
aml_append(method, aml_return(aml_call1(CPU_STS_METHOD, uid)));
|
||||||
|
aml_append(dev, method);
|
||||||
|
|
||||||
|
/* build _MAT object */
|
||||||
|
assert(adevc && adevc->madt_cpu);
|
||||||
|
adevc->madt_cpu(adev, i, arch_ids, madt_buf);
|
||||||
|
switch (madt_buf->data[0]) {
|
||||||
|
case ACPI_APIC_PROCESSOR: {
|
||||||
|
AcpiMadtProcessorApic *apic = (void *)madt_buf->data;
|
||||||
|
apic->flags = cpu_to_le32(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
aml_append(dev, aml_name_decl("_MAT",
|
||||||
|
aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data)));
|
||||||
|
g_array_free(madt_buf, true);
|
||||||
|
|
||||||
|
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
|
||||||
|
aml_append(method, aml_call1(CPU_EJECT_METHOD, uid));
|
||||||
|
aml_append(dev, method);
|
||||||
|
|
||||||
|
method = aml_method("_OST", 3, AML_SERIALIZED);
|
||||||
|
aml_append(method,
|
||||||
|
aml_call4(CPU_OST_METHOD, uid, aml_arg(0),
|
||||||
|
aml_arg(1), aml_arg(2))
|
||||||
|
);
|
||||||
|
aml_append(dev, method);
|
||||||
|
aml_append(cpus_dev, dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aml_append(sb_scope, cpus_dev);
|
||||||
|
aml_append(table, sb_scope);
|
||||||
|
|
||||||
|
method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
|
||||||
|
aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD));
|
||||||
|
aml_append(table, method);
|
||||||
|
|
||||||
|
g_free(cphp_res_path);
|
||||||
|
g_free(arch_ids);
|
||||||
|
}
|
||||||
@@ -34,7 +34,15 @@ static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size)
|
|||||||
static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
|
static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
|
||||||
unsigned int size)
|
unsigned int size)
|
||||||
{
|
{
|
||||||
/* TODO: implement VCPU removal on guest signal that CPU can be removed */
|
/* firmware never used to write in CPU present bitmap so use
|
||||||
|
this fact as means to switch QEMU into modern CPU hotplug
|
||||||
|
mode by writing 0 at the beginning of legacy CPU bitmap
|
||||||
|
*/
|
||||||
|
if (addr == 0 && data == 0) {
|
||||||
|
AcpiCpuHotplug *cpus = opaque;
|
||||||
|
object_property_set_bool(cpus->device, false, "cpu-hotplug-legacy",
|
||||||
|
&error_abort);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps AcpiCpuHotplug_ops = {
|
static const MemoryRegionOps AcpiCpuHotplug_ops = {
|
||||||
@@ -83,6 +91,17 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
|||||||
memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
|
memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
|
||||||
gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
|
gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
|
||||||
memory_region_add_subregion(parent, base, &gpe_cpu->io);
|
memory_region_add_subregion(parent, base, &gpe_cpu->io);
|
||||||
|
gpe_cpu->device = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_switch_to_modern_cphp(AcpiCpuHotplug *gpe_cpu,
|
||||||
|
CPUHotplugState *cpuhp_state,
|
||||||
|
uint16_t io_port)
|
||||||
|
{
|
||||||
|
MemoryRegion *parent = pci_address_space_io(PCI_DEVICE(gpe_cpu->device));
|
||||||
|
|
||||||
|
memory_region_del_subregion(parent, &gpe_cpu->io);
|
||||||
|
cpu_hotplug_hw_init(parent, gpe_cpu->device, cpuhp_state, io_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,
|
void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,
|
||||||
|
|||||||
@@ -189,6 +189,33 @@ static const VMStateDescription vmstate_tco_io_state = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool vmstate_test_use_cpuhp(void *opaque)
|
||||||
|
{
|
||||||
|
ICH9LPCPMRegs *s = opaque;
|
||||||
|
return !s->cpu_hotplug_legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vmstate_cpuhp_pre_load(void *opaque)
|
||||||
|
{
|
||||||
|
ICH9LPCPMRegs *s = opaque;
|
||||||
|
Object *obj = OBJECT(s->gpe_cpu.device);
|
||||||
|
object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_cpuhp_state = {
|
||||||
|
.name = "ich9_pm/cpuhp",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.needed = vmstate_test_use_cpuhp,
|
||||||
|
.pre_load = vmstate_cpuhp_pre_load,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_ich9_pm = {
|
const VMStateDescription vmstate_ich9_pm = {
|
||||||
.name = "ich9_pm",
|
.name = "ich9_pm",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
@@ -209,6 +236,7 @@ const VMStateDescription vmstate_ich9_pm = {
|
|||||||
.subsections = (const VMStateDescription*[]) {
|
.subsections = (const VMStateDescription*[]) {
|
||||||
&vmstate_memhp_state,
|
&vmstate_memhp_state,
|
||||||
&vmstate_tco_io_state,
|
&vmstate_tco_io_state,
|
||||||
|
&vmstate_cpuhp_state,
|
||||||
NULL
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -306,6 +334,26 @@ static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value,
|
|||||||
s->pm.acpi_memory_hotplug.is_enabled = value;
|
s->pm.acpi_memory_hotplug.is_enabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ich9_pm_get_cpu_hotplug_legacy(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
|
||||||
|
return s->pm.cpu_hotplug_legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
|
||||||
|
assert(!value);
|
||||||
|
if (s->pm.cpu_hotplug_legacy && value == false) {
|
||||||
|
acpi_switch_to_modern_cphp(&s->pm.gpe_cpu, &s->pm.cpuhp_state,
|
||||||
|
ICH9_CPU_HOTPLUG_IO_BASE);
|
||||||
|
}
|
||||||
|
s->pm.cpu_hotplug_legacy = value;
|
||||||
|
}
|
||||||
|
|
||||||
static void ich9_pm_get_disable_s3(Object *obj, Visitor *v, const char *name,
|
static void ich9_pm_get_disable_s3(Object *obj, Visitor *v, const char *name,
|
||||||
void *opaque, Error **errp)
|
void *opaque, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -397,6 +445,7 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
|
|||||||
{
|
{
|
||||||
static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
|
static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
|
||||||
pm->acpi_memory_hotplug.is_enabled = true;
|
pm->acpi_memory_hotplug.is_enabled = true;
|
||||||
|
pm->cpu_hotplug_legacy = true;
|
||||||
pm->disable_s3 = 0;
|
pm->disable_s3 = 0;
|
||||||
pm->disable_s4 = 0;
|
pm->disable_s4 = 0;
|
||||||
pm->s4_val = 2;
|
pm->s4_val = 2;
|
||||||
@@ -412,6 +461,10 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
|
|||||||
ich9_pm_get_memory_hotplug_support,
|
ich9_pm_get_memory_hotplug_support,
|
||||||
ich9_pm_set_memory_hotplug_support,
|
ich9_pm_set_memory_hotplug_support,
|
||||||
NULL);
|
NULL);
|
||||||
|
object_property_add_bool(obj, "cpu-hotplug-legacy",
|
||||||
|
ich9_pm_get_cpu_hotplug_legacy,
|
||||||
|
ich9_pm_set_cpu_hotplug_legacy,
|
||||||
|
NULL);
|
||||||
object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8",
|
object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8",
|
||||||
ich9_pm_get_disable_s3,
|
ich9_pm_get_disable_s3,
|
||||||
ich9_pm_set_disable_s3,
|
ich9_pm_set_disable_s3,
|
||||||
@@ -440,7 +493,11 @@ void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|||||||
acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug,
|
acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug,
|
||||||
dev, errp);
|
dev, errp);
|
||||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||||
legacy_acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.gpe_cpu, dev, errp);
|
if (lpc->pm.cpu_hotplug_legacy) {
|
||||||
|
legacy_acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.gpe_cpu, dev, errp);
|
||||||
|
} else {
|
||||||
|
acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "acpi: device plug request for not supported device"
|
error_setg(errp, "acpi: device plug request for not supported device"
|
||||||
" type: %s", object_get_typename(OBJECT(dev)));
|
" type: %s", object_get_typename(OBJECT(dev)));
|
||||||
@@ -457,6 +514,10 @@ void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|||||||
acpi_memory_unplug_request_cb(hotplug_dev,
|
acpi_memory_unplug_request_cb(hotplug_dev,
|
||||||
&lpc->pm.acpi_memory_hotplug, dev,
|
&lpc->pm.acpi_memory_hotplug, dev,
|
||||||
errp);
|
errp);
|
||||||
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
|
||||||
|
!lpc->pm.cpu_hotplug_legacy) {
|
||||||
|
acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state,
|
||||||
|
dev, errp);
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "acpi: device unplug request for not supported device"
|
error_setg(errp, "acpi: device unplug request for not supported device"
|
||||||
" type: %s", object_get_typename(OBJECT(dev)));
|
" type: %s", object_get_typename(OBJECT(dev)));
|
||||||
@@ -471,6 +532,9 @@ void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|||||||
if (lpc->pm.acpi_memory_hotplug.is_enabled &&
|
if (lpc->pm.acpi_memory_hotplug.is_enabled &&
|
||||||
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||||
acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp);
|
acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp);
|
||||||
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
|
||||||
|
!lpc->pm.cpu_hotplug_legacy) {
|
||||||
|
acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp);
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "acpi: device unplug for not supported device"
|
error_setg(errp, "acpi: device unplug for not supported device"
|
||||||
" type: %s", object_get_typename(OBJECT(dev)));
|
" type: %s", object_get_typename(OBJECT(dev)));
|
||||||
@@ -482,4 +546,7 @@ void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
|
|||||||
ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
|
ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
|
||||||
|
|
||||||
acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list);
|
acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list);
|
||||||
|
if (!s->pm.cpu_hotplug_legacy) {
|
||||||
|
acpi_cpu_ospm_status(&s->pm.cpuhp_state, list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
105
hw/acpi/ipmi.c
Normal file
105
hw/acpi/ipmi.c
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* IPMI ACPI firmware handling
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/ipmi/ipmi.h"
|
||||||
|
#include "hw/acpi/aml-build.h"
|
||||||
|
#include "hw/acpi/acpi.h"
|
||||||
|
#include "hw/acpi/ipmi.h"
|
||||||
|
|
||||||
|
static Aml *aml_ipmi_crs(IPMIFwInfo *info)
|
||||||
|
{
|
||||||
|
Aml *crs = aml_resource_template();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The base address is fixed and cannot change. That may be different
|
||||||
|
* if someone does PCI, but we aren't there yet.
|
||||||
|
*/
|
||||||
|
switch (info->memspace) {
|
||||||
|
case IPMI_MEMSPACE_IO:
|
||||||
|
aml_append(crs, aml_io(AML_DECODE16, info->base_address,
|
||||||
|
info->base_address + info->register_length - 1,
|
||||||
|
info->register_spacing, info->register_length));
|
||||||
|
break;
|
||||||
|
case IPMI_MEMSPACE_MEM32:
|
||||||
|
aml_append(crs,
|
||||||
|
aml_dword_memory(AML_POS_DECODE,
|
||||||
|
AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
|
AML_NON_CACHEABLE, AML_READ_WRITE,
|
||||||
|
0xffffffff,
|
||||||
|
info->base_address,
|
||||||
|
info->base_address + info->register_length - 1,
|
||||||
|
info->register_spacing, info->register_length));
|
||||||
|
break;
|
||||||
|
case IPMI_MEMSPACE_MEM64:
|
||||||
|
aml_append(crs,
|
||||||
|
aml_qword_memory(AML_POS_DECODE,
|
||||||
|
AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
|
AML_NON_CACHEABLE, AML_READ_WRITE,
|
||||||
|
0xffffffffffffffffULL,
|
||||||
|
info->base_address,
|
||||||
|
info->base_address + info->register_length - 1,
|
||||||
|
info->register_spacing, info->register_length));
|
||||||
|
break;
|
||||||
|
case IPMI_MEMSPACE_SMBUS:
|
||||||
|
aml_append(crs, aml_return(aml_int(info->base_address)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->interrupt_number) {
|
||||||
|
aml_append(crs, aml_irq_no_flags(info->interrupt_number));
|
||||||
|
}
|
||||||
|
|
||||||
|
return crs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Aml *aml_ipmi_device(IPMIFwInfo *info)
|
||||||
|
{
|
||||||
|
Aml *dev;
|
||||||
|
uint16_t version = ((info->ipmi_spec_major_revision << 8)
|
||||||
|
| (info->ipmi_spec_minor_revision << 4));
|
||||||
|
|
||||||
|
assert(info->ipmi_spec_minor_revision <= 15);
|
||||||
|
|
||||||
|
dev = aml_device("MI%d", info->uuid);
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_eisaid("IPI0001")));
|
||||||
|
aml_append(dev, aml_name_decl("_STR", aml_string("ipmi_%s",
|
||||||
|
info->interface_name)));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", aml_int(info->uuid)));
|
||||||
|
aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(info)));
|
||||||
|
aml_append(dev, aml_name_decl("_IFT", aml_int(info->interface_type)));
|
||||||
|
aml_append(dev, aml_name_decl("_SRV", aml_int(version)));
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_acpi_ipmi_devices(Aml *scope, BusState *bus)
|
||||||
|
{
|
||||||
|
|
||||||
|
BusChild *kid;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
||||||
|
IPMIInterface *ii;
|
||||||
|
IPMIInterfaceClass *iic;
|
||||||
|
IPMIFwInfo info;
|
||||||
|
Object *obj = object_dynamic_cast(OBJECT(kid->child),
|
||||||
|
TYPE_IPMI_INTERFACE);
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ii = IPMI_INTERFACE(obj);
|
||||||
|
iic = IPMI_INTERFACE_GET_CLASS(obj);
|
||||||
|
iic->get_fwinfo(ii, &info);
|
||||||
|
aml_append(scope, aml_ipmi_device(&info));
|
||||||
|
}
|
||||||
|
}
|
||||||
400
hw/acpi/nvdimm.c
400
hw/acpi/nvdimm.c
@@ -216,6 +216,26 @@ static uint32_t nvdimm_slot_to_dcr_index(int slot)
|
|||||||
return nvdimm_slot_to_spa_index(slot) + 1;
|
return nvdimm_slot_to_spa_index(slot) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NVDIMMDevice *nvdimm_get_device_by_handle(uint32_t handle)
|
||||||
|
{
|
||||||
|
NVDIMMDevice *nvdimm = NULL;
|
||||||
|
GSList *list, *device_list = nvdimm_get_plugged_device_list();
|
||||||
|
|
||||||
|
for (list = device_list; list; list = list->next) {
|
||||||
|
NVDIMMDevice *nvd = list->data;
|
||||||
|
int slot = object_property_get_int(OBJECT(nvd), PC_DIMM_SLOT_PROP,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (nvdimm_slot_to_handle(slot) == handle) {
|
||||||
|
nvdimm = nvd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slist_free(device_list);
|
||||||
|
return nvdimm;
|
||||||
|
}
|
||||||
|
|
||||||
/* ACPI 6.0: 5.2.25.1 System Physical Address Range Structure */
|
/* ACPI 6.0: 5.2.25.1 System Physical Address Range Structure */
|
||||||
static void
|
static void
|
||||||
nvdimm_build_structure_spa(GArray *structures, DeviceState *dev)
|
nvdimm_build_structure_spa(GArray *structures, DeviceState *dev)
|
||||||
@@ -406,6 +426,282 @@ struct NvdimmDsmFuncNoPayloadOut {
|
|||||||
} QEMU_PACKED;
|
} QEMU_PACKED;
|
||||||
typedef struct NvdimmDsmFuncNoPayloadOut NvdimmDsmFuncNoPayloadOut;
|
typedef struct NvdimmDsmFuncNoPayloadOut NvdimmDsmFuncNoPayloadOut;
|
||||||
|
|
||||||
|
struct NvdimmFuncGetLabelSizeOut {
|
||||||
|
/* the size of buffer filled by QEMU. */
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t func_ret_status; /* return status code. */
|
||||||
|
uint32_t label_size; /* the size of label data area. */
|
||||||
|
/*
|
||||||
|
* Maximum size of the namespace label data length supported by
|
||||||
|
* the platform in Get/Set Namespace Label Data functions.
|
||||||
|
*/
|
||||||
|
uint32_t max_xfer;
|
||||||
|
} QEMU_PACKED;
|
||||||
|
typedef struct NvdimmFuncGetLabelSizeOut NvdimmFuncGetLabelSizeOut;
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncGetLabelSizeOut) > 4096);
|
||||||
|
|
||||||
|
struct NvdimmFuncGetLabelDataIn {
|
||||||
|
uint32_t offset; /* the offset in the namespace label data area. */
|
||||||
|
uint32_t length; /* the size of data is to be read via the function. */
|
||||||
|
} QEMU_PACKED;
|
||||||
|
typedef struct NvdimmFuncGetLabelDataIn NvdimmFuncGetLabelDataIn;
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncGetLabelDataIn) +
|
||||||
|
offsetof(NvdimmDsmIn, arg3) > 4096);
|
||||||
|
|
||||||
|
struct NvdimmFuncGetLabelDataOut {
|
||||||
|
/* the size of buffer filled by QEMU. */
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t func_ret_status; /* return status code. */
|
||||||
|
uint8_t out_buf[0]; /* the data got via Get Namesapce Label function. */
|
||||||
|
} QEMU_PACKED;
|
||||||
|
typedef struct NvdimmFuncGetLabelDataOut NvdimmFuncGetLabelDataOut;
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncGetLabelDataOut) > 4096);
|
||||||
|
|
||||||
|
struct NvdimmFuncSetLabelDataIn {
|
||||||
|
uint32_t offset; /* the offset in the namespace label data area. */
|
||||||
|
uint32_t length; /* the size of data is to be written via the function. */
|
||||||
|
uint8_t in_buf[0]; /* the data written to label data area. */
|
||||||
|
} QEMU_PACKED;
|
||||||
|
typedef struct NvdimmFuncSetLabelDataIn NvdimmFuncSetLabelDataIn;
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncSetLabelDataIn) +
|
||||||
|
offsetof(NvdimmDsmIn, arg3) > 4096);
|
||||||
|
|
||||||
|
static void
|
||||||
|
nvdimm_dsm_function0(uint32_t supported_func, hwaddr dsm_mem_addr)
|
||||||
|
{
|
||||||
|
NvdimmDsmFunc0Out func0 = {
|
||||||
|
.len = cpu_to_le32(sizeof(func0)),
|
||||||
|
.supported_func = cpu_to_le32(supported_func),
|
||||||
|
};
|
||||||
|
cpu_physical_memory_write(dsm_mem_addr, &func0, sizeof(func0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nvdimm_dsm_no_payload(uint32_t func_ret_status, hwaddr dsm_mem_addr)
|
||||||
|
{
|
||||||
|
NvdimmDsmFuncNoPayloadOut out = {
|
||||||
|
.len = cpu_to_le32(sizeof(out)),
|
||||||
|
.func_ret_status = cpu_to_le32(func_ret_status),
|
||||||
|
};
|
||||||
|
cpu_physical_memory_write(dsm_mem_addr, &out, sizeof(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nvdimm_dsm_root(NvdimmDsmIn *in, hwaddr dsm_mem_addr)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* function 0 is called to inquire which functions are supported by
|
||||||
|
* OSPM
|
||||||
|
*/
|
||||||
|
if (!in->function) {
|
||||||
|
nvdimm_dsm_function0(0 /* No function supported other than
|
||||||
|
function 0 */, dsm_mem_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No function except function 0 is supported yet. */
|
||||||
|
nvdimm_dsm_no_payload(1 /* Not Supported */, dsm_mem_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the max transfer size is the max size transferred by both a
|
||||||
|
* 'Get Namespace Label Data' function and a 'Set Namespace Label Data'
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
static uint32_t nvdimm_get_max_xfer_label_size(void)
|
||||||
|
{
|
||||||
|
uint32_t max_get_size, max_set_size, dsm_memory_size = 4096;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the max data ACPI can read one time which is transferred by
|
||||||
|
* the response of 'Get Namespace Label Data' function.
|
||||||
|
*/
|
||||||
|
max_get_size = dsm_memory_size - sizeof(NvdimmFuncGetLabelDataOut);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the max data ACPI can write one time which is transferred by
|
||||||
|
* 'Set Namespace Label Data' function.
|
||||||
|
*/
|
||||||
|
max_set_size = dsm_memory_size - offsetof(NvdimmDsmIn, arg3) -
|
||||||
|
sizeof(NvdimmFuncSetLabelDataIn);
|
||||||
|
|
||||||
|
return MIN(max_get_size, max_set_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DSM Spec Rev1 4.4 Get Namespace Label Size (Function Index 4).
|
||||||
|
*
|
||||||
|
* It gets the size of Namespace Label data area and the max data size
|
||||||
|
* that Get/Set Namespace Label Data functions can transfer.
|
||||||
|
*/
|
||||||
|
static void nvdimm_dsm_label_size(NVDIMMDevice *nvdimm, hwaddr dsm_mem_addr)
|
||||||
|
{
|
||||||
|
NvdimmFuncGetLabelSizeOut label_size_out = {
|
||||||
|
.len = cpu_to_le32(sizeof(label_size_out)),
|
||||||
|
};
|
||||||
|
uint32_t label_size, mxfer;
|
||||||
|
|
||||||
|
label_size = nvdimm->label_size;
|
||||||
|
mxfer = nvdimm_get_max_xfer_label_size();
|
||||||
|
|
||||||
|
nvdimm_debug("label_size %#x, max_xfer %#x.\n", label_size, mxfer);
|
||||||
|
|
||||||
|
label_size_out.func_ret_status = cpu_to_le32(0 /* Success */);
|
||||||
|
label_size_out.label_size = cpu_to_le32(label_size);
|
||||||
|
label_size_out.max_xfer = cpu_to_le32(mxfer);
|
||||||
|
|
||||||
|
cpu_physical_memory_write(dsm_mem_addr, &label_size_out,
|
||||||
|
sizeof(label_size_out));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t nvdimm_rw_label_data_check(NVDIMMDevice *nvdimm,
|
||||||
|
uint32_t offset, uint32_t length)
|
||||||
|
{
|
||||||
|
uint32_t ret = 3 /* Invalid Input Parameters */;
|
||||||
|
|
||||||
|
if (offset + length < offset) {
|
||||||
|
nvdimm_debug("offset %#x + length %#x is overflow.\n", offset,
|
||||||
|
length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nvdimm->label_size < offset + length) {
|
||||||
|
nvdimm_debug("position %#x is beyond label data (len = %" PRIx64 ").\n",
|
||||||
|
offset + length, nvdimm->label_size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > nvdimm_get_max_xfer_label_size()) {
|
||||||
|
nvdimm_debug("length (%#x) is larger than max_xfer (%#x).\n",
|
||||||
|
length, nvdimm_get_max_xfer_label_size());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 /* Success */;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DSM Spec Rev1 4.5 Get Namespace Label Data (Function Index 5).
|
||||||
|
*/
|
||||||
|
static void nvdimm_dsm_get_label_data(NVDIMMDevice *nvdimm, NvdimmDsmIn *in,
|
||||||
|
hwaddr dsm_mem_addr)
|
||||||
|
{
|
||||||
|
NVDIMMClass *nvc = NVDIMM_GET_CLASS(nvdimm);
|
||||||
|
NvdimmFuncGetLabelDataIn *get_label_data;
|
||||||
|
NvdimmFuncGetLabelDataOut *get_label_data_out;
|
||||||
|
uint32_t status;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
get_label_data = (NvdimmFuncGetLabelDataIn *)in->arg3;
|
||||||
|
le32_to_cpus(&get_label_data->offset);
|
||||||
|
le32_to_cpus(&get_label_data->length);
|
||||||
|
|
||||||
|
nvdimm_debug("Read Label Data: offset %#x length %#x.\n",
|
||||||
|
get_label_data->offset, get_label_data->length);
|
||||||
|
|
||||||
|
status = nvdimm_rw_label_data_check(nvdimm, get_label_data->offset,
|
||||||
|
get_label_data->length);
|
||||||
|
if (status != 0 /* Success */) {
|
||||||
|
nvdimm_dsm_no_payload(status, dsm_mem_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(*get_label_data_out) + get_label_data->length;
|
||||||
|
assert(size <= 4096);
|
||||||
|
get_label_data_out = g_malloc(size);
|
||||||
|
|
||||||
|
get_label_data_out->len = cpu_to_le32(size);
|
||||||
|
get_label_data_out->func_ret_status = cpu_to_le32(0 /* Success */);
|
||||||
|
nvc->read_label_data(nvdimm, get_label_data_out->out_buf,
|
||||||
|
get_label_data->length, get_label_data->offset);
|
||||||
|
|
||||||
|
cpu_physical_memory_write(dsm_mem_addr, get_label_data_out, size);
|
||||||
|
g_free(get_label_data_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DSM Spec Rev1 4.6 Set Namespace Label Data (Function Index 6).
|
||||||
|
*/
|
||||||
|
static void nvdimm_dsm_set_label_data(NVDIMMDevice *nvdimm, NvdimmDsmIn *in,
|
||||||
|
hwaddr dsm_mem_addr)
|
||||||
|
{
|
||||||
|
NVDIMMClass *nvc = NVDIMM_GET_CLASS(nvdimm);
|
||||||
|
NvdimmFuncSetLabelDataIn *set_label_data;
|
||||||
|
uint32_t status;
|
||||||
|
|
||||||
|
set_label_data = (NvdimmFuncSetLabelDataIn *)in->arg3;
|
||||||
|
|
||||||
|
le32_to_cpus(&set_label_data->offset);
|
||||||
|
le32_to_cpus(&set_label_data->length);
|
||||||
|
|
||||||
|
nvdimm_debug("Write Label Data: offset %#x length %#x.\n",
|
||||||
|
set_label_data->offset, set_label_data->length);
|
||||||
|
|
||||||
|
status = nvdimm_rw_label_data_check(nvdimm, set_label_data->offset,
|
||||||
|
set_label_data->length);
|
||||||
|
if (status != 0 /* Success */) {
|
||||||
|
nvdimm_dsm_no_payload(status, dsm_mem_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sizeof(*in) + sizeof(*set_label_data) + set_label_data->length <=
|
||||||
|
4096);
|
||||||
|
|
||||||
|
nvc->write_label_data(nvdimm, set_label_data->in_buf,
|
||||||
|
set_label_data->length, set_label_data->offset);
|
||||||
|
nvdimm_dsm_no_payload(0 /* Success */, dsm_mem_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nvdimm_dsm_device(NvdimmDsmIn *in, hwaddr dsm_mem_addr)
|
||||||
|
{
|
||||||
|
NVDIMMDevice *nvdimm = nvdimm_get_device_by_handle(in->handle);
|
||||||
|
|
||||||
|
/* See the comments in nvdimm_dsm_root(). */
|
||||||
|
if (!in->function) {
|
||||||
|
uint32_t supported_func = 0;
|
||||||
|
|
||||||
|
if (nvdimm && nvdimm->label_size) {
|
||||||
|
supported_func |= 0x1 /* Bit 0 indicates whether there is
|
||||||
|
support for any functions other
|
||||||
|
than function 0. */ |
|
||||||
|
1 << 4 /* Get Namespace Label Size */ |
|
||||||
|
1 << 5 /* Get Namespace Label Data */ |
|
||||||
|
1 << 6 /* Set Namespace Label Data */;
|
||||||
|
}
|
||||||
|
nvdimm_dsm_function0(supported_func, dsm_mem_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nvdimm) {
|
||||||
|
nvdimm_dsm_no_payload(2 /* Non-Existing Memory Device */,
|
||||||
|
dsm_mem_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encode DSM function according to DSM Spec Rev1. */
|
||||||
|
switch (in->function) {
|
||||||
|
case 4 /* Get Namespace Label Size */:
|
||||||
|
if (nvdimm->label_size) {
|
||||||
|
nvdimm_dsm_label_size(nvdimm, dsm_mem_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5 /* Get Namespace Label Data */:
|
||||||
|
if (nvdimm->label_size) {
|
||||||
|
nvdimm_dsm_get_label_data(nvdimm, in, dsm_mem_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x6 /* Set Namespace Label Data */:
|
||||||
|
if (nvdimm->label_size) {
|
||||||
|
nvdimm_dsm_set_label_data(nvdimm, in, dsm_mem_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvdimm_dsm_no_payload(1 /* Not Supported */, dsm_mem_addr);
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t
|
static uint64_t
|
||||||
nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size)
|
nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
{
|
{
|
||||||
@@ -436,26 +732,22 @@ nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
|||||||
nvdimm_debug("Revision %#x Handler %#x Function %#x.\n", in->revision,
|
nvdimm_debug("Revision %#x Handler %#x Function %#x.\n", in->revision,
|
||||||
in->handle, in->function);
|
in->handle, in->function);
|
||||||
|
|
||||||
/*
|
if (in->revision != 0x1 /* Currently we only support DSM Spec Rev1. */) {
|
||||||
* function 0 is called to inquire which functions are supported by
|
nvdimm_debug("Revision %#x is not supported, expect %#x.\n",
|
||||||
* OSPM
|
in->revision, 0x1);
|
||||||
*/
|
nvdimm_dsm_no_payload(1 /* Not Supported */, dsm_mem_addr);
|
||||||
if (in->function == 0) {
|
goto exit;
|
||||||
NvdimmDsmFunc0Out func0 = {
|
|
||||||
.len = cpu_to_le32(sizeof(func0)),
|
|
||||||
/* No function supported other than function 0 */
|
|
||||||
.supported_func = cpu_to_le32(0),
|
|
||||||
};
|
|
||||||
cpu_physical_memory_write(dsm_mem_addr, &func0, sizeof func0);
|
|
||||||
} else {
|
|
||||||
/* No function except function 0 is supported yet. */
|
|
||||||
NvdimmDsmFuncNoPayloadOut out = {
|
|
||||||
.len = cpu_to_le32(sizeof(out)),
|
|
||||||
.func_ret_status = cpu_to_le32(1) /* Not Supported */,
|
|
||||||
};
|
|
||||||
cpu_physical_memory_write(dsm_mem_addr, &out, sizeof(out));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle 0 is reserved for NVDIMM Root Device. */
|
||||||
|
if (!in->handle) {
|
||||||
|
nvdimm_dsm_root(in, dsm_mem_addr);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvdimm_dsm_device(in, dsm_mem_addr);
|
||||||
|
|
||||||
|
exit:
|
||||||
g_free(in);
|
g_free(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,18 +779,39 @@ void nvdimm_init_acpi_state(AcpiNVDIMMState *state, MemoryRegion *io,
|
|||||||
|
|
||||||
static void nvdimm_build_common_dsm(Aml *dev)
|
static void nvdimm_build_common_dsm(Aml *dev)
|
||||||
{
|
{
|
||||||
Aml *method, *ifctx, *function, *dsm_mem, *unpatched, *result_size;
|
Aml *method, *ifctx, *function, *handle, *uuid, *dsm_mem, *result_size;
|
||||||
|
Aml *elsectx, *unsupport, *unpatched, *expected_uuid, *uuid_invalid;
|
||||||
|
Aml *pckg, *pckg_index, *pckg_buf;
|
||||||
uint8_t byte_list[1];
|
uint8_t byte_list[1];
|
||||||
|
|
||||||
method = aml_method(NVDIMM_COMMON_DSM, 4, AML_SERIALIZED);
|
method = aml_method(NVDIMM_COMMON_DSM, 5, AML_SERIALIZED);
|
||||||
|
uuid = aml_arg(0);
|
||||||
function = aml_arg(2);
|
function = aml_arg(2);
|
||||||
|
handle = aml_arg(4);
|
||||||
dsm_mem = aml_name(NVDIMM_ACPI_MEM_ADDR);
|
dsm_mem = aml_name(NVDIMM_ACPI_MEM_ADDR);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do not support any method if DSM memory address has not been
|
* do not support any method if DSM memory address has not been
|
||||||
* patched.
|
* patched.
|
||||||
*/
|
*/
|
||||||
unpatched = aml_if(aml_equal(dsm_mem, aml_int(0x0)));
|
unpatched = aml_equal(dsm_mem, aml_int(0x0));
|
||||||
|
|
||||||
|
expected_uuid = aml_local(0);
|
||||||
|
|
||||||
|
ifctx = aml_if(aml_equal(handle, aml_int(0x0)));
|
||||||
|
aml_append(ifctx, aml_store(
|
||||||
|
aml_touuid("2F10E7A4-9E91-11E4-89D3-123B93F75CBA")
|
||||||
|
/* UUID for NVDIMM Root Device */, expected_uuid));
|
||||||
|
aml_append(method, ifctx);
|
||||||
|
elsectx = aml_else();
|
||||||
|
aml_append(elsectx, aml_store(
|
||||||
|
aml_touuid("4309AC30-0D11-11E4-9191-0800200C9A66")
|
||||||
|
/* UUID for NVDIMM Devices */, expected_uuid));
|
||||||
|
aml_append(method, elsectx);
|
||||||
|
|
||||||
|
uuid_invalid = aml_lnot(aml_equal(uuid, expected_uuid));
|
||||||
|
|
||||||
|
unsupport = aml_if(aml_or(unpatched, uuid_invalid, NULL));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* function 0 is called to inquire what functions are supported by
|
* function 0 is called to inquire what functions are supported by
|
||||||
@@ -507,23 +820,41 @@ static void nvdimm_build_common_dsm(Aml *dev)
|
|||||||
ifctx = aml_if(aml_equal(function, aml_int(0)));
|
ifctx = aml_if(aml_equal(function, aml_int(0)));
|
||||||
byte_list[0] = 0 /* No function Supported */;
|
byte_list[0] = 0 /* No function Supported */;
|
||||||
aml_append(ifctx, aml_return(aml_buffer(1, byte_list)));
|
aml_append(ifctx, aml_return(aml_buffer(1, byte_list)));
|
||||||
aml_append(unpatched, ifctx);
|
aml_append(unsupport, ifctx);
|
||||||
|
|
||||||
/* No function is supported yet. */
|
/* No function is supported yet. */
|
||||||
byte_list[0] = 1 /* Not Supported */;
|
byte_list[0] = 1 /* Not Supported */;
|
||||||
aml_append(unpatched, aml_return(aml_buffer(1, byte_list)));
|
aml_append(unsupport, aml_return(aml_buffer(1, byte_list)));
|
||||||
aml_append(method, unpatched);
|
aml_append(method, unsupport);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The HDLE indicates the DSM function is issued from which device,
|
* The HDLE indicates the DSM function is issued from which device,
|
||||||
* it is not used at this time as no function is supported yet.
|
* it reserves 0 for root device and is the handle for NVDIMM devices.
|
||||||
* Currently we make it always be 0 for all the devices and will set
|
* See the comments in nvdimm_slot_to_handle().
|
||||||
* the appropriate value once real function is implemented.
|
|
||||||
*/
|
*/
|
||||||
aml_append(method, aml_store(aml_int(0x0), aml_name("HDLE")));
|
aml_append(method, aml_store(handle, aml_name("HDLE")));
|
||||||
aml_append(method, aml_store(aml_arg(1), aml_name("REVS")));
|
aml_append(method, aml_store(aml_arg(1), aml_name("REVS")));
|
||||||
aml_append(method, aml_store(aml_arg(2), aml_name("FUNC")));
|
aml_append(method, aml_store(aml_arg(2), aml_name("FUNC")));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The fourth parameter (Arg3) of _DSM is a package which contains
|
||||||
|
* a buffer, the layout of the buffer is specified by UUID (Arg0),
|
||||||
|
* Revision ID (Arg1) and Function Index (Arg2) which are documented
|
||||||
|
* in the DSM Spec.
|
||||||
|
*/
|
||||||
|
pckg = aml_arg(3);
|
||||||
|
ifctx = aml_if(aml_and(aml_equal(aml_object_type(pckg),
|
||||||
|
aml_int(4 /* Package */)) /* It is a Package? */,
|
||||||
|
aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element? */,
|
||||||
|
NULL));
|
||||||
|
|
||||||
|
pckg_index = aml_local(2);
|
||||||
|
pckg_buf = aml_local(3);
|
||||||
|
aml_append(ifctx, aml_store(aml_index(pckg, aml_int(0)), pckg_index));
|
||||||
|
aml_append(ifctx, aml_store(aml_derefof(pckg_index), pckg_buf));
|
||||||
|
aml_append(ifctx, aml_store(pckg_buf, aml_name("ARG3")));
|
||||||
|
aml_append(method, ifctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tell QEMU about the real address of DSM memory, then QEMU
|
* tell QEMU about the real address of DSM memory, then QEMU
|
||||||
* gets the control and fills the result in DSM memory.
|
* gets the control and fills the result in DSM memory.
|
||||||
@@ -542,13 +873,14 @@ static void nvdimm_build_common_dsm(Aml *dev)
|
|||||||
aml_append(dev, method);
|
aml_append(dev, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvdimm_build_device_dsm(Aml *dev)
|
static void nvdimm_build_device_dsm(Aml *dev, uint32_t handle)
|
||||||
{
|
{
|
||||||
Aml *method;
|
Aml *method;
|
||||||
|
|
||||||
method = aml_method("_DSM", 4, AML_NOTSERIALIZED);
|
method = aml_method("_DSM", 4, AML_NOTSERIALIZED);
|
||||||
aml_append(method, aml_return(aml_call4(NVDIMM_COMMON_DSM, aml_arg(0),
|
aml_append(method, aml_return(aml_call5(NVDIMM_COMMON_DSM, aml_arg(0),
|
||||||
aml_arg(1), aml_arg(2), aml_arg(3))));
|
aml_arg(1), aml_arg(2), aml_arg(3),
|
||||||
|
aml_int(handle))));
|
||||||
aml_append(dev, method);
|
aml_append(dev, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,7 +905,7 @@ static void nvdimm_build_nvdimm_devices(GSList *device_list, Aml *root_dev)
|
|||||||
*/
|
*/
|
||||||
aml_append(nvdimm_dev, aml_name_decl("_ADR", aml_int(handle)));
|
aml_append(nvdimm_dev, aml_name_decl("_ADR", aml_int(handle)));
|
||||||
|
|
||||||
nvdimm_build_device_dsm(nvdimm_dev);
|
nvdimm_build_device_dsm(nvdimm_dev, handle);
|
||||||
aml_append(root_dev, nvdimm_dev);
|
aml_append(root_dev, nvdimm_dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,7 +997,9 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets,
|
|||||||
aml_append(dev, field);
|
aml_append(dev, field);
|
||||||
|
|
||||||
nvdimm_build_common_dsm(dev);
|
nvdimm_build_common_dsm(dev);
|
||||||
nvdimm_build_device_dsm(dev);
|
|
||||||
|
/* 0 is reserved for root device. */
|
||||||
|
nvdimm_build_device_dsm(dev, 0);
|
||||||
|
|
||||||
nvdimm_build_nvdimm_devices(device_list, dev);
|
nvdimm_build_nvdimm_devices(device_list, dev);
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "hw/acpi/piix4.h"
|
#include "hw/acpi/piix4.h"
|
||||||
#include "hw/acpi/pcihp.h"
|
#include "hw/acpi/pcihp.h"
|
||||||
#include "hw/acpi/cpu_hotplug.h"
|
#include "hw/acpi/cpu_hotplug.h"
|
||||||
|
#include "hw/acpi/cpu.h"
|
||||||
#include "hw/hotplug.h"
|
#include "hw/hotplug.h"
|
||||||
#include "hw/mem/pc-dimm.h"
|
#include "hw/mem/pc-dimm.h"
|
||||||
#include "hw/acpi/memory_hotplug.h"
|
#include "hw/acpi/memory_hotplug.h"
|
||||||
@@ -86,7 +87,9 @@ typedef struct PIIX4PMState {
|
|||||||
uint8_t disable_s4;
|
uint8_t disable_s4;
|
||||||
uint8_t s4_val;
|
uint8_t s4_val;
|
||||||
|
|
||||||
|
bool cpu_hotplug_legacy;
|
||||||
AcpiCpuHotplug gpe_cpu;
|
AcpiCpuHotplug gpe_cpu;
|
||||||
|
CPUHotplugState cpuhp_state;
|
||||||
|
|
||||||
MemHotplugState acpi_memory_hotplug;
|
MemHotplugState acpi_memory_hotplug;
|
||||||
} PIIX4PMState;
|
} PIIX4PMState;
|
||||||
@@ -273,6 +276,32 @@ static const VMStateDescription vmstate_memhp_state = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool vmstate_test_use_cpuhp(void *opaque)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = opaque;
|
||||||
|
return !s->cpu_hotplug_legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vmstate_cpuhp_pre_load(void *opaque)
|
||||||
|
{
|
||||||
|
Object *obj = OBJECT(opaque);
|
||||||
|
object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_cpuhp_state = {
|
||||||
|
.name = "piix4_pm/cpuhp",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.needed = vmstate_test_use_cpuhp,
|
||||||
|
.pre_load = vmstate_cpuhp_pre_load,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_CPU_HOTPLUG(cpuhp_state, PIIX4PMState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* qemu-kvm 1.2 uses version 3 but advertised as 2
|
/* qemu-kvm 1.2 uses version 3 but advertised as 2
|
||||||
* To support incoming qemu-kvm 1.2 migration, change version_id
|
* To support incoming qemu-kvm 1.2 migration, change version_id
|
||||||
* and minimum_version_id to 2 below (which breaks migration from
|
* and minimum_version_id to 2 below (which breaks migration from
|
||||||
@@ -307,6 +336,7 @@ static const VMStateDescription vmstate_acpi = {
|
|||||||
},
|
},
|
||||||
.subsections = (const VMStateDescription*[]) {
|
.subsections = (const VMStateDescription*[]) {
|
||||||
&vmstate_memhp_state,
|
&vmstate_memhp_state,
|
||||||
|
&vmstate_cpuhp_state,
|
||||||
NULL
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -352,7 +382,11 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
|
|||||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
||||||
acpi_pcihp_device_plug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev, errp);
|
acpi_pcihp_device_plug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev, errp);
|
||||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||||
legacy_acpi_cpu_plug_cb(hotplug_dev, &s->gpe_cpu, dev, errp);
|
if (s->cpu_hotplug_legacy) {
|
||||||
|
legacy_acpi_cpu_plug_cb(hotplug_dev, &s->gpe_cpu, dev, errp);
|
||||||
|
} else {
|
||||||
|
acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "acpi: device plug request for not supported device"
|
error_setg(errp, "acpi: device plug request for not supported device"
|
||||||
" type: %s", object_get_typename(OBJECT(dev)));
|
" type: %s", object_get_typename(OBJECT(dev)));
|
||||||
@@ -371,6 +405,9 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|||||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
||||||
acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev,
|
acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev,
|
||||||
errp);
|
errp);
|
||||||
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
|
||||||
|
!s->cpu_hotplug_legacy) {
|
||||||
|
acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "acpi: device unplug request for not supported device"
|
error_setg(errp, "acpi: device unplug request for not supported device"
|
||||||
" type: %s", object_get_typename(OBJECT(dev)));
|
" type: %s", object_get_typename(OBJECT(dev)));
|
||||||
@@ -385,6 +422,9 @@ static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
|
|||||||
if (s->acpi_memory_hotplug.is_enabled &&
|
if (s->acpi_memory_hotplug.is_enabled &&
|
||||||
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||||
acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
|
acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
|
||||||
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
|
||||||
|
!s->cpu_hotplug_legacy) {
|
||||||
|
acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp);
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "acpi: device unplug for not supported device"
|
error_setg(errp, "acpi: device unplug for not supported device"
|
||||||
" type: %s", object_get_typename(OBJECT(dev)));
|
" type: %s", object_get_typename(OBJECT(dev)));
|
||||||
@@ -560,6 +600,26 @@ static const MemoryRegionOps piix4_gpe_ops = {
|
|||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static bool piix4_get_cpu_hotplug_legacy(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = PIIX4_PM(obj);
|
||||||
|
|
||||||
|
return s->cpu_hotplug_legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void piix4_set_cpu_hotplug_legacy(Object *obj, bool value, Error **errp)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = PIIX4_PM(obj);
|
||||||
|
|
||||||
|
assert(!value);
|
||||||
|
if (s->cpu_hotplug_legacy && value == false) {
|
||||||
|
acpi_switch_to_modern_cphp(&s->gpe_cpu, &s->cpuhp_state,
|
||||||
|
PIIX4_CPU_HOTPLUG_IO_BASE);
|
||||||
|
}
|
||||||
|
s->cpu_hotplug_legacy = value;
|
||||||
|
}
|
||||||
|
|
||||||
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
|
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
|
||||||
PCIBus *bus, PIIX4PMState *s)
|
PCIBus *bus, PIIX4PMState *s)
|
||||||
{
|
{
|
||||||
@@ -570,6 +630,11 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
|
|||||||
acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
|
acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
|
||||||
s->use_acpi_pci_hotplug);
|
s->use_acpi_pci_hotplug);
|
||||||
|
|
||||||
|
s->cpu_hotplug_legacy = true;
|
||||||
|
object_property_add_bool(OBJECT(s), "cpu-hotplug-legacy",
|
||||||
|
piix4_get_cpu_hotplug_legacy,
|
||||||
|
piix4_set_cpu_hotplug_legacy,
|
||||||
|
NULL);
|
||||||
legacy_acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu,
|
legacy_acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu,
|
||||||
PIIX4_CPU_HOTPLUG_IO_BASE);
|
PIIX4_CPU_HOTPLUG_IO_BASE);
|
||||||
|
|
||||||
@@ -583,6 +648,9 @@ static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
|
|||||||
PIIX4PMState *s = PIIX4_PM(adev);
|
PIIX4PMState *s = PIIX4_PM(adev);
|
||||||
|
|
||||||
acpi_memory_ospm_status(&s->acpi_memory_hotplug, list);
|
acpi_memory_ospm_status(&s->acpi_memory_hotplug, list);
|
||||||
|
if (!s->cpu_hotplug_legacy) {
|
||||||
|
acpi_cpu_ospm_status(&s->cpuhp_state, list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
|
static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
|
||||||
@@ -631,6 +699,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
|
|||||||
hc->unplug = piix4_device_unplug_cb;
|
hc->unplug = piix4_device_unplug_cb;
|
||||||
adevc->ospm_status = piix4_ospm_status;
|
adevc->ospm_status = piix4_ospm_status;
|
||||||
adevc->send_event = piix4_send_gpe;
|
adevc->send_event = piix4_send_gpe;
|
||||||
|
adevc->madt_cpu = pc_madt_cpu_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo piix4_pm_info = {
|
static const TypeInfo piix4_pm_info = {
|
||||||
|
|||||||
@@ -16,3 +16,17 @@ mhp_acpi_clear_insert_evt(uint32_t slot) "slot[0x%"PRIx32"] clear insert event"
|
|||||||
mhp_acpi_clear_remove_evt(uint32_t slot) "slot[0x%"PRIx32"] clear remove event"
|
mhp_acpi_clear_remove_evt(uint32_t slot) "slot[0x%"PRIx32"] clear remove event"
|
||||||
mhp_acpi_pc_dimm_deleted(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm deleted"
|
mhp_acpi_pc_dimm_deleted(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm deleted"
|
||||||
mhp_acpi_pc_dimm_delete_failed(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm delete failed"
|
mhp_acpi_pc_dimm_delete_failed(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm delete failed"
|
||||||
|
|
||||||
|
# hw/acpi/cpu.c
|
||||||
|
cpuhp_acpi_invalid_idx_selected(uint32_t idx) "0x%"PRIx32
|
||||||
|
cpuhp_acpi_read_flags(uint32_t idx, uint8_t flags) "idx[0x%"PRIx32"] flags: 0x%"PRIx8
|
||||||
|
cpuhp_acpi_write_idx(uint32_t idx) "set active cpu idx: 0x%"PRIx32
|
||||||
|
cpuhp_acpi_write_cmd(uint32_t idx, uint8_t cmd) "idx[0x%"PRIx32"] cmd: 0x%"PRIx8
|
||||||
|
cpuhp_acpi_read_cmd_data(uint32_t idx, uint32_t data) "idx[0x%"PRIx32"] data: 0x%"PRIx32
|
||||||
|
cpuhp_acpi_cpu_has_events(uint32_t idx, bool ins, bool rm) "idx[0x%"PRIx32"] inserting: %d, removing: %d"
|
||||||
|
cpuhp_acpi_clear_inserting_evt(uint32_t idx) "idx[0x%"PRIx32"]"
|
||||||
|
cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]"
|
||||||
|
cpuhp_acpi_ejecting_invalid_cpu(uint32_t idx) "0x%"PRIx32
|
||||||
|
cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32
|
||||||
|
cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST EVENT: 0x%"PRIx32
|
||||||
|
cpuhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32
|
||||||
|
|||||||
@@ -23,10 +23,19 @@
|
|||||||
#define AST2400_UART_5_BASE 0x00184000
|
#define AST2400_UART_5_BASE 0x00184000
|
||||||
#define AST2400_IOMEM_SIZE 0x00200000
|
#define AST2400_IOMEM_SIZE 0x00200000
|
||||||
#define AST2400_IOMEM_BASE 0x1E600000
|
#define AST2400_IOMEM_BASE 0x1E600000
|
||||||
|
#define AST2400_SMC_BASE AST2400_IOMEM_BASE /* Legacy SMC */
|
||||||
|
#define AST2400_FMC_BASE 0X1E620000
|
||||||
|
#define AST2400_SPI_BASE 0X1E630000
|
||||||
#define AST2400_VIC_BASE 0x1E6C0000
|
#define AST2400_VIC_BASE 0x1E6C0000
|
||||||
|
#define AST2400_SCU_BASE 0x1E6E2000
|
||||||
#define AST2400_TIMER_BASE 0x1E782000
|
#define AST2400_TIMER_BASE 0x1E782000
|
||||||
#define AST2400_I2C_BASE 0x1E78A000
|
#define AST2400_I2C_BASE 0x1E78A000
|
||||||
|
|
||||||
|
#define AST2400_FMC_FLASH_BASE 0x20000000
|
||||||
|
#define AST2400_SPI_FLASH_BASE 0x30000000
|
||||||
|
|
||||||
|
#define AST2400_A0_SILICON_REV 0x02000303
|
||||||
|
|
||||||
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
||||||
static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
|
static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
|
||||||
|
|
||||||
@@ -72,13 +81,31 @@ static void ast2400_init(Object *obj)
|
|||||||
object_initialize(&s->i2c, sizeof(s->i2c), TYPE_ASPEED_I2C);
|
object_initialize(&s->i2c, sizeof(s->i2c), TYPE_ASPEED_I2C);
|
||||||
object_property_add_child(obj, "i2c", OBJECT(&s->i2c), NULL);
|
object_property_add_child(obj, "i2c", OBJECT(&s->i2c), NULL);
|
||||||
qdev_set_parent_bus(DEVICE(&s->i2c), sysbus_get_default());
|
qdev_set_parent_bus(DEVICE(&s->i2c), sysbus_get_default());
|
||||||
|
|
||||||
|
object_initialize(&s->scu, sizeof(s->scu), TYPE_ASPEED_SCU);
|
||||||
|
object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL);
|
||||||
|
qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default());
|
||||||
|
qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
|
||||||
|
AST2400_A0_SILICON_REV);
|
||||||
|
object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
|
||||||
|
"hw-strap1", &error_abort);
|
||||||
|
object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
|
||||||
|
"hw-strap2", &error_abort);
|
||||||
|
|
||||||
|
object_initialize(&s->smc, sizeof(s->smc), "aspeed.smc.fmc");
|
||||||
|
object_property_add_child(obj, "smc", OBJECT(&s->smc), NULL);
|
||||||
|
qdev_set_parent_bus(DEVICE(&s->smc), sysbus_get_default());
|
||||||
|
|
||||||
|
object_initialize(&s->spi, sizeof(s->spi), "aspeed.smc.spi");
|
||||||
|
object_property_add_child(obj, "spi", OBJECT(&s->spi), NULL);
|
||||||
|
qdev_set_parent_bus(DEVICE(&s->spi), sysbus_get_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ast2400_realize(DeviceState *dev, Error **errp)
|
static void ast2400_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
AST2400State *s = AST2400(dev);
|
AST2400State *s = AST2400(dev);
|
||||||
Error *err = NULL;
|
Error *err = NULL, *local_err = NULL;
|
||||||
|
|
||||||
/* IO space */
|
/* IO space */
|
||||||
memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL,
|
memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL,
|
||||||
@@ -110,6 +137,14 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SCU */
|
||||||
|
object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, AST2400_SCU_BASE);
|
||||||
|
|
||||||
/* UART - attach an 8250 to the IO space as our UART5 */
|
/* UART - attach an 8250 to the IO space as our UART5 */
|
||||||
if (serial_hds[0]) {
|
if (serial_hds[0]) {
|
||||||
qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
|
qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
|
||||||
@@ -126,6 +161,30 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE);
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE);
|
||||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
|
||||||
qdev_get_gpio_in(DEVICE(&s->vic), 12));
|
qdev_get_gpio_in(DEVICE(&s->vic), 12));
|
||||||
|
|
||||||
|
/* SMC */
|
||||||
|
object_property_set_int(OBJECT(&s->smc), 1, "num-cs", &err);
|
||||||
|
object_property_set_bool(OBJECT(&s->smc), true, "realized", &local_err);
|
||||||
|
error_propagate(&err, local_err);
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, AST2400_FMC_BASE);
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, AST2400_FMC_FLASH_BASE);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0,
|
||||||
|
qdev_get_gpio_in(DEVICE(&s->vic), 19));
|
||||||
|
|
||||||
|
/* SPI */
|
||||||
|
object_property_set_int(OBJECT(&s->spi), 1, "num-cs", &err);
|
||||||
|
object_property_set_bool(OBJECT(&s->spi), true, "realized", &local_err);
|
||||||
|
error_propagate(&err, local_err);
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, AST2400_SPI_BASE);
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, AST2400_SPI_FLASH_BASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ast2400_class_init(ObjectClass *oc, void *data)
|
static void ast2400_class_init(ObjectClass *oc, void *data)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ static void fsl_imx25_init(Object *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
|
for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
|
||||||
object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX_GPT);
|
object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX25_GPT);
|
||||||
qdev_set_parent_bus(DEVICE(&s->gpt[i]), sysbus_get_default());
|
qdev_set_parent_bus(DEVICE(&s->gpt[i]), sysbus_get_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,16 +249,16 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* initialize 2 x 16 KB ROM */
|
/* initialize 2 x 16 KB ROM */
|
||||||
memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL,
|
memory_region_init_rom(&s->rom[0], NULL,
|
||||||
"imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
|
"imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
|
memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
|
||||||
&s->rom[0]);
|
&s->rom[0]);
|
||||||
memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL,
|
memory_region_init_rom(&s->rom[1], NULL,
|
||||||
"imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
|
"imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ static void fsl_imx31_init(Object *obj)
|
|||||||
qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
|
qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT);
|
object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX31_GPT);
|
||||||
qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
|
qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
|
||||||
|
|
||||||
for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) {
|
for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) {
|
||||||
@@ -219,9 +219,8 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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_rom_device(&s->secure_rom, NULL, NULL, NULL,
|
memory_region_init_rom(&s->secure_rom, NULL, "imx31.secure_rom",
|
||||||
"imx31.secure_rom",
|
FSL_IMX31_SECURE_ROM_SIZE, &err);
|
||||||
FSL_IMX31_SECURE_ROM_SIZE, &err);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
@@ -230,8 +229,8 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
|
|||||||
&s->secure_rom);
|
&s->secure_rom);
|
||||||
|
|
||||||
/* There is also a 16k ROM */
|
/* There is also a 16k ROM */
|
||||||
memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom",
|
memory_region_init_rom(&s->rom, NULL, "imx31.rom",
|
||||||
FSL_IMX31_ROM_SIZE, &err);
|
FSL_IMX31_ROM_SIZE, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ static void fsl_imx6_init(Object *obj)
|
|||||||
object_property_add_child(obj, name, OBJECT(&s->uart[i]), NULL);
|
object_property_add_child(obj, name, OBJECT(&s->uart[i]), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT);
|
object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX6_GPT);
|
||||||
qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
|
qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
|
||||||
object_property_add_child(obj, "gpt", OBJECT(&s->gpt), NULL);
|
object_property_add_child(obj, "gpt", OBJECT(&s->gpt), NULL);
|
||||||
|
|
||||||
@@ -399,8 +399,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
|
|||||||
FSL_IMX6_ENET_MAC_1588_IRQ));
|
FSL_IMX6_ENET_MAC_1588_IRQ));
|
||||||
|
|
||||||
/* ROM memory */
|
/* ROM memory */
|
||||||
memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx6.rom",
|
memory_region_init_rom(&s->rom, NULL, "imx6.rom",
|
||||||
FSL_IMX6_ROM_SIZE, &err);
|
FSL_IMX6_ROM_SIZE, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
@@ -409,8 +409,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
|
|||||||
&s->rom);
|
&s->rom);
|
||||||
|
|
||||||
/* CAAM memory */
|
/* CAAM memory */
|
||||||
memory_region_init_rom_device(&s->caam, NULL, NULL, NULL, "imx6.caam",
|
memory_region_init_rom(&s->caam, NULL, "imx6.caam",
|
||||||
FSL_IMX6_CAAM_MEM_SIZE, &err);
|
FSL_IMX6_CAAM_MEM_SIZE, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "hw/arm/ast2400.h"
|
#include "hw/arm/ast2400.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
|
#include "sysemu/block-backend.h"
|
||||||
|
#include "sysemu/blockdev.h"
|
||||||
|
|
||||||
static struct arm_boot_info palmetto_bmc_binfo = {
|
static struct arm_boot_info palmetto_bmc_binfo = {
|
||||||
.loader_start = AST2400_SDRAM_BASE,
|
.loader_start = AST2400_SDRAM_BASE,
|
||||||
@@ -30,6 +32,32 @@ typedef struct PalmettoBMCState {
|
|||||||
MemoryRegion ram;
|
MemoryRegion ram;
|
||||||
} PalmettoBMCState;
|
} PalmettoBMCState;
|
||||||
|
|
||||||
|
static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int i ;
|
||||||
|
|
||||||
|
for (i = 0; i < s->num_cs; ++i) {
|
||||||
|
AspeedSMCFlash *fl = &s->flashes[i];
|
||||||
|
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||||
|
qemu_irq cs_line;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: check that we are not using a flash module exceeding
|
||||||
|
* the controller segment size
|
||||||
|
*/
|
||||||
|
fl->flash = ssi_create_slave_no_init(s->spi, flashtype);
|
||||||
|
if (dinfo) {
|
||||||
|
qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
|
||||||
|
errp);
|
||||||
|
}
|
||||||
|
qdev_init_nofail(fl->flash);
|
||||||
|
|
||||||
|
cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void palmetto_bmc_init(MachineState *machine)
|
static void palmetto_bmc_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
PalmettoBMCState *bmc;
|
PalmettoBMCState *bmc;
|
||||||
@@ -44,9 +72,14 @@ static void palmetto_bmc_init(MachineState *machine)
|
|||||||
&bmc->ram);
|
&bmc->ram);
|
||||||
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
|
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
|
||||||
&error_abort);
|
&error_abort);
|
||||||
|
object_property_set_int(OBJECT(&bmc->soc), 0x120CE416, "hw-strap1",
|
||||||
|
&error_abort);
|
||||||
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
|
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
|
||||||
&error_abort);
|
&error_abort);
|
||||||
|
|
||||||
|
palmetto_bmc_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort);
|
||||||
|
palmetto_bmc_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort);
|
||||||
|
|
||||||
palmetto_bmc_binfo.kernel_filename = machine->kernel_filename;
|
palmetto_bmc_binfo.kernel_filename = machine->kernel_filename;
|
||||||
palmetto_bmc_binfo.initrd_filename = machine->initrd_filename;
|
palmetto_bmc_binfo.initrd_filename = machine->initrd_filename;
|
||||||
palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline;
|
palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||||
|
|||||||
@@ -86,13 +86,19 @@ static void sabrelite_init(MachineState *machine)
|
|||||||
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");
|
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");
|
||||||
if (spi_bus) {
|
if (spi_bus) {
|
||||||
DeviceState *flash_dev;
|
DeviceState *flash_dev;
|
||||||
|
qemu_irq cs_line;
|
||||||
|
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||||
|
|
||||||
flash_dev = ssi_create_slave(spi_bus, "sst25vf016b");
|
flash_dev = ssi_create_slave_no_init(spi_bus, "sst25vf016b");
|
||||||
if (flash_dev) {
|
if (dinfo) {
|
||||||
qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev,
|
qdev_prop_set_drive(flash_dev, "drive",
|
||||||
SSI_GPIO_CS, 0);
|
blk_by_legacy_dinfo(dinfo),
|
||||||
sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
|
&error_fatal);
|
||||||
}
|
}
|
||||||
|
qdev_init_nofail(flash_dev);
|
||||||
|
|
||||||
|
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -598,15 +598,13 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spitz_lcdtg_init(SSISlave *dev)
|
static void spitz_lcdtg_realize(SSISlave *dev, Error **errp)
|
||||||
{
|
{
|
||||||
SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
|
SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
|
||||||
|
|
||||||
spitz_lcdtg = s;
|
spitz_lcdtg = s;
|
||||||
s->bl_power = 0;
|
s->bl_power = 0;
|
||||||
s->bl_intensity = 0x20;
|
s->bl_intensity = 0x20;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SSP devices */
|
/* SSP devices */
|
||||||
@@ -666,7 +664,7 @@ static void spitz_adc_temp_on(void *opaque, int line, int level)
|
|||||||
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
|
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int corgi_ssp_init(SSISlave *d)
|
static void corgi_ssp_realize(SSISlave *d, Error **errp)
|
||||||
{
|
{
|
||||||
DeviceState *dev = DEVICE(d);
|
DeviceState *dev = DEVICE(d);
|
||||||
CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d);
|
CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d);
|
||||||
@@ -675,8 +673,6 @@ static int corgi_ssp_init(SSISlave *d)
|
|||||||
s->bus[0] = ssi_create_bus(dev, "ssi0");
|
s->bus[0] = ssi_create_bus(dev, "ssi0");
|
||||||
s->bus[1] = ssi_create_bus(dev, "ssi1");
|
s->bus[1] = ssi_create_bus(dev, "ssi1");
|
||||||
s->bus[2] = ssi_create_bus(dev, "ssi2");
|
s->bus[2] = ssi_create_bus(dev, "ssi2");
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spitz_ssp_attach(PXA2xxState *cpu)
|
static void spitz_ssp_attach(PXA2xxState *cpu)
|
||||||
@@ -1121,7 +1117,7 @@ static void corgi_ssp_class_init(ObjectClass *klass, void *data)
|
|||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
||||||
|
|
||||||
k->init = corgi_ssp_init;
|
k->realize = corgi_ssp_realize;
|
||||||
k->transfer = corgi_ssp_transfer;
|
k->transfer = corgi_ssp_transfer;
|
||||||
dc->vmsd = &vmstate_corgi_ssp_regs;
|
dc->vmsd = &vmstate_corgi_ssp_regs;
|
||||||
}
|
}
|
||||||
@@ -1150,7 +1146,7 @@ static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
|
|||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
||||||
|
|
||||||
k->init = spitz_lcdtg_init;
|
k->realize = spitz_lcdtg_realize;
|
||||||
k->transfer = spitz_lcdtg_transfer;
|
k->transfer = spitz_lcdtg_transfer;
|
||||||
dc->vmsd = &vmstate_spitz_lcdtg_regs;
|
dc->vmsd = &vmstate_spitz_lcdtg_regs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,10 +127,9 @@ static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tosa_ssp_init(SSISlave *dev)
|
static void tosa_ssp_realize(SSISlave *dev, Error **errp)
|
||||||
{
|
{
|
||||||
/* Nothing to do. */
|
/* Nothing to do. */
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TYPE_TOSA_DAC "tosa_dac"
|
#define TYPE_TOSA_DAC "tosa_dac"
|
||||||
@@ -283,7 +282,7 @@ static void tosa_ssp_class_init(ObjectClass *klass, void *data)
|
|||||||
{
|
{
|
||||||
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
||||||
|
|
||||||
k->init = tosa_ssp_init;
|
k->realize = tosa_ssp_realize;
|
||||||
k->transfer = tosa_ssp_tansfer;
|
k->transfer = tosa_ssp_tansfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1021,6 +1021,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
|
|||||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2);
|
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2);
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
|
||||||
nr_pcie_buses - 1);
|
nr_pcie_buses - 1);
|
||||||
|
qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0);
|
||||||
|
|
||||||
if (vbi->v2m_phandle) {
|
if (vbi->v2m_phandle) {
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
|
||||||
@@ -1175,6 +1176,10 @@ static void machvirt_init(MachineState *machine)
|
|||||||
VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
|
VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
|
||||||
VirtGuestInfo *guest_info = &guest_info_state->info;
|
VirtGuestInfo *guest_info = &guest_info_state->info;
|
||||||
char **cpustr;
|
char **cpustr;
|
||||||
|
ObjectClass *oc;
|
||||||
|
const char *typename;
|
||||||
|
CPUClass *cc;
|
||||||
|
Error *err = NULL;
|
||||||
bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
||||||
|
|
||||||
if (!cpu_model) {
|
if (!cpu_model) {
|
||||||
@@ -1258,26 +1263,24 @@ static void machvirt_init(MachineState *machine)
|
|||||||
|
|
||||||
create_fdt(vbi);
|
create_fdt(vbi);
|
||||||
|
|
||||||
|
oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
|
||||||
|
if (!oc) {
|
||||||
|
error_report("Unable to find CPU definition");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
typename = object_class_get_name(oc);
|
||||||
|
|
||||||
|
/* convert -smp CPU options specified by the user into global props */
|
||||||
|
cc = CPU_CLASS(oc);
|
||||||
|
cc->parse_features(typename, cpustr[1], &err);
|
||||||
|
g_strfreev(cpustr);
|
||||||
|
if (err) {
|
||||||
|
error_report_err(err);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
for (n = 0; n < smp_cpus; n++) {
|
||||||
ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
|
Object *cpuobj = object_new(typename);
|
||||||
CPUClass *cc = CPU_CLASS(oc);
|
|
||||||
Object *cpuobj;
|
|
||||||
Error *err = NULL;
|
|
||||||
char *cpuopts = g_strdup(cpustr[1]);
|
|
||||||
|
|
||||||
if (!oc) {
|
|
||||||
error_report("Unable to find CPU definition");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
cpuobj = object_new(object_class_get_name(oc));
|
|
||||||
|
|
||||||
/* Handle any CPU options specified by the user */
|
|
||||||
cc->parse_features(CPU(cpuobj), cpuopts, &err);
|
|
||||||
g_free(cpuopts);
|
|
||||||
if (err) {
|
|
||||||
error_report_err(err);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vms->secure) {
|
if (!vms->secure) {
|
||||||
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||||
@@ -1308,7 +1311,6 @@ static void machvirt_init(MachineState *machine)
|
|||||||
|
|
||||||
object_property_set_bool(cpuobj, true, "realized", NULL);
|
object_property_set_bool(cpuobj, true, "realized", NULL);
|
||||||
}
|
}
|
||||||
g_strfreev(cpustr);
|
|
||||||
fdt_add_timer_nodes(vbi, gic_version);
|
fdt_add_timer_nodes(vbi, gic_version);
|
||||||
fdt_add_cpu_nodes(vbi);
|
fdt_add_cpu_nodes(vbi);
|
||||||
fdt_add_psci_node(vbi);
|
fdt_add_psci_node(vbi);
|
||||||
|
|||||||
@@ -138,7 +138,13 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
|
|||||||
spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
|
spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
|
||||||
|
|
||||||
for (j = 0; j < num_ss; ++j) {
|
for (j = 0; j < num_ss; ++j) {
|
||||||
flash_dev = ssi_create_slave(spi, "n25q128");
|
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||||
|
flash_dev = ssi_create_slave_no_init(spi, "n25q128");
|
||||||
|
if (dinfo) {
|
||||||
|
qdev_prop_set_drive(flash_dev, "drive",
|
||||||
|
blk_by_legacy_dinfo(dinfo), &error_fatal);
|
||||||
|
}
|
||||||
|
qdev_init_nofail(flash_dev);
|
||||||
|
|
||||||
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
|
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
|
||||||
sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
|
sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
|
||||||
@@ -294,6 +300,12 @@ static void zynq_init(MachineState *machine)
|
|||||||
sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
|
sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev = qdev_create(NULL, "xlnx.ps7-dev-cfg");
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
|
sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]);
|
||||||
|
sysbus_mmio_map(busdev, 0, 0xF8007000);
|
||||||
|
|
||||||
zynq_binfo.ram_size = ram_size;
|
zynq_binfo.ram_size = ram_size;
|
||||||
zynq_binfo.kernel_filename = kernel_filename;
|
zynq_binfo.kernel_filename = kernel_filename;
|
||||||
zynq_binfo.kernel_cmdline = kernel_cmdline;
|
zynq_binfo.kernel_cmdline = kernel_cmdline;
|
||||||
|
|||||||
@@ -88,12 +88,19 @@ static void xlnx_ep108_init(MachineState *machine)
|
|||||||
SSIBus *spi_bus;
|
SSIBus *spi_bus;
|
||||||
DeviceState *flash_dev;
|
DeviceState *flash_dev;
|
||||||
qemu_irq cs_line;
|
qemu_irq cs_line;
|
||||||
|
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||||
gchar *bus_name = g_strdup_printf("spi%d", i);
|
gchar *bus_name = g_strdup_printf("spi%d", i);
|
||||||
|
|
||||||
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
|
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
|
||||||
g_free(bus_name);
|
g_free(bus_name);
|
||||||
|
|
||||||
flash_dev = ssi_create_slave(spi_bus, "sst25wf080");
|
flash_dev = ssi_create_slave_no_init(spi_bus, "sst25wf080");
|
||||||
|
if (dinfo) {
|
||||||
|
qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo),
|
||||||
|
&error_fatal);
|
||||||
|
}
|
||||||
|
qdev_init_nofail(flash_dev);
|
||||||
|
|
||||||
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
|
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
|
||||||
|
|
||||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);
|
||||||
|
|||||||
@@ -151,14 +151,12 @@ static void z2_lcd_cs(void *opaque, int line, int level)
|
|||||||
z2_lcd->selected = !level;
|
z2_lcd->selected = !level;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zipit_lcd_init(SSISlave *dev)
|
static void zipit_lcd_realize(SSISlave *dev, Error **errp)
|
||||||
{
|
{
|
||||||
ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
|
ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
|
||||||
z->selected = 0;
|
z->selected = 0;
|
||||||
z->enabled = 0;
|
z->enabled = 0;
|
||||||
z->pos = 0;
|
z->pos = 0;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VMStateDescription vmstate_zipit_lcd_state = {
|
static VMStateDescription vmstate_zipit_lcd_state = {
|
||||||
@@ -181,7 +179,7 @@ static void zipit_lcd_class_init(ObjectClass *klass, void *data)
|
|||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
||||||
|
|
||||||
k->init = zipit_lcd_init;
|
k->realize = zipit_lcd_realize;
|
||||||
k->transfer = zipit_lcd_transfer;
|
k->transfer = zipit_lcd_transfer;
|
||||||
dc->vmsd = &vmstate_zipit_lcd_state;
|
dc->vmsd = &vmstate_zipit_lcd_state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ struct IntelHDAState {
|
|||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
uint32_t debug;
|
uint32_t debug;
|
||||||
uint32_t msi;
|
OnOffAuto msi;
|
||||||
bool old_msi_addr;
|
bool old_msi_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
|
|||||||
|
|
||||||
static void intel_hda_update_irq(IntelHDAState *d)
|
static void intel_hda_update_irq(IntelHDAState *d)
|
||||||
{
|
{
|
||||||
int msi = d->msi && msi_enabled(&d->pci);
|
bool msi = msi_enabled(&d->pci);
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
intel_hda_update_int_sts(d);
|
intel_hda_update_int_sts(d);
|
||||||
@@ -1132,6 +1132,8 @@ static void intel_hda_realize(PCIDevice *pci, Error **errp)
|
|||||||
{
|
{
|
||||||
IntelHDAState *d = INTEL_HDA(pci);
|
IntelHDAState *d = INTEL_HDA(pci);
|
||||||
uint8_t *conf = d->pci.config;
|
uint8_t *conf = d->pci.config;
|
||||||
|
Error *err = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
d->name = object_get_typename(OBJECT(d));
|
d->name = object_get_typename(OBJECT(d));
|
||||||
|
|
||||||
@@ -1140,12 +1142,27 @@ static void intel_hda_realize(PCIDevice *pci, Error **errp)
|
|||||||
/* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
|
/* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
|
||||||
conf[0x40] = 0x01;
|
conf[0x40] = 0x01;
|
||||||
|
|
||||||
|
if (d->msi != ON_OFF_AUTO_OFF) {
|
||||||
|
ret = msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60,
|
||||||
|
1, true, false, &err);
|
||||||
|
/* Any error other than -ENOTSUP(board's MSI support is broken)
|
||||||
|
* is a programming error */
|
||||||
|
assert(!ret || ret == -ENOTSUP);
|
||||||
|
if (ret && d->msi == ON_OFF_AUTO_ON) {
|
||||||
|
/* Can't satisfy user's explicit msi=on request, fail */
|
||||||
|
error_append_hint(&err, "You have to use msi=auto (default) or "
|
||||||
|
"msi=off with this machine type.\n");
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(!err || d->msi == ON_OFF_AUTO_AUTO);
|
||||||
|
/* With msi=auto, we fall back to MSI off silently */
|
||||||
|
error_free(err);
|
||||||
|
}
|
||||||
|
|
||||||
memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d,
|
memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d,
|
||||||
"intel-hda", 0x4000);
|
"intel-hda", 0x4000);
|
||||||
pci_register_bar(&d->pci, 0, 0, &d->mmio);
|
pci_register_bar(&d->pci, 0, 0, &d->mmio);
|
||||||
if (d->msi) {
|
|
||||||
msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs),
|
hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs),
|
||||||
intel_hda_response, intel_hda_xfer);
|
intel_hda_response, intel_hda_xfer);
|
||||||
@@ -1235,7 +1252,7 @@ static const VMStateDescription vmstate_intel_hda = {
|
|||||||
|
|
||||||
static Property intel_hda_properties[] = {
|
static Property intel_hda_properties[] = {
|
||||||
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
|
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
|
||||||
DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
|
DEFINE_PROP_ON_OFF_AUTO("msi", IntelHDAState, msi, ON_OFF_AUTO_AUTO),
|
||||||
DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false),
|
DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "hw/timer/i8254.h"
|
#include "hw/timer/i8254.h"
|
||||||
#include "hw/audio/pcspk.h"
|
#include "hw/audio/pcspk.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
#define PCSPK_BUF_LEN 1792
|
#define PCSPK_BUF_LEN 1792
|
||||||
#define PCSPK_SAMPLE_RATE 32000
|
#define PCSPK_SAMPLE_RATE 32000
|
||||||
@@ -169,6 +170,11 @@ static void pcspk_initfn(Object *obj)
|
|||||||
PCSpkState *s = PC_SPEAKER(obj);
|
PCSpkState *s = PC_SPEAKER(obj);
|
||||||
|
|
||||||
memory_region_init_io(&s->ioport, OBJECT(s), &pcspk_io_ops, s, "pcspk", 1);
|
memory_region_init_io(&s->ioport, OBJECT(s), &pcspk_io_ops, s, "pcspk", 1);
|
||||||
|
|
||||||
|
object_property_add_link(obj, "pit", TYPE_PIT_COMMON,
|
||||||
|
(Object **)&s->pit,
|
||||||
|
qdev_prop_allow_set_link_before_realize,
|
||||||
|
0, &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pcspk_realizefn(DeviceState *dev, Error **errp)
|
static void pcspk_realizefn(DeviceState *dev, Error **errp)
|
||||||
@@ -183,7 +189,6 @@ static void pcspk_realizefn(DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
static Property pcspk_properties[] = {
|
static Property pcspk_properties[] = {
|
||||||
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
|
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
|
||||||
DEFINE_PROP_PTR("pit", PCSpkState, pit),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -194,7 +199,7 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data)
|
|||||||
dc->realize = pcspk_realizefn;
|
dc->realize = pcspk_realizefn;
|
||||||
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
||||||
dc->props = pcspk_properties;
|
dc->props = pcspk_properties;
|
||||||
/* Reason: pointer property "pit", realize sets global pcspk_state */
|
/* Reason: realize sets global pcspk_state */
|
||||||
dc->cannot_instantiate_with_device_add_yet = true;
|
dc->cannot_instantiate_with_device_add_yet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,9 @@ struct VirtIOBlockDataPlane {
|
|||||||
bool stopping;
|
bool stopping;
|
||||||
|
|
||||||
VirtIOBlkConf *conf;
|
VirtIOBlkConf *conf;
|
||||||
|
|
||||||
VirtIODevice *vdev;
|
VirtIODevice *vdev;
|
||||||
VirtQueue *vq; /* virtqueue vring */
|
|
||||||
EventNotifier *guest_notifier; /* irq */
|
|
||||||
QEMUBH *bh; /* bh for guest notification */
|
QEMUBH *bh; /* bh for guest notification */
|
||||||
|
unsigned long *batch_notify_vqs;
|
||||||
|
|
||||||
/* Note that these EventNotifiers are assigned by value. This is
|
/* Note that these EventNotifiers are assigned by value. This is
|
||||||
* fine as long as you do not call event_notifier_cleanup on them
|
* fine as long as you do not call event_notifier_cleanup on them
|
||||||
@@ -47,20 +45,36 @@ struct VirtIOBlockDataPlane {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Raise an interrupt to signal guest, if necessary */
|
/* Raise an interrupt to signal guest, if necessary */
|
||||||
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s)
|
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq)
|
||||||
{
|
{
|
||||||
|
set_bit(virtio_get_queue_index(vq), s->batch_notify_vqs);
|
||||||
qemu_bh_schedule(s->bh);
|
qemu_bh_schedule(s->bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notify_guest_bh(void *opaque)
|
static void notify_guest_bh(void *opaque)
|
||||||
{
|
{
|
||||||
VirtIOBlockDataPlane *s = opaque;
|
VirtIOBlockDataPlane *s = opaque;
|
||||||
|
unsigned nvqs = s->conf->num_queues;
|
||||||
|
unsigned long bitmap[BITS_TO_LONGS(nvqs)];
|
||||||
|
unsigned j;
|
||||||
|
|
||||||
if (!virtio_should_notify(s->vdev, s->vq)) {
|
memcpy(bitmap, s->batch_notify_vqs, sizeof(bitmap));
|
||||||
return;
|
memset(s->batch_notify_vqs, 0, sizeof(bitmap));
|
||||||
|
|
||||||
|
for (j = 0; j < nvqs; j += BITS_PER_LONG) {
|
||||||
|
unsigned long bits = bitmap[j];
|
||||||
|
|
||||||
|
while (bits != 0) {
|
||||||
|
unsigned i = j + ctzl(bits);
|
||||||
|
VirtQueue *vq = virtio_get_queue(s->vdev, i);
|
||||||
|
|
||||||
|
if (virtio_should_notify(s->vdev, vq)) {
|
||||||
|
event_notifier_set(virtio_queue_get_guest_notifier(vq));
|
||||||
|
}
|
||||||
|
|
||||||
|
bits &= bits - 1; /* clear right-most bit */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event_notifier_set(s->guest_notifier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Context: QEMU global mutex held */
|
/* Context: QEMU global mutex held */
|
||||||
@@ -79,7 +93,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Don't try if transport does not support notifiers. */
|
/* Don't try if transport does not support notifiers. */
|
||||||
if (!k->set_guest_notifiers || !k->set_host_notifier) {
|
if (!k->set_guest_notifiers || !k->ioeventfd_started) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"device is incompatible with dataplane "
|
"device is incompatible with dataplane "
|
||||||
"(transport does not support notifiers)");
|
"(transport does not support notifiers)");
|
||||||
@@ -104,6 +118,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
|||||||
}
|
}
|
||||||
s->ctx = iothread_get_aio_context(s->iothread);
|
s->ctx = iothread_get_aio_context(s->iothread);
|
||||||
s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
|
s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
|
||||||
|
s->batch_notify_vqs = bitmap_new(conf->num_queues);
|
||||||
|
|
||||||
*dataplane = s;
|
*dataplane = s;
|
||||||
}
|
}
|
||||||
@@ -116,6 +131,7 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtio_blk_data_plane_stop(s);
|
virtio_blk_data_plane_stop(s);
|
||||||
|
g_free(s->batch_notify_vqs);
|
||||||
qemu_bh_delete(s->bh);
|
qemu_bh_delete(s->bh);
|
||||||
object_unref(OBJECT(s->iothread));
|
object_unref(OBJECT(s->iothread));
|
||||||
g_free(s);
|
g_free(s);
|
||||||
@@ -138,6 +154,8 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
|
|||||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
|
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
|
||||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||||
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
||||||
|
unsigned i;
|
||||||
|
unsigned nvqs = s->conf->num_queues;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (vblk->dataplane_started || s->starting) {
|
if (vblk->dataplane_started || s->starting) {
|
||||||
@@ -145,22 +163,25 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->starting = true;
|
s->starting = true;
|
||||||
s->vq = virtio_get_queue(s->vdev, 0);
|
|
||||||
|
|
||||||
/* Set up guest notifier (irq) */
|
/* Set up guest notifier (irq) */
|
||||||
r = k->set_guest_notifiers(qbus->parent, 1, true);
|
r = k->set_guest_notifiers(qbus->parent, nvqs, true);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf(stderr, "virtio-blk failed to set guest notifier (%d), "
|
fprintf(stderr, "virtio-blk failed to set guest notifier (%d), "
|
||||||
"ensure -enable-kvm is set\n", r);
|
"ensure -enable-kvm is set\n", r);
|
||||||
goto fail_guest_notifiers;
|
goto fail_guest_notifiers;
|
||||||
}
|
}
|
||||||
s->guest_notifier = virtio_queue_get_guest_notifier(s->vq);
|
|
||||||
|
|
||||||
/* Set up virtqueue notify */
|
/* Set up virtqueue notify */
|
||||||
r = k->set_host_notifier(qbus->parent, 0, true);
|
for (i = 0; i < nvqs; i++) {
|
||||||
if (r != 0) {
|
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, true);
|
||||||
fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
|
if (r != 0) {
|
||||||
goto fail_host_notifier;
|
fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
|
||||||
|
while (i--) {
|
||||||
|
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
|
||||||
|
}
|
||||||
|
goto fail_guest_notifiers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s->starting = false;
|
s->starting = false;
|
||||||
@@ -170,17 +191,23 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
|
|||||||
blk_set_aio_context(s->conf->conf.blk, s->ctx);
|
blk_set_aio_context(s->conf->conf.blk, s->ctx);
|
||||||
|
|
||||||
/* Kick right away to begin processing requests already in vring */
|
/* Kick right away to begin processing requests already in vring */
|
||||||
event_notifier_set(virtio_queue_get_host_notifier(s->vq));
|
for (i = 0; i < nvqs; i++) {
|
||||||
|
VirtQueue *vq = virtio_get_queue(s->vdev, i);
|
||||||
|
|
||||||
|
event_notifier_set(virtio_queue_get_host_notifier(vq));
|
||||||
|
}
|
||||||
|
|
||||||
/* Get this show started by hooking up our callbacks */
|
/* Get this show started by hooking up our callbacks */
|
||||||
aio_context_acquire(s->ctx);
|
aio_context_acquire(s->ctx);
|
||||||
virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx,
|
for (i = 0; i < nvqs; i++) {
|
||||||
virtio_blk_data_plane_handle_output);
|
VirtQueue *vq = virtio_get_queue(s->vdev, i);
|
||||||
|
|
||||||
|
virtio_queue_aio_set_host_notifier_handler(vq, s->ctx,
|
||||||
|
virtio_blk_data_plane_handle_output);
|
||||||
|
}
|
||||||
aio_context_release(s->ctx);
|
aio_context_release(s->ctx);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fail_host_notifier:
|
|
||||||
k->set_guest_notifiers(qbus->parent, 1, false);
|
|
||||||
fail_guest_notifiers:
|
fail_guest_notifiers:
|
||||||
vblk->dataplane_disabled = true;
|
vblk->dataplane_disabled = true;
|
||||||
s->starting = false;
|
s->starting = false;
|
||||||
@@ -193,6 +220,8 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
|
|||||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
|
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
|
||||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||||
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
||||||
|
unsigned i;
|
||||||
|
unsigned nvqs = s->conf->num_queues;
|
||||||
|
|
||||||
if (!vblk->dataplane_started || s->stopping) {
|
if (!vblk->dataplane_started || s->stopping) {
|
||||||
return;
|
return;
|
||||||
@@ -210,17 +239,23 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
|
|||||||
aio_context_acquire(s->ctx);
|
aio_context_acquire(s->ctx);
|
||||||
|
|
||||||
/* Stop notifications for new requests from guest */
|
/* Stop notifications for new requests from guest */
|
||||||
virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, NULL);
|
for (i = 0; i < nvqs; i++) {
|
||||||
|
VirtQueue *vq = virtio_get_queue(s->vdev, i);
|
||||||
|
|
||||||
|
virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Drain and switch bs back to the QEMU main loop */
|
/* Drain and switch bs back to the QEMU main loop */
|
||||||
blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
|
blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
|
||||||
|
|
||||||
aio_context_release(s->ctx);
|
aio_context_release(s->ctx);
|
||||||
|
|
||||||
k->set_host_notifier(qbus->parent, 0, false);
|
for (i = 0; i < nvqs; i++) {
|
||||||
|
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clean up guest notifier (irq) */
|
/* Clean up guest notifier (irq) */
|
||||||
k->set_guest_notifiers(qbus->parent, 1, false);
|
k->set_guest_notifiers(qbus->parent, nvqs, false);
|
||||||
|
|
||||||
vblk->dataplane_started = false;
|
vblk->dataplane_started = false;
|
||||||
s->stopping = false;
|
s->stopping = false;
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
|
|||||||
void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s);
|
void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s);
|
||||||
void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s);
|
void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s);
|
||||||
void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s);
|
void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s);
|
||||||
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s);
|
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq);
|
||||||
|
|
||||||
#endif /* HW_DATAPLANE_VIRTIO_BLK_H */
|
#endif /* HW_DATAPLANE_VIRTIO_BLK_H */
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "hw/ssi/ssi.h"
|
#include "hw/ssi/ssi.h"
|
||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
#ifndef M25P80_ERR_DEBUG
|
#ifndef M25P80_ERR_DEBUG
|
||||||
#define M25P80_ERR_DEBUG 0
|
#define M25P80_ERR_DEBUG 0
|
||||||
@@ -53,12 +54,17 @@
|
|||||||
/* 16 MiB max in 3 byte address mode */
|
/* 16 MiB max in 3 byte address mode */
|
||||||
#define MAX_3BYTES_SIZE 0x1000000
|
#define MAX_3BYTES_SIZE 0x1000000
|
||||||
|
|
||||||
|
#define SPI_NOR_MAX_ID_LEN 6
|
||||||
|
|
||||||
typedef struct FlashPartInfo {
|
typedef struct FlashPartInfo {
|
||||||
const char *part_name;
|
const char *part_name;
|
||||||
/* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */
|
/*
|
||||||
uint32_t jedec;
|
* This array stores the ID bytes.
|
||||||
/* extended jedec code */
|
* The first three bytes are the JEDIC ID.
|
||||||
uint16_t ext_jedec;
|
* JEDEC ID zero means "no ID" (mostly older chips).
|
||||||
|
*/
|
||||||
|
uint8_t id[SPI_NOR_MAX_ID_LEN];
|
||||||
|
uint8_t id_len;
|
||||||
/* there is confusion between manufacturers as to what a sector is. In this
|
/* there is confusion between manufacturers as to what a sector is. In this
|
||||||
* device model, a "sector" is the size that is erased by the ERASE_SECTOR
|
* device model, a "sector" is the size that is erased by the ERASE_SECTOR
|
||||||
* command (opcode 0xd8).
|
* command (opcode 0xd8).
|
||||||
@@ -70,11 +76,33 @@ typedef struct FlashPartInfo {
|
|||||||
} FlashPartInfo;
|
} FlashPartInfo;
|
||||||
|
|
||||||
/* adapted from linux */
|
/* adapted from linux */
|
||||||
|
/* Used when the "_ext_id" is two bytes at most */
|
||||||
|
#define INFO(_part_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)\
|
||||||
|
.part_name = _part_name,\
|
||||||
|
.id = {\
|
||||||
|
((_jedec_id) >> 16) & 0xff,\
|
||||||
|
((_jedec_id) >> 8) & 0xff,\
|
||||||
|
(_jedec_id) & 0xff,\
|
||||||
|
((_ext_id) >> 8) & 0xff,\
|
||||||
|
(_ext_id) & 0xff,\
|
||||||
|
},\
|
||||||
|
.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),\
|
||||||
|
.sector_size = (_sector_size),\
|
||||||
|
.n_sectors = (_n_sectors),\
|
||||||
|
.page_size = 256,\
|
||||||
|
.flags = (_flags),
|
||||||
|
|
||||||
#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\
|
#define INFO6(_part_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)\
|
||||||
.part_name = (_part_name),\
|
.part_name = _part_name,\
|
||||||
.jedec = (_jedec),\
|
.id = {\
|
||||||
.ext_jedec = (_ext_jedec),\
|
((_jedec_id) >> 16) & 0xff,\
|
||||||
|
((_jedec_id) >> 8) & 0xff,\
|
||||||
|
(_jedec_id) & 0xff,\
|
||||||
|
((_ext_id) >> 16) & 0xff,\
|
||||||
|
((_ext_id) >> 8) & 0xff,\
|
||||||
|
(_ext_id) & 0xff,\
|
||||||
|
},\
|
||||||
|
.id_len = 6,\
|
||||||
.sector_size = (_sector_size),\
|
.sector_size = (_sector_size),\
|
||||||
.n_sectors = (_n_sectors),\
|
.n_sectors = (_n_sectors),\
|
||||||
.page_size = 256,\
|
.page_size = 256,\
|
||||||
@@ -102,12 +130,26 @@ typedef struct FlashPartInfo {
|
|||||||
#define EVCFG_QUAD_IO_ENABLED (1 << 7)
|
#define EVCFG_QUAD_IO_ENABLED (1 << 7)
|
||||||
#define NVCFG_4BYTE_ADDR_MASK (1 << 0)
|
#define NVCFG_4BYTE_ADDR_MASK (1 << 0)
|
||||||
#define NVCFG_LOWER_SEGMENT_MASK (1 << 1)
|
#define NVCFG_LOWER_SEGMENT_MASK (1 << 1)
|
||||||
#define CFG_UPPER_128MB_SEG_ENABLED 0x3
|
|
||||||
|
|
||||||
/* Numonyx (Micron) Flag Status Register macros */
|
/* Numonyx (Micron) Flag Status Register macros */
|
||||||
#define FSR_4BYTE_ADDR_MODE_ENABLED 0x1
|
#define FSR_4BYTE_ADDR_MODE_ENABLED 0x1
|
||||||
#define FSR_FLASH_READY (1 << 7)
|
#define FSR_FLASH_READY (1 << 7)
|
||||||
|
|
||||||
|
/* Spansion configuration registers macros. */
|
||||||
|
#define SPANSION_QUAD_CFG_POS 0
|
||||||
|
#define SPANSION_QUAD_CFG_LEN 1
|
||||||
|
#define SPANSION_DUMMY_CLK_POS 0
|
||||||
|
#define SPANSION_DUMMY_CLK_LEN 4
|
||||||
|
#define SPANSION_ADDR_LEN_POS 7
|
||||||
|
#define SPANSION_ADDR_LEN_LEN 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spansion read mode command length in bytes,
|
||||||
|
* the mode is currently not supported.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPANSION_CONTINUOUS_READ_MODE_CMD_LEN 1
|
||||||
|
|
||||||
static const FlashPartInfo known_devices[] = {
|
static const FlashPartInfo known_devices[] = {
|
||||||
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
|
/* Atmel -- some are (confusingly) marketed as "DataFlash" */
|
||||||
{ INFO("at25fs010", 0x1f6601, 0, 32 << 10, 4, ER_4K) },
|
{ INFO("at25fs010", 0x1f6601, 0, 32 << 10, 4, ER_4K) },
|
||||||
@@ -158,6 +200,8 @@ static const FlashPartInfo known_devices[] = {
|
|||||||
{ INFO("mx25l12855e", 0xc22618, 0, 64 << 10, 256, 0) },
|
{ INFO("mx25l12855e", 0xc22618, 0, 64 << 10, 256, 0) },
|
||||||
{ INFO("mx25l25635e", 0xc22019, 0, 64 << 10, 512, 0) },
|
{ INFO("mx25l25635e", 0xc22019, 0, 64 << 10, 512, 0) },
|
||||||
{ INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) },
|
{ INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) },
|
||||||
|
{ INFO("mx66u51235f", 0xc2253a, 0, 64 << 10, 1024, ER_4K | ER_32K) },
|
||||||
|
{ INFO("mx66u1g45g", 0xc2253b, 0, 64 << 10, 2048, ER_4K | ER_32K) },
|
||||||
|
|
||||||
/* Micron */
|
/* Micron */
|
||||||
{ INFO("n25q032a11", 0x20bb16, 0, 64 << 10, 64, ER_4K) },
|
{ INFO("n25q032a11", 0x20bb16, 0, 64 << 10, 64, ER_4K) },
|
||||||
@@ -168,6 +212,11 @@ static const FlashPartInfo known_devices[] = {
|
|||||||
{ INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, ER_4K) },
|
{ INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, ER_4K) },
|
||||||
{ INFO("n25q256a11", 0x20bb19, 0, 64 << 10, 512, ER_4K) },
|
{ INFO("n25q256a11", 0x20bb19, 0, 64 << 10, 512, ER_4K) },
|
||||||
{ INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
{ INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
||||||
|
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
|
||||||
|
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
||||||
|
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
||||||
|
{ INFO("mt25ql01g", 0x20ba21, 0, 64 << 10, 2048, ER_4K) },
|
||||||
|
{ INFO("mt25qu01g", 0x20bb21, 0, 64 << 10, 2048, ER_4K) },
|
||||||
|
|
||||||
/* Spansion -- single (large) sector size only, at least
|
/* Spansion -- single (large) sector size only, at least
|
||||||
* for the chips listed here (without boot sectors).
|
* for the chips listed here (without boot sectors).
|
||||||
@@ -176,8 +225,8 @@ static const FlashPartInfo known_devices[] = {
|
|||||||
{ INFO("s25sl064p", 0x010216, 0x4d00, 64 << 10, 128, ER_4K) },
|
{ INFO("s25sl064p", 0x010216, 0x4d00, 64 << 10, 128, ER_4K) },
|
||||||
{ INFO("s25fl256s0", 0x010219, 0x4d00, 256 << 10, 128, 0) },
|
{ INFO("s25fl256s0", 0x010219, 0x4d00, 256 << 10, 128, 0) },
|
||||||
{ INFO("s25fl256s1", 0x010219, 0x4d01, 64 << 10, 512, 0) },
|
{ INFO("s25fl256s1", 0x010219, 0x4d01, 64 << 10, 512, 0) },
|
||||||
{ INFO("s25fl512s", 0x010220, 0x4d00, 256 << 10, 256, 0) },
|
{ INFO6("s25fl512s", 0x010220, 0x4d0080, 256 << 10, 256, 0) },
|
||||||
{ INFO("s70fl01gs", 0x010221, 0x4d00, 256 << 10, 256, 0) },
|
{ INFO6("s70fl01gs", 0x010221, 0x4d0080, 256 << 10, 512, 0) },
|
||||||
{ INFO("s25sl12800", 0x012018, 0x0300, 256 << 10, 64, 0) },
|
{ INFO("s25sl12800", 0x012018, 0x0300, 256 << 10, 64, 0) },
|
||||||
{ INFO("s25sl12801", 0x012018, 0x0301, 64 << 10, 256, 0) },
|
{ INFO("s25sl12801", 0x012018, 0x0301, 64 << 10, 256, 0) },
|
||||||
{ INFO("s25fl129p0", 0x012018, 0x4d00, 256 << 10, 64, 0) },
|
{ INFO("s25fl129p0", 0x012018, 0x4d00, 256 << 10, 64, 0) },
|
||||||
@@ -190,6 +239,10 @@ static const FlashPartInfo known_devices[] = {
|
|||||||
{ INFO("s25fl016k", 0xef4015, 0, 64 << 10, 32, ER_4K | ER_32K) },
|
{ INFO("s25fl016k", 0xef4015, 0, 64 << 10, 32, ER_4K | ER_32K) },
|
||||||
{ INFO("s25fl064k", 0xef4017, 0, 64 << 10, 128, ER_4K | ER_32K) },
|
{ INFO("s25fl064k", 0xef4017, 0, 64 << 10, 128, ER_4K | ER_32K) },
|
||||||
|
|
||||||
|
/* Spansion -- boot sectors support */
|
||||||
|
{ INFO6("s25fs512s", 0x010220, 0x4d0081, 256 << 10, 256, 0) },
|
||||||
|
{ INFO6("s70fs01gs", 0x010221, 0x4d0081, 256 << 10, 512, 0) },
|
||||||
|
|
||||||
/* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */
|
/* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */
|
||||||
{ INFO("sst25vf040b", 0xbf258d, 0, 64 << 10, 8, ER_4K) },
|
{ INFO("sst25vf040b", 0xbf258d, 0, 64 << 10, 8, ER_4K) },
|
||||||
{ INFO("sst25vf080b", 0xbf258e, 0, 64 << 10, 16, ER_4K) },
|
{ INFO("sst25vf080b", 0xbf258e, 0, 64 << 10, 16, ER_4K) },
|
||||||
@@ -240,10 +293,6 @@ static const FlashPartInfo known_devices[] = {
|
|||||||
{ INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) },
|
{ INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) },
|
||||||
{ INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
|
{ INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
|
||||||
{ INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K) },
|
{ INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K) },
|
||||||
|
|
||||||
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
|
|
||||||
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
|
||||||
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -255,6 +304,7 @@ typedef enum {
|
|||||||
JEDEC_READ = 0x9f,
|
JEDEC_READ = 0x9f,
|
||||||
BULK_ERASE = 0xc7,
|
BULK_ERASE = 0xc7,
|
||||||
READ_FSR = 0x70,
|
READ_FSR = 0x70,
|
||||||
|
RDCR = 0x15,
|
||||||
|
|
||||||
READ = 0x03,
|
READ = 0x03,
|
||||||
READ4 = 0x13,
|
READ4 = 0x13,
|
||||||
@@ -271,12 +321,14 @@ typedef enum {
|
|||||||
|
|
||||||
PP = 0x02,
|
PP = 0x02,
|
||||||
PP4 = 0x12,
|
PP4 = 0x12,
|
||||||
|
PP4_4 = 0x3e,
|
||||||
DPP = 0xa2,
|
DPP = 0xa2,
|
||||||
QPP = 0x32,
|
QPP = 0x32,
|
||||||
|
|
||||||
ERASE_4K = 0x20,
|
ERASE_4K = 0x20,
|
||||||
ERASE4_4K = 0x21,
|
ERASE4_4K = 0x21,
|
||||||
ERASE_32K = 0x52,
|
ERASE_32K = 0x52,
|
||||||
|
ERASE4_32K = 0x5c,
|
||||||
ERASE_SECTOR = 0xd8,
|
ERASE_SECTOR = 0xd8,
|
||||||
ERASE4_SECTOR = 0xdc,
|
ERASE4_SECTOR = 0xdc,
|
||||||
|
|
||||||
@@ -289,6 +341,13 @@ typedef enum {
|
|||||||
RESET_ENABLE = 0x66,
|
RESET_ENABLE = 0x66,
|
||||||
RESET_MEMORY = 0x99,
|
RESET_MEMORY = 0x99,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Micron: 0x35 - enable QPI
|
||||||
|
* Spansion: 0x35 - read control register
|
||||||
|
*/
|
||||||
|
RDCR_EQIO = 0x35,
|
||||||
|
RSTQIO = 0xf5,
|
||||||
|
|
||||||
RNVCR = 0xB5,
|
RNVCR = 0xB5,
|
||||||
WNVCR = 0xB1,
|
WNVCR = 0xB1,
|
||||||
|
|
||||||
@@ -304,9 +363,18 @@ typedef enum {
|
|||||||
STATE_PAGE_PROGRAM,
|
STATE_PAGE_PROGRAM,
|
||||||
STATE_READ,
|
STATE_READ,
|
||||||
STATE_COLLECTING_DATA,
|
STATE_COLLECTING_DATA,
|
||||||
|
STATE_COLLECTING_VAR_LEN_DATA,
|
||||||
STATE_READING_DATA,
|
STATE_READING_DATA,
|
||||||
} CMDState;
|
} CMDState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MAN_SPANSION,
|
||||||
|
MAN_MACRONIX,
|
||||||
|
MAN_NUMONYX,
|
||||||
|
MAN_WINBOND,
|
||||||
|
MAN_GENERIC,
|
||||||
|
} Manufacturer;
|
||||||
|
|
||||||
typedef struct Flash {
|
typedef struct Flash {
|
||||||
SSISlave parent_obj;
|
SSISlave parent_obj;
|
||||||
|
|
||||||
@@ -322,13 +390,24 @@ typedef struct Flash {
|
|||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
uint8_t needed_bytes;
|
uint8_t needed_bytes;
|
||||||
uint8_t cmd_in_progress;
|
uint8_t cmd_in_progress;
|
||||||
uint64_t cur_addr;
|
uint32_t cur_addr;
|
||||||
uint32_t nonvolatile_cfg;
|
uint32_t nonvolatile_cfg;
|
||||||
|
/* Configuration register for Macronix */
|
||||||
uint32_t volatile_cfg;
|
uint32_t volatile_cfg;
|
||||||
uint32_t enh_volatile_cfg;
|
uint32_t enh_volatile_cfg;
|
||||||
|
/* Spansion cfg registers. */
|
||||||
|
uint8_t spansion_cr1nv;
|
||||||
|
uint8_t spansion_cr2nv;
|
||||||
|
uint8_t spansion_cr3nv;
|
||||||
|
uint8_t spansion_cr4nv;
|
||||||
|
uint8_t spansion_cr1v;
|
||||||
|
uint8_t spansion_cr2v;
|
||||||
|
uint8_t spansion_cr3v;
|
||||||
|
uint8_t spansion_cr4v;
|
||||||
bool write_enable;
|
bool write_enable;
|
||||||
bool four_bytes_address_mode;
|
bool four_bytes_address_mode;
|
||||||
bool reset_enable;
|
bool reset_enable;
|
||||||
|
bool quad_enable;
|
||||||
uint8_t ear;
|
uint8_t ear;
|
||||||
|
|
||||||
int64_t dirty_page;
|
int64_t dirty_page;
|
||||||
@@ -350,8 +429,29 @@ typedef struct M25P80Class {
|
|||||||
#define M25P80_GET_CLASS(obj) \
|
#define M25P80_GET_CLASS(obj) \
|
||||||
OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80)
|
OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80)
|
||||||
|
|
||||||
|
static inline Manufacturer get_man(Flash *s)
|
||||||
|
{
|
||||||
|
switch (s->pi->id[0]) {
|
||||||
|
case 0x20:
|
||||||
|
return MAN_NUMONYX;
|
||||||
|
case 0xEF:
|
||||||
|
return MAN_WINBOND;
|
||||||
|
case 0x01:
|
||||||
|
return MAN_SPANSION;
|
||||||
|
case 0xC2:
|
||||||
|
return MAN_MACRONIX;
|
||||||
|
default:
|
||||||
|
return MAN_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void blk_sync_complete(void *opaque, int ret)
|
static void blk_sync_complete(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
|
QEMUIOVector *iov = opaque;
|
||||||
|
|
||||||
|
qemu_iovec_destroy(iov);
|
||||||
|
g_free(iov);
|
||||||
|
|
||||||
/* do nothing. Masters do not directly interact with the backing store,
|
/* do nothing. Masters do not directly interact with the backing store,
|
||||||
* only the working copy so no mutexing required.
|
* only the working copy so no mutexing required.
|
||||||
*/
|
*/
|
||||||
@@ -359,31 +459,33 @@ static void blk_sync_complete(void *opaque, int ret)
|
|||||||
|
|
||||||
static void flash_sync_page(Flash *s, int page)
|
static void flash_sync_page(Flash *s, int page)
|
||||||
{
|
{
|
||||||
QEMUIOVector iov;
|
QEMUIOVector *iov;
|
||||||
|
|
||||||
if (!s->blk || blk_is_read_only(s->blk)) {
|
if (!s->blk || blk_is_read_only(s->blk)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_iovec_init(&iov, 1);
|
iov = g_new(QEMUIOVector, 1);
|
||||||
qemu_iovec_add(&iov, s->storage + page * s->pi->page_size,
|
qemu_iovec_init(iov, 1);
|
||||||
|
qemu_iovec_add(iov, s->storage + page * s->pi->page_size,
|
||||||
s->pi->page_size);
|
s->pi->page_size);
|
||||||
blk_aio_pwritev(s->blk, page * s->pi->page_size, &iov, 0,
|
blk_aio_pwritev(s->blk, page * s->pi->page_size, iov, 0,
|
||||||
blk_sync_complete, NULL);
|
blk_sync_complete, iov);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
|
static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
|
||||||
{
|
{
|
||||||
QEMUIOVector iov;
|
QEMUIOVector *iov;
|
||||||
|
|
||||||
if (!s->blk || blk_is_read_only(s->blk)) {
|
if (!s->blk || blk_is_read_only(s->blk)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!(len % BDRV_SECTOR_SIZE));
|
assert(!(len % BDRV_SECTOR_SIZE));
|
||||||
qemu_iovec_init(&iov, 1);
|
iov = g_new(QEMUIOVector, 1);
|
||||||
qemu_iovec_add(&iov, s->storage + off, len);
|
qemu_iovec_init(iov, 1);
|
||||||
blk_aio_pwritev(s->blk, off, &iov, 0, blk_sync_complete, NULL);
|
qemu_iovec_add(iov, s->storage + off, len);
|
||||||
|
blk_aio_pwritev(s->blk, off, iov, 0, blk_sync_complete, iov);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flash_erase(Flash *s, int offset, FlashCMD cmd)
|
static void flash_erase(Flash *s, int offset, FlashCMD cmd)
|
||||||
@@ -398,6 +500,7 @@ static void flash_erase(Flash *s, int offset, FlashCMD cmd)
|
|||||||
capa_to_assert = ER_4K;
|
capa_to_assert = ER_4K;
|
||||||
break;
|
break;
|
||||||
case ERASE_32K:
|
case ERASE_32K:
|
||||||
|
case ERASE4_32K:
|
||||||
len = 32 << 10;
|
len = 32 << 10;
|
||||||
capa_to_assert = ER_32K;
|
capa_to_assert = ER_32K;
|
||||||
break;
|
break;
|
||||||
@@ -435,9 +538,9 @@ static inline void flash_sync_dirty(Flash *s, int64_t newpage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void flash_write8(Flash *s, uint64_t addr, uint8_t data)
|
void flash_write8(Flash *s, uint32_t addr, uint8_t data)
|
||||||
{
|
{
|
||||||
int64_t page = addr / s->pi->page_size;
|
uint32_t page = addr / s->pi->page_size;
|
||||||
uint8_t prev = s->storage[s->cur_addr];
|
uint8_t prev = s->storage[s->cur_addr];
|
||||||
|
|
||||||
if (!s->write_enable) {
|
if (!s->write_enable) {
|
||||||
@@ -445,7 +548,7 @@ void flash_write8(Flash *s, uint64_t addr, uint8_t data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((prev ^ data) & data) {
|
if ((prev ^ data) & data) {
|
||||||
DB_PRINT_L(1, "programming zero to one! addr=%" PRIx64 " %" PRIx8
|
DB_PRINT_L(1, "programming zero to one! addr=%" PRIx32 " %" PRIx8
|
||||||
" -> %" PRIx8 "\n", addr, prev, data);
|
" -> %" PRIx8 "\n", addr, prev, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,9 +571,11 @@ static inline int get_addr_length(Flash *s)
|
|||||||
|
|
||||||
switch (s->cmd_in_progress) {
|
switch (s->cmd_in_progress) {
|
||||||
case PP4:
|
case PP4:
|
||||||
|
case PP4_4:
|
||||||
case READ4:
|
case READ4:
|
||||||
case QIOR4:
|
case QIOR4:
|
||||||
case ERASE4_4K:
|
case ERASE4_4K:
|
||||||
|
case ERASE4_32K:
|
||||||
case ERASE4_SECTOR:
|
case ERASE4_SECTOR:
|
||||||
case FAST_READ4:
|
case FAST_READ4:
|
||||||
case DOR4:
|
case DOR4:
|
||||||
@@ -484,18 +589,16 @@ static inline int get_addr_length(Flash *s)
|
|||||||
|
|
||||||
static void complete_collecting_data(Flash *s)
|
static void complete_collecting_data(Flash *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i, n;
|
||||||
|
|
||||||
s->cur_addr = 0;
|
n = get_addr_length(s);
|
||||||
|
s->cur_addr = (n == 3 ? s->ear : 0);
|
||||||
for (i = 0; i < get_addr_length(s); ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
s->cur_addr <<= 8;
|
s->cur_addr <<= 8;
|
||||||
s->cur_addr |= s->data[i];
|
s->cur_addr |= s->data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_addr_length(s) == 3) {
|
s->cur_addr &= s->size - 1;
|
||||||
s->cur_addr += (s->ear & 0x3) * MAX_3BYTES_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->state = STATE_IDLE;
|
s->state = STATE_IDLE;
|
||||||
|
|
||||||
@@ -504,6 +607,7 @@ static void complete_collecting_data(Flash *s)
|
|||||||
case QPP:
|
case QPP:
|
||||||
case PP:
|
case PP:
|
||||||
case PP4:
|
case PP4:
|
||||||
|
case PP4_4:
|
||||||
s->state = STATE_PAGE_PROGRAM;
|
s->state = STATE_PAGE_PROGRAM;
|
||||||
break;
|
break;
|
||||||
case READ:
|
case READ:
|
||||||
@@ -523,11 +627,25 @@ static void complete_collecting_data(Flash *s)
|
|||||||
case ERASE_4K:
|
case ERASE_4K:
|
||||||
case ERASE4_4K:
|
case ERASE4_4K:
|
||||||
case ERASE_32K:
|
case ERASE_32K:
|
||||||
|
case ERASE4_32K:
|
||||||
case ERASE_SECTOR:
|
case ERASE_SECTOR:
|
||||||
case ERASE4_SECTOR:
|
case ERASE4_SECTOR:
|
||||||
flash_erase(s, s->cur_addr, s->cmd_in_progress);
|
flash_erase(s, s->cur_addr, s->cmd_in_progress);
|
||||||
break;
|
break;
|
||||||
case WRSR:
|
case WRSR:
|
||||||
|
switch (get_man(s)) {
|
||||||
|
case MAN_SPANSION:
|
||||||
|
s->quad_enable = !!(s->data[1] & 0x02);
|
||||||
|
break;
|
||||||
|
case MAN_MACRONIX:
|
||||||
|
s->quad_enable = extract32(s->data[0], 6, 1);
|
||||||
|
if (s->len > 1) {
|
||||||
|
s->four_bytes_address_mode = extract32(s->data[1], 5, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (s->write_enable) {
|
if (s->write_enable) {
|
||||||
s->write_enable = false;
|
s->write_enable = false;
|
||||||
}
|
}
|
||||||
@@ -561,8 +679,10 @@ static void reset_memory(Flash *s)
|
|||||||
s->state = STATE_IDLE;
|
s->state = STATE_IDLE;
|
||||||
s->write_enable = false;
|
s->write_enable = false;
|
||||||
s->reset_enable = false;
|
s->reset_enable = false;
|
||||||
|
s->quad_enable = false;
|
||||||
|
|
||||||
if (((s->pi->jedec >> 16) & 0xFF) == JEDEC_NUMONYX) {
|
switch (get_man(s)) {
|
||||||
|
case MAN_NUMONYX:
|
||||||
s->volatile_cfg = 0;
|
s->volatile_cfg = 0;
|
||||||
s->volatile_cfg |= VCFG_DUMMY;
|
s->volatile_cfg |= VCFG_DUMMY;
|
||||||
s->volatile_cfg |= VCFG_WRAP_SEQUENTIAL;
|
s->volatile_cfg |= VCFG_WRAP_SEQUENTIAL;
|
||||||
@@ -592,16 +712,147 @@ static void reset_memory(Flash *s)
|
|||||||
s->four_bytes_address_mode = true;
|
s->four_bytes_address_mode = true;
|
||||||
}
|
}
|
||||||
if (!(s->nonvolatile_cfg & NVCFG_LOWER_SEGMENT_MASK)) {
|
if (!(s->nonvolatile_cfg & NVCFG_LOWER_SEGMENT_MASK)) {
|
||||||
s->ear = CFG_UPPER_128MB_SEG_ENABLED;
|
s->ear = s->size / MAX_3BYTES_SIZE - 1;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case MAN_MACRONIX:
|
||||||
|
s->volatile_cfg = 0x7;
|
||||||
|
break;
|
||||||
|
case MAN_SPANSION:
|
||||||
|
s->spansion_cr1v = s->spansion_cr1nv;
|
||||||
|
s->spansion_cr2v = s->spansion_cr2nv;
|
||||||
|
s->spansion_cr3v = s->spansion_cr3nv;
|
||||||
|
s->spansion_cr4v = s->spansion_cr4nv;
|
||||||
|
s->quad_enable = extract32(s->spansion_cr1v,
|
||||||
|
SPANSION_QUAD_CFG_POS,
|
||||||
|
SPANSION_QUAD_CFG_LEN
|
||||||
|
);
|
||||||
|
s->four_bytes_address_mode = extract32(s->spansion_cr2v,
|
||||||
|
SPANSION_ADDR_LEN_POS,
|
||||||
|
SPANSION_ADDR_LEN_LEN
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DB_PRINT_L(0, "Reset done.\n");
|
DB_PRINT_L(0, "Reset done.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void decode_fast_read_cmd(Flash *s)
|
||||||
|
{
|
||||||
|
s->needed_bytes = get_addr_length(s);
|
||||||
|
switch (get_man(s)) {
|
||||||
|
/* Dummy cycles - modeled with bytes writes instead of bits */
|
||||||
|
case MAN_WINBOND:
|
||||||
|
s->needed_bytes += 8;
|
||||||
|
break;
|
||||||
|
case MAN_NUMONYX:
|
||||||
|
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
||||||
|
break;
|
||||||
|
case MAN_MACRONIX:
|
||||||
|
if (extract32(s->volatile_cfg, 6, 2) == 1) {
|
||||||
|
s->needed_bytes += 6;
|
||||||
|
} else {
|
||||||
|
s->needed_bytes += 8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MAN_SPANSION:
|
||||||
|
s->needed_bytes += extract32(s->spansion_cr2v,
|
||||||
|
SPANSION_DUMMY_CLK_POS,
|
||||||
|
SPANSION_DUMMY_CLK_LEN
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s->pos = 0;
|
||||||
|
s->len = 0;
|
||||||
|
s->state = STATE_COLLECTING_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decode_dio_read_cmd(Flash *s)
|
||||||
|
{
|
||||||
|
s->needed_bytes = get_addr_length(s);
|
||||||
|
/* Dummy cycles modeled with bytes writes instead of bits */
|
||||||
|
switch (get_man(s)) {
|
||||||
|
case MAN_WINBOND:
|
||||||
|
s->needed_bytes += 8;
|
||||||
|
break;
|
||||||
|
case MAN_SPANSION:
|
||||||
|
s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
|
||||||
|
s->needed_bytes += extract32(s->spansion_cr2v,
|
||||||
|
SPANSION_DUMMY_CLK_POS,
|
||||||
|
SPANSION_DUMMY_CLK_LEN
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case MAN_NUMONYX:
|
||||||
|
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
||||||
|
break;
|
||||||
|
case MAN_MACRONIX:
|
||||||
|
switch (extract32(s->volatile_cfg, 6, 2)) {
|
||||||
|
case 1:
|
||||||
|
s->needed_bytes += 6;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
s->needed_bytes += 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s->needed_bytes += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s->pos = 0;
|
||||||
|
s->len = 0;
|
||||||
|
s->state = STATE_COLLECTING_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decode_qio_read_cmd(Flash *s)
|
||||||
|
{
|
||||||
|
s->needed_bytes = get_addr_length(s);
|
||||||
|
/* Dummy cycles modeled with bytes writes instead of bits */
|
||||||
|
switch (get_man(s)) {
|
||||||
|
case MAN_WINBOND:
|
||||||
|
s->needed_bytes += 8;
|
||||||
|
break;
|
||||||
|
case MAN_SPANSION:
|
||||||
|
s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
|
||||||
|
s->needed_bytes += extract32(s->spansion_cr2v,
|
||||||
|
SPANSION_DUMMY_CLK_POS,
|
||||||
|
SPANSION_DUMMY_CLK_LEN
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case MAN_NUMONYX:
|
||||||
|
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
||||||
|
break;
|
||||||
|
case MAN_MACRONIX:
|
||||||
|
switch (extract32(s->volatile_cfg, 6, 2)) {
|
||||||
|
case 1:
|
||||||
|
s->needed_bytes += 4;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
s->needed_bytes += 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s->needed_bytes += 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s->pos = 0;
|
||||||
|
s->len = 0;
|
||||||
|
s->state = STATE_COLLECTING_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
static void decode_new_cmd(Flash *s, uint32_t value)
|
static void decode_new_cmd(Flash *s, uint32_t value)
|
||||||
{
|
{
|
||||||
s->cmd_in_progress = value;
|
s->cmd_in_progress = value;
|
||||||
|
int i;
|
||||||
DB_PRINT_L(0, "decoded new command:%x\n", value);
|
DB_PRINT_L(0, "decoded new command:%x\n", value);
|
||||||
|
|
||||||
if (value != RESET_MEMORY) {
|
if (value != RESET_MEMORY) {
|
||||||
@@ -613,6 +864,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||||||
case ERASE_4K:
|
case ERASE_4K:
|
||||||
case ERASE4_4K:
|
case ERASE4_4K:
|
||||||
case ERASE_32K:
|
case ERASE_32K:
|
||||||
|
case ERASE4_32K:
|
||||||
case ERASE_SECTOR:
|
case ERASE_SECTOR:
|
||||||
case ERASE4_SECTOR:
|
case ERASE4_SECTOR:
|
||||||
case READ:
|
case READ:
|
||||||
@@ -621,6 +873,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||||||
case QPP:
|
case QPP:
|
||||||
case PP:
|
case PP:
|
||||||
case PP4:
|
case PP4:
|
||||||
|
case PP4_4:
|
||||||
s->needed_bytes = get_addr_length(s);
|
s->needed_bytes = get_addr_length(s);
|
||||||
s->pos = 0;
|
s->pos = 0;
|
||||||
s->len = 0;
|
s->len = 0;
|
||||||
@@ -633,56 +886,35 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||||||
case DOR4:
|
case DOR4:
|
||||||
case QOR:
|
case QOR:
|
||||||
case QOR4:
|
case QOR4:
|
||||||
s->needed_bytes = get_addr_length(s);
|
decode_fast_read_cmd(s);
|
||||||
if (((s->pi->jedec >> 16) & 0xFF) == JEDEC_NUMONYX) {
|
|
||||||
/* Dummy cycles modeled with bytes writes instead of bits */
|
|
||||||
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
|
||||||
}
|
|
||||||
s->pos = 0;
|
|
||||||
s->len = 0;
|
|
||||||
s->state = STATE_COLLECTING_DATA;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIOR:
|
case DIOR:
|
||||||
case DIOR4:
|
case DIOR4:
|
||||||
switch ((s->pi->jedec >> 16) & 0xFF) {
|
decode_dio_read_cmd(s);
|
||||||
case JEDEC_WINBOND:
|
|
||||||
case JEDEC_SPANSION:
|
|
||||||
s->needed_bytes = 4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
s->needed_bytes = get_addr_length(s);
|
|
||||||
/* Dummy cycles modeled with bytes writes instead of bits */
|
|
||||||
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
|
||||||
}
|
|
||||||
s->pos = 0;
|
|
||||||
s->len = 0;
|
|
||||||
s->state = STATE_COLLECTING_DATA;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QIOR:
|
case QIOR:
|
||||||
case QIOR4:
|
case QIOR4:
|
||||||
switch ((s->pi->jedec >> 16) & 0xFF) {
|
decode_qio_read_cmd(s);
|
||||||
case JEDEC_WINBOND:
|
|
||||||
case JEDEC_SPANSION:
|
|
||||||
s->needed_bytes = 6;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
s->needed_bytes = get_addr_length(s);
|
|
||||||
/* Dummy cycles modeled with bytes writes instead of bits */
|
|
||||||
s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
|
|
||||||
}
|
|
||||||
s->pos = 0;
|
|
||||||
s->len = 0;
|
|
||||||
s->state = STATE_COLLECTING_DATA;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRSR:
|
case WRSR:
|
||||||
if (s->write_enable) {
|
if (s->write_enable) {
|
||||||
s->needed_bytes = 1;
|
switch (get_man(s)) {
|
||||||
|
case MAN_SPANSION:
|
||||||
|
s->needed_bytes = 2;
|
||||||
|
s->state = STATE_COLLECTING_DATA;
|
||||||
|
break;
|
||||||
|
case MAN_MACRONIX:
|
||||||
|
s->needed_bytes = 2;
|
||||||
|
s->state = STATE_COLLECTING_VAR_LEN_DATA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s->needed_bytes = 1;
|
||||||
|
s->state = STATE_COLLECTING_DATA;
|
||||||
|
}
|
||||||
s->pos = 0;
|
s->pos = 0;
|
||||||
s->len = 0;
|
|
||||||
s->state = STATE_COLLECTING_DATA;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -695,6 +927,9 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||||||
|
|
||||||
case RDSR:
|
case RDSR:
|
||||||
s->data[0] = (!!s->write_enable) << 1;
|
s->data[0] = (!!s->write_enable) << 1;
|
||||||
|
if (get_man(s) == MAN_MACRONIX) {
|
||||||
|
s->data[0] |= (!!s->quad_enable) << 6;
|
||||||
|
}
|
||||||
s->pos = 0;
|
s->pos = 0;
|
||||||
s->len = 1;
|
s->len = 1;
|
||||||
s->state = STATE_READING_DATA;
|
s->state = STATE_READING_DATA;
|
||||||
@@ -712,20 +947,23 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||||||
|
|
||||||
case JEDEC_READ:
|
case JEDEC_READ:
|
||||||
DB_PRINT_L(0, "populated jedec code\n");
|
DB_PRINT_L(0, "populated jedec code\n");
|
||||||
s->data[0] = (s->pi->jedec >> 16) & 0xff;
|
for (i = 0; i < s->pi->id_len; i++) {
|
||||||
s->data[1] = (s->pi->jedec >> 8) & 0xff;
|
s->data[i] = s->pi->id[i];
|
||||||
s->data[2] = s->pi->jedec & 0xff;
|
|
||||||
if (s->pi->ext_jedec) {
|
|
||||||
s->data[3] = (s->pi->ext_jedec >> 8) & 0xff;
|
|
||||||
s->data[4] = s->pi->ext_jedec & 0xff;
|
|
||||||
s->len = 5;
|
|
||||||
} else {
|
|
||||||
s->len = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->len = s->pi->id_len;
|
||||||
s->pos = 0;
|
s->pos = 0;
|
||||||
s->state = STATE_READING_DATA;
|
s->state = STATE_READING_DATA;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RDCR:
|
||||||
|
s->data[0] = s->volatile_cfg & 0xFF;
|
||||||
|
s->data[0] |= (!!s->four_bytes_address_mode) << 5;
|
||||||
|
s->pos = 0;
|
||||||
|
s->len = 1;
|
||||||
|
s->state = STATE_READING_DATA;
|
||||||
|
break;
|
||||||
|
|
||||||
case BULK_ERASE:
|
case BULK_ERASE:
|
||||||
if (s->write_enable) {
|
if (s->write_enable) {
|
||||||
DB_PRINT_L(0, "chip erase\n");
|
DB_PRINT_L(0, "chip erase\n");
|
||||||
@@ -765,7 +1003,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||||||
s->state = STATE_READING_DATA;
|
s->state = STATE_READING_DATA;
|
||||||
break;
|
break;
|
||||||
case WNVCR:
|
case WNVCR:
|
||||||
if (s->write_enable) {
|
if (s->write_enable && get_man(s) == MAN_NUMONYX) {
|
||||||
s->needed_bytes = 2;
|
s->needed_bytes = 2;
|
||||||
s->pos = 0;
|
s->pos = 0;
|
||||||
s->len = 0;
|
s->len = 0;
|
||||||
@@ -808,6 +1046,24 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||||||
reset_memory(s);
|
reset_memory(s);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case RDCR_EQIO:
|
||||||
|
switch (get_man(s)) {
|
||||||
|
case MAN_SPANSION:
|
||||||
|
s->data[0] = (!!s->quad_enable) << 1;
|
||||||
|
s->pos = 0;
|
||||||
|
s->len = 1;
|
||||||
|
s->state = STATE_READING_DATA;
|
||||||
|
break;
|
||||||
|
case MAN_MACRONIX:
|
||||||
|
s->quad_enable = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RSTQIO:
|
||||||
|
s->quad_enable = false;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
|
qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
|
||||||
break;
|
break;
|
||||||
@@ -819,6 +1075,9 @@ static int m25p80_cs(SSISlave *ss, bool select)
|
|||||||
Flash *s = M25P80(ss);
|
Flash *s = M25P80(ss);
|
||||||
|
|
||||||
if (select) {
|
if (select) {
|
||||||
|
if (s->state == STATE_COLLECTING_VAR_LEN_DATA) {
|
||||||
|
complete_collecting_data(s);
|
||||||
|
}
|
||||||
s->len = 0;
|
s->len = 0;
|
||||||
s->pos = 0;
|
s->pos = 0;
|
||||||
s->state = STATE_IDLE;
|
s->state = STATE_IDLE;
|
||||||
@@ -838,20 +1097,21 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
|
|||||||
switch (s->state) {
|
switch (s->state) {
|
||||||
|
|
||||||
case STATE_PAGE_PROGRAM:
|
case STATE_PAGE_PROGRAM:
|
||||||
DB_PRINT_L(1, "page program cur_addr=%#" PRIx64 " data=%" PRIx8 "\n",
|
DB_PRINT_L(1, "page program cur_addr=%#" PRIx32 " data=%" PRIx8 "\n",
|
||||||
s->cur_addr, (uint8_t)tx);
|
s->cur_addr, (uint8_t)tx);
|
||||||
flash_write8(s, s->cur_addr, (uint8_t)tx);
|
flash_write8(s, s->cur_addr, (uint8_t)tx);
|
||||||
s->cur_addr++;
|
s->cur_addr = (s->cur_addr + 1) & (s->size - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_READ:
|
case STATE_READ:
|
||||||
r = s->storage[s->cur_addr];
|
r = s->storage[s->cur_addr];
|
||||||
DB_PRINT_L(1, "READ 0x%" PRIx64 "=%" PRIx8 "\n", s->cur_addr,
|
DB_PRINT_L(1, "READ 0x%" PRIx32 "=%" PRIx8 "\n", s->cur_addr,
|
||||||
(uint8_t)r);
|
(uint8_t)r);
|
||||||
s->cur_addr = (s->cur_addr + 1) % s->size;
|
s->cur_addr = (s->cur_addr + 1) & (s->size - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_COLLECTING_DATA:
|
case STATE_COLLECTING_DATA:
|
||||||
|
case STATE_COLLECTING_VAR_LEN_DATA:
|
||||||
s->data[s->len] = (uint8_t)tx;
|
s->data[s->len] = (uint8_t)tx;
|
||||||
s->len++;
|
s->len++;
|
||||||
|
|
||||||
@@ -878,9 +1138,8 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int m25p80_init(SSISlave *ss)
|
static void m25p80_realize(SSISlave *ss, Error **errp)
|
||||||
{
|
{
|
||||||
DriveInfo *dinfo;
|
|
||||||
Flash *s = M25P80(ss);
|
Flash *s = M25P80(ss);
|
||||||
M25P80Class *mc = M25P80_GET_CLASS(s);
|
M25P80Class *mc = M25P80_GET_CLASS(s);
|
||||||
|
|
||||||
@@ -889,28 +1148,19 @@ static int m25p80_init(SSISlave *ss)
|
|||||||
s->size = s->pi->sector_size * s->pi->n_sectors;
|
s->size = s->pi->sector_size * s->pi->n_sectors;
|
||||||
s->dirty_page = -1;
|
s->dirty_page = -1;
|
||||||
|
|
||||||
/* FIXME use a qdev drive property instead of drive_get_next() */
|
if (s->blk) {
|
||||||
dinfo = drive_get_next(IF_MTD);
|
|
||||||
|
|
||||||
if (dinfo) {
|
|
||||||
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
|
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
|
||||||
s->blk = blk_by_legacy_dinfo(dinfo);
|
|
||||||
blk_attach_dev_nofail(s->blk, s);
|
|
||||||
|
|
||||||
s->storage = blk_blockalign(s->blk, s->size);
|
s->storage = blk_blockalign(s->blk, s->size);
|
||||||
|
|
||||||
/* FIXME: Move to late init */
|
|
||||||
if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) {
|
if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) {
|
||||||
fprintf(stderr, "Failed to initialize SPI flash!\n");
|
error_setg(errp, "failed to read the initial flash content");
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DB_PRINT_L(0, "No BDRV - binding to RAM\n");
|
DB_PRINT_L(0, "No BDRV - binding to RAM\n");
|
||||||
s->storage = blk_blockalign(NULL, s->size);
|
s->storage = blk_blockalign(NULL, s->size);
|
||||||
memset(s->storage, 0xFF, s->size);
|
memset(s->storage, 0xFF, s->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m25p80_reset(DeviceState *d)
|
static void m25p80_reset(DeviceState *d)
|
||||||
@@ -926,13 +1176,19 @@ static void m25p80_pre_save(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Property m25p80_properties[] = {
|
static Property m25p80_properties[] = {
|
||||||
|
/* This is default value for Micron flash */
|
||||||
DEFINE_PROP_UINT32("nonvolatile-cfg", Flash, nonvolatile_cfg, 0x8FFF),
|
DEFINE_PROP_UINT32("nonvolatile-cfg", Flash, nonvolatile_cfg, 0x8FFF),
|
||||||
|
DEFINE_PROP_UINT8("spansion-cr1nv", Flash, spansion_cr1nv, 0x0),
|
||||||
|
DEFINE_PROP_UINT8("spansion-cr2nv", Flash, spansion_cr2nv, 0x8),
|
||||||
|
DEFINE_PROP_UINT8("spansion-cr3nv", Flash, spansion_cr3nv, 0x2),
|
||||||
|
DEFINE_PROP_UINT8("spansion-cr4nv", Flash, spansion_cr4nv, 0x10),
|
||||||
|
DEFINE_PROP_DRIVE("drive", Flash, blk),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const VMStateDescription vmstate_m25p80 = {
|
static const VMStateDescription vmstate_m25p80 = {
|
||||||
.name = "xilinx_spi",
|
.name = "xilinx_spi",
|
||||||
.version_id = 2,
|
.version_id = 3,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.pre_save = m25p80_pre_save,
|
.pre_save = m25p80_pre_save,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
@@ -942,7 +1198,8 @@ static const VMStateDescription vmstate_m25p80 = {
|
|||||||
VMSTATE_UINT32(pos, Flash),
|
VMSTATE_UINT32(pos, Flash),
|
||||||
VMSTATE_UINT8(needed_bytes, Flash),
|
VMSTATE_UINT8(needed_bytes, Flash),
|
||||||
VMSTATE_UINT8(cmd_in_progress, Flash),
|
VMSTATE_UINT8(cmd_in_progress, Flash),
|
||||||
VMSTATE_UINT64(cur_addr, Flash),
|
VMSTATE_UNUSED(4),
|
||||||
|
VMSTATE_UINT32(cur_addr, Flash),
|
||||||
VMSTATE_BOOL(write_enable, Flash),
|
VMSTATE_BOOL(write_enable, Flash),
|
||||||
VMSTATE_BOOL_V(reset_enable, Flash, 2),
|
VMSTATE_BOOL_V(reset_enable, Flash, 2),
|
||||||
VMSTATE_UINT8_V(ear, Flash, 2),
|
VMSTATE_UINT8_V(ear, Flash, 2),
|
||||||
@@ -950,6 +1207,11 @@ static const VMStateDescription vmstate_m25p80 = {
|
|||||||
VMSTATE_UINT32_V(nonvolatile_cfg, Flash, 2),
|
VMSTATE_UINT32_V(nonvolatile_cfg, Flash, 2),
|
||||||
VMSTATE_UINT32_V(volatile_cfg, Flash, 2),
|
VMSTATE_UINT32_V(volatile_cfg, Flash, 2),
|
||||||
VMSTATE_UINT32_V(enh_volatile_cfg, Flash, 2),
|
VMSTATE_UINT32_V(enh_volatile_cfg, Flash, 2),
|
||||||
|
VMSTATE_BOOL_V(quad_enable, Flash, 3),
|
||||||
|
VMSTATE_UINT8_V(spansion_cr1nv, Flash, 3),
|
||||||
|
VMSTATE_UINT8_V(spansion_cr2nv, Flash, 3),
|
||||||
|
VMSTATE_UINT8_V(spansion_cr3nv, Flash, 3),
|
||||||
|
VMSTATE_UINT8_V(spansion_cr4nv, Flash, 3),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -960,7 +1222,7 @@ static void m25p80_class_init(ObjectClass *klass, void *data)
|
|||||||
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
||||||
M25P80Class *mc = M25P80_CLASS(klass);
|
M25P80Class *mc = M25P80_CLASS(klass);
|
||||||
|
|
||||||
k->init = m25p80_init;
|
k->realize = m25p80_realize;
|
||||||
k->transfer = m25p80_transfer8;
|
k->transfer = m25p80_transfer8;
|
||||||
k->set_cs = m25p80_cs;
|
k->set_cs = m25p80_cs;
|
||||||
k->cs_polarity = SSI_CS_LOW;
|
k->cs_polarity = SSI_CS_LOW;
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ do { \
|
|||||||
#define DPRINTF(fmt, ...) do { } while (0)
|
#define DPRINTF(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TYPE_CFI_PFLASH01 "cfi.pflash01"
|
|
||||||
#define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01)
|
#define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01)
|
||||||
|
|
||||||
#define PFLASH_BE 0
|
#define PFLASH_BE 0
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ do { \
|
|||||||
|
|
||||||
#define PFLASH_LAZY_ROMD_THRESHOLD 42
|
#define PFLASH_LAZY_ROMD_THRESHOLD 42
|
||||||
|
|
||||||
#define TYPE_CFI_PFLASH02 "cfi.pflash02"
|
|
||||||
#define CFI_PFLASH02(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH02)
|
#define CFI_PFLASH02(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH02)
|
||||||
|
|
||||||
struct pflash_t {
|
struct pflash_t {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user