Compare commits
850 Commits
pull-gtk-2
...
pull-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ee4de5840 | ||
|
|
ba4d26064e | ||
|
|
4083ae311d | ||
|
|
699eae17b8 | ||
|
|
de5ee4a888 | ||
|
|
db5fd8d709 | ||
|
|
82f11917c9 | ||
|
|
800e2ecc89 | ||
|
|
355392329e | ||
|
|
9220fe54c6 | ||
|
|
177ea79f65 | ||
|
|
5a0826f7d2 | ||
|
|
1535300119 | ||
|
|
d8d5119cae | ||
|
|
5899d6d0b4 | ||
|
|
b8d6ac9f90 | ||
|
|
2ccf97ec0f | ||
|
|
eb513f82f0 | ||
|
|
24e60305c5 | ||
|
|
0c021c1fd2 | ||
|
|
ec53b45bcd | ||
|
|
83ecb22ba2 | ||
|
|
a5bd4470ed | ||
|
|
86a6a9bf55 | ||
|
|
9b6d7b365d | ||
|
|
3996e85c18 | ||
|
|
707ff80021 | ||
|
|
74acb99737 | ||
|
|
877417d9ae | ||
|
|
7dd93291ca | ||
|
|
fcf73af68e | ||
|
|
0002a51889 | ||
|
|
34da30afa4 | ||
|
|
8cd996f493 | ||
|
|
49743df399 | ||
|
|
aca7aaf628 | ||
|
|
1e42c35346 | ||
|
|
36b62ae6a5 | ||
|
|
b449ca3c18 | ||
|
|
e68cba3636 | ||
|
|
ea987c2c21 | ||
|
|
a26ba26e21 | ||
|
|
131fe9b843 | ||
|
|
e1a8c9b67f | ||
|
|
8580b06498 | ||
|
|
f018d8cd21 | ||
|
|
1b826f2778 | ||
|
|
27af7d6ea5 | ||
|
|
df58887b20 | ||
|
|
99efa84d5c | ||
|
|
31fc97c314 | ||
|
|
ae21935924 | ||
|
|
3d59b6808b | ||
|
|
fac6688a18 | ||
|
|
b4952c3677 | ||
|
|
1281f8e308 | ||
|
|
37097418be | ||
|
|
90d6a6730b | ||
|
|
2d8ac5eb7a | ||
|
|
9c6d5c1ade | ||
|
|
9feb8adeaa | ||
|
|
b629a38a13 | ||
|
|
1979b908b6 | ||
|
|
f186aa976b | ||
|
|
488eef2f1d | ||
|
|
c88f68ec3c | ||
|
|
6f84da3a07 | ||
|
|
e1660dc57c | ||
|
|
bee818872c | ||
|
|
07958082fd | ||
|
|
3b9985e9a1 | ||
|
|
3a7f560fa6 | ||
|
|
c1d322e604 | ||
|
|
a00369fc56 | ||
|
|
07d31d07f4 | ||
|
|
47b0f45a92 | ||
|
|
5734edd837 | ||
|
|
e7026f1953 | ||
|
|
9a502563ee | ||
|
|
bb00021de0 | ||
|
|
095e4fa4b5 | ||
|
|
51a2219bdc | ||
|
|
66552b894b | ||
|
|
4d68e86bb1 | ||
|
|
c740ad92d0 | ||
|
|
6d86ae0824 | ||
|
|
ef57137f1b | ||
|
|
d1d1b206b0 | ||
|
|
bc52169660 | ||
|
|
9c8ab1ae0d | ||
|
|
a2d9c0c407 | ||
|
|
1dbe67503b | ||
|
|
99605175c9 | ||
|
|
292be092ad | ||
|
|
04636dc410 | ||
|
|
4dd7b8d30c | ||
|
|
7c6a4ab871 | ||
|
|
bd8baecddc | ||
|
|
c29c1dd312 | ||
|
|
b7b9d39a7a | ||
|
|
c4237dfa63 | ||
|
|
a06e43556e | ||
|
|
527ab22a2a | ||
|
|
1085daf941 | ||
|
|
291680186f | ||
|
|
9f07429e88 | ||
|
|
0a82855a1a | ||
|
|
a97ceca578 | ||
|
|
ee82310f8a | ||
|
|
e012b78cf5 | ||
|
|
fcf5def1ab | ||
|
|
b8aff7d6bf | ||
|
|
709e57753b | ||
|
|
7d5ad15d17 | ||
|
|
a39d97c7be | ||
|
|
d46858377b | ||
|
|
b4f72e31b9 | ||
|
|
57407ea44c | ||
|
|
5435f1d77e | ||
|
|
9e03a0405d | ||
|
|
863f6f52b7 | ||
|
|
8cba80c3a0 | ||
|
|
59ac15326e | ||
|
|
fdb78ec006 | ||
|
|
6781fc412e | ||
|
|
fb85b34da7 | ||
|
|
64ea8038ff | ||
|
|
aaf0301917 | ||
|
|
97052d64e4 | ||
|
|
e77d927f1a | ||
|
|
ec2cbbdd80 | ||
|
|
c00cd99527 | ||
|
|
719cac1ce2 | ||
|
|
4d91558d60 | ||
|
|
364c3e6b8d | ||
|
|
e76d442043 | ||
|
|
f1c5831ca3 | ||
|
|
11fe680858 | ||
|
|
a4ba200894 | ||
|
|
b3e27c3aee | ||
|
|
29c6e6df49 | ||
|
|
7d010ae9e0 | ||
|
|
59a0419856 | ||
|
|
d941fba0b5 | ||
|
|
b1c2fb9b29 | ||
|
|
de77a243b3 | ||
|
|
5e97b623c2 | ||
|
|
f8b6f8edac | ||
|
|
a1666142db | ||
|
|
60786ef339 | ||
|
|
b0cc3f8397 | ||
|
|
62be4e3a50 | ||
|
|
9b8424d573 | ||
|
|
c8d6f66ae7 | ||
|
|
e7af4c6730 | ||
|
|
75c74ccbe1 | ||
|
|
4ee9ced979 | ||
|
|
b8cbc738de | ||
|
|
09f28e5b51 | ||
|
|
759bf45d81 | ||
|
|
c760dbb9dc | ||
|
|
2f285bdd54 | ||
|
|
466976d9ee | ||
|
|
82e345f57e | ||
|
|
f83c2378bb | ||
|
|
aeedd58234 | ||
|
|
56a846157e | ||
|
|
0ff93d11bc | ||
|
|
aac862379c | ||
|
|
3e28c5e363 | ||
|
|
69d1a93774 | ||
|
|
e43668a7d2 | ||
|
|
f90468b646 | ||
|
|
549cfe5d5d | ||
|
|
5f9490de56 | ||
|
|
77bad151fb | ||
|
|
2bf9febc95 | ||
|
|
e6b8fd246c | ||
|
|
338c25b692 | ||
|
|
01a579729b | ||
|
|
e094c4c12f | ||
|
|
58dd0a4787 | ||
|
|
7d45556eff | ||
|
|
00e6fd3e03 | ||
|
|
14ba79c73a | ||
|
|
4814f2d116 | ||
|
|
b748863a7f | ||
|
|
2791128e2f | ||
|
|
cb3778a045 | ||
|
|
44045ce974 | ||
|
|
e6b4e5f479 | ||
|
|
2eaaac1f01 | ||
|
|
ea259acae5 | ||
|
|
aa49668cc3 | ||
|
|
a3a292c420 | ||
|
|
08f432aa3e | ||
|
|
f2f6e00b2e | ||
|
|
5aa8136020 | ||
|
|
debfb917a4 | ||
|
|
d13c040409 | ||
|
|
bfa7362889 | ||
|
|
cd42d5b236 | ||
|
|
bd79255d25 | ||
|
|
4eab7a0a23 | ||
|
|
857cccac0d | ||
|
|
ab0302ee76 | ||
|
|
03de06dde5 | ||
|
|
0266359e57 | ||
|
|
69b058c881 | ||
|
|
2cbcfb281a | ||
|
|
aa351061db | ||
|
|
07abe45c48 | ||
|
|
7d48a0f721 | ||
|
|
578f3c7b08 | ||
|
|
6c87e3d596 | ||
|
|
cfaadf0e89 | ||
|
|
ff6cff7554 | ||
|
|
d789c84547 | ||
|
|
86099db382 | ||
|
|
66708822cd | ||
|
|
5712db6ae5 | ||
|
|
c0ccb02db4 | ||
|
|
61e2f3521c | ||
|
|
223a72f117 | ||
|
|
e5a5604f8f | ||
|
|
12d027f132 | ||
|
|
c8e829b7bf | ||
|
|
51942aee3c | ||
|
|
08828484a5 | ||
|
|
083a58906c | ||
|
|
c29196904b | ||
|
|
e364bab69b | ||
|
|
4902192432 | ||
|
|
af7c9f34b1 | ||
|
|
9ee00ba831 | ||
|
|
7eb1dc7f0b | ||
|
|
52eb3dfd7d | ||
|
|
2e16898a61 | ||
|
|
49d2e648e8 | ||
|
|
60fb1a87b4 | ||
|
|
b28fb27b5e | ||
|
|
dcbfc5cefb | ||
|
|
e2c7d025ad | ||
|
|
df92ee4448 | ||
|
|
62356b7292 | ||
|
|
d13dd2d7a9 | ||
|
|
a664477db8 | ||
|
|
b47d8efa9f | ||
|
|
462037c9e8 | ||
|
|
7e58e2ac77 | ||
|
|
7db96d6cf8 | ||
|
|
ddcd55316f | ||
|
|
3b08098b40 | ||
|
|
f1839938b0 | ||
|
|
703008e81a | ||
|
|
9816833d3b | ||
|
|
c95f3901b4 | ||
|
|
9655b9328a | ||
|
|
436d63ff3e | ||
|
|
b5fd8fa345 | ||
|
|
e2bed107c6 | ||
|
|
f2f1585f60 | ||
|
|
0b79a78169 | ||
|
|
d5de7839d7 | ||
|
|
e4e3917630 | ||
|
|
7f13420ec0 | ||
|
|
45820fccaf | ||
|
|
4b5b443576 | ||
|
|
af715d9802 | ||
|
|
781b717c50 | ||
|
|
328b3b6c44 | ||
|
|
c4e7c17a8e | ||
|
|
adee64249e | ||
|
|
f9d8f66735 | ||
|
|
5546a621a8 | ||
|
|
079eb19cbb | ||
|
|
9ee27d7381 | ||
|
|
cf7087db10 | ||
|
|
c67676711c | ||
|
|
385f57cf9a | ||
|
|
20302e71a5 | ||
|
|
58889fe50a | ||
|
|
71e28e3cc2 | ||
|
|
23120b13c6 | ||
|
|
756ae78b27 | ||
|
|
b574f60268 | ||
|
|
86b182ac0e | ||
|
|
84afc4dd56 | ||
|
|
c246cee4ee | ||
|
|
d3f3a0f453 | ||
|
|
1dfc5c8808 | ||
|
|
62959ffe45 | ||
|
|
63ed4907cb | ||
|
|
0d01b7ce61 | ||
|
|
2c3056f182 | ||
|
|
46522a8223 | ||
|
|
f1ddebd865 | ||
|
|
44f017d03e | ||
|
|
8fc1a3f58f | ||
|
|
5d0fe65078 | ||
|
|
97e89ee914 | ||
|
|
2db59a76c4 | ||
|
|
85d36377e4 | ||
|
|
01673a3401 | ||
|
|
246ae24d7d | ||
|
|
339aaf5b7f | ||
|
|
d86fb03469 | ||
|
|
4db753b1ac | ||
|
|
46817e86fc | ||
|
|
22382bb96c | ||
|
|
b9fd11b867 | ||
|
|
5508099397 | ||
|
|
a41642708a | ||
|
|
e0883e2de0 | ||
|
|
cf7856adef | ||
|
|
555e72f2d0 | ||
|
|
3dcadce507 | ||
|
|
0b2824e5e4 | ||
|
|
d29c431edc | ||
|
|
d4fa5354a2 | ||
|
|
8ef3915263 | ||
|
|
8e5f757044 | ||
|
|
00fb4a1181 | ||
|
|
66991d1103 | ||
|
|
1a4d570017 | ||
|
|
bb962386b8 | ||
|
|
74797f40dc | ||
|
|
1d725ae952 | ||
|
|
cbb26c9a12 | ||
|
|
c48245f0c6 | ||
|
|
d922445020 | ||
|
|
90f12d735d | ||
|
|
27e1fb13f2 | ||
|
|
7215d7e7ae | ||
|
|
81a423e6c6 | ||
|
|
f88f79ec9d | ||
|
|
c357747981 | ||
|
|
8fc605b8aa | ||
|
|
51fdea945a | ||
|
|
2b09f94cdb | ||
|
|
d2bfa6e622 | ||
|
|
6225a4a0e3 | ||
|
|
d75de74967 | ||
|
|
4386f08767 | ||
|
|
11f5ea105c | ||
|
|
8280b12c0e | ||
|
|
36b86e0dc2 | ||
|
|
c7d4d98ae7 | ||
|
|
800675f117 | ||
|
|
44a1f94684 | ||
|
|
977184db39 | ||
|
|
4f9d090012 | ||
|
|
329c9b10b6 | ||
|
|
60fe637bf0 | ||
|
|
d6d69731f5 | ||
|
|
b78accf614 | ||
|
|
fd5f3b6367 | ||
|
|
1240be2435 | ||
|
|
68a5e38a7e | ||
|
|
1f51a5cb97 | ||
|
|
c55156402e | ||
|
|
7f4675c3f7 | ||
|
|
dfa9c2a0f4 | ||
|
|
224d10ff5a | ||
|
|
ece5e5bfa1 | ||
|
|
7302dcd60b | ||
|
|
d368ba4376 | ||
|
|
c7ff8daacf | ||
|
|
1645b8eee5 | ||
|
|
023c3a9707 | ||
|
|
0d931d7062 | ||
|
|
4e02b0fcf5 | ||
|
|
269e235849 | ||
|
|
575a6f4082 | ||
|
|
2f9ac42acf | ||
|
|
78a611f193 | ||
|
|
b3a4f0b1a0 | ||
|
|
64bbd372f2 | ||
|
|
5b9efc39ae | ||
|
|
bf2a7ddb0a | ||
|
|
4e7fa73ec2 | ||
|
|
d8a499f17e | ||
|
|
2a62914bd8 | ||
|
|
626cf8f4c6 | ||
|
|
e511b4d783 | ||
|
|
b4ac20b4df | ||
|
|
f8e1f53334 | ||
|
|
3c55fe2a13 | ||
|
|
0bd0adbe5b | ||
|
|
1c3381af32 | ||
|
|
e42a92ae64 | ||
|
|
ab3ad07f89 | ||
|
|
4be34d1e21 | ||
|
|
18fc805534 | ||
|
|
18cd2c17b5 | ||
|
|
906b53a2de | ||
|
|
0bb0b2d2fe | ||
|
|
e9af2fef24 | ||
|
|
e6eef7c221 | ||
|
|
076796f8fd | ||
|
|
d19ae73e98 | ||
|
|
c7fe4b1298 | ||
|
|
bdfc8480c5 | ||
|
|
b0a0551283 | ||
|
|
5e0b7d8869 | ||
|
|
d229b985b5 | ||
|
|
9fc0e2d8ac | ||
|
|
f41389ae3c | ||
|
|
9551ea6991 | ||
|
|
5eba5a6632 | ||
|
|
54600752a1 | ||
|
|
c4d4525c38 | ||
|
|
18b41f95d2 | ||
|
|
ea32aaf1a7 | ||
|
|
e0d3795654 | ||
|
|
82595da8de | ||
|
|
de35464461 | ||
|
|
8455ce053a | ||
|
|
43f2376e09 | ||
|
|
28b240877b | ||
|
|
b5cf2c1b08 | ||
|
|
43c5d8f800 | ||
|
|
7486458c33 | ||
|
|
85b712c9d5 | ||
|
|
3f394472c5 | ||
|
|
9e0c3e8df5 | ||
|
|
0e82dc7bbd | ||
|
|
30af51ce7f | ||
|
|
a9d1e9daa5 | ||
|
|
0571df44a1 | ||
|
|
9281dbe653 | ||
|
|
942764cc32 | ||
|
|
5c98415b2a | ||
|
|
ebd9fbd7e1 | ||
|
|
99c9c3cb24 | ||
|
|
64baadc272 | ||
|
|
97c61fb78a | ||
|
|
b141290478 | ||
|
|
7c3843332d | ||
|
|
25f2895e0e | ||
|
|
a7130a3ef9 | ||
|
|
38df27c8a7 | ||
|
|
72149414e2 | ||
|
|
a554ecb49d | ||
|
|
b1ab03af89 | ||
|
|
be693c87e4 | ||
|
|
54bf36ed35 | ||
|
|
fb6c91ba2b | ||
|
|
01c097f796 | ||
|
|
b848ce2b9c | ||
|
|
4a7e2d7315 | ||
|
|
88ca1c2d70 | ||
|
|
0c17d68c1d | ||
|
|
11f136ee25 | ||
|
|
7dd8c9af0d | ||
|
|
b85a1fd61c | ||
|
|
6e8801f9de | ||
|
|
137feaa9a1 | ||
|
|
e89e51a17e | ||
|
|
144634ae6c | ||
|
|
770225764f | ||
|
|
de38d23b54 | ||
|
|
0f1a3b2470 | ||
|
|
3f3c82a57d | ||
|
|
51a79b0397 | ||
|
|
c3e3026062 | ||
|
|
3f342b9e0e | ||
|
|
ea30a4b824 | ||
|
|
0eeb17d618 | ||
|
|
57e3a0c7cb | ||
|
|
a38bb0792c | ||
|
|
1ecc3a2df1 | ||
|
|
a09f2d16f6 | ||
|
|
67a5eebca1 | ||
|
|
df6f93182a | ||
|
|
328f1f0f08 | ||
|
|
2b2f7d97d8 | ||
|
|
ed51626066 | ||
|
|
47e04430ed | ||
|
|
0974257ed5 | ||
|
|
a68e0d547f | ||
|
|
83c1bb1868 | ||
|
|
fc2ef4a391 | ||
|
|
3fb763cb55 | ||
|
|
d899d2e248 | ||
|
|
9aeecbbc62 | ||
|
|
03c3359dfc | ||
|
|
73b7bcad43 | ||
|
|
8a3e0bc370 | ||
|
|
e5dc64b8ff | ||
|
|
3ba235a022 | ||
|
|
625fa9fe6f | ||
|
|
0d0d7f47b4 | ||
|
|
0fc9b0d162 | ||
|
|
01212d4ed6 | ||
|
|
6a69b9620a | ||
|
|
3b5e14c76a | ||
|
|
11c89769dc | ||
|
|
2247798d13 | ||
|
|
f798068c56 | ||
|
|
b2439d26f0 | ||
|
|
f75613cf24 | ||
|
|
c614972408 | ||
|
|
fd752801ae | ||
|
|
1bcb15cf77 | ||
|
|
ef8104378c | ||
|
|
5f535a941e | ||
|
|
b89689f5b2 | ||
|
|
d20051856c | ||
|
|
be0677a93c | ||
|
|
d11032315a | ||
|
|
e800e5d4e2 | ||
|
|
a56ebc6ba4 | ||
|
|
c5f6e493bb | ||
|
|
8884dd1bbc | ||
|
|
2ebafc854d | ||
|
|
3dc7ca3c97 | ||
|
|
5d6e96efb8 | ||
|
|
73f1f7564d | ||
|
|
b756b9ce8a | ||
|
|
00e047926e | ||
|
|
d71a8b0686 | ||
|
|
38f3ef574b | ||
|
|
7cddd3728e | ||
|
|
c6684249fd | ||
|
|
b8e665e4d8 | ||
|
|
90c9b1671e | ||
|
|
8f9e835fd2 | ||
|
|
be6273da9e | ||
|
|
e465ce7d09 | ||
|
|
4c58e80acd | ||
|
|
aadf99a792 | ||
|
|
e140177d9c | ||
|
|
2c28b21f7c | ||
|
|
2019ba0a01 | ||
|
|
2bb0dce762 | ||
|
|
17fcb74af9 | ||
|
|
192cf55cc0 | ||
|
|
f48a33b608 | ||
|
|
8779441b1b | ||
|
|
48fe86f640 | ||
|
|
e6bb31ec6f | ||
|
|
8d6adccda2 | ||
|
|
289b276c69 | ||
|
|
9e193c5a65 | ||
|
|
729962f6db | ||
|
|
e3442099a2 | ||
|
|
0b92885420 | ||
|
|
4ef3982a99 | ||
|
|
2389eeae69 | ||
|
|
cc20b07a42 | ||
|
|
4821cd4cfd | ||
|
|
4b58554a0e | ||
|
|
f71eaa74c0 | ||
|
|
4875a77950 | ||
|
|
20a9e77dfa | ||
|
|
04df765ab4 | ||
|
|
43948386bb | ||
|
|
525965b85d | ||
|
|
b196d969ef | ||
|
|
7766aa0c0e | ||
|
|
1c854067b3 | ||
|
|
d504fb4cec | ||
|
|
80b57dda89 | ||
|
|
8ccefb91bf | ||
|
|
e1cf558264 | ||
|
|
9be71be5bd | ||
|
|
44c2286b5d | ||
|
|
24588100ab | ||
|
|
4ad608803c | ||
|
|
7251711472 | ||
|
|
2c80ab15e2 | ||
|
|
8b310fc4f9 | ||
|
|
fcf55f580d | ||
|
|
1a71992376 | ||
|
|
b5369dd841 | ||
|
|
7fb8da2b88 | ||
|
|
45e1611de8 | ||
|
|
d00e6cddc2 | ||
|
|
54f3a180a3 | ||
|
|
0d7954c288 | ||
|
|
b19ca18802 | ||
|
|
bf25983345 | ||
|
|
d3532a0db0 | ||
|
|
db12451dec | ||
|
|
771b6ed37e | ||
|
|
4cae4d5aca | ||
|
|
490309fcfb | ||
|
|
3ef4ebcc5c | ||
|
|
dc622deb2d | ||
|
|
f3b3766899 | ||
|
|
d1048bef9d | ||
|
|
2528043f1f | ||
|
|
df5b2adb73 | ||
|
|
ca6028185d | ||
|
|
dd0247e09a | ||
|
|
6c150fbd34 | ||
|
|
8e815eeefe | ||
|
|
4f99ab7a78 | ||
|
|
ad5b88b1f1 | ||
|
|
109e90e470 | ||
|
|
085f8e88ba | ||
|
|
b03541fa77 | ||
|
|
3d4a70f80f | ||
|
|
a31a7475e9 | ||
|
|
5224c88dd3 | ||
|
|
8092cb7132 | ||
|
|
60e68042cf | ||
|
|
24bf10dac3 | ||
|
|
0c0de1b681 | ||
|
|
91aa70ab2a | ||
|
|
a2b257d621 | ||
|
|
92a37a04d6 | ||
|
|
34dde13685 | ||
|
|
b8865591d4 | ||
|
|
c409572678 | ||
|
|
0e88f47850 | ||
|
|
a00c117338 | ||
|
|
b0af844007 | ||
|
|
7b50d00911 | ||
|
|
8db804ac41 | ||
|
|
7a8919dc29 | ||
|
|
b310a2a609 | ||
|
|
8a0f9b5263 | ||
|
|
9c7074da5e | ||
|
|
ff323a6b54 | ||
|
|
76cb658419 | ||
|
|
f2a64032a1 | ||
|
|
3ade1a055c | ||
|
|
f75ad80f6c | ||
|
|
6c1b663c4c | ||
|
|
af3ff19b48 | ||
|
|
6b896ab261 | ||
|
|
8336e465ac | ||
|
|
b1b1e81fb5 | ||
|
|
ed6273e26f | ||
|
|
776ec96f79 | ||
|
|
b73e8bd414 | ||
|
|
1ab8f867ef | ||
|
|
ea5b201a0a | ||
|
|
444b1996cb | ||
|
|
0be839a270 | ||
|
|
098ffa6674 | ||
|
|
731de38052 | ||
|
|
39411cf3c3 | ||
|
|
f874bf905f | ||
|
|
8676785302 | ||
|
|
d1f06fe665 | ||
|
|
c4875e5b22 | ||
|
|
be2ebc6dad | ||
|
|
d6be29e3fb | ||
|
|
1aba4be97e | ||
|
|
a9be76576e | ||
|
|
d8edf52a51 | ||
|
|
fae38221e7 | ||
|
|
0e8b439ae5 | ||
|
|
86d10328a0 | ||
|
|
6cfcd864a4 | ||
|
|
720fdd6fa9 | ||
|
|
ddd2eab72f | ||
|
|
1def74548d | ||
|
|
77e205a528 | ||
|
|
d4754a9531 | ||
|
|
35fb5b73a2 | ||
|
|
4e70f9271d | ||
|
|
77374582ab | ||
|
|
5bbebf6228 | ||
|
|
b87dcdd074 | ||
|
|
2f01dfacb5 | ||
|
|
91ab2ed722 | ||
|
|
5f58330790 | ||
|
|
f3a9cfddae | ||
|
|
107f0d4677 | ||
|
|
102e56254d | ||
|
|
36ab3c3400 | ||
|
|
1cbdd96813 | ||
|
|
72a065dbb1 | ||
|
|
3251bdcf1c | ||
|
|
bef1301acb | ||
|
|
36334faf35 | ||
|
|
a395f3fa2f | ||
|
|
c52e67924f | ||
|
|
3ef0eab178 | ||
|
|
f4ec5cd29d | ||
|
|
1154d84dcc | ||
|
|
e6a33e45c2 | ||
|
|
c2c00148ec | ||
|
|
b56cb28895 | ||
|
|
e08d300450 | ||
|
|
953ea14d66 | ||
|
|
410bd787bf | ||
|
|
51fc44768a | ||
|
|
935fb91522 | ||
|
|
79ae25af15 | ||
|
|
ae67dc72e4 | ||
|
|
f69c111585 | ||
|
|
6012ca8159 | ||
|
|
c9cf45c1a4 | ||
|
|
e0d0041ec6 | ||
|
|
7f06a3b14d | ||
|
|
4cc47f8b3c | ||
|
|
f73adec709 | ||
|
|
776346cd63 | ||
|
|
705be728c0 | ||
|
|
00c2275c95 | ||
|
|
8f9d989cac | ||
|
|
d208a85f15 | ||
|
|
8447414510 | ||
|
|
ed4b43265d | ||
|
|
59c4f2ecef | ||
|
|
c0787c8dd1 | ||
|
|
f05d9999f4 | ||
|
|
b5e9476c0f | ||
|
|
7f151e6f71 | ||
|
|
f2ad97ff81 | ||
|
|
1e03e40784 | ||
|
|
aecc88616a | ||
|
|
ccf661f827 | ||
|
|
c21fd2c79e | ||
|
|
f17b069010 | ||
|
|
5b009e4008 | ||
|
|
7912d04be6 | ||
|
|
9df98352b7 | ||
|
|
558c2c8ddf | ||
|
|
09c7fbef76 | ||
|
|
1b3e71f8ee | ||
|
|
7a8dda7e5d | ||
|
|
2d9177588b | ||
|
|
25aaa2c568 | ||
|
|
7b4b7c5fc7 | ||
|
|
ea3beed41d | ||
|
|
d20418ee51 | ||
|
|
d21de4d97f | ||
|
|
55783a5521 | ||
|
|
cb269f273f | ||
|
|
342368aff7 | ||
|
|
854795753c | ||
|
|
e30614d517 | ||
|
|
70409e6726 | ||
|
|
c3543fb5fe | ||
|
|
272f458dc8 | ||
|
|
dff4021730 | ||
|
|
7eb7311427 | ||
|
|
c4d01535dc | ||
|
|
e56934bece | ||
|
|
cc4d3ee435 | ||
|
|
bb3e9e1fd7 | ||
|
|
87f2eff016 | ||
|
|
b3191432cf | ||
|
|
f0d4dc18ce | ||
|
|
80765f0734 | ||
|
|
6e76d125f2 | ||
|
|
3752ac8932 | ||
|
|
30de46db50 | ||
|
|
44dd33ba8f | ||
|
|
d4827355f6 | ||
|
|
63c693f8d0 | ||
|
|
c8d943303d | ||
|
|
9e3f973335 | ||
|
|
abe60a439b | ||
|
|
4007b8de6e | ||
|
|
24e669ba53 | ||
|
|
36cbde7c30 | ||
|
|
fdfb7f2cdb | ||
|
|
f70873438d | ||
|
|
7634fe3c27 | ||
|
|
471a9bc144 | ||
|
|
b797318666 | ||
|
|
33cd52b5d7 | ||
|
|
eb5722801c | ||
|
|
f8833a37c0 | ||
|
|
c47493f24f | ||
|
|
cc64b1a194 | ||
|
|
f58aa48314 | ||
|
|
016f775898 | ||
|
|
b88e77f493 | ||
|
|
228aa992fc | ||
|
|
81f194dd69 | ||
|
|
54ff58bb10 | ||
|
|
bf362e9610 | ||
|
|
b8c867ed09 | ||
|
|
4171853cf4 | ||
|
|
9ac58dc59a | ||
|
|
4aee73623d | ||
|
|
0691e8ebce | ||
|
|
8412d11276 | ||
|
|
0b6ff57640 | ||
|
|
8f9fb7ac49 | ||
|
|
e57d02022c | ||
|
|
ebbd8b40a9 | ||
|
|
72189ea41d | ||
|
|
d298118060 | ||
|
|
d5b4dc3b50 | ||
|
|
31bed5509d | ||
|
|
5185f0e0a6 | ||
|
|
43c95d782d | ||
|
|
2bb41e5d30 | ||
|
|
1bc8dae31b | ||
|
|
75d373ef97 | ||
|
|
e93abc147f | ||
|
|
b9fc20bccf | ||
|
|
864867b91b | ||
|
|
45da08fa8a | ||
|
|
6943109011 | ||
|
|
9fae24f554 | ||
|
|
b5c633c5bd | ||
|
|
f4df22102a | ||
|
|
7dcc1f894d | ||
|
|
b53d8923a5 | ||
|
|
d614a51378 | ||
|
|
2b51668fca | ||
|
|
d780615520 | ||
|
|
e3b561be48 | ||
|
|
1cadaa9482 | ||
|
|
179b9f40f2 | ||
|
|
3a0614c6c7 | ||
|
|
55a2201e79 | ||
|
|
ed8a933f97 | ||
|
|
f7685877f5 | ||
|
|
3bdeb68866 | ||
|
|
cbe50b9a8e | ||
|
|
7d05b9c86f | ||
|
|
1e608ec14e | ||
|
|
28f99f08cf | ||
|
|
d4cf28dec2 | ||
|
|
80e7159184 | ||
|
|
4c7895465e | ||
|
|
5692c6e1f8 | ||
|
|
42daa9bed4 | ||
|
|
863f264d10 | ||
|
|
239dfebe12 | ||
|
|
4cf8a45f56 | ||
|
|
b7651e9521 | ||
|
|
b10ac20446 | ||
|
|
e97a391d20 | ||
|
|
2d9e48bc04 | ||
|
|
f31b035a9f | ||
|
|
ba801af429 | ||
|
|
a63eb0ce0f | ||
|
|
339cd2a82a | ||
|
|
faf1f68ba1 | ||
|
|
460c81f14a | ||
|
|
aea14095ea | ||
|
|
9456c2fbcd | ||
|
|
92ceb440d4 | ||
|
|
7207c7f9d7 | ||
|
|
2fb58b7374 | ||
|
|
9f6bcedba6 | ||
|
|
55e9409366 | ||
|
|
e98c0d179f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -109,3 +109,4 @@ cscope.*
|
||||
tags
|
||||
TAGS
|
||||
*~
|
||||
/tests/qemu-iotests/common.env
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -11,7 +11,7 @@ option) any later version.
|
||||
|
||||
As of July 2013, contributions under version 2 of the GNU General Public
|
||||
License (and no later version) are only accepted for the following files
|
||||
or directories: bsd-user/, linux-user/, hw/misc/vfio.c, hw/xen/xen_pt*.
|
||||
or directories: bsd-user/, linux-user/, hw/vfio/, hw/xen/xen_pt*.
|
||||
|
||||
3) The Tiny Code Generator (TCG) is released under the BSD license
|
||||
(see license headers in files).
|
||||
|
||||
42
MAINTAINERS
42
MAINTAINERS
@@ -98,8 +98,12 @@ LM32
|
||||
M: Michael Walle <michael@walle.cc>
|
||||
S: Maintained
|
||||
F: target-lm32/
|
||||
F: disas/lm32.c
|
||||
F: hw/lm32/
|
||||
F: hw/char/lm32_*
|
||||
F: hw/*/lm32_*
|
||||
F: hw/*/milkymist-*
|
||||
F: include/hw/char/lm32_juart.h
|
||||
F: include/hw/lm32/
|
||||
F: tests/tcg/lm32/
|
||||
|
||||
M68K
|
||||
@@ -534,6 +538,7 @@ S390 Virtio
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: hw/s390x/s390-*.c
|
||||
X: hw/s390x/*pci*.[hc]
|
||||
|
||||
S390 Virtio-ccw
|
||||
M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
@@ -544,6 +549,7 @@ F: hw/s390x/s390-virtio-ccw.c
|
||||
F: hw/s390x/css.[hc]
|
||||
F: hw/s390x/sclp*.[hc]
|
||||
F: hw/s390x/ipl*.[hc]
|
||||
F: hw/s390x/*pci*.[hc]
|
||||
F: include/hw/s390x/
|
||||
F: pc-bios/s390-ccw/
|
||||
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
|
||||
@@ -657,7 +663,7 @@ F: hw/usb/dev-serial.c
|
||||
VFIO
|
||||
M: Alex Williamson <alex.williamson@redhat.com>
|
||||
S: Supported
|
||||
F: hw/misc/vfio.c
|
||||
F: hw/vfio/*
|
||||
|
||||
vhost
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
@@ -696,6 +702,14 @@ M: Amit Shah <amit.shah@redhat.com>
|
||||
S: Supported
|
||||
F: hw/char/virtio-serial-bus.c
|
||||
F: hw/char/virtio-console.c
|
||||
F: include/hw/virtio/virtio-serial.h
|
||||
|
||||
virtio-rng
|
||||
M: Amit Shah <amit.shah@redhat.com>
|
||||
S: Supported
|
||||
F: hw/virtio/virtio-rng.c
|
||||
F: include/hw/virtio/virtio-rng.h
|
||||
F: backends/rng*.c
|
||||
|
||||
nvme
|
||||
M: Keith Busch <keith.busch@intel.com>
|
||||
@@ -743,6 +757,7 @@ F: aio-*.c
|
||||
F: block*
|
||||
F: block/
|
||||
F: hw/block/
|
||||
F: migration/block*
|
||||
F: qemu-img*
|
||||
F: qemu-io*
|
||||
F: tests/image-fuzzer/
|
||||
@@ -880,6 +895,12 @@ S: Maintained
|
||||
F: qobject/
|
||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
||||
|
||||
QEMU Guest Agent
|
||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
S: Maintained
|
||||
F: qga/
|
||||
T: git git://github.com/mdroth/qemu.git qga
|
||||
|
||||
QOM
|
||||
M: Anthony Liguori <aliguori@amazon.com>
|
||||
M: Andreas Färber <afaerber@suse.de>
|
||||
@@ -920,6 +941,17 @@ M: Blue Swirl <blauwirbel@gmail.com>
|
||||
S: Odd Fixes
|
||||
F: scripts/checkpatch.pl
|
||||
|
||||
Migration
|
||||
M: Juan Quintela <quintela@redhat.com>
|
||||
M: Amit Shah <amit.shah@redhat.com>
|
||||
S: Maintained
|
||||
F: include/migration/
|
||||
F: migration/
|
||||
F: savevm.c
|
||||
F: arch_init.c
|
||||
F: scripts/vmstate-static-checker.py
|
||||
F: tests/vmstate-static-checker-data/
|
||||
|
||||
Seccomp
|
||||
M: Eduardo Otubo <eduardo.otubo@profitbricks.com>
|
||||
S: Supported
|
||||
@@ -1074,7 +1106,11 @@ S: Supported
|
||||
F: block/ssh.c
|
||||
|
||||
ARCHIPELAGO
|
||||
M: Chrysostomos Nanakos <cnanakos@grnet.gr>
|
||||
M: Chrysostomos Nanakos <chris@include.gr>
|
||||
S: Maintained
|
||||
F: block/archipelago.c
|
||||
|
||||
Bootdevice
|
||||
M: Gonglei <arei.gonglei@huawei.com>
|
||||
S: Maintained
|
||||
F: bootdevice.c
|
||||
|
||||
4
Makefile
4
Makefile
@@ -313,8 +313,8 @@ qemu-%.tar.bz2:
|
||||
|
||||
distclean: clean
|
||||
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
|
||||
rm -f config-all-devices.mak config-all-disas.mak
|
||||
rm -f po/*.mo
|
||||
rm -f config-all-devices.mak config-all-disas.mak config.status
|
||||
rm -f po/*.mo tests/qemu-iotests/common.env
|
||||
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
||||
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
|
||||
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
|
||||
|
||||
@@ -48,15 +48,9 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
|
||||
common-obj-$(CONFIG_LINUX) += fsdev/
|
||||
|
||||
common-obj-y += migration.o migration-tcp.o
|
||||
common-obj-y += vmstate.o
|
||||
common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
|
||||
common-obj-$(CONFIG_RDMA) += migration-rdma.o
|
||||
common-obj-y += migration/
|
||||
common-obj-y += qemu-char.o #aio.o
|
||||
common-obj-y += block-migration.o
|
||||
common-obj-y += page_cache.o xbzrle.o
|
||||
|
||||
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
|
||||
common-obj-y += page_cache.o
|
||||
|
||||
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
} else {
|
||||
if (node == NULL) {
|
||||
/* Alloc and insert if it's not already there */
|
||||
node = g_malloc0(sizeof(AioHandler));
|
||||
node = g_new0(AioHandler, 1);
|
||||
node->pfd.fd = fd;
|
||||
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
|
||||
if (node == NULL) {
|
||||
/* Alloc and insert if it's not already there */
|
||||
node = g_malloc0(sizeof(AioHandler));
|
||||
node = g_new0(AioHandler, 1);
|
||||
node->pfd.fd = fd;
|
||||
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
||||
}
|
||||
@@ -129,7 +129,7 @@ void aio_set_event_notifier(AioContext *ctx,
|
||||
} else {
|
||||
if (node == NULL) {
|
||||
/* Alloc and insert if it's not already there */
|
||||
node = g_malloc0(sizeof(AioHandler));
|
||||
node = g_new0(AioHandler, 1);
|
||||
node->e = e;
|
||||
node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
|
||||
node->pfd.events = G_IO_IN;
|
||||
|
||||
52
arch_init.c
52
arch_init.c
@@ -346,7 +346,8 @@ static void xbzrle_cache_zero_page(ram_addr_t current_addr)
|
||||
|
||||
/* We don't care if this fails to allocate a new cache page
|
||||
* as long as it updated an old one */
|
||||
cache_insert(XBZRLE.cache, current_addr, ZERO_TARGET_PAGE);
|
||||
cache_insert(XBZRLE.cache, current_addr, ZERO_TARGET_PAGE,
|
||||
bitmap_sync_count);
|
||||
}
|
||||
|
||||
#define ENCODING_FLAG_XBZRLE 0x1
|
||||
@@ -358,10 +359,11 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data,
|
||||
int encoded_len = 0, bytes_sent = -1;
|
||||
uint8_t *prev_cached_page;
|
||||
|
||||
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
|
||||
if (!cache_is_cached(XBZRLE.cache, current_addr, bitmap_sync_count)) {
|
||||
acct_info.xbzrle_cache_miss++;
|
||||
if (!last_stage) {
|
||||
if (cache_insert(XBZRLE.cache, current_addr, *current_data) == -1) {
|
||||
if (cache_insert(XBZRLE.cache, current_addr, *current_data,
|
||||
bitmap_sync_count) == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
/* update *current_data when the page has been
|
||||
@@ -486,15 +488,23 @@ static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
|
||||
|
||||
|
||||
/* Needs iothread lock! */
|
||||
/* Fix me: there are too many global variables used in migration process. */
|
||||
static int64_t start_time;
|
||||
static int64_t bytes_xfer_prev;
|
||||
static int64_t num_dirty_pages_period;
|
||||
|
||||
static void migration_bitmap_sync_init(void)
|
||||
{
|
||||
start_time = 0;
|
||||
bytes_xfer_prev = 0;
|
||||
num_dirty_pages_period = 0;
|
||||
}
|
||||
|
||||
static void migration_bitmap_sync(void)
|
||||
{
|
||||
RAMBlock *block;
|
||||
uint64_t num_dirty_pages_init = migration_dirty_pages;
|
||||
MigrationState *s = migrate_get_current();
|
||||
static int64_t start_time;
|
||||
static int64_t bytes_xfer_prev;
|
||||
static int64_t num_dirty_pages_period;
|
||||
int64_t end_time;
|
||||
int64_t bytes_xfer_now;
|
||||
static uint64_t xbzrle_cache_miss_prev;
|
||||
@@ -514,7 +524,7 @@ static void migration_bitmap_sync(void)
|
||||
address_space_sync_dirty_bitmap(&address_space_memory);
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
migration_bitmap_sync_range(block->mr->ram_addr, block->length);
|
||||
migration_bitmap_sync_range(block->mr->ram_addr, block->used_length);
|
||||
}
|
||||
trace_migration_bitmap_sync_end(migration_dirty_pages
|
||||
- num_dirty_pages_init);
|
||||
@@ -660,7 +670,7 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
||||
offset >= last_offset) {
|
||||
break;
|
||||
}
|
||||
if (offset >= block->length) {
|
||||
if (offset >= block->used_length) {
|
||||
offset = 0;
|
||||
block = QTAILQ_NEXT(block, next);
|
||||
if (!block) {
|
||||
@@ -719,7 +729,7 @@ uint64_t ram_bytes_total(void)
|
||||
uint64_t total = 0;
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next)
|
||||
total += block->length;
|
||||
total += block->used_length;
|
||||
|
||||
return total;
|
||||
}
|
||||
@@ -774,6 +784,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
mig_throttle_on = false;
|
||||
dirty_rate_high_cnt = 0;
|
||||
bitmap_sync_count = 0;
|
||||
migration_bitmap_sync_init();
|
||||
|
||||
if (migrate_use_xbzrle()) {
|
||||
XBZRLE_cache_lock();
|
||||
@@ -822,7 +833,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
uint64_t block_pages;
|
||||
|
||||
block_pages = block->length >> TARGET_PAGE_BITS;
|
||||
block_pages = block->used_length >> TARGET_PAGE_BITS;
|
||||
migration_dirty_pages += block_pages;
|
||||
}
|
||||
|
||||
@@ -835,7 +846,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
qemu_put_byte(f, strlen(block->idstr));
|
||||
qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
|
||||
qemu_put_be64(f, block->length);
|
||||
qemu_put_be64(f, block->used_length);
|
||||
}
|
||||
|
||||
qemu_mutex_unlock_ramlist();
|
||||
@@ -1006,7 +1017,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
uint8_t len;
|
||||
|
||||
if (flags & RAM_SAVE_FLAG_CONTINUE) {
|
||||
if (!block) {
|
||||
if (!block || block->max_length <= offset) {
|
||||
error_report("Ack, bad migration stream!");
|
||||
return NULL;
|
||||
}
|
||||
@@ -1019,8 +1030,10 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
id[len] = 0;
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (!strncmp(id, block->idstr, sizeof(id)))
|
||||
if (!strncmp(id, block->idstr, sizeof(id)) &&
|
||||
block->max_length > offset) {
|
||||
return memory_region_get_ram_ptr(block->mr) + offset;
|
||||
}
|
||||
}
|
||||
|
||||
error_report("Can't find block %s!", id);
|
||||
@@ -1075,11 +1088,14 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (!strncmp(id, block->idstr, sizeof(id))) {
|
||||
if (block->length != length) {
|
||||
error_report("Length mismatch: %s: 0x" RAM_ADDR_FMT
|
||||
" in != 0x" RAM_ADDR_FMT, id, length,
|
||||
block->length);
|
||||
ret = -EINVAL;
|
||||
if (length != block->used_length) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
ret = qemu_ram_resize(block->offset, length, &local_err);
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
11
async.c
11
async.c
@@ -44,10 +44,12 @@ struct QEMUBH {
|
||||
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
||||
{
|
||||
QEMUBH *bh;
|
||||
bh = g_malloc0(sizeof(QEMUBH));
|
||||
bh->ctx = ctx;
|
||||
bh->cb = cb;
|
||||
bh->opaque = opaque;
|
||||
bh = g_new(QEMUBH, 1);
|
||||
*bh = (QEMUBH){
|
||||
.ctx = ctx,
|
||||
.cb = cb,
|
||||
.opaque = opaque,
|
||||
};
|
||||
qemu_mutex_lock(&ctx->bh_lock);
|
||||
bh->next = ctx->first_bh;
|
||||
/* Make sure that the members are ready before putting bh into list */
|
||||
@@ -300,6 +302,7 @@ AioContext *aio_context_new(Error **errp)
|
||||
error_setg_errno(errp, -ret, "Failed to initialize event notifier");
|
||||
return NULL;
|
||||
}
|
||||
g_source_set_can_recurse(&ctx->source, true);
|
||||
aio_set_event_notifier(ctx, &ctx->notifier,
|
||||
(EventNotifierHandler *)
|
||||
event_notifier_test_and_clear);
|
||||
|
||||
@@ -191,9 +191,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
|
||||
audio_detach_capture (hw);
|
||||
#endif
|
||||
QLIST_REMOVE (hw, entries);
|
||||
glue (hw->pcm_ops->fini_, TYPE) (hw);
|
||||
glue (s->nb_hw_voices_, TYPE) += 1;
|
||||
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
|
||||
glue (hw->pcm_ops->fini_, TYPE) (hw);
|
||||
g_free (hw);
|
||||
*hwp = NULL;
|
||||
}
|
||||
|
||||
@@ -88,11 +88,7 @@ static char *rng_random_get_filename(Object *obj, Error **errp)
|
||||
{
|
||||
RndRandom *s = RNG_RANDOM(obj);
|
||||
|
||||
if (s->filename) {
|
||||
return g_strdup(s->filename);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return g_strdup(s->filename);
|
||||
}
|
||||
|
||||
static void rng_random_set_filename(Object *obj, const char *filename,
|
||||
|
||||
213
block.c
213
block.c
@@ -97,6 +97,10 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
|
||||
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
|
||||
QLIST_HEAD_INITIALIZER(bdrv_drivers);
|
||||
|
||||
static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors);
|
||||
static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors);
|
||||
/* If non-zero, use only whitelisted block drivers */
|
||||
static int use_bdrv_whitelist;
|
||||
|
||||
@@ -229,7 +233,7 @@ size_t bdrv_opt_mem_align(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
/* check if the path starts with "<protocol>:" */
|
||||
static int path_has_protocol(const char *path)
|
||||
int path_has_protocol(const char *path)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
@@ -303,15 +307,32 @@ void path_combine(char *dest, int dest_size,
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz)
|
||||
void bdrv_get_full_backing_filename_from_filename(const char *backed,
|
||||
const char *backing,
|
||||
char *dest, size_t sz,
|
||||
Error **errp)
|
||||
{
|
||||
if (bs->backing_file[0] == '\0' || path_has_protocol(bs->backing_file)) {
|
||||
pstrcpy(dest, sz, bs->backing_file);
|
||||
if (backing[0] == '\0' || path_has_protocol(backing) ||
|
||||
path_is_absolute(backing))
|
||||
{
|
||||
pstrcpy(dest, sz, backing);
|
||||
} else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) {
|
||||
error_setg(errp, "Cannot use relative backing file names for '%s'",
|
||||
backed);
|
||||
} else {
|
||||
path_combine(dest, sz, bs->filename, bs->backing_file);
|
||||
path_combine(dest, sz, backed, backing);
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
|
||||
Error **errp)
|
||||
{
|
||||
char *backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
|
||||
|
||||
bdrv_get_full_backing_filename_from_filename(backed, bs->backing_file,
|
||||
dest, sz, errp);
|
||||
}
|
||||
|
||||
void bdrv_register(BlockDriver *bdrv)
|
||||
{
|
||||
/* Block drivers without coroutine functions need emulation */
|
||||
@@ -629,7 +650,7 @@ BlockDriver *bdrv_find_protocol(const char *filename,
|
||||
}
|
||||
|
||||
if (!path_has_protocol(filename) || !allow_protocol_prefix) {
|
||||
return bdrv_find_format("file");
|
||||
return &bdrv_file;
|
||||
}
|
||||
|
||||
p = strchr(filename, ':');
|
||||
@@ -648,22 +669,49 @@ BlockDriver *bdrv_find_protocol(const char *filename,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guess image format by probing its contents.
|
||||
* This is not a good idea when your image is raw (CVE-2008-2004), but
|
||||
* we do it anyway for backward compatibility.
|
||||
*
|
||||
* @buf contains the image's first @buf_size bytes.
|
||||
* @buf_size is the buffer size in bytes (generally BLOCK_PROBE_BUF_SIZE,
|
||||
* but can be smaller if the image file is smaller)
|
||||
* @filename is its filename.
|
||||
*
|
||||
* For all block drivers, call the bdrv_probe() method to get its
|
||||
* probing score.
|
||||
* Return the first block driver with the highest probing score.
|
||||
*/
|
||||
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
|
||||
const char *filename)
|
||||
{
|
||||
int score_max = 0, score;
|
||||
BlockDriver *drv = NULL, *d;
|
||||
|
||||
QLIST_FOREACH(d, &bdrv_drivers, list) {
|
||||
if (d->bdrv_probe) {
|
||||
score = d->bdrv_probe(buf, buf_size, filename);
|
||||
if (score > score_max) {
|
||||
score_max = score;
|
||||
drv = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
static int find_image_format(BlockDriverState *bs, const char *filename,
|
||||
BlockDriver **pdrv, Error **errp)
|
||||
{
|
||||
int score, score_max;
|
||||
BlockDriver *drv1, *drv;
|
||||
uint8_t buf[2048];
|
||||
BlockDriver *drv;
|
||||
uint8_t buf[BLOCK_PROBE_BUF_SIZE];
|
||||
int ret = 0;
|
||||
|
||||
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
|
||||
if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
|
||||
drv = bdrv_find_format("raw");
|
||||
if (!drv) {
|
||||
error_setg(errp, "Could not find raw image format");
|
||||
ret = -ENOENT;
|
||||
}
|
||||
*pdrv = drv;
|
||||
*pdrv = &bdrv_raw;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -675,17 +723,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
|
||||
return ret;
|
||||
}
|
||||
|
||||
score_max = 0;
|
||||
drv = NULL;
|
||||
QLIST_FOREACH(drv1, &bdrv_drivers, list) {
|
||||
if (drv1->bdrv_probe) {
|
||||
score = drv1->bdrv_probe(buf, ret, filename);
|
||||
if (score > score_max) {
|
||||
score_max = score;
|
||||
drv = drv1;
|
||||
}
|
||||
}
|
||||
}
|
||||
drv = bdrv_probe_all(buf, ret, filename);
|
||||
if (!drv) {
|
||||
error_setg(errp, "Could not determine image format: No compatible "
|
||||
"driver found");
|
||||
@@ -1162,7 +1200,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
||||
|
||||
bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
|
||||
/* Otherwise we won't be able to commit due to check in bdrv_commit */
|
||||
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT,
|
||||
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
|
||||
bs->backing_blocker);
|
||||
out:
|
||||
bdrv_refresh_limits(bs, NULL);
|
||||
@@ -1180,7 +1218,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
{
|
||||
char *backing_filename = g_malloc0(PATH_MAX);
|
||||
int ret = 0;
|
||||
BlockDriver *back_drv = NULL;
|
||||
BlockDriverState *backing_hd;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -1201,7 +1238,14 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
QDECREF(options);
|
||||
goto free_exit;
|
||||
} else {
|
||||
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX);
|
||||
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
QDECREF(options);
|
||||
goto free_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bs->drv || !bs->drv->supports_backing) {
|
||||
@@ -1213,14 +1257,14 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
|
||||
backing_hd = bdrv_new();
|
||||
|
||||
if (bs->backing_format[0] != '\0') {
|
||||
back_drv = bdrv_find_format(bs->backing_format);
|
||||
if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
|
||||
qdict_put(options, "driver", qstring_from_str(bs->backing_format));
|
||||
}
|
||||
|
||||
assert(bs->backing_hd == NULL);
|
||||
ret = bdrv_open(&backing_hd,
|
||||
*backing_filename ? backing_filename : NULL, NULL, options,
|
||||
bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
|
||||
bdrv_backing_flags(bs->open_flags), NULL, &local_err);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(backing_hd);
|
||||
backing_hd = NULL;
|
||||
@@ -1294,7 +1338,6 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||
char *tmp_filename = g_malloc0(PATH_MAX + 1);
|
||||
int64_t total_size;
|
||||
BlockDriver *bdrv_qcow2;
|
||||
QemuOpts *opts = NULL;
|
||||
QDict *snapshot_options;
|
||||
BlockDriverState *bs_snapshot;
|
||||
@@ -1319,11 +1362,10 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
bdrv_qcow2 = bdrv_find_format("qcow2");
|
||||
opts = qemu_opts_create(bdrv_qcow2->create_opts, NULL, 0,
|
||||
opts = qemu_opts_create(bdrv_qcow2.create_opts, NULL, 0,
|
||||
&error_abort);
|
||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size);
|
||||
ret = bdrv_create(bdrv_qcow2, tmp_filename, opts, &local_err);
|
||||
ret = bdrv_create(&bdrv_qcow2, tmp_filename, opts, &local_err);
|
||||
qemu_opts_del(opts);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
||||
@@ -1343,7 +1385,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||
bs_snapshot = bdrv_new();
|
||||
|
||||
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||
flags, bdrv_qcow2, &local_err);
|
||||
flags, &bdrv_qcow2, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
@@ -1467,6 +1509,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
}
|
||||
|
||||
/* Image format probing */
|
||||
bs->probed = !drv;
|
||||
if (!drv && file) {
|
||||
ret = find_image_format(file, filename, &drv, &local_err);
|
||||
if (ret < 0) {
|
||||
@@ -2173,8 +2216,8 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, NULL) ||
|
||||
bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, NULL)) {
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) ||
|
||||
bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET, NULL)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -2790,8 +2833,8 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
||||
if (nb_sectors <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (nb_sectors > INT_MAX) {
|
||||
nb_sectors = INT_MAX;
|
||||
if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||
nb_sectors = INT_MAX / BDRV_SECTOR_SIZE;
|
||||
}
|
||||
ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
|
||||
if (ret < 0) {
|
||||
@@ -3019,18 +3062,16 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
|
||||
|
||||
max_nb_sectors = ROUND_UP(MAX(0, total_sectors - sector_num),
|
||||
align >> BDRV_SECTOR_BITS);
|
||||
if (max_nb_sectors > 0) {
|
||||
if (nb_sectors < max_nb_sectors) {
|
||||
ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
|
||||
} else if (max_nb_sectors > 0) {
|
||||
QEMUIOVector local_qiov;
|
||||
size_t local_sectors;
|
||||
|
||||
max_nb_sectors = MIN(max_nb_sectors, SIZE_MAX / BDRV_SECTOR_BITS);
|
||||
local_sectors = MIN(max_nb_sectors, nb_sectors);
|
||||
|
||||
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||
qemu_iovec_concat(&local_qiov, qiov, 0,
|
||||
local_sectors * BDRV_SECTOR_SIZE);
|
||||
max_nb_sectors * BDRV_SECTOR_SIZE);
|
||||
|
||||
ret = drv->bdrv_co_readv(bs, sector_num, local_sectors,
|
||||
ret = drv->bdrv_co_readv(bs, sector_num, max_nb_sectors,
|
||||
&local_qiov);
|
||||
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
@@ -3203,6 +3244,9 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
|
||||
if (ret == -ENOTSUP) {
|
||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||
int max_xfer_len = MIN_NON_ZERO(bs->bl.max_transfer_length,
|
||||
MAX_WRITE_ZEROES_DEFAULT);
|
||||
num = MIN(num, max_xfer_len);
|
||||
iov.iov_len = num * BDRV_SECTOR_SIZE;
|
||||
if (iov.iov_base == NULL) {
|
||||
iov.iov_base = qemu_try_blockalign(bs, num * BDRV_SECTOR_SIZE);
|
||||
@@ -3219,7 +3263,7 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
/* Keep bounce buffer around if it is big enough for all
|
||||
* all future requests.
|
||||
*/
|
||||
if (num < max_write_zeroes) {
|
||||
if (num < max_xfer_len) {
|
||||
qemu_vfree(iov.iov_base);
|
||||
iov.iov_base = NULL;
|
||||
}
|
||||
@@ -3801,6 +3845,14 @@ bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base)
|
||||
return top != NULL;
|
||||
}
|
||||
|
||||
BlockDriverState *bdrv_next_node(BlockDriverState *bs)
|
||||
{
|
||||
if (!bs) {
|
||||
return QTAILQ_FIRST(&graph_bdrv_states);
|
||||
}
|
||||
return QTAILQ_NEXT(bs, node_list);
|
||||
}
|
||||
|
||||
BlockDriverState *bdrv_next(BlockDriverState *bs)
|
||||
{
|
||||
if (!bs) {
|
||||
@@ -3809,6 +3861,11 @@ BlockDriverState *bdrv_next(BlockDriverState *bs)
|
||||
return QTAILQ_NEXT(bs, device_list);
|
||||
}
|
||||
|
||||
const char *bdrv_get_node_name(const BlockDriverState *bs)
|
||||
{
|
||||
return bs->node_name;
|
||||
}
|
||||
|
||||
/* TODO check what callers really want: bs->node_name or blk_name() */
|
||||
const char *bdrv_get_device_name(const BlockDriverState *bs)
|
||||
{
|
||||
@@ -3903,9 +3960,9 @@ typedef struct BdrvCoGetBlockStatusData {
|
||||
} BdrvCoGetBlockStatusData;
|
||||
|
||||
/*
|
||||
* Returns true iff the specified sector is present in the disk image. Drivers
|
||||
* not implementing the functionality are assumed to not support backing files,
|
||||
* hence all their sectors are reported as allocated.
|
||||
* Returns the allocation status of the specified sectors.
|
||||
* Drivers not implementing the functionality are assumed to not support
|
||||
* backing files, hence all their sectors are reported as allocated.
|
||||
*
|
||||
* If 'sector_num' is beyond the end of the disk image the return value is 0
|
||||
* and 'pnum' is set to 0.
|
||||
@@ -5361,8 +5418,20 @@ void bdrv_dirty_iter_init(BlockDriverState *bs,
|
||||
hbitmap_iter_init(hbi, bitmap->bitmap, 0);
|
||||
}
|
||||
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int nr_sectors)
|
||||
{
|
||||
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int nr_sectors)
|
||||
{
|
||||
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
@@ -5370,7 +5439,8 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors)
|
||||
static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
@@ -5541,6 +5611,18 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!drv->create_opts) {
|
||||
error_setg(errp, "Format driver '%s' does not support image creation",
|
||||
drv->format_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!proto_drv->create_opts) {
|
||||
error_setg(errp, "Protocol driver '%s' does not support image creation",
|
||||
proto_drv->format_name);
|
||||
return;
|
||||
}
|
||||
|
||||
create_opts = qemu_opts_append(create_opts, drv->create_opts);
|
||||
create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
|
||||
|
||||
@@ -5597,22 +5679,27 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
if (size == -1) {
|
||||
if (backing_file) {
|
||||
BlockDriverState *bs;
|
||||
char *full_backing = g_new0(char, PATH_MAX);
|
||||
int64_t size;
|
||||
int back_flags;
|
||||
|
||||
bdrv_get_full_backing_filename_from_filename(filename, backing_file,
|
||||
full_backing, PATH_MAX,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
g_free(full_backing);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* backing files always opened read-only */
|
||||
back_flags =
|
||||
flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
|
||||
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, back_flags,
|
||||
ret = bdrv_open(&bs, full_backing, NULL, NULL, back_flags,
|
||||
backing_drv, &local_err);
|
||||
g_free(full_backing);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not open '%s': %s",
|
||||
backing_file,
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
goto out;
|
||||
}
|
||||
size = bdrv_getlength(bs);
|
||||
@@ -5633,8 +5720,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
}
|
||||
|
||||
if (!quiet) {
|
||||
printf("Formatting '%s', fmt=%s ", filename, fmt);
|
||||
qemu_opts_print(opts);
|
||||
printf("Formatting '%s', fmt=%s", filename, fmt);
|
||||
qemu_opts_print(opts, " ");
|
||||
puts("");
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "block/accounting.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
||||
int64_t bytes, enum BlockAcctType type)
|
||||
@@ -31,7 +32,7 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
||||
assert(type < BLOCK_MAX_IOTYPE);
|
||||
|
||||
cookie->bytes = bytes;
|
||||
cookie->start_time_ns = get_clock();
|
||||
cookie->start_time_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
cookie->type = type;
|
||||
}
|
||||
|
||||
@@ -41,7 +42,8 @@ void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||
|
||||
stats->nr_bytes[cookie->type] += cookie->bytes;
|
||||
stats->nr_ops[cookie->type]++;
|
||||
stats->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
|
||||
stats->total_time_ns[cookie->type] +=
|
||||
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - cookie->start_time_ns;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -360,6 +360,7 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
hbitmap_free(job->bitmap);
|
||||
|
||||
bdrv_iostatus_disable(target);
|
||||
bdrv_op_unblock_all(target, job->common.blocker);
|
||||
|
||||
data = g_malloc(sizeof(*data));
|
||||
data->ret = ret;
|
||||
@@ -379,6 +380,11 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
assert(target);
|
||||
assert(cb);
|
||||
|
||||
if (bs == target) {
|
||||
error_setg(errp, "Source and target cannot be the same");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
|
||||
on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
||||
!bdrv_iostatus_is_enabled(bs)) {
|
||||
@@ -386,6 +392,26 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bdrv_is_inserted(bs)) {
|
||||
error_setg(errp, "Device is not inserted: %s",
|
||||
bdrv_get_device_name(bs));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bdrv_is_inserted(target)) {
|
||||
error_setg(errp, "Device is not inserted: %s",
|
||||
bdrv_get_device_name(target));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
len = bdrv_getlength(bs);
|
||||
if (len < 0) {
|
||||
error_setg_errno(errp, -len, "unable to get length for '%s'",
|
||||
@@ -399,6 +425,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_op_block_all(target, job->common.blocker);
|
||||
|
||||
job->on_source_error = on_source_error;
|
||||
job->on_target_error = on_target_error;
|
||||
job->target = target;
|
||||
|
||||
@@ -721,93 +721,50 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
|
||||
|
||||
static void blkdebug_refresh_filename(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
struct BlkdebugRule *rule;
|
||||
QDict *opts;
|
||||
QList *inject_error_list = NULL, *set_state_list = NULL;
|
||||
QList *suspend_list = NULL;
|
||||
int event;
|
||||
const QDictEntry *e;
|
||||
bool force_json = false;
|
||||
|
||||
if (!bs->file->full_open_options) {
|
||||
for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
|
||||
if (strcmp(qdict_entry_key(e), "config") &&
|
||||
strcmp(qdict_entry_key(e), "x-image") &&
|
||||
strcmp(qdict_entry_key(e), "image") &&
|
||||
strncmp(qdict_entry_key(e), "image.", strlen("image.")))
|
||||
{
|
||||
force_json = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (force_json && !bs->file->full_open_options) {
|
||||
/* The config file cannot be recreated, so creating a plain filename
|
||||
* is impossible */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force_json && bs->file->exact_filename[0]) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"blkdebug:%s:%s",
|
||||
qdict_get_try_str(bs->options, "config") ?: "",
|
||||
bs->file->exact_filename);
|
||||
}
|
||||
|
||||
opts = qdict_new();
|
||||
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
|
||||
|
||||
QINCREF(bs->file->full_open_options);
|
||||
qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
|
||||
|
||||
for (event = 0; event < BLKDBG_EVENT_MAX; event++) {
|
||||
QLIST_FOREACH(rule, &s->rules[event], next) {
|
||||
if (rule->action == ACTION_INJECT_ERROR) {
|
||||
QDict *inject_error = qdict_new();
|
||||
|
||||
qdict_put_obj(inject_error, "event", QOBJECT(qstring_from_str(
|
||||
BlkdebugEvent_lookup[rule->event])));
|
||||
qdict_put_obj(inject_error, "state",
|
||||
QOBJECT(qint_from_int(rule->state)));
|
||||
qdict_put_obj(inject_error, "errno", QOBJECT(qint_from_int(
|
||||
rule->options.inject.error)));
|
||||
qdict_put_obj(inject_error, "sector", QOBJECT(qint_from_int(
|
||||
rule->options.inject.sector)));
|
||||
qdict_put_obj(inject_error, "once", QOBJECT(qbool_from_int(
|
||||
rule->options.inject.once)));
|
||||
qdict_put_obj(inject_error, "immediately",
|
||||
QOBJECT(qbool_from_int(
|
||||
rule->options.inject.immediately)));
|
||||
|
||||
if (!inject_error_list) {
|
||||
inject_error_list = qlist_new();
|
||||
}
|
||||
|
||||
qlist_append_obj(inject_error_list, QOBJECT(inject_error));
|
||||
} else if (rule->action == ACTION_SET_STATE) {
|
||||
QDict *set_state = qdict_new();
|
||||
|
||||
qdict_put_obj(set_state, "event", QOBJECT(qstring_from_str(
|
||||
BlkdebugEvent_lookup[rule->event])));
|
||||
qdict_put_obj(set_state, "state",
|
||||
QOBJECT(qint_from_int(rule->state)));
|
||||
qdict_put_obj(set_state, "new_state", QOBJECT(qint_from_int(
|
||||
rule->options.set_state.new_state)));
|
||||
|
||||
if (!set_state_list) {
|
||||
set_state_list = qlist_new();
|
||||
}
|
||||
|
||||
qlist_append_obj(set_state_list, QOBJECT(set_state));
|
||||
} else if (rule->action == ACTION_SUSPEND) {
|
||||
QDict *suspend = qdict_new();
|
||||
|
||||
qdict_put_obj(suspend, "event", QOBJECT(qstring_from_str(
|
||||
BlkdebugEvent_lookup[rule->event])));
|
||||
qdict_put_obj(suspend, "state",
|
||||
QOBJECT(qint_from_int(rule->state)));
|
||||
qdict_put_obj(suspend, "tag", QOBJECT(qstring_from_str(
|
||||
rule->options.suspend.tag)));
|
||||
|
||||
if (!suspend_list) {
|
||||
suspend_list = qlist_new();
|
||||
}
|
||||
|
||||
qlist_append_obj(suspend_list, QOBJECT(suspend));
|
||||
}
|
||||
for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
|
||||
if (strcmp(qdict_entry_key(e), "x-image") &&
|
||||
strcmp(qdict_entry_key(e), "image") &&
|
||||
strncmp(qdict_entry_key(e), "image.", strlen("image.")))
|
||||
{
|
||||
qobject_incref(qdict_entry_value(e));
|
||||
qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
|
||||
}
|
||||
}
|
||||
|
||||
if (inject_error_list) {
|
||||
qdict_put_obj(opts, "inject-error", QOBJECT(inject_error_list));
|
||||
}
|
||||
if (set_state_list) {
|
||||
qdict_put_obj(opts, "set-state", QOBJECT(set_state_list));
|
||||
}
|
||||
if (suspend_list) {
|
||||
qdict_put_obj(opts, "suspend", QOBJECT(suspend_list));
|
||||
}
|
||||
|
||||
bs->full_open_options = opts;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,9 +260,6 @@ int blk_attach_dev(BlockBackend *blk, void *dev)
|
||||
blk_ref(blk);
|
||||
blk->dev = dev;
|
||||
bdrv_iostatus_reset(blk->bs);
|
||||
|
||||
/* We're expecting I/O from the device so bump up coroutine pool size */
|
||||
qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -290,7 +287,6 @@ void blk_detach_dev(BlockBackend *blk, void *dev)
|
||||
blk->dev_ops = NULL;
|
||||
blk->dev_opaque = NULL;
|
||||
bdrv_set_guest_block_size(blk->bs, 512);
|
||||
qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
|
||||
blk_unref(blk);
|
||||
}
|
||||
|
||||
@@ -497,6 +493,16 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
||||
return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque);
|
||||
}
|
||||
|
||||
int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
return bdrv_co_discard(blk->bs, sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
int blk_co_flush(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_co_flush(blk->bs);
|
||||
}
|
||||
|
||||
int blk_flush(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_flush(blk->bs);
|
||||
@@ -549,6 +555,11 @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
|
||||
bdrv_set_enable_write_cache(blk->bs, wce);
|
||||
}
|
||||
|
||||
void blk_invalidate_cache(BlockBackend *blk, Error **errp)
|
||||
{
|
||||
bdrv_invalidate_cache(blk->bs, errp);
|
||||
}
|
||||
|
||||
int blk_is_inserted(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_is_inserted(blk->bs);
|
||||
@@ -609,6 +620,29 @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
|
||||
bdrv_set_aio_context(blk->bs, new_context);
|
||||
}
|
||||
|
||||
void blk_add_aio_context_notifier(BlockBackend *blk,
|
||||
void (*attached_aio_context)(AioContext *new_context, void *opaque),
|
||||
void (*detach_aio_context)(void *opaque), void *opaque)
|
||||
{
|
||||
bdrv_add_aio_context_notifier(blk->bs, attached_aio_context,
|
||||
detach_aio_context, opaque);
|
||||
}
|
||||
|
||||
void blk_remove_aio_context_notifier(BlockBackend *blk,
|
||||
void (*attached_aio_context)(AioContext *,
|
||||
void *),
|
||||
void (*detach_aio_context)(void *),
|
||||
void *opaque)
|
||||
{
|
||||
bdrv_remove_aio_context_notifier(blk->bs, attached_aio_context,
|
||||
detach_aio_context, opaque);
|
||||
}
|
||||
|
||||
void blk_add_close_notifier(BlockBackend *blk, Notifier *notify)
|
||||
{
|
||||
bdrv_add_close_notifier(blk->bs, notify);
|
||||
}
|
||||
|
||||
void blk_io_plug(BlockBackend *blk)
|
||||
{
|
||||
bdrv_io_plug(blk->bs);
|
||||
|
||||
@@ -1286,7 +1286,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename;
|
||||
int i, ret;
|
||||
int i, ret = 0;
|
||||
|
||||
if ((BDRV_SECTOR_SIZE % 512) != 0) {
|
||||
error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
|
||||
|
||||
@@ -35,14 +35,14 @@ struct qemu_laiocb {
|
||||
size_t nbytes;
|
||||
QEMUIOVector *qiov;
|
||||
bool is_read;
|
||||
QLIST_ENTRY(qemu_laiocb) node;
|
||||
QSIMPLEQ_ENTRY(qemu_laiocb) next;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct iocb *iocbs[MAX_QUEUED_IO];
|
||||
int plugged;
|
||||
unsigned int size;
|
||||
unsigned int idx;
|
||||
unsigned int n;
|
||||
bool blocked;
|
||||
QSIMPLEQ_HEAD(, qemu_laiocb) pending;
|
||||
} LaioQueue;
|
||||
|
||||
struct qemu_laio_state {
|
||||
@@ -59,6 +59,8 @@ struct qemu_laio_state {
|
||||
int event_max;
|
||||
};
|
||||
|
||||
static void ioq_submit(struct qemu_laio_state *s);
|
||||
|
||||
static inline ssize_t io_event_ret(struct io_event *ev)
|
||||
{
|
||||
return (ssize_t)(((uint64_t)ev->res2 << 32) | ev->res);
|
||||
@@ -135,6 +137,10 @@ static void qemu_laio_completion_bh(void *opaque)
|
||||
|
||||
qemu_laio_process_completion(s, laiocb);
|
||||
}
|
||||
|
||||
if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_laio_completion_cb(EventNotifier *e)
|
||||
@@ -172,50 +178,41 @@ static const AIOCBInfo laio_aiocb_info = {
|
||||
|
||||
static void ioq_init(LaioQueue *io_q)
|
||||
{
|
||||
io_q->size = MAX_QUEUED_IO;
|
||||
io_q->idx = 0;
|
||||
QSIMPLEQ_INIT(&io_q->pending);
|
||||
io_q->plugged = 0;
|
||||
io_q->n = 0;
|
||||
io_q->blocked = false;
|
||||
}
|
||||
|
||||
static int ioq_submit(struct qemu_laio_state *s)
|
||||
static void ioq_submit(struct qemu_laio_state *s)
|
||||
{
|
||||
int ret, i = 0;
|
||||
int len = s->io_q.idx;
|
||||
int ret, len;
|
||||
struct qemu_laiocb *aiocb;
|
||||
struct iocb *iocbs[MAX_QUEUED_IO];
|
||||
QSIMPLEQ_HEAD(, qemu_laiocb) completed;
|
||||
|
||||
do {
|
||||
ret = io_submit(s->ctx, len, s->io_q.iocbs);
|
||||
} while (i++ < 3 && ret == -EAGAIN);
|
||||
len = 0;
|
||||
QSIMPLEQ_FOREACH(aiocb, &s->io_q.pending, next) {
|
||||
iocbs[len++] = &aiocb->iocb;
|
||||
if (len == MAX_QUEUED_IO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* empty io queue */
|
||||
s->io_q.idx = 0;
|
||||
ret = io_submit(s->ctx, len, iocbs);
|
||||
if (ret == -EAGAIN) {
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
i = 0;
|
||||
} else {
|
||||
i = ret;
|
||||
}
|
||||
|
||||
for (; i < len; i++) {
|
||||
struct qemu_laiocb *laiocb =
|
||||
container_of(s->io_q.iocbs[i], struct qemu_laiocb, iocb);
|
||||
|
||||
laiocb->ret = (ret < 0) ? ret : -EIO;
|
||||
qemu_laio_process_completion(s, laiocb);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ioq_enqueue(struct qemu_laio_state *s, struct iocb *iocb)
|
||||
{
|
||||
unsigned int idx = s->io_q.idx;
|
||||
|
||||
s->io_q.iocbs[idx++] = iocb;
|
||||
s->io_q.idx = idx;
|
||||
|
||||
/* submit immediately if queue is full */
|
||||
if (idx == s->io_q.size) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
s->io_q.n -= ret;
|
||||
aiocb = container_of(iocbs[ret - 1], struct qemu_laiocb, iocb);
|
||||
QSIMPLEQ_SPLIT_AFTER(&s->io_q.pending, aiocb, next, &completed);
|
||||
} while (ret == len && !QSIMPLEQ_EMPTY(&s->io_q.pending));
|
||||
s->io_q.blocked = (s->io_q.n > 0);
|
||||
}
|
||||
|
||||
void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
|
||||
@@ -225,22 +222,19 @@ void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
|
||||
s->io_q.plugged++;
|
||||
}
|
||||
|
||||
int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug)
|
||||
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug)
|
||||
{
|
||||
struct qemu_laio_state *s = aio_ctx;
|
||||
int ret = 0;
|
||||
|
||||
assert(s->io_q.plugged > 0 || !unplug);
|
||||
|
||||
if (unplug && --s->io_q.plugged > 0) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->io_q.idx > 0) {
|
||||
ret = ioq_submit(s);
|
||||
if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
@@ -276,12 +270,11 @@ BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
}
|
||||
io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
|
||||
|
||||
if (!s->io_q.plugged) {
|
||||
if (io_submit(s->ctx, 1, &iocbs) < 0) {
|
||||
goto out_free_aiocb;
|
||||
}
|
||||
} else {
|
||||
ioq_enqueue(s, iocbs);
|
||||
QSIMPLEQ_INSERT_TAIL(&s->io_q.pending, laiocb, next);
|
||||
s->io_q.n++;
|
||||
if (!s->io_q.blocked &&
|
||||
(!s->io_q.plugged || s->io_q.n >= MAX_QUEUED_IO)) {
|
||||
ioq_submit(s);
|
||||
}
|
||||
return &laiocb->common;
|
||||
|
||||
|
||||
@@ -128,7 +128,8 @@ static void mirror_write_complete(void *opaque, int ret)
|
||||
BlockDriverState *source = s->common.bs;
|
||||
BlockErrorAction action;
|
||||
|
||||
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
|
||||
bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
|
||||
op->nb_sectors);
|
||||
action = mirror_error_action(s, false, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||
s->ret = ret;
|
||||
@@ -145,7 +146,8 @@ static void mirror_read_complete(void *opaque, int ret)
|
||||
BlockDriverState *source = s->common.bs;
|
||||
BlockErrorAction action;
|
||||
|
||||
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
|
||||
bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
|
||||
op->nb_sectors);
|
||||
action = mirror_error_action(s, true, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||
s->ret = ret;
|
||||
@@ -286,7 +288,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
next_sector += sectors_per_chunk;
|
||||
}
|
||||
|
||||
bdrv_reset_dirty(source, sector_num, nb_sectors);
|
||||
bdrv_reset_dirty_bitmap(source, s->dirty_bitmap, sector_num,
|
||||
nb_sectors);
|
||||
|
||||
/* Copy the dirty cluster. */
|
||||
s->in_flight++;
|
||||
@@ -442,7 +445,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
|
||||
assert(n > 0);
|
||||
if (ret == 1) {
|
||||
bdrv_set_dirty(bs, sector_num, n);
|
||||
bdrv_set_dirty_bitmap(bs, s->dirty_bitmap, sector_num, n);
|
||||
sector_num = next;
|
||||
} else {
|
||||
sector_num += n;
|
||||
|
||||
15
block/nfs.c
15
block/nfs.c
@@ -409,6 +409,19 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QemuOptsList nfs_create_opts = {
|
||||
.name = "nfs-create-opts",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(nfs_create_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Virtual disk size"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
};
|
||||
|
||||
static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -470,6 +483,8 @@ static BlockDriver bdrv_nfs = {
|
||||
|
||||
.instance_size = sizeof(NFSClient),
|
||||
.bdrv_needs_filename = true,
|
||||
.create_opts = &nfs_create_opts,
|
||||
|
||||
.bdrv_has_zero_init = nfs_has_zero_init,
|
||||
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
|
||||
.bdrv_truncate = nfs_file_truncate,
|
||||
|
||||
65
block/qapi.c
65
block/qapi.c
@@ -29,13 +29,6 @@
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#ifdef __linux__
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifndef FS_NOCOW_FL
|
||||
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
{
|
||||
@@ -47,6 +40,13 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
info->encrypted = bs->encrypted;
|
||||
info->encryption_key_missing = bdrv_key_required(bs);
|
||||
|
||||
info->cache = g_new(BlockdevCacheInfo, 1);
|
||||
*info->cache = (BlockdevCacheInfo) {
|
||||
.writeback = bdrv_enable_write_cache(bs),
|
||||
.direct = !!(bs->open_flags & BDRV_O_NOCACHE),
|
||||
.no_flush = !!(bs->open_flags & BDRV_O_NO_FLUSH),
|
||||
};
|
||||
|
||||
if (bs->node_name[0]) {
|
||||
info->has_node_name = true;
|
||||
info->node_name = g_strdup(bs->node_name);
|
||||
@@ -180,9 +180,6 @@ void bdrv_query_image_info(BlockDriverState *bs,
|
||||
int ret;
|
||||
Error *err = NULL;
|
||||
ImageInfo *info;
|
||||
#ifdef __linux__
|
||||
int fd, attr;
|
||||
#endif
|
||||
|
||||
size = bdrv_getlength(bs);
|
||||
if (size < 0) {
|
||||
@@ -212,24 +209,17 @@ void bdrv_query_image_info(BlockDriverState *bs,
|
||||
info->format_specific = bdrv_get_specific_info(bs);
|
||||
info->has_format_specific = info->format_specific != NULL;
|
||||
|
||||
#ifdef __linux__
|
||||
/* get NOCOW info */
|
||||
fd = qemu_open(bs->filename, O_RDONLY | O_NONBLOCK);
|
||||
if (fd >= 0) {
|
||||
if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0 && (attr & FS_NOCOW_FL)) {
|
||||
info->has_nocow = true;
|
||||
info->nocow = true;
|
||||
}
|
||||
qemu_close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
backing_filename = bs->backing_file;
|
||||
if (backing_filename[0] != '\0') {
|
||||
info->backing_filename = g_strdup(backing_filename);
|
||||
info->has_backing_filename = true;
|
||||
bdrv_get_full_backing_filename(bs, backing_filename2,
|
||||
sizeof(backing_filename2));
|
||||
sizeof(backing_filename2), &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
qapi_free_ImageInfo(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(backing_filename, backing_filename2) != 0) {
|
||||
info->full_backing_filename =
|
||||
@@ -322,7 +312,8 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
||||
qapi_free_BlockInfo(info);
|
||||
}
|
||||
|
||||
static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
||||
static BlockStats *bdrv_query_stats(const BlockDriverState *bs,
|
||||
bool query_backing)
|
||||
{
|
||||
BlockStats *s;
|
||||
|
||||
@@ -333,6 +324,11 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
||||
s->device = g_strdup(bdrv_get_device_name(bs));
|
||||
}
|
||||
|
||||
if (bdrv_get_node_name(bs)[0]) {
|
||||
s->has_node_name = true;
|
||||
s->node_name = g_strdup(bdrv_get_node_name(bs));
|
||||
}
|
||||
|
||||
s->stats = g_malloc0(sizeof(*s->stats));
|
||||
s->stats->rd_bytes = bs->stats.nr_bytes[BLOCK_ACCT_READ];
|
||||
s->stats->wr_bytes = bs->stats.nr_bytes[BLOCK_ACCT_WRITE];
|
||||
@@ -347,12 +343,12 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
||||
|
||||
if (bs->file) {
|
||||
s->has_parent = true;
|
||||
s->parent = bdrv_query_stats(bs->file);
|
||||
s->parent = bdrv_query_stats(bs->file, query_backing);
|
||||
}
|
||||
|
||||
if (bs->backing_hd) {
|
||||
if (query_backing && bs->backing_hd) {
|
||||
s->has_backing = true;
|
||||
s->backing = bdrv_query_stats(bs->backing_hd);
|
||||
s->backing = bdrv_query_stats(bs->backing_hd, query_backing);
|
||||
}
|
||||
|
||||
return s;
|
||||
@@ -383,17 +379,22 @@ BlockInfoList *qmp_query_block(Error **errp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BlockStatsList *qmp_query_blockstats(Error **errp)
|
||||
BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
|
||||
bool query_nodes,
|
||||
Error **errp)
|
||||
{
|
||||
BlockStatsList *head = NULL, **p_next = &head;
|
||||
BlockDriverState *bs = NULL;
|
||||
|
||||
while ((bs = bdrv_next(bs))) {
|
||||
/* Just to be safe if query_nodes is not always initialized */
|
||||
query_nodes = has_query_nodes && query_nodes;
|
||||
|
||||
while ((bs = query_nodes ? bdrv_next_node(bs) : bdrv_next(bs))) {
|
||||
BlockStatsList *info = g_malloc0(sizeof(*info));
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
info->value = bdrv_query_stats(bs);
|
||||
info->value = bdrv_query_stats(bs, !query_nodes);
|
||||
aio_context_release(ctx);
|
||||
|
||||
*p_next = info;
|
||||
@@ -655,8 +656,4 @@ void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
|
||||
func_fprintf(f, "Format specific information:\n");
|
||||
bdrv_image_info_specific_dump(func_fprintf, f, info->format_specific);
|
||||
}
|
||||
|
||||
if (info->has_nocow && info->nocow) {
|
||||
func_fprintf(f, "NOCOW flag: set\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1263,7 +1263,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
again:
|
||||
start = offset;
|
||||
remaining = *num << BDRV_SECTOR_BITS;
|
||||
remaining = (uint64_t)*num << BDRV_SECTOR_BITS;
|
||||
cluster_offset = 0;
|
||||
*host_offset = 0;
|
||||
cur_bytes = 0;
|
||||
|
||||
@@ -117,7 +117,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
#ifdef DEBUG_EXT
|
||||
printf("ext.magic = 0x%x\n", ext.magic);
|
||||
#endif
|
||||
if (ext.len > end_offset - offset) {
|
||||
if (offset > end_offset || ext.len > end_offset - offset) {
|
||||
error_setg(errp, "Header extension too large");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1428,10 +1428,23 @@ static void qcow2_close(BlockDriverState *bs)
|
||||
s->l1_table = NULL;
|
||||
|
||||
if (!(bs->open_flags & BDRV_O_INCOMING)) {
|
||||
qcow2_cache_flush(bs, s->l2_table_cache);
|
||||
qcow2_cache_flush(bs, s->refcount_block_cache);
|
||||
int ret1, ret2;
|
||||
|
||||
qcow2_mark_clean(bs);
|
||||
ret1 = qcow2_cache_flush(bs, s->l2_table_cache);
|
||||
ret2 = qcow2_cache_flush(bs, s->refcount_block_cache);
|
||||
|
||||
if (ret1) {
|
||||
error_report("Failed to flush the L2 table cache: %s",
|
||||
strerror(-ret1));
|
||||
}
|
||||
if (ret2) {
|
||||
error_report("Failed to flush the refcount block cache: %s",
|
||||
strerror(-ret2));
|
||||
}
|
||||
|
||||
if (!ret1 && !ret2) {
|
||||
qcow2_mark_clean(bs);
|
||||
}
|
||||
}
|
||||
|
||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||
@@ -1915,10 +1928,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
* refcount of the cluster that is occupied by the header and the refcount
|
||||
* table)
|
||||
*/
|
||||
BlockDriver* drv = bdrv_find_format("qcow2");
|
||||
assert(drv != NULL);
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err);
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
|
||||
&bdrv_qcow2, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
@@ -1970,7 +1982,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
|
||||
ret = bdrv_open(&bs, filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
||||
drv, &local_err);
|
||||
&bdrv_qcow2, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
@@ -2150,8 +2162,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
/* align end of file to a sector boundary to ease reading with
|
||||
sector based I/Os */
|
||||
cluster_offset = bdrv_getlength(bs->file);
|
||||
bdrv_truncate(bs->file, cluster_offset);
|
||||
return 0;
|
||||
return bdrv_truncate(bs->file, cluster_offset);
|
||||
}
|
||||
|
||||
if (nb_sectors != s->cluster_sectors) {
|
||||
@@ -2847,7 +2858,7 @@ static QemuOptsList qcow2_create_opts = {
|
||||
}
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_qcow2 = {
|
||||
BlockDriver bdrv_qcow2 = {
|
||||
.format_name = "qcow2",
|
||||
.instance_size = sizeof(BDRVQcowState),
|
||||
.bdrv_probe = qcow2_probe,
|
||||
|
||||
@@ -41,7 +41,7 @@ BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
void laio_detach_aio_context(void *s, AioContext *old_context);
|
||||
void laio_attach_aio_context(void *s, AioContext *new_context);
|
||||
void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
|
||||
int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug);
|
||||
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -60,9 +60,6 @@
|
||||
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_FIEMAP
|
||||
#include <linux/fiemap.h>
|
||||
#endif
|
||||
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
|
||||
#include <linux/falloc.h>
|
||||
#endif
|
||||
@@ -151,9 +148,6 @@ typedef struct BDRVRawState {
|
||||
bool has_write_zeroes:1;
|
||||
bool discard_zeroes:1;
|
||||
bool needs_alignment;
|
||||
#ifdef CONFIG_FIEMAP
|
||||
bool skip_fiemap;
|
||||
#endif
|
||||
} BDRVRawState;
|
||||
|
||||
typedef struct BDRVRawReopenState {
|
||||
@@ -452,6 +446,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
|
||||
if (fstat(s->fd, &st) < 0) {
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, errno, "Could not stat file");
|
||||
goto fail;
|
||||
}
|
||||
@@ -1457,9 +1452,16 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
"Could not write to the new file");
|
||||
break;
|
||||
}
|
||||
left -= num;
|
||||
left -= result;
|
||||
}
|
||||
if (result >= 0) {
|
||||
result = fsync(fd);
|
||||
if (result < 0) {
|
||||
result = -errno;
|
||||
error_setg_errno(errp, -result,
|
||||
"Could not flush new file to disk");
|
||||
}
|
||||
}
|
||||
fsync(fd);
|
||||
g_free(buf);
|
||||
break;
|
||||
}
|
||||
@@ -1481,83 +1483,93 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int try_fiemap(BlockDriverState *bs, off_t start, off_t *data,
|
||||
off_t *hole, int nb_sectors)
|
||||
{
|
||||
#ifdef CONFIG_FIEMAP
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret = 0;
|
||||
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 = FIEMAP_FLAG_SYNC;
|
||||
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 int try_seek_hole(BlockDriverState *bs, off_t start, off_t *data,
|
||||
off_t *hole)
|
||||
/*
|
||||
* Find allocation range in @bs around offset @start.
|
||||
* May change underlying file descriptor's file offset.
|
||||
* If @start is not in a hole, store @start in @data, and the
|
||||
* beginning of the next hole in @hole, and return 0.
|
||||
* If @start is in a non-trailing hole, store @start in @hole and the
|
||||
* beginning of the next non-hole in @data, and return 0.
|
||||
* If @start is in a trailing hole or beyond EOF, return -ENXIO.
|
||||
* If we can't find out, return a negative errno other than -ENXIO.
|
||||
*/
|
||||
static int find_allocation(BlockDriverState *bs, off_t start,
|
||||
off_t *data, off_t *hole)
|
||||
{
|
||||
#if defined SEEK_HOLE && defined SEEK_DATA
|
||||
BDRVRawState *s = bs->opaque;
|
||||
off_t offs;
|
||||
|
||||
*hole = lseek(s->fd, start, SEEK_HOLE);
|
||||
if (*hole == -1) {
|
||||
return -errno;
|
||||
/*
|
||||
* SEEK_DATA cases:
|
||||
* D1. offs == start: start is in data
|
||||
* D2. offs > start: start is in a hole, next data at offs
|
||||
* D3. offs < 0, errno = ENXIO: either start is in a trailing hole
|
||||
* or start is beyond EOF
|
||||
* If the latter happens, the file has been truncated behind
|
||||
* our back since we opened it. All bets are off then.
|
||||
* Treating like a trailing hole is simplest.
|
||||
* D4. offs < 0, errno != ENXIO: we learned nothing
|
||||
*/
|
||||
offs = lseek(s->fd, start, SEEK_DATA);
|
||||
if (offs < 0) {
|
||||
return -errno; /* D3 or D4 */
|
||||
}
|
||||
assert(offs >= start);
|
||||
|
||||
if (offs > start) {
|
||||
/* D2: in hole, next data at offs */
|
||||
*hole = start;
|
||||
*data = offs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*hole > start) {
|
||||
/* D1: in data, end not yet known */
|
||||
|
||||
/*
|
||||
* SEEK_HOLE cases:
|
||||
* H1. offs == start: start is in a hole
|
||||
* If this happens here, a hole has been dug behind our back
|
||||
* since the previous lseek().
|
||||
* H2. offs > start: either start is in data, next hole at offs,
|
||||
* or start is in trailing hole, EOF at offs
|
||||
* Linux treats trailing holes like any other hole: offs ==
|
||||
* start. Solaris seeks to EOF instead: offs > start (blech).
|
||||
* If that happens here, a hole has been dug behind our back
|
||||
* since the previous lseek().
|
||||
* H3. offs < 0, errno = ENXIO: start is beyond EOF
|
||||
* If this happens, the file has been truncated behind our
|
||||
* back since we opened it. Treat it like a trailing hole.
|
||||
* H4. offs < 0, errno != ENXIO: we learned nothing
|
||||
* Pretend we know nothing at all, i.e. "forget" about D1.
|
||||
*/
|
||||
offs = lseek(s->fd, start, SEEK_HOLE);
|
||||
if (offs < 0) {
|
||||
return -errno; /* D1 and (H3 or H4) */
|
||||
}
|
||||
assert(offs >= start);
|
||||
|
||||
if (offs > start) {
|
||||
/*
|
||||
* D1 and H2: either in data, next hole at offs, or it was in
|
||||
* data but is now in a trailing hole. In the latter case,
|
||||
* all bets are off. Treating it as if it there was data all
|
||||
* the way to EOF is safe, so simply do that.
|
||||
*/
|
||||
*data = start;
|
||||
} 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);
|
||||
}
|
||||
*hole = offs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* D1 and H1 */
|
||||
return -EBUSY;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true iff the specified sector is present in the disk image. Drivers
|
||||
* not implementing the functionality are assumed to not support backing files,
|
||||
* hence all their sectors are reported as allocated.
|
||||
* Returns the allocation status of the specified sectors.
|
||||
*
|
||||
* If 'sector_num' is beyond the end of the disk image the return value is 0
|
||||
* and 'pnum' is set to 0.
|
||||
@@ -1593,28 +1605,26 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
nb_sectors = DIV_ROUND_UP(total_size - start, BDRV_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
ret = try_seek_hole(bs, start, &data, &hole);
|
||||
if (ret < 0) {
|
||||
ret = try_fiemap(bs, start, &data, &hole, nb_sectors);
|
||||
if (ret < 0) {
|
||||
/* Assume everything is allocated. */
|
||||
data = 0;
|
||||
hole = start + nb_sectors * BDRV_SECTOR_SIZE;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
assert(ret >= 0);
|
||||
|
||||
if (data <= start) {
|
||||
ret = find_allocation(bs, start, &data, &hole);
|
||||
if (ret == -ENXIO) {
|
||||
/* Trailing hole */
|
||||
*pnum = nb_sectors;
|
||||
ret = BDRV_BLOCK_ZERO;
|
||||
} else if (ret < 0) {
|
||||
/* No info available, so pretend there are no holes */
|
||||
*pnum = nb_sectors;
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
} else if (data == start) {
|
||||
/* On a data extent, compute sectors to the end of the extent. */
|
||||
*pnum = MIN(nb_sectors, (hole - start) / BDRV_SECTOR_SIZE);
|
||||
return ret | BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
} else {
|
||||
/* On a hole, compute sectors to the beginning of the next extent. */
|
||||
assert(hole == start);
|
||||
*pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE);
|
||||
return ret | BDRV_BLOCK_ZERO | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
ret = BDRV_BLOCK_ZERO;
|
||||
}
|
||||
return ret | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
}
|
||||
|
||||
static coroutine_fn BlockAIOCB *raw_aio_discard(BlockDriverState *bs,
|
||||
@@ -1675,7 +1685,7 @@ static QemuOptsList raw_create_opts = {
|
||||
}
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_file = {
|
||||
BlockDriver bdrv_file = {
|
||||
.format_name = "file",
|
||||
.protocol_name = "file",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
@@ -1913,7 +1923,7 @@ static int fd_open(BlockDriverState *bs)
|
||||
return 0;
|
||||
last_media_present = (s->fd >= 0);
|
||||
if (s->fd >= 0 &&
|
||||
(get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
|
||||
(qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
|
||||
qemu_close(s->fd);
|
||||
s->fd = -1;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
@@ -1922,7 +1932,7 @@ static int fd_open(BlockDriverState *bs)
|
||||
}
|
||||
if (s->fd < 0) {
|
||||
if (s->fd_got_error &&
|
||||
(get_clock() - s->fd_error_time) < FD_OPEN_TIMEOUT) {
|
||||
(qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("No floppy (open delayed)\n");
|
||||
#endif
|
||||
@@ -1930,7 +1940,7 @@ static int fd_open(BlockDriverState *bs)
|
||||
}
|
||||
s->fd = qemu_open(bs->filename, s->open_flags & ~O_NONBLOCK);
|
||||
if (s->fd < 0) {
|
||||
s->fd_error_time = get_clock();
|
||||
s->fd_error_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
s->fd_got_error = 1;
|
||||
if (last_media_present)
|
||||
s->fd_media_changed = 1;
|
||||
@@ -1945,7 +1955,7 @@ static int fd_open(BlockDriverState *bs)
|
||||
}
|
||||
if (!last_media_present)
|
||||
s->fd_media_changed = 1;
|
||||
s->fd_open_time = get_clock();
|
||||
s->fd_open_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
s->fd_got_error = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -540,7 +540,7 @@ static QemuOptsList raw_create_opts = {
|
||||
}
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_file = {
|
||||
BlockDriver bdrv_file = {
|
||||
.format_name = "file",
|
||||
.protocol_name = "file",
|
||||
.instance_size = sizeof(BDRVRawState),
|
||||
|
||||
@@ -58,8 +58,58 @@ static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
void *buf = NULL;
|
||||
BlockDriver *drv;
|
||||
QEMUIOVector local_qiov;
|
||||
int ret;
|
||||
|
||||
if (bs->probed && sector_num == 0) {
|
||||
/* As long as these conditions are true, we can't get partial writes to
|
||||
* the probe buffer and can just directly check the request. */
|
||||
QEMU_BUILD_BUG_ON(BLOCK_PROBE_BUF_SIZE != 512);
|
||||
QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != 512);
|
||||
|
||||
if (nb_sectors == 0) {
|
||||
/* qemu_iovec_to_buf() would fail, but we want to return success
|
||||
* instead of -EINVAL in this case. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = qemu_try_blockalign(bs->file, 512);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = qemu_iovec_to_buf(qiov, 0, buf, 512);
|
||||
if (ret != 512) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
drv = bdrv_probe_all(buf, 512, NULL);
|
||||
if (drv != bs->drv) {
|
||||
ret = -EPERM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Use the checked buffer, a malicious guest might be overwriting its
|
||||
* original buffer in the background. */
|
||||
qemu_iovec_init(&local_qiov, qiov->niov + 1);
|
||||
qemu_iovec_add(&local_qiov, buf, 512);
|
||||
qemu_iovec_concat(&local_qiov, qiov, 512, qiov->size - 512);
|
||||
qiov = &local_qiov;
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
|
||||
ret = bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
|
||||
|
||||
fail:
|
||||
if (qiov == &local_qiov) {
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
}
|
||||
qemu_vfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
@@ -158,6 +208,18 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
bs->sg = bs->file->sg;
|
||||
|
||||
if (bs->probed && !bdrv_is_read_only(bs)) {
|
||||
fprintf(stderr,
|
||||
"WARNING: Image format was not specified for '%s' and probing "
|
||||
"guessed raw.\n"
|
||||
" Automatically detecting the format is dangerous for "
|
||||
"raw images, write operations on block 0 will be restricted.\n"
|
||||
" Specify the 'raw' format explicitly to remove the "
|
||||
"restrictions.\n",
|
||||
bs->file->filename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -173,7 +235,7 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_raw = {
|
||||
BlockDriver bdrv_raw = {
|
||||
.format_name = "raw",
|
||||
.bdrv_probe = &raw_probe,
|
||||
.bdrv_reopen_prepare = &raw_reopen_prepare,
|
||||
|
||||
@@ -459,7 +459,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
|
||||
r = rados_create(&s->cluster, clientname);
|
||||
if (r < 0) {
|
||||
error_setg(&local_err, "error initializing");
|
||||
error_setg(errp, "error initializing");
|
||||
goto failed_opts;
|
||||
}
|
||||
|
||||
@@ -495,19 +495,19 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
r = rados_connect(s->cluster);
|
||||
if (r < 0) {
|
||||
error_setg(&local_err, "error connecting");
|
||||
error_setg(errp, "error connecting");
|
||||
goto failed_shutdown;
|
||||
}
|
||||
|
||||
r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
|
||||
if (r < 0) {
|
||||
error_setg(&local_err, "error opening pool %s", pool);
|
||||
error_setg(errp, "error opening pool %s", pool);
|
||||
goto failed_shutdown;
|
||||
}
|
||||
|
||||
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
|
||||
if (r < 0) {
|
||||
error_setg(&local_err, "error reading header from %s", s->name);
|
||||
error_setg(errp, "error reading header from %s", s->name);
|
||||
goto failed_open;
|
||||
}
|
||||
|
||||
|
||||
19
block/vdi.c
19
block/vdi.c
@@ -120,8 +120,18 @@ typedef unsigned char uuid_t[16];
|
||||
|
||||
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
||||
|
||||
/* max blocks in image is (0xffffffff / 4) */
|
||||
#define VDI_BLOCKS_IN_IMAGE_MAX 0x3fffffff
|
||||
/* The bmap will take up VDI_BLOCKS_IN_IMAGE_MAX * sizeof(uint32_t) bytes; since
|
||||
* the bmap is read and written in a single operation, its size needs to be
|
||||
* limited to INT_MAX; furthermore, when opening an image, the bmap size is
|
||||
* rounded up to be aligned on BDRV_SECTOR_SIZE.
|
||||
* Therefore this should satisfy the following:
|
||||
* VDI_BLOCKS_IN_IMAGE_MAX * sizeof(uint32_t) + BDRV_SECTOR_SIZE == INT_MAX + 1
|
||||
* (INT_MAX + 1 is the first value not representable as an int)
|
||||
* This guarantees that any value below or equal to the constant will, when
|
||||
* multiplied by sizeof(uint32_t) and rounded up to a BDRV_SECTOR_SIZE boundary,
|
||||
* still be below or equal to INT_MAX. */
|
||||
#define VDI_BLOCKS_IN_IMAGE_MAX \
|
||||
((unsigned)((INT_MAX + 1u - BDRV_SECTOR_SIZE) / sizeof(uint32_t)))
|
||||
#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
|
||||
(uint64_t)DEFAULT_CLUSTER_SIZE)
|
||||
|
||||
@@ -842,11 +852,6 @@ static QemuOptsList vdi_create_opts = {
|
||||
.def_value_str = "off"
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.name = BLOCK_OPT_NOCOW,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Turn off copy-on-write (valid only on btrfs)"
|
||||
},
|
||||
/* TODO: An additional option to set UUID values might be useful. */
|
||||
{ /* end of list */ }
|
||||
}
|
||||
|
||||
18
block/vhdx.c
18
block/vhdx.c
@@ -1109,8 +1109,9 @@ static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
/* check the payload block state */
|
||||
switch (s->bat[sinfo.bat_idx] & VHDX_BAT_STATE_BIT_MASK) {
|
||||
case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
|
||||
case PAYLOAD_BLOCK_UNDEFINED: /* fall through */
|
||||
case PAYLOAD_BLOCK_UNMAPPED: /* fall through */
|
||||
case PAYLOAD_BLOCK_UNDEFINED:
|
||||
case PAYLOAD_BLOCK_UNMAPPED:
|
||||
case PAYLOAD_BLOCK_UNMAPPED_v095:
|
||||
case PAYLOAD_BLOCK_ZERO:
|
||||
/* return zero */
|
||||
qemu_iovec_memset(&hd_qiov, 0, 0, sinfo.bytes_avail);
|
||||
@@ -1277,11 +1278,11 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
sectors_to_write += iov2.iov_len >> BDRV_SECTOR_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
|
||||
case PAYLOAD_BLOCK_UNMAPPED: /* fall through */
|
||||
case PAYLOAD_BLOCK_UNDEFINED: /* fall through */
|
||||
case PAYLOAD_BLOCK_UNMAPPED:
|
||||
case PAYLOAD_BLOCK_UNMAPPED_v095:
|
||||
case PAYLOAD_BLOCK_UNDEFINED:
|
||||
bat_prior_offset = sinfo.file_offset;
|
||||
ret = vhdx_allocate_block(bs, s, &sinfo.file_offset);
|
||||
if (ret < 0) {
|
||||
@@ -1773,7 +1774,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0);
|
||||
block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0);
|
||||
type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
|
||||
use_zero_blocks = qemu_opt_get_bool_del(opts, VHDX_BLOCK_OPT_ZERO, false);
|
||||
use_zero_blocks = qemu_opt_get_bool_del(opts, VHDX_BLOCK_OPT_ZERO, true);
|
||||
|
||||
if (image_size > VHDX_MAX_IMAGE_SIZE) {
|
||||
error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB");
|
||||
@@ -1935,7 +1936,9 @@ static QemuOptsList vhdx_create_opts = {
|
||||
{
|
||||
.name = VHDX_BLOCK_OPT_ZERO,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Force use of payload blocks of type 'ZERO'. Non-standard."
|
||||
.help = "Force use of payload blocks of type 'ZERO'. "\
|
||||
"Non-standard, but default. Do not set to 'off' when "\
|
||||
"using 'qemu-img convert' with subformat=dynamic."
|
||||
},
|
||||
{ NULL }
|
||||
}
|
||||
@@ -1953,6 +1956,7 @@ static BlockDriver bdrv_vhdx = {
|
||||
.bdrv_create = vhdx_create,
|
||||
.bdrv_get_info = vhdx_get_info,
|
||||
.bdrv_check = vhdx_check,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
|
||||
.create_opts = &vhdx_create_opts,
|
||||
};
|
||||
|
||||
@@ -226,7 +226,8 @@ typedef struct QEMU_PACKED VHDXLogDataSector {
|
||||
#define PAYLOAD_BLOCK_NOT_PRESENT 0
|
||||
#define PAYLOAD_BLOCK_UNDEFINED 1
|
||||
#define PAYLOAD_BLOCK_ZERO 2
|
||||
#define PAYLOAD_BLOCK_UNMAPPED 5
|
||||
#define PAYLOAD_BLOCK_UNMAPPED 3
|
||||
#define PAYLOAD_BLOCK_UNMAPPED_v095 5
|
||||
#define PAYLOAD_BLOCK_FULLY_PRESENT 6
|
||||
#define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
|
||||
|
||||
|
||||
74
block/vmdk.c
74
block/vmdk.c
@@ -28,6 +28,7 @@
|
||||
#include "qemu/module.h"
|
||||
#include "migration/migration.h"
|
||||
#include <zlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
||||
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
|
||||
@@ -556,8 +557,16 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = MIN(size, 1 << 20); /* avoid unbounded allocation */
|
||||
buf = g_malloc0(size + 1);
|
||||
if (size < 4) {
|
||||
/* Both descriptor file and sparse image must be much larger than 4
|
||||
* bytes, also callers of vmdk_read_desc want to compare the first 4
|
||||
* bytes with VMDK4_MAGIC, let's error out if less is read. */
|
||||
error_setg(errp, "File is too small, not a valid image");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */
|
||||
buf = g_malloc(size + 1);
|
||||
|
||||
ret = bdrv_pread(file, desc_offset, buf, size);
|
||||
if (ret < 0) {
|
||||
@@ -565,6 +574,7 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
|
||||
g_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf[ret] = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -635,6 +645,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
bs->file->total_sectors * 512 - 1536,
|
||||
&footer, sizeof(footer));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Failed to read footer");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -646,6 +657,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
le32_to_cpu(footer.eos_marker.size) != 0 ||
|
||||
le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM)
|
||||
{
|
||||
error_setg(errp, "Invalid footer");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -676,6 +688,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt)
|
||||
* le64_to_cpu(header.granularity);
|
||||
if (l1_entry_sectors == 0) {
|
||||
error_setg(errp, "L1 entry size is invalid");
|
||||
return -EINVAL;
|
||||
}
|
||||
l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
|
||||
@@ -784,10 +797,12 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
||||
VmdkExtent *extent;
|
||||
|
||||
while (*p) {
|
||||
/* parse extent line:
|
||||
/* parse extent line in one of below formats:
|
||||
*
|
||||
* RW [size in sectors] FLAT "file-name.vmdk" OFFSET
|
||||
* or
|
||||
* RW [size in sectors] SPARSE "file-name.vmdk"
|
||||
* RW [size in sectors] VMFS "file-name.vmdk"
|
||||
* RW [size in sectors] VMFSSPARSE "file-name.vmdk"
|
||||
*/
|
||||
flat_offset = -1;
|
||||
ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64,
|
||||
@@ -818,6 +833,14 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
||||
goto next_line;
|
||||
}
|
||||
|
||||
if (!path_is_absolute(fname) && !path_has_protocol(fname) &&
|
||||
!desc_file_path[0])
|
||||
{
|
||||
error_setg(errp, "Cannot use relative extent paths with VMDK "
|
||||
"descriptor file '%s'", bs->file->filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
path_combine(extent_path, sizeof(extent_path),
|
||||
desc_file_path, fname);
|
||||
extent_file = NULL;
|
||||
@@ -894,7 +917,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
|
||||
}
|
||||
s->create_type = g_strdup(ct);
|
||||
s->desc_offset = 0;
|
||||
ret = vmdk_parse_extents(buf, bs, bs->file->filename, errp);
|
||||
ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, errp);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
@@ -902,7 +925,7 @@ exit:
|
||||
static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
char *buf = NULL;
|
||||
char *buf;
|
||||
int ret;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
uint32_t magic;
|
||||
@@ -1538,7 +1561,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
/* update CID on the first write every time the virtual disk is
|
||||
* opened */
|
||||
if (!s->cid_updated) {
|
||||
ret = vmdk_write_cid(bs, time(NULL));
|
||||
ret = vmdk_write_cid(bs, g_random_int());
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -1868,8 +1891,19 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
if (backing_file) {
|
||||
BlockDriverState *bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_NO_BACKING, NULL,
|
||||
char *full_backing = g_new0(char, PATH_MAX);
|
||||
bdrv_get_full_backing_filename_from_filename(filename, backing_file,
|
||||
full_backing, PATH_MAX,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
g_free(full_backing);
|
||||
error_propagate(errp, local_err);
|
||||
ret = -ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
ret = bdrv_open(&bs, full_backing, NULL, NULL, BDRV_O_NO_BACKING, NULL,
|
||||
errp);
|
||||
g_free(full_backing);
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
@@ -1922,7 +1956,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
/* generate descriptor file */
|
||||
desc = g_strdup_printf(desc_template,
|
||||
(uint32_t)time(NULL),
|
||||
g_random_int(),
|
||||
parent_cid,
|
||||
fmt,
|
||||
parent_desc_line,
|
||||
@@ -2137,23 +2171,29 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
|
||||
return spec_info;
|
||||
}
|
||||
|
||||
static bool vmdk_extents_type_eq(const VmdkExtent *a, const VmdkExtent *b)
|
||||
{
|
||||
return a->flat == b->flat &&
|
||||
a->compressed == b->compressed &&
|
||||
(a->flat || a->cluster_sectors == b->cluster_sectors);
|
||||
}
|
||||
|
||||
static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
int i;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
assert(s->num_extents);
|
||||
|
||||
/* See if we have multiple extents but they have different cases */
|
||||
for (i = 1; i < s->num_extents; i++) {
|
||||
if (!vmdk_extents_type_eq(&s->extents[0], &s->extents[i])) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -893,11 +893,6 @@ static QemuOptsList vpc_create_opts = {
|
||||
"Type of virtual hard disk format. Supported formats are "
|
||||
"{dynamic (default) | fixed} "
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_NOCOW,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Turn off copy-on-write (valid only on btrfs)"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2917,6 +2917,12 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
}
|
||||
|
||||
bdrv_qcow = bdrv_find_format("qcow");
|
||||
if (!bdrv_qcow) {
|
||||
error_setg(errp, "Failed to locate qcow driver");
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
|
||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512);
|
||||
qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:");
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
@@ -73,7 +74,7 @@ static void nbd_close_notifier(Notifier *n, void *data)
|
||||
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk;
|
||||
NBDExport *exp;
|
||||
NBDCloseNotifier *n;
|
||||
|
||||
@@ -87,12 +88,12 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
return;
|
||||
}
|
||||
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
blk = blk_by_name(device);
|
||||
if (!blk) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
if (!bdrv_is_inserted(bs)) {
|
||||
if (!blk_is_inserted(blk)) {
|
||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
return;
|
||||
}
|
||||
@@ -100,18 +101,18 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
if (!has_writable) {
|
||||
writable = false;
|
||||
}
|
||||
if (bdrv_is_read_only(bs)) {
|
||||
if (blk_is_read_only(blk)) {
|
||||
writable = false;
|
||||
}
|
||||
|
||||
exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL);
|
||||
exp = nbd_export_new(blk, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL);
|
||||
|
||||
nbd_export_set_name(exp, device);
|
||||
|
||||
n = g_new0(NBDCloseNotifier, 1);
|
||||
n->n.notify = nbd_close_notifier;
|
||||
n->exp = exp;
|
||||
bdrv_add_close_notifier(bs, &n->n);
|
||||
blk_add_close_notifier(blk, &n->n);
|
||||
QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
|
||||
}
|
||||
|
||||
|
||||
288
blockdev.c
288
blockdev.c
@@ -1105,6 +1105,7 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = bdrv_find(device);
|
||||
AioContext *aio_context;
|
||||
QEMUSnapshotInfo sn;
|
||||
Error *local_err = NULL;
|
||||
SnapshotInfo *info = NULL;
|
||||
@@ -1128,25 +1129,34 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, errp)) {
|
||||
goto out_aio_context;
|
||||
}
|
||||
|
||||
ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
goto out_aio_context;
|
||||
}
|
||||
if (!ret) {
|
||||
error_setg(errp,
|
||||
"Snapshot with id '%s' and name '%s' does not exist on "
|
||||
"device '%s'",
|
||||
STR_OR_NULL(id), STR_OR_NULL(name), device);
|
||||
return NULL;
|
||||
goto out_aio_context;
|
||||
}
|
||||
|
||||
bdrv_snapshot_delete(bs, id, name, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
goto out_aio_context;
|
||||
}
|
||||
|
||||
aio_context_release(aio_context);
|
||||
|
||||
info = g_new0(SnapshotInfo, 1);
|
||||
info->id = g_strdup(sn.id_str);
|
||||
info->name = g_strdup(sn.name);
|
||||
@@ -1157,9 +1167,13 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
|
||||
info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
|
||||
|
||||
return info;
|
||||
|
||||
out_aio_context:
|
||||
aio_context_release(aio_context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* New and old BlockDriverState structs for group snapshots */
|
||||
/* New and old BlockDriverState structs for atomic group operations */
|
||||
|
||||
typedef struct BlkTransactionState BlkTransactionState;
|
||||
|
||||
@@ -1193,6 +1207,7 @@ struct BlkTransactionState {
|
||||
typedef struct InternalSnapshotState {
|
||||
BlkTransactionState common;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
QEMUSnapshotInfo sn;
|
||||
} InternalSnapshotState;
|
||||
|
||||
@@ -1226,11 +1241,19 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
/* AioContext is released in .clean() */
|
||||
state->aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(state->aio_context);
|
||||
|
||||
if (!bdrv_is_inserted(bs)) {
|
||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_is_read_only(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
|
||||
return;
|
||||
@@ -1303,11 +1326,22 @@ static void internal_snapshot_abort(BlkTransactionState *common)
|
||||
}
|
||||
}
|
||||
|
||||
static void internal_snapshot_clean(BlkTransactionState *common)
|
||||
{
|
||||
InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState,
|
||||
common, common);
|
||||
|
||||
if (state->aio_context) {
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
/* external snapshot private data */
|
||||
typedef struct ExternalSnapshotState {
|
||||
BlkTransactionState common;
|
||||
BlockDriverState *old_bs;
|
||||
BlockDriverState *new_bs;
|
||||
AioContext *aio_context;
|
||||
} ExternalSnapshotState;
|
||||
|
||||
static void external_snapshot_prepare(BlkTransactionState *common,
|
||||
@@ -1374,6 +1408,10 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Acquire AioContext now so any threads operating on old_bs stop */
|
||||
state->aio_context = bdrv_get_aio_context(state->old_bs);
|
||||
aio_context_acquire(state->aio_context);
|
||||
|
||||
if (!bdrv_is_inserted(state->old_bs)) {
|
||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
return;
|
||||
@@ -1432,6 +1470,8 @@ static void external_snapshot_commit(BlkTransactionState *common)
|
||||
ExternalSnapshotState *state =
|
||||
DO_UPCAST(ExternalSnapshotState, common, common);
|
||||
|
||||
bdrv_set_aio_context(state->new_bs, state->aio_context);
|
||||
|
||||
/* This removes our old bs and adds the new bs */
|
||||
bdrv_append(state->new_bs, state->old_bs);
|
||||
/* We don't need (or want) to use the transactional
|
||||
@@ -1439,6 +1479,8 @@ static void external_snapshot_commit(BlkTransactionState *common)
|
||||
* don't want to abort all of them if one of them fails the reopen */
|
||||
bdrv_reopen(state->new_bs, state->new_bs->open_flags & ~BDRV_O_RDWR,
|
||||
NULL);
|
||||
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
|
||||
static void external_snapshot_abort(BlkTransactionState *common)
|
||||
@@ -1448,23 +1490,38 @@ static void external_snapshot_abort(BlkTransactionState *common)
|
||||
if (state->new_bs) {
|
||||
bdrv_unref(state->new_bs);
|
||||
}
|
||||
if (state->aio_context) {
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct DriveBackupState {
|
||||
BlkTransactionState common;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
BlockJob *job;
|
||||
} DriveBackupState;
|
||||
|
||||
static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
|
||||
{
|
||||
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
||||
BlockDriverState *bs;
|
||||
DriveBackup *backup;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
|
||||
backup = common->action->drive_backup;
|
||||
|
||||
bs = bdrv_find(backup->device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
|
||||
return;
|
||||
}
|
||||
|
||||
/* AioContext is released in .clean() */
|
||||
state->aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(state->aio_context);
|
||||
|
||||
qmp_drive_backup(backup->device, backup->target,
|
||||
backup->has_format, backup->format,
|
||||
backup->sync,
|
||||
@@ -1475,12 +1532,10 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
state->bs = NULL;
|
||||
state->job = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
state->bs = bdrv_find(backup->device);
|
||||
state->bs = bs;
|
||||
state->job = state->bs->job;
|
||||
}
|
||||
|
||||
@@ -1495,6 +1550,88 @@ static void drive_backup_abort(BlkTransactionState *common)
|
||||
}
|
||||
}
|
||||
|
||||
static void drive_backup_clean(BlkTransactionState *common)
|
||||
{
|
||||
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
||||
|
||||
if (state->aio_context) {
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct BlockdevBackupState {
|
||||
BlkTransactionState common;
|
||||
BlockDriverState *bs;
|
||||
BlockJob *job;
|
||||
AioContext *aio_context;
|
||||
} BlockdevBackupState;
|
||||
|
||||
static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
|
||||
{
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
BlockdevBackup *backup;
|
||||
BlockDriverState *bs, *target;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
|
||||
backup = common->action->blockdev_backup;
|
||||
|
||||
bs = bdrv_find(backup->device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
|
||||
return;
|
||||
}
|
||||
|
||||
target = bdrv_find(backup->target);
|
||||
if (!target) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->target);
|
||||
return;
|
||||
}
|
||||
|
||||
/* AioContext is released in .clean() */
|
||||
state->aio_context = bdrv_get_aio_context(bs);
|
||||
if (state->aio_context != bdrv_get_aio_context(target)) {
|
||||
state->aio_context = NULL;
|
||||
error_setg(errp, "Backup between two IO threads is not implemented");
|
||||
return;
|
||||
}
|
||||
aio_context_acquire(state->aio_context);
|
||||
|
||||
qmp_blockdev_backup(backup->device, backup->target,
|
||||
backup->sync,
|
||||
backup->has_speed, backup->speed,
|
||||
backup->has_on_source_error, backup->on_source_error,
|
||||
backup->has_on_target_error, backup->on_target_error,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
state->bs = bs;
|
||||
state->job = state->bs->job;
|
||||
}
|
||||
|
||||
static void blockdev_backup_abort(BlkTransactionState *common)
|
||||
{
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
BlockDriverState *bs = state->bs;
|
||||
|
||||
/* Only cancel if it's the job we started */
|
||||
if (bs && bs->job && bs->job == state->job) {
|
||||
block_job_cancel_sync(bs->job);
|
||||
}
|
||||
}
|
||||
|
||||
static void blockdev_backup_clean(BlkTransactionState *common)
|
||||
{
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
|
||||
if (state->aio_context) {
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void abort_prepare(BlkTransactionState *common, Error **errp)
|
||||
{
|
||||
error_setg(errp, "Transaction aborted using Abort action");
|
||||
@@ -1516,6 +1653,13 @@ static const BdrvActionOps actions[] = {
|
||||
.instance_size = sizeof(DriveBackupState),
|
||||
.prepare = drive_backup_prepare,
|
||||
.abort = drive_backup_abort,
|
||||
.clean = drive_backup_clean,
|
||||
},
|
||||
[TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP] = {
|
||||
.instance_size = sizeof(BlockdevBackupState),
|
||||
.prepare = blockdev_backup_prepare,
|
||||
.abort = blockdev_backup_abort,
|
||||
.clean = blockdev_backup_clean,
|
||||
},
|
||||
[TRANSACTION_ACTION_KIND_ABORT] = {
|
||||
.instance_size = sizeof(BlkTransactionState),
|
||||
@@ -1526,13 +1670,13 @@ static const BdrvActionOps actions[] = {
|
||||
.instance_size = sizeof(InternalSnapshotState),
|
||||
.prepare = internal_snapshot_prepare,
|
||||
.abort = internal_snapshot_abort,
|
||||
.clean = internal_snapshot_clean,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* 'Atomic' group snapshots. The snapshots are taken as a set, and if any fail
|
||||
* then we do not pivot any of the devices in the group, and abandon the
|
||||
* snapshots
|
||||
* 'Atomic' group operations. The operations are performed as a set, and if
|
||||
* any fail then we roll back all operations in the group.
|
||||
*/
|
||||
void qmp_transaction(TransactionActionList *dev_list, Error **errp)
|
||||
{
|
||||
@@ -1543,10 +1687,10 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp)
|
||||
QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionState) snap_bdrv_states;
|
||||
QSIMPLEQ_INIT(&snap_bdrv_states);
|
||||
|
||||
/* drain all i/o before any snapshots */
|
||||
/* drain all i/o before any operations */
|
||||
bdrv_drain_all();
|
||||
|
||||
/* We don't do anything in this loop that commits us to the snapshot */
|
||||
/* We don't do anything in this loop that commits us to the operations */
|
||||
while (NULL != dev_entry) {
|
||||
TransactionAction *dev_info = NULL;
|
||||
const BdrvActionOps *ops;
|
||||
@@ -1581,10 +1725,7 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp)
|
||||
goto exit;
|
||||
|
||||
delete_and_fail:
|
||||
/*
|
||||
* failure, and it is all-or-none; abandon each new bs, and keep using
|
||||
* the original bs for all images
|
||||
*/
|
||||
/* failure, and it is all-or-none; roll back all operations */
|
||||
QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
|
||||
if (state->ops->abort) {
|
||||
state->ops->abort(state);
|
||||
@@ -1603,14 +1744,18 @@ exit:
|
||||
static void eject_device(BlockBackend *blk, int force, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
AioContext *aio_context;
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
if (!blk_dev_has_removable_media(blk)) {
|
||||
error_setg(errp, "Device '%s' is not removable",
|
||||
bdrv_get_device_name(bs));
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
|
||||
@@ -1618,11 +1763,14 @@ static void eject_device(BlockBackend *blk, int force, Error **errp)
|
||||
if (!force) {
|
||||
error_setg(errp, "Device '%s' is locked",
|
||||
bdrv_get_device_name(bs));
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_close(bs);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
|
||||
@@ -1644,6 +1792,7 @@ void qmp_block_passwd(bool has_device, const char *device,
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
int err;
|
||||
|
||||
bs = bdrv_lookup_bs(has_device ? device : NULL,
|
||||
@@ -1654,16 +1803,23 @@ void qmp_block_passwd(bool has_device, const char *device,
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
err = bdrv_set_key(bs, password);
|
||||
if (err == -EINVAL) {
|
||||
error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
|
||||
return;
|
||||
goto out;
|
||||
} else if (err < 0) {
|
||||
error_set(errp, QERR_INVALID_PASSWORD);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
/* Assumes AioContext is held */
|
||||
static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
|
||||
int bdrv_flags, BlockDriver *drv,
|
||||
const char *password, Error **errp)
|
||||
@@ -1696,6 +1852,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
BlockDriver *drv = NULL;
|
||||
int bdrv_flags;
|
||||
Error *err = NULL;
|
||||
@@ -1707,24 +1864,30 @@ void qmp_change_blockdev(const char *device, const char *filename,
|
||||
}
|
||||
bs = blk_bs(blk);
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (format) {
|
||||
drv = bdrv_find_whitelisted_format(format, bs->read_only);
|
||||
if (!drv) {
|
||||
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
eject_device(blk, 0, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
|
||||
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
|
||||
|
||||
qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
/* throttling disk I/O limits */
|
||||
@@ -2055,7 +2218,7 @@ void qmp_block_commit(const char *device,
|
||||
/* drain all i/o before commits */
|
||||
bdrv_drain_all();
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, errp)) {
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2088,6 +2251,10 @@ void qmp_block_commit(const char *device,
|
||||
|
||||
assert(bdrv_get_aio_context(base_bs) == aio_context);
|
||||
|
||||
if (bdrv_op_is_blocked(base_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Do not allow attempts to commit an image into itself */
|
||||
if (top_bs == base_bs) {
|
||||
error_setg(errp, "cannot commit an image into itself");
|
||||
@@ -2156,6 +2323,8 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
/* Although backup_run has this check too, we need to use bs->drv below, so
|
||||
* do an early check redundantly. */
|
||||
if (!bdrv_is_inserted(bs)) {
|
||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
goto out;
|
||||
@@ -2172,6 +2341,7 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
}
|
||||
}
|
||||
|
||||
/* Early check to avoid creating target */
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||
goto out;
|
||||
}
|
||||
@@ -2239,6 +2409,57 @@ BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
|
||||
return bdrv_named_nodes_list();
|
||||
}
|
||||
|
||||
void qmp_blockdev_backup(const char *device, const char *target,
|
||||
enum MirrorSyncMode sync,
|
||||
bool has_speed, int64_t speed,
|
||||
bool has_on_source_error,
|
||||
BlockdevOnError on_source_error,
|
||||
bool has_on_target_error,
|
||||
BlockdevOnError on_target_error,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *target_bs;
|
||||
Error *local_err = NULL;
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!has_speed) {
|
||||
speed = 0;
|
||||
}
|
||||
if (!has_on_source_error) {
|
||||
on_source_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
}
|
||||
if (!has_on_target_error) {
|
||||
on_target_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
}
|
||||
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
target_bs = bdrv_find(target);
|
||||
if (!target_bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, target);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bdrv_ref(target_bs);
|
||||
bdrv_set_aio_context(target_bs, aio_context);
|
||||
backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
|
||||
block_job_cb, bs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
bdrv_unref(target_bs);
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
||||
|
||||
void qmp_drive_mirror(const char *device, const char *target,
|
||||
@@ -2548,6 +2769,7 @@ void qmp_change_backing_file(const char *device,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
AioContext *aio_context;
|
||||
BlockDriverState *image_bs = NULL;
|
||||
Error *local_err = NULL;
|
||||
bool ro;
|
||||
@@ -2561,34 +2783,37 @@ void qmp_change_backing_file(const char *device,
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!image_bs) {
|
||||
error_setg(errp, "image file not found");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bdrv_find_base(image_bs) == image_bs) {
|
||||
error_setg(errp, "not allowing backing file change on an image "
|
||||
"without a backing file");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* even though we are not necessarily operating on bs, we need it to
|
||||
* determine if block ops are currently prohibited on the chain */
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* final sanity check */
|
||||
if (!bdrv_chain_contains(bs, image_bs)) {
|
||||
error_setg(errp, "'%s' and image file are not in the same chain",
|
||||
device);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if not r/w, reopen to make r/w */
|
||||
@@ -2599,7 +2824,7 @@ void qmp_change_backing_file(const char *device,
|
||||
bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2619,6 +2844,9 @@ void qmp_change_backing_file(const char *device,
|
||||
error_propagate(errp, local_err); /* will preserve prior errp */
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||
|
||||
73
bootdevice.c
73
bootdevice.c
@@ -25,6 +25,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/hw.h"
|
||||
|
||||
typedef struct FWBootEntry FWBootEntry;
|
||||
|
||||
@@ -37,6 +38,78 @@ struct FWBootEntry {
|
||||
|
||||
static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =
|
||||
QTAILQ_HEAD_INITIALIZER(fw_boot_order);
|
||||
static QEMUBootSetHandler *boot_set_handler;
|
||||
static void *boot_set_opaque;
|
||||
|
||||
void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
|
||||
{
|
||||
boot_set_handler = func;
|
||||
boot_set_opaque = opaque;
|
||||
}
|
||||
|
||||
void qemu_boot_set(const char *boot_order, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!boot_set_handler) {
|
||||
error_setg(errp, "no function defined to set boot device list for"
|
||||
" this architecture");
|
||||
return;
|
||||
}
|
||||
|
||||
validate_bootdevices(boot_order, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
boot_set_handler(boot_set_opaque, boot_order, errp);
|
||||
}
|
||||
|
||||
void validate_bootdevices(const char *devices, Error **errp)
|
||||
{
|
||||
/* We just do some generic consistency checks */
|
||||
const char *p;
|
||||
int bitmap = 0;
|
||||
|
||||
for (p = devices; *p != '\0'; p++) {
|
||||
/* Allowed boot devices are:
|
||||
* a-b: floppy disk drives
|
||||
* c-f: IDE disk drives
|
||||
* g-m: machine implementation dependent drives
|
||||
* n-p: network devices
|
||||
* It's up to each machine implementation to check if the given boot
|
||||
* devices match the actual hardware implementation and firmware
|
||||
* features.
|
||||
*/
|
||||
if (*p < 'a' || *p > 'p') {
|
||||
error_setg(errp, "Invalid boot device '%c'", *p);
|
||||
return;
|
||||
}
|
||||
if (bitmap & (1 << (*p - 'a'))) {
|
||||
error_setg(errp, "Boot device '%c' was given twice", *p);
|
||||
return;
|
||||
}
|
||||
bitmap |= 1 << (*p - 'a');
|
||||
}
|
||||
}
|
||||
|
||||
void restore_boot_order(void *opaque)
|
||||
{
|
||||
char *normal_boot_order = opaque;
|
||||
static int first = 1;
|
||||
|
||||
/* Restore boot order and remove ourselves after the first boot */
|
||||
if (first) {
|
||||
first = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_boot_set(normal_boot_order, NULL);
|
||||
|
||||
qemu_unregister_reset(restore_boot_order, normal_boot_order);
|
||||
g_free(normal_boot_order);
|
||||
}
|
||||
|
||||
void check_boot_index(int32_t bootindex, Error **errp)
|
||||
{
|
||||
|
||||
@@ -351,8 +351,10 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
|
||||
|
||||
_regs->gpr[1] = infop->start_stack;
|
||||
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
||||
entry = ldq_raw(infop->entry) + infop->load_addr;
|
||||
toc = ldq_raw(infop->entry + 8) + infop->load_addr;
|
||||
get_user_u64(entry, infop->entry);
|
||||
entry += infop->load_addr;
|
||||
get_user_u64(toc, infop->entry + 8);
|
||||
toc += infop->load_addr;
|
||||
_regs->gpr[2] = toc;
|
||||
infop->entry = entry;
|
||||
#endif
|
||||
@@ -365,8 +367,9 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
|
||||
get_user_ual(_regs->gpr[3], pos);
|
||||
pos += sizeof(abi_ulong);
|
||||
_regs->gpr[4] = pos;
|
||||
for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
|
||||
tmp = ldl(pos);
|
||||
for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) {
|
||||
get_user_ual(tmp, pos);
|
||||
}
|
||||
_regs->gpr[5] = pos;
|
||||
}
|
||||
|
||||
|
||||
36
configure
vendored
36
configure
vendored
@@ -1823,13 +1823,14 @@ fi
|
||||
# libseccomp check
|
||||
|
||||
if test "$seccomp" != "no" ; then
|
||||
if $pkg_config --atleast-version=2.1.0 libseccomp; then
|
||||
if test "$cpu" = "i386" || test "$cpu" = "x86_64" &&
|
||||
$pkg_config --atleast-version=2.1.1 libseccomp; then
|
||||
libs_softmmu="$libs_softmmu `$pkg_config --libs libseccomp`"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS `$pkg_config --cflags libseccomp`"
|
||||
seccomp="yes"
|
||||
else
|
||||
if test "$seccomp" = "yes"; then
|
||||
feature_not_found "libseccomp" "Install libseccomp devel >= 2.1.0"
|
||||
feature_not_found "libseccomp" "Install libseccomp devel >= 2.1.1"
|
||||
fi
|
||||
seccomp="no"
|
||||
fi
|
||||
@@ -1868,6 +1869,32 @@ EOF
|
||||
#if !defined(HVM_MAX_VCPUS)
|
||||
# error HVM_MAX_VCPUS not defined
|
||||
#endif
|
||||
int main(void) {
|
||||
xc_interface *xc;
|
||||
xs_daemon_open();
|
||||
xc = xc_interface_open(0, 0, 0);
|
||||
xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
|
||||
xc_gnttab_open(NULL, 0);
|
||||
xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
|
||||
xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000);
|
||||
xc_hvm_create_ioreq_server(xc, 0, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
compile_prog "" "$xen_libs"
|
||||
then
|
||||
xen_ctrl_version=450
|
||||
xen=yes
|
||||
|
||||
elif
|
||||
cat > $TMPC <<EOF &&
|
||||
#include <xenctrl.h>
|
||||
#include <xenstore.h>
|
||||
#include <stdint.h>
|
||||
#include <xen/hvm/hvm_info_table.h>
|
||||
#if !defined(HVM_MAX_VCPUS)
|
||||
# error HVM_MAX_VCPUS not defined
|
||||
#endif
|
||||
int main(void) {
|
||||
xc_interface *xc;
|
||||
xs_daemon_open();
|
||||
@@ -2726,7 +2753,7 @@ fi
|
||||
if test "$modules" = yes; then
|
||||
shacmd_probe="sha1sum sha1 shasum"
|
||||
for c in $shacmd_probe; do
|
||||
if which $c >/dev/null 2>&1; then
|
||||
if has $c; then
|
||||
shacmd="$c"
|
||||
break
|
||||
fi
|
||||
@@ -4282,6 +4309,9 @@ if test -n "$sparc_cpu"; then
|
||||
echo "Target Sparc Arch $sparc_cpu"
|
||||
fi
|
||||
echo "xen support $xen"
|
||||
if test "$xen" = "yes" ; then
|
||||
echo "xen ctrl version $xen_ctrl_version"
|
||||
fi
|
||||
echo "brlapi support $brlapi"
|
||||
echo "bluez support $bluez"
|
||||
echo "Documentation $docs"
|
||||
|
||||
@@ -155,7 +155,7 @@ Coroutine *qemu_coroutine_new(void)
|
||||
stack_t oss;
|
||||
sigset_t sigs;
|
||||
sigset_t osigs;
|
||||
jmp_buf old_env;
|
||||
sigjmp_buf old_env;
|
||||
|
||||
/* The way to manipulate stack is with the sigaltstack function. We
|
||||
* prepare a stack, with it delivering a signal to ourselves and then
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <ucontext.h>
|
||||
#include "qemu-common.h"
|
||||
#include "block/coroutine_int.h"
|
||||
@@ -48,15 +47,8 @@ typedef struct {
|
||||
/**
|
||||
* Per-thread coroutine bookkeeping
|
||||
*/
|
||||
typedef struct {
|
||||
/** Currently executing coroutine */
|
||||
Coroutine *current;
|
||||
|
||||
/** The default coroutine */
|
||||
CoroutineUContext leader;
|
||||
} CoroutineThreadState;
|
||||
|
||||
static pthread_key_t thread_state_key;
|
||||
static __thread CoroutineUContext leader;
|
||||
static __thread Coroutine *current;
|
||||
|
||||
/*
|
||||
* va_args to makecontext() must be type 'int', so passing
|
||||
@@ -68,36 +60,6 @@ union cc_arg {
|
||||
int i[2];
|
||||
};
|
||||
|
||||
static CoroutineThreadState *coroutine_get_thread_state(void)
|
||||
{
|
||||
CoroutineThreadState *s = pthread_getspecific(thread_state_key);
|
||||
|
||||
if (!s) {
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->current = &s->leader.base;
|
||||
pthread_setspecific(thread_state_key, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static void qemu_coroutine_thread_cleanup(void *opaque)
|
||||
{
|
||||
CoroutineThreadState *s = opaque;
|
||||
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) coroutine_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "unable to create leader key: %s\n", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void coroutine_trampoline(int i0, int i1)
|
||||
{
|
||||
union cc_arg arg;
|
||||
@@ -193,15 +155,23 @@ void qemu_coroutine_delete(Coroutine *co_)
|
||||
g_free(co);
|
||||
}
|
||||
|
||||
CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||
CoroutineAction action)
|
||||
/* This function is marked noinline to prevent GCC from inlining it
|
||||
* into coroutine_trampoline(). If we allow it to do that then it
|
||||
* hoists the code to get the address of the TLS variable "current"
|
||||
* out of the while() loop. This is an invalid transformation because
|
||||
* the sigsetjmp() call may be called when running thread A but
|
||||
* return in thread B, and so we might be in a different thread
|
||||
* context each time round the loop.
|
||||
*/
|
||||
CoroutineAction __attribute__((noinline))
|
||||
qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||
CoroutineAction action)
|
||||
{
|
||||
CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
|
||||
CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
|
||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
||||
int ret;
|
||||
|
||||
s->current = to_;
|
||||
current = to_;
|
||||
|
||||
ret = sigsetjmp(from->env, 0);
|
||||
if (ret == 0) {
|
||||
@@ -212,14 +182,13 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||
|
||||
Coroutine *qemu_coroutine_self(void)
|
||||
{
|
||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
||||
|
||||
return s->current;
|
||||
if (!current) {
|
||||
current = &leader.base;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
bool qemu_in_coroutine(void)
|
||||
{
|
||||
CoroutineThreadState *s = pthread_getspecific(thread_state_key);
|
||||
|
||||
return s && s->current->caller;
|
||||
return current && current->caller;
|
||||
}
|
||||
|
||||
15
cpu-exec.c
15
cpu-exec.c
@@ -168,7 +168,9 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
|
||||
}
|
||||
#endif /* DEBUG_DISAS */
|
||||
|
||||
cpu->can_do_io = 0;
|
||||
next_tb = tcg_qemu_tb_exec(env, tb_ptr);
|
||||
cpu->can_do_io = 1;
|
||||
trace_exec_tb_exit((void *) (next_tb & ~TB_EXIT_MASK),
|
||||
next_tb & TB_EXIT_MASK);
|
||||
|
||||
@@ -202,14 +204,19 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
TranslationBlock *tb;
|
||||
target_ulong pc = orig_tb->pc;
|
||||
target_ulong cs_base = orig_tb->cs_base;
|
||||
uint64_t flags = orig_tb->flags;
|
||||
|
||||
/* Should never happen.
|
||||
We only end up here when an existing TB is too long. */
|
||||
if (max_cycles > CF_COUNT_MASK)
|
||||
max_cycles = CF_COUNT_MASK;
|
||||
|
||||
tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
|
||||
max_cycles);
|
||||
/* tb_gen_code can flush our orig_tb, invalidate it now */
|
||||
tb_phys_invalidate(orig_tb, -1);
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags,
|
||||
max_cycles | CF_NOCACHE);
|
||||
cpu->current_tb = tb;
|
||||
/* execute the generated code */
|
||||
trace_exec_tb_nocache(tb, tb->pc);
|
||||
@@ -353,7 +360,6 @@ int cpu_exec(CPUArchState *env)
|
||||
}
|
||||
|
||||
cc->cpu_exec_enter(cpu);
|
||||
cpu->exception_index = -1;
|
||||
|
||||
/* Calculate difference between guest clock and host clock.
|
||||
* This delay includes the delay of the last cycle, so
|
||||
@@ -373,6 +379,7 @@ int cpu_exec(CPUArchState *env)
|
||||
if (ret == EXCP_DEBUG) {
|
||||
cpu_handle_debug_exception(env);
|
||||
}
|
||||
cpu->exception_index = -1;
|
||||
break;
|
||||
} else {
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
@@ -383,6 +390,7 @@ int cpu_exec(CPUArchState *env)
|
||||
cc->do_interrupt(cpu);
|
||||
#endif
|
||||
ret = cpu->exception_index;
|
||||
cpu->exception_index = -1;
|
||||
break;
|
||||
#else
|
||||
cc->do_interrupt(cpu);
|
||||
@@ -537,6 +545,7 @@ int cpu_exec(CPUArchState *env)
|
||||
cpu = current_cpu;
|
||||
env = cpu->env_ptr;
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
cpu->can_do_io = 1;
|
||||
#ifdef TARGET_I386
|
||||
x86_cpu = X86_CPU(cpu);
|
||||
#endif
|
||||
|
||||
39
cpus.c
39
cpus.c
@@ -136,8 +136,7 @@ typedef struct TimersState {
|
||||
|
||||
static TimersState timers_state;
|
||||
|
||||
/* Return the virtual CPU time, based on the instruction counter. */
|
||||
static int64_t cpu_get_icount_locked(void)
|
||||
int64_t cpu_get_icount_raw(void)
|
||||
{
|
||||
int64_t icount;
|
||||
CPUState *cpu = current_cpu;
|
||||
@@ -145,10 +144,18 @@ static int64_t cpu_get_icount_locked(void)
|
||||
icount = timers_state.qemu_icount;
|
||||
if (cpu) {
|
||||
if (!cpu_can_do_io(cpu)) {
|
||||
fprintf(stderr, "Bad clock read\n");
|
||||
fprintf(stderr, "Bad icount read\n");
|
||||
exit(1);
|
||||
}
|
||||
icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
|
||||
}
|
||||
return icount;
|
||||
}
|
||||
|
||||
/* Return the virtual CPU time, based on the instruction counter. */
|
||||
static int64_t cpu_get_icount_locked(void)
|
||||
{
|
||||
int64_t icount = cpu_get_icount_raw();
|
||||
return timers_state.qemu_icount_bias + cpu_icount_to_ns(icount);
|
||||
}
|
||||
|
||||
@@ -317,7 +324,7 @@ static void icount_adjust(void)
|
||||
static void icount_adjust_rt(void *opaque)
|
||||
{
|
||||
timer_mod(icount_rt_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
||||
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000);
|
||||
icount_adjust();
|
||||
}
|
||||
|
||||
@@ -345,7 +352,7 @@ static void icount_warp_rt(void *opaque)
|
||||
|
||||
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
||||
if (runstate_is_running()) {
|
||||
int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
int64_t clock = cpu_get_clock_locked();
|
||||
int64_t warp_delta;
|
||||
|
||||
warp_delta = clock - vm_clock_warp_start;
|
||||
@@ -354,9 +361,8 @@ static void icount_warp_rt(void *opaque)
|
||||
* In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too
|
||||
* far ahead of real time.
|
||||
*/
|
||||
int64_t cur_time = cpu_get_clock_locked();
|
||||
int64_t cur_icount = cpu_get_icount_locked();
|
||||
int64_t delta = cur_time - cur_icount;
|
||||
int64_t delta = clock - cur_icount;
|
||||
warp_delta = MIN(warp_delta, delta);
|
||||
}
|
||||
timers_state.qemu_icount_bias += warp_delta;
|
||||
@@ -419,7 +425,7 @@ void qemu_clock_warp(QEMUClockType type)
|
||||
}
|
||||
|
||||
/* We want to use the earliest deadline from ALL vm_clocks */
|
||||
clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT);
|
||||
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
||||
if (deadline < 0) {
|
||||
return;
|
||||
@@ -437,8 +443,8 @@ void qemu_clock_warp(QEMUClockType type)
|
||||
* sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL
|
||||
* timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL
|
||||
* event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL
|
||||
* after some e"real" time, (related to the time left until the next
|
||||
* event) has passed. The QEMU_CLOCK_REALTIME timer will do this.
|
||||
* after some "real" time, (related to the time left until the next
|
||||
* event) has passed. The QEMU_CLOCK_VIRTUAL_RT clock will do this.
|
||||
* This avoids that the warps are visible externally; for example,
|
||||
* you will not be sending network packets continuously instead of
|
||||
* every 100ms.
|
||||
@@ -512,8 +518,8 @@ void configure_icount(QemuOpts *opts, Error **errp)
|
||||
return;
|
||||
}
|
||||
icount_align_option = qemu_opt_get_bool(opts, "align", false);
|
||||
icount_warp_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
|
||||
icount_warp_rt, NULL);
|
||||
icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
|
||||
icount_warp_rt, NULL);
|
||||
if (strcmp(option, "auto") != 0) {
|
||||
errno = 0;
|
||||
icount_time_shift = strtol(option, &rem_str, 0);
|
||||
@@ -537,10 +543,10 @@ void configure_icount(QemuOpts *opts, Error **errp)
|
||||
the virtual time trigger catches emulated time passing too fast.
|
||||
Realtime triggers occur even when idle, so use them less frequently
|
||||
than VM triggers. */
|
||||
icount_rt_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
|
||||
icount_adjust_rt, NULL);
|
||||
icount_rt_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL_RT,
|
||||
icount_adjust_rt, NULL);
|
||||
timer_mod(icount_rt_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
||||
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000);
|
||||
icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
icount_adjust_vm, NULL);
|
||||
timer_mod(icount_vm_timer,
|
||||
@@ -934,6 +940,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->can_do_io = 1;
|
||||
current_cpu = cpu;
|
||||
|
||||
r = kvm_init_vcpu(cpu);
|
||||
@@ -974,6 +981,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->can_do_io = 1;
|
||||
|
||||
sigemptyset(&waitset);
|
||||
sigaddset(&waitset, SIG_IPI);
|
||||
@@ -1016,6 +1024,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->created = true;
|
||||
cpu->can_do_io = 1;
|
||||
}
|
||||
qemu_cond_signal(&qemu_cpu_cond);
|
||||
|
||||
|
||||
3
cputlb.c
3
cputlb.c
@@ -270,7 +270,8 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
||||
assert(sz >= TARGET_PAGE_SIZE);
|
||||
|
||||
#if defined(DEBUG_TLB)
|
||||
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
|
||||
" prot=%x idx=%d\n",
|
||||
vaddr, paddr, prot, mmu_idx);
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,5 @@ CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_VT82C686=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
|
||||
@@ -32,6 +32,5 @@ CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_VT82C686=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
|
||||
@@ -32,6 +32,5 @@ CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_VT82C686=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
|
||||
@@ -30,3 +30,5 @@ CONFIG_IPACK=y
|
||||
CONFIG_WDT_IB6300ESB=y
|
||||
CONFIG_PCI_TESTDEV=y
|
||||
CONFIG_NVME_PCI=y
|
||||
CONFIG_SD=y
|
||||
CONFIG_SDHCI=y
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
include pci.mak
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_S390_FLIC=y
|
||||
|
||||
@@ -324,6 +324,7 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
|
||||
uint64_t value;
|
||||
int cellnum, vnum, ncells;
|
||||
uint32_t hival;
|
||||
int ret;
|
||||
|
||||
propcells = g_new0(uint32_t, numvalues * 2);
|
||||
|
||||
@@ -331,18 +332,23 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
|
||||
for (vnum = 0; vnum < numvalues; vnum++) {
|
||||
ncells = values[vnum * 2];
|
||||
if (ncells != 1 && ncells != 2) {
|
||||
return -1;
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
value = values[vnum * 2 + 1];
|
||||
hival = cpu_to_be32(value >> 32);
|
||||
if (ncells > 1) {
|
||||
propcells[cellnum++] = hival;
|
||||
} else if (hival != 0) {
|
||||
return -1;
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
propcells[cellnum++] = cpu_to_be32(value);
|
||||
}
|
||||
|
||||
return qemu_fdt_setprop(fdt, node_path, property, propcells,
|
||||
cellnum * sizeof(uint32_t));
|
||||
ret = qemu_fdt_setprop(fdt, node_path, property, propcells,
|
||||
cellnum * sizeof(uint32_t));
|
||||
out:
|
||||
g_free(propcells);
|
||||
return ret;
|
||||
}
|
||||
|
||||
714
disas/mips.c
714
disas/mips.c
@@ -220,6 +220,28 @@ see <http://www.gnu.org/licenses/>. */
|
||||
#define OP_SH_MTACC_D 13
|
||||
#define OP_MASK_MTACC_D 0x3
|
||||
|
||||
/* MSA */
|
||||
#define OP_MASK_1BIT 0x1
|
||||
#define OP_SH_1BIT 16
|
||||
#define OP_MASK_2BIT 0x3
|
||||
#define OP_SH_2BIT 16
|
||||
#define OP_MASK_3BIT 0x7
|
||||
#define OP_SH_3BIT 16
|
||||
#define OP_MASK_4BIT 0xf
|
||||
#define OP_SH_4BIT 16
|
||||
#define OP_MASK_5BIT 0x1f
|
||||
#define OP_SH_5BIT 16
|
||||
#define OP_MASK_10BIT 0x3ff
|
||||
#define OP_SH_10BIT 11
|
||||
#define OP_MASK_MSACR11 0x1f
|
||||
#define OP_SH_MSACR11 11
|
||||
#define OP_MASK_MSACR6 0x1f
|
||||
#define OP_SH_MSACR6 6
|
||||
#define OP_MASK_GPR 0x1f
|
||||
#define OP_SH_GPR 6
|
||||
#define OP_MASK_1_TO_4 0x3
|
||||
#define OP_SH_1_TO_4 6
|
||||
|
||||
#define OP_OP_COP0 0x10
|
||||
#define OP_OP_COP1 0x11
|
||||
#define OP_OP_COP2 0x12
|
||||
@@ -510,6 +532,9 @@ struct mips_opcode
|
||||
/* Instruction writes MDMX accumulator. */
|
||||
#define INSN2_WRITE_MDMX_ACC 0x00000004
|
||||
|
||||
/* Reads the general purpose register in OP_*_RD. */
|
||||
#define INSN2_READ_GPR_D 0x00000200
|
||||
|
||||
/* Instruction is actually a macro. It should be ignored by the
|
||||
disassembler, and requires special treatment by the assembler. */
|
||||
#define INSN_MACRO 0xffffffff
|
||||
@@ -567,7 +592,12 @@ struct mips_opcode
|
||||
#define INSN_5500 0x02000000
|
||||
|
||||
/* MDMX ASE */
|
||||
#define INSN_MDMX 0x04000000
|
||||
#define INSN_MDMX 0x00000000 /* Deprecated */
|
||||
|
||||
/* MIPS MSA Extension */
|
||||
#define INSN_MSA 0x04000000
|
||||
#define INSN_MSA64 0x04000000
|
||||
|
||||
/* MT ASE */
|
||||
#define INSN_MT 0x08000000
|
||||
/* SmartMIPS ASE */
|
||||
@@ -1204,6 +1234,17 @@ extern const int bfd_mips16_num_opcodes;
|
||||
/* MIPS MT ASE support. */
|
||||
#define MT32 INSN_MT
|
||||
|
||||
/* MSA */
|
||||
#define MSA INSN_MSA
|
||||
#define MSA64 INSN_MSA64
|
||||
#define WR_VD INSN_WRITE_FPR_D /* Reuse INSN_WRITE_FPR_D */
|
||||
#define RD_VD WR_VD /* Reuse WR_VD */
|
||||
#define RD_VT INSN_READ_FPR_T /* Reuse INSN_READ_FPR_T */
|
||||
#define RD_VS INSN_READ_FPR_S /* Reuse INSN_READ_FPR_S */
|
||||
#define RD_d INSN2_READ_GPR_D /* Reuse INSN2_READ_GPR_D */
|
||||
|
||||
#define RD_rd6 0
|
||||
|
||||
/* The order of overloaded instructions matters. Label arguments and
|
||||
register arguments look the same. Instructions that can have either
|
||||
for arguments must apear in the correct order in this table for the
|
||||
@@ -1363,6 +1404,541 @@ const struct mips_opcode mips_builtin_opcodes[] =
|
||||
{"cmp.sor.d", "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sne.d", "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
|
||||
/* MSA */
|
||||
{"sll.b", "+d,+e,+f", 0x7800000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"sll.h", "+d,+e,+f", 0x7820000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"sll.w", "+d,+e,+f", 0x7840000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"sll.d", "+d,+e,+f", 0x7860000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"slli.b", "+d,+e,+7", 0x78700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"slli.h", "+d,+e,+8", 0x78600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"slli.w", "+d,+e,+9", 0x78400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"slli.d", "+d,+e,'", 0x78000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sra.b", "+d,+e,+f", 0x7880000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"sra.h", "+d,+e,+f", 0x78a0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"sra.w", "+d,+e,+f", 0x78c0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"sra.d", "+d,+e,+f", 0x78e0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srai.b", "+d,+e,+7", 0x78f00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srai.h", "+d,+e,+8", 0x78e00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srai.w", "+d,+e,+9", 0x78c00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srai.d", "+d,+e,'", 0x78800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srl.b", "+d,+e,+f", 0x7900000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srl.h", "+d,+e,+f", 0x7920000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srl.w", "+d,+e,+f", 0x7940000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srl.d", "+d,+e,+f", 0x7960000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srli.b", "+d,+e,+7", 0x79700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srli.h", "+d,+e,+8", 0x79600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srli.w", "+d,+e,+9", 0x79400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srli.d", "+d,+e,'", 0x79000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bclr.b", "+d,+e,+f", 0x7980000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bclr.h", "+d,+e,+f", 0x79a0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bclr.w", "+d,+e,+f", 0x79c0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bclr.d", "+d,+e,+f", 0x79e0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bclri.b", "+d,+e,+7", 0x79f00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bclri.h", "+d,+e,+8", 0x79e00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bclri.w", "+d,+e,+9", 0x79c00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bclri.d", "+d,+e,'", 0x79800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bset.b", "+d,+e,+f", 0x7a00000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bset.h", "+d,+e,+f", 0x7a20000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bset.w", "+d,+e,+f", 0x7a40000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bset.d", "+d,+e,+f", 0x7a60000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bseti.b", "+d,+e,+7", 0x7a700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bseti.h", "+d,+e,+8", 0x7a600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bseti.w", "+d,+e,+9", 0x7a400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bseti.d", "+d,+e,'", 0x7a000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bneg.b", "+d,+e,+f", 0x7a80000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bneg.h", "+d,+e,+f", 0x7aa0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bneg.w", "+d,+e,+f", 0x7ac0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bneg.d", "+d,+e,+f", 0x7ae0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bnegi.b", "+d,+e,+7", 0x7af00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bnegi.h", "+d,+e,+8", 0x7ae00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bnegi.w", "+d,+e,+9", 0x7ac00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bnegi.d", "+d,+e,'", 0x7a800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"binsl.b", "+d,+e,+f", 0x7b00000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"binsl.h", "+d,+e,+f", 0x7b20000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"binsl.w", "+d,+e,+f", 0x7b40000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"binsl.d", "+d,+e,+f", 0x7b60000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"binsli.b", "+d,+e,+7", 0x7b700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"binsli.h", "+d,+e,+8", 0x7b600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"binsli.w", "+d,+e,+9", 0x7b400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"binsli.d", "+d,+e,'", 0x7b000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"binsr.b", "+d,+e,+f", 0x7b80000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"binsr.h", "+d,+e,+f", 0x7ba0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"binsr.w", "+d,+e,+f", 0x7bc0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"binsr.d", "+d,+e,+f", 0x7be0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"binsri.b", "+d,+e,+7", 0x7bf00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"binsri.h", "+d,+e,+8", 0x7be00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"binsri.w", "+d,+e,+9", 0x7bc00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"binsri.d", "+d,+e,'", 0x7b800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"addv.b", "+d,+e,+f", 0x7800000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"addv.h", "+d,+e,+f", 0x7820000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"addv.w", "+d,+e,+f", 0x7840000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"addv.d", "+d,+e,+f", 0x7860000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"addvi.b", "+d,+e,k", 0x78000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"addvi.h", "+d,+e,k", 0x78200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"addvi.w", "+d,+e,k", 0x78400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"addvi.d", "+d,+e,k", 0x78600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"subv.b", "+d,+e,+f", 0x7880000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subv.h", "+d,+e,+f", 0x78a0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subv.w", "+d,+e,+f", 0x78c0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subv.d", "+d,+e,+f", 0x78e0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subvi.b", "+d,+e,k", 0x78800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"subvi.h", "+d,+e,k", 0x78a00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"subvi.w", "+d,+e,k", 0x78c00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"subvi.d", "+d,+e,k", 0x78e00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"max_s.b", "+d,+e,+f", 0x7900000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_s.h", "+d,+e,+f", 0x7920000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_s.w", "+d,+e,+f", 0x7940000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_s.d", "+d,+e,+f", 0x7960000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"maxi_s.b", "+d,+e,+5", 0x79000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"maxi_s.h", "+d,+e,+5", 0x79200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"maxi_s.w", "+d,+e,+5", 0x79400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"maxi_s.d", "+d,+e,+5", 0x79600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"max_u.b", "+d,+e,+f", 0x7980000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_u.h", "+d,+e,+f", 0x79a0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_u.w", "+d,+e,+f", 0x79c0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_u.d", "+d,+e,+f", 0x79e0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"maxi_u.b", "+d,+e,k", 0x79800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"maxi_u.h", "+d,+e,k", 0x79a00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"maxi_u.w", "+d,+e,k", 0x79c00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"maxi_u.d", "+d,+e,k", 0x79e00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"min_s.b", "+d,+e,+f", 0x7a00000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_s.h", "+d,+e,+f", 0x7a20000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_s.w", "+d,+e,+f", 0x7a40000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_s.d", "+d,+e,+f", 0x7a60000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mini_s.b", "+d,+e,+5", 0x7a000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"mini_s.h", "+d,+e,+5", 0x7a200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"mini_s.w", "+d,+e,+5", 0x7a400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"mini_s.d", "+d,+e,+5", 0x7a600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"min_u.b", "+d,+e,+f", 0x7a80000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_u.h", "+d,+e,+f", 0x7aa0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_u.w", "+d,+e,+f", 0x7ac0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_u.d", "+d,+e,+f", 0x7ae0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mini_u.b", "+d,+e,k", 0x7a800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"mini_u.h", "+d,+e,k", 0x7aa00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"mini_u.w", "+d,+e,k", 0x7ac00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"mini_u.d", "+d,+e,k", 0x7ae00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"max_a.b", "+d,+e,+f", 0x7b00000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_a.h", "+d,+e,+f", 0x7b20000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_a.w", "+d,+e,+f", 0x7b40000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"max_a.d", "+d,+e,+f", 0x7b60000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_a.b", "+d,+e,+f", 0x7b80000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_a.h", "+d,+e,+f", 0x7ba0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_a.w", "+d,+e,+f", 0x7bc0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"min_a.d", "+d,+e,+f", 0x7be0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ceq.b", "+d,+e,+f", 0x7800000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ceq.h", "+d,+e,+f", 0x7820000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ceq.w", "+d,+e,+f", 0x7840000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ceq.d", "+d,+e,+f", 0x7860000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ceqi.b", "+d,+e,+5", 0x78000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ceqi.h", "+d,+e,+5", 0x78200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ceqi.w", "+d,+e,+5", 0x78400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ceqi.d", "+d,+e,+5", 0x78600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clt_s.b", "+d,+e,+f", 0x7900000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clt_s.h", "+d,+e,+f", 0x7920000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clt_s.w", "+d,+e,+f", 0x7940000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clt_s.d", "+d,+e,+f", 0x7960000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clti_s.b", "+d,+e,+5", 0x79000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clti_s.h", "+d,+e,+5", 0x79200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clti_s.w", "+d,+e,+5", 0x79400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clti_s.d", "+d,+e,+5", 0x79600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clt_u.b", "+d,+e,+f", 0x7980000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clt_u.h", "+d,+e,+f", 0x79a0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clt_u.w", "+d,+e,+f", 0x79c0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clt_u.d", "+d,+e,+f", 0x79e0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clti_u.b", "+d,+e,k", 0x79800007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clti_u.h", "+d,+e,k", 0x79a00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clti_u.w", "+d,+e,k", 0x79c00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clti_u.d", "+d,+e,k", 0x79e00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"cle_s.b", "+d,+e,+f", 0x7a00000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"cle_s.h", "+d,+e,+f", 0x7a20000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"cle_s.w", "+d,+e,+f", 0x7a40000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"cle_s.d", "+d,+e,+f", 0x7a60000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clei_s.b", "+d,+e,+5", 0x7a000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clei_s.h", "+d,+e,+5", 0x7a200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clei_s.w", "+d,+e,+5", 0x7a400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clei_s.d", "+d,+e,+5", 0x7a600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"cle_u.b", "+d,+e,+f", 0x7a80000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"cle_u.h", "+d,+e,+f", 0x7aa0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"cle_u.w", "+d,+e,+f", 0x7ac0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"cle_u.d", "+d,+e,+f", 0x7ae0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"clei_u.b", "+d,+e,k", 0x7a800007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clei_u.h", "+d,+e,k", 0x7aa00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clei_u.w", "+d,+e,k", 0x7ac00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"clei_u.d", "+d,+e,k", 0x7ae00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ld.b", "+d,+^(d)", 0x78000020, 0xfc00003f, WR_VD|LDD, RD_d, MSA},
|
||||
{"ld.h", "+d,+#(d)", 0x78000021, 0xfc00003f, WR_VD|LDD, RD_d, MSA},
|
||||
{"ld.w", "+d,+$(d)", 0x78000022, 0xfc00003f, WR_VD|LDD, RD_d, MSA},
|
||||
{"ld.d", "+d,+%(d)", 0x78000023, 0xfc00003f, WR_VD|LDD, RD_d, MSA},
|
||||
{"st.b", "+d,+^(d)", 0x78000024, 0xfc00003f, RD_VD|SM, RD_d, MSA},
|
||||
{"st.h", "+d,+#(d)", 0x78000025, 0xfc00003f, RD_VD|SM, RD_d, MSA},
|
||||
{"st.w", "+d,+$(d)", 0x78000026, 0xfc00003f, RD_VD|SM, RD_d, MSA},
|
||||
{"st.d", "+d,+%(d)", 0x78000027, 0xfc00003f, RD_VD|SM, RD_d, MSA},
|
||||
{"sat_s.b", "+d,+e,+7", 0x7870000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sat_s.h", "+d,+e,+8", 0x7860000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sat_s.w", "+d,+e,+9", 0x7840000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sat_s.d", "+d,+e,'", 0x7800000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sat_u.b", "+d,+e,+7", 0x78f0000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sat_u.h", "+d,+e,+8", 0x78e0000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sat_u.w", "+d,+e,+9", 0x78c0000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sat_u.d", "+d,+e,'", 0x7880000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"add_a.b", "+d,+e,+f", 0x78000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"add_a.h", "+d,+e,+f", 0x78200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"add_a.w", "+d,+e,+f", 0x78400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"add_a.d", "+d,+e,+f", 0x78600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_a.b", "+d,+e,+f", 0x78800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_a.h", "+d,+e,+f", 0x78a00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_a.w", "+d,+e,+f", 0x78c00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_a.d", "+d,+e,+f", 0x78e00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_s.b", "+d,+e,+f", 0x79000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_s.h", "+d,+e,+f", 0x79200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_s.w", "+d,+e,+f", 0x79400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_s.d", "+d,+e,+f", 0x79600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_u.b", "+d,+e,+f", 0x79800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_u.h", "+d,+e,+f", 0x79a00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_u.w", "+d,+e,+f", 0x79c00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"adds_u.d", "+d,+e,+f", 0x79e00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ave_s.b", "+d,+e,+f", 0x7a000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ave_s.h", "+d,+e,+f", 0x7a200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ave_s.w", "+d,+e,+f", 0x7a400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ave_s.d", "+d,+e,+f", 0x7a600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ave_u.b", "+d,+e,+f", 0x7a800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ave_u.h", "+d,+e,+f", 0x7aa00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ave_u.w", "+d,+e,+f", 0x7ac00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ave_u.d", "+d,+e,+f", 0x7ae00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"aver_s.b", "+d,+e,+f", 0x7b000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"aver_s.h", "+d,+e,+f", 0x7b200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"aver_s.w", "+d,+e,+f", 0x7b400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"aver_s.d", "+d,+e,+f", 0x7b600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"aver_u.b", "+d,+e,+f", 0x7b800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"aver_u.h", "+d,+e,+f", 0x7ba00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"aver_u.w", "+d,+e,+f", 0x7bc00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"aver_u.d", "+d,+e,+f", 0x7be00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subs_s.b", "+d,+e,+f", 0x78000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subs_s.h", "+d,+e,+f", 0x78200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subs_s.w", "+d,+e,+f", 0x78400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subs_s.d", "+d,+e,+f", 0x78600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subs_u.b", "+d,+e,+f", 0x78800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subs_u.h", "+d,+e,+f", 0x78a00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subs_u.w", "+d,+e,+f", 0x78c00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subs_u.d", "+d,+e,+f", 0x78e00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subsus_u.b", "+d,+e,+f", 0x79000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subsus_u.h", "+d,+e,+f", 0x79200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subsus_u.w", "+d,+e,+f", 0x79400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subsus_u.d", "+d,+e,+f", 0x79600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subsuu_s.b", "+d,+e,+f", 0x79800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subsuu_s.h", "+d,+e,+f", 0x79a00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subsuu_s.w", "+d,+e,+f", 0x79c00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"subsuu_s.d", "+d,+e,+f", 0x79e00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"asub_s.b", "+d,+e,+f", 0x7a000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"asub_s.h", "+d,+e,+f", 0x7a200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"asub_s.w", "+d,+e,+f", 0x7a400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"asub_s.d", "+d,+e,+f", 0x7a600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"asub_u.b", "+d,+e,+f", 0x7a800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"asub_u.h", "+d,+e,+f", 0x7aa00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"asub_u.w", "+d,+e,+f", 0x7ac00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"asub_u.d", "+d,+e,+f", 0x7ae00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mulv.b", "+d,+e,+f", 0x78000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mulv.h", "+d,+e,+f", 0x78200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mulv.w", "+d,+e,+f", 0x78400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mulv.d", "+d,+e,+f", 0x78600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"maddv.b", "+d,+e,+f", 0x78800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"maddv.h", "+d,+e,+f", 0x78a00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"maddv.w", "+d,+e,+f", 0x78c00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"maddv.d", "+d,+e,+f", 0x78e00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"msubv.b", "+d,+e,+f", 0x79000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"msubv.h", "+d,+e,+f", 0x79200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"msubv.w", "+d,+e,+f", 0x79400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"msubv.d", "+d,+e,+f", 0x79600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"div_s.b", "+d,+e,+f", 0x7a000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"div_s.h", "+d,+e,+f", 0x7a200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"div_s.w", "+d,+e,+f", 0x7a400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"div_s.d", "+d,+e,+f", 0x7a600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"div_u.b", "+d,+e,+f", 0x7a800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"div_u.h", "+d,+e,+f", 0x7aa00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"div_u.w", "+d,+e,+f", 0x7ac00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"div_u.d", "+d,+e,+f", 0x7ae00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mod_s.b", "+d,+e,+f", 0x7b000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mod_s.h", "+d,+e,+f", 0x7b200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mod_s.w", "+d,+e,+f", 0x7b400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mod_s.d", "+d,+e,+f", 0x7b600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mod_u.b", "+d,+e,+f", 0x7b800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mod_u.h", "+d,+e,+f", 0x7ba00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mod_u.w", "+d,+e,+f", 0x7bc00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mod_u.d", "+d,+e,+f", 0x7be00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dotp_s.h", "+d,+e,+f", 0x78200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dotp_s.w", "+d,+e,+f", 0x78400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dotp_s.d", "+d,+e,+f", 0x78600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dotp_u.h", "+d,+e,+f", 0x78a00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dotp_u.w", "+d,+e,+f", 0x78c00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dotp_u.d", "+d,+e,+f", 0x78e00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpadd_s.h", "+d,+e,+f", 0x79200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpadd_s.w", "+d,+e,+f", 0x79400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpadd_s.d", "+d,+e,+f", 0x79600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpadd_u.h", "+d,+e,+f", 0x79a00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpadd_u.w", "+d,+e,+f", 0x79c00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpadd_u.d", "+d,+e,+f", 0x79e00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpsub_s.h", "+d,+e,+f", 0x7a200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpsub_s.w", "+d,+e,+f", 0x7a400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpsub_s.d", "+d,+e,+f", 0x7a600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpsub_u.h", "+d,+e,+f", 0x7aa00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpsub_u.w", "+d,+e,+f", 0x7ac00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"dpsub_u.d", "+d,+e,+f", 0x7ae00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"sld.b", "+d,+e[t]", 0x78000014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA},
|
||||
{"sld.h", "+d,+e[t]", 0x78200014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA},
|
||||
{"sld.w", "+d,+e[t]", 0x78400014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA},
|
||||
{"sld.d", "+d,+e[t]", 0x78600014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA},
|
||||
{"sldi.b", "+d,+e[+9]", 0x78000019, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sldi.h", "+d,+e[+8]", 0x78200019, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sldi.w", "+d,+e[+7]", 0x78300019, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"sldi.d", "+d,+e[+6]", 0x78380019, 0xfffc003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"splat.b", "+d,+e[t]", 0x78800014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA},
|
||||
{"splat.h", "+d,+e[t]", 0x78a00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA},
|
||||
{"splat.w", "+d,+e[t]", 0x78c00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA},
|
||||
{"splat.d", "+d,+e[t]", 0x78e00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA},
|
||||
{"splati.b", "+d,+e[+9]", 0x78400019, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"splati.h", "+d,+e[+8]", 0x78600019, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"splati.w", "+d,+e[+7]", 0x78700019, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"splati.d", "+d,+e[+6]", 0x78780019, 0xfffc003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"pckev.b", "+d,+e,+f", 0x79000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"pckev.h", "+d,+e,+f", 0x79200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"pckev.w", "+d,+e,+f", 0x79400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"pckev.d", "+d,+e,+f", 0x79600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"pckod.b", "+d,+e,+f", 0x79800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"pckod.h", "+d,+e,+f", 0x79a00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"pckod.w", "+d,+e,+f", 0x79c00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"pckod.d", "+d,+e,+f", 0x79e00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvl.b", "+d,+e,+f", 0x7a000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvl.h", "+d,+e,+f", 0x7a200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvl.w", "+d,+e,+f", 0x7a400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvl.d", "+d,+e,+f", 0x7a600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvr.b", "+d,+e,+f", 0x7a800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvr.h", "+d,+e,+f", 0x7aa00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvr.w", "+d,+e,+f", 0x7ac00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvr.d", "+d,+e,+f", 0x7ae00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvev.b", "+d,+e,+f", 0x7b000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvev.h", "+d,+e,+f", 0x7b200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvev.w", "+d,+e,+f", 0x7b400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvev.d", "+d,+e,+f", 0x7b600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvod.b", "+d,+e,+f", 0x7b800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvod.h", "+d,+e,+f", 0x7ba00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvod.w", "+d,+e,+f", 0x7bc00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ilvod.d", "+d,+e,+f", 0x7be00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"vshf.b", "+d,+e,+f", 0x78000015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"vshf.h", "+d,+e,+f", 0x78200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"vshf.w", "+d,+e,+f", 0x78400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"vshf.d", "+d,+e,+f", 0x78600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srar.b", "+d,+e,+f", 0x78800015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srar.h", "+d,+e,+f", 0x78a00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srar.w", "+d,+e,+f", 0x78c00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srar.d", "+d,+e,+f", 0x78e00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srari.b", "+d,+e,+7", 0x7970000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srari.h", "+d,+e,+8", 0x7960000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srari.w", "+d,+e,+9", 0x7940000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srari.d", "+d,+e,'", 0x7900000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srlr.b", "+d,+e,+f", 0x79000015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srlr.h", "+d,+e,+f", 0x79200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srlr.w", "+d,+e,+f", 0x79400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srlr.d", "+d,+e,+f", 0x79600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"srlri.b", "+d,+e,+7", 0x79f0000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srlri.h", "+d,+e,+8", 0x79e0000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srlri.w", "+d,+e,+9", 0x79c0000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"srlri.d", "+d,+e,'", 0x7980000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"hadd_s.h", "+d,+e,+f", 0x7a200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hadd_s.w", "+d,+e,+f", 0x7a400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hadd_s.d", "+d,+e,+f", 0x7a600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hadd_u.h", "+d,+e,+f", 0x7aa00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hadd_u.w", "+d,+e,+f", 0x7ac00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hadd_u.d", "+d,+e,+f", 0x7ae00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hsub_s.h", "+d,+e,+f", 0x7b200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hsub_s.w", "+d,+e,+f", 0x7b400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hsub_s.d", "+d,+e,+f", 0x7b600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hsub_u.h", "+d,+e,+f", 0x7ba00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hsub_u.w", "+d,+e,+f", 0x7bc00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"hsub_u.d", "+d,+e,+f", 0x7be00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"and.v", "+d,+e,+f", 0x7800001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"andi.b", "+d,+e,5", 0x78000000, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"or.v", "+d,+e,+f", 0x7820001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ori.b", "+d,+e,5", 0x79000000, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nor.v", "+d,+e,+f", 0x7840001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"nori.b", "+d,+e,5", 0x7a000000, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"xor.v", "+d,+e,+f", 0x7860001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"xori.b", "+d,+e,5", 0x7b000000, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bmnz.v", "+d,+e,+f", 0x7880001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bmnzi.b", "+d,+e,5", 0x78000001, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bmz.v", "+d,+e,+f", 0x78a0001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bmzi.b", "+d,+e,5", 0x79000001, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bsel.v", "+d,+e,+f", 0x78c0001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"bseli.b", "+d,+e,5", 0x7a000001, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"shf.b", "+d,+e,5", 0x78000002, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"shf.h", "+d,+e,5", 0x79000002, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"shf.w", "+d,+e,5", 0x7a000002, 0xff00003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"bnz.v", "+f,p", 0x45e00000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"bz.v", "+f,p", 0x45600000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"fill.b", "+d,d", 0x7b00001e, 0xffff003f, WR_VD, RD_d, MSA},
|
||||
{"fill.h", "+d,d", 0x7b01001e, 0xffff003f, WR_VD, RD_d, MSA},
|
||||
{"fill.w", "+d,d", 0x7b02001e, 0xffff003f, WR_VD, RD_d, MSA},
|
||||
{"fill.d", "+d,d", 0x7b03001e, 0xffff003f, WR_VD, RD_d, MSA64},
|
||||
{"pcnt.b", "+d,+e", 0x7b04001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"pcnt.h", "+d,+e", 0x7b05001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"pcnt.w", "+d,+e", 0x7b06001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"pcnt.d", "+d,+e", 0x7b07001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nloc.b", "+d,+e", 0x7b08001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nloc.h", "+d,+e", 0x7b09001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nloc.w", "+d,+e", 0x7b0a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nloc.d", "+d,+e", 0x7b0b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nlzc.b", "+d,+e", 0x7b0c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nlzc.h", "+d,+e", 0x7b0d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nlzc.w", "+d,+e", 0x7b0e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"nlzc.d", "+d,+e", 0x7b0f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"copy_s.b", "+i,+e[+9]", 0x78800019, 0xffe0003f, RD_VS, RD_rd6, MSA},
|
||||
{"copy_s.h", "+i,+e[+8]", 0x78a00019, 0xfff0003f, RD_VS, RD_rd6, MSA},
|
||||
{"copy_s.w", "+i,+e[+7]", 0x78b00019, 0xfff8003f, RD_VS, RD_rd6, MSA},
|
||||
{"copy_s.d", "+i,+e[+6]", 0x78b80019, 0xfffc003f, RD_VS, RD_rd6, MSA64},
|
||||
{"copy_u.b", "+i,+e[+9]", 0x78c00019, 0xffe0003f, RD_VS, RD_rd6, MSA},
|
||||
{"copy_u.h", "+i,+e[+8]", 0x78e00019, 0xfff0003f, RD_VS, RD_rd6, MSA},
|
||||
{"copy_u.w", "+i,+e[+7]", 0x78f00019, 0xfff8003f, RD_VS, RD_rd6, MSA},
|
||||
{"copy_u.d", "+i,+e[+6]", 0x78f80019, 0xfffc003f, RD_VS, RD_rd6, MSA64},
|
||||
{"insert.b", "+d[+9],d", 0x79000019, 0xffe0003f, WR_VD|RD_VD, RD_d, MSA},
|
||||
{"insert.h", "+d[+8],d", 0x79200019, 0xfff0003f, WR_VD|RD_VD, RD_d, MSA},
|
||||
{"insert.w", "+d[+7],d", 0x79300019, 0xfff8003f, WR_VD|RD_VD, RD_d, MSA},
|
||||
{"insert.d", "+d[+6],d", 0x79380019, 0xfffc003f, WR_VD|RD_VD, RD_d, MSA64},
|
||||
{"insve.b", "+d[+9],+e[+~]", 0x79400019, 0xffe0003f, WR_VD|RD_VD|RD_VS, 0, MSA},
|
||||
{"insve.h", "+d[+8],+e[+~]", 0x79600019, 0xfff0003f, WR_VD|RD_VD|RD_VS, 0, MSA},
|
||||
{"insve.w", "+d[+7],+e[+~]", 0x79700019, 0xfff8003f, WR_VD|RD_VD|RD_VS, 0, MSA},
|
||||
{"insve.d", "+d[+6],+e[+~]", 0x79780019, 0xfffc003f, WR_VD|RD_VD|RD_VS, 0, MSA},
|
||||
{"bnz.b", "+f,p", 0x47800000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"bnz.h", "+f,p", 0x47a00000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"bnz.w", "+f,p", 0x47c00000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"bnz.d", "+f,p", 0x47e00000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"bz.b", "+f,p", 0x47000000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"bz.h", "+f,p", 0x47200000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"bz.w", "+f,p", 0x47400000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"bz.d", "+f,p", 0x47600000, 0xffe00000, CBD|RD_VT, 0, MSA},
|
||||
{"ldi.b", "+d,+0", 0x7b000007, 0xffe0003f, WR_VD, 0, MSA},
|
||||
{"ldi.h", "+d,+0", 0x7b200007, 0xffe0003f, WR_VD, 0, MSA},
|
||||
{"ldi.w", "+d,+0", 0x7b400007, 0xffe0003f, WR_VD, 0, MSA},
|
||||
{"ldi.d", "+d,+0", 0x7b600007, 0xffe0003f, WR_VD, 0, MSA},
|
||||
{"fcaf.w", "+d,+e,+f", 0x7800001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcaf.d", "+d,+e,+f", 0x7820001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcun.w", "+d,+e,+f", 0x7840001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcun.d", "+d,+e,+f", 0x7860001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fceq.w", "+d,+e,+f", 0x7880001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fceq.d", "+d,+e,+f", 0x78a0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcueq.w", "+d,+e,+f", 0x78c0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcueq.d", "+d,+e,+f", 0x78e0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fclt.w", "+d,+e,+f", 0x7900001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fclt.d", "+d,+e,+f", 0x7920001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcult.w", "+d,+e,+f", 0x7940001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcult.d", "+d,+e,+f", 0x7960001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcle.w", "+d,+e,+f", 0x7980001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcle.d", "+d,+e,+f", 0x79a0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcule.w", "+d,+e,+f", 0x79c0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcule.d", "+d,+e,+f", 0x79e0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsaf.w", "+d,+e,+f", 0x7a00001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsaf.d", "+d,+e,+f", 0x7a20001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsun.w", "+d,+e,+f", 0x7a40001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsun.d", "+d,+e,+f", 0x7a60001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fseq.w", "+d,+e,+f", 0x7a80001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fseq.d", "+d,+e,+f", 0x7aa0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsueq.w", "+d,+e,+f", 0x7ac0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsueq.d", "+d,+e,+f", 0x7ae0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fslt.w", "+d,+e,+f", 0x7b00001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fslt.d", "+d,+e,+f", 0x7b20001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsult.w", "+d,+e,+f", 0x7b40001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsult.d", "+d,+e,+f", 0x7b60001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsle.w", "+d,+e,+f", 0x7b80001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsle.d", "+d,+e,+f", 0x7ba0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsule.w", "+d,+e,+f", 0x7bc0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsule.d", "+d,+e,+f", 0x7be0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fadd.w", "+d,+e,+f", 0x7800001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fadd.d", "+d,+e,+f", 0x7820001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsub.w", "+d,+e,+f", 0x7840001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsub.d", "+d,+e,+f", 0x7860001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmul.w", "+d,+e,+f", 0x7880001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmul.d", "+d,+e,+f", 0x78a0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fdiv.w", "+d,+e,+f", 0x78c0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fdiv.d", "+d,+e,+f", 0x78e0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmadd.w", "+d,+e,+f", 0x7900001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmadd.d", "+d,+e,+f", 0x7920001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmsub.w", "+d,+e,+f", 0x7940001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmsub.d", "+d,+e,+f", 0x7960001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fexp2.w", "+d,+e,+f", 0x79c0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fexp2.d", "+d,+e,+f", 0x79e0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fexdo.h", "+d,+e,+f", 0x7a00001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fexdo.w", "+d,+e,+f", 0x7a20001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ftq.h", "+d,+e,+f", 0x7a80001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"ftq.w", "+d,+e,+f", 0x7aa0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmin.w", "+d,+e,+f", 0x7b00001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmin.d", "+d,+e,+f", 0x7b20001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmin_a.w", "+d,+e,+f", 0x7b40001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmin_a.d", "+d,+e,+f", 0x7b60001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmax.w", "+d,+e,+f", 0x7b80001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmax.d", "+d,+e,+f", 0x7ba0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmax_a.w", "+d,+e,+f", 0x7bc0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fmax_a.d", "+d,+e,+f", 0x7be0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcor.w", "+d,+e,+f", 0x7840001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcor.d", "+d,+e,+f", 0x7860001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcune.w", "+d,+e,+f", 0x7880001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcune.d", "+d,+e,+f", 0x78a0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcne.w", "+d,+e,+f", 0x78c0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fcne.d", "+d,+e,+f", 0x78e0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mul_q.h", "+d,+e,+f", 0x7900001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mul_q.w", "+d,+e,+f", 0x7920001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"madd_q.h", "+d,+e,+f", 0x7940001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"madd_q.w", "+d,+e,+f", 0x7960001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"msub_q.h", "+d,+e,+f", 0x7980001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"msub_q.w", "+d,+e,+f", 0x79a0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsor.w", "+d,+e,+f", 0x7a40001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsor.d", "+d,+e,+f", 0x7a60001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsune.w", "+d,+e,+f", 0x7a80001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsune.d", "+d,+e,+f", 0x7aa0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsne.w", "+d,+e,+f", 0x7ac0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fsne.d", "+d,+e,+f", 0x7ae0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mulr_q.h", "+d,+e,+f", 0x7b00001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"mulr_q.w", "+d,+e,+f", 0x7b20001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"maddr_q.h", "+d,+e,+f", 0x7b40001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"maddr_q.w", "+d,+e,+f", 0x7b60001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"msubr_q.h", "+d,+e,+f", 0x7b80001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"msubr_q.w", "+d,+e,+f", 0x7ba0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA},
|
||||
{"fclass.w", "+d,+e", 0x7b20001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"fclass.d", "+d,+e", 0x7b21001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"fsqrt.w", "+d,+e", 0x7b26001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"fsqrt.d", "+d,+e", 0x7b27001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"frsqrt.w", "+d,+e", 0x7b28001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"frsqrt.d", "+d,+e", 0x7b29001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"frcp.w", "+d,+e", 0x7b2a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"frcp.d", "+d,+e", 0x7b2b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"frint.w", "+d,+e", 0x7b2c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"frint.d", "+d,+e", 0x7b2d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"flog2.w", "+d,+e", 0x7b2e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"flog2.d", "+d,+e", 0x7b2f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"fexupl.w", "+d,+e", 0x7b30001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"fexupl.d", "+d,+e", 0x7b31001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"fexupr.w", "+d,+e", 0x7b32001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"fexupr.d", "+d,+e", 0x7b33001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ffql.w", "+d,+e", 0x7b34001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ffql.d", "+d,+e", 0x7b35001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ffqr.w", "+d,+e", 0x7b36001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ffqr.d", "+d,+e", 0x7b37001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ftint_s.w", "+d,+e", 0x7b38001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ftint_s.d", "+d,+e", 0x7b39001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ftint_u.w", "+d,+e", 0x7b3a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ftint_u.d", "+d,+e", 0x7b3b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ffint_s.w", "+d,+e", 0x7b3c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ffint_s.d", "+d,+e", 0x7b3d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ffint_u.w", "+d,+e", 0x7b3e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ffint_u.d", "+d,+e", 0x7b3f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ftrunc_s.w", "+d,+e", 0x7b40001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ftrunc_s.d", "+d,+e", 0x7b41001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ftrunc_u.w", "+d,+e", 0x7b42001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ftrunc_u.d", "+d,+e", 0x7b43001e, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"ctcmsa", "+h,d", 0x783e0019, 0xffff003f, COD, RD_d, MSA},
|
||||
{"cfcmsa", "+i,+g", 0x787e0019, 0xffff003f, COD, 0, MSA},
|
||||
{"move.v", "+d,+e", 0x78be0019, 0xffff003f, WR_VD|RD_VS, 0, MSA},
|
||||
{"lsa", "d,v,t,+@", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, MSA},
|
||||
{"dlsa", "d,v,t,+@", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, MSA64},
|
||||
|
||||
{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 },
|
||||
{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 },
|
||||
{"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */
|
||||
@@ -2410,6 +2986,8 @@ const struct mips_opcode mips_builtin_opcodes[] =
|
||||
{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0, I1 },
|
||||
{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0, I1 },
|
||||
{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0, I1 },
|
||||
{"tlbinv", "", 0x42000003, 0xffffffff, INSN_TLB, 0, I32 },
|
||||
{"tlbinvf", "", 0x42000004, 0xffffffff, INSN_TLB, 0, I32 },
|
||||
{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0, I1 },
|
||||
{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 },
|
||||
{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 },
|
||||
@@ -2933,6 +3511,7 @@ struct mips_cp0sel_name
|
||||
const char * const name;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* The mips16 registers. */
|
||||
static const unsigned int mips16_to_32_reg_map[] =
|
||||
{
|
||||
@@ -2940,7 +3519,7 @@ static const unsigned int mips16_to_32_reg_map[] =
|
||||
};
|
||||
|
||||
#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]]
|
||||
|
||||
#endif
|
||||
|
||||
static const char * const mips_gpr_names_numeric[32] =
|
||||
{
|
||||
@@ -2998,6 +3577,13 @@ static const char * const mips_fpr_names_64[32] =
|
||||
"fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7"
|
||||
};
|
||||
|
||||
static const char * const mips_wr_names[32] = {
|
||||
"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
|
||||
"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
|
||||
"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
|
||||
"w24", "w25", "w26", "w27", "w28", "w29", "w30", "w31"
|
||||
};
|
||||
|
||||
static const char * const mips_cp0_names_numeric[32] =
|
||||
{
|
||||
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
|
||||
@@ -3216,6 +3802,13 @@ static const char * const mips_hwr_names_mips3264r2[32] =
|
||||
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
|
||||
};
|
||||
|
||||
static const char * const mips_msa_control_names_mips3264r2[32] = {
|
||||
"MSAIR", "MSACSR", "$2", "$3", "$4", "$5", "$6", "$7",
|
||||
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
|
||||
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
|
||||
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
|
||||
};
|
||||
|
||||
struct mips_abi_choice
|
||||
{
|
||||
const char *name;
|
||||
@@ -3333,7 +3926,7 @@ static const struct mips_arch_choice mips_arch_choices[] =
|
||||
|
||||
{ "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
|
||||
(ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2
|
||||
| INSN_MIPS3D | INSN_MT),
|
||||
| INSN_MIPS3D | INSN_MT | INSN_MSA),
|
||||
mips_cp0_names_mips3264r2,
|
||||
mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
|
||||
mips_hwr_names_mips3264r2 },
|
||||
@@ -3687,6 +4280,89 @@ print_insn_args (const char *d,
|
||||
(l >> OP_SH_UDI4) & OP_MASK_UDI4);
|
||||
break;
|
||||
|
||||
case '5': /* 5-bit signed immediate in bit 16 */
|
||||
delta = ((l >> OP_SH_RT) & OP_MASK_RT);
|
||||
if (delta & 0x10) { /* test sign bit */
|
||||
delta |= ~OP_MASK_RT;
|
||||
}
|
||||
(*info->fprintf_func) (info->stream, "%d", delta);
|
||||
break;
|
||||
|
||||
case '6':
|
||||
(*info->fprintf_func) (info->stream, "0x%lx",
|
||||
(l >> OP_SH_2BIT) & OP_MASK_2BIT);
|
||||
break;
|
||||
|
||||
case '7':
|
||||
(*info->fprintf_func) (info->stream, "0x%lx",
|
||||
(l >> OP_SH_3BIT) & OP_MASK_3BIT);
|
||||
break;
|
||||
|
||||
case '8':
|
||||
(*info->fprintf_func) (info->stream, "0x%lx",
|
||||
(l >> OP_SH_4BIT) & OP_MASK_4BIT);
|
||||
break;
|
||||
|
||||
case '9':
|
||||
(*info->fprintf_func) (info->stream, "0x%lx",
|
||||
(l >> OP_SH_5BIT) & OP_MASK_5BIT);
|
||||
break;
|
||||
|
||||
case ':':
|
||||
(*info->fprintf_func) (info->stream, "0x%lx",
|
||||
(l >> OP_SH_1BIT) & OP_MASK_1BIT);
|
||||
break;
|
||||
|
||||
case '!': /* 10-bit pc-relative target in bit 11 */
|
||||
delta = ((l >> OP_SH_10BIT) & OP_MASK_10BIT);
|
||||
if (delta & 0x200) { /* test sign bit */
|
||||
delta |= ~OP_MASK_10BIT;
|
||||
}
|
||||
info->target = (delta << 2) + pc + INSNLEN;
|
||||
(*info->print_address_func) (info->target, info);
|
||||
break;
|
||||
|
||||
case '~':
|
||||
(*info->fprintf_func) (info->stream, "0");
|
||||
break;
|
||||
|
||||
case '@':
|
||||
(*info->fprintf_func) (info->stream, "0x%lx",
|
||||
((l >> OP_SH_1_TO_4) & OP_MASK_1_TO_4)+1);
|
||||
break;
|
||||
|
||||
case '^': /* 10-bit signed immediate << 0 in bit 16 */
|
||||
delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
|
||||
if (delta & 0x200) { /* test sign bit */
|
||||
delta |= ~OP_MASK_IMM10;
|
||||
}
|
||||
(*info->fprintf_func) (info->stream, "%d", delta);
|
||||
break;
|
||||
|
||||
case '#': /* 10-bit signed immediate << 1 in bit 16 */
|
||||
delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
|
||||
if (delta & 0x200) { /* test sign bit */
|
||||
delta |= ~OP_MASK_IMM10;
|
||||
}
|
||||
(*info->fprintf_func) (info->stream, "%d", delta << 1);
|
||||
break;
|
||||
|
||||
case '$': /* 10-bit signed immediate << 2 in bit 16 */
|
||||
delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
|
||||
if (delta & 0x200) { /* test sign bit */
|
||||
delta |= ~OP_MASK_IMM10;
|
||||
}
|
||||
(*info->fprintf_func) (info->stream, "%d", delta << 2);
|
||||
break;
|
||||
|
||||
case '%': /* 10-bit signed immediate << 3 in bit 16 */
|
||||
delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
|
||||
if (delta & 0x200) { /* test sign bit */
|
||||
delta |= ~OP_MASK_IMM10;
|
||||
}
|
||||
(*info->fprintf_func) (info->stream, "%d", delta << 3);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
case 'H':
|
||||
msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
|
||||
@@ -3794,6 +4470,38 @@ print_insn_args (const char *d,
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
(*info->fprintf_func) (info->stream, "%s",
|
||||
mips_wr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
(*info->fprintf_func) (info->stream, "%s",
|
||||
mips_wr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
(*info->fprintf_func) (info->stream, "%s",
|
||||
mips_wr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
(*info->fprintf_func) (info->stream, "%s",
|
||||
mips_msa_control_names_mips3264r2[(l >> OP_SH_MSACR11)
|
||||
& OP_MASK_MSACR11]);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
(*info->fprintf_func) (info->stream, "%s",
|
||||
mips_msa_control_names_mips3264r2[(l >> OP_SH_MSACR6)
|
||||
& OP_MASK_MSACR6]);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
(*info->fprintf_func) (info->stream, "%s",
|
||||
mips_gpr_names[(l >> OP_SH_GPR) & OP_MASK_GPR]);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* xgettext:c-format */
|
||||
(*info->fprintf_func) (info->stream,
|
||||
|
||||
@@ -44,6 +44,8 @@ PCI devices (other than virtio):
|
||||
1b36:0002 PCI serial port (16550A) adapter (docs/specs/pci-serial.txt)
|
||||
1b36:0003 PCI Dual-port 16550A adapter (docs/specs/pci-serial.txt)
|
||||
1b36:0004 PCI Quad-port 16550A adapter (docs/specs/pci-serial.txt)
|
||||
1b36:0005 PCI test device (docs/specs/pci-testdev.txt)
|
||||
1b36:0007 PCI SD Card Host Controller Interface (SDHCI)
|
||||
|
||||
All these devices are documented in docs/specs.
|
||||
|
||||
|
||||
@@ -139,12 +139,12 @@ events are not tightly coupled to a specific trace backend, such as LTTng or
|
||||
SystemTap. Support for trace backends can be added by extending the "tracetool"
|
||||
script.
|
||||
|
||||
The trace backend is chosen at configure time and only one trace backend can
|
||||
be built into the binary:
|
||||
The trace backends are chosen at configure time:
|
||||
|
||||
./configure --trace-backends=simple
|
||||
./configure --enable-trace-backends=simple
|
||||
|
||||
For a list of supported trace backends, try ./configure --help or see below.
|
||||
If multiple backends are enabled, the trace is sent to them all.
|
||||
|
||||
The following subsections describe the supported trace backends.
|
||||
|
||||
|
||||
@@ -71,6 +71,14 @@ encoded buffer:
|
||||
encoded length 24
|
||||
e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
|
||||
|
||||
Cache update strategy
|
||||
=====================
|
||||
Keeping the hot pages in the cache is effective for decreased cache
|
||||
misses. XBZRLE uses a counter as the age of each page. The counter will
|
||||
increase after each ram dirty bitmap sync. When a cache conflict is
|
||||
detected, XBZRLE will only evict pages in the cache that are older than
|
||||
a threshold.
|
||||
|
||||
Usage
|
||||
======================
|
||||
1. Verify the destination QEMU version is able to decode the new format.
|
||||
|
||||
192
exec.c
192
exec.c
@@ -75,6 +75,11 @@ static MemoryRegion io_mem_unassigned;
|
||||
/* RAM is mmap-ed with MAP_SHARED */
|
||||
#define RAM_SHARED (1 << 1)
|
||||
|
||||
/* Only a portion of RAM (used_length) is actually used, and migrated.
|
||||
* This used_length size can change across reboots.
|
||||
*/
|
||||
#define RAM_RESIZEABLE (1 << 2)
|
||||
|
||||
#endif
|
||||
|
||||
struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
|
||||
@@ -434,7 +439,7 @@ static int cpu_common_pre_load(void *opaque)
|
||||
{
|
||||
CPUState *cpu = opaque;
|
||||
|
||||
cpu->exception_index = 0;
|
||||
cpu->exception_index = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -443,7 +448,7 @@ static bool cpu_common_exception_index_needed(void *opaque)
|
||||
{
|
||||
CPUState *cpu = opaque;
|
||||
|
||||
return cpu->exception_index != 0;
|
||||
return tcg_enabled() && cpu->exception_index != -1;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_cpu_common_exception_index = {
|
||||
@@ -548,7 +553,6 @@ void cpu_exec_init(CPUArchState *env)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TARGET_HAS_ICE)
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
||||
{
|
||||
@@ -564,7 +568,6 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* TARGET_HAS_ICE */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
|
||||
@@ -684,7 +687,6 @@ static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
|
||||
int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
|
||||
CPUBreakpoint **breakpoint)
|
||||
{
|
||||
#if defined(TARGET_HAS_ICE)
|
||||
CPUBreakpoint *bp;
|
||||
|
||||
bp = g_malloc(sizeof(*bp));
|
||||
@@ -705,15 +707,11 @@ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
|
||||
*breakpoint = bp;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Remove a specific breakpoint. */
|
||||
int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags)
|
||||
{
|
||||
#if defined(TARGET_HAS_ICE)
|
||||
CPUBreakpoint *bp;
|
||||
|
||||
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
|
||||
@@ -723,27 +721,21 @@ int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags)
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
#else
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Remove a specific breakpoint by reference. */
|
||||
void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *breakpoint)
|
||||
{
|
||||
#if defined(TARGET_HAS_ICE)
|
||||
QTAILQ_REMOVE(&cpu->breakpoints, breakpoint, entry);
|
||||
|
||||
breakpoint_invalidate(cpu, breakpoint->pc);
|
||||
|
||||
g_free(breakpoint);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Remove all matching breakpoints. */
|
||||
void cpu_breakpoint_remove_all(CPUState *cpu, int mask)
|
||||
{
|
||||
#if defined(TARGET_HAS_ICE)
|
||||
CPUBreakpoint *bp, *next;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(bp, &cpu->breakpoints, entry, next) {
|
||||
@@ -751,14 +743,12 @@ void cpu_breakpoint_remove_all(CPUState *cpu, int mask)
|
||||
cpu_breakpoint_remove_by_ref(cpu, bp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* enable or disable single step mode. EXCP_DEBUG is returned by the
|
||||
CPU loop after each instruction */
|
||||
void cpu_single_step(CPUState *cpu, int enabled)
|
||||
{
|
||||
#if defined(TARGET_HAS_ICE)
|
||||
if (cpu->singlestep_enabled != enabled) {
|
||||
cpu->singlestep_enabled = enabled;
|
||||
if (kvm_enabled()) {
|
||||
@@ -770,7 +760,6 @@ void cpu_single_step(CPUState *cpu, int enabled)
|
||||
tb_flush(env);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpu_abort(CPUState *cpu, const char *fmt, ...)
|
||||
@@ -812,11 +801,11 @@ static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
|
||||
|
||||
/* The list is protected by the iothread lock here. */
|
||||
block = ram_list.mru_block;
|
||||
if (block && addr - block->offset < block->length) {
|
||||
if (block && addr - block->offset < block->max_length) {
|
||||
goto found;
|
||||
}
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (addr - block->offset < block->length) {
|
||||
if (addr - block->offset < block->max_length) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
@@ -840,7 +829,7 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
|
||||
|
||||
block = qemu_get_ram_block(start);
|
||||
assert(block == qemu_get_ram_block(end - 1));
|
||||
start1 = (uintptr_t)block->host + (start - block->offset);
|
||||
start1 = (uintptr_t)ramblock_ptr(block, start - block->offset);
|
||||
cpu_tlb_reset_dirty_all(start1, length);
|
||||
}
|
||||
|
||||
@@ -850,7 +839,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
|
||||
{
|
||||
if (length == 0)
|
||||
return;
|
||||
cpu_physical_memory_clear_dirty_range(start, length, client);
|
||||
cpu_physical_memory_clear_dirty_range_type(start, length, client);
|
||||
|
||||
if (tcg_enabled()) {
|
||||
tlb_reset_dirty_range_all(start, length);
|
||||
@@ -909,14 +898,15 @@ static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
|
||||
uint16_t section);
|
||||
static subpage_t *subpage_init(AddressSpace *as, hwaddr base);
|
||||
|
||||
static void *(*phys_mem_alloc)(size_t size) = qemu_anon_ram_alloc;
|
||||
static void *(*phys_mem_alloc)(size_t size, uint64_t *align) =
|
||||
qemu_anon_ram_alloc;
|
||||
|
||||
/*
|
||||
* Set a custom physical guest memory alloator.
|
||||
* Accelerators with unusual needs may need this. Hopefully, we can
|
||||
* get rid of it eventually.
|
||||
*/
|
||||
void phys_mem_set_alloc(void *(*alloc)(size_t))
|
||||
void phys_mem_set_alloc(void *(*alloc)(size_t, uint64_t *align))
|
||||
{
|
||||
phys_mem_alloc = alloc;
|
||||
}
|
||||
@@ -1098,6 +1088,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
error_propagate(errp, local_err);
|
||||
goto error;
|
||||
}
|
||||
block->mr->align = hpagesize;
|
||||
|
||||
if (memory < hpagesize) {
|
||||
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
|
||||
@@ -1184,7 +1175,7 @@ static ram_addr_t find_ram_offset(ram_addr_t size)
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
ram_addr_t end, next = RAM_ADDR_MAX;
|
||||
|
||||
end = block->offset + block->length;
|
||||
end = block->offset + block->max_length;
|
||||
|
||||
QTAILQ_FOREACH(next_block, &ram_list.blocks, next) {
|
||||
if (next_block->offset >= end) {
|
||||
@@ -1212,7 +1203,7 @@ ram_addr_t last_ram_offset(void)
|
||||
ram_addr_t last = 0;
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next)
|
||||
last = MAX(last, block->offset + block->length);
|
||||
last = MAX(last, block->offset + block->max_length);
|
||||
|
||||
return last;
|
||||
}
|
||||
@@ -1294,6 +1285,49 @@ static int memory_try_enable_merging(void *addr, size_t len)
|
||||
return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
|
||||
}
|
||||
|
||||
/* Only legal before guest might have detected the memory size: e.g. on
|
||||
* incoming migration, or right after reset.
|
||||
*
|
||||
* As memory core doesn't know how is memory accessed, it is up to
|
||||
* resize callback to update device state and/or add assertions to detect
|
||||
* misuse, if necessary.
|
||||
*/
|
||||
int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp)
|
||||
{
|
||||
RAMBlock *block = find_ram_block(base);
|
||||
|
||||
assert(block);
|
||||
|
||||
if (block->used_length == newsize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(block->flags & RAM_RESIZEABLE)) {
|
||||
error_setg_errno(errp, EINVAL,
|
||||
"Length mismatch: %s: 0x" RAM_ADDR_FMT
|
||||
" in != 0x" RAM_ADDR_FMT, block->idstr,
|
||||
newsize, block->used_length);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (block->max_length < newsize) {
|
||||
error_setg_errno(errp, EINVAL,
|
||||
"Length too large: %s: 0x" RAM_ADDR_FMT
|
||||
" > 0x" RAM_ADDR_FMT, block->idstr,
|
||||
newsize, block->max_length);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpu_physical_memory_clear_dirty_range(block->offset, block->used_length);
|
||||
block->used_length = newsize;
|
||||
cpu_physical_memory_set_dirty_range(block->offset, block->used_length);
|
||||
memory_region_set_size(block->mr, newsize);
|
||||
if (block->resized) {
|
||||
block->resized(block->idstr, newsize, block->host);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
{
|
||||
RAMBlock *block;
|
||||
@@ -1303,13 +1337,15 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
|
||||
/* This assumes the iothread lock is taken here too. */
|
||||
qemu_mutex_lock_ramlist();
|
||||
new_block->offset = find_ram_offset(new_block->length);
|
||||
new_block->offset = find_ram_offset(new_block->max_length);
|
||||
|
||||
if (!new_block->host) {
|
||||
if (xen_enabled()) {
|
||||
xen_ram_alloc(new_block->offset, new_block->length, new_block->mr);
|
||||
xen_ram_alloc(new_block->offset, new_block->max_length,
|
||||
new_block->mr);
|
||||
} else {
|
||||
new_block->host = phys_mem_alloc(new_block->length);
|
||||
new_block->host = phys_mem_alloc(new_block->max_length,
|
||||
&new_block->mr->align);
|
||||
if (!new_block->host) {
|
||||
error_setg_errno(errp, errno,
|
||||
"cannot set up guest memory '%s'",
|
||||
@@ -1317,13 +1353,13 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
qemu_mutex_unlock_ramlist();
|
||||
return -1;
|
||||
}
|
||||
memory_try_enable_merging(new_block->host, new_block->length);
|
||||
memory_try_enable_merging(new_block->host, new_block->max_length);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep the list sorted from biggest to smallest block. */
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (block->length < new_block->length) {
|
||||
if (block->max_length < new_block->max_length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1347,14 +1383,15 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
old_ram_size, new_ram_size);
|
||||
}
|
||||
}
|
||||
cpu_physical_memory_set_dirty_range(new_block->offset, new_block->length);
|
||||
cpu_physical_memory_set_dirty_range(new_block->offset,
|
||||
new_block->used_length);
|
||||
|
||||
qemu_ram_setup_dump(new_block->host, new_block->length);
|
||||
qemu_madvise(new_block->host, new_block->length, QEMU_MADV_HUGEPAGE);
|
||||
qemu_madvise(new_block->host, new_block->length, QEMU_MADV_DONTFORK);
|
||||
qemu_ram_setup_dump(new_block->host, new_block->max_length);
|
||||
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
|
||||
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
|
||||
|
||||
if (kvm_enabled()) {
|
||||
kvm_setup_guest_memory(new_block->host, new_block->length);
|
||||
kvm_setup_guest_memory(new_block->host, new_block->max_length);
|
||||
}
|
||||
|
||||
return new_block->offset;
|
||||
@@ -1388,7 +1425,8 @@ ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
||||
size = TARGET_PAGE_ALIGN(size);
|
||||
new_block = g_malloc0(sizeof(*new_block));
|
||||
new_block->mr = mr;
|
||||
new_block->length = size;
|
||||
new_block->used_length = size;
|
||||
new_block->max_length = size;
|
||||
new_block->flags = share ? RAM_SHARED : 0;
|
||||
new_block->host = file_ram_alloc(new_block, size,
|
||||
mem_path, errp);
|
||||
@@ -1407,7 +1445,12 @@ ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
||||
}
|
||||
#endif
|
||||
|
||||
ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
||||
static
|
||||
ram_addr_t qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
|
||||
void (*resized)(const char*,
|
||||
uint64_t length,
|
||||
void *host),
|
||||
void *host, bool resizeable,
|
||||
MemoryRegion *mr, Error **errp)
|
||||
{
|
||||
RAMBlock *new_block;
|
||||
@@ -1415,14 +1458,21 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
||||
Error *local_err = NULL;
|
||||
|
||||
size = TARGET_PAGE_ALIGN(size);
|
||||
max_size = TARGET_PAGE_ALIGN(max_size);
|
||||
new_block = g_malloc0(sizeof(*new_block));
|
||||
new_block->mr = mr;
|
||||
new_block->length = size;
|
||||
new_block->resized = resized;
|
||||
new_block->used_length = size;
|
||||
new_block->max_length = max_size;
|
||||
assert(max_size >= size);
|
||||
new_block->fd = -1;
|
||||
new_block->host = host;
|
||||
if (host) {
|
||||
new_block->flags |= RAM_PREALLOC;
|
||||
}
|
||||
if (resizeable) {
|
||||
new_block->flags |= RAM_RESIZEABLE;
|
||||
}
|
||||
addr = ram_block_add(new_block, &local_err);
|
||||
if (local_err) {
|
||||
g_free(new_block);
|
||||
@@ -1432,9 +1482,24 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
||||
return addr;
|
||||
}
|
||||
|
||||
ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
||||
MemoryRegion *mr, Error **errp)
|
||||
{
|
||||
return qemu_ram_alloc_internal(size, size, NULL, host, false, mr, errp);
|
||||
}
|
||||
|
||||
ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp)
|
||||
{
|
||||
return qemu_ram_alloc_from_ptr(size, NULL, mr, errp);
|
||||
return qemu_ram_alloc_internal(size, size, NULL, NULL, false, mr, errp);
|
||||
}
|
||||
|
||||
ram_addr_t qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t maxsz,
|
||||
void (*resized)(const char*,
|
||||
uint64_t length,
|
||||
void *host),
|
||||
MemoryRegion *mr, Error **errp)
|
||||
{
|
||||
return qemu_ram_alloc_internal(size, maxsz, resized, NULL, true, mr, errp);
|
||||
}
|
||||
|
||||
void qemu_ram_free_from_ptr(ram_addr_t addr)
|
||||
@@ -1472,11 +1537,11 @@ void qemu_ram_free(ram_addr_t addr)
|
||||
xen_invalidate_map_cache_entry(block->host);
|
||||
#ifndef _WIN32
|
||||
} else if (block->fd >= 0) {
|
||||
munmap(block->host, block->length);
|
||||
munmap(block->host, block->max_length);
|
||||
close(block->fd);
|
||||
#endif
|
||||
} else {
|
||||
qemu_anon_ram_free(block->host, block->length);
|
||||
qemu_anon_ram_free(block->host, block->max_length);
|
||||
}
|
||||
g_free(block);
|
||||
break;
|
||||
@@ -1496,8 +1561,8 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
offset = addr - block->offset;
|
||||
if (offset < block->length) {
|
||||
vaddr = block->host + offset;
|
||||
if (offset < block->max_length) {
|
||||
vaddr = ramblock_ptr(block, offset);
|
||||
if (block->flags & RAM_PREALLOC) {
|
||||
;
|
||||
} else if (xen_enabled()) {
|
||||
@@ -1548,7 +1613,7 @@ void *qemu_get_ram_block_host_ptr(ram_addr_t addr)
|
||||
{
|
||||
RAMBlock *block = qemu_get_ram_block(addr);
|
||||
|
||||
return block->host;
|
||||
return ramblock_ptr(block, 0);
|
||||
}
|
||||
|
||||
/* Return a host pointer to ram allocated with qemu_ram_alloc.
|
||||
@@ -1572,10 +1637,10 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
|
||||
return xen_map_cache(addr, 0, 0);
|
||||
} else if (block->host == NULL) {
|
||||
block->host =
|
||||
xen_map_cache(block->offset, block->length, 1);
|
||||
xen_map_cache(block->offset, block->max_length, 1);
|
||||
}
|
||||
}
|
||||
return block->host + (addr - block->offset);
|
||||
return ramblock_ptr(block, addr - block->offset);
|
||||
}
|
||||
|
||||
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
|
||||
@@ -1591,10 +1656,10 @@ static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
|
||||
RAMBlock *block;
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (addr - block->offset < block->length) {
|
||||
if (addr - block->offset + *size > block->length)
|
||||
*size = block->length - addr + block->offset;
|
||||
return block->host + (addr - block->offset);
|
||||
if (addr - block->offset < block->max_length) {
|
||||
if (addr - block->offset + *size > block->max_length)
|
||||
*size = block->max_length - addr + block->offset;
|
||||
return ramblock_ptr(block, addr - block->offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1616,7 +1681,7 @@ MemoryRegion *qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
|
||||
}
|
||||
|
||||
block = ram_list.mru_block;
|
||||
if (block && block->host && host - block->host < block->length) {
|
||||
if (block && block->host && host - block->host < block->max_length) {
|
||||
goto found;
|
||||
}
|
||||
|
||||
@@ -1625,7 +1690,7 @@ MemoryRegion *qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
|
||||
if (block->host == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (host - block->host < block->length) {
|
||||
if (host - block->host < block->max_length) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
@@ -1765,7 +1830,7 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
|
||||
unsigned len)
|
||||
{
|
||||
subpage_t *subpage = opaque;
|
||||
uint8_t buf[4];
|
||||
uint8_t buf[8];
|
||||
|
||||
#if defined(DEBUG_SUBPAGE)
|
||||
printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
|
||||
@@ -1779,6 +1844,8 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
|
||||
return lduw_p(buf);
|
||||
case 4:
|
||||
return ldl_p(buf);
|
||||
case 8:
|
||||
return ldq_p(buf);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@@ -1788,7 +1855,7 @@ static void subpage_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned len)
|
||||
{
|
||||
subpage_t *subpage = opaque;
|
||||
uint8_t buf[4];
|
||||
uint8_t buf[8];
|
||||
|
||||
#if defined(DEBUG_SUBPAGE)
|
||||
printf("%s: subpage %p len %u addr " TARGET_FMT_plx
|
||||
@@ -1805,6 +1872,9 @@ static void subpage_write(void *opaque, hwaddr addr,
|
||||
case 4:
|
||||
stl_p(buf, value);
|
||||
break;
|
||||
case 8:
|
||||
stq_p(buf, value);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@@ -1827,6 +1897,10 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
|
||||
static const MemoryRegionOps subpage_ops = {
|
||||
.read = subpage_read,
|
||||
.write = subpage_write,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 8,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 8,
|
||||
.valid.accepts = subpage_accepts,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
@@ -2066,10 +2140,8 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
||||
static void invalidate_and_set_dirty(hwaddr addr,
|
||||
hwaddr length)
|
||||
{
|
||||
if (cpu_physical_memory_is_clean(addr)) {
|
||||
/* invalidate code */
|
||||
tb_invalidate_phys_page_range(addr, addr + length, 0);
|
||||
/* set dirty bit */
|
||||
if (cpu_physical_memory_range_includes_clean(addr, length)) {
|
||||
tb_invalidate_phys_range(addr, addr + length, 0);
|
||||
cpu_physical_memory_set_dirty_range_nocode(addr, length);
|
||||
}
|
||||
xen_modified_memory(addr, length);
|
||||
@@ -2872,7 +2944,7 @@ void qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
|
||||
RAMBlock *block;
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
func(block->host, block->offset, block->length, opaque);
|
||||
func(block->host, block->offset, block->used_length, opaque);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
20
gdbstub.c
20
gdbstub.c
@@ -317,6 +317,8 @@ static GDBState *gdbserver_state;
|
||||
|
||||
bool gdb_has_xml;
|
||||
|
||||
int semihosting_target = SEMIHOSTING_TARGET_AUTO;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* XXX: This is not thread safe. Do we care? */
|
||||
static int gdbserver_fd = -1;
|
||||
@@ -351,10 +353,19 @@ static enum {
|
||||
GDB_SYS_DISABLED,
|
||||
} gdb_syscall_mode;
|
||||
|
||||
/* If gdb is connected when the first semihosting syscall occurs then use
|
||||
remote gdb syscalls. Otherwise use native file IO. */
|
||||
/* Decide if either remote gdb syscalls or native file IO should be used. */
|
||||
int use_gdb_syscalls(void)
|
||||
{
|
||||
if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) {
|
||||
/* -semihosting-config target=native */
|
||||
return false;
|
||||
} else if (semihosting_target == SEMIHOSTING_TARGET_GDB) {
|
||||
/* -semihosting-config target=gdb */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -semihosting-config target=auto */
|
||||
/* On the first call check if gdb is connected and remember. */
|
||||
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
|
||||
gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
|
||||
: GDB_SYS_DISABLED);
|
||||
@@ -823,7 +834,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
||||
action = *p++;
|
||||
signal = 0;
|
||||
if (action == 'C' || action == 'S') {
|
||||
signal = strtoul(p, (char **)&p, 16);
|
||||
signal = gdb_signal_to_target(strtoul(p, (char **)&p, 16));
|
||||
if (signal == -1) {
|
||||
signal = 0;
|
||||
}
|
||||
} else if (action != 'c' && action != 's') {
|
||||
res = 0;
|
||||
break;
|
||||
|
||||
233
hmp.c
233
hmp.c
@@ -290,14 +290,131 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
|
||||
qapi_free_CpuInfoList(cpu_list);
|
||||
}
|
||||
|
||||
static void print_block_info(Monitor *mon, BlockInfo *info,
|
||||
BlockDeviceInfo *inserted, bool verbose)
|
||||
{
|
||||
ImageInfo *image_info;
|
||||
|
||||
assert(!info || !info->has_inserted || info->inserted == inserted);
|
||||
|
||||
if (info) {
|
||||
monitor_printf(mon, "%s", info->device);
|
||||
if (inserted && inserted->has_node_name) {
|
||||
monitor_printf(mon, " (%s)", inserted->node_name);
|
||||
}
|
||||
} else {
|
||||
assert(inserted);
|
||||
monitor_printf(mon, "%s",
|
||||
inserted->has_node_name
|
||||
? inserted->node_name
|
||||
: "<anonymous>");
|
||||
}
|
||||
|
||||
if (inserted) {
|
||||
monitor_printf(mon, ": %s (%s%s%s)\n",
|
||||
inserted->file,
|
||||
inserted->drv,
|
||||
inserted->ro ? ", read-only" : "",
|
||||
inserted->encrypted ? ", encrypted" : "");
|
||||
} else {
|
||||
monitor_printf(mon, ": [not inserted]\n");
|
||||
}
|
||||
|
||||
if (info) {
|
||||
if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
|
||||
monitor_printf(mon, " I/O status: %s\n",
|
||||
BlockDeviceIoStatus_lookup[info->io_status]);
|
||||
}
|
||||
|
||||
if (info->removable) {
|
||||
monitor_printf(mon, " Removable device: %slocked, tray %s\n",
|
||||
info->locked ? "" : "not ",
|
||||
info->tray_open ? "open" : "closed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!inserted) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, " Cache mode: %s%s%s\n",
|
||||
inserted->cache->writeback ? "writeback" : "writethrough",
|
||||
inserted->cache->direct ? ", direct" : "",
|
||||
inserted->cache->no_flush ? ", ignore flushes" : "");
|
||||
|
||||
if (inserted->has_backing_file) {
|
||||
monitor_printf(mon,
|
||||
" Backing file: %s "
|
||||
"(chain depth: %" PRId64 ")\n",
|
||||
inserted->backing_file,
|
||||
inserted->backing_file_depth);
|
||||
}
|
||||
|
||||
if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
||||
monitor_printf(mon, " Detect zeroes: %s\n",
|
||||
BlockdevDetectZeroesOptions_lookup[inserted->detect_zeroes]);
|
||||
}
|
||||
|
||||
if (inserted->bps || inserted->bps_rd || inserted->bps_wr ||
|
||||
inserted->iops || inserted->iops_rd || inserted->iops_wr)
|
||||
{
|
||||
monitor_printf(mon, " I/O throttling: bps=%" PRId64
|
||||
" bps_rd=%" PRId64 " bps_wr=%" PRId64
|
||||
" bps_max=%" PRId64
|
||||
" bps_rd_max=%" PRId64
|
||||
" bps_wr_max=%" PRId64
|
||||
" iops=%" PRId64 " iops_rd=%" PRId64
|
||||
" iops_wr=%" PRId64
|
||||
" iops_max=%" PRId64
|
||||
" iops_rd_max=%" PRId64
|
||||
" iops_wr_max=%" PRId64
|
||||
" iops_size=%" PRId64 "\n",
|
||||
inserted->bps,
|
||||
inserted->bps_rd,
|
||||
inserted->bps_wr,
|
||||
inserted->bps_max,
|
||||
inserted->bps_rd_max,
|
||||
inserted->bps_wr_max,
|
||||
inserted->iops,
|
||||
inserted->iops_rd,
|
||||
inserted->iops_wr,
|
||||
inserted->iops_max,
|
||||
inserted->iops_rd_max,
|
||||
inserted->iops_wr_max,
|
||||
inserted->iops_size);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
monitor_printf(mon, "\nImages:\n");
|
||||
image_info = inserted->image;
|
||||
while (1) {
|
||||
bdrv_image_info_dump((fprintf_function)monitor_printf,
|
||||
mon, image_info);
|
||||
if (image_info->has_backing_image) {
|
||||
image_info = image_info->backing_image;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hmp_info_block(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
BlockInfoList *block_list, *info;
|
||||
ImageInfo *image_info;
|
||||
BlockDeviceInfoList *blockdev_list, *blockdev;
|
||||
const char *device = qdict_get_try_str(qdict, "device");
|
||||
bool verbose = qdict_get_try_bool(qdict, "verbose", 0);
|
||||
bool nodes = qdict_get_try_bool(qdict, "nodes", 0);
|
||||
bool printed = false;
|
||||
|
||||
block_list = qmp_query_block(NULL);
|
||||
/* Print BlockBackend information */
|
||||
if (!nodes) {
|
||||
block_list = qmp_query_block(false);
|
||||
} else {
|
||||
block_list = NULL;
|
||||
}
|
||||
|
||||
for (info = block_list; info; info = info->next) {
|
||||
if (device && strcmp(device, info->value->device)) {
|
||||
@@ -308,102 +425,40 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
monitor_printf(mon, "%s", info->value->device);
|
||||
if (info->value->has_inserted) {
|
||||
monitor_printf(mon, ": %s (%s%s%s)\n",
|
||||
info->value->inserted->file,
|
||||
info->value->inserted->drv,
|
||||
info->value->inserted->ro ? ", read-only" : "",
|
||||
info->value->inserted->encrypted ? ", encrypted" : "");
|
||||
} else {
|
||||
monitor_printf(mon, ": [not inserted]\n");
|
||||
}
|
||||
|
||||
if (info->value->has_io_status && info->value->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
|
||||
monitor_printf(mon, " I/O status: %s\n",
|
||||
BlockDeviceIoStatus_lookup[info->value->io_status]);
|
||||
}
|
||||
|
||||
if (info->value->removable) {
|
||||
monitor_printf(mon, " Removable device: %slocked, tray %s\n",
|
||||
info->value->locked ? "" : "not ",
|
||||
info->value->tray_open ? "open" : "closed");
|
||||
}
|
||||
|
||||
|
||||
if (!info->value->has_inserted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info->value->inserted->has_backing_file) {
|
||||
monitor_printf(mon,
|
||||
" Backing file: %s "
|
||||
"(chain depth: %" PRId64 ")\n",
|
||||
info->value->inserted->backing_file,
|
||||
info->value->inserted->backing_file_depth);
|
||||
}
|
||||
|
||||
if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
||||
monitor_printf(mon, " Detect zeroes: %s\n",
|
||||
BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
|
||||
}
|
||||
|
||||
if (info->value->inserted->bps
|
||||
|| info->value->inserted->bps_rd
|
||||
|| info->value->inserted->bps_wr
|
||||
|| info->value->inserted->iops
|
||||
|| info->value->inserted->iops_rd
|
||||
|| info->value->inserted->iops_wr)
|
||||
{
|
||||
monitor_printf(mon, " I/O throttling: bps=%" PRId64
|
||||
" bps_rd=%" PRId64 " bps_wr=%" PRId64
|
||||
" bps_max=%" PRId64
|
||||
" bps_rd_max=%" PRId64
|
||||
" bps_wr_max=%" PRId64
|
||||
" iops=%" PRId64 " iops_rd=%" PRId64
|
||||
" iops_wr=%" PRId64
|
||||
" iops_max=%" PRId64
|
||||
" iops_rd_max=%" PRId64
|
||||
" iops_wr_max=%" PRId64
|
||||
" iops_size=%" PRId64 "\n",
|
||||
info->value->inserted->bps,
|
||||
info->value->inserted->bps_rd,
|
||||
info->value->inserted->bps_wr,
|
||||
info->value->inserted->bps_max,
|
||||
info->value->inserted->bps_rd_max,
|
||||
info->value->inserted->bps_wr_max,
|
||||
info->value->inserted->iops,
|
||||
info->value->inserted->iops_rd,
|
||||
info->value->inserted->iops_wr,
|
||||
info->value->inserted->iops_max,
|
||||
info->value->inserted->iops_rd_max,
|
||||
info->value->inserted->iops_wr_max,
|
||||
info->value->inserted->iops_size);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
monitor_printf(mon, "\nImages:\n");
|
||||
image_info = info->value->inserted->image;
|
||||
while (1) {
|
||||
bdrv_image_info_dump((fprintf_function)monitor_printf,
|
||||
mon, image_info);
|
||||
if (image_info->has_backing_image) {
|
||||
image_info = image_info->backing_image;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
print_block_info(mon, info->value, info->value->has_inserted
|
||||
? info->value->inserted : NULL,
|
||||
verbose);
|
||||
printed = true;
|
||||
}
|
||||
|
||||
qapi_free_BlockInfoList(block_list);
|
||||
|
||||
if ((!device && !nodes) || printed) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print node information */
|
||||
blockdev_list = qmp_query_named_block_nodes(NULL);
|
||||
for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
|
||||
assert(blockdev->value->has_node_name);
|
||||
if (device && strcmp(device, blockdev->value->node_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blockdev != blockdev_list) {
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
print_block_info(mon, NULL, blockdev->value, verbose);
|
||||
}
|
||||
qapi_free_BlockDeviceInfoList(blockdev_list);
|
||||
}
|
||||
|
||||
void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
BlockStatsList *stats_list, *stats;
|
||||
|
||||
stats_list = qmp_query_blockstats(NULL);
|
||||
stats_list = qmp_query_blockstats(false, false, NULL);
|
||||
|
||||
for (stats = stats_list; stats; stats = stats->next) {
|
||||
if (!stats->value->has_device) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "fsdev/qemu-fsdev.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/event_notifier.h"
|
||||
#include "block/coroutine.h"
|
||||
#include "virtio-9p-coth.h"
|
||||
|
||||
@@ -26,15 +27,11 @@ void co_run_in_worker_bh(void *opaque)
|
||||
g_thread_pool_push(v9fs_pool.pool, co, NULL);
|
||||
}
|
||||
|
||||
static void v9fs_qemu_process_req_done(void *arg)
|
||||
static void v9fs_qemu_process_req_done(EventNotifier *e)
|
||||
{
|
||||
char byte;
|
||||
ssize_t len;
|
||||
Coroutine *co;
|
||||
|
||||
do {
|
||||
len = read(v9fs_pool.rfd, &byte, sizeof(byte));
|
||||
} while (len == -1 && errno == EINTR);
|
||||
event_notifier_test_and_clear(e);
|
||||
|
||||
while ((co = g_async_queue_try_pop(v9fs_pool.completed)) != NULL) {
|
||||
qemu_coroutine_enter(co, NULL);
|
||||
@@ -43,22 +40,18 @@ static void v9fs_qemu_process_req_done(void *arg)
|
||||
|
||||
static void v9fs_thread_routine(gpointer data, gpointer user_data)
|
||||
{
|
||||
ssize_t len;
|
||||
char byte = 0;
|
||||
Coroutine *co = data;
|
||||
|
||||
qemu_coroutine_enter(co, NULL);
|
||||
|
||||
g_async_queue_push(v9fs_pool.completed, co);
|
||||
do {
|
||||
len = write(v9fs_pool.wfd, &byte, sizeof(byte));
|
||||
} while (len == -1 && errno == EINTR);
|
||||
|
||||
event_notifier_set(&v9fs_pool.e);
|
||||
}
|
||||
|
||||
int v9fs_init_worker_threads(void)
|
||||
{
|
||||
int ret = 0;
|
||||
int notifier_fds[2];
|
||||
V9fsThPool *p = &v9fs_pool;
|
||||
sigset_t set, oldset;
|
||||
|
||||
@@ -66,10 +59,6 @@ int v9fs_init_worker_threads(void)
|
||||
/* Leave signal handling to the iothread. */
|
||||
pthread_sigmask(SIG_SETMASK, &set, &oldset);
|
||||
|
||||
if (qemu_pipe(notifier_fds) == -1) {
|
||||
ret = -1;
|
||||
goto err_out;
|
||||
}
|
||||
p->pool = g_thread_pool_new(v9fs_thread_routine, p, -1, FALSE, NULL);
|
||||
if (!p->pool) {
|
||||
ret = -1;
|
||||
@@ -84,13 +73,9 @@ int v9fs_init_worker_threads(void)
|
||||
ret = -1;
|
||||
goto err_out;
|
||||
}
|
||||
p->rfd = notifier_fds[0];
|
||||
p->wfd = notifier_fds[1];
|
||||
event_notifier_init(&p->e, 0);
|
||||
|
||||
fcntl(p->rfd, F_SETFL, O_NONBLOCK);
|
||||
fcntl(p->wfd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
qemu_set_fd_handler(p->rfd, v9fs_qemu_process_req_done, NULL, NULL);
|
||||
event_notifier_set_handler(&p->e, v9fs_qemu_process_req_done);
|
||||
err_out:
|
||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||
return ret;
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct V9fsThPool {
|
||||
int rfd;
|
||||
int wfd;
|
||||
EventNotifier e;
|
||||
|
||||
GThreadPool *pool;
|
||||
GAsyncQueue *completed;
|
||||
} V9fsThPool;
|
||||
|
||||
@@ -26,6 +26,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += ssi/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += timer/
|
||||
devices-dirs-$(CONFIG_TPM) += tpm/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += usb/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += vfio/
|
||||
devices-dirs-$(CONFIG_VIRTIO) += virtio/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += xen/
|
||||
|
||||
@@ -376,8 +376,11 @@ static void acpi_notify_wakeup(Notifier *notifier, void *data)
|
||||
/* ACPI PM1a EVT */
|
||||
uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
|
||||
{
|
||||
int64_t d = acpi_pm_tmr_get_clock();
|
||||
if (d >= ar->tmr.overflow_time) {
|
||||
/* Compare ns-clock, not PM timer ticks, because
|
||||
acpi_pm_tmr_update function uses ns for setting the timer. */
|
||||
int64_t d = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
if (d >= muldiv64(ar->tmr.overflow_time,
|
||||
get_ticks_per_sec(), PM_TIMER_FREQUENCY)) {
|
||||
ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS;
|
||||
}
|
||||
return ar->pm1.evt.sts;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "hw/mem/pc-dimm.h"
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
#include "hw/acpi/acpi_dev_interface.h"
|
||||
#include "hw/xen/xen.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
@@ -501,6 +502,9 @@ I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
||||
s->irq = sci_irq;
|
||||
s->smi_irq = smi_irq;
|
||||
s->kvm_enabled = kvm_enabled;
|
||||
if (xen_enabled()) {
|
||||
s->use_acpi_pci_hotplug = false;
|
||||
}
|
||||
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
|
||||
102
hw/arm/boot.c
102
hw/arm/boot.c
@@ -329,6 +329,8 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
|
||||
* Returns: the size of the device tree image on success,
|
||||
* 0 if the image size exceeds the limit,
|
||||
* -1 on errors.
|
||||
*
|
||||
* Note: Must not be called unless have_dtb(binfo) is true.
|
||||
*/
|
||||
static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
||||
hwaddr addr_limit)
|
||||
@@ -352,7 +354,7 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
||||
goto fail;
|
||||
}
|
||||
g_free(filename);
|
||||
} else if (binfo->get_dtb) {
|
||||
} else {
|
||||
fdt = binfo->get_dtb(binfo, &size);
|
||||
if (!fdt) {
|
||||
fprintf(stderr, "Board was unable to create a dtb blob\n");
|
||||
@@ -455,6 +457,16 @@ static void do_cpu_reset(void *opaque)
|
||||
env->thumb = info->entry & 1;
|
||||
}
|
||||
} else {
|
||||
/* If we are booting Linux then we need to check whether we are
|
||||
* booting into secure or non-secure state and adjust the state
|
||||
* accordingly. Out of reset, ARM is defined to be in secure state
|
||||
* (SCR.NS = 0), we change that here if non-secure boot has been
|
||||
* requested.
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_EL3) && !info->secure_boot) {
|
||||
env->cp15.scr_el3 |= SCR_NS;
|
||||
}
|
||||
|
||||
if (CPU(cpu) == first_cpu) {
|
||||
if (env->aarch64) {
|
||||
env->pc = info->loader_start;
|
||||
@@ -476,6 +488,55 @@ static void do_cpu_reset(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
|
||||
* by key.
|
||||
* @fw_cfg: The firmware config instance to store the data in.
|
||||
* @size_key: The firmware config key to store the size of the loaded
|
||||
* data under, with fw_cfg_add_i32().
|
||||
* @data_key: The firmware config key to store the loaded data under,
|
||||
* with fw_cfg_add_bytes().
|
||||
* @image_name: The name of the image file to load. If it is NULL, the
|
||||
* function returns without doing anything.
|
||||
* @try_decompress: Whether the image should be decompressed (gunzipped) before
|
||||
* adding it to fw_cfg. If decompression fails, the image is
|
||||
* loaded as-is.
|
||||
*
|
||||
* In case of failure, the function prints an error message to stderr and the
|
||||
* process exits with status 1.
|
||||
*/
|
||||
static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
||||
uint16_t data_key, const char *image_name,
|
||||
bool try_decompress)
|
||||
{
|
||||
size_t size = -1;
|
||||
uint8_t *data;
|
||||
|
||||
if (image_name == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (try_decompress) {
|
||||
size = load_image_gzipped_buffer(image_name,
|
||||
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
|
||||
}
|
||||
|
||||
if (size == (size_t)-1) {
|
||||
gchar *contents;
|
||||
gsize length;
|
||||
|
||||
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
|
||||
fprintf(stderr, "failed to load \"%s\"\n", image_name);
|
||||
exit(1);
|
||||
}
|
||||
size = length;
|
||||
data = (uint8_t *)contents;
|
||||
}
|
||||
|
||||
fw_cfg_add_i32(fw_cfg, size_key, size);
|
||||
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
||||
}
|
||||
|
||||
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
{
|
||||
CPUState *cs;
|
||||
@@ -498,19 +559,48 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
}
|
||||
|
||||
/* Load the kernel. */
|
||||
if (!info->kernel_filename) {
|
||||
if (!info->kernel_filename || info->firmware_loaded) {
|
||||
|
||||
if (have_dtb(info)) {
|
||||
/* If we have a device tree blob, but no kernel to supply it to,
|
||||
* copy it to the base of RAM for a bootloader to pick up.
|
||||
/* If we have a device tree blob, but no kernel to supply it to (or
|
||||
* the kernel is supposed to be loaded by the bootloader), copy the
|
||||
* DTB to the base of RAM for the bootloader to pick up.
|
||||
*/
|
||||
if (load_dtb(info->loader_start, info, 0) < 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* If no kernel specified, do nothing; we will start from address 0
|
||||
* (typically a boot ROM image) in the same way as hardware.
|
||||
if (info->kernel_filename) {
|
||||
FWCfgState *fw_cfg;
|
||||
bool try_decompressing_kernel;
|
||||
|
||||
fw_cfg = fw_cfg_find();
|
||||
try_decompressing_kernel = arm_feature(&cpu->env,
|
||||
ARM_FEATURE_AARCH64);
|
||||
|
||||
/* Expose the kernel, the command line, and the initrd in fw_cfg.
|
||||
* We don't process them here at all, it's all left to the
|
||||
* firmware.
|
||||
*/
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
|
||||
info->kernel_filename,
|
||||
try_decompressing_kernel);
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
|
||||
info->initrd_filename, false);
|
||||
|
||||
if (info->kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
||||
strlen(info->kernel_cmdline) + 1);
|
||||
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
|
||||
info->kernel_cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
/* We will start from address 0 (typically a boot ROM image) in the
|
||||
* same way as hardware.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -152,6 +152,17 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
/* By default A9 CPUs have EL3 enabled. This board does not currently
|
||||
* support EL3 so the CPU EL3 property is disabled before realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
s->cpu[n] = ARM_CPU(cpuobj);
|
||||
object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
|
||||
"reset-cbar", &error_abort);
|
||||
|
||||
@@ -241,6 +241,18 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
||||
cpuobj = object_new(object_class_get_name(oc));
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
/* By default A9 and A15 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
* realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
|
||||
"reset-cbar", &error_abort);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "net/net.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define TYPE_INTEGRATOR_CM "integrator_core"
|
||||
#define INTEGRATOR_CM(obj) \
|
||||
@@ -469,6 +470,8 @@ static void integratorcp_init(MachineState *machine)
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
ObjectClass *cpu_oc;
|
||||
Object *cpuobj;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
@@ -476,16 +479,40 @@ static void integratorcp_init(MachineState *machine)
|
||||
qemu_irq pic[32];
|
||||
DeviceState *dev;
|
||||
int i;
|
||||
Error *err = NULL;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm926";
|
||||
}
|
||||
cpu = cpu_arm_init(cpu_model);
|
||||
if (!cpu) {
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||
if (!cpu_oc) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
|
||||
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
* realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
|
||||
|
||||
@@ -1344,7 +1344,7 @@ static void n8x0_init(MachineState *machine,
|
||||
n8x0_dss_setup(s);
|
||||
n8x0_cbus_setup(s);
|
||||
n8x0_uart_setup(s);
|
||||
if (usb_enabled(false)) {
|
||||
if (usb_enabled()) {
|
||||
n8x0_usb_setup(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -273,10 +273,10 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
case 3:
|
||||
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
||||
s->cpu->env.cp15.c1_sys = 0;
|
||||
s->cpu->env.cp15.sctlr_ns = 0;
|
||||
s->cpu->env.cp15.c1_coproc = 0;
|
||||
s->cpu->env.cp15.ttbr0_el1 = 0;
|
||||
s->cpu->env.cp15.c3 = 0;
|
||||
s->cpu->env.cp15.ttbr0_el[1] = 0;
|
||||
s->cpu->env.cp15.dacr_ns = 0;
|
||||
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
||||
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
||||
|
||||
@@ -2143,7 +2143,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
|
||||
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
|
||||
}
|
||||
|
||||
if (usb_enabled(false)) {
|
||||
if (usb_enabled()) {
|
||||
sysbus_create_simple("sysbus-ohci", 0x4c000000,
|
||||
qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
|
||||
}
|
||||
@@ -2276,7 +2276,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
|
||||
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
|
||||
}
|
||||
|
||||
if (usb_enabled(false)) {
|
||||
if (usb_enabled()) {
|
||||
sysbus_create_simple("sysbus-ohci", 0x4c000000,
|
||||
qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ static void realview_init(MachineState *machine,
|
||||
CPUARMState *env;
|
||||
ObjectClass *cpu_oc;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_lo;
|
||||
MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
|
||||
@@ -101,6 +101,18 @@ static void realview_init(MachineState *machine,
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
/* By default A9,A15 and ARM1176 CPUs have EL3 enabled. This board
|
||||
* does not currently support EL3 so the CPU EL3 property is disabled
|
||||
* before realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_pb && is_mpcore) {
|
||||
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
||||
if (err) {
|
||||
@@ -135,6 +147,7 @@ static void realview_init(MachineState *machine,
|
||||
|
||||
if (is_pb && ram_size > 0x20000000) {
|
||||
/* Core tile RAM. */
|
||||
ram_lo = g_new(MemoryRegion, 1);
|
||||
low_ram_size = ram_size - 0x20000000;
|
||||
ram_size = 0x20000000;
|
||||
memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size,
|
||||
@@ -248,7 +261,7 @@ static void realview_init(MachineState *machine,
|
||||
sysbus_connect_irq(busdev, 2, pic[50]);
|
||||
sysbus_connect_irq(busdev, 3, pic[51]);
|
||||
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
|
||||
if (usb_enabled(false)) {
|
||||
if (usb_enabled()) {
|
||||
pci_create_simple(pci_bus, -1, "pci-ohci");
|
||||
}
|
||||
n = drive_get_max_bus(IF_SCSI);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define VERSATILE_FLASH_ADDR 0x34000000
|
||||
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
|
||||
@@ -175,6 +176,8 @@ static struct arm_boot_info versatile_binfo;
|
||||
|
||||
static void versatile_init(MachineState *machine, int board_id)
|
||||
{
|
||||
ObjectClass *cpu_oc;
|
||||
Object *cpuobj;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
@@ -189,15 +192,40 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||
int n;
|
||||
int done_smc = 0;
|
||||
DriveInfo *dinfo;
|
||||
Error *err = NULL;
|
||||
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "arm926";
|
||||
}
|
||||
cpu = cpu_arm_init(machine->cpu_model);
|
||||
if (!cpu) {
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
|
||||
if (!cpu_oc) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
|
||||
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
* realization.
|
||||
*/
|
||||
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
@@ -253,7 +281,7 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||
pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
|
||||
}
|
||||
}
|
||||
if (usb_enabled(false)) {
|
||||
if (usb_enabled()) {
|
||||
pci_create_simple(pci_bus, -1, "pci-ohci");
|
||||
}
|
||||
n = drive_get_max_bus(IF_SCSI);
|
||||
|
||||
@@ -157,7 +157,27 @@ static hwaddr motherboard_aseries_map[] = {
|
||||
|
||||
typedef struct VEDBoardInfo VEDBoardInfo;
|
||||
|
||||
typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
|
||||
typedef struct {
|
||||
MachineClass parent;
|
||||
VEDBoardInfo *daughterboard;
|
||||
} VexpressMachineClass;
|
||||
|
||||
typedef struct {
|
||||
MachineState parent;
|
||||
bool secure;
|
||||
} VexpressMachineState;
|
||||
|
||||
#define TYPE_VEXPRESS_MACHINE "vexpress"
|
||||
#define TYPE_VEXPRESS_A9_MACHINE "vexpress-a9"
|
||||
#define TYPE_VEXPRESS_A15_MACHINE "vexpress-a15"
|
||||
#define VEXPRESS_MACHINE(obj) \
|
||||
OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE)
|
||||
#define VEXPRESS_MACHINE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(VexpressMachineClass, obj, TYPE_VEXPRESS_MACHINE)
|
||||
#define VEXPRESS_MACHINE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(VexpressMachineClass, klass, TYPE_VEXPRESS_MACHINE)
|
||||
|
||||
typedef void DBoardInitFn(const VexpressMachineState *machine,
|
||||
ram_addr_t ram_size,
|
||||
const char *cpu_model,
|
||||
qemu_irq *pic);
|
||||
@@ -176,7 +196,7 @@ struct VEDBoardInfo {
|
||||
};
|
||||
|
||||
static void init_cpus(const char *cpu_model, const char *privdev,
|
||||
hwaddr periphbase, qemu_irq *pic)
|
||||
hwaddr periphbase, qemu_irq *pic, bool secure)
|
||||
{
|
||||
ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||
DeviceState *dev;
|
||||
@@ -193,6 +213,10 @@ static void init_cpus(const char *cpu_model, const char *privdev,
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
if (!secure) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||
}
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
object_property_set_int(cpuobj, periphbase,
|
||||
"reset-cbar", &error_abort);
|
||||
@@ -232,7 +256,7 @@ static void init_cpus(const char *cpu_model, const char *privdev,
|
||||
}
|
||||
}
|
||||
|
||||
static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
static void a9_daughterboard_init(const VexpressMachineState *vms,
|
||||
ram_addr_t ram_size,
|
||||
const char *cpu_model,
|
||||
qemu_irq *pic)
|
||||
@@ -268,7 +292,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
memory_region_add_subregion(sysmem, 0x60000000, ram);
|
||||
|
||||
/* 0x1e000000 A9MPCore (SCU) private memory region */
|
||||
init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic);
|
||||
init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure);
|
||||
|
||||
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
|
||||
|
||||
@@ -322,7 +346,7 @@ static VEDBoardInfo a9_daughterboard = {
|
||||
.init = a9_daughterboard_init,
|
||||
};
|
||||
|
||||
static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
static void a15_daughterboard_init(const VexpressMachineState *vms,
|
||||
ram_addr_t ram_size,
|
||||
const char *cpu_model,
|
||||
qemu_irq *pic)
|
||||
@@ -354,7 +378,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
||||
|
||||
/* 0x2c000000 A15MPCore private memory region (GIC) */
|
||||
init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic);
|
||||
init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure);
|
||||
|
||||
/* A15 daughterboard peripherals: */
|
||||
|
||||
@@ -513,9 +537,11 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
|
||||
return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
|
||||
}
|
||||
|
||||
static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
MachineState *machine)
|
||||
static void vexpress_common_init(MachineState *machine)
|
||||
{
|
||||
VexpressMachineState *vms = VEXPRESS_MACHINE(machine);
|
||||
VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
|
||||
VEDBoardInfo *daughterboard = vmc->daughterboard;;
|
||||
DeviceState *dev, *sysctl, *pl041;
|
||||
qemu_irq pic[64];
|
||||
uint32_t sys_id;
|
||||
@@ -530,8 +556,7 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
const hwaddr *map = daughterboard->motherboard_map;
|
||||
int i;
|
||||
|
||||
daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model,
|
||||
pic);
|
||||
daughterboard->init(vms, machine->ram_size, machine->cpu_model, pic);
|
||||
|
||||
/*
|
||||
* If a bios file was provided, attempt to map it into memory
|
||||
@@ -678,39 +703,99 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
|
||||
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
|
||||
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
|
||||
/* Indicate that when booting Linux we should be in secure state */
|
||||
daughterboard->bootinfo.secure_boot = true;
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
|
||||
}
|
||||
|
||||
static void vexpress_a9_init(MachineState *machine)
|
||||
static bool vexpress_get_secure(Object *obj, Error **errp)
|
||||
{
|
||||
vexpress_common_init(&a9_daughterboard, machine);
|
||||
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||
|
||||
return vms->secure;
|
||||
}
|
||||
|
||||
static void vexpress_a15_init(MachineState *machine)
|
||||
static void vexpress_set_secure(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
vexpress_common_init(&a15_daughterboard, machine);
|
||||
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||
|
||||
vms->secure = value;
|
||||
}
|
||||
|
||||
static QEMUMachine vexpress_a9_machine = {
|
||||
.name = "vexpress-a9",
|
||||
.desc = "ARM Versatile Express for Cortex-A9",
|
||||
.init = vexpress_a9_init,
|
||||
.block_default_type = IF_SCSI,
|
||||
.max_cpus = 4,
|
||||
static void vexpress_instance_init(Object *obj)
|
||||
{
|
||||
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||
|
||||
/* EL3 is enabled by default on vexpress */
|
||||
vms->secure = true;
|
||||
object_property_add_bool(obj, "secure", vexpress_get_secure,
|
||||
vexpress_set_secure, NULL);
|
||||
object_property_set_description(obj, "secure",
|
||||
"Set on/off to enable/disable the ARM "
|
||||
"Security Extensions (TrustZone)",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void vexpress_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = TYPE_VEXPRESS_MACHINE;
|
||||
mc->desc = "ARM Versatile Express";
|
||||
mc->init = vexpress_common_init;
|
||||
mc->block_default_type = IF_SCSI;
|
||||
mc->max_cpus = 4;
|
||||
}
|
||||
|
||||
static void vexpress_a9_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = TYPE_VEXPRESS_A9_MACHINE;
|
||||
mc->desc = "ARM Versatile Express for Cortex-A9";
|
||||
|
||||
vmc->daughterboard = &a9_daughterboard;;
|
||||
}
|
||||
|
||||
static void vexpress_a15_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = TYPE_VEXPRESS_A15_MACHINE;
|
||||
mc->desc = "ARM Versatile Express for Cortex-A15";
|
||||
|
||||
vmc->daughterboard = &a15_daughterboard;
|
||||
}
|
||||
|
||||
static const TypeInfo vexpress_info = {
|
||||
.name = TYPE_VEXPRESS_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.abstract = true,
|
||||
.instance_size = sizeof(VexpressMachineState),
|
||||
.instance_init = vexpress_instance_init,
|
||||
.class_size = sizeof(VexpressMachineClass),
|
||||
.class_init = vexpress_class_init,
|
||||
};
|
||||
|
||||
static QEMUMachine vexpress_a15_machine = {
|
||||
.name = "vexpress-a15",
|
||||
.desc = "ARM Versatile Express for Cortex-A15",
|
||||
.init = vexpress_a15_init,
|
||||
.block_default_type = IF_SCSI,
|
||||
.max_cpus = 4,
|
||||
static const TypeInfo vexpress_a9_info = {
|
||||
.name = TYPE_VEXPRESS_A9_MACHINE,
|
||||
.parent = TYPE_VEXPRESS_MACHINE,
|
||||
.class_init = vexpress_a9_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo vexpress_a15_info = {
|
||||
.name = TYPE_VEXPRESS_A15_MACHINE,
|
||||
.parent = TYPE_VEXPRESS_MACHINE,
|
||||
.class_init = vexpress_a15_class_init,
|
||||
};
|
||||
|
||||
static void vexpress_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&vexpress_a9_machine);
|
||||
qemu_register_machine(&vexpress_a15_machine);
|
||||
type_register_static(&vexpress_info);
|
||||
type_register_static(&vexpress_a9_info);
|
||||
type_register_static(&vexpress_a15_info);
|
||||
}
|
||||
|
||||
machine_init(vexpress_machine_init);
|
||||
|
||||
@@ -68,6 +68,7 @@ enum {
|
||||
VIRT_UART,
|
||||
VIRT_MMIO,
|
||||
VIRT_RTC,
|
||||
VIRT_FW_CFG,
|
||||
};
|
||||
|
||||
typedef struct MemMapEntry {
|
||||
@@ -86,6 +87,24 @@ typedef struct VirtBoardInfo {
|
||||
uint32_t clock_phandle;
|
||||
} VirtBoardInfo;
|
||||
|
||||
typedef struct {
|
||||
MachineClass parent;
|
||||
VirtBoardInfo *daughterboard;
|
||||
} VirtMachineClass;
|
||||
|
||||
typedef struct {
|
||||
MachineState parent;
|
||||
bool secure;
|
||||
} VirtMachineState;
|
||||
|
||||
#define TYPE_VIRT_MACHINE "virt"
|
||||
#define VIRT_MACHINE(obj) \
|
||||
OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
|
||||
#define VIRT_MACHINE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE)
|
||||
#define VIRT_MACHINE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
|
||||
|
||||
/* Addresses and sizes of our components.
|
||||
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
|
||||
* 128MB..256MB is used for miscellaneous device I/O.
|
||||
@@ -107,6 +126,7 @@ static const MemMapEntry a15memmap[] = {
|
||||
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
|
||||
[VIRT_UART] = { 0x09000000, 0x00001000 },
|
||||
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
||||
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
|
||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
/* 0x10000000 .. 0x40000000 reserved for PCI */
|
||||
@@ -389,7 +409,7 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
qemu_fdt_setprop(vbi->fdt, nodename, "clock-names",
|
||||
clocknames, sizeof(clocknames));
|
||||
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/chosen", "linux,stdout-path", nodename);
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename);
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
@@ -519,6 +539,23 @@ static void create_flash(const VirtBoardInfo *vbi)
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
static void create_fw_cfg(const VirtBoardInfo *vbi)
|
||||
{
|
||||
hwaddr base = vbi->memmap[VIRT_FW_CFG].base;
|
||||
hwaddr size = vbi->memmap[VIRT_FW_CFG].size;
|
||||
char *nodename;
|
||||
|
||||
fw_cfg_init_mem_wide(base + 8, base, 8);
|
||||
|
||||
nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename,
|
||||
"compatible", "qemu,fw-cfg-mmio");
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||
2, base, 2, size);
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
{
|
||||
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
||||
@@ -529,6 +566,7 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
|
||||
static void machvirt_init(MachineState *machine)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(machine);
|
||||
qemu_irq pic[NUM_IRQS];
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
int n;
|
||||
@@ -566,6 +604,10 @@ static void machvirt_init(MachineState *machine)
|
||||
}
|
||||
cpuobj = object_new(object_class_get_name(oc));
|
||||
|
||||
if (!vms->secure) {
|
||||
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||
}
|
||||
|
||||
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
|
||||
NULL);
|
||||
|
||||
@@ -604,6 +646,8 @@ static void machvirt_init(MachineState *machine)
|
||||
*/
|
||||
create_virtio_devices(vbi, pic);
|
||||
|
||||
create_fw_cfg(vbi);
|
||||
|
||||
vbi->bootinfo.ram_size = machine->ram_size;
|
||||
vbi->bootinfo.kernel_filename = machine->kernel_filename;
|
||||
vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
@@ -612,19 +656,60 @@ static void machvirt_init(MachineState *machine)
|
||||
vbi->bootinfo.board_id = -1;
|
||||
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
|
||||
vbi->bootinfo.get_dtb = machvirt_dtb;
|
||||
vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
|
||||
}
|
||||
|
||||
static QEMUMachine machvirt_a15_machine = {
|
||||
.name = "virt",
|
||||
.desc = "ARM Virtual Machine",
|
||||
.init = machvirt_init,
|
||||
.max_cpus = 8,
|
||||
static bool virt_get_secure(Object *obj, Error **errp)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
return vms->secure;
|
||||
}
|
||||
|
||||
static void virt_set_secure(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
vms->secure = value;
|
||||
}
|
||||
|
||||
static void virt_instance_init(Object *obj)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
/* EL3 is enabled by default on virt */
|
||||
vms->secure = true;
|
||||
object_property_add_bool(obj, "secure", virt_get_secure,
|
||||
virt_set_secure, NULL);
|
||||
object_property_set_description(obj, "secure",
|
||||
"Set on/off to enable/disable the ARM "
|
||||
"Security Extensions (TrustZone)",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void virt_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->name = TYPE_VIRT_MACHINE;
|
||||
mc->desc = "ARM Virtual Machine",
|
||||
mc->init = machvirt_init;
|
||||
mc->max_cpus = 8;
|
||||
}
|
||||
|
||||
static const TypeInfo machvirt_info = {
|
||||
.name = TYPE_VIRT_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(VirtMachineState),
|
||||
.instance_init = virt_instance_init,
|
||||
.class_size = sizeof(VirtMachineClass),
|
||||
.class_init = virt_class_init,
|
||||
};
|
||||
|
||||
static void machvirt_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&machvirt_a15_machine);
|
||||
type_register_static(&machvirt_info);
|
||||
}
|
||||
|
||||
machine_init(machvirt_machine_init);
|
||||
|
||||
@@ -126,6 +126,18 @@ static void zynq_init(MachineState *machine)
|
||||
|
||||
cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
|
||||
|
||||
/* By default A9 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
* realization.
|
||||
*/
|
||||
if (object_property_find(OBJECT(cpu), "has_el3", NULL)) {
|
||||
object_property_set_bool(OBJECT(cpu), false, "has_el3", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
|
||||
@@ -197,7 +197,14 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
|
||||
s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
|
||||
|
||||
@@ -476,7 +476,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
||||
|
||||
switch (dw10) {
|
||||
case NVME_NUMBER_OF_QUEUES:
|
||||
req->cqe.result = cpu_to_le32(n->num_queues);
|
||||
req->cqe.result =
|
||||
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||
break;
|
||||
default:
|
||||
return NVME_INVALID_FIELD | NVME_DNR;
|
||||
@@ -490,7 +491,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
||||
|
||||
switch (dw10) {
|
||||
case NVME_NUMBER_OF_QUEUES:
|
||||
req->cqe.result = cpu_to_le32(n->num_queues);
|
||||
req->cqe.result =
|
||||
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||
break;
|
||||
default:
|
||||
return NVME_INVALID_FIELD | NVME_DNR;
|
||||
@@ -583,8 +585,7 @@ static int nvme_start_ctrl(NvmeCtrl *n)
|
||||
NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) ||
|
||||
NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) ||
|
||||
NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) ||
|
||||
!NVME_AQA_ASQS(n->bar.aqa) || NVME_AQA_ASQS(n->bar.aqa) > 4095 ||
|
||||
!NVME_AQA_ACQS(n->bar.aqa) || NVME_AQA_ACQS(n->bar.aqa) > 4095) {
|
||||
!NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -812,8 +813,9 @@ static int nvme_init(PCIDevice *pci_dev)
|
||||
NVME_CAP_SET_AMS(n->bar.cap, 1);
|
||||
NVME_CAP_SET_TO(n->bar.cap, 0xf);
|
||||
NVME_CAP_SET_CSS(n->bar.cap, 1);
|
||||
NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
|
||||
|
||||
n->bar.vs = 0x00010001;
|
||||
n->bar.vs = 0x00010100;
|
||||
n->bar.intmc = n->bar.intms = 0;
|
||||
|
||||
for (i = 0; i < n->num_namespaces; i++) {
|
||||
|
||||
@@ -688,7 +688,7 @@ typedef struct NvmeCtrl {
|
||||
NvmeBar bar;
|
||||
BlockConf conf;
|
||||
|
||||
uint16_t page_size;
|
||||
uint32_t page_size;
|
||||
uint16_t page_bits;
|
||||
uint16_t max_prp_ents;
|
||||
uint16_t cqe_size;
|
||||
|
||||
@@ -744,6 +744,7 @@ static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
dc->realize = pflash_cfi02_realize;
|
||||
dc->props = pflash_cfi02_properties;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo pflash_cfi02_info = {
|
||||
|
||||
@@ -59,6 +59,13 @@ struct PersistentGrant {
|
||||
|
||||
typedef struct PersistentGrant PersistentGrant;
|
||||
|
||||
struct PersistentRegion {
|
||||
void *addr;
|
||||
int num;
|
||||
};
|
||||
|
||||
typedef struct PersistentRegion PersistentRegion;
|
||||
|
||||
struct ioreq {
|
||||
blkif_request_t req;
|
||||
int16_t status;
|
||||
@@ -118,6 +125,7 @@ struct XenBlkDev {
|
||||
gboolean feature_discard;
|
||||
gboolean feature_persistent;
|
||||
GTree *persistent_gnts;
|
||||
GSList *persistent_regions;
|
||||
unsigned int persistent_gnt_count;
|
||||
unsigned int max_grants;
|
||||
|
||||
@@ -177,6 +185,23 @@ static void destroy_grant(gpointer pgnt)
|
||||
g_free(grant);
|
||||
}
|
||||
|
||||
static void remove_persistent_region(gpointer data, gpointer dev)
|
||||
{
|
||||
PersistentRegion *region = data;
|
||||
struct XenBlkDev *blkdev = dev;
|
||||
XenGnttab gnt = blkdev->xendev.gnttabdev;
|
||||
|
||||
if (xc_gnttab_munmap(gnt, region->addr, region->num) != 0) {
|
||||
xen_be_printf(&blkdev->xendev, 0,
|
||||
"xc_gnttab_munmap region %p failed: %s\n",
|
||||
region->addr, strerror(errno));
|
||||
}
|
||||
xen_be_printf(&blkdev->xendev, 3,
|
||||
"unmapped grant region %p with %d pages\n",
|
||||
region->addr, region->num);
|
||||
g_free(region);
|
||||
}
|
||||
|
||||
static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
|
||||
{
|
||||
struct ioreq *ioreq = NULL;
|
||||
@@ -343,6 +368,7 @@ static int ioreq_map(struct ioreq *ioreq)
|
||||
void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
int i, j, new_maps = 0;
|
||||
PersistentGrant *grant;
|
||||
PersistentRegion *region;
|
||||
/* domids and refs variables will contain the information necessary
|
||||
* to map the grants that are needed to fulfill this request.
|
||||
*
|
||||
@@ -421,7 +447,22 @@ static int ioreq_map(struct ioreq *ioreq)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ioreq->blkdev->feature_persistent) {
|
||||
if (ioreq->blkdev->feature_persistent && new_maps != 0 &&
|
||||
(!batch_maps || (ioreq->blkdev->persistent_gnt_count + new_maps <=
|
||||
ioreq->blkdev->max_grants))) {
|
||||
/*
|
||||
* If we are using persistent grants and batch mappings only
|
||||
* add the new maps to the list of persistent grants if the whole
|
||||
* area can be persistently mapped.
|
||||
*/
|
||||
if (batch_maps) {
|
||||
region = g_malloc0(sizeof(*region));
|
||||
region->addr = ioreq->pages;
|
||||
region->num = new_maps;
|
||||
ioreq->blkdev->persistent_regions = g_slist_append(
|
||||
ioreq->blkdev->persistent_regions,
|
||||
region);
|
||||
}
|
||||
while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants)
|
||||
&& new_maps) {
|
||||
/* Go through the list of newly mapped grants and add as many
|
||||
@@ -447,6 +488,7 @@ static int ioreq_map(struct ioreq *ioreq)
|
||||
grant);
|
||||
ioreq->blkdev->persistent_gnt_count++;
|
||||
}
|
||||
assert(!batch_maps || new_maps == 0);
|
||||
}
|
||||
for (i = 0; i < ioreq->v.niov; i++) {
|
||||
ioreq->v.iov[i].iov_base += (uintptr_t)page[i];
|
||||
@@ -971,7 +1013,10 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST;
|
||||
blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp,
|
||||
NULL, NULL,
|
||||
batch_maps ?
|
||||
(GDestroyNotify)g_free :
|
||||
(GDestroyNotify)destroy_grant);
|
||||
blkdev->persistent_regions = NULL;
|
||||
blkdev->persistent_gnt_count = 0;
|
||||
}
|
||||
|
||||
@@ -1000,6 +1045,26 @@ static void blk_disconnect(struct XenDevice *xendev)
|
||||
blkdev->cnt_map--;
|
||||
blkdev->sring = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmap persistent grants before switching to the closed state
|
||||
* so the frontend can free them.
|
||||
*
|
||||
* In the !batch_maps case g_tree_destroy will take care of unmapping
|
||||
* the grant, but in the batch_maps case we need to iterate over every
|
||||
* region in persistent_regions and unmap it.
|
||||
*/
|
||||
if (blkdev->feature_persistent) {
|
||||
g_tree_destroy(blkdev->persistent_gnts);
|
||||
assert(batch_maps || blkdev->persistent_gnt_count == 0);
|
||||
if (batch_maps) {
|
||||
blkdev->persistent_gnt_count = 0;
|
||||
g_slist_foreach(blkdev->persistent_regions,
|
||||
(GFunc)remove_persistent_region, blkdev);
|
||||
g_slist_free(blkdev->persistent_regions);
|
||||
}
|
||||
blkdev->feature_persistent = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int blk_free(struct XenDevice *xendev)
|
||||
@@ -1011,11 +1076,6 @@ static int blk_free(struct XenDevice *xendev)
|
||||
blk_disconnect(xendev);
|
||||
}
|
||||
|
||||
/* Free persistent grants */
|
||||
if (blkdev->feature_persistent) {
|
||||
g_tree_destroy(blkdev->persistent_gnts);
|
||||
}
|
||||
|
||||
while (!QLIST_EMPTY(&blkdev->freelist)) {
|
||||
ioreq = QLIST_FIRST(&blkdev->freelist);
|
||||
QLIST_REMOVE(ioreq, list);
|
||||
|
||||
@@ -52,7 +52,8 @@ typedef struct SCLPConsoleLM {
|
||||
* event_pending is set when a newline character is encountered
|
||||
*
|
||||
* The maximum command line length is limited by the maximum
|
||||
* space available in an SCCB
|
||||
* space available in an SCCB. Line mode console input is sent
|
||||
* truncated to the guest in case it doesn't fit into the SCCB.
|
||||
*/
|
||||
|
||||
static int chr_can_read(void *opaque)
|
||||
@@ -61,10 +62,8 @@ static int chr_can_read(void *opaque)
|
||||
|
||||
if (scon->event.event_pending) {
|
||||
return 0;
|
||||
} else if (SIZE_CONSOLE_BUFFER - scon->length) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void chr_read(void *opaque, const uint8_t *buf, int size)
|
||||
@@ -78,6 +77,10 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
|
||||
sclp_service_interrupt(0);
|
||||
return;
|
||||
}
|
||||
if (scon->length == SIZE_CONSOLE_BUFFER) {
|
||||
/* Eat the character, but still process CR and LF. */
|
||||
return;
|
||||
}
|
||||
scon->buf[scon->length] = *buf;
|
||||
scon->length += 1;
|
||||
if (scon->echo) {
|
||||
@@ -125,6 +128,7 @@ static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
|
||||
cons->length = 0;
|
||||
/* data provided and no more data pending */
|
||||
event->event_pending = false;
|
||||
qemu_notify_event();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ typedef struct SCLPConsole {
|
||||
uint32_t iov_bs; /* offset in buf for char layer read operation */
|
||||
uint32_t iov_data_len; /* length of byte stream in buffer */
|
||||
uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
|
||||
bool notify; /* qemu_notify_event() req'd if true */
|
||||
} SCLPConsole;
|
||||
|
||||
/* character layer call-back functions */
|
||||
@@ -44,8 +45,12 @@ typedef struct SCLPConsole {
|
||||
static int chr_can_read(void *opaque)
|
||||
{
|
||||
SCLPConsole *scon = opaque;
|
||||
int avail = SIZE_BUFFER_VT220 - scon->iov_data_len;
|
||||
|
||||
return SIZE_BUFFER_VT220 - scon->iov_data_len;
|
||||
if (avail == 0) {
|
||||
scon->notify = true;
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
|
||||
/* Send data from a char device over to the guest */
|
||||
@@ -113,6 +118,10 @@ static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
|
||||
cons->iov_sclp += avail;
|
||||
/* more data pending */
|
||||
}
|
||||
if (cons->notify) {
|
||||
cons->notify = false;
|
||||
qemu_notify_event();
|
||||
}
|
||||
}
|
||||
|
||||
static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
|
||||
@@ -229,6 +238,7 @@ static void console_reset(DeviceState *dev)
|
||||
scon->iov_bs = 0;
|
||||
scon->iov_data_len = 0;
|
||||
scon->iov_sclp_rest = 0;
|
||||
scon->notify = false;
|
||||
}
|
||||
|
||||
static int console_exit(SCLPEvent *event)
|
||||
|
||||
@@ -224,21 +224,23 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
SerialState *s = opaque;
|
||||
|
||||
do {
|
||||
assert(!(s->lsr & UART_LSR_TEMT));
|
||||
if (s->tsr_retry <= 0) {
|
||||
assert(!(s->lsr & UART_LSR_THRE));
|
||||
|
||||
if (s->fcr & UART_FCR_FE) {
|
||||
if (fifo8_is_empty(&s->xmit_fifo)) {
|
||||
return FALSE;
|
||||
}
|
||||
assert(!fifo8_is_empty(&s->xmit_fifo));
|
||||
s->tsr = fifo8_pop(&s->xmit_fifo);
|
||||
if (!s->xmit_fifo.num) {
|
||||
s->lsr |= UART_LSR_THRE;
|
||||
}
|
||||
} else if ((s->lsr & UART_LSR_THRE)) {
|
||||
return FALSE;
|
||||
} else {
|
||||
s->tsr = s->thr;
|
||||
s->lsr |= UART_LSR_THRE;
|
||||
s->lsr &= ~UART_LSR_TEMT;
|
||||
}
|
||||
if ((s->lsr & UART_LSR_THRE) && !s->thr_ipending) {
|
||||
s->thr_ipending = 1;
|
||||
serial_update_irq(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,17 +258,13 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
} else {
|
||||
s->tsr_retry = 0;
|
||||
}
|
||||
|
||||
/* Transmit another byte if it is already available. It is only
|
||||
possible when FIFO is enabled and not empty. */
|
||||
} while ((s->fcr & UART_FCR_FE) && !fifo8_is_empty(&s->xmit_fifo));
|
||||
} while (!(s->lsr & UART_LSR_THRE));
|
||||
|
||||
s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
|
||||
if (s->lsr & UART_LSR_THRE) {
|
||||
s->lsr |= UART_LSR_TEMT;
|
||||
s->thr_ipending = 1;
|
||||
serial_update_irq(s);
|
||||
}
|
||||
s->lsr |= UART_LSR_TEMT;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -323,10 +321,10 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
fifo8_pop(&s->xmit_fifo);
|
||||
}
|
||||
fifo8_push(&s->xmit_fifo, s->thr);
|
||||
s->lsr &= ~UART_LSR_TEMT;
|
||||
}
|
||||
s->thr_ipending = 0;
|
||||
s->lsr &= ~UART_LSR_THRE;
|
||||
s->lsr &= ~UART_LSR_TEMT;
|
||||
serial_update_irq(s);
|
||||
if (s->tsr_retry <= 0) {
|
||||
serial_xmit(NULL, G_IO_OUT, s);
|
||||
@@ -338,10 +336,12 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
s->divider = (s->divider & 0x00ff) | (val << 8);
|
||||
serial_update_parameters(s);
|
||||
} else {
|
||||
uint8_t changed = (s->ier ^ val) & 0x0f;
|
||||
s->ier = val & 0x0f;
|
||||
/* If the backend device is a real serial port, turn polling of the modem
|
||||
status lines on physical port on or off depending on UART_IER_MSI state */
|
||||
if (s->poll_msl >= 0) {
|
||||
* status lines on physical port on or off depending on UART_IER_MSI state.
|
||||
*/
|
||||
if ((changed & UART_IER_MSI) && s->poll_msl >= 0) {
|
||||
if (s->ier & UART_IER_MSI) {
|
||||
s->poll_msl = 1;
|
||||
serial_update_msl(s);
|
||||
@@ -350,8 +350,27 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
s->poll_msl = 0;
|
||||
}
|
||||
}
|
||||
if (s->lsr & UART_LSR_THRE) {
|
||||
s->thr_ipending = 1;
|
||||
|
||||
/* Turning on the THRE interrupt on IER can trigger the interrupt
|
||||
* if LSR.THRE=1, even if it had been masked before by reading IIR.
|
||||
* This is not in the datasheet, but Windows relies on it. It is
|
||||
* unclear if THRE has to be resampled every time THRI becomes
|
||||
* 1, or only on the rising edge. Bochs does the latter, and Windows
|
||||
* always toggles IER to all zeroes and back to all ones, so do the
|
||||
* same.
|
||||
*
|
||||
* If IER.THRI is zero, thr_ipending is not used. Set it to zero
|
||||
* so that the thr_ipending subsection is not migrated.
|
||||
*/
|
||||
if (changed & UART_IER_THRI) {
|
||||
if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
|
||||
s->thr_ipending = 1;
|
||||
} else {
|
||||
s->thr_ipending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
serial_update_irq(s);
|
||||
}
|
||||
}
|
||||
@@ -365,12 +384,15 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
/* FIFO clear */
|
||||
|
||||
if (val & UART_FCR_RFR) {
|
||||
s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
|
||||
timer_del(s->fifo_timeout_timer);
|
||||
s->timeout_ipending = 0;
|
||||
fifo8_reset(&s->recv_fifo);
|
||||
}
|
||||
|
||||
if (val & UART_FCR_XFR) {
|
||||
s->lsr |= UART_LSR_THRE;
|
||||
s->thr_ipending = 1;
|
||||
fifo8_reset(&s->xmit_fifo);
|
||||
}
|
||||
|
||||
@@ -623,8 +645,17 @@ static int serial_post_load(void *opaque, int version_id)
|
||||
static bool serial_thr_ipending_needed(void *opaque)
|
||||
{
|
||||
SerialState *s = opaque;
|
||||
bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
|
||||
return s->thr_ipending != expected_value;
|
||||
|
||||
if (s->ier & UART_IER_THRI) {
|
||||
bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
|
||||
return s->thr_ipending != expected_value;
|
||||
} else {
|
||||
/* LSR.THRE will be sampled again when the interrupt is
|
||||
* enabled. thr_ipending is not used in this case, do
|
||||
* not migrate it.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_serial_thr_ipending = {
|
||||
|
||||
@@ -482,10 +482,14 @@ static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
|
||||
/* Guest requested config info */
|
||||
static void get_config(VirtIODevice *vdev, uint8_t *config_data)
|
||||
{
|
||||
VirtIOSerial *vser;
|
||||
VirtIOSerial *vser = VIRTIO_SERIAL(vdev);
|
||||
struct virtio_console_config *config =
|
||||
(struct virtio_console_config *)config_data;
|
||||
|
||||
vser = VIRTIO_SERIAL(vdev);
|
||||
memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
|
||||
config->cols = 0;
|
||||
config->rows = 0;
|
||||
config->max_nr_ports = virtio_tswap32(vdev,
|
||||
vser->serial.max_virtserial_ports);
|
||||
}
|
||||
|
||||
static void guest_reset(VirtIOSerial *vser)
|
||||
@@ -533,10 +537,6 @@ static void vser_reset(VirtIODevice *vdev)
|
||||
|
||||
vser = VIRTIO_SERIAL(vdev);
|
||||
guest_reset(vser);
|
||||
|
||||
/* In case we have switched endianness */
|
||||
vser->config.max_nr_ports =
|
||||
virtio_tswap32(vdev, vser->serial.max_virtserial_ports);
|
||||
}
|
||||
|
||||
static void virtio_serial_save(QEMUFile *f, void *opaque)
|
||||
@@ -551,15 +551,16 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
|
||||
VirtIOSerialPort *port;
|
||||
uint32_t nr_active_ports;
|
||||
unsigned int i, max_nr_ports;
|
||||
struct virtio_console_config config;
|
||||
|
||||
/* The config space */
|
||||
qemu_put_be16s(f, &s->config.cols);
|
||||
qemu_put_be16s(f, &s->config.rows);
|
||||
|
||||
qemu_put_be32s(f, &s->config.max_nr_ports);
|
||||
/* The config space (ignored on the far end in current versions) */
|
||||
get_config(vdev, (uint8_t *)&config);
|
||||
qemu_put_be16s(f, &config.cols);
|
||||
qemu_put_be16s(f, &config.rows);
|
||||
qemu_put_be32s(f, &config.max_nr_ports);
|
||||
|
||||
/* The ports map */
|
||||
max_nr_ports = virtio_tswap32(vdev, s->config.max_nr_ports);
|
||||
max_nr_ports = s->serial.max_virtserial_ports;
|
||||
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
||||
qemu_put_be32s(f, &s->ports_map[i]);
|
||||
}
|
||||
@@ -715,13 +716,7 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
qemu_get_be16s(f, (uint16_t *) &tmp);
|
||||
qemu_get_be32s(f, &tmp);
|
||||
|
||||
/* Note: this is the only location where we use tswap32() instead of
|
||||
* virtio_tswap32() because:
|
||||
* - virtio_tswap32() only makes sense when the device is fully restored
|
||||
* - the target endianness that was used to populate s->config is
|
||||
* necessarly the default one
|
||||
*/
|
||||
max_nr_ports = tswap32(s->config.max_nr_ports);
|
||||
max_nr_ports = s->serial.max_virtserial_ports;
|
||||
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
||||
qemu_get_be32s(f, &ports_map);
|
||||
|
||||
@@ -784,10 +779,9 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
|
||||
/* This function is only used if a port id is not provided by the user */
|
||||
static uint32_t find_free_port_id(VirtIOSerial *vser)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
|
||||
unsigned int i, max_nr_ports;
|
||||
|
||||
max_nr_ports = virtio_tswap32(vdev, vser->config.max_nr_ports);
|
||||
max_nr_ports = vser->serial.max_virtserial_ports;
|
||||
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
||||
uint32_t map, bit;
|
||||
|
||||
@@ -848,7 +842,6 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
|
||||
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
|
||||
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||
VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev));
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(bus->vser);
|
||||
int max_nr_ports;
|
||||
bool plugging_port0;
|
||||
Error *err = NULL;
|
||||
@@ -871,7 +864,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (find_port_by_name(port->name)) {
|
||||
if (port->name != NULL && find_port_by_name(port->name)) {
|
||||
error_setg(errp, "virtio-serial-bus: A port already exists by name %s",
|
||||
port->name);
|
||||
return;
|
||||
@@ -890,7 +883,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
max_nr_ports = virtio_tswap32(vdev, port->vser->config.max_nr_ports);
|
||||
max_nr_ports = port->vser->serial.max_virtserial_ports;
|
||||
if (port->id >= max_nr_ports) {
|
||||
error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, "
|
||||
"max. allowed: %u", max_nr_ports - 1);
|
||||
@@ -995,8 +988,6 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
|
||||
vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
|
||||
}
|
||||
|
||||
vser->config.max_nr_ports =
|
||||
virtio_tswap32(vdev, vser->serial.max_virtserial_ports);
|
||||
vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32)
|
||||
* sizeof(vser->ports_map[0]));
|
||||
/*
|
||||
|
||||
@@ -14,3 +14,4 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o
|
||||
common-obj-$(CONFIG_SOFTMMU) += null-machine.o
|
||||
common-obj-$(CONFIG_SOFTMMU) += loader.o
|
||||
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
|
||||
common-obj-$(CONFIG_SOFTMMU) += platform-bus.o
|
||||
|
||||
@@ -80,6 +80,13 @@ int load_image(const char *filename, uint8_t *addr)
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
if (size == -1) {
|
||||
fprintf(stderr, "file %-20s: get size error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
if (read(fd, addr, size) != size) {
|
||||
close(fd);
|
||||
@@ -607,14 +614,9 @@ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
/* This simply prevents g_malloc in the function below from allocating
|
||||
* a huge amount of memory, by placing a limit on the maximum
|
||||
* uncompressed image size that load_image_gzipped will read.
|
||||
*/
|
||||
#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
|
||||
|
||||
/* Load a gzip-compressed kernel. */
|
||||
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
|
||||
int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
|
||||
uint8_t **buffer)
|
||||
{
|
||||
uint8_t *compressed_data = NULL;
|
||||
uint8_t *data = NULL;
|
||||
@@ -646,8 +648,11 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rom_add_blob_fixed(filename, data, bytes, addr);
|
||||
/* trim to actual size and return to caller */
|
||||
*buffer = g_realloc(data, bytes);
|
||||
ret = bytes;
|
||||
/* ownership has been transferred to caller */
|
||||
data = NULL;
|
||||
|
||||
out:
|
||||
g_free(compressed_data);
|
||||
@@ -655,6 +660,20 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Load a gzip-compressed kernel. */
|
||||
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||
{
|
||||
int bytes;
|
||||
uint8_t *data;
|
||||
|
||||
bytes = load_image_gzipped_buffer(filename, max_sz, &data);
|
||||
if (bytes != -1) {
|
||||
rom_add_blob_fixed(filename, data, bytes, addr);
|
||||
g_free(data);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions for reboot-persistent memory regions.
|
||||
* - used for vga bios and option roms.
|
||||
@@ -705,12 +724,22 @@ static void rom_insert(Rom *rom)
|
||||
QTAILQ_INSERT_TAIL(&roms, rom, next);
|
||||
}
|
||||
|
||||
static void fw_cfg_resized(const char *id, uint64_t length, void *host)
|
||||
{
|
||||
if (fw_cfg) {
|
||||
fw_cfg_modify_file(fw_cfg, id + strlen("/rom@"), host, length);
|
||||
}
|
||||
}
|
||||
|
||||
static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
|
||||
{
|
||||
void *data;
|
||||
|
||||
rom->mr = g_malloc(sizeof(*rom->mr));
|
||||
memory_region_init_ram(rom->mr, owner, name, rom->datasize, &error_abort);
|
||||
memory_region_init_resizeable_ram(rom->mr, owner, name,
|
||||
rom->datasize, rom->romsize,
|
||||
fw_cfg_resized,
|
||||
&error_abort);
|
||||
memory_region_set_readonly(rom->mr, true);
|
||||
vmstate_register_ram_global(rom->mr);
|
||||
|
||||
@@ -748,6 +777,12 @@ int rom_add_file(const char *file, const char *fw_dir,
|
||||
}
|
||||
rom->addr = addr;
|
||||
rom->romsize = lseek(fd, 0, SEEK_END);
|
||||
if (rom->romsize == -1) {
|
||||
fprintf(stderr, "rom: file %-20s: get size error: %s\n",
|
||||
rom->name, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
rom->datasize = rom->romsize;
|
||||
rom->data = g_malloc0(rom->datasize);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
@@ -798,37 +833,39 @@ err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
hwaddr addr, const char *fw_file_name,
|
||||
ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
size_t max_len, hwaddr addr, const char *fw_file_name,
|
||||
FWCfgReadCallback fw_callback, void *callback_opaque)
|
||||
{
|
||||
Rom *rom;
|
||||
void *data = NULL;
|
||||
ram_addr_t ret = RAM_ADDR_MAX;
|
||||
|
||||
rom = g_malloc0(sizeof(*rom));
|
||||
rom->name = g_strdup(name);
|
||||
rom->addr = addr;
|
||||
rom->romsize = len;
|
||||
rom->romsize = max_len ? max_len : len;
|
||||
rom->datasize = len;
|
||||
rom->data = g_malloc0(rom->datasize);
|
||||
memcpy(rom->data, blob, len);
|
||||
rom_insert(rom);
|
||||
if (fw_file_name && fw_cfg) {
|
||||
char devpath[100];
|
||||
void *data;
|
||||
|
||||
snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
|
||||
|
||||
if (rom_file_has_mr) {
|
||||
data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
|
||||
ret = memory_region_get_ram_addr(rom->mr);
|
||||
} else {
|
||||
data = rom->data;
|
||||
}
|
||||
|
||||
fw_cfg_add_file_callback(fw_cfg, fw_file_name,
|
||||
fw_callback, callback_opaque,
|
||||
data, rom->romsize);
|
||||
data, rom->datasize);
|
||||
}
|
||||
return data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function is specific for elf program because we don't need to allocate
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
static char *machine_get_accel(Object *obj, Error **errp)
|
||||
{
|
||||
@@ -257,52 +260,128 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp)
|
||||
ms->iommu = value;
|
||||
}
|
||||
|
||||
static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
||||
{
|
||||
error_report("Option '-device %s' cannot be handled by this machine",
|
||||
object_class_get_name(object_get_class(OBJECT(sbdev))));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void machine_init_notify(Notifier *notifier, void *data)
|
||||
{
|
||||
Object *machine = qdev_get_machine();
|
||||
ObjectClass *oc = object_get_class(machine);
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
if (mc->has_dynamic_sysbus) {
|
||||
/* Our machine can handle dynamic sysbus devices, we're all good */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all dynamically created devices and check whether there
|
||||
* are sysbus devices among them. If there are, error out.
|
||||
*/
|
||||
foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
|
||||
}
|
||||
|
||||
static void machine_initfn(Object *obj)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
|
||||
object_property_add_str(obj, "accel",
|
||||
machine_get_accel, machine_set_accel, NULL);
|
||||
object_property_set_description(obj, "accel",
|
||||
"Accelerator list",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "kernel-irqchip",
|
||||
machine_get_kernel_irqchip,
|
||||
machine_set_kernel_irqchip,
|
||||
NULL);
|
||||
object_property_set_description(obj, "kernel-irqchip",
|
||||
"Use KVM in-kernel irqchip",
|
||||
NULL);
|
||||
object_property_add(obj, "kvm-shadow-mem", "int",
|
||||
machine_get_kvm_shadow_mem,
|
||||
machine_set_kvm_shadow_mem,
|
||||
NULL, NULL, NULL);
|
||||
object_property_set_description(obj, "kvm-shadow-mem",
|
||||
"KVM shadow MMU size",
|
||||
NULL);
|
||||
object_property_add_str(obj, "kernel",
|
||||
machine_get_kernel, machine_set_kernel, NULL);
|
||||
object_property_set_description(obj, "kernel",
|
||||
"Linux kernel image file",
|
||||
NULL);
|
||||
object_property_add_str(obj, "initrd",
|
||||
machine_get_initrd, machine_set_initrd, NULL);
|
||||
object_property_set_description(obj, "initrd",
|
||||
"Linux initial ramdisk file",
|
||||
NULL);
|
||||
object_property_add_str(obj, "append",
|
||||
machine_get_append, machine_set_append, NULL);
|
||||
object_property_set_description(obj, "append",
|
||||
"Linux kernel command line",
|
||||
NULL);
|
||||
object_property_add_str(obj, "dtb",
|
||||
machine_get_dtb, machine_set_dtb, NULL);
|
||||
object_property_set_description(obj, "dtb",
|
||||
"Linux kernel device tree file",
|
||||
NULL);
|
||||
object_property_add_str(obj, "dumpdtb",
|
||||
machine_get_dumpdtb, machine_set_dumpdtb, NULL);
|
||||
object_property_set_description(obj, "dumpdtb",
|
||||
"Dump current dtb to a file and quit",
|
||||
NULL);
|
||||
object_property_add(obj, "phandle-start", "int",
|
||||
machine_get_phandle_start,
|
||||
machine_set_phandle_start,
|
||||
NULL, NULL, NULL);
|
||||
object_property_set_description(obj, "phandle-start",
|
||||
"The first phandle ID we may generate dynamically",
|
||||
NULL);
|
||||
object_property_add_str(obj, "dt-compatible",
|
||||
machine_get_dt_compatible,
|
||||
machine_set_dt_compatible,
|
||||
NULL);
|
||||
object_property_set_description(obj, "dt-compatible",
|
||||
"Overrides the \"compatible\" property of the dt root node",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "dump-guest-core",
|
||||
machine_get_dump_guest_core,
|
||||
machine_set_dump_guest_core,
|
||||
NULL);
|
||||
object_property_set_description(obj, "dump-guest-core",
|
||||
"Include guest memory in a core dump",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "mem-merge",
|
||||
machine_get_mem_merge,
|
||||
machine_set_mem_merge, NULL);
|
||||
object_property_set_description(obj, "mem-merge",
|
||||
"Enable/disable memory merge support",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "usb",
|
||||
machine_get_usb,
|
||||
machine_set_usb, NULL);
|
||||
object_property_set_description(obj, "usb",
|
||||
"Set on/off to enable/disable usb",
|
||||
NULL);
|
||||
object_property_add_str(obj, "firmware",
|
||||
machine_get_firmware,
|
||||
machine_set_firmware, NULL);
|
||||
object_property_set_description(obj, "firmware",
|
||||
"Firmware image",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "iommu",
|
||||
machine_get_iommu,
|
||||
machine_set_iommu, NULL);
|
||||
object_property_set_description(obj, "iommu",
|
||||
"Set on/off to enable/disable Intel IOMMU (VT-d)",
|
||||
NULL);
|
||||
|
||||
/* Register notifier when init is done for sysbus sanity checks */
|
||||
ms->sysbus_notifier.notify = machine_init_notify;
|
||||
qemu_add_machine_init_done_notifier(&ms->sysbus_notifier);
|
||||
}
|
||||
|
||||
static void machine_finalize(Object *obj)
|
||||
@@ -319,6 +398,11 @@ static void machine_finalize(Object *obj)
|
||||
g_free(ms->firmware);
|
||||
}
|
||||
|
||||
bool machine_usb(MachineState *machine)
|
||||
{
|
||||
return machine->usb;
|
||||
}
|
||||
|
||||
static const TypeInfo machine_info = {
|
||||
.name = TYPE_MACHINE,
|
||||
.parent = TYPE_OBJECT,
|
||||
|
||||
253
hw/core/platform-bus.c
Normal file
253
hw/core/platform-bus.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Platform Bus device to support dynamic Sysbus devices
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Alexander Graf, <agraf@suse.de>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hw/platform-bus.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
|
||||
/*
|
||||
* Returns the PlatformBus IRQ number for a SysBusDevice irq number or -1 if
|
||||
* the IRQ is not mapped on this Platform bus.
|
||||
*/
|
||||
int platform_bus_get_irqn(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||
int n)
|
||||
{
|
||||
qemu_irq sbirq = sysbus_get_connected_irq(sbdev, n);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pbus->num_irqs; i++) {
|
||||
if (pbus->irqs[i] == sbirq) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* IRQ not mapped on platform bus */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the PlatformBus MMIO region offset for Region n of a SysBusDevice or
|
||||
* -1 if the region is not mapped on this Platform bus.
|
||||
*/
|
||||
hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||
int n)
|
||||
{
|
||||
MemoryRegion *pbus_mr = &pbus->mmio;
|
||||
MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
|
||||
Object *pbus_mr_obj = OBJECT(pbus_mr);
|
||||
Object *parent_mr;
|
||||
|
||||
if (!memory_region_is_mapped(sbdev_mr)) {
|
||||
/* Region is not mapped? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL);
|
||||
|
||||
assert(parent_mr);
|
||||
if (parent_mr != pbus_mr_obj) {
|
||||
/* MMIO region is not mapped on platform bus */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);
|
||||
}
|
||||
|
||||
static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
|
||||
{
|
||||
PlatformBusDevice *pbus = opaque;
|
||||
qemu_irq sbirq;
|
||||
int n, i;
|
||||
|
||||
for (n = 0; ; n++) {
|
||||
if (!sysbus_has_irq(sbdev, n)) {
|
||||
break;
|
||||
}
|
||||
|
||||
sbirq = sysbus_get_connected_irq(sbdev, n);
|
||||
for (i = 0; i < pbus->num_irqs; i++) {
|
||||
if (pbus->irqs[i] == sbirq) {
|
||||
bitmap_set(pbus->used_irqs, i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all sysbus devices and look for unassigned IRQ lines as well as
|
||||
* unassociated MMIO regions. Connect them to the platform bus if available.
|
||||
*/
|
||||
static void plaform_bus_refresh_irqs(PlatformBusDevice *pbus)
|
||||
{
|
||||
bitmap_zero(pbus->used_irqs, pbus->num_irqs);
|
||||
foreach_dynamic_sysbus_device(platform_bus_count_irqs, pbus);
|
||||
pbus->done_gathering = true;
|
||||
}
|
||||
|
||||
static int platform_bus_map_irq(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||
int n)
|
||||
{
|
||||
int max_irqs = pbus->num_irqs;
|
||||
int irqn;
|
||||
|
||||
if (sysbus_is_irq_connected(sbdev, n)) {
|
||||
/* IRQ is already mapped, nothing to do */
|
||||
return 0;
|
||||
}
|
||||
|
||||
irqn = find_first_zero_bit(pbus->used_irqs, max_irqs);
|
||||
if (irqn >= max_irqs) {
|
||||
hw_error("Platform Bus: Can not fit IRQ line");
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_bit(irqn, pbus->used_irqs);
|
||||
sysbus_connect_irq(sbdev, n, pbus->irqs[irqn]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
||||
int n)
|
||||
{
|
||||
MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
|
||||
uint64_t size = memory_region_size(sbdev_mr);
|
||||
uint64_t alignment = (1ULL << (63 - clz64(size + size - 1)));
|
||||
uint64_t off;
|
||||
bool found_region = false;
|
||||
|
||||
if (memory_region_is_mapped(sbdev_mr)) {
|
||||
/* Region is already mapped, nothing to do */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for empty space in the MMIO space that is naturally aligned with
|
||||
* the target device's memory region
|
||||
*/
|
||||
for (off = 0; off < pbus->mmio_size; off += alignment) {
|
||||
if (!memory_region_find(&pbus->mmio, off, size).mr) {
|
||||
found_region = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_region) {
|
||||
hw_error("Platform Bus: Can not fit MMIO region of size %"PRIx64, size);
|
||||
}
|
||||
|
||||
/* Map the device's region into our Platform Bus MMIO space */
|
||||
memory_region_add_subregion(&pbus->mmio, off, sbdev_mr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each sysbus device, look for unassigned IRQ lines as well as
|
||||
* unassociated MMIO regions. Connect them to the platform bus if available.
|
||||
*/
|
||||
static int link_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
||||
{
|
||||
PlatformBusDevice *pbus = opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; sysbus_has_irq(sbdev, i); i++) {
|
||||
platform_bus_map_irq(pbus, sbdev, i);
|
||||
}
|
||||
|
||||
for (i = 0; sysbus_has_mmio(sbdev, i); i++) {
|
||||
platform_bus_map_mmio(pbus, sbdev, i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void platform_bus_init_notify(Notifier *notifier, void *data)
|
||||
{
|
||||
PlatformBusDevice *pb = container_of(notifier, PlatformBusDevice, notifier);
|
||||
|
||||
/*
|
||||
* Generate a bitmap of used IRQ lines, as the user might have specified
|
||||
* them on the command line.
|
||||
*/
|
||||
plaform_bus_refresh_irqs(pb);
|
||||
|
||||
foreach_dynamic_sysbus_device(link_sysbus_device, pb);
|
||||
}
|
||||
|
||||
static void platform_bus_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PlatformBusDevice *pbus;
|
||||
SysBusDevice *d;
|
||||
int i;
|
||||
|
||||
d = SYS_BUS_DEVICE(dev);
|
||||
pbus = PLATFORM_BUS_DEVICE(dev);
|
||||
|
||||
memory_region_init(&pbus->mmio, NULL, "platform bus", pbus->mmio_size);
|
||||
sysbus_init_mmio(d, &pbus->mmio);
|
||||
|
||||
pbus->used_irqs = bitmap_new(pbus->num_irqs);
|
||||
pbus->irqs = g_new0(qemu_irq, pbus->num_irqs);
|
||||
for (i = 0; i < pbus->num_irqs; i++) {
|
||||
sysbus_init_irq(d, &pbus->irqs[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register notifier that allows us to gather dangling devices once the
|
||||
* machine is completely assembled
|
||||
*/
|
||||
pbus->notifier.notify = platform_bus_init_notify;
|
||||
qemu_add_machine_init_done_notifier(&pbus->notifier);
|
||||
}
|
||||
|
||||
static Property platform_bus_properties[] = {
|
||||
DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0),
|
||||
DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void platform_bus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = platform_bus_realize;
|
||||
dc->props = platform_bus_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo platform_bus_info = {
|
||||
.name = TYPE_PLATFORM_BUS_DEVICE,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PlatformBusDevice),
|
||||
.class_init = platform_bus_class_init,
|
||||
};
|
||||
|
||||
static void platform_bus_register_types(void)
|
||||
{
|
||||
type_register_static(&platform_bus_info);
|
||||
}
|
||||
|
||||
type_init(platform_bus_register_types)
|
||||
@@ -177,42 +177,69 @@ PropertyInfo qdev_prop_chr = {
|
||||
};
|
||||
|
||||
/* --- netdev device --- */
|
||||
|
||||
static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
|
||||
static void get_netdev(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
NICPeers *peers_ptr = (NICPeers *)ptr;
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
|
||||
|
||||
visit_type_str(v, &p, name, errp);
|
||||
g_free(p);
|
||||
}
|
||||
|
||||
static void set_netdev(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
|
||||
NetClientState **ncs = peers_ptr->ncs;
|
||||
NetClientState *peers[MAX_QUEUE_NUM];
|
||||
int queues, i = 0;
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
int queues, err = 0, i = 0;
|
||||
char *str;
|
||||
|
||||
if (dev->realized) {
|
||||
qdev_prop_set_after_realize(dev, name, errp);
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_str(v, &str, name, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
queues = qemu_find_net_clients_except(str, peers,
|
||||
NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
MAX_QUEUE_NUM);
|
||||
if (queues == 0) {
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (queues > MAX_QUEUE_NUM) {
|
||||
ret = -E2BIG;
|
||||
goto err;
|
||||
error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
|
||||
str, queues, MAX_QUEUE_NUM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < queues; i++) {
|
||||
if (peers[i] == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (peers[i]->peer) {
|
||||
ret = -EEXIST;
|
||||
goto err;
|
||||
err = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ncs[i]) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ncs[i] = peers[i];
|
||||
@@ -221,30 +248,9 @@ static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
|
||||
|
||||
peers_ptr->queues = queues;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *print_netdev(void *ptr)
|
||||
{
|
||||
NetClientState *netdev = ptr;
|
||||
const char *val = netdev->name ? netdev->name : "";
|
||||
|
||||
return g_strdup(val);
|
||||
}
|
||||
|
||||
static void get_netdev(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
get_pointer(obj, v, opaque, print_netdev, name, errp);
|
||||
}
|
||||
|
||||
static void set_netdev(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
set_pointer(obj, v, opaque, parse_netdev, name, errp);
|
||||
out:
|
||||
error_set_from_qdev_prop_error(errp, err, dev, prop, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_netdev = {
|
||||
|
||||
@@ -189,6 +189,56 @@ int qdev_init(DeviceState *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QTAILQ_HEAD(device_listeners, DeviceListener) device_listeners
|
||||
= QTAILQ_HEAD_INITIALIZER(device_listeners);
|
||||
|
||||
enum ListenerDirection { Forward, Reverse };
|
||||
|
||||
#define DEVICE_LISTENER_CALL(_callback, _direction, _args...) \
|
||||
do { \
|
||||
DeviceListener *_listener; \
|
||||
\
|
||||
switch (_direction) { \
|
||||
case Forward: \
|
||||
QTAILQ_FOREACH(_listener, &device_listeners, link) { \
|
||||
if (_listener->_callback) { \
|
||||
_listener->_callback(_listener, ##_args); \
|
||||
} \
|
||||
} \
|
||||
break; \
|
||||
case Reverse: \
|
||||
QTAILQ_FOREACH_REVERSE(_listener, &device_listeners, \
|
||||
device_listeners, link) { \
|
||||
if (_listener->_callback) { \
|
||||
_listener->_callback(_listener, ##_args); \
|
||||
} \
|
||||
} \
|
||||
break; \
|
||||
default: \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int device_listener_add(DeviceState *dev, void *opaque)
|
||||
{
|
||||
DEVICE_LISTENER_CALL(realize, Forward, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void device_listener_register(DeviceListener *listener)
|
||||
{
|
||||
QTAILQ_INSERT_TAIL(&device_listeners, listener, link);
|
||||
|
||||
qbus_walk_children(sysbus_get_default(), NULL, NULL, device_listener_add,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
void device_listener_unregister(DeviceListener *listener)
|
||||
{
|
||||
QTAILQ_REMOVE(&device_listeners, listener, link);
|
||||
}
|
||||
|
||||
static void device_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
@@ -453,6 +503,17 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
||||
g_free(propname);
|
||||
}
|
||||
|
||||
qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
|
||||
{
|
||||
char *propname = g_strdup_printf("%s[%d]",
|
||||
name ? name : "unnamed-gpio-out", n);
|
||||
|
||||
qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
|
||||
NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disconnect a GPIO ouput, returning the disconnected input (if any) */
|
||||
|
||||
static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
|
||||
@@ -924,7 +985,7 @@ void qdev_alias_all_properties(DeviceState *target, Object *source)
|
||||
} while (class != object_class_by_name(TYPE_DEVICE));
|
||||
}
|
||||
|
||||
int qdev_build_hotpluggable_device_list(Object *obj, void *opaque)
|
||||
static int qdev_add_hotpluggable_device(Object *obj, void *opaque)
|
||||
{
|
||||
GSList **list = opaque;
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
@@ -933,10 +994,18 @@ int qdev_build_hotpluggable_device_list(Object *obj, void *opaque)
|
||||
*list = g_slist_append(*list, dev);
|
||||
}
|
||||
|
||||
object_child_foreach(obj, qdev_build_hotpluggable_device_list, opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GSList *qdev_build_hotpluggable_device_list(Object *peripheral)
|
||||
{
|
||||
GSList *list = NULL;
|
||||
|
||||
object_child_foreach(peripheral, qdev_add_hotpluggable_device, &list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static bool device_get_realized(Object *obj, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
@@ -975,6 +1044,8 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DEVICE_LISTENER_CALL(realize, Forward, dev);
|
||||
|
||||
hotplug_ctrl = qdev_get_hotplug_handler(dev);
|
||||
if (hotplug_ctrl) {
|
||||
hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
|
||||
@@ -1016,6 +1087,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
|
||||
dc->unrealize(dev, local_errp);
|
||||
}
|
||||
dev->pending_deleted_event = true;
|
||||
DEVICE_LISTENER_CALL(unrealize, Reverse, dev);
|
||||
}
|
||||
|
||||
if (local_err != NULL) {
|
||||
@@ -1122,9 +1194,7 @@ static void device_finalize(Object *obj)
|
||||
NamedGPIOList *ngl, *next;
|
||||
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
if (dev->opts) {
|
||||
qemu_opts_del(dev->opts);
|
||||
}
|
||||
qemu_opts_del(dev->opts);
|
||||
|
||||
QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) {
|
||||
QLIST_REMOVE(ngl, node);
|
||||
|
||||
@@ -24,6 +24,51 @@
|
||||
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
|
||||
static char *sysbus_get_fw_dev_path(DeviceState *dev);
|
||||
|
||||
typedef struct SysBusFind {
|
||||
void *opaque;
|
||||
FindSysbusDeviceFunc *func;
|
||||
} SysBusFind;
|
||||
|
||||
/* Run func() for every sysbus device, traverse the tree for everything else */
|
||||
static int find_sysbus_device(Object *obj, void *opaque)
|
||||
{
|
||||
SysBusFind *find = opaque;
|
||||
Object *dev;
|
||||
SysBusDevice *sbdev;
|
||||
|
||||
dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
|
||||
sbdev = (SysBusDevice *)dev;
|
||||
|
||||
if (!sbdev) {
|
||||
/* Container, traverse it for children */
|
||||
return object_child_foreach(obj, find_sysbus_device, opaque);
|
||||
}
|
||||
|
||||
find->func(sbdev, find->opaque);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all dynamically created sysbus devices and call
|
||||
* func() for each instance.
|
||||
*/
|
||||
void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque)
|
||||
{
|
||||
Object *container;
|
||||
SysBusFind find = {
|
||||
.func = func,
|
||||
.opaque = opaque,
|
||||
};
|
||||
|
||||
/* Loop through all sysbus devices that were spawened outside the machine */
|
||||
container = container_get(qdev_get_machine(), "/peripheral");
|
||||
find_sysbus_device(container, &find);
|
||||
container = container_get(qdev_get_machine(), "/peripheral-anon");
|
||||
find_sysbus_device(container, &find);
|
||||
}
|
||||
|
||||
|
||||
static void system_bus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
BusClass *k = BUS_CLASS(klass);
|
||||
@@ -39,11 +84,38 @@ static const TypeInfo system_bus_info = {
|
||||
.class_init = system_bus_class_init,
|
||||
};
|
||||
|
||||
/* Check whether an IRQ source exists */
|
||||
bool sysbus_has_irq(SysBusDevice *dev, int n)
|
||||
{
|
||||
char *prop = g_strdup_printf("%s[%d]", SYSBUS_DEVICE_GPIO_IRQ, n);
|
||||
ObjectProperty *r;
|
||||
|
||||
r = object_property_find(OBJECT(dev), prop, NULL);
|
||||
return (r != NULL);
|
||||
}
|
||||
|
||||
bool sysbus_is_irq_connected(SysBusDevice *dev, int n)
|
||||
{
|
||||
return !!sysbus_get_connected_irq(dev, n);
|
||||
}
|
||||
|
||||
qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n)
|
||||
{
|
||||
DeviceState *d = DEVICE(dev);
|
||||
return qdev_get_gpio_out_connector(d, SYSBUS_DEVICE_GPIO_IRQ, n);
|
||||
}
|
||||
|
||||
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
|
||||
{
|
||||
qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
|
||||
}
|
||||
|
||||
/* Check whether an MMIO region exists */
|
||||
bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n)
|
||||
{
|
||||
return (n < dev->num_mmio);
|
||||
}
|
||||
|
||||
static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
|
||||
bool may_overlap, int priority)
|
||||
{
|
||||
@@ -238,13 +310,6 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *k = DEVICE_CLASS(klass);
|
||||
k->init = sysbus_device_init;
|
||||
k->bus_type = TYPE_SYSTEM_BUS;
|
||||
/*
|
||||
* device_add plugs devices into suitable bus. For "real" buses,
|
||||
* that actually connects the device. For sysbus, the connections
|
||||
* need to be made separately, and device_add can't do that. The
|
||||
* device would be left unconnected, and could not possibly work.
|
||||
*/
|
||||
k->cannot_instantiate_with_device_add_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo sysbus_device_type_info = {
|
||||
|
||||
@@ -73,11 +73,11 @@ typedef struct ICCBridgeState {
|
||||
MemoryRegion apic_container;
|
||||
} ICCBridgeState;
|
||||
|
||||
#define ICC_BRIGDE(obj) OBJECT_CHECK(ICCBridgeState, (obj), TYPE_ICC_BRIDGE)
|
||||
#define ICC_BRIDGE(obj) OBJECT_CHECK(ICCBridgeState, (obj), TYPE_ICC_BRIDGE)
|
||||
|
||||
static void icc_bridge_init(Object *obj)
|
||||
{
|
||||
ICCBridgeState *s = ICC_BRIGDE(obj);
|
||||
ICCBridgeState *s = ICC_BRIDGE(obj);
|
||||
SysBusDevice *sb = SYS_BUS_DEVICE(obj);
|
||||
|
||||
qbus_create_inplace(&s->icc_bus, sizeof(s->icc_bus), TYPE_ICC_BUS,
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "qemu-common.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/devices.h"
|
||||
#include "vga_int.h"
|
||||
#include "ui/pixel_ops.h"
|
||||
|
||||
typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
|
||||
|
||||
@@ -173,20 +173,6 @@
|
||||
|
||||
#define CIRRUS_PNPMMIO_SIZE 0x1000
|
||||
|
||||
#define BLTUNSAFE(s) \
|
||||
( \
|
||||
( /* check dst is within bounds */ \
|
||||
(s)->cirrus_blt_height * ABS((s)->cirrus_blt_dstpitch) \
|
||||
+ ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \
|
||||
(s)->vga.vram_size \
|
||||
) || \
|
||||
( /* check src is within bounds */ \
|
||||
(s)->cirrus_blt_height * ABS((s)->cirrus_blt_srcpitch) \
|
||||
+ ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \
|
||||
(s)->vga.vram_size \
|
||||
) \
|
||||
)
|
||||
|
||||
struct CirrusVGAState;
|
||||
typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
|
||||
uint8_t * dst, const uint8_t * src,
|
||||
@@ -216,8 +202,6 @@ typedef struct CirrusVGAState {
|
||||
uint32_t cirrus_bank_base[2];
|
||||
uint32_t cirrus_bank_limit[2];
|
||||
uint8_t cirrus_hidden_palette[48];
|
||||
uint32_t hw_cursor_x;
|
||||
uint32_t hw_cursor_y;
|
||||
int cirrus_blt_pixelwidth;
|
||||
int cirrus_blt_width;
|
||||
int cirrus_blt_height;
|
||||
@@ -279,6 +263,50 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
|
||||
*
|
||||
***************************************/
|
||||
|
||||
static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
int32_t pitch, int32_t addr)
|
||||
{
|
||||
if (pitch < 0) {
|
||||
int64_t min = addr
|
||||
+ ((int64_t)s->cirrus_blt_height-1) * pitch;
|
||||
int32_t max = addr
|
||||
+ s->cirrus_blt_width;
|
||||
if (min < 0 || max >= s->vga.vram_size) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int64_t max = addr
|
||||
+ ((int64_t)s->cirrus_blt_height-1) * pitch
|
||||
+ s->cirrus_blt_width;
|
||||
if (max >= s->vga.vram_size) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool blit_is_unsafe(struct CirrusVGAState *s)
|
||||
{
|
||||
/* should be the case, see cirrus_bitblt_start */
|
||||
assert(s->cirrus_blt_width > 0);
|
||||
assert(s->cirrus_blt_height > 0);
|
||||
|
||||
if (s->cirrus_blt_width > CIRRUS_BLTBUFSIZE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
|
||||
s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
|
||||
return true;
|
||||
}
|
||||
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
|
||||
s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
@@ -636,7 +664,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
|
||||
|
||||
dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
|
||||
|
||||
if (BLTUNSAFE(s))
|
||||
if (blit_is_unsafe(s))
|
||||
return 0;
|
||||
|
||||
(*s->cirrus_rop) (s, dst, src,
|
||||
@@ -654,8 +682,9 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||
{
|
||||
cirrus_fill_t rop_func;
|
||||
|
||||
if (BLTUNSAFE(s))
|
||||
if (blit_is_unsafe(s)) {
|
||||
return 0;
|
||||
}
|
||||
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
|
||||
rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
||||
s->cirrus_blt_dstpitch,
|
||||
@@ -752,7 +781,7 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
|
||||
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||
{
|
||||
if (BLTUNSAFE(s))
|
||||
if (blit_is_unsafe(s))
|
||||
return 0;
|
||||
|
||||
cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
|
||||
@@ -1297,7 +1326,7 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
|
||||
case 0xd0:
|
||||
case 0xf0: // Graphics Cursor X
|
||||
s->vga.sr[0x10] = val;
|
||||
s->hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
|
||||
s->vga.hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
|
||||
break;
|
||||
case 0x11:
|
||||
case 0x31:
|
||||
@@ -1308,7 +1337,7 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
|
||||
case 0xd1:
|
||||
case 0xf1: // Graphics Cursor Y
|
||||
s->vga.sr[0x11] = val;
|
||||
s->hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
|
||||
s->vga.hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
|
||||
break;
|
||||
case 0x07: // Extended Sequencer Mode
|
||||
cirrus_update_memory_access(s);
|
||||
@@ -1320,7 +1349,6 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
|
||||
case 0x0d: // VCLK 2
|
||||
case 0x0e: // VCLK 3
|
||||
case 0x0f: // DRAM Control
|
||||
case 0x12: // Graphics Cursor Attribute
|
||||
case 0x13: // Graphics Cursor Pattern Address
|
||||
case 0x14: // Scratch Register 2
|
||||
case 0x15: // Scratch Register 3
|
||||
@@ -1339,6 +1367,14 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
|
||||
s->vga.sr_index, val);
|
||||
#endif
|
||||
break;
|
||||
case 0x12: // Graphics Cursor Attribute
|
||||
s->vga.sr[0x12] = val;
|
||||
s->vga.force_shadow = !!(val & CIRRUS_CURSOR_SHOW);
|
||||
#ifdef DEBUG_CIRRUS
|
||||
printf("cirrus: cursor ctl SR12=%02x (force shadow: %d)\n",
|
||||
val, s->vga.force_shadow);
|
||||
#endif
|
||||
break;
|
||||
case 0x17: // Configuration Readback and Extended Control
|
||||
s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38)
|
||||
| (val & 0xc7);
|
||||
@@ -2157,14 +2193,14 @@ static void cirrus_cursor_invalidate(VGACommonState *s1)
|
||||
}
|
||||
/* invalidate last cursor and new cursor if any change */
|
||||
if (s->last_hw_cursor_size != size ||
|
||||
s->last_hw_cursor_x != s->hw_cursor_x ||
|
||||
s->last_hw_cursor_y != s->hw_cursor_y) {
|
||||
s->last_hw_cursor_x != s->vga.hw_cursor_x ||
|
||||
s->last_hw_cursor_y != s->vga.hw_cursor_y) {
|
||||
|
||||
invalidate_cursor1(s);
|
||||
|
||||
s->last_hw_cursor_size = size;
|
||||
s->last_hw_cursor_x = s->hw_cursor_x;
|
||||
s->last_hw_cursor_y = s->hw_cursor_y;
|
||||
s->last_hw_cursor_x = s->vga.hw_cursor_x;
|
||||
s->last_hw_cursor_y = s->vga.hw_cursor_y;
|
||||
/* compute the real cursor min and max y */
|
||||
cirrus_cursor_compute_yrange(s);
|
||||
invalidate_cursor1(s);
|
||||
@@ -2221,14 +2257,15 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
|
||||
} else {
|
||||
h = 32;
|
||||
}
|
||||
if (scr_y < s->hw_cursor_y ||
|
||||
scr_y >= (s->hw_cursor_y + h))
|
||||
if (scr_y < s->vga.hw_cursor_y ||
|
||||
scr_y >= (s->vga.hw_cursor_y + h)) {
|
||||
return;
|
||||
}
|
||||
|
||||
src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
|
||||
if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
|
||||
src += (s->vga.sr[0x13] & 0x3c) * 256;
|
||||
src += (scr_y - s->hw_cursor_y) * 16;
|
||||
src += (scr_y - s->vga.hw_cursor_y) * 16;
|
||||
poffset = 8;
|
||||
content = ((uint32_t *)src)[0] |
|
||||
((uint32_t *)src)[1] |
|
||||
@@ -2236,7 +2273,7 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
|
||||
((uint32_t *)src)[3];
|
||||
} else {
|
||||
src += (s->vga.sr[0x13] & 0x3f) * 256;
|
||||
src += (scr_y - s->hw_cursor_y) * 4;
|
||||
src += (scr_y - s->vga.hw_cursor_y) * 4;
|
||||
|
||||
|
||||
poffset = 128;
|
||||
@@ -2248,10 +2285,10 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
|
||||
return;
|
||||
w = h;
|
||||
|
||||
x1 = s->hw_cursor_x;
|
||||
x1 = s->vga.hw_cursor_x;
|
||||
if (x1 >= s->vga.last_scr_width)
|
||||
return;
|
||||
x2 = s->hw_cursor_x + w;
|
||||
x2 = s->vga.hw_cursor_x + w;
|
||||
if (x2 > s->vga.last_scr_width)
|
||||
x2 = s->vga.last_scr_width;
|
||||
w = x2 - x1;
|
||||
@@ -2740,8 +2777,8 @@ static const VMStateDescription vmstate_cirrus_vga = {
|
||||
VMSTATE_INT32(vga.bank_offset, CirrusVGAState),
|
||||
VMSTATE_UINT8(cirrus_hidden_dac_lockindex, CirrusVGAState),
|
||||
VMSTATE_UINT8(cirrus_hidden_dac_data, CirrusVGAState),
|
||||
VMSTATE_UINT32(hw_cursor_x, CirrusVGAState),
|
||||
VMSTATE_UINT32(hw_cursor_y, CirrusVGAState),
|
||||
VMSTATE_UINT32(vga.hw_cursor_x, CirrusVGAState),
|
||||
VMSTATE_UINT32(vga.hw_cursor_y, CirrusVGAState),
|
||||
/* XXX: we do not save the bitblt state - we assume we do not save
|
||||
the state when the blitter is active */
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
||||
@@ -283,12 +283,14 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
|
||||
qxl->ssd.mouse_x = cmd->u.set.position.x;
|
||||
qxl->ssd.mouse_y = cmd->u.set.position.y;
|
||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||
qemu_bh_schedule(qxl->ssd.cursor_bh);
|
||||
break;
|
||||
case QXL_CURSOR_MOVE:
|
||||
qemu_mutex_lock(&qxl->ssd.lock);
|
||||
qxl->ssd.mouse_x = cmd->u.position.x;
|
||||
qxl->ssd.mouse_y = cmd->u.position.y;
|
||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||
qemu_bh_schedule(qxl->ssd.cursor_bh);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -1092,6 +1092,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
||||
spice_qxl_driver_unload(&d->ssd.qxl);
|
||||
#endif
|
||||
graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga);
|
||||
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT);
|
||||
qemu_spice_create_host_primary(&d->ssd);
|
||||
d->mode = QXL_MODE_VGA;
|
||||
vga_dirty_log_start(&d->vga);
|
||||
@@ -1105,6 +1106,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
|
||||
}
|
||||
trace_qxl_exit_vga_mode(d->id);
|
||||
graphic_console_set_hwops(d->ssd.dcl.con, &qxl_ops, d);
|
||||
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE);
|
||||
vga_dirty_log_stop(&d->vga);
|
||||
qxl_destroy_primary(d, QXL_SYNC);
|
||||
}
|
||||
@@ -1153,6 +1155,7 @@ static void qxl_soft_reset(PCIQXLDevice *d)
|
||||
qxl_enter_vga_mode(d);
|
||||
} else {
|
||||
d->mode = QXL_MODE_UNDEFINED;
|
||||
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1861,10 +1864,6 @@ static void display_refresh(DisplayChangeListener *dcl)
|
||||
|
||||
if (qxl->mode == QXL_MODE_VGA) {
|
||||
qemu_spice_display_refresh(&qxl->ssd);
|
||||
} else {
|
||||
qemu_mutex_lock(&qxl->ssd.lock);
|
||||
qemu_spice_cursor_refresh_unlocked(&qxl->ssd);
|
||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2025,6 +2024,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
qxl_reset_state(qxl);
|
||||
|
||||
qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl);
|
||||
qxl->ssd.cursor_bh = qemu_bh_new(qemu_spice_cursor_refresh_bh, &qxl->ssd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -321,6 +321,7 @@ static void secondary_class_init(ObjectClass *klass, void *data)
|
||||
dc->vmsd = &vmstate_vga_pci;
|
||||
dc->props = secondary_pci_properties;
|
||||
dc->reset = pci_secondary_vga_reset;
|
||||
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo vga_info = {
|
||||
|
||||
@@ -1436,6 +1436,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
uint8_t *d;
|
||||
uint32_t v, addr1, addr;
|
||||
vga_draw_line_func *vga_draw_line = NULL;
|
||||
bool share_surface;
|
||||
pixman_format_code_t format;
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
bool byteswap = !s->big_endian_fb;
|
||||
#else
|
||||
@@ -1479,21 +1481,42 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
}
|
||||
|
||||
depth = s->get_bpp(s);
|
||||
|
||||
/*
|
||||
* Check whether we can share the surface with the backend
|
||||
* or whether we need a shadow surface. We share native
|
||||
* endian surfaces for 15bpp and above and byteswapped
|
||||
* surfaces for 24bpp and above.
|
||||
*/
|
||||
format = qemu_default_pixman_format(depth, !byteswap);
|
||||
if (format) {
|
||||
share_surface = dpy_gfx_check_format(s->con, format)
|
||||
&& !s->force_shadow;
|
||||
} else {
|
||||
share_surface = false;
|
||||
}
|
||||
if (s->line_offset != s->last_line_offset ||
|
||||
disp_width != s->last_width ||
|
||||
height != s->last_height ||
|
||||
s->last_depth != depth ||
|
||||
s->last_byteswap != byteswap) {
|
||||
if (depth == 32 || (depth == 16 && !byteswap)) {
|
||||
pixman_format_code_t format =
|
||||
qemu_default_pixman_format(depth, !byteswap);
|
||||
s->last_byteswap != byteswap ||
|
||||
share_surface != is_buffer_shared(surface)) {
|
||||
if (share_surface) {
|
||||
surface = qemu_create_displaysurface_from(disp_width,
|
||||
height, format, s->line_offset,
|
||||
s->vram_ptr + (s->start_addr * 4));
|
||||
dpy_gfx_replace_surface(s->con, surface);
|
||||
#ifdef DEBUG_VGA
|
||||
printf("VGA: Using shared surface for depth=%d swap=%d\n",
|
||||
depth, byteswap);
|
||||
#endif
|
||||
} else {
|
||||
qemu_console_resize(s->con, disp_width, height);
|
||||
surface = qemu_console_surface(s->con);
|
||||
#ifdef DEBUG_VGA
|
||||
printf("VGA: Using shadow surface for depth=%d swap=%d\n",
|
||||
depth, byteswap);
|
||||
#endif
|
||||
}
|
||||
s->last_scr_width = disp_width;
|
||||
s->last_scr_height = height;
|
||||
|
||||
@@ -151,6 +151,7 @@ typedef struct VGACommonState {
|
||||
uint32_t last_scr_width, last_scr_height; /* in pixels */
|
||||
uint32_t last_depth; /* in bits */
|
||||
bool last_byteswap;
|
||||
bool force_shadow;
|
||||
uint8_t cursor_start, cursor_end;
|
||||
bool cursor_visible_phase;
|
||||
int64_t cursor_blink_time;
|
||||
@@ -162,6 +163,8 @@ typedef struct VGACommonState {
|
||||
bool default_endian_fb;
|
||||
/* hardware mouse cursor support */
|
||||
uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
|
||||
uint32_t hw_cursor_x;
|
||||
uint32_t hw_cursor_y;
|
||||
void (*cursor_invalidate)(struct VGACommonState *s);
|
||||
void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
|
||||
/* tell for each page if it has been updated since the last time */
|
||||
|
||||
@@ -2,5 +2,6 @@ common-obj-$(CONFIG_MAX7310) += max7310.o
|
||||
common-obj-$(CONFIG_PL061) += pl061.o
|
||||
common-obj-$(CONFIG_PUV3) += puv3_gpio.o
|
||||
common-obj-$(CONFIG_ZAURUS) += zaurus.o
|
||||
common-obj-$(CONFIG_E500) += mpc8xxx.o
|
||||
|
||||
obj-$(CONFIG_OMAP) += omap_gpio.o
|
||||
|
||||
217
hw/gpio/mpc8xxx.c
Normal file
217
hw/gpio/mpc8xxx.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* GPIO Controller for a lot of Freescale SoCs
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Alexander Graf, <agraf@suse.de>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_MPC8XXX_GPIO "mpc8xxx_gpio"
|
||||
#define MPC8XXX_GPIO(obj) OBJECT_CHECK(MPC8XXXGPIOState, (obj), TYPE_MPC8XXX_GPIO)
|
||||
|
||||
typedef struct MPC8XXXGPIOState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
qemu_irq out[32];
|
||||
|
||||
uint32_t dir;
|
||||
uint32_t odr;
|
||||
uint32_t dat;
|
||||
uint32_t ier;
|
||||
uint32_t imr;
|
||||
uint32_t icr;
|
||||
} MPC8XXXGPIOState;
|
||||
|
||||
static const VMStateDescription vmstate_mpc8xxx_gpio = {
|
||||
.name = "mpc8xxx_gpio",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(dir, MPC8XXXGPIOState),
|
||||
VMSTATE_UINT32(odr, MPC8XXXGPIOState),
|
||||
VMSTATE_UINT32(dat, MPC8XXXGPIOState),
|
||||
VMSTATE_UINT32(ier, MPC8XXXGPIOState),
|
||||
VMSTATE_UINT32(imr, MPC8XXXGPIOState),
|
||||
VMSTATE_UINT32(icr, MPC8XXXGPIOState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s)
|
||||
{
|
||||
qemu_set_irq(s->irq, !!(s->ier & s->imr));
|
||||
}
|
||||
|
||||
static uint64_t mpc8xxx_gpio_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
|
||||
|
||||
if (size != 4) {
|
||||
/* All registers are 32bit */
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case 0x0: /* Direction */
|
||||
return s->dir;
|
||||
case 0x4: /* Open Drain */
|
||||
return s->odr;
|
||||
case 0x8: /* Data */
|
||||
return s->dat;
|
||||
case 0xC: /* Interrupt Event */
|
||||
return s->ier;
|
||||
case 0x10: /* Interrupt Mask */
|
||||
return s->imr;
|
||||
case 0x14: /* Interrupt Control */
|
||||
return s->icr;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void mpc8xxx_write_data(MPC8XXXGPIOState *s, uint32_t new_data)
|
||||
{
|
||||
uint32_t old_data = s->dat;
|
||||
uint32_t diff = old_data ^ new_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
uint32_t mask = 0x80000000 >> i;
|
||||
if (!(diff & mask)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->dir & mask) {
|
||||
/* Output */
|
||||
qemu_set_irq(s->out[i], (new_data & mask) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
s->dat = new_data;
|
||||
}
|
||||
|
||||
static void mpc8xxx_gpio_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
|
||||
|
||||
if (size != 4) {
|
||||
/* All registers are 32bit */
|
||||
return;
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case 0x0: /* Direction */
|
||||
s->dir = value;
|
||||
break;
|
||||
case 0x4: /* Open Drain */
|
||||
s->odr = value;
|
||||
break;
|
||||
case 0x8: /* Data */
|
||||
mpc8xxx_write_data(s, value);
|
||||
break;
|
||||
case 0xC: /* Interrupt Event */
|
||||
s->ier &= ~value;
|
||||
break;
|
||||
case 0x10: /* Interrupt Mask */
|
||||
s->imr = value;
|
||||
break;
|
||||
case 0x14: /* Interrupt Control */
|
||||
s->icr = value;
|
||||
break;
|
||||
}
|
||||
|
||||
mpc8xxx_gpio_update(s);
|
||||
}
|
||||
|
||||
static void mpc8xxx_gpio_reset(MPC8XXXGPIOState *s)
|
||||
{
|
||||
s->dir = 0;
|
||||
s->odr = 0;
|
||||
s->dat = 0;
|
||||
s->ier = 0;
|
||||
s->imr = 0;
|
||||
s->icr = 0;
|
||||
}
|
||||
|
||||
static void mpc8xxx_gpio_set_irq(void * opaque, int irq, int level)
|
||||
{
|
||||
MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
|
||||
uint32_t mask;
|
||||
|
||||
mask = 0x80000000 >> irq;
|
||||
if ((s->dir & mask) == 0) {
|
||||
uint32_t old_value = s->dat & mask;
|
||||
|
||||
s->dat &= ~mask;
|
||||
if (level)
|
||||
s->dat |= mask;
|
||||
|
||||
if (!(s->icr & irq) || (old_value && !level)) {
|
||||
s->ier |= mask;
|
||||
}
|
||||
|
||||
mpc8xxx_gpio_update(s);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mpc8xxx_gpio_ops = {
|
||||
.read = mpc8xxx_gpio_read,
|
||||
.write = mpc8xxx_gpio_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static int mpc8xxx_gpio_initfn(SysBusDevice *sbd)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &mpc8xxx_gpio_ops, s, "mpc8xxx_gpio", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32);
|
||||
qdev_init_gpio_out(dev, s->out, 32);
|
||||
mpc8xxx_gpio_reset(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = mpc8xxx_gpio_initfn;
|
||||
dc->vmsd = &vmstate_mpc8xxx_gpio;
|
||||
}
|
||||
|
||||
static const TypeInfo mpc8xxx_gpio_info = {
|
||||
.name = TYPE_MPC8XXX_GPIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MPC8XXXGPIOState),
|
||||
.class_init = mpc8xxx_gpio_class_init,
|
||||
};
|
||||
|
||||
static void mpc8xxx_gpio_register_types(void)
|
||||
{
|
||||
type_register_static(&mpc8xxx_gpio_info);
|
||||
}
|
||||
|
||||
type_init(mpc8xxx_gpio_register_types)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user