Compare commits
592 Commits
pull-usb-2
...
pull-audio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd6c88305f | ||
|
|
105a060188 | ||
|
|
3e890c77cf | ||
|
|
7a87a7b3e4 | ||
|
|
e607784fed | ||
|
|
9bd9d5e357 | ||
|
|
774d566cdb | ||
|
|
2ca92bb993 | ||
|
|
3d2bb5cc81 | ||
|
|
61e8a92364 | ||
|
|
4c0c9bbe78 | ||
|
|
2ea5a2ca1f | ||
|
|
60510aed69 | ||
|
|
e4b998d47d | ||
|
|
dfc15c7ceb | ||
|
|
70d7f984a0 | ||
|
|
13caf1fd2b | ||
|
|
d324b36ad9 | ||
|
|
7900e9f1f9 | ||
|
|
59a1c327d7 | ||
|
|
ea4571eb87 | ||
|
|
c4241c7d38 | ||
|
|
92611c0019 | ||
|
|
00108f2d4d | ||
|
|
fcd252062a | ||
|
|
f59df3f235 | ||
|
|
e508a92b62 | ||
|
|
626187d86b | ||
|
|
1456364ff0 | ||
|
|
99f678a679 | ||
|
|
76e3e1bcae | ||
|
|
83e9a4aec9 | ||
|
|
057d5f62f8 | ||
|
|
67d43538ae | ||
|
|
bc242f9bb6 | ||
|
|
8908f4d185 | ||
|
|
b033cd3d00 | ||
|
|
9f82e0ff4b | ||
|
|
c44ad1fddc | ||
|
|
f5e51e7f10 | ||
|
|
873169022a | ||
|
|
6d093a4f49 | ||
|
|
b15d422a23 | ||
|
|
cef60c925c | ||
|
|
98f9e35bef | ||
|
|
69d4c703a5 | ||
|
|
fff8c539bd | ||
|
|
94783de6fe | ||
|
|
5d59fd998f | ||
|
|
ef3ef4a040 | ||
|
|
e6bf23f82d | ||
|
|
9530570fa5 | ||
|
|
bf15f63cad | ||
|
|
501bb4b0cb | ||
|
|
3a5d30bf27 | ||
|
|
6afafa86f3 | ||
|
|
4fc4732047 | ||
|
|
d6bb65fcd2 | ||
|
|
4f9cc73422 | ||
|
|
cc03ff9d0a | ||
|
|
786ad214c7 | ||
|
|
c348e48175 | ||
|
|
f6969b9fef | ||
|
|
bd93976a1a | ||
|
|
91f32b0c92 | ||
|
|
1094fd3a62 | ||
|
|
b48fa074b5 | ||
|
|
992d3e64c8 | ||
|
|
fca72d9b49 | ||
|
|
77d1c3c63f | ||
|
|
84d18f065f | ||
|
|
ff9ec34de8 | ||
|
|
dde3a21840 | ||
|
|
6399ab3325 | ||
|
|
9d2eec202f | ||
|
|
ecc7e84327 | ||
|
|
a1b29c9ae0 | ||
|
|
189f792dc5 | ||
|
|
464a1441c1 | ||
|
|
e64e958e20 | ||
|
|
e201b56418 | ||
|
|
23ec69ed37 | ||
|
|
c8d7027253 | ||
|
|
f096dc9618 | ||
|
|
3031244b01 | ||
|
|
e46b225a31 | ||
|
|
7a3a00979d | ||
|
|
46eef33b89 | ||
|
|
f6aa2f7dee | ||
|
|
0dbcf95a1e | ||
|
|
078a1c37ca | ||
|
|
44e3a39f30 | ||
|
|
90ce3d76eb | ||
|
|
a50f98b066 | ||
|
|
88c1ee73d3 | ||
|
|
5556332aba | ||
|
|
b33276a7a8 | ||
|
|
24c84e687e | ||
|
|
262471794d | ||
|
|
62dc90c668 | ||
|
|
21684af023 | ||
|
|
3f281822b2 | ||
|
|
c1570e2a1f | ||
|
|
a63e5e0c0d | ||
|
|
e41b509d68 | ||
|
|
85ca1202d1 | ||
|
|
104059da54 | ||
|
|
f31c41ff5e | ||
|
|
c7bcc85d66 | ||
|
|
515f23462b | ||
|
|
dae3bda422 | ||
|
|
0b7593e085 | ||
|
|
98a6528461 | ||
|
|
7ce7ffe027 | ||
|
|
03ff777048 | ||
|
|
9e4d9620c4 | ||
|
|
7d9268647c | ||
|
|
a5829ccfc3 | ||
|
|
23802b4fe0 | ||
|
|
1f9c4cfda4 | ||
|
|
08c9cacf0e | ||
|
|
227d327252 | ||
|
|
a21ac343d1 | ||
|
|
5c57090255 | ||
|
|
371468297c | ||
|
|
76491071b3 | ||
|
|
b815ec5eea | ||
|
|
5297ea6fb8 | ||
|
|
0c5e94ee83 | ||
|
|
dd67fa5052 | ||
|
|
57b6bdf37c | ||
|
|
cc67f4d1f9 | ||
|
|
2aa4a86f59 | ||
|
|
18968ca1a3 | ||
|
|
e001807847 | ||
|
|
39a611a3e0 | ||
|
|
92838a19c1 | ||
|
|
85f68d552b | ||
|
|
74769fe7c8 | ||
|
|
4a053e7f71 | ||
|
|
a21baf7999 | ||
|
|
9fe451a08e | ||
|
|
dd37dfa9e7 | ||
|
|
59ab56b9ad | ||
|
|
933069eb53 | ||
|
|
b8bcf811bf | ||
|
|
b1be45153e | ||
|
|
bc229b0f90 | ||
|
|
a5f96db7e8 | ||
|
|
70b5169032 | ||
|
|
96dca6b9a9 | ||
|
|
a5c828525e | ||
|
|
6749695eaa | ||
|
|
3687d53259 | ||
|
|
bb6c5e3c3a | ||
|
|
5c1904f103 | ||
|
|
5ec889b4b1 | ||
|
|
28f106afb3 | ||
|
|
ee13ed1cbc | ||
|
|
1a838745b8 | ||
|
|
933b19ea97 | ||
|
|
292363e15c | ||
|
|
aaab89a68e | ||
|
|
b3be57c358 | ||
|
|
0888a29caa | ||
|
|
f673e70ccc | ||
|
|
9d74f6fef0 | ||
|
|
628a746cf0 | ||
|
|
5631e69c26 | ||
|
|
a4550442b9 | ||
|
|
2e38847b8d | ||
|
|
2a22165194 | ||
|
|
db3be60deb | ||
|
|
5ce5944dc0 | ||
|
|
2198a12143 | ||
|
|
ab1da85791 | ||
|
|
f606604f1c | ||
|
|
41701aa4ee | ||
|
|
2c17449b30 | ||
|
|
fdfba1a298 | ||
|
|
33bde2e13f | ||
|
|
09daed848c | ||
|
|
c6c6958c98 | ||
|
|
1b3fb98ff0 | ||
|
|
3be91e862a | ||
|
|
777170946f | ||
|
|
29d8ec7bee | ||
|
|
8fa7574904 | ||
|
|
702f6df960 | ||
|
|
a87f39543a | ||
|
|
ea81ce06a4 | ||
|
|
736d120af4 | ||
|
|
b4dd99a363 | ||
|
|
b4160af160 | ||
|
|
e527526d35 | ||
|
|
417c45ab2f | ||
|
|
5e95494380 | ||
|
|
a66e657e18 | ||
|
|
5d268704d7 | ||
|
|
c24d5e0b91 | ||
|
|
2897ae0267 | ||
|
|
5fdae20cef | ||
|
|
1a37eca107 | ||
|
|
0ee4de6ce1 | ||
|
|
9f117d4184 | ||
|
|
a1483f88b6 | ||
|
|
963116b0b3 | ||
|
|
c0f2bf9b3f | ||
|
|
73db416ae7 | ||
|
|
e96126ffa5 | ||
|
|
eaf944a438 | ||
|
|
5f5bcd80f8 | ||
|
|
af91f9a73c | ||
|
|
99c4a85ce6 | ||
|
|
ad6aef43d3 | ||
|
|
693a50ade3 | ||
|
|
7c2bbf4aa6 | ||
|
|
33304ec9fa | ||
|
|
16f0587e0a | ||
|
|
5d259fc7da | ||
|
|
765003db02 | ||
|
|
170632dbc9 | ||
|
|
a19737f1bd | ||
|
|
ecd792fd21 | ||
|
|
1f7bf7d068 | ||
|
|
6542aa9c75 | ||
|
|
f51062061e | ||
|
|
1f6b12f75f | ||
|
|
69991d7dcb | ||
|
|
db7dfd4c7e | ||
|
|
22f90bcb2b | ||
|
|
58892d4782 | ||
|
|
c4e57af852 | ||
|
|
999b53ec87 | ||
|
|
37fd5b53ba | ||
|
|
878a735d00 | ||
|
|
3144f78b3f | ||
|
|
c3dc9fd5ac | ||
|
|
a9d477c4e3 | ||
|
|
a1b1d277cd | ||
|
|
aa7d461ae9 | ||
|
|
40d225009e | ||
|
|
8d999995e4 | ||
|
|
239c20c7c8 | ||
|
|
f93d013895 | ||
|
|
39d8211893 | ||
|
|
d980fd59a4 | ||
|
|
86cbc418ce | ||
|
|
94b6c911c6 | ||
|
|
45aecc6dbb | ||
|
|
effa8e0643 | ||
|
|
c0b2b5fa36 | ||
|
|
3720a7ea36 | ||
|
|
c1de788ab9 | ||
|
|
0173a00521 | ||
|
|
8b12a0cfc1 | ||
|
|
6d9571f7d8 | ||
|
|
3ea3bd6245 | ||
|
|
4db0014521 | ||
|
|
91abb80b5f | ||
|
|
bc1c72171c | ||
|
|
26530780c2 | ||
|
|
31db5b3638 | ||
|
|
e5d3df6deb | ||
|
|
7454e51d2b | ||
|
|
d160024fe5 | ||
|
|
35b307126c | ||
|
|
e358edc8e9 | ||
|
|
a1b4d9eff9 | ||
|
|
99d09dd328 | ||
|
|
a7b613cf68 | ||
|
|
8f5001f9ed | ||
|
|
5a2223ca26 | ||
|
|
f41152bd9d | ||
|
|
667ff9612b | ||
|
|
8c5edce5b7 | ||
|
|
9a59e6e307 | ||
|
|
3dd3a2b965 | ||
|
|
2b2449f7e4 | ||
|
|
34f4aa83f9 | ||
|
|
3604a76fea | ||
|
|
2f45356427 | ||
|
|
02d3bf7fe7 | ||
|
|
b2c623a3d9 | ||
|
|
f40c49ac9f | ||
|
|
e67b3ca53a | ||
|
|
9396b05a5a | ||
|
|
89db9987c0 | ||
|
|
a17b2fd358 | ||
|
|
a5615b14a6 | ||
|
|
905f26f222 | ||
|
|
c91e681a55 | ||
|
|
f6c6483b25 | ||
|
|
f9ee9f9ac2 | ||
|
|
20bcf73fa8 | ||
|
|
7c08db30e6 | ||
|
|
82beb53633 | ||
|
|
c1f412260b | ||
|
|
48a5f3bcbb | ||
|
|
5ef68987e5 | ||
|
|
1c90ef2619 | ||
|
|
7bc3d711b4 | ||
|
|
234cc64796 | ||
|
|
977c7b6d89 | ||
|
|
f0b9b11164 | ||
|
|
2bc65d2b02 | ||
|
|
2a573259eb | ||
|
|
803a932706 | ||
|
|
b73dcfb16f | ||
|
|
7171a3933f | ||
|
|
81e207707e | ||
|
|
56db2e5843 | ||
|
|
1ad3c6abc0 | ||
|
|
41419b0f11 | ||
|
|
cd4eb4c5ac | ||
|
|
50df8d5db0 | ||
|
|
8cfc114a2f | ||
|
|
ce603d8ef1 | ||
|
|
4a6da670f8 | ||
|
|
3065839c72 | ||
|
|
d66433ffdc | ||
|
|
fd5d5afad8 | ||
|
|
8909114649 | ||
|
|
795ca114d3 | ||
|
|
3761abb167 | ||
|
|
f06b85218a | ||
|
|
f8b7ee38b3 | ||
|
|
1a9978a51a | ||
|
|
b9317661d1 | ||
|
|
0e5fc994d2 | ||
|
|
2f61120c10 | ||
|
|
b4a8c9ae97 | ||
|
|
850bbe1b94 | ||
|
|
bd88091cfb | ||
|
|
b76afd1072 | ||
|
|
5eaac2f828 | ||
|
|
d5d1507b34 | ||
|
|
c6830cdb2c | ||
|
|
c428c5a21c | ||
|
|
1165ae613d | ||
|
|
dc9a353cf7 | ||
|
|
1b7650ef2f | ||
|
|
170a60345e | ||
|
|
f50159fa9b | ||
|
|
fb0a078f3a | ||
|
|
f43aa8e18a | ||
|
|
14b4a8b9c6 | ||
|
|
55aff7f133 | ||
|
|
136cd19d05 | ||
|
|
5b0adce156 | ||
|
|
41ab7b5510 | ||
|
|
4d1cef840d | ||
|
|
845ea09acc | ||
|
|
1f8a73af12 | ||
|
|
956d272eb2 | ||
|
|
e1cea1144a | ||
|
|
b305dba6cf | ||
|
|
0ae39320bd | ||
|
|
a08582f41e | ||
|
|
901ad5259f | ||
|
|
c9975a8387 | ||
|
|
34f7b0a276 | ||
|
|
43630e5853 | ||
|
|
2ce7062501 | ||
|
|
4e82bc01ec | ||
|
|
a290c62a75 | ||
|
|
664c6733d7 | ||
|
|
7655f39bde | ||
|
|
9972da669f | ||
|
|
2cdaca90dd | ||
|
|
b48adc0d30 | ||
|
|
51a9b04bd3 | ||
|
|
83bfffec72 | ||
|
|
360a6f2dbd | ||
|
|
f3f8c4f4d2 | ||
|
|
67bb93890d | ||
|
|
4a0ff1ce73 | ||
|
|
5fa5469c08 | ||
|
|
7c51048fa9 | ||
|
|
5c73747f3c | ||
|
|
384b26fb06 | ||
|
|
df54e47d2b | ||
|
|
72430bf5eb | ||
|
|
89e4a51ca9 | ||
|
|
44c68de044 | ||
|
|
0159a64397 | ||
|
|
97374ce538 | ||
|
|
8e02b35926 | ||
|
|
dc08f85188 | ||
|
|
360e607b88 | ||
|
|
0706f7c85b | ||
|
|
18d13fa293 | ||
|
|
056f49ff2c | ||
|
|
57d3e1b3f5 | ||
|
|
269e09f3fc | ||
|
|
90e9cf28e5 | ||
|
|
69252c0467 | ||
|
|
8b6d14087d | ||
|
|
234eef51a1 | ||
|
|
736ec1677f | ||
|
|
05735a2a9c | ||
|
|
b618c28831 | ||
|
|
8a745f2a92 | ||
|
|
1f149e721f | ||
|
|
c444dfabfc | ||
|
|
2ad657e3f3 | ||
|
|
4bf2c138dd | ||
|
|
a75143eda2 | ||
|
|
4e17997d49 | ||
|
|
9a305c8fc7 | ||
|
|
4c8a949b24 | ||
|
|
f30ee8a968 | ||
|
|
306077640a | ||
|
|
b8124cecb5 | ||
|
|
2867534f3d | ||
|
|
e4cf8ed08a | ||
|
|
61a3f63560 | ||
|
|
562e56a9f8 | ||
|
|
1aa149b479 | ||
|
|
4782434f3c | ||
|
|
d6610bc2ad | ||
|
|
81cea5e7f2 | ||
|
|
99fd437dee | ||
|
|
9e047b9824 | ||
|
|
db4728e6fe | ||
|
|
eb0acfdde6 | ||
|
|
4d25299cb2 | ||
|
|
0651596cbe | ||
|
|
69d09245d1 | ||
|
|
a3a74ab90e | ||
|
|
084137ddbb | ||
|
|
4500bc98a6 | ||
|
|
cebc92a213 | ||
|
|
cc8fa0e808 | ||
|
|
9dd6cabdd3 | ||
|
|
9e8458c023 | ||
|
|
c2304b52f1 | ||
|
|
d259793808 | ||
|
|
4dd72e04c2 | ||
|
|
8977557ae4 | ||
|
|
15bce1b7c5 | ||
|
|
3e16d14fd9 | ||
|
|
2d23d5edb5 | ||
|
|
085bb5bb64 | ||
|
|
2a1137753f | ||
|
|
c9d78213b8 | ||
|
|
ba00599cc3 | ||
|
|
0169c51155 | ||
|
|
1c51e68b18 | ||
|
|
7d64b2c2e2 | ||
|
|
14ac4febb2 | ||
|
|
f4b27793a8 | ||
|
|
e9f526ab7b | ||
|
|
0d688cf7d8 | ||
|
|
d5103588aa | ||
|
|
9e1cb96d9a | ||
|
|
cd33d02a10 | ||
|
|
b35ee7fb23 | ||
|
|
2c9880c45e | ||
|
|
8407d5d7e2 | ||
|
|
a3ef657185 | ||
|
|
775aa8b6e0 | ||
|
|
28de2dcd88 | ||
|
|
3b8242e0ea | ||
|
|
6460440f34 | ||
|
|
7327145f63 | ||
|
|
2dbafdc012 | ||
|
|
ec746e10cb | ||
|
|
65afd211c7 | ||
|
|
793ed47a7a | ||
|
|
6601553e27 | ||
|
|
244eadef5c | ||
|
|
b404f72036 | ||
|
|
1b0288ae7f | ||
|
|
d0c7f642f5 | ||
|
|
c25f53b06e | ||
|
|
1b7fd72955 | ||
|
|
339064d506 | ||
|
|
1ff735bdc4 | ||
|
|
e5354657a6 | ||
|
|
355ef4ac95 | ||
|
|
466ad822de | ||
|
|
d34682cd4a | ||
|
|
dabfa6cc2e | ||
|
|
3722290074 | ||
|
|
4da8358596 | ||
|
|
72706ea4cd | ||
|
|
031fd1be56 | ||
|
|
0901f67ecd | ||
|
|
3b1dbd11a6 | ||
|
|
212a5a8f09 | ||
|
|
12d3ba821d | ||
|
|
c13163fba1 | ||
|
|
6913c0c2ce | ||
|
|
dc364f4cdc | ||
|
|
c8059b97e1 | ||
|
|
d8a7b061ae | ||
|
|
6df3bf8eb3 | ||
|
|
9cd767376f | ||
|
|
0e3bd9932f | ||
|
|
3c4b4e383e | ||
|
|
e69968d472 | ||
|
|
34ceed81f9 | ||
|
|
46bae92713 | ||
|
|
385c04d0b6 | ||
|
|
d80ac658f2 | ||
|
|
91f84f652d | ||
|
|
30bd6a4daf | ||
|
|
3fb11779ca | ||
|
|
be331341a1 | ||
|
|
fd0fee34b5 | ||
|
|
1bf20b8280 | ||
|
|
8592a545b6 | ||
|
|
22511ad681 | ||
|
|
70b6198acc | ||
|
|
4373593d51 | ||
|
|
d095b46533 | ||
|
|
505d758334 | ||
|
|
054963f8f0 | ||
|
|
da557aac18 | ||
|
|
2a05cbe426 | ||
|
|
2258e3fe20 | ||
|
|
72daa72eee | ||
|
|
89f2b21e36 | ||
|
|
85a040e548 | ||
|
|
adf5c449e5 | ||
|
|
9f23fc0c23 | ||
|
|
05a8c22271 | ||
|
|
d4881b9bcb | ||
|
|
466b49f276 | ||
|
|
4694020d3c | ||
|
|
0cf17e1817 | ||
|
|
13401ba0b9 | ||
|
|
0150cd81cf | ||
|
|
c60bf3391b | ||
|
|
585ea0c841 | ||
|
|
7fa9e1f941 | ||
|
|
b7fcff0179 | ||
|
|
9f23fce7b2 | ||
|
|
cf7f616b9d | ||
|
|
7c815372f3 | ||
|
|
15744b0b8f | ||
|
|
92397116a6 | ||
|
|
487c191002 | ||
|
|
d2329f27c9 | ||
|
|
2c77f52e39 | ||
|
|
e04fb07fd1 | ||
|
|
492044581c | ||
|
|
8cc3aecf84 | ||
|
|
5f04c14a10 | ||
|
|
2777ccc55b | ||
|
|
439d19f292 | ||
|
|
918b94e287 | ||
|
|
0c2acb163f | ||
|
|
39e6a38cdd | ||
|
|
8d7b5a1da0 | ||
|
|
47c16ed56a | ||
|
|
794798e36e | ||
|
|
fc33b9004c | ||
|
|
0193c62c94 | ||
|
|
732c66ce64 | ||
|
|
3dbe85b840 | ||
|
|
87ca1f77b1 | ||
|
|
d3a2fd9b29 | ||
|
|
1cb27d9233 | ||
|
|
2c02d1ad48 | ||
|
|
3babcc8704 | ||
|
|
a39ca6a124 | ||
|
|
fe54b24930 | ||
|
|
19a894ba77 | ||
|
|
850484a295 | ||
|
|
e6baf6130e | ||
|
|
fb3ecb7ea4 | ||
|
|
bf2eaf718e | ||
|
|
dc9fc1cac5 | ||
|
|
7af6f46c61 | ||
|
|
e638073c56 | ||
|
|
d20b43dfea | ||
|
|
7c4228b477 | ||
|
|
584f2be79d | ||
|
|
94ccff1338 | ||
|
|
dc6afb99b3 | ||
|
|
49fb65c7f9 | ||
|
|
e9c0f0f58a | ||
|
|
33325a53f1 | ||
|
|
fbb9c590ca | ||
|
|
2ba8285289 | ||
|
|
6bdf863d94 | ||
|
|
a94b36ddd6 | ||
|
|
0522604b09 | ||
|
|
f86746c263 | ||
|
|
79e9ebebbf |
152
.gitignore
vendored
152
.gitignore
vendored
@@ -1,64 +1,66 @@
|
|||||||
config-devices.*
|
/config-devices.*
|
||||||
config-all-devices.*
|
/config-all-devices.*
|
||||||
config-all-disas.*
|
/config-all-disas.*
|
||||||
config-host.*
|
/config-host.*
|
||||||
config-target.*
|
/config-target.*
|
||||||
config.status
|
/config.status
|
||||||
trace/generated-tracers.h
|
/trace/generated-tracers.h
|
||||||
trace/generated-tracers.c
|
/trace/generated-tracers.c
|
||||||
trace/generated-tracers-dtrace.h
|
/trace/generated-tracers-dtrace.h
|
||||||
trace/generated-tracers.dtrace
|
/trace/generated-tracers.dtrace
|
||||||
trace/generated-events.h
|
/trace/generated-events.h
|
||||||
trace/generated-events.c
|
/trace/generated-events.c
|
||||||
libcacard/trace/generated-tracers.c
|
/trace/generated-ust-provider.h
|
||||||
|
/trace/generated-ust.c
|
||||||
|
/libcacard/trace/generated-tracers.c
|
||||||
*-timestamp
|
*-timestamp
|
||||||
*-softmmu
|
/*-softmmu
|
||||||
*-darwin-user
|
/*-darwin-user
|
||||||
*-linux-user
|
/*-linux-user
|
||||||
*-bsd-user
|
/*-bsd-user
|
||||||
libdis*
|
libdis*
|
||||||
libuser
|
libuser
|
||||||
linux-headers/asm
|
/linux-headers/asm
|
||||||
qapi-generated
|
/qapi-generated
|
||||||
qapi-types.[ch]
|
/qapi-types.[ch]
|
||||||
qapi-visit.[ch]
|
/qapi-visit.[ch]
|
||||||
qmp-commands.h
|
/qmp-commands.h
|
||||||
qmp-marshal.c
|
/qmp-marshal.c
|
||||||
qemu-doc.html
|
/qemu-doc.html
|
||||||
qemu-tech.html
|
/qemu-tech.html
|
||||||
qemu-doc.info
|
/qemu-doc.info
|
||||||
qemu-tech.info
|
/qemu-tech.info
|
||||||
qemu.1
|
/qemu.1
|
||||||
qemu.pod
|
/qemu.pod
|
||||||
qemu-img.1
|
/qemu-img.1
|
||||||
qemu-img.pod
|
/qemu-img.pod
|
||||||
qemu-img
|
/qemu-img
|
||||||
qemu-nbd
|
/qemu-nbd
|
||||||
qemu-nbd.8
|
/qemu-nbd.8
|
||||||
qemu-nbd.pod
|
/qemu-nbd.pod
|
||||||
qemu-options.def
|
/qemu-options.def
|
||||||
qemu-options.texi
|
/qemu-options.texi
|
||||||
qemu-img-cmds.texi
|
/qemu-img-cmds.texi
|
||||||
qemu-img-cmds.h
|
/qemu-img-cmds.h
|
||||||
qemu-io
|
/qemu-io
|
||||||
qemu-ga
|
/qemu-ga
|
||||||
qemu-bridge-helper
|
/qemu-bridge-helper
|
||||||
qemu-monitor.texi
|
/qemu-monitor.texi
|
||||||
vscclient
|
/qmp-commands.txt
|
||||||
qmp-commands.txt
|
/vscclient
|
||||||
test-bitops
|
/test-bitops
|
||||||
test-coroutine
|
/test-coroutine
|
||||||
test-int128
|
/test-int128
|
||||||
test-opts-visitor
|
/test-opts-visitor
|
||||||
test-qmp-input-visitor
|
/test-qmp-input-visitor
|
||||||
test-qmp-output-visitor
|
/test-qmp-output-visitor
|
||||||
test-string-input-visitor
|
/test-string-input-visitor
|
||||||
test-string-output-visitor
|
/test-string-output-visitor
|
||||||
test-visitor-serialization
|
/test-visitor-serialization
|
||||||
fsdev/virtfs-proxy-helper
|
/fsdev/virtfs-proxy-helper
|
||||||
fsdev/virtfs-proxy-helper.1
|
/fsdev/virtfs-proxy-helper.1
|
||||||
fsdev/virtfs-proxy-helper.pod
|
/fsdev/virtfs-proxy-helper.pod
|
||||||
.gdbinit
|
/.gdbinit
|
||||||
*.a
|
*.a
|
||||||
*.aux
|
*.aux
|
||||||
*.cp
|
*.cp
|
||||||
@@ -77,7 +79,7 @@ fsdev/virtfs-proxy-helper.pod
|
|||||||
*.tp
|
*.tp
|
||||||
*.vr
|
*.vr
|
||||||
*.d
|
*.d
|
||||||
!scripts/qemu-guest-agent/fsfreeze-hook.d
|
!/scripts/qemu-guest-agent/fsfreeze-hook.d
|
||||||
*.o
|
*.o
|
||||||
*.lo
|
*.lo
|
||||||
*.la
|
*.la
|
||||||
@@ -90,22 +92,22 @@ fsdev/virtfs-proxy-helper.pod
|
|||||||
*.gcda
|
*.gcda
|
||||||
*.gcno
|
*.gcno
|
||||||
patches
|
patches
|
||||||
pc-bios/bios-pq/status
|
/pc-bios/bios-pq/status
|
||||||
pc-bios/vgabios-pq/status
|
/pc-bios/vgabios-pq/status
|
||||||
pc-bios/optionrom/linuxboot.asm
|
/pc-bios/optionrom/linuxboot.asm
|
||||||
pc-bios/optionrom/linuxboot.bin
|
/pc-bios/optionrom/linuxboot.bin
|
||||||
pc-bios/optionrom/linuxboot.raw
|
/pc-bios/optionrom/linuxboot.raw
|
||||||
pc-bios/optionrom/linuxboot.img
|
/pc-bios/optionrom/linuxboot.img
|
||||||
pc-bios/optionrom/multiboot.asm
|
/pc-bios/optionrom/multiboot.asm
|
||||||
pc-bios/optionrom/multiboot.bin
|
/pc-bios/optionrom/multiboot.bin
|
||||||
pc-bios/optionrom/multiboot.raw
|
/pc-bios/optionrom/multiboot.raw
|
||||||
pc-bios/optionrom/multiboot.img
|
/pc-bios/optionrom/multiboot.img
|
||||||
pc-bios/optionrom/kvmvapic.asm
|
/pc-bios/optionrom/kvmvapic.asm
|
||||||
pc-bios/optionrom/kvmvapic.bin
|
/pc-bios/optionrom/kvmvapic.bin
|
||||||
pc-bios/optionrom/kvmvapic.raw
|
/pc-bios/optionrom/kvmvapic.raw
|
||||||
pc-bios/optionrom/kvmvapic.img
|
/pc-bios/optionrom/kvmvapic.img
|
||||||
pc-bios/s390-ccw/s390-ccw.elf
|
/pc-bios/s390-ccw/s390-ccw.elf
|
||||||
pc-bios/s390-ccw/s390-ccw.img
|
/pc-bios/s390-ccw/s390-ccw.img
|
||||||
.stgit-*
|
.stgit-*
|
||||||
cscope.*
|
cscope.*
|
||||||
tags
|
tags
|
||||||
|
|||||||
@@ -610,6 +610,7 @@ F: hw/*/*vhost*
|
|||||||
|
|
||||||
virtio
|
virtio
|
||||||
M: Anthony Liguori <aliguori@amazon.com>
|
M: Anthony Liguori <aliguori@amazon.com>
|
||||||
|
M: Michael S. Tsirkin <mst@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: hw/*/virtio*
|
F: hw/*/virtio*
|
||||||
|
|
||||||
@@ -936,6 +937,11 @@ M: Peter Lieven <pl@kamp.de>
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: block/iscsi.c
|
F: block/iscsi.c
|
||||||
|
|
||||||
|
NFS
|
||||||
|
M: Peter Lieven <pl@kamp.de>
|
||||||
|
S: Maintained
|
||||||
|
F: block/nfs.c
|
||||||
|
|
||||||
SSH
|
SSH
|
||||||
M: Richard W.M. Jones <rjones@redhat.com>
|
M: Richard W.M. Jones <rjones@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -57,6 +57,11 @@ GENERATED_HEADERS += trace/generated-tracers-dtrace.h
|
|||||||
endif
|
endif
|
||||||
GENERATED_SOURCES += trace/generated-tracers.c
|
GENERATED_SOURCES += trace/generated-tracers.c
|
||||||
|
|
||||||
|
ifeq ($(TRACE_BACKEND),ust)
|
||||||
|
GENERATED_HEADERS += trace/generated-ust-provider.h
|
||||||
|
GENERATED_SOURCES += trace/generated-ust.c
|
||||||
|
endif
|
||||||
|
|
||||||
# Don't try to regenerate Makefile or configure
|
# Don't try to regenerate Makefile or configure
|
||||||
# We don't generate any of them
|
# We don't generate any of them
|
||||||
Makefile: ;
|
Makefile: ;
|
||||||
@@ -290,7 +295,7 @@ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr \
|
|||||||
bepo cz
|
bepo cz
|
||||||
|
|
||||||
ifdef INSTALL_BLOBS
|
ifdef INSTALL_BLOBS
|
||||||
BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
|
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
|
||||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
|
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
|
||||||
acpi-dsdt.aml q35-acpi-dsdt.aml \
|
acpi-dsdt.aml q35-acpi-dsdt.aml \
|
||||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \
|
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ libcacard-y += libcacard/vcardt.o
|
|||||||
ifeq ($(CONFIG_SOFTMMU),y)
|
ifeq ($(CONFIG_SOFTMMU),y)
|
||||||
common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
|
common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
|
||||||
common-obj-y += net/
|
common-obj-y += net/
|
||||||
common-obj-y += readline.o
|
|
||||||
common-obj-y += qdev-monitor.o device-hotplug.o
|
common-obj-y += qdev-monitor.o device-hotplug.o
|
||||||
common-obj-$(CONFIG_WIN32) += os-win32.o
|
common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||||
common-obj-$(CONFIG_POSIX) += os-posix.o
|
common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||||
|
|||||||
49
arch_init.c
49
arch_init.c
@@ -164,20 +164,22 @@ static struct {
|
|||||||
uint8_t *encoded_buf;
|
uint8_t *encoded_buf;
|
||||||
/* buffer for storing page content */
|
/* buffer for storing page content */
|
||||||
uint8_t *current_buf;
|
uint8_t *current_buf;
|
||||||
/* buffer used for XBZRLE decoding */
|
|
||||||
uint8_t *decoded_buf;
|
|
||||||
/* Cache for XBZRLE */
|
/* Cache for XBZRLE */
|
||||||
PageCache *cache;
|
PageCache *cache;
|
||||||
} XBZRLE = {
|
} XBZRLE = {
|
||||||
.encoded_buf = NULL,
|
.encoded_buf = NULL,
|
||||||
.current_buf = NULL,
|
.current_buf = NULL,
|
||||||
.decoded_buf = NULL,
|
|
||||||
.cache = NULL,
|
.cache = NULL,
|
||||||
};
|
};
|
||||||
|
/* buffer used for XBZRLE decoding */
|
||||||
|
static uint8_t *xbzrle_decoded_buf;
|
||||||
|
|
||||||
int64_t xbzrle_cache_resize(int64_t new_size)
|
int64_t xbzrle_cache_resize(int64_t new_size)
|
||||||
{
|
{
|
||||||
|
if (new_size < TARGET_PAGE_SIZE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (XBZRLE.cache != NULL) {
|
if (XBZRLE.cache != NULL) {
|
||||||
return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) *
|
return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) *
|
||||||
TARGET_PAGE_SIZE;
|
TARGET_PAGE_SIZE;
|
||||||
@@ -282,7 +284,9 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
|||||||
|
|
||||||
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
|
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
|
||||||
if (!last_stage) {
|
if (!last_stage) {
|
||||||
cache_insert(XBZRLE.cache, current_addr, current_data);
|
if (cache_insert(XBZRLE.cache, current_addr, current_data) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
acct_info.xbzrle_cache_miss++;
|
acct_info.xbzrle_cache_miss++;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -602,6 +606,12 @@ uint64_t ram_bytes_total(void)
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void free_xbzrle_decoded_buf(void)
|
||||||
|
{
|
||||||
|
g_free(xbzrle_decoded_buf);
|
||||||
|
xbzrle_decoded_buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void migration_end(void)
|
static void migration_end(void)
|
||||||
{
|
{
|
||||||
if (migration_bitmap) {
|
if (migration_bitmap) {
|
||||||
@@ -615,8 +625,9 @@ static void migration_end(void)
|
|||||||
g_free(XBZRLE.cache);
|
g_free(XBZRLE.cache);
|
||||||
g_free(XBZRLE.encoded_buf);
|
g_free(XBZRLE.encoded_buf);
|
||||||
g_free(XBZRLE.current_buf);
|
g_free(XBZRLE.current_buf);
|
||||||
g_free(XBZRLE.decoded_buf);
|
|
||||||
XBZRLE.cache = NULL;
|
XBZRLE.cache = NULL;
|
||||||
|
XBZRLE.encoded_buf = NULL;
|
||||||
|
XBZRLE.current_buf = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,8 +666,22 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
|||||||
DPRINTF("Error creating cache\n");
|
DPRINTF("Error creating cache\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
XBZRLE.encoded_buf = g_malloc0(TARGET_PAGE_SIZE);
|
|
||||||
XBZRLE.current_buf = g_malloc(TARGET_PAGE_SIZE);
|
/* We prefer not to abort if there is no memory */
|
||||||
|
XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE);
|
||||||
|
if (!XBZRLE.encoded_buf) {
|
||||||
|
DPRINTF("Error allocating encoded_buf\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE);
|
||||||
|
if (!XBZRLE.current_buf) {
|
||||||
|
DPRINTF("Error allocating current_buf\n");
|
||||||
|
g_free(XBZRLE.encoded_buf);
|
||||||
|
XBZRLE.encoded_buf = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
acct_clear();
|
acct_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,8 +832,8 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
|||||||
unsigned int xh_len;
|
unsigned int xh_len;
|
||||||
int xh_flags;
|
int xh_flags;
|
||||||
|
|
||||||
if (!XBZRLE.decoded_buf) {
|
if (!xbzrle_decoded_buf) {
|
||||||
XBZRLE.decoded_buf = g_malloc(TARGET_PAGE_SIZE);
|
xbzrle_decoded_buf = g_malloc(TARGET_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract RLE header */
|
/* extract RLE header */
|
||||||
@@ -825,10 +850,10 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* load data and decode */
|
/* load data and decode */
|
||||||
qemu_get_buffer(f, XBZRLE.decoded_buf, xh_len);
|
qemu_get_buffer(f, xbzrle_decoded_buf, xh_len);
|
||||||
|
|
||||||
/* decode RLE */
|
/* decode RLE */
|
||||||
ret = xbzrle_decode_buffer(XBZRLE.decoded_buf, xh_len, host,
|
ret = xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
|
||||||
TARGET_PAGE_SIZE);
|
TARGET_PAGE_SIZE);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
|
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
|
||||||
|
|||||||
@@ -25,8 +25,17 @@
|
|||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
|
|
||||||
#define LINE_IN_SAMPLES 1024
|
#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
|
||||||
#define LINE_OUT_SAMPLES 1024
|
#define LINE_OUT_SAMPLES (480 * 4)
|
||||||
|
#else
|
||||||
|
#define LINE_OUT_SAMPLES (256 * 4)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
|
||||||
|
#define LINE_IN_SAMPLES (480 * 4)
|
||||||
|
#else
|
||||||
|
#define LINE_IN_SAMPLES (256 * 4)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct SpiceRateCtl {
|
typedef struct SpiceRateCtl {
|
||||||
int64_t start_ticks;
|
int64_t start_ticks;
|
||||||
@@ -111,7 +120,11 @@ static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
|
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
|
||||||
struct audsettings settings;
|
struct audsettings settings;
|
||||||
|
|
||||||
|
#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
|
||||||
|
settings.freq = spice_server_get_best_playback_rate(NULL);
|
||||||
|
#else
|
||||||
settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ;
|
settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ;
|
||||||
|
#endif
|
||||||
settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN;
|
settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN;
|
||||||
settings.fmt = AUD_FMT_S16;
|
settings.fmt = AUD_FMT_S16;
|
||||||
settings.endianness = AUDIO_HOST_ENDIANNESS;
|
settings.endianness = AUDIO_HOST_ENDIANNESS;
|
||||||
@@ -122,6 +135,9 @@ static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
|
|||||||
|
|
||||||
out->sin.base.sif = &playback_sif.base;
|
out->sin.base.sif = &playback_sif.base;
|
||||||
qemu_spice_add_interface (&out->sin.base);
|
qemu_spice_add_interface (&out->sin.base);
|
||||||
|
#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
|
||||||
|
spice_server_set_playback_rate(&out->sin, settings.freq);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +248,11 @@ static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
|
|||||||
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
|
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
|
||||||
struct audsettings settings;
|
struct audsettings settings;
|
||||||
|
|
||||||
|
#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
|
||||||
|
settings.freq = spice_server_get_best_record_rate(NULL);
|
||||||
|
#else
|
||||||
settings.freq = SPICE_INTERFACE_RECORD_FREQ;
|
settings.freq = SPICE_INTERFACE_RECORD_FREQ;
|
||||||
|
#endif
|
||||||
settings.nchannels = SPICE_INTERFACE_RECORD_CHAN;
|
settings.nchannels = SPICE_INTERFACE_RECORD_CHAN;
|
||||||
settings.fmt = AUD_FMT_S16;
|
settings.fmt = AUD_FMT_S16;
|
||||||
settings.endianness = AUDIO_HOST_ENDIANNESS;
|
settings.endianness = AUDIO_HOST_ENDIANNESS;
|
||||||
@@ -243,6 +263,9 @@ static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
|
|||||||
|
|
||||||
in->sin.base.sif = &record_sif.base;
|
in->sin.base.sif = &record_sif.base;
|
||||||
qemu_spice_add_interface (&in->sin.base);
|
qemu_spice_add_interface (&in->sin.base);
|
||||||
|
#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
|
||||||
|
spice_server_set_record_rate(&in->sin, settings.freq);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "sysemu/rng.h"
|
#include "sysemu/rng.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
|
#include "qom/object_interfaces.h"
|
||||||
|
|
||||||
void rng_backend_request_entropy(RngBackend *s, size_t size,
|
void rng_backend_request_entropy(RngBackend *s, size_t size,
|
||||||
EntropyReceiveFunc *receive_entropy,
|
EntropyReceiveFunc *receive_entropy,
|
||||||
@@ -40,9 +41,9 @@ static bool rng_backend_prop_get_opened(Object *obj, Error **errp)
|
|||||||
return s->opened;
|
return s->opened;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rng_backend_open(RngBackend *s, Error **errp)
|
static void rng_backend_complete(UserCreatable *uc, Error **errp)
|
||||||
{
|
{
|
||||||
object_property_set_bool(OBJECT(s), true, "opened", errp);
|
object_property_set_bool(OBJECT(uc), true, "opened", errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
||||||
@@ -76,13 +77,25 @@ static void rng_backend_init(Object *obj)
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rng_backend_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||||
|
|
||||||
|
ucc->complete = rng_backend_complete;
|
||||||
|
}
|
||||||
|
|
||||||
static const TypeInfo rng_backend_info = {
|
static const TypeInfo rng_backend_info = {
|
||||||
.name = TYPE_RNG_BACKEND,
|
.name = TYPE_RNG_BACKEND,
|
||||||
.parent = TYPE_OBJECT,
|
.parent = TYPE_OBJECT,
|
||||||
.instance_size = sizeof(RngBackend),
|
.instance_size = sizeof(RngBackend),
|
||||||
.instance_init = rng_backend_init,
|
.instance_init = rng_backend_init,
|
||||||
.class_size = sizeof(RngBackendClass),
|
.class_size = sizeof(RngBackendClass),
|
||||||
|
.class_init = rng_backend_class_init,
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
|
{ TYPE_USER_CREATABLE },
|
||||||
|
{ }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
|||||||
ifeq ($(CONFIG_POSIX),y)
|
ifeq ($(CONFIG_POSIX),y)
|
||||||
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
||||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||||
|
block-obj-$(CONFIG_LIBNFS) += nfs.o
|
||||||
block-obj-$(CONFIG_CURL) += curl.o
|
block-obj-$(CONFIG_CURL) += curl.o
|
||||||
block-obj-$(CONFIG_RBD) += rbd.o
|
block-obj-$(CONFIG_RBD) += rbd.o
|
||||||
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
|
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
|
||||||
|
|||||||
@@ -181,8 +181,13 @@ static int coroutine_fn backup_before_write_notify(
|
|||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
BdrvTrackedRequest *req = opaque;
|
BdrvTrackedRequest *req = opaque;
|
||||||
|
int64_t sector_num = req->offset >> BDRV_SECTOR_BITS;
|
||||||
|
int nb_sectors = req->bytes >> BDRV_SECTOR_BITS;
|
||||||
|
|
||||||
return backup_do_cow(req->bs, req->sector_num, req->nb_sectors, NULL);
|
assert((req->offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||||
|
assert((req->bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||||
|
|
||||||
|
return backup_do_cow(req->bs, sector_num, nb_sectors, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||||
|
|||||||
@@ -186,6 +186,14 @@ static const char *event_names[BLKDBG_EVENT_MAX] = {
|
|||||||
|
|
||||||
[BLKDBG_FLUSH_TO_OS] = "flush_to_os",
|
[BLKDBG_FLUSH_TO_OS] = "flush_to_os",
|
||||||
[BLKDBG_FLUSH_TO_DISK] = "flush_to_disk",
|
[BLKDBG_FLUSH_TO_DISK] = "flush_to_disk",
|
||||||
|
|
||||||
|
[BLKDBG_PWRITEV_RMW_HEAD] = "pwritev_rmw.head",
|
||||||
|
[BLKDBG_PWRITEV_RMW_AFTER_HEAD] = "pwritev_rmw.after_head",
|
||||||
|
[BLKDBG_PWRITEV_RMW_TAIL] = "pwritev_rmw.tail",
|
||||||
|
[BLKDBG_PWRITEV_RMW_AFTER_TAIL] = "pwritev_rmw.after_tail",
|
||||||
|
[BLKDBG_PWRITEV] = "pwritev",
|
||||||
|
[BLKDBG_PWRITEV_ZERO] = "pwritev_zero",
|
||||||
|
[BLKDBG_PWRITEV_DONE] = "pwritev_done",
|
||||||
};
|
};
|
||||||
|
|
||||||
static int get_event_by_name(const char *name, BlkDebugEvent *event)
|
static int get_event_by_name(const char *name, BlkDebugEvent *event)
|
||||||
@@ -271,19 +279,33 @@ static void remove_rule(BlkdebugRule *rule)
|
|||||||
g_free(rule);
|
g_free(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_config(BDRVBlkdebugState *s, const char *filename)
|
static int read_config(BDRVBlkdebugState *s, const char *filename,
|
||||||
|
QDict *options, Error **errp)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
struct add_rule_data d;
|
struct add_rule_data d;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
f = fopen(filename, "r");
|
if (filename) {
|
||||||
if (f == NULL) {
|
f = fopen(filename, "r");
|
||||||
return -errno;
|
if (f == NULL) {
|
||||||
|
error_setg_errno(errp, errno, "Could not read blkdebug config file");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qemu_config_parse(f, config_groups, filename);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Could not parse blkdebug config file");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qemu_config_parse(f, config_groups, filename);
|
qemu_config_parse_qdict(options, config_groups, &local_err);
|
||||||
if (ret < 0) {
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +320,9 @@ static int read_config(BDRVBlkdebugState *s, const char *filename)
|
|||||||
fail:
|
fail:
|
||||||
qemu_opts_reset(&inject_error_opts);
|
qemu_opts_reset(&inject_error_opts);
|
||||||
qemu_opts_reset(&set_state_opts);
|
qemu_opts_reset(&set_state_opts);
|
||||||
fclose(f);
|
if (f) {
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +334,9 @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
|
|||||||
|
|
||||||
/* Parse the blkdebug: prefix */
|
/* Parse the blkdebug: prefix */
|
||||||
if (!strstart(filename, "blkdebug:", &filename)) {
|
if (!strstart(filename, "blkdebug:", &filename)) {
|
||||||
error_setg(errp, "File name string must start with 'blkdebug:'");
|
/* There was no prefix; therefore, all options have to be already
|
||||||
|
present in the QDict (except for the filename) */
|
||||||
|
qdict_put(options, "x-image", qstring_from_str(filename));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,6 +372,11 @@ static QemuOptsList runtime_opts = {
|
|||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "[internal use only, will be removed]",
|
.help = "[internal use only, will be removed]",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "align",
|
||||||
|
.type = QEMU_OPT_SIZE,
|
||||||
|
.help = "Required alignment in bytes",
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -356,46 +387,52 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
BDRVBlkdebugState *s = bs->opaque;
|
BDRVBlkdebugState *s = bs->opaque;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename, *config;
|
const char *config;
|
||||||
|
uint64_t align;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read rules from config file */
|
/* Read rules from config file or command line options */
|
||||||
config = qemu_opt_get(opts, "config");
|
config = qemu_opt_get(opts, "config");
|
||||||
if (config) {
|
ret = read_config(s, config, options, errp);
|
||||||
ret = read_config(s, config);
|
if (ret) {
|
||||||
if (ret < 0) {
|
goto out;
|
||||||
error_setg_errno(errp, -ret, "Could not read blkdebug config file");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set initial state */
|
/* Set initial state */
|
||||||
s->state = 1;
|
s->state = 1;
|
||||||
|
|
||||||
/* Open the backing file */
|
/* Open the backing file */
|
||||||
filename = qemu_opt_get(opts, "x-image");
|
ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
|
||||||
if (filename == NULL) {
|
flags, true, false, &local_err);
|
||||||
error_setg(errp, "Could not retrieve image file name");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs->file, filename, NULL, flags, &local_err);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto fail;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set request alignment */
|
||||||
|
align = qemu_opt_get_size(opts, "align", bs->request_alignment);
|
||||||
|
if (align > 0 && align < INT_MAX && !(align & (align - 1))) {
|
||||||
|
bs->request_alignment = align;
|
||||||
|
} else {
|
||||||
|
error_setg(errp, "Invalid alignment");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail_unref;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
goto out;
|
||||||
|
|
||||||
|
fail_unref:
|
||||||
|
bdrv_unref(bs->file);
|
||||||
|
out:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,9 @@ static void blkverify_parse_filename(const char *filename, QDict *options,
|
|||||||
|
|
||||||
/* Parse the blkverify: prefix */
|
/* Parse the blkverify: prefix */
|
||||||
if (!strstart(filename, "blkverify:", &filename)) {
|
if (!strstart(filename, "blkverify:", &filename)) {
|
||||||
error_setg(errp, "File name string must start with 'blkverify:'");
|
/* There was no prefix; therefore, all options have to be already
|
||||||
|
present in the QDict (except for the filename) */
|
||||||
|
qdict_put(options, "x-image", qstring_from_str(filename));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,44 +124,29 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
BDRVBlkverifyState *s = bs->opaque;
|
BDRVBlkverifyState *s = bs->opaque;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename, *raw;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the raw image filename */
|
/* Open the raw file */
|
||||||
raw = qemu_opt_get(opts, "x-raw");
|
ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options,
|
||||||
if (raw == NULL) {
|
"raw", flags, true, false, &local_err);
|
||||||
error_setg(errp, "Could not retrieve raw image filename");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs->file, raw, NULL, flags, &local_err);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open the test file */
|
/* Open the test file */
|
||||||
filename = qemu_opt_get(opts, "x-image");
|
ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), options,
|
||||||
if (filename == NULL) {
|
"test", flags, false, false, &local_err);
|
||||||
error_setg(errp, "Could not retrieve test image filename");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->test_file = bdrv_new("");
|
|
||||||
ret = bdrv_open(s->test_file, filename, NULL, flags, NULL, &local_err);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
bdrv_unref(s->test_file);
|
|
||||||
s->test_file = NULL;
|
s->test_file = NULL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -417,7 +404,7 @@ static BlockDriver bdrv_blkverify = {
|
|||||||
.bdrv_aio_writev = blkverify_aio_writev,
|
.bdrv_aio_writev = blkverify_aio_writev,
|
||||||
.bdrv_aio_flush = blkverify_aio_flush,
|
.bdrv_aio_flush = blkverify_aio_flush,
|
||||||
|
|
||||||
.bdrv_check_ext_snapshot = bdrv_check_ext_snapshot_forbidden,
|
.authorizations = { true, false },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_blkverify_init(void)
|
static void bdrv_blkverify_init(void)
|
||||||
|
|||||||
@@ -351,7 +351,8 @@ static int cow_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_file_open(&cow_bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
ret = bdrv_file_open(&cow_bs, filename, NULL, NULL, BDRV_O_RDWR,
|
||||||
|
&local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
|
|||||||
83
block/curl.c
83
block/curl.c
@@ -34,6 +34,11 @@
|
|||||||
#define DPRINTF(fmt, ...) do { } while (0)
|
#define DPRINTF(fmt, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LIBCURL_VERSION_NUM >= 0x071000
|
||||||
|
/* The multi interface timer callback was introduced in 7.16.0 */
|
||||||
|
#define NEED_CURL_TIMER_CALLBACK
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
||||||
CURLPROTO_FTP | CURLPROTO_FTPS | \
|
CURLPROTO_FTP | CURLPROTO_FTPS | \
|
||||||
CURLPROTO_TFTP)
|
CURLPROTO_TFTP)
|
||||||
@@ -77,6 +82,7 @@ typedef struct CURLState
|
|||||||
|
|
||||||
typedef struct BDRVCURLState {
|
typedef struct BDRVCURLState {
|
||||||
CURLM *multi;
|
CURLM *multi;
|
||||||
|
QEMUTimer timer;
|
||||||
size_t len;
|
size_t len;
|
||||||
CURLState states[CURL_NUM_STATES];
|
CURLState states[CURL_NUM_STATES];
|
||||||
char *url;
|
char *url;
|
||||||
@@ -87,6 +93,23 @@ typedef struct BDRVCURLState {
|
|||||||
static void curl_clean_state(CURLState *s);
|
static void curl_clean_state(CURLState *s);
|
||||||
static void curl_multi_do(void *arg);
|
static void curl_multi_do(void *arg);
|
||||||
|
|
||||||
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
|
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||||
|
{
|
||||||
|
BDRVCURLState *s = opaque;
|
||||||
|
|
||||||
|
DPRINTF("CURL: timer callback timeout_ms %ld\n", timeout_ms);
|
||||||
|
if (timeout_ms == -1) {
|
||||||
|
timer_del(&s->timer);
|
||||||
|
} else {
|
||||||
|
int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000;
|
||||||
|
timer_mod(&s->timer,
|
||||||
|
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||||
void *s, void *sp)
|
void *s, void *sp)
|
||||||
{
|
{
|
||||||
@@ -209,20 +232,10 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|||||||
return FIND_RET_NONE;
|
return FIND_RET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_do(void *arg)
|
static void curl_multi_read(BDRVCURLState *s)
|
||||||
{
|
{
|
||||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
|
||||||
int running;
|
|
||||||
int r;
|
|
||||||
int msgs_in_queue;
|
int msgs_in_queue;
|
||||||
|
|
||||||
if (!s->multi)
|
|
||||||
return;
|
|
||||||
|
|
||||||
do {
|
|
||||||
r = curl_multi_socket_all(s->multi, &running);
|
|
||||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
|
||||||
|
|
||||||
/* Try to find done transfers, so we can free the easy
|
/* Try to find done transfers, so we can free the easy
|
||||||
* handle again. */
|
* handle again. */
|
||||||
do {
|
do {
|
||||||
@@ -266,6 +279,41 @@ static void curl_multi_do(void *arg)
|
|||||||
} while(msgs_in_queue);
|
} while(msgs_in_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void curl_multi_do(void *arg)
|
||||||
|
{
|
||||||
|
BDRVCURLState *s = (BDRVCURLState *)arg;
|
||||||
|
int running;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!s->multi) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
r = curl_multi_socket_all(s->multi, &running);
|
||||||
|
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||||
|
|
||||||
|
curl_multi_read(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void curl_multi_timeout_do(void *arg)
|
||||||
|
{
|
||||||
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
|
BDRVCURLState *s = (BDRVCURLState *)arg;
|
||||||
|
int running;
|
||||||
|
|
||||||
|
if (!s->multi) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
|
|
||||||
|
curl_multi_read(s);
|
||||||
|
#else
|
||||||
|
abort();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static CURLState *curl_init_state(BDRVCURLState *s)
|
static CURLState *curl_init_state(BDRVCURLState *s)
|
||||||
{
|
{
|
||||||
CURLState *state = NULL;
|
CURLState *state = NULL;
|
||||||
@@ -415,7 +463,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
goto out_noclean;
|
goto out_noclean;
|
||||||
@@ -473,12 +521,20 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
curl_easy_cleanup(state->curl);
|
curl_easy_cleanup(state->curl);
|
||||||
state->curl = NULL;
|
state->curl = NULL;
|
||||||
|
|
||||||
|
aio_timer_init(bdrv_get_aio_context(bs), &s->timer,
|
||||||
|
QEMU_CLOCK_REALTIME, SCALE_NS,
|
||||||
|
curl_multi_timeout_do, s);
|
||||||
|
|
||||||
// Now we know the file exists and its size, so let's
|
// Now we know the file exists and its size, so let's
|
||||||
// initialize the multi interface!
|
// initialize the multi interface!
|
||||||
|
|
||||||
s->multi = curl_multi_init();
|
s->multi = curl_multi_init();
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
||||||
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
|
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
||||||
|
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
||||||
|
#endif
|
||||||
curl_multi_do(s);
|
curl_multi_do(s);
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
@@ -597,6 +653,9 @@ static void curl_close(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
if (s->multi)
|
if (s->multi)
|
||||||
curl_multi_cleanup(s->multi);
|
curl_multi_cleanup(s->multi);
|
||||||
|
|
||||||
|
timer_del(&s->timer);
|
||||||
|
|
||||||
g_free(s->url);
|
g_free(s->url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
316
block/gluster.c
316
block/gluster.c
@@ -21,19 +21,15 @@
|
|||||||
#include "qemu/uri.h"
|
#include "qemu/uri.h"
|
||||||
|
|
||||||
typedef struct GlusterAIOCB {
|
typedef struct GlusterAIOCB {
|
||||||
BlockDriverAIOCB common;
|
|
||||||
int64_t size;
|
int64_t size;
|
||||||
int ret;
|
int ret;
|
||||||
bool *finished;
|
|
||||||
QEMUBH *bh;
|
QEMUBH *bh;
|
||||||
|
Coroutine *coroutine;
|
||||||
} GlusterAIOCB;
|
} GlusterAIOCB;
|
||||||
|
|
||||||
typedef struct BDRVGlusterState {
|
typedef struct BDRVGlusterState {
|
||||||
struct glfs *glfs;
|
struct glfs *glfs;
|
||||||
int fds[2];
|
|
||||||
struct glfs_fd *fd;
|
struct glfs_fd *fd;
|
||||||
int event_reader_pos;
|
|
||||||
GlusterAIOCB *event_acb;
|
|
||||||
} BDRVGlusterState;
|
} BDRVGlusterState;
|
||||||
|
|
||||||
#define GLUSTER_FD_READ 0
|
#define GLUSTER_FD_READ 0
|
||||||
@@ -231,46 +227,32 @@ out:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_gluster_complete_aio(GlusterAIOCB *acb, BDRVGlusterState *s)
|
static void qemu_gluster_complete_aio(void *opaque)
|
||||||
{
|
{
|
||||||
int ret;
|
GlusterAIOCB *acb = (GlusterAIOCB *)opaque;
|
||||||
bool *finished = acb->finished;
|
|
||||||
BlockDriverCompletionFunc *cb = acb->common.cb;
|
|
||||||
void *opaque = acb->common.opaque;
|
|
||||||
|
|
||||||
if (!acb->ret || acb->ret == acb->size) {
|
qemu_bh_delete(acb->bh);
|
||||||
ret = 0; /* Success */
|
acb->bh = NULL;
|
||||||
} else if (acb->ret < 0) {
|
qemu_coroutine_enter(acb->coroutine, NULL);
|
||||||
ret = acb->ret; /* Read/Write failed */
|
|
||||||
} else {
|
|
||||||
ret = -EIO; /* Partial read/write - fail it */
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
cb(opaque, ret);
|
|
||||||
if (finished) {
|
|
||||||
*finished = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_gluster_aio_event_reader(void *opaque)
|
/*
|
||||||
|
* AIO callback routine called from GlusterFS thread.
|
||||||
|
*/
|
||||||
|
static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
||||||
{
|
{
|
||||||
BDRVGlusterState *s = opaque;
|
GlusterAIOCB *acb = (GlusterAIOCB *)arg;
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
do {
|
if (!ret || ret == acb->size) {
|
||||||
char *p = (char *)&s->event_acb;
|
acb->ret = 0; /* Success */
|
||||||
|
} else if (ret < 0) {
|
||||||
|
acb->ret = ret; /* Read/Write failed */
|
||||||
|
} else {
|
||||||
|
acb->ret = -EIO; /* Partial read/write - fail it */
|
||||||
|
}
|
||||||
|
|
||||||
ret = read(s->fds[GLUSTER_FD_READ], p + s->event_reader_pos,
|
acb->bh = qemu_bh_new(qemu_gluster_complete_aio, acb);
|
||||||
sizeof(s->event_acb) - s->event_reader_pos);
|
qemu_bh_schedule(acb->bh);
|
||||||
if (ret > 0) {
|
|
||||||
s->event_reader_pos += ret;
|
|
||||||
if (s->event_reader_pos == sizeof(s->event_acb)) {
|
|
||||||
s->event_reader_pos = 0;
|
|
||||||
qemu_gluster_complete_aio(s->event_acb, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Convert to fine grained options */
|
/* TODO Convert to fine grained options */
|
||||||
@@ -300,7 +282,7 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@@ -309,7 +291,6 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
|||||||
|
|
||||||
filename = qemu_opt_get(opts, "filename");
|
filename = qemu_opt_get(opts, "filename");
|
||||||
|
|
||||||
|
|
||||||
s->glfs = qemu_gluster_init(gconf, filename);
|
s->glfs = qemu_gluster_init(gconf, filename);
|
||||||
if (!s->glfs) {
|
if (!s->glfs) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
@@ -329,18 +310,8 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
|||||||
s->fd = glfs_open(s->glfs, gconf->image, open_flags);
|
s->fd = glfs_open(s->glfs, gconf->image, open_flags);
|
||||||
if (!s->fd) {
|
if (!s->fd) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qemu_pipe(s->fds);
|
|
||||||
if (ret < 0) {
|
|
||||||
ret = -errno;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
fcntl(s->fds[GLUSTER_FD_READ], F_SETFL, O_NONBLOCK);
|
|
||||||
qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ],
|
|
||||||
qemu_gluster_aio_event_reader, NULL, s);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
qemu_gluster_gconf_free(gconf);
|
qemu_gluster_gconf_free(gconf);
|
||||||
@@ -356,12 +327,65 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
|
static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
|
||||||
|
BDRVGlusterState *s = bs->opaque;
|
||||||
|
off_t size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
off_t offset = sector_num * BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
|
acb->size = size;
|
||||||
|
acb->ret = 0;
|
||||||
|
acb->coroutine = qemu_coroutine_self();
|
||||||
|
|
||||||
|
ret = glfs_zerofill_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
ret = acb->ret;
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_slice_free(GlusterAIOCB, acb);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool gluster_supports_zerofill(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
|
||||||
|
int64_t size)
|
||||||
|
{
|
||||||
|
return glfs_zerofill(fd, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static inline bool gluster_supports_zerofill(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
|
||||||
|
int64_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int qemu_gluster_create(const char *filename,
|
static int qemu_gluster_create(const char *filename,
|
||||||
QEMUOptionParameter *options, Error **errp)
|
QEMUOptionParameter *options, Error **errp)
|
||||||
{
|
{
|
||||||
struct glfs *glfs;
|
struct glfs *glfs;
|
||||||
struct glfs_fd *fd;
|
struct glfs_fd *fd;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int prealloc = 0;
|
||||||
int64_t total_size = 0;
|
int64_t total_size = 0;
|
||||||
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
|
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
|
||||||
|
|
||||||
@@ -374,6 +398,19 @@ static int qemu_gluster_create(const char *filename,
|
|||||||
while (options && options->name) {
|
while (options && options->name) {
|
||||||
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
||||||
total_size = options->value.n / BDRV_SECTOR_SIZE;
|
total_size = options->value.n / BDRV_SECTOR_SIZE;
|
||||||
|
} else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
|
||||||
|
if (!options->value.s || !strcmp(options->value.s, "off")) {
|
||||||
|
prealloc = 0;
|
||||||
|
} else if (!strcmp(options->value.s, "full") &&
|
||||||
|
gluster_supports_zerofill()) {
|
||||||
|
prealloc = 1;
|
||||||
|
} else {
|
||||||
|
error_setg(errp, "Invalid preallocation mode: '%s'"
|
||||||
|
" or GlusterFS doesn't support zerofill API",
|
||||||
|
options->value.s);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
options++;
|
options++;
|
||||||
}
|
}
|
||||||
@@ -383,9 +420,15 @@ static int qemu_gluster_create(const char *filename,
|
|||||||
if (!fd) {
|
if (!fd) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
} else {
|
} else {
|
||||||
if (glfs_ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
|
if (!glfs_ftruncate(fd, total_size * BDRV_SECTOR_SIZE)) {
|
||||||
|
if (prealloc && qemu_gluster_zerofill(fd, 0,
|
||||||
|
total_size * BDRV_SECTOR_SIZE)) {
|
||||||
|
ret = -errno;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfs_close(fd) != 0) {
|
if (glfs_close(fd) != 0) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
}
|
}
|
||||||
@@ -398,58 +441,18 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_gluster_aio_cancel(BlockDriverAIOCB *blockacb)
|
static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
|
||||||
{
|
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int write)
|
||||||
GlusterAIOCB *acb = (GlusterAIOCB *)blockacb;
|
|
||||||
bool finished = false;
|
|
||||||
|
|
||||||
acb->finished = &finished;
|
|
||||||
while (!finished) {
|
|
||||||
qemu_aio_wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo gluster_aiocb_info = {
|
|
||||||
.aiocb_size = sizeof(GlusterAIOCB),
|
|
||||||
.cancel = qemu_gluster_aio_cancel,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
|
||||||
{
|
|
||||||
GlusterAIOCB *acb = (GlusterAIOCB *)arg;
|
|
||||||
BlockDriverState *bs = acb->common.bs;
|
|
||||||
BDRVGlusterState *s = bs->opaque;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
acb->ret = ret;
|
|
||||||
retval = qemu_write_full(s->fds[GLUSTER_FD_WRITE], &acb, sizeof(acb));
|
|
||||||
if (retval != sizeof(acb)) {
|
|
||||||
/*
|
|
||||||
* Gluster AIO callback thread failed to notify the waiting
|
|
||||||
* QEMU thread about IO completion.
|
|
||||||
*/
|
|
||||||
error_report("Gluster AIO completion failed: %s", strerror(errno));
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static BlockDriverAIOCB *qemu_gluster_aio_rw(BlockDriverState *bs,
|
|
||||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
|
||||||
BlockDriverCompletionFunc *cb, void *opaque, int write)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
GlusterAIOCB *acb;
|
GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
|
||||||
BDRVGlusterState *s = bs->opaque;
|
BDRVGlusterState *s = bs->opaque;
|
||||||
size_t size;
|
size_t size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
off_t offset;
|
off_t offset = sector_num * BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
offset = sector_num * BDRV_SECTOR_SIZE;
|
|
||||||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
|
||||||
|
|
||||||
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
|
|
||||||
acb->size = size;
|
acb->size = size;
|
||||||
acb->ret = 0;
|
acb->ret = 0;
|
||||||
acb->finished = NULL;
|
acb->coroutine = qemu_coroutine_self();
|
||||||
|
|
||||||
if (write) {
|
if (write) {
|
||||||
ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
|
ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
|
||||||
@@ -460,13 +463,16 @@ static BlockDriverAIOCB *qemu_gluster_aio_rw(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
ret = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
return &acb->common;
|
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
ret = acb->ret;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
qemu_aio_release(acb);
|
g_slice_free(GlusterAIOCB, acb);
|
||||||
return NULL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset)
|
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
@@ -482,71 +488,68 @@ static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *qemu_gluster_aio_readv(BlockDriverState *bs,
|
static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
|
||||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
|
||||||
{
|
{
|
||||||
return qemu_gluster_aio_rw(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
|
return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *qemu_gluster_aio_writev(BlockDriverState *bs,
|
static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
|
||||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
|
||||||
{
|
{
|
||||||
return qemu_gluster_aio_rw(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
|
return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *qemu_gluster_aio_flush(BlockDriverState *bs,
|
static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
GlusterAIOCB *acb;
|
GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
|
||||||
BDRVGlusterState *s = bs->opaque;
|
BDRVGlusterState *s = bs->opaque;
|
||||||
|
|
||||||
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
|
|
||||||
acb->size = 0;
|
acb->size = 0;
|
||||||
acb->ret = 0;
|
acb->ret = 0;
|
||||||
acb->finished = NULL;
|
acb->coroutine = qemu_coroutine_self();
|
||||||
|
|
||||||
ret = glfs_fsync_async(s->fd, &gluster_finish_aiocb, acb);
|
ret = glfs_fsync_async(s->fd, &gluster_finish_aiocb, acb);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
ret = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
return &acb->common;
|
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
ret = acb->ret;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
qemu_aio_release(acb);
|
g_slice_free(GlusterAIOCB, acb);
|
||||||
return NULL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_GLUSTERFS_DISCARD
|
#ifdef CONFIG_GLUSTERFS_DISCARD
|
||||||
static BlockDriverAIOCB *qemu_gluster_aio_discard(BlockDriverState *bs,
|
static coroutine_fn int qemu_gluster_co_discard(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors, BlockDriverCompletionFunc *cb,
|
int64_t sector_num, int nb_sectors)
|
||||||
void *opaque)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
GlusterAIOCB *acb;
|
GlusterAIOCB *acb = g_slice_new(GlusterAIOCB);
|
||||||
BDRVGlusterState *s = bs->opaque;
|
BDRVGlusterState *s = bs->opaque;
|
||||||
size_t size;
|
size_t size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
off_t offset;
|
off_t offset = sector_num * BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
offset = sector_num * BDRV_SECTOR_SIZE;
|
|
||||||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
|
||||||
|
|
||||||
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
|
|
||||||
acb->size = 0;
|
acb->size = 0;
|
||||||
acb->ret = 0;
|
acb->ret = 0;
|
||||||
acb->finished = NULL;
|
acb->coroutine = qemu_coroutine_self();
|
||||||
|
|
||||||
ret = glfs_discard_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
|
ret = glfs_discard_async(s->fd, offset, size, &gluster_finish_aiocb, acb);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
ret = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
return &acb->common;
|
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
ret = acb->ret;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
qemu_aio_release(acb);
|
g_slice_free(GlusterAIOCB, acb);
|
||||||
return NULL;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -581,10 +584,6 @@ static void qemu_gluster_close(BlockDriverState *bs)
|
|||||||
{
|
{
|
||||||
BDRVGlusterState *s = bs->opaque;
|
BDRVGlusterState *s = bs->opaque;
|
||||||
|
|
||||||
close(s->fds[GLUSTER_FD_READ]);
|
|
||||||
close(s->fds[GLUSTER_FD_WRITE]);
|
|
||||||
qemu_aio_set_fd_handler(s->fds[GLUSTER_FD_READ], NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (s->fd) {
|
if (s->fd) {
|
||||||
glfs_close(s->fd);
|
glfs_close(s->fd);
|
||||||
s->fd = NULL;
|
s->fd = NULL;
|
||||||
@@ -604,6 +603,11 @@ static QEMUOptionParameter qemu_gluster_create_options[] = {
|
|||||||
.type = OPT_SIZE,
|
.type = OPT_SIZE,
|
||||||
.help = "Virtual disk size"
|
.help = "Virtual disk size"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = BLOCK_OPT_PREALLOC,
|
||||||
|
.type = OPT_STRING,
|
||||||
|
.help = "Preallocation mode (allowed values: off, full)"
|
||||||
|
},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -618,12 +622,15 @@ static BlockDriver bdrv_gluster = {
|
|||||||
.bdrv_getlength = qemu_gluster_getlength,
|
.bdrv_getlength = qemu_gluster_getlength,
|
||||||
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
|
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
|
||||||
.bdrv_truncate = qemu_gluster_truncate,
|
.bdrv_truncate = qemu_gluster_truncate,
|
||||||
.bdrv_aio_readv = qemu_gluster_aio_readv,
|
.bdrv_co_readv = qemu_gluster_co_readv,
|
||||||
.bdrv_aio_writev = qemu_gluster_aio_writev,
|
.bdrv_co_writev = qemu_gluster_co_writev,
|
||||||
.bdrv_aio_flush = qemu_gluster_aio_flush,
|
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
|
||||||
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
|
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
|
||||||
#ifdef CONFIG_GLUSTERFS_DISCARD
|
#ifdef CONFIG_GLUSTERFS_DISCARD
|
||||||
.bdrv_aio_discard = qemu_gluster_aio_discard,
|
.bdrv_co_discard = qemu_gluster_co_discard,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
|
.bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes,
|
||||||
#endif
|
#endif
|
||||||
.create_options = qemu_gluster_create_options,
|
.create_options = qemu_gluster_create_options,
|
||||||
};
|
};
|
||||||
@@ -639,12 +646,15 @@ static BlockDriver bdrv_gluster_tcp = {
|
|||||||
.bdrv_getlength = qemu_gluster_getlength,
|
.bdrv_getlength = qemu_gluster_getlength,
|
||||||
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
|
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
|
||||||
.bdrv_truncate = qemu_gluster_truncate,
|
.bdrv_truncate = qemu_gluster_truncate,
|
||||||
.bdrv_aio_readv = qemu_gluster_aio_readv,
|
.bdrv_co_readv = qemu_gluster_co_readv,
|
||||||
.bdrv_aio_writev = qemu_gluster_aio_writev,
|
.bdrv_co_writev = qemu_gluster_co_writev,
|
||||||
.bdrv_aio_flush = qemu_gluster_aio_flush,
|
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
|
||||||
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
|
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
|
||||||
#ifdef CONFIG_GLUSTERFS_DISCARD
|
#ifdef CONFIG_GLUSTERFS_DISCARD
|
||||||
.bdrv_aio_discard = qemu_gluster_aio_discard,
|
.bdrv_co_discard = qemu_gluster_co_discard,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
|
.bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes,
|
||||||
#endif
|
#endif
|
||||||
.create_options = qemu_gluster_create_options,
|
.create_options = qemu_gluster_create_options,
|
||||||
};
|
};
|
||||||
@@ -660,12 +670,15 @@ static BlockDriver bdrv_gluster_unix = {
|
|||||||
.bdrv_getlength = qemu_gluster_getlength,
|
.bdrv_getlength = qemu_gluster_getlength,
|
||||||
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
|
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
|
||||||
.bdrv_truncate = qemu_gluster_truncate,
|
.bdrv_truncate = qemu_gluster_truncate,
|
||||||
.bdrv_aio_readv = qemu_gluster_aio_readv,
|
.bdrv_co_readv = qemu_gluster_co_readv,
|
||||||
.bdrv_aio_writev = qemu_gluster_aio_writev,
|
.bdrv_co_writev = qemu_gluster_co_writev,
|
||||||
.bdrv_aio_flush = qemu_gluster_aio_flush,
|
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
|
||||||
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
|
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
|
||||||
#ifdef CONFIG_GLUSTERFS_DISCARD
|
#ifdef CONFIG_GLUSTERFS_DISCARD
|
||||||
.bdrv_aio_discard = qemu_gluster_aio_discard,
|
.bdrv_co_discard = qemu_gluster_co_discard,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
|
.bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes,
|
||||||
#endif
|
#endif
|
||||||
.create_options = qemu_gluster_create_options,
|
.create_options = qemu_gluster_create_options,
|
||||||
};
|
};
|
||||||
@@ -681,12 +694,15 @@ static BlockDriver bdrv_gluster_rdma = {
|
|||||||
.bdrv_getlength = qemu_gluster_getlength,
|
.bdrv_getlength = qemu_gluster_getlength,
|
||||||
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
|
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
|
||||||
.bdrv_truncate = qemu_gluster_truncate,
|
.bdrv_truncate = qemu_gluster_truncate,
|
||||||
.bdrv_aio_readv = qemu_gluster_aio_readv,
|
.bdrv_co_readv = qemu_gluster_co_readv,
|
||||||
.bdrv_aio_writev = qemu_gluster_aio_writev,
|
.bdrv_co_writev = qemu_gluster_co_writev,
|
||||||
.bdrv_aio_flush = qemu_gluster_aio_flush,
|
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
|
||||||
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
|
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
|
||||||
#ifdef CONFIG_GLUSTERFS_DISCARD
|
#ifdef CONFIG_GLUSTERFS_DISCARD
|
||||||
.bdrv_aio_discard = qemu_gluster_aio_discard,
|
.bdrv_co_discard = qemu_gluster_co_discard,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
|
.bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes,
|
||||||
#endif
|
#endif
|
||||||
.create_options = qemu_gluster_create_options,
|
.create_options = qemu_gluster_create_options,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ retry:
|
|||||||
iscsi_co_generic_cb, &iTask);
|
iscsi_co_generic_cb, &iTask);
|
||||||
if (iTask.task == NULL) {
|
if (iTask.task == NULL) {
|
||||||
g_free(buf);
|
g_free(buf);
|
||||||
return -EIO;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||||
scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
|
scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
|
||||||
@@ -376,7 +376,7 @@ retry:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (iTask.task == NULL) {
|
if (iTask.task == NULL) {
|
||||||
return -EIO;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||||
scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov);
|
scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov);
|
||||||
@@ -419,7 +419,7 @@ static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
|||||||
retry:
|
retry:
|
||||||
if (iscsi_synchronizecache10_task(iscsilun->iscsi, iscsilun->lun, 0, 0, 0,
|
if (iscsi_synchronizecache10_task(iscsilun->iscsi, iscsilun->lun, 0, 0, 0,
|
||||||
0, iscsi_co_generic_cb, &iTask) == NULL) {
|
0, iscsi_co_generic_cb, &iTask) == NULL) {
|
||||||
return -EIO;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!iTask.complete) {
|
while (!iTask.complete) {
|
||||||
@@ -669,7 +669,7 @@ retry:
|
|||||||
sector_qemu2lun(sector_num, iscsilun),
|
sector_qemu2lun(sector_num, iscsilun),
|
||||||
8 + 16, iscsi_co_generic_cb,
|
8 + 16, iscsi_co_generic_cb,
|
||||||
&iTask) == NULL) {
|
&iTask) == NULL) {
|
||||||
ret = -EIO;
|
ret = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,7 +753,7 @@ coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
|
|||||||
retry:
|
retry:
|
||||||
if (iscsi_unmap_task(iscsilun->iscsi, iscsilun->lun, 0, 0, &list, 1,
|
if (iscsi_unmap_task(iscsilun->iscsi, iscsilun->lun, 0, 0, &list, 1,
|
||||||
iscsi_co_generic_cb, &iTask) == NULL) {
|
iscsi_co_generic_cb, &iTask) == NULL) {
|
||||||
return -EIO;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!iTask.complete) {
|
while (!iTask.complete) {
|
||||||
@@ -822,7 +822,7 @@ retry:
|
|||||||
iscsilun->zeroblock, iscsilun->block_size,
|
iscsilun->zeroblock, iscsilun->block_size,
|
||||||
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
|
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
|
||||||
0, 0, iscsi_co_generic_cb, &iTask) == NULL) {
|
0, 0, iscsi_co_generic_cb, &iTask) == NULL) {
|
||||||
return -EIO;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!iTask.complete) {
|
while (!iTask.complete) {
|
||||||
@@ -1099,6 +1099,10 @@ fail:
|
|||||||
/*
|
/*
|
||||||
* We support iscsi url's on the form
|
* We support iscsi url's on the form
|
||||||
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
|
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
|
||||||
|
*
|
||||||
|
* Note: flags are currently not used by iscsi_open. If this function
|
||||||
|
* is changed such that flags are used, please examine iscsi_reopen_prepare()
|
||||||
|
* to see if needs to be changed as well.
|
||||||
*/
|
*/
|
||||||
static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
@@ -1123,7 +1127,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@@ -1217,6 +1221,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
||||||
|
bs->request_alignment = iscsilun->block_size;
|
||||||
|
|
||||||
/* Medium changer or tape. We dont have any emulation for this so this must
|
/* Medium changer or tape. We dont have any emulation for this so this must
|
||||||
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
||||||
@@ -1265,23 +1270,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
sizeof(struct scsi_inquiry_block_limits));
|
sizeof(struct scsi_inquiry_block_limits));
|
||||||
scsi_free_scsi_task(task);
|
scsi_free_scsi_task(task);
|
||||||
task = NULL;
|
task = NULL;
|
||||||
|
|
||||||
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
|
||||||
bs->bl.max_discard = sector_lun2qemu(iscsilun->bl.max_unmap,
|
|
||||||
iscsilun);
|
|
||||||
}
|
|
||||||
bs->bl.discard_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
|
||||||
iscsilun);
|
|
||||||
|
|
||||||
if (iscsilun->bl.max_ws_len < 0xffffffff) {
|
|
||||||
bs->bl.max_write_zeroes = sector_lun2qemu(iscsilun->bl.max_ws_len,
|
|
||||||
iscsilun);
|
|
||||||
}
|
|
||||||
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
|
||||||
iscsilun);
|
|
||||||
|
|
||||||
bs->bl.opt_transfer_length = sector_lun2qemu(iscsilun->bl.opt_xfer_len,
|
|
||||||
iscsilun);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||||
@@ -1326,6 +1314,42 @@ static void iscsi_close(BlockDriverState *bs)
|
|||||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int iscsi_refresh_limits(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
|
|
||||||
|
/* We don't actually refresh here, but just return data queried in
|
||||||
|
* iscsi_open(): iscsi targets don't change their limits. */
|
||||||
|
if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
|
||||||
|
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
||||||
|
bs->bl.max_discard = sector_lun2qemu(iscsilun->bl.max_unmap,
|
||||||
|
iscsilun);
|
||||||
|
}
|
||||||
|
bs->bl.discard_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||||
|
iscsilun);
|
||||||
|
|
||||||
|
if (iscsilun->bl.max_ws_len < 0xffffffff) {
|
||||||
|
bs->bl.max_write_zeroes = sector_lun2qemu(iscsilun->bl.max_ws_len,
|
||||||
|
iscsilun);
|
||||||
|
}
|
||||||
|
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||||
|
iscsilun);
|
||||||
|
}
|
||||||
|
bs->bl.opt_transfer_length = sector_lun2qemu(iscsilun->bl.opt_xfer_len,
|
||||||
|
iscsilun);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Since iscsi_open() ignores bdrv_flags, there is nothing to do here in
|
||||||
|
* prepare. Note that this will not re-establish a connection with an iSCSI
|
||||||
|
* target - it is effectively a NOP. */
|
||||||
|
static int iscsi_reopen_prepare(BDRVReopenState *state,
|
||||||
|
BlockReopenQueue *queue, Error **errp)
|
||||||
|
{
|
||||||
|
/* NOP */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
{
|
{
|
||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
@@ -1434,10 +1458,12 @@ static BlockDriver bdrv_iscsi = {
|
|||||||
.bdrv_close = iscsi_close,
|
.bdrv_close = iscsi_close,
|
||||||
.bdrv_create = iscsi_create,
|
.bdrv_create = iscsi_create,
|
||||||
.create_options = iscsi_create_options,
|
.create_options = iscsi_create_options,
|
||||||
|
.bdrv_reopen_prepare = iscsi_reopen_prepare,
|
||||||
|
|
||||||
.bdrv_getlength = iscsi_getlength,
|
.bdrv_getlength = iscsi_getlength,
|
||||||
.bdrv_get_info = iscsi_get_info,
|
.bdrv_get_info = iscsi_get_info,
|
||||||
.bdrv_truncate = iscsi_truncate,
|
.bdrv_truncate = iscsi_truncate,
|
||||||
|
.bdrv_refresh_limits = iscsi_refresh_limits,
|
||||||
|
|
||||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||||
.bdrv_co_get_block_status = iscsi_co_get_block_status,
|
.bdrv_co_get_block_status = iscsi_co_get_block_status,
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret)
|
|||||||
bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
|
bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_iovec_destroy(&op->qiov);
|
||||||
g_slice_free(MirrorOp, op);
|
g_slice_free(MirrorOp, op);
|
||||||
qemu_coroutine_enter(s->common.co, NULL);
|
qemu_coroutine_enter(s->common.co, NULL);
|
||||||
}
|
}
|
||||||
@@ -630,11 +631,56 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base,
|
|||||||
BlockDriverCompletionFunc *cb,
|
BlockDriverCompletionFunc *cb,
|
||||||
void *opaque, Error **errp)
|
void *opaque, Error **errp)
|
||||||
{
|
{
|
||||||
|
int64_t length, base_length;
|
||||||
|
int orig_base_flags;
|
||||||
|
int ret;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
orig_base_flags = bdrv_get_flags(base);
|
||||||
|
|
||||||
if (bdrv_reopen(base, bs->open_flags, errp)) {
|
if (bdrv_reopen(base, bs->open_flags, errp)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length = bdrv_getlength(bs);
|
||||||
|
if (length < 0) {
|
||||||
|
error_setg_errno(errp, -length,
|
||||||
|
"Unable to determine length of %s", bs->filename);
|
||||||
|
goto error_restore_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
base_length = bdrv_getlength(base);
|
||||||
|
if (base_length < 0) {
|
||||||
|
error_setg_errno(errp, -base_length,
|
||||||
|
"Unable to determine length of %s", base->filename);
|
||||||
|
goto error_restore_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > base_length) {
|
||||||
|
ret = bdrv_truncate(base, length);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret,
|
||||||
|
"Top image %s is larger than base image %s, and "
|
||||||
|
"resize of base image failed",
|
||||||
|
bs->filename, base->filename);
|
||||||
|
goto error_restore_flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bdrv_ref(base);
|
bdrv_ref(base);
|
||||||
mirror_start_job(bs, base, speed, 0, 0,
|
mirror_start_job(bs, base, speed, 0, 0,
|
||||||
on_error, on_error, cb, opaque, errp,
|
on_error, on_error, cb, opaque, &local_err,
|
||||||
&commit_active_job_driver, false, base);
|
&commit_active_job_driver, false, base);
|
||||||
|
if (error_is_set(&local_err)) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
goto error_restore_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error_restore_flags:
|
||||||
|
/* ignore error and errp for bdrv_reopen, because we want to propagate
|
||||||
|
* the original error */
|
||||||
|
bdrv_reopen(base, orig_base_flags, NULL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ static int nbd_config(BDRVNBDState *s, QDict *options, char **export)
|
|||||||
&error_abort);
|
&error_abort);
|
||||||
|
|
||||||
qemu_opts_absorb_qdict(s->socket_opts, options, &local_err);
|
qemu_opts_absorb_qdict(s->socket_opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|||||||
439
block/nfs.c
Normal file
439
block/nfs.c
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Block driver for native access to files on NFS shares
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Peter Lieven <pl@kamp.de>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config-host.h"
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "qemu/config-file.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "block/block_int.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "qemu/iov.h"
|
||||||
|
#include "qemu/uri.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include <nfsc/libnfs.h>
|
||||||
|
|
||||||
|
typedef struct NFSClient {
|
||||||
|
struct nfs_context *context;
|
||||||
|
struct nfsfh *fh;
|
||||||
|
int events;
|
||||||
|
bool has_zero_init;
|
||||||
|
} NFSClient;
|
||||||
|
|
||||||
|
typedef struct NFSRPC {
|
||||||
|
int ret;
|
||||||
|
int complete;
|
||||||
|
QEMUIOVector *iov;
|
||||||
|
struct stat *st;
|
||||||
|
Coroutine *co;
|
||||||
|
QEMUBH *bh;
|
||||||
|
} NFSRPC;
|
||||||
|
|
||||||
|
static void nfs_process_read(void *arg);
|
||||||
|
static void nfs_process_write(void *arg);
|
||||||
|
|
||||||
|
static void nfs_set_events(NFSClient *client)
|
||||||
|
{
|
||||||
|
int ev = nfs_which_events(client->context);
|
||||||
|
if (ev != client->events) {
|
||||||
|
qemu_aio_set_fd_handler(nfs_get_fd(client->context),
|
||||||
|
(ev & POLLIN) ? nfs_process_read : NULL,
|
||||||
|
(ev & POLLOUT) ? nfs_process_write : NULL,
|
||||||
|
client);
|
||||||
|
|
||||||
|
}
|
||||||
|
client->events = ev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs_process_read(void *arg)
|
||||||
|
{
|
||||||
|
NFSClient *client = arg;
|
||||||
|
nfs_service(client->context, POLLIN);
|
||||||
|
nfs_set_events(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs_process_write(void *arg)
|
||||||
|
{
|
||||||
|
NFSClient *client = arg;
|
||||||
|
nfs_service(client->context, POLLOUT);
|
||||||
|
nfs_set_events(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs_co_init_task(NFSClient *client, NFSRPC *task)
|
||||||
|
{
|
||||||
|
*task = (NFSRPC) {
|
||||||
|
.co = qemu_coroutine_self(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs_co_generic_bh_cb(void *opaque)
|
||||||
|
{
|
||||||
|
NFSRPC *task = opaque;
|
||||||
|
qemu_bh_delete(task->bh);
|
||||||
|
qemu_coroutine_enter(task->co, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
NFSRPC *task = private_data;
|
||||||
|
task->complete = 1;
|
||||||
|
task->ret = ret;
|
||||||
|
if (task->ret > 0 && task->iov) {
|
||||||
|
if (task->ret <= task->iov->size) {
|
||||||
|
qemu_iovec_from_buf(task->iov, 0, data, task->ret);
|
||||||
|
} else {
|
||||||
|
task->ret = -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (task->ret == 0 && task->st) {
|
||||||
|
memcpy(task->st, data, sizeof(struct stat));
|
||||||
|
}
|
||||||
|
if (task->co) {
|
||||||
|
task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task);
|
||||||
|
qemu_bh_schedule(task->bh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int coroutine_fn nfs_co_readv(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors,
|
||||||
|
QEMUIOVector *iov)
|
||||||
|
{
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
NFSRPC task;
|
||||||
|
|
||||||
|
nfs_co_init_task(client, &task);
|
||||||
|
task.iov = iov;
|
||||||
|
|
||||||
|
if (nfs_pread_async(client->context, client->fh,
|
||||||
|
sector_num * BDRV_SECTOR_SIZE,
|
||||||
|
nb_sectors * BDRV_SECTOR_SIZE,
|
||||||
|
nfs_co_generic_cb, &task) != 0) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!task.complete) {
|
||||||
|
nfs_set_events(client);
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task.ret < 0) {
|
||||||
|
return task.ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zero pad short reads */
|
||||||
|
if (task.ret < iov->size) {
|
||||||
|
qemu_iovec_memset(iov, task.ret, 0, iov->size - task.ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int coroutine_fn nfs_co_writev(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors,
|
||||||
|
QEMUIOVector *iov)
|
||||||
|
{
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
NFSRPC task;
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
nfs_co_init_task(client, &task);
|
||||||
|
|
||||||
|
buf = g_malloc(nb_sectors * BDRV_SECTOR_SIZE);
|
||||||
|
qemu_iovec_to_buf(iov, 0, buf, nb_sectors * BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
|
if (nfs_pwrite_async(client->context, client->fh,
|
||||||
|
sector_num * BDRV_SECTOR_SIZE,
|
||||||
|
nb_sectors * BDRV_SECTOR_SIZE,
|
||||||
|
buf, nfs_co_generic_cb, &task) != 0) {
|
||||||
|
g_free(buf);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!task.complete) {
|
||||||
|
nfs_set_events(client);
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(buf);
|
||||||
|
|
||||||
|
if (task.ret != nb_sectors * BDRV_SECTOR_SIZE) {
|
||||||
|
return task.ret < 0 ? task.ret : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
NFSRPC task;
|
||||||
|
|
||||||
|
nfs_co_init_task(client, &task);
|
||||||
|
|
||||||
|
if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
|
||||||
|
&task) != 0) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!task.complete) {
|
||||||
|
nfs_set_events(client);
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO Convert to fine grained options */
|
||||||
|
static QemuOptsList runtime_opts = {
|
||||||
|
.name = "nfs",
|
||||||
|
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||||
|
.desc = {
|
||||||
|
{
|
||||||
|
.name = "filename",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "URL to the NFS file",
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nfs_client_close(NFSClient *client)
|
||||||
|
{
|
||||||
|
if (client->context) {
|
||||||
|
if (client->fh) {
|
||||||
|
nfs_close(client->context, client->fh);
|
||||||
|
}
|
||||||
|
qemu_aio_set_fd_handler(nfs_get_fd(client->context), NULL, NULL, NULL);
|
||||||
|
nfs_destroy_context(client->context);
|
||||||
|
}
|
||||||
|
memset(client, 0, sizeof(NFSClient));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs_file_close(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
nfs_client_close(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
||||||
|
int flags, Error **errp)
|
||||||
|
{
|
||||||
|
int ret = -EINVAL, i;
|
||||||
|
struct stat st;
|
||||||
|
URI *uri;
|
||||||
|
QueryParams *qp = NULL;
|
||||||
|
char *file = NULL, *strp = NULL;
|
||||||
|
|
||||||
|
uri = uri_parse(filename);
|
||||||
|
if (!uri) {
|
||||||
|
error_setg(errp, "Invalid URL specified");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
strp = strrchr(uri->path, '/');
|
||||||
|
if (strp == NULL) {
|
||||||
|
error_setg(errp, "Invalid URL specified");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
file = g_strdup(strp);
|
||||||
|
*strp = 0;
|
||||||
|
|
||||||
|
client->context = nfs_init_context();
|
||||||
|
if (client->context == NULL) {
|
||||||
|
error_setg(errp, "Failed to init NFS context");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
qp = query_params_parse(uri->query);
|
||||||
|
for (i = 0; i < qp->n; i++) {
|
||||||
|
if (!qp->p[i].value) {
|
||||||
|
error_setg(errp, "Value for NFS parameter expected: %s",
|
||||||
|
qp->p[i].name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!strncmp(qp->p[i].name, "uid", 3)) {
|
||||||
|
nfs_set_uid(client->context, atoi(qp->p[i].value));
|
||||||
|
} else if (!strncmp(qp->p[i].name, "gid", 3)) {
|
||||||
|
nfs_set_gid(client->context, atoi(qp->p[i].value));
|
||||||
|
} else if (!strncmp(qp->p[i].name, "tcp-syncnt", 10)) {
|
||||||
|
nfs_set_tcp_syncnt(client->context, atoi(qp->p[i].value));
|
||||||
|
} else {
|
||||||
|
error_setg(errp, "Unknown NFS parameter name: %s",
|
||||||
|
qp->p[i].name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nfs_mount(client->context, uri->server, uri->path);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Failed to mount nfs share: %s",
|
||||||
|
nfs_get_error(client->context));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & O_CREAT) {
|
||||||
|
ret = nfs_creat(client->context, file, 0600, &client->fh);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Failed to create file: %s",
|
||||||
|
nfs_get_error(client->context));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = nfs_open(client->context, file, flags, &client->fh);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Failed to open file : %s",
|
||||||
|
nfs_get_error(client->context));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nfs_fstat(client->context, client->fh, &st);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Failed to fstat file: %s",
|
||||||
|
nfs_get_error(client->context));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = DIV_ROUND_UP(st.st_size, BDRV_SECTOR_SIZE);
|
||||||
|
client->has_zero_init = S_ISREG(st.st_mode);
|
||||||
|
goto out;
|
||||||
|
fail:
|
||||||
|
nfs_client_close(client);
|
||||||
|
out:
|
||||||
|
if (qp) {
|
||||||
|
query_params_free(qp);
|
||||||
|
}
|
||||||
|
uri_free(uri);
|
||||||
|
g_free(file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
|
Error **errp) {
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
int64_t ret;
|
||||||
|
QemuOpts *opts;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
|
if (error_is_set(&local_err)) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
ret = nfs_client_open(client, qemu_opt_get(opts, "filename"),
|
||||||
|
(flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
|
||||||
|
errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bs->total_sectors = ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs_file_create(const char *url, QEMUOptionParameter *options,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int64_t total_size = 0;
|
||||||
|
NFSClient *client = g_malloc0(sizeof(NFSClient));
|
||||||
|
|
||||||
|
/* Read out options */
|
||||||
|
while (options && options->name) {
|
||||||
|
if (!strcmp(options->name, "size")) {
|
||||||
|
total_size = options->value.n;
|
||||||
|
}
|
||||||
|
options++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nfs_client_open(client, url, O_CREAT, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = nfs_ftruncate(client->context, client->fh, total_size);
|
||||||
|
nfs_client_close(client);
|
||||||
|
out:
|
||||||
|
g_free(client);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs_has_zero_init(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
return client->has_zero_init;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
NFSRPC task = {0};
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
task.st = &st;
|
||||||
|
if (nfs_fstat_async(client->context, client->fh, nfs_co_generic_cb,
|
||||||
|
&task) != 0) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!task.complete) {
|
||||||
|
nfs_set_events(client);
|
||||||
|
qemu_aio_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (task.ret < 0 ? task.ret : st.st_blocks * st.st_blksize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs_file_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
|
{
|
||||||
|
NFSClient *client = bs->opaque;
|
||||||
|
return nfs_ftruncate(client->context, client->fh, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockDriver bdrv_nfs = {
|
||||||
|
.format_name = "nfs",
|
||||||
|
.protocol_name = "nfs",
|
||||||
|
|
||||||
|
.instance_size = sizeof(NFSClient),
|
||||||
|
.bdrv_needs_filename = true,
|
||||||
|
.bdrv_has_zero_init = nfs_has_zero_init,
|
||||||
|
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
|
||||||
|
.bdrv_truncate = nfs_file_truncate,
|
||||||
|
|
||||||
|
.bdrv_file_open = nfs_file_open,
|
||||||
|
.bdrv_close = nfs_file_close,
|
||||||
|
.bdrv_create = nfs_file_create,
|
||||||
|
|
||||||
|
.bdrv_co_readv = nfs_co_readv,
|
||||||
|
.bdrv_co_writev = nfs_co_writev,
|
||||||
|
.bdrv_co_flush_to_disk = nfs_co_flush,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nfs_block_init(void)
|
||||||
|
{
|
||||||
|
bdrv_register(&bdrv_nfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
block_init(nfs_block_init);
|
||||||
118
block/qapi.c
118
block/qapi.c
@@ -29,6 +29,60 @@
|
|||||||
#include "qapi/qmp-output-visitor.h"
|
#include "qapi/qmp-output-visitor.h"
|
||||||
#include "qapi/qmp/types.h"
|
#include "qapi/qmp/types.h"
|
||||||
|
|
||||||
|
BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BlockDeviceInfo *info = g_malloc0(sizeof(*info));
|
||||||
|
|
||||||
|
info->file = g_strdup(bs->filename);
|
||||||
|
info->ro = bs->read_only;
|
||||||
|
info->drv = g_strdup(bs->drv->format_name);
|
||||||
|
info->encrypted = bs->encrypted;
|
||||||
|
info->encryption_key_missing = bdrv_key_required(bs);
|
||||||
|
|
||||||
|
if (bs->node_name[0]) {
|
||||||
|
info->has_node_name = true;
|
||||||
|
info->node_name = g_strdup(bs->node_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bs->backing_file[0]) {
|
||||||
|
info->has_backing_file = true;
|
||||||
|
info->backing_file = g_strdup(bs->backing_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
info->backing_file_depth = bdrv_get_backing_file_depth(bs);
|
||||||
|
|
||||||
|
if (bs->io_limits_enabled) {
|
||||||
|
ThrottleConfig cfg;
|
||||||
|
throttle_get_config(&bs->throttle_state, &cfg);
|
||||||
|
info->bps = cfg.buckets[THROTTLE_BPS_TOTAL].avg;
|
||||||
|
info->bps_rd = cfg.buckets[THROTTLE_BPS_READ].avg;
|
||||||
|
info->bps_wr = cfg.buckets[THROTTLE_BPS_WRITE].avg;
|
||||||
|
|
||||||
|
info->iops = cfg.buckets[THROTTLE_OPS_TOTAL].avg;
|
||||||
|
info->iops_rd = cfg.buckets[THROTTLE_OPS_READ].avg;
|
||||||
|
info->iops_wr = cfg.buckets[THROTTLE_OPS_WRITE].avg;
|
||||||
|
|
||||||
|
info->has_bps_max = cfg.buckets[THROTTLE_BPS_TOTAL].max;
|
||||||
|
info->bps_max = cfg.buckets[THROTTLE_BPS_TOTAL].max;
|
||||||
|
info->has_bps_rd_max = cfg.buckets[THROTTLE_BPS_READ].max;
|
||||||
|
info->bps_rd_max = cfg.buckets[THROTTLE_BPS_READ].max;
|
||||||
|
info->has_bps_wr_max = cfg.buckets[THROTTLE_BPS_WRITE].max;
|
||||||
|
info->bps_wr_max = cfg.buckets[THROTTLE_BPS_WRITE].max;
|
||||||
|
|
||||||
|
info->has_iops_max = cfg.buckets[THROTTLE_OPS_TOTAL].max;
|
||||||
|
info->iops_max = cfg.buckets[THROTTLE_OPS_TOTAL].max;
|
||||||
|
info->has_iops_rd_max = cfg.buckets[THROTTLE_OPS_READ].max;
|
||||||
|
info->iops_rd_max = cfg.buckets[THROTTLE_OPS_READ].max;
|
||||||
|
info->has_iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max;
|
||||||
|
info->iops_wr_max = cfg.buckets[THROTTLE_OPS_WRITE].max;
|
||||||
|
|
||||||
|
info->has_iops_size = cfg.op_size;
|
||||||
|
info->iops_size = cfg.op_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 0 on success, with *p_list either set to describe snapshot
|
* Returns 0 on success, with *p_list either set to describe snapshot
|
||||||
* information, or NULL because there are no snapshots. Returns -errno on
|
* information, or NULL because there are no snapshots. Returns -errno on
|
||||||
@@ -211,66 +265,13 @@ void bdrv_query_info(BlockDriverState *bs,
|
|||||||
|
|
||||||
if (bs->drv) {
|
if (bs->drv) {
|
||||||
info->has_inserted = true;
|
info->has_inserted = true;
|
||||||
info->inserted = g_malloc0(sizeof(*info->inserted));
|
info->inserted = bdrv_block_device_info(bs);
|
||||||
info->inserted->file = g_strdup(bs->filename);
|
|
||||||
info->inserted->ro = bs->read_only;
|
|
||||||
info->inserted->drv = g_strdup(bs->drv->format_name);
|
|
||||||
info->inserted->encrypted = bs->encrypted;
|
|
||||||
info->inserted->encryption_key_missing = bdrv_key_required(bs);
|
|
||||||
|
|
||||||
if (bs->backing_file[0]) {
|
|
||||||
info->inserted->has_backing_file = true;
|
|
||||||
info->inserted->backing_file = g_strdup(bs->backing_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
info->inserted->backing_file_depth = bdrv_get_backing_file_depth(bs);
|
|
||||||
|
|
||||||
if (bs->io_limits_enabled) {
|
|
||||||
ThrottleConfig cfg;
|
|
||||||
throttle_get_config(&bs->throttle_state, &cfg);
|
|
||||||
info->inserted->bps = cfg.buckets[THROTTLE_BPS_TOTAL].avg;
|
|
||||||
info->inserted->bps_rd = cfg.buckets[THROTTLE_BPS_READ].avg;
|
|
||||||
info->inserted->bps_wr = cfg.buckets[THROTTLE_BPS_WRITE].avg;
|
|
||||||
|
|
||||||
info->inserted->iops = cfg.buckets[THROTTLE_OPS_TOTAL].avg;
|
|
||||||
info->inserted->iops_rd = cfg.buckets[THROTTLE_OPS_READ].avg;
|
|
||||||
info->inserted->iops_wr = cfg.buckets[THROTTLE_OPS_WRITE].avg;
|
|
||||||
|
|
||||||
info->inserted->has_bps_max =
|
|
||||||
cfg.buckets[THROTTLE_BPS_TOTAL].max;
|
|
||||||
info->inserted->bps_max =
|
|
||||||
cfg.buckets[THROTTLE_BPS_TOTAL].max;
|
|
||||||
info->inserted->has_bps_rd_max =
|
|
||||||
cfg.buckets[THROTTLE_BPS_READ].max;
|
|
||||||
info->inserted->bps_rd_max =
|
|
||||||
cfg.buckets[THROTTLE_BPS_READ].max;
|
|
||||||
info->inserted->has_bps_wr_max =
|
|
||||||
cfg.buckets[THROTTLE_BPS_WRITE].max;
|
|
||||||
info->inserted->bps_wr_max =
|
|
||||||
cfg.buckets[THROTTLE_BPS_WRITE].max;
|
|
||||||
|
|
||||||
info->inserted->has_iops_max =
|
|
||||||
cfg.buckets[THROTTLE_OPS_TOTAL].max;
|
|
||||||
info->inserted->iops_max =
|
|
||||||
cfg.buckets[THROTTLE_OPS_TOTAL].max;
|
|
||||||
info->inserted->has_iops_rd_max =
|
|
||||||
cfg.buckets[THROTTLE_OPS_READ].max;
|
|
||||||
info->inserted->iops_rd_max =
|
|
||||||
cfg.buckets[THROTTLE_OPS_READ].max;
|
|
||||||
info->inserted->has_iops_wr_max =
|
|
||||||
cfg.buckets[THROTTLE_OPS_WRITE].max;
|
|
||||||
info->inserted->iops_wr_max =
|
|
||||||
cfg.buckets[THROTTLE_OPS_WRITE].max;
|
|
||||||
|
|
||||||
info->inserted->has_iops_size = cfg.op_size;
|
|
||||||
info->inserted->iops_size = cfg.op_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bs0 = bs;
|
bs0 = bs;
|
||||||
p_image_info = &info->inserted->image;
|
p_image_info = &info->inserted->image;
|
||||||
while (1) {
|
while (1) {
|
||||||
bdrv_query_image_info(bs0, p_image_info, &local_err);
|
bdrv_query_image_info(bs0, p_image_info, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -318,6 +319,11 @@ BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
|||||||
s->parent = bdrv_query_stats(bs->file);
|
s->parent = bdrv_query_stats(bs->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bs->backing_hd) {
|
||||||
|
s->has_backing = true;
|
||||||
|
s->backing = bdrv_query_stats(bs->backing_hd);
|
||||||
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +336,7 @@ BlockInfoList *qmp_query_block(Error **errp)
|
|||||||
while ((bs = bdrv_next(bs))) {
|
while ((bs = bdrv_next(bs))) {
|
||||||
BlockInfoList *info = g_malloc0(sizeof(*info));
|
BlockInfoList *info = g_malloc0(sizeof(*info));
|
||||||
bdrv_query_info(bs, &info->value, &local_err);
|
bdrv_query_info(bs, &info->value, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -691,7 +691,8 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_file_open(&qcow_bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
ret = bdrv_file_open(&qcow_bs, filename, NULL, NULL, BDRV_O_RDWR,
|
||||||
|
&local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
|
|||||||
@@ -1182,7 +1182,7 @@ fail:
|
|||||||
* Return 0 on success and -errno in error cases
|
* Return 0 on success and -errno in error cases
|
||||||
*/
|
*/
|
||||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m)
|
int *num, uint64_t *host_offset, QCowL2Meta **m)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t start, remaining;
|
uint64_t start, remaining;
|
||||||
@@ -1190,15 +1190,13 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
uint64_t cur_bytes;
|
uint64_t cur_bytes;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset,
|
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset, *num);
|
||||||
n_start, n_end);
|
|
||||||
|
|
||||||
assert(n_start * BDRV_SECTOR_SIZE == offset_into_cluster(s, offset));
|
assert((offset & ~BDRV_SECTOR_MASK) == 0);
|
||||||
offset = start_of_cluster(s, offset);
|
|
||||||
|
|
||||||
again:
|
again:
|
||||||
start = offset + (n_start << BDRV_SECTOR_BITS);
|
start = offset;
|
||||||
remaining = (n_end - n_start) << BDRV_SECTOR_BITS;
|
remaining = *num << BDRV_SECTOR_BITS;
|
||||||
cluster_offset = 0;
|
cluster_offset = 0;
|
||||||
*host_offset = 0;
|
*host_offset = 0;
|
||||||
cur_bytes = 0;
|
cur_bytes = 0;
|
||||||
@@ -1284,7 +1282,7 @@ again:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*num = (n_end - n_start) - (remaining >> BDRV_SECTOR_BITS);
|
*num -= remaining >> BDRV_SECTOR_BITS;
|
||||||
assert(*num > 0);
|
assert(*num > 0);
|
||||||
assert(*host_offset != 0);
|
assert(*host_offset != 0);
|
||||||
|
|
||||||
|
|||||||
@@ -676,7 +676,13 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t cluster_index;
|
uint64_t cluster_index;
|
||||||
uint64_t old_free_cluster_index;
|
uint64_t old_free_cluster_index;
|
||||||
int i, refcount, ret;
|
uint64_t i;
|
||||||
|
int refcount, ret;
|
||||||
|
|
||||||
|
assert(nb_clusters >= 0);
|
||||||
|
if (nb_clusters == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check how many clusters there are free */
|
/* Check how many clusters there are free */
|
||||||
cluster_index = offset >> s->cluster_bits;
|
cluster_index = offset >> s->cluster_bits;
|
||||||
|
|||||||
@@ -606,7 +606,8 @@ int qcow2_snapshot_delete(BlockDriverState *bs,
|
|||||||
s->nb_snapshots--;
|
s->nb_snapshots--;
|
||||||
ret = qcow2_write_snapshots(bs);
|
ret = qcow2_write_snapshots(bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Failed to remove snapshot from snapshot list");
|
error_setg_errno(errp, -ret,
|
||||||
|
"Failed to remove snapshot from snapshot list");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,7 +625,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs,
|
|||||||
ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
|
ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
|
||||||
sn.l1_size, -1);
|
sn.l1_size, -1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Failed to free the cluster and L1 table");
|
error_setg_errno(errp, -ret, "Failed to free the cluster and L1 table");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t),
|
qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t),
|
||||||
@@ -633,7 +634,8 @@ int qcow2_snapshot_delete(BlockDriverState *bs,
|
|||||||
/* must update the copied flag on the current cluster offsets */
|
/* must update the copied flag on the current cluster offsets */
|
||||||
ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
|
ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Failed to update snapshot status in disk");
|
error_setg_errno(errp, -ret,
|
||||||
|
"Failed to update snapshot status in disk");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -671,7 +671,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
/* Enable lazy_refcounts according to image and command line options */
|
/* Enable lazy_refcounts according to image and command line options */
|
||||||
opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -718,7 +718,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
bs->bl.write_zeroes_alignment = s->cluster_sectors;
|
|
||||||
|
|
||||||
if (s->use_lazy_refcounts && s->qcow_version < 3) {
|
if (s->use_lazy_refcounts && s->qcow_version < 3) {
|
||||||
error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
|
error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
|
||||||
@@ -751,6 +750,15 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qcow2_refresh_limits(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
|
||||||
|
bs->bl.write_zeroes_alignment = s->cluster_sectors;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
@@ -992,7 +1000,6 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int index_in_cluster;
|
int index_in_cluster;
|
||||||
int n_end;
|
|
||||||
int ret;
|
int ret;
|
||||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
int cur_nr_sectors; /* number of sectors in current iteration */
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
@@ -1016,14 +1023,16 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
|||||||
|
|
||||||
trace_qcow2_writev_start_part(qemu_coroutine_self());
|
trace_qcow2_writev_start_part(qemu_coroutine_self());
|
||||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||||
n_end = index_in_cluster + remaining_sectors;
|
cur_nr_sectors = remaining_sectors;
|
||||||
if (s->crypt_method &&
|
if (s->crypt_method &&
|
||||||
n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors) {
|
cur_nr_sectors >
|
||||||
n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
|
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster) {
|
||||||
|
cur_nr_sectors =
|
||||||
|
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_alloc_cluster_offset(bs, sector_num << 9,
|
ret = qcow2_alloc_cluster_offset(bs, sector_num << 9,
|
||||||
index_in_cluster, n_end, &cur_nr_sectors, &cluster_offset, &l2meta);
|
&cur_nr_sectors, &cluster_offset, &l2meta);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -1395,34 +1404,34 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
int ret;
|
int ret;
|
||||||
QCowL2Meta *meta;
|
QCowL2Meta *meta;
|
||||||
|
|
||||||
nb_sectors = bdrv_getlength(bs) >> 9;
|
nb_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
while (nb_sectors) {
|
while (nb_sectors) {
|
||||||
num = MIN(nb_sectors, INT_MAX >> 9);
|
num = MIN(nb_sectors, INT_MAX >> BDRV_SECTOR_BITS);
|
||||||
ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
|
ret = qcow2_alloc_cluster_offset(bs, offset, &num,
|
||||||
&host_offset, &meta);
|
&host_offset, &meta);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
|
||||||
if (ret < 0) {
|
|
||||||
qcow2_free_any_clusters(bs, meta->alloc_offset, meta->nb_clusters,
|
|
||||||
QCOW2_DISCARD_NEVER);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There are no dependent requests, but we need to remove our request
|
|
||||||
* from the list of in-flight requests */
|
|
||||||
if (meta != NULL) {
|
if (meta != NULL) {
|
||||||
|
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
||||||
|
if (ret < 0) {
|
||||||
|
qcow2_free_any_clusters(bs, meta->alloc_offset,
|
||||||
|
meta->nb_clusters, QCOW2_DISCARD_NEVER);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There are no dependent requests, but we need to remove our
|
||||||
|
* request from the list of in-flight requests */
|
||||||
QLIST_REMOVE(meta, next_in_flight);
|
QLIST_REMOVE(meta, next_in_flight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Preallocate data if requested */
|
/* TODO Preallocate data if requested */
|
||||||
|
|
||||||
nb_sectors -= num;
|
nb_sectors -= num;
|
||||||
offset += num << 9;
|
offset += num << BDRV_SECTOR_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1431,9 +1440,10 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
* EOF). Extend the image to the last allocated sector.
|
* EOF). Extend the image to the last allocated sector.
|
||||||
*/
|
*/
|
||||||
if (host_offset != 0) {
|
if (host_offset != 0) {
|
||||||
uint8_t buf[512];
|
uint8_t buf[BDRV_SECTOR_SIZE];
|
||||||
memset(buf, 0, 512);
|
memset(buf, 0, BDRV_SECTOR_SIZE);
|
||||||
ret = bdrv_write(bs->file, (host_offset >> 9) + num - 1, buf, 1);
|
ret = bdrv_write(bs->file, (host_offset >> BDRV_SECTOR_BITS) + num - 1,
|
||||||
|
buf, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1483,7 +1493,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1595,7 +1605,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
ret = bdrv_open(bs, filename, NULL,
|
ret = bdrv_open(bs, filename, NULL,
|
||||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
||||||
drv, &local_err);
|
drv, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -1675,32 +1685,12 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
|
|
||||||
ret = qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
|
ret = qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
|
||||||
cluster_size, prealloc, options, version, &local_err);
|
cluster_size, prealloc, options, version, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcow2_make_empty(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
/* XXX: not correct */
|
|
||||||
BDRVQcowState *s = bs->opaque;
|
|
||||||
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
memset(s->l1_table, 0, l1_length);
|
|
||||||
if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_length) < 0)
|
|
||||||
return -1;
|
|
||||||
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
l2_cache_reset(bs);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
|
static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
@@ -2244,7 +2234,6 @@ static BlockDriver bdrv_qcow2 = {
|
|||||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||||
.bdrv_co_get_block_status = qcow2_co_get_block_status,
|
.bdrv_co_get_block_status = qcow2_co_get_block_status,
|
||||||
.bdrv_set_key = qcow2_set_key,
|
.bdrv_set_key = qcow2_set_key,
|
||||||
.bdrv_make_empty = qcow2_make_empty,
|
|
||||||
|
|
||||||
.bdrv_co_readv = qcow2_co_readv,
|
.bdrv_co_readv = qcow2_co_readv,
|
||||||
.bdrv_co_writev = qcow2_co_writev,
|
.bdrv_co_writev = qcow2_co_writev,
|
||||||
@@ -2268,6 +2257,7 @@ static BlockDriver bdrv_qcow2 = {
|
|||||||
|
|
||||||
.bdrv_change_backing_file = qcow2_change_backing_file,
|
.bdrv_change_backing_file = qcow2_change_backing_file,
|
||||||
|
|
||||||
|
.bdrv_refresh_limits = qcow2_refresh_limits,
|
||||||
.bdrv_invalidate_cache = qcow2_invalidate_cache,
|
.bdrv_invalidate_cache = qcow2_invalidate_cache,
|
||||||
|
|
||||||
.create_options = qcow2_create_options,
|
.create_options = qcow2_create_options,
|
||||||
|
|||||||
@@ -340,11 +340,11 @@ typedef enum QCow2MetadataOverlap {
|
|||||||
#define QCOW2_OL_ALL \
|
#define QCOW2_OL_ALL \
|
||||||
(QCOW2_OL_CACHED | QCOW2_OL_INACTIVE_L2)
|
(QCOW2_OL_CACHED | QCOW2_OL_INACTIVE_L2)
|
||||||
|
|
||||||
#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
|
#define L1E_OFFSET_MASK 0x00fffffffffffe00ULL
|
||||||
#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
|
#define L2E_OFFSET_MASK 0x00fffffffffffe00ULL
|
||||||
#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
|
#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
|
||||||
|
|
||||||
#define REFT_OFFSET_MASK 0xffffffffffffff00ULL
|
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
|
||||||
|
|
||||||
static inline int64_t start_of_cluster(BDRVQcowState *s, int64_t offset)
|
static inline int64_t start_of_cluster(BDRVQcowState *s, int64_t offset)
|
||||||
{
|
{
|
||||||
@@ -468,7 +468,7 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
|||||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int *num, uint64_t *cluster_offset);
|
int *num, uint64_t *cluster_offset);
|
||||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m);
|
int *num, uint64_t *host_offset, QCowL2Meta **m);
|
||||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
int compressed_size);
|
int compressed_size);
|
||||||
|
|||||||
21
block/qed.c
21
block/qed.c
@@ -495,7 +495,6 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->bl.write_zeroes_alignment = s->header.cluster_size >> BDRV_SECTOR_BITS;
|
|
||||||
s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
qed_need_check_timer_cb, s);
|
qed_need_check_timer_cb, s);
|
||||||
|
|
||||||
@@ -507,6 +506,15 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bdrv_qed_refresh_limits(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVQEDState *s = bs->opaque;
|
||||||
|
|
||||||
|
bs->bl.write_zeroes_alignment = s->header.cluster_size >> BDRV_SECTOR_BITS;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* We have nothing to do for QED reopen, stubs just return
|
/* We have nothing to do for QED reopen, stubs just return
|
||||||
* success */
|
* success */
|
||||||
static int bdrv_qed_reopen_prepare(BDRVReopenState *state,
|
static int bdrv_qed_reopen_prepare(BDRVReopenState *state,
|
||||||
@@ -563,8 +571,8 @@ static int qed_create(const char *filename, uint32_t cluster_size,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB,
|
ret = bdrv_file_open(&bs, filename, NULL, NULL,
|
||||||
&local_err);
|
BDRV_O_RDWR | BDRV_O_CACHE_WB, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
@@ -723,11 +731,6 @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
|
|||||||
return cb.status;
|
return cb.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bdrv_qed_make_empty(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
|
static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
|
||||||
{
|
{
|
||||||
return acb->common.bs->opaque;
|
return acb->common.bs->opaque;
|
||||||
@@ -1609,13 +1612,13 @@ static BlockDriver bdrv_qed = {
|
|||||||
.bdrv_create = bdrv_qed_create,
|
.bdrv_create = bdrv_qed_create,
|
||||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||||
.bdrv_co_get_block_status = bdrv_qed_co_get_block_status,
|
.bdrv_co_get_block_status = bdrv_qed_co_get_block_status,
|
||||||
.bdrv_make_empty = bdrv_qed_make_empty,
|
|
||||||
.bdrv_aio_readv = bdrv_qed_aio_readv,
|
.bdrv_aio_readv = bdrv_qed_aio_readv,
|
||||||
.bdrv_aio_writev = bdrv_qed_aio_writev,
|
.bdrv_aio_writev = bdrv_qed_aio_writev,
|
||||||
.bdrv_co_write_zeroes = bdrv_qed_co_write_zeroes,
|
.bdrv_co_write_zeroes = bdrv_qed_co_write_zeroes,
|
||||||
.bdrv_truncate = bdrv_qed_truncate,
|
.bdrv_truncate = bdrv_qed_truncate,
|
||||||
.bdrv_getlength = bdrv_qed_getlength,
|
.bdrv_getlength = bdrv_qed_getlength,
|
||||||
.bdrv_get_info = bdrv_qed_get_info,
|
.bdrv_get_info = bdrv_qed_get_info,
|
||||||
|
.bdrv_refresh_limits = bdrv_qed_refresh_limits,
|
||||||
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
|
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
|
||||||
.bdrv_invalidate_cache = bdrv_qed_invalidate_cache,
|
.bdrv_invalidate_cache = bdrv_qed_invalidate_cache,
|
||||||
.bdrv_check = bdrv_qed_check,
|
.bdrv_check = bdrv_qed_check,
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ typedef struct BDRVRawState {
|
|||||||
int fd;
|
int fd;
|
||||||
int type;
|
int type;
|
||||||
int open_flags;
|
int open_flags;
|
||||||
|
size_t buf_align;
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
/* linux floppy specific */
|
/* linux floppy specific */
|
||||||
int64_t fd_open_time;
|
int64_t fd_open_time;
|
||||||
@@ -213,6 +215,76 @@ static int raw_normalize_devicepath(const char **filename)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void raw_probe_alignment(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
char *buf;
|
||||||
|
unsigned int sector_size;
|
||||||
|
|
||||||
|
/* For /dev/sg devices the alignment is not really used.
|
||||||
|
With buffered I/O, we don't have any restrictions. */
|
||||||
|
if (bs->sg || !(s->open_flags & O_DIRECT)) {
|
||||||
|
bs->request_alignment = 1;
|
||||||
|
s->buf_align = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try a few ioctls to get the right size */
|
||||||
|
bs->request_alignment = 0;
|
||||||
|
s->buf_align = 0;
|
||||||
|
|
||||||
|
#ifdef BLKSSZGET
|
||||||
|
if (ioctl(s->fd, BLKSSZGET, §or_size) >= 0) {
|
||||||
|
bs->request_alignment = sector_size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef DKIOCGETBLOCKSIZE
|
||||||
|
if (ioctl(s->fd, DKIOCGETBLOCKSIZE, §or_size) >= 0) {
|
||||||
|
bs->request_alignment = sector_size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef DIOCGSECTORSIZE
|
||||||
|
if (ioctl(s->fd, DIOCGSECTORSIZE, §or_size) >= 0) {
|
||||||
|
bs->request_alignment = sector_size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_XFS
|
||||||
|
if (s->is_xfs) {
|
||||||
|
struct dioattr da;
|
||||||
|
if (xfsctl(NULL, s->fd, XFS_IOC_DIOINFO, &da) >= 0) {
|
||||||
|
bs->request_alignment = da.d_miniosz;
|
||||||
|
/* The kernel returns wrong information for d_mem */
|
||||||
|
/* s->buf_align = da.d_mem; */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we could not get the sizes so far, we can only guess them */
|
||||||
|
if (!s->buf_align) {
|
||||||
|
size_t align;
|
||||||
|
buf = qemu_memalign(MAX_BLOCKSIZE, 2 * MAX_BLOCKSIZE);
|
||||||
|
for (align = 512; align <= MAX_BLOCKSIZE; align <<= 1) {
|
||||||
|
if (pread(s->fd, buf + align, MAX_BLOCKSIZE, 0) >= 0) {
|
||||||
|
s->buf_align = align;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qemu_vfree(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bs->request_alignment) {
|
||||||
|
size_t align;
|
||||||
|
buf = qemu_memalign(s->buf_align, MAX_BLOCKSIZE);
|
||||||
|
for (align = 512; align <= MAX_BLOCKSIZE; align <<= 1) {
|
||||||
|
if (pread(s->fd, buf, align, 0) >= 0) {
|
||||||
|
bs->request_alignment = align;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qemu_vfree(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void raw_parse_flags(int bdrv_flags, int *open_flags)
|
static void raw_parse_flags(int bdrv_flags, int *open_flags)
|
||||||
{
|
{
|
||||||
assert(open_flags != NULL);
|
assert(open_flags != NULL);
|
||||||
@@ -289,7 +361,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -376,7 +448,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
s->type = FTYPE_FILE;
|
s->type = FTYPE_FILE;
|
||||||
ret = raw_open_common(bs, options, flags, 0, &local_err);
|
ret = raw_open_common(bs, options, flags, 0, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -463,7 +535,6 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void raw_reopen_commit(BDRVReopenState *state)
|
static void raw_reopen_commit(BDRVReopenState *state)
|
||||||
{
|
{
|
||||||
BDRVRawReopenState *raw_s = state->opaque;
|
BDRVRawReopenState *raw_s = state->opaque;
|
||||||
@@ -499,23 +570,15 @@ static void raw_reopen_abort(BDRVReopenState *state)
|
|||||||
state->opaque = NULL;
|
state->opaque = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int raw_refresh_limits(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
|
||||||
/* XXX: use host sector size if necessary with:
|
raw_probe_alignment(bs);
|
||||||
#ifdef DIOCGSECTORSIZE
|
bs->bl.opt_mem_alignment = s->buf_align;
|
||||||
{
|
|
||||||
unsigned int sectorsize = 512;
|
return 0;
|
||||||
if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) &&
|
}
|
||||||
sectorsize > bufsize)
|
|
||||||
bufsize = sectorsize;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_COCOA
|
|
||||||
uint32_t blockSize = 512;
|
|
||||||
if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
|
|
||||||
bufsize = blockSize;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
|
|
||||||
static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
|
static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
|
||||||
{
|
{
|
||||||
@@ -1363,6 +1426,7 @@ static BlockDriver bdrv_file = {
|
|||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
.bdrv_aio_discard = raw_aio_discard,
|
.bdrv_aio_discard = raw_aio_discard,
|
||||||
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
@@ -1533,7 +1597,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
ret = raw_open_common(bs, options, flags, 0, &local_err);
|
ret = raw_open_common(bs, options, flags, 0, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1740,6 +1804,7 @@ static BlockDriver bdrv_host_device = {
|
|||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
.bdrv_aio_discard = hdev_aio_discard,
|
.bdrv_aio_discard = hdev_aio_discard,
|
||||||
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
@@ -1767,7 +1832,7 @@ static int floppy_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
/* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
|
/* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
|
||||||
ret = raw_open_common(bs, options, flags, O_NONBLOCK, &local_err);
|
ret = raw_open_common(bs, options, flags, O_NONBLOCK, &local_err);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1871,6 +1936,7 @@ static BlockDriver bdrv_host_floppy = {
|
|||||||
.bdrv_aio_readv = raw_aio_readv,
|
.bdrv_aio_readv = raw_aio_readv,
|
||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
@@ -1895,7 +1961,7 @@ static int cdrom_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
/* open will not fail even if no CD is inserted, so add O_NONBLOCK */
|
/* open will not fail even if no CD is inserted, so add O_NONBLOCK */
|
||||||
ret = raw_open_common(bs, options, flags, O_NONBLOCK, &local_err);
|
ret = raw_open_common(bs, options, flags, O_NONBLOCK, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1981,6 +2047,7 @@ static BlockDriver bdrv_host_cdrom = {
|
|||||||
.bdrv_aio_readv = raw_aio_readv,
|
.bdrv_aio_readv = raw_aio_readv,
|
||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
@@ -2011,7 +2078,7 @@ static int cdrom_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
ret = raw_open_common(bs, options, flags, 0, &local_err);
|
ret = raw_open_common(bs, options, flags, 0, &local_err);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2110,6 +2177,7 @@ static BlockDriver bdrv_host_cdrom = {
|
|||||||
.bdrv_aio_readv = raw_aio_readv,
|
.bdrv_aio_readv = raw_aio_readv,
|
||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
|
|||||||
@@ -202,6 +202,35 @@ static int set_sparse(int fd)
|
|||||||
NULL, 0, NULL, 0, &returned, NULL);
|
NULL, 0, NULL, 0, &returned, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void raw_probe_alignment(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
DWORD sectorsPerCluster, freeClusters, totalClusters, count;
|
||||||
|
DISK_GEOMETRY_EX dg;
|
||||||
|
BOOL status;
|
||||||
|
|
||||||
|
if (s->type == FTYPE_CD) {
|
||||||
|
bs->request_alignment = 2048;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (s->type == FTYPE_HARDDISK) {
|
||||||
|
status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||||
|
NULL, 0, &dg, sizeof(dg), &count, NULL);
|
||||||
|
if (status != 0) {
|
||||||
|
bs->request_alignment = dg.Geometry.BytesPerSector;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* try GetDiskFreeSpace too */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->drive_path[0]) {
|
||||||
|
GetDiskFreeSpace(s->drive_path, §orsPerCluster,
|
||||||
|
&dg.Geometry.BytesPerSector,
|
||||||
|
&freeClusters, &totalClusters);
|
||||||
|
bs->request_alignment = dg.Geometry.BytesPerSector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
|
static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
|
||||||
{
|
{
|
||||||
assert(access_flags != NULL);
|
assert(access_flags != NULL);
|
||||||
@@ -250,7 +279,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -269,6 +298,17 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filename[0] && filename[1] == ':') {
|
||||||
|
snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]);
|
||||||
|
} else if (filename[0] == '\\' && filename[1] == '\\') {
|
||||||
|
s->drive_path[0] = 0;
|
||||||
|
} else {
|
||||||
|
/* Relative path. */
|
||||||
|
char buf[MAX_PATH];
|
||||||
|
GetCurrentDirectory(MAX_PATH, buf);
|
||||||
|
snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", buf[0]);
|
||||||
|
}
|
||||||
|
|
||||||
s->hfile = CreateFile(filename, access_flags,
|
s->hfile = CreateFile(filename, access_flags,
|
||||||
FILE_SHARE_READ, NULL,
|
FILE_SHARE_READ, NULL,
|
||||||
OPEN_EXISTING, overlapped, NULL);
|
OPEN_EXISTING, overlapped, NULL);
|
||||||
@@ -293,6 +333,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->aio = aio;
|
s->aio = aio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
raw_probe_alignment(bs);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
@@ -553,7 +594,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0,
|
QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
|
|||||||
@@ -90,6 +90,12 @@ static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|||||||
return bdrv_get_info(bs->file, bdi);
|
return bdrv_get_info(bs->file, bdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int raw_refresh_limits(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
bs->bl = bs->file->bl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
{
|
{
|
||||||
return bdrv_truncate(bs->file, offset);
|
return bdrv_truncate(bs->file, offset);
|
||||||
@@ -140,7 +146,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bdrv_create_file(filename, options, &local_err);
|
ret = bdrv_create_file(filename, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -150,7 +156,6 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
bs->sg = bs->file->sg;
|
bs->sg = bs->file->sg;
|
||||||
bs->bl = bs->file->bl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +187,7 @@ static BlockDriver bdrv_raw = {
|
|||||||
.bdrv_getlength = &raw_getlength,
|
.bdrv_getlength = &raw_getlength,
|
||||||
.has_variable_length = true,
|
.has_variable_length = true,
|
||||||
.bdrv_get_info = &raw_get_info,
|
.bdrv_get_info = &raw_get_info,
|
||||||
|
.bdrv_refresh_limits = &raw_refresh_limits,
|
||||||
.bdrv_is_inserted = &raw_is_inserted,
|
.bdrv_is_inserted = &raw_is_inserted,
|
||||||
.bdrv_media_changed = &raw_media_changed,
|
.bdrv_media_changed = &raw_media_changed,
|
||||||
.bdrv_eject = &raw_eject,
|
.bdrv_eject = &raw_eject,
|
||||||
|
|||||||
132
block/rbd.c
132
block/rbd.c
@@ -95,18 +95,13 @@ typedef struct RADOSCB {
|
|||||||
#define RBD_FD_WRITE 1
|
#define RBD_FD_WRITE 1
|
||||||
|
|
||||||
typedef struct BDRVRBDState {
|
typedef struct BDRVRBDState {
|
||||||
int fds[2];
|
|
||||||
rados_t cluster;
|
rados_t cluster;
|
||||||
rados_ioctx_t io_ctx;
|
rados_ioctx_t io_ctx;
|
||||||
rbd_image_t image;
|
rbd_image_t image;
|
||||||
char name[RBD_MAX_IMAGE_NAME_SIZE];
|
char name[RBD_MAX_IMAGE_NAME_SIZE];
|
||||||
char *snap;
|
char *snap;
|
||||||
int event_reader_pos;
|
|
||||||
RADOSCB *event_rcb;
|
|
||||||
} BDRVRBDState;
|
} BDRVRBDState;
|
||||||
|
|
||||||
static void rbd_aio_bh_cb(void *opaque);
|
|
||||||
|
|
||||||
static int qemu_rbd_next_tok(char *dst, int dst_len,
|
static int qemu_rbd_next_tok(char *dst, int dst_len,
|
||||||
char *src, char delim,
|
char *src, char delim,
|
||||||
const char *name,
|
const char *name,
|
||||||
@@ -369,9 +364,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This aio completion is being called from qemu_rbd_aio_event_reader()
|
* This aio completion is being called from rbd_finish_bh() and runs in qemu
|
||||||
* and runs in qemu context. It schedules a bh, but just in case the aio
|
* BH context.
|
||||||
* was not cancelled before.
|
|
||||||
*/
|
*/
|
||||||
static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
||||||
{
|
{
|
||||||
@@ -401,36 +395,19 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
|||||||
acb->ret = r;
|
acb->ret = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Note that acb->bh can be NULL in case where the aio was cancelled */
|
|
||||||
acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
|
|
||||||
qemu_bh_schedule(acb->bh);
|
|
||||||
g_free(rcb);
|
g_free(rcb);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
if (acb->cmd == RBD_AIO_READ) {
|
||||||
* aio fd read handler. It runs in the qemu context and calls the
|
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
|
||||||
* completion handling of completed rados aio operations.
|
}
|
||||||
*/
|
qemu_vfree(acb->bounce);
|
||||||
static void qemu_rbd_aio_event_reader(void *opaque)
|
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
||||||
{
|
acb->status = 0;
|
||||||
BDRVRBDState *s = opaque;
|
|
||||||
|
|
||||||
ssize_t ret;
|
if (!acb->cancelled) {
|
||||||
|
qemu_aio_release(acb);
|
||||||
do {
|
}
|
||||||
char *p = (char *)&s->event_rcb;
|
|
||||||
|
|
||||||
/* now read the rcb pointer that was sent from a non qemu thread */
|
|
||||||
ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
|
|
||||||
sizeof(s->event_rcb) - s->event_reader_pos);
|
|
||||||
if (ret > 0) {
|
|
||||||
s->event_reader_pos += ret;
|
|
||||||
if (s->event_reader_pos == sizeof(s->event_rcb)) {
|
|
||||||
s->event_reader_pos = 0;
|
|
||||||
qemu_rbd_complete_aio(s->event_rcb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Convert to fine grained options */
|
/* TODO Convert to fine grained options */
|
||||||
@@ -463,7 +440,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
@@ -538,23 +515,9 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
bs->read_only = (s->snap != NULL);
|
bs->read_only = (s->snap != NULL);
|
||||||
|
|
||||||
s->event_reader_pos = 0;
|
|
||||||
r = qemu_pipe(s->fds);
|
|
||||||
if (r < 0) {
|
|
||||||
error_report("error opening eventfd");
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
|
|
||||||
fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
|
|
||||||
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
|
|
||||||
NULL, s);
|
|
||||||
|
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
failed:
|
|
||||||
rbd_close(s->image);
|
|
||||||
failed_open:
|
failed_open:
|
||||||
rados_ioctx_destroy(s->io_ctx);
|
rados_ioctx_destroy(s->io_ctx);
|
||||||
failed_shutdown:
|
failed_shutdown:
|
||||||
@@ -569,10 +532,6 @@ static void qemu_rbd_close(BlockDriverState *bs)
|
|||||||
{
|
{
|
||||||
BDRVRBDState *s = bs->opaque;
|
BDRVRBDState *s = bs->opaque;
|
||||||
|
|
||||||
close(s->fds[0]);
|
|
||||||
close(s->fds[1]);
|
|
||||||
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL);
|
|
||||||
|
|
||||||
rbd_close(s->image);
|
rbd_close(s->image);
|
||||||
rados_ioctx_destroy(s->io_ctx);
|
rados_ioctx_destroy(s->io_ctx);
|
||||||
g_free(s->snap);
|
g_free(s->snap);
|
||||||
@@ -600,34 +559,11 @@ static const AIOCBInfo rbd_aiocb_info = {
|
|||||||
.cancel = qemu_rbd_aio_cancel,
|
.cancel = qemu_rbd_aio_cancel,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qemu_rbd_send_pipe(BDRVRBDState *s, RADOSCB *rcb)
|
static void rbd_finish_bh(void *opaque)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
RADOSCB *rcb = opaque;
|
||||||
while (1) {
|
qemu_bh_delete(rcb->acb->bh);
|
||||||
fd_set wfd;
|
qemu_rbd_complete_aio(rcb);
|
||||||
int fd = s->fds[RBD_FD_WRITE];
|
|
||||||
|
|
||||||
/* send the op pointer to the qemu thread that is responsible
|
|
||||||
for the aio/op completion. Must do it in a qemu thread context */
|
|
||||||
ret = write(fd, (void *)&rcb, sizeof(rcb));
|
|
||||||
if (ret >= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (errno == EINTR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (errno != EAGAIN) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_ZERO(&wfd);
|
|
||||||
FD_SET(fd, &wfd);
|
|
||||||
do {
|
|
||||||
ret = select(fd + 1, NULL, &wfd, NULL, NULL);
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -635,40 +571,18 @@ static int qemu_rbd_send_pipe(BDRVRBDState *s, RADOSCB *rcb)
|
|||||||
*
|
*
|
||||||
* Note: this function is being called from a non qemu thread so
|
* Note: this function is being called from a non qemu thread so
|
||||||
* we need to be careful about what we do here. Generally we only
|
* we need to be careful about what we do here. Generally we only
|
||||||
* write to the block notification pipe, and do the rest of the
|
* schedule a BH, and do the rest of the io completion handling
|
||||||
* io completion handling from qemu_rbd_aio_event_reader() which
|
* from rbd_finish_bh() which runs in a qemu context.
|
||||||
* runs in a qemu context.
|
|
||||||
*/
|
*/
|
||||||
static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
|
static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
|
||||||
{
|
{
|
||||||
int ret;
|
RBDAIOCB *acb = rcb->acb;
|
||||||
|
|
||||||
rcb->ret = rbd_aio_get_return_value(c);
|
rcb->ret = rbd_aio_get_return_value(c);
|
||||||
rbd_aio_release(c);
|
rbd_aio_release(c);
|
||||||
ret = qemu_rbd_send_pipe(rcb->s, rcb);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_report("failed writing to acb->s->fds");
|
|
||||||
g_free(rcb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Callback when all queued rbd_aio requests are complete */
|
acb->bh = qemu_bh_new(rbd_finish_bh, rcb);
|
||||||
|
qemu_bh_schedule(acb->bh);
|
||||||
static void rbd_aio_bh_cb(void *opaque)
|
|
||||||
{
|
|
||||||
RBDAIOCB *acb = opaque;
|
|
||||||
|
|
||||||
if (acb->cmd == RBD_AIO_READ) {
|
|
||||||
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
|
|
||||||
}
|
|
||||||
qemu_vfree(acb->bounce);
|
|
||||||
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
|
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
acb->bh = NULL;
|
|
||||||
acb->status = 0;
|
|
||||||
|
|
||||||
if (!acb->cancelled) {
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rbd_aio_discard_wrapper(rbd_image_t image,
|
static int rbd_aio_discard_wrapper(rbd_image_t image,
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ typedef struct SheepdogVdiReq {
|
|||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t data_length;
|
uint32_t data_length;
|
||||||
uint64_t vdi_size;
|
uint64_t vdi_size;
|
||||||
uint32_t vdi_id;
|
uint32_t base_vdi_id;
|
||||||
uint8_t copies;
|
uint8_t copies;
|
||||||
uint8_t copy_policy;
|
uint8_t copy_policy;
|
||||||
uint8_t reserved[2];
|
uint8_t reserved[2];
|
||||||
@@ -1385,7 +1385,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@@ -1493,7 +1493,7 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
|||||||
|
|
||||||
memset(&hdr, 0, sizeof(hdr));
|
memset(&hdr, 0, sizeof(hdr));
|
||||||
hdr.opcode = SD_OP_NEW_VDI;
|
hdr.opcode = SD_OP_NEW_VDI;
|
||||||
hdr.vdi_id = s->inode.vdi_id;
|
hdr.base_vdi_id = s->inode.vdi_id;
|
||||||
|
|
||||||
wlen = SD_MAX_VDI_LEN;
|
wlen = SD_MAX_VDI_LEN;
|
||||||
|
|
||||||
@@ -1534,7 +1534,7 @@ static int sd_prealloc(const char *filename)
|
|||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
@@ -1684,7 +1684,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
|
|
||||||
if (backing_file) {
|
if (backing_file) {
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
BDRVSheepdogState *s;
|
BDRVSheepdogState *base;
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
|
|
||||||
/* Currently, only Sheepdog backing image is supported. */
|
/* Currently, only Sheepdog backing image is supported. */
|
||||||
@@ -1695,22 +1695,22 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs, backing_file, NULL, 0, &local_err);
|
ret = bdrv_file_open(&bs, backing_file, NULL, NULL, 0, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = bs->opaque;
|
base = bs->opaque;
|
||||||
|
|
||||||
if (!is_snapshot(&s->inode)) {
|
if (!is_snapshot(&base->inode)) {
|
||||||
error_report("cannot clone from a non snapshot vdi");
|
error_report("cannot clone from a non snapshot vdi");
|
||||||
bdrv_unref(bs);
|
bdrv_unref(bs);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
s->inode.vdi_id = base->inode.vdi_id;
|
||||||
bdrv_unref(bs);
|
bdrv_unref(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1743,7 +1743,7 @@ static void sd_close(BlockDriverState *bs)
|
|||||||
memset(&hdr, 0, sizeof(hdr));
|
memset(&hdr, 0, sizeof(hdr));
|
||||||
|
|
||||||
hdr.opcode = SD_OP_RELEASE_VDI;
|
hdr.opcode = SD_OP_RELEASE_VDI;
|
||||||
hdr.vdi_id = s->inode.vdi_id;
|
hdr.base_vdi_id = s->inode.vdi_id;
|
||||||
wlen = strlen(s->name) + 1;
|
wlen = strlen(s->name) + 1;
|
||||||
hdr.data_length = wlen;
|
hdr.data_length = wlen;
|
||||||
hdr.flags = SD_FLAG_CMD_WRITE;
|
hdr.flags = SD_FLAG_CMD_WRITE;
|
||||||
@@ -1846,7 +1846,7 @@ static bool sd_delete(BDRVSheepdogState *s)
|
|||||||
unsigned int wlen = SD_MAX_VDI_LEN, rlen = 0;
|
unsigned int wlen = SD_MAX_VDI_LEN, rlen = 0;
|
||||||
SheepdogVdiReq hdr = {
|
SheepdogVdiReq hdr = {
|
||||||
.opcode = SD_OP_DEL_VDI,
|
.opcode = SD_OP_DEL_VDI,
|
||||||
.vdi_id = s->inode.vdi_id,
|
.base_vdi_id = s->inode.vdi_id,
|
||||||
.data_length = wlen,
|
.data_length = wlen,
|
||||||
.flags = SD_FLAG_CMD_WRITE,
|
.flags = SD_FLAG_CMD_WRITE,
|
||||||
};
|
};
|
||||||
@@ -2442,11 +2442,12 @@ sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
|||||||
{
|
{
|
||||||
BDRVSheepdogState *s = bs->opaque;
|
BDRVSheepdogState *s = bs->opaque;
|
||||||
SheepdogInode *inode = &s->inode;
|
SheepdogInode *inode = &s->inode;
|
||||||
unsigned long start = sector_num * BDRV_SECTOR_SIZE / SD_DATA_OBJ_SIZE,
|
uint64_t offset = sector_num * BDRV_SECTOR_SIZE;
|
||||||
|
unsigned long start = offset / SD_DATA_OBJ_SIZE,
|
||||||
end = DIV_ROUND_UP((sector_num + nb_sectors) *
|
end = DIV_ROUND_UP((sector_num + nb_sectors) *
|
||||||
BDRV_SECTOR_SIZE, SD_DATA_OBJ_SIZE);
|
BDRV_SECTOR_SIZE, SD_DATA_OBJ_SIZE);
|
||||||
unsigned long idx;
|
unsigned long idx;
|
||||||
int64_t ret = BDRV_BLOCK_DATA;
|
int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset;
|
||||||
|
|
||||||
for (idx = start; idx < end; idx++) {
|
for (idx = start; idx < end; idx++) {
|
||||||
if (inode->data_vdi_id[idx] == 0) {
|
if (inode->data_vdi_id[idx] == 0) {
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
|
|||||||
ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err);
|
ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
|
|||||||
unused->backing_hd = NULL;
|
unused->backing_hd = NULL;
|
||||||
bdrv_unref(unused);
|
bdrv_unref(unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bdrv_refresh_limits(top);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn stream_run(void *opaque)
|
static void coroutine_fn stream_run(void *opaque)
|
||||||
|
|||||||
@@ -965,8 +965,8 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
cpu_to_le32s((uint32_t *)(buffer + 4));
|
cpu_to_le32s((uint32_t *)(buffer + 4));
|
||||||
|
|
||||||
/* now write to the log */
|
/* now write to the log */
|
||||||
vhdx_log_write_sectors(bs, &s->log, §ors_written, buffer,
|
ret = vhdx_log_write_sectors(bs, &s->log, §ors_written, buffer,
|
||||||
desc_sectors + sectors);
|
desc_sectors + sectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|||||||
10
block/vhdx.c
10
block/vhdx.c
@@ -374,7 +374,7 @@ static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
inactive_header->log_guid = *log_guid;
|
inactive_header->log_guid = *log_guid;
|
||||||
}
|
}
|
||||||
|
|
||||||
vhdx_write_header(bs->file, inactive_header, header_offset, true);
|
ret = vhdx_write_header(bs->file, inactive_header, header_offset, true);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1797,7 +1797,7 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -1810,13 +1810,13 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL,
|
creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL,
|
||||||
&creator_items, NULL);
|
&creator_items, NULL);
|
||||||
signature = cpu_to_le64(VHDX_FILE_SIGNATURE);
|
signature = cpu_to_le64(VHDX_FILE_SIGNATURE);
|
||||||
bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature));
|
ret = bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto delete_and_exit;
|
goto delete_and_exit;
|
||||||
}
|
}
|
||||||
if (creator) {
|
if (creator) {
|
||||||
bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET + sizeof(signature), creator,
|
ret = bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET + sizeof(signature),
|
||||||
creator_items * sizeof(gunichar2));
|
creator, creator_items * sizeof(gunichar2));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto delete_and_exit;
|
goto delete_and_exit;
|
||||||
}
|
}
|
||||||
|
|||||||
99
block/vmdk.c
99
block/vmdk.c
@@ -428,10 +428,6 @@ static int vmdk_add_extent(BlockDriverState *bs,
|
|||||||
extent->l2_size = l2_size;
|
extent->l2_size = l2_size;
|
||||||
extent->cluster_sectors = flat ? sectors : cluster_sectors;
|
extent->cluster_sectors = flat ? sectors : cluster_sectors;
|
||||||
|
|
||||||
if (!flat) {
|
|
||||||
bs->bl.write_zeroes_alignment =
|
|
||||||
MAX(bs->bl.write_zeroes_alignment, cluster_sectors);
|
|
||||||
}
|
|
||||||
if (s->num_extents > 1) {
|
if (s->num_extents > 1) {
|
||||||
extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
|
extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
|
||||||
} else {
|
} else {
|
||||||
@@ -640,6 +636,13 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) {
|
if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) {
|
||||||
l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9;
|
l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9;
|
||||||
}
|
}
|
||||||
|
if (bdrv_getlength(file) <
|
||||||
|
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) {
|
||||||
|
error_report("File truncated, expecting at least %lld bytes",
|
||||||
|
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = vmdk_add_extent(bs, file, false,
|
ret = vmdk_add_extent(bs, file, false,
|
||||||
le64_to_cpu(header.capacity),
|
le64_to_cpu(header.capacity),
|
||||||
le64_to_cpu(header.gd_offset) << 9,
|
le64_to_cpu(header.gd_offset) << 9,
|
||||||
@@ -654,6 +657,10 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
extent->compressed =
|
extent->compressed =
|
||||||
le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
|
le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
|
||||||
|
if (extent->compressed) {
|
||||||
|
g_free(s->create_type);
|
||||||
|
s->create_type = g_strdup("streamOptimized");
|
||||||
|
}
|
||||||
extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER;
|
extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER;
|
||||||
extent->version = le32_to_cpu(header.version);
|
extent->version = le32_to_cpu(header.version);
|
||||||
extent->has_zero_grain = le32_to_cpu(header.flags) & VMDK4_FLAG_ZERO_GRAIN;
|
extent->has_zero_grain = le32_to_cpu(header.flags) & VMDK4_FLAG_ZERO_GRAIN;
|
||||||
@@ -769,8 +776,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
|||||||
|
|
||||||
path_combine(extent_path, sizeof(extent_path),
|
path_combine(extent_path, sizeof(extent_path),
|
||||||
desc_file_path, fname);
|
desc_file_path, fname);
|
||||||
ret = bdrv_file_open(&extent_file, extent_path, NULL, bs->open_flags,
|
ret = bdrv_file_open(&extent_file, extent_path, NULL, NULL,
|
||||||
errp);
|
bs->open_flags, errp);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -891,6 +898,23 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int vmdk_refresh_limits(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < s->num_extents; i++) {
|
||||||
|
if (!s->extents[i].flat) {
|
||||||
|
bs->bl.write_zeroes_alignment =
|
||||||
|
MAX(bs->bl.write_zeroes_alignment,
|
||||||
|
s->extents[i].cluster_sectors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int get_whole_cluster(BlockDriverState *bs,
|
static int get_whole_cluster(BlockDriverState *bs,
|
||||||
VmdkExtent *extent,
|
VmdkExtent *extent,
|
||||||
uint64_t cluster_offset,
|
uint64_t cluster_offset,
|
||||||
@@ -1325,8 +1349,8 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
{
|
{
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
VmdkExtent *extent = NULL;
|
VmdkExtent *extent = NULL;
|
||||||
int n, ret;
|
int ret;
|
||||||
int64_t index_in_cluster;
|
int64_t index_in_cluster, n;
|
||||||
uint64_t extent_begin_sector, extent_relative_sector_num;
|
uint64_t extent_begin_sector, extent_relative_sector_num;
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
VmdkMetaData m_data;
|
VmdkMetaData m_data;
|
||||||
@@ -1469,7 +1493,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -1478,7 +1502,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
|||||||
if (flat) {
|
if (flat) {
|
||||||
ret = bdrv_truncate(bs, filesize);
|
ret = bdrv_truncate(bs, filesize);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Could not truncate file");
|
error_setg_errno(errp, -ret, "Could not truncate file");
|
||||||
}
|
}
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1538,7 +1562,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
|||||||
|
|
||||||
ret = bdrv_truncate(bs, le64_to_cpu(header.grain_offset) << 9);
|
ret = bdrv_truncate(bs, le64_to_cpu(header.grain_offset) << 9);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Could not truncate file");
|
error_setg_errno(errp, -ret, "Could not truncate file");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1807,7 +1831,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = bdrv_file_open(&new_bs, filename, NULL, BDRV_O_RDWR, &local_err);
|
ret = bdrv_file_open(&new_bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not write description");
|
error_setg_errno(errp, -ret, "Could not write description");
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -1822,7 +1846,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
if (desc_offset == 0) {
|
if (desc_offset == 0) {
|
||||||
ret = bdrv_truncate(new_bs, desc_len);
|
ret = bdrv_truncate(new_bs, desc_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Could not truncate file");
|
error_setg_errno(errp, -ret, "Could not truncate file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit:
|
exit:
|
||||||
@@ -1918,6 +1942,53 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result,
|
||||||
|
BdrvCheckMode fix)
|
||||||
|
{
|
||||||
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
VmdkExtent *extent = NULL;
|
||||||
|
int64_t sector_num = 0;
|
||||||
|
int64_t total_sectors = bdrv_getlength(bs) / BDRV_SECTOR_SIZE;
|
||||||
|
int ret;
|
||||||
|
uint64_t cluster_offset;
|
||||||
|
|
||||||
|
if (fix) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (sector_num >= total_sectors) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
extent = find_extent(s, sector_num, extent);
|
||||||
|
if (!extent) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: could not find extent for sector %" PRId64 "\n",
|
||||||
|
sector_num);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = get_cluster_offset(bs, extent, NULL,
|
||||||
|
sector_num << BDRV_SECTOR_BITS,
|
||||||
|
0, &cluster_offset);
|
||||||
|
if (ret == VMDK_ERROR) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: could not get cluster_offset for sector %"
|
||||||
|
PRId64 "\n", sector_num);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret == VMDK_OK && cluster_offset >= bdrv_getlength(extent->file)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: cluster offset for sector %"
|
||||||
|
PRId64 " points after EOF\n", sector_num);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sector_num += extent->cluster_sectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->corruptions++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
|
static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -1991,6 +2062,7 @@ static BlockDriver bdrv_vmdk = {
|
|||||||
.instance_size = sizeof(BDRVVmdkState),
|
.instance_size = sizeof(BDRVVmdkState),
|
||||||
.bdrv_probe = vmdk_probe,
|
.bdrv_probe = vmdk_probe,
|
||||||
.bdrv_open = vmdk_open,
|
.bdrv_open = vmdk_open,
|
||||||
|
.bdrv_check = vmdk_check,
|
||||||
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
||||||
.bdrv_read = vmdk_co_read,
|
.bdrv_read = vmdk_co_read,
|
||||||
.bdrv_write = vmdk_co_write,
|
.bdrv_write = vmdk_co_write,
|
||||||
@@ -2002,6 +2074,7 @@ static BlockDriver bdrv_vmdk = {
|
|||||||
.bdrv_get_allocated_file_size = vmdk_get_allocated_file_size,
|
.bdrv_get_allocated_file_size = vmdk_get_allocated_file_size,
|
||||||
.bdrv_has_zero_init = vmdk_has_zero_init,
|
.bdrv_has_zero_init = vmdk_has_zero_init,
|
||||||
.bdrv_get_specific_info = vmdk_get_specific_info,
|
.bdrv_get_specific_info = vmdk_get_specific_info,
|
||||||
|
.bdrv_refresh_limits = vmdk_refresh_limits,
|
||||||
|
|
||||||
.create_options = vmdk_create_options,
|
.create_options = vmdk_create_options,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1085,7 +1085,7 @@ DLOG(if (stderr == NULL) {
|
|||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|||||||
199
blockdev.c
199
blockdev.c
@@ -307,12 +307,10 @@ static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
|
|||||||
typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
|
typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
|
||||||
|
|
||||||
/* Takes the ownership of bs_opts */
|
/* Takes the ownership of bs_opts */
|
||||||
static DriveInfo *blockdev_init(QDict *bs_opts,
|
static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||||
BlockInterfaceType type,
|
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
const char *buf;
|
const char *buf;
|
||||||
const char *file = NULL;
|
|
||||||
const char *serial;
|
const char *serial;
|
||||||
int ro = 0;
|
int ro = 0;
|
||||||
int bdrv_flags = 0;
|
int bdrv_flags = 0;
|
||||||
@@ -332,13 +330,13 @@ static DriveInfo *blockdev_init(QDict *bs_opts,
|
|||||||
* stay in bs_opts for processing by bdrv_open(). */
|
* stay in bs_opts for processing by bdrv_open(). */
|
||||||
id = qdict_get_try_str(bs_opts, "id");
|
id = qdict_get_try_str(bs_opts, "id");
|
||||||
opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error);
|
opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error);
|
||||||
if (error_is_set(&error)) {
|
if (error) {
|
||||||
error_propagate(errp, error);
|
error_propagate(errp, error);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_opts_absorb_qdict(opts, bs_opts, &error);
|
qemu_opts_absorb_qdict(opts, bs_opts, &error);
|
||||||
if (error_is_set(&error)) {
|
if (error) {
|
||||||
error_propagate(errp, error);
|
error_propagate(errp, error);
|
||||||
goto early_err;
|
goto early_err;
|
||||||
}
|
}
|
||||||
@@ -354,7 +352,6 @@ static DriveInfo *blockdev_init(QDict *bs_opts,
|
|||||||
ro = qemu_opt_get_bool(opts, "read-only", 0);
|
ro = qemu_opt_get_bool(opts, "read-only", 0);
|
||||||
copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false);
|
copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false);
|
||||||
|
|
||||||
file = qemu_opt_get(opts, "file");
|
|
||||||
serial = qemu_opt_get(opts, "serial");
|
serial = qemu_opt_get(opts, "serial");
|
||||||
|
|
||||||
if ((buf = qemu_opt_get(opts, "discard")) != NULL) {
|
if ((buf = qemu_opt_get(opts, "discard")) != NULL) {
|
||||||
@@ -439,13 +436,8 @@ static DriveInfo *blockdev_init(QDict *bs_opts,
|
|||||||
|
|
||||||
on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
|
on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
|
||||||
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
|
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
|
||||||
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
|
|
||||||
error_setg(errp, "werror is not supported by this bus type");
|
|
||||||
goto early_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
on_write_error = parse_block_error_action(buf, 0, &error);
|
on_write_error = parse_block_error_action(buf, 0, &error);
|
||||||
if (error_is_set(&error)) {
|
if (error) {
|
||||||
error_propagate(errp, error);
|
error_propagate(errp, error);
|
||||||
goto early_err;
|
goto early_err;
|
||||||
}
|
}
|
||||||
@@ -453,25 +445,25 @@ static DriveInfo *blockdev_init(QDict *bs_opts,
|
|||||||
|
|
||||||
on_read_error = BLOCKDEV_ON_ERROR_REPORT;
|
on_read_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||||
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
|
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
|
||||||
if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
|
|
||||||
error_report("rerror is not supported by this bus type");
|
|
||||||
goto early_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
on_read_error = parse_block_error_action(buf, 1, &error);
|
on_read_error = parse_block_error_action(buf, 1, &error);
|
||||||
if (error_is_set(&error)) {
|
if (error) {
|
||||||
error_propagate(errp, error);
|
error_propagate(errp, error);
|
||||||
goto early_err;
|
goto early_err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bdrv_find_node(qemu_opts_id(opts))) {
|
||||||
|
error_setg(errp, "device id=%s is conflicting with a node-name",
|
||||||
|
qemu_opts_id(opts));
|
||||||
|
goto early_err;
|
||||||
|
}
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
dinfo = g_malloc0(sizeof(*dinfo));
|
dinfo = g_malloc0(sizeof(*dinfo));
|
||||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||||
dinfo->bdrv = bdrv_new(dinfo->id);
|
dinfo->bdrv = bdrv_new(dinfo->id);
|
||||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||||
dinfo->bdrv->read_only = ro;
|
dinfo->bdrv->read_only = ro;
|
||||||
dinfo->type = type;
|
|
||||||
dinfo->refcount = 1;
|
dinfo->refcount = 1;
|
||||||
if (serial != NULL) {
|
if (serial != NULL) {
|
||||||
dinfo->serial = g_strdup(serial);
|
dinfo->serial = g_strdup(serial);
|
||||||
@@ -599,6 +591,10 @@ QemuOptsList qemu_legacy_drive_opts = {
|
|||||||
.name = "addr",
|
.name = "addr",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "pci address (virtio only)",
|
.help = "pci address (virtio only)",
|
||||||
|
},{
|
||||||
|
.name = "file",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "file name",
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Options that are passed on, but have special semantics with -drive */
|
/* Options that are passed on, but have special semantics with -drive */
|
||||||
@@ -606,6 +602,14 @@ QemuOptsList qemu_legacy_drive_opts = {
|
|||||||
.name = "read-only",
|
.name = "read-only",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
.help = "open drive file as read-only",
|
.help = "open drive file as read-only",
|
||||||
|
},{
|
||||||
|
.name = "rerror",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "read error action",
|
||||||
|
},{
|
||||||
|
.name = "werror",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "write error action",
|
||||||
},{
|
},{
|
||||||
.name = "copy-on-read",
|
.name = "copy-on-read",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
@@ -627,8 +631,10 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
|||||||
int cyls, heads, secs, translation;
|
int cyls, heads, secs, translation;
|
||||||
int max_devs, bus_id, unit_id, index;
|
int max_devs, bus_id, unit_id, index;
|
||||||
const char *devaddr;
|
const char *devaddr;
|
||||||
|
const char *werror, *rerror;
|
||||||
bool read_only = false;
|
bool read_only = false;
|
||||||
bool copy_on_read;
|
bool copy_on_read;
|
||||||
|
const char *filename;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
/* Change legacy command line options into QMP ones */
|
/* Change legacy command line options into QMP ones */
|
||||||
@@ -685,7 +691,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
|||||||
legacy_opts = qemu_opts_create(&qemu_legacy_drive_opts, NULL, 0,
|
legacy_opts = qemu_opts_create(&qemu_legacy_drive_opts, NULL, 0,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err);
|
qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -773,6 +779,10 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
|||||||
translation = BIOS_ATA_TRANSLATION_NONE;
|
translation = BIOS_ATA_TRANSLATION_NONE;
|
||||||
} else if (!strcmp(value, "lba")) {
|
} else if (!strcmp(value, "lba")) {
|
||||||
translation = BIOS_ATA_TRANSLATION_LBA;
|
translation = BIOS_ATA_TRANSLATION_LBA;
|
||||||
|
} else if (!strcmp(value, "large")) {
|
||||||
|
translation = BIOS_ATA_TRANSLATION_LARGE;
|
||||||
|
} else if (!strcmp(value, "rechs")) {
|
||||||
|
translation = BIOS_ATA_TRANSLATION_RECHS;
|
||||||
} else if (!strcmp(value, "auto")) {
|
} else if (!strcmp(value, "auto")) {
|
||||||
translation = BIOS_ATA_TRANSLATION_AUTO;
|
translation = BIOS_ATA_TRANSLATION_AUTO;
|
||||||
} else {
|
} else {
|
||||||
@@ -867,16 +877,39 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filename = qemu_opt_get(legacy_opts, "file");
|
||||||
|
|
||||||
|
/* Check werror/rerror compatibility with if=... */
|
||||||
|
werror = qemu_opt_get(legacy_opts, "werror");
|
||||||
|
if (werror != NULL) {
|
||||||
|
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO &&
|
||||||
|
type != IF_NONE) {
|
||||||
|
error_report("werror is not supported by this bus type");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
qdict_put(bs_opts, "werror", qstring_from_str(werror));
|
||||||
|
}
|
||||||
|
|
||||||
|
rerror = qemu_opt_get(legacy_opts, "rerror");
|
||||||
|
if (rerror != NULL) {
|
||||||
|
if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI &&
|
||||||
|
type != IF_NONE) {
|
||||||
|
error_report("rerror is not supported by this bus type");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
qdict_put(bs_opts, "rerror", qstring_from_str(rerror));
|
||||||
|
}
|
||||||
|
|
||||||
/* Actual block device init: Functionality shared with blockdev-add */
|
/* Actual block device init: Functionality shared with blockdev-add */
|
||||||
dinfo = blockdev_init(bs_opts, type, &local_err);
|
dinfo = blockdev_init(filename, bs_opts, &local_err);
|
||||||
if (dinfo == NULL) {
|
if (dinfo == NULL) {
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
qerror_report_err(local_err);
|
qerror_report_err(local_err);
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
}
|
}
|
||||||
goto fail;
|
goto fail;
|
||||||
} else {
|
} else {
|
||||||
assert(!error_is_set(&local_err));
|
assert(!local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set legacy DriveInfo fields */
|
/* Set legacy DriveInfo fields */
|
||||||
@@ -888,6 +921,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
|||||||
dinfo->secs = secs;
|
dinfo->secs = secs;
|
||||||
dinfo->trans = translation;
|
dinfo->trans = translation;
|
||||||
|
|
||||||
|
dinfo->type = type;
|
||||||
dinfo->bus = bus_id;
|
dinfo->bus = bus_id;
|
||||||
dinfo->unit = unit_id;
|
dinfo->unit = unit_id;
|
||||||
dinfo->devaddr = devaddr;
|
dinfo->devaddr = devaddr;
|
||||||
@@ -942,14 +976,22 @@ static void blockdev_do_action(int kind, void *data, Error **errp)
|
|||||||
qmp_transaction(&list, errp);
|
qmp_transaction(&list, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
|
void qmp_blockdev_snapshot_sync(bool has_device, const char *device,
|
||||||
|
bool has_node_name, const char *node_name,
|
||||||
|
const char *snapshot_file,
|
||||||
|
bool has_snapshot_node_name,
|
||||||
|
const char *snapshot_node_name,
|
||||||
bool has_format, const char *format,
|
bool has_format, const char *format,
|
||||||
bool has_mode, enum NewImageMode mode,
|
bool has_mode, NewImageMode mode, Error **errp)
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
BlockdevSnapshot snapshot = {
|
BlockdevSnapshot snapshot = {
|
||||||
|
.has_device = has_device,
|
||||||
.device = (char *) device,
|
.device = (char *) device,
|
||||||
|
.has_node_name = has_node_name,
|
||||||
|
.node_name = (char *) node_name,
|
||||||
.snapshot_file = (char *) snapshot_file,
|
.snapshot_file = (char *) snapshot_file,
|
||||||
|
.has_snapshot_node_name = has_snapshot_node_name,
|
||||||
|
.snapshot_node_name = (char *) snapshot_node_name,
|
||||||
.has_format = has_format,
|
.has_format = has_format,
|
||||||
.format = (char *) format,
|
.format = (char *) format,
|
||||||
.has_mode = has_mode,
|
.has_mode = has_mode,
|
||||||
@@ -1004,7 +1046,7 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
|
ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1017,7 +1059,7 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bdrv_snapshot_delete(bs, id, name, &local_err);
|
bdrv_snapshot_delete(bs, id, name, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1187,8 +1229,14 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
|||||||
{
|
{
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
int flags, ret;
|
int flags, ret;
|
||||||
|
QDict *options = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
bool has_device = false;
|
||||||
const char *device;
|
const char *device;
|
||||||
|
bool has_node_name = false;
|
||||||
|
const char *node_name;
|
||||||
|
bool has_snapshot_node_name = false;
|
||||||
|
const char *snapshot_node_name;
|
||||||
const char *new_image_file;
|
const char *new_image_file;
|
||||||
const char *format = "qcow2";
|
const char *format = "qcow2";
|
||||||
enum NewImageMode mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
enum NewImageMode mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||||
@@ -1199,7 +1247,14 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
|||||||
/* get parameters */
|
/* get parameters */
|
||||||
g_assert(action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC);
|
g_assert(action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC);
|
||||||
|
|
||||||
|
has_device = action->blockdev_snapshot_sync->has_device;
|
||||||
device = action->blockdev_snapshot_sync->device;
|
device = action->blockdev_snapshot_sync->device;
|
||||||
|
has_node_name = action->blockdev_snapshot_sync->has_node_name;
|
||||||
|
node_name = action->blockdev_snapshot_sync->node_name;
|
||||||
|
has_snapshot_node_name =
|
||||||
|
action->blockdev_snapshot_sync->has_snapshot_node_name;
|
||||||
|
snapshot_node_name = action->blockdev_snapshot_sync->snapshot_node_name;
|
||||||
|
|
||||||
new_image_file = action->blockdev_snapshot_sync->snapshot_file;
|
new_image_file = action->blockdev_snapshot_sync->snapshot_file;
|
||||||
if (action->blockdev_snapshot_sync->has_format) {
|
if (action->blockdev_snapshot_sync->has_format) {
|
||||||
format = action->blockdev_snapshot_sync->format;
|
format = action->blockdev_snapshot_sync->format;
|
||||||
@@ -1215,9 +1270,21 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->old_bs = bdrv_find(device);
|
state->old_bs = bdrv_lookup_bs(has_device ? device : NULL,
|
||||||
if (!state->old_bs) {
|
has_node_name ? node_name : NULL,
|
||||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_node_name && !has_snapshot_node_name) {
|
||||||
|
error_setg(errp, "New snapshot node name missing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_snapshot_node_name && bdrv_find_node(snapshot_node_name)) {
|
||||||
|
error_setg(errp, "New snapshot node name already existing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1238,7 +1305,7 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_check_ext_snapshot(state->old_bs) != EXT_SNAPSHOT_ALLOWED) {
|
if (!bdrv_is_first_non_filter(state->old_bs)) {
|
||||||
error_set(errp, QERR_FEATURE_DISABLED, "snapshot");
|
error_set(errp, QERR_FEATURE_DISABLED, "snapshot");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1251,17 +1318,23 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
|||||||
state->old_bs->filename,
|
state->old_bs->filename,
|
||||||
state->old_bs->drv->format_name,
|
state->old_bs->drv->format_name,
|
||||||
NULL, -1, flags, &local_err, false);
|
NULL, -1, flags, &local_err, false);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_snapshot_node_name) {
|
||||||
|
options = qdict_new();
|
||||||
|
qdict_put(options, "node-name",
|
||||||
|
qstring_from_str(snapshot_node_name));
|
||||||
|
}
|
||||||
|
|
||||||
/* We will manually add the backing_hd field to the bs later */
|
/* We will manually add the backing_hd field to the bs later */
|
||||||
state->new_bs = bdrv_new("");
|
state->new_bs = bdrv_new("");
|
||||||
/* TODO Inherit bs->options or only take explicit options with an
|
/* TODO Inherit bs->options or only take explicit options with an
|
||||||
* extended QMP command? */
|
* extended QMP command? */
|
||||||
ret = bdrv_open(state->new_bs, new_image_file, NULL,
|
ret = bdrv_open(state->new_bs, new_image_file, options,
|
||||||
flags | BDRV_O_NO_BACKING, drv, &local_err);
|
flags | BDRV_O_NO_BACKING, drv, &local_err);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
@@ -1314,7 +1387,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
|
|||||||
backup->has_on_source_error, backup->on_source_error,
|
backup->has_on_source_error, backup->on_source_error,
|
||||||
backup->has_on_target_error, backup->on_target_error,
|
backup->has_on_target_error, backup->on_target_error,
|
||||||
&local_err);
|
&local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
state->bs = NULL;
|
state->bs = NULL;
|
||||||
state->job = NULL;
|
state->job = NULL;
|
||||||
@@ -1406,7 +1479,7 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp)
|
|||||||
QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
|
QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
|
||||||
|
|
||||||
state->ops->prepare(state, &local_err);
|
state->ops->prepare(state, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto delete_and_fail;
|
goto delete_and_fail;
|
||||||
}
|
}
|
||||||
@@ -1476,14 +1549,19 @@ void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
|
|||||||
eject_device(bs, force, errp);
|
eject_device(bs, force, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_block_passwd(const char *device, const char *password, Error **errp)
|
void qmp_block_passwd(bool has_device, const char *device,
|
||||||
|
bool has_node_name, const char *node_name,
|
||||||
|
const char *password, Error **errp)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
bs = bdrv_find(device);
|
bs = bdrv_lookup_bs(has_device ? device : NULL,
|
||||||
if (!bs) {
|
has_node_name ? node_name : NULL,
|
||||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1547,7 +1625,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
eject_device(bs, 0, &err);
|
eject_device(bs, 0, &err);
|
||||||
if (error_is_set(&err)) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1673,14 +1751,24 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_block_resize(const char *device, int64_t size, Error **errp)
|
void qmp_block_resize(bool has_device, const char *device,
|
||||||
|
bool has_node_name, const char *node_name,
|
||||||
|
int64_t size, Error **errp)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
bs = bdrv_find(device);
|
bs = bdrv_lookup_bs(has_device ? device : NULL,
|
||||||
if (!bs) {
|
has_node_name ? node_name : NULL,
|
||||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bdrv_is_first_non_filter(bs)) {
|
||||||
|
error_set(errp, QERR_FEATURE_DISABLED, "resize");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1767,7 +1855,7 @@ void qmp_block_stream(const char *device, bool has_base,
|
|||||||
|
|
||||||
stream_start(bs, base_bs, base, has_speed ? speed : 0,
|
stream_start(bs, base_bs, base, has_speed ? speed : 0,
|
||||||
on_error, block_job_cb, bs, &local_err);
|
on_error, block_job_cb, bs, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1925,7 +2013,7 @@ void qmp_drive_backup(const char *device, const char *target,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1947,6 +2035,11 @@ void qmp_drive_backup(const char *device, const char *target,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
|
||||||
|
{
|
||||||
|
return bdrv_named_nodes_list();
|
||||||
|
}
|
||||||
|
|
||||||
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
||||||
|
|
||||||
void qmp_drive_mirror(const char *device, const char *target,
|
void qmp_drive_mirror(const char *device, const char *target,
|
||||||
@@ -2061,7 +2154,7 @@ void qmp_drive_mirror(const char *device, const char *target,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2200,7 +2293,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
|
|
||||||
visit_type_BlockdevOptions(qmp_output_get_visitor(ov),
|
visit_type_BlockdevOptions(qmp_output_get_visitor(ov),
|
||||||
&options, NULL, &local_err);
|
&options, NULL, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -2210,8 +2303,8 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
|
|
||||||
qdict_flatten(qdict);
|
qdict_flatten(qdict);
|
||||||
|
|
||||||
blockdev_init(qdict, IF_NONE, &local_err);
|
blockdev_init(NULL, qdict, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -2250,10 +2343,6 @@ QemuOptsList qemu_common_drive_opts = {
|
|||||||
.name = "snapshot",
|
.name = "snapshot",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
.help = "enable/disable snapshot mode",
|
.help = "enable/disable snapshot mode",
|
||||||
},{
|
|
||||||
.name = "file",
|
|
||||||
.type = QEMU_OPT_STRING,
|
|
||||||
.help = "disk image",
|
|
||||||
},{
|
},{
|
||||||
.name = "discard",
|
.name = "discard",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
|||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
block_job_set_speed(job, speed, &local_err);
|
block_job_set_speed(job, speed, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
bs->job = NULL;
|
bs->job = NULL;
|
||||||
g_free(job);
|
g_free(job);
|
||||||
bdrv_set_in_use(bs, 0);
|
bdrv_set_in_use(bs, 0);
|
||||||
@@ -92,7 +92,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
job->driver->set_speed(job, speed, &local_err);
|
job->driver->set_speed(job, speed, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
154
configure
vendored
154
configure
vendored
@@ -251,11 +251,13 @@ vss_win32_sdk=""
|
|||||||
win_sdk="no"
|
win_sdk="no"
|
||||||
want_tools="yes"
|
want_tools="yes"
|
||||||
libiscsi=""
|
libiscsi=""
|
||||||
|
libnfs=""
|
||||||
coroutine=""
|
coroutine=""
|
||||||
coroutine_pool=""
|
coroutine_pool=""
|
||||||
seccomp=""
|
seccomp=""
|
||||||
glusterfs=""
|
glusterfs=""
|
||||||
glusterfs_discard="no"
|
glusterfs_discard="no"
|
||||||
|
glusterfs_zerofill="no"
|
||||||
virtio_blk_data_plane=""
|
virtio_blk_data_plane=""
|
||||||
gtk=""
|
gtk=""
|
||||||
gtkabi="2.0"
|
gtkabi="2.0"
|
||||||
@@ -839,6 +841,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-libiscsi) libiscsi="yes"
|
--enable-libiscsi) libiscsi="yes"
|
||||||
;;
|
;;
|
||||||
|
--disable-libnfs) libnfs="no"
|
||||||
|
;;
|
||||||
|
--enable-libnfs) libnfs="yes"
|
||||||
|
;;
|
||||||
--enable-profiler) profiler="yes"
|
--enable-profiler) profiler="yes"
|
||||||
;;
|
;;
|
||||||
--disable-cocoa) cocoa="no"
|
--disable-cocoa) cocoa="no"
|
||||||
@@ -1228,6 +1234,8 @@ Advanced options (experts only):
|
|||||||
--enable-rbd enable building the rados block device (rbd)
|
--enable-rbd enable building the rados block device (rbd)
|
||||||
--disable-libiscsi disable iscsi support
|
--disable-libiscsi disable iscsi support
|
||||||
--enable-libiscsi enable iscsi support
|
--enable-libiscsi enable iscsi support
|
||||||
|
--disable-libnfs disable nfs support
|
||||||
|
--enable-libnfs enable nfs support
|
||||||
--disable-smartcard-nss disable smartcard nss support
|
--disable-smartcard-nss disable smartcard nss support
|
||||||
--enable-smartcard-nss enable smartcard nss support
|
--enable-smartcard-nss enable smartcard nss support
|
||||||
--disable-libusb disable libusb (for usb passthrough)
|
--disable-libusb disable libusb (for usb passthrough)
|
||||||
@@ -1384,6 +1392,11 @@ EOF
|
|||||||
pie="no"
|
pie="no"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if compile_prog "-fno-pie" "-nopie"; then
|
||||||
|
CFLAGS_NOPIE="-fno-pie"
|
||||||
|
LDFLAGS_NOPIE="-nopie"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
@@ -1466,9 +1479,11 @@ esac
|
|||||||
|
|
||||||
feature_not_found() {
|
feature_not_found() {
|
||||||
feature=$1
|
feature=$1
|
||||||
|
remedy=$2
|
||||||
|
|
||||||
error_exit "User requested feature $feature" \
|
error_exit "User requested feature $feature" \
|
||||||
"configure was not able to find it"
|
"configure was not able to find it." \
|
||||||
|
"$remedy"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
@@ -1516,7 +1531,7 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
if ! compile_object ; then
|
if ! compile_object ; then
|
||||||
feature_not_found "nptl"
|
feature_not_found "nptl" "Install glibc and linux kernel headers."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1547,7 +1562,7 @@ if test "$seccomp" != "no" ; then
|
|||||||
seccomp="yes"
|
seccomp="yes"
|
||||||
else
|
else
|
||||||
if test "$seccomp" = "yes"; then
|
if test "$seccomp" = "yes"; then
|
||||||
feature_not_found "libseccomp"
|
feature_not_found "libseccomp" "Install libseccomp devel >= 2.1.0"
|
||||||
fi
|
fi
|
||||||
seccomp="no"
|
seccomp="no"
|
||||||
fi
|
fi
|
||||||
@@ -1572,7 +1587,7 @@ EOF
|
|||||||
if ! compile_prog "" "$xen_libs" ; then
|
if ! compile_prog "" "$xen_libs" ; then
|
||||||
# Xen not found
|
# Xen not found
|
||||||
if test "$xen" = "yes" ; then
|
if test "$xen" = "yes" ; then
|
||||||
feature_not_found "xen"
|
feature_not_found "xen" "Install xen devel"
|
||||||
fi
|
fi
|
||||||
xen=no
|
xen=no
|
||||||
|
|
||||||
@@ -1695,7 +1710,7 @@ EOF
|
|||||||
# Xen version unsupported
|
# Xen version unsupported
|
||||||
else
|
else
|
||||||
if test "$xen" = "yes" ; then
|
if test "$xen" = "yes" ; then
|
||||||
feature_not_found "xen (unsupported version)"
|
feature_not_found "xen (unsupported version)" "Install supported xen (e.g. 4.0, 3.4, 3.3)"
|
||||||
fi
|
fi
|
||||||
xen=no
|
xen=no
|
||||||
fi
|
fi
|
||||||
@@ -1744,7 +1759,7 @@ if test "$sparse" != "no" ; then
|
|||||||
sparse=yes
|
sparse=yes
|
||||||
else
|
else
|
||||||
if test "$sparse" = "yes" ; then
|
if test "$sparse" = "yes" ; then
|
||||||
feature_not_found "sparse"
|
feature_not_found "sparse" "Install sparse binary"
|
||||||
fi
|
fi
|
||||||
sparse=no
|
sparse=no
|
||||||
fi
|
fi
|
||||||
@@ -1766,7 +1781,7 @@ if test "$gtk" != "no"; then
|
|||||||
fi
|
fi
|
||||||
if ! $pkg_config --exists "$gtkpackage >= $gtkversion"; then
|
if ! $pkg_config --exists "$gtkpackage >= $gtkversion"; then
|
||||||
if test "$gtk" = "yes" ; then
|
if test "$gtk" = "yes" ; then
|
||||||
feature_not_found "gtk"
|
feature_not_found "gtk" "Install gtk2 or gtk3 (requires --with-gtkabi=3.0 option to configure) devel"
|
||||||
fi
|
fi
|
||||||
gtk="no"
|
gtk="no"
|
||||||
elif ! $pkg_config --exists "$vtepackage >= $vteversion"; then
|
elif ! $pkg_config --exists "$vtepackage >= $vteversion"; then
|
||||||
@@ -1801,7 +1816,7 @@ elif has ${sdl_config}; then
|
|||||||
_sdlversion=`$sdlconfig --version | sed 's/[^0-9]//g'`
|
_sdlversion=`$sdlconfig --version | sed 's/[^0-9]//g'`
|
||||||
else
|
else
|
||||||
if test "$sdl" = "yes" ; then
|
if test "$sdl" = "yes" ; then
|
||||||
feature_not_found "sdl"
|
feature_not_found "sdl" "Install SDL devel"
|
||||||
fi
|
fi
|
||||||
sdl=no
|
sdl=no
|
||||||
fi
|
fi
|
||||||
@@ -1845,7 +1860,7 @@ EOF
|
|||||||
fi # static link
|
fi # static link
|
||||||
else # sdl not found
|
else # sdl not found
|
||||||
if test "$sdl" = "yes" ; then
|
if test "$sdl" = "yes" ; then
|
||||||
feature_not_found "sdl"
|
feature_not_found "sdl" "Install SDL devel"
|
||||||
fi
|
fi
|
||||||
sdl=no
|
sdl=no
|
||||||
fi # sdl compile test
|
fi # sdl compile test
|
||||||
@@ -1911,10 +1926,10 @@ EOF
|
|||||||
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags"
|
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags"
|
||||||
else
|
else
|
||||||
if test "$vnc_tls" = "yes" ; then
|
if test "$vnc_tls" = "yes" ; then
|
||||||
feature_not_found "vnc-tls"
|
feature_not_found "vnc-tls" "Install gnutls devel"
|
||||||
fi
|
fi
|
||||||
if test "$vnc_ws" = "yes" ; then
|
if test "$vnc_ws" = "yes" ; then
|
||||||
feature_not_found "vnc-ws"
|
feature_not_found "vnc-ws" "Install gnutls devel"
|
||||||
fi
|
fi
|
||||||
vnc_tls=no
|
vnc_tls=no
|
||||||
vnc_ws=no
|
vnc_ws=no
|
||||||
@@ -1938,7 +1953,7 @@ EOF
|
|||||||
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_sasl_cflags"
|
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_sasl_cflags"
|
||||||
else
|
else
|
||||||
if test "$vnc_sasl" = "yes" ; then
|
if test "$vnc_sasl" = "yes" ; then
|
||||||
feature_not_found "vnc-sasl"
|
feature_not_found "vnc-sasl" "Install Cyrus SASL devel"
|
||||||
fi
|
fi
|
||||||
vnc_sasl=no
|
vnc_sasl=no
|
||||||
fi
|
fi
|
||||||
@@ -1960,7 +1975,7 @@ EOF
|
|||||||
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_jpeg_cflags"
|
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_jpeg_cflags"
|
||||||
else
|
else
|
||||||
if test "$vnc_jpeg" = "yes" ; then
|
if test "$vnc_jpeg" = "yes" ; then
|
||||||
feature_not_found "vnc-jpeg"
|
feature_not_found "vnc-jpeg" "Install libjpeg-turbo devel"
|
||||||
fi
|
fi
|
||||||
vnc_jpeg=no
|
vnc_jpeg=no
|
||||||
fi
|
fi
|
||||||
@@ -1992,7 +2007,7 @@ EOF
|
|||||||
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_png_cflags"
|
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_png_cflags"
|
||||||
else
|
else
|
||||||
if test "$vnc_png" = "yes" ; then
|
if test "$vnc_png" = "yes" ; then
|
||||||
feature_not_found "vnc-png"
|
feature_not_found "vnc-png" "Install libpng devel"
|
||||||
fi
|
fi
|
||||||
vnc_png=no
|
vnc_png=no
|
||||||
fi
|
fi
|
||||||
@@ -2036,7 +2051,7 @@ EOF
|
|||||||
libs_tools="$uuid_libs $libs_tools"
|
libs_tools="$uuid_libs $libs_tools"
|
||||||
else
|
else
|
||||||
if test "$uuid" = "yes" ; then
|
if test "$uuid" = "yes" ; then
|
||||||
feature_not_found "uuid"
|
feature_not_found "uuid" "Install libuuid devel"
|
||||||
fi
|
fi
|
||||||
uuid=no
|
uuid=no
|
||||||
fi
|
fi
|
||||||
@@ -2070,7 +2085,7 @@ EOF
|
|||||||
xfs="yes"
|
xfs="yes"
|
||||||
else
|
else
|
||||||
if test "$xfs" = "yes" ; then
|
if test "$xfs" = "yes" ; then
|
||||||
feature_not_found "xfs"
|
feature_not_found "xfs" "Instal xfsprogs/xfslibs devel"
|
||||||
fi
|
fi
|
||||||
xfs=no
|
xfs=no
|
||||||
fi
|
fi
|
||||||
@@ -2096,7 +2111,7 @@ EOF
|
|||||||
libs_tools="$vde_libs $libs_tools"
|
libs_tools="$vde_libs $libs_tools"
|
||||||
else
|
else
|
||||||
if test "$vde" = "yes" ; then
|
if test "$vde" = "yes" ; then
|
||||||
feature_not_found "vde"
|
feature_not_found "vde" "Install vde (Virtual Distributed Ethernet) devel"
|
||||||
fi
|
fi
|
||||||
vde=no
|
vde=no
|
||||||
fi
|
fi
|
||||||
@@ -2139,7 +2154,7 @@ EOF
|
|||||||
libs_tools="$cap_libs $libs_tools"
|
libs_tools="$cap_libs $libs_tools"
|
||||||
else
|
else
|
||||||
if test "$cap_ng" = "yes" ; then
|
if test "$cap_ng" = "yes" ; then
|
||||||
feature_not_found "cap_ng"
|
feature_not_found "cap_ng" "Install libcap-ng devel"
|
||||||
fi
|
fi
|
||||||
cap_ng=no
|
cap_ng=no
|
||||||
fi
|
fi
|
||||||
@@ -2244,7 +2259,7 @@ EOF
|
|||||||
libs_softmmu="$brlapi_libs $libs_softmmu"
|
libs_softmmu="$brlapi_libs $libs_softmmu"
|
||||||
else
|
else
|
||||||
if test "$brlapi" = "yes" ; then
|
if test "$brlapi" = "yes" ; then
|
||||||
feature_not_found "brlapi"
|
feature_not_found "brlapi" "Install brlapi devel"
|
||||||
fi
|
fi
|
||||||
brlapi=no
|
brlapi=no
|
||||||
fi
|
fi
|
||||||
@@ -2281,7 +2296,7 @@ EOF
|
|||||||
curses=yes
|
curses=yes
|
||||||
else
|
else
|
||||||
if test "$curses" = "yes" ; then
|
if test "$curses" = "yes" ; then
|
||||||
feature_not_found "curses"
|
feature_not_found "curses" "Install ncurses devel"
|
||||||
fi
|
fi
|
||||||
curses=no
|
curses=no
|
||||||
fi
|
fi
|
||||||
@@ -2307,7 +2322,7 @@ EOF
|
|||||||
libs_softmmu="$curl_libs $libs_softmmu"
|
libs_softmmu="$curl_libs $libs_softmmu"
|
||||||
else
|
else
|
||||||
if test "$curl" = "yes" ; then
|
if test "$curl" = "yes" ; then
|
||||||
feature_not_found "curl"
|
feature_not_found "curl" "Install libcurl devel"
|
||||||
fi
|
fi
|
||||||
curl=no
|
curl=no
|
||||||
fi
|
fi
|
||||||
@@ -2327,7 +2342,7 @@ EOF
|
|||||||
libs_softmmu="$bluez_libs $libs_softmmu"
|
libs_softmmu="$bluez_libs $libs_softmmu"
|
||||||
else
|
else
|
||||||
if test "$bluez" = "yes" ; then
|
if test "$bluez" = "yes" ; then
|
||||||
feature_not_found "bluez"
|
feature_not_found "bluez" "Install bluez-libs/libbluetooth devel"
|
||||||
fi
|
fi
|
||||||
bluez="no"
|
bluez="no"
|
||||||
fi
|
fi
|
||||||
@@ -2463,7 +2478,7 @@ EOF
|
|||||||
libs_softmmu="$rbd_libs $libs_softmmu"
|
libs_softmmu="$rbd_libs $libs_softmmu"
|
||||||
else
|
else
|
||||||
if test "$rbd" = "yes" ; then
|
if test "$rbd" = "yes" ; then
|
||||||
feature_not_found "rados block device"
|
feature_not_found "rados block device" "Install librbd/ceph devel"
|
||||||
fi
|
fi
|
||||||
rbd=no
|
rbd=no
|
||||||
fi
|
fi
|
||||||
@@ -2529,7 +2544,7 @@ EOF
|
|||||||
libs_tools="$libs_tools -laio"
|
libs_tools="$libs_tools -laio"
|
||||||
else
|
else
|
||||||
if test "$linux_aio" = "yes" ; then
|
if test "$linux_aio" = "yes" ; then
|
||||||
feature_not_found "linux AIO"
|
feature_not_found "linux AIO" "Install libaio devel"
|
||||||
fi
|
fi
|
||||||
linux_aio=no
|
linux_aio=no
|
||||||
fi
|
fi
|
||||||
@@ -2577,7 +2592,7 @@ EOF
|
|||||||
libattr=yes
|
libattr=yes
|
||||||
else
|
else
|
||||||
if test "$attr" = "yes" ; then
|
if test "$attr" = "yes" ; then
|
||||||
feature_not_found "ATTR"
|
feature_not_found "ATTR" "Install libc6 or libattr devel"
|
||||||
fi
|
fi
|
||||||
attr=no
|
attr=no
|
||||||
fi
|
fi
|
||||||
@@ -2654,8 +2669,8 @@ EOF
|
|||||||
fdt_libs="-L\$(BUILD_DIR)/dtc/libfdt $fdt_libs"
|
fdt_libs="-L\$(BUILD_DIR)/dtc/libfdt $fdt_libs"
|
||||||
elif test "$fdt" = "yes" ; then
|
elif test "$fdt" = "yes" ; then
|
||||||
# have neither and want - prompt for system/submodule install
|
# have neither and want - prompt for system/submodule install
|
||||||
error_exit "DTC not present. Your options:" \
|
error_exit "DTC (libfdt) not present. Your options:" \
|
||||||
" (1) Preferred: Install the DTC devel package" \
|
" (1) Preferred: Install the DTC (libfdt) devel package" \
|
||||||
" (2) Fetch the DTC submodule, using:" \
|
" (2) Fetch the DTC submodule, using:" \
|
||||||
" git submodule update --init dtc"
|
" git submodule update --init dtc"
|
||||||
else
|
else
|
||||||
@@ -2681,7 +2696,7 @@ EOF
|
|||||||
glx=yes
|
glx=yes
|
||||||
else
|
else
|
||||||
if test "$glx" = "yes" ; then
|
if test "$glx" = "yes" ; then
|
||||||
feature_not_found "glx"
|
feature_not_found "glx" "Install GL devel (e.g. MESA)"
|
||||||
fi
|
fi
|
||||||
glx_libs=
|
glx_libs=
|
||||||
glx=no
|
glx=no
|
||||||
@@ -2701,9 +2716,12 @@ if test "$glusterfs" != "no" ; then
|
|||||||
if $pkg_config --atleast-version=5 glusterfs-api; then
|
if $pkg_config --atleast-version=5 glusterfs-api; then
|
||||||
glusterfs_discard="yes"
|
glusterfs_discard="yes"
|
||||||
fi
|
fi
|
||||||
|
if $pkg_config --atleast-version=6 glusterfs-api; then
|
||||||
|
glusterfs_zerofill="yes"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
if test "$glusterfs" = "yes" ; then
|
if test "$glusterfs" = "yes" ; then
|
||||||
feature_not_found "GlusterFS backend support"
|
feature_not_found "GlusterFS backend support" "Install glusterfs-api devel"
|
||||||
fi
|
fi
|
||||||
glusterfs="no"
|
glusterfs="no"
|
||||||
fi
|
fi
|
||||||
@@ -3023,7 +3041,7 @@ if test "$docs" != "no" ; then
|
|||||||
docs=yes
|
docs=yes
|
||||||
else
|
else
|
||||||
if test "$docs" = "yes" ; then
|
if test "$docs" = "yes" ; then
|
||||||
feature_not_found "docs"
|
feature_not_found "docs" "Install texinfo and Perl/perl-podlators"
|
||||||
fi
|
fi
|
||||||
docs=no
|
docs=no
|
||||||
fi
|
fi
|
||||||
@@ -3072,7 +3090,7 @@ EOF
|
|||||||
LIBS="$LIBS -liscsi"
|
LIBS="$LIBS -liscsi"
|
||||||
else
|
else
|
||||||
if test "$libiscsi" = "yes" ; then
|
if test "$libiscsi" = "yes" ; then
|
||||||
feature_not_found "libiscsi"
|
feature_not_found "libiscsi" "Install libiscsi devel"
|
||||||
fi
|
fi
|
||||||
libiscsi="no"
|
libiscsi="no"
|
||||||
fi
|
fi
|
||||||
@@ -3156,7 +3174,7 @@ EOF
|
|||||||
spice_server_version=$($pkg_config --modversion spice-server)
|
spice_server_version=$($pkg_config --modversion spice-server)
|
||||||
else
|
else
|
||||||
if test "$spice" = "yes" ; then
|
if test "$spice" = "yes" ; then
|
||||||
feature_not_found "spice"
|
feature_not_found "spice" "Install spice-server and spice-protocol devel"
|
||||||
fi
|
fi
|
||||||
spice="no"
|
spice="no"
|
||||||
fi
|
fi
|
||||||
@@ -3206,7 +3224,7 @@ if test "$libusb" != "no" ; then
|
|||||||
libs_softmmu="$libs_softmmu $libusb_libs"
|
libs_softmmu="$libs_softmmu $libusb_libs"
|
||||||
else
|
else
|
||||||
if test "$libusb" = "yes"; then
|
if test "$libusb" = "yes"; then
|
||||||
feature_not_found "libusb"
|
feature_not_found "libusb" "Install libusb devel"
|
||||||
fi
|
fi
|
||||||
libusb="no"
|
libusb="no"
|
||||||
fi
|
fi
|
||||||
@@ -3222,7 +3240,7 @@ if test "$usb_redir" != "no" ; then
|
|||||||
libs_softmmu="$libs_softmmu $usb_redir_libs"
|
libs_softmmu="$libs_softmmu $usb_redir_libs"
|
||||||
else
|
else
|
||||||
if test "$usb_redir" = "yes"; then
|
if test "$usb_redir" = "yes"; then
|
||||||
feature_not_found "usb-redir"
|
feature_not_found "usb-redir" "Install usbredir devel"
|
||||||
fi
|
fi
|
||||||
usb_redir="no"
|
usb_redir="no"
|
||||||
fi
|
fi
|
||||||
@@ -3361,15 +3379,25 @@ fi
|
|||||||
# For 'ust' backend, test if ust headers are present
|
# For 'ust' backend, test if ust headers are present
|
||||||
if test "$trace_backend" = "ust"; then
|
if test "$trace_backend" = "ust"; then
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
#include <ust/tracepoint.h>
|
#include <lttng/tracepoint.h>
|
||||||
#include <ust/marker.h>
|
|
||||||
int main(void) { return 0; }
|
int main(void) { return 0; }
|
||||||
EOF
|
EOF
|
||||||
if compile_prog "" "" ; then
|
if compile_prog "" "" ; then
|
||||||
LIBS="-lust -lurcu-bp $LIBS"
|
if $pkg_config lttng-ust --exists; then
|
||||||
libs_qga="-lust -lurcu-bp $libs_qga"
|
lttng_ust_libs=`$pkg_config --libs lttng-ust`
|
||||||
|
else
|
||||||
|
lttng_ust_libs="-llttng-ust"
|
||||||
|
fi
|
||||||
|
if $pkg_config liburcu-bp --exists; then
|
||||||
|
urcu_bp_libs=`$pkg_config --libs liburcu-bp`
|
||||||
|
else
|
||||||
|
urcu_bp_libs="-lurcu-bp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
LIBS="$lttng_ust_libs $urcu_bp_libs $LIBS"
|
||||||
|
libs_qga="$lttng_ust_libs $urcu_bp_libs $libs_qga"
|
||||||
else
|
else
|
||||||
error_exit "Trace backend 'ust' missing libust header files"
|
error_exit "Trace backend 'ust' missing lttng-ust header files"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -3546,7 +3574,18 @@ cpuid_h=no
|
|||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
int main(void) {
|
int main(void) {
|
||||||
return 0;
|
unsigned a, b, c, d;
|
||||||
|
int max = __get_cpuid_max(0, 0);
|
||||||
|
|
||||||
|
if (max >= 1) {
|
||||||
|
__cpuid(1, a, b, c, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max >= 7) {
|
||||||
|
__cpuid_count(7, 0, a, b, c, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
if compile_prog "" "" ; then
|
if compile_prog "" "" ; then
|
||||||
@@ -3596,6 +3635,20 @@ elif test "$debug" = "no" ; then
|
|||||||
CFLAGS="-O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
|
CFLAGS="-O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# Do we have libnfs
|
||||||
|
if test "$libnfs" != "no" ; then
|
||||||
|
if $pkg_config --atleast-version=1.9.2 libnfs; then
|
||||||
|
libnfs="yes"
|
||||||
|
libnfs_libs=$($pkg_config --libs libnfs)
|
||||||
|
LIBS="$LIBS $libnfs_libs"
|
||||||
|
else
|
||||||
|
if test "$libnfs" = "yes" ; then
|
||||||
|
feature_not_found "libnfs"
|
||||||
|
fi
|
||||||
|
libnfs="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Disable zero malloc errors for official releases unless explicitly told to
|
# Disable zero malloc errors for official releases unless explicitly told to
|
||||||
# enable/disable
|
# enable/disable
|
||||||
@@ -3825,6 +3878,7 @@ echo "libiscsi support $libiscsi (1.4.0)"
|
|||||||
else
|
else
|
||||||
echo "libiscsi support $libiscsi"
|
echo "libiscsi support $libiscsi"
|
||||||
fi
|
fi
|
||||||
|
echo "libnfs support $libnfs"
|
||||||
echo "build guest agent $guest_agent"
|
echo "build guest agent $guest_agent"
|
||||||
echo "QGA VSS support $guest_agent_with_vss"
|
echo "QGA VSS support $guest_agent_with_vss"
|
||||||
echo "seccomp support $seccomp"
|
echo "seccomp support $seccomp"
|
||||||
@@ -4161,6 +4215,10 @@ if test "$libiscsi" = "yes" ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$libnfs" = "yes" ; then
|
||||||
|
echo "CONFIG_LIBNFS=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$seccomp" = "yes"; then
|
if test "$seccomp" = "yes"; then
|
||||||
echo "CONFIG_SECCOMP=y" >> $config_host_mak
|
echo "CONFIG_SECCOMP=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -4229,6 +4287,10 @@ if test "$glusterfs_discard" = "yes" ; then
|
|||||||
echo "CONFIG_GLUSTERFS_DISCARD=y" >> $config_host_mak
|
echo "CONFIG_GLUSTERFS_DISCARD=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$glusterfs_zerofill" = "yes" ; then
|
||||||
|
echo "CONFIG_GLUSTERFS_ZEROFILL=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$libssh2" = "yes" ; then
|
if test "$libssh2" = "yes" ; then
|
||||||
echo "CONFIG_LIBSSH2=y" >> $config_host_mak
|
echo "CONFIG_LIBSSH2=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
@@ -4286,7 +4348,7 @@ if test "$trace_backend" = "ftrace"; then
|
|||||||
echo "CONFIG_TRACE_FTRACE=y" >> $config_host_mak
|
echo "CONFIG_TRACE_FTRACE=y" >> $config_host_mak
|
||||||
trace_default=no
|
trace_default=no
|
||||||
else
|
else
|
||||||
feature_not_found "ftrace(trace backend)"
|
feature_not_found "ftrace(trace backend)" "ftrace requires Linux"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
|
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
|
||||||
@@ -4342,6 +4404,7 @@ echo "LD=$ld" >> $config_host_mak
|
|||||||
echo "WINDRES=$windres" >> $config_host_mak
|
echo "WINDRES=$windres" >> $config_host_mak
|
||||||
echo "LIBTOOL=$libtool" >> $config_host_mak
|
echo "LIBTOOL=$libtool" >> $config_host_mak
|
||||||
echo "CFLAGS=$CFLAGS" >> $config_host_mak
|
echo "CFLAGS=$CFLAGS" >> $config_host_mak
|
||||||
|
echo "CFLAGS_NOPIE=$CFLAGS_NOPIE" >> $config_host_mak
|
||||||
echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
|
echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
|
||||||
echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
|
echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
|
||||||
if test "$sparse" = "yes" ; then
|
if test "$sparse" = "yes" ; then
|
||||||
@@ -4355,6 +4418,7 @@ else
|
|||||||
echo "AUTOCONF_HOST := " >> $config_host_mak
|
echo "AUTOCONF_HOST := " >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
|
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
|
||||||
|
echo "LDFLAGS_NOPIE=$LDFLAGS_NOPIE" >> $config_host_mak
|
||||||
echo "LIBTOOLFLAGS=$LIBTOOLFLAGS" >> $config_host_mak
|
echo "LIBTOOLFLAGS=$LIBTOOLFLAGS" >> $config_host_mak
|
||||||
echo "LIBS+=$LIBS" >> $config_host_mak
|
echo "LIBS+=$LIBS" >> $config_host_mak
|
||||||
echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
|
echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
|
||||||
@@ -4633,6 +4697,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
|
|||||||
arm)
|
arm)
|
||||||
echo "CONFIG_ARM_DIS=y" >> $config_target_mak
|
echo "CONFIG_ARM_DIS=y" >> $config_target_mak
|
||||||
echo "CONFIG_ARM_DIS=y" >> config-all-disas.mak
|
echo "CONFIG_ARM_DIS=y" >> config-all-disas.mak
|
||||||
|
if test -n "${cxx}"; then
|
||||||
|
echo "CONFIG_ARM_A64_DIS=y" >> $config_target_mak
|
||||||
|
echo "CONFIG_ARM_A64_DIS=y" >> config-all-disas.mak
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
cris)
|
cris)
|
||||||
echo "CONFIG_CRIS_DIS=y" >> $config_target_mak
|
echo "CONFIG_CRIS_DIS=y" >> $config_target_mak
|
||||||
@@ -4766,6 +4834,10 @@ for bios_file in \
|
|||||||
do
|
do
|
||||||
FILES="$FILES pc-bios/`basename $bios_file`"
|
FILES="$FILES pc-bios/`basename $bios_file`"
|
||||||
done
|
done
|
||||||
|
for test_file in `find $source_path/tests/acpi-test-data -type f`
|
||||||
|
do
|
||||||
|
FILES="$FILES tests/acpi-test-data`echo $test_file | sed -e 's/.*acpi-test-data//'`"
|
||||||
|
done
|
||||||
mkdir -p $DIRS
|
mkdir -p $DIRS
|
||||||
for f in $FILES ; do
|
for f in $FILES ; do
|
||||||
if [ -e "$source_path/$f" ] && [ "$source_path" != `pwd` ]; then
|
if [ -e "$source_path/$f" ] && [ "$source_path" != `pwd` ]; then
|
||||||
|
|||||||
@@ -395,7 +395,10 @@ int cpu_exec(CPUArchState *env)
|
|||||||
/* FIXME: this should respect TPR */
|
/* FIXME: this should respect TPR */
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR,
|
cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR,
|
||||||
0);
|
0);
|
||||||
intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
|
intno = ldl_phys(cpu->as,
|
||||||
|
env->vm_vmcb
|
||||||
|
+ offsetof(struct vmcb,
|
||||||
|
control.int_vector));
|
||||||
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
|
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
|
||||||
do_interrupt_x86_hardirq(env, intno, 1);
|
do_interrupt_x86_hardirq(env, intno, 1);
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
|
cpu->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
|
||||||
|
|||||||
2
cpus.c
2
cpus.c
@@ -1119,6 +1119,8 @@ void resume_all_vcpus(void)
|
|||||||
|
|
||||||
static void qemu_tcg_init_vcpu(CPUState *cpu)
|
static void qemu_tcg_init_vcpu(CPUState *cpu)
|
||||||
{
|
{
|
||||||
|
tcg_cpu_address_space_init(cpu, cpu->as);
|
||||||
|
|
||||||
/* share a single thread for all cpus with TCG */
|
/* share a single thread for all cpus with TCG */
|
||||||
if (!tcg_cpu_thread) {
|
if (!tcg_cpu_thread) {
|
||||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||||
|
|||||||
7
cputlb.c
7
cputlb.c
@@ -232,6 +232,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
|
|||||||
uintptr_t addend;
|
uintptr_t addend;
|
||||||
CPUTLBEntry *te;
|
CPUTLBEntry *te;
|
||||||
hwaddr iotlb, xlat, sz;
|
hwaddr iotlb, xlat, sz;
|
||||||
|
CPUState *cpu = ENV_GET_CPU(env);
|
||||||
|
|
||||||
assert(size >= TARGET_PAGE_SIZE);
|
assert(size >= TARGET_PAGE_SIZE);
|
||||||
if (size != TARGET_PAGE_SIZE) {
|
if (size != TARGET_PAGE_SIZE) {
|
||||||
@@ -239,7 +240,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sz = size;
|
sz = size;
|
||||||
section = address_space_translate_for_iotlb(&address_space_memory, paddr,
|
section = address_space_translate_for_iotlb(cpu->as, paddr,
|
||||||
&xlat, &sz);
|
&xlat, &sz);
|
||||||
assert(sz >= TARGET_PAGE_SIZE);
|
assert(sz >= TARGET_PAGE_SIZE);
|
||||||
|
|
||||||
@@ -305,6 +306,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
|||||||
int mmu_idx, page_index, pd;
|
int mmu_idx, page_index, pd;
|
||||||
void *p;
|
void *p;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
|
CPUState *cpu = ENV_GET_CPU(env1);
|
||||||
|
|
||||||
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||||
mmu_idx = cpu_mmu_index(env1);
|
mmu_idx = cpu_mmu_index(env1);
|
||||||
@@ -313,9 +315,8 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
|||||||
cpu_ldub_code(env1, addr);
|
cpu_ldub_code(env1, addr);
|
||||||
}
|
}
|
||||||
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
|
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
|
||||||
mr = iotlb_to_region(pd);
|
mr = iotlb_to_region(cpu->as, pd);
|
||||||
if (memory_region_is_unassigned(mr)) {
|
if (memory_region_is_unassigned(mr)) {
|
||||||
CPUState *cpu = ENV_GET_CPU(env1);
|
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
|
||||||
if (cc->do_unassigned_access) {
|
if (cc->do_unassigned_access) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ CONFIG_SSI_SD=y
|
|||||||
CONFIG_SSI_M25P80=y
|
CONFIG_SSI_M25P80=y
|
||||||
CONFIG_LAN9118=y
|
CONFIG_LAN9118=y
|
||||||
CONFIG_SMC91C111=y
|
CONFIG_SMC91C111=y
|
||||||
|
CONFIG_ALLWINNER_EMAC=y
|
||||||
CONFIG_DS1338=y
|
CONFIG_DS1338=y
|
||||||
CONFIG_PFLASH_CFI01=y
|
CONFIG_PFLASH_CFI01=y
|
||||||
CONFIG_PFLASH_CFI02=y
|
CONFIG_PFLASH_CFI02=y
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ CONFIG_I8259=y
|
|||||||
CONFIG_XILINX=y
|
CONFIG_XILINX=y
|
||||||
CONFIG_XILINX_ETHLITE=y
|
CONFIG_XILINX_ETHLITE=y
|
||||||
CONFIG_OPENPIC=y
|
CONFIG_OPENPIC=y
|
||||||
|
CONFIG_PREP=y
|
||||||
|
CONFIG_MAC=y
|
||||||
CONFIG_E500=y
|
CONFIG_E500=y
|
||||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||||
# For PReP
|
# For PReP
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ CONFIG_XILINX=y
|
|||||||
CONFIG_XILINX_ETHLITE=y
|
CONFIG_XILINX_ETHLITE=y
|
||||||
CONFIG_OPENPIC=y
|
CONFIG_OPENPIC=y
|
||||||
CONFIG_PSERIES=y
|
CONFIG_PSERIES=y
|
||||||
|
CONFIG_PREP=y
|
||||||
|
CONFIG_MAC=y
|
||||||
CONFIG_E500=y
|
CONFIG_E500=y
|
||||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||||
# For pSeries
|
# For pSeries
|
||||||
|
|||||||
@@ -3,32 +3,12 @@
|
|||||||
include pci.mak
|
include pci.mak
|
||||||
include sound.mak
|
include sound.mak
|
||||||
include usb.mak
|
include usb.mak
|
||||||
CONFIG_ISA_MMIO=y
|
|
||||||
CONFIG_ESCC=y
|
|
||||||
CONFIG_M48T59=y
|
CONFIG_M48T59=y
|
||||||
CONFIG_VGA=y
|
CONFIG_VGA=y
|
||||||
CONFIG_VGA_PCI=y
|
CONFIG_VGA_PCI=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
CONFIG_I8254=y
|
|
||||||
CONFIG_PCKBD=y
|
|
||||||
CONFIG_FDC=y
|
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_OPENPIC=y
|
CONFIG_OPENPIC=y
|
||||||
CONFIG_PREP_PCI=y
|
|
||||||
CONFIG_MACIO=y
|
|
||||||
CONFIG_CUDA=y
|
|
||||||
CONFIG_ADB=y
|
|
||||||
CONFIG_MAC_NVRAM=y
|
|
||||||
CONFIG_MAC_DBDMA=y
|
|
||||||
CONFIG_HEATHROW_PIC=y
|
|
||||||
CONFIG_GRACKLE_PCI=y
|
|
||||||
CONFIG_UNIN_PCI=y
|
|
||||||
CONFIG_DEC_PCI=y
|
|
||||||
CONFIG_PPCE500_PCI=y
|
|
||||||
CONFIG_IDE_ISA=y
|
|
||||||
CONFIG_IDE_CMD646=y
|
|
||||||
CONFIG_IDE_MACIO=y
|
|
||||||
CONFIG_NE2000_ISA=y
|
|
||||||
CONFIG_PFLASH_CFI01=y
|
CONFIG_PFLASH_CFI01=y
|
||||||
CONFIG_PFLASH_CFI02=y
|
CONFIG_PFLASH_CFI02=y
|
||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
@@ -36,8 +16,3 @@ CONFIG_I8259=y
|
|||||||
CONFIG_XILINX=y
|
CONFIG_XILINX=y
|
||||||
CONFIG_XILINX_ETHLITE=y
|
CONFIG_XILINX_ETHLITE=y
|
||||||
CONFIG_OPENPIC=y
|
CONFIG_OPENPIC=y
|
||||||
CONFIG_E500=y
|
|
||||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
|
||||||
# For PReP
|
|
||||||
CONFIG_MC146818RTC=y
|
|
||||||
CONFIG_ISA_TESTDEV=y
|
|
||||||
|
|||||||
14
disas.c
14
disas.c
@@ -190,7 +190,7 @@ static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
|
|||||||
/* Disassemble this for me please... (debugging). 'flags' has the following
|
/* Disassemble this for me please... (debugging). 'flags' has the following
|
||||||
values:
|
values:
|
||||||
i386 - 1 means 16 bit code, 2 means 64 bit code
|
i386 - 1 means 16 bit code, 2 means 64 bit code
|
||||||
arm - bit 0 = thumb, bit 1 = reverse endian
|
arm - bit 0 = thumb, bit 1 = reverse endian, bit 2 = A64
|
||||||
ppc - nonzero means little endian
|
ppc - nonzero means little endian
|
||||||
other targets - unused
|
other targets - unused
|
||||||
*/
|
*/
|
||||||
@@ -225,7 +225,15 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code,
|
|||||||
}
|
}
|
||||||
print_insn = print_insn_i386;
|
print_insn = print_insn_i386;
|
||||||
#elif defined(TARGET_ARM)
|
#elif defined(TARGET_ARM)
|
||||||
if (flags & 1) {
|
if (flags & 4) {
|
||||||
|
/* We might not be compiled with the A64 disassembler
|
||||||
|
* because it needs a C++ compiler; in that case we will
|
||||||
|
* fall through to the default print_insn_od case.
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_ARM_A64_DIS)
|
||||||
|
print_insn = print_insn_arm_a64;
|
||||||
|
#endif
|
||||||
|
} else if (flags & 1) {
|
||||||
print_insn = print_insn_thumb1;
|
print_insn = print_insn_thumb1;
|
||||||
} else {
|
} else {
|
||||||
print_insn = print_insn_arm;
|
print_insn = print_insn_arm;
|
||||||
@@ -356,6 +364,8 @@ void disas(FILE *out, void *code, unsigned long size)
|
|||||||
#elif defined(_ARCH_PPC)
|
#elif defined(_ARCH_PPC)
|
||||||
s.info.disassembler_options = (char *)"any";
|
s.info.disassembler_options = (char *)"any";
|
||||||
print_insn = print_insn_ppc;
|
print_insn = print_insn_ppc;
|
||||||
|
#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
|
||||||
|
print_insn = print_insn_arm_a64;
|
||||||
#elif defined(__alpha__)
|
#elif defined(__alpha__)
|
||||||
print_insn = print_insn_alpha;
|
print_insn = print_insn_alpha;
|
||||||
#elif defined(__sparc__)
|
#elif defined(__sparc__)
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
|
||||||
common-obj-$(CONFIG_ALPHA_DIS) += alpha.o
|
common-obj-$(CONFIG_ALPHA_DIS) += alpha.o
|
||||||
common-obj-$(CONFIG_ARM_DIS) += arm.o
|
common-obj-$(CONFIG_ARM_DIS) += arm.o
|
||||||
|
common-obj-$(CONFIG_ARM_A64_DIS) += arm-a64.o
|
||||||
|
common-obj-$(CONFIG_ARM_A64_DIS) += libvixl/
|
||||||
|
libvixldir = $(SRC_PATH)/disas/libvixl
|
||||||
|
$(obj)/arm-a64.o: QEMU_CFLAGS += -I$(libvixldir)
|
||||||
common-obj-$(CONFIG_CRIS_DIS) += cris.o
|
common-obj-$(CONFIG_CRIS_DIS) += cris.o
|
||||||
common-obj-$(CONFIG_HPPA_DIS) += hppa.o
|
common-obj-$(CONFIG_HPPA_DIS) += hppa.o
|
||||||
common-obj-$(CONFIG_I386_DIS) += i386.o
|
common-obj-$(CONFIG_I386_DIS) += i386.o
|
||||||
|
|||||||
87
disas/arm-a64.cc
Normal file
87
disas/arm-a64.cc
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* ARM A64 disassembly output wrapper to libvixl
|
||||||
|
* Copyright (c) 2013 Linaro Limited
|
||||||
|
* Written by Claudio Fontana
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "a64/disasm-a64.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "disas/bfd.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace vixl;
|
||||||
|
|
||||||
|
static Decoder *vixl_decoder = NULL;
|
||||||
|
static Disassembler *vixl_disasm = NULL;
|
||||||
|
|
||||||
|
/* We don't use libvixl's PrintDisassembler because its output
|
||||||
|
* is a little unhelpful (trailing newlines, for example).
|
||||||
|
* Instead we use our own very similar variant so we have
|
||||||
|
* control over the format.
|
||||||
|
*/
|
||||||
|
class QEMUDisassembler : public Disassembler {
|
||||||
|
public:
|
||||||
|
explicit QEMUDisassembler(FILE *stream) : stream_(stream) { }
|
||||||
|
~QEMUDisassembler() { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ProcessOutput(Instruction *instr) {
|
||||||
|
fprintf(stream_, "%08" PRIx32 " %s",
|
||||||
|
instr->InstructionBits(), GetOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE *stream_;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int vixl_is_initialized(void)
|
||||||
|
{
|
||||||
|
return vixl_decoder != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vixl_init(FILE *f) {
|
||||||
|
vixl_decoder = new Decoder();
|
||||||
|
vixl_disasm = new QEMUDisassembler(f);
|
||||||
|
vixl_decoder->AppendVisitor(vixl_disasm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INSN_SIZE 4
|
||||||
|
|
||||||
|
/* Disassemble ARM A64 instruction. This is our only entry
|
||||||
|
* point from QEMU's C code.
|
||||||
|
*/
|
||||||
|
int print_insn_arm_a64(uint64_t addr, disassemble_info *info)
|
||||||
|
{
|
||||||
|
uint8_t bytes[INSN_SIZE];
|
||||||
|
uint32_t instr;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = info->read_memory_func(addr, bytes, INSN_SIZE, info);
|
||||||
|
if (status != 0) {
|
||||||
|
info->memory_error_func(status, addr, info);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vixl_is_initialized()) {
|
||||||
|
vixl_init(info->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
instr = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24;
|
||||||
|
vixl_decoder->Decode(reinterpret_cast<Instruction*>(&instr));
|
||||||
|
|
||||||
|
return INSN_SIZE;
|
||||||
|
}
|
||||||
154
disas/i386.c
154
disas/i386.c
@@ -171,6 +171,7 @@ static void print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma dis
|
|||||||
static void print_displacement (char *, bfd_vma);
|
static void print_displacement (char *, bfd_vma);
|
||||||
static void OP_E (int, int);
|
static void OP_E (int, int);
|
||||||
static void OP_G (int, int);
|
static void OP_G (int, int);
|
||||||
|
static void OP_vvvv (int, int);
|
||||||
static bfd_vma get64 (void);
|
static bfd_vma get64 (void);
|
||||||
static bfd_signed_vma get32 (void);
|
static bfd_signed_vma get32 (void);
|
||||||
static bfd_signed_vma get32s (void);
|
static bfd_signed_vma get32s (void);
|
||||||
@@ -264,6 +265,9 @@ static int rex_used;
|
|||||||
current instruction. */
|
current instruction. */
|
||||||
static int used_prefixes;
|
static int used_prefixes;
|
||||||
|
|
||||||
|
/* The VEX.vvvv register, unencoded. */
|
||||||
|
static int vex_reg;
|
||||||
|
|
||||||
/* Flags stored in PREFIXES. */
|
/* Flags stored in PREFIXES. */
|
||||||
#define PREFIX_REPZ 1
|
#define PREFIX_REPZ 1
|
||||||
#define PREFIX_REPNZ 2
|
#define PREFIX_REPNZ 2
|
||||||
@@ -278,6 +282,10 @@ static int used_prefixes;
|
|||||||
#define PREFIX_ADDR 0x400
|
#define PREFIX_ADDR 0x400
|
||||||
#define PREFIX_FWAIT 0x800
|
#define PREFIX_FWAIT 0x800
|
||||||
|
|
||||||
|
#define PREFIX_VEX_0F 0x1000
|
||||||
|
#define PREFIX_VEX_0F38 0x2000
|
||||||
|
#define PREFIX_VEX_0F3A 0x4000
|
||||||
|
|
||||||
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
|
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
|
||||||
to ADDR (exclusive) are valid. Returns 1 for success, longjmps
|
to ADDR (exclusive) are valid. Returns 1 for success, longjmps
|
||||||
on error. */
|
on error. */
|
||||||
@@ -323,6 +331,7 @@ fetch_data(struct disassemble_info *info, bfd_byte *addr)
|
|||||||
|
|
||||||
#define XX { NULL, 0 }
|
#define XX { NULL, 0 }
|
||||||
|
|
||||||
|
#define Bv { OP_vvvv, v_mode }
|
||||||
#define Eb { OP_E, b_mode }
|
#define Eb { OP_E, b_mode }
|
||||||
#define Ev { OP_E, v_mode }
|
#define Ev { OP_E, v_mode }
|
||||||
#define Ed { OP_E, d_mode }
|
#define Ed { OP_E, d_mode }
|
||||||
@@ -671,7 +680,8 @@ fetch_data(struct disassemble_info *info, bfd_byte *addr)
|
|||||||
#define PREGRP102 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 102 } }
|
#define PREGRP102 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 102 } }
|
||||||
#define PREGRP103 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 103 } }
|
#define PREGRP103 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 103 } }
|
||||||
#define PREGRP104 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 104 } }
|
#define PREGRP104 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 104 } }
|
||||||
|
#define PREGRP105 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 105 } }
|
||||||
|
#define PREGRP106 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 106 } }
|
||||||
|
|
||||||
#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } }
|
#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } }
|
||||||
#define X86_64_1 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } }
|
#define X86_64_1 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } }
|
||||||
@@ -1449,7 +1459,7 @@ static const unsigned char threebyte_0x38_uses_DATA_prefix[256] = {
|
|||||||
/* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
|
/* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
|
||||||
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1, /* df */
|
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1, /* df */
|
||||||
/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
|
/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
|
||||||
/* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
|
/* f0 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* ff */
|
||||||
/* ------------------------------- */
|
/* ------------------------------- */
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||||
};
|
};
|
||||||
@@ -1473,7 +1483,7 @@ static const unsigned char threebyte_0x38_uses_REPNZ_prefix[256] = {
|
|||||||
/* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
|
/* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
|
||||||
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
|
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
|
||||||
/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
|
/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
|
||||||
/* f0 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
|
/* f0 */ 1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* ff */
|
||||||
/* ------------------------------- */
|
/* ------------------------------- */
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||||
};
|
};
|
||||||
@@ -1497,7 +1507,7 @@ static const unsigned char threebyte_0x38_uses_REPZ_prefix[256] = {
|
|||||||
/* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
|
/* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
|
||||||
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
|
/* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
|
||||||
/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
|
/* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
|
||||||
/* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
|
/* f0 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* ff */
|
||||||
/* ------------------------------- */
|
/* ------------------------------- */
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||||
};
|
};
|
||||||
@@ -2632,17 +2642,17 @@ static const struct dis386 prefix_user_table[][4] = {
|
|||||||
|
|
||||||
/* PREGRP87 */
|
/* PREGRP87 */
|
||||||
{
|
{
|
||||||
|
{ "movbe", { Gv, Ev } },
|
||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
{ "(bad)", { XX } },
|
{ "movbe", { Gv, Ev } },
|
||||||
{ "(bad)", { XX } },
|
|
||||||
{ "crc32", { Gdq, { CRC32_Fixup, b_mode } } },
|
{ "crc32", { Gdq, { CRC32_Fixup, b_mode } } },
|
||||||
},
|
},
|
||||||
|
|
||||||
/* PREGRP88 */
|
/* PREGRP88 */
|
||||||
{
|
{
|
||||||
|
{ "movbe", { Ev, Gv } },
|
||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
{ "(bad)", { XX } },
|
{ "movbe", { Ev, Gv } },
|
||||||
{ "(bad)", { XX } },
|
|
||||||
{ "crc32", { Gdq, { CRC32_Fixup, v_mode } } },
|
{ "crc32", { Gdq, { CRC32_Fixup, v_mode } } },
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -2774,6 +2784,22 @@ static const struct dis386 prefix_user_table[][4] = {
|
|||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/* PREGRP105 */
|
||||||
|
{
|
||||||
|
{ "andnS", { Gv, Bv, Ev } },
|
||||||
|
{ "(bad)", { XX } },
|
||||||
|
{ "(bad)", { XX } },
|
||||||
|
{ "(bad)", { XX } },
|
||||||
|
},
|
||||||
|
|
||||||
|
/* PREGRP106 */
|
||||||
|
{
|
||||||
|
{ "bextrS", { Gv, Ev, Bv } },
|
||||||
|
{ "sarxS", { Gv, Ev, Bv } },
|
||||||
|
{ "shlxS", { Gv, Ev, Bv } },
|
||||||
|
{ "shrxS", { Gv, Ev, Bv } },
|
||||||
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct dis386 x86_64_table[][2] = {
|
static const struct dis386 x86_64_table[][2] = {
|
||||||
@@ -3071,12 +3097,12 @@ static const struct dis386 three_byte_table[][256] = {
|
|||||||
/* f0 */
|
/* f0 */
|
||||||
{ PREGRP87 },
|
{ PREGRP87 },
|
||||||
{ PREGRP88 },
|
{ PREGRP88 },
|
||||||
|
{ PREGRP105 },
|
||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
{ "(bad)", { XX } },
|
{ PREGRP106 },
|
||||||
{ "(bad)", { XX } },
|
|
||||||
/* f8 */
|
/* f8 */
|
||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
{ "(bad)", { XX } },
|
{ "(bad)", { XX } },
|
||||||
@@ -3477,6 +3503,74 @@ ckprefix (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ckvexprefix (void)
|
||||||
|
{
|
||||||
|
int op, vex2, vex3, newrex = 0, newpfx = prefixes;
|
||||||
|
|
||||||
|
if (address_mode == mode_16bit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch_data(the_info, codep + 1);
|
||||||
|
op = *codep;
|
||||||
|
|
||||||
|
if (op != 0xc4 && op != 0xc5) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch_data(the_info, codep + 2);
|
||||||
|
vex2 = codep[1];
|
||||||
|
|
||||||
|
if (address_mode == mode_32bit && (vex2 & 0xc0) != 0xc0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == 0xc4) {
|
||||||
|
/* Three byte VEX prefix. */
|
||||||
|
fetch_data(the_info, codep + 3);
|
||||||
|
vex3 = codep[2];
|
||||||
|
|
||||||
|
newrex |= (vex2 & 0x80 ? 0 : REX_R);
|
||||||
|
newrex |= (vex2 & 0x40 ? 0 : REX_X);
|
||||||
|
newrex |= (vex2 & 0x20 ? 0 : REX_B);
|
||||||
|
newrex |= (vex3 & 0x80 ? REX_W : 0);
|
||||||
|
switch (vex2 & 0x1f) { /* VEX.m-mmmm */
|
||||||
|
case 1:
|
||||||
|
newpfx |= PREFIX_VEX_0F;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
newpfx |= PREFIX_VEX_0F | PREFIX_VEX_0F38;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
newpfx |= PREFIX_VEX_0F | PREFIX_VEX_0F3A;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vex2 = vex3;
|
||||||
|
codep += 3;
|
||||||
|
} else {
|
||||||
|
/* Two byte VEX prefix. */
|
||||||
|
newrex |= (vex2 & 0x80 ? 0 : REX_R);
|
||||||
|
codep += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
vex_reg = (~vex2 >> 3) & 15; /* VEX.vvvv */
|
||||||
|
switch (vex2 & 3) { /* VEX.pp */
|
||||||
|
case 1:
|
||||||
|
newpfx |= PREFIX_DATA; /* 0x66 */
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
newpfx |= PREFIX_REPZ; /* 0xf3 */
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
newpfx |= PREFIX_REPNZ; /* 0xf2 */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rex = newrex;
|
||||||
|
prefixes = newpfx;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the name of the prefix byte PREF, or NULL if PREF is not a
|
/* Return the name of the prefix byte PREF, or NULL if PREF is not a
|
||||||
prefix byte. */
|
prefix byte. */
|
||||||
|
|
||||||
@@ -3598,6 +3692,7 @@ print_insn (bfd_vma pc, disassemble_info *info)
|
|||||||
const char *p;
|
const char *p;
|
||||||
struct dis_private priv;
|
struct dis_private priv;
|
||||||
unsigned char op;
|
unsigned char op;
|
||||||
|
unsigned char threebyte;
|
||||||
|
|
||||||
if (info->mach == bfd_mach_x86_64_intel_syntax
|
if (info->mach == bfd_mach_x86_64_intel_syntax
|
||||||
|| info->mach == bfd_mach_x86_64)
|
|| info->mach == bfd_mach_x86_64)
|
||||||
@@ -3752,6 +3847,7 @@ print_insn (bfd_vma pc, disassemble_info *info)
|
|||||||
|
|
||||||
obufp = obuf;
|
obufp = obuf;
|
||||||
ckprefix ();
|
ckprefix ();
|
||||||
|
ckvexprefix ();
|
||||||
|
|
||||||
insn_codep = codep;
|
insn_codep = codep;
|
||||||
sizeflag = priv.orig_sizeflag;
|
sizeflag = priv.orig_sizeflag;
|
||||||
@@ -3775,18 +3871,29 @@ print_insn (bfd_vma pc, disassemble_info *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
op = 0;
|
op = 0;
|
||||||
|
if (prefixes & PREFIX_VEX_0F)
|
||||||
|
{
|
||||||
|
used_prefixes |= PREFIX_VEX_0F | PREFIX_VEX_0F38 | PREFIX_VEX_0F3A;
|
||||||
|
if (prefixes & PREFIX_VEX_0F38)
|
||||||
|
threebyte = 0x38;
|
||||||
|
else if (prefixes & PREFIX_VEX_0F3A)
|
||||||
|
threebyte = 0x3a;
|
||||||
|
else
|
||||||
|
threebyte = *codep++;
|
||||||
|
goto vex_opcode;
|
||||||
|
}
|
||||||
if (*codep == 0x0f)
|
if (*codep == 0x0f)
|
||||||
{
|
{
|
||||||
unsigned char threebyte;
|
|
||||||
fetch_data(info, codep + 2);
|
fetch_data(info, codep + 2);
|
||||||
threebyte = *++codep;
|
threebyte = codep[1];
|
||||||
|
codep += 2;
|
||||||
|
vex_opcode:
|
||||||
dp = &dis386_twobyte[threebyte];
|
dp = &dis386_twobyte[threebyte];
|
||||||
need_modrm = twobyte_has_modrm[*codep];
|
need_modrm = twobyte_has_modrm[threebyte];
|
||||||
uses_DATA_prefix = twobyte_uses_DATA_prefix[*codep];
|
uses_DATA_prefix = twobyte_uses_DATA_prefix[threebyte];
|
||||||
uses_REPNZ_prefix = twobyte_uses_REPNZ_prefix[*codep];
|
uses_REPNZ_prefix = twobyte_uses_REPNZ_prefix[threebyte];
|
||||||
uses_REPZ_prefix = twobyte_uses_REPZ_prefix[*codep];
|
uses_REPZ_prefix = twobyte_uses_REPZ_prefix[threebyte];
|
||||||
uses_LOCK_prefix = (*codep & ~0x02) == 0x20;
|
uses_LOCK_prefix = (threebyte & ~0x02) == 0x20;
|
||||||
codep++;
|
|
||||||
if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE)
|
if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE)
|
||||||
{
|
{
|
||||||
fetch_data(info, codep + 2);
|
fetch_data(info, codep + 2);
|
||||||
@@ -5291,6 +5398,17 @@ OP_G (int bytemode, int sizeflag)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
OP_vvvv (int bytemode, int sizeflags)
|
||||||
|
{
|
||||||
|
USED_REX (REX_W);
|
||||||
|
if (rex & REX_W) {
|
||||||
|
oappend(names64[vex_reg]);
|
||||||
|
} else {
|
||||||
|
oappend(names32[vex_reg]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bfd_vma
|
static bfd_vma
|
||||||
get64 (void)
|
get64 (void)
|
||||||
{
|
{
|
||||||
|
|||||||
30
disas/libvixl/LICENCE
Normal file
30
disas/libvixl/LICENCE
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
LICENCE
|
||||||
|
=======
|
||||||
|
|
||||||
|
The software in this repository is covered by the following licence.
|
||||||
|
|
||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
8
disas/libvixl/Makefile.objs
Normal file
8
disas/libvixl/Makefile.objs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
libvixl_OBJS = utils.o \
|
||||||
|
a64/instructions-a64.o \
|
||||||
|
a64/decoder-a64.o \
|
||||||
|
a64/disasm-a64.o
|
||||||
|
|
||||||
|
$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS += -I$(SRC_PATH)/disas/libvixl
|
||||||
|
|
||||||
|
common-obj-$(CONFIG_ARM_A64_DIS) += $(libvixl_OBJS)
|
||||||
12
disas/libvixl/README
Normal file
12
disas/libvixl/README
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
The code in this directory is a subset of libvixl:
|
||||||
|
https://github.com/armvixl/vixl
|
||||||
|
(specifically, it is the set of files needed for disassembly only,
|
||||||
|
taken from libvixl 1.1).
|
||||||
|
Bugfixes should preferably be sent upstream initially.
|
||||||
|
|
||||||
|
The disassembler does not currently support the entire A64 instruction
|
||||||
|
set. Notably:
|
||||||
|
* No Advanced SIMD support.
|
||||||
|
* Limited support for system instructions.
|
||||||
|
* A few miscellaneous integer and floating point instructions are missing.
|
||||||
1784
disas/libvixl/a64/assembler-a64.h
Normal file
1784
disas/libvixl/a64/assembler-a64.h
Normal file
File diff suppressed because it is too large
Load Diff
1104
disas/libvixl/a64/constants-a64.h
Normal file
1104
disas/libvixl/a64/constants-a64.h
Normal file
File diff suppressed because it is too large
Load Diff
56
disas/libvixl/a64/cpu-a64.h
Normal file
56
disas/libvixl/a64/cpu-a64.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef VIXL_CPU_A64_H
|
||||||
|
#define VIXL_CPU_A64_H
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
|
||||||
|
class CPU {
|
||||||
|
public:
|
||||||
|
// Initialise CPU support.
|
||||||
|
static void SetUp();
|
||||||
|
|
||||||
|
// Ensures the data at a given address and with a given size is the same for
|
||||||
|
// the I and D caches. I and D caches are not automatically coherent on ARM
|
||||||
|
// so this operation is required before any dynamically generated code can
|
||||||
|
// safely run.
|
||||||
|
static void EnsureIAndDCacheCoherency(void *address, size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Return the content of the cache type register.
|
||||||
|
static uint32_t GetCacheType();
|
||||||
|
|
||||||
|
// I and D cache line size in bytes.
|
||||||
|
static unsigned icache_line_size_;
|
||||||
|
static unsigned dcache_line_size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vixl
|
||||||
|
|
||||||
|
#endif // VIXL_CPU_A64_H
|
||||||
712
disas/libvixl/a64/decoder-a64.cc
Normal file
712
disas/libvixl/a64/decoder-a64.cc
Normal file
@@ -0,0 +1,712 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "a64/decoder-a64.h"
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
// Top-level instruction decode function.
|
||||||
|
void Decoder::Decode(Instruction *instr) {
|
||||||
|
if (instr->Bits(28, 27) == 0) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
switch (instr->Bits(27, 24)) {
|
||||||
|
// 0: PC relative addressing.
|
||||||
|
case 0x0: DecodePCRelAddressing(instr); break;
|
||||||
|
|
||||||
|
// 1: Add/sub immediate.
|
||||||
|
case 0x1: DecodeAddSubImmediate(instr); break;
|
||||||
|
|
||||||
|
// A: Logical shifted register.
|
||||||
|
// Add/sub with carry.
|
||||||
|
// Conditional compare register.
|
||||||
|
// Conditional compare immediate.
|
||||||
|
// Conditional select.
|
||||||
|
// Data processing 1 source.
|
||||||
|
// Data processing 2 source.
|
||||||
|
// B: Add/sub shifted register.
|
||||||
|
// Add/sub extended register.
|
||||||
|
// Data processing 3 source.
|
||||||
|
case 0xA:
|
||||||
|
case 0xB: DecodeDataProcessing(instr); break;
|
||||||
|
|
||||||
|
// 2: Logical immediate.
|
||||||
|
// Move wide immediate.
|
||||||
|
case 0x2: DecodeLogical(instr); break;
|
||||||
|
|
||||||
|
// 3: Bitfield.
|
||||||
|
// Extract.
|
||||||
|
case 0x3: DecodeBitfieldExtract(instr); break;
|
||||||
|
|
||||||
|
// 4: Unconditional branch immediate.
|
||||||
|
// Exception generation.
|
||||||
|
// Compare and branch immediate.
|
||||||
|
// 5: Compare and branch immediate.
|
||||||
|
// Conditional branch.
|
||||||
|
// System.
|
||||||
|
// 6,7: Unconditional branch.
|
||||||
|
// Test and branch immediate.
|
||||||
|
case 0x4:
|
||||||
|
case 0x5:
|
||||||
|
case 0x6:
|
||||||
|
case 0x7: DecodeBranchSystemException(instr); break;
|
||||||
|
|
||||||
|
// 8,9: Load/store register pair post-index.
|
||||||
|
// Load register literal.
|
||||||
|
// Load/store register unscaled immediate.
|
||||||
|
// Load/store register immediate post-index.
|
||||||
|
// Load/store register immediate pre-index.
|
||||||
|
// Load/store register offset.
|
||||||
|
// Load/store exclusive.
|
||||||
|
// C,D: Load/store register pair offset.
|
||||||
|
// Load/store register pair pre-index.
|
||||||
|
// Load/store register unsigned immediate.
|
||||||
|
// Advanced SIMD.
|
||||||
|
case 0x8:
|
||||||
|
case 0x9:
|
||||||
|
case 0xC:
|
||||||
|
case 0xD: DecodeLoadStore(instr); break;
|
||||||
|
|
||||||
|
// E: FP fixed point conversion.
|
||||||
|
// FP integer conversion.
|
||||||
|
// FP data processing 1 source.
|
||||||
|
// FP compare.
|
||||||
|
// FP immediate.
|
||||||
|
// FP data processing 2 source.
|
||||||
|
// FP conditional compare.
|
||||||
|
// FP conditional select.
|
||||||
|
// Advanced SIMD.
|
||||||
|
// F: FP data processing 3 source.
|
||||||
|
// Advanced SIMD.
|
||||||
|
case 0xE:
|
||||||
|
case 0xF: DecodeFP(instr); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Decoder::AppendVisitor(DecoderVisitor* new_visitor) {
|
||||||
|
visitors_.remove(new_visitor);
|
||||||
|
visitors_.push_front(new_visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::PrependVisitor(DecoderVisitor* new_visitor) {
|
||||||
|
visitors_.remove(new_visitor);
|
||||||
|
visitors_.push_back(new_visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
|
||||||
|
DecoderVisitor* registered_visitor) {
|
||||||
|
visitors_.remove(new_visitor);
|
||||||
|
std::list<DecoderVisitor*>::iterator it;
|
||||||
|
for (it = visitors_.begin(); it != visitors_.end(); it++) {
|
||||||
|
if (*it == registered_visitor) {
|
||||||
|
visitors_.insert(it, new_visitor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We reached the end of the list. The last element must be
|
||||||
|
// registered_visitor.
|
||||||
|
ASSERT(*it == registered_visitor);
|
||||||
|
visitors_.insert(it, new_visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
|
||||||
|
DecoderVisitor* registered_visitor) {
|
||||||
|
visitors_.remove(new_visitor);
|
||||||
|
std::list<DecoderVisitor*>::iterator it;
|
||||||
|
for (it = visitors_.begin(); it != visitors_.end(); it++) {
|
||||||
|
if (*it == registered_visitor) {
|
||||||
|
it++;
|
||||||
|
visitors_.insert(it, new_visitor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We reached the end of the list. The last element must be
|
||||||
|
// registered_visitor.
|
||||||
|
ASSERT(*it == registered_visitor);
|
||||||
|
visitors_.push_back(new_visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
|
||||||
|
visitors_.remove(visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodePCRelAddressing(Instruction* instr) {
|
||||||
|
ASSERT(instr->Bits(27, 24) == 0x0);
|
||||||
|
// We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
|
||||||
|
// decode.
|
||||||
|
ASSERT(instr->Bit(28) == 0x1);
|
||||||
|
VisitPCRelAddressing(instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
||||||
|
ASSERT((instr->Bits(27, 24) == 0x4) ||
|
||||||
|
(instr->Bits(27, 24) == 0x5) ||
|
||||||
|
(instr->Bits(27, 24) == 0x6) ||
|
||||||
|
(instr->Bits(27, 24) == 0x7) );
|
||||||
|
|
||||||
|
switch (instr->Bits(31, 29)) {
|
||||||
|
case 0:
|
||||||
|
case 4: {
|
||||||
|
VisitUnconditionalBranch(instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
case 5: {
|
||||||
|
if (instr->Bit(25) == 0) {
|
||||||
|
VisitCompareBranch(instr);
|
||||||
|
} else {
|
||||||
|
VisitTestBranch(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
if (instr->Bit(25) == 0) {
|
||||||
|
if ((instr->Bit(24) == 0x1) ||
|
||||||
|
(instr->Mask(0x01000010) == 0x00000010)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitConditionalBranch(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
if (instr->Bit(25) == 0) {
|
||||||
|
if (instr->Bit(24) == 0) {
|
||||||
|
if ((instr->Bits(4, 2) != 0) ||
|
||||||
|
(instr->Mask(0x00E0001D) == 0x00200001) ||
|
||||||
|
(instr->Mask(0x00E0001D) == 0x00400001) ||
|
||||||
|
(instr->Mask(0x00E0001E) == 0x00200002) ||
|
||||||
|
(instr->Mask(0x00E0001E) == 0x00400002) ||
|
||||||
|
(instr->Mask(0x00E0001C) == 0x00600000) ||
|
||||||
|
(instr->Mask(0x00E0001C) == 0x00800000) ||
|
||||||
|
(instr->Mask(0x00E0001F) == 0x00A00000) ||
|
||||||
|
(instr->Mask(0x00C0001C) == 0x00C00000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitException(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (instr->Bits(23, 22) == 0) {
|
||||||
|
const Instr masked_003FF0E0 = instr->Mask(0x003FF0E0);
|
||||||
|
if ((instr->Bits(21, 19) == 0x4) ||
|
||||||
|
(masked_003FF0E0 == 0x00033000) ||
|
||||||
|
(masked_003FF0E0 == 0x003FF020) ||
|
||||||
|
(masked_003FF0E0 == 0x003FF060) ||
|
||||||
|
(masked_003FF0E0 == 0x003FF0E0) ||
|
||||||
|
(instr->Mask(0x00388000) == 0x00008000) ||
|
||||||
|
(instr->Mask(0x0038E000) == 0x00000000) ||
|
||||||
|
(instr->Mask(0x0039E000) == 0x00002000) ||
|
||||||
|
(instr->Mask(0x003AE000) == 0x00002000) ||
|
||||||
|
(instr->Mask(0x003CE000) == 0x00042000) ||
|
||||||
|
(instr->Mask(0x003FFFC0) == 0x000320C0) ||
|
||||||
|
(instr->Mask(0x003FF100) == 0x00032100) ||
|
||||||
|
(instr->Mask(0x003FF200) == 0x00032200) ||
|
||||||
|
(instr->Mask(0x003FF400) == 0x00032400) ||
|
||||||
|
(instr->Mask(0x003FF800) == 0x00032800) ||
|
||||||
|
(instr->Mask(0x0038F000) == 0x00005000) ||
|
||||||
|
(instr->Mask(0x0038E000) == 0x00006000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitSystem(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((instr->Bit(24) == 0x1) ||
|
||||||
|
(instr->Bits(20, 16) != 0x1F) ||
|
||||||
|
(instr->Bits(15, 10) != 0) ||
|
||||||
|
(instr->Bits(4, 0) != 0) ||
|
||||||
|
(instr->Bits(24, 21) == 0x3) ||
|
||||||
|
(instr->Bits(24, 22) == 0x3)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitUnconditionalBranchToRegister(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
case 7: {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeLoadStore(Instruction* instr) {
|
||||||
|
ASSERT((instr->Bits(27, 24) == 0x8) ||
|
||||||
|
(instr->Bits(27, 24) == 0x9) ||
|
||||||
|
(instr->Bits(27, 24) == 0xC) ||
|
||||||
|
(instr->Bits(27, 24) == 0xD) );
|
||||||
|
|
||||||
|
if (instr->Bit(24) == 0) {
|
||||||
|
if (instr->Bit(28) == 0) {
|
||||||
|
if (instr->Bit(29) == 0) {
|
||||||
|
if (instr->Bit(26) == 0) {
|
||||||
|
// TODO: VisitLoadStoreExclusive.
|
||||||
|
VisitUnimplemented(instr);
|
||||||
|
} else {
|
||||||
|
DecodeAdvSIMDLoadStore(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((instr->Bits(31, 30) == 0x3) ||
|
||||||
|
(instr->Mask(0xC4400000) == 0x40000000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(23) == 0) {
|
||||||
|
if (instr->Mask(0xC4400000) == 0xC0400000) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitLoadStorePairNonTemporal(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VisitLoadStorePairPostIndex(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(29) == 0) {
|
||||||
|
if (instr->Mask(0xC4000000) == 0xC4000000) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitLoadLiteral(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((instr->Mask(0x84C00000) == 0x80C00000) ||
|
||||||
|
(instr->Mask(0x44800000) == 0x44800000) ||
|
||||||
|
(instr->Mask(0x84800000) == 0x84800000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(21) == 0) {
|
||||||
|
switch (instr->Bits(11, 10)) {
|
||||||
|
case 0: {
|
||||||
|
VisitLoadStoreUnscaledOffset(instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
if (instr->Mask(0xC4C00000) == 0xC0800000) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitLoadStorePostIndex(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
// TODO: VisitLoadStoreRegisterOffsetUnpriv.
|
||||||
|
VisitUnimplemented(instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
if (instr->Mask(0xC4C00000) == 0xC0800000) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitLoadStorePreIndex(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (instr->Bits(11, 10) == 0x2) {
|
||||||
|
if (instr->Bit(14) == 0) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitLoadStoreRegisterOffset(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(28) == 0) {
|
||||||
|
if (instr->Bit(29) == 0) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if ((instr->Bits(31, 30) == 0x3) ||
|
||||||
|
(instr->Mask(0xC4400000) == 0x40000000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(23) == 0) {
|
||||||
|
VisitLoadStorePairOffset(instr);
|
||||||
|
} else {
|
||||||
|
VisitLoadStorePairPreIndex(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(29) == 0) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if ((instr->Mask(0x84C00000) == 0x80C00000) ||
|
||||||
|
(instr->Mask(0x44800000) == 0x44800000) ||
|
||||||
|
(instr->Mask(0x84800000) == 0x84800000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitLoadStoreUnsignedOffset(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeLogical(Instruction* instr) {
|
||||||
|
ASSERT(instr->Bits(27, 24) == 0x2);
|
||||||
|
|
||||||
|
if (instr->Mask(0x80400000) == 0x00400000) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(23) == 0) {
|
||||||
|
VisitLogicalImmediate(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bits(30, 29) == 0x1) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitMoveWideImmediate(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
||||||
|
ASSERT(instr->Bits(27, 24) == 0x3);
|
||||||
|
|
||||||
|
if ((instr->Mask(0x80400000) == 0x80000000) ||
|
||||||
|
(instr->Mask(0x80400000) == 0x00400000) ||
|
||||||
|
(instr->Mask(0x80008000) == 0x00008000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else if (instr->Bit(23) == 0) {
|
||||||
|
if ((instr->Mask(0x80200000) == 0x00200000) ||
|
||||||
|
(instr->Mask(0x60000000) == 0x60000000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitBitfield(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((instr->Mask(0x60200000) == 0x00200000) ||
|
||||||
|
(instr->Mask(0x60000000) != 0x00000000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitExtract(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
||||||
|
ASSERT(instr->Bits(27, 24) == 0x1);
|
||||||
|
if (instr->Bit(23) == 1) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitAddSubImmediate(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeDataProcessing(Instruction* instr) {
|
||||||
|
ASSERT((instr->Bits(27, 24) == 0xA) ||
|
||||||
|
(instr->Bits(27, 24) == 0xB) );
|
||||||
|
|
||||||
|
if (instr->Bit(24) == 0) {
|
||||||
|
if (instr->Bit(28) == 0) {
|
||||||
|
if (instr->Mask(0x80008000) == 0x00008000) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitLogicalShifted(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (instr->Bits(23, 21)) {
|
||||||
|
case 0: {
|
||||||
|
if (instr->Mask(0x0000FC00) != 0) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitAddSubWithCarry(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
if ((instr->Bit(29) == 0) ||
|
||||||
|
(instr->Mask(0x00000410) != 0)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(11) == 0) {
|
||||||
|
VisitConditionalCompareRegister(instr);
|
||||||
|
} else {
|
||||||
|
VisitConditionalCompareImmediate(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
if (instr->Mask(0x20000800) != 0x00000000) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitConditionalSelect(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
if (instr->Bit(29) == 0x1) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(30) == 0) {
|
||||||
|
if ((instr->Bit(15) == 0x1) ||
|
||||||
|
(instr->Bits(15, 11) == 0) ||
|
||||||
|
(instr->Bits(15, 12) == 0x1) ||
|
||||||
|
(instr->Bits(15, 12) == 0x3) ||
|
||||||
|
(instr->Bits(15, 13) == 0x3) ||
|
||||||
|
(instr->Mask(0x8000EC00) == 0x00004C00) ||
|
||||||
|
(instr->Mask(0x8000E800) == 0x80004000) ||
|
||||||
|
(instr->Mask(0x8000E400) == 0x80004000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitDataProcessing2Source(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((instr->Bit(13) == 1) ||
|
||||||
|
(instr->Bits(20, 16) != 0) ||
|
||||||
|
(instr->Bits(15, 14) != 0) ||
|
||||||
|
(instr->Mask(0xA01FFC00) == 0x00000C00) ||
|
||||||
|
(instr->Mask(0x201FF800) == 0x00001800)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitDataProcessing1Source(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
case 5:
|
||||||
|
case 7: VisitUnallocated(instr); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(28) == 0) {
|
||||||
|
if (instr->Bit(21) == 0) {
|
||||||
|
if ((instr->Bits(23, 22) == 0x3) ||
|
||||||
|
(instr->Mask(0x80008000) == 0x00008000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitAddSubShifted(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((instr->Mask(0x00C00000) != 0x00000000) ||
|
||||||
|
(instr->Mask(0x00001400) == 0x00001400) ||
|
||||||
|
(instr->Mask(0x00001800) == 0x00001800)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitAddSubExtended(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((instr->Bit(30) == 0x1) ||
|
||||||
|
(instr->Bits(30, 29) == 0x1) ||
|
||||||
|
(instr->Mask(0xE0600000) == 0x00200000) ||
|
||||||
|
(instr->Mask(0xE0608000) == 0x00400000) ||
|
||||||
|
(instr->Mask(0x60608000) == 0x00408000) ||
|
||||||
|
(instr->Mask(0x60E00000) == 0x00E00000) ||
|
||||||
|
(instr->Mask(0x60E00000) == 0x00800000) ||
|
||||||
|
(instr->Mask(0x60E00000) == 0x00600000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitDataProcessing3Source(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeFP(Instruction* instr) {
|
||||||
|
ASSERT((instr->Bits(27, 24) == 0xE) ||
|
||||||
|
(instr->Bits(27, 24) == 0xF) );
|
||||||
|
|
||||||
|
if (instr->Bit(28) == 0) {
|
||||||
|
DecodeAdvSIMDDataProcessing(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(29) == 1) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bits(31, 30) == 0x3) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else if (instr->Bits(31, 30) == 0x1) {
|
||||||
|
DecodeAdvSIMDDataProcessing(instr);
|
||||||
|
} else {
|
||||||
|
if (instr->Bit(24) == 0) {
|
||||||
|
if (instr->Bit(21) == 0) {
|
||||||
|
if ((instr->Bit(23) == 1) ||
|
||||||
|
(instr->Bit(18) == 1) ||
|
||||||
|
(instr->Mask(0x80008000) == 0x00000000) ||
|
||||||
|
(instr->Mask(0x000E0000) == 0x00000000) ||
|
||||||
|
(instr->Mask(0x000E0000) == 0x000A0000) ||
|
||||||
|
(instr->Mask(0x00160000) == 0x00000000) ||
|
||||||
|
(instr->Mask(0x00160000) == 0x00120000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitFPFixedPointConvert(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (instr->Bits(15, 10) == 32) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else if (instr->Bits(15, 10) == 0) {
|
||||||
|
if ((instr->Bits(23, 22) == 0x3) ||
|
||||||
|
(instr->Mask(0x000E0000) == 0x000A0000) ||
|
||||||
|
(instr->Mask(0x000E0000) == 0x000C0000) ||
|
||||||
|
(instr->Mask(0x00160000) == 0x00120000) ||
|
||||||
|
(instr->Mask(0x00160000) == 0x00140000) ||
|
||||||
|
(instr->Mask(0x20C40000) == 0x00800000) ||
|
||||||
|
(instr->Mask(0x20C60000) == 0x00840000) ||
|
||||||
|
(instr->Mask(0xA0C60000) == 0x80060000) ||
|
||||||
|
(instr->Mask(0xA0C60000) == 0x00860000) ||
|
||||||
|
(instr->Mask(0xA0C60000) == 0x00460000) ||
|
||||||
|
(instr->Mask(0xA0CE0000) == 0x80860000) ||
|
||||||
|
(instr->Mask(0xA0CE0000) == 0x804E0000) ||
|
||||||
|
(instr->Mask(0xA0CE0000) == 0x000E0000) ||
|
||||||
|
(instr->Mask(0xA0D60000) == 0x00160000) ||
|
||||||
|
(instr->Mask(0xA0D60000) == 0x80560000) ||
|
||||||
|
(instr->Mask(0xA0D60000) == 0x80960000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitFPIntegerConvert(instr);
|
||||||
|
}
|
||||||
|
} else if (instr->Bits(14, 10) == 16) {
|
||||||
|
const Instr masked_A0DF8000 = instr->Mask(0xA0DF8000);
|
||||||
|
if ((instr->Mask(0x80180000) != 0) ||
|
||||||
|
(masked_A0DF8000 == 0x00020000) ||
|
||||||
|
(masked_A0DF8000 == 0x00030000) ||
|
||||||
|
(masked_A0DF8000 == 0x00068000) ||
|
||||||
|
(masked_A0DF8000 == 0x00428000) ||
|
||||||
|
(masked_A0DF8000 == 0x00430000) ||
|
||||||
|
(masked_A0DF8000 == 0x00468000) ||
|
||||||
|
(instr->Mask(0xA0D80000) == 0x00800000) ||
|
||||||
|
(instr->Mask(0xA0DE0000) == 0x00C00000) ||
|
||||||
|
(instr->Mask(0xA0DF0000) == 0x00C30000) ||
|
||||||
|
(instr->Mask(0xA0DC0000) == 0x00C40000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitFPDataProcessing1Source(instr);
|
||||||
|
}
|
||||||
|
} else if (instr->Bits(13, 10) == 8) {
|
||||||
|
if ((instr->Bits(15, 14) != 0) ||
|
||||||
|
(instr->Bits(2, 0) != 0) ||
|
||||||
|
(instr->Mask(0x80800000) != 0x00000000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitFPCompare(instr);
|
||||||
|
}
|
||||||
|
} else if (instr->Bits(12, 10) == 4) {
|
||||||
|
if ((instr->Bits(9, 5) != 0) ||
|
||||||
|
(instr->Mask(0x80800000) != 0x00000000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitFPImmediate(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (instr->Mask(0x80800000) != 0x00000000) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
switch (instr->Bits(11, 10)) {
|
||||||
|
case 1: {
|
||||||
|
VisitFPConditionalCompare(instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
if ((instr->Bits(15, 14) == 0x3) ||
|
||||||
|
(instr->Mask(0x00009000) == 0x00009000) ||
|
||||||
|
(instr->Mask(0x0000A000) == 0x0000A000)) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitFPDataProcessing2Source(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
VisitFPConditionalSelect(instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Bit 30 == 1 has been handled earlier.
|
||||||
|
ASSERT(instr->Bit(30) == 0);
|
||||||
|
if (instr->Mask(0xA0800000) != 0) {
|
||||||
|
VisitUnallocated(instr);
|
||||||
|
} else {
|
||||||
|
VisitFPDataProcessing3Source(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) {
|
||||||
|
// TODO: Implement Advanced SIMD load/store instruction decode.
|
||||||
|
ASSERT(instr->Bits(29, 25) == 0x6);
|
||||||
|
VisitUnimplemented(instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
|
||||||
|
// TODO: Implement Advanced SIMD data processing instruction decode.
|
||||||
|
ASSERT(instr->Bits(27, 25) == 0x7);
|
||||||
|
VisitUnimplemented(instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFINE_VISITOR_CALLERS(A) \
|
||||||
|
void Decoder::Visit##A(Instruction *instr) { \
|
||||||
|
ASSERT(instr->Mask(A##FMask) == A##Fixed); \
|
||||||
|
std::list<DecoderVisitor*>::iterator it; \
|
||||||
|
for (it = visitors_.begin(); it != visitors_.end(); it++) { \
|
||||||
|
(*it)->Visit##A(instr); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
VISITOR_LIST(DEFINE_VISITOR_CALLERS)
|
||||||
|
#undef DEFINE_VISITOR_CALLERS
|
||||||
|
} // namespace vixl
|
||||||
198
disas/libvixl/a64/decoder-a64.h
Normal file
198
disas/libvixl/a64/decoder-a64.h
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef VIXL_A64_DECODER_A64_H_
|
||||||
|
#define VIXL_A64_DECODER_A64_H_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
#include "a64/instructions-a64.h"
|
||||||
|
|
||||||
|
|
||||||
|
// List macro containing all visitors needed by the decoder class.
|
||||||
|
|
||||||
|
#define VISITOR_LIST(V) \
|
||||||
|
V(PCRelAddressing) \
|
||||||
|
V(AddSubImmediate) \
|
||||||
|
V(LogicalImmediate) \
|
||||||
|
V(MoveWideImmediate) \
|
||||||
|
V(Bitfield) \
|
||||||
|
V(Extract) \
|
||||||
|
V(UnconditionalBranch) \
|
||||||
|
V(UnconditionalBranchToRegister) \
|
||||||
|
V(CompareBranch) \
|
||||||
|
V(TestBranch) \
|
||||||
|
V(ConditionalBranch) \
|
||||||
|
V(System) \
|
||||||
|
V(Exception) \
|
||||||
|
V(LoadStorePairPostIndex) \
|
||||||
|
V(LoadStorePairOffset) \
|
||||||
|
V(LoadStorePairPreIndex) \
|
||||||
|
V(LoadStorePairNonTemporal) \
|
||||||
|
V(LoadLiteral) \
|
||||||
|
V(LoadStoreUnscaledOffset) \
|
||||||
|
V(LoadStorePostIndex) \
|
||||||
|
V(LoadStorePreIndex) \
|
||||||
|
V(LoadStoreRegisterOffset) \
|
||||||
|
V(LoadStoreUnsignedOffset) \
|
||||||
|
V(LogicalShifted) \
|
||||||
|
V(AddSubShifted) \
|
||||||
|
V(AddSubExtended) \
|
||||||
|
V(AddSubWithCarry) \
|
||||||
|
V(ConditionalCompareRegister) \
|
||||||
|
V(ConditionalCompareImmediate) \
|
||||||
|
V(ConditionalSelect) \
|
||||||
|
V(DataProcessing1Source) \
|
||||||
|
V(DataProcessing2Source) \
|
||||||
|
V(DataProcessing3Source) \
|
||||||
|
V(FPCompare) \
|
||||||
|
V(FPConditionalCompare) \
|
||||||
|
V(FPConditionalSelect) \
|
||||||
|
V(FPImmediate) \
|
||||||
|
V(FPDataProcessing1Source) \
|
||||||
|
V(FPDataProcessing2Source) \
|
||||||
|
V(FPDataProcessing3Source) \
|
||||||
|
V(FPIntegerConvert) \
|
||||||
|
V(FPFixedPointConvert) \
|
||||||
|
V(Unallocated) \
|
||||||
|
V(Unimplemented)
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
|
||||||
|
// The Visitor interface. Disassembler and simulator (and other tools)
|
||||||
|
// must provide implementations for all of these functions.
|
||||||
|
class DecoderVisitor {
|
||||||
|
public:
|
||||||
|
#define DECLARE(A) virtual void Visit##A(Instruction* instr) = 0;
|
||||||
|
VISITOR_LIST(DECLARE)
|
||||||
|
#undef DECLARE
|
||||||
|
|
||||||
|
virtual ~DecoderVisitor() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Visitors are registered in a list.
|
||||||
|
std::list<DecoderVisitor*> visitors_;
|
||||||
|
|
||||||
|
friend class Decoder;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Decoder: public DecoderVisitor {
|
||||||
|
public:
|
||||||
|
Decoder() {}
|
||||||
|
|
||||||
|
// Top-level instruction decoder function. Decodes an instruction and calls
|
||||||
|
// the visitor functions registered with the Decoder class.
|
||||||
|
void Decode(Instruction *instr);
|
||||||
|
|
||||||
|
// Register a new visitor class with the decoder.
|
||||||
|
// Decode() will call the corresponding visitor method from all registered
|
||||||
|
// visitor classes when decoding reaches the leaf node of the instruction
|
||||||
|
// decode tree.
|
||||||
|
// Visitors are called in the order.
|
||||||
|
// A visitor can only be registered once.
|
||||||
|
// Registering an already registered visitor will update its position.
|
||||||
|
//
|
||||||
|
// d.AppendVisitor(V1);
|
||||||
|
// d.AppendVisitor(V2);
|
||||||
|
// d.PrependVisitor(V2); // Move V2 at the start of the list.
|
||||||
|
// d.InsertVisitorBefore(V3, V2);
|
||||||
|
// d.AppendVisitor(V4);
|
||||||
|
// d.AppendVisitor(V4); // No effect.
|
||||||
|
//
|
||||||
|
// d.Decode(i);
|
||||||
|
//
|
||||||
|
// will call in order visitor methods in V3, V2, V1, V4.
|
||||||
|
void AppendVisitor(DecoderVisitor* visitor);
|
||||||
|
void PrependVisitor(DecoderVisitor* visitor);
|
||||||
|
void InsertVisitorBefore(DecoderVisitor* new_visitor,
|
||||||
|
DecoderVisitor* registered_visitor);
|
||||||
|
void InsertVisitorAfter(DecoderVisitor* new_visitor,
|
||||||
|
DecoderVisitor* registered_visitor);
|
||||||
|
|
||||||
|
// Remove a previously registered visitor class from the list of visitors
|
||||||
|
// stored by the decoder.
|
||||||
|
void RemoveVisitor(DecoderVisitor* visitor);
|
||||||
|
|
||||||
|
#define DECLARE(A) void Visit##A(Instruction* instr);
|
||||||
|
VISITOR_LIST(DECLARE)
|
||||||
|
#undef DECLARE
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Decode the PC relative addressing instruction, and call the corresponding
|
||||||
|
// visitors.
|
||||||
|
// On entry, instruction bits 27:24 = 0x0.
|
||||||
|
void DecodePCRelAddressing(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the add/subtract immediate instruction, and call the correspoding
|
||||||
|
// visitors.
|
||||||
|
// On entry, instruction bits 27:24 = 0x1.
|
||||||
|
void DecodeAddSubImmediate(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the branch, system command, and exception generation parts of
|
||||||
|
// the instruction tree, and call the corresponding visitors.
|
||||||
|
// On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}.
|
||||||
|
void DecodeBranchSystemException(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the load and store parts of the instruction tree, and call
|
||||||
|
// the corresponding visitors.
|
||||||
|
// On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
|
||||||
|
void DecodeLoadStore(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the logical immediate and move wide immediate parts of the
|
||||||
|
// instruction tree, and call the corresponding visitors.
|
||||||
|
// On entry, instruction bits 27:24 = 0x2.
|
||||||
|
void DecodeLogical(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the bitfield and extraction parts of the instruction tree,
|
||||||
|
// and call the corresponding visitors.
|
||||||
|
// On entry, instruction bits 27:24 = 0x3.
|
||||||
|
void DecodeBitfieldExtract(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the data processing parts of the instruction tree, and call the
|
||||||
|
// corresponding visitors.
|
||||||
|
// On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
|
||||||
|
void DecodeDataProcessing(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the floating point parts of the instruction tree, and call the
|
||||||
|
// corresponding visitors.
|
||||||
|
// On entry, instruction bits 27:24 = {0xE, 0xF}.
|
||||||
|
void DecodeFP(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
|
||||||
|
// and call the corresponding visitors.
|
||||||
|
// On entry, instruction bits 29:25 = 0x6.
|
||||||
|
void DecodeAdvSIMDLoadStore(Instruction* instr);
|
||||||
|
|
||||||
|
// Decode the Advanced SIMD (NEON) data processing part of the instruction
|
||||||
|
// tree, and call the corresponding visitors.
|
||||||
|
// On entry, instruction bits 27:25 = 0x7.
|
||||||
|
void DecodeAdvSIMDDataProcessing(Instruction* instr);
|
||||||
|
};
|
||||||
|
} // namespace vixl
|
||||||
|
|
||||||
|
#endif // VIXL_A64_DECODER_A64_H_
|
||||||
1678
disas/libvixl/a64/disasm-a64.cc
Normal file
1678
disas/libvixl/a64/disasm-a64.cc
Normal file
File diff suppressed because it is too large
Load Diff
109
disas/libvixl/a64/disasm-a64.h
Normal file
109
disas/libvixl/a64/disasm-a64.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef VIXL_A64_DISASM_A64_H
|
||||||
|
#define VIXL_A64_DISASM_A64_H
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "instructions-a64.h"
|
||||||
|
#include "decoder-a64.h"
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
|
||||||
|
class Disassembler: public DecoderVisitor {
|
||||||
|
public:
|
||||||
|
Disassembler();
|
||||||
|
Disassembler(char* text_buffer, int buffer_size);
|
||||||
|
virtual ~Disassembler();
|
||||||
|
char* GetOutput();
|
||||||
|
|
||||||
|
// Declare all Visitor functions.
|
||||||
|
#define DECLARE(A) void Visit##A(Instruction* instr);
|
||||||
|
VISITOR_LIST(DECLARE)
|
||||||
|
#undef DECLARE
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void ProcessOutput(Instruction* instr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Format(Instruction* instr, const char* mnemonic, const char* format);
|
||||||
|
void Substitute(Instruction* instr, const char* string);
|
||||||
|
int SubstituteField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteRegisterField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteImmediateField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteLiteralField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteBitfieldImmediateField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteShiftField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteExtendField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteConditionField(Instruction* instr, const char* format);
|
||||||
|
int SubstitutePCRelAddressField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteBranchTargetField(Instruction* instr, const char* format);
|
||||||
|
int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
|
||||||
|
int SubstitutePrefetchField(Instruction* instr, const char* format);
|
||||||
|
|
||||||
|
inline bool RdIsZROrSP(Instruction* instr) const {
|
||||||
|
return (instr->Rd() == kZeroRegCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool RnIsZROrSP(Instruction* instr) const {
|
||||||
|
return (instr->Rn() == kZeroRegCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool RmIsZROrSP(Instruction* instr) const {
|
||||||
|
return (instr->Rm() == kZeroRegCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool RaIsZROrSP(Instruction* instr) const {
|
||||||
|
return (instr->Ra() == kZeroRegCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
|
||||||
|
|
||||||
|
void ResetOutput();
|
||||||
|
void AppendToOutput(const char* string, ...);
|
||||||
|
|
||||||
|
char* buffer_;
|
||||||
|
uint32_t buffer_pos_;
|
||||||
|
uint32_t buffer_size_;
|
||||||
|
bool own_buffer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PrintDisassembler: public Disassembler {
|
||||||
|
public:
|
||||||
|
explicit PrintDisassembler(FILE* stream) : stream_(stream) { }
|
||||||
|
~PrintDisassembler() { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void ProcessOutput(Instruction* instr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE *stream_;
|
||||||
|
};
|
||||||
|
} // namespace vixl
|
||||||
|
|
||||||
|
#endif // VIXL_A64_DISASM_A64_H
|
||||||
238
disas/libvixl/a64/instructions-a64.cc
Normal file
238
disas/libvixl/a64/instructions-a64.cc
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "a64/instructions-a64.h"
|
||||||
|
#include "a64/assembler-a64.h"
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
|
||||||
|
|
||||||
|
static uint64_t RotateRight(uint64_t value,
|
||||||
|
unsigned int rotate,
|
||||||
|
unsigned int width) {
|
||||||
|
ASSERT(width <= 64);
|
||||||
|
rotate &= 63;
|
||||||
|
return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) |
|
||||||
|
(value >> rotate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
|
||||||
|
uint64_t value,
|
||||||
|
unsigned width) {
|
||||||
|
ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
|
||||||
|
(width == 32));
|
||||||
|
ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||||
|
uint64_t result = value & ((1UL << width) - 1UL);
|
||||||
|
for (unsigned i = width; i < reg_size; i *= 2) {
|
||||||
|
result |= (result << i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Logical immediates can't encode zero, so a return value of zero is used to
|
||||||
|
// indicate a failure case. Specifically, where the constraints on imm_s are
|
||||||
|
// not met.
|
||||||
|
uint64_t Instruction::ImmLogical() {
|
||||||
|
unsigned reg_size = SixtyFourBits() ? kXRegSize : kWRegSize;
|
||||||
|
int64_t n = BitN();
|
||||||
|
int64_t imm_s = ImmSetBits();
|
||||||
|
int64_t imm_r = ImmRotate();
|
||||||
|
|
||||||
|
// An integer is constructed from the n, imm_s and imm_r bits according to
|
||||||
|
// the following table:
|
||||||
|
//
|
||||||
|
// N imms immr size S R
|
||||||
|
// 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
|
||||||
|
// 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
|
||||||
|
// 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
|
||||||
|
// 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
|
||||||
|
// 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
|
||||||
|
// 0 11110s xxxxxr 2 UInt(s) UInt(r)
|
||||||
|
// (s bits must not be all set)
|
||||||
|
//
|
||||||
|
// A pattern is constructed of size bits, where the least significant S+1
|
||||||
|
// bits are set. The pattern is rotated right by R, and repeated across a
|
||||||
|
// 32 or 64-bit value, depending on destination register width.
|
||||||
|
//
|
||||||
|
|
||||||
|
if (n == 1) {
|
||||||
|
if (imm_s == 0x3F) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint64_t bits = (1UL << (imm_s + 1)) - 1;
|
||||||
|
return RotateRight(bits, imm_r, 64);
|
||||||
|
} else {
|
||||||
|
if ((imm_s >> 1) == 0x1F) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (int width = 0x20; width >= 0x2; width >>= 1) {
|
||||||
|
if ((imm_s & width) == 0) {
|
||||||
|
int mask = width - 1;
|
||||||
|
if ((imm_s & mask) == mask) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1;
|
||||||
|
return RepeatBitsAcrossReg(reg_size,
|
||||||
|
RotateRight(bits, imm_r & mask, width),
|
||||||
|
width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float Instruction::ImmFP32() {
|
||||||
|
// ImmFP: abcdefgh (8 bits)
|
||||||
|
// Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits)
|
||||||
|
// where B is b ^ 1
|
||||||
|
uint32_t bits = ImmFP();
|
||||||
|
uint32_t bit7 = (bits >> 7) & 0x1;
|
||||||
|
uint32_t bit6 = (bits >> 6) & 0x1;
|
||||||
|
uint32_t bit5_to_0 = bits & 0x3f;
|
||||||
|
uint32_t result = (bit7 << 31) | ((32 - bit6) << 25) | (bit5_to_0 << 19);
|
||||||
|
|
||||||
|
return rawbits_to_float(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double Instruction::ImmFP64() {
|
||||||
|
// ImmFP: abcdefgh (8 bits)
|
||||||
|
// Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
|
||||||
|
// 0000.0000.0000.0000.0000.0000.0000.0000 (64 bits)
|
||||||
|
// where B is b ^ 1
|
||||||
|
uint32_t bits = ImmFP();
|
||||||
|
uint64_t bit7 = (bits >> 7) & 0x1;
|
||||||
|
uint64_t bit6 = (bits >> 6) & 0x1;
|
||||||
|
uint64_t bit5_to_0 = bits & 0x3f;
|
||||||
|
uint64_t result = (bit7 << 63) | ((256 - bit6) << 54) | (bit5_to_0 << 48);
|
||||||
|
|
||||||
|
return rawbits_to_double(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LSDataSize CalcLSPairDataSize(LoadStorePairOp op) {
|
||||||
|
switch (op) {
|
||||||
|
case STP_x:
|
||||||
|
case LDP_x:
|
||||||
|
case STP_d:
|
||||||
|
case LDP_d: return LSDoubleWord;
|
||||||
|
default: return LSWord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Instruction* Instruction::ImmPCOffsetTarget() {
|
||||||
|
ptrdiff_t offset;
|
||||||
|
if (IsPCRelAddressing()) {
|
||||||
|
// PC-relative addressing. Only ADR is supported.
|
||||||
|
offset = ImmPCRel();
|
||||||
|
} else {
|
||||||
|
// All PC-relative branches.
|
||||||
|
ASSERT(BranchType() != UnknownBranchType);
|
||||||
|
// Relative branch offsets are instruction-size-aligned.
|
||||||
|
offset = ImmBranch() << kInstructionSizeLog2;
|
||||||
|
}
|
||||||
|
return this + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int Instruction::ImmBranch() const {
|
||||||
|
switch (BranchType()) {
|
||||||
|
case CondBranchType: return ImmCondBranch();
|
||||||
|
case UncondBranchType: return ImmUncondBranch();
|
||||||
|
case CompareBranchType: return ImmCmpBranch();
|
||||||
|
case TestBranchType: return ImmTestBranch();
|
||||||
|
default: UNREACHABLE();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Instruction::SetImmPCOffsetTarget(Instruction* target) {
|
||||||
|
if (IsPCRelAddressing()) {
|
||||||
|
SetPCRelImmTarget(target);
|
||||||
|
} else {
|
||||||
|
SetBranchImmTarget(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Instruction::SetPCRelImmTarget(Instruction* target) {
|
||||||
|
// ADRP is not supported, so 'this' must point to an ADR instruction.
|
||||||
|
ASSERT(Mask(PCRelAddressingMask) == ADR);
|
||||||
|
|
||||||
|
Instr imm = Assembler::ImmPCRelAddress(target - this);
|
||||||
|
|
||||||
|
SetInstructionBits(Mask(~ImmPCRel_mask) | imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Instruction::SetBranchImmTarget(Instruction* target) {
|
||||||
|
ASSERT(((target - this) & 3) == 0);
|
||||||
|
Instr branch_imm = 0;
|
||||||
|
uint32_t imm_mask = 0;
|
||||||
|
int offset = (target - this) >> kInstructionSizeLog2;
|
||||||
|
switch (BranchType()) {
|
||||||
|
case CondBranchType: {
|
||||||
|
branch_imm = Assembler::ImmCondBranch(offset);
|
||||||
|
imm_mask = ImmCondBranch_mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UncondBranchType: {
|
||||||
|
branch_imm = Assembler::ImmUncondBranch(offset);
|
||||||
|
imm_mask = ImmUncondBranch_mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CompareBranchType: {
|
||||||
|
branch_imm = Assembler::ImmCmpBranch(offset);
|
||||||
|
imm_mask = ImmCmpBranch_mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TestBranchType: {
|
||||||
|
branch_imm = Assembler::ImmTestBranch(offset);
|
||||||
|
imm_mask = ImmTestBranch_mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: UNREACHABLE();
|
||||||
|
}
|
||||||
|
SetInstructionBits(Mask(~imm_mask) | branch_imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Instruction::SetImmLLiteral(Instruction* source) {
|
||||||
|
ASSERT(((source - this) & 3) == 0);
|
||||||
|
int offset = (source - this) >> kLiteralEntrySizeLog2;
|
||||||
|
Instr imm = Assembler::ImmLLiteral(offset);
|
||||||
|
Instr mask = ImmLLiteral_mask;
|
||||||
|
|
||||||
|
SetInstructionBits(Mask(~mask) | imm);
|
||||||
|
}
|
||||||
|
} // namespace vixl
|
||||||
|
|
||||||
344
disas/libvixl/a64/instructions-a64.h
Normal file
344
disas/libvixl/a64/instructions-a64.h
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef VIXL_A64_INSTRUCTIONS_A64_H_
|
||||||
|
#define VIXL_A64_INSTRUCTIONS_A64_H_
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "a64/constants-a64.h"
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
// ISA constants. --------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef uint32_t Instr;
|
||||||
|
const unsigned kInstructionSize = 4;
|
||||||
|
const unsigned kInstructionSizeLog2 = 2;
|
||||||
|
const unsigned kLiteralEntrySize = 4;
|
||||||
|
const unsigned kLiteralEntrySizeLog2 = 2;
|
||||||
|
const unsigned kMaxLoadLiteralRange = 1 * MBytes;
|
||||||
|
|
||||||
|
const unsigned kWRegSize = 32;
|
||||||
|
const unsigned kWRegSizeLog2 = 5;
|
||||||
|
const unsigned kWRegSizeInBytes = kWRegSize / 8;
|
||||||
|
const unsigned kXRegSize = 64;
|
||||||
|
const unsigned kXRegSizeLog2 = 6;
|
||||||
|
const unsigned kXRegSizeInBytes = kXRegSize / 8;
|
||||||
|
const unsigned kSRegSize = 32;
|
||||||
|
const unsigned kSRegSizeLog2 = 5;
|
||||||
|
const unsigned kSRegSizeInBytes = kSRegSize / 8;
|
||||||
|
const unsigned kDRegSize = 64;
|
||||||
|
const unsigned kDRegSizeLog2 = 6;
|
||||||
|
const unsigned kDRegSizeInBytes = kDRegSize / 8;
|
||||||
|
const int64_t kWRegMask = 0x00000000ffffffffLL;
|
||||||
|
const int64_t kXRegMask = 0xffffffffffffffffLL;
|
||||||
|
const int64_t kSRegMask = 0x00000000ffffffffLL;
|
||||||
|
const int64_t kDRegMask = 0xffffffffffffffffLL;
|
||||||
|
const int64_t kXSignMask = 0x1LL << 63;
|
||||||
|
const int64_t kWSignMask = 0x1LL << 31;
|
||||||
|
const int64_t kByteMask = 0xffL;
|
||||||
|
const int64_t kHalfWordMask = 0xffffL;
|
||||||
|
const int64_t kWordMask = 0xffffffffLL;
|
||||||
|
const uint64_t kXMaxUInt = 0xffffffffffffffffULL;
|
||||||
|
const uint64_t kWMaxUInt = 0xffffffffULL;
|
||||||
|
const int64_t kXMaxInt = 0x7fffffffffffffffLL;
|
||||||
|
const int64_t kXMinInt = 0x8000000000000000LL;
|
||||||
|
const int32_t kWMaxInt = 0x7fffffff;
|
||||||
|
const int32_t kWMinInt = 0x80000000;
|
||||||
|
const unsigned kLinkRegCode = 30;
|
||||||
|
const unsigned kZeroRegCode = 31;
|
||||||
|
const unsigned kSPRegInternalCode = 63;
|
||||||
|
const unsigned kRegCodeMask = 0x1f;
|
||||||
|
|
||||||
|
// AArch64 floating-point specifics. These match IEEE-754.
|
||||||
|
const unsigned kDoubleMantissaBits = 52;
|
||||||
|
const unsigned kDoubleExponentBits = 11;
|
||||||
|
const unsigned kFloatMantissaBits = 23;
|
||||||
|
const unsigned kFloatExponentBits = 8;
|
||||||
|
|
||||||
|
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
|
||||||
|
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
|
||||||
|
const double kFP64PositiveInfinity = rawbits_to_double(0x7ff0000000000000ULL);
|
||||||
|
const double kFP64NegativeInfinity = rawbits_to_double(0xfff0000000000000ULL);
|
||||||
|
|
||||||
|
// This value is a signalling NaN as both a double and as a float (taking the
|
||||||
|
// least-significant word).
|
||||||
|
static const double kFP64SignallingNaN = rawbits_to_double(0x7ff000007f800001ULL);
|
||||||
|
static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
|
||||||
|
|
||||||
|
// A similar value, but as a quiet NaN.
|
||||||
|
static const double kFP64QuietNaN = rawbits_to_double(0x7ff800007fc00001ULL);
|
||||||
|
static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
|
||||||
|
|
||||||
|
enum LSDataSize {
|
||||||
|
LSByte = 0,
|
||||||
|
LSHalfword = 1,
|
||||||
|
LSWord = 2,
|
||||||
|
LSDoubleWord = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
LSDataSize CalcLSPairDataSize(LoadStorePairOp op);
|
||||||
|
|
||||||
|
enum ImmBranchType {
|
||||||
|
UnknownBranchType = 0,
|
||||||
|
CondBranchType = 1,
|
||||||
|
UncondBranchType = 2,
|
||||||
|
CompareBranchType = 3,
|
||||||
|
TestBranchType = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AddrMode {
|
||||||
|
Offset,
|
||||||
|
PreIndex,
|
||||||
|
PostIndex
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FPRounding {
|
||||||
|
// The first four values are encodable directly by FPCR<RMode>.
|
||||||
|
FPTieEven = 0x0,
|
||||||
|
FPPositiveInfinity = 0x1,
|
||||||
|
FPNegativeInfinity = 0x2,
|
||||||
|
FPZero = 0x3,
|
||||||
|
|
||||||
|
// The final rounding mode is only available when explicitly specified by the
|
||||||
|
// instruction (such as with fcvta). It cannot be set in FPCR.
|
||||||
|
FPTieAway
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Reg31Mode {
|
||||||
|
Reg31IsStackPointer,
|
||||||
|
Reg31IsZeroRegister
|
||||||
|
};
|
||||||
|
|
||||||
|
// Instructions. ---------------------------------------------------------------
|
||||||
|
|
||||||
|
class Instruction {
|
||||||
|
public:
|
||||||
|
inline Instr InstructionBits() const {
|
||||||
|
return *(reinterpret_cast<const Instr*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetInstructionBits(Instr new_instr) {
|
||||||
|
*(reinterpret_cast<Instr*>(this)) = new_instr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Bit(int pos) const {
|
||||||
|
return (InstructionBits() >> pos) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t Bits(int msb, int lsb) const {
|
||||||
|
return unsigned_bitextract_32(msb, lsb, InstructionBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int32_t SignedBits(int msb, int lsb) const {
|
||||||
|
int32_t bits = *(reinterpret_cast<const int32_t*>(this));
|
||||||
|
return signed_bitextract_32(msb, lsb, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Instr Mask(uint32_t mask) const {
|
||||||
|
return InstructionBits() & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
|
||||||
|
inline int64_t Name() const { return Func(HighBit, LowBit); }
|
||||||
|
INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
|
||||||
|
#undef DEFINE_GETTER
|
||||||
|
|
||||||
|
// ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
|
||||||
|
// formed from ImmPCRelLo and ImmPCRelHi.
|
||||||
|
int ImmPCRel() const {
|
||||||
|
int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
|
||||||
|
int const width = ImmPCRelLo_width + ImmPCRelHi_width;
|
||||||
|
return signed_bitextract_32(width-1, 0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ImmLogical();
|
||||||
|
float ImmFP32();
|
||||||
|
double ImmFP64();
|
||||||
|
|
||||||
|
inline LSDataSize SizeLSPair() const {
|
||||||
|
return CalcLSPairDataSize(
|
||||||
|
static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers.
|
||||||
|
inline bool IsCondBranchImm() const {
|
||||||
|
return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsUncondBranchImm() const {
|
||||||
|
return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsCompareBranch() const {
|
||||||
|
return Mask(CompareBranchFMask) == CompareBranchFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsTestBranch() const {
|
||||||
|
return Mask(TestBranchFMask) == TestBranchFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsPCRelAddressing() const {
|
||||||
|
return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsLogicalImmediate() const {
|
||||||
|
return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsAddSubImmediate() const {
|
||||||
|
return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsAddSubExtended() const {
|
||||||
|
return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsLoadOrStore() const {
|
||||||
|
return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsMovn() const {
|
||||||
|
return (Mask(MoveWideImmediateMask) == MOVN_x) ||
|
||||||
|
(Mask(MoveWideImmediateMask) == MOVN_w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicate whether Rd can be the stack pointer or the zero register. This
|
||||||
|
// does not check that the instruction actually has an Rd field.
|
||||||
|
inline Reg31Mode RdMode() const {
|
||||||
|
// The following instructions use sp or wsp as Rd:
|
||||||
|
// Add/sub (immediate) when not setting the flags.
|
||||||
|
// Add/sub (extended) when not setting the flags.
|
||||||
|
// Logical (immediate) when not setting the flags.
|
||||||
|
// Otherwise, r31 is the zero register.
|
||||||
|
if (IsAddSubImmediate() || IsAddSubExtended()) {
|
||||||
|
if (Mask(AddSubSetFlagsBit)) {
|
||||||
|
return Reg31IsZeroRegister;
|
||||||
|
} else {
|
||||||
|
return Reg31IsStackPointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (IsLogicalImmediate()) {
|
||||||
|
// Of the logical (immediate) instructions, only ANDS (and its aliases)
|
||||||
|
// can set the flags. The others can all write into sp.
|
||||||
|
// Note that some logical operations are not available to
|
||||||
|
// immediate-operand instructions, so we have to combine two masks here.
|
||||||
|
if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
|
||||||
|
return Reg31IsZeroRegister;
|
||||||
|
} else {
|
||||||
|
return Reg31IsStackPointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Reg31IsZeroRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicate whether Rn can be the stack pointer or the zero register. This
|
||||||
|
// does not check that the instruction actually has an Rn field.
|
||||||
|
inline Reg31Mode RnMode() const {
|
||||||
|
// The following instructions use sp or wsp as Rn:
|
||||||
|
// All loads and stores.
|
||||||
|
// Add/sub (immediate).
|
||||||
|
// Add/sub (extended).
|
||||||
|
// Otherwise, r31 is the zero register.
|
||||||
|
if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
|
||||||
|
return Reg31IsStackPointer;
|
||||||
|
}
|
||||||
|
return Reg31IsZeroRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ImmBranchType BranchType() const {
|
||||||
|
if (IsCondBranchImm()) {
|
||||||
|
return CondBranchType;
|
||||||
|
} else if (IsUncondBranchImm()) {
|
||||||
|
return UncondBranchType;
|
||||||
|
} else if (IsCompareBranch()) {
|
||||||
|
return CompareBranchType;
|
||||||
|
} else if (IsTestBranch()) {
|
||||||
|
return TestBranchType;
|
||||||
|
} else {
|
||||||
|
return UnknownBranchType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the target of this instruction. 'this' may be a branch or a
|
||||||
|
// PC-relative addressing instruction.
|
||||||
|
Instruction* ImmPCOffsetTarget();
|
||||||
|
|
||||||
|
// Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
|
||||||
|
// a PC-relative addressing instruction.
|
||||||
|
void SetImmPCOffsetTarget(Instruction* target);
|
||||||
|
// Patch a literal load instruction to load from 'source'.
|
||||||
|
void SetImmLLiteral(Instruction* source);
|
||||||
|
|
||||||
|
inline uint8_t* LiteralAddress() {
|
||||||
|
int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
|
||||||
|
return reinterpret_cast<uint8_t*>(this) + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t Literal32() {
|
||||||
|
uint32_t literal;
|
||||||
|
memcpy(&literal, LiteralAddress(), sizeof(literal));
|
||||||
|
|
||||||
|
return literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t Literal64() {
|
||||||
|
uint64_t literal;
|
||||||
|
memcpy(&literal, LiteralAddress(), sizeof(literal));
|
||||||
|
|
||||||
|
return literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float LiteralFP32() {
|
||||||
|
return rawbits_to_float(Literal32());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double LiteralFP64() {
|
||||||
|
return rawbits_to_double(Literal64());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Instruction* NextInstruction() {
|
||||||
|
return this + kInstructionSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Instruction* InstructionAtOffset(int64_t offset) {
|
||||||
|
ASSERT(IsWordAligned(this + offset));
|
||||||
|
return this + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> static inline Instruction* Cast(T src) {
|
||||||
|
return reinterpret_cast<Instruction*>(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline int ImmBranch() const;
|
||||||
|
|
||||||
|
void SetPCRelImmTarget(Instruction* target);
|
||||||
|
void SetBranchImmTarget(Instruction* target);
|
||||||
|
};
|
||||||
|
} // namespace vixl
|
||||||
|
|
||||||
|
#endif // VIXL_A64_INSTRUCTIONS_A64_H_
|
||||||
65
disas/libvixl/globals.h
Normal file
65
disas/libvixl/globals.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef VIXL_GLOBALS_H
|
||||||
|
#define VIXL_GLOBALS_H
|
||||||
|
|
||||||
|
// Get the standard printf format macros for C99 stdint types.
|
||||||
|
#define __STDC_FORMAT_MACROS
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
|
|
||||||
|
const int KBytes = 1024;
|
||||||
|
const int MBytes = 1024 * KBytes;
|
||||||
|
|
||||||
|
#define ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define ASSERT(condition) assert(condition)
|
||||||
|
#define CHECK(condition) ASSERT(condition)
|
||||||
|
#define UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); ABORT()
|
||||||
|
#define UNREACHABLE() printf("UNREACHABLE\t"); ABORT()
|
||||||
|
#else
|
||||||
|
#define ASSERT(condition) ((void) 0)
|
||||||
|
#define CHECK(condition) assert(condition)
|
||||||
|
#define UNIMPLEMENTED() ((void) 0)
|
||||||
|
#define UNREACHABLE() ((void) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T> inline void USE(T) {}
|
||||||
|
|
||||||
|
#define ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); ABORT()
|
||||||
|
|
||||||
|
#endif // VIXL_GLOBALS_H
|
||||||
43
disas/libvixl/platform.h
Normal file
43
disas/libvixl/platform.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef PLATFORM_H
|
||||||
|
#define PLATFORM_H
|
||||||
|
|
||||||
|
// Define platform specific functionalities.
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
#ifdef USE_SIMULATOR
|
||||||
|
// Currently we assume running the simulator implies running on x86 hardware.
|
||||||
|
inline void HostBreakpoint() { asm("int3"); }
|
||||||
|
#else
|
||||||
|
inline void HostBreakpoint() {
|
||||||
|
// TODO: Implement HostBreakpoint on a64.
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace vixl
|
||||||
|
|
||||||
|
#endif
|
||||||
126
disas/libvixl/utils.cc
Normal file
126
disas/libvixl/utils.cc
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
|
||||||
|
uint32_t float_to_rawbits(float value) {
|
||||||
|
uint32_t bits = 0;
|
||||||
|
memcpy(&bits, &value, 4);
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t double_to_rawbits(double value) {
|
||||||
|
uint64_t bits = 0;
|
||||||
|
memcpy(&bits, &value, 8);
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float rawbits_to_float(uint32_t bits) {
|
||||||
|
float value = 0.0;
|
||||||
|
memcpy(&value, &bits, 4);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double rawbits_to_double(uint64_t bits) {
|
||||||
|
double value = 0.0;
|
||||||
|
memcpy(&value, &bits, 8);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CountLeadingZeros(uint64_t value, int width) {
|
||||||
|
ASSERT((width == 32) || (width == 64));
|
||||||
|
int count = 0;
|
||||||
|
uint64_t bit_test = 1UL << (width - 1);
|
||||||
|
while ((count < width) && ((bit_test & value) == 0)) {
|
||||||
|
count++;
|
||||||
|
bit_test >>= 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CountLeadingSignBits(int64_t value, int width) {
|
||||||
|
ASSERT((width == 32) || (width == 64));
|
||||||
|
if (value >= 0) {
|
||||||
|
return CountLeadingZeros(value, width) - 1;
|
||||||
|
} else {
|
||||||
|
return CountLeadingZeros(~value, width) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CountTrailingZeros(uint64_t value, int width) {
|
||||||
|
ASSERT((width == 32) || (width == 64));
|
||||||
|
int count = 0;
|
||||||
|
while ((count < width) && (((value >> count) & 1) == 0)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CountSetBits(uint64_t value, int width) {
|
||||||
|
// TODO: Other widths could be added here, as the implementation already
|
||||||
|
// supports them.
|
||||||
|
ASSERT((width == 32) || (width == 64));
|
||||||
|
|
||||||
|
// Mask out unused bits to ensure that they are not counted.
|
||||||
|
value &= (0xffffffffffffffffULL >> (64-width));
|
||||||
|
|
||||||
|
// Add up the set bits.
|
||||||
|
// The algorithm works by adding pairs of bit fields together iteratively,
|
||||||
|
// where the size of each bit field doubles each time.
|
||||||
|
// An example for an 8-bit value:
|
||||||
|
// Bits: h g f e d c b a
|
||||||
|
// \ | \ | \ | \ |
|
||||||
|
// value = h+g f+e d+c b+a
|
||||||
|
// \ | \ |
|
||||||
|
// value = h+g+f+e d+c+b+a
|
||||||
|
// \ |
|
||||||
|
// value = h+g+f+e+d+c+b+a
|
||||||
|
value = ((value >> 1) & 0x5555555555555555ULL) +
|
||||||
|
(value & 0x5555555555555555ULL);
|
||||||
|
value = ((value >> 2) & 0x3333333333333333ULL) +
|
||||||
|
(value & 0x3333333333333333ULL);
|
||||||
|
value = ((value >> 4) & 0x0f0f0f0f0f0f0f0fULL) +
|
||||||
|
(value & 0x0f0f0f0f0f0f0f0fULL);
|
||||||
|
value = ((value >> 8) & 0x00ff00ff00ff00ffULL) +
|
||||||
|
(value & 0x00ff00ff00ff00ffULL);
|
||||||
|
value = ((value >> 16) & 0x0000ffff0000ffffULL) +
|
||||||
|
(value & 0x0000ffff0000ffffULL);
|
||||||
|
value = ((value >> 32) & 0x00000000ffffffffULL) +
|
||||||
|
(value & 0x00000000ffffffffULL);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
} // namespace vixl
|
||||||
126
disas/libvixl/utils.h
Normal file
126
disas/libvixl/utils.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// Copyright 2013, ARM Limited
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of ARM Limited nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without
|
||||||
|
// specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef VIXL_UTILS_H
|
||||||
|
#define VIXL_UTILS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
namespace vixl {
|
||||||
|
|
||||||
|
// Check number width.
|
||||||
|
inline bool is_intn(unsigned n, int64_t x) {
|
||||||
|
ASSERT((0 < n) && (n < 64));
|
||||||
|
int64_t limit = 1ULL << (n - 1);
|
||||||
|
return (-limit <= x) && (x < limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_uintn(unsigned n, int64_t x) {
|
||||||
|
ASSERT((0 < n) && (n < 64));
|
||||||
|
return !(x >> n);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned truncate_to_intn(unsigned n, int64_t x) {
|
||||||
|
ASSERT((0 < n) && (n < 64));
|
||||||
|
return (x & ((1ULL << n) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INT_1_TO_63_LIST(V) \
|
||||||
|
V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) \
|
||||||
|
V(9) V(10) V(11) V(12) V(13) V(14) V(15) V(16) \
|
||||||
|
V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24) \
|
||||||
|
V(25) V(26) V(27) V(28) V(29) V(30) V(31) V(32) \
|
||||||
|
V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \
|
||||||
|
V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) \
|
||||||
|
V(49) V(50) V(51) V(52) V(53) V(54) V(55) V(56) \
|
||||||
|
V(57) V(58) V(59) V(60) V(61) V(62) V(63)
|
||||||
|
|
||||||
|
#define DECLARE_IS_INT_N(N) \
|
||||||
|
inline bool is_int##N(int64_t x) { return is_intn(N, x); }
|
||||||
|
#define DECLARE_IS_UINT_N(N) \
|
||||||
|
inline bool is_uint##N(int64_t x) { return is_uintn(N, x); }
|
||||||
|
#define DECLARE_TRUNCATE_TO_INT_N(N) \
|
||||||
|
inline int truncate_to_int##N(int x) { return truncate_to_intn(N, x); }
|
||||||
|
INT_1_TO_63_LIST(DECLARE_IS_INT_N)
|
||||||
|
INT_1_TO_63_LIST(DECLARE_IS_UINT_N)
|
||||||
|
INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N)
|
||||||
|
#undef DECLARE_IS_INT_N
|
||||||
|
#undef DECLARE_IS_UINT_N
|
||||||
|
#undef DECLARE_TRUNCATE_TO_INT_N
|
||||||
|
|
||||||
|
// Bit field extraction.
|
||||||
|
inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) {
|
||||||
|
return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) {
|
||||||
|
return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int32_t signed_bitextract_32(int msb, int lsb, int32_t x) {
|
||||||
|
return (x << (31 - msb)) >> (lsb + 31 - msb);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int64_t signed_bitextract_64(int msb, int lsb, int64_t x) {
|
||||||
|
return (x << (63 - msb)) >> (lsb + 63 - msb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// floating point representation
|
||||||
|
uint32_t float_to_rawbits(float value);
|
||||||
|
uint64_t double_to_rawbits(double value);
|
||||||
|
float rawbits_to_float(uint32_t bits);
|
||||||
|
double rawbits_to_double(uint64_t bits);
|
||||||
|
|
||||||
|
// Bits counting.
|
||||||
|
int CountLeadingZeros(uint64_t value, int width);
|
||||||
|
int CountLeadingSignBits(int64_t value, int width);
|
||||||
|
int CountTrailingZeros(uint64_t value, int width);
|
||||||
|
int CountSetBits(uint64_t value, int width);
|
||||||
|
|
||||||
|
// Pointer alignment
|
||||||
|
// TODO: rename/refactor to make it specific to instructions.
|
||||||
|
template<typename T>
|
||||||
|
bool IsWordAligned(T pointer) {
|
||||||
|
ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
|
||||||
|
return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment a pointer until it has the specified alignment.
|
||||||
|
template<class T>
|
||||||
|
T AlignUp(T pointer, size_t alignment) {
|
||||||
|
ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||||
|
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
|
||||||
|
size_t align_step = (alignment - pointer_raw) % alignment;
|
||||||
|
ASSERT((pointer_raw + align_step) % alignment == 0);
|
||||||
|
return reinterpret_cast<T>(pointer_raw + align_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace vixl
|
||||||
|
|
||||||
|
#endif // VIXL_UTILS_H
|
||||||
@@ -479,7 +479,7 @@ Data: None.
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
{ "event": "WATCHDOG",
|
{ "event": "WAKEUP",
|
||||||
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
||||||
|
|
||||||
WATCHDOG
|
WATCHDOG
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
|
|||||||
Generic ACPI GPE block. Bit 2 (GPE.2) used to notify CPU
|
Generic ACPI GPE block. Bit 2 (GPE.2) used to notify CPU
|
||||||
hot-add/remove event to ACPI BIOS, via SCI interrupt.
|
hot-add/remove event to ACPI BIOS, via SCI interrupt.
|
||||||
|
|
||||||
CPU present bitmap (IO port 0xaf00-0xaf1f, 1-byte access):
|
CPU present bitmap for:
|
||||||
|
ICH9-LPC (IO port 0x0cd8-0xcf7, 1-byte access)
|
||||||
|
PIIX-PM (IO port 0xaf00-0xaf1f, 1-byte access)
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
One bit per CPU. Bit position reflects corresponding CPU APIC ID.
|
One bit per CPU. Bit position reflects corresponding CPU APIC ID.
|
||||||
Read-only.
|
Read-only.
|
||||||
|
|||||||
@@ -214,6 +214,42 @@ The "ust" backend uses the LTTng Userspace Tracer library. There are no
|
|||||||
monitor commands built into QEMU, instead UST utilities should be used to list,
|
monitor commands built into QEMU, instead UST utilities should be used to list,
|
||||||
enable/disable, and dump traces.
|
enable/disable, and dump traces.
|
||||||
|
|
||||||
|
Package lttng-tools is required for userspace tracing. You must ensure that the
|
||||||
|
current user belongs to the "tracing" group, or manually launch the
|
||||||
|
lttng-sessiond daemon for the current user prior to running any instance of
|
||||||
|
QEMU.
|
||||||
|
|
||||||
|
While running an instrumented QEMU, LTTng should be able to list all available
|
||||||
|
events:
|
||||||
|
|
||||||
|
lttng list -u
|
||||||
|
|
||||||
|
Create tracing session:
|
||||||
|
|
||||||
|
lttng create mysession
|
||||||
|
|
||||||
|
Enable events:
|
||||||
|
|
||||||
|
lttng enable-event qemu:g_malloc -u
|
||||||
|
|
||||||
|
Where the events can either be a comma-separated list of events, or "-a" to
|
||||||
|
enable all tracepoint events. Start and stop tracing as needed:
|
||||||
|
|
||||||
|
lttng start
|
||||||
|
lttng stop
|
||||||
|
|
||||||
|
View the trace:
|
||||||
|
|
||||||
|
lttng view
|
||||||
|
|
||||||
|
Destroy tracing session:
|
||||||
|
|
||||||
|
lttng destroy
|
||||||
|
|
||||||
|
Babeltrace can be used at any later time to view the trace:
|
||||||
|
|
||||||
|
babeltrace $HOME/lttng-traces/mysession-<date>-<time>
|
||||||
|
|
||||||
=== SystemTap ===
|
=== SystemTap ===
|
||||||
|
|
||||||
The "dtrace" backend uses DTrace sdt probes but has only been tested with
|
The "dtrace" backend uses DTrace sdt probes but has only been tested with
|
||||||
|
|||||||
214
exec.c
214
exec.c
@@ -138,6 +138,7 @@ typedef struct subpage_t {
|
|||||||
|
|
||||||
static void io_mem_init(void);
|
static void io_mem_init(void);
|
||||||
static void memory_map_init(void);
|
static void memory_map_init(void);
|
||||||
|
static void tcg_commit(MemoryListener *listener);
|
||||||
|
|
||||||
static MemoryRegion io_mem_watch;
|
static MemoryRegion io_mem_watch;
|
||||||
#endif
|
#endif
|
||||||
@@ -339,6 +340,18 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
|||||||
return section;
|
return section;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||||
|
{
|
||||||
|
if (memory_region_is_ram(mr)) {
|
||||||
|
return !(is_write && mr->readonly);
|
||||||
|
}
|
||||||
|
if (memory_region_is_romd(mr)) {
|
||||||
|
return !is_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||||
hwaddr *xlat, hwaddr *plen,
|
hwaddr *xlat, hwaddr *plen,
|
||||||
bool is_write)
|
bool is_write)
|
||||||
@@ -368,6 +381,11 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
|||||||
as = iotlb.target_as;
|
as = iotlb.target_as;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (memory_access_is_direct(mr, is_write)) {
|
||||||
|
hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
|
||||||
|
len = MIN(page, len);
|
||||||
|
}
|
||||||
|
|
||||||
*plen = len;
|
*plen = len;
|
||||||
*xlat = addr;
|
*xlat = addr;
|
||||||
return mr;
|
return mr;
|
||||||
@@ -436,6 +454,22 @@ CPUState *qemu_get_cpu(int index)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as)
|
||||||
|
{
|
||||||
|
/* We only support one address space per cpu at the moment. */
|
||||||
|
assert(cpu->as == as);
|
||||||
|
|
||||||
|
if (cpu->tcg_as_listener) {
|
||||||
|
memory_listener_unregister(cpu->tcg_as_listener);
|
||||||
|
} else {
|
||||||
|
cpu->tcg_as_listener = g_new0(MemoryListener, 1);
|
||||||
|
}
|
||||||
|
cpu->tcg_as_listener->commit = tcg_commit;
|
||||||
|
memory_listener_register(cpu->tcg_as_listener, as);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void cpu_exec_init(CPUArchState *env)
|
void cpu_exec_init(CPUArchState *env)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
CPUState *cpu = ENV_GET_CPU(env);
|
||||||
@@ -455,6 +489,7 @@ void cpu_exec_init(CPUArchState *env)
|
|||||||
QTAILQ_INIT(&env->breakpoints);
|
QTAILQ_INIT(&env->breakpoints);
|
||||||
QTAILQ_INIT(&env->watchpoints);
|
QTAILQ_INIT(&env->watchpoints);
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
cpu->as = &address_space_memory;
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
#endif
|
#endif
|
||||||
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
|
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
|
||||||
@@ -486,7 +521,8 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
|||||||
{
|
{
|
||||||
hwaddr phys = cpu_get_phys_page_debug(cpu, pc);
|
hwaddr phys = cpu_get_phys_page_debug(cpu, pc);
|
||||||
if (phys != -1) {
|
if (phys != -1) {
|
||||||
tb_invalidate_phys_addr(phys | (pc & ~TARGET_PAGE_MASK));
|
tb_invalidate_phys_addr(cpu->as,
|
||||||
|
phys | (pc & ~TARGET_PAGE_MASK));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -778,7 +814,7 @@ hwaddr memory_region_section_get_iotlb(CPUArchState *env,
|
|||||||
iotlb |= PHYS_SECTION_ROM;
|
iotlb |= PHYS_SECTION_ROM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
iotlb = section - address_space_memory.dispatch->map.sections;
|
iotlb = section - section->address_space->dispatch->map.sections;
|
||||||
iotlb += xlat;
|
iotlb += xlat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,6 +910,7 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti
|
|||||||
|
|
||||||
if (!(existing->mr->subpage)) {
|
if (!(existing->mr->subpage)) {
|
||||||
subpage = subpage_init(d->as, base);
|
subpage = subpage_init(d->as, base);
|
||||||
|
subsection.address_space = d->as;
|
||||||
subsection.mr = &subpage->iomem;
|
subsection.mr = &subpage->iomem;
|
||||||
phys_page_set(d, base >> TARGET_PAGE_BITS, 1,
|
phys_page_set(d, base >> TARGET_PAGE_BITS, 1,
|
||||||
phys_section_add(&d->map, &subsection));
|
phys_section_add(&d->map, &subsection));
|
||||||
@@ -1070,7 +1107,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* MAP_POPULATE silently ignores failures */
|
/* MAP_POPULATE silently ignores failures */
|
||||||
for (i = 0; i < (memory/hpagesize)-1; i++) {
|
for (i = 0; i < (memory/hpagesize); i++) {
|
||||||
memset(area + (hpagesize*i), 0, 1);
|
memset(area + (hpagesize*i), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1575,9 +1612,9 @@ static uint64_t watch_mem_read(void *opaque, hwaddr addr,
|
|||||||
{
|
{
|
||||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_READ);
|
check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_READ);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1: return ldub_phys(addr);
|
case 1: return ldub_phys(&address_space_memory, addr);
|
||||||
case 2: return lduw_phys(addr);
|
case 2: return lduw_phys(&address_space_memory, addr);
|
||||||
case 4: return ldl_phys(addr);
|
case 4: return ldl_phys(&address_space_memory, addr);
|
||||||
default: abort();
|
default: abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1588,13 +1625,13 @@ static void watch_mem_write(void *opaque, hwaddr addr,
|
|||||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_WRITE);
|
check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_WRITE);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
stb_phys(addr, val);
|
stb_phys(&address_space_memory, addr, val);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
stw_phys(addr, val);
|
stw_phys(&address_space_memory, addr, val);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
stl_phys(addr, val);
|
stl_phys(&address_space_memory, addr, val);
|
||||||
break;
|
break;
|
||||||
default: abort();
|
default: abort();
|
||||||
}
|
}
|
||||||
@@ -1719,6 +1756,7 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base)
|
|||||||
static uint16_t dummy_section(PhysPageMap *map, MemoryRegion *mr)
|
static uint16_t dummy_section(PhysPageMap *map, MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
MemoryRegionSection section = {
|
MemoryRegionSection section = {
|
||||||
|
.address_space = &address_space_memory,
|
||||||
.mr = mr,
|
.mr = mr,
|
||||||
.offset_within_address_space = 0,
|
.offset_within_address_space = 0,
|
||||||
.offset_within_region = 0,
|
.offset_within_region = 0,
|
||||||
@@ -1728,10 +1766,9 @@ static uint16_t dummy_section(PhysPageMap *map, MemoryRegion *mr)
|
|||||||
return phys_section_add(map, §ion);
|
return phys_section_add(map, §ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryRegion *iotlb_to_region(hwaddr index)
|
MemoryRegion *iotlb_to_region(AddressSpace *as, hwaddr index)
|
||||||
{
|
{
|
||||||
return address_space_memory.dispatch->map.sections[
|
return as->dispatch->map.sections[index & ~TARGET_PAGE_MASK].mr;
|
||||||
index & ~TARGET_PAGE_MASK].mr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void io_mem_init(void)
|
static void io_mem_init(void)
|
||||||
@@ -1791,6 +1828,11 @@ static void tcg_commit(MemoryListener *listener)
|
|||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
CPUArchState *env = cpu->env_ptr;
|
CPUArchState *env = cpu->env_ptr;
|
||||||
|
|
||||||
|
/* FIXME: Disentangle the cpu.h circular files deps so we can
|
||||||
|
directly get the right CPU from listener. */
|
||||||
|
if (cpu->tcg_as_listener != listener) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
tlb_flush(env, 1);
|
tlb_flush(env, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1811,10 +1853,6 @@ static MemoryListener core_memory_listener = {
|
|||||||
.priority = 1,
|
.priority = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static MemoryListener tcg_memory_listener = {
|
|
||||||
.commit = tcg_commit,
|
|
||||||
};
|
|
||||||
|
|
||||||
void address_space_init_dispatch(AddressSpace *as)
|
void address_space_init_dispatch(AddressSpace *as)
|
||||||
{
|
{
|
||||||
as->dispatch = NULL;
|
as->dispatch = NULL;
|
||||||
@@ -1850,9 +1888,6 @@ static void memory_map_init(void)
|
|||||||
address_space_init(&address_space_io, system_io, "I/O");
|
address_space_init(&address_space_io, system_io, "I/O");
|
||||||
|
|
||||||
memory_listener_register(&core_memory_listener, &address_space_memory);
|
memory_listener_register(&core_memory_listener, &address_space_memory);
|
||||||
if (tcg_enabled()) {
|
|
||||||
memory_listener_register(&tcg_memory_listener, &address_space_memory);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryRegion *get_system_memory(void)
|
MemoryRegion *get_system_memory(void)
|
||||||
@@ -1923,18 +1958,6 @@ static void invalidate_and_set_dirty(hwaddr addr,
|
|||||||
xen_modified_memory(addr, length);
|
xen_modified_memory(addr, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
|
||||||
{
|
|
||||||
if (memory_region_is_ram(mr)) {
|
|
||||||
return !(is_write && mr->readonly);
|
|
||||||
}
|
|
||||||
if (memory_region_is_romd(mr)) {
|
|
||||||
return !is_write;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
|
static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
|
||||||
{
|
{
|
||||||
unsigned access_size_max = mr->ops->valid.max_access_size;
|
unsigned access_size_max = mr->ops->valid.max_access_size;
|
||||||
@@ -2079,7 +2102,7 @@ enum write_rom_type {
|
|||||||
FLUSH_CACHE,
|
FLUSH_CACHE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void cpu_physical_memory_write_rom_internal(
|
static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
|
||||||
hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
|
hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
|
||||||
{
|
{
|
||||||
hwaddr l;
|
hwaddr l;
|
||||||
@@ -2089,8 +2112,7 @@ static inline void cpu_physical_memory_write_rom_internal(
|
|||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
l = len;
|
l = len;
|
||||||
mr = address_space_translate(&address_space_memory,
|
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||||
addr, &addr1, &l, true);
|
|
||||||
|
|
||||||
if (!(memory_region_is_ram(mr) ||
|
if (!(memory_region_is_ram(mr) ||
|
||||||
memory_region_is_romd(mr))) {
|
memory_region_is_romd(mr))) {
|
||||||
@@ -2116,10 +2138,10 @@ static inline void cpu_physical_memory_write_rom_internal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* used for ROM loading : can write in RAM and ROM */
|
/* used for ROM loading : can write in RAM and ROM */
|
||||||
void cpu_physical_memory_write_rom(hwaddr addr,
|
void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
|
||||||
const uint8_t *buf, int len)
|
const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
cpu_physical_memory_write_rom_internal(addr, buf, len, WRITE_DATA);
|
cpu_physical_memory_write_rom_internal(as, addr, buf, len, WRITE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_flush_icache_range(hwaddr start, int len)
|
void cpu_flush_icache_range(hwaddr start, int len)
|
||||||
@@ -2134,7 +2156,8 @@ void cpu_flush_icache_range(hwaddr start, int len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_physical_memory_write_rom_internal(start, NULL, len, FLUSH_CACHE);
|
cpu_physical_memory_write_rom_internal(&address_space_memory,
|
||||||
|
start, NULL, len, FLUSH_CACHE);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -2325,7 +2348,7 @@ void cpu_physical_memory_unmap(void *buffer, hwaddr len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* warning: addr must be aligned */
|
/* warning: addr must be aligned */
|
||||||
static inline uint32_t ldl_phys_internal(hwaddr addr,
|
static inline uint32_t ldl_phys_internal(AddressSpace *as, hwaddr addr,
|
||||||
enum device_endian endian)
|
enum device_endian endian)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
@@ -2334,8 +2357,7 @@ static inline uint32_t ldl_phys_internal(hwaddr addr,
|
|||||||
hwaddr l = 4;
|
hwaddr l = 4;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
|
|
||||||
mr = address_space_translate(&address_space_memory, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||||
false);
|
|
||||||
if (l < 4 || !memory_access_is_direct(mr, false)) {
|
if (l < 4 || !memory_access_is_direct(mr, false)) {
|
||||||
/* I/O case */
|
/* I/O case */
|
||||||
io_mem_read(mr, addr1, &val, 4);
|
io_mem_read(mr, addr1, &val, 4);
|
||||||
@@ -2368,23 +2390,23 @@ static inline uint32_t ldl_phys_internal(hwaddr addr,
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ldl_phys(hwaddr addr)
|
uint32_t ldl_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
return ldl_phys_internal(as, addr, DEVICE_NATIVE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ldl_le_phys(hwaddr addr)
|
uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
return ldl_phys_internal(as, addr, DEVICE_LITTLE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ldl_be_phys(hwaddr addr)
|
uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
return ldl_phys_internal(as, addr, DEVICE_BIG_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* warning: addr must be aligned */
|
/* warning: addr must be aligned */
|
||||||
static inline uint64_t ldq_phys_internal(hwaddr addr,
|
static inline uint64_t ldq_phys_internal(AddressSpace *as, hwaddr addr,
|
||||||
enum device_endian endian)
|
enum device_endian endian)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
@@ -2393,7 +2415,7 @@ static inline uint64_t ldq_phys_internal(hwaddr addr,
|
|||||||
hwaddr l = 8;
|
hwaddr l = 8;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
|
|
||||||
mr = address_space_translate(&address_space_memory, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
false);
|
false);
|
||||||
if (l < 8 || !memory_access_is_direct(mr, false)) {
|
if (l < 8 || !memory_access_is_direct(mr, false)) {
|
||||||
/* I/O case */
|
/* I/O case */
|
||||||
@@ -2427,31 +2449,31 @@ static inline uint64_t ldq_phys_internal(hwaddr addr,
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ldq_phys(hwaddr addr)
|
uint64_t ldq_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
return ldq_phys_internal(as, addr, DEVICE_NATIVE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ldq_le_phys(hwaddr addr)
|
uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
return ldq_phys_internal(as, addr, DEVICE_LITTLE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ldq_be_phys(hwaddr addr)
|
uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
return ldq_phys_internal(as, addr, DEVICE_BIG_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: optimize */
|
/* XXX: optimize */
|
||||||
uint32_t ldub_phys(hwaddr addr)
|
uint32_t ldub_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
uint8_t val;
|
uint8_t val;
|
||||||
cpu_physical_memory_read(addr, &val, 1);
|
address_space_rw(as, addr, &val, 1, 0);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* warning: addr must be aligned */
|
/* warning: addr must be aligned */
|
||||||
static inline uint32_t lduw_phys_internal(hwaddr addr,
|
static inline uint32_t lduw_phys_internal(AddressSpace *as, hwaddr addr,
|
||||||
enum device_endian endian)
|
enum device_endian endian)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
@@ -2460,7 +2482,7 @@ static inline uint32_t lduw_phys_internal(hwaddr addr,
|
|||||||
hwaddr l = 2;
|
hwaddr l = 2;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
|
|
||||||
mr = address_space_translate(&address_space_memory, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
false);
|
false);
|
||||||
if (l < 2 || !memory_access_is_direct(mr, false)) {
|
if (l < 2 || !memory_access_is_direct(mr, false)) {
|
||||||
/* I/O case */
|
/* I/O case */
|
||||||
@@ -2494,32 +2516,32 @@ static inline uint32_t lduw_phys_internal(hwaddr addr,
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lduw_phys(hwaddr addr)
|
uint32_t lduw_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
return lduw_phys_internal(as, addr, DEVICE_NATIVE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lduw_le_phys(hwaddr addr)
|
uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
return lduw_phys_internal(as, addr, DEVICE_LITTLE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lduw_be_phys(hwaddr addr)
|
uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr)
|
||||||
{
|
{
|
||||||
return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
return lduw_phys_internal(as, addr, DEVICE_BIG_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* warning: addr must be aligned. The ram page is not masked as dirty
|
/* warning: addr must be aligned. The ram page is not masked as dirty
|
||||||
and the code inside is not invalidated. It is useful if the dirty
|
and the code inside is not invalidated. It is useful if the dirty
|
||||||
bits are used to track modified PTEs */
|
bits are used to track modified PTEs */
|
||||||
void stl_phys_notdirty(hwaddr addr, uint32_t val)
|
void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
hwaddr l = 4;
|
hwaddr l = 4;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
|
|
||||||
mr = address_space_translate(&address_space_memory, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
true);
|
true);
|
||||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||||
io_mem_write(mr, addr1, val, 4);
|
io_mem_write(mr, addr1, val, 4);
|
||||||
@@ -2542,7 +2564,8 @@ void stl_phys_notdirty(hwaddr addr, uint32_t val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* warning: addr must be aligned */
|
/* warning: addr must be aligned */
|
||||||
static inline void stl_phys_internal(hwaddr addr, uint32_t val,
|
static inline void stl_phys_internal(AddressSpace *as,
|
||||||
|
hwaddr addr, uint32_t val,
|
||||||
enum device_endian endian)
|
enum device_endian endian)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
@@ -2550,7 +2573,7 @@ static inline void stl_phys_internal(hwaddr addr, uint32_t val,
|
|||||||
hwaddr l = 4;
|
hwaddr l = 4;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
|
|
||||||
mr = address_space_translate(&address_space_memory, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
true);
|
true);
|
||||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
@@ -2582,30 +2605,31 @@ static inline void stl_phys_internal(hwaddr addr, uint32_t val,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stl_phys(hwaddr addr, uint32_t val)
|
void stl_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
{
|
{
|
||||||
stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
|
stl_phys_internal(as, addr, val, DEVICE_NATIVE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stl_le_phys(hwaddr addr, uint32_t val)
|
void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
{
|
{
|
||||||
stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
|
stl_phys_internal(as, addr, val, DEVICE_LITTLE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stl_be_phys(hwaddr addr, uint32_t val)
|
void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
{
|
{
|
||||||
stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
|
stl_phys_internal(as, addr, val, DEVICE_BIG_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: optimize */
|
/* XXX: optimize */
|
||||||
void stb_phys(hwaddr addr, uint32_t val)
|
void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
{
|
{
|
||||||
uint8_t v = val;
|
uint8_t v = val;
|
||||||
cpu_physical_memory_write(addr, &v, 1);
|
address_space_rw(as, addr, &v, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* warning: addr must be aligned */
|
/* warning: addr must be aligned */
|
||||||
static inline void stw_phys_internal(hwaddr addr, uint32_t val,
|
static inline void stw_phys_internal(AddressSpace *as,
|
||||||
|
hwaddr addr, uint32_t val,
|
||||||
enum device_endian endian)
|
enum device_endian endian)
|
||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
@@ -2613,8 +2637,7 @@ static inline void stw_phys_internal(hwaddr addr, uint32_t val,
|
|||||||
hwaddr l = 2;
|
hwaddr l = 2;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
|
|
||||||
mr = address_space_translate(&address_space_memory, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||||
true);
|
|
||||||
if (l < 2 || !memory_access_is_direct(mr, true)) {
|
if (l < 2 || !memory_access_is_direct(mr, true)) {
|
||||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||||
@@ -2645,38 +2668,38 @@ static inline void stw_phys_internal(hwaddr addr, uint32_t val,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stw_phys(hwaddr addr, uint32_t val)
|
void stw_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
{
|
{
|
||||||
stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
|
stw_phys_internal(as, addr, val, DEVICE_NATIVE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stw_le_phys(hwaddr addr, uint32_t val)
|
void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
{
|
{
|
||||||
stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
|
stw_phys_internal(as, addr, val, DEVICE_LITTLE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stw_be_phys(hwaddr addr, uint32_t val)
|
void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
{
|
{
|
||||||
stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
|
stw_phys_internal(as, addr, val, DEVICE_BIG_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: optimize */
|
/* XXX: optimize */
|
||||||
void stq_phys(hwaddr addr, uint64_t val)
|
void stq_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||||
{
|
{
|
||||||
val = tswap64(val);
|
val = tswap64(val);
|
||||||
cpu_physical_memory_write(addr, &val, 8);
|
address_space_rw(as, addr, (void *) &val, 8, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stq_le_phys(hwaddr addr, uint64_t val)
|
void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||||
{
|
{
|
||||||
val = cpu_to_le64(val);
|
val = cpu_to_le64(val);
|
||||||
cpu_physical_memory_write(addr, &val, 8);
|
address_space_rw(as, addr, (void *) &val, 8, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stq_be_phys(hwaddr addr, uint64_t val)
|
void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||||
{
|
{
|
||||||
val = cpu_to_be64(val);
|
val = cpu_to_be64(val);
|
||||||
cpu_physical_memory_write(addr, &val, 8);
|
address_space_rw(as, addr, (void *) &val, 8, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual memory access for debug (includes writing to ROM) */
|
/* virtual memory access for debug (includes writing to ROM) */
|
||||||
@@ -2697,10 +2720,11 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
|||||||
if (l > len)
|
if (l > len)
|
||||||
l = len;
|
l = len;
|
||||||
phys_addr += (addr & ~TARGET_PAGE_MASK);
|
phys_addr += (addr & ~TARGET_PAGE_MASK);
|
||||||
if (is_write)
|
if (is_write) {
|
||||||
cpu_physical_memory_write_rom(phys_addr, buf, l);
|
cpu_physical_memory_write_rom(cpu->as, phys_addr, buf, l);
|
||||||
else
|
} else {
|
||||||
cpu_physical_memory_rw(phys_addr, buf, l, is_write);
|
address_space_rw(cpu->as, phys_addr, buf, l, 0);
|
||||||
|
}
|
||||||
len -= l;
|
len -= l;
|
||||||
buf += l;
|
buf += l;
|
||||||
addr += l;
|
addr += l;
|
||||||
|
|||||||
@@ -2372,6 +2372,17 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Zero plus something non-zero : just return the something */
|
/* Zero plus something non-zero : just return the something */
|
||||||
|
if (flags & float_muladd_halve_result) {
|
||||||
|
if (cExp == 0) {
|
||||||
|
normalizeFloat32Subnormal(cSig, &cExp, &cSig);
|
||||||
|
}
|
||||||
|
/* Subtract one to halve, and one again because roundAndPackFloat32
|
||||||
|
* wants one less than the true exponent.
|
||||||
|
*/
|
||||||
|
cExp -= 2;
|
||||||
|
cSig = (cSig | 0x00800000) << 7;
|
||||||
|
return roundAndPackFloat32(cSign ^ signflip, cExp, cSig STATUS_VAR);
|
||||||
|
}
|
||||||
return packFloat32(cSign ^ signflip, cExp, cSig);
|
return packFloat32(cSign ^ signflip, cExp, cSig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2408,6 +2419,9 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
|
|||||||
/* Throw out the special case of c being an exact zero now */
|
/* Throw out the special case of c being an exact zero now */
|
||||||
shift64RightJamming(pSig64, 32, &pSig64);
|
shift64RightJamming(pSig64, 32, &pSig64);
|
||||||
pSig = pSig64;
|
pSig = pSig64;
|
||||||
|
if (flags & float_muladd_halve_result) {
|
||||||
|
pExp--;
|
||||||
|
}
|
||||||
return roundAndPackFloat32(zSign, pExp - 1,
|
return roundAndPackFloat32(zSign, pExp - 1,
|
||||||
pSig STATUS_VAR);
|
pSig STATUS_VAR);
|
||||||
}
|
}
|
||||||
@@ -2472,6 +2486,10 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
|
|||||||
zSig64 <<= shiftcount;
|
zSig64 <<= shiftcount;
|
||||||
zExp -= shiftcount;
|
zExp -= shiftcount;
|
||||||
}
|
}
|
||||||
|
if (flags & float_muladd_halve_result) {
|
||||||
|
zExp--;
|
||||||
|
}
|
||||||
|
|
||||||
shift64RightJamming(zSig64, 32, &zSig64);
|
shift64RightJamming(zSig64, 32, &zSig64);
|
||||||
return roundAndPackFloat32(zSign, zExp, zSig64 STATUS_VAR);
|
return roundAndPackFloat32(zSign, zExp, zSig64 STATUS_VAR);
|
||||||
}
|
}
|
||||||
@@ -4088,6 +4106,17 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Zero plus something non-zero : just return the something */
|
/* Zero plus something non-zero : just return the something */
|
||||||
|
if (flags & float_muladd_halve_result) {
|
||||||
|
if (cExp == 0) {
|
||||||
|
normalizeFloat64Subnormal(cSig, &cExp, &cSig);
|
||||||
|
}
|
||||||
|
/* Subtract one to halve, and one again because roundAndPackFloat64
|
||||||
|
* wants one less than the true exponent.
|
||||||
|
*/
|
||||||
|
cExp -= 2;
|
||||||
|
cSig = (cSig | 0x0010000000000000ULL) << 10;
|
||||||
|
return roundAndPackFloat64(cSign ^ signflip, cExp, cSig STATUS_VAR);
|
||||||
|
}
|
||||||
return packFloat64(cSign ^ signflip, cExp, cSig);
|
return packFloat64(cSign ^ signflip, cExp, cSig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4123,6 +4152,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
|
|||||||
if (!cSig) {
|
if (!cSig) {
|
||||||
/* Throw out the special case of c being an exact zero now */
|
/* Throw out the special case of c being an exact zero now */
|
||||||
shift128RightJamming(pSig0, pSig1, 64, &pSig0, &pSig1);
|
shift128RightJamming(pSig0, pSig1, 64, &pSig0, &pSig1);
|
||||||
|
if (flags & float_muladd_halve_result) {
|
||||||
|
pExp--;
|
||||||
|
}
|
||||||
return roundAndPackFloat64(zSign, pExp - 1,
|
return roundAndPackFloat64(zSign, pExp - 1,
|
||||||
pSig1 STATUS_VAR);
|
pSig1 STATUS_VAR);
|
||||||
}
|
}
|
||||||
@@ -4159,6 +4191,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
|
|||||||
zExp--;
|
zExp--;
|
||||||
}
|
}
|
||||||
shift128RightJamming(zSig0, zSig1, 64, &zSig0, &zSig1);
|
shift128RightJamming(zSig0, zSig1, 64, &zSig0, &zSig1);
|
||||||
|
if (flags & float_muladd_halve_result) {
|
||||||
|
zExp--;
|
||||||
|
}
|
||||||
return roundAndPackFloat64(zSign, zExp, zSig1 STATUS_VAR);
|
return roundAndPackFloat64(zSign, zExp, zSig1 STATUS_VAR);
|
||||||
} else {
|
} else {
|
||||||
/* Subtraction */
|
/* Subtraction */
|
||||||
@@ -4209,6 +4244,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
|
|||||||
zExp -= (shiftcount + 64);
|
zExp -= (shiftcount + 64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (flags & float_muladd_halve_result) {
|
||||||
|
zExp--;
|
||||||
|
}
|
||||||
return roundAndPackFloat64(zSign, zExp, zSig0 STATUS_VAR);
|
return roundAndPackFloat64(zSign, zExp, zSig0 STATUS_VAR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ STEXI
|
|||||||
@item commit
|
@item commit
|
||||||
@findex commit
|
@findex commit
|
||||||
Commit changes to the disk images (if -snapshot is used) or backing files.
|
Commit changes to the disk images (if -snapshot is used) or backing files.
|
||||||
|
If the backing file is smaller than the snapshot, then the backing file will be
|
||||||
|
resized to be the same size as the snapshot. If the snapshot is smaller than
|
||||||
|
the backing file, the backing file will not be truncated. If you want the
|
||||||
|
backing file to match the size of the smaller snapshot, you can safely truncate
|
||||||
|
it yourself once the commit operation successfully completes.
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
25
hmp.c
25
hmp.c
@@ -871,7 +871,7 @@ void hmp_block_passwd(Monitor *mon, const QDict *qdict)
|
|||||||
const char *password = qdict_get_str(qdict, "password");
|
const char *password = qdict_get_str(qdict, "password");
|
||||||
Error *errp = NULL;
|
Error *errp = NULL;
|
||||||
|
|
||||||
qmp_block_passwd(device, password, &errp);
|
qmp_block_passwd(true, device, false, NULL, password, &errp);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,7 +881,7 @@ void hmp_balloon(Monitor *mon, const QDict *qdict)
|
|||||||
Error *errp = NULL;
|
Error *errp = NULL;
|
||||||
|
|
||||||
qmp_balloon(value, &errp);
|
qmp_balloon(value, &errp);
|
||||||
if (error_is_set(&errp)) {
|
if (errp) {
|
||||||
monitor_printf(mon, "balloon: %s\n", error_get_pretty(errp));
|
monitor_printf(mon, "balloon: %s\n", error_get_pretty(errp));
|
||||||
error_free(errp);
|
error_free(errp);
|
||||||
}
|
}
|
||||||
@@ -893,7 +893,7 @@ void hmp_block_resize(Monitor *mon, const QDict *qdict)
|
|||||||
int64_t size = qdict_get_int(qdict, "size");
|
int64_t size = qdict_get_int(qdict, "size");
|
||||||
Error *errp = NULL;
|
Error *errp = NULL;
|
||||||
|
|
||||||
qmp_block_resize(device, size, &errp);
|
qmp_block_resize(true, device, false, NULL, size, &errp);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -972,7 +972,9 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||||
qmp_blockdev_snapshot_sync(device, filename, !!format, format,
|
qmp_blockdev_snapshot_sync(true, device, false, NULL,
|
||||||
|
filename, false, NULL,
|
||||||
|
!!format, format,
|
||||||
true, mode, &errp);
|
true, mode, &errp);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &errp);
|
||||||
}
|
}
|
||||||
@@ -1092,11 +1094,11 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
|
|||||||
hmp_handle_error(mon, &err);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hmp_change_read_arg(Monitor *mon, const char *password,
|
static void hmp_change_read_arg(void *opaque, const char *password,
|
||||||
void *opaque)
|
void *readline_opaque)
|
||||||
{
|
{
|
||||||
qmp_change_vnc_password(password, NULL);
|
qmp_change_vnc_password(password, NULL);
|
||||||
monitor_read_command(mon, 1);
|
monitor_read_command(opaque, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_change(Monitor *mon, const QDict *qdict)
|
void hmp_change(Monitor *mon, const QDict *qdict)
|
||||||
@@ -1116,7 +1118,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qmp_change(device, target, !!arg, arg, &err);
|
qmp_change(device, target, !!arg, arg, &err);
|
||||||
if (error_is_set(&err) &&
|
if (err &&
|
||||||
error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
|
error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
|
||||||
error_free(err);
|
error_free(err);
|
||||||
monitor_read_block_device_key(mon, device, NULL, NULL);
|
monitor_read_block_device_key(mon, device, NULL, NULL);
|
||||||
@@ -1232,7 +1234,8 @@ static void hmp_migrate_status_cb(void *opaque)
|
|||||||
MigrationInfo *info;
|
MigrationInfo *info;
|
||||||
|
|
||||||
info = qmp_query_migrate(NULL);
|
info = qmp_query_migrate(NULL);
|
||||||
if (!info->has_status || strcmp(info->status, "active") == 0) {
|
if (!info->has_status || strcmp(info->status, "active") == 0 ||
|
||||||
|
strcmp(info->status, "setup") == 0) {
|
||||||
if (info->has_disk) {
|
if (info->has_disk) {
|
||||||
int progress;
|
int progress;
|
||||||
|
|
||||||
@@ -1333,12 +1336,12 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict)
|
|||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
|
|
||||||
opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err);
|
opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err);
|
||||||
if (error_is_set(&err)) {
|
if (err) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
netdev_add(opts, &err);
|
netdev_add(opts, &err);
|
||||||
if (error_is_set(&err)) {
|
if (err) {
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,10 +38,6 @@ int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
|
|||||||
});
|
});
|
||||||
v9fs_path_unlock(s);
|
v9fs_path_unlock(s);
|
||||||
}
|
}
|
||||||
/* The ioctl may not be supported depending on the path */
|
|
||||||
if (err == -ENOTTY) {
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -582,6 +582,7 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
|
|||||||
static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
||||||
mode_t st_mode, uint64_t *st_gen)
|
mode_t st_mode, uint64_t *st_gen)
|
||||||
{
|
{
|
||||||
|
#ifdef FS_IOC_GETVERSION
|
||||||
int err;
|
int err;
|
||||||
V9fsFidOpenState fid_open;
|
V9fsFidOpenState fid_open;
|
||||||
|
|
||||||
@@ -590,7 +591,8 @@ static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
|||||||
* We can get fd for regular files and directories only
|
* We can get fd for regular files and directories only
|
||||||
*/
|
*/
|
||||||
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
|
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
|
||||||
return 0;
|
errno = ENOTTY;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
err = handle_open(ctx, path, O_RDONLY, &fid_open);
|
err = handle_open(ctx, path, O_RDONLY, &fid_open);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
@@ -599,6 +601,10 @@ static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
|||||||
err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
|
err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
|
||||||
handle_close(ctx, &fid_open);
|
handle_close(ctx, &fid_open);
|
||||||
return err;
|
return err;
|
||||||
|
#else
|
||||||
|
errno = ENOTTY;
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_init(FsContext *ctx)
|
static int handle_init(FsContext *ctx)
|
||||||
|
|||||||
@@ -1068,8 +1068,8 @@ err_out:
|
|||||||
static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
||||||
mode_t st_mode, uint64_t *st_gen)
|
mode_t st_mode, uint64_t *st_gen)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
#ifdef FS_IOC_GETVERSION
|
#ifdef FS_IOC_GETVERSION
|
||||||
|
int err;
|
||||||
V9fsFidOpenState fid_open;
|
V9fsFidOpenState fid_open;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1077,7 +1077,8 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
|||||||
* We can get fd for regular files and directories only
|
* We can get fd for regular files and directories only
|
||||||
*/
|
*/
|
||||||
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
|
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
|
||||||
return 0;
|
errno = ENOTTY;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
err = local_open(ctx, path, O_RDONLY, &fid_open);
|
err = local_open(ctx, path, O_RDONLY, &fid_open);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
@@ -1085,10 +1086,11 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
|
|||||||
}
|
}
|
||||||
err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
|
err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
|
||||||
local_close(ctx, &fid_open);
|
local_close(ctx, &fid_open);
|
||||||
#else
|
|
||||||
err = -ENOTTY;
|
|
||||||
#endif
|
|
||||||
return err;
|
return err;
|
||||||
|
#else
|
||||||
|
errno = ENOTTY;
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_init(FsContext *ctx)
|
static int local_init(FsContext *ctx)
|
||||||
|
|||||||
@@ -1086,7 +1086,8 @@ static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
|
|||||||
* we can get fd for regular files and directories only
|
* we can get fd for regular files and directories only
|
||||||
*/
|
*/
|
||||||
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
|
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
|
||||||
return 0;
|
errno = ENOTTY;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
|
err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|||||||
@@ -1080,10 +1080,18 @@ static void v9fs_getattr(void *opaque)
|
|||||||
/* fill st_gen if requested and supported by underlying fs */
|
/* fill st_gen if requested and supported by underlying fs */
|
||||||
if (request_mask & P9_STATS_GEN) {
|
if (request_mask & P9_STATS_GEN) {
|
||||||
retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
|
retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
|
||||||
if (retval < 0) {
|
switch (retval) {
|
||||||
|
case 0:
|
||||||
|
/* we have valid st_gen: update result mask */
|
||||||
|
v9stat_dotl.st_result_mask |= P9_STATS_GEN;
|
||||||
|
break;
|
||||||
|
case -EINTR:
|
||||||
|
/* request cancelled, e.g. by Tflush */
|
||||||
goto out;
|
goto out;
|
||||||
|
default:
|
||||||
|
/* failed to get st_gen: not fatal, ignore */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
v9stat_dotl.st_result_mask |= P9_STATS_GEN;
|
|
||||||
}
|
}
|
||||||
retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
|
retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += i2c/
|
|||||||
devices-dirs-$(CONFIG_SOFTMMU) += ide/
|
devices-dirs-$(CONFIG_SOFTMMU) += ide/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += input/
|
devices-dirs-$(CONFIG_SOFTMMU) += input/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += intc/
|
devices-dirs-$(CONFIG_SOFTMMU) += intc/
|
||||||
|
devices-dirs-$(CONFIG_IPACK) += ipack/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += isa/
|
devices-dirs-$(CONFIG_SOFTMMU) += isa/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += misc/
|
devices-dirs-$(CONFIG_SOFTMMU) += misc/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += net/
|
devices-dirs-$(CONFIG_SOFTMMU) += net/
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
common-obj-$(CONFIG_ACPI) += core.o piix4.o ich9.o
|
common-obj-$(CONFIG_ACPI) += core.o piix4.o ich9.o pcihp.o cpu_hotplug.o
|
||||||
|
|
||||||
|
|||||||
64
hw/acpi/cpu_hotplug.c
Normal file
64
hw/acpi/cpu_hotplug.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* QEMU ACPI hotplug utilities
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Red Hat Inc
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Igor Mammedov <imammedo@redhat.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
#include "hw/hw.h"
|
||||||
|
#include "hw/acpi/cpu_hotplug.h"
|
||||||
|
|
||||||
|
static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
|
{
|
||||||
|
AcpiCpuHotplug *cpus = opaque;
|
||||||
|
uint64_t val = cpus->sts[addr];
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
/* TODO: implement VCPU removal on guest signal that CPU can be removed */
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps AcpiCpuHotplug_ops = {
|
||||||
|
.read = cpu_status_read,
|
||||||
|
.write = cpu_status_write,
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
.valid = {
|
||||||
|
.min_access_size = 1,
|
||||||
|
.max_access_size = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void AcpiCpuHotplug_add(ACPIGPE *gpe, AcpiCpuHotplug *g, CPUState *cpu)
|
||||||
|
{
|
||||||
|
CPUClass *k = CPU_GET_CLASS(cpu);
|
||||||
|
int64_t cpu_id;
|
||||||
|
|
||||||
|
*gpe->sts = *gpe->sts | ACPI_CPU_HOTPLUG_STATUS;
|
||||||
|
cpu_id = k->get_arch_id(CPU(cpu));
|
||||||
|
g->sts[cpu_id / 8] |= (1 << (cpu_id % 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AcpiCpuHotplug_init(MemoryRegion *parent, Object *owner,
|
||||||
|
AcpiCpuHotplug *gpe_cpu, uint16_t base)
|
||||||
|
{
|
||||||
|
CPUState *cpu;
|
||||||
|
|
||||||
|
CPU_FOREACH(cpu) {
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
int64_t id = cc->get_arch_id(cpu);
|
||||||
|
|
||||||
|
g_assert((id / 8) < ACPI_GPE_PROC_LEN);
|
||||||
|
gpe_cpu->sts[id / 8] |= (1 << (id % 8));
|
||||||
|
}
|
||||||
|
memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
|
||||||
|
gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
|
||||||
|
memory_region_add_subregion(parent, base, &gpe_cpu->io);
|
||||||
|
}
|
||||||
@@ -185,6 +185,15 @@ static void pm_powerdown_req(Notifier *n, void *opaque)
|
|||||||
acpi_pm1_evt_power_down(&pm->acpi_regs);
|
acpi_pm1_evt_power_down(&pm->acpi_regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ich9_cpu_added_req(Notifier *n, void *opaque)
|
||||||
|
{
|
||||||
|
ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, cpu_added_notifier);
|
||||||
|
|
||||||
|
assert(pm != NULL);
|
||||||
|
AcpiCpuHotplug_add(&pm->acpi_regs.gpe, &pm->gpe_cpu, CPU(opaque));
|
||||||
|
acpi_update_sci(&pm->acpi_regs, pm->irq);
|
||||||
|
}
|
||||||
|
|
||||||
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
||||||
qemu_irq sci_irq)
|
qemu_irq sci_irq)
|
||||||
{
|
{
|
||||||
@@ -210,6 +219,11 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
|||||||
qemu_register_reset(pm_reset, pm);
|
qemu_register_reset(pm_reset, pm);
|
||||||
pm->powerdown_notifier.notify = pm_powerdown_req;
|
pm->powerdown_notifier.notify = pm_powerdown_req;
|
||||||
qemu_register_powerdown_notifier(&pm->powerdown_notifier);
|
qemu_register_powerdown_notifier(&pm->powerdown_notifier);
|
||||||
|
|
||||||
|
AcpiCpuHotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
|
||||||
|
&pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE);
|
||||||
|
pm->cpu_added_notifier.notify = ich9_cpu_added_req;
|
||||||
|
qemu_register_cpu_added_notifier(&pm->cpu_added_notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v,
|
static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v,
|
||||||
|
|||||||
331
hw/acpi/pcihp.c
Normal file
331
hw/acpi/pcihp.c
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
/*
|
||||||
|
* QEMU<->ACPI BIOS PCI hotplug interface
|
||||||
|
*
|
||||||
|
* QEMU supports PCI hotplug via ACPI. This module
|
||||||
|
* implements the interface between QEMU and the ACPI BIOS.
|
||||||
|
* Interface specification - see docs/specs/acpi_pci_hotplug.txt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)
|
||||||
|
* Copyright (c) 2006 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License version 2 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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/>
|
||||||
|
*
|
||||||
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||||
|
* GNU GPL, version 2 or (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hw/acpi/pcihp.h"
|
||||||
|
|
||||||
|
#include "hw/hw.h"
|
||||||
|
#include "hw/i386/pc.h"
|
||||||
|
#include "hw/pci/pci.h"
|
||||||
|
#include "hw/acpi/acpi.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "qemu/range.h"
|
||||||
|
#include "exec/ioport.h"
|
||||||
|
#include "exec/address-spaces.h"
|
||||||
|
#include "hw/pci/pci_bus.h"
|
||||||
|
#include "qom/qom-qobject.h"
|
||||||
|
#include "qapi/qmp/qint.h"
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define ACPI_PCIHP_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define ACPI_PCIHP_DPRINTF(format, ...) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ACPI_PCI_HOTPLUG_STATUS 2
|
||||||
|
#define ACPI_PCIHP_ADDR 0xae00
|
||||||
|
#define ACPI_PCIHP_SIZE 0x0014
|
||||||
|
#define ACPI_PCIHP_LEGACY_SIZE 0x000f
|
||||||
|
#define PCI_UP_BASE 0x0000
|
||||||
|
#define PCI_DOWN_BASE 0x0004
|
||||||
|
#define PCI_EJ_BASE 0x0008
|
||||||
|
#define PCI_RMV_BASE 0x000c
|
||||||
|
#define PCI_SEL_BASE 0x0010
|
||||||
|
|
||||||
|
typedef struct AcpiPciHpFind {
|
||||||
|
int bsel;
|
||||||
|
PCIBus *bus;
|
||||||
|
} AcpiPciHpFind;
|
||||||
|
|
||||||
|
static int acpi_pcihp_get_bsel(PCIBus *bus)
|
||||||
|
{
|
||||||
|
QObject *o = object_property_get_qobject(OBJECT(bus),
|
||||||
|
ACPI_PCIHP_PROP_BSEL, NULL);
|
||||||
|
int64_t bsel = -1;
|
||||||
|
if (o) {
|
||||||
|
bsel = qint_get_int(qobject_to_qint(o));
|
||||||
|
}
|
||||||
|
if (bsel < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return bsel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque)
|
||||||
|
{
|
||||||
|
AcpiPciHpFind *find = opaque;
|
||||||
|
if (find->bsel == acpi_pcihp_get_bsel(bus)) {
|
||||||
|
find->bus = bus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PCIBus *acpi_pcihp_find_hotplug_bus(AcpiPciHpState *s, int bsel)
|
||||||
|
{
|
||||||
|
AcpiPciHpFind find = { .bsel = bsel, .bus = NULL };
|
||||||
|
|
||||||
|
if (bsel < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_for_each_bus(s->root, acpi_pcihp_test_hotplug_bus, &find);
|
||||||
|
|
||||||
|
/* Make bsel 0 eject root bus if bsel property is not set,
|
||||||
|
* for compatibility with non acpi setups.
|
||||||
|
* TODO: really needed?
|
||||||
|
*/
|
||||||
|
if (!bsel && !find.bus) {
|
||||||
|
find.bus = s->root;
|
||||||
|
}
|
||||||
|
return find.bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
|
||||||
|
{
|
||||||
|
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
|
||||||
|
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||||
|
/*
|
||||||
|
* ACPI doesn't allow hotplug of bridge devices. Don't allow
|
||||||
|
* hot-unplug of bridge devices unless they were added by hotplug
|
||||||
|
* (and so, not described by acpi).
|
||||||
|
*/
|
||||||
|
return (pc->is_bridge && !dev->qdev.hotplugged) || !dc->hotpluggable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
|
||||||
|
{
|
||||||
|
BusChild *kid, *next;
|
||||||
|
int slot = ffs(slots) - 1;
|
||||||
|
PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
|
||||||
|
|
||||||
|
if (!bus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark request as complete */
|
||||||
|
s->acpi_pcihp_pci_status[bsel].down &= ~(1U << slot);
|
||||||
|
s->acpi_pcihp_pci_status[bsel].up &= ~(1U << slot);
|
||||||
|
|
||||||
|
QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
|
||||||
|
DeviceState *qdev = kid->child;
|
||||||
|
PCIDevice *dev = PCI_DEVICE(qdev);
|
||||||
|
if (PCI_SLOT(dev->devfn) == slot) {
|
||||||
|
if (!acpi_pcihp_pc_no_hotplug(s, dev)) {
|
||||||
|
object_unparent(OBJECT(qdev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel)
|
||||||
|
{
|
||||||
|
BusChild *kid, *next;
|
||||||
|
PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
|
||||||
|
|
||||||
|
/* Execute any pending removes during reset */
|
||||||
|
while (s->acpi_pcihp_pci_status[bsel].down) {
|
||||||
|
acpi_pcihp_eject_slot(s, bsel, s->acpi_pcihp_pci_status[bsel].down);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->acpi_pcihp_pci_status[bsel].hotplug_enable = ~0;
|
||||||
|
|
||||||
|
if (!bus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
|
||||||
|
DeviceState *qdev = kid->child;
|
||||||
|
PCIDevice *pdev = PCI_DEVICE(qdev);
|
||||||
|
int slot = PCI_SLOT(pdev->devfn);
|
||||||
|
|
||||||
|
if (acpi_pcihp_pc_no_hotplug(s, pdev)) {
|
||||||
|
s->acpi_pcihp_pci_status[bsel].hotplug_enable &= ~(1U << slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_pcihp_update(AcpiPciHpState *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ACPI_PCIHP_MAX_HOTPLUG_BUS; ++i) {
|
||||||
|
acpi_pcihp_update_hotplug_bus(s, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_pcihp_reset(AcpiPciHpState *s)
|
||||||
|
{
|
||||||
|
acpi_pcihp_update(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_pcihp_device_plug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
PCIDevice *pdev = PCI_DEVICE(dev);
|
||||||
|
int slot = PCI_SLOT(pdev->devfn);
|
||||||
|
int bsel = acpi_pcihp_get_bsel(pdev->bus);
|
||||||
|
if (bsel < 0) {
|
||||||
|
error_setg(errp, "Unsupported bus. Bus doesn't have property '"
|
||||||
|
ACPI_PCIHP_PROP_BSEL "' set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't send event when device is enabled during qemu machine creation:
|
||||||
|
* it is present on boot, no hotplug event is necessary. We do send an
|
||||||
|
* event when the device is disabled later. */
|
||||||
|
if (!dev->hotplugged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
|
||||||
|
|
||||||
|
ar->gpe.sts[0] |= ACPI_PCI_HOTPLUG_STATUS;
|
||||||
|
acpi_update_sci(ar, irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
PCIDevice *pdev = PCI_DEVICE(dev);
|
||||||
|
int slot = PCI_SLOT(pdev->devfn);
|
||||||
|
int bsel = acpi_pcihp_get_bsel(pdev->bus);
|
||||||
|
if (bsel < 0) {
|
||||||
|
error_setg(errp, "Unsupported bus. Bus doesn't have property '"
|
||||||
|
ACPI_PCIHP_PROP_BSEL "' set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
|
||||||
|
|
||||||
|
ar->gpe.sts[0] |= ACPI_PCI_HOTPLUG_STATUS;
|
||||||
|
acpi_update_sci(ar, irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
|
{
|
||||||
|
AcpiPciHpState *s = opaque;
|
||||||
|
uint32_t val = 0;
|
||||||
|
int bsel = s->hotplug_select;
|
||||||
|
|
||||||
|
if (bsel < 0 || bsel > ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case PCI_UP_BASE:
|
||||||
|
val = s->acpi_pcihp_pci_status[bsel].up;
|
||||||
|
if (!s->legacy_piix) {
|
||||||
|
s->acpi_pcihp_pci_status[bsel].up = 0;
|
||||||
|
}
|
||||||
|
ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val);
|
||||||
|
break;
|
||||||
|
case PCI_DOWN_BASE:
|
||||||
|
val = s->acpi_pcihp_pci_status[bsel].down;
|
||||||
|
ACPI_PCIHP_DPRINTF("pci_down_read %" PRIu32 "\n", val);
|
||||||
|
break;
|
||||||
|
case PCI_EJ_BASE:
|
||||||
|
/* No feature defined yet */
|
||||||
|
ACPI_PCIHP_DPRINTF("pci_features_read %" PRIu32 "\n", val);
|
||||||
|
break;
|
||||||
|
case PCI_RMV_BASE:
|
||||||
|
val = s->acpi_pcihp_pci_status[bsel].hotplug_enable;
|
||||||
|
ACPI_PCIHP_DPRINTF("pci_rmv_read %" PRIu32 "\n", val);
|
||||||
|
break;
|
||||||
|
case PCI_SEL_BASE:
|
||||||
|
val = s->hotplug_select;
|
||||||
|
ACPI_PCIHP_DPRINTF("pci_sel_read %" PRIu32 "\n", val);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_write(void *opaque, hwaddr addr, uint64_t data,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
AcpiPciHpState *s = opaque;
|
||||||
|
switch (addr) {
|
||||||
|
case PCI_EJ_BASE:
|
||||||
|
if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
acpi_pcihp_eject_slot(s, s->hotplug_select, data);
|
||||||
|
ACPI_PCIHP_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n",
|
||||||
|
addr, data);
|
||||||
|
break;
|
||||||
|
case PCI_SEL_BASE:
|
||||||
|
s->hotplug_select = data;
|
||||||
|
ACPI_PCIHP_DPRINTF("pcisel write %" HWADDR_PRIx " <== %" PRIu64 "\n",
|
||||||
|
addr, data);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps acpi_pcihp_io_ops = {
|
||||||
|
.read = pci_read,
|
||||||
|
.write = pci_write,
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
.valid = {
|
||||||
|
.min_access_size = 4,
|
||||||
|
.max_access_size = 4,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void acpi_pcihp_init(AcpiPciHpState *s, PCIBus *root_bus,
|
||||||
|
MemoryRegion *address_space_io, bool bridges_enabled)
|
||||||
|
{
|
||||||
|
uint16_t io_size = ACPI_PCIHP_SIZE;
|
||||||
|
|
||||||
|
s->root= root_bus;
|
||||||
|
s->legacy_piix = !bridges_enabled;
|
||||||
|
|
||||||
|
if (s->legacy_piix) {
|
||||||
|
unsigned *bus_bsel = g_malloc(sizeof *bus_bsel);
|
||||||
|
|
||||||
|
io_size = ACPI_PCIHP_LEGACY_SIZE;
|
||||||
|
|
||||||
|
*bus_bsel = ACPI_PCIHP_BSEL_DEFAULT;
|
||||||
|
object_property_add_uint32_ptr(OBJECT(root_bus), ACPI_PCIHP_PROP_BSEL,
|
||||||
|
bus_bsel, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_init_io(&s->io, NULL, &acpi_pcihp_io_ops, s,
|
||||||
|
"acpi-pci-hotplug", io_size);
|
||||||
|
memory_region_add_subregion(address_space_io, ACPI_PCIHP_ADDR, &s->io);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_acpi_pcihp_pci_status = {
|
||||||
|
.name = "acpi_pcihp_pci_status",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.fields = (VMStateField []) {
|
||||||
|
VMSTATE_UINT32(up, AcpiPciHpPciStatus),
|
||||||
|
VMSTATE_UINT32(down, AcpiPciHpPciStatus),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
413
hw/acpi/piix4.c
413
hw/acpi/piix4.c
@@ -30,6 +30,9 @@
|
|||||||
#include "hw/nvram/fw_cfg.h"
|
#include "hw/nvram/fw_cfg.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "hw/acpi/piix4.h"
|
#include "hw/acpi/piix4.h"
|
||||||
|
#include "hw/acpi/pcihp.h"
|
||||||
|
#include "hw/acpi/cpu_hotplug.h"
|
||||||
|
#include "hw/hotplug.h"
|
||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
|
|
||||||
@@ -42,28 +45,11 @@
|
|||||||
#define GPE_BASE 0xafe0
|
#define GPE_BASE 0xafe0
|
||||||
#define GPE_LEN 4
|
#define GPE_LEN 4
|
||||||
|
|
||||||
#define PCI_HOTPLUG_ADDR 0xae00
|
|
||||||
#define PCI_HOTPLUG_SIZE 0x000f
|
|
||||||
#define PCI_UP_BASE 0xae00
|
|
||||||
#define PCI_DOWN_BASE 0xae04
|
|
||||||
#define PCI_EJ_BASE 0xae08
|
|
||||||
#define PCI_RMV_BASE 0xae0c
|
|
||||||
|
|
||||||
#define PIIX4_PROC_BASE 0xaf00
|
|
||||||
#define PIIX4_PROC_LEN 32
|
|
||||||
|
|
||||||
#define PIIX4_PCI_HOTPLUG_STATUS 2
|
|
||||||
#define PIIX4_CPU_HOTPLUG_STATUS 4
|
|
||||||
|
|
||||||
struct pci_status {
|
struct pci_status {
|
||||||
uint32_t up; /* deprecated, maintained for migration compatibility */
|
uint32_t up; /* deprecated, maintained for migration compatibility */
|
||||||
uint32_t down;
|
uint32_t down;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct CPUStatus {
|
|
||||||
uint8_t sts[PIIX4_PROC_LEN];
|
|
||||||
} CPUStatus;
|
|
||||||
|
|
||||||
typedef struct PIIX4PMState {
|
typedef struct PIIX4PMState {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
PCIDevice parent_obj;
|
PCIDevice parent_obj;
|
||||||
@@ -73,8 +59,6 @@ typedef struct PIIX4PMState {
|
|||||||
uint32_t io_base;
|
uint32_t io_base;
|
||||||
|
|
||||||
MemoryRegion io_gpe;
|
MemoryRegion io_gpe;
|
||||||
MemoryRegion io_pci;
|
|
||||||
MemoryRegion io_cpu;
|
|
||||||
ACPIREGS ar;
|
ACPIREGS ar;
|
||||||
|
|
||||||
APMState apm;
|
APMState apm;
|
||||||
@@ -88,16 +72,14 @@ typedef struct PIIX4PMState {
|
|||||||
Notifier machine_ready;
|
Notifier machine_ready;
|
||||||
Notifier powerdown_notifier;
|
Notifier powerdown_notifier;
|
||||||
|
|
||||||
/* for pci hotplug */
|
AcpiPciHpState acpi_pci_hotplug;
|
||||||
struct pci_status pci0_status;
|
bool use_acpi_pci_hotplug;
|
||||||
uint32_t pci0_hotplug_enable;
|
|
||||||
uint32_t pci0_slot_device_present;
|
|
||||||
|
|
||||||
uint8_t disable_s3;
|
uint8_t disable_s3;
|
||||||
uint8_t disable_s4;
|
uint8_t disable_s4;
|
||||||
uint8_t s4_val;
|
uint8_t s4_val;
|
||||||
|
|
||||||
CPUStatus gpe_cpu;
|
AcpiCpuHotplug gpe_cpu;
|
||||||
Notifier cpu_added_notifier;
|
Notifier cpu_added_notifier;
|
||||||
} PIIX4PMState;
|
} PIIX4PMState;
|
||||||
|
|
||||||
@@ -173,17 +155,6 @@ static void pm_write_config(PCIDevice *d,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmstate_pci_status_pre_save(void *opaque)
|
|
||||||
{
|
|
||||||
struct pci_status *pci0_status = opaque;
|
|
||||||
PIIX4PMState *s = container_of(pci0_status, PIIX4PMState, pci0_status);
|
|
||||||
|
|
||||||
/* We no longer track up, so build a safe value for migrating
|
|
||||||
* to a version that still does... of course these might get lost
|
|
||||||
* by an old buggy implementation, but we try. */
|
|
||||||
pci0_status->up = s->pci0_slot_device_present & s->pci0_hotplug_enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vmstate_acpi_post_load(void *opaque, int version_id)
|
static int vmstate_acpi_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
PIIX4PMState *s = opaque;
|
PIIX4PMState *s = opaque;
|
||||||
@@ -219,10 +190,9 @@ static const VMStateDescription vmstate_pci_status = {
|
|||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.minimum_version_id_old = 1,
|
||||||
.pre_save = vmstate_pci_status_pre_save,
|
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField []) {
|
||||||
VMSTATE_UINT32(up, struct pci_status),
|
VMSTATE_UINT32(up, struct AcpiPciHpPciStatus),
|
||||||
VMSTATE_UINT32(down, struct pci_status),
|
VMSTATE_UINT32(down, struct AcpiPciHpPciStatus),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -259,10 +229,23 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
|
|||||||
qemu_get_be16s(f, &temp);
|
qemu_get_be16s(f, &temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = vmstate_load_state(f, &vmstate_pci_status, &s->pci0_status, 1);
|
ret = vmstate_load_state(f, &vmstate_pci_status,
|
||||||
|
&s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = opaque;
|
||||||
|
return s->use_acpi_pci_hotplug;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = opaque;
|
||||||
|
return !s->use_acpi_pci_hotplug;
|
||||||
|
}
|
||||||
|
|
||||||
/* qemu-kvm 1.2 uses version 3 but advertised as 2
|
/* qemu-kvm 1.2 uses version 3 but advertised as 2
|
||||||
* To support incoming qemu-kvm 1.2 migration, change version_id
|
* To support incoming qemu-kvm 1.2 migration, change version_id
|
||||||
* and minimum_version_id to 2 below (which breaks migration from
|
* and minimum_version_id to 2 below (which breaks migration from
|
||||||
@@ -285,66 +268,18 @@ static const VMStateDescription vmstate_acpi = {
|
|||||||
VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
|
VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
|
||||||
VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
|
VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
|
||||||
VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
|
VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
|
||||||
VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
|
VMSTATE_STRUCT_TEST(
|
||||||
struct pci_status),
|
acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT],
|
||||||
|
PIIX4PMState,
|
||||||
|
vmstate_test_no_use_acpi_pci_hotplug,
|
||||||
|
2, vmstate_pci_status,
|
||||||
|
struct AcpiPciHpPciStatus),
|
||||||
|
VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
|
||||||
|
vmstate_test_use_acpi_pci_hotplug),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
|
|
||||||
{
|
|
||||||
BusChild *kid, *next;
|
|
||||||
BusState *bus = qdev_get_parent_bus(DEVICE(s));
|
|
||||||
int slot = ffs(slots) - 1;
|
|
||||||
bool slot_free = true;
|
|
||||||
|
|
||||||
/* Mark request as complete */
|
|
||||||
s->pci0_status.down &= ~(1U << slot);
|
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
|
|
||||||
DeviceState *qdev = kid->child;
|
|
||||||
PCIDevice *dev = PCI_DEVICE(qdev);
|
|
||||||
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
|
|
||||||
if (PCI_SLOT(dev->devfn) == slot) {
|
|
||||||
if (pc->no_hotplug) {
|
|
||||||
slot_free = false;
|
|
||||||
} else {
|
|
||||||
object_unparent(OBJECT(qdev));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (slot_free) {
|
|
||||||
s->pci0_slot_device_present &= ~(1U << slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void piix4_update_hotplug(PIIX4PMState *s)
|
|
||||||
{
|
|
||||||
BusState *bus = qdev_get_parent_bus(DEVICE(s));
|
|
||||||
BusChild *kid, *next;
|
|
||||||
|
|
||||||
/* Execute any pending removes during reset */
|
|
||||||
while (s->pci0_status.down) {
|
|
||||||
acpi_piix_eject_slot(s, s->pci0_status.down);
|
|
||||||
}
|
|
||||||
|
|
||||||
s->pci0_hotplug_enable = ~0;
|
|
||||||
s->pci0_slot_device_present = 0;
|
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
|
|
||||||
DeviceState *qdev = kid->child;
|
|
||||||
PCIDevice *pdev = PCI_DEVICE(qdev);
|
|
||||||
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
|
|
||||||
int slot = PCI_SLOT(pdev->devfn);
|
|
||||||
|
|
||||||
if (pc->no_hotplug) {
|
|
||||||
s->pci0_hotplug_enable &= ~(1U << slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
s->pci0_slot_device_present |= (1U << slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void piix4_reset(void *opaque)
|
static void piix4_reset(void *opaque)
|
||||||
{
|
{
|
||||||
PIIX4PMState *s = opaque;
|
PIIX4PMState *s = opaque;
|
||||||
@@ -364,7 +299,7 @@ static void piix4_reset(void *opaque)
|
|||||||
pci_conf[0x5B] = 0x02;
|
pci_conf[0x5B] = 0x02;
|
||||||
}
|
}
|
||||||
pm_io_space_update(s);
|
pm_io_space_update(s);
|
||||||
piix4_update_hotplug(s);
|
acpi_pcihp_reset(&s->acpi_pci_hotplug);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
|
static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
|
||||||
@@ -375,6 +310,28 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
|
|||||||
acpi_pm1_evt_power_down(&s->ar);
|
acpi_pm1_evt_power_down(&s->ar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void piix4_pci_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
|
||||||
|
acpi_pcihp_device_plug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void piix4_pci_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||||||
|
DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
|
||||||
|
acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev,
|
||||||
|
errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
|
||||||
|
{
|
||||||
|
PIIX4PMState *s = opaque;
|
||||||
|
|
||||||
|
qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
|
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
|
||||||
{
|
{
|
||||||
PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
|
PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
|
||||||
@@ -388,6 +345,12 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
|
|||||||
pci_conf[0x63] = 0x60;
|
pci_conf[0x63] = 0x60;
|
||||||
pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
|
pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
|
||||||
(memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
|
(memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
|
||||||
|
|
||||||
|
if (s->use_acpi_pci_hotplug) {
|
||||||
|
pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s);
|
||||||
|
} else {
|
||||||
|
piix4_update_bus_hotplug(d->bus, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void piix4_pm_add_propeties(PIIX4PMState *s)
|
static void piix4_pm_add_propeties(PIIX4PMState *s)
|
||||||
@@ -476,9 +439,9 @@ Object *piix4_pm_find(void)
|
|||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
||||||
qemu_irq sci_irq, qemu_irq smi_irq,
|
qemu_irq sci_irq, qemu_irq smi_irq,
|
||||||
int kvm_enabled, FWCfgState *fw_cfg)
|
int kvm_enabled, FWCfgState *fw_cfg)
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
PIIX4PMState *s;
|
PIIX4PMState *s;
|
||||||
@@ -504,50 +467,6 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
|||||||
return s->smb.smbus;
|
return s->smb.smbus;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property piix4_pm_properties[] = {
|
|
||||||
DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
|
|
||||||
DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
|
|
||||||
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
|
|
||||||
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
};
|
|
||||||
|
|
||||||
static void piix4_pm_class_init(ObjectClass *klass, void *data)
|
|
||||||
{
|
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
||||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
|
||||||
|
|
||||||
k->no_hotplug = 1;
|
|
||||||
k->init = piix4_pm_initfn;
|
|
||||||
k->config_write = pm_write_config;
|
|
||||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
|
||||||
k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
|
|
||||||
k->revision = 0x03;
|
|
||||||
k->class_id = PCI_CLASS_BRIDGE_OTHER;
|
|
||||||
dc->desc = "PM";
|
|
||||||
dc->vmsd = &vmstate_acpi;
|
|
||||||
dc->props = piix4_pm_properties;
|
|
||||||
/*
|
|
||||||
* Reason: part of PIIX4 southbridge, needs to be wired up,
|
|
||||||
* e.g. by mips_malta_init()
|
|
||||||
*/
|
|
||||||
dc->cannot_instantiate_with_device_add_yet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const TypeInfo piix4_pm_info = {
|
|
||||||
.name = TYPE_PIIX4_PM,
|
|
||||||
.parent = TYPE_PCI_DEVICE,
|
|
||||||
.instance_size = sizeof(PIIX4PMState),
|
|
||||||
.class_init = piix4_pm_class_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void piix4_pm_register_types(void)
|
|
||||||
{
|
|
||||||
type_register_static(&piix4_pm_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_init(piix4_pm_register_types)
|
|
||||||
|
|
||||||
static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
|
static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
|
||||||
{
|
{
|
||||||
PIIX4PMState *s = opaque;
|
PIIX4PMState *s = opaque;
|
||||||
@@ -578,182 +497,80 @@ static const MemoryRegionOps piix4_gpe_ops = {
|
|||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
|
|
||||||
{
|
|
||||||
PIIX4PMState *s = opaque;
|
|
||||||
uint32_t val = 0;
|
|
||||||
|
|
||||||
switch (addr) {
|
|
||||||
case PCI_UP_BASE - PCI_HOTPLUG_ADDR:
|
|
||||||
/* Manufacture an "up" value to cause a device check on any hotplug
|
|
||||||
* slot with a device. Extra device checks are harmless. */
|
|
||||||
val = s->pci0_slot_device_present & s->pci0_hotplug_enable;
|
|
||||||
PIIX4_DPRINTF("pci_up_read %" PRIu32 "\n", val);
|
|
||||||
break;
|
|
||||||
case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR:
|
|
||||||
val = s->pci0_status.down;
|
|
||||||
PIIX4_DPRINTF("pci_down_read %" PRIu32 "\n", val);
|
|
||||||
break;
|
|
||||||
case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
|
|
||||||
/* No feature defined yet */
|
|
||||||
PIIX4_DPRINTF("pci_features_read %" PRIu32 "\n", val);
|
|
||||||
break;
|
|
||||||
case PCI_RMV_BASE - PCI_HOTPLUG_ADDR:
|
|
||||||
val = s->pci0_hotplug_enable;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pci_write(void *opaque, hwaddr addr, uint64_t data,
|
|
||||||
unsigned int size)
|
|
||||||
{
|
|
||||||
switch (addr) {
|
|
||||||
case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
|
|
||||||
acpi_piix_eject_slot(opaque, (uint32_t)data);
|
|
||||||
PIIX4_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n",
|
|
||||||
addr, data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const MemoryRegionOps piix4_pci_ops = {
|
|
||||||
.read = pci_read,
|
|
||||||
.write = pci_write,
|
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
|
||||||
.valid = {
|
|
||||||
.min_access_size = 4,
|
|
||||||
.max_access_size = 4,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size)
|
|
||||||
{
|
|
||||||
PIIX4PMState *s = opaque;
|
|
||||||
CPUStatus *cpus = &s->gpe_cpu;
|
|
||||||
uint64_t val = cpus->sts[addr];
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
|
|
||||||
unsigned int size)
|
|
||||||
{
|
|
||||||
/* TODO: implement VCPU removal on guest signal that CPU can be removed */
|
|
||||||
}
|
|
||||||
|
|
||||||
static const MemoryRegionOps cpu_hotplug_ops = {
|
|
||||||
.read = cpu_status_read,
|
|
||||||
.write = cpu_status_write,
|
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
|
||||||
.valid = {
|
|
||||||
.min_access_size = 1,
|
|
||||||
.max_access_size = 1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PLUG,
|
|
||||||
UNPLUG,
|
|
||||||
} HotplugEventType;
|
|
||||||
|
|
||||||
static void piix4_cpu_hotplug_req(PIIX4PMState *s, CPUState *cpu,
|
|
||||||
HotplugEventType action)
|
|
||||||
{
|
|
||||||
CPUStatus *g = &s->gpe_cpu;
|
|
||||||
ACPIGPE *gpe = &s->ar.gpe;
|
|
||||||
CPUClass *k = CPU_GET_CLASS(cpu);
|
|
||||||
int64_t cpu_id;
|
|
||||||
|
|
||||||
assert(s != NULL);
|
|
||||||
|
|
||||||
*gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
|
|
||||||
cpu_id = k->get_arch_id(CPU(cpu));
|
|
||||||
if (action == PLUG) {
|
|
||||||
g->sts[cpu_id / 8] |= (1 << (cpu_id % 8));
|
|
||||||
} else {
|
|
||||||
g->sts[cpu_id / 8] &= ~(1 << (cpu_id % 8));
|
|
||||||
}
|
|
||||||
acpi_update_sci(&s->ar, s->irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void piix4_cpu_added_req(Notifier *n, void *opaque)
|
static void piix4_cpu_added_req(Notifier *n, void *opaque)
|
||||||
{
|
{
|
||||||
PIIX4PMState *s = container_of(n, PIIX4PMState, cpu_added_notifier);
|
PIIX4PMState *s = container_of(n, PIIX4PMState, cpu_added_notifier);
|
||||||
|
|
||||||
piix4_cpu_hotplug_req(s, CPU(opaque), PLUG);
|
assert(s != NULL);
|
||||||
|
AcpiCpuHotplug_add(&s->ar.gpe, &s->gpe_cpu, CPU(opaque));
|
||||||
|
acpi_update_sci(&s->ar, s->irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
|
|
||||||
PCIHotplugState state);
|
|
||||||
|
|
||||||
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
|
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
|
||||||
PCIBus *bus, PIIX4PMState *s)
|
PCIBus *bus, PIIX4PMState *s)
|
||||||
{
|
{
|
||||||
CPUState *cpu;
|
|
||||||
|
|
||||||
memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s,
|
memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s,
|
||||||
"acpi-gpe0", GPE_LEN);
|
"acpi-gpe0", GPE_LEN);
|
||||||
memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
|
memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
|
||||||
|
|
||||||
memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
|
acpi_pcihp_init(&s->acpi_pci_hotplug, bus, parent,
|
||||||
"acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
|
s->use_acpi_pci_hotplug);
|
||||||
memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
|
|
||||||
&s->io_pci);
|
|
||||||
pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
|
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
AcpiCpuHotplug_init(parent, OBJECT(s), &s->gpe_cpu,
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
PIIX4_CPU_HOTPLUG_IO_BASE);
|
||||||
int64_t id = cc->get_arch_id(cpu);
|
|
||||||
|
|
||||||
g_assert((id / 8) < PIIX4_PROC_LEN);
|
|
||||||
s->gpe_cpu.sts[id / 8] |= (1 << (id % 8));
|
|
||||||
}
|
|
||||||
memory_region_init_io(&s->io_cpu, OBJECT(s), &cpu_hotplug_ops, s,
|
|
||||||
"acpi-cpu-hotplug", PIIX4_PROC_LEN);
|
|
||||||
memory_region_add_subregion(parent, PIIX4_PROC_BASE, &s->io_cpu);
|
|
||||||
s->cpu_added_notifier.notify = piix4_cpu_added_req;
|
s->cpu_added_notifier.notify = piix4_cpu_added_req;
|
||||||
qemu_register_cpu_added_notifier(&s->cpu_added_notifier);
|
qemu_register_cpu_added_notifier(&s->cpu_added_notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_device(PIIX4PMState *s, int slot)
|
static Property piix4_pm_properties[] = {
|
||||||
|
DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
|
||||||
|
DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
|
||||||
|
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
|
||||||
|
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
|
||||||
|
DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
|
||||||
|
use_acpi_pci_hotplug, true),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void piix4_pm_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
s->pci0_slot_device_present |= (1U << slot);
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||||
|
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
|
||||||
|
|
||||||
|
k->init = piix4_pm_initfn;
|
||||||
|
k->config_write = pm_write_config;
|
||||||
|
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||||
|
k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
|
||||||
|
k->revision = 0x03;
|
||||||
|
k->class_id = PCI_CLASS_BRIDGE_OTHER;
|
||||||
|
dc->desc = "PM";
|
||||||
|
dc->vmsd = &vmstate_acpi;
|
||||||
|
dc->props = piix4_pm_properties;
|
||||||
|
/*
|
||||||
|
* Reason: part of PIIX4 southbridge, needs to be wired up,
|
||||||
|
* e.g. by mips_malta_init()
|
||||||
|
*/
|
||||||
|
dc->cannot_instantiate_with_device_add_yet = true;
|
||||||
|
dc->hotpluggable = false;
|
||||||
|
hc->plug = piix4_pci_device_plug_cb;
|
||||||
|
hc->unplug = piix4_pci_device_unplug_cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_device(PIIX4PMState *s, int slot)
|
static const TypeInfo piix4_pm_info = {
|
||||||
{
|
.name = TYPE_PIIX4_PM,
|
||||||
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
|
.parent = TYPE_PCI_DEVICE,
|
||||||
s->pci0_status.down |= (1U << slot);
|
.instance_size = sizeof(PIIX4PMState),
|
||||||
}
|
.class_init = piix4_pm_class_init,
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
|
{ TYPE_HOTPLUG_HANDLER },
|
||||||
PCIHotplugState state)
|
{ }
|
||||||
{
|
|
||||||
int slot = PCI_SLOT(dev->devfn);
|
|
||||||
PIIX4PMState *s = PIIX4_PM(qdev);
|
|
||||||
|
|
||||||
/* Don't send event when device is enabled during qemu machine creation:
|
|
||||||
* it is present on boot, no hotplug event is necessary. We do send an
|
|
||||||
* event when the device is disabled later. */
|
|
||||||
if (state == PCI_COLDPLUG_ENABLED) {
|
|
||||||
s->pci0_slot_device_present |= (1U << slot);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (state == PCI_HOTPLUG_ENABLED) {
|
static void piix4_pm_register_types(void)
|
||||||
enable_device(s, slot);
|
{
|
||||||
} else {
|
type_register_static(&piix4_pm_info);
|
||||||
disable_device(s, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
acpi_update_sci(&s->ar, s->irq);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type_init(piix4_pm_register_types)
|
||||||
|
|||||||
@@ -161,8 +161,9 @@ static void clipper_init(QEMUMachineInitArgs *args)
|
|||||||
load_image_targphys(initrd_filename, initrd_base,
|
load_image_targphys(initrd_filename, initrd_base,
|
||||||
ram_size - initrd_base);
|
ram_size - initrd_base);
|
||||||
|
|
||||||
stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL);
|
stq_phys(&address_space_memory,
|
||||||
stq_phys(param_offset + 0x108, initrd_size);
|
param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL);
|
||||||
|
stq_phys(&address_space_memory, param_offset + 0x108, initrd_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -613,7 +613,7 @@ static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
|
|||||||
translation, given the address of the PTE. */
|
translation, given the address of the PTE. */
|
||||||
static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
|
static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
|
||||||
{
|
{
|
||||||
uint64_t pte = ldq_phys(pte_addr);
|
uint64_t pte = ldq_phys(&address_space_memory, pte_addr);
|
||||||
|
|
||||||
/* Check valid bit. */
|
/* Check valid bit. */
|
||||||
if ((pte & 1) == 0) {
|
if ((pte & 1) == 0) {
|
||||||
|
|||||||
@@ -31,6 +31,13 @@ static void aw_a10_init(Object *obj)
|
|||||||
|
|
||||||
object_initialize(&s->timer, sizeof(s->timer), TYPE_AW_A10_PIT);
|
object_initialize(&s->timer, sizeof(s->timer), TYPE_AW_A10_PIT);
|
||||||
qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default());
|
qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default());
|
||||||
|
|
||||||
|
object_initialize(&s->emac, sizeof(s->emac), TYPE_AW_EMAC);
|
||||||
|
qdev_set_parent_bus(DEVICE(&s->emac), sysbus_get_default());
|
||||||
|
if (nd_table[0].used) {
|
||||||
|
qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC);
|
||||||
|
qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aw_a10_realize(DeviceState *dev, Error **errp)
|
static void aw_a10_realize(DeviceState *dev, Error **errp)
|
||||||
@@ -76,6 +83,15 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
|
|||||||
sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
|
sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
|
||||||
sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
|
sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
|
||||||
|
|
||||||
|
object_property_set_bool(OBJECT(&s->emac), true, "realized", &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbusdev = SYS_BUS_DEVICE(&s->emac);
|
||||||
|
sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE);
|
||||||
|
sysbus_connect_irq(sysbusdev, 0, s->irq[55]);
|
||||||
|
|
||||||
serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
|
serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
|
||||||
115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
|
115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "sysemu/device_tree.h"
|
#include "sysemu/device_tree.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
|
#include "exec/address-spaces.h"
|
||||||
|
|
||||||
/* Kernel boot protocol is specified in the kernel docs
|
/* Kernel boot protocol is specified in the kernel docs
|
||||||
* Documentation/arm/Booting and Documentation/arm64/booting.txt
|
* Documentation/arm/Booting and Documentation/arm64/booting.txt
|
||||||
@@ -169,12 +170,17 @@ static void default_reset_secondary(ARMCPU *cpu,
|
|||||||
{
|
{
|
||||||
CPUARMState *env = &cpu->env;
|
CPUARMState *env = &cpu->env;
|
||||||
|
|
||||||
stl_phys_notdirty(info->smp_bootreg_addr, 0);
|
stl_phys_notdirty(&address_space_memory, info->smp_bootreg_addr, 0);
|
||||||
env->regs[15] = info->smp_loader_start;
|
env->regs[15] = info->smp_loader_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool have_dtb(const struct arm_boot_info *info)
|
||||||
|
{
|
||||||
|
return info->dtb_filename || info->get_dtb;
|
||||||
|
}
|
||||||
|
|
||||||
#define WRITE_WORD(p, value) do { \
|
#define WRITE_WORD(p, value) do { \
|
||||||
stl_phys_notdirty(p, value); \
|
stl_phys_notdirty(&address_space_memory, p, value); \
|
||||||
p += 4; \
|
p += 4; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@@ -421,7 +427,7 @@ static void do_cpu_reset(void *opaque)
|
|||||||
env->regs[15] = info->loader_start;
|
env->regs[15] = info->loader_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info->dtb_filename) {
|
if (!have_dtb(info)) {
|
||||||
if (old_param) {
|
if (old_param) {
|
||||||
set_kernel_args_old(info);
|
set_kernel_args_old(info);
|
||||||
} else {
|
} else {
|
||||||
@@ -542,7 +548,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
/* for device tree boot, we pass the DTB directly in r2. Otherwise
|
/* for device tree boot, we pass the DTB directly in r2. Otherwise
|
||||||
* we point to the kernel args.
|
* we point to the kernel args.
|
||||||
*/
|
*/
|
||||||
if (info->dtb_filename || info->get_dtb) {
|
if (have_dtb(info)) {
|
||||||
/* Place the DTB after the initrd in memory. Note that some
|
/* Place the DTB after the initrd in memory. Note that some
|
||||||
* kernels will trash anything in the 4K page the initrd
|
* kernels will trash anything in the 4K page the initrd
|
||||||
* ends in, so make sure the DTB isn't caught up in that.
|
* ends in, so make sure the DTB isn't caught up in that.
|
||||||
|
|||||||
@@ -36,10 +36,17 @@ static void cubieboard_init(QEMUMachineInitArgs *args)
|
|||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
s->a10 = AW_A10(object_new(TYPE_AW_A10));
|
s->a10 = AW_A10(object_new(TYPE_AW_A10));
|
||||||
|
|
||||||
|
object_property_set_int(OBJECT(&s->a10->emac), 1, "phy-addr", &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_report("Couldn't set phy address: %s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
|
object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_report("Couldn't realize Allwinner A10: %s\n",
|
error_report("Couldn't realize Allwinner A10: %s",
|
||||||
error_get_pretty(err));
|
error_get_pretty(err));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
|||||||
busdev = SYS_BUS_DEVICE(dev);
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
sysbus_connect_irq(busdev, 0, i2c_irq);
|
sysbus_connect_irq(busdev, 0, i2c_irq);
|
||||||
sysbus_mmio_map(busdev, 0, addr);
|
sysbus_mmio_map(busdev, 0, addr);
|
||||||
s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
|
s->i2c_if[n] = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -69,11 +69,11 @@ static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
|
|||||||
|
|
||||||
switch (info->nb_cpus) {
|
switch (info->nb_cpus) {
|
||||||
case 4:
|
case 4:
|
||||||
stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0);
|
stl_phys_notdirty(&address_space_memory, SMP_BOOT_REG + 0x30, 0);
|
||||||
case 3:
|
case 3:
|
||||||
stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0);
|
stl_phys_notdirty(&address_space_memory, SMP_BOOT_REG + 0x20, 0);
|
||||||
case 2:
|
case 2:
|
||||||
stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0);
|
stl_phys_notdirty(&address_space_memory, SMP_BOOT_REG + 0x10, 0);
|
||||||
env->regs[15] = SMP_BOOT_ADDR;
|
env->regs[15] = SMP_BOOT_ADDR;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1593,7 +1593,7 @@ static void musicpal_init(QEMUMachineInitArgs *args)
|
|||||||
DeviceState *key_dev;
|
DeviceState *key_dev;
|
||||||
DeviceState *wm8750_dev;
|
DeviceState *wm8750_dev;
|
||||||
SysBusDevice *s;
|
SysBusDevice *s;
|
||||||
i2c_bus *i2c;
|
I2CBus *i2c;
|
||||||
int i;
|
int i;
|
||||||
unsigned long flash_size;
|
unsigned long flash_size;
|
||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
@@ -1687,7 +1687,7 @@ static void musicpal_init(QEMUMachineInitArgs *args)
|
|||||||
dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
|
dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
|
||||||
pic[MP_GPIO_IRQ]);
|
pic[MP_GPIO_IRQ]);
|
||||||
i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
|
i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
|
||||||
i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c");
|
i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c");
|
||||||
|
|
||||||
lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL);
|
lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL);
|
||||||
key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL);
|
key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL);
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ static void n8x0_i2c_setup(struct n800_s *s)
|
|||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO);
|
qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO);
|
||||||
i2c_bus *i2c = omap_i2c_bus(s->mpu->i2c[0]);
|
I2CBus *i2c = omap_i2c_bus(s->mpu->i2c[0]);
|
||||||
|
|
||||||
/* Attach a menelaus PM chip */
|
/* Attach a menelaus PM chip */
|
||||||
dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR);
|
dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR);
|
||||||
|
|||||||
@@ -224,27 +224,24 @@ static const VMStateDescription vmstate_pxa2xx_cm = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
static uint64_t pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
uint64_t *value)
|
|
||||||
{
|
{
|
||||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||||
*value = s->clkcfg;
|
return s->clkcfg;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||||
s->clkcfg = value & 0xf;
|
s->clkcfg = value & 0xf;
|
||||||
if (value & 2) {
|
if (value & 2) {
|
||||||
printf("%s: CPU frequency change attempt\n", __func__);
|
printf("%s: CPU frequency change attempt\n", __func__);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||||
static const char *pwrmode[8] = {
|
static const char *pwrmode[8] = {
|
||||||
@@ -310,36 +307,29 @@ static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
printf("%s: machine entered %s mode\n", __func__,
|
printf("%s: machine entered %s mode\n", __func__,
|
||||||
pwrmode[value & 7]);
|
pwrmode[value & 7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
static uint64_t pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
uint64_t *value)
|
|
||||||
{
|
{
|
||||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||||
*value = s->pmnc;
|
return s->pmnc;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||||
s->pmnc = value;
|
s->pmnc = value;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
uint64_t *value)
|
|
||||||
{
|
{
|
||||||
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
||||||
if (s->pmnc & 1) {
|
if (s->pmnc & 1) {
|
||||||
*value = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
} else {
|
} else {
|
||||||
*value = 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const ARMCPRegInfo pxa_cp_reginfo[] = {
|
static const ARMCPRegInfo pxa_cp_reginfo[] = {
|
||||||
@@ -1222,8 +1212,14 @@ static const TypeInfo pxa2xx_rtc_sysbus_info = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* I2C Interface */
|
/* I2C Interface */
|
||||||
typedef struct {
|
|
||||||
I2CSlave i2c;
|
#define TYPE_PXA2XX_I2C_SLAVE "pxa2xx-i2c-slave"
|
||||||
|
#define PXA2XX_I2C_SLAVE(obj) \
|
||||||
|
OBJECT_CHECK(PXA2xxI2CSlaveState, (obj), TYPE_PXA2XX_I2C_SLAVE)
|
||||||
|
|
||||||
|
typedef struct PXA2xxI2CSlaveState {
|
||||||
|
I2CSlave parent_obj;
|
||||||
|
|
||||||
PXA2xxI2CState *host;
|
PXA2xxI2CState *host;
|
||||||
} PXA2xxI2CSlaveState;
|
} PXA2xxI2CSlaveState;
|
||||||
|
|
||||||
@@ -1238,7 +1234,7 @@ struct PXA2xxI2CState {
|
|||||||
|
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
PXA2xxI2CSlaveState *slave;
|
PXA2xxI2CSlaveState *slave;
|
||||||
i2c_bus *bus;
|
I2CBus *bus;
|
||||||
qemu_irq irq;
|
qemu_irq irq;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t region_size;
|
uint32_t region_size;
|
||||||
@@ -1268,7 +1264,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s)
|
|||||||
/* These are only stubs now. */
|
/* These are only stubs now. */
|
||||||
static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||||
{
|
{
|
||||||
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
|
PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
|
||||||
PXA2xxI2CState *s = slave->host;
|
PXA2xxI2CState *s = slave->host;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
@@ -1292,10 +1288,12 @@ static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
|||||||
|
|
||||||
static int pxa2xx_i2c_rx(I2CSlave *i2c)
|
static int pxa2xx_i2c_rx(I2CSlave *i2c)
|
||||||
{
|
{
|
||||||
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
|
PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
|
||||||
PXA2xxI2CState *s = slave->host;
|
PXA2xxI2CState *s = slave->host;
|
||||||
if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
|
|
||||||
|
if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->status & (1 << 0)) { /* RWM */
|
if (s->status & (1 << 0)) { /* RWM */
|
||||||
s->status |= 1 << 6; /* set ITE */
|
s->status |= 1 << 6; /* set ITE */
|
||||||
@@ -1307,10 +1305,12 @@ static int pxa2xx_i2c_rx(I2CSlave *i2c)
|
|||||||
|
|
||||||
static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
|
static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
|
||||||
{
|
{
|
||||||
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
|
PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
|
||||||
PXA2xxI2CState *s = slave->host;
|
PXA2xxI2CState *s = slave->host;
|
||||||
if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
|
|
||||||
|
if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(s->status & (1 << 0))) { /* RWM */
|
if (!(s->status & (1 << 0))) { /* RWM */
|
||||||
s->status |= 1 << 7; /* set IRF */
|
s->status |= 1 << 7; /* set IRF */
|
||||||
@@ -1325,6 +1325,7 @@ static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr,
|
|||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
|
PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
|
||||||
|
I2CSlave *slave;
|
||||||
|
|
||||||
addr -= s->offset;
|
addr -= s->offset;
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
@@ -1333,7 +1334,8 @@ static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr,
|
|||||||
case ISR:
|
case ISR:
|
||||||
return s->status | (i2c_bus_busy(s->bus) << 2);
|
return s->status | (i2c_bus_busy(s->bus) << 2);
|
||||||
case ISAR:
|
case ISAR:
|
||||||
return s->slave->i2c.address;
|
slave = I2C_SLAVE(s->slave);
|
||||||
|
return slave->address;
|
||||||
case IDBR:
|
case IDBR:
|
||||||
return s->data;
|
return s->data;
|
||||||
case IBMR:
|
case IBMR:
|
||||||
@@ -1408,7 +1410,7 @@ static void pxa2xx_i2c_write(void *opaque, hwaddr addr,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ISAR:
|
case ISAR:
|
||||||
i2c_set_slave_address(&s->slave->i2c, value & 0x7f);
|
i2c_set_slave_address(I2C_SLAVE(s->slave), value & 0x7f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDBR:
|
case IDBR:
|
||||||
@@ -1432,7 +1434,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
|
|||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.minimum_version_id_old = 1,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField []) {
|
||||||
VMSTATE_I2C_SLAVE(i2c, PXA2xxI2CSlaveState),
|
VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1448,7 +1450,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c = {
|
|||||||
VMSTATE_UINT8(ibmr, PXA2xxI2CState),
|
VMSTATE_UINT8(ibmr, PXA2xxI2CState),
|
||||||
VMSTATE_UINT8(data, PXA2xxI2CState),
|
VMSTATE_UINT8(data, PXA2xxI2CState),
|
||||||
VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
|
VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
|
||||||
vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState *),
|
vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1470,7 +1472,7 @@ static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo pxa2xx_i2c_slave_info = {
|
static const TypeInfo pxa2xx_i2c_slave_info = {
|
||||||
.name = "pxa2xx-i2c-slave",
|
.name = TYPE_PXA2XX_I2C_SLAVE,
|
||||||
.parent = TYPE_I2C_SLAVE,
|
.parent = TYPE_I2C_SLAVE,
|
||||||
.instance_size = sizeof(PXA2xxI2CSlaveState),
|
.instance_size = sizeof(PXA2xxI2CSlaveState),
|
||||||
.class_init = pxa2xx_i2c_slave_class_init,
|
.class_init = pxa2xx_i2c_slave_class_init,
|
||||||
@@ -1482,7 +1484,7 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
|
|||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
SysBusDevice *i2c_dev;
|
SysBusDevice *i2c_dev;
|
||||||
PXA2xxI2CState *s;
|
PXA2xxI2CState *s;
|
||||||
i2c_bus *i2cbus;
|
I2CBus *i2cbus;
|
||||||
|
|
||||||
dev = qdev_create(NULL, TYPE_PXA2XX_I2C);
|
dev = qdev_create(NULL, TYPE_PXA2XX_I2C);
|
||||||
qdev_prop_set_uint32(dev, "size", region_size + 1);
|
qdev_prop_set_uint32(dev, "size", region_size + 1);
|
||||||
@@ -1496,8 +1498,8 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
|
|||||||
s = PXA2XX_I2C(i2c_dev);
|
s = PXA2XX_I2C(i2c_dev);
|
||||||
/* FIXME: Should the slave device really be on a separate bus? */
|
/* FIXME: Should the slave device really be on a separate bus? */
|
||||||
i2cbus = i2c_init_bus(dev, "dummy");
|
i2cbus = i2c_init_bus(dev, "dummy");
|
||||||
dev = i2c_create_slave(i2cbus, "pxa2xx-i2c-slave", 0);
|
dev = i2c_create_slave(i2cbus, TYPE_PXA2XX_I2C_SLAVE, 0);
|
||||||
s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE(dev));
|
s->slave = PXA2XX_I2C_SLAVE(dev);
|
||||||
s->slave->host = s;
|
s->slave->host = s;
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
@@ -1518,7 +1520,7 @@ static int pxa2xx_i2c_initfn(SysBusDevice *sbd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
|
I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
|
||||||
{
|
{
|
||||||
return s->bus;
|
return s->bus;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,20 +217,17 @@ static const int pxa2xx_cp_reg_map[0x10] = {
|
|||||||
[0xa] = ICPR2,
|
[0xa] = ICPR2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
static uint64_t pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
uint64_t *value)
|
|
||||||
{
|
{
|
||||||
int offset = pxa2xx_cp_reg_map[ri->crn];
|
int offset = pxa2xx_cp_reg_map[ri->crn];
|
||||||
*value = pxa2xx_pic_mem_read(ri->opaque, offset, 4);
|
return pxa2xx_pic_mem_read(ri->opaque, offset, 4);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
int offset = pxa2xx_cp_reg_map[ri->crn];
|
int offset = pxa2xx_cp_reg_map[ri->crn];
|
||||||
pxa2xx_pic_mem_write(ri->opaque, offset, value, 4);
|
pxa2xx_pic_mem_write(ri->opaque, offset, value, 4);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define REGINFO_FOR_PIC_CP(NAME, CRN) \
|
#define REGINFO_FOR_PIC_CP(NAME, CRN) \
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ static void realview_init(QEMUMachineInitArgs *args,
|
|||||||
qemu_irq mmc_irq[2];
|
qemu_irq mmc_irq[2];
|
||||||
PCIBus *pci_bus = NULL;
|
PCIBus *pci_bus = NULL;
|
||||||
NICInfo *nd;
|
NICInfo *nd;
|
||||||
i2c_bus *i2c;
|
I2CBus *i2c;
|
||||||
int n;
|
int n;
|
||||||
int done_nic = 0;
|
int done_nic = 0;
|
||||||
qemu_irq cpu_irq[4];
|
qemu_irq cpu_irq[4];
|
||||||
@@ -255,7 +255,7 @@ static void realview_init(QEMUMachineInitArgs *args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
|
dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
|
||||||
i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
|
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
||||||
i2c_create_slave(i2c, "ds1338", 0x68);
|
i2c_create_slave(i2c, "ds1338", 0x68);
|
||||||
|
|
||||||
/* Memory map for RealView Emulation Baseboard: */
|
/* Memory map for RealView Emulation Baseboard: */
|
||||||
|
|||||||
@@ -734,7 +734,7 @@ static void spitz_wm8750_addr(void *opaque, int line, int level)
|
|||||||
static void spitz_i2c_setup(PXA2xxState *cpu)
|
static void spitz_i2c_setup(PXA2xxState *cpu)
|
||||||
{
|
{
|
||||||
/* Attach the CPU on one end of our I2C bus. */
|
/* Attach the CPU on one end of our I2C bus. */
|
||||||
i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
|
I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
|
||||||
|
|
||||||
DeviceState *wm;
|
DeviceState *wm;
|
||||||
|
|
||||||
|
|||||||
@@ -692,7 +692,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq,
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
i2c_bus *bus;
|
I2CBus *bus;
|
||||||
qemu_irq irq;
|
qemu_irq irq;
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
uint32_t msa;
|
uint32_t msa;
|
||||||
@@ -868,7 +868,7 @@ static int stellaris_i2c_init(SysBusDevice *sbd)
|
|||||||
{
|
{
|
||||||
DeviceState *dev = DEVICE(sbd);
|
DeviceState *dev = DEVICE(sbd);
|
||||||
stellaris_i2c_state *s = STELLARIS_I2C(dev);
|
stellaris_i2c_state *s = STELLARIS_I2C(dev);
|
||||||
i2c_bus *bus;
|
I2CBus *bus;
|
||||||
|
|
||||||
sysbus_init_irq(sbd, &s->irq);
|
sysbus_init_irq(sbd, &s->irq);
|
||||||
bus = i2c_init_bus(dev, "i2c");
|
bus = i2c_init_bus(dev, "i2c");
|
||||||
@@ -1213,7 +1213,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
|
|||||||
qemu_irq adc;
|
qemu_irq adc;
|
||||||
int sram_size;
|
int sram_size;
|
||||||
int flash_size;
|
int flash_size;
|
||||||
i2c_bus *i2c;
|
I2CBus *i2c;
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
@@ -1256,7 +1256,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
|
|||||||
|
|
||||||
if (board->dc2 & (1 << 12)) {
|
if (board->dc2 & (1 << 12)) {
|
||||||
dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000, pic[8]);
|
dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000, pic[8]);
|
||||||
i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
|
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
||||||
if (board->peripherals & BP_OLED_I2C) {
|
if (board->peripherals & BP_OLED_I2C) {
|
||||||
i2c_create_slave(i2c, "ssd0303", 0x3d);
|
i2c_create_slave(i2c, "ssd0303", 0x3d);
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user