Compare commits
684 Commits
v2.0.1
...
pull-audio
Author | SHA1 | Date | |
---|---|---|---|
|
b1fe60cd35 | ||
|
a2554a334a | ||
|
c5fa6c86d0 | ||
|
5bc8f026dd | ||
|
6a23082b4e | ||
|
24fd848950 | ||
|
59e7a13005 | ||
|
97256073b1 | ||
|
2ada510698 | ||
|
65e7545ea3 | ||
|
2a766d294a | ||
|
66e6536e0c | ||
|
ce53f2f98f | ||
|
528728fd93 | ||
|
02aa76c2ba | ||
|
2858ab09e6 | ||
|
11b389f21e | ||
|
b162b49adc | ||
|
40d19394b7 | ||
|
13e315dada | ||
|
6297d9a279 | ||
|
29136cd8a4 | ||
|
87a560c455 | ||
|
297a3646c2 | ||
|
cdaec3808e | ||
|
2ddb16a95f | ||
|
f9f3a5ecde | ||
|
be3c771796 | ||
|
192cca60ae | ||
|
4fa953f20d | ||
|
468866b816 | ||
|
e2cd0f4fb4 | ||
|
cbc95538ed | ||
|
f9bee751be | ||
|
6e2bb3ec70 | ||
|
1a381811b4 | ||
|
16a9189921 | ||
|
ba43bc25c9 | ||
|
895527eea5 | ||
|
a10c64e0df | ||
|
061cdd8182 | ||
|
50cb70d185 | ||
|
6b7aa99eb4 | ||
|
ef3cb5ca82 | ||
|
06e33c1c3c | ||
|
7d983531c6 | ||
|
d880b28cef | ||
|
db76ec6291 | ||
|
7b7066b1db | ||
|
ad19b35808 | ||
|
f167dc37da | ||
|
547ec12141 | ||
|
fb5964152d | ||
|
f24efee41e | ||
|
b8dd88b85c | ||
|
a5a04f2830 | ||
|
a175689654 | ||
|
450445d543 | ||
|
719ffe1f5f | ||
|
d6ed7312d1 | ||
|
35d08458a9 | ||
|
6e3d652ab2 | ||
|
14bcfdc7f1 | ||
|
fb626663da | ||
|
f30d56e7d6 | ||
|
cb3d83bc49 | ||
|
89f26e6b7b | ||
|
1a7917210b | ||
|
c3a699be3c | ||
|
2a41c92854 | ||
|
7e7e5858f8 | ||
|
c94239fe56 | ||
|
654039b42a | ||
|
2f0d8631b7 | ||
|
2e11986727 | ||
|
889ac2a32f | ||
|
eacd606ca7 | ||
|
a9171c4fb5 | ||
|
c6fa443b3d | ||
|
7fd5f064d1 | ||
|
5c10495ab1 | ||
|
8f1e884b38 | ||
|
09319b3041 | ||
|
cd2b9b8680 | ||
|
fccae3226d | ||
|
4700a316df | ||
|
4a92a558f4 | ||
|
7b4d915e11 | ||
|
43175fa96a | ||
|
05e7e819d7 | ||
|
e0723c4510 | ||
|
50a2c6e55f | ||
|
7848c8d19f | ||
|
fd460606fd | ||
|
010e639a8d | ||
|
304520291a | ||
|
639973a474 | ||
|
ee11f7a822 | ||
|
ada4135f84 | ||
|
8e03c100a7 | ||
|
41a3f3c1bc | ||
|
1b5498f687 | ||
|
e5bfd64050 | ||
|
7dfba6dfbf | ||
|
12f7fb6086 | ||
|
6d35556caa | ||
|
1b939d9227 | ||
|
dc1823ce26 | ||
|
96d0ee7f09 | ||
|
af3cbfbe80 | ||
|
cf06667428 | ||
|
dddbb2e1e3 | ||
|
eb68a4fa4e | ||
|
4e9cf8409a | ||
|
fdd8ec7184 | ||
|
00d7a1acab | ||
|
a8111212b3 | ||
|
6bf3e99747 | ||
|
5053361b3e | ||
|
a7f96f7666 | ||
|
ae0218e350 | ||
|
5588ff2921 | ||
|
8c081b1802 | ||
|
8587c30c3e | ||
|
267c931985 | ||
|
abce5964be | ||
|
38cf39f739 | ||
|
e083c4a233 | ||
|
f6bff89d06 | ||
|
1813e1758d | ||
|
52a1f64ec5 | ||
|
5c53bb8121 | ||
|
4387345a96 | ||
|
86360ad71d | ||
|
9372514080 | ||
|
9d171bd937 | ||
|
2a8e6c7a85 | ||
|
5a007547df | ||
|
fd040174ac | ||
|
e86e869770 | ||
|
e940bc13ee | ||
|
4f11aa8a40 | ||
|
4557117d9e | ||
|
02ce232c50 | ||
|
b1e6fc0817 | ||
|
06b4f00d53 | ||
|
b690d679c1 | ||
|
cc1626556d | ||
|
cd0c5389dd | ||
|
ab31979a7e | ||
|
66ef8bd9c1 | ||
|
2767ceec4e | ||
|
5e54769c92 | ||
|
0f230bf70e | ||
|
ee16ce9337 | ||
|
196857f8bf | ||
|
4af8be1f88 | ||
|
415168e0c7 | ||
|
a903f40c31 | ||
|
64dfefed16 | ||
|
7daecb3065 | ||
|
77dbc81b0f | ||
|
10f08a0a34 | ||
|
74fe188cd1 | ||
|
ba0ad89e2c | ||
|
85f49cad87 | ||
|
ec209aca83 | ||
|
5f4d5e1aa6 | ||
|
1a443c1b8b | ||
|
f915db07ef | ||
|
65f33bc002 | ||
|
e940f543ae | ||
|
636713bad4 | ||
|
ef47827ac4 | ||
|
6877cff044 | ||
|
7d9cb533f5 | ||
|
7a98593b34 | ||
|
64135217a7 | ||
|
5b877045d3 | ||
|
f3455d4704 | ||
|
42ee4194f2 | ||
|
cd9aa33e2c | ||
|
665f119fba | ||
|
bcdcf75d62 | ||
|
4951013ff5 | ||
|
cf10a5b18f | ||
|
5906366ef0 | ||
|
e9c5c1f40c | ||
|
cb45de6798 | ||
|
a719a27c82 | ||
|
33aaad529e | ||
|
98c1200af1 | ||
|
0a60774906 | ||
|
849d8284c5 | ||
|
0db564eee2 | ||
|
264f8b4fdc | ||
|
8f98aeb9c0 | ||
|
2115182f0c | ||
|
d608cc5c53 | ||
|
5c40c7395d | ||
|
5a8b231e7e | ||
|
43cbeffb19 | ||
|
6b342cc9c8 | ||
|
a76a2f729a | ||
|
4f60af9ac0 | ||
|
ff788b6fe6 | ||
|
5894145a26 | ||
|
e00e36fb91 | ||
|
1dad2ce973 | ||
|
ef0bd3bba6 | ||
|
30b572efd5 | ||
|
b160d7f84a | ||
|
53158adc23 | ||
|
9c24a52e29 | ||
|
ad7443e40a | ||
|
7d08f0da90 | ||
|
8e25c274ae | ||
|
edc1ba7a7a | ||
|
307b2f0148 | ||
|
6ad7c326a1 | ||
|
797720876a | ||
|
a22f8f3894 | ||
|
f95c967a79 | ||
|
f33cc84dd4 | ||
|
69b15212d7 | ||
|
770e39f743 | ||
|
6a0a70b0f5 | ||
|
fbdb664cb6 | ||
|
6075137d94 | ||
|
79f320246c | ||
|
bfaaad0281 | ||
|
f73cdbc6ac | ||
|
f5a014d236 | ||
|
4798fe55c4 | ||
|
ad0a118fa3 | ||
|
8e8be266af | ||
|
4fc00556ab | ||
|
f31352041b | ||
|
8b6bb0ad17 | ||
|
04b0de0ee8 | ||
|
b18a990c3d | ||
|
cab00a5aa1 | ||
|
62622c11f2 | ||
|
ad3f7e31bf | ||
|
c8097612ce | ||
|
d5fdb85e3d | ||
|
046a184414 | ||
|
c976437c7d | ||
|
285364e968 | ||
|
fe680d0dac | ||
|
aa93200b88 | ||
|
9df11c9f08 | ||
|
8cbad670ce | ||
|
8d1dc5d188 | ||
|
c9541f67df | ||
|
7f8fea8b3d | ||
|
9ac1c4c07e | ||
|
097a97a665 | ||
|
7c38ecd097 | ||
|
56bf1a8e90 | ||
|
c4400206d4 | ||
|
422f32c5b1 | ||
|
951916d02c | ||
|
9898370497 | ||
|
03e2bfee37 | ||
|
cf972928fc | ||
|
8bc3923343 | ||
|
58570ed894 | ||
|
71411d3580 | ||
|
1534ee93cc | ||
|
21a246a43b | ||
|
d99598cc99 | ||
|
d97326eec2 | ||
|
0d6ab3ab91 | ||
|
e30d1d8c71 | ||
|
548f52ea06 | ||
|
ca99993adc | ||
|
a890a2f913 | ||
|
98f93ddd84 | ||
|
73d963c0a7 | ||
|
a9c380db3b | ||
|
767adce2d9 | ||
|
9f8e9895c5 | ||
|
3476436a44 | ||
|
3c3ce98142 | ||
|
52f91c3723 | ||
|
5193be3be3 | ||
|
ead7a57df3 | ||
|
caa881abe0 | ||
|
36cf2a3713 | ||
|
4b53c2c72c | ||
|
d2ef4b61fe | ||
|
d8d0a0bc7e | ||
|
5f691ff91d | ||
|
3f1c49e213 | ||
|
ae2158ad6c | ||
|
cc45995294 | ||
|
848696bf35 | ||
|
cc900d34e7 | ||
|
efbf5df020 | ||
|
fbaf445a89 | ||
|
8fa74c947d | ||
|
d7b50c0cc0 | ||
|
535b45631a | ||
|
a7d915f388 | ||
|
a7ded163db | ||
|
4688c94c1f | ||
|
0175ba109e | ||
|
65cd9064e1 | ||
|
a7737e4496 | ||
|
2f719f195c | ||
|
958db90cd5 | ||
|
f1e298794d | ||
|
aaa663916d | ||
|
00b4fbe274 | ||
|
9e1d668ba9 | ||
|
ce0abca3e3 | ||
|
a39fb273bd | ||
|
eea750a562 | ||
|
71f7fe48e1 | ||
|
4082f0889b | ||
|
5bf81c8d63 | ||
|
35fc1f7189 | ||
|
c97294ec1b | ||
|
8ebb876357 | ||
|
afa82daf16 | ||
|
9cd04ccf75 | ||
|
457d397a24 | ||
|
2dc7fdf33d | ||
|
9e4eff5b54 | ||
|
f7eaed8555 | ||
|
ada435f47e | ||
|
1c76551fae | ||
|
69e25d26b4 | ||
|
2e6e8d7a25 | ||
|
cb36acb672 | ||
|
e41fca3da7 | ||
|
e6667f719c | ||
|
7bf8ef196e | ||
|
3458b2b075 | ||
|
6a86dec619 | ||
|
214bb280c6 | ||
|
ad6919dc0a | ||
|
24e76ff06b | ||
|
2468265465 | ||
|
43ce393ee5 | ||
|
e586822a58 | ||
|
6d30db19ca | ||
|
18cb008865 | ||
|
7af03928b1 | ||
|
34d6086236 | ||
|
a29e5ba21f | ||
|
4bc2975698 | ||
|
52b6549442 | ||
|
8c0f0a60d4 | ||
|
aa07f5ecf9 | ||
|
fdaad4715a | ||
|
e50bf23438 | ||
|
c090c10dc4 | ||
|
87f6ede9bb | ||
|
f42c5c8ec8 | ||
|
3078e848fa | ||
|
6420474384 | ||
|
37f0806ed9 | ||
|
6ab9f49934 | ||
|
1b505f93bc | ||
|
fed3ffb9f1 | ||
|
252ec40576 | ||
|
e3da9921eb | ||
|
3b77157964 | ||
|
051b9980b9 | ||
|
52b08670e2 | ||
|
61e5b75c17 | ||
|
b7079df410 | ||
|
1f2cead324 | ||
|
838ef60249 | ||
|
b69cdef876 | ||
|
e466183718 | ||
|
38bbc0a580 | ||
|
9e550b3260 | ||
|
f6246509be | ||
|
0549ea8b6d | ||
|
e1b42f456f | ||
|
b93f995081 | ||
|
a49139af77 | ||
|
521b2b5df0 | ||
|
91f827dcff | ||
|
48add816cf | ||
|
e080f0fdff | ||
|
40f1ee27aa | ||
|
35d0d40a03 | ||
|
f1f25a2e2e | ||
|
7e3d98dd31 | ||
|
8bfea15dda | ||
|
5669b44de5 | ||
|
317fc44ef2 | ||
|
0b50cc8853 | ||
|
cffb12051a | ||
|
c883db0df9 | ||
|
cc8a7e560c | ||
|
c557527455 | ||
|
b006f8162e | ||
|
c3cc95bd15 | ||
|
373df5b135 | ||
|
e855e4fb7b | ||
|
3d2acaa308 | ||
|
5917af812e | ||
|
b03c38057b | ||
|
3f2fde2a00 | ||
|
8b15d9f1d2 | ||
|
341a034742 | ||
|
d437074140 | ||
|
db1da1f2b5 | ||
|
3d914488ae | ||
|
105923e08c | ||
|
9068f20dfb | ||
|
a3f4d63d63 | ||
|
f92d61f336 | ||
|
4843877e5d | ||
|
5f6979cba9 | ||
|
ebd0c614d7 | ||
|
035b239826 | ||
|
35e2da1556 | ||
|
b357f902bf | ||
|
98b90bab3f | ||
|
425532d71d | ||
|
f4c166619e | ||
|
8b66eefe0d | ||
|
34b1a49cb1 | ||
|
a24fba935a | ||
|
9f44adc573 | ||
|
4bb7a41ed6 | ||
|
71b926992e | ||
|
f0e9736012 | ||
|
7db1689c35 | ||
|
e2da502c00 | ||
|
dbe5c58f2a | ||
|
93156cef1c | ||
|
13de54eedd | ||
|
d383c625e2 | ||
|
4522b69c6c | ||
|
23335f6273 | ||
|
34bb4d02e0 | ||
|
6ee143a0a4 | ||
|
a41b2c995b | ||
|
d09a18d44d | ||
|
4bbeb8b173 | ||
|
4a39cbb034 | ||
|
a889bc2bb2 | ||
|
0850fd583f | ||
|
63e3e24db2 | ||
|
e2bbfc8ee2 | ||
|
b87b8a8b32 | ||
|
7a30842186 | ||
|
b920cad669 | ||
|
00a9cacaea | ||
|
b0f9300ca3 | ||
|
9057698d93 | ||
|
d461863d3c | ||
|
7fb8b5d9c4 | ||
|
24c12b7923 | ||
|
6924bc1eef | ||
|
a629f2fdba | ||
|
5d77c8f9b6 | ||
|
a27b04577e | ||
|
296b14491a | ||
|
2d2ad6d090 | ||
|
6e1d3c1c85 | ||
|
e96e5ae880 | ||
|
eb6282f230 | ||
|
e3f9bb011a | ||
|
8439761852 | ||
|
172fc4dd33 | ||
|
f70edf9948 | ||
|
92de901290 | ||
|
4399c438a4 | ||
|
0fb6395c0c | ||
|
a28315ebaf | ||
|
460787605e | ||
|
9974ad40bf | ||
|
d1db760d7b | ||
|
1ba4b6a553 | ||
|
0b9f0e2fd7 | ||
|
1b7a0f758b | ||
|
c20499d985 | ||
|
c3481247e5 | ||
|
9083da1d4c | ||
|
638fb14169 | ||
|
2da1b3abbc | ||
|
bfa40f77af | ||
|
f7bdc41acc | ||
|
073a341151 | ||
|
0b15abfcbc | ||
|
f231b88db1 | ||
|
d73f0beadb | ||
|
4ad417baa4 | ||
|
4a66d3bf9a | ||
|
d876f60d14 | ||
|
027a79c373 | ||
|
02d1608980 | ||
|
411f491e0a | ||
|
f663faac3e | ||
|
b925965294 | ||
|
16cf0b2b34 | ||
|
13a12f869b | ||
|
7931b05987 | ||
|
44b0c0bbb5 | ||
|
860643bc5a | ||
|
9ffd26859d | ||
|
8c0124490b | ||
|
0e96643c98 | ||
|
ad600a4d49 | ||
|
ba3627ec38 | ||
|
4b8abfb78e | ||
|
370e681629 | ||
|
840a178c94 | ||
|
9b17031ac4 | ||
|
ac1307abfe | ||
|
409951f552 | ||
|
90d9d30152 | ||
|
f2d953ec31 | ||
|
9ffe333276 | ||
|
98522f63f4 | ||
|
5ff679b47d | ||
|
636ea3708c | ||
|
acd7fdc6d8 | ||
|
b8afb520e4 | ||
|
4ab9dab5b9 | ||
|
9ce10c0bdc | ||
|
da15ee5134 | ||
|
1dd3a44753 | ||
|
54db38a479 | ||
|
02eb19d0ec | ||
|
662deb908f | ||
|
f46fc4e6a9 | ||
|
df9ebea53e | ||
|
671c835b7d | ||
|
4b304cfae1 | ||
|
1194dcba22 | ||
|
170bf9315b | ||
|
f6c6afc1d4 | ||
|
d998e555d2 | ||
|
1976cccec8 | ||
|
50c5c4d125 | ||
|
20022fa15f | ||
|
ad5171dbd4 | ||
|
b36dc67b95 | ||
|
9d85d55732 | ||
|
2300aed15d | ||
|
e40cdb0e6e | ||
|
968fc24d84 | ||
|
423d00c857 | ||
|
ee25595f01 | ||
|
86e117724a | ||
|
d61ce900b9 | ||
|
1634df567d | ||
|
b321afbefd | ||
|
0374f5089a | ||
|
3bf16cb31a | ||
|
4bdd547aaa | ||
|
af9fe31070 | ||
|
1f91f39219 | ||
|
b672cf66c3 | ||
|
4c186ee2cf | ||
|
dcf91778ca | ||
|
2d03b49c3f | ||
|
e44a90c596 | ||
|
33bbd75a7c | ||
|
5538937368 | ||
|
6954a1cd97 | ||
|
15e3611e1c | ||
|
db302f8f93 | ||
|
6619bc5c55 | ||
|
103db49a10 | ||
|
286226a479 | ||
|
a63f9f85e3 | ||
|
323a8771cf | ||
|
2237094d96 | ||
|
1c70aa6264 | ||
|
f727d0e621 | ||
|
b5cde1da0a | ||
|
177311157c | ||
|
7633378d5f | ||
|
c29f9a0a29 | ||
|
f318cec6ad | ||
|
377a44ec8f | ||
|
3933443e38 | ||
|
19525524a7 | ||
|
f32cdad55d | ||
|
9449fdf61f | ||
|
00a29f3ddc | ||
|
85acfa9c38 | ||
|
1090b9c6cc | ||
|
2eef0bf821 | ||
|
014406b510 | ||
|
0ff644a786 | ||
|
cb1fa941c1 | ||
|
a50c0f5133 | ||
|
52e60cdd34 | ||
|
2f2a00aec9 | ||
|
a65f1de982 | ||
|
f502cfc207 | ||
|
a0618a1990 | ||
|
6cd8a2649a | ||
|
7e09797c29 | ||
|
aca3f40b37 | ||
|
9225d739e7 | ||
|
2c8dd31863 | ||
|
2c7ffc414d | ||
|
90e496386f | ||
|
8c6afa6ab1 | ||
|
00892383c9 | ||
|
d4a2dc675b | ||
|
8bcbf37caa | ||
|
abf1172fc6 | ||
|
c2b820fe58 | ||
|
ccd380876b | ||
|
c6138aabfb | ||
|
5149e557d7 | ||
|
06ef8604e9 | ||
|
39acc64741 | ||
|
e566be049a | ||
|
8f811b9a4a | ||
|
a9e05a1ceb | ||
|
0e154fe92c | ||
|
ef3765cb95 | ||
|
e8d8fef48f | ||
|
6580935246 | ||
|
76bff4f82f | ||
|
e20b8c04a3 | ||
|
8b0190bbde | ||
|
f477ed3c11 | ||
|
cd2754addc | ||
|
3d045dbca5 | ||
|
baee04abba | ||
|
b144be9e06 | ||
|
5e5863ecf1 | ||
|
9a734d64f9 | ||
|
9a8fa1bdad | ||
|
83ebb7cd01 | ||
|
42774a56ec | ||
|
958683482c | ||
|
cd2d46fd21 | ||
|
595b8fdd54 | ||
|
a4af30447b | ||
|
46010969f3 | ||
|
c67b67e511 | ||
|
1eaa1da7e4 | ||
|
8f56ced8aa | ||
|
89fe090bb3 | ||
|
6b88b37c0e | ||
|
075b8ddb9b | ||
|
de4d3555fa | ||
|
3bd67b7dab | ||
|
db4a16458c | ||
|
194cfb43d5 | ||
|
64f45e4991 | ||
|
5238c88657 | ||
|
67debe3ae5 | ||
|
b825025f08 | ||
|
a056c9faa4 | ||
|
3d4299f425 | ||
|
dc73dfd4bc | ||
|
edd8824cd4 | ||
|
e81864a109 | ||
|
de61d14fa7 | ||
|
667b1cdd4e | ||
|
9e4177ad6d | ||
|
dc0c8aaf2c | ||
|
ae7ab46aa8 | ||
|
6f4724672c | ||
|
38d195aa05 | ||
|
95f72aa90a | ||
|
d82b78e48b | ||
|
3d9e69a238 | ||
|
cae1f6f3e6 | ||
|
81d8a5ee19 | ||
|
c6e310d938 | ||
|
d8918df577 | ||
|
4ec4f0bd56 | ||
|
dfeb5fe770 | ||
|
929f8b5550 | ||
|
8bf56493f1 | ||
|
661f7fa4b0 |
18
.gitignore
vendored
18
.gitignore
vendored
@@ -18,8 +18,8 @@
|
|||||||
/*-darwin-user
|
/*-darwin-user
|
||||||
/*-linux-user
|
/*-linux-user
|
||||||
/*-bsd-user
|
/*-bsd-user
|
||||||
libdis*
|
/libdis*
|
||||||
libuser
|
/libuser
|
||||||
/linux-headers/asm
|
/linux-headers/asm
|
||||||
/qga/qapi-generated
|
/qga/qapi-generated
|
||||||
/qapi-generated
|
/qapi-generated
|
||||||
@@ -49,19 +49,9 @@ libuser
|
|||||||
/qemu-monitor.texi
|
/qemu-monitor.texi
|
||||||
/qmp-commands.txt
|
/qmp-commands.txt
|
||||||
/vscclient
|
/vscclient
|
||||||
/test-bitops
|
|
||||||
/test-coroutine
|
|
||||||
/test-int128
|
|
||||||
/test-opts-visitor
|
|
||||||
/test-qmp-input-visitor
|
|
||||||
/test-qmp-output-visitor
|
|
||||||
/test-string-input-visitor
|
|
||||||
/test-string-output-visitor
|
|
||||||
/test-visitor-serialization
|
|
||||||
/fsdev/virtfs-proxy-helper
|
/fsdev/virtfs-proxy-helper
|
||||||
/fsdev/virtfs-proxy-helper.1
|
/fsdev/virtfs-proxy-helper.1
|
||||||
/fsdev/virtfs-proxy-helper.pod
|
/fsdev/virtfs-proxy-helper.pod
|
||||||
/.gdbinit
|
|
||||||
*.a
|
*.a
|
||||||
*.aux
|
*.aux
|
||||||
*.cp
|
*.cp
|
||||||
@@ -90,12 +80,8 @@ libuser
|
|||||||
*.pc
|
*.pc
|
||||||
.libs
|
.libs
|
||||||
.sdk
|
.sdk
|
||||||
*.swp
|
|
||||||
*.orig
|
|
||||||
.pc
|
|
||||||
*.gcda
|
*.gcda
|
||||||
*.gcno
|
*.gcno
|
||||||
patches
|
|
||||||
/pc-bios/bios-pq/status
|
/pc-bios/bios-pq/status
|
||||||
/pc-bios/vgabios-pq/status
|
/pc-bios/vgabios-pq/status
|
||||||
/pc-bios/optionrom/linuxboot.asm
|
/pc-bios/optionrom/linuxboot.asm
|
||||||
|
30
MAINTAINERS
30
MAINTAINERS
@@ -52,6 +52,13 @@ General Project Administration
|
|||||||
------------------------------
|
------------------------------
|
||||||
M: Anthony Liguori <aliguori@amazon.com>
|
M: Anthony Liguori <aliguori@amazon.com>
|
||||||
|
|
||||||
|
Responsible Disclosure, Reporting Security Issues
|
||||||
|
------------------------------
|
||||||
|
W: http://wiki.qemu.org/SecurityProcess
|
||||||
|
M: Michael S. Tsirkin <mst@redhat.com>
|
||||||
|
M: Anthony Liguori <aliguori@amazon.com>
|
||||||
|
L: secalert@redhat.com
|
||||||
|
|
||||||
Guest CPU cores (TCG):
|
Guest CPU cores (TCG):
|
||||||
----------------------
|
----------------------
|
||||||
Alpha
|
Alpha
|
||||||
@@ -601,6 +608,7 @@ USB
|
|||||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/usb/*
|
F: hw/usb/*
|
||||||
|
F: tests/usb-hcd-ehci-test.c
|
||||||
|
|
||||||
VFIO
|
VFIO
|
||||||
M: Alex Williamson <alex.williamson@redhat.com>
|
M: Alex Williamson <alex.williamson@redhat.com>
|
||||||
@@ -651,6 +659,12 @@ S: Supported
|
|||||||
F: hw/block/nvme*
|
F: hw/block/nvme*
|
||||||
F: tests/nvme-test.c
|
F: tests/nvme-test.c
|
||||||
|
|
||||||
|
megasas
|
||||||
|
M: Hannes Reinecke <hare@suse.de>
|
||||||
|
S: Supported
|
||||||
|
F: hw/scsi/megasas.c
|
||||||
|
F: hw/scsi/mfi.h
|
||||||
|
|
||||||
Xilinx EDK
|
Xilinx EDK
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||||
@@ -666,6 +680,9 @@ M: Gerd Hoffmann <kraxel@redhat.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: audio/
|
F: audio/
|
||||||
F: hw/audio/
|
F: hw/audio/
|
||||||
|
F: tests/ac97-test.c
|
||||||
|
F: tests/es1370-test.c
|
||||||
|
F: tests/intel-hda-test.c
|
||||||
|
|
||||||
Block
|
Block
|
||||||
M: Kevin Wolf <kwolf@redhat.com>
|
M: Kevin Wolf <kwolf@redhat.com>
|
||||||
@@ -674,6 +691,8 @@ S: Supported
|
|||||||
F: block*
|
F: block*
|
||||||
F: block/
|
F: block/
|
||||||
F: hw/block/
|
F: hw/block/
|
||||||
|
F: qemu-img*
|
||||||
|
F: qemu-io*
|
||||||
T: git git://repo.or.cz/qemu/kevin.git block
|
T: git git://repo.or.cz/qemu/kevin.git block
|
||||||
T: git git://github.com/stefanha/qemu.git block
|
T: git git://github.com/stefanha/qemu.git block
|
||||||
|
|
||||||
@@ -778,6 +797,17 @@ S: Supported
|
|||||||
F: qapi-schema.json
|
F: qapi-schema.json
|
||||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
||||||
|
|
||||||
|
QOM
|
||||||
|
M: Anthony Liguori <aliguori@amazon.com>
|
||||||
|
M: Andreas Färber <afaerber@suse.de>
|
||||||
|
S: Supported
|
||||||
|
T: git git://github.com/afaerber/qemu-cpu.git qom-next
|
||||||
|
F: include/qom/
|
||||||
|
X: include/qom/cpu.h
|
||||||
|
F: qom/
|
||||||
|
X: qom/cpu.c
|
||||||
|
F: tests/qom-test.c
|
||||||
|
|
||||||
QMP
|
QMP
|
||||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
46
Makefile
46
Makefile
@@ -148,10 +148,6 @@ endif
|
|||||||
|
|
||||||
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
|
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
|
||||||
|
|
||||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
|
||||||
|
|
||||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
|
|
||||||
|
|
||||||
config-host.h: config-host.h-timestamp
|
config-host.h: config-host.h-timestamp
|
||||||
config-host.h-timestamp: config-host.mak
|
config-host.h-timestamp: config-host.mak
|
||||||
qemu-options.def: $(SRC_PATH)/qemu-options.hx
|
qemu-options.def: $(SRC_PATH)/qemu-options.hx
|
||||||
@@ -195,8 +191,6 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
|
|||||||
|
|
||||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
||||||
|
|
||||||
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
|
|
||||||
|
|
||||||
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h | $(BUILD_DIR)/version.lo
|
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h | $(BUILD_DIR)/version.lo
|
||||||
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o")
|
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o")
|
||||||
$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h
|
$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h
|
||||||
@@ -238,23 +232,35 @@ qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
|
|||||||
|
|
||||||
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
|
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
|
||||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||||
|
$(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \
|
||||||
|
" GEN $@")
|
||||||
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
|
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
|
||||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||||
|
$(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \
|
||||||
|
" GEN $@")
|
||||||
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
|
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
|
||||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||||
|
$(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \
|
||||||
|
" GEN $@")
|
||||||
|
|
||||||
qapi-types.c qapi-types.h :\
|
qapi-types.c qapi-types.h :\
|
||||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." -b < $<, " GEN $@")
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||||
|
$(gen-out-type) -o "." -b -i $<, \
|
||||||
|
" GEN $@")
|
||||||
qapi-visit.c qapi-visit.h :\
|
qapi-visit.c qapi-visit.h :\
|
||||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." -b < $<, " GEN $@")
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||||
|
$(gen-out-type) -o "." -b -i $<, \
|
||||||
|
" GEN $@")
|
||||||
qmp-commands.h qmp-marshal.c :\
|
qmp-commands.h qmp-marshal.c :\
|
||||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@")
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||||
|
$(gen-out-type) -o "." -m -i $<, \
|
||||||
|
" GEN $@")
|
||||||
|
|
||||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
||||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
||||||
@@ -372,17 +378,25 @@ install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \
|
|||||||
install-datadir install-localstatedir
|
install-datadir install-localstatedir
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
|
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
|
||||||
ifneq ($(TOOLS),)
|
ifneq ($(TOOLS),)
|
||||||
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
|
$(INSTALL_PROG) $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||||
|
ifneq ($(STRIP),)
|
||||||
|
$(STRIP) $(TOOLS:%="$(DESTDIR)$(bindir)/%")
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
ifneq ($(CONFIG_MODULES),)
|
ifneq ($(CONFIG_MODULES),)
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
||||||
for s in $(patsubst %.mo,%$(DSOSUF),$(modules-m)); do \
|
for s in $(modules-m:.mo=$(DSOSUF)); do \
|
||||||
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \
|
t="$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \
|
||||||
|
$(INSTALL_LIB) $$s "$$t"; \
|
||||||
|
test -z "$(STRIP)" || $(STRIP) "$$t"; \
|
||||||
done
|
done
|
||||||
endif
|
endif
|
||||||
ifneq ($(HELPERS-y),)
|
ifneq ($(HELPERS-y),)
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
|
$(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
|
||||||
$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
|
$(INSTALL_PROG) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
|
||||||
|
ifneq ($(STRIP),)
|
||||||
|
$(STRIP) $(HELPERS-y:%="$(DESTDIR)$(libexecdir)/%")
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
ifneq ($(BLOBS),)
|
ifneq ($(BLOBS),)
|
||||||
set -e; for x in $(BLOBS); do \
|
set -e; for x in $(BLOBS); do \
|
||||||
|
@@ -31,6 +31,8 @@ libcacard-y += libcacard/vcard_emul_nss.o
|
|||||||
libcacard-y += libcacard/vcard_emul_type.o
|
libcacard-y += libcacard/vcard_emul_type.o
|
||||||
libcacard-y += libcacard/card_7816.o
|
libcacard-y += libcacard/card_7816.o
|
||||||
libcacard-y += libcacard/vcardt.o
|
libcacard-y += libcacard/vcardt.o
|
||||||
|
libcacard/vcard_emul_nss.o-cflags := $(NSS_CFLAGS)
|
||||||
|
libcacard/vcard_emul_nss.o-libs := $(NSS_LIBS)
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Target independent part of system emulation. The long term path is to
|
# Target independent part of system emulation. The long term path is to
|
||||||
@@ -64,9 +66,11 @@ common-obj-y += hw/
|
|||||||
|
|
||||||
common-obj-y += ui/
|
common-obj-y += ui/
|
||||||
common-obj-y += bt-host.o bt-vhci.o
|
common-obj-y += bt-host.o bt-vhci.o
|
||||||
|
bt-host.o-cflags := $(BLUEZ_CFLAGS)
|
||||||
|
|
||||||
common-obj-y += dma-helpers.o
|
common-obj-y += dma-helpers.o
|
||||||
common-obj-y += vl.o
|
common-obj-y += vl.o
|
||||||
|
vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS)
|
||||||
common-obj-y += tpm.o
|
common-obj-y += tpm.o
|
||||||
|
|
||||||
common-obj-$(CONFIG_SLIRP) += slirp/
|
common-obj-$(CONFIG_SLIRP) += slirp/
|
||||||
|
@@ -16,19 +16,22 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/include
|
|||||||
ifdef CONFIG_USER_ONLY
|
ifdef CONFIG_USER_ONLY
|
||||||
# user emulator name
|
# user emulator name
|
||||||
QEMU_PROG=qemu-$(TARGET_NAME)
|
QEMU_PROG=qemu-$(TARGET_NAME)
|
||||||
|
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||||
else
|
else
|
||||||
# system emulator name
|
# system emulator name
|
||||||
|
QEMU_PROG=qemu-system-$(TARGET_NAME)$(EXESUF)
|
||||||
ifneq (,$(findstring -mwindows,$(libs_softmmu)))
|
ifneq (,$(findstring -mwindows,$(libs_softmmu)))
|
||||||
# Terminate program name with a 'w' because the linker builds a windows executable.
|
# Terminate program name with a 'w' because the linker builds a windows executable.
|
||||||
QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF)
|
QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF)
|
||||||
endif # windows executable
|
$(QEMU_PROG): $(QEMU_PROGW)
|
||||||
QEMU_PROG=qemu-system-$(TARGET_NAME)$(EXESUF)
|
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
|
||||||
|
QEMU_PROG_BUILD = $(QEMU_PROGW)
|
||||||
|
else
|
||||||
|
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
PROGS=$(QEMU_PROG)
|
PROGS=$(QEMU_PROG) $(QEMU_PROGW)
|
||||||
ifdef QEMU_PROGW
|
|
||||||
PROGS+=$(QEMU_PROGW)
|
|
||||||
endif
|
|
||||||
STPFILES=
|
STPFILES=
|
||||||
|
|
||||||
config-target.h: config-target.h-timestamp
|
config-target.h: config-target.h-timestamp
|
||||||
@@ -120,8 +123,10 @@ obj-y += dump.o
|
|||||||
LIBS+=$(libs_softmmu)
|
LIBS+=$(libs_softmmu)
|
||||||
|
|
||||||
# xen support
|
# xen support
|
||||||
obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o
|
obj-$(CONFIG_XEN) += xen-common.o
|
||||||
obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o
|
obj-$(CONFIG_XEN_I386) += xen-hvm.o xen-mapcache.o
|
||||||
|
obj-$(call lnot,$(CONFIG_XEN)) += xen-common-stub.o
|
||||||
|
obj-$(call lnot,$(CONFIG_XEN_I386)) += xen-hvm-stub.o
|
||||||
|
|
||||||
# Hardware support
|
# Hardware support
|
||||||
ifeq ($(TARGET_NAME), sparc64)
|
ifeq ($(TARGET_NAME), sparc64)
|
||||||
@@ -138,10 +143,7 @@ endif # CONFIG_SOFTMMU
|
|||||||
%/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS)
|
%/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS)
|
||||||
|
|
||||||
dummy := $(call unnest-vars,,obj-y)
|
dummy := $(call unnest-vars,,obj-y)
|
||||||
|
all-obj-y := $(obj-y)
|
||||||
# we are making another call to unnest-vars with different vars, protect obj-y,
|
|
||||||
# it can be overriden in subdir Makefile.objs
|
|
||||||
obj-y-save := $(obj-y)
|
|
||||||
|
|
||||||
block-obj-y :=
|
block-obj-y :=
|
||||||
common-obj-y :=
|
common-obj-y :=
|
||||||
@@ -151,27 +153,16 @@ dummy := $(call unnest-vars,.., \
|
|||||||
block-obj-m \
|
block-obj-m \
|
||||||
common-obj-y \
|
common-obj-y \
|
||||||
common-obj-m)
|
common-obj-m)
|
||||||
|
all-obj-y += $(common-obj-y)
|
||||||
# Now restore obj-y
|
|
||||||
obj-y := $(obj-y-save)
|
|
||||||
|
|
||||||
all-obj-y = $(obj-y) $(common-obj-y)
|
|
||||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
|
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
|
||||||
|
|
||||||
ifndef CONFIG_HAIKU
|
ifndef CONFIG_HAIKU
|
||||||
LIBS+=-lm
|
LIBS+=-lm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef QEMU_PROGW
|
# build either PROG or PROGW
|
||||||
# The linker builds a windows executable. Make also a console executable.
|
$(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
||||||
$(QEMU_PROGW): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
|
||||||
$(call LINK,$^)
|
$(call LINK,$^)
|
||||||
$(QEMU_PROG): $(QEMU_PROGW)
|
|
||||||
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
|
|
||||||
else
|
|
||||||
$(QEMU_PROG): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
|
||||||
$(call LINK,$^)
|
|
||||||
endif
|
|
||||||
|
|
||||||
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
|
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
|
||||||
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
|
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
|
||||||
@@ -192,9 +183,9 @@ endif
|
|||||||
|
|
||||||
install: all
|
install: all
|
||||||
ifneq ($(PROGS),)
|
ifneq ($(PROGS),)
|
||||||
$(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)"
|
$(INSTALL_PROG) $(PROGS) "$(DESTDIR)$(bindir)"
|
||||||
ifneq ($(STRIP),)
|
ifneq ($(STRIP),)
|
||||||
$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
|
$(STRIP) $(PROGS:%="$(DESTDIR)$(bindir)/%")
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||||
|
367
arch_init.c
367
arch_init.c
@@ -45,6 +45,7 @@
|
|||||||
#include "hw/audio/pcspk.h"
|
#include "hw/audio/pcspk.h"
|
||||||
#include "migration/page_cache.h"
|
#include "migration/page_cache.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "exec/cpu-all.h"
|
#include "exec/cpu-all.h"
|
||||||
@@ -110,6 +111,8 @@ static bool mig_throttle_on;
|
|||||||
static int dirty_rate_high_cnt;
|
static int dirty_rate_high_cnt;
|
||||||
static void check_guest_throttling(void);
|
static void check_guest_throttling(void);
|
||||||
|
|
||||||
|
static uint64_t bitmap_sync_count;
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* ram save/restore */
|
/* ram save/restore */
|
||||||
|
|
||||||
@@ -167,11 +170,8 @@ static struct {
|
|||||||
/* Cache for XBZRLE, Protected by lock. */
|
/* Cache for XBZRLE, Protected by lock. */
|
||||||
PageCache *cache;
|
PageCache *cache;
|
||||||
QemuMutex lock;
|
QemuMutex lock;
|
||||||
} XBZRLE = {
|
} XBZRLE;
|
||||||
.encoded_buf = NULL,
|
|
||||||
.current_buf = NULL,
|
|
||||||
.cache = NULL,
|
|
||||||
};
|
|
||||||
/* buffer used for XBZRLE decoding */
|
/* buffer used for XBZRLE decoding */
|
||||||
static uint8_t *xbzrle_decoded_buf;
|
static uint8_t *xbzrle_decoded_buf;
|
||||||
|
|
||||||
@@ -187,41 +187,44 @@ static void XBZRLE_cache_unlock(void)
|
|||||||
qemu_mutex_unlock(&XBZRLE.lock);
|
qemu_mutex_unlock(&XBZRLE.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* called from qmp_migrate_set_cache_size in main thread, possibly while
|
||||||
|
* a migration is in progress.
|
||||||
|
* A running migration maybe using the cache and might finish during this
|
||||||
|
* call, hence changes to the cache are protected by XBZRLE.lock().
|
||||||
|
*/
|
||||||
int64_t xbzrle_cache_resize(int64_t new_size)
|
int64_t xbzrle_cache_resize(int64_t new_size)
|
||||||
{
|
{
|
||||||
PageCache *new_cache, *cache_to_free;
|
PageCache *new_cache;
|
||||||
|
int64_t ret;
|
||||||
|
|
||||||
if (new_size < TARGET_PAGE_SIZE) {
|
if (new_size < TARGET_PAGE_SIZE) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no need to lock, the current thread holds qemu big lock */
|
XBZRLE_cache_lock();
|
||||||
|
|
||||||
if (XBZRLE.cache != NULL) {
|
if (XBZRLE.cache != NULL) {
|
||||||
/* check XBZRLE.cache again later */
|
|
||||||
if (pow2floor(new_size) == migrate_xbzrle_cache_size()) {
|
if (pow2floor(new_size) == migrate_xbzrle_cache_size()) {
|
||||||
return pow2floor(new_size);
|
goto out_new_size;
|
||||||
}
|
}
|
||||||
new_cache = cache_init(new_size / TARGET_PAGE_SIZE,
|
new_cache = cache_init(new_size / TARGET_PAGE_SIZE,
|
||||||
TARGET_PAGE_SIZE);
|
TARGET_PAGE_SIZE);
|
||||||
if (!new_cache) {
|
if (!new_cache) {
|
||||||
DPRINTF("Error creating cache\n");
|
error_report("Error creating cache");
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
XBZRLE_cache_lock();
|
cache_fini(XBZRLE.cache);
|
||||||
/* the XBZRLE.cache may have be destroyed, check it again */
|
XBZRLE.cache = new_cache;
|
||||||
if (XBZRLE.cache != NULL) {
|
|
||||||
cache_to_free = XBZRLE.cache;
|
|
||||||
XBZRLE.cache = new_cache;
|
|
||||||
} else {
|
|
||||||
cache_to_free = new_cache;
|
|
||||||
}
|
|
||||||
XBZRLE_cache_unlock();
|
|
||||||
|
|
||||||
cache_fini(cache_to_free);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pow2floor(new_size);
|
out_new_size:
|
||||||
|
ret = pow2floor(new_size);
|
||||||
|
out:
|
||||||
|
XBZRLE_cache_unlock();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* accounting for migration statistics */
|
/* accounting for migration statistics */
|
||||||
@@ -233,6 +236,7 @@ typedef struct AccountingInfo {
|
|||||||
uint64_t xbzrle_bytes;
|
uint64_t xbzrle_bytes;
|
||||||
uint64_t xbzrle_pages;
|
uint64_t xbzrle_pages;
|
||||||
uint64_t xbzrle_cache_miss;
|
uint64_t xbzrle_cache_miss;
|
||||||
|
double xbzrle_cache_miss_rate;
|
||||||
uint64_t xbzrle_overflows;
|
uint64_t xbzrle_overflows;
|
||||||
} AccountingInfo;
|
} AccountingInfo;
|
||||||
|
|
||||||
@@ -288,6 +292,11 @@ uint64_t xbzrle_mig_pages_cache_miss(void)
|
|||||||
return acct_info.xbzrle_cache_miss;
|
return acct_info.xbzrle_cache_miss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double xbzrle_mig_cache_miss_rate(void)
|
||||||
|
{
|
||||||
|
return acct_info.xbzrle_cache_miss_rate;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t xbzrle_mig_pages_overflow(void)
|
uint64_t xbzrle_mig_pages_overflow(void)
|
||||||
{
|
{
|
||||||
return acct_info.xbzrle_overflows;
|
return acct_info.xbzrle_overflows;
|
||||||
@@ -340,7 +349,7 @@ static void xbzrle_cache_zero_page(ram_addr_t current_addr)
|
|||||||
|
|
||||||
#define ENCODING_FLAG_XBZRLE 0x1
|
#define ENCODING_FLAG_XBZRLE 0x1
|
||||||
|
|
||||||
static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data,
|
||||||
ram_addr_t current_addr, RAMBlock *block,
|
ram_addr_t current_addr, RAMBlock *block,
|
||||||
ram_addr_t offset, int cont, bool last_stage)
|
ram_addr_t offset, int cont, bool last_stage)
|
||||||
{
|
{
|
||||||
@@ -348,19 +357,23 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
|||||||
uint8_t *prev_cached_page;
|
uint8_t *prev_cached_page;
|
||||||
|
|
||||||
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
|
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
|
||||||
|
acct_info.xbzrle_cache_miss++;
|
||||||
if (!last_stage) {
|
if (!last_stage) {
|
||||||
if (cache_insert(XBZRLE.cache, current_addr, current_data) == -1) {
|
if (cache_insert(XBZRLE.cache, current_addr, *current_data) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
} else {
|
||||||
|
/* update *current_data when the page has been
|
||||||
|
inserted into cache */
|
||||||
|
*current_data = get_cached_data(XBZRLE.cache, current_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
acct_info.xbzrle_cache_miss++;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_cached_page = get_cached_data(XBZRLE.cache, current_addr);
|
prev_cached_page = get_cached_data(XBZRLE.cache, current_addr);
|
||||||
|
|
||||||
/* save current buffer into memory */
|
/* save current buffer into memory */
|
||||||
memcpy(XBZRLE.current_buf, current_data, TARGET_PAGE_SIZE);
|
memcpy(XBZRLE.current_buf, *current_data, TARGET_PAGE_SIZE);
|
||||||
|
|
||||||
/* XBZRLE encoding (if there is no overflow) */
|
/* XBZRLE encoding (if there is no overflow) */
|
||||||
encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf,
|
encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf,
|
||||||
@@ -373,7 +386,10 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
|||||||
DPRINTF("Overflow\n");
|
DPRINTF("Overflow\n");
|
||||||
acct_info.xbzrle_overflows++;
|
acct_info.xbzrle_overflows++;
|
||||||
/* update data in the cache */
|
/* update data in the cache */
|
||||||
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
|
if (!last_stage) {
|
||||||
|
memcpy(prev_cached_page, *current_data, TARGET_PAGE_SIZE);
|
||||||
|
*current_data = prev_cached_page;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,6 +495,10 @@ static void migration_bitmap_sync(void)
|
|||||||
static int64_t num_dirty_pages_period;
|
static int64_t num_dirty_pages_period;
|
||||||
int64_t end_time;
|
int64_t end_time;
|
||||||
int64_t bytes_xfer_now;
|
int64_t bytes_xfer_now;
|
||||||
|
static uint64_t xbzrle_cache_miss_prev;
|
||||||
|
static uint64_t iterations_prev;
|
||||||
|
|
||||||
|
bitmap_sync_count++;
|
||||||
|
|
||||||
if (!bytes_xfer_prev) {
|
if (!bytes_xfer_prev) {
|
||||||
bytes_xfer_prev = ram_bytes_transferred();
|
bytes_xfer_prev = ram_bytes_transferred();
|
||||||
@@ -520,29 +540,113 @@ static void migration_bitmap_sync(void)
|
|||||||
} else {
|
} else {
|
||||||
mig_throttle_on = false;
|
mig_throttle_on = false;
|
||||||
}
|
}
|
||||||
|
if (migrate_use_xbzrle()) {
|
||||||
|
if (iterations_prev != 0) {
|
||||||
|
acct_info.xbzrle_cache_miss_rate =
|
||||||
|
(double)(acct_info.xbzrle_cache_miss -
|
||||||
|
xbzrle_cache_miss_prev) /
|
||||||
|
(acct_info.iterations - iterations_prev);
|
||||||
|
}
|
||||||
|
iterations_prev = acct_info.iterations;
|
||||||
|
xbzrle_cache_miss_prev = acct_info.xbzrle_cache_miss;
|
||||||
|
}
|
||||||
s->dirty_pages_rate = num_dirty_pages_period * 1000
|
s->dirty_pages_rate = num_dirty_pages_period * 1000
|
||||||
/ (end_time - start_time);
|
/ (end_time - start_time);
|
||||||
s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
|
s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
|
||||||
start_time = end_time;
|
start_time = end_time;
|
||||||
num_dirty_pages_period = 0;
|
num_dirty_pages_period = 0;
|
||||||
|
s->dirty_sync_count = bitmap_sync_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ram_save_block: Writes a page of memory to the stream f
|
* ram_save_page: Send the given page to the stream
|
||||||
|
*
|
||||||
|
* Returns: Number of bytes written.
|
||||||
|
*/
|
||||||
|
static int ram_save_page(QEMUFile *f, RAMBlock* block, ram_addr_t offset,
|
||||||
|
bool last_stage)
|
||||||
|
{
|
||||||
|
int bytes_sent;
|
||||||
|
int cont;
|
||||||
|
ram_addr_t current_addr;
|
||||||
|
MemoryRegion *mr = block->mr;
|
||||||
|
uint8_t *p;
|
||||||
|
int ret;
|
||||||
|
bool send_async = true;
|
||||||
|
|
||||||
|
cont = (block == last_sent_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
|
||||||
|
|
||||||
|
p = memory_region_get_ram_ptr(mr) + offset;
|
||||||
|
|
||||||
|
/* In doubt sent page as normal */
|
||||||
|
bytes_sent = -1;
|
||||||
|
ret = ram_control_save_page(f, block->offset,
|
||||||
|
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
||||||
|
|
||||||
|
XBZRLE_cache_lock();
|
||||||
|
|
||||||
|
current_addr = block->offset + offset;
|
||||||
|
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
||||||
|
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
||||||
|
if (bytes_sent > 0) {
|
||||||
|
acct_info.norm_pages++;
|
||||||
|
} else if (bytes_sent == 0) {
|
||||||
|
acct_info.dup_pages++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (is_zero_range(p, TARGET_PAGE_SIZE)) {
|
||||||
|
acct_info.dup_pages++;
|
||||||
|
bytes_sent = save_block_hdr(f, block, offset, cont,
|
||||||
|
RAM_SAVE_FLAG_COMPRESS);
|
||||||
|
qemu_put_byte(f, 0);
|
||||||
|
bytes_sent++;
|
||||||
|
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
||||||
|
* page would be stale
|
||||||
|
*/
|
||||||
|
xbzrle_cache_zero_page(current_addr);
|
||||||
|
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
||||||
|
bytes_sent = save_xbzrle_page(f, &p, current_addr, block,
|
||||||
|
offset, cont, last_stage);
|
||||||
|
if (!last_stage) {
|
||||||
|
/* Can't send this cached data async, since the cache page
|
||||||
|
* might get updated before it gets to the wire
|
||||||
|
*/
|
||||||
|
send_async = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XBZRLE overflow or normal page */
|
||||||
|
if (bytes_sent == -1) {
|
||||||
|
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
||||||
|
if (send_async) {
|
||||||
|
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
||||||
|
} else {
|
||||||
|
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
||||||
|
}
|
||||||
|
bytes_sent += TARGET_PAGE_SIZE;
|
||||||
|
acct_info.norm_pages++;
|
||||||
|
}
|
||||||
|
|
||||||
|
XBZRLE_cache_unlock();
|
||||||
|
|
||||||
|
return bytes_sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ram_find_and_save_block: Finds a page to send and sends it to f
|
||||||
*
|
*
|
||||||
* Returns: The number of bytes written.
|
* Returns: The number of bytes written.
|
||||||
* 0 means no dirty pages
|
* 0 means no dirty pages
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int ram_save_block(QEMUFile *f, bool last_stage)
|
static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
||||||
{
|
{
|
||||||
RAMBlock *block = last_seen_block;
|
RAMBlock *block = last_seen_block;
|
||||||
ram_addr_t offset = last_offset;
|
ram_addr_t offset = last_offset;
|
||||||
bool complete_round = false;
|
bool complete_round = false;
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
ram_addr_t current_addr;
|
|
||||||
|
|
||||||
if (!block)
|
if (!block)
|
||||||
block = QTAILQ_FIRST(&ram_list.blocks);
|
block = QTAILQ_FIRST(&ram_list.blocks);
|
||||||
@@ -563,70 +667,8 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
|
|||||||
ram_bulk_stage = false;
|
ram_bulk_stage = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int ret;
|
bytes_sent = ram_save_page(f, block, offset, last_stage);
|
||||||
uint8_t *p;
|
|
||||||
bool send_async = true;
|
|
||||||
int cont = (block == last_sent_block) ?
|
|
||||||
RAM_SAVE_FLAG_CONTINUE : 0;
|
|
||||||
|
|
||||||
p = memory_region_get_ram_ptr(mr) + offset;
|
|
||||||
|
|
||||||
/* In doubt sent page as normal */
|
|
||||||
bytes_sent = -1;
|
|
||||||
ret = ram_control_save_page(f, block->offset,
|
|
||||||
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
|
||||||
|
|
||||||
XBZRLE_cache_lock();
|
|
||||||
|
|
||||||
current_addr = block->offset + offset;
|
|
||||||
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
|
||||||
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
|
||||||
if (bytes_sent > 0) {
|
|
||||||
acct_info.norm_pages++;
|
|
||||||
} else if (bytes_sent == 0) {
|
|
||||||
acct_info.dup_pages++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (is_zero_range(p, TARGET_PAGE_SIZE)) {
|
|
||||||
acct_info.dup_pages++;
|
|
||||||
bytes_sent = save_block_hdr(f, block, offset, cont,
|
|
||||||
RAM_SAVE_FLAG_COMPRESS);
|
|
||||||
qemu_put_byte(f, 0);
|
|
||||||
bytes_sent++;
|
|
||||||
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
|
||||||
* page would be stale
|
|
||||||
*/
|
|
||||||
xbzrle_cache_zero_page(current_addr);
|
|
||||||
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
|
||||||
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
|
|
||||||
offset, cont, last_stage);
|
|
||||||
if (!last_stage) {
|
|
||||||
/* We must send exactly what's in the xbzrle cache
|
|
||||||
* even if the page wasn't xbzrle compressed, so that
|
|
||||||
* it's right next time.
|
|
||||||
*/
|
|
||||||
p = get_cached_data(XBZRLE.cache, current_addr);
|
|
||||||
|
|
||||||
/* Can't send this cached data async, since the cache page
|
|
||||||
* might get updated before it gets to the wire
|
|
||||||
*/
|
|
||||||
send_async = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XBZRLE overflow or normal page */
|
|
||||||
if (bytes_sent == -1) {
|
|
||||||
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
|
||||||
if (send_async) {
|
|
||||||
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
|
||||||
} else {
|
|
||||||
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
|
||||||
}
|
|
||||||
bytes_sent += TARGET_PAGE_SIZE;
|
|
||||||
acct_info.norm_pages++;
|
|
||||||
}
|
|
||||||
|
|
||||||
XBZRLE_cache_unlock();
|
|
||||||
/* if page is unmodified, continue to the next */
|
/* if page is unmodified, continue to the next */
|
||||||
if (bytes_sent > 0) {
|
if (bytes_sent > 0) {
|
||||||
last_sent_block = block;
|
last_sent_block = block;
|
||||||
@@ -726,37 +768,34 @@ static void reset_ram_globals(void)
|
|||||||
static int ram_save_setup(QEMUFile *f, void *opaque)
|
static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||||
{
|
{
|
||||||
RAMBlock *block;
|
RAMBlock *block;
|
||||||
int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS;
|
int64_t ram_bitmap_pages; /* Size of bitmap in pages, including gaps */
|
||||||
|
|
||||||
migration_bitmap = bitmap_new(ram_pages);
|
|
||||||
bitmap_set(migration_bitmap, 0, ram_pages);
|
|
||||||
migration_dirty_pages = ram_pages;
|
|
||||||
mig_throttle_on = false;
|
mig_throttle_on = false;
|
||||||
dirty_rate_high_cnt = 0;
|
dirty_rate_high_cnt = 0;
|
||||||
|
bitmap_sync_count = 0;
|
||||||
|
|
||||||
if (migrate_use_xbzrle()) {
|
if (migrate_use_xbzrle()) {
|
||||||
qemu_mutex_lock_iothread();
|
XBZRLE_cache_lock();
|
||||||
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
|
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
|
||||||
TARGET_PAGE_SIZE,
|
TARGET_PAGE_SIZE,
|
||||||
TARGET_PAGE_SIZE);
|
TARGET_PAGE_SIZE);
|
||||||
if (!XBZRLE.cache) {
|
if (!XBZRLE.cache) {
|
||||||
qemu_mutex_unlock_iothread();
|
XBZRLE_cache_unlock();
|
||||||
DPRINTF("Error creating cache\n");
|
error_report("Error creating cache");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
qemu_mutex_init(&XBZRLE.lock);
|
XBZRLE_cache_unlock();
|
||||||
qemu_mutex_unlock_iothread();
|
|
||||||
|
|
||||||
/* We prefer not to abort if there is no memory */
|
/* We prefer not to abort if there is no memory */
|
||||||
XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
|
XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
|
||||||
if (!XBZRLE.encoded_buf) {
|
if (!XBZRLE.encoded_buf) {
|
||||||
DPRINTF("Error allocating encoded_buf\n");
|
error_report("Error allocating encoded_buf");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE);
|
XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE);
|
||||||
if (!XBZRLE.current_buf) {
|
if (!XBZRLE.current_buf) {
|
||||||
DPRINTF("Error allocating current_buf\n");
|
error_report("Error allocating current_buf");
|
||||||
g_free(XBZRLE.encoded_buf);
|
g_free(XBZRLE.encoded_buf);
|
||||||
XBZRLE.encoded_buf = NULL;
|
XBZRLE.encoded_buf = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -770,6 +809,22 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
|||||||
bytes_transferred = 0;
|
bytes_transferred = 0;
|
||||||
reset_ram_globals();
|
reset_ram_globals();
|
||||||
|
|
||||||
|
ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS;
|
||||||
|
migration_bitmap = bitmap_new(ram_bitmap_pages);
|
||||||
|
bitmap_set(migration_bitmap, 0, ram_bitmap_pages);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count the total number of pages used by ram blocks not including any
|
||||||
|
* gaps due to alignment or unplugs.
|
||||||
|
*/
|
||||||
|
migration_dirty_pages = 0;
|
||||||
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
|
uint64_t block_pages;
|
||||||
|
|
||||||
|
block_pages = block->length >> TARGET_PAGE_BITS;
|
||||||
|
migration_dirty_pages += block_pages;
|
||||||
|
}
|
||||||
|
|
||||||
memory_global_dirty_log_start();
|
memory_global_dirty_log_start();
|
||||||
migration_bitmap_sync();
|
migration_bitmap_sync();
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
@@ -812,7 +867,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
|||||||
while ((ret = qemu_file_rate_limit(f)) == 0) {
|
while ((ret = qemu_file_rate_limit(f)) == 0) {
|
||||||
int bytes_sent;
|
int bytes_sent;
|
||||||
|
|
||||||
bytes_sent = ram_save_block(f, false);
|
bytes_sent = ram_find_and_save_block(f, false);
|
||||||
/* no more blocks to sent */
|
/* no more blocks to sent */
|
||||||
if (bytes_sent == 0) {
|
if (bytes_sent == 0) {
|
||||||
break;
|
break;
|
||||||
@@ -874,7 +929,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
|
|||||||
while (true) {
|
while (true) {
|
||||||
int bytes_sent;
|
int bytes_sent;
|
||||||
|
|
||||||
bytes_sent = ram_save_block(f, true);
|
bytes_sent = ram_find_and_save_block(f, true);
|
||||||
/* no more blocks to sent */
|
/* no more blocks to sent */
|
||||||
if (bytes_sent == 0) {
|
if (bytes_sent == 0) {
|
||||||
break;
|
break;
|
||||||
@@ -908,7 +963,6 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
|
|||||||
|
|
||||||
static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
||||||
{
|
{
|
||||||
int ret, rc = 0;
|
|
||||||
unsigned int xh_len;
|
unsigned int xh_len;
|
||||||
int xh_flags;
|
int xh_flags;
|
||||||
|
|
||||||
@@ -933,18 +987,13 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
|||||||
qemu_get_buffer(f, xbzrle_decoded_buf, xh_len);
|
qemu_get_buffer(f, xbzrle_decoded_buf, xh_len);
|
||||||
|
|
||||||
/* decode RLE */
|
/* decode RLE */
|
||||||
ret = xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
|
if (xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
|
||||||
TARGET_PAGE_SIZE);
|
TARGET_PAGE_SIZE) == -1) {
|
||||||
if (ret == -1) {
|
|
||||||
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
|
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
|
||||||
rc = -1;
|
return -1;
|
||||||
} else if (ret > TARGET_PAGE_SIZE) {
|
|
||||||
fprintf(stderr, "Failed to load XBZRLE page - size %d exceeds %d!\n",
|
|
||||||
ret, TARGET_PAGE_SIZE);
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *host_from_stream_offset(QEMUFile *f,
|
static inline void *host_from_stream_offset(QEMUFile *f,
|
||||||
@@ -997,8 +1046,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
|
|
||||||
seq_iter++;
|
seq_iter++;
|
||||||
|
|
||||||
if (version_id < 4 || version_id > 4) {
|
if (version_id != 4) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -1008,44 +1058,42 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
addr &= TARGET_PAGE_MASK;
|
addr &= TARGET_PAGE_MASK;
|
||||||
|
|
||||||
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
|
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
|
||||||
if (version_id == 4) {
|
/* Synchronize RAM block list */
|
||||||
/* Synchronize RAM block list */
|
char id[256];
|
||||||
char id[256];
|
ram_addr_t length;
|
||||||
ram_addr_t length;
|
ram_addr_t total_ram_bytes = addr;
|
||||||
ram_addr_t total_ram_bytes = addr;
|
|
||||||
|
|
||||||
while (total_ram_bytes) {
|
while (total_ram_bytes) {
|
||||||
RAMBlock *block;
|
RAMBlock *block;
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
|
|
||||||
len = qemu_get_byte(f);
|
len = qemu_get_byte(f);
|
||||||
qemu_get_buffer(f, (uint8_t *)id, len);
|
qemu_get_buffer(f, (uint8_t *)id, len);
|
||||||
id[len] = 0;
|
id[len] = 0;
|
||||||
length = qemu_get_be64(f);
|
length = qemu_get_be64(f);
|
||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
if (!strncmp(id, block->idstr, sizeof(id))) {
|
if (!strncmp(id, block->idstr, sizeof(id))) {
|
||||||
if (block->length != length) {
|
if (block->length != length) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Length mismatch: %s: " RAM_ADDR_FMT
|
"Length mismatch: %s: " RAM_ADDR_FMT
|
||||||
" in != " RAM_ADDR_FMT "\n", id, length,
|
" in != " RAM_ADDR_FMT "\n", id, length,
|
||||||
block->length);
|
block->length);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!block) {
|
|
||||||
fprintf(stderr, "Unknown ramblock \"%s\", cannot "
|
|
||||||
"accept migration\n", id);
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
total_ram_bytes -= length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!block) {
|
||||||
|
fprintf(stderr, "Unknown ramblock \"%s\", cannot "
|
||||||
|
"accept migration\n", id);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_ram_bytes -= length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1055,7 +1103,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
|
|
||||||
host = host_from_stream_offset(f, addr, flags);
|
host = host_from_stream_offset(f, addr, flags);
|
||||||
if (!host) {
|
if (!host) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = qemu_get_byte(f);
|
ch = qemu_get_byte(f);
|
||||||
@@ -1065,14 +1114,16 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
|
|
||||||
host = host_from_stream_offset(f, addr, flags);
|
host = host_from_stream_offset(f, addr, flags);
|
||||||
if (!host) {
|
if (!host) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
|
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
|
||||||
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
|
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
|
||||||
void *host = host_from_stream_offset(f, addr, flags);
|
void *host = host_from_stream_offset(f, addr, flags);
|
||||||
if (!host) {
|
if (!host) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load_xbzrle(f, addr, host) < 0) {
|
if (load_xbzrle(f, addr, host) < 0) {
|
||||||
@@ -1095,7 +1146,7 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveVMHandlers savevm_ram_handlers = {
|
static SaveVMHandlers savevm_ram_handlers = {
|
||||||
.save_live_setup = ram_save_setup,
|
.save_live_setup = ram_save_setup,
|
||||||
.save_live_iterate = ram_save_iterate,
|
.save_live_iterate = ram_save_iterate,
|
||||||
.save_live_complete = ram_save_complete,
|
.save_live_complete = ram_save_complete,
|
||||||
@@ -1104,6 +1155,12 @@ SaveVMHandlers savevm_ram_handlers = {
|
|||||||
.cancel = ram_migration_cancel,
|
.cancel = ram_migration_cancel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ram_mig_init(void)
|
||||||
|
{
|
||||||
|
qemu_mutex_init(&XBZRLE.lock);
|
||||||
|
register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
struct soundhw {
|
struct soundhw {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *descr;
|
const char *descr;
|
||||||
|
@@ -14,4 +14,4 @@ common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
|
|||||||
common-obj-y += wavcapture.o
|
common-obj-y += wavcapture.o
|
||||||
|
|
||||||
$(obj)/audio.o $(obj)/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
|
$(obj)/audio.o $(obj)/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
|
||||||
$(obj)/sdlaudio.o: QEMU_CFLAGS += $(SDL_CFLAGS)
|
sdlaudio.o-cflags := $(SDL_CFLAGS)
|
||||||
|
@@ -1812,8 +1812,7 @@ static const VMStateDescription vmstate_audio = {
|
|||||||
.name = "audio",
|
.name = "audio",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -3,6 +3,6 @@ common-obj-$(CONFIG_POSIX) += rng-random.o
|
|||||||
|
|
||||||
common-obj-y += msmouse.o
|
common-obj-y += msmouse.o
|
||||||
common-obj-$(CONFIG_BRLAPI) += baum.o
|
common-obj-$(CONFIG_BRLAPI) += baum.o
|
||||||
$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
|
baum.o-cflags := $(SDL_CFLAGS)
|
||||||
|
|
||||||
common-obj-$(CONFIG_TPM) += tpm.o
|
common-obj-$(CONFIG_TPM) += tpm.o
|
||||||
|
@@ -50,6 +50,7 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
|||||||
{
|
{
|
||||||
RngBackend *s = RNG_BACKEND(obj);
|
RngBackend *s = RNG_BACKEND(obj);
|
||||||
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
|
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
if (value == s->opened) {
|
if (value == s->opened) {
|
||||||
return;
|
return;
|
||||||
@@ -61,12 +62,14 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (k->opened) {
|
if (k->opened) {
|
||||||
k->opened(s, errp);
|
k->opened(s, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error_is_set(errp)) {
|
s->opened = true;
|
||||||
s->opened = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rng_backend_init(Object *obj)
|
static void rng_backend_init(Object *obj)
|
||||||
|
@@ -112,6 +112,7 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
|||||||
{
|
{
|
||||||
TPMBackend *s = TPM_BACKEND(obj);
|
TPMBackend *s = TPM_BACKEND(obj);
|
||||||
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
if (value == s->opened) {
|
if (value == s->opened) {
|
||||||
return;
|
return;
|
||||||
@@ -123,12 +124,14 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (k->opened) {
|
if (k->opened) {
|
||||||
k->opened(s, errp);
|
k->opened(s, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error_is_set(errp)) {
|
s->opened = true;
|
||||||
s->opened = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tpm_backend_instance_init(Object *obj)
|
static void tpm_backend_instance_init(Object *obj)
|
||||||
|
@@ -310,13 +310,28 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
|
|||||||
|
|
||||||
/* Called with iothread lock taken. */
|
/* Called with iothread lock taken. */
|
||||||
|
|
||||||
static void set_dirty_tracking(void)
|
static int set_dirty_tracking(void)
|
||||||
{
|
{
|
||||||
BlkMigDevState *bmds;
|
BlkMigDevState *bmds;
|
||||||
|
int ret;
|
||||||
|
|
||||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||||
bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE);
|
bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE,
|
||||||
|
NULL);
|
||||||
|
if (!bmds->dirty_bitmap) {
|
||||||
|
ret = -errno;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||||
|
if (bmds->dirty_bitmap) {
|
||||||
|
bdrv_release_dirty_bitmap(bmds->bs, bmds->dirty_bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unset_dirty_tracking(void)
|
static void unset_dirty_tracking(void)
|
||||||
@@ -611,10 +626,17 @@ static int block_save_setup(QEMUFile *f, void *opaque)
|
|||||||
block_mig_state.submitted, block_mig_state.transferred);
|
block_mig_state.submitted, block_mig_state.transferred);
|
||||||
|
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
init_blk_migration(f);
|
|
||||||
|
|
||||||
/* start track dirty blocks */
|
/* start track dirty blocks */
|
||||||
set_dirty_tracking();
|
ret = set_dirty_tracking();
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_blk_migration(f);
|
||||||
|
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
|
|
||||||
ret = flush_blks(f);
|
ret = flush_blks(f);
|
||||||
|
228
block.c
228
block.c
@@ -332,10 +332,21 @@ void bdrv_register(BlockDriver *bdrv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* create a new block device (by default it is empty) */
|
/* create a new block device (by default it is empty) */
|
||||||
BlockDriverState *bdrv_new(const char *device_name)
|
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
|
||||||
|
if (bdrv_find(device_name)) {
|
||||||
|
error_setg(errp, "Device with id '%s' already exists",
|
||||||
|
device_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (bdrv_find_node(device_name)) {
|
||||||
|
error_setg(errp, "Device with node-name '%s' already exists",
|
||||||
|
device_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bs = g_malloc0(sizeof(BlockDriverState));
|
bs = g_malloc0(sizeof(BlockDriverState));
|
||||||
QLIST_INIT(&bs->dirty_bitmaps);
|
QLIST_INIT(&bs->dirty_bitmaps);
|
||||||
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
|
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
|
||||||
@@ -763,15 +774,54 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
|
|||||||
bs->copy_on_read--;
|
bs->copy_on_read--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the flags that a temporary snapshot should get, based on the
|
||||||
|
* originally requested flags (the originally requested image will have flags
|
||||||
|
* like a backing file)
|
||||||
|
*/
|
||||||
|
static int bdrv_temp_snapshot_flags(int flags)
|
||||||
|
{
|
||||||
|
return (flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the flags that bs->file should get, based on the given flags for
|
||||||
|
* the parent BDS
|
||||||
|
*/
|
||||||
|
static int bdrv_inherited_flags(int flags)
|
||||||
|
{
|
||||||
|
/* Enable protocol handling, disable format probing for bs->file */
|
||||||
|
flags |= BDRV_O_PROTOCOL;
|
||||||
|
|
||||||
|
/* Our block drivers take care to send flushes and respect unmap policy,
|
||||||
|
* so we can enable both unconditionally on lower layers. */
|
||||||
|
flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
|
||||||
|
|
||||||
|
/* Clear flags that only apply to the top layer */
|
||||||
|
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the flags that bs->backing_hd should get, based on the given flags
|
||||||
|
* for the parent BDS
|
||||||
|
*/
|
||||||
|
static int bdrv_backing_flags(int flags)
|
||||||
|
{
|
||||||
|
/* backing files always opened read-only */
|
||||||
|
flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
|
||||||
|
|
||||||
|
/* snapshot=on is handled on the top layer */
|
||||||
|
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||||
{
|
{
|
||||||
int open_flags = flags | BDRV_O_CACHE_WB;
|
int open_flags = flags | BDRV_O_CACHE_WB;
|
||||||
|
|
||||||
/* The backing file of a temporary snapshot is read-only */
|
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
|
||||||
open_flags &= ~BDRV_O_RDWR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear flags that are internal to the block layer before opening the
|
* Clear flags that are internal to the block layer before opening the
|
||||||
* image.
|
* image.
|
||||||
@@ -781,45 +831,43 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
|||||||
/*
|
/*
|
||||||
* Snapshots should be writable.
|
* Snapshots should be writable.
|
||||||
*/
|
*/
|
||||||
if (bs->is_temporary) {
|
if (flags & BDRV_O_TEMPORARY) {
|
||||||
open_flags |= BDRV_O_RDWR;
|
open_flags |= BDRV_O_RDWR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return open_flags;
|
return open_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bdrv_assign_node_name(BlockDriverState *bs,
|
static void bdrv_assign_node_name(BlockDriverState *bs,
|
||||||
const char *node_name,
|
const char *node_name,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
if (!node_name) {
|
if (!node_name) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* empty string node name is invalid */
|
/* empty string node name is invalid */
|
||||||
if (node_name[0] == '\0') {
|
if (node_name[0] == '\0') {
|
||||||
error_setg(errp, "Empty node name");
|
error_setg(errp, "Empty node name");
|
||||||
return -EINVAL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* takes care of avoiding namespaces collisions */
|
/* takes care of avoiding namespaces collisions */
|
||||||
if (bdrv_find(node_name)) {
|
if (bdrv_find(node_name)) {
|
||||||
error_setg(errp, "node-name=%s is conflicting with a device id",
|
error_setg(errp, "node-name=%s is conflicting with a device id",
|
||||||
node_name);
|
node_name);
|
||||||
return -EINVAL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* takes care of avoiding duplicates node names */
|
/* takes care of avoiding duplicates node names */
|
||||||
if (bdrv_find_node(node_name)) {
|
if (bdrv_find_node(node_name)) {
|
||||||
error_setg(errp, "Duplicate node name");
|
error_setg(errp, "Duplicate node name");
|
||||||
return -EINVAL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy node name into the bs and insert it into the graph list */
|
/* copy node name into the bs and insert it into the graph list */
|
||||||
pstrcpy(bs->node_name, sizeof(bs->node_name), node_name);
|
pstrcpy(bs->node_name, sizeof(bs->node_name), node_name);
|
||||||
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);
|
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -854,9 +902,10 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
|||||||
trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
|
trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
|
||||||
|
|
||||||
node_name = qdict_get_try_str(options, "node-name");
|
node_name = qdict_get_try_str(options, "node-name");
|
||||||
ret = bdrv_assign_node_name(bs, node_name, errp);
|
bdrv_assign_node_name(bs, node_name, &local_err);
|
||||||
if (ret < 0) {
|
if (local_err) {
|
||||||
return ret;
|
error_propagate(errp, local_err);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
qdict_del(options, "node-name");
|
qdict_del(options, "node-name");
|
||||||
|
|
||||||
@@ -941,13 +990,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
|||||||
bdrv_refresh_limits(bs);
|
bdrv_refresh_limits(bs);
|
||||||
assert(bdrv_opt_mem_align(bs) != 0);
|
assert(bdrv_opt_mem_align(bs) != 0);
|
||||||
assert((bs->request_alignment != 0) || bs->sg);
|
assert((bs->request_alignment != 0) || bs->sg);
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
if (bs->is_temporary) {
|
|
||||||
assert(bs->filename[0] != '\0');
|
|
||||||
unlink(bs->filename);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_and_fail:
|
free_and_fail:
|
||||||
@@ -1058,14 +1100,14 @@ fail:
|
|||||||
*/
|
*/
|
||||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||||
{
|
{
|
||||||
char backing_filename[PATH_MAX];
|
char *backing_filename = g_malloc0(PATH_MAX);
|
||||||
int back_flags, ret;
|
int ret = 0;
|
||||||
BlockDriver *back_drv = NULL;
|
BlockDriver *back_drv = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
if (bs->backing_hd != NULL) {
|
if (bs->backing_hd != NULL) {
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
return 0;
|
goto free_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NULL means an empty set of options */
|
/* NULL means an empty set of options */
|
||||||
@@ -1078,31 +1120,26 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
backing_filename[0] = '\0';
|
backing_filename[0] = '\0';
|
||||||
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
|
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
return 0;
|
goto free_exit;
|
||||||
} else {
|
} else {
|
||||||
bdrv_get_full_backing_filename(bs, backing_filename,
|
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX);
|
||||||
sizeof(backing_filename));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->backing_format[0] != '\0') {
|
if (bs->backing_format[0] != '\0') {
|
||||||
back_drv = bdrv_find_format(bs->backing_format);
|
back_drv = bdrv_find_format(bs->backing_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* backing files always opened read-only */
|
|
||||||
back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT |
|
|
||||||
BDRV_O_COPY_ON_READ);
|
|
||||||
|
|
||||||
assert(bs->backing_hd == NULL);
|
assert(bs->backing_hd == NULL);
|
||||||
ret = bdrv_open(&bs->backing_hd,
|
ret = bdrv_open(&bs->backing_hd,
|
||||||
*backing_filename ? backing_filename : NULL, NULL, options,
|
*backing_filename ? backing_filename : NULL, NULL, options,
|
||||||
back_flags, back_drv, &local_err);
|
bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bs->backing_hd = NULL;
|
bs->backing_hd = NULL;
|
||||||
bs->open_flags |= BDRV_O_NO_BACKING;
|
bs->open_flags |= BDRV_O_NO_BACKING;
|
||||||
error_setg(errp, "Could not open backing file: %s",
|
error_setg(errp, "Could not open backing file: %s",
|
||||||
error_get_pretty(local_err));
|
error_get_pretty(local_err));
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
return ret;
|
goto free_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->backing_hd->file) {
|
if (bs->backing_hd->file) {
|
||||||
@@ -1113,7 +1150,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
/* Recalculate the BlockLimits with the backing file */
|
/* Recalculate the BlockLimits with the backing file */
|
||||||
bdrv_refresh_limits(bs);
|
bdrv_refresh_limits(bs);
|
||||||
|
|
||||||
return 0;
|
free_exit:
|
||||||
|
g_free(backing_filename);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1167,11 +1206,10 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||||
{
|
{
|
||||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||||
char tmp_filename[PATH_MAX + 1];
|
char *tmp_filename = g_malloc0(PATH_MAX + 1);
|
||||||
|
|
||||||
int64_t total_size;
|
int64_t total_size;
|
||||||
BlockDriver *bdrv_qcow2;
|
BlockDriver *bdrv_qcow2;
|
||||||
QEMUOptionParameter *create_options;
|
QEMUOptionParameter *create_options;
|
||||||
@@ -1187,15 +1225,15 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
|||||||
total_size = bdrv_getlength(bs);
|
total_size = bdrv_getlength(bs);
|
||||||
if (total_size < 0) {
|
if (total_size < 0) {
|
||||||
error_setg_errno(errp, -total_size, "Could not get image size");
|
error_setg_errno(errp, -total_size, "Could not get image size");
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
total_size &= BDRV_SECTOR_MASK;
|
total_size &= BDRV_SECTOR_MASK;
|
||||||
|
|
||||||
/* Create the temporary image */
|
/* Create the temporary image */
|
||||||
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_qcow2 = bdrv_find_format("qcow2");
|
bdrv_qcow2 = bdrv_find_format("qcow2");
|
||||||
@@ -1211,7 +1249,7 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
|||||||
"'%s': %s", tmp_filename,
|
"'%s': %s", tmp_filename,
|
||||||
error_get_pretty(local_err));
|
error_get_pretty(local_err));
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare a new options QDict for the temporary file */
|
/* Prepare a new options QDict for the temporary file */
|
||||||
@@ -1221,17 +1259,19 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
|||||||
qdict_put(snapshot_options, "file.filename",
|
qdict_put(snapshot_options, "file.filename",
|
||||||
qstring_from_str(tmp_filename));
|
qstring_from_str(tmp_filename));
|
||||||
|
|
||||||
bs_snapshot = bdrv_new("");
|
bs_snapshot = bdrv_new("", &error_abort);
|
||||||
bs_snapshot->is_temporary = 1;
|
|
||||||
|
|
||||||
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||||
bs->open_flags & ~BDRV_O_SNAPSHOT, bdrv_qcow2, &local_err);
|
flags, bdrv_qcow2, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_append(bs_snapshot, bs);
|
bdrv_append(bs_snapshot, bs);
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free(tmp_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1257,6 +1297,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
BlockDriverState *file = NULL, *bs;
|
BlockDriverState *file = NULL, *bs;
|
||||||
const char *drvname;
|
const char *drvname;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
int snapshot_flags = 0;
|
||||||
|
|
||||||
assert(pbs);
|
assert(pbs);
|
||||||
|
|
||||||
@@ -1288,7 +1329,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
if (*pbs) {
|
if (*pbs) {
|
||||||
bs = *pbs;
|
bs = *pbs;
|
||||||
} else {
|
} else {
|
||||||
bs = bdrv_new("");
|
bs = bdrv_new("", &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NULL means an empty set of options */
|
/* NULL means an empty set of options */
|
||||||
@@ -1317,13 +1358,17 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
if (flags & BDRV_O_RDWR) {
|
if (flags & BDRV_O_RDWR) {
|
||||||
flags |= BDRV_O_ALLOW_RDWR;
|
flags |= BDRV_O_ALLOW_RDWR;
|
||||||
}
|
}
|
||||||
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
|
snapshot_flags = bdrv_temp_snapshot_flags(flags);
|
||||||
|
flags = bdrv_backing_flags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
assert(file == NULL);
|
assert(file == NULL);
|
||||||
ret = bdrv_open_image(&file, filename, options, "file",
|
ret = bdrv_open_image(&file, filename, options, "file",
|
||||||
bdrv_open_flags(bs, flags | BDRV_O_UNMAP) |
|
bdrv_inherited_flags(flags),
|
||||||
BDRV_O_PROTOCOL, true, &local_err);
|
true, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the right image format driver */
|
/* Find the right image format driver */
|
||||||
@@ -1334,7 +1379,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_setg(errp, "Invalid driver: '%s'", drvname);
|
error_setg(errp, "Invalid driver: '%s'", drvname);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1344,18 +1389,18 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
} else {
|
} else {
|
||||||
error_setg(errp, "Must specify either driver or file");
|
error_setg(errp, "Must specify either driver or file");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open the image */
|
/* Open the image */
|
||||||
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
|
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file && (bs->file != file)) {
|
if (file && (bs->file != file)) {
|
||||||
@@ -1376,8 +1421,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
|
|
||||||
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
|
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
|
||||||
* temporary snapshot afterwards. */
|
* temporary snapshot afterwards. */
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
if (snapshot_flags) {
|
||||||
bdrv_append_temp_snapshot(bs, &local_err);
|
bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto close_and_fail;
|
goto close_and_fail;
|
||||||
@@ -1417,14 +1462,10 @@ done:
|
|||||||
*pbs = bs;
|
*pbs = bs;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unlink_and_fail:
|
fail:
|
||||||
if (file != NULL) {
|
if (file != NULL) {
|
||||||
bdrv_unref(file);
|
bdrv_unref(file);
|
||||||
}
|
}
|
||||||
if (bs->is_temporary) {
|
|
||||||
unlink(filename);
|
|
||||||
}
|
|
||||||
fail:
|
|
||||||
QDECREF(bs->options);
|
QDECREF(bs->options);
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
bs->options = NULL;
|
bs->options = NULL;
|
||||||
@@ -1488,8 +1529,11 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
|||||||
QSIMPLEQ_INIT(bs_queue);
|
QSIMPLEQ_INIT(bs_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* bdrv_open() masks this flag out */
|
||||||
|
flags &= ~BDRV_O_PROTOCOL;
|
||||||
|
|
||||||
if (bs->file) {
|
if (bs->file) {
|
||||||
bdrv_reopen_queue(bs_queue, bs->file, flags);
|
bdrv_reopen_queue(bs_queue, bs->file, bdrv_inherited_flags(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
||||||
@@ -1704,11 +1748,6 @@ void bdrv_close(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
bs->drv->bdrv_close(bs);
|
bs->drv->bdrv_close(bs);
|
||||||
g_free(bs->opaque);
|
g_free(bs->opaque);
|
||||||
#ifdef _WIN32
|
|
||||||
if (bs->is_temporary) {
|
|
||||||
unlink(bs->filename);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
bs->drv = NULL;
|
bs->drv = NULL;
|
||||||
bs->copy_on_read = 0;
|
bs->copy_on_read = 0;
|
||||||
@@ -1832,7 +1871,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
|||||||
BlockDriverState *bs_src)
|
BlockDriverState *bs_src)
|
||||||
{
|
{
|
||||||
/* move some fields that need to stay attached to the device */
|
/* move some fields that need to stay attached to the device */
|
||||||
bs_dest->open_flags = bs_src->open_flags;
|
|
||||||
|
|
||||||
/* dev info */
|
/* dev info */
|
||||||
bs_dest->dev_ops = bs_src->dev_ops;
|
bs_dest->dev_ops = bs_src->dev_ops;
|
||||||
@@ -2581,6 +2619,10 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
|||||||
{
|
{
|
||||||
int64_t len;
|
int64_t len;
|
||||||
|
|
||||||
|
if (size > INT_MAX) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
if (!bdrv_is_inserted(bs))
|
if (!bdrv_is_inserted(bs))
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
|
|
||||||
@@ -2601,7 +2643,7 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
|||||||
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors)
|
int nb_sectors)
|
||||||
{
|
{
|
||||||
if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
if (nb_sectors < 0 || nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2686,6 +2728,10 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
|
|||||||
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
|
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (nb_sectors < 0 || nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
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(bs, sector_num << BDRV_SECTOR_BITS,
|
||||||
&qiov, is_write, flags);
|
&qiov, is_write, flags);
|
||||||
@@ -2741,10 +2787,16 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
|||||||
*/
|
*/
|
||||||
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
int64_t target_size = bdrv_getlength(bs) / BDRV_SECTOR_SIZE;
|
int64_t target_size;
|
||||||
int64_t ret, nb_sectors, sector_num = 0;
|
int64_t ret, nb_sectors, sector_num = 0;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
target_size = bdrv_getlength(bs);
|
||||||
|
if (target_size < 0) {
|
||||||
|
return target_size;
|
||||||
|
}
|
||||||
|
target_size /= BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
nb_sectors = target_size - sector_num;
|
nb_sectors = target_size - sector_num;
|
||||||
if (nb_sectors <= 0) {
|
if (nb_sectors <= 0) {
|
||||||
@@ -3574,10 +3626,25 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
|
|||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
|
int count = 0;
|
||||||
|
const char **formats = NULL;
|
||||||
|
|
||||||
QLIST_FOREACH(drv, &bdrv_drivers, list) {
|
QLIST_FOREACH(drv, &bdrv_drivers, list) {
|
||||||
it(opaque, drv->format_name);
|
if (drv->format_name) {
|
||||||
|
bool found = false;
|
||||||
|
int i = count;
|
||||||
|
while (formats && i && !found) {
|
||||||
|
found = !strcmp(formats[--i], drv->format_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
formats = g_realloc(formats, (count + 1) * sizeof(char *));
|
||||||
|
formats[count++] = drv->format_name;
|
||||||
|
it(opaque, drv->format_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
g_free(formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is to find block backend bs */
|
/* This function is to find block backend bs */
|
||||||
@@ -5096,7 +5163,8 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity)
|
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
int64_t bitmap_size;
|
int64_t bitmap_size;
|
||||||
BdrvDirtyBitmap *bitmap;
|
BdrvDirtyBitmap *bitmap;
|
||||||
@@ -5105,7 +5173,13 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity)
|
|||||||
|
|
||||||
granularity >>= BDRV_SECTOR_BITS;
|
granularity >>= BDRV_SECTOR_BITS;
|
||||||
assert(granularity);
|
assert(granularity);
|
||||||
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS);
|
bitmap_size = bdrv_getlength(bs);
|
||||||
|
if (bitmap_size < 0) {
|
||||||
|
error_setg_errno(errp, -bitmap_size, "could not get length of device");
|
||||||
|
errno = -bitmap_size;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
bitmap_size >>= BDRV_SECTOR_BITS;
|
||||||
bitmap = g_malloc0(sizeof(BdrvDirtyBitmap));
|
bitmap = g_malloc0(sizeof(BdrvDirtyBitmap));
|
||||||
bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
|
bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
|
||||||
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
|
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
|
||||||
|
@@ -187,13 +187,14 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
|||||||
uint64_t offset = sector_num * 512;
|
uint64_t offset = sector_num * 512;
|
||||||
uint64_t extent_index, extent_offset, bitmap_offset;
|
uint64_t extent_index, extent_offset, bitmap_offset;
|
||||||
char bitmap_entry;
|
char bitmap_entry;
|
||||||
|
int ret;
|
||||||
|
|
||||||
// seek to sector
|
// seek to sector
|
||||||
extent_index = offset / s->extent_size;
|
extent_index = offset / s->extent_size;
|
||||||
extent_offset = (offset % s->extent_size) / 512;
|
extent_offset = (offset % s->extent_size) / 512;
|
||||||
|
|
||||||
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
||||||
return -1; /* not allocated */
|
return 0; /* not allocated */
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap_offset = s->data_offset +
|
bitmap_offset = s->data_offset +
|
||||||
@@ -201,13 +202,14 @@ 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 */
|
||||||
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||||
&bitmap_entry, 1) != 1) {
|
&bitmap_entry, 1);
|
||||||
return -1;
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
||||||
return -1; /* not allocated */
|
return 0; /* not allocated */
|
||||||
}
|
}
|
||||||
|
|
||||||
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
||||||
@@ -220,13 +222,16 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
int64_t block_offset = seek_to_sector(bs, sector_num);
|
int64_t block_offset = seek_to_sector(bs, sector_num);
|
||||||
if (block_offset >= 0) {
|
if (block_offset < 0) {
|
||||||
|
return block_offset;
|
||||||
|
} else if (block_offset > 0) {
|
||||||
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
||||||
if (ret != 512) {
|
if (ret < 0) {
|
||||||
return -1;
|
return ret;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
memset(buf, 0, 512);
|
memset(buf, 0, 512);
|
||||||
|
}
|
||||||
nb_sectors--;
|
nb_sectors--;
|
||||||
sector_num++;
|
sector_num++;
|
||||||
buf += 512;
|
buf += 512;
|
||||||
|
@@ -72,7 +72,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
s->block_size = be32_to_cpu(s->block_size);
|
s->block_size = be32_to_cpu(s->block_size);
|
||||||
if (s->block_size % 512) {
|
if (s->block_size % 512) {
|
||||||
error_setg(errp, "block_size %u must be a multiple of 512",
|
error_setg(errp, "block_size %" PRIu32 " must be a multiple of 512",
|
||||||
s->block_size);
|
s->block_size);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
* need a buffer this big.
|
* need a buffer this big.
|
||||||
*/
|
*/
|
||||||
if (s->block_size > MAX_BLOCK_SIZE) {
|
if (s->block_size > MAX_BLOCK_SIZE) {
|
||||||
error_setg(errp, "block_size %u must be %u MB or less",
|
error_setg(errp, "block_size %" PRIu32 " must be %u MB or less",
|
||||||
s->block_size,
|
s->block_size,
|
||||||
MAX_BLOCK_SIZE / (1024 * 1024));
|
MAX_BLOCK_SIZE / (1024 * 1024));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -101,7 +101,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
/* read offsets */
|
/* read offsets */
|
||||||
if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
||||||
/* Prevent integer overflow */
|
/* Prevent integer overflow */
|
||||||
error_setg(errp, "n_blocks %u must be %zu or less",
|
error_setg(errp, "n_blocks %" PRIu32 " must be %zu or less",
|
||||||
s->n_blocks,
|
s->n_blocks,
|
||||||
(UINT32_MAX - 1) / sizeof(uint64_t));
|
(UINT32_MAX - 1) / sizeof(uint64_t));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -133,7 +133,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
if (s->offsets[i] < s->offsets[i - 1]) {
|
if (s->offsets[i] < s->offsets[i - 1]) {
|
||||||
error_setg(errp, "offsets not monotonically increasing at "
|
error_setg(errp, "offsets not monotonically increasing at "
|
||||||
"index %u, image file is corrupt", i);
|
"index %" PRIu32 ", image file is corrupt", i);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -146,8 +146,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
* ridiculous s->compressed_block allocation.
|
* ridiculous s->compressed_block allocation.
|
||||||
*/
|
*/
|
||||||
if (size > 2 * MAX_BLOCK_SIZE) {
|
if (size > 2 * MAX_BLOCK_SIZE) {
|
||||||
error_setg(errp, "invalid compressed block size at index %u, "
|
error_setg(errp, "invalid compressed block size at index %" PRIu32
|
||||||
"image file is corrupt", i);
|
", image file is corrupt", i);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@@ -194,7 +194,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
|||||||
if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
|
if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
|
||||||
on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
||||||
!bdrv_iostatus_is_enabled(bs)) {
|
!bdrv_iostatus_is_enabled(bs)) {
|
||||||
error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
|
error_setg(errp, "Invalid parameter combination");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -82,7 +82,7 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
||||||
char version[64];
|
char version[64];
|
||||||
snprintf(version, sizeof(version),
|
snprintf(version, sizeof(version),
|
||||||
"COW version %d", cow_header.version);
|
"COW version %" PRIu32, cow_header.version);
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
bs->device_name, "cow", version);
|
bs->device_name, "cow", version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
149
block/curl.c
149
block/curl.c
@@ -71,6 +71,7 @@ typedef struct CURLState
|
|||||||
struct BDRVCURLState *s;
|
struct BDRVCURLState *s;
|
||||||
CURLAIOCB *acb[CURL_NUM_ACB];
|
CURLAIOCB *acb[CURL_NUM_ACB];
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
|
curl_socket_t sock_fd;
|
||||||
char *orig_buf;
|
char *orig_buf;
|
||||||
size_t buf_start;
|
size_t buf_start;
|
||||||
size_t buf_off;
|
size_t buf_off;
|
||||||
@@ -92,6 +93,7 @@ typedef struct BDRVCURLState {
|
|||||||
|
|
||||||
static void curl_clean_state(CURLState *s);
|
static void curl_clean_state(CURLState *s);
|
||||||
static void curl_multi_do(void *arg);
|
static void curl_multi_do(void *arg);
|
||||||
|
static void curl_multi_read(void *arg);
|
||||||
|
|
||||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||||
@@ -113,16 +115,20 @@ static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
|||||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||||
void *s, void *sp)
|
void *s, void *sp)
|
||||||
{
|
{
|
||||||
|
CURLState *state = NULL;
|
||||||
|
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
|
||||||
|
state->sock_fd = fd;
|
||||||
|
|
||||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case CURL_POLL_IN:
|
case CURL_POLL_IN:
|
||||||
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, s);
|
qemu_aio_set_fd_handler(fd, curl_multi_read, NULL, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_OUT:
|
case CURL_POLL_OUT:
|
||||||
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, s);
|
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_INOUT:
|
case CURL_POLL_INOUT:
|
||||||
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, s);
|
qemu_aio_set_fd_handler(fd, curl_multi_read, curl_multi_do, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_REMOVE:
|
case CURL_POLL_REMOVE:
|
||||||
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
|
||||||
@@ -155,7 +161,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|||||||
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
||||||
|
|
||||||
if (!s || !s->orig_buf)
|
if (!s || !s->orig_buf)
|
||||||
goto read_end;
|
return 0;
|
||||||
|
|
||||||
if (s->buf_off >= s->buf_len) {
|
if (s->buf_off >= s->buf_len) {
|
||||||
/* buffer full, read nothing */
|
/* buffer full, read nothing */
|
||||||
@@ -180,7 +186,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read_end:
|
|
||||||
return realsize;
|
return realsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +220,8 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for unfinished chunks
|
// Wait for unfinished chunks
|
||||||
if ((start >= state->buf_start) &&
|
if (state->in_use &&
|
||||||
|
(start >= state->buf_start) &&
|
||||||
(start <= buf_fend) &&
|
(start <= buf_fend) &&
|
||||||
(end >= state->buf_start) &&
|
(end >= state->buf_start) &&
|
||||||
(end <= buf_fend))
|
(end <= buf_fend))
|
||||||
@@ -237,68 +243,69 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|||||||
return FIND_RET_NONE;
|
return FIND_RET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_read(BDRVCURLState *s)
|
static void curl_multi_check_completion(BDRVCURLState *s)
|
||||||
{
|
{
|
||||||
int msgs_in_queue;
|
int msgs_in_queue;
|
||||||
|
|
||||||
/* Try to find done transfers, so we can free the easy
|
/* Try to find done transfers, so we can free the easy
|
||||||
* handle again. */
|
* handle again. */
|
||||||
do {
|
for (;;) {
|
||||||
CURLMsg *msg;
|
CURLMsg *msg;
|
||||||
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
|
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
|
||||||
|
|
||||||
|
/* Quit when there are no more completions */
|
||||||
if (!msg)
|
if (!msg)
|
||||||
break;
|
break;
|
||||||
if (msg->msg == CURLMSG_NONE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (msg->msg) {
|
if (msg->msg == CURLMSG_DONE) {
|
||||||
case CURLMSG_DONE:
|
CURLState *state = NULL;
|
||||||
{
|
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
|
||||||
CURLState *state = NULL;
|
(char **)&state);
|
||||||
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
|
|
||||||
|
|
||||||
/* ACBs for successful messages get completed in curl_read_cb */
|
/* ACBs for successful messages get completed in curl_read_cb */
|
||||||
if (msg->data.result != CURLE_OK) {
|
if (msg->data.result != CURLE_OK) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < CURL_NUM_ACB; i++) {
|
for (i = 0; i < CURL_NUM_ACB; i++) {
|
||||||
CURLAIOCB *acb = state->acb[i];
|
CURLAIOCB *acb = state->acb[i];
|
||||||
|
|
||||||
if (acb == NULL) {
|
if (acb == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
acb->common.cb(acb->common.opaque, -EIO);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
state->acb[i] = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
curl_clean_state(state);
|
acb->common.cb(acb->common.opaque, -EIO);
|
||||||
break;
|
qemu_aio_release(acb);
|
||||||
|
state->acb[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
msgs_in_queue = 0;
|
curl_clean_state(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(msgs_in_queue);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_do(void *arg)
|
static void curl_multi_do(void *arg)
|
||||||
{
|
{
|
||||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
CURLState *s = (CURLState *)arg;
|
||||||
int running;
|
int running;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!s->multi) {
|
if (!s->s->multi) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = curl_multi_socket_all(s->multi, &running);
|
r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
|
||||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||||
|
|
||||||
curl_multi_read(s);
|
}
|
||||||
|
|
||||||
|
static void curl_multi_read(void *arg)
|
||||||
|
{
|
||||||
|
CURLState *s = (CURLState *)arg;
|
||||||
|
|
||||||
|
curl_multi_do(arg);
|
||||||
|
curl_multi_check_completion(s->s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_timeout_do(void *arg)
|
static void curl_multi_timeout_do(void *arg)
|
||||||
@@ -313,7 +320,7 @@ static void curl_multi_timeout_do(void *arg)
|
|||||||
|
|
||||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
|
|
||||||
curl_multi_read(s);
|
curl_multi_check_completion(s);
|
||||||
#else
|
#else
|
||||||
abort();
|
abort();
|
||||||
#endif
|
#endif
|
||||||
@@ -337,44 +344,42 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!state) {
|
if (!state) {
|
||||||
g_usleep(100);
|
qemu_aio_wait();
|
||||||
curl_multi_do(s);
|
|
||||||
}
|
}
|
||||||
} while(!state);
|
} while(!state);
|
||||||
|
|
||||||
if (state->curl)
|
if (!state->curl) {
|
||||||
goto has_curl;
|
state->curl = curl_easy_init();
|
||||||
|
if (!state->curl) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||||
|
(void *)curl_read_cb);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
|
||||||
|
|
||||||
state->curl = curl_easy_init();
|
/* Restrict supported protocols to avoid security issues in the more
|
||||||
if (!state->curl)
|
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
|
||||||
return NULL;
|
* CVE-2013-0249.
|
||||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
*
|
||||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
* Restricting protocols is only supported from 7.19.4 upwards.
|
||||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
|
*/
|
||||||
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
|
|
||||||
|
|
||||||
/* Restrict supported protocols to avoid security issues in the more
|
|
||||||
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
|
|
||||||
* CVE-2013-0249.
|
|
||||||
*
|
|
||||||
* Restricting protocols is only supported from 7.19.4 upwards.
|
|
||||||
*/
|
|
||||||
#if LIBCURL_VERSION_NUM >= 0x071304
|
#if LIBCURL_VERSION_NUM >= 0x071304
|
||||||
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
|
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
|
||||||
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
|
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
has_curl:
|
|
||||||
|
|
||||||
state->s = s;
|
state->s = s;
|
||||||
|
|
||||||
@@ -531,19 +536,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
// initialize the multi interface!
|
// initialize the multi interface!
|
||||||
|
|
||||||
s->multi = curl_multi_init();
|
s->multi = curl_multi_init();
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
||||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
||||||
#endif
|
#endif
|
||||||
curl_multi_do(s);
|
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg);
|
error_setg(errp, "CURL: Error opening file: %s", state->errmsg);
|
||||||
curl_easy_cleanup(state->curl);
|
curl_easy_cleanup(state->curl);
|
||||||
state->curl = NULL;
|
state->curl = NULL;
|
||||||
out_noclean:
|
out_noclean:
|
||||||
@@ -566,6 +569,7 @@ static const AIOCBInfo curl_aiocb_info = {
|
|||||||
static void curl_readv_bh_cb(void *p)
|
static void curl_readv_bh_cb(void *p)
|
||||||
{
|
{
|
||||||
CURLState *state;
|
CURLState *state;
|
||||||
|
int running;
|
||||||
|
|
||||||
CURLAIOCB *acb = p;
|
CURLAIOCB *acb = p;
|
||||||
BDRVCURLState *s = acb->common.bs->opaque;
|
BDRVCURLState *s = acb->common.bs->opaque;
|
||||||
@@ -614,8 +618,9 @@ static void curl_readv_bh_cb(void *p)
|
|||||||
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
||||||
|
|
||||||
curl_multi_add_handle(s->multi, state->curl);
|
curl_multi_add_handle(s->multi, state->curl);
|
||||||
curl_multi_do(s);
|
|
||||||
|
|
||||||
|
/* Tell curl it needs to kick things off */
|
||||||
|
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||||
|
@@ -248,8 +248,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
||||||
error_report("sector count %" PRIu64 " for chunk %u is "
|
error_report("sector count %" PRIu64 " for chunk %" PRIu32
|
||||||
"larger than max (%u)",
|
" is larger than max (%u)",
|
||||||
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -269,8 +269,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
||||||
error_report("length %" PRIu64 " for chunk %u is larger "
|
error_report("length %" PRIu64 " for chunk %" PRIu32
|
||||||
"than max (%u)",
|
" is larger than max (%u)",
|
||||||
s->lengths[i], i, DMG_LENGTHS_MAX);
|
s->lengths[i], i, DMG_LENGTHS_MAX);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@@ -207,6 +207,11 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
|
|||||||
"volume=%s image=%s transport=%s", gconf->server,
|
"volume=%s image=%s transport=%s", gconf->server,
|
||||||
gconf->port, gconf->volname, gconf->image,
|
gconf->port, gconf->volname, gconf->image,
|
||||||
gconf->transport);
|
gconf->transport);
|
||||||
|
|
||||||
|
/* glfs_init sometimes doesn't set errno although docs suggest that */
|
||||||
|
if (errno == 0)
|
||||||
|
errno = EINVAL;
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
return glfs;
|
return glfs;
|
||||||
@@ -482,7 +487,7 @@ static int qemu_gluster_create(const char *filename,
|
|||||||
|
|
||||||
glfs = qemu_gluster_init(gconf, filename, errp);
|
glfs = qemu_gluster_init(gconf, filename, errp);
|
||||||
if (!glfs) {
|
if (!glfs) {
|
||||||
ret = -EINVAL;
|
ret = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
332
block/iscsi.c
332
block/iscsi.c
@@ -2,7 +2,7 @@
|
|||||||
* QEMU Block driver for iSCSI images
|
* QEMU Block driver for iSCSI images
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||||
* Copyright (c) 2012-2013 Peter Lieven <pl@kamp.de>
|
* Copyright (c) 2012-2014 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
|
||||||
@@ -30,6 +30,8 @@
|
|||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "qemu/bitops.h"
|
||||||
|
#include "qemu/bitmap.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "block/scsi.h"
|
#include "block/scsi.h"
|
||||||
@@ -59,6 +61,8 @@ typedef struct IscsiLun {
|
|||||||
struct scsi_inquiry_logical_block_provisioning lbp;
|
struct scsi_inquiry_logical_block_provisioning lbp;
|
||||||
struct scsi_inquiry_block_limits bl;
|
struct scsi_inquiry_block_limits bl;
|
||||||
unsigned char *zeroblock;
|
unsigned char *zeroblock;
|
||||||
|
unsigned long *allocationmap;
|
||||||
|
int cluster_sectors;
|
||||||
} IscsiLun;
|
} IscsiLun;
|
||||||
|
|
||||||
typedef struct IscsiTask {
|
typedef struct IscsiTask {
|
||||||
@@ -92,6 +96,15 @@ typedef struct IscsiAIOCB {
|
|||||||
#define MAX_NOP_FAILURES 3
|
#define MAX_NOP_FAILURES 3
|
||||||
#define ISCSI_CMD_RETRIES 5
|
#define ISCSI_CMD_RETRIES 5
|
||||||
|
|
||||||
|
/* this threshhold is a trade-off knob to choose between
|
||||||
|
* the potential additional overhead of an extra GET_LBA_STATUS request
|
||||||
|
* vs. unnecessarily reading a lot of zero sectors over the wire.
|
||||||
|
* If a read request is greater or equal than ISCSI_CHECKALLOC_THRES
|
||||||
|
* sectors we check the allocation status of the area covered by the
|
||||||
|
* request first if the allocationmap indicates that the area might be
|
||||||
|
* unallocated. */
|
||||||
|
#define ISCSI_CHECKALLOC_THRES 64
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iscsi_bh_cb(void *p)
|
iscsi_bh_cb(void *p)
|
||||||
{
|
{
|
||||||
@@ -273,6 +286,32 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num,
|
||||||
|
int nb_sectors)
|
||||||
|
{
|
||||||
|
if (iscsilun->allocationmap == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bitmap_set(iscsilun->allocationmap,
|
||||||
|
sector_num / iscsilun->cluster_sectors,
|
||||||
|
DIV_ROUND_UP(nb_sectors, iscsilun->cluster_sectors));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num,
|
||||||
|
int nb_sectors)
|
||||||
|
{
|
||||||
|
int64_t cluster_num, nb_clusters;
|
||||||
|
if (iscsilun->allocationmap == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cluster_num = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors);
|
||||||
|
nb_clusters = (sector_num + nb_sectors) / iscsilun->cluster_sectors
|
||||||
|
- cluster_num;
|
||||||
|
if (nb_clusters > 0) {
|
||||||
|
bitmap_clear(iscsilun->allocationmap, cluster_num, nb_clusters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors,
|
int64_t sector_num, int nb_sectors,
|
||||||
QEMUIOVector *iov)
|
QEMUIOVector *iov)
|
||||||
@@ -336,9 +375,127 @@ retry:
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||||
|
int64_t sector_num, int nb_sectors)
|
||||||
|
{
|
||||||
|
unsigned long size;
|
||||||
|
if (iscsilun->allocationmap == NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors);
|
||||||
|
return !(find_next_bit(iscsilun->allocationmap, size,
|
||||||
|
sector_num / iscsilun->cluster_sectors) == size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||||
|
|
||||||
|
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||||
|
int64_t sector_num,
|
||||||
|
int nb_sectors, int *pnum)
|
||||||
|
{
|
||||||
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
|
struct scsi_get_lba_status *lbas = NULL;
|
||||||
|
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||||
|
struct IscsiTask iTask;
|
||||||
|
int64_t ret;
|
||||||
|
|
||||||
|
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||||
|
|
||||||
|
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default to all sectors allocated */
|
||||||
|
ret = BDRV_BLOCK_DATA;
|
||||||
|
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
|
||||||
|
*pnum = nb_sectors;
|
||||||
|
|
||||||
|
/* LUN does not support logical block provisioning */
|
||||||
|
if (iscsilun->lbpme == 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
|
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||||
|
sector_qemu2lun(sector_num, iscsilun),
|
||||||
|
8 + 16, iscsi_co_generic_cb,
|
||||||
|
&iTask) == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!iTask.complete) {
|
||||||
|
iscsi_set_events(iscsilun);
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iTask.do_retry) {
|
||||||
|
if (iTask.task != NULL) {
|
||||||
|
scsi_free_scsi_task(iTask.task);
|
||||||
|
iTask.task = NULL;
|
||||||
|
}
|
||||||
|
iTask.complete = 0;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||||
|
/* in case the get_lba_status_callout fails (i.e.
|
||||||
|
* because the device is busy or the cmd is not
|
||||||
|
* supported) we pretend all blocks are allocated
|
||||||
|
* for backwards compatibility */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
lbas = scsi_datain_unmarshall(iTask.task);
|
||||||
|
if (lbas == NULL) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
lbasd = &lbas->descriptors[0];
|
||||||
|
|
||||||
|
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
|
||||||
|
|
||||||
|
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
|
||||||
|
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
|
||||||
|
ret &= ~BDRV_BLOCK_DATA;
|
||||||
|
if (iscsilun->lbprz) {
|
||||||
|
ret |= BDRV_BLOCK_ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret & BDRV_BLOCK_ZERO) {
|
||||||
|
iscsi_allocationmap_clear(iscsilun, sector_num, *pnum);
|
||||||
|
} else {
|
||||||
|
iscsi_allocationmap_set(iscsilun, sector_num, *pnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pnum > nb_sectors) {
|
||||||
|
*pnum = nb_sectors;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
if (iTask.task != NULL) {
|
||||||
|
scsi_free_scsi_task(iTask.task);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
||||||
|
|
||||||
|
|
||||||
static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors,
|
int64_t sector_num, int nb_sectors,
|
||||||
QEMUIOVector *iov)
|
QEMUIOVector *iov)
|
||||||
@@ -355,6 +512,22 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||||
|
if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES &&
|
||||||
|
!iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
|
||||||
|
int64_t ret;
|
||||||
|
int pnum;
|
||||||
|
ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (ret & BDRV_BLOCK_ZERO && pnum >= nb_sectors) {
|
||||||
|
qemu_iovec_memset(iov, 0, 0x00, iov->size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||||
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
||||||
|
|
||||||
@@ -643,101 +816,6 @@ iscsi_getlength(BlockDriverState *bs)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
|
||||||
|
|
||||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
|
||||||
int64_t sector_num,
|
|
||||||
int nb_sectors, int *pnum)
|
|
||||||
{
|
|
||||||
IscsiLun *iscsilun = bs->opaque;
|
|
||||||
struct scsi_get_lba_status *lbas = NULL;
|
|
||||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
|
||||||
struct IscsiTask iTask;
|
|
||||||
int64_t ret;
|
|
||||||
|
|
||||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
|
||||||
|
|
||||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* default to all sectors allocated */
|
|
||||||
ret = BDRV_BLOCK_DATA;
|
|
||||||
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
|
|
||||||
*pnum = nb_sectors;
|
|
||||||
|
|
||||||
/* LUN does not support logical block provisioning */
|
|
||||||
if (iscsilun->lbpme == 0) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
retry:
|
|
||||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
|
||||||
sector_qemu2lun(sector_num, iscsilun),
|
|
||||||
8 + 16, iscsi_co_generic_cb,
|
|
||||||
&iTask) == NULL) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!iTask.complete) {
|
|
||||||
iscsi_set_events(iscsilun);
|
|
||||||
qemu_coroutine_yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iTask.do_retry) {
|
|
||||||
if (iTask.task != NULL) {
|
|
||||||
scsi_free_scsi_task(iTask.task);
|
|
||||||
iTask.task = NULL;
|
|
||||||
}
|
|
||||||
iTask.complete = 0;
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
|
||||||
/* in case the get_lba_status_callout fails (i.e.
|
|
||||||
* because the device is busy or the cmd is not
|
|
||||||
* supported) we pretend all blocks are allocated
|
|
||||||
* for backwards compatibility */
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
lbas = scsi_datain_unmarshall(iTask.task);
|
|
||||||
if (lbas == NULL) {
|
|
||||||
ret = -EIO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
lbasd = &lbas->descriptors[0];
|
|
||||||
|
|
||||||
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
|
|
||||||
ret = -EIO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
|
|
||||||
if (*pnum > nb_sectors) {
|
|
||||||
*pnum = nb_sectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
|
|
||||||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
|
|
||||||
ret &= ~BDRV_BLOCK_DATA;
|
|
||||||
if (iscsilun->lbprz) {
|
|
||||||
ret |= BDRV_BLOCK_ZERO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (iTask.task != NULL) {
|
|
||||||
scsi_free_scsi_task(iTask.task);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
|
coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors)
|
int nb_sectors)
|
||||||
@@ -791,6 +869,8 @@ retry:
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,13 +889,14 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||||
/* WRITE SAME without UNMAP is not supported by the target */
|
/* WRITE SAME with UNMAP is not supported by the target,
|
||||||
return -ENOTSUP;
|
* fall back and try WRITE SAME without UNMAP */
|
||||||
|
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||||
/* WRITE SAME with UNMAP is not supported by the target */
|
/* WRITE SAME without UNMAP is not supported by the target */
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -864,6 +945,12 @@ retry:
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & BDRV_REQ_MAY_UNMAP) {
|
||||||
|
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
|
||||||
|
} else {
|
||||||
|
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1095,16 +1182,15 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
|||||||
*inq = scsi_datain_unmarshall(task);
|
*inq = scsi_datain_unmarshall(task);
|
||||||
if (*inq == NULL) {
|
if (*inq == NULL) {
|
||||||
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
||||||
goto fail;
|
goto fail_with_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (!error_is_set(errp)) {
|
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
||||||
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
iscsi_get_error(iscsi));
|
||||||
iscsi_get_error(iscsi));
|
fail_with_err:
|
||||||
}
|
|
||||||
if (task != NULL) {
|
if (task != NULL) {
|
||||||
scsi_free_scsi_task(task);
|
scsi_free_scsi_task(task);
|
||||||
}
|
}
|
||||||
@@ -1296,6 +1382,22 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||||
|
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||||
|
* reasonable size */
|
||||||
|
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 &&
|
||||||
|
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||||
|
iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
|
||||||
|
iscsilun->block_size) >> BDRV_SECTOR_BITS;
|
||||||
|
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||||
|
if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||||
|
iscsilun->allocationmap =
|
||||||
|
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||||
|
iscsilun->cluster_sectors));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
if (initiator_name != NULL) {
|
if (initiator_name != NULL) {
|
||||||
@@ -1329,6 +1431,7 @@ static void iscsi_close(BlockDriverState *bs)
|
|||||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL);
|
||||||
iscsi_destroy_context(iscsi);
|
iscsi_destroy_context(iscsi);
|
||||||
g_free(iscsilun->zeroblock);
|
g_free(iscsilun->zeroblock);
|
||||||
|
g_free(iscsilun->allocationmap);
|
||||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1389,6 +1492,13 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iscsilun->allocationmap != NULL) {
|
||||||
|
g_free(iscsilun->allocationmap);
|
||||||
|
iscsilun->allocationmap =
|
||||||
|
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||||
|
iscsilun->cluster_sectors));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1401,7 +1511,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
IscsiLun *iscsilun = NULL;
|
IscsiLun *iscsilun = NULL;
|
||||||
QDict *bs_options;
|
QDict *bs_options;
|
||||||
|
|
||||||
bs = bdrv_new("");
|
bs = bdrv_new("", &error_abort);
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
while (options && options->name) {
|
while (options && options->name) {
|
||||||
@@ -1451,13 +1561,7 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
||||||
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
||||||
/* Guess the internal cluster (page) size of the iscsi target by the means
|
bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
|
||||||
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
|
||||||
* reasonable size for bdi->cluster_size */
|
|
||||||
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 &&
|
|
||||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
|
||||||
bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -325,11 +325,11 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
|
|
||||||
s->common.len = bdrv_getlength(bs);
|
s->common.len = bdrv_getlength(bs);
|
||||||
if (s->common.len <= 0) {
|
if (s->common.len <= 0) {
|
||||||
block_job_completed(&s->common, s->common.len);
|
ret = s->common.len;
|
||||||
return;
|
goto immediate_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity;
|
length = DIV_ROUND_UP(s->common.len, s->granularity);
|
||||||
s->in_flight_bitmap = bitmap_new(length);
|
s->in_flight_bitmap = bitmap_new(length);
|
||||||
|
|
||||||
/* If we have no backing file yet in the destination, we cannot let
|
/* If we have no backing file yet in the destination, we cannot let
|
||||||
@@ -339,7 +339,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
bdrv_get_backing_filename(s->target, backing_filename,
|
bdrv_get_backing_filename(s->target, backing_filename,
|
||||||
sizeof(backing_filename));
|
sizeof(backing_filename));
|
||||||
if (backing_filename[0] && !s->target->backing_hd) {
|
if (backing_filename[0] && !s->target->backing_hd) {
|
||||||
bdrv_get_info(s->target, &bdi);
|
ret = bdrv_get_info(s->target, &bdi);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto immediate_exit;
|
||||||
|
}
|
||||||
if (s->granularity < bdi.cluster_size) {
|
if (s->granularity < bdi.cluster_size) {
|
||||||
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
|
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
|
||||||
s->cow_bitmap = bitmap_new(length);
|
s->cow_bitmap = bitmap_new(length);
|
||||||
@@ -605,7 +608,10 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
|||||||
s->granularity = granularity;
|
s->granularity = granularity;
|
||||||
s->buf_size = MAX(buf_size, granularity);
|
s->buf_size = MAX(buf_size, granularity);
|
||||||
|
|
||||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity);
|
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp);
|
||||||
|
if (!s->dirty_bitmap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
bdrv_set_enable_write_cache(s->target, true);
|
bdrv_set_enable_write_cache(s->target, true);
|
||||||
bdrv_set_on_error(s->target, on_target_error, on_target_error);
|
bdrv_set_on_error(s->target, on_target_error, on_target_error);
|
||||||
bdrv_iostatus_enable(s->target);
|
bdrv_iostatus_enable(s->target);
|
||||||
@@ -677,7 +683,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base,
|
|||||||
mirror_start_job(bs, base, speed, 0, 0,
|
mirror_start_job(bs, base, speed, 0, 0,
|
||||||
on_error, on_error, cb, opaque, &local_err,
|
on_error, on_error, cb, opaque, &local_err,
|
||||||
&commit_active_job_driver, false, base);
|
&commit_active_job_driver, false, base);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto error_restore_flags;
|
goto error_restore_flags;
|
||||||
}
|
}
|
||||||
|
@@ -175,7 +175,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
|
|||||||
InetSocketAddress *addr = NULL;
|
InetSocketAddress *addr = NULL;
|
||||||
|
|
||||||
addr = inet_parse(host_spec, errp);
|
addr = inet_parse(host_spec, errp);
|
||||||
if (error_is_set(errp)) {
|
if (!addr) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -256,6 +256,10 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
|||||||
error_setg(errp, "Invalid URL specified");
|
error_setg(errp, "Invalid URL specified");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if (!uri->server) {
|
||||||
|
error_setg(errp, "Invalid URL specified");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
strp = strrchr(uri->path, '/');
|
strp = strrchr(uri->path, '/');
|
||||||
if (strp == NULL) {
|
if (strp == NULL) {
|
||||||
error_setg(errp, "Invalid URL specified");
|
error_setg(errp, "Invalid URL specified");
|
||||||
@@ -343,7 +347,7 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@@ -532,12 +532,11 @@ 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)
|
||||||
{
|
{
|
||||||
Error *local_err = NULL;
|
|
||||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||||
QObject *obj, *data;
|
QObject *obj, *data;
|
||||||
|
|
||||||
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
|
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
|
||||||
&local_err);
|
&error_abort);
|
||||||
obj = qmp_output_get_qobject(ov);
|
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");
|
||||||
|
@@ -119,7 +119,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
if (header.version != QCOW_VERSION) {
|
if (header.version != QCOW_VERSION) {
|
||||||
char version[64];
|
char version[64];
|
||||||
snprintf(version, sizeof(version), "QCOW version %d", header.version);
|
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
|
||||||
|
header.version);
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
bs->device_name, "qcow", version);
|
bs->device_name, "qcow", version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
@@ -42,6 +42,13 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
if (min_size <= s->l1_size)
|
if (min_size <= s->l1_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Do a sanity check on min_size before trying to calculate new_l1_size
|
||||||
|
* (this prevents overflows during the while loop for the calculation of
|
||||||
|
* new_l1_size) */
|
||||||
|
if (min_size > INT_MAX / sizeof(uint64_t)) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
if (exact_size) {
|
if (exact_size) {
|
||||||
new_l1_size = min_size;
|
new_l1_size = min_size;
|
||||||
} else {
|
} else {
|
||||||
@@ -1360,9 +1367,9 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
|||||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||||
|
|
||||||
for (i = 0; i < nb_clusters; i++) {
|
for (i = 0; i < nb_clusters; i++) {
|
||||||
uint64_t old_offset;
|
uint64_t old_l2_entry;
|
||||||
|
|
||||||
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that a discarded area reads back as zeroes for v3 images
|
* Make sure that a discarded area reads back as zeroes for v3 images
|
||||||
@@ -1373,12 +1380,22 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
|||||||
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
||||||
* holding s->lock, so that doesn't work today.
|
* holding s->lock, so that doesn't work today.
|
||||||
*/
|
*/
|
||||||
if (old_offset & QCOW_OFLAG_ZERO) {
|
switch (qcow2_get_cluster_type(old_l2_entry)) {
|
||||||
continue;
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
}
|
if (!bs->backing_hd) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if ((old_offset & L2E_OFFSET_MASK) == 0 && !bs->backing_hd) {
|
case QCOW2_CLUSTER_ZERO:
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First remove L2 entries */
|
/* First remove L2 entries */
|
||||||
@@ -1390,7 +1407,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Then decrease the refcount */
|
/* Then decrease the refcount */
|
||||||
qcow2_free_any_clusters(bs, old_offset, 1, type);
|
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
|
@@ -653,6 +653,15 @@ retry:
|
|||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure that all offsets in the "allocated" range are representable
|
||||||
|
* in an int64_t */
|
||||||
|
if (s->free_cluster_index > 0 &&
|
||||||
|
s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits))
|
||||||
|
{
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC2
|
#ifdef DEBUG_ALLOC2
|
||||||
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
||||||
size,
|
size,
|
||||||
@@ -1480,6 +1489,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size = bdrv_getlength(bs->file);
|
size = bdrv_getlength(bs->file);
|
||||||
|
if (size < 0) {
|
||||||
|
res->check_errors++;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
nb_clusters = size_to_clusters(s, size);
|
nb_clusters = size_to_clusters(s, size);
|
||||||
if (nb_clusters > INT_MAX) {
|
if (nb_clusters > INT_MAX) {
|
||||||
res->check_errors++;
|
res->check_errors++;
|
||||||
|
@@ -124,8 +124,9 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
|||||||
|
|
||||||
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
|
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
|
||||||
if (ext.len >= sizeof(bs->backing_format)) {
|
if (ext.len >= sizeof(bs->backing_format)) {
|
||||||
error_setg(errp, "ERROR: ext_backing_format: len=%u too large"
|
error_setg(errp, "ERROR: ext_backing_format: len=%" PRIu32
|
||||||
" (>=%zu)", ext.len, sizeof(bs->backing_format));
|
" too large (>=%zu)", ext.len,
|
||||||
|
sizeof(bs->backing_format));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
||||||
@@ -483,7 +484,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (header.version < 2 || header.version > 3) {
|
if (header.version < 2 || header.version > 3) {
|
||||||
report_unsupported(bs, errp, "QCOW version %d", header.version);
|
report_unsupported(bs, errp, "QCOW version %" PRIu32, header.version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -493,7 +494,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
/* Initialise cluster size */
|
/* Initialise cluster size */
|
||||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||||
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
error_setg(errp, "Unsupported cluster size: 2^%" PRIu32,
|
||||||
|
header.cluster_bits);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -591,7 +593,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->refcount_order = header.refcount_order;
|
s->refcount_order = header.refcount_order;
|
||||||
|
|
||||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||||
error_setg(errp, "Unsupported encryption method: %i",
|
error_setg(errp, "Unsupported encryption method: %" PRIu32,
|
||||||
header.crypt_method);
|
header.crypt_method);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
16
block/qed.c
16
block/qed.c
@@ -650,19 +650,21 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!qed_is_cluster_size_valid(cluster_size)) {
|
if (!qed_is_cluster_size_valid(cluster_size)) {
|
||||||
fprintf(stderr, "QED cluster size must be within range [%u, %u] and power of 2\n",
|
error_setg(errp, "QED cluster size must be within range [%u, %u] "
|
||||||
QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
|
"and power of 2",
|
||||||
|
QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (!qed_is_table_size_valid(table_size)) {
|
if (!qed_is_table_size_valid(table_size)) {
|
||||||
fprintf(stderr, "QED table size must be within range [%u, %u] and power of 2\n",
|
error_setg(errp, "QED table size must be within range [%u, %u] "
|
||||||
QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
|
"and power of 2",
|
||||||
|
QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
|
if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
|
||||||
fprintf(stderr, "QED image size must be a non-zero multiple of "
|
error_setg(errp, "QED image size must be a non-zero multiple of "
|
||||||
"cluster size and less than %" PRIu64 " bytes\n",
|
"cluster size and less than %" PRIu64 " bytes",
|
||||||
qed_max_image_size(cluster_size, table_size));
|
qed_max_image_size(cluster_size, table_size));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -753,7 +753,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&quorum_runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&quorum_runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -828,7 +828,7 @@ close_exit:
|
|||||||
g_free(opened);
|
g_free(opened);
|
||||||
exit:
|
exit:
|
||||||
/* propagate error */
|
/* propagate error */
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
QDECREF(list);
|
QDECREF(list);
|
||||||
|
@@ -146,6 +146,9 @@ typedef struct BDRVRawState {
|
|||||||
bool has_discard:1;
|
bool has_discard:1;
|
||||||
bool has_write_zeroes:1;
|
bool has_write_zeroes:1;
|
||||||
bool discard_zeroes:1;
|
bool discard_zeroes:1;
|
||||||
|
#ifdef CONFIG_FIEMAP
|
||||||
|
bool skip_fiemap;
|
||||||
|
#endif
|
||||||
} BDRVRawState;
|
} BDRVRawState;
|
||||||
|
|
||||||
typedef struct BDRVRawReopenState {
|
typedef struct BDRVRawReopenState {
|
||||||
@@ -366,7 +369,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename;
|
const char *filename = NULL;
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
@@ -446,6 +449,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
|
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
|
||||||
|
unlink(filename);
|
||||||
|
}
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1269,6 +1275,83 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data,
|
||||||
|
off_t *hole, int nb_sectors, int *pnum)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_FIEMAP
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||||
|
struct {
|
||||||
|
struct fiemap fm;
|
||||||
|
struct fiemap_extent fe;
|
||||||
|
} f;
|
||||||
|
|
||||||
|
if (s->skip_fiemap) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.fm.fm_start = start;
|
||||||
|
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
f.fm.fm_flags = 0;
|
||||||
|
f.fm.fm_extent_count = 1;
|
||||||
|
f.fm.fm_reserved = 0;
|
||||||
|
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
|
||||||
|
s->skip_fiemap = true;
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.fm.fm_mapped_extents == 0) {
|
||||||
|
/* No extents found, data is beyond f.fm.fm_start + f.fm.fm_length.
|
||||||
|
* f.fm.fm_start + f.fm.fm_length must be clamped to the file size!
|
||||||
|
*/
|
||||||
|
off_t length = lseek(s->fd, 0, SEEK_END);
|
||||||
|
*hole = f.fm.fm_start;
|
||||||
|
*data = MIN(f.fm.fm_start + f.fm.fm_length, length);
|
||||||
|
} else {
|
||||||
|
*data = f.fe.fe_logical;
|
||||||
|
*hole = f.fe.fe_logical + f.fe.fe_length;
|
||||||
|
if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) {
|
||||||
|
ret |= BDRV_BLOCK_ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return -ENOTSUP;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t try_seek_hole(BlockDriverState *bs, off_t start, off_t *data,
|
||||||
|
off_t *hole, int *pnum)
|
||||||
|
{
|
||||||
|
#if defined SEEK_HOLE && defined SEEK_DATA
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
|
||||||
|
*hole = lseek(s->fd, start, SEEK_HOLE);
|
||||||
|
if (*hole == -1) {
|
||||||
|
/* -ENXIO indicates that sector_num was past the end of the file.
|
||||||
|
* There is a virtual hole there. */
|
||||||
|
assert(errno != -ENXIO);
|
||||||
|
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*hole > start) {
|
||||||
|
*data = start;
|
||||||
|
} else {
|
||||||
|
/* On a hole. We need another syscall to find its end. */
|
||||||
|
*data = lseek(s->fd, start, SEEK_DATA);
|
||||||
|
if (*data == -1) {
|
||||||
|
*data = lseek(s->fd, 0, SEEK_END);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||||
|
#else
|
||||||
|
return -ENOTSUP;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true iff the specified sector is present in the disk image. Drivers
|
* Returns true iff the specified sector is present in the disk image. Drivers
|
||||||
* not implementing the functionality are assumed to not support backing files,
|
* not implementing the functionality are assumed to not support backing files,
|
||||||
@@ -1285,10 +1368,10 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
* beyond the end of the disk image it will be clamped.
|
* beyond the end of the disk image it will be clamped.
|
||||||
*/
|
*/
|
||||||
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||||
int64_t sector_num,
|
int64_t sector_num,
|
||||||
int nb_sectors, int *pnum)
|
int nb_sectors, int *pnum)
|
||||||
{
|
{
|
||||||
off_t start, data, hole;
|
off_t start, data = 0, hole = 0;
|
||||||
int64_t ret;
|
int64_t ret;
|
||||||
|
|
||||||
ret = fd_open(bs);
|
ret = fd_open(bs);
|
||||||
@@ -1297,71 +1380,18 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
start = sector_num * BDRV_SECTOR_SIZE;
|
start = sector_num * BDRV_SECTOR_SIZE;
|
||||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
|
||||||
|
|
||||||
#ifdef CONFIG_FIEMAP
|
ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum);
|
||||||
|
if (ret < 0) {
|
||||||
BDRVRawState *s = bs->opaque;
|
ret = try_seek_hole(bs, start, &data, &hole, pnum);
|
||||||
struct {
|
if (ret < 0) {
|
||||||
struct fiemap fm;
|
/* Assume everything is allocated. */
|
||||||
struct fiemap_extent fe;
|
data = 0;
|
||||||
} f;
|
hole = start + nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||||
f.fm.fm_start = start;
|
|
||||||
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
|
|
||||||
f.fm.fm_flags = 0;
|
|
||||||
f.fm.fm_extent_count = 1;
|
|
||||||
f.fm.fm_reserved = 0;
|
|
||||||
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
|
|
||||||
/* Assume everything is allocated. */
|
|
||||||
*pnum = nb_sectors;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f.fm.fm_mapped_extents == 0) {
|
|
||||||
/* No extents found, data is beyond f.fm.fm_start + f.fm.fm_length.
|
|
||||||
* f.fm.fm_start + f.fm.fm_length must be clamped to the file size!
|
|
||||||
*/
|
|
||||||
off_t length = lseek(s->fd, 0, SEEK_END);
|
|
||||||
hole = f.fm.fm_start;
|
|
||||||
data = MIN(f.fm.fm_start + f.fm.fm_length, length);
|
|
||||||
} else {
|
|
||||||
data = f.fe.fe_logical;
|
|
||||||
hole = f.fe.fe_logical + f.fe.fe_length;
|
|
||||||
if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) {
|
|
||||||
ret |= BDRV_BLOCK_ZERO;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined SEEK_HOLE && defined SEEK_DATA
|
|
||||||
|
|
||||||
BDRVRawState *s = bs->opaque;
|
|
||||||
|
|
||||||
hole = lseek(s->fd, start, SEEK_HOLE);
|
|
||||||
if (hole == -1) {
|
|
||||||
/* -ENXIO indicates that sector_num was past the end of the file.
|
|
||||||
* There is a virtual hole there. */
|
|
||||||
assert(errno != -ENXIO);
|
|
||||||
|
|
||||||
/* Most likely EINVAL. Assume everything is allocated. */
|
|
||||||
*pnum = nb_sectors;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hole > start) {
|
|
||||||
data = start;
|
|
||||||
} else {
|
|
||||||
/* On a hole. We need another syscall to find its end. */
|
|
||||||
data = lseek(s->fd, start, SEEK_DATA);
|
|
||||||
if (data == -1) {
|
|
||||||
data = lseek(s->fd, 0, SEEK_END);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
data = 0;
|
|
||||||
hole = start + nb_sectors * BDRV_SECTOR_SIZE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (data <= start) {
|
if (data <= start) {
|
||||||
/* On a data extent, compute sectors to the end of the extent. */
|
/* On a data extent, compute sectors to the end of the extent. */
|
||||||
*pnum = MIN(nb_sectors, (hole - start) / BDRV_SECTOR_SIZE);
|
*pnum = MIN(nb_sectors, (hole - start) / BDRV_SECTOR_SIZE);
|
||||||
|
@@ -390,6 +390,9 @@ static void raw_close(BlockDriverState *bs)
|
|||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
CloseHandle(s->hfile);
|
CloseHandle(s->hfile);
|
||||||
|
if (bs->open_flags & BDRV_O_TEMPORARY) {
|
||||||
|
unlink(bs->filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
|
@@ -1099,7 +1099,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rsp->result != SD_RES_SUCCESS) {
|
if (rsp->result != SD_RES_SUCCESS) {
|
||||||
error_report("cannot get vdi info, %s, %s %d %s",
|
error_report("cannot get vdi info, %s, %s %" PRIu32 " %s",
|
||||||
sd_strerror(rsp->result), filename, snapid, tag);
|
sd_strerror(rsp->result), filename, snapid, tag);
|
||||||
if (rsp->result == SD_RES_NO_VDI) {
|
if (rsp->result == SD_RES_NO_VDI) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
@@ -2316,8 +2316,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
|||||||
sn_tab[found].vm_state_size = inode.vm_state_size;
|
sn_tab[found].vm_state_size = inode.vm_state_size;
|
||||||
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
|
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
|
||||||
|
|
||||||
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
|
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str),
|
||||||
inode.snap_id);
|
"%" PRIu32, inode.snap_id);
|
||||||
pstrcpy(sn_tab[found].name,
|
pstrcpy(sn_tab[found].name,
|
||||||
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
|
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
|
||||||
inode.tag);
|
inode.tag);
|
||||||
|
28
block/vdi.c
28
block/vdi.c
@@ -408,34 +408,35 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (header.signature != VDI_SIGNATURE) {
|
if (header.signature != VDI_SIGNATURE) {
|
||||||
error_setg(errp, "Image not in VDI format (bad signature %08x)", header.signature);
|
error_setg(errp, "Image not in VDI format (bad signature %08" PRIx32
|
||||||
|
")", header.signature);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.version != VDI_VERSION_1_1) {
|
} else if (header.version != VDI_VERSION_1_1) {
|
||||||
error_setg(errp, "unsupported VDI image (version %u.%u)",
|
error_setg(errp, "unsupported VDI image (version %" PRIu32 ".%" PRIu32
|
||||||
header.version >> 16, header.version & 0xffff);
|
")", header.version >> 16, header.version & 0xffff);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
||||||
/* We only support block maps which start on a sector boundary. */
|
/* We only support block maps which start on a sector boundary. */
|
||||||
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
||||||
"0x%x)", header.offset_bmap);
|
"0x%" PRIx32 ")", header.offset_bmap);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
||||||
/* We only support data blocks which start on a sector boundary. */
|
/* We only support data blocks which start on a sector boundary. */
|
||||||
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%x)",
|
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%"
|
||||||
header.offset_data);
|
PRIx32 ")", header.offset_data);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.sector_size != SECTOR_SIZE) {
|
} else if (header.sector_size != SECTOR_SIZE) {
|
||||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
error_setg(errp, "unsupported VDI image (sector size %" PRIu32
|
||||||
header.sector_size, SECTOR_SIZE);
|
" is not %u)", header.sector_size, SECTOR_SIZE);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
||||||
error_setg(errp, "unsupported VDI image (block size %u is not %u)",
|
error_setg(errp, "unsupported VDI image (block size %" PRIu32
|
||||||
header.block_size, DEFAULT_CLUSTER_SIZE);
|
" is not %u)", header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.disk_size >
|
} else if (header.disk_size >
|
||||||
@@ -755,6 +756,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
vdi_header_to_le(&header);
|
vdi_header_to_le(&header);
|
||||||
if (write(fd, &header, sizeof(header)) < 0) {
|
if (write(fd, &header, sizeof(header)) < 0) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bmap_size > 0) {
|
if (bmap_size > 0) {
|
||||||
@@ -768,6 +770,8 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
}
|
}
|
||||||
if (write(fd, bmap, bmap_size) < 0) {
|
if (write(fd, bmap, bmap_size) < 0) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
g_free(bmap);
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
g_free(bmap);
|
g_free(bmap);
|
||||||
}
|
}
|
||||||
@@ -775,10 +779,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
if (image_type == VDI_TYPE_STATIC) {
|
if (image_type == VDI_TYPE_STATIC) {
|
||||||
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (close(fd) < 0) {
|
close_and_exit:
|
||||||
|
if ((close(fd) < 0) && !result) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
block/vmdk.c
58
block/vmdk.c
@@ -262,7 +262,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
|
|||||||
p_name = strstr(desc, cid_str);
|
p_name = strstr(desc, cid_str);
|
||||||
if (p_name != NULL) {
|
if (p_name != NULL) {
|
||||||
p_name += cid_str_size;
|
p_name += cid_str_size;
|
||||||
sscanf(p_name, "%x", &cid);
|
sscanf(p_name, "%" SCNx32, &cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cid;
|
return cid;
|
||||||
@@ -290,7 +290,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
|||||||
p_name = strstr(desc, "CID");
|
p_name = strstr(desc, "CID");
|
||||||
if (p_name != NULL) {
|
if (p_name != NULL) {
|
||||||
p_name += sizeof("CID");
|
p_name += sizeof("CID");
|
||||||
snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
|
snprintf(p_name, sizeof(desc) - (p_name - desc), "%" PRIx32 "\n", cid);
|
||||||
pstrcat(desc, sizeof(desc), tmp_desc);
|
pstrcat(desc, sizeof(desc), tmp_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,7 +640,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
|
|
||||||
if (le32_to_cpu(header.version) > 3) {
|
if (le32_to_cpu(header.version) > 3) {
|
||||||
char buf[64];
|
char buf[64];
|
||||||
snprintf(buf, sizeof(buf), "VMDK version %d",
|
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
|
||||||
le32_to_cpu(header.version));
|
le32_to_cpu(header.version));
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
bs->device_name, "vmdk", buf);
|
bs->device_name, "vmdk", buf);
|
||||||
@@ -671,8 +671,9 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
if (bdrv_getlength(file) <
|
if (bdrv_getlength(file) <
|
||||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) {
|
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) {
|
||||||
error_setg(errp, "File truncated, expecting at least %lld bytes",
|
error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes",
|
||||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE);
|
(int64_t)(le64_to_cpu(header.grain_offset)
|
||||||
|
* BDRV_SECTOR_SIZE));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1495,6 +1496,19 @@ static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vmdk_write_compressed(BlockDriverState *bs,
|
||||||
|
int64_t sector_num,
|
||||||
|
const uint8_t *buf,
|
||||||
|
int nb_sectors)
|
||||||
|
{
|
||||||
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
if (s->num_extents == 1 && s->extents[0].compressed) {
|
||||||
|
return vmdk_write(bs, sector_num, buf, nb_sectors, false, false);
|
||||||
|
} else {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
|
static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
|
||||||
int64_t sector_num,
|
int64_t sector_num,
|
||||||
int nb_sectors,
|
int nb_sectors,
|
||||||
@@ -1707,8 +1721,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
const char desc_template[] =
|
const char desc_template[] =
|
||||||
"# Disk DescriptorFile\n"
|
"# Disk DescriptorFile\n"
|
||||||
"version=1\n"
|
"version=1\n"
|
||||||
"CID=%x\n"
|
"CID=%" PRIx32 "\n"
|
||||||
"parentCID=%x\n"
|
"parentCID=%" PRIx32 "\n"
|
||||||
"createType=\"%s\"\n"
|
"createType=\"%s\"\n"
|
||||||
"%s"
|
"%s"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1720,7 +1734,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
"\n"
|
"\n"
|
||||||
"ddb.virtualHWVersion = \"%d\"\n"
|
"ddb.virtualHWVersion = \"%d\"\n"
|
||||||
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
|
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
|
||||||
"ddb.geometry.heads = \"%d\"\n"
|
"ddb.geometry.heads = \"%" PRIu32 "\"\n"
|
||||||
"ddb.geometry.sectors = \"63\"\n"
|
"ddb.geometry.sectors = \"63\"\n"
|
||||||
"ddb.adapterType = \"%s\"\n";
|
"ddb.adapterType = \"%s\"\n";
|
||||||
|
|
||||||
@@ -1780,9 +1794,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
strcmp(fmt, "twoGbMaxExtentFlat"));
|
strcmp(fmt, "twoGbMaxExtentFlat"));
|
||||||
compress = !strcmp(fmt, "streamOptimized");
|
compress = !strcmp(fmt, "streamOptimized");
|
||||||
if (flat) {
|
if (flat) {
|
||||||
desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
|
desc_extent_line = "RW %" PRId64 " FLAT \"%s\" 0\n";
|
||||||
} else {
|
} else {
|
||||||
desc_extent_line = "RW %lld SPARSE \"%s\"\n";
|
desc_extent_line = "RW %" PRId64 " SPARSE \"%s\"\n";
|
||||||
}
|
}
|
||||||
if (flat && backing_file) {
|
if (flat && backing_file) {
|
||||||
error_setg(errp, "Flat image can't have backing file");
|
error_setg(errp, "Flat image can't have backing file");
|
||||||
@@ -1850,7 +1864,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
}
|
}
|
||||||
/* generate descriptor file */
|
/* generate descriptor file */
|
||||||
desc = g_strdup_printf(desc_template,
|
desc = g_strdup_printf(desc_template,
|
||||||
(unsigned int)time(NULL),
|
(uint32_t)time(NULL),
|
||||||
parent_cid,
|
parent_cid,
|
||||||
fmt,
|
fmt,
|
||||||
parent_desc_line,
|
parent_desc_line,
|
||||||
@@ -2062,6 +2076,26 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
|
|||||||
return spec_info;
|
return spec_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
assert(s->num_extents);
|
||||||
|
bdi->needs_compressed_writes = s->extents[0].compressed;
|
||||||
|
if (!s->extents[0].flat) {
|
||||||
|
bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS;
|
||||||
|
}
|
||||||
|
/* See if we have multiple extents but they have different cases */
|
||||||
|
for (i = 1; i < s->num_extents; i++) {
|
||||||
|
if (bdi->needs_compressed_writes != s->extents[i].compressed ||
|
||||||
|
(bdi->cluster_size && bdi->cluster_size !=
|
||||||
|
s->extents[i].cluster_sectors << BDRV_SECTOR_BITS)) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static QEMUOptionParameter vmdk_create_options[] = {
|
static QEMUOptionParameter vmdk_create_options[] = {
|
||||||
{
|
{
|
||||||
.name = BLOCK_OPT_SIZE,
|
.name = BLOCK_OPT_SIZE,
|
||||||
@@ -2108,6 +2142,7 @@ static BlockDriver bdrv_vmdk = {
|
|||||||
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
||||||
.bdrv_read = vmdk_co_read,
|
.bdrv_read = vmdk_co_read,
|
||||||
.bdrv_write = vmdk_co_write,
|
.bdrv_write = vmdk_co_write,
|
||||||
|
.bdrv_write_compressed = vmdk_write_compressed,
|
||||||
.bdrv_co_write_zeroes = vmdk_co_write_zeroes,
|
.bdrv_co_write_zeroes = vmdk_co_write_zeroes,
|
||||||
.bdrv_close = vmdk_close,
|
.bdrv_close = vmdk_close,
|
||||||
.bdrv_create = vmdk_create,
|
.bdrv_create = vmdk_create,
|
||||||
@@ -2117,6 +2152,7 @@ static BlockDriver bdrv_vmdk = {
|
|||||||
.bdrv_has_zero_init = vmdk_has_zero_init,
|
.bdrv_has_zero_init = vmdk_has_zero_init,
|
||||||
.bdrv_get_specific_info = vmdk_get_specific_info,
|
.bdrv_get_specific_info = vmdk_get_specific_info,
|
||||||
.bdrv_refresh_limits = vmdk_refresh_limits,
|
.bdrv_refresh_limits = vmdk_refresh_limits,
|
||||||
|
.bdrv_get_info = vmdk_get_info,
|
||||||
|
|
||||||
.create_options = vmdk_create_options,
|
.create_options = vmdk_create_options,
|
||||||
};
|
};
|
||||||
|
@@ -2947,7 +2947,7 @@ static int enable_write_target(BDRVVVFATState *s)
|
|||||||
unlink(s->qcow_filename);
|
unlink(s->qcow_filename);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s->bs->backing_hd = bdrv_new("");
|
s->bs->backing_hd = bdrv_new("", &error_abort);
|
||||||
s->bs->backing_hd->drv = &vvfat_write_target;
|
s->bs->backing_hd->drv = &vvfat_write_target;
|
||||||
s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
|
s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
|
||||||
*(void**)s->bs->backing_hd->opaque = s;
|
*(void**)s->bs->backing_hd->opaque = s;
|
||||||
|
31
blockdev.c
31
blockdev.c
@@ -452,16 +452,14 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_find_node(qemu_opts_id(opts))) {
|
|
||||||
error_setg(errp, "device id=%s is conflicting with a node-name",
|
|
||||||
qemu_opts_id(opts));
|
|
||||||
goto early_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
dinfo = g_malloc0(sizeof(*dinfo));
|
dinfo = g_malloc0(sizeof(*dinfo));
|
||||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||||
dinfo->bdrv = bdrv_new(dinfo->id);
|
dinfo->bdrv = bdrv_new(dinfo->id, &error);
|
||||||
|
if (error) {
|
||||||
|
error_propagate(errp, error);
|
||||||
|
goto bdrv_new_err;
|
||||||
|
}
|
||||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||||
dinfo->bdrv->read_only = ro;
|
dinfo->bdrv->read_only = ro;
|
||||||
dinfo->refcount = 1;
|
dinfo->refcount = 1;
|
||||||
@@ -523,8 +521,9 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
bdrv_unref(dinfo->bdrv);
|
bdrv_unref(dinfo->bdrv);
|
||||||
g_free(dinfo->id);
|
|
||||||
QTAILQ_REMOVE(&drives, dinfo, next);
|
QTAILQ_REMOVE(&drives, dinfo, next);
|
||||||
|
bdrv_new_err:
|
||||||
|
g_free(dinfo->id);
|
||||||
g_free(dinfo);
|
g_free(dinfo);
|
||||||
early_err:
|
early_err:
|
||||||
QDECREF(bs_opts);
|
QDECREF(bs_opts);
|
||||||
@@ -1116,6 +1115,7 @@ typedef struct InternalSnapshotState {
|
|||||||
static void internal_snapshot_prepare(BlkTransactionState *common,
|
static void internal_snapshot_prepare(BlkTransactionState *common,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
const char *device;
|
const char *device;
|
||||||
const char *name;
|
const char *name;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
@@ -1164,8 +1164,10 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check whether a snapshot with name exist */
|
/* check whether a snapshot with name exist */
|
||||||
ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &old_sn, errp);
|
ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &old_sn,
|
||||||
if (error_is_set(errp)) {
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
} else if (ret) {
|
} else if (ret) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
@@ -1521,14 +1523,16 @@ static void eject_device(BlockDriverState *bs, int force, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!bdrv_dev_has_removable_media(bs)) {
|
if (!bdrv_dev_has_removable_media(bs)) {
|
||||||
error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
|
error_setg(errp, "Device '%s' is not removable",
|
||||||
|
bdrv_get_device_name(bs));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
|
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
|
||||||
bdrv_dev_eject_request(bs, force);
|
bdrv_dev_eject_request(bs, force);
|
||||||
if (!force) {
|
if (!force) {
|
||||||
error_set(errp, QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
|
error_setg(errp, "Device '%s' is locked",
|
||||||
|
bdrv_get_device_name(bs));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2220,7 +2224,8 @@ void qmp_block_job_cancel(const char *device,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (job->paused && !force) {
|
if (job->paused && !force) {
|
||||||
error_set(errp, QERR_BLOCK_JOB_PAUSED, device);
|
error_setg(errp, "The block job for device '%s' is currently paused",
|
||||||
|
device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -88,7 +88,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
|||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
if (!job->driver->set_speed) {
|
if (!job->driver->set_speed) {
|
||||||
error_set(errp, QERR_NOT_SUPPORTED);
|
error_set(errp, QERR_UNSUPPORTED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
job->driver->set_speed(job, speed, &local_err);
|
job->driver->set_speed(job, speed, &local_err);
|
||||||
|
@@ -43,7 +43,7 @@ unsigned long reserved_va;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
|
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
|
||||||
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
|
const char *qemu_uname_release;
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
enum BSDType bsd_type;
|
enum BSDType bsd_type;
|
||||||
|
|
||||||
@@ -1003,8 +1003,6 @@ int main(int argc, char **argv)
|
|||||||
cpu->opaque = ts;
|
cpu->opaque = ts;
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
cpu_x86_set_cpl(env, 3);
|
|
||||||
|
|
||||||
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
||||||
env->hflags |= HF_PE_MASK;
|
env->hflags |= HF_PE_MASK;
|
||||||
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
|
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
|
||||||
|
60
configure
vendored
60
configure
vendored
@@ -285,7 +285,6 @@ softmmu="yes"
|
|||||||
linux_user="no"
|
linux_user="no"
|
||||||
bsd_user="no"
|
bsd_user="no"
|
||||||
guest_base="yes"
|
guest_base="yes"
|
||||||
uname_release=""
|
|
||||||
aix="no"
|
aix="no"
|
||||||
blobs="yes"
|
blobs="yes"
|
||||||
pkgversion=""
|
pkgversion=""
|
||||||
@@ -404,6 +403,14 @@ fi
|
|||||||
# make source path absolute
|
# make source path absolute
|
||||||
source_path=`cd "$source_path"; pwd`
|
source_path=`cd "$source_path"; pwd`
|
||||||
|
|
||||||
|
# running configure in the source tree?
|
||||||
|
# we know that's the case if configure is there.
|
||||||
|
if test -f "./configure"; then
|
||||||
|
pwd_is_source_path="y"
|
||||||
|
else
|
||||||
|
pwd_is_source_path="n"
|
||||||
|
fi
|
||||||
|
|
||||||
check_define() {
|
check_define() {
|
||||||
cat > $TMPC <<EOF
|
cat > $TMPC <<EOF
|
||||||
#if !defined($1)
|
#if !defined($1)
|
||||||
@@ -945,8 +952,6 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--disable-pie) pie="no"
|
--disable-pie) pie="no"
|
||||||
;;
|
;;
|
||||||
--enable-uname-release=*) uname_release="$optarg"
|
|
||||||
;;
|
|
||||||
--enable-werror) werror="yes"
|
--enable-werror) werror="yes"
|
||||||
;;
|
;;
|
||||||
--disable-werror) werror="no"
|
--disable-werror) werror="no"
|
||||||
@@ -1087,7 +1092,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-quorum) quorum="yes"
|
--enable-quorum) quorum="yes"
|
||||||
;;
|
;;
|
||||||
*) echo "ERROR: unknown option $opt"; show_help="yes"
|
*)
|
||||||
|
echo "ERROR: unknown option $opt"
|
||||||
|
echo "Try '$0 --help' for more information"
|
||||||
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -1129,11 +1137,11 @@ case "$cpu" in
|
|||||||
CPU_CFLAGS="-m64 -mcpu=ultrasparc"
|
CPU_CFLAGS="-m64 -mcpu=ultrasparc"
|
||||||
;;
|
;;
|
||||||
s390)
|
s390)
|
||||||
CPU_CFLAGS="-m31 -march=z990"
|
CPU_CFLAGS="-m31"
|
||||||
LDFLAGS="-m31 $LDFLAGS"
|
LDFLAGS="-m31 $LDFLAGS"
|
||||||
;;
|
;;
|
||||||
s390x)
|
s390x)
|
||||||
CPU_CFLAGS="-m64 -march=z990"
|
CPU_CFLAGS="-m64"
|
||||||
LDFLAGS="-m64 $LDFLAGS"
|
LDFLAGS="-m64 $LDFLAGS"
|
||||||
;;
|
;;
|
||||||
i386)
|
i386)
|
||||||
@@ -1217,8 +1225,8 @@ Advanced options (experts only):
|
|||||||
--enable-modules enable modules support
|
--enable-modules enable modules support
|
||||||
--enable-debug-tcg enable TCG debugging
|
--enable-debug-tcg enable TCG debugging
|
||||||
--disable-debug-tcg disable TCG debugging (default)
|
--disable-debug-tcg disable TCG debugging (default)
|
||||||
--enable-debug-info enable debugging information (default)
|
--enable-debug-info enable debugging information (default)
|
||||||
--disable-debug-info disable debugging information
|
--disable-debug-info disable debugging information
|
||||||
--enable-debug enable common debug build options
|
--enable-debug enable common debug build options
|
||||||
--enable-sparse enable sparse checker
|
--enable-sparse enable sparse checker
|
||||||
--disable-sparse disable sparse checker (default)
|
--disable-sparse disable sparse checker (default)
|
||||||
@@ -1230,6 +1238,7 @@ Advanced options (experts only):
|
|||||||
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
||||||
--disable-gtk disable gtk UI
|
--disable-gtk disable gtk UI
|
||||||
--enable-gtk enable gtk UI
|
--enable-gtk enable gtk UI
|
||||||
|
--with-gtkabi select preferred GTK ABI 2.0 or 3.0
|
||||||
--disable-virtfs disable VirtFS
|
--disable-virtfs disable VirtFS
|
||||||
--enable-virtfs enable VirtFS
|
--enable-virtfs enable VirtFS
|
||||||
--disable-vnc disable VNC
|
--disable-vnc disable VNC
|
||||||
@@ -1291,7 +1300,6 @@ Advanced options (experts only):
|
|||||||
--fmod-lib path to FMOD library
|
--fmod-lib path to FMOD library
|
||||||
--fmod-inc path to FMOD includes
|
--fmod-inc path to FMOD includes
|
||||||
--oss-lib path to OSS library
|
--oss-lib path to OSS library
|
||||||
--enable-uname-release=R Return R for uname -r in usermode emulation
|
|
||||||
--cpu=CPU Build for host CPU [$cpu]
|
--cpu=CPU Build for host CPU [$cpu]
|
||||||
--disable-uuid disable uuid support
|
--disable-uuid disable uuid support
|
||||||
--enable-uuid enable uuid support
|
--enable-uuid enable uuid support
|
||||||
@@ -1353,7 +1361,7 @@ Advanced options (experts only):
|
|||||||
|
|
||||||
NOTE: The object files are built at the place where configure is launched
|
NOTE: The object files are built at the place where configure is launched
|
||||||
EOF
|
EOF
|
||||||
exit 1
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Now we have handled --enable-tcg-interpreter and know we're not just
|
# Now we have handled --enable-tcg-interpreter and know we're not just
|
||||||
@@ -2624,7 +2632,7 @@ done
|
|||||||
if test "$modules" = yes; then
|
if test "$modules" = yes; then
|
||||||
shacmd_probe="sha1sum sha1 shasum"
|
shacmd_probe="sha1sum sha1 shasum"
|
||||||
for c in $shacmd_probe; do
|
for c in $shacmd_probe; do
|
||||||
if which $c &>/dev/null; then
|
if which $c >/dev/null 2>&1; then
|
||||||
shacmd="$c"
|
shacmd="$c"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -2940,7 +2948,7 @@ EOF
|
|||||||
fdt=yes
|
fdt=yes
|
||||||
dtc_internal="yes"
|
dtc_internal="yes"
|
||||||
mkdir -p dtc
|
mkdir -p dtc
|
||||||
if [ "$source_path" != `pwd` ] ; then
|
if [ "$pwd_is_source_path" != "y" ] ; then
|
||||||
symlink "$source_path/dtc/Makefile" "dtc/Makefile"
|
symlink "$source_path/dtc/Makefile" "dtc/Makefile"
|
||||||
symlink "$source_path/dtc/scripts" "dtc/scripts"
|
symlink "$source_path/dtc/scripts" "dtc/scripts"
|
||||||
fi
|
fi
|
||||||
@@ -3462,10 +3470,10 @@ if test "$smartcard_nss" != "no"; then
|
|||||||
#include <pk11pub.h>
|
#include <pk11pub.h>
|
||||||
int main(void) { PK11_FreeSlot(0); return 0; }
|
int main(void) { PK11_FreeSlot(0); return 0; }
|
||||||
EOF
|
EOF
|
||||||
smartcard_includes="-I\$(SRC_PATH)/libcacard"
|
# FIXME: do not include $glib_* in here
|
||||||
libcacard_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs"
|
nss_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs"
|
||||||
libcacard_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags"
|
nss_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags"
|
||||||
test_cflags="$libcacard_cflags"
|
test_cflags="$nss_cflags"
|
||||||
# The header files in nss < 3.13.3 have a bug which causes them to
|
# The header files in nss < 3.13.3 have a bug which causes them to
|
||||||
# emit a warning. If we're going to compile QEMU with -Werror, then
|
# emit a warning. If we're going to compile QEMU with -Werror, then
|
||||||
# test that the headers don't have this bug. Otherwise we would pass
|
# test that the headers don't have this bug. Otherwise we would pass
|
||||||
@@ -3475,11 +3483,8 @@ EOF
|
|||||||
fi
|
fi
|
||||||
if test -n "$libtool" &&
|
if test -n "$libtool" &&
|
||||||
$pkg_config --atleast-version=3.12.8 nss && \
|
$pkg_config --atleast-version=3.12.8 nss && \
|
||||||
compile_prog "$test_cflags" "$libcacard_libs"; then
|
compile_prog "$test_cflags" "$nss_libs"; then
|
||||||
smartcard_nss="yes"
|
smartcard_nss="yes"
|
||||||
QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags"
|
|
||||||
QEMU_INCLUDES="$QEMU_INCLUDES $smartcard_includes"
|
|
||||||
libs_softmmu="$libcacard_libs $libs_softmmu"
|
|
||||||
else
|
else
|
||||||
if test "$smartcard_nss" = "yes"; then
|
if test "$smartcard_nss" = "yes"; then
|
||||||
feature_not_found "nss"
|
feature_not_found "nss"
|
||||||
@@ -4095,7 +4100,6 @@ echo "sparse enabled $sparse"
|
|||||||
echo "strip binaries $strip_opt"
|
echo "strip binaries $strip_opt"
|
||||||
echo "profiler $profiler"
|
echo "profiler $profiler"
|
||||||
echo "static build $static"
|
echo "static build $static"
|
||||||
echo "-Werror enabled $werror"
|
|
||||||
if test "$darwin" = "yes" ; then
|
if test "$darwin" = "yes" ; then
|
||||||
echo "Cocoa support $cocoa"
|
echo "Cocoa support $cocoa"
|
||||||
fi
|
fi
|
||||||
@@ -4125,8 +4129,6 @@ echo "xen support $xen"
|
|||||||
echo "brlapi support $brlapi"
|
echo "brlapi support $brlapi"
|
||||||
echo "bluez support $bluez"
|
echo "bluez support $bluez"
|
||||||
echo "Documentation $docs"
|
echo "Documentation $docs"
|
||||||
[ ! -z "$uname_release" ] && \
|
|
||||||
echo "uname -r $uname_release"
|
|
||||||
echo "GUEST_BASE $guest_base"
|
echo "GUEST_BASE $guest_base"
|
||||||
echo "PIE $pie"
|
echo "PIE $pie"
|
||||||
echo "vde support $vde"
|
echo "vde support $vde"
|
||||||
@@ -4148,7 +4150,9 @@ echo "libcap-ng support $cap_ng"
|
|||||||
echo "vhost-net support $vhost_net"
|
echo "vhost-net support $vhost_net"
|
||||||
echo "vhost-scsi support $vhost_scsi"
|
echo "vhost-scsi support $vhost_scsi"
|
||||||
echo "Trace backend $trace_backend"
|
echo "Trace backend $trace_backend"
|
||||||
|
if test "$trace_backend" = "simple"; then
|
||||||
echo "Trace output file $trace_file-<pid>"
|
echo "Trace output file $trace_file-<pid>"
|
||||||
|
fi
|
||||||
if test "$spice" = "yes"; then
|
if test "$spice" = "yes"; then
|
||||||
echo "spice support $spice ($spice_protocol_version/$spice_server_version)"
|
echo "spice support $spice ($spice_protocol_version/$spice_server_version)"
|
||||||
else
|
else
|
||||||
@@ -4347,6 +4351,7 @@ if test "$modules" = "yes"; then
|
|||||||
fi
|
fi
|
||||||
if test "$sdl" = "yes" ; then
|
if test "$sdl" = "yes" ; then
|
||||||
echo "CONFIG_SDL=y" >> $config_host_mak
|
echo "CONFIG_SDL=y" >> $config_host_mak
|
||||||
|
echo "CONFIG_SDLABI=$sdlabi" >> $config_host_mak
|
||||||
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
|
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$cocoa" = "yes" ; then
|
if test "$cocoa" = "yes" ; then
|
||||||
@@ -4430,6 +4435,7 @@ fi
|
|||||||
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
||||||
if test "$gtk" = "yes" ; then
|
if test "$gtk" = "yes" ; then
|
||||||
echo "CONFIG_GTK=y" >> $config_host_mak
|
echo "CONFIG_GTK=y" >> $config_host_mak
|
||||||
|
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
|
||||||
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$vte" = "yes" ; then
|
if test "$vte" = "yes" ; then
|
||||||
@@ -4492,8 +4498,8 @@ fi
|
|||||||
|
|
||||||
if test "$smartcard_nss" = "yes" ; then
|
if test "$smartcard_nss" = "yes" ; then
|
||||||
echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
|
echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
|
||||||
echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
|
echo "NSS_LIBS=$nss_libs" >> $config_host_mak
|
||||||
echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak
|
echo "NSS_CFLAGS=$nss_cflags" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$libusb" = "yes" ; then
|
if test "$libusb" = "yes" ; then
|
||||||
@@ -4539,8 +4545,6 @@ if [ "$bsd" = "yes" ] ; then
|
|||||||
echo "CONFIG_BSD=y" >> $config_host_mak
|
echo "CONFIG_BSD=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak
|
|
||||||
|
|
||||||
if test "$zero_malloc" = "yes" ; then
|
if test "$zero_malloc" = "yes" ; then
|
||||||
echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak
|
echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -5179,7 +5183,7 @@ do
|
|||||||
done
|
done
|
||||||
mkdir -p $DIRS
|
mkdir -p $DIRS
|
||||||
for f in $FILES ; do
|
for f in $FILES ; do
|
||||||
if [ -e "$source_path/$f" ] && [ "$source_path" != `pwd` ]; then
|
if [ -e "$source_path/$f" ] && [ "$pwd_is_source_path" != "y" ]; then
|
||||||
symlink "$source_path/$f" "$f"
|
symlink "$source_path/$f" "$f"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@@ -115,14 +115,11 @@ static inline GThread *create_thread(GThreadFunc func, gpointer data)
|
|||||||
|
|
||||||
static void __attribute__((constructor)) coroutine_init(void)
|
static void __attribute__((constructor)) coroutine_init(void)
|
||||||
{
|
{
|
||||||
if (!g_thread_supported()) {
|
|
||||||
#if !GLIB_CHECK_VERSION(2, 31, 0)
|
#if !GLIB_CHECK_VERSION(2, 31, 0)
|
||||||
|
if (!g_thread_supported()) {
|
||||||
g_thread_init(NULL);
|
g_thread_init(NULL);
|
||||||
#else
|
|
||||||
fprintf(stderr, "glib threading failed to initialize.\n");
|
|
||||||
exit(1);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
init_coroutine_cond();
|
init_coroutine_cond();
|
||||||
}
|
}
|
||||||
|
23
cpu-exec.c
23
cpu-exec.c
@@ -335,6 +335,18 @@ int cpu_exec(CPUArchState *env)
|
|||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(TARGET_I386)
|
||||||
|
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||||
|
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
||||||
|
do_cpu_init(x86_cpu);
|
||||||
|
cpu->exception_index = EXCP_HALTED;
|
||||||
|
cpu_loop_exit(cpu);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (interrupt_request & CPU_INTERRUPT_RESET) {
|
||||||
|
cpu_reset(cpu);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
if (interrupt_request & CPU_INTERRUPT_POLL) {
|
if (interrupt_request & CPU_INTERRUPT_POLL) {
|
||||||
@@ -342,13 +354,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
apic_poll_irq(x86_cpu->apic_state);
|
apic_poll_irq(x86_cpu->apic_state);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
if (interrupt_request & CPU_INTERRUPT_SIPI) {
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT,
|
|
||||||
0);
|
|
||||||
do_cpu_init(x86_cpu);
|
|
||||||
cpu->exception_index = EXCP_HALTED;
|
|
||||||
cpu_loop_exit(cpu);
|
|
||||||
} else if (interrupt_request & CPU_INTERRUPT_SIPI) {
|
|
||||||
do_cpu_sipi(x86_cpu);
|
do_cpu_sipi(x86_cpu);
|
||||||
} else if (env->hflags2 & HF2_GIF_MASK) {
|
} else if (env->hflags2 & HF2_GIF_MASK) {
|
||||||
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
|
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
|
||||||
@@ -405,9 +411,6 @@ int cpu_exec(CPUArchState *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_PPC)
|
#elif defined(TARGET_PPC)
|
||||||
if ((interrupt_request & CPU_INTERRUPT_RESET)) {
|
|
||||||
cpu_reset(cpu);
|
|
||||||
}
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
||||||
ppc_hw_interrupt(env);
|
ppc_hw_interrupt(env);
|
||||||
if (env->pending_interrupts == 0) {
|
if (env->pending_interrupts == 0) {
|
||||||
|
5
cpus.c
5
cpus.c
@@ -430,8 +430,7 @@ static const VMStateDescription vmstate_timers = {
|
|||||||
.name = "timer",
|
.name = "timer",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_INT64(cpu_ticks_offset, TimersState),
|
VMSTATE_INT64(cpu_ticks_offset, TimersState),
|
||||||
VMSTATE_INT64(dummy, TimersState),
|
VMSTATE_INT64(dummy, TimersState),
|
||||||
VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
|
VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
|
||||||
@@ -1454,7 +1453,7 @@ void qmp_pmemsave(int64_t addr, int64_t size, const char *filename,
|
|||||||
l = sizeof(buf);
|
l = sizeof(buf);
|
||||||
if (l > size)
|
if (l > size)
|
||||||
l = size;
|
l = size;
|
||||||
cpu_physical_memory_rw(addr, buf, l, 0);
|
cpu_physical_memory_read(addr, buf, l);
|
||||||
if (fwrite(buf, 1, l, f) != l) {
|
if (fwrite(buf, 1, l, f) != l) {
|
||||||
error_set(errp, QERR_IO_ERROR);
|
error_set(errp, QERR_IO_ERROR);
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
CONFIG_USB_TABLET_WACOM=y
|
CONFIG_USB_TABLET_WACOM=y
|
||||||
CONFIG_USB_STORAGE_BOT=y
|
CONFIG_USB_STORAGE_BOT=y
|
||||||
CONFIG_USB_STORAGE_UAS=y
|
CONFIG_USB_STORAGE_UAS=y
|
||||||
|
CONFIG_USB_STORAGE_MTP=y
|
||||||
CONFIG_USB_SMARTCARD=y
|
CONFIG_USB_SMARTCARD=y
|
||||||
CONFIG_USB_AUDIO=y
|
CONFIG_USB_AUDIO=y
|
||||||
CONFIG_USB_SERIAL=y
|
CONFIG_USB_SERIAL=y
|
||||||
|
@@ -40,7 +40,7 @@ DriveInfo *add_init_drive(const char *optstr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
mc = MACHINE_GET_CLASS(current_machine);
|
mc = MACHINE_GET_CLASS(current_machine);
|
||||||
dinfo = drive_init(opts, mc->qemu_machine->block_default_type);
|
dinfo = drive_init(opts, mc->block_default_type);
|
||||||
if (!dinfo) {
|
if (!dinfo) {
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@@ -4,7 +4,7 @@ common-obj-$(CONFIG_ARM_DIS) += arm.o
|
|||||||
common-obj-$(CONFIG_ARM_A64_DIS) += arm-a64.o
|
common-obj-$(CONFIG_ARM_A64_DIS) += arm-a64.o
|
||||||
common-obj-$(CONFIG_ARM_A64_DIS) += libvixl/
|
common-obj-$(CONFIG_ARM_A64_DIS) += libvixl/
|
||||||
libvixldir = $(SRC_PATH)/disas/libvixl
|
libvixldir = $(SRC_PATH)/disas/libvixl
|
||||||
$(obj)/arm-a64.o: QEMU_CFLAGS += -I$(libvixldir)
|
arm-a64.o-cflags := -I$(libvixldir)
|
||||||
common-obj-$(CONFIG_CRIS_DIS) += cris.o
|
common-obj-$(CONFIG_CRIS_DIS) += cris.o
|
||||||
common-obj-$(CONFIG_HPPA_DIS) += hppa.o
|
common-obj-$(CONFIG_HPPA_DIS) += hppa.o
|
||||||
common-obj-$(CONFIG_I386_DIS) += i386.o
|
common-obj-$(CONFIG_I386_DIS) += i386.o
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -116,6 +116,8 @@ V_(ImmCmpBranch, 23, 5, SignedBits) \
|
|||||||
V_(ImmLLiteral, 23, 5, SignedBits) \
|
V_(ImmLLiteral, 23, 5, SignedBits) \
|
||||||
V_(ImmException, 20, 5, Bits) \
|
V_(ImmException, 20, 5, Bits) \
|
||||||
V_(ImmHint, 11, 5, Bits) \
|
V_(ImmHint, 11, 5, Bits) \
|
||||||
|
V_(ImmBarrierDomain, 11, 10, Bits) \
|
||||||
|
V_(ImmBarrierType, 9, 8, Bits) \
|
||||||
\
|
\
|
||||||
/* System (MRS, MSR) */ \
|
/* System (MRS, MSR) */ \
|
||||||
V_(ImmSystemRegister, 19, 5, Bits) \
|
V_(ImmSystemRegister, 19, 5, Bits) \
|
||||||
@@ -181,7 +183,7 @@ enum Condition {
|
|||||||
inline Condition InvertCondition(Condition cond) {
|
inline Condition InvertCondition(Condition cond) {
|
||||||
// Conditions al and nv behave identically, as "always true". They can't be
|
// Conditions al and nv behave identically, as "always true". They can't be
|
||||||
// inverted, because there is no "always false" condition.
|
// inverted, because there is no "always false" condition.
|
||||||
ASSERT((cond != al) && (cond != nv));
|
VIXL_ASSERT((cond != al) && (cond != nv));
|
||||||
return static_cast<Condition>(cond ^ 1);
|
return static_cast<Condition>(cond ^ 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,6 +248,20 @@ enum SystemHint {
|
|||||||
SEVL = 5
|
SEVL = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum BarrierDomain {
|
||||||
|
OuterShareable = 0,
|
||||||
|
NonShareable = 1,
|
||||||
|
InnerShareable = 2,
|
||||||
|
FullSystem = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BarrierType {
|
||||||
|
BarrierOther = 0,
|
||||||
|
BarrierReads = 1,
|
||||||
|
BarrierWrites = 2,
|
||||||
|
BarrierAll = 3
|
||||||
|
};
|
||||||
|
|
||||||
// System/special register names.
|
// System/special register names.
|
||||||
// This information is not encoded as one field but as the concatenation of
|
// This information is not encoded as one field but as the concatenation of
|
||||||
// multiple fields (Op0<0>, Op1, Crn, Crm, Op2).
|
// multiple fields (Op0<0>, Op1, Crn, Crm, Op2).
|
||||||
@@ -274,7 +290,7 @@ enum SystemRegister {
|
|||||||
//
|
//
|
||||||
// The enumerations can be used like this:
|
// The enumerations can be used like this:
|
||||||
//
|
//
|
||||||
// ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed);
|
// VIXL_ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed);
|
||||||
// switch(instr->Mask(PCRelAddressingMask)) {
|
// switch(instr->Mask(PCRelAddressingMask)) {
|
||||||
// case ADR: Format("adr 'Xd, 'AddrPCRelByte"); break;
|
// case ADR: Format("adr 'Xd, 'AddrPCRelByte"); break;
|
||||||
// case ADRP: Format("adrp 'Xd, 'AddrPCRelPage"); break;
|
// case ADRP: Format("adrp 'Xd, 'AddrPCRelPage"); break;
|
||||||
@@ -560,6 +576,15 @@ enum ExceptionOp {
|
|||||||
DCPS3 = ExceptionFixed | 0x00A00003
|
DCPS3 = ExceptionFixed | 0x00A00003
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MemBarrierOp {
|
||||||
|
MemBarrierFixed = 0xD503309F,
|
||||||
|
MemBarrierFMask = 0xFFFFF09F,
|
||||||
|
MemBarrierMask = 0xFFFFF0FF,
|
||||||
|
DSB = MemBarrierFixed | 0x00000000,
|
||||||
|
DMB = MemBarrierFixed | 0x00000020,
|
||||||
|
ISB = MemBarrierFixed | 0x00000040
|
||||||
|
};
|
||||||
|
|
||||||
// Any load or store.
|
// Any load or store.
|
||||||
enum LoadStoreAnyOp {
|
enum LoadStoreAnyOp {
|
||||||
LoadStoreAnyFMask = 0x0a000000,
|
LoadStoreAnyFMask = 0x0a000000,
|
||||||
@@ -927,17 +952,22 @@ enum FPDataProcessing1SourceOp {
|
|||||||
FRINTN = FRINTN_s,
|
FRINTN = FRINTN_s,
|
||||||
FRINTP_s = FPDataProcessing1SourceFixed | 0x00048000,
|
FRINTP_s = FPDataProcessing1SourceFixed | 0x00048000,
|
||||||
FRINTP_d = FPDataProcessing1SourceFixed | FP64 | 0x00048000,
|
FRINTP_d = FPDataProcessing1SourceFixed | FP64 | 0x00048000,
|
||||||
|
FRINTP = FRINTP_s,
|
||||||
FRINTM_s = FPDataProcessing1SourceFixed | 0x00050000,
|
FRINTM_s = FPDataProcessing1SourceFixed | 0x00050000,
|
||||||
FRINTM_d = FPDataProcessing1SourceFixed | FP64 | 0x00050000,
|
FRINTM_d = FPDataProcessing1SourceFixed | FP64 | 0x00050000,
|
||||||
|
FRINTM = FRINTM_s,
|
||||||
FRINTZ_s = FPDataProcessing1SourceFixed | 0x00058000,
|
FRINTZ_s = FPDataProcessing1SourceFixed | 0x00058000,
|
||||||
FRINTZ_d = FPDataProcessing1SourceFixed | FP64 | 0x00058000,
|
FRINTZ_d = FPDataProcessing1SourceFixed | FP64 | 0x00058000,
|
||||||
FRINTZ = FRINTZ_s,
|
FRINTZ = FRINTZ_s,
|
||||||
FRINTA_s = FPDataProcessing1SourceFixed | 0x00060000,
|
FRINTA_s = FPDataProcessing1SourceFixed | 0x00060000,
|
||||||
FRINTA_d = FPDataProcessing1SourceFixed | FP64 | 0x00060000,
|
FRINTA_d = FPDataProcessing1SourceFixed | FP64 | 0x00060000,
|
||||||
|
FRINTA = FRINTA_s,
|
||||||
FRINTX_s = FPDataProcessing1SourceFixed | 0x00070000,
|
FRINTX_s = FPDataProcessing1SourceFixed | 0x00070000,
|
||||||
FRINTX_d = FPDataProcessing1SourceFixed | FP64 | 0x00070000,
|
FRINTX_d = FPDataProcessing1SourceFixed | FP64 | 0x00070000,
|
||||||
|
FRINTX = FRINTX_s,
|
||||||
FRINTI_s = FPDataProcessing1SourceFixed | 0x00078000,
|
FRINTI_s = FPDataProcessing1SourceFixed | 0x00078000,
|
||||||
FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000
|
FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000,
|
||||||
|
FRINTI = FRINTI_s
|
||||||
};
|
};
|
||||||
|
|
||||||
// Floating point data processing 2 source.
|
// Floating point data processing 2 source.
|
||||||
|
@@ -132,7 +132,7 @@ void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
|
|||||||
}
|
}
|
||||||
// We reached the end of the list. The last element must be
|
// We reached the end of the list. The last element must be
|
||||||
// registered_visitor.
|
// registered_visitor.
|
||||||
ASSERT(*it == registered_visitor);
|
VIXL_ASSERT(*it == registered_visitor);
|
||||||
visitors_.insert(it, new_visitor);
|
visitors_.insert(it, new_visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
|
|||||||
}
|
}
|
||||||
// We reached the end of the list. The last element must be
|
// We reached the end of the list. The last element must be
|
||||||
// registered_visitor.
|
// registered_visitor.
|
||||||
ASSERT(*it == registered_visitor);
|
VIXL_ASSERT(*it == registered_visitor);
|
||||||
visitors_.push_back(new_visitor);
|
visitors_.push_back(new_visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,16 +161,16 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
|
|||||||
|
|
||||||
|
|
||||||
void Decoder::DecodePCRelAddressing(Instruction* instr) {
|
void Decoder::DecodePCRelAddressing(Instruction* instr) {
|
||||||
ASSERT(instr->Bits(27, 24) == 0x0);
|
VIXL_ASSERT(instr->Bits(27, 24) == 0x0);
|
||||||
// We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
|
// We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
|
||||||
// decode.
|
// decode.
|
||||||
ASSERT(instr->Bit(28) == 0x1);
|
VIXL_ASSERT(instr->Bit(28) == 0x1);
|
||||||
VisitPCRelAddressing(instr);
|
VisitPCRelAddressing(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
||||||
ASSERT((instr->Bits(27, 24) == 0x4) ||
|
VIXL_ASSERT((instr->Bits(27, 24) == 0x4) ||
|
||||||
(instr->Bits(27, 24) == 0x5) ||
|
(instr->Bits(27, 24) == 0x5) ||
|
||||||
(instr->Bits(27, 24) == 0x6) ||
|
(instr->Bits(27, 24) == 0x6) ||
|
||||||
(instr->Bits(27, 24) == 0x7) );
|
(instr->Bits(27, 24) == 0x7) );
|
||||||
@@ -271,7 +271,7 @@ void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeLoadStore(Instruction* instr) {
|
void Decoder::DecodeLoadStore(Instruction* instr) {
|
||||||
ASSERT((instr->Bits(27, 24) == 0x8) ||
|
VIXL_ASSERT((instr->Bits(27, 24) == 0x8) ||
|
||||||
(instr->Bits(27, 24) == 0x9) ||
|
(instr->Bits(27, 24) == 0x9) ||
|
||||||
(instr->Bits(27, 24) == 0xC) ||
|
(instr->Bits(27, 24) == 0xC) ||
|
||||||
(instr->Bits(27, 24) == 0xD) );
|
(instr->Bits(27, 24) == 0xD) );
|
||||||
@@ -390,7 +390,7 @@ void Decoder::DecodeLoadStore(Instruction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeLogical(Instruction* instr) {
|
void Decoder::DecodeLogical(Instruction* instr) {
|
||||||
ASSERT(instr->Bits(27, 24) == 0x2);
|
VIXL_ASSERT(instr->Bits(27, 24) == 0x2);
|
||||||
|
|
||||||
if (instr->Mask(0x80400000) == 0x00400000) {
|
if (instr->Mask(0x80400000) == 0x00400000) {
|
||||||
VisitUnallocated(instr);
|
VisitUnallocated(instr);
|
||||||
@@ -409,7 +409,7 @@ void Decoder::DecodeLogical(Instruction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
||||||
ASSERT(instr->Bits(27, 24) == 0x3);
|
VIXL_ASSERT(instr->Bits(27, 24) == 0x3);
|
||||||
|
|
||||||
if ((instr->Mask(0x80400000) == 0x80000000) ||
|
if ((instr->Mask(0x80400000) == 0x80000000) ||
|
||||||
(instr->Mask(0x80400000) == 0x00400000) ||
|
(instr->Mask(0x80400000) == 0x00400000) ||
|
||||||
@@ -434,7 +434,7 @@ void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
||||||
ASSERT(instr->Bits(27, 24) == 0x1);
|
VIXL_ASSERT(instr->Bits(27, 24) == 0x1);
|
||||||
if (instr->Bit(23) == 1) {
|
if (instr->Bit(23) == 1) {
|
||||||
VisitUnallocated(instr);
|
VisitUnallocated(instr);
|
||||||
} else {
|
} else {
|
||||||
@@ -444,8 +444,8 @@ void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeDataProcessing(Instruction* instr) {
|
void Decoder::DecodeDataProcessing(Instruction* instr) {
|
||||||
ASSERT((instr->Bits(27, 24) == 0xA) ||
|
VIXL_ASSERT((instr->Bits(27, 24) == 0xA) ||
|
||||||
(instr->Bits(27, 24) == 0xB) );
|
(instr->Bits(27, 24) == 0xB));
|
||||||
|
|
||||||
if (instr->Bit(24) == 0) {
|
if (instr->Bit(24) == 0) {
|
||||||
if (instr->Bit(28) == 0) {
|
if (instr->Bit(28) == 0) {
|
||||||
@@ -559,8 +559,8 @@ void Decoder::DecodeDataProcessing(Instruction* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeFP(Instruction* instr) {
|
void Decoder::DecodeFP(Instruction* instr) {
|
||||||
ASSERT((instr->Bits(27, 24) == 0xE) ||
|
VIXL_ASSERT((instr->Bits(27, 24) == 0xE) ||
|
||||||
(instr->Bits(27, 24) == 0xF) );
|
(instr->Bits(27, 24) == 0xF));
|
||||||
|
|
||||||
if (instr->Bit(28) == 0) {
|
if (instr->Bit(28) == 0) {
|
||||||
DecodeAdvSIMDDataProcessing(instr);
|
DecodeAdvSIMDDataProcessing(instr);
|
||||||
@@ -665,14 +665,14 @@ void Decoder::DecodeFP(Instruction* instr) {
|
|||||||
VisitFPConditionalSelect(instr);
|
VisitFPConditionalSelect(instr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Bit 30 == 1 has been handled earlier.
|
// Bit 30 == 1 has been handled earlier.
|
||||||
ASSERT(instr->Bit(30) == 0);
|
VIXL_ASSERT(instr->Bit(30) == 0);
|
||||||
if (instr->Mask(0xA0800000) != 0) {
|
if (instr->Mask(0xA0800000) != 0) {
|
||||||
VisitUnallocated(instr);
|
VisitUnallocated(instr);
|
||||||
} else {
|
} else {
|
||||||
@@ -687,21 +687,21 @@ void Decoder::DecodeFP(Instruction* instr) {
|
|||||||
|
|
||||||
void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) {
|
void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) {
|
||||||
// TODO: Implement Advanced SIMD load/store instruction decode.
|
// TODO: Implement Advanced SIMD load/store instruction decode.
|
||||||
ASSERT(instr->Bits(29, 25) == 0x6);
|
VIXL_ASSERT(instr->Bits(29, 25) == 0x6);
|
||||||
VisitUnimplemented(instr);
|
VisitUnimplemented(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
|
void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
|
||||||
// TODO: Implement Advanced SIMD data processing instruction decode.
|
// TODO: Implement Advanced SIMD data processing instruction decode.
|
||||||
ASSERT(instr->Bits(27, 25) == 0x7);
|
VIXL_ASSERT(instr->Bits(27, 25) == 0x7);
|
||||||
VisitUnimplemented(instr);
|
VisitUnimplemented(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define DEFINE_VISITOR_CALLERS(A) \
|
#define DEFINE_VISITOR_CALLERS(A) \
|
||||||
void Decoder::Visit##A(Instruction *instr) { \
|
void Decoder::Visit##A(Instruction *instr) { \
|
||||||
ASSERT(instr->Mask(A##FMask) == A##Fixed); \
|
VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \
|
||||||
std::list<DecoderVisitor*>::iterator it; \
|
std::list<DecoderVisitor*>::iterator it; \
|
||||||
for (it = visitors_.begin(); it != visitors_.end(); it++) { \
|
for (it = visitors_.begin(); it != visitors_.end(); it++) { \
|
||||||
(*it)->Visit##A(instr); \
|
(*it)->Visit##A(instr); \
|
||||||
|
@@ -95,7 +95,7 @@ void Disassembler::VisitAddSubImmediate(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ void Disassembler::VisitAddSubShifted(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -180,7 +180,7 @@ void Disassembler::VisitAddSubExtended(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,7 @@ void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -258,30 +258,30 @@ void Disassembler::VisitLogicalImmediate(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
|
bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
|
||||||
ASSERT((reg_size == kXRegSize) ||
|
VIXL_ASSERT((reg_size == kXRegSize) ||
|
||||||
((reg_size == kWRegSize) && (value <= 0xffffffff)));
|
((reg_size == kWRegSize) && (value <= 0xffffffff)));
|
||||||
|
|
||||||
// Test for movz: 16 bits set at positions 0, 16, 32 or 48.
|
// Test for movz: 16 bits set at positions 0, 16, 32 or 48.
|
||||||
if (((value & 0xffffffffffff0000ULL) == 0ULL) ||
|
if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||
|
||||||
((value & 0xffffffff0000ffffULL) == 0ULL) ||
|
((value & UINT64_C(0xffffffff0000ffff)) == 0) ||
|
||||||
((value & 0xffff0000ffffffffULL) == 0ULL) ||
|
((value & UINT64_C(0xffff0000ffffffff)) == 0) ||
|
||||||
((value & 0x0000ffffffffffffULL) == 0ULL)) {
|
((value & UINT64_C(0x0000ffffffffffff)) == 0)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
|
// Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
|
||||||
if ((reg_size == kXRegSize) &&
|
if ((reg_size == kXRegSize) &&
|
||||||
(((value & 0xffffffffffff0000ULL) == 0xffffffffffff0000ULL) ||
|
(((~value & UINT64_C(0xffffffffffff0000)) == 0) ||
|
||||||
((value & 0xffffffff0000ffffULL) == 0xffffffff0000ffffULL) ||
|
((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||
|
||||||
((value & 0xffff0000ffffffffULL) == 0xffff0000ffffffffULL) ||
|
((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||
|
||||||
((value & 0x0000ffffffffffffULL) == 0x0000ffffffffffffULL))) {
|
((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((reg_size == kWRegSize) &&
|
if ((reg_size == kWRegSize) &&
|
||||||
@@ -337,7 +337,7 @@ void Disassembler::VisitLogicalShifted(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
@@ -353,7 +353,7 @@ void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
|
|||||||
case CCMN_x: mnemonic = "ccmn"; break;
|
case CCMN_x: mnemonic = "ccmn"; break;
|
||||||
case CCMP_w:
|
case CCMP_w:
|
||||||
case CCMP_x: mnemonic = "ccmp"; break;
|
case CCMP_x: mnemonic = "ccmp"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -368,7 +368,7 @@ void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
|
|||||||
case CCMN_x_imm: mnemonic = "ccmn"; break;
|
case CCMN_x_imm: mnemonic = "ccmn"; break;
|
||||||
case CCMP_w_imm:
|
case CCMP_w_imm:
|
||||||
case CCMP_x_imm: mnemonic = "ccmp"; break;
|
case CCMP_x_imm: mnemonic = "ccmp"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -421,7 +421,7 @@ void Disassembler::VisitConditionalSelect(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -520,7 +520,7 @@ void Disassembler::VisitExtract(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -538,7 +538,7 @@ void Disassembler::VisitPCRelAddressing(Instruction* instr) {
|
|||||||
void Disassembler::VisitConditionalBranch(Instruction* instr) {
|
void Disassembler::VisitConditionalBranch(Instruction* instr) {
|
||||||
switch (instr->Mask(ConditionalBranchMask)) {
|
switch (instr->Mask(ConditionalBranchMask)) {
|
||||||
case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
|
case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,7 +570,7 @@ void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
|
|||||||
switch (instr->Mask(UnconditionalBranchMask)) {
|
switch (instr->Mask(UnconditionalBranchMask)) {
|
||||||
case B: mnemonic = "b"; break;
|
case B: mnemonic = "b"; break;
|
||||||
case BL: mnemonic = "bl"; break;
|
case BL: mnemonic = "bl"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -591,7 +591,7 @@ void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
|
|||||||
FORMAT(CLS, "cls");
|
FORMAT(CLS, "cls");
|
||||||
#undef FORMAT
|
#undef FORMAT
|
||||||
case REV32_x: mnemonic = "rev32"; break;
|
case REV32_x: mnemonic = "rev32"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -690,7 +690,7 @@ void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
|
|||||||
form = form_xxx;
|
form = form_xxx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -705,7 +705,7 @@ void Disassembler::VisitCompareBranch(Instruction* instr) {
|
|||||||
case CBZ_x: mnemonic = "cbz"; break;
|
case CBZ_x: mnemonic = "cbz"; break;
|
||||||
case CBNZ_w:
|
case CBNZ_w:
|
||||||
case CBNZ_x: mnemonic = "cbnz"; break;
|
case CBNZ_x: mnemonic = "cbnz"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -722,7 +722,7 @@ void Disassembler::VisitTestBranch(Instruction* instr) {
|
|||||||
switch (instr->Mask(TestBranchMask)) {
|
switch (instr->Mask(TestBranchMask)) {
|
||||||
case TBZ: mnemonic = "tbz"; break;
|
case TBZ: mnemonic = "tbz"; break;
|
||||||
case TBNZ: mnemonic = "tbnz"; break;
|
case TBNZ: mnemonic = "tbnz"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -742,7 +742,7 @@ void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
|
|||||||
case MOVZ_x: mnemonic = "movz"; break;
|
case MOVZ_x: mnemonic = "movz"; break;
|
||||||
case MOVK_w:
|
case MOVK_w:
|
||||||
case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
|
case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -981,7 +981,7 @@ void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
|
|||||||
switch (instr->Mask(FPConditionalSelectMask)) {
|
switch (instr->Mask(FPConditionalSelectMask)) {
|
||||||
case FCSEL_s:
|
case FCSEL_s:
|
||||||
case FCSEL_d: mnemonic = "fcsel"; break;
|
case FCSEL_d: mnemonic = "fcsel"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -1033,7 +1033,7 @@ void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
|
|||||||
FORMAT(FMINNM, "fminnm");
|
FORMAT(FMINNM, "fminnm");
|
||||||
FORMAT(FNMUL, "fnmul");
|
FORMAT(FNMUL, "fnmul");
|
||||||
#undef FORMAT
|
#undef FORMAT
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -1052,7 +1052,7 @@ void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
|
|||||||
FORMAT(FNMADD, "fnmadd");
|
FORMAT(FNMADD, "fnmadd");
|
||||||
FORMAT(FNMSUB, "fnmsub");
|
FORMAT(FNMSUB, "fnmsub");
|
||||||
#undef FORMAT
|
#undef FORMAT
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -1065,7 +1065,7 @@ void Disassembler::VisitFPImmediate(Instruction* instr) {
|
|||||||
switch (instr->Mask(FPImmediateMask)) {
|
switch (instr->Mask(FPImmediateMask)) {
|
||||||
case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
|
case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
|
||||||
case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
|
case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -1082,6 +1082,14 @@ void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
|
|||||||
case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
|
case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
|
||||||
case FMOV_sw:
|
case FMOV_sw:
|
||||||
case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
|
case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
|
||||||
|
case FCVTAS_ws:
|
||||||
|
case FCVTAS_xs:
|
||||||
|
case FCVTAS_wd:
|
||||||
|
case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
|
||||||
|
case FCVTAU_ws:
|
||||||
|
case FCVTAU_xs:
|
||||||
|
case FCVTAU_wd:
|
||||||
|
case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
|
||||||
case FCVTMS_ws:
|
case FCVTMS_ws:
|
||||||
case FCVTMS_xs:
|
case FCVTMS_xs:
|
||||||
case FCVTMS_wd:
|
case FCVTMS_wd:
|
||||||
@@ -1141,7 +1149,7 @@ void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
|
|||||||
case UCVTF_sx_fixed:
|
case UCVTF_sx_fixed:
|
||||||
case UCVTF_dw_fixed:
|
case UCVTF_dw_fixed:
|
||||||
case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
|
case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
}
|
}
|
||||||
@@ -1176,7 +1184,7 @@ void Disassembler::VisitSystem(Instruction* instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
|
} else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
|
||||||
ASSERT(instr->Mask(SystemHintMask) == HINT);
|
VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT);
|
||||||
switch (instr->ImmHint()) {
|
switch (instr->ImmHint()) {
|
||||||
case NOP: {
|
case NOP: {
|
||||||
mnemonic = "nop";
|
mnemonic = "nop";
|
||||||
@@ -1184,6 +1192,24 @@ void Disassembler::VisitSystem(Instruction* instr) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
|
||||||
|
switch (instr->Mask(MemBarrierMask)) {
|
||||||
|
case DMB: {
|
||||||
|
mnemonic = "dmb";
|
||||||
|
form = "'M";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DSB: {
|
||||||
|
mnemonic = "dsb";
|
||||||
|
form = "'M";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ISB: {
|
||||||
|
mnemonic = "isb";
|
||||||
|
form = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Format(instr, mnemonic, form);
|
Format(instr, mnemonic, form);
|
||||||
@@ -1226,7 +1252,7 @@ void Disassembler::ProcessOutput(Instruction* /*instr*/) {
|
|||||||
|
|
||||||
void Disassembler::Format(Instruction* instr, const char* mnemonic,
|
void Disassembler::Format(Instruction* instr, const char* mnemonic,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT(mnemonic != NULL);
|
VIXL_ASSERT(mnemonic != NULL);
|
||||||
ResetOutput();
|
ResetOutput();
|
||||||
Substitute(instr, mnemonic);
|
Substitute(instr, mnemonic);
|
||||||
if (format != NULL) {
|
if (format != NULL) {
|
||||||
@@ -1268,8 +1294,9 @@ int Disassembler::SubstituteField(Instruction* instr, const char* format) {
|
|||||||
case 'A': return SubstitutePCRelAddressField(instr, format);
|
case 'A': return SubstitutePCRelAddressField(instr, format);
|
||||||
case 'B': return SubstituteBranchTargetField(instr, format);
|
case 'B': return SubstituteBranchTargetField(instr, format);
|
||||||
case 'O': return SubstituteLSRegOffsetField(instr, format);
|
case 'O': return SubstituteLSRegOffsetField(instr, format);
|
||||||
|
case 'M': return SubstituteBarrierField(instr, format);
|
||||||
default: {
|
default: {
|
||||||
UNREACHABLE();
|
VIXL_UNREACHABLE();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1294,7 +1321,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increase field length for registers tagged as stack.
|
// Increase field length for registers tagged as stack.
|
||||||
@@ -1331,7 +1358,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
|
|||||||
|
|
||||||
int Disassembler::SubstituteImmediateField(Instruction* instr,
|
int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT(format[0] == 'I');
|
VIXL_ASSERT(format[0] == 'I');
|
||||||
|
|
||||||
switch (format[1]) {
|
switch (format[1]) {
|
||||||
case 'M': { // IMoveImm or IMoveLSL.
|
case 'M': { // IMoveImm or IMoveLSL.
|
||||||
@@ -1339,10 +1366,10 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
|||||||
uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
|
uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
|
||||||
AppendToOutput("#0x%" PRIx64, imm);
|
AppendToOutput("#0x%" PRIx64, imm);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(format[5] == 'L');
|
VIXL_ASSERT(format[5] == 'L');
|
||||||
AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
|
AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
|
||||||
if (instr->ShiftMoveWide() > 0) {
|
if (instr->ShiftMoveWide() > 0) {
|
||||||
AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide());
|
AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 8;
|
return 8;
|
||||||
@@ -1384,14 +1411,14 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
|||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
case 'A': { // IAddSub.
|
case 'A': { // IAddSub.
|
||||||
ASSERT(instr->ShiftAddSub() <= 1);
|
VIXL_ASSERT(instr->ShiftAddSub() <= 1);
|
||||||
int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
|
int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
|
||||||
AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
|
AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
case 'F': { // IFPSingle, IFPDouble or IFPFBits.
|
case 'F': { // IFPSingle, IFPDouble or IFPFBits.
|
||||||
if (format[3] == 'F') { // IFPFbits.
|
if (format[3] == 'F') { // IFPFbits.
|
||||||
AppendToOutput("#%" PRId64, 64 - instr->FPScale());
|
AppendToOutput("#%d", 64 - instr->FPScale());
|
||||||
return 8;
|
return 8;
|
||||||
} else {
|
} else {
|
||||||
AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
|
AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
|
||||||
@@ -1412,27 +1439,27 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
|||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
case 'P': { // IP - Conditional compare.
|
case 'P': { // IP - Conditional compare.
|
||||||
AppendToOutput("#%" PRId64, instr->ImmCondCmp());
|
AppendToOutput("#%d", instr->ImmCondCmp());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
case 'B': { // Bitfields.
|
case 'B': { // Bitfields.
|
||||||
return SubstituteBitfieldImmediateField(instr, format);
|
return SubstituteBitfieldImmediateField(instr, format);
|
||||||
}
|
}
|
||||||
case 'E': { // IExtract.
|
case 'E': { // IExtract.
|
||||||
AppendToOutput("#%" PRId64, instr->ImmS());
|
AppendToOutput("#%d", instr->ImmS());
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
case 'S': { // IS - Test and branch bit.
|
case 'S': { // IS - Test and branch bit.
|
||||||
AppendToOutput("#%" PRId64, (instr->ImmTestBranchBit5() << 5) |
|
AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
|
||||||
instr->ImmTestBranchBit40());
|
instr->ImmTestBranchBit40());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
case 'D': { // IDebug - HLT and BRK instructions.
|
case 'D': { // IDebug - HLT and BRK instructions.
|
||||||
AppendToOutput("#0x%" PRIx64, instr->ImmException());
|
AppendToOutput("#0x%x", instr->ImmException());
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
UNIMPLEMENTED();
|
VIXL_UNIMPLEMENTED();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1441,7 +1468,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
|||||||
|
|
||||||
int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT((format[0] == 'I') && (format[1] == 'B'));
|
VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
|
||||||
unsigned r = instr->ImmR();
|
unsigned r = instr->ImmR();
|
||||||
unsigned s = instr->ImmS();
|
unsigned s = instr->ImmS();
|
||||||
|
|
||||||
@@ -1455,19 +1482,19 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
|||||||
AppendToOutput("#%d", s + 1);
|
AppendToOutput("#%d", s + 1);
|
||||||
return 5;
|
return 5;
|
||||||
} else {
|
} else {
|
||||||
ASSERT(format[3] == '-');
|
VIXL_ASSERT(format[3] == '-');
|
||||||
AppendToOutput("#%d", s - r + 1);
|
AppendToOutput("#%d", s - r + 1);
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'Z': { // IBZ-r.
|
case 'Z': { // IBZ-r.
|
||||||
ASSERT((format[3] == '-') && (format[4] == 'r'));
|
VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
|
||||||
unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
|
unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
|
||||||
AppendToOutput("#%d", reg_size - r);
|
AppendToOutput("#%d", reg_size - r);
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
UNREACHABLE();
|
VIXL_UNREACHABLE();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1476,7 +1503,7 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
|||||||
|
|
||||||
int Disassembler::SubstituteLiteralField(Instruction* instr,
|
int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT(strncmp(format, "LValue", 6) == 0);
|
VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
|
||||||
USE(format);
|
USE(format);
|
||||||
|
|
||||||
switch (instr->Mask(LoadLiteralMask)) {
|
switch (instr->Mask(LoadLiteralMask)) {
|
||||||
@@ -1484,7 +1511,7 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
|
|||||||
case LDR_x_lit:
|
case LDR_x_lit:
|
||||||
case LDR_s_lit:
|
case LDR_s_lit:
|
||||||
case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
|
case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 6;
|
return 6;
|
||||||
@@ -1492,12 +1519,12 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
|
|||||||
|
|
||||||
|
|
||||||
int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||||
ASSERT(format[0] == 'H');
|
VIXL_ASSERT(format[0] == 'H');
|
||||||
ASSERT(instr->ShiftDP() <= 0x3);
|
VIXL_ASSERT(instr->ShiftDP() <= 0x3);
|
||||||
|
|
||||||
switch (format[1]) {
|
switch (format[1]) {
|
||||||
case 'D': { // HDP.
|
case 'D': { // HDP.
|
||||||
ASSERT(instr->ShiftDP() != ROR);
|
VIXL_ASSERT(instr->ShiftDP() != ROR);
|
||||||
} // Fall through.
|
} // Fall through.
|
||||||
case 'L': { // HLo.
|
case 'L': { // HLo.
|
||||||
if (instr->ImmDPShift() != 0) {
|
if (instr->ImmDPShift() != 0) {
|
||||||
@@ -1508,7 +1535,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED();
|
VIXL_UNIMPLEMENTED();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1516,7 +1543,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
|||||||
|
|
||||||
int Disassembler::SubstituteConditionField(Instruction* instr,
|
int Disassembler::SubstituteConditionField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT(format[0] == 'C');
|
VIXL_ASSERT(format[0] == 'C');
|
||||||
const char* condition_code[] = { "eq", "ne", "hs", "lo",
|
const char* condition_code[] = { "eq", "ne", "hs", "lo",
|
||||||
"mi", "pl", "vs", "vc",
|
"mi", "pl", "vs", "vc",
|
||||||
"hi", "ls", "ge", "lt",
|
"hi", "ls", "ge", "lt",
|
||||||
@@ -1538,27 +1565,27 @@ int Disassembler::SubstituteConditionField(Instruction* instr,
|
|||||||
int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
|
int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
USE(format);
|
USE(format);
|
||||||
ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
|
VIXL_ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
|
||||||
|
|
||||||
int offset = instr->ImmPCRel();
|
int offset = instr->ImmPCRel();
|
||||||
|
|
||||||
// Only ADR (AddrPCRelByte) is supported.
|
// Only ADR (AddrPCRelByte) is supported.
|
||||||
ASSERT(strcmp(format, "AddrPCRelByte") == 0);
|
VIXL_ASSERT(strcmp(format, "AddrPCRelByte") == 0);
|
||||||
|
|
||||||
char sign = '+';
|
char sign = '+';
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
offset = -offset;
|
offset = -offset;
|
||||||
sign = '-';
|
sign = '-';
|
||||||
}
|
}
|
||||||
// TODO: Extend this to support printing the target address.
|
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
|
||||||
AppendToOutput("#%c0x%x", sign, offset);
|
AppendToOutput("#%c0x%x (addr %p)", sign, offset, instr + offset);
|
||||||
return 13;
|
return 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT(strncmp(format, "BImm", 4) == 0);
|
VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
|
||||||
|
|
||||||
int64_t offset = 0;
|
int64_t offset = 0;
|
||||||
switch (format[5]) {
|
switch (format[5]) {
|
||||||
@@ -1570,7 +1597,7 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
|||||||
case 'm': offset = instr->ImmCmpBranch(); break;
|
case 'm': offset = instr->ImmCmpBranch(); break;
|
||||||
// BImmTest - test and branch immediate.
|
// BImmTest - test and branch immediate.
|
||||||
case 'e': offset = instr->ImmTestBranch(); break;
|
case 'e': offset = instr->ImmTestBranch(); break;
|
||||||
default: UNIMPLEMENTED();
|
default: VIXL_UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
offset <<= kInstructionSizeLog2;
|
offset <<= kInstructionSizeLog2;
|
||||||
char sign = '+';
|
char sign = '+';
|
||||||
@@ -1578,15 +1605,16 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
|||||||
offset = -offset;
|
offset = -offset;
|
||||||
sign = '-';
|
sign = '-';
|
||||||
}
|
}
|
||||||
AppendToOutput("#%c0x%" PRIx64, sign, offset);
|
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
|
||||||
|
AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, instr + offset);
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Disassembler::SubstituteExtendField(Instruction* instr,
|
int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT(strncmp(format, "Ext", 3) == 0);
|
VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
|
||||||
ASSERT(instr->ExtendMode() <= 7);
|
VIXL_ASSERT(instr->ExtendMode() <= 7);
|
||||||
USE(format);
|
USE(format);
|
||||||
|
|
||||||
const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
|
const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
|
||||||
@@ -1598,12 +1626,12 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
|
|||||||
(((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
|
(((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
|
||||||
(instr->ExtendMode() == UXTX))) {
|
(instr->ExtendMode() == UXTX))) {
|
||||||
if (instr->ImmExtendShift() > 0) {
|
if (instr->ImmExtendShift() > 0) {
|
||||||
AppendToOutput(", lsl #%" PRId64, instr->ImmExtendShift());
|
AppendToOutput(", lsl #%d", instr->ImmExtendShift());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
|
AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
|
||||||
if (instr->ImmExtendShift() > 0) {
|
if (instr->ImmExtendShift() > 0) {
|
||||||
AppendToOutput(" #%" PRId64, instr->ImmExtendShift());
|
AppendToOutput(" #%d", instr->ImmExtendShift());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 3;
|
return 3;
|
||||||
@@ -1612,7 +1640,7 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
|
|||||||
|
|
||||||
int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT(strncmp(format, "Offsetreg", 9) == 0);
|
VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
|
||||||
const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
|
const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
|
||||||
"undefined", "undefined", "sxtw", "sxtx" };
|
"undefined", "undefined", "sxtw", "sxtx" };
|
||||||
USE(format);
|
USE(format);
|
||||||
@@ -1632,7 +1660,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
|||||||
if (!((ext == UXTX) && (shift == 0))) {
|
if (!((ext == UXTX) && (shift == 0))) {
|
||||||
AppendToOutput(", %s", extend_mode[ext]);
|
AppendToOutput(", %s", extend_mode[ext]);
|
||||||
if (shift != 0) {
|
if (shift != 0) {
|
||||||
AppendToOutput(" #%" PRId64, instr->SizeLS());
|
AppendToOutput(" #%d", instr->SizeLS());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 9;
|
return 9;
|
||||||
@@ -1641,7 +1669,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
|||||||
|
|
||||||
int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
||||||
const char* format) {
|
const char* format) {
|
||||||
ASSERT(format[0] == 'P');
|
VIXL_ASSERT(format[0] == 'P');
|
||||||
USE(format);
|
USE(format);
|
||||||
|
|
||||||
int prefetch_mode = instr->PrefetchMode();
|
int prefetch_mode = instr->PrefetchMode();
|
||||||
@@ -1654,6 +1682,23 @@ int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
|||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Disassembler::SubstituteBarrierField(Instruction* instr,
|
||||||
|
const char* format) {
|
||||||
|
VIXL_ASSERT(format[0] == 'M');
|
||||||
|
USE(format);
|
||||||
|
|
||||||
|
static const char* options[4][4] = {
|
||||||
|
{ "sy (0b0000)", "oshld", "oshst", "osh" },
|
||||||
|
{ "sy (0b0100)", "nshld", "nshst", "nsh" },
|
||||||
|
{ "sy (0b1000)", "ishld", "ishst", "ish" },
|
||||||
|
{ "sy (0b1100)", "ld", "st", "sy" }
|
||||||
|
};
|
||||||
|
int domain = instr->ImmBarrierDomain();
|
||||||
|
int type = instr->ImmBarrierType();
|
||||||
|
|
||||||
|
AppendToOutput("%s", options[domain][type]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void Disassembler::ResetOutput() {
|
void Disassembler::ResetOutput() {
|
||||||
buffer_pos_ = 0;
|
buffer_pos_ = 0;
|
||||||
|
@@ -64,6 +64,7 @@ class Disassembler: public DecoderVisitor {
|
|||||||
int SubstituteBranchTargetField(Instruction* instr, const char* format);
|
int SubstituteBranchTargetField(Instruction* instr, const char* format);
|
||||||
int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
|
int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
|
||||||
int SubstitutePrefetchField(Instruction* instr, const char* format);
|
int SubstitutePrefetchField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteBarrierField(Instruction* instr, const char* format);
|
||||||
|
|
||||||
inline bool RdIsZROrSP(Instruction* instr) const {
|
inline bool RdIsZROrSP(Instruction* instr) const {
|
||||||
return (instr->Rd() == kZeroRegCode);
|
return (instr->Rd() == kZeroRegCode);
|
||||||
|
@@ -33,20 +33,20 @@ namespace vixl {
|
|||||||
static uint64_t RotateRight(uint64_t value,
|
static uint64_t RotateRight(uint64_t value,
|
||||||
unsigned int rotate,
|
unsigned int rotate,
|
||||||
unsigned int width) {
|
unsigned int width) {
|
||||||
ASSERT(width <= 64);
|
VIXL_ASSERT(width <= 64);
|
||||||
rotate &= 63;
|
rotate &= 63;
|
||||||
return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) |
|
return ((value & ((UINT64_C(1) << rotate) - 1)) <<
|
||||||
(value >> rotate);
|
(width - rotate)) | (value >> rotate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
|
static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
|
||||||
uint64_t value,
|
uint64_t value,
|
||||||
unsigned width) {
|
unsigned width) {
|
||||||
ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
|
VIXL_ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
|
||||||
(width == 32));
|
(width == 32));
|
||||||
ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||||
uint64_t result = value & ((1UL << width) - 1UL);
|
uint64_t result = value & ((UINT64_C(1) << width) - 1);
|
||||||
for (unsigned i = width; i < reg_size; i *= 2) {
|
for (unsigned i = width; i < reg_size; i *= 2) {
|
||||||
result |= (result << i);
|
result |= (result << i);
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ uint64_t Instruction::ImmLogical() {
|
|||||||
if (imm_s == 0x3F) {
|
if (imm_s == 0x3F) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint64_t bits = (1UL << (imm_s + 1)) - 1;
|
uint64_t bits = (UINT64_C(1) << (imm_s + 1)) - 1;
|
||||||
return RotateRight(bits, imm_r, 64);
|
return RotateRight(bits, imm_r, 64);
|
||||||
} else {
|
} else {
|
||||||
if ((imm_s >> 1) == 0x1F) {
|
if ((imm_s >> 1) == 0x1F) {
|
||||||
@@ -96,14 +96,14 @@ uint64_t Instruction::ImmLogical() {
|
|||||||
if ((imm_s & mask) == mask) {
|
if ((imm_s & mask) == mask) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1;
|
uint64_t bits = (UINT64_C(1) << ((imm_s & mask) + 1)) - 1;
|
||||||
return RepeatBitsAcrossReg(reg_size,
|
return RepeatBitsAcrossReg(reg_size,
|
||||||
RotateRight(bits, imm_r & mask, width),
|
RotateRight(bits, imm_r & mask, width),
|
||||||
width);
|
width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
VIXL_UNREACHABLE();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ Instruction* Instruction::ImmPCOffsetTarget() {
|
|||||||
offset = ImmPCRel();
|
offset = ImmPCRel();
|
||||||
} else {
|
} else {
|
||||||
// All PC-relative branches.
|
// All PC-relative branches.
|
||||||
ASSERT(BranchType() != UnknownBranchType);
|
VIXL_ASSERT(BranchType() != UnknownBranchType);
|
||||||
// Relative branch offsets are instruction-size-aligned.
|
// Relative branch offsets are instruction-size-aligned.
|
||||||
offset = ImmBranch() << kInstructionSizeLog2;
|
offset = ImmBranch() << kInstructionSizeLog2;
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ inline int Instruction::ImmBranch() const {
|
|||||||
case UncondBranchType: return ImmUncondBranch();
|
case UncondBranchType: return ImmUncondBranch();
|
||||||
case CompareBranchType: return ImmCmpBranch();
|
case CompareBranchType: return ImmCmpBranch();
|
||||||
case TestBranchType: return ImmTestBranch();
|
case TestBranchType: return ImmTestBranch();
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) {
|
|||||||
|
|
||||||
void Instruction::SetPCRelImmTarget(Instruction* target) {
|
void Instruction::SetPCRelImmTarget(Instruction* target) {
|
||||||
// ADRP is not supported, so 'this' must point to an ADR instruction.
|
// ADRP is not supported, so 'this' must point to an ADR instruction.
|
||||||
ASSERT(Mask(PCRelAddressingMask) == ADR);
|
VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR);
|
||||||
|
|
||||||
Instr imm = Assembler::ImmPCRelAddress(target - this);
|
Instr imm = Assembler::ImmPCRelAddress(target - this);
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) {
|
|||||||
|
|
||||||
|
|
||||||
void Instruction::SetBranchImmTarget(Instruction* target) {
|
void Instruction::SetBranchImmTarget(Instruction* target) {
|
||||||
ASSERT(((target - this) & 3) == 0);
|
VIXL_ASSERT(((target - this) & 3) == 0);
|
||||||
Instr branch_imm = 0;
|
Instr branch_imm = 0;
|
||||||
uint32_t imm_mask = 0;
|
uint32_t imm_mask = 0;
|
||||||
int offset = (target - this) >> kInstructionSizeLog2;
|
int offset = (target - this) >> kInstructionSizeLog2;
|
||||||
@@ -220,14 +220,14 @@ void Instruction::SetBranchImmTarget(Instruction* target) {
|
|||||||
imm_mask = ImmTestBranch_mask;
|
imm_mask = ImmTestBranch_mask;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: UNREACHABLE();
|
default: VIXL_UNREACHABLE();
|
||||||
}
|
}
|
||||||
SetInstructionBits(Mask(~imm_mask) | branch_imm);
|
SetInstructionBits(Mask(~imm_mask) | branch_imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Instruction::SetImmLLiteral(Instruction* source) {
|
void Instruction::SetImmLLiteral(Instruction* source) {
|
||||||
ASSERT(((source - this) & 3) == 0);
|
VIXL_ASSERT(((source - this) & 3) == 0);
|
||||||
int offset = (source - this) >> kLiteralEntrySizeLog2;
|
int offset = (source - this) >> kLiteralEntrySizeLog2;
|
||||||
Instr imm = Assembler::ImmLLiteral(offset);
|
Instr imm = Assembler::ImmLLiteral(offset);
|
||||||
Instr mask = ImmLLiteral_mask;
|
Instr mask = ImmLLiteral_mask;
|
||||||
|
@@ -44,30 +44,36 @@ const unsigned kMaxLoadLiteralRange = 1 * MBytes;
|
|||||||
const unsigned kWRegSize = 32;
|
const unsigned kWRegSize = 32;
|
||||||
const unsigned kWRegSizeLog2 = 5;
|
const unsigned kWRegSizeLog2 = 5;
|
||||||
const unsigned kWRegSizeInBytes = kWRegSize / 8;
|
const unsigned kWRegSizeInBytes = kWRegSize / 8;
|
||||||
|
const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3;
|
||||||
const unsigned kXRegSize = 64;
|
const unsigned kXRegSize = 64;
|
||||||
const unsigned kXRegSizeLog2 = 6;
|
const unsigned kXRegSizeLog2 = 6;
|
||||||
const unsigned kXRegSizeInBytes = kXRegSize / 8;
|
const unsigned kXRegSizeInBytes = kXRegSize / 8;
|
||||||
|
const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3;
|
||||||
const unsigned kSRegSize = 32;
|
const unsigned kSRegSize = 32;
|
||||||
const unsigned kSRegSizeLog2 = 5;
|
const unsigned kSRegSizeLog2 = 5;
|
||||||
const unsigned kSRegSizeInBytes = kSRegSize / 8;
|
const unsigned kSRegSizeInBytes = kSRegSize / 8;
|
||||||
|
const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3;
|
||||||
const unsigned kDRegSize = 64;
|
const unsigned kDRegSize = 64;
|
||||||
const unsigned kDRegSizeLog2 = 6;
|
const unsigned kDRegSizeLog2 = 6;
|
||||||
const unsigned kDRegSizeInBytes = kDRegSize / 8;
|
const unsigned kDRegSizeInBytes = kDRegSize / 8;
|
||||||
const int64_t kWRegMask = 0x00000000ffffffffLL;
|
const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3;
|
||||||
const int64_t kXRegMask = 0xffffffffffffffffLL;
|
const uint64_t kWRegMask = UINT64_C(0xffffffff);
|
||||||
const int64_t kSRegMask = 0x00000000ffffffffLL;
|
const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff);
|
||||||
const int64_t kDRegMask = 0xffffffffffffffffLL;
|
const uint64_t kSRegMask = UINT64_C(0xffffffff);
|
||||||
const int64_t kXSignMask = 0x1LL << 63;
|
const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff);
|
||||||
const int64_t kWSignMask = 0x1LL << 31;
|
const uint64_t kSSignMask = UINT64_C(0x80000000);
|
||||||
const int64_t kByteMask = 0xffL;
|
const uint64_t kDSignMask = UINT64_C(0x8000000000000000);
|
||||||
const int64_t kHalfWordMask = 0xffffL;
|
const uint64_t kWSignMask = UINT64_C(0x80000000);
|
||||||
const int64_t kWordMask = 0xffffffffLL;
|
const uint64_t kXSignMask = UINT64_C(0x8000000000000000);
|
||||||
const uint64_t kXMaxUInt = 0xffffffffffffffffULL;
|
const uint64_t kByteMask = UINT64_C(0xff);
|
||||||
const uint64_t kWMaxUInt = 0xffffffffULL;
|
const uint64_t kHalfWordMask = UINT64_C(0xffff);
|
||||||
const int64_t kXMaxInt = 0x7fffffffffffffffLL;
|
const uint64_t kWordMask = UINT64_C(0xffffffff);
|
||||||
const int64_t kXMinInt = 0x8000000000000000LL;
|
const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff);
|
||||||
const int32_t kWMaxInt = 0x7fffffff;
|
const uint64_t kWMaxUInt = UINT64_C(0xffffffff);
|
||||||
const int32_t kWMinInt = 0x80000000;
|
const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff);
|
||||||
|
const int64_t kXMinInt = INT64_C(0x8000000000000000);
|
||||||
|
const int32_t kWMaxInt = INT32_C(0x7fffffff);
|
||||||
|
const int32_t kWMinInt = INT32_C(0x80000000);
|
||||||
const unsigned kLinkRegCode = 30;
|
const unsigned kLinkRegCode = 30;
|
||||||
const unsigned kZeroRegCode = 31;
|
const unsigned kZeroRegCode = 31;
|
||||||
const unsigned kSPRegInternalCode = 63;
|
const unsigned kSPRegInternalCode = 63;
|
||||||
@@ -81,18 +87,28 @@ const unsigned kFloatExponentBits = 8;
|
|||||||
|
|
||||||
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
|
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
|
||||||
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
|
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
|
||||||
const double kFP64PositiveInfinity = rawbits_to_double(0x7ff0000000000000ULL);
|
const double kFP64PositiveInfinity =
|
||||||
const double kFP64NegativeInfinity = rawbits_to_double(0xfff0000000000000ULL);
|
rawbits_to_double(UINT64_C(0x7ff0000000000000));
|
||||||
|
const double kFP64NegativeInfinity =
|
||||||
|
rawbits_to_double(UINT64_C(0xfff0000000000000));
|
||||||
|
|
||||||
// This value is a signalling NaN as both a double and as a float (taking the
|
// This value is a signalling NaN as both a double and as a float (taking the
|
||||||
// least-significant word).
|
// least-significant word).
|
||||||
static const double kFP64SignallingNaN = rawbits_to_double(0x7ff000007f800001ULL);
|
static const double kFP64SignallingNaN =
|
||||||
|
rawbits_to_double(UINT64_C(0x7ff000007f800001));
|
||||||
static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
|
static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
|
||||||
|
|
||||||
// A similar value, but as a quiet NaN.
|
// A similar value, but as a quiet NaN.
|
||||||
static const double kFP64QuietNaN = rawbits_to_double(0x7ff800007fc00001ULL);
|
static const double kFP64QuietNaN =
|
||||||
|
rawbits_to_double(UINT64_C(0x7ff800007fc00001));
|
||||||
static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
|
static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
|
||||||
|
|
||||||
|
// The default NaN values (for FPCR.DN=1).
|
||||||
|
static const double kFP64DefaultNaN =
|
||||||
|
rawbits_to_double(UINT64_C(0x7ff8000000000000));
|
||||||
|
static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000);
|
||||||
|
|
||||||
|
|
||||||
enum LSDataSize {
|
enum LSDataSize {
|
||||||
LSByte = 0,
|
LSByte = 0,
|
||||||
LSHalfword = 1,
|
LSHalfword = 1,
|
||||||
@@ -325,7 +341,7 @@ class Instruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline Instruction* InstructionAtOffset(int64_t offset) {
|
inline Instruction* InstructionAtOffset(int64_t offset) {
|
||||||
ASSERT(IsWordAligned(this + offset));
|
VIXL_ASSERT(IsWordAligned(this + offset));
|
||||||
return this + offset;
|
return this + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,8 +27,20 @@
|
|||||||
#ifndef VIXL_GLOBALS_H
|
#ifndef VIXL_GLOBALS_H
|
||||||
#define VIXL_GLOBALS_H
|
#define VIXL_GLOBALS_H
|
||||||
|
|
||||||
// Get the standard printf format macros for C99 stdint types.
|
// Get standard C99 macros for integer types.
|
||||||
|
#ifndef __STDC_CONSTANT_MACROS
|
||||||
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __STDC_LIMIT_MACROS
|
||||||
|
#define __STDC_LIMIT_MACROS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __STDC_FORMAT_MACROS
|
||||||
#define __STDC_FORMAT_MACROS
|
#define __STDC_FORMAT_MACROS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@@ -45,21 +57,29 @@ typedef uint8_t byte;
|
|||||||
const int KBytes = 1024;
|
const int KBytes = 1024;
|
||||||
const int MBytes = 1024 * KBytes;
|
const int MBytes = 1024 * KBytes;
|
||||||
|
|
||||||
#define ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
|
#define VIXL_ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define ASSERT(condition) assert(condition)
|
#define VIXL_ASSERT(condition) assert(condition)
|
||||||
#define CHECK(condition) ASSERT(condition)
|
#define VIXL_CHECK(condition) VIXL_ASSERT(condition)
|
||||||
#define UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); ABORT()
|
#define VIXL_UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); VIXL_ABORT()
|
||||||
#define UNREACHABLE() printf("UNREACHABLE\t"); ABORT()
|
#define VIXL_UNREACHABLE() printf("UNREACHABLE\t"); VIXL_ABORT()
|
||||||
#else
|
#else
|
||||||
#define ASSERT(condition) ((void) 0)
|
#define VIXL_ASSERT(condition) ((void) 0)
|
||||||
#define CHECK(condition) assert(condition)
|
#define VIXL_CHECK(condition) assert(condition)
|
||||||
#define UNIMPLEMENTED() ((void) 0)
|
#define VIXL_UNIMPLEMENTED() ((void) 0)
|
||||||
#define UNREACHABLE() ((void) 0)
|
#define VIXL_UNREACHABLE() ((void) 0)
|
||||||
#endif
|
#endif
|
||||||
|
// This is not as powerful as template based assertions, but it is simple.
|
||||||
|
// It assumes that the descriptions are unique. If this starts being a problem,
|
||||||
|
// we can switch to a different implemention.
|
||||||
|
#define VIXL_CONCAT(a, b) a##b
|
||||||
|
#define VIXL_STATIC_ASSERT_LINE(line, condition) \
|
||||||
|
typedef char VIXL_CONCAT(STATIC_ASSERT_LINE_, line)[(condition) ? 1 : -1] \
|
||||||
|
__attribute__((unused))
|
||||||
|
#define VIXL_STATIC_ASSERT(condition) VIXL_STATIC_ASSERT_LINE(__LINE__, condition) //NOLINT
|
||||||
|
|
||||||
template <typename T> inline void USE(T) {}
|
template <typename T> inline void USE(T) {}
|
||||||
|
|
||||||
#define ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); ABORT()
|
#define VIXL_ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); VIXL_ABORT()
|
||||||
|
|
||||||
#endif // VIXL_GLOBALS_H
|
#endif // VIXL_GLOBALS_H
|
||||||
|
@@ -34,9 +34,7 @@ namespace vixl {
|
|||||||
// Currently we assume running the simulator implies running on x86 hardware.
|
// Currently we assume running the simulator implies running on x86 hardware.
|
||||||
inline void HostBreakpoint() { asm("int3"); }
|
inline void HostBreakpoint() { asm("int3"); }
|
||||||
#else
|
#else
|
||||||
inline void HostBreakpoint() {
|
inline void HostBreakpoint() { asm("brk"); }
|
||||||
// TODO: Implement HostBreakpoint on a64.
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
} // namespace vixl
|
} // namespace vixl
|
||||||
|
|
||||||
|
@@ -58,9 +58,9 @@ double rawbits_to_double(uint64_t bits) {
|
|||||||
|
|
||||||
|
|
||||||
int CountLeadingZeros(uint64_t value, int width) {
|
int CountLeadingZeros(uint64_t value, int width) {
|
||||||
ASSERT((width == 32) || (width == 64));
|
VIXL_ASSERT((width == 32) || (width == 64));
|
||||||
int count = 0;
|
int count = 0;
|
||||||
uint64_t bit_test = 1UL << (width - 1);
|
uint64_t bit_test = UINT64_C(1) << (width - 1);
|
||||||
while ((count < width) && ((bit_test & value) == 0)) {
|
while ((count < width) && ((bit_test & value) == 0)) {
|
||||||
count++;
|
count++;
|
||||||
bit_test >>= 1;
|
bit_test >>= 1;
|
||||||
@@ -70,7 +70,7 @@ int CountLeadingZeros(uint64_t value, int width) {
|
|||||||
|
|
||||||
|
|
||||||
int CountLeadingSignBits(int64_t value, int width) {
|
int CountLeadingSignBits(int64_t value, int width) {
|
||||||
ASSERT((width == 32) || (width == 64));
|
VIXL_ASSERT((width == 32) || (width == 64));
|
||||||
if (value >= 0) {
|
if (value >= 0) {
|
||||||
return CountLeadingZeros(value, width) - 1;
|
return CountLeadingZeros(value, width) - 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -80,7 +80,7 @@ int CountLeadingSignBits(int64_t value, int width) {
|
|||||||
|
|
||||||
|
|
||||||
int CountTrailingZeros(uint64_t value, int width) {
|
int CountTrailingZeros(uint64_t value, int width) {
|
||||||
ASSERT((width == 32) || (width == 64));
|
VIXL_ASSERT((width == 32) || (width == 64));
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while ((count < width) && (((value >> count) & 1) == 0)) {
|
while ((count < width) && (((value >> count) & 1) == 0)) {
|
||||||
count++;
|
count++;
|
||||||
@@ -92,10 +92,10 @@ int CountTrailingZeros(uint64_t value, int width) {
|
|||||||
int CountSetBits(uint64_t value, int width) {
|
int CountSetBits(uint64_t value, int width) {
|
||||||
// TODO: Other widths could be added here, as the implementation already
|
// TODO: Other widths could be added here, as the implementation already
|
||||||
// supports them.
|
// supports them.
|
||||||
ASSERT((width == 32) || (width == 64));
|
VIXL_ASSERT((width == 32) || (width == 64));
|
||||||
|
|
||||||
// Mask out unused bits to ensure that they are not counted.
|
// Mask out unused bits to ensure that they are not counted.
|
||||||
value &= (0xffffffffffffffffULL >> (64-width));
|
value &= (UINT64_C(0xffffffffffffffff) >> (64-width));
|
||||||
|
|
||||||
// Add up the set bits.
|
// Add up the set bits.
|
||||||
// The algorithm works by adding pairs of bit fields together iteratively,
|
// The algorithm works by adding pairs of bit fields together iteratively,
|
||||||
@@ -108,18 +108,19 @@ int CountSetBits(uint64_t value, int width) {
|
|||||||
// value = h+g+f+e d+c+b+a
|
// value = h+g+f+e d+c+b+a
|
||||||
// \ |
|
// \ |
|
||||||
// value = h+g+f+e+d+c+b+a
|
// value = h+g+f+e+d+c+b+a
|
||||||
value = ((value >> 1) & 0x5555555555555555ULL) +
|
const uint64_t kMasks[] = {
|
||||||
(value & 0x5555555555555555ULL);
|
UINT64_C(0x5555555555555555),
|
||||||
value = ((value >> 2) & 0x3333333333333333ULL) +
|
UINT64_C(0x3333333333333333),
|
||||||
(value & 0x3333333333333333ULL);
|
UINT64_C(0x0f0f0f0f0f0f0f0f),
|
||||||
value = ((value >> 4) & 0x0f0f0f0f0f0f0f0fULL) +
|
UINT64_C(0x00ff00ff00ff00ff),
|
||||||
(value & 0x0f0f0f0f0f0f0f0fULL);
|
UINT64_C(0x0000ffff0000ffff),
|
||||||
value = ((value >> 8) & 0x00ff00ff00ff00ffULL) +
|
UINT64_C(0x00000000ffffffff),
|
||||||
(value & 0x00ff00ff00ff00ffULL);
|
};
|
||||||
value = ((value >> 16) & 0x0000ffff0000ffffULL) +
|
|
||||||
(value & 0x0000ffff0000ffffULL);
|
for (unsigned i = 0; i < (sizeof(kMasks) / sizeof(kMasks[0])); i++) {
|
||||||
value = ((value >> 32) & 0x00000000ffffffffULL) +
|
int shift = 1 << i;
|
||||||
(value & 0x00000000ffffffffULL);
|
value = ((value >> shift) & kMasks[i]) + (value & kMasks[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
#ifndef VIXL_UTILS_H
|
#ifndef VIXL_UTILS_H
|
||||||
#define VIXL_UTILS_H
|
#define VIXL_UTILS_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
@@ -35,19 +35,19 @@ namespace vixl {
|
|||||||
|
|
||||||
// Check number width.
|
// Check number width.
|
||||||
inline bool is_intn(unsigned n, int64_t x) {
|
inline bool is_intn(unsigned n, int64_t x) {
|
||||||
ASSERT((0 < n) && (n < 64));
|
VIXL_ASSERT((0 < n) && (n < 64));
|
||||||
int64_t limit = 1ULL << (n - 1);
|
int64_t limit = INT64_C(1) << (n - 1);
|
||||||
return (-limit <= x) && (x < limit);
|
return (-limit <= x) && (x < limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_uintn(unsigned n, int64_t x) {
|
inline bool is_uintn(unsigned n, int64_t x) {
|
||||||
ASSERT((0 < n) && (n < 64));
|
VIXL_ASSERT((0 < n) && (n < 64));
|
||||||
return !(x >> n);
|
return !(x >> n);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned truncate_to_intn(unsigned n, int64_t x) {
|
inline unsigned truncate_to_intn(unsigned n, int64_t x) {
|
||||||
ASSERT((0 < n) && (n < 64));
|
VIXL_ASSERT((0 < n) && (n < 64));
|
||||||
return (x & ((1ULL << n) - 1));
|
return (x & ((INT64_C(1) << n) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define INT_1_TO_63_LIST(V) \
|
#define INT_1_TO_63_LIST(V) \
|
||||||
@@ -90,13 +90,67 @@ inline int64_t signed_bitextract_64(int msb, int lsb, int64_t x) {
|
|||||||
return (x << (63 - msb)) >> (lsb + 63 - msb);
|
return (x << (63 - msb)) >> (lsb + 63 - msb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// floating point representation
|
// Floating point representation.
|
||||||
uint32_t float_to_rawbits(float value);
|
uint32_t float_to_rawbits(float value);
|
||||||
uint64_t double_to_rawbits(double value);
|
uint64_t double_to_rawbits(double value);
|
||||||
float rawbits_to_float(uint32_t bits);
|
float rawbits_to_float(uint32_t bits);
|
||||||
double rawbits_to_double(uint64_t bits);
|
double rawbits_to_double(uint64_t bits);
|
||||||
|
|
||||||
// Bits counting.
|
|
||||||
|
// NaN tests.
|
||||||
|
inline bool IsSignallingNaN(double num) {
|
||||||
|
const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000);
|
||||||
|
uint64_t raw = double_to_rawbits(num);
|
||||||
|
if (isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool IsSignallingNaN(float num) {
|
||||||
|
const uint32_t kFP32QuietNaNMask = 0x00400000;
|
||||||
|
uint32_t raw = float_to_rawbits(num);
|
||||||
|
if (isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool IsQuietNaN(T num) {
|
||||||
|
return isnan(num) && !IsSignallingNaN(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convert the NaN in 'num' to a quiet NaN.
|
||||||
|
inline double ToQuietNaN(double num) {
|
||||||
|
const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000);
|
||||||
|
VIXL_ASSERT(isnan(num));
|
||||||
|
return rawbits_to_double(double_to_rawbits(num) | kFP64QuietNaNMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline float ToQuietNaN(float num) {
|
||||||
|
const uint32_t kFP32QuietNaNMask = 0x00400000;
|
||||||
|
VIXL_ASSERT(isnan(num));
|
||||||
|
return rawbits_to_float(float_to_rawbits(num) | kFP32QuietNaNMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fused multiply-add.
|
||||||
|
inline double FusedMultiplyAdd(double op1, double op2, double a) {
|
||||||
|
return fma(op1, op2, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline float FusedMultiplyAdd(float op1, float op2, float a) {
|
||||||
|
return fmaf(op1, op2, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Bit counting.
|
||||||
int CountLeadingZeros(uint64_t value, int width);
|
int CountLeadingZeros(uint64_t value, int width);
|
||||||
int CountLeadingSignBits(int64_t value, int width);
|
int CountLeadingSignBits(int64_t value, int width);
|
||||||
int CountTrailingZeros(uint64_t value, int width);
|
int CountTrailingZeros(uint64_t value, int width);
|
||||||
@@ -106,20 +160,30 @@ int CountSetBits(uint64_t value, int width);
|
|||||||
// TODO: rename/refactor to make it specific to instructions.
|
// TODO: rename/refactor to make it specific to instructions.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool IsWordAligned(T pointer) {
|
bool IsWordAligned(T pointer) {
|
||||||
ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
|
VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
|
||||||
return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
|
return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment a pointer until it has the specified alignment.
|
// Increment a pointer until it has the specified alignment.
|
||||||
template<class T>
|
template<class T>
|
||||||
T AlignUp(T pointer, size_t alignment) {
|
T AlignUp(T pointer, size_t alignment) {
|
||||||
ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||||
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
|
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
|
||||||
size_t align_step = (alignment - pointer_raw) % alignment;
|
size_t align_step = (alignment - pointer_raw) % alignment;
|
||||||
ASSERT((pointer_raw + align_step) % alignment == 0);
|
VIXL_ASSERT((pointer_raw + align_step) % alignment == 0);
|
||||||
return reinterpret_cast<T>(pointer_raw + align_step);
|
return reinterpret_cast<T>(pointer_raw + align_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decrement a pointer until it has the specified alignment.
|
||||||
|
template<class T>
|
||||||
|
T AlignDown(T pointer, size_t alignment) {
|
||||||
|
VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||||
|
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
|
||||||
|
size_t align_step = pointer_raw % alignment;
|
||||||
|
VIXL_ASSERT((pointer_raw - align_step) % alignment == 0);
|
||||||
|
return reinterpret_cast<T>(pointer_raw - align_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace vixl
|
} // namespace vixl
|
||||||
|
|
||||||
|
@@ -232,8 +232,8 @@ various constraints can be supplied to control how these callbacks are called:
|
|||||||
(in bytes) supported by the *implementation*; other access sizes will be
|
(in bytes) supported by the *implementation*; other access sizes will be
|
||||||
emulated using the ones available. For example a 4-byte write will be
|
emulated using the ones available. For example a 4-byte write will be
|
||||||
emulated using four 1-byte writes, if .impl.max_access_size = 1.
|
emulated using four 1-byte writes, if .impl.max_access_size = 1.
|
||||||
- .impl.valid specifies that the *implementation* only supports unaligned
|
- .impl.unaligned specifies that the *implementation* supports unaligned
|
||||||
accesses; unaligned accesses will be emulated by two aligned accesses.
|
accesses; if false, unaligned accesses will be emulated by two aligned
|
||||||
- .old_portio and .old_mmio can be used to ease porting from code using
|
accesses.
|
||||||
cpu_register_io_memory() and register_ioport(). They should not be used
|
- .old_mmio can be used to ease porting from code using
|
||||||
in new code.
|
cpu_register_io_memory(). It should not be used in new code.
|
||||||
|
@@ -139,8 +139,7 @@ static const VMStateDescription vmstate_kbd = {
|
|||||||
.name = "pckbd",
|
.name = "pckbd",
|
||||||
.version_id = 3,
|
.version_id = 3,
|
||||||
.minimum_version_id = 3,
|
.minimum_version_id = 3,
|
||||||
.minimum_version_id_old = 3,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_UINT8(write_cmd, KBDState),
|
VMSTATE_UINT8(write_cmd, KBDState),
|
||||||
VMSTATE_UINT8(status, KBDState),
|
VMSTATE_UINT8(status, KBDState),
|
||||||
VMSTATE_UINT8(mode, KBDState),
|
VMSTATE_UINT8(mode, KBDState),
|
||||||
@@ -168,12 +167,13 @@ You can see that there are several version fields:
|
|||||||
- minimum_version_id: the minimum version_id that VMState is able to understand
|
- minimum_version_id: the minimum version_id that VMState is able to understand
|
||||||
for that device.
|
for that device.
|
||||||
- minimum_version_id_old: For devices that were not able to port to vmstate, we can
|
- minimum_version_id_old: For devices that were not able to port to vmstate, we can
|
||||||
assign a function that knows how to read this old state.
|
assign a function that knows how to read this old state. This field is
|
||||||
|
ignored if there is no load_state_old handler.
|
||||||
|
|
||||||
So, VMState is able to read versions from minimum_version_id to
|
So, VMState is able to read versions from minimum_version_id to
|
||||||
version_id. And the function load_state_old() is able to load state
|
version_id. And the function load_state_old() (if present) is able to
|
||||||
from minimum_version_id_old to minimum_version_id. This function is
|
load state from minimum_version_id_old to minimum_version_id. This
|
||||||
deprecated and will be removed when no more users are left.
|
function is deprecated and will be removed when no more users are left.
|
||||||
|
|
||||||
=== Massaging functions ===
|
=== Massaging functions ===
|
||||||
|
|
||||||
@@ -255,10 +255,9 @@ const VMStateDescription vmstate_ide_drive_pio_state = {
|
|||||||
.name = "ide_drive/pio_state",
|
.name = "ide_drive/pio_state",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.pre_save = ide_drive_pio_pre_save,
|
.pre_save = ide_drive_pio_pre_save,
|
||||||
.post_load = ide_drive_pio_post_load,
|
.post_load = ide_drive_pio_post_load,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_INT32(req_nb_sectors, IDEState),
|
VMSTATE_INT32(req_nb_sectors, IDEState),
|
||||||
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
|
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
|
||||||
vmstate_info_uint8, uint8_t),
|
vmstate_info_uint8, uint8_t),
|
||||||
@@ -275,9 +274,8 @@ const VMStateDescription vmstate_ide_drive = {
|
|||||||
.name = "ide_drive",
|
.name = "ide_drive",
|
||||||
.version_id = 3,
|
.version_id = 3,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.post_load = ide_drive_post_load,
|
.post_load = ide_drive_post_load,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField[]) {
|
||||||
.... several fields ....
|
.... several fields ....
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
|
@@ -40,6 +40,17 @@ enumeration types and union types.
|
|||||||
Generally speaking, types definitions should always use CamelCase for the type
|
Generally speaking, types definitions should always use CamelCase for the type
|
||||||
names. Command names should be all lower case with words separated by a hyphen.
|
names. Command names should be all lower case with words separated by a hyphen.
|
||||||
|
|
||||||
|
|
||||||
|
=== Includes ===
|
||||||
|
|
||||||
|
The QAPI schema definitions can be modularized using the 'include' directive:
|
||||||
|
|
||||||
|
{ 'include': 'path/to/file.json'}
|
||||||
|
|
||||||
|
The directive is evaluated recursively, and include paths are relative to the
|
||||||
|
file using the directive. Multiple includes of the same file are safe.
|
||||||
|
|
||||||
|
|
||||||
=== Complex types ===
|
=== Complex types ===
|
||||||
|
|
||||||
A complex type is a dictionary containing a single key whose value is a
|
A complex type is a dictionary containing a single key whose value is a
|
||||||
@@ -49,10 +60,34 @@ example of a complex type is:
|
|||||||
{ 'type': 'MyType',
|
{ 'type': 'MyType',
|
||||||
'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
|
'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
|
||||||
|
|
||||||
The use of '*' as a prefix to the name means the member is optional. Optional
|
The use of '*' as a prefix to the name means the member is optional.
|
||||||
members should always be added to the end of the dictionary to preserve
|
|
||||||
backwards compatibility.
|
|
||||||
|
|
||||||
|
The default initialization value of an optional argument should not be changed
|
||||||
|
between versions of QEMU unless the new default maintains backward
|
||||||
|
compatibility to the user-visible behavior of the old default.
|
||||||
|
|
||||||
|
With proper documentation, this policy still allows some flexibility; for
|
||||||
|
example, documenting that a default of 0 picks an optimal buffer size allows
|
||||||
|
one release to declare the optimal size at 512 while another release declares
|
||||||
|
the optimal size at 4096 - the user-visible behavior is not the bytes used by
|
||||||
|
the buffer, but the fact that the buffer was optimal size.
|
||||||
|
|
||||||
|
On input structures (only mentioned in the 'data' side of a command), changing
|
||||||
|
from mandatory to optional is safe (older clients will supply the option, and
|
||||||
|
newer clients can benefit from the default); changing from optional to
|
||||||
|
mandatory is backwards incompatible (older clients may be omitting the option,
|
||||||
|
and must continue to work).
|
||||||
|
|
||||||
|
On output structures (only mentioned in the 'returns' side of a command),
|
||||||
|
changing from mandatory to optional is in general unsafe (older clients may be
|
||||||
|
expecting the field, and could crash if it is missing), although it can be done
|
||||||
|
if the only way that the optional argument will be omitted is when it is
|
||||||
|
triggered by the presence of a new input flag to the command that older clients
|
||||||
|
don't know to send. Changing from optional to mandatory is safe.
|
||||||
|
|
||||||
|
A structure that is used in both input and output of various commands
|
||||||
|
must consider the backwards compatibility constraints of both directions
|
||||||
|
of use.
|
||||||
|
|
||||||
A complex type definition can specify another complex type as its base.
|
A complex type definition can specify another complex type as its base.
|
||||||
In this case, the fields of the base type are included as top-level fields
|
In this case, the fields of the base type are included as top-level fields
|
||||||
@@ -195,14 +230,13 @@ node structure that can be used to chain together a list of such types in
|
|||||||
case we want to accept/return a list of this type with a command), and a
|
case we want to accept/return a list of this type with a command), and a
|
||||||
command which takes that type as a parameter and returns the same type:
|
command which takes that type as a parameter and returns the same type:
|
||||||
|
|
||||||
mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
|
$ cat example-schema.json
|
||||||
{ 'type': 'UserDefOne',
|
{ 'type': 'UserDefOne',
|
||||||
'data': { 'integer': 'int', 'string': 'str' } }
|
'data': { 'integer': 'int', 'string': 'str' } }
|
||||||
|
|
||||||
{ 'command': 'my-command',
|
{ 'command': 'my-command',
|
||||||
'data': {'arg1': 'UserDefOne'},
|
'data': {'arg1': 'UserDefOne'},
|
||||||
'returns': 'UserDefOne' }
|
'returns': 'UserDefOne' }
|
||||||
mdroth@illuin:~/w/qemu2.git$
|
|
||||||
|
|
||||||
=== scripts/qapi-types.py ===
|
=== scripts/qapi-types.py ===
|
||||||
|
|
||||||
@@ -220,14 +254,25 @@ created code.
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
|
$ python scripts/qapi-types.py --output-dir="qapi-generated" \
|
||||||
--output-dir="qapi-generated" --prefix="example-" < example-schema.json
|
--prefix="example-" --input-file=example-schema.json
|
||||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
|
$ cat qapi-generated/example-qapi-types.c
|
||||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
#include "qapi/qapi-dealloc-visitor.h"
|
void qapi_free_UserDefOneList(UserDefOneList * obj)
|
||||||
#include "example-qapi-types.h"
|
{
|
||||||
#include "example-qapi-visit.h"
|
QapiDeallocVisitor *md;
|
||||||
|
Visitor *v;
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
md = qapi_dealloc_visitor_new();
|
||||||
|
v = qapi_dealloc_get_visitor(md);
|
||||||
|
visit_type_UserDefOneList(v, &obj, NULL, NULL);
|
||||||
|
qapi_dealloc_visitor_cleanup(md);
|
||||||
|
}
|
||||||
|
|
||||||
void qapi_free_UserDefOne(UserDefOne * obj)
|
void qapi_free_UserDefOne(UserDefOne * obj)
|
||||||
{
|
{
|
||||||
@@ -244,32 +289,38 @@ Example:
|
|||||||
qapi_dealloc_visitor_cleanup(md);
|
qapi_dealloc_visitor_cleanup(md);
|
||||||
}
|
}
|
||||||
|
|
||||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
|
$ cat qapi-generated/example-qapi-types.h
|
||||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
[Uninteresting stuff omitted...]
|
||||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
|
||||||
#define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
|
||||||
|
|
||||||
#include "qapi/qapi-types-core.h"
|
#ifndef EXAMPLE_QAPI_TYPES_H
|
||||||
|
#define EXAMPLE_QAPI_TYPES_H
|
||||||
|
|
||||||
|
[Builtin types omitted...]
|
||||||
|
|
||||||
typedef struct UserDefOne UserDefOne;
|
typedef struct UserDefOne UserDefOne;
|
||||||
|
|
||||||
typedef struct UserDefOneList
|
typedef struct UserDefOneList
|
||||||
{
|
{
|
||||||
UserDefOne *value;
|
union {
|
||||||
|
UserDefOne *value;
|
||||||
|
uint64_t padding;
|
||||||
|
};
|
||||||
struct UserDefOneList *next;
|
struct UserDefOneList *next;
|
||||||
} UserDefOneList;
|
} UserDefOneList;
|
||||||
|
|
||||||
|
[Functions on builtin types omitted...]
|
||||||
|
|
||||||
struct UserDefOne
|
struct UserDefOne
|
||||||
{
|
{
|
||||||
int64_t integer;
|
int64_t integer;
|
||||||
char * string;
|
char * string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void qapi_free_UserDefOneList(UserDefOneList * obj);
|
||||||
void qapi_free_UserDefOne(UserDefOne * obj);
|
void qapi_free_UserDefOne(UserDefOne * obj);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
=== scripts/qapi-visit.py ===
|
=== scripts/qapi-visit.py ===
|
||||||
|
|
||||||
Used to generate the visitor functions used to walk through and convert
|
Used to generate the visitor functions used to walk through and convert
|
||||||
@@ -290,51 +341,78 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
|
$ python scripts/qapi-visit.py --output-dir="qapi-generated"
|
||||||
--output-dir="qapi-generated" --prefix="example-" < example-schema.json
|
--prefix="example-" --input-file=example-schema.json
|
||||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
|
$ cat qapi-generated/example-qapi-visit.c
|
||||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
#include "example-qapi-visit.h"
|
static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
visit_type_int(m, &(*obj)->integer, "integer", &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
visit_type_str(m, &(*obj)->string, "string", &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
error_propagate(errp, err);
|
||||||
|
}
|
||||||
|
|
||||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
|
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
|
Error *err = NULL;
|
||||||
visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
|
|
||||||
visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
|
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err);
|
||||||
visit_end_struct(m, errp);
|
if (!err) {
|
||||||
|
if (*obj) {
|
||||||
|
visit_type_UserDefOne_fields(m, obj, errp);
|
||||||
|
}
|
||||||
|
visit_end_struct(m, &err);
|
||||||
|
}
|
||||||
|
error_propagate(errp, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
|
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
GenericList *i, **prev = (GenericList **)obj;
|
Error *err = NULL;
|
||||||
|
GenericList *i, **prev;
|
||||||
|
|
||||||
visit_start_list(m, name, errp);
|
visit_start_list(m, name, &err);
|
||||||
|
if (err) {
|
||||||
for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
|
goto out;
|
||||||
UserDefOneList *native_i = (UserDefOneList *)i;
|
|
||||||
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_end_list(m, errp);
|
for (prev = (GenericList **)obj;
|
||||||
|
!err && (i = visit_next_list(m, prev, &err)) != NULL;
|
||||||
|
prev = &i) {
|
||||||
|
UserDefOneList *native_i = (UserDefOneList *)i;
|
||||||
|
visit_type_UserDefOne(m, &native_i->value, NULL, &err);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_propagate(errp, err);
|
||||||
|
err = NULL;
|
||||||
|
visit_end_list(m, &err);
|
||||||
|
out:
|
||||||
|
error_propagate(errp, err);
|
||||||
}
|
}
|
||||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
|
$ python scripts/qapi-commands.py --output-dir="qapi-generated" \
|
||||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
--prefix="example-" --input-file=example-schema.json
|
||||||
|
$ cat qapi-generated/example-qapi-visit.h
|
||||||
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
#ifndef EXAMPLE_QAPI_VISIT_H
|
||||||
#define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
#define EXAMPLE_QAPI_VISIT_H
|
||||||
|
|
||||||
#include "qapi/qapi-visit-core.h"
|
[Visitors for builtin types omitted...]
|
||||||
#include "example-qapi-types.h"
|
|
||||||
|
|
||||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
|
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
|
||||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
|
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
mdroth@illuin:~/w/qemu2.git$
|
|
||||||
|
|
||||||
(The actual structure of the visit_type_* functions is a bit more complex
|
|
||||||
in order to propagate errors correctly and avoid leaking memory).
|
|
||||||
|
|
||||||
=== scripts/qapi-commands.py ===
|
=== scripts/qapi-commands.py ===
|
||||||
|
|
||||||
@@ -355,77 +433,80 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
|
$ cat qapi-generated/example-qmp-marshal.c
|
||||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
#include "qemu-objects.h"
|
|
||||||
#include "qapi/qmp-core.h"
|
|
||||||
#include "qapi/qapi-visit-core.h"
|
|
||||||
#include "qapi/qmp-output-visitor.h"
|
|
||||||
#include "qapi/qmp-input-visitor.h"
|
|
||||||
#include "qapi/qapi-dealloc-visitor.h"
|
|
||||||
#include "example-qapi-types.h"
|
|
||||||
#include "example-qapi-visit.h"
|
|
||||||
|
|
||||||
#include "example-qmp-commands.h"
|
|
||||||
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
|
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
|
||||||
{
|
{
|
||||||
QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
|
Error *local_err = NULL;
|
||||||
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
||||||
|
QapiDeallocVisitor *md;
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
|
|
||||||
v = qmp_output_get_visitor(mo);
|
v = qmp_output_get_visitor(mo);
|
||||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
visit_type_UserDefOne(v, &ret_in, "unused", &local_err);
|
||||||
v = qapi_dealloc_get_visitor(md);
|
if (local_err) {
|
||||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
goto out;
|
||||||
qapi_dealloc_visitor_cleanup(md);
|
}
|
||||||
|
|
||||||
|
|
||||||
*ret_out = qmp_output_get_qobject(mo);
|
*ret_out = qmp_output_get_qobject(mo);
|
||||||
|
|
||||||
|
out:
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
qmp_output_visitor_cleanup(mo);
|
||||||
|
md = qapi_dealloc_visitor_new();
|
||||||
|
v = qapi_dealloc_get_visitor(md);
|
||||||
|
visit_type_UserDefOne(v, &ret_in, "unused", NULL);
|
||||||
|
qapi_dealloc_visitor_cleanup(md);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
|
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
UserDefOne * retval = NULL;
|
UserDefOne * retval = NULL;
|
||||||
QmpInputVisitor *mi;
|
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
|
||||||
QapiDeallocVisitor *md;
|
QapiDeallocVisitor *md;
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
UserDefOne * arg1 = NULL;
|
UserDefOne * arg1 = NULL;
|
||||||
|
|
||||||
mi = qmp_input_visitor_new(QOBJECT(args));
|
|
||||||
v = qmp_input_get_visitor(mi);
|
v = qmp_input_get_visitor(mi);
|
||||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
|
||||||
|
if (local_err) {
|
||||||
if (error_is_set(errp)) {
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
retval = qmp_my_command(arg1, errp);
|
|
||||||
qmp_marshal_output_my_command(retval, ret, errp);
|
retval = qmp_my_command(arg1, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmp_marshal_output_my_command(retval, ret, &local_err);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
qmp_input_visitor_cleanup(mi);
|
||||||
md = qapi_dealloc_visitor_new();
|
md = qapi_dealloc_visitor_new();
|
||||||
v = qapi_dealloc_get_visitor(md);
|
v = qapi_dealloc_get_visitor(md);
|
||||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
visit_type_UserDefOne(v, &arg1, "arg1", NULL);
|
||||||
qapi_dealloc_visitor_cleanup(md);
|
qapi_dealloc_visitor_cleanup(md);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qmp_init_marshal(void)
|
static void qmp_init_marshal(void)
|
||||||
{
|
{
|
||||||
qmp_register_command("my-command", qmp_marshal_input_my_command);
|
qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
qapi_init(qmp_init_marshal);
|
qapi_init(qmp_init_marshal);
|
||||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
|
$ cat qapi-generated/example-qmp-commands.h
|
||||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
#ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
#ifndef EXAMPLE_QMP_COMMANDS_H
|
||||||
#define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
#define EXAMPLE_QMP_COMMANDS_H
|
||||||
|
|
||||||
#include "example-qapi-types.h"
|
#include "example-qapi-types.h"
|
||||||
#include "error.h"
|
#include "qapi/qmp/qdict.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
|
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
mdroth@illuin:~/w/qemu2.git$
|
|
||||||
|
@@ -5,9 +5,10 @@ QEMU Standard VGA
|
|||||||
Exists in two variants, for isa and pci.
|
Exists in two variants, for isa and pci.
|
||||||
|
|
||||||
command line switches:
|
command line switches:
|
||||||
-vga std [ picks isa for -M isapc, otherwise pci ]
|
-vga std [ picks isa for -M isapc, otherwise pci ]
|
||||||
-device VGA [ pci variant ]
|
-device VGA [ pci variant ]
|
||||||
-device isa-vga [ isa variant ]
|
-device isa-vga [ isa variant ]
|
||||||
|
-device secondary-vga [ legacy-free pci variant ]
|
||||||
|
|
||||||
|
|
||||||
PCI spec
|
PCI spec
|
||||||
@@ -31,9 +32,15 @@ PCI ROM Region:
|
|||||||
Holds the vgabios (qemu 0.14+).
|
Holds the vgabios (qemu 0.14+).
|
||||||
|
|
||||||
|
|
||||||
|
The legacy-free variant has no ROM and has PCI_CLASS_DISPLAY_OTHER
|
||||||
|
instead of PCI_CLASS_DISPLAY_VGA.
|
||||||
|
|
||||||
|
|
||||||
IO ports used
|
IO ports used
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
Doesn't apply to the legacy-free pci variant, use the MMIO bar instead.
|
||||||
|
|
||||||
03c0 - 03df : standard vga ports
|
03c0 - 03df : standard vga ports
|
||||||
01ce : bochs vbe interface index port
|
01ce : bochs vbe interface index port
|
||||||
01cf : bochs vbe interface data port (x86 only)
|
01cf : bochs vbe interface data port (x86 only)
|
||||||
|
@@ -308,12 +308,12 @@ Here's the implementation of the "hello-world" HMP command:
|
|||||||
void hmp_hello_world(Monitor *mon, const QDict *qdict)
|
void hmp_hello_world(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *message = qdict_get_try_str(qdict, "message");
|
const char *message = qdict_get_try_str(qdict, "message");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_hello_world(!!message, message, &errp);
|
qmp_hello_world(!!message, message, &err);
|
||||||
if (error_is_set(&errp)) {
|
if (err) {
|
||||||
monitor_printf(mon, "%s\n", error_get_pretty(errp));
|
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
||||||
error_free(errp);
|
error_free(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,7 +328,7 @@ There are three important points to be noticed:
|
|||||||
2. hmp_hello_world() performs error checking. In this example we just print
|
2. hmp_hello_world() performs error checking. In this example we just print
|
||||||
the error description to the user, but we could do more, like taking
|
the error description to the user, but we could do more, like taking
|
||||||
different actions depending on the error qmp_hello_world() returns
|
different actions depending on the error qmp_hello_world() returns
|
||||||
3. The "errp" variable must be initialized to NULL before performing the
|
3. The "err" variable must be initialized to NULL before performing the
|
||||||
QMP call
|
QMP call
|
||||||
|
|
||||||
There's one last step to actually make the command available to monitor users,
|
There's one last step to actually make the command available to monitor users,
|
||||||
@@ -480,12 +480,12 @@ Here's the HMP counterpart of the query-alarm-clock command:
|
|||||||
void hmp_info_alarm_clock(Monitor *mon)
|
void hmp_info_alarm_clock(Monitor *mon)
|
||||||
{
|
{
|
||||||
QemuAlarmClock *clock;
|
QemuAlarmClock *clock;
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
clock = qmp_query_alarm_clock(&errp);
|
clock = qmp_query_alarm_clock(&err);
|
||||||
if (error_is_set(&errp)) {
|
if (err) {
|
||||||
monitor_printf(mon, "Could not query alarm clock information\n");
|
monitor_printf(mon, "Could not query alarm clock information\n");
|
||||||
error_free(errp);
|
error_free(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,12 +631,12 @@ has to traverse the list, it's shown below for reference:
|
|||||||
void hmp_info_alarm_methods(Monitor *mon)
|
void hmp_info_alarm_methods(Monitor *mon)
|
||||||
{
|
{
|
||||||
TimerAlarmMethodList *method_list, *method;
|
TimerAlarmMethodList *method_list, *method;
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
method_list = qmp_query_alarm_methods(&errp);
|
method_list = qmp_query_alarm_methods(&err);
|
||||||
if (error_is_set(&errp)) {
|
if (err) {
|
||||||
monitor_printf(mon, "Could not query alarm methods\n");
|
monitor_printf(mon, "Could not query alarm methods\n");
|
||||||
error_free(errp);
|
error_free(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
dump.c
6
dump.c
@@ -86,7 +86,6 @@ typedef struct DumpState {
|
|||||||
bool has_filter;
|
bool has_filter;
|
||||||
int64_t begin;
|
int64_t begin;
|
||||||
int64_t length;
|
int64_t length;
|
||||||
Error **errp;
|
|
||||||
|
|
||||||
uint8_t *note_buf; /* buffer for notes */
|
uint8_t *note_buf; /* buffer for notes */
|
||||||
size_t note_buf_offset; /* the writing place in note_buf */
|
size_t note_buf_offset; /* the writing place in note_buf */
|
||||||
@@ -1570,7 +1569,6 @@ static int dump_init(DumpState *s, int fd, bool has_format,
|
|||||||
nr_cpus++;
|
nr_cpus++;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->errp = errp;
|
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
s->has_filter = has_filter;
|
s->has_filter = has_filter;
|
||||||
s->begin = begin;
|
s->begin = begin;
|
||||||
@@ -1780,11 +1778,11 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
|
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
|
||||||
if (create_kdump_vmcore(s) < 0 && !error_is_set(s->errp)) {
|
if (create_kdump_vmcore(s) < 0) {
|
||||||
error_set(errp, QERR_IO_ERROR);
|
error_set(errp, QERR_IO_ERROR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (create_vmcore(s) < 0 && !error_is_set(s->errp)) {
|
if (create_vmcore(s) < 0) {
|
||||||
error_set(errp, QERR_IO_ERROR);
|
error_set(errp, QERR_IO_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
exec.c
5
exec.c
@@ -380,7 +380,7 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
|||||||
as = iotlb.target_as;
|
as = iotlb.target_as;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memory_access_is_direct(mr, is_write)) {
|
if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
|
||||||
hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
|
hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
|
||||||
len = MIN(page, len);
|
len = MIN(page, len);
|
||||||
}
|
}
|
||||||
@@ -429,9 +429,8 @@ const VMStateDescription vmstate_cpu_common = {
|
|||||||
.name = "cpu_common",
|
.name = "cpu_common",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.post_load = cpu_common_post_load,
|
.post_load = cpu_common_post_load,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(halted, CPUState),
|
VMSTATE_UINT32(halted, CPUState),
|
||||||
VMSTATE_UINT32(interrupt_request, CPUState),
|
VMSTATE_UINT32(interrupt_request, CPUState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
@@ -760,6 +760,7 @@ static int proxy_socket(const char *path, uid_t uid, gid_t gid)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size = sizeof(qemu);
|
||||||
client = accept(sock, (struct sockaddr *)&qemu, &size);
|
client = accept(sock, (struct sockaddr *)&qemu, &size);
|
||||||
if (client < 0) {
|
if (client < 0) {
|
||||||
do_perror("accept");
|
do_perror("accept");
|
||||||
|
@@ -176,7 +176,7 @@ ETEXI
|
|||||||
|
|
||||||
{
|
{
|
||||||
.name = "drive_del",
|
.name = "drive_del",
|
||||||
.args_type = "id:s",
|
.args_type = "id:B",
|
||||||
.params = "device",
|
.params = "device",
|
||||||
.help = "remove host block device",
|
.help = "remove host block device",
|
||||||
.user_print = monitor_user_noop,
|
.user_print = monitor_user_noop,
|
||||||
@@ -556,6 +556,7 @@ ETEXI
|
|||||||
.params = "keys [hold_ms]",
|
.params = "keys [hold_ms]",
|
||||||
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
|
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
|
||||||
.mhandler.cmd = hmp_send_key,
|
.mhandler.cmd = hmp_send_key,
|
||||||
|
.command_completion = sendkey_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -658,6 +659,7 @@ ETEXI
|
|||||||
.help = "add device, like -device on the command line",
|
.help = "add device, like -device on the command line",
|
||||||
.user_print = monitor_user_noop,
|
.user_print = monitor_user_noop,
|
||||||
.mhandler.cmd_new = do_device_add,
|
.mhandler.cmd_new = do_device_add,
|
||||||
|
.command_completion = device_add_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -673,6 +675,7 @@ ETEXI
|
|||||||
.params = "device",
|
.params = "device",
|
||||||
.help = "remove device",
|
.help = "remove device",
|
||||||
.mhandler.cmd = hmp_device_del,
|
.mhandler.cmd = hmp_device_del,
|
||||||
|
.command_completion = device_del_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -998,26 +1001,34 @@ ETEXI
|
|||||||
|
|
||||||
{
|
{
|
||||||
.name = "dump-guest-memory",
|
.name = "dump-guest-memory",
|
||||||
.args_type = "paging:-p,filename:F,begin:i?,length:i?",
|
.args_type = "paging:-p,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?",
|
||||||
.params = "[-p] filename [begin] [length]",
|
.params = "[-p] [-z|-l|-s] filename [begin length]",
|
||||||
.help = "dump guest memory to file"
|
.help = "dump guest memory into file 'filename'.\n\t\t\t"
|
||||||
"\n\t\t\t begin(optional): the starting physical address"
|
"-p: do paging to get guest's memory mapping.\n\t\t\t"
|
||||||
"\n\t\t\t length(optional): the memory size, in bytes",
|
"-z: dump in kdump-compressed format, with zlib compression.\n\t\t\t"
|
||||||
|
"-l: dump in kdump-compressed format, with lzo compression.\n\t\t\t"
|
||||||
|
"-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t"
|
||||||
|
"begin: the starting physical address.\n\t\t\t"
|
||||||
|
"length: the memory size, in bytes.",
|
||||||
.mhandler.cmd = hmp_dump_guest_memory,
|
.mhandler.cmd = hmp_dump_guest_memory,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@item dump-guest-memory [-p] @var{protocol} @var{begin} @var{length}
|
@item dump-guest-memory [-p] @var{filename} @var{begin} @var{length}
|
||||||
|
@item dump-guest-memory [-z|-l|-s] @var{filename}
|
||||||
@findex dump-guest-memory
|
@findex dump-guest-memory
|
||||||
Dump guest memory to @var{protocol}. The file can be processed with crash or
|
Dump guest memory to @var{protocol}. The file can be processed with crash or
|
||||||
gdb.
|
gdb. Without -z|-l|-s, the dump format is ELF.
|
||||||
filename: dump file name
|
-p: do paging to get guest's memory mapping.
|
||||||
paging: do paging to get guest's memory mapping
|
-z: dump in kdump-compressed format, with zlib compression.
|
||||||
|
-l: dump in kdump-compressed format, with lzo compression.
|
||||||
|
-s: dump in kdump-compressed format, with snappy compression.
|
||||||
|
filename: dump file name.
|
||||||
begin: the starting physical address. It's optional, and should be
|
begin: the starting physical address. It's optional, and should be
|
||||||
specified with length together.
|
specified together with length.
|
||||||
length: the memory size, in bytes. It's optional, and should be specified
|
length: the memory size, in bytes. It's optional, and should be specified
|
||||||
with begin together.
|
together with begin.
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1223,9 +1234,10 @@ ETEXI
|
|||||||
{
|
{
|
||||||
.name = "netdev_add",
|
.name = "netdev_add",
|
||||||
.args_type = "netdev:O",
|
.args_type = "netdev:O",
|
||||||
.params = "[user|tap|socket|hubport|netmap],id=str[,prop=value][,...]",
|
.params = "[user|tap|socket|vde|bridge|hubport|netmap],id=str[,prop=value][,...]",
|
||||||
.help = "add host network device",
|
.help = "add host network device",
|
||||||
.mhandler.cmd = hmp_netdev_add,
|
.mhandler.cmd = hmp_netdev_add,
|
||||||
|
.command_completion = netdev_add_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -1240,6 +1252,7 @@ ETEXI
|
|||||||
.params = "id",
|
.params = "id",
|
||||||
.help = "remove host network device",
|
.help = "remove host network device",
|
||||||
.mhandler.cmd = hmp_netdev_del,
|
.mhandler.cmd = hmp_netdev_del,
|
||||||
|
.command_completion = netdev_del_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -1254,6 +1267,7 @@ ETEXI
|
|||||||
.params = "[qom-type=]type,id=str[,prop=value][,...]",
|
.params = "[qom-type=]type,id=str[,prop=value][,...]",
|
||||||
.help = "create QOM object",
|
.help = "create QOM object",
|
||||||
.mhandler.cmd = hmp_object_add,
|
.mhandler.cmd = hmp_object_add,
|
||||||
|
.command_completion = object_add_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -1268,6 +1282,7 @@ ETEXI
|
|||||||
.params = "id",
|
.params = "id",
|
||||||
.help = "destroy QOM object",
|
.help = "destroy QOM object",
|
||||||
.mhandler.cmd = hmp_object_del,
|
.mhandler.cmd = hmp_object_del,
|
||||||
|
.command_completion = object_del_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -1327,6 +1342,7 @@ ETEXI
|
|||||||
.params = "name on|off",
|
.params = "name on|off",
|
||||||
.help = "change the link status of a network adapter",
|
.help = "change the link status of a network adapter",
|
||||||
.mhandler.cmd = hmp_set_link,
|
.mhandler.cmd = hmp_set_link,
|
||||||
|
.command_completion = set_link_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -1610,6 +1626,7 @@ ETEXI
|
|||||||
.params = "args",
|
.params = "args",
|
||||||
.help = "add chardev",
|
.help = "add chardev",
|
||||||
.mhandler.cmd = hmp_chardev_add,
|
.mhandler.cmd = hmp_chardev_add,
|
||||||
|
.command_completion = chardev_add_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -1626,6 +1643,7 @@ ETEXI
|
|||||||
.params = "id",
|
.params = "id",
|
||||||
.help = "remove chardev",
|
.help = "remove chardev",
|
||||||
.mhandler.cmd = hmp_chardev_remove,
|
.mhandler.cmd = hmp_chardev_remove,
|
||||||
|
.command_completion = chardev_remove_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
|
180
hmp.c
180
hmp.c
@@ -28,7 +28,8 @@
|
|||||||
|
|
||||||
static void hmp_handle_error(Monitor *mon, Error **errp)
|
static void hmp_handle_error(Monitor *mon, Error **errp)
|
||||||
{
|
{
|
||||||
if (error_is_set(errp)) {
|
assert(errp);
|
||||||
|
if (*errp) {
|
||||||
monitor_printf(mon, "%s\n", error_get_pretty(*errp));
|
monitor_printf(mon, "%s\n", error_get_pretty(*errp));
|
||||||
error_free(*errp);
|
error_free(*errp);
|
||||||
}
|
}
|
||||||
@@ -188,6 +189,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
|||||||
info->ram->normal);
|
info->ram->normal);
|
||||||
monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
|
monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
|
||||||
info->ram->normal_bytes >> 10);
|
info->ram->normal_bytes >> 10);
|
||||||
|
monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
|
||||||
|
info->ram->dirty_sync_count);
|
||||||
if (info->ram->dirty_pages_rate) {
|
if (info->ram->dirty_pages_rate) {
|
||||||
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
|
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
|
||||||
info->ram->dirty_pages_rate);
|
info->ram->dirty_pages_rate);
|
||||||
@@ -212,6 +215,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
|||||||
info->xbzrle_cache->pages);
|
info->xbzrle_cache->pages);
|
||||||
monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
|
monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
|
||||||
info->xbzrle_cache->cache_miss);
|
info->xbzrle_cache->cache_miss);
|
||||||
|
monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n",
|
||||||
|
info->xbzrle_cache->cache_miss_rate);
|
||||||
monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
|
monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
|
||||||
info->xbzrle_cache->overflow);
|
info->xbzrle_cache->overflow);
|
||||||
}
|
}
|
||||||
@@ -750,10 +755,10 @@ void hmp_memsave(Monitor *mon, const QDict *qdict)
|
|||||||
uint32_t size = qdict_get_int(qdict, "size");
|
uint32_t size = qdict_get_int(qdict, "size");
|
||||||
const char *filename = qdict_get_str(qdict, "filename");
|
const char *filename = qdict_get_str(qdict, "filename");
|
||||||
uint64_t addr = qdict_get_int(qdict, "val");
|
uint64_t addr = qdict_get_int(qdict, "val");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &errp);
|
qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_pmemsave(Monitor *mon, const QDict *qdict)
|
void hmp_pmemsave(Monitor *mon, const QDict *qdict)
|
||||||
@@ -761,21 +766,21 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
|
|||||||
uint32_t size = qdict_get_int(qdict, "size");
|
uint32_t size = qdict_get_int(qdict, "size");
|
||||||
const char *filename = qdict_get_str(qdict, "filename");
|
const char *filename = qdict_get_str(qdict, "filename");
|
||||||
uint64_t addr = qdict_get_int(qdict, "val");
|
uint64_t addr = qdict_get_int(qdict, "val");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_pmemsave(addr, size, filename, &errp);
|
qmp_pmemsave(addr, size, filename, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_ringbuf_write(Monitor *mon, const QDict *qdict)
|
void hmp_ringbuf_write(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *chardev = qdict_get_str(qdict, "device");
|
const char *chardev = qdict_get_str(qdict, "device");
|
||||||
const char *data = qdict_get_str(qdict, "data");
|
const char *data = qdict_get_str(qdict, "data");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_ringbuf_write(chardev, data, false, 0, &errp);
|
qmp_ringbuf_write(chardev, data, false, 0, &err);
|
||||||
|
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
||||||
@@ -783,13 +788,13 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
|||||||
uint32_t size = qdict_get_int(qdict, "size");
|
uint32_t size = qdict_get_int(qdict, "size");
|
||||||
const char *chardev = qdict_get_str(qdict, "device");
|
const char *chardev = qdict_get_str(qdict, "device");
|
||||||
char *data;
|
char *data;
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
data = qmp_ringbuf_read(chardev, size, false, 0, &errp);
|
data = qmp_ringbuf_read(chardev, size, false, 0, &err);
|
||||||
if (errp) {
|
if (err) {
|
||||||
monitor_printf(mon, "%s\n", error_get_pretty(errp));
|
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
||||||
error_free(errp);
|
error_free(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,7 +829,7 @@ static bool key_is_missing(const BlockInfo *bdev)
|
|||||||
void hmp_cont(Monitor *mon, const QDict *qdict)
|
void hmp_cont(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
BlockInfoList *bdev_list, *bdev;
|
BlockInfoList *bdev_list, *bdev;
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
bdev_list = qmp_query_block(NULL);
|
bdev_list = qmp_query_block(NULL);
|
||||||
for (bdev = bdev_list; bdev; bdev = bdev->next) {
|
for (bdev = bdev_list; bdev; bdev = bdev->next) {
|
||||||
@@ -835,8 +840,8 @@ void hmp_cont(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qmp_cont(&errp);
|
qmp_cont(&err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
qapi_free_BlockInfoList(bdev_list);
|
qapi_free_BlockInfoList(bdev_list);
|
||||||
@@ -849,41 +854,41 @@ void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
|
|||||||
|
|
||||||
void hmp_inject_nmi(Monitor *mon, const QDict *qdict)
|
void hmp_inject_nmi(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_inject_nmi(&errp);
|
qmp_inject_nmi(&err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_set_link(Monitor *mon, const QDict *qdict)
|
void hmp_set_link(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *name = qdict_get_str(qdict, "name");
|
const char *name = qdict_get_str(qdict, "name");
|
||||||
int up = qdict_get_bool(qdict, "up");
|
int up = qdict_get_bool(qdict, "up");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_set_link(name, up, &errp);
|
qmp_set_link(name, up, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_block_passwd(Monitor *mon, const QDict *qdict)
|
void hmp_block_passwd(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *device = qdict_get_str(qdict, "device");
|
const char *device = qdict_get_str(qdict, "device");
|
||||||
const char *password = qdict_get_str(qdict, "password");
|
const char *password = qdict_get_str(qdict, "password");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_block_passwd(true, device, false, NULL, password, &errp);
|
qmp_block_passwd(true, device, false, NULL, password, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_balloon(Monitor *mon, const QDict *qdict)
|
void hmp_balloon(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
int64_t value = qdict_get_int(qdict, "value");
|
int64_t value = qdict_get_int(qdict, "value");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_balloon(value, &errp);
|
qmp_balloon(value, &err);
|
||||||
if (errp) {
|
if (err) {
|
||||||
monitor_printf(mon, "balloon: %s\n", error_get_pretty(errp));
|
monitor_printf(mon, "balloon: %s\n", error_get_pretty(err));
|
||||||
error_free(errp);
|
error_free(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,10 +896,10 @@ void hmp_block_resize(Monitor *mon, const QDict *qdict)
|
|||||||
{
|
{
|
||||||
const char *device = qdict_get_str(qdict, "device");
|
const char *device = qdict_get_str(qdict, "device");
|
||||||
int64_t size = qdict_get_int(qdict, "size");
|
int64_t size = qdict_get_int(qdict, "size");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_block_resize(true, device, false, NULL, size, &errp);
|
qmp_block_resize(true, device, false, NULL, size, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
||||||
@@ -905,11 +910,11 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
|||||||
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
||||||
int full = qdict_get_try_bool(qdict, "full", 0);
|
int full = qdict_get_try_bool(qdict, "full", 0);
|
||||||
enum NewImageMode mode;
|
enum NewImageMode mode;
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
error_set(&errp, QERR_MISSING_PARAMETER, "target");
|
error_set(&err, QERR_MISSING_PARAMETER, "target");
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,8 +927,8 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
|||||||
qmp_drive_mirror(device, filename, !!format, format,
|
qmp_drive_mirror(device, filename, !!format, format,
|
||||||
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||||
true, mode, false, 0, false, 0, false, 0,
|
true, mode, false, 0, false, 0, false, 0,
|
||||||
false, 0, false, 0, &errp);
|
false, 0, false, 0, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
||||||
@@ -934,11 +939,11 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
|||||||
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
||||||
int full = qdict_get_try_bool(qdict, "full", 0);
|
int full = qdict_get_try_bool(qdict, "full", 0);
|
||||||
enum NewImageMode mode;
|
enum NewImageMode mode;
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
error_set(&errp, QERR_MISSING_PARAMETER, "target");
|
error_set(&err, QERR_MISSING_PARAMETER, "target");
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,8 +955,8 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
|||||||
|
|
||||||
qmp_drive_backup(device, filename, !!format, format,
|
qmp_drive_backup(device, filename, !!format, format,
|
||||||
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||||
true, mode, false, 0, false, 0, false, 0, &errp);
|
true, mode, false, 0, false, 0, false, 0, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
||||||
@@ -961,13 +966,13 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
|||||||
const char *format = qdict_get_try_str(qdict, "format");
|
const char *format = qdict_get_try_str(qdict, "format");
|
||||||
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
|
||||||
enum NewImageMode mode;
|
enum NewImageMode mode;
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
/* In the future, if 'snapshot-file' is not specified, the snapshot
|
/* In the future, if 'snapshot-file' is not specified, the snapshot
|
||||||
will be taken internally. Today it's actually required. */
|
will be taken internally. Today it's actually required. */
|
||||||
error_set(&errp, QERR_MISSING_PARAMETER, "snapshot-file");
|
error_set(&err, QERR_MISSING_PARAMETER, "snapshot-file");
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,18 +980,18 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
|||||||
qmp_blockdev_snapshot_sync(true, device, false, NULL,
|
qmp_blockdev_snapshot_sync(true, device, false, NULL,
|
||||||
filename, false, NULL,
|
filename, false, NULL,
|
||||||
!!format, format,
|
!!format, format,
|
||||||
true, mode, &errp);
|
true, mode, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
|
void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *device = qdict_get_str(qdict, "device");
|
const char *device = qdict_get_str(qdict, "device");
|
||||||
const char *name = qdict_get_str(qdict, "name");
|
const char *name = qdict_get_str(qdict, "name");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_blockdev_snapshot_internal_sync(device, name, &errp);
|
qmp_blockdev_snapshot_internal_sync(device, name, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
||||||
@@ -994,11 +999,11 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
|||||||
const char *device = qdict_get_str(qdict, "device");
|
const char *device = qdict_get_str(qdict, "device");
|
||||||
const char *name = qdict_get_str(qdict, "name");
|
const char *name = qdict_get_str(qdict, "name");
|
||||||
const char *id = qdict_get_try_str(qdict, "id");
|
const char *id = qdict_get_try_str(qdict, "id");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
|
qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
|
||||||
true, name, &errp);
|
true, name, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
|
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
|
||||||
@@ -1306,18 +1311,37 @@ void hmp_device_del(Monitor *mon, const QDict *qdict)
|
|||||||
|
|
||||||
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
int paging = qdict_get_try_bool(qdict, "paging", 0);
|
int paging = qdict_get_try_bool(qdict, "paging", 0);
|
||||||
|
int zlib = qdict_get_try_bool(qdict, "zlib", 0);
|
||||||
|
int lzo = qdict_get_try_bool(qdict, "lzo", 0);
|
||||||
|
int snappy = qdict_get_try_bool(qdict, "snappy", 0);
|
||||||
const char *file = qdict_get_str(qdict, "filename");
|
const char *file = qdict_get_str(qdict, "filename");
|
||||||
bool has_begin = qdict_haskey(qdict, "begin");
|
bool has_begin = qdict_haskey(qdict, "begin");
|
||||||
bool has_length = qdict_haskey(qdict, "length");
|
bool has_length = qdict_haskey(qdict, "length");
|
||||||
/* kdump-compressed format is not supported for HMP */
|
|
||||||
bool has_format = false;
|
|
||||||
int64_t begin = 0;
|
int64_t begin = 0;
|
||||||
int64_t length = 0;
|
int64_t length = 0;
|
||||||
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
||||||
char *prot;
|
char *prot;
|
||||||
|
|
||||||
|
if (zlib + lzo + snappy > 1) {
|
||||||
|
error_setg(&err, "only one of '-z|-l|-s' can be set");
|
||||||
|
hmp_handle_error(mon, &err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zlib) {
|
||||||
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lzo) {
|
||||||
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snappy) {
|
||||||
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
|
||||||
|
}
|
||||||
|
|
||||||
if (has_begin) {
|
if (has_begin) {
|
||||||
begin = qdict_get_int(qdict, "begin");
|
begin = qdict_get_int(qdict, "begin");
|
||||||
}
|
}
|
||||||
@@ -1328,8 +1352,8 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
|||||||
prot = g_strconcat("file:", file, NULL);
|
prot = g_strconcat("file:", file, NULL);
|
||||||
|
|
||||||
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
||||||
has_format, dump_format, &errp);
|
true, dump_format, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
g_free(prot);
|
g_free(prot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1364,6 +1388,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
|
|||||||
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
Error *err_end = NULL;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
char *type = NULL;
|
char *type = NULL;
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
@@ -1387,24 +1412,23 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|||||||
qdict_del(pdict, "qom-type");
|
qdict_del(pdict, "qom-type");
|
||||||
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
|
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto out_clean;
|
goto out_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
qdict_del(pdict, "id");
|
qdict_del(pdict, "id");
|
||||||
visit_type_str(opts_get_visitor(ov), &id, "id", &err);
|
visit_type_str(opts_get_visitor(ov), &id, "id", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto out_clean;
|
goto out_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_add(type, id, pdict, opts_get_visitor(ov), &err);
|
object_add(type, id, pdict, opts_get_visitor(ov), &err);
|
||||||
if (err) {
|
|
||||||
goto out_clean;
|
out_end:
|
||||||
}
|
visit_end_struct(opts_get_visitor(ov), &err_end);
|
||||||
visit_end_struct(opts_get_visitor(ov), &err);
|
if (!err && err_end) {
|
||||||
if (err) {
|
|
||||||
qmp_object_del(id, NULL);
|
qmp_object_del(id, NULL);
|
||||||
}
|
}
|
||||||
|
error_propagate(&err, err_end);
|
||||||
out_clean:
|
out_clean:
|
||||||
opts_visitor_cleanup(ov);
|
opts_visitor_cleanup(ov);
|
||||||
|
|
||||||
@@ -1421,19 +1445,19 @@ out:
|
|||||||
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *fdname = qdict_get_str(qdict, "fdname");
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_getfd(fdname, &errp);
|
qmp_getfd(fdname, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_closefd(Monitor *mon, const QDict *qdict)
|
void hmp_closefd(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *fdname = qdict_get_str(qdict, "fdname");
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_closefd(fdname, &errp);
|
qmp_closefd(fdname, &err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_send_key(Monitor *mon, const QDict *qdict)
|
void hmp_send_key(Monitor *mon, const QDict *qdict)
|
||||||
@@ -1583,10 +1607,10 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
|
|||||||
|
|
||||||
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
|
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
Error *errp = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_nbd_server_stop(&errp);
|
qmp_nbd_server_stop(&err);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_cpu_add(Monitor *mon, const QDict *qdict)
|
void hmp_cpu_add(Monitor *mon, const QDict *qdict)
|
||||||
|
11
hmp.h
11
hmp.h
@@ -15,6 +15,7 @@
|
|||||||
#define HMP_H
|
#define HMP_H
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
|
#include "qemu/readline.h"
|
||||||
#include "qapi-types.h"
|
#include "qapi-types.h"
|
||||||
#include "qapi/qmp/qdict.h"
|
#include "qapi/qmp/qdict.h"
|
||||||
|
|
||||||
@@ -92,5 +93,15 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict);
|
|||||||
void hmp_cpu_add(Monitor *mon, const QDict *qdict);
|
void hmp_cpu_add(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_object_add(Monitor *mon, const QDict *qdict);
|
void hmp_object_add(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
||||||
|
void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include "hw/virtio/virtio.h"
|
#include "hw/virtio/virtio.h"
|
||||||
#include "virtio-9p.h"
|
#include "virtio-9p.h"
|
||||||
#include "virtio-9p-xattr.h"
|
#include "virtio-9p-xattr.h"
|
||||||
|
#include "fsdev/qemu-fsdev.h" /* local_ops */
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
/* Root node for synth file system */
|
/* Root node for synth file system */
|
||||||
V9fsSynthNode v9fs_synth_root = {
|
static V9fsSynthNode v9fs_synth_root = {
|
||||||
.name = "/",
|
.name = "/",
|
||||||
.actual_attr = {
|
.actual_attr = {
|
||||||
.mode = 0555 | S_IFDIR,
|
.mode = 0555 | S_IFDIR,
|
||||||
|
@@ -987,8 +987,9 @@ static void v9fs_attach(void *opaque)
|
|||||||
*/
|
*/
|
||||||
if (!s->migration_blocker) {
|
if (!s->migration_blocker) {
|
||||||
s->root_fid = fid;
|
s->root_fid = fid;
|
||||||
error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
|
error_setg(&s->migration_blocker,
|
||||||
s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
|
"Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
|
||||||
|
s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
|
||||||
migrate_add_blocker(s->migration_blocker);
|
migrate_add_blocker(s->migration_blocker);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
@@ -63,16 +63,18 @@ typedef struct AcpiPciHpFind {
|
|||||||
|
|
||||||
static int acpi_pcihp_get_bsel(PCIBus *bus)
|
static int acpi_pcihp_get_bsel(PCIBus *bus)
|
||||||
{
|
{
|
||||||
QObject *o = object_property_get_qobject(OBJECT(bus),
|
Error *local_err = NULL;
|
||||||
ACPI_PCIHP_PROP_BSEL, NULL);
|
int64_t bsel = object_property_get_int(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
|
||||||
int64_t bsel = -1;
|
&local_err);
|
||||||
if (o) {
|
|
||||||
bsel = qint_get_int(qobject_to_qint(o));
|
if (local_err || bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
||||||
}
|
if (local_err) {
|
||||||
if (bsel < 0) {
|
error_free(local_err);
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
} else {
|
||||||
|
return bsel;
|
||||||
}
|
}
|
||||||
return bsel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque)
|
static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque)
|
||||||
|
@@ -43,6 +43,19 @@ static void cubieboard_init(QEMUMachineInitArgs *args)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_property_set_int(OBJECT(&s->a10->timer), 32768, "clk0-freq", &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_report("Couldn't set clk0 frequency: %s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
object_property_set_int(OBJECT(&s->a10->timer), 24000000, "clk1-freq",
|
||||||
|
&err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_report("Couldn't set clk1 frequency: %s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
|
object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_report("Couldn't realize Allwinner A10: %s",
|
error_report("Couldn't realize Allwinner A10: %s",
|
||||||
|
@@ -134,7 +134,6 @@ static VMStateDescription vmstate_highbank_regs = {
|
|||||||
.name = "highbank-regs",
|
.name = "highbank-regs",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
|
VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
|
||||||
VMSTATE_END_OF_LIST(),
|
VMSTATE_END_OF_LIST(),
|
||||||
|
@@ -405,7 +405,6 @@ static const VMStateDescription mv88w8618_eth_vmsd = {
|
|||||||
.name = "mv88w8618_eth",
|
.name = "mv88w8618_eth",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(smir, mv88w8618_eth_state),
|
VMSTATE_UINT32(smir, mv88w8618_eth_state),
|
||||||
VMSTATE_UINT32(icr, mv88w8618_eth_state),
|
VMSTATE_UINT32(icr, mv88w8618_eth_state),
|
||||||
@@ -642,7 +641,6 @@ static const VMStateDescription musicpal_lcd_vmsd = {
|
|||||||
.name = "musicpal_lcd",
|
.name = "musicpal_lcd",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(brightness, musicpal_lcd_state),
|
VMSTATE_UINT32(brightness, musicpal_lcd_state),
|
||||||
VMSTATE_UINT32(mode, musicpal_lcd_state),
|
VMSTATE_UINT32(mode, musicpal_lcd_state),
|
||||||
@@ -769,7 +767,6 @@ static const VMStateDescription mv88w8618_pic_vmsd = {
|
|||||||
.name = "mv88w8618_pic",
|
.name = "mv88w8618_pic",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(level, mv88w8618_pic_state),
|
VMSTATE_UINT32(level, mv88w8618_pic_state),
|
||||||
VMSTATE_UINT32(enabled, mv88w8618_pic_state),
|
VMSTATE_UINT32(enabled, mv88w8618_pic_state),
|
||||||
@@ -940,7 +937,6 @@ static const VMStateDescription mv88w8618_timer_vmsd = {
|
|||||||
.name = "timer",
|
.name = "timer",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
|
VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
|
||||||
VMSTATE_UINT32(limit, mv88w8618_timer_state),
|
VMSTATE_UINT32(limit, mv88w8618_timer_state),
|
||||||
@@ -952,7 +948,6 @@ static const VMStateDescription mv88w8618_pit_vmsd = {
|
|||||||
.name = "mv88w8618_pit",
|
.name = "mv88w8618_pit",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
|
VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
|
||||||
mv88w8618_timer_vmsd, mv88w8618_timer_state),
|
mv88w8618_timer_vmsd, mv88w8618_timer_state),
|
||||||
@@ -1041,7 +1036,6 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = {
|
|||||||
.name = "mv88w8618_flashcfg",
|
.name = "mv88w8618_flashcfg",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
|
VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
@@ -1381,7 +1375,6 @@ static const VMStateDescription musicpal_gpio_vmsd = {
|
|||||||
.name = "musicpal_gpio",
|
.name = "musicpal_gpio",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
|
VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
|
||||||
VMSTATE_UINT32(out_state, musicpal_gpio_state),
|
VMSTATE_UINT32(out_state, musicpal_gpio_state),
|
||||||
@@ -1548,7 +1541,6 @@ static const VMStateDescription musicpal_key_vmsd = {
|
|||||||
.name = "musicpal_key",
|
.name = "musicpal_key",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(kbd_extended, musicpal_key_state),
|
VMSTATE_UINT32(kbd_extended, musicpal_key_state),
|
||||||
VMSTATE_UINT32(pressed_keys, musicpal_key_state),
|
VMSTATE_UINT32(pressed_keys, musicpal_key_state),
|
||||||
|
@@ -2709,8 +2709,8 @@ static void omap_rtc_write(void *opaque, hwaddr addr,
|
|||||||
s->ti += ti[1];
|
s->ti += ti[1];
|
||||||
} else {
|
} else {
|
||||||
/* A less accurate version */
|
/* A less accurate version */
|
||||||
s->ti -= (s->current_tm.tm_year % 100) * 31536000;
|
s->ti -= (time_t)(s->current_tm.tm_year % 100) * 31536000;
|
||||||
s->ti += from_bcd(value) * 31536000;
|
s->ti += (time_t)from_bcd(value) * 31536000;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@@ -148,8 +148,7 @@ static const VMStateDescription vmstate_pxa2xx_pm = {
|
|||||||
.name = "pxa2xx_pm",
|
.name = "pxa2xx_pm",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
|
VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
@@ -215,8 +214,7 @@ static const VMStateDescription vmstate_pxa2xx_cm = {
|
|||||||
.name = "pxa2xx_cm",
|
.name = "pxa2xx_cm",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
|
VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
|
||||||
VMSTATE_UINT32(clkcfg, PXA2xxState),
|
VMSTATE_UINT32(clkcfg, PXA2xxState),
|
||||||
VMSTATE_UINT32(pmnc, PXA2xxState),
|
VMSTATE_UINT32(pmnc, PXA2xxState),
|
||||||
@@ -440,8 +438,7 @@ static const VMStateDescription vmstate_pxa2xx_mm = {
|
|||||||
.name = "pxa2xx_mm",
|
.name = "pxa2xx_mm",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
|
VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
@@ -732,7 +729,7 @@ static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
|
|||||||
static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
|
static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
|
PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
|
||||||
int i;
|
int i, v;
|
||||||
|
|
||||||
s->enable = qemu_get_be32(f);
|
s->enable = qemu_get_be32(f);
|
||||||
|
|
||||||
@@ -746,7 +743,11 @@ static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
qemu_get_8s(f, &s->ssrsa);
|
qemu_get_8s(f, &s->ssrsa);
|
||||||
qemu_get_8s(f, &s->ssacd);
|
qemu_get_8s(f, &s->ssacd);
|
||||||
|
|
||||||
s->rx_level = qemu_get_byte(f);
|
v = qemu_get_byte(f);
|
||||||
|
if (v < 0 || v > ARRAY_SIZE(s->rx_fifo)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
s->rx_level = v;
|
||||||
s->rx_start = 0;
|
s->rx_start = 0;
|
||||||
for (i = 0; i < s->rx_level; i ++)
|
for (i = 0; i < s->rx_level; i ++)
|
||||||
s->rx_fifo[i] = qemu_get_byte(f);
|
s->rx_fifo[i] = qemu_get_byte(f);
|
||||||
@@ -1168,7 +1169,6 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
|
|||||||
.name = "pxa2xx_rtc",
|
.name = "pxa2xx_rtc",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.pre_save = pxa2xx_rtc_pre_save,
|
.pre_save = pxa2xx_rtc_pre_save,
|
||||||
.post_load = pxa2xx_rtc_post_load,
|
.post_load = pxa2xx_rtc_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
@@ -1432,8 +1432,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
|
|||||||
.name = "pxa2xx_i2c_slave",
|
.name = "pxa2xx_i2c_slave",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState),
|
VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
@@ -1443,8 +1442,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c = {
|
|||||||
.name = "pxa2xx_i2c",
|
.name = "pxa2xx_i2c",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_UINT16(control, PXA2xxI2CState),
|
VMSTATE_UINT16(control, PXA2xxI2CState),
|
||||||
VMSTATE_UINT16(status, PXA2xxI2CState),
|
VMSTATE_UINT16(status, PXA2xxI2CState),
|
||||||
VMSTATE_UINT8(ibmr, PXA2xxI2CState),
|
VMSTATE_UINT8(ibmr, PXA2xxI2CState),
|
||||||
@@ -1701,8 +1699,7 @@ static const VMStateDescription vmstate_pxa2xx_i2s = {
|
|||||||
.name = "pxa2xx_i2s",
|
.name = "pxa2xx_i2s",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
|
VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
|
||||||
VMSTATE_UINT32(status, PXA2xxI2SState),
|
VMSTATE_UINT32(status, PXA2xxI2SState),
|
||||||
VMSTATE_UINT32(mask, PXA2xxI2SState),
|
VMSTATE_UINT32(mask, PXA2xxI2SState),
|
||||||
|
@@ -313,8 +313,7 @@ static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
|
|||||||
.name = "pxa2xx-gpio",
|
.name = "pxa2xx-gpio",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_INT32(lines, PXA2xxGPIOInfo),
|
VMSTATE_INT32(lines, PXA2xxGPIOInfo),
|
||||||
VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||||
VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||||
|
@@ -296,7 +296,6 @@ static VMStateDescription vmstate_pxa2xx_pic_regs = {
|
|||||||
.name = "pxa2xx_pic",
|
.name = "pxa2xx_pic",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.post_load = pxa2xx_pic_post_load,
|
.post_load = pxa2xx_pic_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
|
VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
|
||||||
|
@@ -1006,8 +1006,7 @@ static VMStateDescription vmstate_sl_nand_info = {
|
|||||||
.name = "sl-nand",
|
.name = "sl-nand",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_UINT8(ctl, SLNANDState),
|
VMSTATE_UINT8(ctl, SLNANDState),
|
||||||
VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
|
VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
|
||||||
VMSTATE_END_OF_LIST(),
|
VMSTATE_END_OF_LIST(),
|
||||||
@@ -1041,9 +1040,8 @@ static VMStateDescription vmstate_spitz_kbd = {
|
|||||||
.name = "spitz-keyboard",
|
.name = "spitz-keyboard",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.post_load = spitz_keyboard_post_load,
|
.post_load = spitz_keyboard_post_load,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT16(sense_state, SpitzKeyboardState),
|
VMSTATE_UINT16(sense_state, SpitzKeyboardState),
|
||||||
VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
|
VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
|
||||||
VMSTATE_UNUSED_TEST(is_version_0, 5),
|
VMSTATE_UNUSED_TEST(is_version_0, 5),
|
||||||
@@ -1076,8 +1074,7 @@ static const VMStateDescription vmstate_corgi_ssp_regs = {
|
|||||||
.name = "corgi-ssp",
|
.name = "corgi-ssp",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 2,
|
.minimum_version_id = 2,
|
||||||
.minimum_version_id_old = 2,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState),
|
VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState),
|
||||||
VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
|
VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
|
||||||
VMSTATE_END_OF_LIST(),
|
VMSTATE_END_OF_LIST(),
|
||||||
@@ -1105,8 +1102,7 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = {
|
|||||||
.name = "spitz-lcdtg",
|
.name = "spitz-lcdtg",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG),
|
VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG),
|
||||||
VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
|
VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
|
||||||
VMSTATE_UINT32(bl_power, SpitzLCDTG),
|
VMSTATE_UINT32(bl_power, SpitzLCDTG),
|
||||||
|
@@ -185,12 +185,19 @@ static uint64_t gptm_read(void *opaque, hwaddr offset,
|
|||||||
case 0x44: /* TBPMR */
|
case 0x44: /* TBPMR */
|
||||||
return s->match_prescale[1];
|
return s->match_prescale[1];
|
||||||
case 0x48: /* TAR */
|
case 0x48: /* TAR */
|
||||||
if (s->control == 1)
|
if (s->config == 1) {
|
||||||
return s->rtc;
|
return s->rtc;
|
||||||
|
}
|
||||||
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"GPTM: read of TAR but timer read not supported");
|
||||||
|
return 0;
|
||||||
case 0x4c: /* TBR */
|
case 0x4c: /* TBR */
|
||||||
hw_error("TODO: Timer value read\n");
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"GPTM: read of TBR but timer read not supported");
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"GPTM: read at bad offset 0x%x\n", (int)offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,8 +293,7 @@ static const VMStateDescription vmstate_stellaris_gptm = {
|
|||||||
.name = "stellaris_gptm",
|
.name = "stellaris_gptm",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32(config, gptm_state),
|
VMSTATE_UINT32(config, gptm_state),
|
||||||
VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
|
VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
|
||||||
VMSTATE_UINT32(control, gptm_state),
|
VMSTATE_UINT32(control, gptm_state),
|
||||||
@@ -643,9 +649,8 @@ static const VMStateDescription vmstate_stellaris_sys = {
|
|||||||
.name = "stellaris_sys",
|
.name = "stellaris_sys",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.post_load = stellaris_sys_post_load,
|
.post_load = stellaris_sys_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(pborctl, ssys_state),
|
VMSTATE_UINT32(pborctl, ssys_state),
|
||||||
VMSTATE_UINT32(ldopctl, ssys_state),
|
VMSTATE_UINT32(ldopctl, ssys_state),
|
||||||
VMSTATE_UINT32(int_mask, ssys_state),
|
VMSTATE_UINT32(int_mask, ssys_state),
|
||||||
@@ -851,8 +856,7 @@ static const VMStateDescription vmstate_stellaris_i2c = {
|
|||||||
.name = "stellaris_i2c",
|
.name = "stellaris_i2c",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32(msa, stellaris_i2c_state),
|
VMSTATE_UINT32(msa, stellaris_i2c_state),
|
||||||
VMSTATE_UINT32(mcs, stellaris_i2c_state),
|
VMSTATE_UINT32(mcs, stellaris_i2c_state),
|
||||||
VMSTATE_UINT32(mdr, stellaris_i2c_state),
|
VMSTATE_UINT32(mdr, stellaris_i2c_state),
|
||||||
@@ -1121,8 +1125,7 @@ static const VMStateDescription vmstate_stellaris_adc = {
|
|||||||
.name = "stellaris_adc",
|
.name = "stellaris_adc",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32(actss, stellaris_adc_state),
|
VMSTATE_UINT32(actss, stellaris_adc_state),
|
||||||
VMSTATE_UINT32(ris, stellaris_adc_state),
|
VMSTATE_UINT32(ris, stellaris_adc_state),
|
||||||
VMSTATE_UINT32(im, stellaris_adc_state),
|
VMSTATE_UINT32(im, stellaris_adc_state),
|
||||||
|
@@ -199,7 +199,6 @@ static VMStateDescription vmstate_strongarm_pic_regs = {
|
|||||||
.name = "strongarm_pic",
|
.name = "strongarm_pic",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.post_load = strongarm_pic_post_load,
|
.post_load = strongarm_pic_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(pending, StrongARMPICState),
|
VMSTATE_UINT32(pending, StrongARMPICState),
|
||||||
@@ -424,7 +423,6 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = {
|
|||||||
.name = "strongarm-rtc",
|
.name = "strongarm-rtc",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.pre_save = strongarm_rtc_pre_save,
|
.pre_save = strongarm_rtc_pre_save,
|
||||||
.post_load = strongarm_rtc_post_load,
|
.post_load = strongarm_rtc_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
@@ -670,7 +668,6 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = {
|
|||||||
.name = "strongarm-gpio",
|
.name = "strongarm-gpio",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
|
VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
|
||||||
VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
|
VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
|
||||||
@@ -842,7 +839,6 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = {
|
|||||||
.name = "strongarm-ppc",
|
.name = "strongarm-ppc",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
|
VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
|
||||||
VMSTATE_UINT32(olevel, StrongARMPPCInfo),
|
VMSTATE_UINT32(olevel, StrongARMPPCInfo),
|
||||||
@@ -1293,7 +1289,6 @@ static const VMStateDescription vmstate_strongarm_uart_regs = {
|
|||||||
.name = "strongarm-uart",
|
.name = "strongarm-uart",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.post_load = strongarm_uart_post_load,
|
.post_load = strongarm_uart_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT8(utcr0, StrongARMUARTState),
|
VMSTATE_UINT8(utcr0, StrongARMUARTState),
|
||||||
@@ -1553,7 +1548,6 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = {
|
|||||||
.name = "strongarm-ssp",
|
.name = "strongarm-ssp",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.post_load = strongarm_ssp_post_load,
|
.post_load = strongarm_ssp_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
|
VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
|
||||||
|
@@ -75,8 +75,6 @@ typedef struct MemMapEntry {
|
|||||||
typedef struct VirtBoardInfo {
|
typedef struct VirtBoardInfo {
|
||||||
struct arm_boot_info bootinfo;
|
struct arm_boot_info bootinfo;
|
||||||
const char *cpu_model;
|
const char *cpu_model;
|
||||||
const char *qdevname;
|
|
||||||
const char *gic_compatible;
|
|
||||||
const MemMapEntry *memmap;
|
const MemMapEntry *memmap;
|
||||||
const int *irqmap;
|
const int *irqmap;
|
||||||
int smp_cpus;
|
int smp_cpus;
|
||||||
@@ -98,10 +96,10 @@ typedef struct VirtBoardInfo {
|
|||||||
static const MemMapEntry a15memmap[] = {
|
static const MemMapEntry a15memmap[] = {
|
||||||
/* Space up to 0x8000000 is reserved for a boot ROM */
|
/* Space up to 0x8000000 is reserved for a boot ROM */
|
||||||
[VIRT_FLASH] = { 0, 0x8000000 },
|
[VIRT_FLASH] = { 0, 0x8000000 },
|
||||||
[VIRT_CPUPERIPHS] = { 0x8000000, 0x8000 },
|
[VIRT_CPUPERIPHS] = { 0x8000000, 0x20000 },
|
||||||
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
||||||
[VIRT_GIC_DIST] = { 0x8001000, 0x1000 },
|
[VIRT_GIC_DIST] = { 0x8000000, 0x10000 },
|
||||||
[VIRT_GIC_CPU] = { 0x8002000, 0x1000 },
|
[VIRT_GIC_CPU] = { 0x8010000, 0x10000 },
|
||||||
[VIRT_UART] = { 0x9000000, 0x1000 },
|
[VIRT_UART] = { 0x9000000, 0x1000 },
|
||||||
[VIRT_MMIO] = { 0xa000000, 0x200 },
|
[VIRT_MMIO] = { 0xa000000, 0x200 },
|
||||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||||
@@ -117,16 +115,16 @@ static const int a15irqmap[] = {
|
|||||||
static VirtBoardInfo machines[] = {
|
static VirtBoardInfo machines[] = {
|
||||||
{
|
{
|
||||||
.cpu_model = "cortex-a15",
|
.cpu_model = "cortex-a15",
|
||||||
.qdevname = "a15mpcore_priv",
|
.memmap = a15memmap,
|
||||||
.gic_compatible = "arm,cortex-a15-gic",
|
.irqmap = a15irqmap,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cpu_model = "cortex-a57",
|
||||||
.memmap = a15memmap,
|
.memmap = a15memmap,
|
||||||
.irqmap = a15irqmap,
|
.irqmap = a15irqmap,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.cpu_model = "host",
|
.cpu_model = "host",
|
||||||
/* We use the A15 private peripheral model to get a V2 GIC */
|
|
||||||
.qdevname = "a15mpcore_priv",
|
|
||||||
.gic_compatible = "arm,cortex-a15-gic",
|
|
||||||
.memmap = a15memmap,
|
.memmap = a15memmap,
|
||||||
.irqmap = a15irqmap,
|
.irqmap = a15irqmap,
|
||||||
},
|
},
|
||||||
@@ -251,8 +249,9 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
|
|||||||
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
|
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
|
||||||
|
|
||||||
qemu_fdt_add_subnode(vbi->fdt, "/intc");
|
qemu_fdt_add_subnode(vbi->fdt, "/intc");
|
||||||
|
/* 'cortex-a15-gic' means 'GIC v2' */
|
||||||
qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
|
qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
|
||||||
vbi->gic_compatible);
|
"arm,cortex-a15-gic");
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
|
||||||
qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
|
qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
|
||||||
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
|
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
|
||||||
@@ -263,6 +262,56 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
|
|||||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
|
{
|
||||||
|
/* We create a standalone GIC v2 */
|
||||||
|
DeviceState *gicdev;
|
||||||
|
SysBusDevice *gicbusdev;
|
||||||
|
const char *gictype = "arm_gic";
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (kvm_irqchip_in_kernel()) {
|
||||||
|
gictype = "kvm-arm-gic";
|
||||||
|
}
|
||||||
|
|
||||||
|
gicdev = qdev_create(NULL, gictype);
|
||||||
|
qdev_prop_set_uint32(gicdev, "revision", 2);
|
||||||
|
qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
|
||||||
|
/* Note that the num-irq property counts both internal and external
|
||||||
|
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
||||||
|
*/
|
||||||
|
qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
|
||||||
|
qdev_init_nofail(gicdev);
|
||||||
|
gicbusdev = SYS_BUS_DEVICE(gicdev);
|
||||||
|
sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
|
||||||
|
sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
|
||||||
|
|
||||||
|
/* Wire the outputs from each CPU's generic timer to the
|
||||||
|
* appropriate GIC PPI inputs, and the GIC's IRQ output to
|
||||||
|
* the CPU's IRQ input.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
|
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||||
|
int ppibase = NUM_IRQS + i * 32;
|
||||||
|
/* physical timer; we wire it up to the non-secure timer's ID,
|
||||||
|
* since a real A15 always has TrustZone but QEMU doesn't.
|
||||||
|
*/
|
||||||
|
qdev_connect_gpio_out(cpudev, 0,
|
||||||
|
qdev_get_gpio_in(gicdev, ppibase + 30));
|
||||||
|
/* virtual timer */
|
||||||
|
qdev_connect_gpio_out(cpudev, 1,
|
||||||
|
qdev_get_gpio_in(gicdev, ppibase + 27));
|
||||||
|
|
||||||
|
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_IRQS; i++) {
|
||||||
|
pic[i] = qdev_get_gpio_in(gicdev, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt_add_gic_node(vbi);
|
||||||
|
}
|
||||||
|
|
||||||
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
{
|
{
|
||||||
char *nodename;
|
char *nodename;
|
||||||
@@ -340,8 +389,6 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
|||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
int n;
|
int n;
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
DeviceState *dev;
|
|
||||||
SysBusDevice *busdev;
|
|
||||||
const char *cpu_model = args->cpu_model;
|
const char *cpu_model = args->cpu_model;
|
||||||
VirtBoardInfo *vbi;
|
VirtBoardInfo *vbi;
|
||||||
|
|
||||||
@@ -404,25 +451,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
|||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
||||||
|
|
||||||
dev = qdev_create(NULL, vbi->qdevname);
|
create_gic(vbi, pic);
|
||||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
|
||||||
/* Note that the num-irq property counts both internal and external
|
|
||||||
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
|
||||||
*/
|
|
||||||
qdev_prop_set_uint32(dev, "num-irq", NUM_IRQS + 32);
|
|
||||||
qdev_init_nofail(dev);
|
|
||||||
busdev = SYS_BUS_DEVICE(dev);
|
|
||||||
sysbus_mmio_map(busdev, 0, vbi->memmap[VIRT_CPUPERIPHS].base);
|
|
||||||
fdt_add_gic_node(vbi);
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
|
||||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
|
|
||||||
|
|
||||||
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n = 0; n < NUM_IRQS; n++) {
|
|
||||||
pic[n] = qdev_get_gpio_in(dev, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
create_uart(vbi, pic);
|
create_uart(vbi, pic);
|
||||||
|
|
||||||
|
@@ -164,7 +164,6 @@ static VMStateDescription vmstate_zipit_lcd_state = {
|
|||||||
.name = "zipit-lcd",
|
.name = "zipit-lcd",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 2,
|
.minimum_version_id = 2,
|
||||||
.minimum_version_id_old = 2,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_SSI_SLAVE(ssidev, ZipitLCD),
|
VMSTATE_SSI_SLAVE(ssidev, ZipitLCD),
|
||||||
VMSTATE_INT32(selected, ZipitLCD),
|
VMSTATE_INT32(selected, ZipitLCD),
|
||||||
@@ -275,7 +274,6 @@ static VMStateDescription vmstate_aer915_state = {
|
|||||||
.name = "aer915",
|
.name = "aer915",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_INT32(len, AER915State),
|
VMSTATE_INT32(len, AER915State),
|
||||||
VMSTATE_BUFFER(buf, AER915State),
|
VMSTATE_BUFFER(buf, AER915State),
|
||||||
|
@@ -86,6 +86,7 @@ typedef struct {
|
|||||||
#ifndef HAS_YMF262
|
#ifndef HAS_YMF262
|
||||||
FM_OPL *opl;
|
FM_OPL *opl;
|
||||||
#endif
|
#endif
|
||||||
|
PortioList port_list;
|
||||||
} AdlibState;
|
} AdlibState;
|
||||||
|
|
||||||
static AdlibState *glob_adlib;
|
static AdlibState *glob_adlib;
|
||||||
@@ -293,7 +294,6 @@ static MemoryRegionPortio adlib_portio_list[] = {
|
|||||||
static void adlib_realizefn (DeviceState *dev, Error **errp)
|
static void adlib_realizefn (DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
AdlibState *s = ADLIB(dev);
|
AdlibState *s = ADLIB(dev);
|
||||||
PortioList *port_list = g_new(PortioList, 1);
|
|
||||||
struct audsettings as;
|
struct audsettings as;
|
||||||
|
|
||||||
if (glob_adlib) {
|
if (glob_adlib) {
|
||||||
@@ -349,8 +349,8 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
adlib_portio_list[0].offset = s->port;
|
adlib_portio_list[0].offset = s->port;
|
||||||
adlib_portio_list[1].offset = s->port + 8;
|
adlib_portio_list[1].offset = s->port + 8;
|
||||||
portio_list_init (port_list, OBJECT(s), adlib_portio_list, s, "adlib");
|
portio_list_init (&s->port_list, OBJECT(s), adlib_portio_list, s, "adlib");
|
||||||
portio_list_add (port_list, isa_address_space_io(&s->parent_obj), 0);
|
portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property adlib_properties[] = {
|
static Property adlib_properties[] = {
|
||||||
|
@@ -261,6 +261,9 @@ static void hda_audio_set_amp(HDAAudioStream *st)
|
|||||||
left = left * 255 / QEMU_HDA_AMP_STEPS;
|
left = left * 255 / QEMU_HDA_AMP_STEPS;
|
||||||
right = right * 255 / QEMU_HDA_AMP_STEPS;
|
right = right * 255 / QEMU_HDA_AMP_STEPS;
|
||||||
|
|
||||||
|
if (!st->state->mixer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (st->output) {
|
if (st->output) {
|
||||||
AUD_set_volume_out(st->voice.out, muted, left, right);
|
AUD_set_volume_out(st->voice.out, muted, left, right);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -245,7 +245,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
|
|||||||
|
|
||||||
/* update global status */
|
/* update global status */
|
||||||
if (sts & d->int_ctl) {
|
if (sts & d->int_ctl) {
|
||||||
sts |= (1 << 31);
|
sts |= (1U << 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
d->int_sts = sts;
|
d->int_sts = sts;
|
||||||
@@ -257,7 +257,7 @@ static void intel_hda_update_irq(IntelHDAState *d)
|
|||||||
int level;
|
int level;
|
||||||
|
|
||||||
intel_hda_update_int_sts(d);
|
intel_hda_update_int_sts(d);
|
||||||
if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
|
if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) {
|
||||||
level = 1;
|
level = 1;
|
||||||
} else {
|
} else {
|
||||||
level = 0;
|
level = 0;
|
||||||
@@ -574,7 +574,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
|
|||||||
if (st->ctl & 0x01) {
|
if (st->ctl & 0x01) {
|
||||||
/* reset */
|
/* reset */
|
||||||
dprint(d, 1, "st #%d: reset\n", reg->stream);
|
dprint(d, 1, "st #%d: reset\n", reg->stream);
|
||||||
st->ctl = 0;
|
st->ctl = SD_STS_FIFO_READY << 24;
|
||||||
}
|
}
|
||||||
if ((st->ctl & 0x02) != (old & 0x02)) {
|
if ((st->ctl & 0x02) != (old & 0x02)) {
|
||||||
uint32_t stnr = (st->ctl >> 20) & 0x0f;
|
uint32_t stnr = (st->ctl >> 20) & 0x0f;
|
||||||
@@ -829,6 +829,7 @@ static const struct IntelHDAReg regtab[] = {
|
|||||||
.wclear = 0x1c000000, \
|
.wclear = 0x1c000000, \
|
||||||
.offset = offsetof(IntelHDAState, st[_i].ctl), \
|
.offset = offsetof(IntelHDAState, st[_i].ctl), \
|
||||||
.whandler = intel_hda_set_st_ctl, \
|
.whandler = intel_hda_set_st_ctl, \
|
||||||
|
.reset = SD_STS_FIFO_READY << 24 \
|
||||||
}, \
|
}, \
|
||||||
[ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
|
[ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
|
||||||
.stream = _i, \
|
.stream = _i, \
|
||||||
|
@@ -324,9 +324,8 @@ const VMStateDescription vmstate_lm4549_state = {
|
|||||||
.name = "lm4549_state",
|
.name = "lm4549_state",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.post_load = lm4549_post_load,
|
||||||
.post_load = &lm4549_post_load,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32(voice_is_active, lm4549_state),
|
VMSTATE_UINT32(voice_is_active, lm4549_state),
|
||||||
VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
|
VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
|
||||||
VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE),
|
VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE),
|
||||||
|
@@ -259,7 +259,6 @@ static const VMStateDescription mv88w8618_audio_vmsd = {
|
|||||||
.name = "mv88w8618_audio",
|
.name = "mv88w8618_audio",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(playback_mode, mv88w8618_audio_state),
|
VMSTATE_UINT32(playback_mode, mv88w8618_audio_state),
|
||||||
VMSTATE_UINT32(status, mv88w8618_audio_state),
|
VMSTATE_UINT32(status, mv88w8618_audio_state),
|
||||||
|
@@ -316,9 +316,8 @@ static const VMStateDescription vmstate_milkymist_ac97 = {
|
|||||||
.name = "milkymist-ac97",
|
.name = "milkymist-ac97",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.post_load = ac97_post_load,
|
.post_load = ac97_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
|
VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
|
@@ -561,8 +561,7 @@ static const VMStateDescription vmstate_pl041_regfile = {
|
|||||||
.name = "pl041_regfile",
|
.name = "pl041_regfile",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile),
|
#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile),
|
||||||
#include "pl041.hx"
|
#include "pl041.hx"
|
||||||
#undef REGISTER
|
#undef REGISTER
|
||||||
@@ -574,8 +573,7 @@ static const VMStateDescription vmstate_pl041_fifo = {
|
|||||||
.name = "pl041_fifo",
|
.name = "pl041_fifo",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT32(level, pl041_fifo),
|
VMSTATE_UINT32(level, pl041_fifo),
|
||||||
VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH),
|
VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
@@ -586,8 +584,7 @@ static const VMStateDescription vmstate_pl041_channel = {
|
|||||||
.name = "pl041_channel",
|
.name = "pl041_channel",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_STRUCT(tx_fifo, pl041_channel, 0,
|
VMSTATE_STRUCT(tx_fifo, pl041_channel, 0,
|
||||||
vmstate_pl041_fifo, pl041_fifo),
|
vmstate_pl041_fifo, pl041_fifo),
|
||||||
VMSTATE_UINT8(tx_enabled, pl041_channel),
|
VMSTATE_UINT8(tx_enabled, pl041_channel),
|
||||||
|
@@ -583,10 +583,9 @@ static const VMStateDescription vmstate_wm8750 = {
|
|||||||
.name = CODEC,
|
.name = CODEC,
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
|
||||||
.pre_save = wm8750_pre_save,
|
.pre_save = wm8750_pre_save,
|
||||||
.post_load = wm8750_post_load,
|
.post_load = wm8750_post_load,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
|
VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
|
||||||
VMSTATE_INT32(i2c_len, WM8750State),
|
VMSTATE_INT32(i2c_len, WM8750State),
|
||||||
VMSTATE_INT32(enable, WM8750State),
|
VMSTATE_INT32(enable, WM8750State),
|
||||||
|
@@ -81,8 +81,7 @@ VMStateDescription vmstate_ecc_state = {
|
|||||||
.name = "ecc-state",
|
.name = "ecc-state",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.minimum_version_id_old = 0,
|
.fields = (VMStateField[]) {
|
||||||
.fields = (VMStateField []) {
|
|
||||||
VMSTATE_UINT8(cp, ECCState),
|
VMSTATE_UINT8(cp, ECCState),
|
||||||
VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
|
VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
|
||||||
VMSTATE_UINT16(count, ECCState),
|
VMSTATE_UINT16(count, ECCState),
|
||||||
|
@@ -653,7 +653,6 @@ static const VMStateDescription vmstate_m25p80 = {
|
|||||||
.name = "xilinx_spi",
|
.name = "xilinx_spi",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.pre_save = m25p80_pre_save,
|
.pre_save = m25p80_pre_save,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT8(state, Flash),
|
VMSTATE_UINT8(state, Flash),
|
||||||
|
@@ -346,10 +346,9 @@ static const VMStateDescription vmstate_nand = {
|
|||||||
.name = "nand",
|
.name = "nand",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.pre_save = nand_pre_save,
|
.pre_save = nand_pre_save,
|
||||||
.post_load = nand_post_load,
|
.post_load = nand_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT8(cle, NANDFlashState),
|
VMSTATE_UINT8(cle, NANDFlashState),
|
||||||
VMSTATE_UINT8(ale, NANDFlashState),
|
VMSTATE_UINT8(ale, NANDFlashState),
|
||||||
VMSTATE_UINT8(ce, NANDFlashState),
|
VMSTATE_UINT8(ce, NANDFlashState),
|
||||||
|
@@ -169,7 +169,6 @@ static const VMStateDescription vmstate_onenand = {
|
|||||||
.name = "onenand",
|
.name = "onenand",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
|
||||||
.pre_save = onenand_pre_save,
|
.pre_save = onenand_pre_save,
|
||||||
.post_load = onenand_post_load,
|
.post_load = onenand_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
|
@@ -79,6 +79,12 @@ static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_reque
|
|||||||
dst->handle = src->handle;
|
dst->handle = src->handle;
|
||||||
dst->id = src->id;
|
dst->id = src->id;
|
||||||
dst->sector_number = src->sector_number;
|
dst->sector_number = src->sector_number;
|
||||||
|
if (src->operation == BLKIF_OP_DISCARD) {
|
||||||
|
struct blkif_request_discard *s = (void *)src;
|
||||||
|
struct blkif_request_discard *d = (void *)dst;
|
||||||
|
d->nr_sectors = s->nr_sectors;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (n > src->nr_segments)
|
if (n > src->nr_segments)
|
||||||
n = src->nr_segments;
|
n = src->nr_segments;
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
@@ -94,6 +100,12 @@ static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_reque
|
|||||||
dst->handle = src->handle;
|
dst->handle = src->handle;
|
||||||
dst->id = src->id;
|
dst->id = src->id;
|
||||||
dst->sector_number = src->sector_number;
|
dst->sector_number = src->sector_number;
|
||||||
|
if (src->operation == BLKIF_OP_DISCARD) {
|
||||||
|
struct blkif_request_discard *s = (void *)src;
|
||||||
|
struct blkif_request_discard *d = (void *)dst;
|
||||||
|
d->nr_sectors = s->nr_sectors;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (n > src->nr_segments)
|
if (n > src->nr_segments)
|
||||||
n = src->nr_segments;
|
n = src->nr_segments;
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
|
@@ -114,6 +114,7 @@ struct XenBlkDev {
|
|||||||
int requests_finished;
|
int requests_finished;
|
||||||
|
|
||||||
/* Persistent grants extension */
|
/* Persistent grants extension */
|
||||||
|
gboolean feature_discard;
|
||||||
gboolean feature_persistent;
|
gboolean feature_persistent;
|
||||||
GTree *persistent_gnts;
|
GTree *persistent_gnts;
|
||||||
unsigned int persistent_gnt_count;
|
unsigned int persistent_gnt_count;
|
||||||
@@ -253,6 +254,8 @@ static int ioreq_parse(struct ioreq *ioreq)
|
|||||||
case BLKIF_OP_WRITE:
|
case BLKIF_OP_WRITE:
|
||||||
ioreq->prot = PROT_READ; /* from memory */
|
ioreq->prot = PROT_READ; /* from memory */
|
||||||
break;
|
break;
|
||||||
|
case BLKIF_OP_DISCARD:
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
|
xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
|
||||||
ioreq->req.operation);
|
ioreq->req.operation);
|
||||||
@@ -492,6 +495,7 @@ static void qemu_aio_complete(void *opaque, int ret)
|
|||||||
case BLKIF_OP_READ:
|
case BLKIF_OP_READ:
|
||||||
bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
|
bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
|
||||||
break;
|
break;
|
||||||
|
case BLKIF_OP_DISCARD:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -532,6 +536,15 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
|||||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||||
qemu_aio_complete, ioreq);
|
qemu_aio_complete, ioreq);
|
||||||
break;
|
break;
|
||||||
|
case BLKIF_OP_DISCARD:
|
||||||
|
{
|
||||||
|
struct blkif_request_discard *discard_req = (void *)&ioreq->req;
|
||||||
|
ioreq->aio_inflight++;
|
||||||
|
bdrv_aio_discard(blkdev->bs,
|
||||||
|
discard_req->sector_number, discard_req->nr_sectors,
|
||||||
|
qemu_aio_complete, ioreq);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
/* unknown operation (shouldn't happen -- parse catches this) */
|
/* unknown operation (shouldn't happen -- parse catches this) */
|
||||||
goto err;
|
goto err;
|
||||||
@@ -710,6 +723,21 @@ static void blk_alloc(struct XenDevice *xendev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void blk_parse_discard(struct XenBlkDev *blkdev)
|
||||||
|
{
|
||||||
|
int enable;
|
||||||
|
|
||||||
|
blkdev->feature_discard = true;
|
||||||
|
|
||||||
|
if (xenstore_read_be_int(&blkdev->xendev, "discard-enable", &enable) == 0) {
|
||||||
|
blkdev->feature_discard = !!enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blkdev->feature_discard) {
|
||||||
|
xenstore_write_be_int(&blkdev->xendev, "feature-discard", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int blk_init(struct XenDevice *xendev)
|
static int blk_init(struct XenDevice *xendev)
|
||||||
{
|
{
|
||||||
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
||||||
@@ -777,6 +805,8 @@ static int blk_init(struct XenDevice *xendev)
|
|||||||
xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1);
|
xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1);
|
||||||
xenstore_write_be_int(&blkdev->xendev, "info", info);
|
xenstore_write_be_int(&blkdev->xendev, "info", info);
|
||||||
|
|
||||||
|
blk_parse_discard(blkdev);
|
||||||
|
|
||||||
g_free(directiosafe);
|
g_free(directiosafe);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -812,16 +842,22 @@ static int blk_connect(struct XenDevice *xendev)
|
|||||||
qflags |= BDRV_O_RDWR;
|
qflags |= BDRV_O_RDWR;
|
||||||
readonly = false;
|
readonly = false;
|
||||||
}
|
}
|
||||||
|
if (blkdev->feature_discard) {
|
||||||
|
qflags |= BDRV_O_UNMAP;
|
||||||
|
}
|
||||||
|
|
||||||
/* init qemu block driver */
|
/* init qemu block driver */
|
||||||
index = (blkdev->xendev.dev - 202 * 256) / 16;
|
index = (blkdev->xendev.dev - 202 * 256) / 16;
|
||||||
blkdev->dinfo = drive_get(IF_XEN, 0, index);
|
blkdev->dinfo = drive_get(IF_XEN, 0, index);
|
||||||
if (!blkdev->dinfo) {
|
if (!blkdev->dinfo) {
|
||||||
|
Error *local_err = NULL;
|
||||||
/* setup via xenbus -> create new block driver instance */
|
/* setup via xenbus -> create new block driver instance */
|
||||||
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
||||||
blkdev->bs = bdrv_new(blkdev->dev);
|
blkdev->bs = bdrv_new(blkdev->dev, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
blkdev->bs = NULL;
|
||||||
|
}
|
||||||
if (blkdev->bs) {
|
if (blkdev->bs) {
|
||||||
Error *local_err = NULL;
|
|
||||||
BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto,
|
BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto,
|
||||||
readonly);
|
readonly);
|
||||||
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
|
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user