Compare commits
577 Commits
v2.2.1
...
pull-input
Author | SHA1 | Date | |
---|---|---|---|
|
0ee4de5840 | ||
|
ba4d26064e | ||
|
4083ae311d | ||
|
699eae17b8 | ||
|
de5ee4a888 | ||
|
db5fd8d709 | ||
|
82f11917c9 | ||
|
800e2ecc89 | ||
|
355392329e | ||
|
9220fe54c6 | ||
|
177ea79f65 | ||
|
5a0826f7d2 | ||
|
1535300119 | ||
|
d8d5119cae | ||
|
5899d6d0b4 | ||
|
b8d6ac9f90 | ||
|
2ccf97ec0f | ||
|
eb513f82f0 | ||
|
24e60305c5 | ||
|
0c021c1fd2 | ||
|
ec53b45bcd | ||
|
83ecb22ba2 | ||
|
a5bd4470ed | ||
|
86a6a9bf55 | ||
|
9b6d7b365d | ||
|
3996e85c18 | ||
|
707ff80021 | ||
|
74acb99737 | ||
|
877417d9ae | ||
|
7dd93291ca | ||
|
fcf73af68e | ||
|
0002a51889 | ||
|
34da30afa4 | ||
|
8cd996f493 | ||
|
49743df399 | ||
|
aca7aaf628 | ||
|
1e42c35346 | ||
|
36b62ae6a5 | ||
|
b449ca3c18 | ||
|
e68cba3636 | ||
|
ea987c2c21 | ||
|
a26ba26e21 | ||
|
131fe9b843 | ||
|
e1a8c9b67f | ||
|
8580b06498 | ||
|
f018d8cd21 | ||
|
1b826f2778 | ||
|
27af7d6ea5 | ||
|
df58887b20 | ||
|
99efa84d5c | ||
|
31fc97c314 | ||
|
ae21935924 | ||
|
3d59b6808b | ||
|
fac6688a18 | ||
|
b4952c3677 | ||
|
1281f8e308 | ||
|
37097418be | ||
|
90d6a6730b | ||
|
2d8ac5eb7a | ||
|
9c6d5c1ade | ||
|
9feb8adeaa | ||
|
b629a38a13 | ||
|
1979b908b6 | ||
|
f186aa976b | ||
|
488eef2f1d | ||
|
c88f68ec3c | ||
|
6f84da3a07 | ||
|
e1660dc57c | ||
|
bee818872c | ||
|
07958082fd | ||
|
3b9985e9a1 | ||
|
3a7f560fa6 | ||
|
c1d322e604 | ||
|
a00369fc56 | ||
|
07d31d07f4 | ||
|
47b0f45a92 | ||
|
5734edd837 | ||
|
e7026f1953 | ||
|
9a502563ee | ||
|
bb00021de0 | ||
|
095e4fa4b5 | ||
|
51a2219bdc | ||
|
66552b894b | ||
|
4d68e86bb1 | ||
|
c740ad92d0 | ||
|
6d86ae0824 | ||
|
ef57137f1b | ||
|
d1d1b206b0 | ||
|
bc52169660 | ||
|
9c8ab1ae0d | ||
|
a2d9c0c407 | ||
|
1dbe67503b | ||
|
99605175c9 | ||
|
292be092ad | ||
|
04636dc410 | ||
|
4dd7b8d30c | ||
|
7c6a4ab871 | ||
|
bd8baecddc | ||
|
c29c1dd312 | ||
|
b7b9d39a7a | ||
|
c4237dfa63 | ||
|
a06e43556e | ||
|
527ab22a2a | ||
|
1085daf941 | ||
|
291680186f | ||
|
9f07429e88 | ||
|
0a82855a1a | ||
|
a97ceca578 | ||
|
ee82310f8a | ||
|
e012b78cf5 | ||
|
fcf5def1ab | ||
|
b8aff7d6bf | ||
|
709e57753b | ||
|
7d5ad15d17 | ||
|
a39d97c7be | ||
|
d46858377b | ||
|
b4f72e31b9 | ||
|
57407ea44c | ||
|
5435f1d77e | ||
|
9e03a0405d | ||
|
863f6f52b7 | ||
|
8cba80c3a0 | ||
|
59ac15326e | ||
|
fdb78ec006 | ||
|
6781fc412e | ||
|
fb85b34da7 | ||
|
64ea8038ff | ||
|
aaf0301917 | ||
|
97052d64e4 | ||
|
e77d927f1a | ||
|
ec2cbbdd80 | ||
|
c00cd99527 | ||
|
719cac1ce2 | ||
|
4d91558d60 | ||
|
364c3e6b8d | ||
|
e76d442043 | ||
|
f1c5831ca3 | ||
|
11fe680858 | ||
|
a4ba200894 | ||
|
b3e27c3aee | ||
|
29c6e6df49 | ||
|
7d010ae9e0 | ||
|
59a0419856 | ||
|
d941fba0b5 | ||
|
b1c2fb9b29 | ||
|
de77a243b3 | ||
|
5e97b623c2 | ||
|
f8b6f8edac | ||
|
a1666142db | ||
|
60786ef339 | ||
|
b0cc3f8397 | ||
|
62be4e3a50 | ||
|
9b8424d573 | ||
|
c8d6f66ae7 | ||
|
e7af4c6730 | ||
|
75c74ccbe1 | ||
|
4ee9ced979 | ||
|
b8cbc738de | ||
|
09f28e5b51 | ||
|
759bf45d81 | ||
|
c760dbb9dc | ||
|
2f285bdd54 | ||
|
466976d9ee | ||
|
82e345f57e | ||
|
f83c2378bb | ||
|
aeedd58234 | ||
|
56a846157e | ||
|
0ff93d11bc | ||
|
aac862379c | ||
|
3e28c5e363 | ||
|
69d1a93774 | ||
|
e43668a7d2 | ||
|
f90468b646 | ||
|
549cfe5d5d | ||
|
5f9490de56 | ||
|
77bad151fb | ||
|
2bf9febc95 | ||
|
e6b8fd246c | ||
|
338c25b692 | ||
|
01a579729b | ||
|
e094c4c12f | ||
|
58dd0a4787 | ||
|
7d45556eff | ||
|
00e6fd3e03 | ||
|
14ba79c73a | ||
|
4814f2d116 | ||
|
b748863a7f | ||
|
2791128e2f | ||
|
cb3778a045 | ||
|
44045ce974 | ||
|
e6b4e5f479 | ||
|
2eaaac1f01 | ||
|
ea259acae5 | ||
|
aa49668cc3 | ||
|
a3a292c420 | ||
|
08f432aa3e | ||
|
f2f6e00b2e | ||
|
5aa8136020 | ||
|
debfb917a4 | ||
|
d13c040409 | ||
|
bfa7362889 | ||
|
cd42d5b236 | ||
|
bd79255d25 | ||
|
4eab7a0a23 | ||
|
857cccac0d | ||
|
ab0302ee76 | ||
|
03de06dde5 | ||
|
0266359e57 | ||
|
69b058c881 | ||
|
2cbcfb281a | ||
|
aa351061db | ||
|
07abe45c48 | ||
|
7d48a0f721 | ||
|
578f3c7b08 | ||
|
6c87e3d596 | ||
|
cfaadf0e89 | ||
|
ff6cff7554 | ||
|
d789c84547 | ||
|
86099db382 | ||
|
66708822cd | ||
|
5712db6ae5 | ||
|
c0ccb02db4 | ||
|
61e2f3521c | ||
|
223a72f117 | ||
|
e5a5604f8f | ||
|
12d027f132 | ||
|
c8e829b7bf | ||
|
51942aee3c | ||
|
08828484a5 | ||
|
083a58906c | ||
|
c29196904b | ||
|
e364bab69b | ||
|
4902192432 | ||
|
af7c9f34b1 | ||
|
9ee00ba831 | ||
|
7eb1dc7f0b | ||
|
52eb3dfd7d | ||
|
2e16898a61 | ||
|
49d2e648e8 | ||
|
60fb1a87b4 | ||
|
b28fb27b5e | ||
|
dcbfc5cefb | ||
|
e2c7d025ad | ||
|
df92ee4448 | ||
|
62356b7292 | ||
|
d13dd2d7a9 | ||
|
a664477db8 | ||
|
b47d8efa9f | ||
|
462037c9e8 | ||
|
7e58e2ac77 | ||
|
7db96d6cf8 | ||
|
ddcd55316f | ||
|
3b08098b40 | ||
|
f1839938b0 | ||
|
703008e81a | ||
|
9816833d3b | ||
|
c95f3901b4 | ||
|
9655b9328a | ||
|
436d63ff3e | ||
|
b5fd8fa345 | ||
|
e2bed107c6 | ||
|
f2f1585f60 | ||
|
0b79a78169 | ||
|
d5de7839d7 | ||
|
e4e3917630 | ||
|
7f13420ec0 | ||
|
45820fccaf | ||
|
4b5b443576 | ||
|
af715d9802 | ||
|
781b717c50 | ||
|
328b3b6c44 | ||
|
c4e7c17a8e | ||
|
adee64249e | ||
|
f9d8f66735 | ||
|
5546a621a8 | ||
|
079eb19cbb | ||
|
9ee27d7381 | ||
|
cf7087db10 | ||
|
c67676711c | ||
|
385f57cf9a | ||
|
20302e71a5 | ||
|
58889fe50a | ||
|
71e28e3cc2 | ||
|
23120b13c6 | ||
|
756ae78b27 | ||
|
b574f60268 | ||
|
86b182ac0e | ||
|
84afc4dd56 | ||
|
c246cee4ee | ||
|
d3f3a0f453 | ||
|
1dfc5c8808 | ||
|
62959ffe45 | ||
|
63ed4907cb | ||
|
0d01b7ce61 | ||
|
2c3056f182 | ||
|
46522a8223 | ||
|
f1ddebd865 | ||
|
44f017d03e | ||
|
8fc1a3f58f | ||
|
5d0fe65078 | ||
|
97e89ee914 | ||
|
2db59a76c4 | ||
|
85d36377e4 | ||
|
01673a3401 | ||
|
246ae24d7d | ||
|
339aaf5b7f | ||
|
d86fb03469 | ||
|
4db753b1ac | ||
|
46817e86fc | ||
|
22382bb96c | ||
|
b9fd11b867 | ||
|
5508099397 | ||
|
a41642708a | ||
|
e0883e2de0 | ||
|
cf7856adef | ||
|
555e72f2d0 | ||
|
3dcadce507 | ||
|
0b2824e5e4 | ||
|
d29c431edc | ||
|
d4fa5354a2 | ||
|
8ef3915263 | ||
|
8e5f757044 | ||
|
00fb4a1181 | ||
|
66991d1103 | ||
|
1a4d570017 | ||
|
bb962386b8 | ||
|
74797f40dc | ||
|
1d725ae952 | ||
|
cbb26c9a12 | ||
|
c48245f0c6 | ||
|
d922445020 | ||
|
90f12d735d | ||
|
27e1fb13f2 | ||
|
7215d7e7ae | ||
|
81a423e6c6 | ||
|
f88f79ec9d | ||
|
c357747981 | ||
|
8fc605b8aa | ||
|
51fdea945a | ||
|
2b09f94cdb | ||
|
d2bfa6e622 | ||
|
6225a4a0e3 | ||
|
d75de74967 | ||
|
4386f08767 | ||
|
11f5ea105c | ||
|
8280b12c0e | ||
|
36b86e0dc2 | ||
|
c7d4d98ae7 | ||
|
800675f117 | ||
|
44a1f94684 | ||
|
977184db39 | ||
|
4f9d090012 | ||
|
329c9b10b6 | ||
|
60fe637bf0 | ||
|
d6d69731f5 | ||
|
b78accf614 | ||
|
fd5f3b6367 | ||
|
1240be2435 | ||
|
68a5e38a7e | ||
|
1f51a5cb97 | ||
|
c55156402e | ||
|
7f4675c3f7 | ||
|
dfa9c2a0f4 | ||
|
224d10ff5a | ||
|
ece5e5bfa1 | ||
|
7302dcd60b | ||
|
d368ba4376 | ||
|
c7ff8daacf | ||
|
1645b8eee5 | ||
|
023c3a9707 | ||
|
0d931d7062 | ||
|
4e02b0fcf5 | ||
|
269e235849 | ||
|
575a6f4082 | ||
|
2f9ac42acf | ||
|
78a611f193 | ||
|
b3a4f0b1a0 | ||
|
64bbd372f2 | ||
|
5b9efc39ae | ||
|
bf2a7ddb0a | ||
|
4e7fa73ec2 | ||
|
d8a499f17e | ||
|
2a62914bd8 | ||
|
626cf8f4c6 | ||
|
e511b4d783 | ||
|
b4ac20b4df | ||
|
f8e1f53334 | ||
|
3c55fe2a13 | ||
|
0bd0adbe5b | ||
|
1c3381af32 | ||
|
e42a92ae64 | ||
|
ab3ad07f89 | ||
|
4be34d1e21 | ||
|
18fc805534 | ||
|
18cd2c17b5 | ||
|
906b53a2de | ||
|
0bb0b2d2fe | ||
|
e9af2fef24 | ||
|
e6eef7c221 | ||
|
076796f8fd | ||
|
d19ae73e98 | ||
|
c7fe4b1298 | ||
|
bdfc8480c5 | ||
|
b0a0551283 | ||
|
5e0b7d8869 | ||
|
d229b985b5 | ||
|
9fc0e2d8ac | ||
|
f41389ae3c | ||
|
9551ea6991 | ||
|
5eba5a6632 | ||
|
54600752a1 | ||
|
c4d4525c38 | ||
|
18b41f95d2 | ||
|
ea32aaf1a7 | ||
|
e0d3795654 | ||
|
82595da8de | ||
|
de35464461 | ||
|
8455ce053a | ||
|
43f2376e09 | ||
|
28b240877b | ||
|
b5cf2c1b08 | ||
|
43c5d8f800 | ||
|
7486458c33 | ||
|
85b712c9d5 | ||
|
3f394472c5 | ||
|
9e0c3e8df5 | ||
|
0e82dc7bbd | ||
|
30af51ce7f | ||
|
a9d1e9daa5 | ||
|
0571df44a1 | ||
|
9281dbe653 | ||
|
942764cc32 | ||
|
5c98415b2a | ||
|
ebd9fbd7e1 | ||
|
99c9c3cb24 | ||
|
64baadc272 | ||
|
97c61fb78a | ||
|
b141290478 | ||
|
7c3843332d | ||
|
25f2895e0e | ||
|
a7130a3ef9 | ||
|
38df27c8a7 | ||
|
72149414e2 | ||
|
a554ecb49d | ||
|
b1ab03af89 | ||
|
be693c87e4 | ||
|
54bf36ed35 | ||
|
fb6c91ba2b | ||
|
01c097f796 | ||
|
b848ce2b9c | ||
|
4a7e2d7315 | ||
|
88ca1c2d70 | ||
|
0c17d68c1d | ||
|
11f136ee25 | ||
|
7dd8c9af0d | ||
|
b85a1fd61c | ||
|
6e8801f9de | ||
|
137feaa9a1 | ||
|
e89e51a17e | ||
|
144634ae6c | ||
|
770225764f | ||
|
de38d23b54 | ||
|
0f1a3b2470 | ||
|
3f3c82a57d | ||
|
51a79b0397 | ||
|
c3e3026062 | ||
|
3f342b9e0e | ||
|
ea30a4b824 | ||
|
0eeb17d618 | ||
|
57e3a0c7cb | ||
|
a38bb0792c | ||
|
1ecc3a2df1 | ||
|
a09f2d16f6 | ||
|
67a5eebca1 | ||
|
df6f93182a | ||
|
328f1f0f08 | ||
|
2b2f7d97d8 | ||
|
ed51626066 | ||
|
47e04430ed | ||
|
0974257ed5 | ||
|
a68e0d547f | ||
|
83c1bb1868 | ||
|
fc2ef4a391 | ||
|
3fb763cb55 | ||
|
d899d2e248 | ||
|
9aeecbbc62 | ||
|
03c3359dfc | ||
|
73b7bcad43 | ||
|
8a3e0bc370 | ||
|
e5dc64b8ff | ||
|
3ba235a022 | ||
|
625fa9fe6f | ||
|
0d0d7f47b4 | ||
|
0fc9b0d162 | ||
|
01212d4ed6 | ||
|
6a69b9620a | ||
|
3b5e14c76a | ||
|
11c89769dc | ||
|
2247798d13 | ||
|
f798068c56 | ||
|
b2439d26f0 | ||
|
f75613cf24 | ||
|
c614972408 | ||
|
fd752801ae | ||
|
1bcb15cf77 | ||
|
ef8104378c | ||
|
5f535a941e | ||
|
b89689f5b2 | ||
|
d20051856c | ||
|
be0677a93c | ||
|
d11032315a | ||
|
e800e5d4e2 | ||
|
a56ebc6ba4 | ||
|
c5f6e493bb | ||
|
8884dd1bbc | ||
|
2ebafc854d | ||
|
3dc7ca3c97 | ||
|
5d6e96efb8 | ||
|
73f1f7564d | ||
|
b756b9ce8a | ||
|
00e047926e | ||
|
d71a8b0686 | ||
|
38f3ef574b | ||
|
7cddd3728e | ||
|
c6684249fd | ||
|
b8e665e4d8 | ||
|
90c9b1671e | ||
|
8f9e835fd2 | ||
|
be6273da9e | ||
|
e465ce7d09 | ||
|
4c58e80acd | ||
|
aadf99a792 | ||
|
e140177d9c | ||
|
2c28b21f7c | ||
|
2019ba0a01 | ||
|
2bb0dce762 | ||
|
17fcb74af9 | ||
|
192cf55cc0 | ||
|
f48a33b608 | ||
|
8779441b1b | ||
|
48fe86f640 | ||
|
e6bb31ec6f | ||
|
8d6adccda2 | ||
|
289b276c69 | ||
|
9e193c5a65 | ||
|
729962f6db | ||
|
e3442099a2 | ||
|
0b92885420 | ||
|
4ef3982a99 | ||
|
2389eeae69 | ||
|
cc20b07a42 | ||
|
4821cd4cfd | ||
|
4b58554a0e | ||
|
f71eaa74c0 | ||
|
4875a77950 | ||
|
20a9e77dfa | ||
|
04df765ab4 | ||
|
43948386bb | ||
|
525965b85d | ||
|
b196d969ef | ||
|
7766aa0c0e | ||
|
1c854067b3 | ||
|
d504fb4cec | ||
|
80b57dda89 | ||
|
8ccefb91bf | ||
|
e1cf558264 | ||
|
9be71be5bd | ||
|
44c2286b5d | ||
|
24588100ab | ||
|
4ad608803c | ||
|
7251711472 | ||
|
2c80ab15e2 | ||
|
8b310fc4f9 | ||
|
fcf55f580d | ||
|
1a71992376 | ||
|
b5369dd841 | ||
|
7fb8da2b88 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -109,3 +109,4 @@ cscope.*
|
|||||||
tags
|
tags
|
||||||
TAGS
|
TAGS
|
||||||
*~
|
*~
|
||||||
|
/tests/qemu-iotests/common.env
|
||||||
|
2
LICENSE
2
LICENSE
@@ -11,7 +11,7 @@ option) any later version.
|
|||||||
|
|
||||||
As of July 2013, contributions under version 2 of the GNU General Public
|
As of July 2013, contributions under version 2 of the GNU General Public
|
||||||
License (and no later version) are only accepted for the following files
|
License (and no later version) are only accepted for the following files
|
||||||
or directories: bsd-user/, linux-user/, hw/misc/vfio.c, hw/xen/xen_pt*.
|
or directories: bsd-user/, linux-user/, hw/vfio/, hw/xen/xen_pt*.
|
||||||
|
|
||||||
3) The Tiny Code Generator (TCG) is released under the BSD license
|
3) The Tiny Code Generator (TCG) is released under the BSD license
|
||||||
(see license headers in files).
|
(see license headers in files).
|
||||||
|
26
MAINTAINERS
26
MAINTAINERS
@@ -98,8 +98,12 @@ LM32
|
|||||||
M: Michael Walle <michael@walle.cc>
|
M: Michael Walle <michael@walle.cc>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: target-lm32/
|
F: target-lm32/
|
||||||
|
F: disas/lm32.c
|
||||||
F: hw/lm32/
|
F: hw/lm32/
|
||||||
F: hw/char/lm32_*
|
F: hw/*/lm32_*
|
||||||
|
F: hw/*/milkymist-*
|
||||||
|
F: include/hw/char/lm32_juart.h
|
||||||
|
F: include/hw/lm32/
|
||||||
F: tests/tcg/lm32/
|
F: tests/tcg/lm32/
|
||||||
|
|
||||||
M68K
|
M68K
|
||||||
@@ -534,6 +538,7 @@ S390 Virtio
|
|||||||
M: Alexander Graf <agraf@suse.de>
|
M: Alexander Graf <agraf@suse.de>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/s390x/s390-*.c
|
F: hw/s390x/s390-*.c
|
||||||
|
X: hw/s390x/*pci*.[hc]
|
||||||
|
|
||||||
S390 Virtio-ccw
|
S390 Virtio-ccw
|
||||||
M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||||
@@ -544,6 +549,7 @@ F: hw/s390x/s390-virtio-ccw.c
|
|||||||
F: hw/s390x/css.[hc]
|
F: hw/s390x/css.[hc]
|
||||||
F: hw/s390x/sclp*.[hc]
|
F: hw/s390x/sclp*.[hc]
|
||||||
F: hw/s390x/ipl*.[hc]
|
F: hw/s390x/ipl*.[hc]
|
||||||
|
F: hw/s390x/*pci*.[hc]
|
||||||
F: include/hw/s390x/
|
F: include/hw/s390x/
|
||||||
F: pc-bios/s390-ccw/
|
F: pc-bios/s390-ccw/
|
||||||
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
|
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
|
||||||
@@ -657,7 +663,7 @@ F: hw/usb/dev-serial.c
|
|||||||
VFIO
|
VFIO
|
||||||
M: Alex Williamson <alex.williamson@redhat.com>
|
M: Alex Williamson <alex.williamson@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: hw/misc/vfio.c
|
F: hw/vfio/*
|
||||||
|
|
||||||
vhost
|
vhost
|
||||||
M: Michael S. Tsirkin <mst@redhat.com>
|
M: Michael S. Tsirkin <mst@redhat.com>
|
||||||
@@ -696,6 +702,14 @@ M: Amit Shah <amit.shah@redhat.com>
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: hw/char/virtio-serial-bus.c
|
F: hw/char/virtio-serial-bus.c
|
||||||
F: hw/char/virtio-console.c
|
F: hw/char/virtio-console.c
|
||||||
|
F: include/hw/virtio/virtio-serial.h
|
||||||
|
|
||||||
|
virtio-rng
|
||||||
|
M: Amit Shah <amit.shah@redhat.com>
|
||||||
|
S: Supported
|
||||||
|
F: hw/virtio/virtio-rng.c
|
||||||
|
F: include/hw/virtio/virtio-rng.h
|
||||||
|
F: backends/rng*.c
|
||||||
|
|
||||||
nvme
|
nvme
|
||||||
M: Keith Busch <keith.busch@intel.com>
|
M: Keith Busch <keith.busch@intel.com>
|
||||||
@@ -743,6 +757,7 @@ F: aio-*.c
|
|||||||
F: block*
|
F: block*
|
||||||
F: block/
|
F: block/
|
||||||
F: hw/block/
|
F: hw/block/
|
||||||
|
F: migration/block*
|
||||||
F: qemu-img*
|
F: qemu-img*
|
||||||
F: qemu-io*
|
F: qemu-io*
|
||||||
F: tests/image-fuzzer/
|
F: tests/image-fuzzer/
|
||||||
@@ -928,12 +943,14 @@ F: scripts/checkpatch.pl
|
|||||||
|
|
||||||
Migration
|
Migration
|
||||||
M: Juan Quintela <quintela@redhat.com>
|
M: Juan Quintela <quintela@redhat.com>
|
||||||
|
M: Amit Shah <amit.shah@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: include/migration/
|
F: include/migration/
|
||||||
F: migration*
|
F: migration/
|
||||||
F: savevm.c
|
F: savevm.c
|
||||||
F: arch_init.c
|
F: arch_init.c
|
||||||
F: vmstate.c
|
F: scripts/vmstate-static-checker.py
|
||||||
|
F: tests/vmstate-static-checker-data/
|
||||||
|
|
||||||
Seccomp
|
Seccomp
|
||||||
M: Eduardo Otubo <eduardo.otubo@profitbricks.com>
|
M: Eduardo Otubo <eduardo.otubo@profitbricks.com>
|
||||||
@@ -1089,7 +1106,6 @@ S: Supported
|
|||||||
F: block/ssh.c
|
F: block/ssh.c
|
||||||
|
|
||||||
ARCHIPELAGO
|
ARCHIPELAGO
|
||||||
M: Chrysostomos Nanakos <cnanakos@grnet.gr>
|
|
||||||
M: Chrysostomos Nanakos <chris@include.gr>
|
M: Chrysostomos Nanakos <chris@include.gr>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: block/archipelago.c
|
F: block/archipelago.c
|
||||||
|
4
Makefile
4
Makefile
@@ -313,8 +313,8 @@ qemu-%.tar.bz2:
|
|||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
|
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
|
||||||
rm -f config-all-devices.mak config-all-disas.mak
|
rm -f config-all-devices.mak config-all-disas.mak config.status
|
||||||
rm -f po/*.mo
|
rm -f po/*.mo tests/qemu-iotests/common.env
|
||||||
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
||||||
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
|
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
|
||||||
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
|
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
|
||||||
|
@@ -48,15 +48,9 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
|
|||||||
|
|
||||||
common-obj-$(CONFIG_LINUX) += fsdev/
|
common-obj-$(CONFIG_LINUX) += fsdev/
|
||||||
|
|
||||||
common-obj-y += migration.o migration-tcp.o
|
common-obj-y += migration/
|
||||||
common-obj-y += vmstate.o
|
|
||||||
common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
|
|
||||||
common-obj-$(CONFIG_RDMA) += migration-rdma.o
|
|
||||||
common-obj-y += qemu-char.o #aio.o
|
common-obj-y += qemu-char.o #aio.o
|
||||||
common-obj-y += block-migration.o
|
common-obj-y += page_cache.o
|
||||||
common-obj-y += page_cache.o xbzrle.o
|
|
||||||
|
|
||||||
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
|
|
||||||
|
|
||||||
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
|
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
|
||||||
|
|
||||||
|
@@ -73,7 +73,7 @@ void aio_set_fd_handler(AioContext *ctx,
|
|||||||
} else {
|
} else {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
/* Alloc and insert if it's not already there */
|
/* Alloc and insert if it's not already there */
|
||||||
node = g_malloc0(sizeof(AioHandler));
|
node = g_new0(AioHandler, 1);
|
||||||
node->pfd.fd = fd;
|
node->pfd.fd = fd;
|
||||||
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
||||||
|
|
||||||
|
@@ -67,7 +67,7 @@ void aio_set_fd_handler(AioContext *ctx,
|
|||||||
|
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
/* Alloc and insert if it's not already there */
|
/* Alloc and insert if it's not already there */
|
||||||
node = g_malloc0(sizeof(AioHandler));
|
node = g_new0(AioHandler, 1);
|
||||||
node->pfd.fd = fd;
|
node->pfd.fd = fd;
|
||||||
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ void aio_set_event_notifier(AioContext *ctx,
|
|||||||
} else {
|
} else {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
/* Alloc and insert if it's not already there */
|
/* Alloc and insert if it's not already there */
|
||||||
node = g_malloc0(sizeof(AioHandler));
|
node = g_new0(AioHandler, 1);
|
||||||
node->e = e;
|
node->e = e;
|
||||||
node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
|
node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
|
||||||
node->pfd.events = G_IO_IN;
|
node->pfd.events = G_IO_IN;
|
||||||
|
36
arch_init.c
36
arch_init.c
@@ -346,7 +346,8 @@ static void xbzrle_cache_zero_page(ram_addr_t current_addr)
|
|||||||
|
|
||||||
/* We don't care if this fails to allocate a new cache page
|
/* We don't care if this fails to allocate a new cache page
|
||||||
* as long as it updated an old one */
|
* as long as it updated an old one */
|
||||||
cache_insert(XBZRLE.cache, current_addr, ZERO_TARGET_PAGE);
|
cache_insert(XBZRLE.cache, current_addr, ZERO_TARGET_PAGE,
|
||||||
|
bitmap_sync_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ENCODING_FLAG_XBZRLE 0x1
|
#define ENCODING_FLAG_XBZRLE 0x1
|
||||||
@@ -358,10 +359,11 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data,
|
|||||||
int encoded_len = 0, bytes_sent = -1;
|
int encoded_len = 0, bytes_sent = -1;
|
||||||
uint8_t *prev_cached_page;
|
uint8_t *prev_cached_page;
|
||||||
|
|
||||||
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
|
if (!cache_is_cached(XBZRLE.cache, current_addr, bitmap_sync_count)) {
|
||||||
acct_info.xbzrle_cache_miss++;
|
acct_info.xbzrle_cache_miss++;
|
||||||
if (!last_stage) {
|
if (!last_stage) {
|
||||||
if (cache_insert(XBZRLE.cache, current_addr, *current_data) == -1) {
|
if (cache_insert(XBZRLE.cache, current_addr, *current_data,
|
||||||
|
bitmap_sync_count) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
/* update *current_data when the page has been
|
/* update *current_data when the page has been
|
||||||
@@ -522,7 +524,7 @@ static void migration_bitmap_sync(void)
|
|||||||
address_space_sync_dirty_bitmap(&address_space_memory);
|
address_space_sync_dirty_bitmap(&address_space_memory);
|
||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
migration_bitmap_sync_range(block->mr->ram_addr, block->length);
|
migration_bitmap_sync_range(block->mr->ram_addr, block->used_length);
|
||||||
}
|
}
|
||||||
trace_migration_bitmap_sync_end(migration_dirty_pages
|
trace_migration_bitmap_sync_end(migration_dirty_pages
|
||||||
- num_dirty_pages_init);
|
- num_dirty_pages_init);
|
||||||
@@ -668,7 +670,7 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
|||||||
offset >= last_offset) {
|
offset >= last_offset) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (offset >= block->length) {
|
if (offset >= block->used_length) {
|
||||||
offset = 0;
|
offset = 0;
|
||||||
block = QTAILQ_NEXT(block, next);
|
block = QTAILQ_NEXT(block, next);
|
||||||
if (!block) {
|
if (!block) {
|
||||||
@@ -727,7 +729,7 @@ uint64_t ram_bytes_total(void)
|
|||||||
uint64_t total = 0;
|
uint64_t total = 0;
|
||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next)
|
QTAILQ_FOREACH(block, &ram_list.blocks, next)
|
||||||
total += block->length;
|
total += block->used_length;
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
@@ -831,7 +833,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
|||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
uint64_t block_pages;
|
uint64_t block_pages;
|
||||||
|
|
||||||
block_pages = block->length >> TARGET_PAGE_BITS;
|
block_pages = block->used_length >> TARGET_PAGE_BITS;
|
||||||
migration_dirty_pages += block_pages;
|
migration_dirty_pages += block_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,7 +846,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
|||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
qemu_put_byte(f, strlen(block->idstr));
|
qemu_put_byte(f, strlen(block->idstr));
|
||||||
qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
|
qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
|
||||||
qemu_put_be64(f, block->length);
|
qemu_put_be64(f, block->used_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_mutex_unlock_ramlist();
|
qemu_mutex_unlock_ramlist();
|
||||||
@@ -1015,7 +1017,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
|||||||
uint8_t len;
|
uint8_t len;
|
||||||
|
|
||||||
if (flags & RAM_SAVE_FLAG_CONTINUE) {
|
if (flags & RAM_SAVE_FLAG_CONTINUE) {
|
||||||
if (!block || block->length <= offset) {
|
if (!block || block->max_length <= offset) {
|
||||||
error_report("Ack, bad migration stream!");
|
error_report("Ack, bad migration stream!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1028,7 +1030,8 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
|||||||
id[len] = 0;
|
id[len] = 0;
|
||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
if (!strncmp(id, block->idstr, sizeof(id)) && block->length > offset) {
|
if (!strncmp(id, block->idstr, sizeof(id)) &&
|
||||||
|
block->max_length > offset) {
|
||||||
return memory_region_get_ram_ptr(block->mr) + offset;
|
return memory_region_get_ram_ptr(block->mr) + offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1085,11 +1088,14 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
if (!strncmp(id, block->idstr, sizeof(id))) {
|
if (!strncmp(id, block->idstr, sizeof(id))) {
|
||||||
if (block->length != length) {
|
if (length != block->used_length) {
|
||||||
error_report("Length mismatch: %s: 0x" RAM_ADDR_FMT
|
Error *local_err = NULL;
|
||||||
" in != 0x" RAM_ADDR_FMT, id, length,
|
|
||||||
block->length);
|
ret = qemu_ram_resize(block->offset, length, &local_err);
|
||||||
ret = -EINVAL;
|
if (local_err) {
|
||||||
|
error_report("%s", error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
11
async.c
11
async.c
@@ -44,10 +44,12 @@ struct QEMUBH {
|
|||||||
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
QEMUBH *bh;
|
QEMUBH *bh;
|
||||||
bh = g_malloc0(sizeof(QEMUBH));
|
bh = g_new(QEMUBH, 1);
|
||||||
bh->ctx = ctx;
|
*bh = (QEMUBH){
|
||||||
bh->cb = cb;
|
.ctx = ctx,
|
||||||
bh->opaque = opaque;
|
.cb = cb,
|
||||||
|
.opaque = opaque,
|
||||||
|
};
|
||||||
qemu_mutex_lock(&ctx->bh_lock);
|
qemu_mutex_lock(&ctx->bh_lock);
|
||||||
bh->next = ctx->first_bh;
|
bh->next = ctx->first_bh;
|
||||||
/* Make sure that the members are ready before putting bh into list */
|
/* Make sure that the members are ready before putting bh into list */
|
||||||
@@ -300,6 +302,7 @@ AioContext *aio_context_new(Error **errp)
|
|||||||
error_setg_errno(errp, -ret, "Failed to initialize event notifier");
|
error_setg_errno(errp, -ret, "Failed to initialize event notifier");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
g_source_set_can_recurse(&ctx->source, true);
|
||||||
aio_set_event_notifier(ctx, &ctx->notifier,
|
aio_set_event_notifier(ctx, &ctx->notifier,
|
||||||
(EventNotifierHandler *)
|
(EventNotifierHandler *)
|
||||||
event_notifier_test_and_clear);
|
event_notifier_test_and_clear);
|
||||||
|
@@ -88,11 +88,7 @@ static char *rng_random_get_filename(Object *obj, Error **errp)
|
|||||||
{
|
{
|
||||||
RndRandom *s = RNG_RANDOM(obj);
|
RndRandom *s = RNG_RANDOM(obj);
|
||||||
|
|
||||||
if (s->filename) {
|
return g_strdup(s->filename);
|
||||||
return g_strdup(s->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rng_random_set_filename(Object *obj, const char *filename,
|
static void rng_random_set_filename(Object *obj, const char *filename,
|
||||||
|
162
block.c
162
block.c
@@ -97,6 +97,10 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
|
|||||||
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
|
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
|
||||||
QLIST_HEAD_INITIALIZER(bdrv_drivers);
|
QLIST_HEAD_INITIALIZER(bdrv_drivers);
|
||||||
|
|
||||||
|
static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||||
|
int nr_sectors);
|
||||||
|
static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||||
|
int nr_sectors);
|
||||||
/* If non-zero, use only whitelisted block drivers */
|
/* If non-zero, use only whitelisted block drivers */
|
||||||
static int use_bdrv_whitelist;
|
static int use_bdrv_whitelist;
|
||||||
|
|
||||||
@@ -229,7 +233,7 @@ size_t bdrv_opt_mem_align(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check if the path starts with "<protocol>:" */
|
/* check if the path starts with "<protocol>:" */
|
||||||
static int path_has_protocol(const char *path)
|
int path_has_protocol(const char *path)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
@@ -303,15 +307,32 @@ void path_combine(char *dest, int dest_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz)
|
void bdrv_get_full_backing_filename_from_filename(const char *backed,
|
||||||
|
const char *backing,
|
||||||
|
char *dest, size_t sz,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
if (bs->backing_file[0] == '\0' || path_has_protocol(bs->backing_file)) {
|
if (backing[0] == '\0' || path_has_protocol(backing) ||
|
||||||
pstrcpy(dest, sz, bs->backing_file);
|
path_is_absolute(backing))
|
||||||
|
{
|
||||||
|
pstrcpy(dest, sz, backing);
|
||||||
|
} else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) {
|
||||||
|
error_setg(errp, "Cannot use relative backing file names for '%s'",
|
||||||
|
backed);
|
||||||
} else {
|
} else {
|
||||||
path_combine(dest, sz, bs->filename, bs->backing_file);
|
path_combine(dest, sz, backed, backing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
char *backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
|
||||||
|
|
||||||
|
bdrv_get_full_backing_filename_from_filename(backed, bs->backing_file,
|
||||||
|
dest, sz, errp);
|
||||||
|
}
|
||||||
|
|
||||||
void bdrv_register(BlockDriver *bdrv)
|
void bdrv_register(BlockDriver *bdrv)
|
||||||
{
|
{
|
||||||
/* Block drivers without coroutine functions need emulation */
|
/* Block drivers without coroutine functions need emulation */
|
||||||
@@ -648,12 +669,44 @@ BlockDriver *bdrv_find_protocol(const char *filename,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Guess image format by probing its contents.
|
||||||
|
* This is not a good idea when your image is raw (CVE-2008-2004), but
|
||||||
|
* we do it anyway for backward compatibility.
|
||||||
|
*
|
||||||
|
* @buf contains the image's first @buf_size bytes.
|
||||||
|
* @buf_size is the buffer size in bytes (generally BLOCK_PROBE_BUF_SIZE,
|
||||||
|
* but can be smaller if the image file is smaller)
|
||||||
|
* @filename is its filename.
|
||||||
|
*
|
||||||
|
* For all block drivers, call the bdrv_probe() method to get its
|
||||||
|
* probing score.
|
||||||
|
* Return the first block driver with the highest probing score.
|
||||||
|
*/
|
||||||
|
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
|
||||||
|
const char *filename)
|
||||||
|
{
|
||||||
|
int score_max = 0, score;
|
||||||
|
BlockDriver *drv = NULL, *d;
|
||||||
|
|
||||||
|
QLIST_FOREACH(d, &bdrv_drivers, list) {
|
||||||
|
if (d->bdrv_probe) {
|
||||||
|
score = d->bdrv_probe(buf, buf_size, filename);
|
||||||
|
if (score > score_max) {
|
||||||
|
score_max = score;
|
||||||
|
drv = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return drv;
|
||||||
|
}
|
||||||
|
|
||||||
static int find_image_format(BlockDriverState *bs, const char *filename,
|
static int find_image_format(BlockDriverState *bs, const char *filename,
|
||||||
BlockDriver **pdrv, Error **errp)
|
BlockDriver **pdrv, Error **errp)
|
||||||
{
|
{
|
||||||
int score, score_max;
|
BlockDriver *drv;
|
||||||
BlockDriver *drv1, *drv;
|
uint8_t buf[BLOCK_PROBE_BUF_SIZE];
|
||||||
uint8_t buf[2048];
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
|
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
|
||||||
@@ -670,17 +723,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
score_max = 0;
|
drv = bdrv_probe_all(buf, ret, filename);
|
||||||
drv = NULL;
|
|
||||||
QLIST_FOREACH(drv1, &bdrv_drivers, list) {
|
|
||||||
if (drv1->bdrv_probe) {
|
|
||||||
score = drv1->bdrv_probe(buf, ret, filename);
|
|
||||||
if (score > score_max) {
|
|
||||||
score_max = score;
|
|
||||||
drv = drv1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_setg(errp, "Could not determine image format: No compatible "
|
error_setg(errp, "Could not determine image format: No compatible "
|
||||||
"driver found");
|
"driver found");
|
||||||
@@ -1157,7 +1200,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
|||||||
|
|
||||||
bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
|
bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
|
||||||
/* Otherwise we won't be able to commit due to check in bdrv_commit */
|
/* Otherwise we won't be able to commit due to check in bdrv_commit */
|
||||||
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT,
|
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
|
||||||
bs->backing_blocker);
|
bs->backing_blocker);
|
||||||
out:
|
out:
|
||||||
bdrv_refresh_limits(bs, NULL);
|
bdrv_refresh_limits(bs, NULL);
|
||||||
@@ -1195,7 +1238,14 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
goto free_exit;
|
goto free_exit;
|
||||||
} else {
|
} else {
|
||||||
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX);
|
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
QDECREF(options);
|
||||||
|
goto free_exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bs->drv || !bs->drv->supports_backing) {
|
if (!bs->drv || !bs->drv->supports_backing) {
|
||||||
@@ -1459,6 +1509,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Image format probing */
|
/* Image format probing */
|
||||||
|
bs->probed = !drv;
|
||||||
if (!drv && file) {
|
if (!drv && file) {
|
||||||
ret = find_image_format(file, filename, &drv, &local_err);
|
ret = find_image_format(file, filename, &drv, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -2165,8 +2216,8 @@ int bdrv_commit(BlockDriverState *bs)
|
|||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, NULL) ||
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) ||
|
||||||
bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, NULL)) {
|
bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET, NULL)) {
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3011,18 +3062,16 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
|
|||||||
|
|
||||||
max_nb_sectors = ROUND_UP(MAX(0, total_sectors - sector_num),
|
max_nb_sectors = ROUND_UP(MAX(0, total_sectors - sector_num),
|
||||||
align >> BDRV_SECTOR_BITS);
|
align >> BDRV_SECTOR_BITS);
|
||||||
if (max_nb_sectors > 0) {
|
if (nb_sectors < max_nb_sectors) {
|
||||||
|
ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
|
||||||
|
} else if (max_nb_sectors > 0) {
|
||||||
QEMUIOVector local_qiov;
|
QEMUIOVector local_qiov;
|
||||||
size_t local_sectors;
|
|
||||||
|
|
||||||
max_nb_sectors = MIN(max_nb_sectors, SIZE_MAX / BDRV_SECTOR_BITS);
|
|
||||||
local_sectors = MIN(max_nb_sectors, nb_sectors);
|
|
||||||
|
|
||||||
qemu_iovec_init(&local_qiov, qiov->niov);
|
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||||
qemu_iovec_concat(&local_qiov, qiov, 0,
|
qemu_iovec_concat(&local_qiov, qiov, 0,
|
||||||
local_sectors * BDRV_SECTOR_SIZE);
|
max_nb_sectors * BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
ret = drv->bdrv_co_readv(bs, sector_num, local_sectors,
|
ret = drv->bdrv_co_readv(bs, sector_num, max_nb_sectors,
|
||||||
&local_qiov);
|
&local_qiov);
|
||||||
|
|
||||||
qemu_iovec_destroy(&local_qiov);
|
qemu_iovec_destroy(&local_qiov);
|
||||||
@@ -3195,6 +3244,9 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
|||||||
|
|
||||||
if (ret == -ENOTSUP) {
|
if (ret == -ENOTSUP) {
|
||||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||||
|
int max_xfer_len = MIN_NON_ZERO(bs->bl.max_transfer_length,
|
||||||
|
MAX_WRITE_ZEROES_DEFAULT);
|
||||||
|
num = MIN(num, max_xfer_len);
|
||||||
iov.iov_len = num * BDRV_SECTOR_SIZE;
|
iov.iov_len = num * BDRV_SECTOR_SIZE;
|
||||||
if (iov.iov_base == NULL) {
|
if (iov.iov_base == NULL) {
|
||||||
iov.iov_base = qemu_try_blockalign(bs, num * BDRV_SECTOR_SIZE);
|
iov.iov_base = qemu_try_blockalign(bs, num * BDRV_SECTOR_SIZE);
|
||||||
@@ -3211,7 +3263,7 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
|||||||
/* Keep bounce buffer around if it is big enough for all
|
/* Keep bounce buffer around if it is big enough for all
|
||||||
* all future requests.
|
* all future requests.
|
||||||
*/
|
*/
|
||||||
if (num < max_write_zeroes) {
|
if (num < max_xfer_len) {
|
||||||
qemu_vfree(iov.iov_base);
|
qemu_vfree(iov.iov_base);
|
||||||
iov.iov_base = NULL;
|
iov.iov_base = NULL;
|
||||||
}
|
}
|
||||||
@@ -3793,6 +3845,14 @@ bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base)
|
|||||||
return top != NULL;
|
return top != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockDriverState *bdrv_next_node(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
if (!bs) {
|
||||||
|
return QTAILQ_FIRST(&graph_bdrv_states);
|
||||||
|
}
|
||||||
|
return QTAILQ_NEXT(bs, node_list);
|
||||||
|
}
|
||||||
|
|
||||||
BlockDriverState *bdrv_next(BlockDriverState *bs)
|
BlockDriverState *bdrv_next(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
if (!bs) {
|
if (!bs) {
|
||||||
@@ -3801,6 +3861,11 @@ BlockDriverState *bdrv_next(BlockDriverState *bs)
|
|||||||
return QTAILQ_NEXT(bs, device_list);
|
return QTAILQ_NEXT(bs, device_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *bdrv_get_node_name(const BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
return bs->node_name;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO check what callers really want: bs->node_name or blk_name() */
|
/* TODO check what callers really want: bs->node_name or blk_name() */
|
||||||
const char *bdrv_get_device_name(const BlockDriverState *bs)
|
const char *bdrv_get_device_name(const BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
@@ -5353,8 +5418,20 @@ void bdrv_dirty_iter_init(BlockDriverState *bs,
|
|||||||
hbitmap_iter_init(hbi, bitmap->bitmap, 0);
|
hbitmap_iter_init(hbi, bitmap->bitmap, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||||
int nr_sectors)
|
int64_t cur_sector, int nr_sectors)
|
||||||
|
{
|
||||||
|
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||||
|
int64_t cur_sector, int nr_sectors)
|
||||||
|
{
|
||||||
|
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||||
|
int nr_sectors)
|
||||||
{
|
{
|
||||||
BdrvDirtyBitmap *bitmap;
|
BdrvDirtyBitmap *bitmap;
|
||||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||||
@@ -5362,7 +5439,8 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors)
|
static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||||
|
int nr_sectors)
|
||||||
{
|
{
|
||||||
BdrvDirtyBitmap *bitmap;
|
BdrvDirtyBitmap *bitmap;
|
||||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||||
@@ -5601,16 +5679,26 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
if (size == -1) {
|
if (size == -1) {
|
||||||
if (backing_file) {
|
if (backing_file) {
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
char *full_backing = g_new0(char, PATH_MAX);
|
||||||
int64_t size;
|
int64_t size;
|
||||||
int back_flags;
|
int back_flags;
|
||||||
|
|
||||||
|
bdrv_get_full_backing_filename_from_filename(filename, backing_file,
|
||||||
|
full_backing, PATH_MAX,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
g_free(full_backing);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* backing files always opened read-only */
|
/* backing files always opened read-only */
|
||||||
back_flags =
|
back_flags =
|
||||||
flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
|
flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
|
||||||
|
|
||||||
bs = NULL;
|
bs = NULL;
|
||||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, back_flags,
|
ret = bdrv_open(&bs, full_backing, NULL, NULL, back_flags,
|
||||||
backing_drv, &local_err);
|
backing_drv, &local_err);
|
||||||
|
g_free(full_backing);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -5632,8 +5720,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
printf("Formatting '%s', fmt=%s ", filename, fmt);
|
printf("Formatting '%s', fmt=%s", filename, fmt);
|
||||||
qemu_opts_print(opts);
|
qemu_opts_print(opts, " ");
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "block/accounting.h"
|
#include "block/accounting.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
|
#include "qemu/timer.h"
|
||||||
|
|
||||||
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
||||||
int64_t bytes, enum BlockAcctType type)
|
int64_t bytes, enum BlockAcctType type)
|
||||||
@@ -31,7 +32,7 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
|||||||
assert(type < BLOCK_MAX_IOTYPE);
|
assert(type < BLOCK_MAX_IOTYPE);
|
||||||
|
|
||||||
cookie->bytes = bytes;
|
cookie->bytes = bytes;
|
||||||
cookie->start_time_ns = get_clock();
|
cookie->start_time_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||||
cookie->type = type;
|
cookie->type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +42,8 @@ void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
|||||||
|
|
||||||
stats->nr_bytes[cookie->type] += cookie->bytes;
|
stats->nr_bytes[cookie->type] += cookie->bytes;
|
||||||
stats->nr_ops[cookie->type]++;
|
stats->nr_ops[cookie->type]++;
|
||||||
stats->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
|
stats->total_time_ns[cookie->type] +=
|
||||||
|
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - cookie->start_time_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -360,6 +360,7 @@ static void coroutine_fn backup_run(void *opaque)
|
|||||||
hbitmap_free(job->bitmap);
|
hbitmap_free(job->bitmap);
|
||||||
|
|
||||||
bdrv_iostatus_disable(target);
|
bdrv_iostatus_disable(target);
|
||||||
|
bdrv_op_unblock_all(target, job->common.blocker);
|
||||||
|
|
||||||
data = g_malloc(sizeof(*data));
|
data = g_malloc(sizeof(*data));
|
||||||
data->ret = ret;
|
data->ret = ret;
|
||||||
@@ -379,6 +380,11 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
|||||||
assert(target);
|
assert(target);
|
||||||
assert(cb);
|
assert(cb);
|
||||||
|
|
||||||
|
if (bs == target) {
|
||||||
|
error_setg(errp, "Source and target cannot be the same");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
|
if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
|
||||||
on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
||||||
!bdrv_iostatus_is_enabled(bs)) {
|
!bdrv_iostatus_is_enabled(bs)) {
|
||||||
@@ -386,6 +392,26 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!bdrv_is_inserted(bs)) {
|
||||||
|
error_setg(errp, "Device is not inserted: %s",
|
||||||
|
bdrv_get_device_name(bs));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bdrv_is_inserted(target)) {
|
||||||
|
error_setg(errp, "Device is not inserted: %s",
|
||||||
|
bdrv_get_device_name(target));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
len = bdrv_getlength(bs);
|
len = bdrv_getlength(bs);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
error_setg_errno(errp, -len, "unable to get length for '%s'",
|
error_setg_errno(errp, -len, "unable to get length for '%s'",
|
||||||
@@ -399,6 +425,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bdrv_op_block_all(target, job->common.blocker);
|
||||||
|
|
||||||
job->on_source_error = on_source_error;
|
job->on_source_error = on_source_error;
|
||||||
job->on_target_error = on_target_error;
|
job->on_target_error = on_target_error;
|
||||||
job->target = target;
|
job->target = target;
|
||||||
|
@@ -721,93 +721,50 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
|
|||||||
|
|
||||||
static void blkdebug_refresh_filename(BlockDriverState *bs)
|
static void blkdebug_refresh_filename(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVBlkdebugState *s = bs->opaque;
|
|
||||||
struct BlkdebugRule *rule;
|
|
||||||
QDict *opts;
|
QDict *opts;
|
||||||
QList *inject_error_list = NULL, *set_state_list = NULL;
|
const QDictEntry *e;
|
||||||
QList *suspend_list = NULL;
|
bool force_json = false;
|
||||||
int event;
|
|
||||||
|
|
||||||
if (!bs->file->full_open_options) {
|
for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
|
||||||
|
if (strcmp(qdict_entry_key(e), "config") &&
|
||||||
|
strcmp(qdict_entry_key(e), "x-image") &&
|
||||||
|
strcmp(qdict_entry_key(e), "image") &&
|
||||||
|
strncmp(qdict_entry_key(e), "image.", strlen("image.")))
|
||||||
|
{
|
||||||
|
force_json = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_json && !bs->file->full_open_options) {
|
||||||
/* The config file cannot be recreated, so creating a plain filename
|
/* The config file cannot be recreated, so creating a plain filename
|
||||||
* is impossible */
|
* is impossible */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!force_json && bs->file->exact_filename[0]) {
|
||||||
|
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||||
|
"blkdebug:%s:%s",
|
||||||
|
qdict_get_try_str(bs->options, "config") ?: "",
|
||||||
|
bs->file->exact_filename);
|
||||||
|
}
|
||||||
|
|
||||||
opts = qdict_new();
|
opts = qdict_new();
|
||||||
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
|
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
|
||||||
|
|
||||||
QINCREF(bs->file->full_open_options);
|
QINCREF(bs->file->full_open_options);
|
||||||
qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
|
qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
|
||||||
|
|
||||||
for (event = 0; event < BLKDBG_EVENT_MAX; event++) {
|
for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
|
||||||
QLIST_FOREACH(rule, &s->rules[event], next) {
|
if (strcmp(qdict_entry_key(e), "x-image") &&
|
||||||
if (rule->action == ACTION_INJECT_ERROR) {
|
strcmp(qdict_entry_key(e), "image") &&
|
||||||
QDict *inject_error = qdict_new();
|
strncmp(qdict_entry_key(e), "image.", strlen("image.")))
|
||||||
|
{
|
||||||
qdict_put_obj(inject_error, "event", QOBJECT(qstring_from_str(
|
qobject_incref(qdict_entry_value(e));
|
||||||
BlkdebugEvent_lookup[rule->event])));
|
qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
|
||||||
qdict_put_obj(inject_error, "state",
|
|
||||||
QOBJECT(qint_from_int(rule->state)));
|
|
||||||
qdict_put_obj(inject_error, "errno", QOBJECT(qint_from_int(
|
|
||||||
rule->options.inject.error)));
|
|
||||||
qdict_put_obj(inject_error, "sector", QOBJECT(qint_from_int(
|
|
||||||
rule->options.inject.sector)));
|
|
||||||
qdict_put_obj(inject_error, "once", QOBJECT(qbool_from_int(
|
|
||||||
rule->options.inject.once)));
|
|
||||||
qdict_put_obj(inject_error, "immediately",
|
|
||||||
QOBJECT(qbool_from_int(
|
|
||||||
rule->options.inject.immediately)));
|
|
||||||
|
|
||||||
if (!inject_error_list) {
|
|
||||||
inject_error_list = qlist_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
qlist_append_obj(inject_error_list, QOBJECT(inject_error));
|
|
||||||
} else if (rule->action == ACTION_SET_STATE) {
|
|
||||||
QDict *set_state = qdict_new();
|
|
||||||
|
|
||||||
qdict_put_obj(set_state, "event", QOBJECT(qstring_from_str(
|
|
||||||
BlkdebugEvent_lookup[rule->event])));
|
|
||||||
qdict_put_obj(set_state, "state",
|
|
||||||
QOBJECT(qint_from_int(rule->state)));
|
|
||||||
qdict_put_obj(set_state, "new_state", QOBJECT(qint_from_int(
|
|
||||||
rule->options.set_state.new_state)));
|
|
||||||
|
|
||||||
if (!set_state_list) {
|
|
||||||
set_state_list = qlist_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
qlist_append_obj(set_state_list, QOBJECT(set_state));
|
|
||||||
} else if (rule->action == ACTION_SUSPEND) {
|
|
||||||
QDict *suspend = qdict_new();
|
|
||||||
|
|
||||||
qdict_put_obj(suspend, "event", QOBJECT(qstring_from_str(
|
|
||||||
BlkdebugEvent_lookup[rule->event])));
|
|
||||||
qdict_put_obj(suspend, "state",
|
|
||||||
QOBJECT(qint_from_int(rule->state)));
|
|
||||||
qdict_put_obj(suspend, "tag", QOBJECT(qstring_from_str(
|
|
||||||
rule->options.suspend.tag)));
|
|
||||||
|
|
||||||
if (!suspend_list) {
|
|
||||||
suspend_list = qlist_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
qlist_append_obj(suspend_list, QOBJECT(suspend));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inject_error_list) {
|
|
||||||
qdict_put_obj(opts, "inject-error", QOBJECT(inject_error_list));
|
|
||||||
}
|
|
||||||
if (set_state_list) {
|
|
||||||
qdict_put_obj(opts, "set-state", QOBJECT(set_state_list));
|
|
||||||
}
|
|
||||||
if (suspend_list) {
|
|
||||||
qdict_put_obj(opts, "suspend", QOBJECT(suspend_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
bs->full_open_options = opts;
|
bs->full_open_options = opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -260,9 +260,6 @@ int blk_attach_dev(BlockBackend *blk, void *dev)
|
|||||||
blk_ref(blk);
|
blk_ref(blk);
|
||||||
blk->dev = dev;
|
blk->dev = dev;
|
||||||
bdrv_iostatus_reset(blk->bs);
|
bdrv_iostatus_reset(blk->bs);
|
||||||
|
|
||||||
/* We're expecting I/O from the device so bump up coroutine pool size */
|
|
||||||
qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +287,6 @@ void blk_detach_dev(BlockBackend *blk, void *dev)
|
|||||||
blk->dev_ops = NULL;
|
blk->dev_ops = NULL;
|
||||||
blk->dev_opaque = NULL;
|
blk->dev_opaque = NULL;
|
||||||
bdrv_set_guest_block_size(blk->bs, 512);
|
bdrv_set_guest_block_size(blk->bs, 512);
|
||||||
qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
|
|
||||||
blk_unref(blk);
|
blk_unref(blk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,6 +493,16 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
|||||||
return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque);
|
return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
|
||||||
|
{
|
||||||
|
return bdrv_co_discard(blk->bs, sector_num, nb_sectors);
|
||||||
|
}
|
||||||
|
|
||||||
|
int blk_co_flush(BlockBackend *blk)
|
||||||
|
{
|
||||||
|
return bdrv_co_flush(blk->bs);
|
||||||
|
}
|
||||||
|
|
||||||
int blk_flush(BlockBackend *blk)
|
int blk_flush(BlockBackend *blk)
|
||||||
{
|
{
|
||||||
return bdrv_flush(blk->bs);
|
return bdrv_flush(blk->bs);
|
||||||
@@ -549,6 +555,11 @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
|
|||||||
bdrv_set_enable_write_cache(blk->bs, wce);
|
bdrv_set_enable_write_cache(blk->bs, wce);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void blk_invalidate_cache(BlockBackend *blk, Error **errp)
|
||||||
|
{
|
||||||
|
bdrv_invalidate_cache(blk->bs, errp);
|
||||||
|
}
|
||||||
|
|
||||||
int blk_is_inserted(BlockBackend *blk)
|
int blk_is_inserted(BlockBackend *blk)
|
||||||
{
|
{
|
||||||
return bdrv_is_inserted(blk->bs);
|
return bdrv_is_inserted(blk->bs);
|
||||||
@@ -609,6 +620,29 @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
|
|||||||
bdrv_set_aio_context(blk->bs, new_context);
|
bdrv_set_aio_context(blk->bs, new_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void blk_add_aio_context_notifier(BlockBackend *blk,
|
||||||
|
void (*attached_aio_context)(AioContext *new_context, void *opaque),
|
||||||
|
void (*detach_aio_context)(void *opaque), void *opaque)
|
||||||
|
{
|
||||||
|
bdrv_add_aio_context_notifier(blk->bs, attached_aio_context,
|
||||||
|
detach_aio_context, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blk_remove_aio_context_notifier(BlockBackend *blk,
|
||||||
|
void (*attached_aio_context)(AioContext *,
|
||||||
|
void *),
|
||||||
|
void (*detach_aio_context)(void *),
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
bdrv_remove_aio_context_notifier(blk->bs, attached_aio_context,
|
||||||
|
detach_aio_context, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blk_add_close_notifier(BlockBackend *blk, Notifier *notify)
|
||||||
|
{
|
||||||
|
bdrv_add_close_notifier(blk->bs, notify);
|
||||||
|
}
|
||||||
|
|
||||||
void blk_io_plug(BlockBackend *blk)
|
void blk_io_plug(BlockBackend *blk)
|
||||||
{
|
{
|
||||||
bdrv_io_plug(blk->bs);
|
bdrv_io_plug(blk->bs);
|
||||||
|
@@ -35,14 +35,14 @@ struct qemu_laiocb {
|
|||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
bool is_read;
|
bool is_read;
|
||||||
QLIST_ENTRY(qemu_laiocb) node;
|
QSIMPLEQ_ENTRY(qemu_laiocb) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct iocb *iocbs[MAX_QUEUED_IO];
|
|
||||||
int plugged;
|
int plugged;
|
||||||
unsigned int size;
|
unsigned int n;
|
||||||
unsigned int idx;
|
bool blocked;
|
||||||
|
QSIMPLEQ_HEAD(, qemu_laiocb) pending;
|
||||||
} LaioQueue;
|
} LaioQueue;
|
||||||
|
|
||||||
struct qemu_laio_state {
|
struct qemu_laio_state {
|
||||||
@@ -59,6 +59,8 @@ struct qemu_laio_state {
|
|||||||
int event_max;
|
int event_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void ioq_submit(struct qemu_laio_state *s);
|
||||||
|
|
||||||
static inline ssize_t io_event_ret(struct io_event *ev)
|
static inline ssize_t io_event_ret(struct io_event *ev)
|
||||||
{
|
{
|
||||||
return (ssize_t)(((uint64_t)ev->res2 << 32) | ev->res);
|
return (ssize_t)(((uint64_t)ev->res2 << 32) | ev->res);
|
||||||
@@ -135,6 +137,10 @@ static void qemu_laio_completion_bh(void *opaque)
|
|||||||
|
|
||||||
qemu_laio_process_completion(s, laiocb);
|
qemu_laio_process_completion(s, laiocb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
|
||||||
|
ioq_submit(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_laio_completion_cb(EventNotifier *e)
|
static void qemu_laio_completion_cb(EventNotifier *e)
|
||||||
@@ -172,50 +178,41 @@ static const AIOCBInfo laio_aiocb_info = {
|
|||||||
|
|
||||||
static void ioq_init(LaioQueue *io_q)
|
static void ioq_init(LaioQueue *io_q)
|
||||||
{
|
{
|
||||||
io_q->size = MAX_QUEUED_IO;
|
QSIMPLEQ_INIT(&io_q->pending);
|
||||||
io_q->idx = 0;
|
|
||||||
io_q->plugged = 0;
|
io_q->plugged = 0;
|
||||||
|
io_q->n = 0;
|
||||||
|
io_q->blocked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioq_submit(struct qemu_laio_state *s)
|
static void ioq_submit(struct qemu_laio_state *s)
|
||||||
{
|
{
|
||||||
int ret, i = 0;
|
int ret, len;
|
||||||
int len = s->io_q.idx;
|
struct qemu_laiocb *aiocb;
|
||||||
|
struct iocb *iocbs[MAX_QUEUED_IO];
|
||||||
|
QSIMPLEQ_HEAD(, qemu_laiocb) completed;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = io_submit(s->ctx, len, s->io_q.iocbs);
|
len = 0;
|
||||||
} while (i++ < 3 && ret == -EAGAIN);
|
QSIMPLEQ_FOREACH(aiocb, &s->io_q.pending, next) {
|
||||||
|
iocbs[len++] = &aiocb->iocb;
|
||||||
|
if (len == MAX_QUEUED_IO) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* empty io queue */
|
ret = io_submit(s->ctx, len, iocbs);
|
||||||
s->io_q.idx = 0;
|
if (ret == -EAGAIN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
if (ret < 0) {
|
s->io_q.n -= ret;
|
||||||
i = 0;
|
aiocb = container_of(iocbs[ret - 1], struct qemu_laiocb, iocb);
|
||||||
} else {
|
QSIMPLEQ_SPLIT_AFTER(&s->io_q.pending, aiocb, next, &completed);
|
||||||
i = ret;
|
} while (ret == len && !QSIMPLEQ_EMPTY(&s->io_q.pending));
|
||||||
}
|
s->io_q.blocked = (s->io_q.n > 0);
|
||||||
|
|
||||||
for (; i < len; i++) {
|
|
||||||
struct qemu_laiocb *laiocb =
|
|
||||||
container_of(s->io_q.iocbs[i], struct qemu_laiocb, iocb);
|
|
||||||
|
|
||||||
laiocb->ret = (ret < 0) ? ret : -EIO;
|
|
||||||
qemu_laio_process_completion(s, laiocb);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ioq_enqueue(struct qemu_laio_state *s, struct iocb *iocb)
|
|
||||||
{
|
|
||||||
unsigned int idx = s->io_q.idx;
|
|
||||||
|
|
||||||
s->io_q.iocbs[idx++] = iocb;
|
|
||||||
s->io_q.idx = idx;
|
|
||||||
|
|
||||||
/* submit immediately if queue is full */
|
|
||||||
if (idx == s->io_q.size) {
|
|
||||||
ioq_submit(s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
|
void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
|
||||||
@@ -225,22 +222,19 @@ void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
|
|||||||
s->io_q.plugged++;
|
s->io_q.plugged++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug)
|
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug)
|
||||||
{
|
{
|
||||||
struct qemu_laio_state *s = aio_ctx;
|
struct qemu_laio_state *s = aio_ctx;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
assert(s->io_q.plugged > 0 || !unplug);
|
assert(s->io_q.plugged > 0 || !unplug);
|
||||||
|
|
||||||
if (unplug && --s->io_q.plugged > 0) {
|
if (unplug && --s->io_q.plugged > 0) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->io_q.idx > 0) {
|
if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
|
||||||
ret = ioq_submit(s);
|
ioq_submit(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||||
@@ -276,12 +270,11 @@ BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
|||||||
}
|
}
|
||||||
io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
|
io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
|
||||||
|
|
||||||
if (!s->io_q.plugged) {
|
QSIMPLEQ_INSERT_TAIL(&s->io_q.pending, laiocb, next);
|
||||||
if (io_submit(s->ctx, 1, &iocbs) < 0) {
|
s->io_q.n++;
|
||||||
goto out_free_aiocb;
|
if (!s->io_q.blocked &&
|
||||||
}
|
(!s->io_q.plugged || s->io_q.n >= MAX_QUEUED_IO)) {
|
||||||
} else {
|
ioq_submit(s);
|
||||||
ioq_enqueue(s, iocbs);
|
|
||||||
}
|
}
|
||||||
return &laiocb->common;
|
return &laiocb->common;
|
||||||
|
|
||||||
|
@@ -128,7 +128,8 @@ static void mirror_write_complete(void *opaque, int ret)
|
|||||||
BlockDriverState *source = s->common.bs;
|
BlockDriverState *source = s->common.bs;
|
||||||
BlockErrorAction action;
|
BlockErrorAction action;
|
||||||
|
|
||||||
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
|
bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
|
||||||
|
op->nb_sectors);
|
||||||
action = mirror_error_action(s, false, -ret);
|
action = mirror_error_action(s, false, -ret);
|
||||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||||
s->ret = ret;
|
s->ret = ret;
|
||||||
@@ -145,7 +146,8 @@ static void mirror_read_complete(void *opaque, int ret)
|
|||||||
BlockDriverState *source = s->common.bs;
|
BlockDriverState *source = s->common.bs;
|
||||||
BlockErrorAction action;
|
BlockErrorAction action;
|
||||||
|
|
||||||
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
|
bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
|
||||||
|
op->nb_sectors);
|
||||||
action = mirror_error_action(s, true, -ret);
|
action = mirror_error_action(s, true, -ret);
|
||||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||||
s->ret = ret;
|
s->ret = ret;
|
||||||
@@ -286,7 +288,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
next_sector += sectors_per_chunk;
|
next_sector += sectors_per_chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_reset_dirty(source, sector_num, nb_sectors);
|
bdrv_reset_dirty_bitmap(source, s->dirty_bitmap, sector_num,
|
||||||
|
nb_sectors);
|
||||||
|
|
||||||
/* Copy the dirty cluster. */
|
/* Copy the dirty cluster. */
|
||||||
s->in_flight++;
|
s->in_flight++;
|
||||||
@@ -442,7 +445,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
|
|
||||||
assert(n > 0);
|
assert(n > 0);
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
bdrv_set_dirty(bs, sector_num, n);
|
bdrv_set_dirty_bitmap(bs, s->dirty_bitmap, sector_num, n);
|
||||||
sector_num = next;
|
sector_num = next;
|
||||||
} else {
|
} else {
|
||||||
sector_num += n;
|
sector_num += n;
|
||||||
|
39
block/qapi.c
39
block/qapi.c
@@ -40,6 +40,13 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
|||||||
info->encrypted = bs->encrypted;
|
info->encrypted = bs->encrypted;
|
||||||
info->encryption_key_missing = bdrv_key_required(bs);
|
info->encryption_key_missing = bdrv_key_required(bs);
|
||||||
|
|
||||||
|
info->cache = g_new(BlockdevCacheInfo, 1);
|
||||||
|
*info->cache = (BlockdevCacheInfo) {
|
||||||
|
.writeback = bdrv_enable_write_cache(bs),
|
||||||
|
.direct = !!(bs->open_flags & BDRV_O_NOCACHE),
|
||||||
|
.no_flush = !!(bs->open_flags & BDRV_O_NO_FLUSH),
|
||||||
|
};
|
||||||
|
|
||||||
if (bs->node_name[0]) {
|
if (bs->node_name[0]) {
|
||||||
info->has_node_name = true;
|
info->has_node_name = true;
|
||||||
info->node_name = g_strdup(bs->node_name);
|
info->node_name = g_strdup(bs->node_name);
|
||||||
@@ -207,7 +214,12 @@ void bdrv_query_image_info(BlockDriverState *bs,
|
|||||||
info->backing_filename = g_strdup(backing_filename);
|
info->backing_filename = g_strdup(backing_filename);
|
||||||
info->has_backing_filename = true;
|
info->has_backing_filename = true;
|
||||||
bdrv_get_full_backing_filename(bs, backing_filename2,
|
bdrv_get_full_backing_filename(bs, backing_filename2,
|
||||||
sizeof(backing_filename2));
|
sizeof(backing_filename2), &err);
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
qapi_free_ImageInfo(info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(backing_filename, backing_filename2) != 0) {
|
if (strcmp(backing_filename, backing_filename2) != 0) {
|
||||||
info->full_backing_filename =
|
info->full_backing_filename =
|
||||||
@@ -300,7 +312,8 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
|||||||
qapi_free_BlockInfo(info);
|
qapi_free_BlockInfo(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
static BlockStats *bdrv_query_stats(const BlockDriverState *bs,
|
||||||
|
bool query_backing)
|
||||||
{
|
{
|
||||||
BlockStats *s;
|
BlockStats *s;
|
||||||
|
|
||||||
@@ -311,6 +324,11 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
|||||||
s->device = g_strdup(bdrv_get_device_name(bs));
|
s->device = g_strdup(bdrv_get_device_name(bs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bdrv_get_node_name(bs)[0]) {
|
||||||
|
s->has_node_name = true;
|
||||||
|
s->node_name = g_strdup(bdrv_get_node_name(bs));
|
||||||
|
}
|
||||||
|
|
||||||
s->stats = g_malloc0(sizeof(*s->stats));
|
s->stats = g_malloc0(sizeof(*s->stats));
|
||||||
s->stats->rd_bytes = bs->stats.nr_bytes[BLOCK_ACCT_READ];
|
s->stats->rd_bytes = bs->stats.nr_bytes[BLOCK_ACCT_READ];
|
||||||
s->stats->wr_bytes = bs->stats.nr_bytes[BLOCK_ACCT_WRITE];
|
s->stats->wr_bytes = bs->stats.nr_bytes[BLOCK_ACCT_WRITE];
|
||||||
@@ -325,12 +343,12 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
|||||||
|
|
||||||
if (bs->file) {
|
if (bs->file) {
|
||||||
s->has_parent = true;
|
s->has_parent = true;
|
||||||
s->parent = bdrv_query_stats(bs->file);
|
s->parent = bdrv_query_stats(bs->file, query_backing);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->backing_hd) {
|
if (query_backing && bs->backing_hd) {
|
||||||
s->has_backing = true;
|
s->has_backing = true;
|
||||||
s->backing = bdrv_query_stats(bs->backing_hd);
|
s->backing = bdrv_query_stats(bs->backing_hd, query_backing);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
@@ -361,17 +379,22 @@ BlockInfoList *qmp_query_block(Error **errp)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockStatsList *qmp_query_blockstats(Error **errp)
|
BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
|
||||||
|
bool query_nodes,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
BlockStatsList *head = NULL, **p_next = &head;
|
BlockStatsList *head = NULL, **p_next = &head;
|
||||||
BlockDriverState *bs = NULL;
|
BlockDriverState *bs = NULL;
|
||||||
|
|
||||||
while ((bs = bdrv_next(bs))) {
|
/* Just to be safe if query_nodes is not always initialized */
|
||||||
|
query_nodes = has_query_nodes && query_nodes;
|
||||||
|
|
||||||
|
while ((bs = query_nodes ? bdrv_next_node(bs) : bdrv_next(bs))) {
|
||||||
BlockStatsList *info = g_malloc0(sizeof(*info));
|
BlockStatsList *info = g_malloc0(sizeof(*info));
|
||||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||||
|
|
||||||
aio_context_acquire(ctx);
|
aio_context_acquire(ctx);
|
||||||
info->value = bdrv_query_stats(bs);
|
info->value = bdrv_query_stats(bs, !query_nodes);
|
||||||
aio_context_release(ctx);
|
aio_context_release(ctx);
|
||||||
|
|
||||||
*p_next = info;
|
*p_next = info;
|
||||||
|
@@ -41,7 +41,7 @@ BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
|||||||
void laio_detach_aio_context(void *s, AioContext *old_context);
|
void laio_detach_aio_context(void *s, AioContext *old_context);
|
||||||
void laio_attach_aio_context(void *s, AioContext *new_context);
|
void laio_attach_aio_context(void *s, AioContext *new_context);
|
||||||
void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
|
void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
|
||||||
int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug);
|
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@@ -1923,7 +1923,7 @@ static int fd_open(BlockDriverState *bs)
|
|||||||
return 0;
|
return 0;
|
||||||
last_media_present = (s->fd >= 0);
|
last_media_present = (s->fd >= 0);
|
||||||
if (s->fd >= 0 &&
|
if (s->fd >= 0 &&
|
||||||
(get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
|
(qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
|
||||||
qemu_close(s->fd);
|
qemu_close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
#ifdef DEBUG_FLOPPY
|
#ifdef DEBUG_FLOPPY
|
||||||
@@ -1932,7 +1932,7 @@ static int fd_open(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
if (s->fd < 0) {
|
if (s->fd < 0) {
|
||||||
if (s->fd_got_error &&
|
if (s->fd_got_error &&
|
||||||
(get_clock() - s->fd_error_time) < FD_OPEN_TIMEOUT) {
|
(qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
|
||||||
#ifdef DEBUG_FLOPPY
|
#ifdef DEBUG_FLOPPY
|
||||||
printf("No floppy (open delayed)\n");
|
printf("No floppy (open delayed)\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -1940,7 +1940,7 @@ static int fd_open(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
s->fd = qemu_open(bs->filename, s->open_flags & ~O_NONBLOCK);
|
s->fd = qemu_open(bs->filename, s->open_flags & ~O_NONBLOCK);
|
||||||
if (s->fd < 0) {
|
if (s->fd < 0) {
|
||||||
s->fd_error_time = get_clock();
|
s->fd_error_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||||
s->fd_got_error = 1;
|
s->fd_got_error = 1;
|
||||||
if (last_media_present)
|
if (last_media_present)
|
||||||
s->fd_media_changed = 1;
|
s->fd_media_changed = 1;
|
||||||
@@ -1955,7 +1955,7 @@ static int fd_open(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
if (!last_media_present)
|
if (!last_media_present)
|
||||||
s->fd_media_changed = 1;
|
s->fd_media_changed = 1;
|
||||||
s->fd_open_time = get_clock();
|
s->fd_open_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||||
s->fd_got_error = 0;
|
s->fd_got_error = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -58,8 +58,58 @@ static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
|
static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors, QEMUIOVector *qiov)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
|
void *buf = NULL;
|
||||||
|
BlockDriver *drv;
|
||||||
|
QEMUIOVector local_qiov;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (bs->probed && sector_num == 0) {
|
||||||
|
/* As long as these conditions are true, we can't get partial writes to
|
||||||
|
* the probe buffer and can just directly check the request. */
|
||||||
|
QEMU_BUILD_BUG_ON(BLOCK_PROBE_BUF_SIZE != 512);
|
||||||
|
QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != 512);
|
||||||
|
|
||||||
|
if (nb_sectors == 0) {
|
||||||
|
/* qemu_iovec_to_buf() would fail, but we want to return success
|
||||||
|
* instead of -EINVAL in this case. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = qemu_try_blockalign(bs->file, 512);
|
||||||
|
if (!buf) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qemu_iovec_to_buf(qiov, 0, buf, 512);
|
||||||
|
if (ret != 512) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv = bdrv_probe_all(buf, 512, NULL);
|
||||||
|
if (drv != bs->drv) {
|
||||||
|
ret = -EPERM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the checked buffer, a malicious guest might be overwriting its
|
||||||
|
* original buffer in the background. */
|
||||||
|
qemu_iovec_init(&local_qiov, qiov->niov + 1);
|
||||||
|
qemu_iovec_add(&local_qiov, buf, 512);
|
||||||
|
qemu_iovec_concat(&local_qiov, qiov, 512, qiov->size - 512);
|
||||||
|
qiov = &local_qiov;
|
||||||
|
}
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||||
return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
|
ret = bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (qiov == &local_qiov) {
|
||||||
|
qemu_iovec_destroy(&local_qiov);
|
||||||
|
}
|
||||||
|
qemu_vfree(buf);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||||
@@ -158,6 +208,18 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
bs->sg = bs->file->sg;
|
bs->sg = bs->file->sg;
|
||||||
|
|
||||||
|
if (bs->probed && !bdrv_is_read_only(bs)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: Image format was not specified for '%s' and probing "
|
||||||
|
"guessed raw.\n"
|
||||||
|
" Automatically detecting the format is dangerous for "
|
||||||
|
"raw images, write operations on block 0 will be restricted.\n"
|
||||||
|
" Specify the 'raw' format explicitly to remove the "
|
||||||
|
"restrictions.\n",
|
||||||
|
bs->file->filename);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -459,7 +459,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
|
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
|
||||||
r = rados_create(&s->cluster, clientname);
|
r = rados_create(&s->cluster, clientname);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
error_setg(&local_err, "error initializing");
|
error_setg(errp, "error initializing");
|
||||||
goto failed_opts;
|
goto failed_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,19 +495,19 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
r = rados_connect(s->cluster);
|
r = rados_connect(s->cluster);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
error_setg(&local_err, "error connecting");
|
error_setg(errp, "error connecting");
|
||||||
goto failed_shutdown;
|
goto failed_shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
|
r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
error_setg(&local_err, "error opening pool %s", pool);
|
error_setg(errp, "error opening pool %s", pool);
|
||||||
goto failed_shutdown;
|
goto failed_shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
|
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
error_setg(&local_err, "error reading header from %s", s->name);
|
error_setg(errp, "error reading header from %s", s->name);
|
||||||
goto failed_open;
|
goto failed_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -852,11 +852,6 @@ static QemuOptsList vdi_create_opts = {
|
|||||||
.def_value_str = "off"
|
.def_value_str = "off"
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
.name = BLOCK_OPT_NOCOW,
|
|
||||||
.type = QEMU_OPT_BOOL,
|
|
||||||
.help = "Turn off copy-on-write (valid only on btrfs)"
|
|
||||||
},
|
|
||||||
/* TODO: An additional option to set UUID values might be useful. */
|
/* TODO: An additional option to set UUID values might be useful. */
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
}
|
}
|
||||||
|
18
block/vhdx.c
18
block/vhdx.c
@@ -1109,8 +1109,9 @@ static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
/* check the payload block state */
|
/* check the payload block state */
|
||||||
switch (s->bat[sinfo.bat_idx] & VHDX_BAT_STATE_BIT_MASK) {
|
switch (s->bat[sinfo.bat_idx] & VHDX_BAT_STATE_BIT_MASK) {
|
||||||
case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
|
case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
|
||||||
case PAYLOAD_BLOCK_UNDEFINED: /* fall through */
|
case PAYLOAD_BLOCK_UNDEFINED:
|
||||||
case PAYLOAD_BLOCK_UNMAPPED: /* fall through */
|
case PAYLOAD_BLOCK_UNMAPPED:
|
||||||
|
case PAYLOAD_BLOCK_UNMAPPED_v095:
|
||||||
case PAYLOAD_BLOCK_ZERO:
|
case PAYLOAD_BLOCK_ZERO:
|
||||||
/* return zero */
|
/* return zero */
|
||||||
qemu_iovec_memset(&hd_qiov, 0, 0, sinfo.bytes_avail);
|
qemu_iovec_memset(&hd_qiov, 0, 0, sinfo.bytes_avail);
|
||||||
@@ -1277,11 +1278,11 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
sectors_to_write += iov2.iov_len >> BDRV_SECTOR_BITS;
|
sectors_to_write += iov2.iov_len >> BDRV_SECTOR_BITS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
|
case PAYLOAD_BLOCK_NOT_PRESENT: /* fall through */
|
||||||
case PAYLOAD_BLOCK_UNMAPPED: /* fall through */
|
case PAYLOAD_BLOCK_UNMAPPED:
|
||||||
case PAYLOAD_BLOCK_UNDEFINED: /* fall through */
|
case PAYLOAD_BLOCK_UNMAPPED_v095:
|
||||||
|
case PAYLOAD_BLOCK_UNDEFINED:
|
||||||
bat_prior_offset = sinfo.file_offset;
|
bat_prior_offset = sinfo.file_offset;
|
||||||
ret = vhdx_allocate_block(bs, s, &sinfo.file_offset);
|
ret = vhdx_allocate_block(bs, s, &sinfo.file_offset);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1773,7 +1774,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0);
|
log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0);
|
||||||
block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0);
|
block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0);
|
||||||
type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
|
type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
|
||||||
use_zero_blocks = qemu_opt_get_bool_del(opts, VHDX_BLOCK_OPT_ZERO, false);
|
use_zero_blocks = qemu_opt_get_bool_del(opts, VHDX_BLOCK_OPT_ZERO, true);
|
||||||
|
|
||||||
if (image_size > VHDX_MAX_IMAGE_SIZE) {
|
if (image_size > VHDX_MAX_IMAGE_SIZE) {
|
||||||
error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB");
|
error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB");
|
||||||
@@ -1935,7 +1936,9 @@ static QemuOptsList vhdx_create_opts = {
|
|||||||
{
|
{
|
||||||
.name = VHDX_BLOCK_OPT_ZERO,
|
.name = VHDX_BLOCK_OPT_ZERO,
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
.help = "Force use of payload blocks of type 'ZERO'. Non-standard."
|
.help = "Force use of payload blocks of type 'ZERO'. "\
|
||||||
|
"Non-standard, but default. Do not set to 'off' when "\
|
||||||
|
"using 'qemu-img convert' with subformat=dynamic."
|
||||||
},
|
},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
}
|
}
|
||||||
@@ -1953,6 +1956,7 @@ static BlockDriver bdrv_vhdx = {
|
|||||||
.bdrv_create = vhdx_create,
|
.bdrv_create = vhdx_create,
|
||||||
.bdrv_get_info = vhdx_get_info,
|
.bdrv_get_info = vhdx_get_info,
|
||||||
.bdrv_check = vhdx_check,
|
.bdrv_check = vhdx_check,
|
||||||
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||||
|
|
||||||
.create_opts = &vhdx_create_opts,
|
.create_opts = &vhdx_create_opts,
|
||||||
};
|
};
|
||||||
|
@@ -226,7 +226,8 @@ typedef struct QEMU_PACKED VHDXLogDataSector {
|
|||||||
#define PAYLOAD_BLOCK_NOT_PRESENT 0
|
#define PAYLOAD_BLOCK_NOT_PRESENT 0
|
||||||
#define PAYLOAD_BLOCK_UNDEFINED 1
|
#define PAYLOAD_BLOCK_UNDEFINED 1
|
||||||
#define PAYLOAD_BLOCK_ZERO 2
|
#define PAYLOAD_BLOCK_ZERO 2
|
||||||
#define PAYLOAD_BLOCK_UNMAPPED 5
|
#define PAYLOAD_BLOCK_UNMAPPED 3
|
||||||
|
#define PAYLOAD_BLOCK_UNMAPPED_v095 5
|
||||||
#define PAYLOAD_BLOCK_FULLY_PRESENT 6
|
#define PAYLOAD_BLOCK_FULLY_PRESENT 6
|
||||||
#define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
|
#define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
|
||||||
|
|
||||||
|
52
block/vmdk.c
52
block/vmdk.c
@@ -28,6 +28,7 @@
|
|||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "migration/migration.h"
|
#include "migration/migration.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
||||||
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
|
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
|
||||||
@@ -556,8 +557,16 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = MIN(size, 1 << 20); /* avoid unbounded allocation */
|
if (size < 4) {
|
||||||
buf = g_malloc0(size + 1);
|
/* Both descriptor file and sparse image must be much larger than 4
|
||||||
|
* bytes, also callers of vmdk_read_desc want to compare the first 4
|
||||||
|
* bytes with VMDK4_MAGIC, let's error out if less is read. */
|
||||||
|
error_setg(errp, "File is too small, not a valid image");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */
|
||||||
|
buf = g_malloc(size + 1);
|
||||||
|
|
||||||
ret = bdrv_pread(file, desc_offset, buf, size);
|
ret = bdrv_pread(file, desc_offset, buf, size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -565,6 +574,7 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
|
|||||||
g_free(buf);
|
g_free(buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
buf[ret] = 0;
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@@ -635,6 +645,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
bs->file->total_sectors * 512 - 1536,
|
bs->file->total_sectors * 512 - 1536,
|
||||||
&footer, sizeof(footer));
|
&footer, sizeof(footer));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Failed to read footer");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,6 +657,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
le32_to_cpu(footer.eos_marker.size) != 0 ||
|
le32_to_cpu(footer.eos_marker.size) != 0 ||
|
||||||
le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM)
|
le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM)
|
||||||
{
|
{
|
||||||
|
error_setg(errp, "Invalid footer");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,6 +688,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt)
|
l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt)
|
||||||
* le64_to_cpu(header.granularity);
|
* le64_to_cpu(header.granularity);
|
||||||
if (l1_entry_sectors == 0) {
|
if (l1_entry_sectors == 0) {
|
||||||
|
error_setg(errp, "L1 entry size is invalid");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
|
l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
|
||||||
@@ -784,10 +797,12 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
|||||||
VmdkExtent *extent;
|
VmdkExtent *extent;
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
/* parse extent line:
|
/* parse extent line in one of below formats:
|
||||||
|
*
|
||||||
* RW [size in sectors] FLAT "file-name.vmdk" OFFSET
|
* RW [size in sectors] FLAT "file-name.vmdk" OFFSET
|
||||||
* or
|
|
||||||
* RW [size in sectors] SPARSE "file-name.vmdk"
|
* RW [size in sectors] SPARSE "file-name.vmdk"
|
||||||
|
* RW [size in sectors] VMFS "file-name.vmdk"
|
||||||
|
* RW [size in sectors] VMFSSPARSE "file-name.vmdk"
|
||||||
*/
|
*/
|
||||||
flat_offset = -1;
|
flat_offset = -1;
|
||||||
ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64,
|
ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64,
|
||||||
@@ -818,6 +833,14 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
|||||||
goto next_line;
|
goto next_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!path_is_absolute(fname) && !path_has_protocol(fname) &&
|
||||||
|
!desc_file_path[0])
|
||||||
|
{
|
||||||
|
error_setg(errp, "Cannot use relative extent paths with VMDK "
|
||||||
|
"descriptor file '%s'", bs->file->filename);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
path_combine(extent_path, sizeof(extent_path),
|
path_combine(extent_path, sizeof(extent_path),
|
||||||
desc_file_path, fname);
|
desc_file_path, fname);
|
||||||
extent_file = NULL;
|
extent_file = NULL;
|
||||||
@@ -894,7 +917,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
|
|||||||
}
|
}
|
||||||
s->create_type = g_strdup(ct);
|
s->create_type = g_strdup(ct);
|
||||||
s->desc_offset = 0;
|
s->desc_offset = 0;
|
||||||
ret = vmdk_parse_extents(buf, bs, bs->file->filename, errp);
|
ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, errp);
|
||||||
exit:
|
exit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -902,7 +925,7 @@ exit:
|
|||||||
static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
char *buf = NULL;
|
char *buf;
|
||||||
int ret;
|
int ret;
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
@@ -1538,7 +1561,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
/* update CID on the first write every time the virtual disk is
|
/* update CID on the first write every time the virtual disk is
|
||||||
* opened */
|
* opened */
|
||||||
if (!s->cid_updated) {
|
if (!s->cid_updated) {
|
||||||
ret = vmdk_write_cid(bs, time(NULL));
|
ret = vmdk_write_cid(bs, g_random_int());
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1868,8 +1891,19 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
}
|
}
|
||||||
if (backing_file) {
|
if (backing_file) {
|
||||||
BlockDriverState *bs = NULL;
|
BlockDriverState *bs = NULL;
|
||||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_NO_BACKING, NULL,
|
char *full_backing = g_new0(char, PATH_MAX);
|
||||||
|
bdrv_get_full_backing_filename_from_filename(filename, backing_file,
|
||||||
|
full_backing, PATH_MAX,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
g_free(full_backing);
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
ret = bdrv_open(&bs, full_backing, NULL, NULL, BDRV_O_NO_BACKING, NULL,
|
||||||
errp);
|
errp);
|
||||||
|
g_free(full_backing);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -1922,7 +1956,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
}
|
}
|
||||||
/* generate descriptor file */
|
/* generate descriptor file */
|
||||||
desc = g_strdup_printf(desc_template,
|
desc = g_strdup_printf(desc_template,
|
||||||
(uint32_t)time(NULL),
|
g_random_int(),
|
||||||
parent_cid,
|
parent_cid,
|
||||||
fmt,
|
fmt,
|
||||||
parent_desc_line,
|
parent_desc_line,
|
||||||
|
15
block/vpc.c
15
block/vpc.c
@@ -801,7 +801,6 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
|
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
|
||||||
total_size = total_sectors * BDRV_SECTOR_SIZE;
|
|
||||||
|
|
||||||
/* Prepare the Hard Disk Footer */
|
/* Prepare the Hard Disk Footer */
|
||||||
memset(buf, 0, 1024);
|
memset(buf, 0, 1024);
|
||||||
@@ -823,8 +822,13 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||||||
/* Version of Virtual PC 2007 */
|
/* Version of Virtual PC 2007 */
|
||||||
footer->major = cpu_to_be16(0x0005);
|
footer->major = cpu_to_be16(0x0005);
|
||||||
footer->minor = cpu_to_be16(0x0003);
|
footer->minor = cpu_to_be16(0x0003);
|
||||||
footer->orig_size = cpu_to_be64(total_size);
|
if (disk_type == VHD_DYNAMIC) {
|
||||||
footer->size = cpu_to_be64(total_size);
|
footer->orig_size = cpu_to_be64(total_sectors * 512);
|
||||||
|
footer->size = cpu_to_be64(total_sectors * 512);
|
||||||
|
} else {
|
||||||
|
footer->orig_size = cpu_to_be64(total_size);
|
||||||
|
footer->size = cpu_to_be64(total_size);
|
||||||
|
}
|
||||||
footer->cyls = cpu_to_be16(cyls);
|
footer->cyls = cpu_to_be16(cyls);
|
||||||
footer->heads = heads;
|
footer->heads = heads;
|
||||||
footer->secs_per_cyl = secs_per_cyl;
|
footer->secs_per_cyl = secs_per_cyl;
|
||||||
@@ -889,11 +893,6 @@ static QemuOptsList vpc_create_opts = {
|
|||||||
"Type of virtual hard disk format. Supported formats are "
|
"Type of virtual hard disk format. Supported formats are "
|
||||||
"{dynamic (default) | fixed} "
|
"{dynamic (default) | fixed} "
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = BLOCK_OPT_NOCOW,
|
|
||||||
.type = QEMU_OPT_BOOL,
|
|
||||||
.help = "Turn off copy-on-write (valid only on btrfs)"
|
|
||||||
},
|
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
|
#include "sysemu/block-backend.h"
|
||||||
#include "hw/block/block.h"
|
#include "hw/block/block.h"
|
||||||
#include "monitor/monitor.h"
|
#include "monitor/monitor.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
@@ -73,7 +74,7 @@ static void nbd_close_notifier(Notifier *n, void *data)
|
|||||||
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
BlockBackend *blk;
|
||||||
NBDExport *exp;
|
NBDExport *exp;
|
||||||
NBDCloseNotifier *n;
|
NBDCloseNotifier *n;
|
||||||
|
|
||||||
@@ -87,12 +88,12 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs = bdrv_find(device);
|
blk = blk_by_name(device);
|
||||||
if (!bs) {
|
if (!blk) {
|
||||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!bdrv_is_inserted(bs)) {
|
if (!blk_is_inserted(blk)) {
|
||||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -100,18 +101,18 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
|||||||
if (!has_writable) {
|
if (!has_writable) {
|
||||||
writable = false;
|
writable = false;
|
||||||
}
|
}
|
||||||
if (bdrv_is_read_only(bs)) {
|
if (blk_is_read_only(blk)) {
|
||||||
writable = false;
|
writable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL);
|
exp = nbd_export_new(blk, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL);
|
||||||
|
|
||||||
nbd_export_set_name(exp, device);
|
nbd_export_set_name(exp, device);
|
||||||
|
|
||||||
n = g_new0(NBDCloseNotifier, 1);
|
n = g_new0(NBDCloseNotifier, 1);
|
||||||
n->n.notify = nbd_close_notifier;
|
n->n.notify = nbd_close_notifier;
|
||||||
n->exp = exp;
|
n->exp = exp;
|
||||||
bdrv_add_close_notifier(bs, &n->n);
|
blk_add_close_notifier(blk, &n->n);
|
||||||
QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
|
QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
288
blockdev.c
288
blockdev.c
@@ -1105,6 +1105,7 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = bdrv_find(device);
|
BlockDriverState *bs = bdrv_find(device);
|
||||||
|
AioContext *aio_context;
|
||||||
QEMUSnapshotInfo sn;
|
QEMUSnapshotInfo sn;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
SnapshotInfo *info = NULL;
|
SnapshotInfo *info = NULL;
|
||||||
@@ -1128,25 +1129,34 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, errp)) {
|
||||||
|
goto out_aio_context;
|
||||||
|
}
|
||||||
|
|
||||||
ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
|
ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return NULL;
|
goto out_aio_context;
|
||||||
}
|
}
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"Snapshot with id '%s' and name '%s' does not exist on "
|
"Snapshot with id '%s' and name '%s' does not exist on "
|
||||||
"device '%s'",
|
"device '%s'",
|
||||||
STR_OR_NULL(id), STR_OR_NULL(name), device);
|
STR_OR_NULL(id), STR_OR_NULL(name), device);
|
||||||
return NULL;
|
goto out_aio_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_snapshot_delete(bs, id, name, &local_err);
|
bdrv_snapshot_delete(bs, id, name, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return NULL;
|
goto out_aio_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aio_context_release(aio_context);
|
||||||
|
|
||||||
info = g_new0(SnapshotInfo, 1);
|
info = g_new0(SnapshotInfo, 1);
|
||||||
info->id = g_strdup(sn.id_str);
|
info->id = g_strdup(sn.id_str);
|
||||||
info->name = g_strdup(sn.name);
|
info->name = g_strdup(sn.name);
|
||||||
@@ -1157,9 +1167,13 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
|
|||||||
info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
|
info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
|
||||||
|
out_aio_context:
|
||||||
|
aio_context_release(aio_context);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* New and old BlockDriverState structs for group snapshots */
|
/* New and old BlockDriverState structs for atomic group operations */
|
||||||
|
|
||||||
typedef struct BlkTransactionState BlkTransactionState;
|
typedef struct BlkTransactionState BlkTransactionState;
|
||||||
|
|
||||||
@@ -1193,6 +1207,7 @@ struct BlkTransactionState {
|
|||||||
typedef struct InternalSnapshotState {
|
typedef struct InternalSnapshotState {
|
||||||
BlkTransactionState common;
|
BlkTransactionState common;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
AioContext *aio_context;
|
||||||
QEMUSnapshotInfo sn;
|
QEMUSnapshotInfo sn;
|
||||||
} InternalSnapshotState;
|
} InternalSnapshotState;
|
||||||
|
|
||||||
@@ -1226,11 +1241,19 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* AioContext is released in .clean() */
|
||||||
|
state->aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(state->aio_context);
|
||||||
|
|
||||||
if (!bdrv_is_inserted(bs)) {
|
if (!bdrv_is_inserted(bs)) {
|
||||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (bdrv_is_read_only(bs)) {
|
if (bdrv_is_read_only(bs)) {
|
||||||
error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
|
error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
|
||||||
return;
|
return;
|
||||||
@@ -1303,11 +1326,22 @@ static void internal_snapshot_abort(BlkTransactionState *common)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void internal_snapshot_clean(BlkTransactionState *common)
|
||||||
|
{
|
||||||
|
InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState,
|
||||||
|
common, common);
|
||||||
|
|
||||||
|
if (state->aio_context) {
|
||||||
|
aio_context_release(state->aio_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* external snapshot private data */
|
/* external snapshot private data */
|
||||||
typedef struct ExternalSnapshotState {
|
typedef struct ExternalSnapshotState {
|
||||||
BlkTransactionState common;
|
BlkTransactionState common;
|
||||||
BlockDriverState *old_bs;
|
BlockDriverState *old_bs;
|
||||||
BlockDriverState *new_bs;
|
BlockDriverState *new_bs;
|
||||||
|
AioContext *aio_context;
|
||||||
} ExternalSnapshotState;
|
} ExternalSnapshotState;
|
||||||
|
|
||||||
static void external_snapshot_prepare(BlkTransactionState *common,
|
static void external_snapshot_prepare(BlkTransactionState *common,
|
||||||
@@ -1374,6 +1408,10 @@ static void external_snapshot_prepare(BlkTransactionState *common,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Acquire AioContext now so any threads operating on old_bs stop */
|
||||||
|
state->aio_context = bdrv_get_aio_context(state->old_bs);
|
||||||
|
aio_context_acquire(state->aio_context);
|
||||||
|
|
||||||
if (!bdrv_is_inserted(state->old_bs)) {
|
if (!bdrv_is_inserted(state->old_bs)) {
|
||||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||||
return;
|
return;
|
||||||
@@ -1432,6 +1470,8 @@ static void external_snapshot_commit(BlkTransactionState *common)
|
|||||||
ExternalSnapshotState *state =
|
ExternalSnapshotState *state =
|
||||||
DO_UPCAST(ExternalSnapshotState, common, common);
|
DO_UPCAST(ExternalSnapshotState, common, common);
|
||||||
|
|
||||||
|
bdrv_set_aio_context(state->new_bs, state->aio_context);
|
||||||
|
|
||||||
/* This removes our old bs and adds the new bs */
|
/* This removes our old bs and adds the new bs */
|
||||||
bdrv_append(state->new_bs, state->old_bs);
|
bdrv_append(state->new_bs, state->old_bs);
|
||||||
/* We don't need (or want) to use the transactional
|
/* We don't need (or want) to use the transactional
|
||||||
@@ -1439,6 +1479,8 @@ static void external_snapshot_commit(BlkTransactionState *common)
|
|||||||
* don't want to abort all of them if one of them fails the reopen */
|
* don't want to abort all of them if one of them fails the reopen */
|
||||||
bdrv_reopen(state->new_bs, state->new_bs->open_flags & ~BDRV_O_RDWR,
|
bdrv_reopen(state->new_bs, state->new_bs->open_flags & ~BDRV_O_RDWR,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
aio_context_release(state->aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void external_snapshot_abort(BlkTransactionState *common)
|
static void external_snapshot_abort(BlkTransactionState *common)
|
||||||
@@ -1448,23 +1490,38 @@ static void external_snapshot_abort(BlkTransactionState *common)
|
|||||||
if (state->new_bs) {
|
if (state->new_bs) {
|
||||||
bdrv_unref(state->new_bs);
|
bdrv_unref(state->new_bs);
|
||||||
}
|
}
|
||||||
|
if (state->aio_context) {
|
||||||
|
aio_context_release(state->aio_context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct DriveBackupState {
|
typedef struct DriveBackupState {
|
||||||
BlkTransactionState common;
|
BlkTransactionState common;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
AioContext *aio_context;
|
||||||
BlockJob *job;
|
BlockJob *job;
|
||||||
} DriveBackupState;
|
} DriveBackupState;
|
||||||
|
|
||||||
static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
|
static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
|
||||||
{
|
{
|
||||||
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
||||||
|
BlockDriverState *bs;
|
||||||
DriveBackup *backup;
|
DriveBackup *backup;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
|
assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
|
||||||
backup = common->action->drive_backup;
|
backup = common->action->drive_backup;
|
||||||
|
|
||||||
|
bs = bdrv_find(backup->device);
|
||||||
|
if (!bs) {
|
||||||
|
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AioContext is released in .clean() */
|
||||||
|
state->aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(state->aio_context);
|
||||||
|
|
||||||
qmp_drive_backup(backup->device, backup->target,
|
qmp_drive_backup(backup->device, backup->target,
|
||||||
backup->has_format, backup->format,
|
backup->has_format, backup->format,
|
||||||
backup->sync,
|
backup->sync,
|
||||||
@@ -1475,12 +1532,10 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
|
|||||||
&local_err);
|
&local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
state->bs = NULL;
|
|
||||||
state->job = NULL;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->bs = bdrv_find(backup->device);
|
state->bs = bs;
|
||||||
state->job = state->bs->job;
|
state->job = state->bs->job;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1495,6 +1550,88 @@ static void drive_backup_abort(BlkTransactionState *common)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drive_backup_clean(BlkTransactionState *common)
|
||||||
|
{
|
||||||
|
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
|
||||||
|
|
||||||
|
if (state->aio_context) {
|
||||||
|
aio_context_release(state->aio_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct BlockdevBackupState {
|
||||||
|
BlkTransactionState common;
|
||||||
|
BlockDriverState *bs;
|
||||||
|
BlockJob *job;
|
||||||
|
AioContext *aio_context;
|
||||||
|
} BlockdevBackupState;
|
||||||
|
|
||||||
|
static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
|
||||||
|
{
|
||||||
|
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||||
|
BlockdevBackup *backup;
|
||||||
|
BlockDriverState *bs, *target;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
|
||||||
|
backup = common->action->blockdev_backup;
|
||||||
|
|
||||||
|
bs = bdrv_find(backup->device);
|
||||||
|
if (!bs) {
|
||||||
|
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = bdrv_find(backup->target);
|
||||||
|
if (!target) {
|
||||||
|
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AioContext is released in .clean() */
|
||||||
|
state->aio_context = bdrv_get_aio_context(bs);
|
||||||
|
if (state->aio_context != bdrv_get_aio_context(target)) {
|
||||||
|
state->aio_context = NULL;
|
||||||
|
error_setg(errp, "Backup between two IO threads is not implemented");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
aio_context_acquire(state->aio_context);
|
||||||
|
|
||||||
|
qmp_blockdev_backup(backup->device, backup->target,
|
||||||
|
backup->sync,
|
||||||
|
backup->has_speed, backup->speed,
|
||||||
|
backup->has_on_source_error, backup->on_source_error,
|
||||||
|
backup->has_on_target_error, backup->on_target_error,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->bs = bs;
|
||||||
|
state->job = state->bs->job;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blockdev_backup_abort(BlkTransactionState *common)
|
||||||
|
{
|
||||||
|
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||||
|
BlockDriverState *bs = state->bs;
|
||||||
|
|
||||||
|
/* Only cancel if it's the job we started */
|
||||||
|
if (bs && bs->job && bs->job == state->job) {
|
||||||
|
block_job_cancel_sync(bs->job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blockdev_backup_clean(BlkTransactionState *common)
|
||||||
|
{
|
||||||
|
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||||
|
|
||||||
|
if (state->aio_context) {
|
||||||
|
aio_context_release(state->aio_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void abort_prepare(BlkTransactionState *common, Error **errp)
|
static void abort_prepare(BlkTransactionState *common, Error **errp)
|
||||||
{
|
{
|
||||||
error_setg(errp, "Transaction aborted using Abort action");
|
error_setg(errp, "Transaction aborted using Abort action");
|
||||||
@@ -1516,6 +1653,13 @@ static const BdrvActionOps actions[] = {
|
|||||||
.instance_size = sizeof(DriveBackupState),
|
.instance_size = sizeof(DriveBackupState),
|
||||||
.prepare = drive_backup_prepare,
|
.prepare = drive_backup_prepare,
|
||||||
.abort = drive_backup_abort,
|
.abort = drive_backup_abort,
|
||||||
|
.clean = drive_backup_clean,
|
||||||
|
},
|
||||||
|
[TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP] = {
|
||||||
|
.instance_size = sizeof(BlockdevBackupState),
|
||||||
|
.prepare = blockdev_backup_prepare,
|
||||||
|
.abort = blockdev_backup_abort,
|
||||||
|
.clean = blockdev_backup_clean,
|
||||||
},
|
},
|
||||||
[TRANSACTION_ACTION_KIND_ABORT] = {
|
[TRANSACTION_ACTION_KIND_ABORT] = {
|
||||||
.instance_size = sizeof(BlkTransactionState),
|
.instance_size = sizeof(BlkTransactionState),
|
||||||
@@ -1526,13 +1670,13 @@ static const BdrvActionOps actions[] = {
|
|||||||
.instance_size = sizeof(InternalSnapshotState),
|
.instance_size = sizeof(InternalSnapshotState),
|
||||||
.prepare = internal_snapshot_prepare,
|
.prepare = internal_snapshot_prepare,
|
||||||
.abort = internal_snapshot_abort,
|
.abort = internal_snapshot_abort,
|
||||||
|
.clean = internal_snapshot_clean,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 'Atomic' group snapshots. The snapshots are taken as a set, and if any fail
|
* 'Atomic' group operations. The operations are performed as a set, and if
|
||||||
* then we do not pivot any of the devices in the group, and abandon the
|
* any fail then we roll back all operations in the group.
|
||||||
* snapshots
|
|
||||||
*/
|
*/
|
||||||
void qmp_transaction(TransactionActionList *dev_list, Error **errp)
|
void qmp_transaction(TransactionActionList *dev_list, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -1543,10 +1687,10 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp)
|
|||||||
QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionState) snap_bdrv_states;
|
QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionState) snap_bdrv_states;
|
||||||
QSIMPLEQ_INIT(&snap_bdrv_states);
|
QSIMPLEQ_INIT(&snap_bdrv_states);
|
||||||
|
|
||||||
/* drain all i/o before any snapshots */
|
/* drain all i/o before any operations */
|
||||||
bdrv_drain_all();
|
bdrv_drain_all();
|
||||||
|
|
||||||
/* We don't do anything in this loop that commits us to the snapshot */
|
/* We don't do anything in this loop that commits us to the operations */
|
||||||
while (NULL != dev_entry) {
|
while (NULL != dev_entry) {
|
||||||
TransactionAction *dev_info = NULL;
|
TransactionAction *dev_info = NULL;
|
||||||
const BdrvActionOps *ops;
|
const BdrvActionOps *ops;
|
||||||
@@ -1581,10 +1725,7 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp)
|
|||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
delete_and_fail:
|
delete_and_fail:
|
||||||
/*
|
/* failure, and it is all-or-none; roll back all operations */
|
||||||
* failure, and it is all-or-none; abandon each new bs, and keep using
|
|
||||||
* the original bs for all images
|
|
||||||
*/
|
|
||||||
QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
|
QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
|
||||||
if (state->ops->abort) {
|
if (state->ops->abort) {
|
||||||
state->ops->abort(state);
|
state->ops->abort(state);
|
||||||
@@ -1603,14 +1744,18 @@ exit:
|
|||||||
static void eject_device(BlockBackend *blk, int force, Error **errp)
|
static void eject_device(BlockBackend *blk, int force, Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = blk_bs(blk);
|
BlockDriverState *bs = blk_bs(blk);
|
||||||
|
AioContext *aio_context;
|
||||||
|
|
||||||
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!blk_dev_has_removable_media(blk)) {
|
if (!blk_dev_has_removable_media(blk)) {
|
||||||
error_setg(errp, "Device '%s' is not removable",
|
error_setg(errp, "Device '%s' is not removable",
|
||||||
bdrv_get_device_name(bs));
|
bdrv_get_device_name(bs));
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
|
if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
|
||||||
@@ -1618,11 +1763,14 @@ static void eject_device(BlockBackend *blk, int force, Error **errp)
|
|||||||
if (!force) {
|
if (!force) {
|
||||||
error_setg(errp, "Device '%s' is locked",
|
error_setg(errp, "Device '%s' is locked",
|
||||||
bdrv_get_device_name(bs));
|
bdrv_get_device_name(bs));
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_close(bs);
|
bdrv_close(bs);
|
||||||
|
|
||||||
|
out:
|
||||||
|
aio_context_release(aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
|
void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
|
||||||
@@ -1644,6 +1792,7 @@ void qmp_block_passwd(bool has_device, const char *device,
|
|||||||
{
|
{
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
AioContext *aio_context;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
bs = bdrv_lookup_bs(has_device ? device : NULL,
|
bs = bdrv_lookup_bs(has_device ? device : NULL,
|
||||||
@@ -1654,16 +1803,23 @@ void qmp_block_passwd(bool has_device, const char *device,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
err = bdrv_set_key(bs, password);
|
err = bdrv_set_key(bs, password);
|
||||||
if (err == -EINVAL) {
|
if (err == -EINVAL) {
|
||||||
error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
|
error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
|
||||||
return;
|
goto out;
|
||||||
} else if (err < 0) {
|
} else if (err < 0) {
|
||||||
error_set(errp, QERR_INVALID_PASSWORD);
|
error_set(errp, QERR_INVALID_PASSWORD);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
aio_context_release(aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Assumes AioContext is held */
|
||||||
static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
|
static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
|
||||||
int bdrv_flags, BlockDriver *drv,
|
int bdrv_flags, BlockDriver *drv,
|
||||||
const char *password, Error **errp)
|
const char *password, Error **errp)
|
||||||
@@ -1696,6 +1852,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
|
|||||||
{
|
{
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
AioContext *aio_context;
|
||||||
BlockDriver *drv = NULL;
|
BlockDriver *drv = NULL;
|
||||||
int bdrv_flags;
|
int bdrv_flags;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
@@ -1707,24 +1864,30 @@ void qmp_change_blockdev(const char *device, const char *filename,
|
|||||||
}
|
}
|
||||||
bs = blk_bs(blk);
|
bs = blk_bs(blk);
|
||||||
|
|
||||||
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
if (format) {
|
if (format) {
|
||||||
drv = bdrv_find_whitelisted_format(format, bs->read_only);
|
drv = bdrv_find_whitelisted_format(format, bs->read_only);
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
|
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eject_device(blk, 0, &err);
|
eject_device(blk, 0, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
|
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
|
||||||
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
|
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
|
||||||
|
|
||||||
qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
|
qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
|
||||||
|
|
||||||
|
out:
|
||||||
|
aio_context_release(aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* throttling disk I/O limits */
|
/* throttling disk I/O limits */
|
||||||
@@ -2055,7 +2218,7 @@ void qmp_block_commit(const char *device,
|
|||||||
/* drain all i/o before commits */
|
/* drain all i/o before commits */
|
||||||
bdrv_drain_all();
|
bdrv_drain_all();
|
||||||
|
|
||||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, errp)) {
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, errp)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2088,6 +2251,10 @@ void qmp_block_commit(const char *device,
|
|||||||
|
|
||||||
assert(bdrv_get_aio_context(base_bs) == aio_context);
|
assert(bdrv_get_aio_context(base_bs) == aio_context);
|
||||||
|
|
||||||
|
if (bdrv_op_is_blocked(base_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Do not allow attempts to commit an image into itself */
|
/* Do not allow attempts to commit an image into itself */
|
||||||
if (top_bs == base_bs) {
|
if (top_bs == base_bs) {
|
||||||
error_setg(errp, "cannot commit an image into itself");
|
error_setg(errp, "cannot commit an image into itself");
|
||||||
@@ -2156,6 +2323,8 @@ void qmp_drive_backup(const char *device, const char *target,
|
|||||||
aio_context = bdrv_get_aio_context(bs);
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
aio_context_acquire(aio_context);
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
|
/* Although backup_run has this check too, we need to use bs->drv below, so
|
||||||
|
* do an early check redundantly. */
|
||||||
if (!bdrv_is_inserted(bs)) {
|
if (!bdrv_is_inserted(bs)) {
|
||||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -2172,6 +2341,7 @@ void qmp_drive_backup(const char *device, const char *target,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Early check to avoid creating target */
|
||||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -2239,6 +2409,57 @@ BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
|
|||||||
return bdrv_named_nodes_list();
|
return bdrv_named_nodes_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qmp_blockdev_backup(const char *device, const char *target,
|
||||||
|
enum MirrorSyncMode sync,
|
||||||
|
bool has_speed, int64_t speed,
|
||||||
|
bool has_on_source_error,
|
||||||
|
BlockdevOnError on_source_error,
|
||||||
|
bool has_on_target_error,
|
||||||
|
BlockdevOnError on_target_error,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
BlockDriverState *bs;
|
||||||
|
BlockDriverState *target_bs;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
AioContext *aio_context;
|
||||||
|
|
||||||
|
if (!has_speed) {
|
||||||
|
speed = 0;
|
||||||
|
}
|
||||||
|
if (!has_on_source_error) {
|
||||||
|
on_source_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||||
|
}
|
||||||
|
if (!has_on_target_error) {
|
||||||
|
on_target_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs = bdrv_find(device);
|
||||||
|
if (!bs) {
|
||||||
|
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
|
target_bs = bdrv_find(target);
|
||||||
|
if (!target_bs) {
|
||||||
|
error_set(errp, QERR_DEVICE_NOT_FOUND, target);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_ref(target_bs);
|
||||||
|
bdrv_set_aio_context(target_bs, aio_context);
|
||||||
|
backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
|
||||||
|
block_job_cb, bs, &local_err);
|
||||||
|
if (local_err != NULL) {
|
||||||
|
bdrv_unref(target_bs);
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
aio_context_release(aio_context);
|
||||||
|
}
|
||||||
|
|
||||||
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
#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,
|
||||||
@@ -2548,6 +2769,7 @@ void qmp_change_backing_file(const char *device,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = NULL;
|
BlockDriverState *bs = NULL;
|
||||||
|
AioContext *aio_context;
|
||||||
BlockDriverState *image_bs = NULL;
|
BlockDriverState *image_bs = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
bool ro;
|
bool ro;
|
||||||
@@ -2561,34 +2783,37 @@ void qmp_change_backing_file(const char *device,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
|
image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!image_bs) {
|
if (!image_bs) {
|
||||||
error_setg(errp, "image file not found");
|
error_setg(errp, "image file not found");
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_find_base(image_bs) == image_bs) {
|
if (bdrv_find_base(image_bs) == image_bs) {
|
||||||
error_setg(errp, "not allowing backing file change on an image "
|
error_setg(errp, "not allowing backing file change on an image "
|
||||||
"without a backing file");
|
"without a backing file");
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* even though we are not necessarily operating on bs, we need it to
|
/* even though we are not necessarily operating on bs, we need it to
|
||||||
* determine if block ops are currently prohibited on the chain */
|
* determine if block ops are currently prohibited on the chain */
|
||||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* final sanity check */
|
/* final sanity check */
|
||||||
if (!bdrv_chain_contains(bs, image_bs)) {
|
if (!bdrv_chain_contains(bs, image_bs)) {
|
||||||
error_setg(errp, "'%s' and image file are not in the same chain",
|
error_setg(errp, "'%s' and image file are not in the same chain",
|
||||||
device);
|
device);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if not r/w, reopen to make r/w */
|
/* if not r/w, reopen to make r/w */
|
||||||
@@ -2599,7 +2824,7 @@ void qmp_change_backing_file(const char *device,
|
|||||||
bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
|
bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2619,6 +2844,9 @@ void qmp_change_backing_file(const char *device,
|
|||||||
error_propagate(errp, local_err); /* will preserve prior errp */
|
error_propagate(errp, local_err); /* will preserve prior errp */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
aio_context_release(aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||||
|
73
bootdevice.c
73
bootdevice.c
@@ -25,6 +25,7 @@
|
|||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/hw.h"
|
||||||
|
|
||||||
typedef struct FWBootEntry FWBootEntry;
|
typedef struct FWBootEntry FWBootEntry;
|
||||||
|
|
||||||
@@ -37,6 +38,78 @@ struct FWBootEntry {
|
|||||||
|
|
||||||
static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =
|
static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =
|
||||||
QTAILQ_HEAD_INITIALIZER(fw_boot_order);
|
QTAILQ_HEAD_INITIALIZER(fw_boot_order);
|
||||||
|
static QEMUBootSetHandler *boot_set_handler;
|
||||||
|
static void *boot_set_opaque;
|
||||||
|
|
||||||
|
void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
|
||||||
|
{
|
||||||
|
boot_set_handler = func;
|
||||||
|
boot_set_opaque = opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_boot_set(const char *boot_order, Error **errp)
|
||||||
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
if (!boot_set_handler) {
|
||||||
|
error_setg(errp, "no function defined to set boot device list for"
|
||||||
|
" this architecture");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_bootdevices(boot_order, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_set_handler(boot_set_opaque, boot_order, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void validate_bootdevices(const char *devices, Error **errp)
|
||||||
|
{
|
||||||
|
/* We just do some generic consistency checks */
|
||||||
|
const char *p;
|
||||||
|
int bitmap = 0;
|
||||||
|
|
||||||
|
for (p = devices; *p != '\0'; p++) {
|
||||||
|
/* Allowed boot devices are:
|
||||||
|
* a-b: floppy disk drives
|
||||||
|
* c-f: IDE disk drives
|
||||||
|
* g-m: machine implementation dependent drives
|
||||||
|
* n-p: network devices
|
||||||
|
* It's up to each machine implementation to check if the given boot
|
||||||
|
* devices match the actual hardware implementation and firmware
|
||||||
|
* features.
|
||||||
|
*/
|
||||||
|
if (*p < 'a' || *p > 'p') {
|
||||||
|
error_setg(errp, "Invalid boot device '%c'", *p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bitmap & (1 << (*p - 'a'))) {
|
||||||
|
error_setg(errp, "Boot device '%c' was given twice", *p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bitmap |= 1 << (*p - 'a');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_boot_order(void *opaque)
|
||||||
|
{
|
||||||
|
char *normal_boot_order = opaque;
|
||||||
|
static int first = 1;
|
||||||
|
|
||||||
|
/* Restore boot order and remove ourselves after the first boot */
|
||||||
|
if (first) {
|
||||||
|
first = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_boot_set(normal_boot_order, NULL);
|
||||||
|
|
||||||
|
qemu_unregister_reset(restore_boot_order, normal_boot_order);
|
||||||
|
g_free(normal_boot_order);
|
||||||
|
}
|
||||||
|
|
||||||
void check_boot_index(int32_t bootindex, Error **errp)
|
void check_boot_index(int32_t bootindex, Error **errp)
|
||||||
{
|
{
|
||||||
|
@@ -351,8 +351,10 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
|
|||||||
|
|
||||||
_regs->gpr[1] = infop->start_stack;
|
_regs->gpr[1] = infop->start_stack;
|
||||||
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
||||||
entry = ldq_raw(infop->entry) + infop->load_addr;
|
get_user_u64(entry, infop->entry);
|
||||||
toc = ldq_raw(infop->entry + 8) + infop->load_addr;
|
entry += infop->load_addr;
|
||||||
|
get_user_u64(toc, infop->entry + 8);
|
||||||
|
toc += infop->load_addr;
|
||||||
_regs->gpr[2] = toc;
|
_regs->gpr[2] = toc;
|
||||||
infop->entry = entry;
|
infop->entry = entry;
|
||||||
#endif
|
#endif
|
||||||
@@ -365,8 +367,9 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
|
|||||||
get_user_ual(_regs->gpr[3], pos);
|
get_user_ual(_regs->gpr[3], pos);
|
||||||
pos += sizeof(abi_ulong);
|
pos += sizeof(abi_ulong);
|
||||||
_regs->gpr[4] = pos;
|
_regs->gpr[4] = pos;
|
||||||
for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
|
for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) {
|
||||||
tmp = ldl(pos);
|
get_user_ual(tmp, pos);
|
||||||
|
}
|
||||||
_regs->gpr[5] = pos;
|
_regs->gpr[5] = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
configure
vendored
33
configure
vendored
@@ -1830,7 +1830,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" "Install libseccomp devel >= 2.1.0"
|
feature_not_found "libseccomp" "Install libseccomp devel >= 2.1.1"
|
||||||
fi
|
fi
|
||||||
seccomp="no"
|
seccomp="no"
|
||||||
fi
|
fi
|
||||||
@@ -1869,6 +1869,32 @@ EOF
|
|||||||
#if !defined(HVM_MAX_VCPUS)
|
#if !defined(HVM_MAX_VCPUS)
|
||||||
# error HVM_MAX_VCPUS not defined
|
# error HVM_MAX_VCPUS not defined
|
||||||
#endif
|
#endif
|
||||||
|
int main(void) {
|
||||||
|
xc_interface *xc;
|
||||||
|
xs_daemon_open();
|
||||||
|
xc = xc_interface_open(0, 0, 0);
|
||||||
|
xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
|
||||||
|
xc_gnttab_open(NULL, 0);
|
||||||
|
xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
|
||||||
|
xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000);
|
||||||
|
xc_hvm_create_ioreq_server(xc, 0, 0, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
compile_prog "" "$xen_libs"
|
||||||
|
then
|
||||||
|
xen_ctrl_version=450
|
||||||
|
xen=yes
|
||||||
|
|
||||||
|
elif
|
||||||
|
cat > $TMPC <<EOF &&
|
||||||
|
#include <xenctrl.h>
|
||||||
|
#include <xenstore.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <xen/hvm/hvm_info_table.h>
|
||||||
|
#if !defined(HVM_MAX_VCPUS)
|
||||||
|
# error HVM_MAX_VCPUS not defined
|
||||||
|
#endif
|
||||||
int main(void) {
|
int main(void) {
|
||||||
xc_interface *xc;
|
xc_interface *xc;
|
||||||
xs_daemon_open();
|
xs_daemon_open();
|
||||||
@@ -2727,7 +2753,7 @@ fi
|
|||||||
if test "$modules" = yes; then
|
if test "$modules" = yes; then
|
||||||
shacmd_probe="sha1sum sha1 shasum"
|
shacmd_probe="sha1sum sha1 shasum"
|
||||||
for c in $shacmd_probe; do
|
for c in $shacmd_probe; do
|
||||||
if which $c >/dev/null 2>&1; then
|
if has $c; then
|
||||||
shacmd="$c"
|
shacmd="$c"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -4283,6 +4309,9 @@ if test -n "$sparc_cpu"; then
|
|||||||
echo "Target Sparc Arch $sparc_cpu"
|
echo "Target Sparc Arch $sparc_cpu"
|
||||||
fi
|
fi
|
||||||
echo "xen support $xen"
|
echo "xen support $xen"
|
||||||
|
if test "$xen" = "yes" ; then
|
||||||
|
echo "xen ctrl version $xen_ctrl_version"
|
||||||
|
fi
|
||||||
echo "brlapi support $brlapi"
|
echo "brlapi support $brlapi"
|
||||||
echo "bluez support $bluez"
|
echo "bluez support $bluez"
|
||||||
echo "Documentation $docs"
|
echo "Documentation $docs"
|
||||||
|
@@ -25,7 +25,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <ucontext.h>
|
#include <ucontext.h>
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "block/coroutine_int.h"
|
#include "block/coroutine_int.h"
|
||||||
@@ -48,15 +47,8 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* Per-thread coroutine bookkeeping
|
* Per-thread coroutine bookkeeping
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
static __thread CoroutineUContext leader;
|
||||||
/** Currently executing coroutine */
|
static __thread Coroutine *current;
|
||||||
Coroutine *current;
|
|
||||||
|
|
||||||
/** The default coroutine */
|
|
||||||
CoroutineUContext leader;
|
|
||||||
} CoroutineThreadState;
|
|
||||||
|
|
||||||
static pthread_key_t thread_state_key;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* va_args to makecontext() must be type 'int', so passing
|
* va_args to makecontext() must be type 'int', so passing
|
||||||
@@ -68,36 +60,6 @@ union cc_arg {
|
|||||||
int i[2];
|
int i[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static CoroutineThreadState *coroutine_get_thread_state(void)
|
|
||||||
{
|
|
||||||
CoroutineThreadState *s = pthread_getspecific(thread_state_key);
|
|
||||||
|
|
||||||
if (!s) {
|
|
||||||
s = g_malloc0(sizeof(*s));
|
|
||||||
s->current = &s->leader.base;
|
|
||||||
pthread_setspecific(thread_state_key, s);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qemu_coroutine_thread_cleanup(void *opaque)
|
|
||||||
{
|
|
||||||
CoroutineThreadState *s = opaque;
|
|
||||||
|
|
||||||
g_free(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __attribute__((constructor)) coroutine_init(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup);
|
|
||||||
if (ret != 0) {
|
|
||||||
fprintf(stderr, "unable to create leader key: %s\n", strerror(errno));
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void coroutine_trampoline(int i0, int i1)
|
static void coroutine_trampoline(int i0, int i1)
|
||||||
{
|
{
|
||||||
union cc_arg arg;
|
union cc_arg arg;
|
||||||
@@ -193,15 +155,23 @@ void qemu_coroutine_delete(Coroutine *co_)
|
|||||||
g_free(co);
|
g_free(co);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
/* This function is marked noinline to prevent GCC from inlining it
|
||||||
CoroutineAction action)
|
* into coroutine_trampoline(). If we allow it to do that then it
|
||||||
|
* hoists the code to get the address of the TLS variable "current"
|
||||||
|
* out of the while() loop. This is an invalid transformation because
|
||||||
|
* the sigsetjmp() call may be called when running thread A but
|
||||||
|
* return in thread B, and so we might be in a different thread
|
||||||
|
* context each time round the loop.
|
||||||
|
*/
|
||||||
|
CoroutineAction __attribute__((noinline))
|
||||||
|
qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||||
|
CoroutineAction action)
|
||||||
{
|
{
|
||||||
CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
|
CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
|
||||||
CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
|
CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
|
||||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
s->current = to_;
|
current = to_;
|
||||||
|
|
||||||
ret = sigsetjmp(from->env, 0);
|
ret = sigsetjmp(from->env, 0);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
@@ -212,14 +182,13 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
|||||||
|
|
||||||
Coroutine *qemu_coroutine_self(void)
|
Coroutine *qemu_coroutine_self(void)
|
||||||
{
|
{
|
||||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
if (!current) {
|
||||||
|
current = &leader.base;
|
||||||
return s->current;
|
}
|
||||||
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool qemu_in_coroutine(void)
|
bool qemu_in_coroutine(void)
|
||||||
{
|
{
|
||||||
CoroutineThreadState *s = pthread_getspecific(thread_state_key);
|
return current && current->caller;
|
||||||
|
|
||||||
return s && s->current->caller;
|
|
||||||
}
|
}
|
||||||
|
15
cpu-exec.c
15
cpu-exec.c
@@ -168,7 +168,9 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
|
|||||||
}
|
}
|
||||||
#endif /* DEBUG_DISAS */
|
#endif /* DEBUG_DISAS */
|
||||||
|
|
||||||
|
cpu->can_do_io = 0;
|
||||||
next_tb = tcg_qemu_tb_exec(env, tb_ptr);
|
next_tb = tcg_qemu_tb_exec(env, tb_ptr);
|
||||||
|
cpu->can_do_io = 1;
|
||||||
trace_exec_tb_exit((void *) (next_tb & ~TB_EXIT_MASK),
|
trace_exec_tb_exit((void *) (next_tb & ~TB_EXIT_MASK),
|
||||||
next_tb & TB_EXIT_MASK);
|
next_tb & TB_EXIT_MASK);
|
||||||
|
|
||||||
@@ -202,14 +204,19 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
|
|||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
CPUState *cpu = ENV_GET_CPU(env);
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
|
target_ulong pc = orig_tb->pc;
|
||||||
|
target_ulong cs_base = orig_tb->cs_base;
|
||||||
|
uint64_t flags = orig_tb->flags;
|
||||||
|
|
||||||
/* Should never happen.
|
/* Should never happen.
|
||||||
We only end up here when an existing TB is too long. */
|
We only end up here when an existing TB is too long. */
|
||||||
if (max_cycles > CF_COUNT_MASK)
|
if (max_cycles > CF_COUNT_MASK)
|
||||||
max_cycles = CF_COUNT_MASK;
|
max_cycles = CF_COUNT_MASK;
|
||||||
|
|
||||||
tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
|
/* tb_gen_code can flush our orig_tb, invalidate it now */
|
||||||
max_cycles);
|
tb_phys_invalidate(orig_tb, -1);
|
||||||
|
tb = tb_gen_code(cpu, pc, cs_base, flags,
|
||||||
|
max_cycles | CF_NOCACHE);
|
||||||
cpu->current_tb = tb;
|
cpu->current_tb = tb;
|
||||||
/* execute the generated code */
|
/* execute the generated code */
|
||||||
trace_exec_tb_nocache(tb, tb->pc);
|
trace_exec_tb_nocache(tb, tb->pc);
|
||||||
@@ -353,7 +360,6 @@ int cpu_exec(CPUArchState *env)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cc->cpu_exec_enter(cpu);
|
cc->cpu_exec_enter(cpu);
|
||||||
cpu->exception_index = -1;
|
|
||||||
|
|
||||||
/* Calculate difference between guest clock and host clock.
|
/* Calculate difference between guest clock and host clock.
|
||||||
* This delay includes the delay of the last cycle, so
|
* This delay includes the delay of the last cycle, so
|
||||||
@@ -373,6 +379,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
if (ret == EXCP_DEBUG) {
|
if (ret == EXCP_DEBUG) {
|
||||||
cpu_handle_debug_exception(env);
|
cpu_handle_debug_exception(env);
|
||||||
}
|
}
|
||||||
|
cpu->exception_index = -1;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
@@ -383,6 +390,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
cc->do_interrupt(cpu);
|
cc->do_interrupt(cpu);
|
||||||
#endif
|
#endif
|
||||||
ret = cpu->exception_index;
|
ret = cpu->exception_index;
|
||||||
|
cpu->exception_index = -1;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
cc->do_interrupt(cpu);
|
cc->do_interrupt(cpu);
|
||||||
@@ -537,6 +545,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
cpu = current_cpu;
|
cpu = current_cpu;
|
||||||
env = cpu->env_ptr;
|
env = cpu->env_ptr;
|
||||||
cc = CPU_GET_CLASS(cpu);
|
cc = CPU_GET_CLASS(cpu);
|
||||||
|
cpu->can_do_io = 1;
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
x86_cpu = X86_CPU(cpu);
|
x86_cpu = X86_CPU(cpu);
|
||||||
#endif
|
#endif
|
||||||
|
43
cpus.c
43
cpus.c
@@ -136,8 +136,7 @@ typedef struct TimersState {
|
|||||||
|
|
||||||
static TimersState timers_state;
|
static TimersState timers_state;
|
||||||
|
|
||||||
/* Return the virtual CPU time, based on the instruction counter. */
|
int64_t cpu_get_icount_raw(void)
|
||||||
static int64_t cpu_get_icount_locked(void)
|
|
||||||
{
|
{
|
||||||
int64_t icount;
|
int64_t icount;
|
||||||
CPUState *cpu = current_cpu;
|
CPUState *cpu = current_cpu;
|
||||||
@@ -145,10 +144,18 @@ static int64_t cpu_get_icount_locked(void)
|
|||||||
icount = timers_state.qemu_icount;
|
icount = timers_state.qemu_icount;
|
||||||
if (cpu) {
|
if (cpu) {
|
||||||
if (!cpu_can_do_io(cpu)) {
|
if (!cpu_can_do_io(cpu)) {
|
||||||
fprintf(stderr, "Bad clock read\n");
|
fprintf(stderr, "Bad icount read\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
|
icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
|
||||||
}
|
}
|
||||||
|
return icount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the virtual CPU time, based on the instruction counter. */
|
||||||
|
static int64_t cpu_get_icount_locked(void)
|
||||||
|
{
|
||||||
|
int64_t icount = cpu_get_icount_raw();
|
||||||
return timers_state.qemu_icount_bias + cpu_icount_to_ns(icount);
|
return timers_state.qemu_icount_bias + cpu_icount_to_ns(icount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +324,7 @@ static void icount_adjust(void)
|
|||||||
static void icount_adjust_rt(void *opaque)
|
static void icount_adjust_rt(void *opaque)
|
||||||
{
|
{
|
||||||
timer_mod(icount_rt_timer,
|
timer_mod(icount_rt_timer,
|
||||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000);
|
||||||
icount_adjust();
|
icount_adjust();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +352,7 @@ static void icount_warp_rt(void *opaque)
|
|||||||
|
|
||||||
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
||||||
if (runstate_is_running()) {
|
if (runstate_is_running()) {
|
||||||
int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
int64_t clock = cpu_get_clock_locked();
|
||||||
int64_t warp_delta;
|
int64_t warp_delta;
|
||||||
|
|
||||||
warp_delta = clock - vm_clock_warp_start;
|
warp_delta = clock - vm_clock_warp_start;
|
||||||
@@ -354,9 +361,8 @@ static void icount_warp_rt(void *opaque)
|
|||||||
* In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too
|
* In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too
|
||||||
* far ahead of real time.
|
* far ahead of real time.
|
||||||
*/
|
*/
|
||||||
int64_t cur_time = cpu_get_clock_locked();
|
|
||||||
int64_t cur_icount = cpu_get_icount_locked();
|
int64_t cur_icount = cpu_get_icount_locked();
|
||||||
int64_t delta = cur_time - cur_icount;
|
int64_t delta = clock - cur_icount;
|
||||||
warp_delta = MIN(warp_delta, delta);
|
warp_delta = MIN(warp_delta, delta);
|
||||||
}
|
}
|
||||||
timers_state.qemu_icount_bias += warp_delta;
|
timers_state.qemu_icount_bias += warp_delta;
|
||||||
@@ -372,19 +378,15 @@ static void icount_warp_rt(void *opaque)
|
|||||||
void qtest_clock_warp(int64_t dest)
|
void qtest_clock_warp(int64_t dest)
|
||||||
{
|
{
|
||||||
int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
AioContext *aio_context;
|
|
||||||
assert(qtest_enabled());
|
assert(qtest_enabled());
|
||||||
aio_context = qemu_get_aio_context();
|
|
||||||
while (clock < dest) {
|
while (clock < dest) {
|
||||||
int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
||||||
int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
|
int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
|
||||||
|
|
||||||
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
||||||
timers_state.qemu_icount_bias += warp;
|
timers_state.qemu_icount_bias += warp;
|
||||||
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
|
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
|
||||||
|
|
||||||
qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
|
qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
|
||||||
timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]);
|
|
||||||
clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
}
|
}
|
||||||
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
|
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
|
||||||
@@ -423,7 +425,7 @@ void qemu_clock_warp(QEMUClockType type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We want to use the earliest deadline from ALL vm_clocks */
|
/* We want to use the earliest deadline from ALL vm_clocks */
|
||||||
clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT);
|
||||||
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
||||||
if (deadline < 0) {
|
if (deadline < 0) {
|
||||||
return;
|
return;
|
||||||
@@ -441,8 +443,8 @@ void qemu_clock_warp(QEMUClockType type)
|
|||||||
* sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL
|
* sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL
|
||||||
* timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL
|
* timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL
|
||||||
* event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL
|
* event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL
|
||||||
* after some e"real" time, (related to the time left until the next
|
* after some "real" time, (related to the time left until the next
|
||||||
* event) has passed. The QEMU_CLOCK_REALTIME timer will do this.
|
* event) has passed. The QEMU_CLOCK_VIRTUAL_RT clock will do this.
|
||||||
* This avoids that the warps are visible externally; for example,
|
* This avoids that the warps are visible externally; for example,
|
||||||
* you will not be sending network packets continuously instead of
|
* you will not be sending network packets continuously instead of
|
||||||
* every 100ms.
|
* every 100ms.
|
||||||
@@ -516,8 +518,8 @@ void configure_icount(QemuOpts *opts, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
icount_align_option = qemu_opt_get_bool(opts, "align", false);
|
icount_align_option = qemu_opt_get_bool(opts, "align", false);
|
||||||
icount_warp_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
|
icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
|
||||||
icount_warp_rt, NULL);
|
icount_warp_rt, NULL);
|
||||||
if (strcmp(option, "auto") != 0) {
|
if (strcmp(option, "auto") != 0) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
icount_time_shift = strtol(option, &rem_str, 0);
|
icount_time_shift = strtol(option, &rem_str, 0);
|
||||||
@@ -541,10 +543,10 @@ void configure_icount(QemuOpts *opts, Error **errp)
|
|||||||
the virtual time trigger catches emulated time passing too fast.
|
the virtual time trigger catches emulated time passing too fast.
|
||||||
Realtime triggers occur even when idle, so use them less frequently
|
Realtime triggers occur even when idle, so use them less frequently
|
||||||
than VM triggers. */
|
than VM triggers. */
|
||||||
icount_rt_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
|
icount_rt_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL_RT,
|
||||||
icount_adjust_rt, NULL);
|
icount_adjust_rt, NULL);
|
||||||
timer_mod(icount_rt_timer,
|
timer_mod(icount_rt_timer,
|
||||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000);
|
||||||
icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
icount_adjust_vm, NULL);
|
icount_adjust_vm, NULL);
|
||||||
timer_mod(icount_vm_timer,
|
timer_mod(icount_vm_timer,
|
||||||
@@ -938,6 +940,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
|
|||||||
qemu_mutex_lock(&qemu_global_mutex);
|
qemu_mutex_lock(&qemu_global_mutex);
|
||||||
qemu_thread_get_self(cpu->thread);
|
qemu_thread_get_self(cpu->thread);
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
|
cpu->can_do_io = 1;
|
||||||
current_cpu = cpu;
|
current_cpu = cpu;
|
||||||
|
|
||||||
r = kvm_init_vcpu(cpu);
|
r = kvm_init_vcpu(cpu);
|
||||||
@@ -978,6 +981,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
|
|||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
qemu_thread_get_self(cpu->thread);
|
qemu_thread_get_self(cpu->thread);
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
|
cpu->can_do_io = 1;
|
||||||
|
|
||||||
sigemptyset(&waitset);
|
sigemptyset(&waitset);
|
||||||
sigaddset(&waitset, SIG_IPI);
|
sigaddset(&waitset, SIG_IPI);
|
||||||
@@ -1020,6 +1024,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
|||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
cpu->thread_id = qemu_get_thread_id();
|
cpu->thread_id = qemu_get_thread_id();
|
||||||
cpu->created = true;
|
cpu->created = true;
|
||||||
|
cpu->can_do_io = 1;
|
||||||
}
|
}
|
||||||
qemu_cond_signal(&qemu_cpu_cond);
|
qemu_cond_signal(&qemu_cpu_cond);
|
||||||
|
|
||||||
|
3
cputlb.c
3
cputlb.c
@@ -270,7 +270,8 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
|||||||
assert(sz >= TARGET_PAGE_SIZE);
|
assert(sz >= TARGET_PAGE_SIZE);
|
||||||
|
|
||||||
#if defined(DEBUG_TLB)
|
#if defined(DEBUG_TLB)
|
||||||
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
|
qemu_log_mask(CPU_LOG_MMU,
|
||||||
|
"tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
|
||||||
" prot=%x idx=%d\n",
|
" prot=%x idx=%d\n",
|
||||||
vaddr, paddr, prot, mmu_idx);
|
vaddr, paddr, prot, mmu_idx);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -30,3 +30,5 @@ CONFIG_IPACK=y
|
|||||||
CONFIG_WDT_IB6300ESB=y
|
CONFIG_WDT_IB6300ESB=y
|
||||||
CONFIG_PCI_TESTDEV=y
|
CONFIG_PCI_TESTDEV=y
|
||||||
CONFIG_NVME_PCI=y
|
CONFIG_NVME_PCI=y
|
||||||
|
CONFIG_SD=y
|
||||||
|
CONFIG_SDHCI=y
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
include pci.mak
|
||||||
CONFIG_VIRTIO=y
|
CONFIG_VIRTIO=y
|
||||||
CONFIG_SCLPCONSOLE=y
|
CONFIG_SCLPCONSOLE=y
|
||||||
CONFIG_S390_FLIC=y
|
CONFIG_S390_FLIC=y
|
||||||
|
@@ -324,6 +324,7 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
|
|||||||
uint64_t value;
|
uint64_t value;
|
||||||
int cellnum, vnum, ncells;
|
int cellnum, vnum, ncells;
|
||||||
uint32_t hival;
|
uint32_t hival;
|
||||||
|
int ret;
|
||||||
|
|
||||||
propcells = g_new0(uint32_t, numvalues * 2);
|
propcells = g_new0(uint32_t, numvalues * 2);
|
||||||
|
|
||||||
@@ -331,18 +332,23 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
|
|||||||
for (vnum = 0; vnum < numvalues; vnum++) {
|
for (vnum = 0; vnum < numvalues; vnum++) {
|
||||||
ncells = values[vnum * 2];
|
ncells = values[vnum * 2];
|
||||||
if (ncells != 1 && ncells != 2) {
|
if (ncells != 1 && ncells != 2) {
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
value = values[vnum * 2 + 1];
|
value = values[vnum * 2 + 1];
|
||||||
hival = cpu_to_be32(value >> 32);
|
hival = cpu_to_be32(value >> 32);
|
||||||
if (ncells > 1) {
|
if (ncells > 1) {
|
||||||
propcells[cellnum++] = hival;
|
propcells[cellnum++] = hival;
|
||||||
} else if (hival != 0) {
|
} else if (hival != 0) {
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
propcells[cellnum++] = cpu_to_be32(value);
|
propcells[cellnum++] = cpu_to_be32(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return qemu_fdt_setprop(fdt, node_path, property, propcells,
|
ret = qemu_fdt_setprop(fdt, node_path, property, propcells,
|
||||||
cellnum * sizeof(uint32_t));
|
cellnum * sizeof(uint32_t));
|
||||||
|
out:
|
||||||
|
g_free(propcells);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
10
disas/mips.c
10
disas/mips.c
@@ -3511,6 +3511,7 @@ struct mips_cp0sel_name
|
|||||||
const char * const name;
|
const char * const name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* The mips16 registers. */
|
/* The mips16 registers. */
|
||||||
static const unsigned int mips16_to_32_reg_map[] =
|
static const unsigned int mips16_to_32_reg_map[] =
|
||||||
{
|
{
|
||||||
@@ -3518,7 +3519,7 @@ static const unsigned int mips16_to_32_reg_map[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]]
|
#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]]
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char * const mips_gpr_names_numeric[32] =
|
static const char * const mips_gpr_names_numeric[32] =
|
||||||
{
|
{
|
||||||
@@ -3801,13 +3802,6 @@ static const char * const mips_hwr_names_mips3264r2[32] =
|
|||||||
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
|
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const mips_msa_control_names_numeric[32] = {
|
|
||||||
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
|
|
||||||
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
|
|
||||||
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
|
|
||||||
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * const mips_msa_control_names_mips3264r2[32] = {
|
static const char * const mips_msa_control_names_mips3264r2[32] = {
|
||||||
"MSAIR", "MSACSR", "$2", "$3", "$4", "$5", "$6", "$7",
|
"MSAIR", "MSACSR", "$2", "$3", "$4", "$5", "$6", "$7",
|
||||||
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
|
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
|
||||||
|
@@ -44,6 +44,8 @@ PCI devices (other than virtio):
|
|||||||
1b36:0002 PCI serial port (16550A) adapter (docs/specs/pci-serial.txt)
|
1b36:0002 PCI serial port (16550A) adapter (docs/specs/pci-serial.txt)
|
||||||
1b36:0003 PCI Dual-port 16550A adapter (docs/specs/pci-serial.txt)
|
1b36:0003 PCI Dual-port 16550A adapter (docs/specs/pci-serial.txt)
|
||||||
1b36:0004 PCI Quad-port 16550A adapter (docs/specs/pci-serial.txt)
|
1b36:0004 PCI Quad-port 16550A adapter (docs/specs/pci-serial.txt)
|
||||||
|
1b36:0005 PCI test device (docs/specs/pci-testdev.txt)
|
||||||
|
1b36:0007 PCI SD Card Host Controller Interface (SDHCI)
|
||||||
|
|
||||||
All these devices are documented in docs/specs.
|
All these devices are documented in docs/specs.
|
||||||
|
|
||||||
|
@@ -71,6 +71,14 @@ encoded buffer:
|
|||||||
encoded length 24
|
encoded length 24
|
||||||
e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
|
e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
|
||||||
|
|
||||||
|
Cache update strategy
|
||||||
|
=====================
|
||||||
|
Keeping the hot pages in the cache is effective for decreased cache
|
||||||
|
misses. XBZRLE uses a counter as the age of each page. The counter will
|
||||||
|
increase after each ram dirty bitmap sync. When a cache conflict is
|
||||||
|
detected, XBZRLE will only evict pages in the cache that are older than
|
||||||
|
a threshold.
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
======================
|
======================
|
||||||
1. Verify the destination QEMU version is able to decode the new format.
|
1. Verify the destination QEMU version is able to decode the new format.
|
||||||
|
175
exec.c
175
exec.c
@@ -75,6 +75,11 @@ static MemoryRegion io_mem_unassigned;
|
|||||||
/* RAM is mmap-ed with MAP_SHARED */
|
/* RAM is mmap-ed with MAP_SHARED */
|
||||||
#define RAM_SHARED (1 << 1)
|
#define RAM_SHARED (1 << 1)
|
||||||
|
|
||||||
|
/* Only a portion of RAM (used_length) is actually used, and migrated.
|
||||||
|
* This used_length size can change across reboots.
|
||||||
|
*/
|
||||||
|
#define RAM_RESIZEABLE (1 << 2)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
|
struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
|
||||||
@@ -548,7 +553,6 @@ void cpu_exec_init(CPUArchState *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_HAS_ICE)
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
||||||
{
|
{
|
||||||
@@ -564,7 +568,6 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif /* TARGET_HAS_ICE */
|
|
||||||
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
|
void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
|
||||||
@@ -684,7 +687,6 @@ static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
|
|||||||
int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
|
int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
|
||||||
CPUBreakpoint **breakpoint)
|
CPUBreakpoint **breakpoint)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_HAS_ICE)
|
|
||||||
CPUBreakpoint *bp;
|
CPUBreakpoint *bp;
|
||||||
|
|
||||||
bp = g_malloc(sizeof(*bp));
|
bp = g_malloc(sizeof(*bp));
|
||||||
@@ -705,15 +707,11 @@ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
|
|||||||
*breakpoint = bp;
|
*breakpoint = bp;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
|
||||||
return -ENOSYS;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove a specific breakpoint. */
|
/* Remove a specific breakpoint. */
|
||||||
int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags)
|
int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_HAS_ICE)
|
|
||||||
CPUBreakpoint *bp;
|
CPUBreakpoint *bp;
|
||||||
|
|
||||||
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
|
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
|
||||||
@@ -723,27 +721,21 @@ int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
#else
|
|
||||||
return -ENOSYS;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove a specific breakpoint by reference. */
|
/* Remove a specific breakpoint by reference. */
|
||||||
void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *breakpoint)
|
void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *breakpoint)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_HAS_ICE)
|
|
||||||
QTAILQ_REMOVE(&cpu->breakpoints, breakpoint, entry);
|
QTAILQ_REMOVE(&cpu->breakpoints, breakpoint, entry);
|
||||||
|
|
||||||
breakpoint_invalidate(cpu, breakpoint->pc);
|
breakpoint_invalidate(cpu, breakpoint->pc);
|
||||||
|
|
||||||
g_free(breakpoint);
|
g_free(breakpoint);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove all matching breakpoints. */
|
/* Remove all matching breakpoints. */
|
||||||
void cpu_breakpoint_remove_all(CPUState *cpu, int mask)
|
void cpu_breakpoint_remove_all(CPUState *cpu, int mask)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_HAS_ICE)
|
|
||||||
CPUBreakpoint *bp, *next;
|
CPUBreakpoint *bp, *next;
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(bp, &cpu->breakpoints, entry, next) {
|
QTAILQ_FOREACH_SAFE(bp, &cpu->breakpoints, entry, next) {
|
||||||
@@ -751,14 +743,12 @@ void cpu_breakpoint_remove_all(CPUState *cpu, int mask)
|
|||||||
cpu_breakpoint_remove_by_ref(cpu, bp);
|
cpu_breakpoint_remove_by_ref(cpu, bp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enable or disable single step mode. EXCP_DEBUG is returned by the
|
/* enable or disable single step mode. EXCP_DEBUG is returned by the
|
||||||
CPU loop after each instruction */
|
CPU loop after each instruction */
|
||||||
void cpu_single_step(CPUState *cpu, int enabled)
|
void cpu_single_step(CPUState *cpu, int enabled)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_HAS_ICE)
|
|
||||||
if (cpu->singlestep_enabled != enabled) {
|
if (cpu->singlestep_enabled != enabled) {
|
||||||
cpu->singlestep_enabled = enabled;
|
cpu->singlestep_enabled = enabled;
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
@@ -770,7 +760,6 @@ void cpu_single_step(CPUState *cpu, int enabled)
|
|||||||
tb_flush(env);
|
tb_flush(env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_abort(CPUState *cpu, const char *fmt, ...)
|
void cpu_abort(CPUState *cpu, const char *fmt, ...)
|
||||||
@@ -812,11 +801,11 @@ static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
|
|||||||
|
|
||||||
/* The list is protected by the iothread lock here. */
|
/* The list is protected by the iothread lock here. */
|
||||||
block = ram_list.mru_block;
|
block = ram_list.mru_block;
|
||||||
if (block && addr - block->offset < block->length) {
|
if (block && addr - block->offset < block->max_length) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
if (addr - block->offset < block->length) {
|
if (addr - block->offset < block->max_length) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -840,7 +829,7 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
|
|||||||
|
|
||||||
block = qemu_get_ram_block(start);
|
block = qemu_get_ram_block(start);
|
||||||
assert(block == qemu_get_ram_block(end - 1));
|
assert(block == qemu_get_ram_block(end - 1));
|
||||||
start1 = (uintptr_t)block->host + (start - block->offset);
|
start1 = (uintptr_t)ramblock_ptr(block, start - block->offset);
|
||||||
cpu_tlb_reset_dirty_all(start1, length);
|
cpu_tlb_reset_dirty_all(start1, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,7 +839,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
|
|||||||
{
|
{
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
return;
|
return;
|
||||||
cpu_physical_memory_clear_dirty_range(start, length, client);
|
cpu_physical_memory_clear_dirty_range_type(start, length, client);
|
||||||
|
|
||||||
if (tcg_enabled()) {
|
if (tcg_enabled()) {
|
||||||
tlb_reset_dirty_range_all(start, length);
|
tlb_reset_dirty_range_all(start, length);
|
||||||
@@ -1186,7 +1175,7 @@ static ram_addr_t find_ram_offset(ram_addr_t size)
|
|||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
ram_addr_t end, next = RAM_ADDR_MAX;
|
ram_addr_t end, next = RAM_ADDR_MAX;
|
||||||
|
|
||||||
end = block->offset + block->length;
|
end = block->offset + block->max_length;
|
||||||
|
|
||||||
QTAILQ_FOREACH(next_block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(next_block, &ram_list.blocks, next) {
|
||||||
if (next_block->offset >= end) {
|
if (next_block->offset >= end) {
|
||||||
@@ -1214,7 +1203,7 @@ ram_addr_t last_ram_offset(void)
|
|||||||
ram_addr_t last = 0;
|
ram_addr_t last = 0;
|
||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next)
|
QTAILQ_FOREACH(block, &ram_list.blocks, next)
|
||||||
last = MAX(last, block->offset + block->length);
|
last = MAX(last, block->offset + block->max_length);
|
||||||
|
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
@@ -1296,6 +1285,49 @@ static int memory_try_enable_merging(void *addr, size_t len)
|
|||||||
return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
|
return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Only legal before guest might have detected the memory size: e.g. on
|
||||||
|
* incoming migration, or right after reset.
|
||||||
|
*
|
||||||
|
* As memory core doesn't know how is memory accessed, it is up to
|
||||||
|
* resize callback to update device state and/or add assertions to detect
|
||||||
|
* misuse, if necessary.
|
||||||
|
*/
|
||||||
|
int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp)
|
||||||
|
{
|
||||||
|
RAMBlock *block = find_ram_block(base);
|
||||||
|
|
||||||
|
assert(block);
|
||||||
|
|
||||||
|
if (block->used_length == newsize) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(block->flags & RAM_RESIZEABLE)) {
|
||||||
|
error_setg_errno(errp, EINVAL,
|
||||||
|
"Length mismatch: %s: 0x" RAM_ADDR_FMT
|
||||||
|
" in != 0x" RAM_ADDR_FMT, block->idstr,
|
||||||
|
newsize, block->used_length);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block->max_length < newsize) {
|
||||||
|
error_setg_errno(errp, EINVAL,
|
||||||
|
"Length too large: %s: 0x" RAM_ADDR_FMT
|
||||||
|
" > 0x" RAM_ADDR_FMT, block->idstr,
|
||||||
|
newsize, block->max_length);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_physical_memory_clear_dirty_range(block->offset, block->used_length);
|
||||||
|
block->used_length = newsize;
|
||||||
|
cpu_physical_memory_set_dirty_range(block->offset, block->used_length);
|
||||||
|
memory_region_set_size(block->mr, newsize);
|
||||||
|
if (block->resized) {
|
||||||
|
block->resized(block->idstr, newsize, block->host);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
||||||
{
|
{
|
||||||
RAMBlock *block;
|
RAMBlock *block;
|
||||||
@@ -1305,13 +1337,14 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
|||||||
|
|
||||||
/* This assumes the iothread lock is taken here too. */
|
/* This assumes the iothread lock is taken here too. */
|
||||||
qemu_mutex_lock_ramlist();
|
qemu_mutex_lock_ramlist();
|
||||||
new_block->offset = find_ram_offset(new_block->length);
|
new_block->offset = find_ram_offset(new_block->max_length);
|
||||||
|
|
||||||
if (!new_block->host) {
|
if (!new_block->host) {
|
||||||
if (xen_enabled()) {
|
if (xen_enabled()) {
|
||||||
xen_ram_alloc(new_block->offset, new_block->length, new_block->mr);
|
xen_ram_alloc(new_block->offset, new_block->max_length,
|
||||||
|
new_block->mr);
|
||||||
} else {
|
} else {
|
||||||
new_block->host = phys_mem_alloc(new_block->length,
|
new_block->host = phys_mem_alloc(new_block->max_length,
|
||||||
&new_block->mr->align);
|
&new_block->mr->align);
|
||||||
if (!new_block->host) {
|
if (!new_block->host) {
|
||||||
error_setg_errno(errp, errno,
|
error_setg_errno(errp, errno,
|
||||||
@@ -1320,13 +1353,13 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
|||||||
qemu_mutex_unlock_ramlist();
|
qemu_mutex_unlock_ramlist();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memory_try_enable_merging(new_block->host, new_block->length);
|
memory_try_enable_merging(new_block->host, new_block->max_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the list sorted from biggest to smallest block. */
|
/* Keep the list sorted from biggest to smallest block. */
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
if (block->length < new_block->length) {
|
if (block->max_length < new_block->max_length) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1350,14 +1383,15 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
|||||||
old_ram_size, new_ram_size);
|
old_ram_size, new_ram_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cpu_physical_memory_set_dirty_range(new_block->offset, new_block->length);
|
cpu_physical_memory_set_dirty_range(new_block->offset,
|
||||||
|
new_block->used_length);
|
||||||
|
|
||||||
qemu_ram_setup_dump(new_block->host, new_block->length);
|
qemu_ram_setup_dump(new_block->host, new_block->max_length);
|
||||||
qemu_madvise(new_block->host, new_block->length, QEMU_MADV_HUGEPAGE);
|
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
|
||||||
qemu_madvise(new_block->host, new_block->length, QEMU_MADV_DONTFORK);
|
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
|
||||||
|
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
kvm_setup_guest_memory(new_block->host, new_block->length);
|
kvm_setup_guest_memory(new_block->host, new_block->max_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_block->offset;
|
return new_block->offset;
|
||||||
@@ -1391,7 +1425,8 @@ ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
|||||||
size = TARGET_PAGE_ALIGN(size);
|
size = TARGET_PAGE_ALIGN(size);
|
||||||
new_block = g_malloc0(sizeof(*new_block));
|
new_block = g_malloc0(sizeof(*new_block));
|
||||||
new_block->mr = mr;
|
new_block->mr = mr;
|
||||||
new_block->length = size;
|
new_block->used_length = size;
|
||||||
|
new_block->max_length = size;
|
||||||
new_block->flags = share ? RAM_SHARED : 0;
|
new_block->flags = share ? RAM_SHARED : 0;
|
||||||
new_block->host = file_ram_alloc(new_block, size,
|
new_block->host = file_ram_alloc(new_block, size,
|
||||||
mem_path, errp);
|
mem_path, errp);
|
||||||
@@ -1410,7 +1445,12 @@ ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
static
|
||||||
|
ram_addr_t qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
|
||||||
|
void (*resized)(const char*,
|
||||||
|
uint64_t length,
|
||||||
|
void *host),
|
||||||
|
void *host, bool resizeable,
|
||||||
MemoryRegion *mr, Error **errp)
|
MemoryRegion *mr, Error **errp)
|
||||||
{
|
{
|
||||||
RAMBlock *new_block;
|
RAMBlock *new_block;
|
||||||
@@ -1418,14 +1458,21 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
|||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
size = TARGET_PAGE_ALIGN(size);
|
size = TARGET_PAGE_ALIGN(size);
|
||||||
|
max_size = TARGET_PAGE_ALIGN(max_size);
|
||||||
new_block = g_malloc0(sizeof(*new_block));
|
new_block = g_malloc0(sizeof(*new_block));
|
||||||
new_block->mr = mr;
|
new_block->mr = mr;
|
||||||
new_block->length = size;
|
new_block->resized = resized;
|
||||||
|
new_block->used_length = size;
|
||||||
|
new_block->max_length = max_size;
|
||||||
|
assert(max_size >= size);
|
||||||
new_block->fd = -1;
|
new_block->fd = -1;
|
||||||
new_block->host = host;
|
new_block->host = host;
|
||||||
if (host) {
|
if (host) {
|
||||||
new_block->flags |= RAM_PREALLOC;
|
new_block->flags |= RAM_PREALLOC;
|
||||||
}
|
}
|
||||||
|
if (resizeable) {
|
||||||
|
new_block->flags |= RAM_RESIZEABLE;
|
||||||
|
}
|
||||||
addr = ram_block_add(new_block, &local_err);
|
addr = ram_block_add(new_block, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
g_free(new_block);
|
g_free(new_block);
|
||||||
@@ -1435,9 +1482,24 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
|||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
|
||||||
|
MemoryRegion *mr, Error **errp)
|
||||||
|
{
|
||||||
|
return qemu_ram_alloc_internal(size, size, NULL, host, false, mr, errp);
|
||||||
|
}
|
||||||
|
|
||||||
ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp)
|
ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp)
|
||||||
{
|
{
|
||||||
return qemu_ram_alloc_from_ptr(size, NULL, mr, errp);
|
return qemu_ram_alloc_internal(size, size, NULL, NULL, false, mr, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ram_addr_t qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t maxsz,
|
||||||
|
void (*resized)(const char*,
|
||||||
|
uint64_t length,
|
||||||
|
void *host),
|
||||||
|
MemoryRegion *mr, Error **errp)
|
||||||
|
{
|
||||||
|
return qemu_ram_alloc_internal(size, maxsz, resized, NULL, true, mr, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_ram_free_from_ptr(ram_addr_t addr)
|
void qemu_ram_free_from_ptr(ram_addr_t addr)
|
||||||
@@ -1475,11 +1537,11 @@ void qemu_ram_free(ram_addr_t addr)
|
|||||||
xen_invalidate_map_cache_entry(block->host);
|
xen_invalidate_map_cache_entry(block->host);
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
} else if (block->fd >= 0) {
|
} else if (block->fd >= 0) {
|
||||||
munmap(block->host, block->length);
|
munmap(block->host, block->max_length);
|
||||||
close(block->fd);
|
close(block->fd);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
qemu_anon_ram_free(block->host, block->length);
|
qemu_anon_ram_free(block->host, block->max_length);
|
||||||
}
|
}
|
||||||
g_free(block);
|
g_free(block);
|
||||||
break;
|
break;
|
||||||
@@ -1499,8 +1561,8 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
|
|||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
offset = addr - block->offset;
|
offset = addr - block->offset;
|
||||||
if (offset < block->length) {
|
if (offset < block->max_length) {
|
||||||
vaddr = block->host + offset;
|
vaddr = ramblock_ptr(block, offset);
|
||||||
if (block->flags & RAM_PREALLOC) {
|
if (block->flags & RAM_PREALLOC) {
|
||||||
;
|
;
|
||||||
} else if (xen_enabled()) {
|
} else if (xen_enabled()) {
|
||||||
@@ -1551,7 +1613,7 @@ void *qemu_get_ram_block_host_ptr(ram_addr_t addr)
|
|||||||
{
|
{
|
||||||
RAMBlock *block = qemu_get_ram_block(addr);
|
RAMBlock *block = qemu_get_ram_block(addr);
|
||||||
|
|
||||||
return block->host;
|
return ramblock_ptr(block, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a host pointer to ram allocated with qemu_ram_alloc.
|
/* Return a host pointer to ram allocated with qemu_ram_alloc.
|
||||||
@@ -1575,10 +1637,10 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
|
|||||||
return xen_map_cache(addr, 0, 0);
|
return xen_map_cache(addr, 0, 0);
|
||||||
} else if (block->host == NULL) {
|
} else if (block->host == NULL) {
|
||||||
block->host =
|
block->host =
|
||||||
xen_map_cache(block->offset, block->length, 1);
|
xen_map_cache(block->offset, block->max_length, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return block->host + (addr - block->offset);
|
return ramblock_ptr(block, addr - block->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
|
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
|
||||||
@@ -1594,10 +1656,10 @@ static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
|
|||||||
RAMBlock *block;
|
RAMBlock *block;
|
||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
if (addr - block->offset < block->length) {
|
if (addr - block->offset < block->max_length) {
|
||||||
if (addr - block->offset + *size > block->length)
|
if (addr - block->offset + *size > block->max_length)
|
||||||
*size = block->length - addr + block->offset;
|
*size = block->max_length - addr + block->offset;
|
||||||
return block->host + (addr - block->offset);
|
return ramblock_ptr(block, addr - block->offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1619,7 +1681,7 @@ MemoryRegion *qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
block = ram_list.mru_block;
|
block = ram_list.mru_block;
|
||||||
if (block && block->host && host - block->host < block->length) {
|
if (block && block->host && host - block->host < block->max_length) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1628,7 +1690,7 @@ MemoryRegion *qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
|
|||||||
if (block->host == NULL) {
|
if (block->host == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (host - block->host < block->length) {
|
if (host - block->host < block->max_length) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1768,7 +1830,7 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
|
|||||||
unsigned len)
|
unsigned len)
|
||||||
{
|
{
|
||||||
subpage_t *subpage = opaque;
|
subpage_t *subpage = opaque;
|
||||||
uint8_t buf[4];
|
uint8_t buf[8];
|
||||||
|
|
||||||
#if defined(DEBUG_SUBPAGE)
|
#if defined(DEBUG_SUBPAGE)
|
||||||
printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
|
printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
|
||||||
@@ -1782,6 +1844,8 @@ static uint64_t subpage_read(void *opaque, hwaddr addr,
|
|||||||
return lduw_p(buf);
|
return lduw_p(buf);
|
||||||
case 4:
|
case 4:
|
||||||
return ldl_p(buf);
|
return ldl_p(buf);
|
||||||
|
case 8:
|
||||||
|
return ldq_p(buf);
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@@ -1791,7 +1855,7 @@ static void subpage_write(void *opaque, hwaddr addr,
|
|||||||
uint64_t value, unsigned len)
|
uint64_t value, unsigned len)
|
||||||
{
|
{
|
||||||
subpage_t *subpage = opaque;
|
subpage_t *subpage = opaque;
|
||||||
uint8_t buf[4];
|
uint8_t buf[8];
|
||||||
|
|
||||||
#if defined(DEBUG_SUBPAGE)
|
#if defined(DEBUG_SUBPAGE)
|
||||||
printf("%s: subpage %p len %u addr " TARGET_FMT_plx
|
printf("%s: subpage %p len %u addr " TARGET_FMT_plx
|
||||||
@@ -1808,6 +1872,9 @@ static void subpage_write(void *opaque, hwaddr addr,
|
|||||||
case 4:
|
case 4:
|
||||||
stl_p(buf, value);
|
stl_p(buf, value);
|
||||||
break;
|
break;
|
||||||
|
case 8:
|
||||||
|
stq_p(buf, value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@@ -1830,6 +1897,10 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
|
|||||||
static const MemoryRegionOps subpage_ops = {
|
static const MemoryRegionOps subpage_ops = {
|
||||||
.read = subpage_read,
|
.read = subpage_read,
|
||||||
.write = subpage_write,
|
.write = subpage_write,
|
||||||
|
.impl.min_access_size = 1,
|
||||||
|
.impl.max_access_size = 8,
|
||||||
|
.valid.min_access_size = 1,
|
||||||
|
.valid.max_access_size = 8,
|
||||||
.valid.accepts = subpage_accepts,
|
.valid.accepts = subpage_accepts,
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
@@ -2873,7 +2944,7 @@ void qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
|
|||||||
RAMBlock *block;
|
RAMBlock *block;
|
||||||
|
|
||||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||||
func(block->host, block->offset, block->length, opaque);
|
func(block->host, block->offset, block->used_length, opaque);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
15
gdbstub.c
15
gdbstub.c
@@ -317,6 +317,8 @@ static GDBState *gdbserver_state;
|
|||||||
|
|
||||||
bool gdb_has_xml;
|
bool gdb_has_xml;
|
||||||
|
|
||||||
|
int semihosting_target = SEMIHOSTING_TARGET_AUTO;
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
/* XXX: This is not thread safe. Do we care? */
|
/* XXX: This is not thread safe. Do we care? */
|
||||||
static int gdbserver_fd = -1;
|
static int gdbserver_fd = -1;
|
||||||
@@ -351,10 +353,19 @@ static enum {
|
|||||||
GDB_SYS_DISABLED,
|
GDB_SYS_DISABLED,
|
||||||
} gdb_syscall_mode;
|
} gdb_syscall_mode;
|
||||||
|
|
||||||
/* If gdb is connected when the first semihosting syscall occurs then use
|
/* Decide if either remote gdb syscalls or native file IO should be used. */
|
||||||
remote gdb syscalls. Otherwise use native file IO. */
|
|
||||||
int use_gdb_syscalls(void)
|
int use_gdb_syscalls(void)
|
||||||
{
|
{
|
||||||
|
if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) {
|
||||||
|
/* -semihosting-config target=native */
|
||||||
|
return false;
|
||||||
|
} else if (semihosting_target == SEMIHOSTING_TARGET_GDB) {
|
||||||
|
/* -semihosting-config target=gdb */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -semihosting-config target=auto */
|
||||||
|
/* On the first call check if gdb is connected and remember. */
|
||||||
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
|
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
|
||||||
gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
|
gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
|
||||||
: GDB_SYS_DISABLED);
|
: GDB_SYS_DISABLED);
|
||||||
|
233
hmp.c
233
hmp.c
@@ -290,14 +290,131 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
|
|||||||
qapi_free_CpuInfoList(cpu_list);
|
qapi_free_CpuInfoList(cpu_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_block_info(Monitor *mon, BlockInfo *info,
|
||||||
|
BlockDeviceInfo *inserted, bool verbose)
|
||||||
|
{
|
||||||
|
ImageInfo *image_info;
|
||||||
|
|
||||||
|
assert(!info || !info->has_inserted || info->inserted == inserted);
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
monitor_printf(mon, "%s", info->device);
|
||||||
|
if (inserted && inserted->has_node_name) {
|
||||||
|
monitor_printf(mon, " (%s)", inserted->node_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(inserted);
|
||||||
|
monitor_printf(mon, "%s",
|
||||||
|
inserted->has_node_name
|
||||||
|
? inserted->node_name
|
||||||
|
: "<anonymous>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inserted) {
|
||||||
|
monitor_printf(mon, ": %s (%s%s%s)\n",
|
||||||
|
inserted->file,
|
||||||
|
inserted->drv,
|
||||||
|
inserted->ro ? ", read-only" : "",
|
||||||
|
inserted->encrypted ? ", encrypted" : "");
|
||||||
|
} else {
|
||||||
|
monitor_printf(mon, ": [not inserted]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
|
||||||
|
monitor_printf(mon, " I/O status: %s\n",
|
||||||
|
BlockDeviceIoStatus_lookup[info->io_status]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->removable) {
|
||||||
|
monitor_printf(mon, " Removable device: %slocked, tray %s\n",
|
||||||
|
info->locked ? "" : "not ",
|
||||||
|
info->tray_open ? "open" : "closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!inserted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor_printf(mon, " Cache mode: %s%s%s\n",
|
||||||
|
inserted->cache->writeback ? "writeback" : "writethrough",
|
||||||
|
inserted->cache->direct ? ", direct" : "",
|
||||||
|
inserted->cache->no_flush ? ", ignore flushes" : "");
|
||||||
|
|
||||||
|
if (inserted->has_backing_file) {
|
||||||
|
monitor_printf(mon,
|
||||||
|
" Backing file: %s "
|
||||||
|
"(chain depth: %" PRId64 ")\n",
|
||||||
|
inserted->backing_file,
|
||||||
|
inserted->backing_file_depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
||||||
|
monitor_printf(mon, " Detect zeroes: %s\n",
|
||||||
|
BlockdevDetectZeroesOptions_lookup[inserted->detect_zeroes]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inserted->bps || inserted->bps_rd || inserted->bps_wr ||
|
||||||
|
inserted->iops || inserted->iops_rd || inserted->iops_wr)
|
||||||
|
{
|
||||||
|
monitor_printf(mon, " I/O throttling: bps=%" PRId64
|
||||||
|
" bps_rd=%" PRId64 " bps_wr=%" PRId64
|
||||||
|
" bps_max=%" PRId64
|
||||||
|
" bps_rd_max=%" PRId64
|
||||||
|
" bps_wr_max=%" PRId64
|
||||||
|
" iops=%" PRId64 " iops_rd=%" PRId64
|
||||||
|
" iops_wr=%" PRId64
|
||||||
|
" iops_max=%" PRId64
|
||||||
|
" iops_rd_max=%" PRId64
|
||||||
|
" iops_wr_max=%" PRId64
|
||||||
|
" iops_size=%" PRId64 "\n",
|
||||||
|
inserted->bps,
|
||||||
|
inserted->bps_rd,
|
||||||
|
inserted->bps_wr,
|
||||||
|
inserted->bps_max,
|
||||||
|
inserted->bps_rd_max,
|
||||||
|
inserted->bps_wr_max,
|
||||||
|
inserted->iops,
|
||||||
|
inserted->iops_rd,
|
||||||
|
inserted->iops_wr,
|
||||||
|
inserted->iops_max,
|
||||||
|
inserted->iops_rd_max,
|
||||||
|
inserted->iops_wr_max,
|
||||||
|
inserted->iops_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
monitor_printf(mon, "\nImages:\n");
|
||||||
|
image_info = inserted->image;
|
||||||
|
while (1) {
|
||||||
|
bdrv_image_info_dump((fprintf_function)monitor_printf,
|
||||||
|
mon, image_info);
|
||||||
|
if (image_info->has_backing_image) {
|
||||||
|
image_info = image_info->backing_image;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void hmp_info_block(Monitor *mon, const QDict *qdict)
|
void hmp_info_block(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
BlockInfoList *block_list, *info;
|
BlockInfoList *block_list, *info;
|
||||||
ImageInfo *image_info;
|
BlockDeviceInfoList *blockdev_list, *blockdev;
|
||||||
const char *device = qdict_get_try_str(qdict, "device");
|
const char *device = qdict_get_try_str(qdict, "device");
|
||||||
bool verbose = qdict_get_try_bool(qdict, "verbose", 0);
|
bool verbose = qdict_get_try_bool(qdict, "verbose", 0);
|
||||||
|
bool nodes = qdict_get_try_bool(qdict, "nodes", 0);
|
||||||
|
bool printed = false;
|
||||||
|
|
||||||
block_list = qmp_query_block(NULL);
|
/* Print BlockBackend information */
|
||||||
|
if (!nodes) {
|
||||||
|
block_list = qmp_query_block(false);
|
||||||
|
} else {
|
||||||
|
block_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (info = block_list; info; info = info->next) {
|
for (info = block_list; info; info = info->next) {
|
||||||
if (device && strcmp(device, info->value->device)) {
|
if (device && strcmp(device, info->value->device)) {
|
||||||
@@ -308,102 +425,40 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
|
|||||||
monitor_printf(mon, "\n");
|
monitor_printf(mon, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor_printf(mon, "%s", info->value->device);
|
print_block_info(mon, info->value, info->value->has_inserted
|
||||||
if (info->value->has_inserted) {
|
? info->value->inserted : NULL,
|
||||||
monitor_printf(mon, ": %s (%s%s%s)\n",
|
verbose);
|
||||||
info->value->inserted->file,
|
printed = true;
|
||||||
info->value->inserted->drv,
|
|
||||||
info->value->inserted->ro ? ", read-only" : "",
|
|
||||||
info->value->inserted->encrypted ? ", encrypted" : "");
|
|
||||||
} else {
|
|
||||||
monitor_printf(mon, ": [not inserted]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->value->has_io_status && info->value->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
|
|
||||||
monitor_printf(mon, " I/O status: %s\n",
|
|
||||||
BlockDeviceIoStatus_lookup[info->value->io_status]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->value->removable) {
|
|
||||||
monitor_printf(mon, " Removable device: %slocked, tray %s\n",
|
|
||||||
info->value->locked ? "" : "not ",
|
|
||||||
info->value->tray_open ? "open" : "closed");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!info->value->has_inserted) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->value->inserted->has_backing_file) {
|
|
||||||
monitor_printf(mon,
|
|
||||||
" Backing file: %s "
|
|
||||||
"(chain depth: %" PRId64 ")\n",
|
|
||||||
info->value->inserted->backing_file,
|
|
||||||
info->value->inserted->backing_file_depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
|
||||||
monitor_printf(mon, " Detect zeroes: %s\n",
|
|
||||||
BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->value->inserted->bps
|
|
||||||
|| info->value->inserted->bps_rd
|
|
||||||
|| info->value->inserted->bps_wr
|
|
||||||
|| info->value->inserted->iops
|
|
||||||
|| info->value->inserted->iops_rd
|
|
||||||
|| info->value->inserted->iops_wr)
|
|
||||||
{
|
|
||||||
monitor_printf(mon, " I/O throttling: bps=%" PRId64
|
|
||||||
" bps_rd=%" PRId64 " bps_wr=%" PRId64
|
|
||||||
" bps_max=%" PRId64
|
|
||||||
" bps_rd_max=%" PRId64
|
|
||||||
" bps_wr_max=%" PRId64
|
|
||||||
" iops=%" PRId64 " iops_rd=%" PRId64
|
|
||||||
" iops_wr=%" PRId64
|
|
||||||
" iops_max=%" PRId64
|
|
||||||
" iops_rd_max=%" PRId64
|
|
||||||
" iops_wr_max=%" PRId64
|
|
||||||
" iops_size=%" PRId64 "\n",
|
|
||||||
info->value->inserted->bps,
|
|
||||||
info->value->inserted->bps_rd,
|
|
||||||
info->value->inserted->bps_wr,
|
|
||||||
info->value->inserted->bps_max,
|
|
||||||
info->value->inserted->bps_rd_max,
|
|
||||||
info->value->inserted->bps_wr_max,
|
|
||||||
info->value->inserted->iops,
|
|
||||||
info->value->inserted->iops_rd,
|
|
||||||
info->value->inserted->iops_wr,
|
|
||||||
info->value->inserted->iops_max,
|
|
||||||
info->value->inserted->iops_rd_max,
|
|
||||||
info->value->inserted->iops_wr_max,
|
|
||||||
info->value->inserted->iops_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
monitor_printf(mon, "\nImages:\n");
|
|
||||||
image_info = info->value->inserted->image;
|
|
||||||
while (1) {
|
|
||||||
bdrv_image_info_dump((fprintf_function)monitor_printf,
|
|
||||||
mon, image_info);
|
|
||||||
if (image_info->has_backing_image) {
|
|
||||||
image_info = image_info->backing_image;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qapi_free_BlockInfoList(block_list);
|
qapi_free_BlockInfoList(block_list);
|
||||||
|
|
||||||
|
if ((!device && !nodes) || printed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print node information */
|
||||||
|
blockdev_list = qmp_query_named_block_nodes(NULL);
|
||||||
|
for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
|
||||||
|
assert(blockdev->value->has_node_name);
|
||||||
|
if (device && strcmp(device, blockdev->value->node_name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockdev != blockdev_list) {
|
||||||
|
monitor_printf(mon, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_block_info(mon, NULL, blockdev->value, verbose);
|
||||||
|
}
|
||||||
|
qapi_free_BlockDeviceInfoList(blockdev_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
|
void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
BlockStatsList *stats_list, *stats;
|
BlockStatsList *stats_list, *stats;
|
||||||
|
|
||||||
stats_list = qmp_query_blockstats(NULL);
|
stats_list = qmp_query_blockstats(false, false, NULL);
|
||||||
|
|
||||||
for (stats = stats_list; stats; stats = stats->next) {
|
for (stats = stats_list; stats; stats = stats->next) {
|
||||||
if (!stats->value->has_device) {
|
if (!stats->value->has_device) {
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "fsdev/qemu-fsdev.h"
|
#include "fsdev/qemu-fsdev.h"
|
||||||
#include "qemu/thread.h"
|
#include "qemu/thread.h"
|
||||||
|
#include "qemu/event_notifier.h"
|
||||||
#include "block/coroutine.h"
|
#include "block/coroutine.h"
|
||||||
#include "virtio-9p-coth.h"
|
#include "virtio-9p-coth.h"
|
||||||
|
|
||||||
@@ -26,15 +27,11 @@ void co_run_in_worker_bh(void *opaque)
|
|||||||
g_thread_pool_push(v9fs_pool.pool, co, NULL);
|
g_thread_pool_push(v9fs_pool.pool, co, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void v9fs_qemu_process_req_done(void *arg)
|
static void v9fs_qemu_process_req_done(EventNotifier *e)
|
||||||
{
|
{
|
||||||
char byte;
|
|
||||||
ssize_t len;
|
|
||||||
Coroutine *co;
|
Coroutine *co;
|
||||||
|
|
||||||
do {
|
event_notifier_test_and_clear(e);
|
||||||
len = read(v9fs_pool.rfd, &byte, sizeof(byte));
|
|
||||||
} while (len == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
while ((co = g_async_queue_try_pop(v9fs_pool.completed)) != NULL) {
|
while ((co = g_async_queue_try_pop(v9fs_pool.completed)) != NULL) {
|
||||||
qemu_coroutine_enter(co, NULL);
|
qemu_coroutine_enter(co, NULL);
|
||||||
@@ -43,22 +40,18 @@ static void v9fs_qemu_process_req_done(void *arg)
|
|||||||
|
|
||||||
static void v9fs_thread_routine(gpointer data, gpointer user_data)
|
static void v9fs_thread_routine(gpointer data, gpointer user_data)
|
||||||
{
|
{
|
||||||
ssize_t len;
|
|
||||||
char byte = 0;
|
|
||||||
Coroutine *co = data;
|
Coroutine *co = data;
|
||||||
|
|
||||||
qemu_coroutine_enter(co, NULL);
|
qemu_coroutine_enter(co, NULL);
|
||||||
|
|
||||||
g_async_queue_push(v9fs_pool.completed, co);
|
g_async_queue_push(v9fs_pool.completed, co);
|
||||||
do {
|
|
||||||
len = write(v9fs_pool.wfd, &byte, sizeof(byte));
|
event_notifier_set(&v9fs_pool.e);
|
||||||
} while (len == -1 && errno == EINTR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int v9fs_init_worker_threads(void)
|
int v9fs_init_worker_threads(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int notifier_fds[2];
|
|
||||||
V9fsThPool *p = &v9fs_pool;
|
V9fsThPool *p = &v9fs_pool;
|
||||||
sigset_t set, oldset;
|
sigset_t set, oldset;
|
||||||
|
|
||||||
@@ -66,10 +59,6 @@ int v9fs_init_worker_threads(void)
|
|||||||
/* Leave signal handling to the iothread. */
|
/* Leave signal handling to the iothread. */
|
||||||
pthread_sigmask(SIG_SETMASK, &set, &oldset);
|
pthread_sigmask(SIG_SETMASK, &set, &oldset);
|
||||||
|
|
||||||
if (qemu_pipe(notifier_fds) == -1) {
|
|
||||||
ret = -1;
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
p->pool = g_thread_pool_new(v9fs_thread_routine, p, -1, FALSE, NULL);
|
p->pool = g_thread_pool_new(v9fs_thread_routine, p, -1, FALSE, NULL);
|
||||||
if (!p->pool) {
|
if (!p->pool) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
@@ -84,13 +73,9 @@ int v9fs_init_worker_threads(void)
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
p->rfd = notifier_fds[0];
|
event_notifier_init(&p->e, 0);
|
||||||
p->wfd = notifier_fds[1];
|
|
||||||
|
|
||||||
fcntl(p->rfd, F_SETFL, O_NONBLOCK);
|
event_notifier_set_handler(&p->e, v9fs_qemu_process_req_done);
|
||||||
fcntl(p->wfd, F_SETFL, O_NONBLOCK);
|
|
||||||
|
|
||||||
qemu_set_fd_handler(p->rfd, v9fs_qemu_process_req_done, NULL, NULL);
|
|
||||||
err_out:
|
err_out:
|
||||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -21,8 +21,8 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
typedef struct V9fsThPool {
|
typedef struct V9fsThPool {
|
||||||
int rfd;
|
EventNotifier e;
|
||||||
int wfd;
|
|
||||||
GThreadPool *pool;
|
GThreadPool *pool;
|
||||||
GAsyncQueue *completed;
|
GAsyncQueue *completed;
|
||||||
} V9fsThPool;
|
} V9fsThPool;
|
||||||
|
@@ -26,6 +26,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += ssi/
|
|||||||
devices-dirs-$(CONFIG_SOFTMMU) += timer/
|
devices-dirs-$(CONFIG_SOFTMMU) += timer/
|
||||||
devices-dirs-$(CONFIG_TPM) += tpm/
|
devices-dirs-$(CONFIG_TPM) += tpm/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += usb/
|
devices-dirs-$(CONFIG_SOFTMMU) += usb/
|
||||||
|
devices-dirs-$(CONFIG_SOFTMMU) += vfio/
|
||||||
devices-dirs-$(CONFIG_VIRTIO) += virtio/
|
devices-dirs-$(CONFIG_VIRTIO) += virtio/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
|
devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += xen/
|
devices-dirs-$(CONFIG_SOFTMMU) += xen/
|
||||||
|
102
hw/arm/boot.c
102
hw/arm/boot.c
@@ -329,6 +329,8 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
|
|||||||
* Returns: the size of the device tree image on success,
|
* Returns: the size of the device tree image on success,
|
||||||
* 0 if the image size exceeds the limit,
|
* 0 if the image size exceeds the limit,
|
||||||
* -1 on errors.
|
* -1 on errors.
|
||||||
|
*
|
||||||
|
* Note: Must not be called unless have_dtb(binfo) is true.
|
||||||
*/
|
*/
|
||||||
static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
||||||
hwaddr addr_limit)
|
hwaddr addr_limit)
|
||||||
@@ -352,7 +354,7 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
g_free(filename);
|
g_free(filename);
|
||||||
} else if (binfo->get_dtb) {
|
} else {
|
||||||
fdt = binfo->get_dtb(binfo, &size);
|
fdt = binfo->get_dtb(binfo, &size);
|
||||||
if (!fdt) {
|
if (!fdt) {
|
||||||
fprintf(stderr, "Board was unable to create a dtb blob\n");
|
fprintf(stderr, "Board was unable to create a dtb blob\n");
|
||||||
@@ -455,6 +457,16 @@ static void do_cpu_reset(void *opaque)
|
|||||||
env->thumb = info->entry & 1;
|
env->thumb = info->entry & 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* If we are booting Linux then we need to check whether we are
|
||||||
|
* booting into secure or non-secure state and adjust the state
|
||||||
|
* accordingly. Out of reset, ARM is defined to be in secure state
|
||||||
|
* (SCR.NS = 0), we change that here if non-secure boot has been
|
||||||
|
* requested.
|
||||||
|
*/
|
||||||
|
if (arm_feature(env, ARM_FEATURE_EL3) && !info->secure_boot) {
|
||||||
|
env->cp15.scr_el3 |= SCR_NS;
|
||||||
|
}
|
||||||
|
|
||||||
if (CPU(cpu) == first_cpu) {
|
if (CPU(cpu) == first_cpu) {
|
||||||
if (env->aarch64) {
|
if (env->aarch64) {
|
||||||
env->pc = info->loader_start;
|
env->pc = info->loader_start;
|
||||||
@@ -476,6 +488,55 @@ static void do_cpu_reset(void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
|
||||||
|
* by key.
|
||||||
|
* @fw_cfg: The firmware config instance to store the data in.
|
||||||
|
* @size_key: The firmware config key to store the size of the loaded
|
||||||
|
* data under, with fw_cfg_add_i32().
|
||||||
|
* @data_key: The firmware config key to store the loaded data under,
|
||||||
|
* with fw_cfg_add_bytes().
|
||||||
|
* @image_name: The name of the image file to load. If it is NULL, the
|
||||||
|
* function returns without doing anything.
|
||||||
|
* @try_decompress: Whether the image should be decompressed (gunzipped) before
|
||||||
|
* adding it to fw_cfg. If decompression fails, the image is
|
||||||
|
* loaded as-is.
|
||||||
|
*
|
||||||
|
* In case of failure, the function prints an error message to stderr and the
|
||||||
|
* process exits with status 1.
|
||||||
|
*/
|
||||||
|
static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
||||||
|
uint16_t data_key, const char *image_name,
|
||||||
|
bool try_decompress)
|
||||||
|
{
|
||||||
|
size_t size = -1;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
if (image_name == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (try_decompress) {
|
||||||
|
size = load_image_gzipped_buffer(image_name,
|
||||||
|
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == (size_t)-1) {
|
||||||
|
gchar *contents;
|
||||||
|
gsize length;
|
||||||
|
|
||||||
|
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
|
||||||
|
fprintf(stderr, "failed to load \"%s\"\n", image_name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
size = length;
|
||||||
|
data = (uint8_t *)contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_cfg_add_i32(fw_cfg, size_key, size);
|
||||||
|
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||||
{
|
{
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
@@ -498,19 +559,48 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load the kernel. */
|
/* Load the kernel. */
|
||||||
if (!info->kernel_filename) {
|
if (!info->kernel_filename || info->firmware_loaded) {
|
||||||
|
|
||||||
if (have_dtb(info)) {
|
if (have_dtb(info)) {
|
||||||
/* If we have a device tree blob, but no kernel to supply it to,
|
/* If we have a device tree blob, but no kernel to supply it to (or
|
||||||
* copy it to the base of RAM for a bootloader to pick up.
|
* the kernel is supposed to be loaded by the bootloader), copy the
|
||||||
|
* DTB to the base of RAM for the bootloader to pick up.
|
||||||
*/
|
*/
|
||||||
if (load_dtb(info->loader_start, info, 0) < 0) {
|
if (load_dtb(info->loader_start, info, 0) < 0) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no kernel specified, do nothing; we will start from address 0
|
if (info->kernel_filename) {
|
||||||
* (typically a boot ROM image) in the same way as hardware.
|
FWCfgState *fw_cfg;
|
||||||
|
bool try_decompressing_kernel;
|
||||||
|
|
||||||
|
fw_cfg = fw_cfg_find();
|
||||||
|
try_decompressing_kernel = arm_feature(&cpu->env,
|
||||||
|
ARM_FEATURE_AARCH64);
|
||||||
|
|
||||||
|
/* Expose the kernel, the command line, and the initrd in fw_cfg.
|
||||||
|
* We don't process them here at all, it's all left to the
|
||||||
|
* firmware.
|
||||||
|
*/
|
||||||
|
load_image_to_fw_cfg(fw_cfg,
|
||||||
|
FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
|
||||||
|
info->kernel_filename,
|
||||||
|
try_decompressing_kernel);
|
||||||
|
load_image_to_fw_cfg(fw_cfg,
|
||||||
|
FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
|
||||||
|
info->initrd_filename, false);
|
||||||
|
|
||||||
|
if (info->kernel_cmdline) {
|
||||||
|
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
||||||
|
strlen(info->kernel_cmdline) + 1);
|
||||||
|
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
|
||||||
|
info->kernel_cmdline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We will start from address 0 (typically a boot ROM image) in the
|
||||||
|
* same way as hardware.
|
||||||
*/
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -152,6 +152,17 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
|||||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
|
/* By default A9 CPUs have EL3 enabled. This board does not currently
|
||||||
|
* support EL3 so the CPU EL3 property is disabled before realization.
|
||||||
|
*/
|
||||||
|
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||||
|
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s->cpu[n] = ARM_CPU(cpuobj);
|
s->cpu[n] = ARM_CPU(cpuobj);
|
||||||
object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
|
object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
|
||||||
"reset-cbar", &error_abort);
|
"reset-cbar", &error_abort);
|
||||||
|
@@ -241,6 +241,18 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
|||||||
cpuobj = object_new(object_class_get_name(oc));
|
cpuobj = object_new(object_class_get_name(oc));
|
||||||
cpu = ARM_CPU(cpuobj);
|
cpu = ARM_CPU(cpuobj);
|
||||||
|
|
||||||
|
/* By default A9 and A15 CPUs have EL3 enabled. This board does not
|
||||||
|
* currently support EL3 so the CPU EL3 property is disabled before
|
||||||
|
* realization.
|
||||||
|
*/
|
||||||
|
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||||
|
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||||
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
|
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
|
||||||
"reset-cbar", &error_abort);
|
"reset-cbar", &error_abort);
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
#define TYPE_INTEGRATOR_CM "integrator_core"
|
#define TYPE_INTEGRATOR_CM "integrator_core"
|
||||||
#define INTEGRATOR_CM(obj) \
|
#define INTEGRATOR_CM(obj) \
|
||||||
@@ -469,6 +470,8 @@ static void integratorcp_init(MachineState *machine)
|
|||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
|
ObjectClass *cpu_oc;
|
||||||
|
Object *cpuobj;
|
||||||
ARMCPU *cpu;
|
ARMCPU *cpu;
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
@@ -476,16 +479,40 @@ static void integratorcp_init(MachineState *machine)
|
|||||||
qemu_irq pic[32];
|
qemu_irq pic[32];
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
int i;
|
int i;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
if (!cpu_model) {
|
if (!cpu_model) {
|
||||||
cpu_model = "arm926";
|
cpu_model = "arm926";
|
||||||
}
|
}
|
||||||
cpu = cpu_arm_init(cpu_model);
|
|
||||||
if (!cpu) {
|
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||||
|
if (!cpu_oc) {
|
||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
fprintf(stderr, "Unable to find CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||||
|
|
||||||
|
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
||||||
|
* currently support EL3 so the CPU EL3 property is disabled before
|
||||||
|
* realization.
|
||||||
|
*/
|
||||||
|
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||||
|
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu = ARM_CPU(cpuobj);
|
||||||
|
|
||||||
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
|
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
|
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
|
||||||
|
@@ -1344,7 +1344,7 @@ static void n8x0_init(MachineState *machine,
|
|||||||
n8x0_dss_setup(s);
|
n8x0_dss_setup(s);
|
||||||
n8x0_cbus_setup(s);
|
n8x0_cbus_setup(s);
|
||||||
n8x0_uart_setup(s);
|
n8x0_uart_setup(s);
|
||||||
if (usb_enabled(false)) {
|
if (usb_enabled()) {
|
||||||
n8x0_usb_setup(s);
|
n8x0_usb_setup(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -273,10 +273,10 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
case 3:
|
case 3:
|
||||||
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||||
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
||||||
s->cpu->env.cp15.c1_sys = 0;
|
s->cpu->env.cp15.sctlr_ns = 0;
|
||||||
s->cpu->env.cp15.c1_coproc = 0;
|
s->cpu->env.cp15.c1_coproc = 0;
|
||||||
s->cpu->env.cp15.ttbr0_el1 = 0;
|
s->cpu->env.cp15.ttbr0_el[1] = 0;
|
||||||
s->cpu->env.cp15.c3 = 0;
|
s->cpu->env.cp15.dacr_ns = 0;
|
||||||
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
||||||
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
||||||
|
|
||||||
@@ -2143,7 +2143,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
|
|||||||
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
|
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usb_enabled(false)) {
|
if (usb_enabled()) {
|
||||||
sysbus_create_simple("sysbus-ohci", 0x4c000000,
|
sysbus_create_simple("sysbus-ohci", 0x4c000000,
|
||||||
qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
|
qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
|
||||||
}
|
}
|
||||||
@@ -2276,7 +2276,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
|
|||||||
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
|
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usb_enabled(false)) {
|
if (usb_enabled()) {
|
||||||
sysbus_create_simple("sysbus-ohci", 0x4c000000,
|
sysbus_create_simple("sysbus-ohci", 0x4c000000,
|
||||||
qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
|
qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
|
||||||
}
|
}
|
||||||
|
@@ -52,7 +52,7 @@ static void realview_init(MachineState *machine,
|
|||||||
CPUARMState *env;
|
CPUARMState *env;
|
||||||
ObjectClass *cpu_oc;
|
ObjectClass *cpu_oc;
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
|
MemoryRegion *ram_lo;
|
||||||
MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
|
MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
|
MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
|
||||||
@@ -101,6 +101,18 @@ static void realview_init(MachineState *machine,
|
|||||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
|
/* By default A9,A15 and ARM1176 CPUs have EL3 enabled. This board
|
||||||
|
* does not currently support EL3 so the CPU EL3 property is disabled
|
||||||
|
* before realization.
|
||||||
|
*/
|
||||||
|
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||||
|
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_pb && is_mpcore) {
|
if (is_pb && is_mpcore) {
|
||||||
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -135,6 +147,7 @@ static void realview_init(MachineState *machine,
|
|||||||
|
|
||||||
if (is_pb && ram_size > 0x20000000) {
|
if (is_pb && ram_size > 0x20000000) {
|
||||||
/* Core tile RAM. */
|
/* Core tile RAM. */
|
||||||
|
ram_lo = g_new(MemoryRegion, 1);
|
||||||
low_ram_size = ram_size - 0x20000000;
|
low_ram_size = ram_size - 0x20000000;
|
||||||
ram_size = 0x20000000;
|
ram_size = 0x20000000;
|
||||||
memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size,
|
memory_region_init_ram(ram_lo, NULL, "realview.lowmem", low_ram_size,
|
||||||
@@ -248,7 +261,7 @@ static void realview_init(MachineState *machine,
|
|||||||
sysbus_connect_irq(busdev, 2, pic[50]);
|
sysbus_connect_irq(busdev, 2, pic[50]);
|
||||||
sysbus_connect_irq(busdev, 3, pic[51]);
|
sysbus_connect_irq(busdev, 3, pic[51]);
|
||||||
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
|
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
|
||||||
if (usb_enabled(false)) {
|
if (usb_enabled()) {
|
||||||
pci_create_simple(pci_bus, -1, "pci-ohci");
|
pci_create_simple(pci_bus, -1, "pci-ohci");
|
||||||
}
|
}
|
||||||
n = drive_get_max_bus(IF_SCSI);
|
n = drive_get_max_bus(IF_SCSI);
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "hw/block/flash.h"
|
#include "hw/block/flash.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
#define VERSATILE_FLASH_ADDR 0x34000000
|
#define VERSATILE_FLASH_ADDR 0x34000000
|
||||||
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
|
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
|
||||||
@@ -175,6 +176,8 @@ static struct arm_boot_info versatile_binfo;
|
|||||||
|
|
||||||
static void versatile_init(MachineState *machine, int board_id)
|
static void versatile_init(MachineState *machine, int board_id)
|
||||||
{
|
{
|
||||||
|
ObjectClass *cpu_oc;
|
||||||
|
Object *cpuobj;
|
||||||
ARMCPU *cpu;
|
ARMCPU *cpu;
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
@@ -189,15 +192,40 @@ static void versatile_init(MachineState *machine, int board_id)
|
|||||||
int n;
|
int n;
|
||||||
int done_smc = 0;
|
int done_smc = 0;
|
||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
if (!machine->cpu_model) {
|
if (!machine->cpu_model) {
|
||||||
machine->cpu_model = "arm926";
|
machine->cpu_model = "arm926";
|
||||||
}
|
}
|
||||||
cpu = cpu_arm_init(machine->cpu_model);
|
|
||||||
if (!cpu) {
|
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
|
||||||
|
if (!cpu_oc) {
|
||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
fprintf(stderr, "Unable to find CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||||
|
|
||||||
|
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
||||||
|
* currently support EL3 so the CPU EL3 property is disabled before
|
||||||
|
* realization.
|
||||||
|
*/
|
||||||
|
if (object_property_find(cpuobj, "has_el3", NULL)) {
|
||||||
|
object_property_set_bool(cpuobj, false, "has_el3", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu = ARM_CPU(cpuobj);
|
||||||
|
|
||||||
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
|
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
@@ -253,7 +281,7 @@ static void versatile_init(MachineState *machine, int board_id)
|
|||||||
pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
|
pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (usb_enabled(false)) {
|
if (usb_enabled()) {
|
||||||
pci_create_simple(pci_bus, -1, "pci-ohci");
|
pci_create_simple(pci_bus, -1, "pci-ohci");
|
||||||
}
|
}
|
||||||
n = drive_get_max_bus(IF_SCSI);
|
n = drive_get_max_bus(IF_SCSI);
|
||||||
|
@@ -157,7 +157,27 @@ static hwaddr motherboard_aseries_map[] = {
|
|||||||
|
|
||||||
typedef struct VEDBoardInfo VEDBoardInfo;
|
typedef struct VEDBoardInfo VEDBoardInfo;
|
||||||
|
|
||||||
typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
|
typedef struct {
|
||||||
|
MachineClass parent;
|
||||||
|
VEDBoardInfo *daughterboard;
|
||||||
|
} VexpressMachineClass;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MachineState parent;
|
||||||
|
bool secure;
|
||||||
|
} VexpressMachineState;
|
||||||
|
|
||||||
|
#define TYPE_VEXPRESS_MACHINE "vexpress"
|
||||||
|
#define TYPE_VEXPRESS_A9_MACHINE "vexpress-a9"
|
||||||
|
#define TYPE_VEXPRESS_A15_MACHINE "vexpress-a15"
|
||||||
|
#define VEXPRESS_MACHINE(obj) \
|
||||||
|
OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE)
|
||||||
|
#define VEXPRESS_MACHINE_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(VexpressMachineClass, obj, TYPE_VEXPRESS_MACHINE)
|
||||||
|
#define VEXPRESS_MACHINE_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(VexpressMachineClass, klass, TYPE_VEXPRESS_MACHINE)
|
||||||
|
|
||||||
|
typedef void DBoardInitFn(const VexpressMachineState *machine,
|
||||||
ram_addr_t ram_size,
|
ram_addr_t ram_size,
|
||||||
const char *cpu_model,
|
const char *cpu_model,
|
||||||
qemu_irq *pic);
|
qemu_irq *pic);
|
||||||
@@ -176,7 +196,7 @@ struct VEDBoardInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void init_cpus(const char *cpu_model, const char *privdev,
|
static void init_cpus(const char *cpu_model, const char *privdev,
|
||||||
hwaddr periphbase, qemu_irq *pic)
|
hwaddr periphbase, qemu_irq *pic, bool secure)
|
||||||
{
|
{
|
||||||
ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
@@ -193,6 +213,10 @@ static void init_cpus(const char *cpu_model, const char *privdev,
|
|||||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
|
if (!secure) {
|
||||||
|
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||||
object_property_set_int(cpuobj, periphbase,
|
object_property_set_int(cpuobj, periphbase,
|
||||||
"reset-cbar", &error_abort);
|
"reset-cbar", &error_abort);
|
||||||
@@ -232,7 +256,7 @@ static void init_cpus(const char *cpu_model, const char *privdev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
static void a9_daughterboard_init(const VexpressMachineState *vms,
|
||||||
ram_addr_t ram_size,
|
ram_addr_t ram_size,
|
||||||
const char *cpu_model,
|
const char *cpu_model,
|
||||||
qemu_irq *pic)
|
qemu_irq *pic)
|
||||||
@@ -268,7 +292,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
memory_region_add_subregion(sysmem, 0x60000000, ram);
|
memory_region_add_subregion(sysmem, 0x60000000, ram);
|
||||||
|
|
||||||
/* 0x1e000000 A9MPCore (SCU) private memory region */
|
/* 0x1e000000 A9MPCore (SCU) private memory region */
|
||||||
init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic);
|
init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure);
|
||||||
|
|
||||||
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
|
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
|
||||||
|
|
||||||
@@ -322,7 +346,7 @@ static VEDBoardInfo a9_daughterboard = {
|
|||||||
.init = a9_daughterboard_init,
|
.init = a9_daughterboard_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
static void a15_daughterboard_init(const VexpressMachineState *vms,
|
||||||
ram_addr_t ram_size,
|
ram_addr_t ram_size,
|
||||||
const char *cpu_model,
|
const char *cpu_model,
|
||||||
qemu_irq *pic)
|
qemu_irq *pic)
|
||||||
@@ -354,7 +378,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
||||||
|
|
||||||
/* 0x2c000000 A15MPCore private memory region (GIC) */
|
/* 0x2c000000 A15MPCore private memory region (GIC) */
|
||||||
init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic);
|
init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure);
|
||||||
|
|
||||||
/* A15 daughterboard peripherals: */
|
/* A15 daughterboard peripherals: */
|
||||||
|
|
||||||
@@ -513,9 +537,11 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
|
|||||||
return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
|
return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
static void vexpress_common_init(MachineState *machine)
|
||||||
MachineState *machine)
|
|
||||||
{
|
{
|
||||||
|
VexpressMachineState *vms = VEXPRESS_MACHINE(machine);
|
||||||
|
VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
|
||||||
|
VEDBoardInfo *daughterboard = vmc->daughterboard;;
|
||||||
DeviceState *dev, *sysctl, *pl041;
|
DeviceState *dev, *sysctl, *pl041;
|
||||||
qemu_irq pic[64];
|
qemu_irq pic[64];
|
||||||
uint32_t sys_id;
|
uint32_t sys_id;
|
||||||
@@ -530,8 +556,7 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
|||||||
const hwaddr *map = daughterboard->motherboard_map;
|
const hwaddr *map = daughterboard->motherboard_map;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model,
|
daughterboard->init(vms, machine->ram_size, machine->cpu_model, pic);
|
||||||
pic);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a bios file was provided, attempt to map it into memory
|
* If a bios file was provided, attempt to map it into memory
|
||||||
@@ -678,39 +703,99 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
|||||||
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
|
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
|
||||||
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
|
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
|
||||||
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
|
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
|
||||||
|
/* Indicate that when booting Linux we should be in secure state */
|
||||||
|
daughterboard->bootinfo.secure_boot = true;
|
||||||
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
|
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vexpress_a9_init(MachineState *machine)
|
static bool vexpress_get_secure(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
vexpress_common_init(&a9_daughterboard, machine);
|
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||||
|
|
||||||
|
return vms->secure;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vexpress_a15_init(MachineState *machine)
|
static void vexpress_set_secure(Object *obj, bool value, Error **errp)
|
||||||
{
|
{
|
||||||
vexpress_common_init(&a15_daughterboard, machine);
|
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||||
|
|
||||||
|
vms->secure = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine vexpress_a9_machine = {
|
static void vexpress_instance_init(Object *obj)
|
||||||
.name = "vexpress-a9",
|
{
|
||||||
.desc = "ARM Versatile Express for Cortex-A9",
|
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
|
||||||
.init = vexpress_a9_init,
|
|
||||||
.block_default_type = IF_SCSI,
|
/* EL3 is enabled by default on vexpress */
|
||||||
.max_cpus = 4,
|
vms->secure = true;
|
||||||
|
object_property_add_bool(obj, "secure", vexpress_get_secure,
|
||||||
|
vexpress_set_secure, NULL);
|
||||||
|
object_property_set_description(obj, "secure",
|
||||||
|
"Set on/off to enable/disable the ARM "
|
||||||
|
"Security Extensions (TrustZone)",
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vexpress_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mc->name = TYPE_VEXPRESS_MACHINE;
|
||||||
|
mc->desc = "ARM Versatile Express";
|
||||||
|
mc->init = vexpress_common_init;
|
||||||
|
mc->block_default_type = IF_SCSI;
|
||||||
|
mc->max_cpus = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vexpress_a9_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mc->name = TYPE_VEXPRESS_A9_MACHINE;
|
||||||
|
mc->desc = "ARM Versatile Express for Cortex-A9";
|
||||||
|
|
||||||
|
vmc->daughterboard = &a9_daughterboard;;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vexpress_a15_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mc->name = TYPE_VEXPRESS_A15_MACHINE;
|
||||||
|
mc->desc = "ARM Versatile Express for Cortex-A15";
|
||||||
|
|
||||||
|
vmc->daughterboard = &a15_daughterboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo vexpress_info = {
|
||||||
|
.name = TYPE_VEXPRESS_MACHINE,
|
||||||
|
.parent = TYPE_MACHINE,
|
||||||
|
.abstract = true,
|
||||||
|
.instance_size = sizeof(VexpressMachineState),
|
||||||
|
.instance_init = vexpress_instance_init,
|
||||||
|
.class_size = sizeof(VexpressMachineClass),
|
||||||
|
.class_init = vexpress_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static QEMUMachine vexpress_a15_machine = {
|
static const TypeInfo vexpress_a9_info = {
|
||||||
.name = "vexpress-a15",
|
.name = TYPE_VEXPRESS_A9_MACHINE,
|
||||||
.desc = "ARM Versatile Express for Cortex-A15",
|
.parent = TYPE_VEXPRESS_MACHINE,
|
||||||
.init = vexpress_a15_init,
|
.class_init = vexpress_a9_class_init,
|
||||||
.block_default_type = IF_SCSI,
|
};
|
||||||
.max_cpus = 4,
|
|
||||||
|
static const TypeInfo vexpress_a15_info = {
|
||||||
|
.name = TYPE_VEXPRESS_A15_MACHINE,
|
||||||
|
.parent = TYPE_VEXPRESS_MACHINE,
|
||||||
|
.class_init = vexpress_a15_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vexpress_machine_init(void)
|
static void vexpress_machine_init(void)
|
||||||
{
|
{
|
||||||
qemu_register_machine(&vexpress_a9_machine);
|
type_register_static(&vexpress_info);
|
||||||
qemu_register_machine(&vexpress_a15_machine);
|
type_register_static(&vexpress_a9_info);
|
||||||
|
type_register_static(&vexpress_a15_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_init(vexpress_machine_init);
|
machine_init(vexpress_machine_init);
|
||||||
|
@@ -68,6 +68,7 @@ enum {
|
|||||||
VIRT_UART,
|
VIRT_UART,
|
||||||
VIRT_MMIO,
|
VIRT_MMIO,
|
||||||
VIRT_RTC,
|
VIRT_RTC,
|
||||||
|
VIRT_FW_CFG,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct MemMapEntry {
|
typedef struct MemMapEntry {
|
||||||
@@ -86,6 +87,24 @@ typedef struct VirtBoardInfo {
|
|||||||
uint32_t clock_phandle;
|
uint32_t clock_phandle;
|
||||||
} VirtBoardInfo;
|
} VirtBoardInfo;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MachineClass parent;
|
||||||
|
VirtBoardInfo *daughterboard;
|
||||||
|
} VirtMachineClass;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MachineState parent;
|
||||||
|
bool secure;
|
||||||
|
} VirtMachineState;
|
||||||
|
|
||||||
|
#define TYPE_VIRT_MACHINE "virt"
|
||||||
|
#define VIRT_MACHINE(obj) \
|
||||||
|
OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
|
||||||
|
#define VIRT_MACHINE_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE)
|
||||||
|
#define VIRT_MACHINE_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
|
||||||
|
|
||||||
/* Addresses and sizes of our components.
|
/* Addresses and sizes of our components.
|
||||||
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
|
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
|
||||||
* 128MB..256MB is used for miscellaneous device I/O.
|
* 128MB..256MB is used for miscellaneous device I/O.
|
||||||
@@ -107,6 +126,7 @@ static const MemMapEntry a15memmap[] = {
|
|||||||
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
|
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
|
||||||
[VIRT_UART] = { 0x09000000, 0x00001000 },
|
[VIRT_UART] = { 0x09000000, 0x00001000 },
|
||||||
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
||||||
|
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
|
||||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||||
/* 0x10000000 .. 0x40000000 reserved for PCI */
|
/* 0x10000000 .. 0x40000000 reserved for PCI */
|
||||||
@@ -519,6 +539,23 @@ static void create_flash(const VirtBoardInfo *vbi)
|
|||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_fw_cfg(const VirtBoardInfo *vbi)
|
||||||
|
{
|
||||||
|
hwaddr base = vbi->memmap[VIRT_FW_CFG].base;
|
||||||
|
hwaddr size = vbi->memmap[VIRT_FW_CFG].size;
|
||||||
|
char *nodename;
|
||||||
|
|
||||||
|
fw_cfg_init_mem_wide(base + 8, base, 8);
|
||||||
|
|
||||||
|
nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
|
||||||
|
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||||
|
qemu_fdt_setprop_string(vbi->fdt, nodename,
|
||||||
|
"compatible", "qemu,fw-cfg-mmio");
|
||||||
|
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||||
|
2, base, 2, size);
|
||||||
|
g_free(nodename);
|
||||||
|
}
|
||||||
|
|
||||||
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||||
{
|
{
|
||||||
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
||||||
@@ -529,6 +566,7 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
|||||||
|
|
||||||
static void machvirt_init(MachineState *machine)
|
static void machvirt_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
|
VirtMachineState *vms = VIRT_MACHINE(machine);
|
||||||
qemu_irq pic[NUM_IRQS];
|
qemu_irq pic[NUM_IRQS];
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
int n;
|
int n;
|
||||||
@@ -566,6 +604,10 @@ static void machvirt_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
cpuobj = object_new(object_class_get_name(oc));
|
cpuobj = object_new(object_class_get_name(oc));
|
||||||
|
|
||||||
|
if (!vms->secure) {
|
||||||
|
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
|
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@@ -604,6 +646,8 @@ static void machvirt_init(MachineState *machine)
|
|||||||
*/
|
*/
|
||||||
create_virtio_devices(vbi, pic);
|
create_virtio_devices(vbi, pic);
|
||||||
|
|
||||||
|
create_fw_cfg(vbi);
|
||||||
|
|
||||||
vbi->bootinfo.ram_size = machine->ram_size;
|
vbi->bootinfo.ram_size = machine->ram_size;
|
||||||
vbi->bootinfo.kernel_filename = machine->kernel_filename;
|
vbi->bootinfo.kernel_filename = machine->kernel_filename;
|
||||||
vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
|
vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
|
||||||
@@ -612,19 +656,60 @@ static void machvirt_init(MachineState *machine)
|
|||||||
vbi->bootinfo.board_id = -1;
|
vbi->bootinfo.board_id = -1;
|
||||||
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
|
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
|
||||||
vbi->bootinfo.get_dtb = machvirt_dtb;
|
vbi->bootinfo.get_dtb = machvirt_dtb;
|
||||||
|
vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
||||||
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
|
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QEMUMachine machvirt_a15_machine = {
|
static bool virt_get_secure(Object *obj, Error **errp)
|
||||||
.name = "virt",
|
{
|
||||||
.desc = "ARM Virtual Machine",
|
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||||
.init = machvirt_init,
|
|
||||||
.max_cpus = 8,
|
return vms->secure;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virt_set_secure(Object *obj, bool value, Error **errp)
|
||||||
|
{
|
||||||
|
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||||
|
|
||||||
|
vms->secure = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virt_instance_init(Object *obj)
|
||||||
|
{
|
||||||
|
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||||
|
|
||||||
|
/* EL3 is enabled by default on virt */
|
||||||
|
vms->secure = true;
|
||||||
|
object_property_add_bool(obj, "secure", virt_get_secure,
|
||||||
|
virt_set_secure, NULL);
|
||||||
|
object_property_set_description(obj, "secure",
|
||||||
|
"Set on/off to enable/disable the ARM "
|
||||||
|
"Security Extensions (TrustZone)",
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virt_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mc->name = TYPE_VIRT_MACHINE;
|
||||||
|
mc->desc = "ARM Virtual Machine",
|
||||||
|
mc->init = machvirt_init;
|
||||||
|
mc->max_cpus = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo machvirt_info = {
|
||||||
|
.name = TYPE_VIRT_MACHINE,
|
||||||
|
.parent = TYPE_MACHINE,
|
||||||
|
.instance_size = sizeof(VirtMachineState),
|
||||||
|
.instance_init = virt_instance_init,
|
||||||
|
.class_size = sizeof(VirtMachineClass),
|
||||||
|
.class_init = virt_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void machvirt_machine_init(void)
|
static void machvirt_machine_init(void)
|
||||||
{
|
{
|
||||||
qemu_register_machine(&machvirt_a15_machine);
|
type_register_static(&machvirt_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_init(machvirt_machine_init);
|
machine_init(machvirt_machine_init);
|
||||||
|
@@ -126,6 +126,18 @@ static void zynq_init(MachineState *machine)
|
|||||||
|
|
||||||
cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
|
cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
|
||||||
|
|
||||||
|
/* By default A9 CPUs have EL3 enabled. This board does not
|
||||||
|
* currently support EL3 so the CPU EL3 property is disabled before
|
||||||
|
* realization.
|
||||||
|
*/
|
||||||
|
if (object_property_find(OBJECT(cpu), "has_el3", NULL)) {
|
||||||
|
object_property_set_bool(OBJECT(cpu), false, "has_el3", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err);
|
object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_report("%s", error_get_pretty(err));
|
error_report("%s", error_get_pretty(err));
|
||||||
|
@@ -999,7 +999,7 @@ static IO_READ_PROTO (dsp_read)
|
|||||||
retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
|
retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
|
||||||
if (s->mixer_regs[0x82] & 1) {
|
if (s->mixer_regs[0x82] & 1) {
|
||||||
ack = 1;
|
ack = 1;
|
||||||
s->mixer_regs[0x82] &= ~1;
|
s->mixer_regs[0x82] &= 1;
|
||||||
qemu_irq_lower (s->pic);
|
qemu_irq_lower (s->pic);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1008,7 +1008,7 @@ static IO_READ_PROTO (dsp_read)
|
|||||||
retval = 0xff;
|
retval = 0xff;
|
||||||
if (s->mixer_regs[0x82] & 2) {
|
if (s->mixer_regs[0x82] & 2) {
|
||||||
ack = 1;
|
ack = 1;
|
||||||
s->mixer_regs[0x82] &= ~2;
|
s->mixer_regs[0x82] &= 2;
|
||||||
qemu_irq_lower (s->pic);
|
qemu_irq_lower (s->pic);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@@ -197,7 +197,14 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
|||||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
|
||||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
|
||||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
|
||||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT, s->blocker);
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
|
||||||
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
|
||||||
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
|
||||||
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
|
||||||
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, s->blocker);
|
||||||
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, s->blocker);
|
||||||
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
|
||||||
|
s->blocker);
|
||||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR, s->blocker);
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR, s->blocker);
|
||||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
|
||||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
|
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
|
||||||
|
@@ -476,7 +476,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
|||||||
|
|
||||||
switch (dw10) {
|
switch (dw10) {
|
||||||
case NVME_NUMBER_OF_QUEUES:
|
case NVME_NUMBER_OF_QUEUES:
|
||||||
req->cqe.result = cpu_to_le32(n->num_queues);
|
req->cqe.result =
|
||||||
|
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
return NVME_INVALID_FIELD | NVME_DNR;
|
||||||
@@ -490,7 +491,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
|||||||
|
|
||||||
switch (dw10) {
|
switch (dw10) {
|
||||||
case NVME_NUMBER_OF_QUEUES:
|
case NVME_NUMBER_OF_QUEUES:
|
||||||
req->cqe.result = cpu_to_le32(n->num_queues);
|
req->cqe.result =
|
||||||
|
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
return NVME_INVALID_FIELD | NVME_DNR;
|
||||||
@@ -811,8 +813,9 @@ static int nvme_init(PCIDevice *pci_dev)
|
|||||||
NVME_CAP_SET_AMS(n->bar.cap, 1);
|
NVME_CAP_SET_AMS(n->bar.cap, 1);
|
||||||
NVME_CAP_SET_TO(n->bar.cap, 0xf);
|
NVME_CAP_SET_TO(n->bar.cap, 0xf);
|
||||||
NVME_CAP_SET_CSS(n->bar.cap, 1);
|
NVME_CAP_SET_CSS(n->bar.cap, 1);
|
||||||
|
NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
|
||||||
|
|
||||||
n->bar.vs = 0x00010001;
|
n->bar.vs = 0x00010100;
|
||||||
n->bar.intmc = n->bar.intms = 0;
|
n->bar.intmc = n->bar.intms = 0;
|
||||||
|
|
||||||
for (i = 0; i < n->num_namespaces; i++) {
|
for (i = 0; i < n->num_namespaces; i++) {
|
||||||
|
@@ -688,7 +688,7 @@ typedef struct NvmeCtrl {
|
|||||||
NvmeBar bar;
|
NvmeBar bar;
|
||||||
BlockConf conf;
|
BlockConf conf;
|
||||||
|
|
||||||
uint16_t page_size;
|
uint32_t page_size;
|
||||||
uint16_t page_bits;
|
uint16_t page_bits;
|
||||||
uint16_t max_prp_ents;
|
uint16_t max_prp_ents;
|
||||||
uint16_t cqe_size;
|
uint16_t cqe_size;
|
||||||
|
@@ -744,6 +744,7 @@ static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
|
|||||||
|
|
||||||
dc->realize = pflash_cfi02_realize;
|
dc->realize = pflash_cfi02_realize;
|
||||||
dc->props = pflash_cfi02_properties;
|
dc->props = pflash_cfi02_properties;
|
||||||
|
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo pflash_cfi02_info = {
|
static const TypeInfo pflash_cfi02_info = {
|
||||||
|
@@ -224,21 +224,23 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
|||||||
SerialState *s = opaque;
|
SerialState *s = opaque;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
assert(!(s->lsr & UART_LSR_TEMT));
|
||||||
if (s->tsr_retry <= 0) {
|
if (s->tsr_retry <= 0) {
|
||||||
|
assert(!(s->lsr & UART_LSR_THRE));
|
||||||
|
|
||||||
if (s->fcr & UART_FCR_FE) {
|
if (s->fcr & UART_FCR_FE) {
|
||||||
if (fifo8_is_empty(&s->xmit_fifo)) {
|
assert(!fifo8_is_empty(&s->xmit_fifo));
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
s->tsr = fifo8_pop(&s->xmit_fifo);
|
s->tsr = fifo8_pop(&s->xmit_fifo);
|
||||||
if (!s->xmit_fifo.num) {
|
if (!s->xmit_fifo.num) {
|
||||||
s->lsr |= UART_LSR_THRE;
|
s->lsr |= UART_LSR_THRE;
|
||||||
}
|
}
|
||||||
} else if ((s->lsr & UART_LSR_THRE)) {
|
|
||||||
return FALSE;
|
|
||||||
} else {
|
} else {
|
||||||
s->tsr = s->thr;
|
s->tsr = s->thr;
|
||||||
s->lsr |= UART_LSR_THRE;
|
s->lsr |= UART_LSR_THRE;
|
||||||
s->lsr &= ~UART_LSR_TEMT;
|
}
|
||||||
|
if ((s->lsr & UART_LSR_THRE) && !s->thr_ipending) {
|
||||||
|
s->thr_ipending = 1;
|
||||||
|
serial_update_irq(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,17 +258,13 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
|||||||
} else {
|
} else {
|
||||||
s->tsr_retry = 0;
|
s->tsr_retry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transmit another byte if it is already available. It is only
|
/* Transmit another byte if it is already available. It is only
|
||||||
possible when FIFO is enabled and not empty. */
|
possible when FIFO is enabled and not empty. */
|
||||||
} while ((s->fcr & UART_FCR_FE) && !fifo8_is_empty(&s->xmit_fifo));
|
} while (!(s->lsr & UART_LSR_THRE));
|
||||||
|
|
||||||
s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
s->lsr |= UART_LSR_TEMT;
|
||||||
if (s->lsr & UART_LSR_THRE) {
|
|
||||||
s->lsr |= UART_LSR_TEMT;
|
|
||||||
s->thr_ipending = 1;
|
|
||||||
serial_update_irq(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -323,10 +321,10 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
fifo8_pop(&s->xmit_fifo);
|
fifo8_pop(&s->xmit_fifo);
|
||||||
}
|
}
|
||||||
fifo8_push(&s->xmit_fifo, s->thr);
|
fifo8_push(&s->xmit_fifo, s->thr);
|
||||||
s->lsr &= ~UART_LSR_TEMT;
|
|
||||||
}
|
}
|
||||||
s->thr_ipending = 0;
|
s->thr_ipending = 0;
|
||||||
s->lsr &= ~UART_LSR_THRE;
|
s->lsr &= ~UART_LSR_THRE;
|
||||||
|
s->lsr &= ~UART_LSR_TEMT;
|
||||||
serial_update_irq(s);
|
serial_update_irq(s);
|
||||||
if (s->tsr_retry <= 0) {
|
if (s->tsr_retry <= 0) {
|
||||||
serial_xmit(NULL, G_IO_OUT, s);
|
serial_xmit(NULL, G_IO_OUT, s);
|
||||||
@@ -338,10 +336,12 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
s->divider = (s->divider & 0x00ff) | (val << 8);
|
s->divider = (s->divider & 0x00ff) | (val << 8);
|
||||||
serial_update_parameters(s);
|
serial_update_parameters(s);
|
||||||
} else {
|
} else {
|
||||||
|
uint8_t changed = (s->ier ^ val) & 0x0f;
|
||||||
s->ier = val & 0x0f;
|
s->ier = val & 0x0f;
|
||||||
/* If the backend device is a real serial port, turn polling of the modem
|
/* If the backend device is a real serial port, turn polling of the modem
|
||||||
status lines on physical port on or off depending on UART_IER_MSI state */
|
* status lines on physical port on or off depending on UART_IER_MSI state.
|
||||||
if (s->poll_msl >= 0) {
|
*/
|
||||||
|
if ((changed & UART_IER_MSI) && s->poll_msl >= 0) {
|
||||||
if (s->ier & UART_IER_MSI) {
|
if (s->ier & UART_IER_MSI) {
|
||||||
s->poll_msl = 1;
|
s->poll_msl = 1;
|
||||||
serial_update_msl(s);
|
serial_update_msl(s);
|
||||||
@@ -356,18 +356,23 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
* This is not in the datasheet, but Windows relies on it. It is
|
* This is not in the datasheet, but Windows relies on it. It is
|
||||||
* unclear if THRE has to be resampled every time THRI becomes
|
* unclear if THRE has to be resampled every time THRI becomes
|
||||||
* 1, or only on the rising edge. Bochs does the latter, and Windows
|
* 1, or only on the rising edge. Bochs does the latter, and Windows
|
||||||
* always toggles IER to all zeroes and back to all ones. But for
|
* always toggles IER to all zeroes and back to all ones, so do the
|
||||||
* now leave it as it has always been in QEMU.
|
* same.
|
||||||
*
|
*
|
||||||
* If IER.THRI is zero, thr_ipending is not used. Set it to zero
|
* If IER.THRI is zero, thr_ipending is not used. Set it to zero
|
||||||
* so that the thr_ipending subsection is not migrated.
|
* so that the thr_ipending subsection is not migrated.
|
||||||
*/
|
*/
|
||||||
if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
|
if (changed & UART_IER_THRI) {
|
||||||
s->thr_ipending = 1;
|
if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
|
||||||
} else {
|
s->thr_ipending = 1;
|
||||||
s->thr_ipending = 0;
|
} else {
|
||||||
|
s->thr_ipending = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
serial_update_irq(s);
|
||||||
}
|
}
|
||||||
serial_update_irq(s);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
@@ -379,12 +384,15 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
/* FIFO clear */
|
/* FIFO clear */
|
||||||
|
|
||||||
if (val & UART_FCR_RFR) {
|
if (val & UART_FCR_RFR) {
|
||||||
|
s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
|
||||||
timer_del(s->fifo_timeout_timer);
|
timer_del(s->fifo_timeout_timer);
|
||||||
s->timeout_ipending = 0;
|
s->timeout_ipending = 0;
|
||||||
fifo8_reset(&s->recv_fifo);
|
fifo8_reset(&s->recv_fifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val & UART_FCR_XFR) {
|
if (val & UART_FCR_XFR) {
|
||||||
|
s->lsr |= UART_LSR_THRE;
|
||||||
|
s->thr_ipending = 1;
|
||||||
fifo8_reset(&s->xmit_fifo);
|
fifo8_reset(&s->xmit_fifo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -482,10 +482,14 @@ static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
|
|||||||
/* Guest requested config info */
|
/* Guest requested config info */
|
||||||
static void get_config(VirtIODevice *vdev, uint8_t *config_data)
|
static void get_config(VirtIODevice *vdev, uint8_t *config_data)
|
||||||
{
|
{
|
||||||
VirtIOSerial *vser;
|
VirtIOSerial *vser = VIRTIO_SERIAL(vdev);
|
||||||
|
struct virtio_console_config *config =
|
||||||
|
(struct virtio_console_config *)config_data;
|
||||||
|
|
||||||
vser = VIRTIO_SERIAL(vdev);
|
config->cols = 0;
|
||||||
memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
|
config->rows = 0;
|
||||||
|
config->max_nr_ports = virtio_tswap32(vdev,
|
||||||
|
vser->serial.max_virtserial_ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void guest_reset(VirtIOSerial *vser)
|
static void guest_reset(VirtIOSerial *vser)
|
||||||
@@ -533,10 +537,6 @@ static void vser_reset(VirtIODevice *vdev)
|
|||||||
|
|
||||||
vser = VIRTIO_SERIAL(vdev);
|
vser = VIRTIO_SERIAL(vdev);
|
||||||
guest_reset(vser);
|
guest_reset(vser);
|
||||||
|
|
||||||
/* In case we have switched endianness */
|
|
||||||
vser->config.max_nr_ports =
|
|
||||||
virtio_tswap32(vdev, vser->serial.max_virtserial_ports);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_serial_save(QEMUFile *f, void *opaque)
|
static void virtio_serial_save(QEMUFile *f, void *opaque)
|
||||||
@@ -551,15 +551,16 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
|
|||||||
VirtIOSerialPort *port;
|
VirtIOSerialPort *port;
|
||||||
uint32_t nr_active_ports;
|
uint32_t nr_active_ports;
|
||||||
unsigned int i, max_nr_ports;
|
unsigned int i, max_nr_ports;
|
||||||
|
struct virtio_console_config config;
|
||||||
|
|
||||||
/* The config space */
|
/* The config space (ignored on the far end in current versions) */
|
||||||
qemu_put_be16s(f, &s->config.cols);
|
get_config(vdev, (uint8_t *)&config);
|
||||||
qemu_put_be16s(f, &s->config.rows);
|
qemu_put_be16s(f, &config.cols);
|
||||||
|
qemu_put_be16s(f, &config.rows);
|
||||||
qemu_put_be32s(f, &s->config.max_nr_ports);
|
qemu_put_be32s(f, &config.max_nr_ports);
|
||||||
|
|
||||||
/* The ports map */
|
/* The ports map */
|
||||||
max_nr_ports = virtio_tswap32(vdev, s->config.max_nr_ports);
|
max_nr_ports = s->serial.max_virtserial_ports;
|
||||||
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
||||||
qemu_put_be32s(f, &s->ports_map[i]);
|
qemu_put_be32s(f, &s->ports_map[i]);
|
||||||
}
|
}
|
||||||
@@ -715,13 +716,7 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
|
|||||||
qemu_get_be16s(f, (uint16_t *) &tmp);
|
qemu_get_be16s(f, (uint16_t *) &tmp);
|
||||||
qemu_get_be32s(f, &tmp);
|
qemu_get_be32s(f, &tmp);
|
||||||
|
|
||||||
/* Note: this is the only location where we use tswap32() instead of
|
max_nr_ports = s->serial.max_virtserial_ports;
|
||||||
* virtio_tswap32() because:
|
|
||||||
* - virtio_tswap32() only makes sense when the device is fully restored
|
|
||||||
* - the target endianness that was used to populate s->config is
|
|
||||||
* necessarly the default one
|
|
||||||
*/
|
|
||||||
max_nr_ports = tswap32(s->config.max_nr_ports);
|
|
||||||
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
||||||
qemu_get_be32s(f, &ports_map);
|
qemu_get_be32s(f, &ports_map);
|
||||||
|
|
||||||
@@ -784,10 +779,9 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
|
|||||||
/* This function is only used if a port id is not provided by the user */
|
/* This function is only used if a port id is not provided by the user */
|
||||||
static uint32_t find_free_port_id(VirtIOSerial *vser)
|
static uint32_t find_free_port_id(VirtIOSerial *vser)
|
||||||
{
|
{
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
|
|
||||||
unsigned int i, max_nr_ports;
|
unsigned int i, max_nr_ports;
|
||||||
|
|
||||||
max_nr_ports = virtio_tswap32(vdev, vser->config.max_nr_ports);
|
max_nr_ports = vser->serial.max_virtserial_ports;
|
||||||
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
||||||
uint32_t map, bit;
|
uint32_t map, bit;
|
||||||
|
|
||||||
@@ -848,7 +842,6 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
|
|||||||
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
|
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
|
||||||
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev));
|
VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev));
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(bus->vser);
|
|
||||||
int max_nr_ports;
|
int max_nr_ports;
|
||||||
bool plugging_port0;
|
bool plugging_port0;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
@@ -890,7 +883,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
max_nr_ports = virtio_tswap32(vdev, port->vser->config.max_nr_ports);
|
max_nr_ports = port->vser->serial.max_virtserial_ports;
|
||||||
if (port->id >= max_nr_ports) {
|
if (port->id >= max_nr_ports) {
|
||||||
error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, "
|
error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, "
|
||||||
"max. allowed: %u", max_nr_ports - 1);
|
"max. allowed: %u", max_nr_ports - 1);
|
||||||
@@ -995,8 +988,6 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
|
|||||||
vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
|
vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
vser->config.max_nr_ports =
|
|
||||||
virtio_tswap32(vdev, vser->serial.max_virtserial_ports);
|
|
||||||
vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32)
|
vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32)
|
||||||
* sizeof(vser->ports_map[0]));
|
* sizeof(vser->ports_map[0]));
|
||||||
/*
|
/*
|
||||||
|
@@ -614,14 +614,9 @@ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
|
|||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This simply prevents g_malloc in the function below from allocating
|
/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
|
||||||
* a huge amount of memory, by placing a limit on the maximum
|
int load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
|
||||||
* uncompressed image size that load_image_gzipped will read.
|
uint8_t **buffer)
|
||||||
*/
|
|
||||||
#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20)
|
|
||||||
|
|
||||||
/* Load a gzip-compressed kernel. */
|
|
||||||
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
|
||||||
{
|
{
|
||||||
uint8_t *compressed_data = NULL;
|
uint8_t *compressed_data = NULL;
|
||||||
uint8_t *data = NULL;
|
uint8_t *data = NULL;
|
||||||
@@ -653,8 +648,11 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rom_add_blob_fixed(filename, data, bytes, addr);
|
/* trim to actual size and return to caller */
|
||||||
|
*buffer = g_realloc(data, bytes);
|
||||||
ret = bytes;
|
ret = bytes;
|
||||||
|
/* ownership has been transferred to caller */
|
||||||
|
data = NULL;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
g_free(compressed_data);
|
g_free(compressed_data);
|
||||||
@@ -662,6 +660,20 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load a gzip-compressed kernel. */
|
||||||
|
int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||||
|
{
|
||||||
|
int bytes;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
bytes = load_image_gzipped_buffer(filename, max_sz, &data);
|
||||||
|
if (bytes != -1) {
|
||||||
|
rom_add_blob_fixed(filename, data, bytes, addr);
|
||||||
|
g_free(data);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions for reboot-persistent memory regions.
|
* Functions for reboot-persistent memory regions.
|
||||||
* - used for vga bios and option roms.
|
* - used for vga bios and option roms.
|
||||||
@@ -712,12 +724,22 @@ static void rom_insert(Rom *rom)
|
|||||||
QTAILQ_INSERT_TAIL(&roms, rom, next);
|
QTAILQ_INSERT_TAIL(&roms, rom, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fw_cfg_resized(const char *id, uint64_t length, void *host)
|
||||||
|
{
|
||||||
|
if (fw_cfg) {
|
||||||
|
fw_cfg_modify_file(fw_cfg, id + strlen("/rom@"), host, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
|
static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
|
||||||
{
|
{
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
rom->mr = g_malloc(sizeof(*rom->mr));
|
rom->mr = g_malloc(sizeof(*rom->mr));
|
||||||
memory_region_init_ram(rom->mr, owner, name, rom->datasize, &error_abort);
|
memory_region_init_resizeable_ram(rom->mr, owner, name,
|
||||||
|
rom->datasize, rom->romsize,
|
||||||
|
fw_cfg_resized,
|
||||||
|
&error_abort);
|
||||||
memory_region_set_readonly(rom->mr, true);
|
memory_region_set_readonly(rom->mr, true);
|
||||||
vmstate_register_ram_global(rom->mr);
|
vmstate_register_ram_global(rom->mr);
|
||||||
|
|
||||||
@@ -812,7 +834,7 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
||||||
hwaddr addr, const char *fw_file_name,
|
size_t max_len, hwaddr addr, const char *fw_file_name,
|
||||||
FWCfgReadCallback fw_callback, void *callback_opaque)
|
FWCfgReadCallback fw_callback, void *callback_opaque)
|
||||||
{
|
{
|
||||||
Rom *rom;
|
Rom *rom;
|
||||||
@@ -821,7 +843,7 @@ ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
|||||||
rom = g_malloc0(sizeof(*rom));
|
rom = g_malloc0(sizeof(*rom));
|
||||||
rom->name = g_strdup(name);
|
rom->name = g_strdup(name);
|
||||||
rom->addr = addr;
|
rom->addr = addr;
|
||||||
rom->romsize = len;
|
rom->romsize = max_len ? max_len : len;
|
||||||
rom->datasize = len;
|
rom->datasize = len;
|
||||||
rom->data = g_malloc0(rom->datasize);
|
rom->data = g_malloc0(rom->datasize);
|
||||||
memcpy(rom->data, blob, len);
|
memcpy(rom->data, blob, len);
|
||||||
@@ -841,7 +863,7 @@ ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
|||||||
|
|
||||||
fw_cfg_add_file_callback(fw_cfg, fw_file_name,
|
fw_cfg_add_file_callback(fw_cfg, fw_file_name,
|
||||||
fw_callback, callback_opaque,
|
fw_callback, callback_opaque,
|
||||||
data, rom->romsize);
|
data, rom->datasize);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -291,48 +291,93 @@ static void machine_initfn(Object *obj)
|
|||||||
|
|
||||||
object_property_add_str(obj, "accel",
|
object_property_add_str(obj, "accel",
|
||||||
machine_get_accel, machine_set_accel, NULL);
|
machine_get_accel, machine_set_accel, NULL);
|
||||||
|
object_property_set_description(obj, "accel",
|
||||||
|
"Accelerator list",
|
||||||
|
NULL);
|
||||||
object_property_add_bool(obj, "kernel-irqchip",
|
object_property_add_bool(obj, "kernel-irqchip",
|
||||||
machine_get_kernel_irqchip,
|
machine_get_kernel_irqchip,
|
||||||
machine_set_kernel_irqchip,
|
machine_set_kernel_irqchip,
|
||||||
NULL);
|
NULL);
|
||||||
|
object_property_set_description(obj, "kernel-irqchip",
|
||||||
|
"Use KVM in-kernel irqchip",
|
||||||
|
NULL);
|
||||||
object_property_add(obj, "kvm-shadow-mem", "int",
|
object_property_add(obj, "kvm-shadow-mem", "int",
|
||||||
machine_get_kvm_shadow_mem,
|
machine_get_kvm_shadow_mem,
|
||||||
machine_set_kvm_shadow_mem,
|
machine_set_kvm_shadow_mem,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
object_property_set_description(obj, "kvm-shadow-mem",
|
||||||
|
"KVM shadow MMU size",
|
||||||
|
NULL);
|
||||||
object_property_add_str(obj, "kernel",
|
object_property_add_str(obj, "kernel",
|
||||||
machine_get_kernel, machine_set_kernel, NULL);
|
machine_get_kernel, machine_set_kernel, NULL);
|
||||||
|
object_property_set_description(obj, "kernel",
|
||||||
|
"Linux kernel image file",
|
||||||
|
NULL);
|
||||||
object_property_add_str(obj, "initrd",
|
object_property_add_str(obj, "initrd",
|
||||||
machine_get_initrd, machine_set_initrd, NULL);
|
machine_get_initrd, machine_set_initrd, NULL);
|
||||||
|
object_property_set_description(obj, "initrd",
|
||||||
|
"Linux initial ramdisk file",
|
||||||
|
NULL);
|
||||||
object_property_add_str(obj, "append",
|
object_property_add_str(obj, "append",
|
||||||
machine_get_append, machine_set_append, NULL);
|
machine_get_append, machine_set_append, NULL);
|
||||||
|
object_property_set_description(obj, "append",
|
||||||
|
"Linux kernel command line",
|
||||||
|
NULL);
|
||||||
object_property_add_str(obj, "dtb",
|
object_property_add_str(obj, "dtb",
|
||||||
machine_get_dtb, machine_set_dtb, NULL);
|
machine_get_dtb, machine_set_dtb, NULL);
|
||||||
|
object_property_set_description(obj, "dtb",
|
||||||
|
"Linux kernel device tree file",
|
||||||
|
NULL);
|
||||||
object_property_add_str(obj, "dumpdtb",
|
object_property_add_str(obj, "dumpdtb",
|
||||||
machine_get_dumpdtb, machine_set_dumpdtb, NULL);
|
machine_get_dumpdtb, machine_set_dumpdtb, NULL);
|
||||||
|
object_property_set_description(obj, "dumpdtb",
|
||||||
|
"Dump current dtb to a file and quit",
|
||||||
|
NULL);
|
||||||
object_property_add(obj, "phandle-start", "int",
|
object_property_add(obj, "phandle-start", "int",
|
||||||
machine_get_phandle_start,
|
machine_get_phandle_start,
|
||||||
machine_set_phandle_start,
|
machine_set_phandle_start,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
object_property_set_description(obj, "phandle-start",
|
||||||
|
"The first phandle ID we may generate dynamically",
|
||||||
|
NULL);
|
||||||
object_property_add_str(obj, "dt-compatible",
|
object_property_add_str(obj, "dt-compatible",
|
||||||
machine_get_dt_compatible,
|
machine_get_dt_compatible,
|
||||||
machine_set_dt_compatible,
|
machine_set_dt_compatible,
|
||||||
NULL);
|
NULL);
|
||||||
|
object_property_set_description(obj, "dt-compatible",
|
||||||
|
"Overrides the \"compatible\" property of the dt root node",
|
||||||
|
NULL);
|
||||||
object_property_add_bool(obj, "dump-guest-core",
|
object_property_add_bool(obj, "dump-guest-core",
|
||||||
machine_get_dump_guest_core,
|
machine_get_dump_guest_core,
|
||||||
machine_set_dump_guest_core,
|
machine_set_dump_guest_core,
|
||||||
NULL);
|
NULL);
|
||||||
|
object_property_set_description(obj, "dump-guest-core",
|
||||||
|
"Include guest memory in a core dump",
|
||||||
|
NULL);
|
||||||
object_property_add_bool(obj, "mem-merge",
|
object_property_add_bool(obj, "mem-merge",
|
||||||
machine_get_mem_merge,
|
machine_get_mem_merge,
|
||||||
machine_set_mem_merge, NULL);
|
machine_set_mem_merge, NULL);
|
||||||
|
object_property_set_description(obj, "mem-merge",
|
||||||
|
"Enable/disable memory merge support",
|
||||||
|
NULL);
|
||||||
object_property_add_bool(obj, "usb",
|
object_property_add_bool(obj, "usb",
|
||||||
machine_get_usb,
|
machine_get_usb,
|
||||||
machine_set_usb, NULL);
|
machine_set_usb, NULL);
|
||||||
|
object_property_set_description(obj, "usb",
|
||||||
|
"Set on/off to enable/disable usb",
|
||||||
|
NULL);
|
||||||
object_property_add_str(obj, "firmware",
|
object_property_add_str(obj, "firmware",
|
||||||
machine_get_firmware,
|
machine_get_firmware,
|
||||||
machine_set_firmware, NULL);
|
machine_set_firmware, NULL);
|
||||||
|
object_property_set_description(obj, "firmware",
|
||||||
|
"Firmware image",
|
||||||
|
NULL);
|
||||||
object_property_add_bool(obj, "iommu",
|
object_property_add_bool(obj, "iommu",
|
||||||
machine_get_iommu,
|
machine_get_iommu,
|
||||||
machine_set_iommu, NULL);
|
machine_set_iommu, NULL);
|
||||||
|
object_property_set_description(obj, "iommu",
|
||||||
|
"Set on/off to enable/disable Intel IOMMU (VT-d)",
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* Register notifier when init is done for sysbus sanity checks */
|
/* Register notifier when init is done for sysbus sanity checks */
|
||||||
ms->sysbus_notifier.notify = machine_init_notify;
|
ms->sysbus_notifier.notify = machine_init_notify;
|
||||||
@@ -353,6 +398,11 @@ static void machine_finalize(Object *obj)
|
|||||||
g_free(ms->firmware);
|
g_free(ms->firmware);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool machine_usb(MachineState *machine)
|
||||||
|
{
|
||||||
|
return machine->usb;
|
||||||
|
}
|
||||||
|
|
||||||
static const TypeInfo machine_info = {
|
static const TypeInfo machine_info = {
|
||||||
.name = TYPE_MACHINE,
|
.name = TYPE_MACHINE,
|
||||||
.parent = TYPE_OBJECT,
|
.parent = TYPE_OBJECT,
|
||||||
|
@@ -177,42 +177,69 @@ PropertyInfo qdev_prop_chr = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* --- netdev device --- */
|
/* --- netdev device --- */
|
||||||
|
static void get_netdev(Object *obj, Visitor *v, void *opaque,
|
||||||
static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
|
const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
NICPeers *peers_ptr = (NICPeers *)ptr;
|
DeviceState *dev = DEVICE(obj);
|
||||||
|
Property *prop = opaque;
|
||||||
|
NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
|
||||||
|
char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
|
||||||
|
|
||||||
|
visit_type_str(v, &p, name, errp);
|
||||||
|
g_free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_netdev(Object *obj, Visitor *v, void *opaque,
|
||||||
|
const char *name, Error **errp)
|
||||||
|
{
|
||||||
|
DeviceState *dev = DEVICE(obj);
|
||||||
|
Property *prop = opaque;
|
||||||
|
NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
|
||||||
NetClientState **ncs = peers_ptr->ncs;
|
NetClientState **ncs = peers_ptr->ncs;
|
||||||
NetClientState *peers[MAX_QUEUE_NUM];
|
NetClientState *peers[MAX_QUEUE_NUM];
|
||||||
int queues, i = 0;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int queues, err = 0, i = 0;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
if (dev->realized) {
|
||||||
|
qdev_prop_set_after_realize(dev, name, errp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
visit_type_str(v, &str, name, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
queues = qemu_find_net_clients_except(str, peers,
|
queues = qemu_find_net_clients_except(str, peers,
|
||||||
NET_CLIENT_OPTIONS_KIND_NIC,
|
NET_CLIENT_OPTIONS_KIND_NIC,
|
||||||
MAX_QUEUE_NUM);
|
MAX_QUEUE_NUM);
|
||||||
if (queues == 0) {
|
if (queues == 0) {
|
||||||
ret = -ENOENT;
|
err = -ENOENT;
|
||||||
goto err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queues > MAX_QUEUE_NUM) {
|
if (queues > MAX_QUEUE_NUM) {
|
||||||
ret = -E2BIG;
|
error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
|
||||||
goto err;
|
str, queues, MAX_QUEUE_NUM);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < queues; i++) {
|
for (i = 0; i < queues; i++) {
|
||||||
if (peers[i] == NULL) {
|
if (peers[i] == NULL) {
|
||||||
ret = -ENOENT;
|
err = -ENOENT;
|
||||||
goto err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peers[i]->peer) {
|
if (peers[i]->peer) {
|
||||||
ret = -EEXIST;
|
err = -EEXIST;
|
||||||
goto err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ncs[i]) {
|
if (ncs[i]) {
|
||||||
ret = -EINVAL;
|
err = -EINVAL;
|
||||||
goto err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ncs[i] = peers[i];
|
ncs[i] = peers[i];
|
||||||
@@ -221,30 +248,9 @@ static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
|
|||||||
|
|
||||||
peers_ptr->queues = queues;
|
peers_ptr->queues = queues;
|
||||||
|
|
||||||
return 0;
|
out:
|
||||||
|
error_set_from_qdev_prop_error(errp, err, dev, prop, str);
|
||||||
err:
|
g_free(str);
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *print_netdev(void *ptr)
|
|
||||||
{
|
|
||||||
NetClientState *netdev = ptr;
|
|
||||||
const char *val = netdev->name ? netdev->name : "";
|
|
||||||
|
|
||||||
return g_strdup(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_netdev(Object *obj, Visitor *v, void *opaque,
|
|
||||||
const char *name, Error **errp)
|
|
||||||
{
|
|
||||||
get_pointer(obj, v, opaque, print_netdev, name, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_netdev(Object *obj, Visitor *v, void *opaque,
|
|
||||||
const char *name, Error **errp)
|
|
||||||
{
|
|
||||||
set_pointer(obj, v, opaque, parse_netdev, name, errp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyInfo qdev_prop_netdev = {
|
PropertyInfo qdev_prop_netdev = {
|
||||||
|
@@ -189,6 +189,56 @@ int qdev_init(DeviceState *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QTAILQ_HEAD(device_listeners, DeviceListener) device_listeners
|
||||||
|
= QTAILQ_HEAD_INITIALIZER(device_listeners);
|
||||||
|
|
||||||
|
enum ListenerDirection { Forward, Reverse };
|
||||||
|
|
||||||
|
#define DEVICE_LISTENER_CALL(_callback, _direction, _args...) \
|
||||||
|
do { \
|
||||||
|
DeviceListener *_listener; \
|
||||||
|
\
|
||||||
|
switch (_direction) { \
|
||||||
|
case Forward: \
|
||||||
|
QTAILQ_FOREACH(_listener, &device_listeners, link) { \
|
||||||
|
if (_listener->_callback) { \
|
||||||
|
_listener->_callback(_listener, ##_args); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
case Reverse: \
|
||||||
|
QTAILQ_FOREACH_REVERSE(_listener, &device_listeners, \
|
||||||
|
device_listeners, link) { \
|
||||||
|
if (_listener->_callback) { \
|
||||||
|
_listener->_callback(_listener, ##_args); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
abort(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static int device_listener_add(DeviceState *dev, void *opaque)
|
||||||
|
{
|
||||||
|
DEVICE_LISTENER_CALL(realize, Forward, dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_listener_register(DeviceListener *listener)
|
||||||
|
{
|
||||||
|
QTAILQ_INSERT_TAIL(&device_listeners, listener, link);
|
||||||
|
|
||||||
|
qbus_walk_children(sysbus_get_default(), NULL, NULL, device_listener_add,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_listener_unregister(DeviceListener *listener)
|
||||||
|
{
|
||||||
|
QTAILQ_REMOVE(&device_listeners, listener, link);
|
||||||
|
}
|
||||||
|
|
||||||
static void device_realize(DeviceState *dev, Error **errp)
|
static void device_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||||
@@ -938,12 +988,7 @@ void qdev_alias_all_properties(DeviceState *target, Object *source)
|
|||||||
static int qdev_add_hotpluggable_device(Object *obj, void *opaque)
|
static int qdev_add_hotpluggable_device(Object *obj, void *opaque)
|
||||||
{
|
{
|
||||||
GSList **list = opaque;
|
GSList **list = opaque;
|
||||||
DeviceState *dev = (DeviceState *)object_dynamic_cast(OBJECT(obj),
|
DeviceState *dev = DEVICE(obj);
|
||||||
TYPE_DEVICE);
|
|
||||||
|
|
||||||
if (dev == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev->realized && object_property_get_bool(obj, "hotpluggable", NULL)) {
|
if (dev->realized && object_property_get_bool(obj, "hotpluggable", NULL)) {
|
||||||
*list = g_slist_append(*list, dev);
|
*list = g_slist_append(*list, dev);
|
||||||
@@ -999,6 +1044,8 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEVICE_LISTENER_CALL(realize, Forward, dev);
|
||||||
|
|
||||||
hotplug_ctrl = qdev_get_hotplug_handler(dev);
|
hotplug_ctrl = qdev_get_hotplug_handler(dev);
|
||||||
if (hotplug_ctrl) {
|
if (hotplug_ctrl) {
|
||||||
hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
|
hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
|
||||||
@@ -1040,6 +1087,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
|
|||||||
dc->unrealize(dev, local_errp);
|
dc->unrealize(dev, local_errp);
|
||||||
}
|
}
|
||||||
dev->pending_deleted_event = true;
|
dev->pending_deleted_event = true;
|
||||||
|
DEVICE_LISTENER_CALL(unrealize, Reverse, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local_err != NULL) {
|
if (local_err != NULL) {
|
||||||
@@ -1146,9 +1194,7 @@ static void device_finalize(Object *obj)
|
|||||||
NamedGPIOList *ngl, *next;
|
NamedGPIOList *ngl, *next;
|
||||||
|
|
||||||
DeviceState *dev = DEVICE(obj);
|
DeviceState *dev = DEVICE(obj);
|
||||||
if (dev->opts) {
|
qemu_opts_del(dev->opts);
|
||||||
qemu_opts_del(dev->opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) {
|
QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) {
|
||||||
QLIST_REMOVE(ngl, node);
|
QLIST_REMOVE(ngl, node);
|
||||||
|
@@ -21,7 +21,6 @@
|
|||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
#include "hw/devices.h"
|
#include "hw/devices.h"
|
||||||
#include "vga_int.h"
|
|
||||||
#include "ui/pixel_ops.h"
|
#include "ui/pixel_ops.h"
|
||||||
|
|
||||||
typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
|
typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
|
||||||
|
@@ -202,8 +202,6 @@ typedef struct CirrusVGAState {
|
|||||||
uint32_t cirrus_bank_base[2];
|
uint32_t cirrus_bank_base[2];
|
||||||
uint32_t cirrus_bank_limit[2];
|
uint32_t cirrus_bank_limit[2];
|
||||||
uint8_t cirrus_hidden_palette[48];
|
uint8_t cirrus_hidden_palette[48];
|
||||||
uint32_t hw_cursor_x;
|
|
||||||
uint32_t hw_cursor_y;
|
|
||||||
int cirrus_blt_pixelwidth;
|
int cirrus_blt_pixelwidth;
|
||||||
int cirrus_blt_width;
|
int cirrus_blt_width;
|
||||||
int cirrus_blt_height;
|
int cirrus_blt_height;
|
||||||
@@ -1328,7 +1326,7 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
|
|||||||
case 0xd0:
|
case 0xd0:
|
||||||
case 0xf0: // Graphics Cursor X
|
case 0xf0: // Graphics Cursor X
|
||||||
s->vga.sr[0x10] = val;
|
s->vga.sr[0x10] = val;
|
||||||
s->hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
|
s->vga.hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
|
||||||
break;
|
break;
|
||||||
case 0x11:
|
case 0x11:
|
||||||
case 0x31:
|
case 0x31:
|
||||||
@@ -1339,7 +1337,7 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
|
|||||||
case 0xd1:
|
case 0xd1:
|
||||||
case 0xf1: // Graphics Cursor Y
|
case 0xf1: // Graphics Cursor Y
|
||||||
s->vga.sr[0x11] = val;
|
s->vga.sr[0x11] = val;
|
||||||
s->hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
|
s->vga.hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
|
||||||
break;
|
break;
|
||||||
case 0x07: // Extended Sequencer Mode
|
case 0x07: // Extended Sequencer Mode
|
||||||
cirrus_update_memory_access(s);
|
cirrus_update_memory_access(s);
|
||||||
@@ -1351,7 +1349,6 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
|
|||||||
case 0x0d: // VCLK 2
|
case 0x0d: // VCLK 2
|
||||||
case 0x0e: // VCLK 3
|
case 0x0e: // VCLK 3
|
||||||
case 0x0f: // DRAM Control
|
case 0x0f: // DRAM Control
|
||||||
case 0x12: // Graphics Cursor Attribute
|
|
||||||
case 0x13: // Graphics Cursor Pattern Address
|
case 0x13: // Graphics Cursor Pattern Address
|
||||||
case 0x14: // Scratch Register 2
|
case 0x14: // Scratch Register 2
|
||||||
case 0x15: // Scratch Register 3
|
case 0x15: // Scratch Register 3
|
||||||
@@ -1370,6 +1367,14 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
|
|||||||
s->vga.sr_index, val);
|
s->vga.sr_index, val);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
case 0x12: // Graphics Cursor Attribute
|
||||||
|
s->vga.sr[0x12] = val;
|
||||||
|
s->vga.force_shadow = !!(val & CIRRUS_CURSOR_SHOW);
|
||||||
|
#ifdef DEBUG_CIRRUS
|
||||||
|
printf("cirrus: cursor ctl SR12=%02x (force shadow: %d)\n",
|
||||||
|
val, s->vga.force_shadow);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
case 0x17: // Configuration Readback and Extended Control
|
case 0x17: // Configuration Readback and Extended Control
|
||||||
s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38)
|
s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38)
|
||||||
| (val & 0xc7);
|
| (val & 0xc7);
|
||||||
@@ -2188,14 +2193,14 @@ static void cirrus_cursor_invalidate(VGACommonState *s1)
|
|||||||
}
|
}
|
||||||
/* invalidate last cursor and new cursor if any change */
|
/* invalidate last cursor and new cursor if any change */
|
||||||
if (s->last_hw_cursor_size != size ||
|
if (s->last_hw_cursor_size != size ||
|
||||||
s->last_hw_cursor_x != s->hw_cursor_x ||
|
s->last_hw_cursor_x != s->vga.hw_cursor_x ||
|
||||||
s->last_hw_cursor_y != s->hw_cursor_y) {
|
s->last_hw_cursor_y != s->vga.hw_cursor_y) {
|
||||||
|
|
||||||
invalidate_cursor1(s);
|
invalidate_cursor1(s);
|
||||||
|
|
||||||
s->last_hw_cursor_size = size;
|
s->last_hw_cursor_size = size;
|
||||||
s->last_hw_cursor_x = s->hw_cursor_x;
|
s->last_hw_cursor_x = s->vga.hw_cursor_x;
|
||||||
s->last_hw_cursor_y = s->hw_cursor_y;
|
s->last_hw_cursor_y = s->vga.hw_cursor_y;
|
||||||
/* compute the real cursor min and max y */
|
/* compute the real cursor min and max y */
|
||||||
cirrus_cursor_compute_yrange(s);
|
cirrus_cursor_compute_yrange(s);
|
||||||
invalidate_cursor1(s);
|
invalidate_cursor1(s);
|
||||||
@@ -2252,14 +2257,15 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
|
|||||||
} else {
|
} else {
|
||||||
h = 32;
|
h = 32;
|
||||||
}
|
}
|
||||||
if (scr_y < s->hw_cursor_y ||
|
if (scr_y < s->vga.hw_cursor_y ||
|
||||||
scr_y >= (s->hw_cursor_y + h))
|
scr_y >= (s->vga.hw_cursor_y + h)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
|
src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
|
||||||
if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
|
if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
|
||||||
src += (s->vga.sr[0x13] & 0x3c) * 256;
|
src += (s->vga.sr[0x13] & 0x3c) * 256;
|
||||||
src += (scr_y - s->hw_cursor_y) * 16;
|
src += (scr_y - s->vga.hw_cursor_y) * 16;
|
||||||
poffset = 8;
|
poffset = 8;
|
||||||
content = ((uint32_t *)src)[0] |
|
content = ((uint32_t *)src)[0] |
|
||||||
((uint32_t *)src)[1] |
|
((uint32_t *)src)[1] |
|
||||||
@@ -2267,7 +2273,7 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
|
|||||||
((uint32_t *)src)[3];
|
((uint32_t *)src)[3];
|
||||||
} else {
|
} else {
|
||||||
src += (s->vga.sr[0x13] & 0x3f) * 256;
|
src += (s->vga.sr[0x13] & 0x3f) * 256;
|
||||||
src += (scr_y - s->hw_cursor_y) * 4;
|
src += (scr_y - s->vga.hw_cursor_y) * 4;
|
||||||
|
|
||||||
|
|
||||||
poffset = 128;
|
poffset = 128;
|
||||||
@@ -2279,10 +2285,10 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
|
|||||||
return;
|
return;
|
||||||
w = h;
|
w = h;
|
||||||
|
|
||||||
x1 = s->hw_cursor_x;
|
x1 = s->vga.hw_cursor_x;
|
||||||
if (x1 >= s->vga.last_scr_width)
|
if (x1 >= s->vga.last_scr_width)
|
||||||
return;
|
return;
|
||||||
x2 = s->hw_cursor_x + w;
|
x2 = s->vga.hw_cursor_x + w;
|
||||||
if (x2 > s->vga.last_scr_width)
|
if (x2 > s->vga.last_scr_width)
|
||||||
x2 = s->vga.last_scr_width;
|
x2 = s->vga.last_scr_width;
|
||||||
w = x2 - x1;
|
w = x2 - x1;
|
||||||
@@ -2771,8 +2777,8 @@ static const VMStateDescription vmstate_cirrus_vga = {
|
|||||||
VMSTATE_INT32(vga.bank_offset, CirrusVGAState),
|
VMSTATE_INT32(vga.bank_offset, CirrusVGAState),
|
||||||
VMSTATE_UINT8(cirrus_hidden_dac_lockindex, CirrusVGAState),
|
VMSTATE_UINT8(cirrus_hidden_dac_lockindex, CirrusVGAState),
|
||||||
VMSTATE_UINT8(cirrus_hidden_dac_data, CirrusVGAState),
|
VMSTATE_UINT8(cirrus_hidden_dac_data, CirrusVGAState),
|
||||||
VMSTATE_UINT32(hw_cursor_x, CirrusVGAState),
|
VMSTATE_UINT32(vga.hw_cursor_x, CirrusVGAState),
|
||||||
VMSTATE_UINT32(hw_cursor_y, CirrusVGAState),
|
VMSTATE_UINT32(vga.hw_cursor_y, CirrusVGAState),
|
||||||
/* XXX: we do not save the bitblt state - we assume we do not save
|
/* XXX: we do not save the bitblt state - we assume we do not save
|
||||||
the state when the blitter is active */
|
the state when the blitter is active */
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
@@ -283,12 +283,14 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
|
|||||||
qxl->ssd.mouse_x = cmd->u.set.position.x;
|
qxl->ssd.mouse_x = cmd->u.set.position.x;
|
||||||
qxl->ssd.mouse_y = cmd->u.set.position.y;
|
qxl->ssd.mouse_y = cmd->u.set.position.y;
|
||||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||||
|
qemu_bh_schedule(qxl->ssd.cursor_bh);
|
||||||
break;
|
break;
|
||||||
case QXL_CURSOR_MOVE:
|
case QXL_CURSOR_MOVE:
|
||||||
qemu_mutex_lock(&qxl->ssd.lock);
|
qemu_mutex_lock(&qxl->ssd.lock);
|
||||||
qxl->ssd.mouse_x = cmd->u.position.x;
|
qxl->ssd.mouse_x = cmd->u.position.x;
|
||||||
qxl->ssd.mouse_y = cmd->u.position.y;
|
qxl->ssd.mouse_y = cmd->u.position.y;
|
||||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||||
|
qemu_bh_schedule(qxl->ssd.cursor_bh);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -1092,6 +1092,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
|||||||
spice_qxl_driver_unload(&d->ssd.qxl);
|
spice_qxl_driver_unload(&d->ssd.qxl);
|
||||||
#endif
|
#endif
|
||||||
graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga);
|
graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga);
|
||||||
|
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT);
|
||||||
qemu_spice_create_host_primary(&d->ssd);
|
qemu_spice_create_host_primary(&d->ssd);
|
||||||
d->mode = QXL_MODE_VGA;
|
d->mode = QXL_MODE_VGA;
|
||||||
vga_dirty_log_start(&d->vga);
|
vga_dirty_log_start(&d->vga);
|
||||||
@@ -1105,6 +1106,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
|
|||||||
}
|
}
|
||||||
trace_qxl_exit_vga_mode(d->id);
|
trace_qxl_exit_vga_mode(d->id);
|
||||||
graphic_console_set_hwops(d->ssd.dcl.con, &qxl_ops, d);
|
graphic_console_set_hwops(d->ssd.dcl.con, &qxl_ops, d);
|
||||||
|
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE);
|
||||||
vga_dirty_log_stop(&d->vga);
|
vga_dirty_log_stop(&d->vga);
|
||||||
qxl_destroy_primary(d, QXL_SYNC);
|
qxl_destroy_primary(d, QXL_SYNC);
|
||||||
}
|
}
|
||||||
@@ -1153,6 +1155,7 @@ static void qxl_soft_reset(PCIQXLDevice *d)
|
|||||||
qxl_enter_vga_mode(d);
|
qxl_enter_vga_mode(d);
|
||||||
} else {
|
} else {
|
||||||
d->mode = QXL_MODE_UNDEFINED;
|
d->mode = QXL_MODE_UNDEFINED;
|
||||||
|
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1861,10 +1864,6 @@ static void display_refresh(DisplayChangeListener *dcl)
|
|||||||
|
|
||||||
if (qxl->mode == QXL_MODE_VGA) {
|
if (qxl->mode == QXL_MODE_VGA) {
|
||||||
qemu_spice_display_refresh(&qxl->ssd);
|
qemu_spice_display_refresh(&qxl->ssd);
|
||||||
} else {
|
|
||||||
qemu_mutex_lock(&qxl->ssd.lock);
|
|
||||||
qemu_spice_cursor_refresh_unlocked(&qxl->ssd);
|
|
||||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2025,6 +2024,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
|||||||
qxl_reset_state(qxl);
|
qxl_reset_state(qxl);
|
||||||
|
|
||||||
qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl);
|
qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl);
|
||||||
|
qxl->ssd.cursor_bh = qemu_bh_new(qemu_spice_cursor_refresh_bh, &qxl->ssd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -321,6 +321,7 @@ static void secondary_class_init(ObjectClass *klass, void *data)
|
|||||||
dc->vmsd = &vmstate_vga_pci;
|
dc->vmsd = &vmstate_vga_pci;
|
||||||
dc->props = secondary_pci_properties;
|
dc->props = secondary_pci_properties;
|
||||||
dc->reset = pci_secondary_vga_reset;
|
dc->reset = pci_secondary_vga_reset;
|
||||||
|
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo vga_info = {
|
static const TypeInfo vga_info = {
|
||||||
|
@@ -1436,6 +1436,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|||||||
uint8_t *d;
|
uint8_t *d;
|
||||||
uint32_t v, addr1, addr;
|
uint32_t v, addr1, addr;
|
||||||
vga_draw_line_func *vga_draw_line = NULL;
|
vga_draw_line_func *vga_draw_line = NULL;
|
||||||
|
bool share_surface;
|
||||||
|
pixman_format_code_t format;
|
||||||
#ifdef HOST_WORDS_BIGENDIAN
|
#ifdef HOST_WORDS_BIGENDIAN
|
||||||
bool byteswap = !s->big_endian_fb;
|
bool byteswap = !s->big_endian_fb;
|
||||||
#else
|
#else
|
||||||
@@ -1479,21 +1481,42 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|||||||
}
|
}
|
||||||
|
|
||||||
depth = s->get_bpp(s);
|
depth = s->get_bpp(s);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether we can share the surface with the backend
|
||||||
|
* or whether we need a shadow surface. We share native
|
||||||
|
* endian surfaces for 15bpp and above and byteswapped
|
||||||
|
* surfaces for 24bpp and above.
|
||||||
|
*/
|
||||||
|
format = qemu_default_pixman_format(depth, !byteswap);
|
||||||
|
if (format) {
|
||||||
|
share_surface = dpy_gfx_check_format(s->con, format)
|
||||||
|
&& !s->force_shadow;
|
||||||
|
} else {
|
||||||
|
share_surface = false;
|
||||||
|
}
|
||||||
if (s->line_offset != s->last_line_offset ||
|
if (s->line_offset != s->last_line_offset ||
|
||||||
disp_width != s->last_width ||
|
disp_width != s->last_width ||
|
||||||
height != s->last_height ||
|
height != s->last_height ||
|
||||||
s->last_depth != depth ||
|
s->last_depth != depth ||
|
||||||
s->last_byteswap != byteswap) {
|
s->last_byteswap != byteswap ||
|
||||||
if (depth == 32 || (depth == 16 && !byteswap)) {
|
share_surface != is_buffer_shared(surface)) {
|
||||||
pixman_format_code_t format =
|
if (share_surface) {
|
||||||
qemu_default_pixman_format(depth, !byteswap);
|
|
||||||
surface = qemu_create_displaysurface_from(disp_width,
|
surface = qemu_create_displaysurface_from(disp_width,
|
||||||
height, format, s->line_offset,
|
height, format, s->line_offset,
|
||||||
s->vram_ptr + (s->start_addr * 4));
|
s->vram_ptr + (s->start_addr * 4));
|
||||||
dpy_gfx_replace_surface(s->con, surface);
|
dpy_gfx_replace_surface(s->con, surface);
|
||||||
|
#ifdef DEBUG_VGA
|
||||||
|
printf("VGA: Using shared surface for depth=%d swap=%d\n",
|
||||||
|
depth, byteswap);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
qemu_console_resize(s->con, disp_width, height);
|
qemu_console_resize(s->con, disp_width, height);
|
||||||
surface = qemu_console_surface(s->con);
|
surface = qemu_console_surface(s->con);
|
||||||
|
#ifdef DEBUG_VGA
|
||||||
|
printf("VGA: Using shadow surface for depth=%d swap=%d\n",
|
||||||
|
depth, byteswap);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
s->last_scr_width = disp_width;
|
s->last_scr_width = disp_width;
|
||||||
s->last_scr_height = height;
|
s->last_scr_height = height;
|
||||||
|
@@ -151,6 +151,7 @@ typedef struct VGACommonState {
|
|||||||
uint32_t last_scr_width, last_scr_height; /* in pixels */
|
uint32_t last_scr_width, last_scr_height; /* in pixels */
|
||||||
uint32_t last_depth; /* in bits */
|
uint32_t last_depth; /* in bits */
|
||||||
bool last_byteswap;
|
bool last_byteswap;
|
||||||
|
bool force_shadow;
|
||||||
uint8_t cursor_start, cursor_end;
|
uint8_t cursor_start, cursor_end;
|
||||||
bool cursor_visible_phase;
|
bool cursor_visible_phase;
|
||||||
int64_t cursor_blink_time;
|
int64_t cursor_blink_time;
|
||||||
@@ -162,6 +163,8 @@ typedef struct VGACommonState {
|
|||||||
bool default_endian_fb;
|
bool default_endian_fb;
|
||||||
/* hardware mouse cursor support */
|
/* hardware mouse cursor support */
|
||||||
uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
|
uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
|
||||||
|
uint32_t hw_cursor_x;
|
||||||
|
uint32_t hw_cursor_y;
|
||||||
void (*cursor_invalidate)(struct VGACommonState *s);
|
void (*cursor_invalidate)(struct VGACommonState *s);
|
||||||
void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
|
void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
|
||||||
/* tell for each page if it has been updated since the last time */
|
/* tell for each page if it has been updated since the last time */
|
||||||
|
@@ -68,6 +68,17 @@
|
|||||||
|
|
||||||
#define ACPI_BUILD_TABLE_SIZE 0x20000
|
#define ACPI_BUILD_TABLE_SIZE 0x20000
|
||||||
|
|
||||||
|
/* Reserve RAM space for tables: add another order of magnitude. */
|
||||||
|
#define ACPI_BUILD_TABLE_MAX_SIZE 0x200000
|
||||||
|
|
||||||
|
/* #define DEBUG_ACPI_BUILD */
|
||||||
|
#ifdef DEBUG_ACPI_BUILD
|
||||||
|
#define ACPI_BUILD_DPRINTF(fmt, ...) \
|
||||||
|
do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0)
|
||||||
|
#else
|
||||||
|
#define ACPI_BUILD_DPRINTF(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct AcpiCpuInfo {
|
typedef struct AcpiCpuInfo {
|
||||||
DECLARE_BITMAP(found_cpus, ACPI_CPU_HOTPLUG_ID_LIMIT);
|
DECLARE_BITMAP(found_cpus, ACPI_CPU_HOTPLUG_ID_LIMIT);
|
||||||
} AcpiCpuInfo;
|
} AcpiCpuInfo;
|
||||||
@@ -246,8 +257,6 @@ static void acpi_get_pci_info(PcPciInfo *info)
|
|||||||
#define ACPI_BUILD_APPNAME6 "BOCHS "
|
#define ACPI_BUILD_APPNAME6 "BOCHS "
|
||||||
#define ACPI_BUILD_APPNAME4 "BXPC"
|
#define ACPI_BUILD_APPNAME4 "BXPC"
|
||||||
|
|
||||||
#define ACPI_BUILD_DPRINTF(level, fmt, ...) do {} while (0)
|
|
||||||
|
|
||||||
#define ACPI_BUILD_TABLE_FILE "etc/acpi/tables"
|
#define ACPI_BUILD_TABLE_FILE "etc/acpi/tables"
|
||||||
#define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp"
|
#define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp"
|
||||||
#define ACPI_BUILD_TPMLOG_FILE "etc/tpm/log"
|
#define ACPI_BUILD_TPMLOG_FILE "etc/tpm/log"
|
||||||
@@ -273,12 +282,12 @@ build_header(GArray *linker, GArray *table_data,
|
|||||||
|
|
||||||
static inline GArray *build_alloc_array(void)
|
static inline GArray *build_alloc_array(void)
|
||||||
{
|
{
|
||||||
return g_array_new(false, true /* clear */, 1);
|
return g_array_new(false, true /* clear */, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void build_free_array(GArray *array)
|
static inline void build_free_array(GArray *array)
|
||||||
{
|
{
|
||||||
g_array_free(array, true);
|
g_array_free(array, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void build_prepend_byte(GArray *array, uint8_t val)
|
static inline void build_prepend_byte(GArray *array, uint8_t val)
|
||||||
@@ -1569,7 +1578,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
|
|||||||
|
|
||||||
table_offsets = g_array_new(false, true /* clear */,
|
table_offsets = g_array_new(false, true /* clear */,
|
||||||
sizeof(uint32_t));
|
sizeof(uint32_t));
|
||||||
ACPI_BUILD_DPRINTF(3, "init ACPI tables\n");
|
ACPI_BUILD_DPRINTF("init ACPI tables\n");
|
||||||
|
|
||||||
bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE,
|
bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE,
|
||||||
64 /* Ensure FACS is aligned */,
|
64 /* Ensure FACS is aligned */,
|
||||||
@@ -1712,6 +1721,11 @@ static void acpi_build_update(void *build_opaque, uint32_t offset)
|
|||||||
acpi_build(build_state->guest_info, &tables);
|
acpi_build(build_state->guest_info, &tables);
|
||||||
|
|
||||||
assert(acpi_data_len(tables.table_data) == build_state->table_size);
|
assert(acpi_data_len(tables.table_data) == build_state->table_size);
|
||||||
|
|
||||||
|
/* Make sure RAM size is correct - in case it got changed by migration */
|
||||||
|
qemu_ram_resize(build_state->table_ram, build_state->table_size,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
memcpy(qemu_get_ram_ptr(build_state->table_ram), tables.table_data->data,
|
memcpy(qemu_get_ram_ptr(build_state->table_ram), tables.table_data->data,
|
||||||
build_state->table_size);
|
build_state->table_size);
|
||||||
|
|
||||||
@@ -1728,10 +1742,10 @@ static void acpi_build_reset(void *build_opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ram_addr_t acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob,
|
static ram_addr_t acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob,
|
||||||
const char *name)
|
const char *name, uint64_t max_size)
|
||||||
{
|
{
|
||||||
return rom_add_blob(name, blob->data, acpi_data_len(blob), -1, name,
|
return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
|
||||||
acpi_build_update, build_state);
|
name, acpi_build_update, build_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_acpi_build = {
|
static const VMStateDescription vmstate_acpi_build = {
|
||||||
@@ -1750,17 +1764,17 @@ void acpi_setup(PcGuestInfo *guest_info)
|
|||||||
AcpiBuildState *build_state;
|
AcpiBuildState *build_state;
|
||||||
|
|
||||||
if (!guest_info->fw_cfg) {
|
if (!guest_info->fw_cfg) {
|
||||||
ACPI_BUILD_DPRINTF(3, "No fw cfg. Bailing out.\n");
|
ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!guest_info->has_acpi_build) {
|
if (!guest_info->has_acpi_build) {
|
||||||
ACPI_BUILD_DPRINTF(3, "ACPI build disabled. Bailing out.\n");
|
ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!acpi_enabled) {
|
if (!acpi_enabled) {
|
||||||
ACPI_BUILD_DPRINTF(3, "ACPI disabled. Bailing out.\n");
|
ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1775,11 +1789,12 @@ void acpi_setup(PcGuestInfo *guest_info)
|
|||||||
|
|
||||||
/* Now expose it all to Guest */
|
/* Now expose it all to Guest */
|
||||||
build_state->table_ram = acpi_add_rom_blob(build_state, tables.table_data,
|
build_state->table_ram = acpi_add_rom_blob(build_state, tables.table_data,
|
||||||
ACPI_BUILD_TABLE_FILE);
|
ACPI_BUILD_TABLE_FILE,
|
||||||
|
ACPI_BUILD_TABLE_MAX_SIZE);
|
||||||
assert(build_state->table_ram != RAM_ADDR_MAX);
|
assert(build_state->table_ram != RAM_ADDR_MAX);
|
||||||
build_state->table_size = acpi_data_len(tables.table_data);
|
build_state->table_size = acpi_data_len(tables.table_data);
|
||||||
|
|
||||||
acpi_add_rom_blob(NULL, tables.linker, "etc/table-loader");
|
acpi_add_rom_blob(NULL, tables.linker, "etc/table-loader", 0);
|
||||||
|
|
||||||
fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
|
fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
|
||||||
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
|
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
|
||||||
|
@@ -94,7 +94,6 @@ Scope(\_SB) {
|
|||||||
|
|
||||||
Device(CPU_HOTPLUG_RESOURCE_DEVICE) {
|
Device(CPU_HOTPLUG_RESOURCE_DEVICE) {
|
||||||
Name(_HID, EisaId("PNP0A06"))
|
Name(_HID, EisaId("PNP0A06"))
|
||||||
Name(_UID, "CPU hotplug resources")
|
|
||||||
|
|
||||||
Name(_CRS, ResourceTemplate() {
|
Name(_CRS, ResourceTemplate() {
|
||||||
IO(Decode16, CPU_STATUS_BASE, CPU_STATUS_BASE, 0, CPU_STATUS_LEN)
|
IO(Decode16, CPU_STATUS_BASE, CPU_STATUS_BASE, 0, CPU_STATUS_LEN)
|
||||||
|
@@ -3,12 +3,12 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x53,
|
0x53,
|
||||||
0x44,
|
0x44,
|
||||||
0x54,
|
0x54,
|
||||||
0x25,
|
0x8,
|
||||||
0xe,
|
0xe,
|
||||||
0x0,
|
0x0,
|
||||||
0x0,
|
0x0,
|
||||||
0x1,
|
0x1,
|
||||||
0x6e,
|
0xfc,
|
||||||
0x42,
|
0x42,
|
||||||
0x58,
|
0x58,
|
||||||
0x50,
|
0x50,
|
||||||
@@ -31,8 +31,8 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x4e,
|
0x4e,
|
||||||
0x54,
|
0x54,
|
||||||
0x4c,
|
0x4c,
|
||||||
0x14,
|
0x28,
|
||||||
0x2,
|
0x8,
|
||||||
0x14,
|
0x14,
|
||||||
0x20,
|
0x20,
|
||||||
0x10,
|
0x10,
|
||||||
@@ -2318,8 +2318,8 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x53,
|
0x53,
|
||||||
0x1,
|
0x1,
|
||||||
0x10,
|
0x10,
|
||||||
0x4f,
|
0x42,
|
||||||
0x12,
|
0x11,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x53,
|
0x53,
|
||||||
0x42,
|
0x42,
|
||||||
@@ -2551,8 +2551,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x60,
|
0x60,
|
||||||
0x5b,
|
0x5b,
|
||||||
0x82,
|
0x82,
|
||||||
0x46,
|
0x29,
|
||||||
0x4,
|
|
||||||
0x50,
|
0x50,
|
||||||
0x52,
|
0x52,
|
||||||
0x45,
|
0x45,
|
||||||
@@ -2569,34 +2568,6 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x6,
|
0x6,
|
||||||
0x8,
|
0x8,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x55,
|
|
||||||
0x49,
|
|
||||||
0x44,
|
|
||||||
0xd,
|
|
||||||
0x43,
|
|
||||||
0x50,
|
|
||||||
0x55,
|
|
||||||
0x20,
|
|
||||||
0x68,
|
|
||||||
0x6f,
|
|
||||||
0x74,
|
|
||||||
0x70,
|
|
||||||
0x6c,
|
|
||||||
0x75,
|
|
||||||
0x67,
|
|
||||||
0x20,
|
|
||||||
0x72,
|
|
||||||
0x65,
|
|
||||||
0x73,
|
|
||||||
0x6f,
|
|
||||||
0x75,
|
|
||||||
0x72,
|
|
||||||
0x63,
|
|
||||||
0x65,
|
|
||||||
0x73,
|
|
||||||
0x0,
|
|
||||||
0x8,
|
|
||||||
0x5f,
|
|
||||||
0x43,
|
0x43,
|
||||||
0x52,
|
0x52,
|
||||||
0x53,
|
0x53,
|
||||||
|
@@ -88,7 +88,7 @@ static void kvmclock_vm_state_change(void *opaque, int running,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (running) {
|
if (running) {
|
||||||
struct kvm_clock_data data;
|
struct kvm_clock_data data = {};
|
||||||
uint64_t time_at_migration = kvmclock_current_nsec(s);
|
uint64_t time_at_migration = kvmclock_current_nsec(s);
|
||||||
|
|
||||||
s->clock_valid = false;
|
s->clock_valid = false;
|
||||||
@@ -99,7 +99,6 @@ static void kvmclock_vm_state_change(void *opaque, int running,
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.clock = s->clock;
|
data.clock = s->clock;
|
||||||
data.flags = 0;
|
|
||||||
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
|
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(ret));
|
fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(ret));
|
||||||
|
@@ -138,7 +138,7 @@ static void kvm_pit_get(PITCommonState *pit)
|
|||||||
static void kvm_pit_put(PITCommonState *pit)
|
static void kvm_pit_put(PITCommonState *pit)
|
||||||
{
|
{
|
||||||
KVMPITState *s = KVM_PIT(pit);
|
KVMPITState *s = KVM_PIT(pit);
|
||||||
struct kvm_pit_state2 kpit;
|
struct kvm_pit_state2 kpit = {};
|
||||||
struct kvm_pit_channel_state *kchan;
|
struct kvm_pit_channel_state *kchan;
|
||||||
struct PITChannelState *sc;
|
struct PITChannelState *sc;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
@@ -54,6 +54,7 @@ enum {
|
|||||||
MBI_MODS_COUNT = 20,
|
MBI_MODS_COUNT = 20,
|
||||||
MBI_MODS_ADDR = 24,
|
MBI_MODS_ADDR = 24,
|
||||||
MBI_MMAP_ADDR = 48,
|
MBI_MMAP_ADDR = 48,
|
||||||
|
MBI_BOOTLOADER = 64,
|
||||||
|
|
||||||
MBI_SIZE = 88,
|
MBI_SIZE = 88,
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ enum {
|
|||||||
MULTIBOOT_FLAGS_CMDLINE = 1 << 2,
|
MULTIBOOT_FLAGS_CMDLINE = 1 << 2,
|
||||||
MULTIBOOT_FLAGS_MODULES = 1 << 3,
|
MULTIBOOT_FLAGS_MODULES = 1 << 3,
|
||||||
MULTIBOOT_FLAGS_MMAP = 1 << 6,
|
MULTIBOOT_FLAGS_MMAP = 1 << 6,
|
||||||
|
MULTIBOOT_FLAGS_BOOTLOADER = 1 << 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -87,6 +89,8 @@ typedef struct {
|
|||||||
hwaddr offset_mbinfo;
|
hwaddr offset_mbinfo;
|
||||||
/* offset in buffer for cmdlines in bytes */
|
/* offset in buffer for cmdlines in bytes */
|
||||||
hwaddr offset_cmdlines;
|
hwaddr offset_cmdlines;
|
||||||
|
/* offset in buffer for bootloader name in bytes */
|
||||||
|
hwaddr offset_bootloader;
|
||||||
/* offset of modules in bytes */
|
/* offset of modules in bytes */
|
||||||
hwaddr offset_mods;
|
hwaddr offset_mods;
|
||||||
/* available slots for mb modules infos */
|
/* available slots for mb modules infos */
|
||||||
@@ -95,6 +99,8 @@ typedef struct {
|
|||||||
int mb_mods_count;
|
int mb_mods_count;
|
||||||
} MultibootState;
|
} MultibootState;
|
||||||
|
|
||||||
|
const char *bootloader_name = "qemu";
|
||||||
|
|
||||||
static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
|
static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
|
||||||
{
|
{
|
||||||
hwaddr p = s->offset_cmdlines;
|
hwaddr p = s->offset_cmdlines;
|
||||||
@@ -105,6 +111,16 @@ static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
|
|||||||
return s->mb_buf_phys + p;
|
return s->mb_buf_phys + p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t mb_add_bootloader(MultibootState *s, const char *bootloader)
|
||||||
|
{
|
||||||
|
hwaddr p = s->offset_bootloader;
|
||||||
|
char *b = (char *)s->mb_buf + p;
|
||||||
|
|
||||||
|
memcpy(b, bootloader, strlen(bootloader) + 1);
|
||||||
|
s->offset_bootloader += strlen(b) + 1;
|
||||||
|
return s->mb_buf_phys + p;
|
||||||
|
}
|
||||||
|
|
||||||
static void mb_add_mod(MultibootState *s,
|
static void mb_add_mod(MultibootState *s,
|
||||||
hwaddr start, hwaddr end,
|
hwaddr start, hwaddr end,
|
||||||
hwaddr cmdline_phys)
|
hwaddr cmdline_phys)
|
||||||
@@ -241,9 +257,10 @@ int load_multiboot(FWCfgState *fw_cfg,
|
|||||||
mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
|
mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
|
||||||
mbs.offset_mbinfo = mbs.mb_buf_size;
|
mbs.offset_mbinfo = mbs.mb_buf_size;
|
||||||
|
|
||||||
/* Calculate space for cmdlines and mb_mods */
|
/* Calculate space for cmdlines, bootloader name, and mb_mods */
|
||||||
mbs.mb_buf_size += strlen(kernel_filename) + 1;
|
mbs.mb_buf_size += strlen(kernel_filename) + 1;
|
||||||
mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
|
mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
|
||||||
|
mbs.mb_buf_size += strlen(bootloader_name) + 1;
|
||||||
if (initrd_filename) {
|
if (initrd_filename) {
|
||||||
const char *r = initrd_filename;
|
const char *r = initrd_filename;
|
||||||
mbs.mb_buf_size += strlen(r) + 1;
|
mbs.mb_buf_size += strlen(r) + 1;
|
||||||
@@ -257,9 +274,11 @@ int load_multiboot(FWCfgState *fw_cfg,
|
|||||||
|
|
||||||
mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
|
mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
|
||||||
|
|
||||||
/* enlarge mb_buf to hold cmdlines and mb-info structs */
|
/* enlarge mb_buf to hold cmdlines, bootloader, mb-info structs */
|
||||||
mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
|
mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
|
||||||
mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
|
mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
|
||||||
|
mbs.offset_bootloader = mbs.offset_cmdlines + strlen(kernel_filename) + 1
|
||||||
|
+ strlen(kernel_cmdline) + 1;
|
||||||
|
|
||||||
if (initrd_filename) {
|
if (initrd_filename) {
|
||||||
char *next_initrd, not_last;
|
char *next_initrd, not_last;
|
||||||
@@ -306,6 +325,8 @@ int load_multiboot(FWCfgState *fw_cfg,
|
|||||||
kernel_filename, kernel_cmdline);
|
kernel_filename, kernel_cmdline);
|
||||||
stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
|
stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
|
||||||
|
|
||||||
|
stl_p(bootinfo + MBI_BOOTLOADER, mb_add_bootloader(&mbs, bootloader_name));
|
||||||
|
|
||||||
stl_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo);
|
stl_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo);
|
||||||
stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
|
stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
|
||||||
|
|
||||||
@@ -314,7 +335,8 @@ int load_multiboot(FWCfgState *fw_cfg,
|
|||||||
| MULTIBOOT_FLAGS_BOOT_DEVICE
|
| MULTIBOOT_FLAGS_BOOT_DEVICE
|
||||||
| MULTIBOOT_FLAGS_CMDLINE
|
| MULTIBOOT_FLAGS_CMDLINE
|
||||||
| MULTIBOOT_FLAGS_MODULES
|
| MULTIBOOT_FLAGS_MODULES
|
||||||
| MULTIBOOT_FLAGS_MMAP);
|
| MULTIBOOT_FLAGS_MMAP
|
||||||
|
| MULTIBOOT_FLAGS_BOOTLOADER);
|
||||||
stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
|
stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
|
||||||
stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
|
stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
|
||||||
|
|
||||||
|
36
hw/i386/pc.c
36
hw/i386/pc.c
@@ -282,7 +282,7 @@ static int boot_device2nibble(char boot_device)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_boot_dev(ISADevice *s, const char *boot_device)
|
static void set_boot_dev(ISADevice *s, const char *boot_device, Error **errp)
|
||||||
{
|
{
|
||||||
#define PC_MAX_BOOT_DEVICES 3
|
#define PC_MAX_BOOT_DEVICES 3
|
||||||
int nbds, bds[3] = { 0, };
|
int nbds, bds[3] = { 0, };
|
||||||
@@ -290,25 +290,24 @@ static int set_boot_dev(ISADevice *s, const char *boot_device)
|
|||||||
|
|
||||||
nbds = strlen(boot_device);
|
nbds = strlen(boot_device);
|
||||||
if (nbds > PC_MAX_BOOT_DEVICES) {
|
if (nbds > PC_MAX_BOOT_DEVICES) {
|
||||||
error_report("Too many boot devices for PC");
|
error_setg(errp, "Too many boot devices for PC");
|
||||||
return(1);
|
return;
|
||||||
}
|
}
|
||||||
for (i = 0; i < nbds; i++) {
|
for (i = 0; i < nbds; i++) {
|
||||||
bds[i] = boot_device2nibble(boot_device[i]);
|
bds[i] = boot_device2nibble(boot_device[i]);
|
||||||
if (bds[i] == 0) {
|
if (bds[i] == 0) {
|
||||||
error_report("Invalid boot device for PC: '%c'",
|
error_setg(errp, "Invalid boot device for PC: '%c'",
|
||||||
boot_device[i]);
|
boot_device[i]);
|
||||||
return(1);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
|
rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
|
||||||
rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
|
rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
|
||||||
return(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pc_boot_set(void *opaque, const char *boot_device)
|
static void pc_boot_set(void *opaque, const char *boot_device, Error **errp)
|
||||||
{
|
{
|
||||||
return set_boot_dev(opaque, boot_device);
|
set_boot_dev(opaque, boot_device, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct pc_cmos_init_late_arg {
|
typedef struct pc_cmos_init_late_arg {
|
||||||
@@ -365,6 +364,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
|||||||
FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
|
FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
|
||||||
static pc_cmos_init_late_arg arg;
|
static pc_cmos_init_late_arg arg;
|
||||||
PCMachineState *pc_machine = PC_MACHINE(machine);
|
PCMachineState *pc_machine = PC_MACHINE(machine);
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
/* various important CMOS locations needed by PC/Bochs bios */
|
/* various important CMOS locations needed by PC/Bochs bios */
|
||||||
|
|
||||||
@@ -412,7 +412,9 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
|||||||
object_property_set_link(OBJECT(machine), OBJECT(s),
|
object_property_set_link(OBJECT(machine), OBJECT(s),
|
||||||
"rtc_state", &error_abort);
|
"rtc_state", &error_abort);
|
||||||
|
|
||||||
if (set_boot_dev(s, boot_device)) {
|
set_boot_dev(s, boot_device, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report("%s", error_get_pretty(local_err));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,8 +604,7 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* new "etc/e820" file -- include ram too */
|
/* new "etc/e820" file -- include ram too */
|
||||||
e820_table = g_realloc(e820_table,
|
e820_table = g_renew(struct e820_entry, e820_table, e820_entries + 1);
|
||||||
sizeof(struct e820_entry) * (e820_entries+1));
|
|
||||||
e820_table[e820_entries].address = cpu_to_le64(address);
|
e820_table[e820_entries].address = cpu_to_le64(address);
|
||||||
e820_table[e820_entries].length = cpu_to_le64(length);
|
e820_table[e820_entries].length = cpu_to_le64(length);
|
||||||
e820_table[e820_entries].type = cpu_to_le32(type);
|
e820_table[e820_entries].type = cpu_to_le32(type);
|
||||||
@@ -648,7 +649,7 @@ static FWCfgState *bochs_bios_init(void)
|
|||||||
int i, j;
|
int i, j;
|
||||||
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
|
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
|
||||||
|
|
||||||
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
|
fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
|
||||||
/* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
|
/* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
|
||||||
*
|
*
|
||||||
* SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
|
* SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
|
||||||
@@ -1169,7 +1170,7 @@ FWCfgState *xen_load_linux(const char *kernel_filename,
|
|||||||
|
|
||||||
assert(kernel_filename != NULL);
|
assert(kernel_filename != NULL);
|
||||||
|
|
||||||
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
|
fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
|
||||||
rom_set_fw(fw_cfg);
|
rom_set_fw(fw_cfg);
|
||||||
|
|
||||||
load_linux(fw_cfg, kernel_filename, initrd_filename,
|
load_linux(fw_cfg, kernel_filename, initrd_filename,
|
||||||
@@ -1804,17 +1805,24 @@ static void pc_machine_initfn(Object *obj)
|
|||||||
object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int",
|
object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int",
|
||||||
pc_machine_get_hotplug_memory_region_size,
|
pc_machine_get_hotplug_memory_region_size,
|
||||||
NULL, NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
pcms->max_ram_below_4g = 1ULL << 32; /* 4G */
|
pcms->max_ram_below_4g = 1ULL << 32; /* 4G */
|
||||||
object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
|
object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
|
||||||
pc_machine_get_max_ram_below_4g,
|
pc_machine_get_max_ram_below_4g,
|
||||||
pc_machine_set_max_ram_below_4g,
|
pc_machine_set_max_ram_below_4g,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
object_property_set_description(obj, PC_MACHINE_MAX_RAM_BELOW_4G,
|
||||||
|
"Maximum ram below the 4G boundary (32bit boundary)",
|
||||||
|
NULL);
|
||||||
|
|
||||||
pcms->vmport = ON_OFF_AUTO_AUTO;
|
pcms->vmport = ON_OFF_AUTO_AUTO;
|
||||||
object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto",
|
object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto",
|
||||||
pc_machine_get_vmport,
|
pc_machine_get_vmport,
|
||||||
pc_machine_set_vmport,
|
pc_machine_set_vmport,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
object_property_set_description(obj, PC_MACHINE_VMPORT,
|
||||||
|
"Enable vmport (pc & q35)",
|
||||||
|
NULL);
|
||||||
|
|
||||||
pcms->enforce_aligned_dimm = true;
|
pcms->enforce_aligned_dimm = true;
|
||||||
object_property_add_bool(obj, PC_MACHINE_ENFORCE_ALIGNED_DIMM,
|
object_property_add_bool(obj, PC_MACHINE_ENFORCE_ALIGNED_DIMM,
|
||||||
|
@@ -274,7 +274,7 @@ static void pc_init1(MachineState *machine,
|
|||||||
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
|
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
|
||||||
machine, floppy, idebus[0], idebus[1], rtc_state);
|
machine, floppy, idebus[0], idebus[1], rtc_state);
|
||||||
|
|
||||||
if (pci_enabled && usb_enabled(false)) {
|
if (pci_enabled && usb_enabled()) {
|
||||||
pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
|
pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,9 +308,33 @@ static void pc_init_pci(MachineState *machine)
|
|||||||
pc_init1(machine, 1, 1);
|
pc_init1(machine, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_compat_2_2(MachineState *machine)
|
||||||
|
{
|
||||||
|
x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Conroe", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Penryn", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Nehalem", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Westmere", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("SandyBridge", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Haswell", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Broadwell", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G1", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G2", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G3", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G4", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G5", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_F16C);
|
||||||
|
x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND);
|
||||||
|
x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C);
|
||||||
|
x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND);
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_compat_2_1(MachineState *machine)
|
static void pc_compat_2_1(MachineState *machine)
|
||||||
{
|
{
|
||||||
PCMachineState *pcms = PC_MACHINE(machine);
|
PCMachineState *pcms = PC_MACHINE(machine);
|
||||||
|
|
||||||
|
pc_compat_2_2(machine);
|
||||||
smbios_uuid_encoded = false;
|
smbios_uuid_encoded = false;
|
||||||
x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
||||||
x86_cpu_compat_set_features("core2duo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
x86_cpu_compat_set_features("core2duo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
||||||
@@ -385,6 +409,12 @@ static void pc_compat_1_2(MachineState *machine)
|
|||||||
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_init_pci_2_2(MachineState *machine)
|
||||||
|
{
|
||||||
|
pc_compat_2_2(machine);
|
||||||
|
pc_init_pci(machine);
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_init_pci_2_1(MachineState *machine)
|
static void pc_init_pci_2_1(MachineState *machine)
|
||||||
{
|
{
|
||||||
pc_compat_2_1(machine);
|
pc_compat_2_1(machine);
|
||||||
@@ -478,19 +508,27 @@ static void pc_xen_hvm_init(MachineState *machine)
|
|||||||
.desc = "Standard PC (i440FX + PIIX, 1996)", \
|
.desc = "Standard PC (i440FX + PIIX, 1996)", \
|
||||||
.hot_add_cpu = pc_hot_add_cpu
|
.hot_add_cpu = pc_hot_add_cpu
|
||||||
|
|
||||||
#define PC_I440FX_2_2_MACHINE_OPTIONS \
|
#define PC_I440FX_2_3_MACHINE_OPTIONS \
|
||||||
PC_I440FX_MACHINE_OPTIONS, \
|
PC_I440FX_MACHINE_OPTIONS, \
|
||||||
.default_machine_opts = "firmware=bios-256k.bin", \
|
.default_machine_opts = "firmware=bios-256k.bin", \
|
||||||
.default_display = "std"
|
.default_display = "std"
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v2_2 = {
|
static QEMUMachine pc_i440fx_machine_v2_3 = {
|
||||||
PC_I440FX_2_2_MACHINE_OPTIONS,
|
PC_I440FX_2_3_MACHINE_OPTIONS,
|
||||||
.name = "pc-i440fx-2.2",
|
.name = "pc-i440fx-2.3",
|
||||||
.alias = "pc",
|
.alias = "pc",
|
||||||
.init = pc_init_pci,
|
.init = pc_init_pci,
|
||||||
.is_default = 1,
|
.is_default = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PC_I440FX_2_2_MACHINE_OPTIONS PC_I440FX_2_3_MACHINE_OPTIONS
|
||||||
|
|
||||||
|
static QEMUMachine pc_i440fx_machine_v2_2 = {
|
||||||
|
PC_I440FX_2_2_MACHINE_OPTIONS,
|
||||||
|
.name = "pc-i440fx-2.2",
|
||||||
|
.init = pc_init_pci_2_2,
|
||||||
|
};
|
||||||
|
|
||||||
#define PC_I440FX_2_1_MACHINE_OPTIONS \
|
#define PC_I440FX_2_1_MACHINE_OPTIONS \
|
||||||
PC_I440FX_MACHINE_OPTIONS, \
|
PC_I440FX_MACHINE_OPTIONS, \
|
||||||
.default_machine_opts = "firmware=bios-256k.bin"
|
.default_machine_opts = "firmware=bios-256k.bin"
|
||||||
@@ -928,6 +966,7 @@ static QEMUMachine xenfv_machine = {
|
|||||||
|
|
||||||
static void pc_machine_init(void)
|
static void pc_machine_init(void)
|
||||||
{
|
{
|
||||||
|
qemu_register_pc_machine(&pc_i440fx_machine_v2_3);
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_2);
|
qemu_register_pc_machine(&pc_i440fx_machine_v2_2);
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_1);
|
qemu_register_pc_machine(&pc_i440fx_machine_v2_1);
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_0);
|
qemu_register_pc_machine(&pc_i440fx_machine_v2_0);
|
||||||
|
@@ -265,7 +265,7 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
|
ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
|
||||||
ahci_ide_create_devs(ahci, hd);
|
ahci_ide_create_devs(ahci, hd);
|
||||||
|
|
||||||
if (usb_enabled(false)) {
|
if (usb_enabled()) {
|
||||||
/* Should we create 6 UHCI according to ich9 spec? */
|
/* Should we create 6 UHCI according to ich9 spec? */
|
||||||
ehci_create_ich9_with_companions(host_bus, 0x1d);
|
ehci_create_ich9_with_companions(host_bus, 0x1d);
|
||||||
}
|
}
|
||||||
@@ -287,10 +287,33 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_compat_2_2(MachineState *machine)
|
||||||
|
{
|
||||||
|
x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Conroe", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Penryn", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Nehalem", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Westmere", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("SandyBridge", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Haswell", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Broadwell", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G1", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G2", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G3", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G4", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Opteron_G5", FEAT_1_EDX, 0, CPUID_VME);
|
||||||
|
x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_F16C);
|
||||||
|
x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND);
|
||||||
|
x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C);
|
||||||
|
x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND);
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_compat_2_1(MachineState *machine)
|
static void pc_compat_2_1(MachineState *machine)
|
||||||
{
|
{
|
||||||
PCMachineState *pcms = PC_MACHINE(machine);
|
PCMachineState *pcms = PC_MACHINE(machine);
|
||||||
|
|
||||||
|
pc_compat_2_2(machine);
|
||||||
pcms->enforce_aligned_dimm = false;
|
pcms->enforce_aligned_dimm = false;
|
||||||
smbios_uuid_encoded = false;
|
smbios_uuid_encoded = false;
|
||||||
x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0);
|
||||||
@@ -334,6 +357,12 @@ static void pc_compat_1_4(MachineState *machine)
|
|||||||
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_q35_init_2_2(MachineState *machine)
|
||||||
|
{
|
||||||
|
pc_compat_2_2(machine);
|
||||||
|
pc_q35_init(machine);
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_q35_init_2_1(MachineState *machine)
|
static void pc_q35_init_2_1(MachineState *machine)
|
||||||
{
|
{
|
||||||
pc_compat_2_1(machine);
|
pc_compat_2_1(machine);
|
||||||
@@ -377,16 +406,24 @@ static void pc_q35_init_1_4(MachineState *machine)
|
|||||||
.hot_add_cpu = pc_hot_add_cpu, \
|
.hot_add_cpu = pc_hot_add_cpu, \
|
||||||
.units_per_default_bus = 1
|
.units_per_default_bus = 1
|
||||||
|
|
||||||
#define PC_Q35_2_2_MACHINE_OPTIONS \
|
#define PC_Q35_2_3_MACHINE_OPTIONS \
|
||||||
PC_Q35_MACHINE_OPTIONS, \
|
PC_Q35_MACHINE_OPTIONS, \
|
||||||
.default_machine_opts = "firmware=bios-256k.bin", \
|
.default_machine_opts = "firmware=bios-256k.bin", \
|
||||||
.default_display = "std"
|
.default_display = "std"
|
||||||
|
|
||||||
|
static QEMUMachine pc_q35_machine_v2_3 = {
|
||||||
|
PC_Q35_2_3_MACHINE_OPTIONS,
|
||||||
|
.name = "pc-q35-2.3",
|
||||||
|
.alias = "q35",
|
||||||
|
.init = pc_q35_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PC_Q35_2_2_MACHINE_OPTIONS PC_Q35_2_3_MACHINE_OPTIONS
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v2_2 = {
|
static QEMUMachine pc_q35_machine_v2_2 = {
|
||||||
PC_Q35_2_2_MACHINE_OPTIONS,
|
PC_Q35_2_2_MACHINE_OPTIONS,
|
||||||
.name = "pc-q35-2.2",
|
.name = "pc-q35-2.2",
|
||||||
.alias = "q35",
|
.init = pc_q35_init_2_2,
|
||||||
.init = pc_q35_init,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PC_Q35_2_1_MACHINE_OPTIONS \
|
#define PC_Q35_2_1_MACHINE_OPTIONS \
|
||||||
@@ -465,6 +502,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
|
|||||||
|
|
||||||
static void pc_q35_machine_init(void)
|
static void pc_q35_machine_init(void)
|
||||||
{
|
{
|
||||||
|
qemu_register_pc_machine(&pc_q35_machine_v2_3);
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v2_2);
|
qemu_register_pc_machine(&pc_q35_machine_v2_2);
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v2_1);
|
qemu_register_pc_machine(&pc_q35_machine_v2_1);
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v2_0);
|
qemu_register_pc_machine(&pc_q35_machine_v2_0);
|
||||||
|
@@ -204,9 +204,7 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
|
|||||||
fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
|
fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (filename) {
|
g_free(filename);
|
||||||
g_free(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* map the last 128KB of the BIOS in ISA space */
|
/* map the last 128KB of the BIOS in ISA space */
|
||||||
isa_bios_size = bios_size;
|
isa_bios_size = bios_size;
|
||||||
|
@@ -3,12 +3,12 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x53,
|
0x53,
|
||||||
0x44,
|
0x44,
|
||||||
0x54,
|
0x54,
|
||||||
0x13,
|
0xf6,
|
||||||
0x20,
|
0x1f,
|
||||||
0x0,
|
0x0,
|
||||||
0x0,
|
0x0,
|
||||||
0x1,
|
0x1,
|
||||||
0x2,
|
0x91,
|
||||||
0x42,
|
0x42,
|
||||||
0x58,
|
0x58,
|
||||||
0x50,
|
0x50,
|
||||||
@@ -31,8 +31,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x4e,
|
0x4e,
|
||||||
0x54,
|
0x54,
|
||||||
0x4c,
|
0x4c,
|
||||||
0x14,
|
0x28,
|
||||||
0x2,
|
0x8,
|
||||||
0x14,
|
0x14,
|
||||||
0x20,
|
0x20,
|
||||||
0x10,
|
0x10,
|
||||||
@@ -6959,8 +6959,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x53,
|
0x53,
|
||||||
0x1,
|
0x1,
|
||||||
0x10,
|
0x10,
|
||||||
0x4f,
|
0x42,
|
||||||
0x12,
|
0x11,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x53,
|
0x53,
|
||||||
0x42,
|
0x42,
|
||||||
@@ -7192,8 +7192,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x60,
|
0x60,
|
||||||
0x5b,
|
0x5b,
|
||||||
0x82,
|
0x82,
|
||||||
0x46,
|
0x29,
|
||||||
0x4,
|
|
||||||
0x50,
|
0x50,
|
||||||
0x52,
|
0x52,
|
||||||
0x45,
|
0x45,
|
||||||
@@ -7210,34 +7209,6 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x6,
|
0x6,
|
||||||
0x8,
|
0x8,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x55,
|
|
||||||
0x49,
|
|
||||||
0x44,
|
|
||||||
0xd,
|
|
||||||
0x43,
|
|
||||||
0x50,
|
|
||||||
0x55,
|
|
||||||
0x20,
|
|
||||||
0x68,
|
|
||||||
0x6f,
|
|
||||||
0x74,
|
|
||||||
0x70,
|
|
||||||
0x6c,
|
|
||||||
0x75,
|
|
||||||
0x67,
|
|
||||||
0x20,
|
|
||||||
0x72,
|
|
||||||
0x65,
|
|
||||||
0x73,
|
|
||||||
0x6f,
|
|
||||||
0x75,
|
|
||||||
0x72,
|
|
||||||
0x63,
|
|
||||||
0x65,
|
|
||||||
0x73,
|
|
||||||
0x0,
|
|
||||||
0x8,
|
|
||||||
0x5f,
|
|
||||||
0x43,
|
0x43,
|
||||||
0x52,
|
0x52,
|
||||||
0x53,
|
0x53,
|
||||||
|
@@ -34,15 +34,15 @@
|
|||||||
#include <hw/ide/pci.h>
|
#include <hw/ide/pci.h>
|
||||||
#include <hw/ide/ahci.h>
|
#include <hw/ide/ahci.h>
|
||||||
|
|
||||||
/* #define DEBUG_AHCI */
|
#define DEBUG_AHCI 0
|
||||||
|
|
||||||
#ifdef DEBUG_AHCI
|
|
||||||
#define DPRINTF(port, fmt, ...) \
|
#define DPRINTF(port, fmt, ...) \
|
||||||
do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \
|
do { \
|
||||||
fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
|
if (DEBUG_AHCI) { \
|
||||||
#else
|
fprintf(stderr, "ahci: %s: [%d] ", __func__, port); \
|
||||||
#define DPRINTF(port, fmt, ...) do {} while(0)
|
fprintf(stderr, fmt, ## __VA_ARGS__); \
|
||||||
#endif
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static void check_cmd(AHCIState *s, int port);
|
static void check_cmd(AHCIState *s, int port);
|
||||||
static int handle_cmd(AHCIState *s,int port,int slot);
|
static int handle_cmd(AHCIState *s,int port,int slot);
|
||||||
@@ -551,7 +551,7 @@ static void ahci_reset_port(AHCIState *s, int port)
|
|||||||
|
|
||||||
static void debug_print_fis(uint8_t *fis, int cmd_len)
|
static void debug_print_fis(uint8_t *fis, int cmd_len)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_AHCI
|
#if DEBUG_AHCI
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
fprintf(stderr, "fis:");
|
fprintf(stderr, "fis:");
|
||||||
@@ -580,7 +580,7 @@ static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
|
|||||||
sdb_fis = (SDBFIS *)&ad->res_fis[RES_FIS_SDBFIS];
|
sdb_fis = (SDBFIS *)&ad->res_fis[RES_FIS_SDBFIS];
|
||||||
ide_state = &ad->port.ifs[0];
|
ide_state = &ad->port.ifs[0];
|
||||||
|
|
||||||
sdb_fis->type = 0xA1;
|
sdb_fis->type = SATA_FIS_TYPE_SDB;
|
||||||
/* Interrupt pending & Notification bit */
|
/* Interrupt pending & Notification bit */
|
||||||
sdb_fis->flags = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
|
sdb_fis->flags = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
|
||||||
sdb_fis->status = ide_state->status & 0x77;
|
sdb_fis->status = ide_state->status & 0x77;
|
||||||
@@ -631,7 +631,7 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
|
|||||||
|
|
||||||
pio_fis = &ad->res_fis[RES_FIS_PSFIS];
|
pio_fis = &ad->res_fis[RES_FIS_PSFIS];
|
||||||
|
|
||||||
pio_fis[0] = 0x5f;
|
pio_fis[0] = SATA_FIS_TYPE_PIO_SETUP;
|
||||||
pio_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
|
pio_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
|
||||||
pio_fis[2] = s->status;
|
pio_fis[2] = s->status;
|
||||||
pio_fis[3] = s->error;
|
pio_fis[3] = s->error;
|
||||||
@@ -690,7 +690,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
|||||||
|
|
||||||
d2h_fis = &ad->res_fis[RES_FIS_RFIS];
|
d2h_fis = &ad->res_fis[RES_FIS_RFIS];
|
||||||
|
|
||||||
d2h_fis[0] = 0x34;
|
d2h_fis[0] = SATA_FIS_TYPE_REGISTER_D2H;
|
||||||
d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
|
d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
|
||||||
d2h_fis[2] = s->status;
|
d2h_fis[2] = s->status;
|
||||||
d2h_fis[3] = s->error;
|
d2h_fis[3] = s->error;
|
||||||
@@ -1154,9 +1154,7 @@ out:
|
|||||||
static void ahci_start_dma(IDEDMA *dma, IDEState *s,
|
static void ahci_start_dma(IDEDMA *dma, IDEState *s,
|
||||||
BlockCompletionFunc *dma_cb)
|
BlockCompletionFunc *dma_cb)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_AHCI
|
|
||||||
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
||||||
#endif
|
|
||||||
DPRINTF(ad->port_no, "\n");
|
DPRINTF(ad->port_no, "\n");
|
||||||
s->io_buffer_offset = 0;
|
s->io_buffer_offset = 0;
|
||||||
dma_cb(s, 0);
|
dma_cb(s, 0);
|
||||||
|
@@ -156,7 +156,10 @@
|
|||||||
#define AHCI_SCR_SCTL_DET 0xf
|
#define AHCI_SCR_SCTL_DET 0xf
|
||||||
|
|
||||||
#define SATA_FIS_TYPE_REGISTER_H2D 0x27
|
#define SATA_FIS_TYPE_REGISTER_H2D 0x27
|
||||||
#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
|
#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
|
||||||
|
#define SATA_FIS_TYPE_REGISTER_D2H 0x34
|
||||||
|
#define SATA_FIS_TYPE_PIO_SETUP 0x5f
|
||||||
|
#define SATA_FIS_TYPE_SDB 0xA1
|
||||||
|
|
||||||
#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
|
#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
|
||||||
#define AHCI_CMD_HDR_PRDT_LEN 16
|
#define AHCI_CMD_HDR_PRDT_LEN 16
|
||||||
|
111
hw/ide/atapi.c
111
hw/ide/atapi.c
@@ -621,20 +621,107 @@ static void cmd_request_sense(IDEState *s, uint8_t *buf)
|
|||||||
|
|
||||||
static void cmd_inquiry(IDEState *s, uint8_t *buf)
|
static void cmd_inquiry(IDEState *s, uint8_t *buf)
|
||||||
{
|
{
|
||||||
|
uint8_t page_code = buf[2];
|
||||||
int max_len = buf[4];
|
int max_len = buf[4];
|
||||||
|
|
||||||
buf[0] = 0x05; /* CD-ROM */
|
unsigned idx = 0;
|
||||||
buf[1] = 0x80; /* removable */
|
unsigned size_idx;
|
||||||
buf[2] = 0x00; /* ISO */
|
unsigned preamble_len;
|
||||||
buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
|
|
||||||
buf[4] = 31; /* additional length */
|
/* If the EVPD (Enable Vital Product Data) bit is set in byte 1,
|
||||||
buf[5] = 0; /* reserved */
|
* we are being asked for a specific page of info indicated by byte 2. */
|
||||||
buf[6] = 0; /* reserved */
|
if (buf[1] & 0x01) {
|
||||||
buf[7] = 0; /* reserved */
|
preamble_len = 4;
|
||||||
padstr8(buf + 8, 8, "QEMU");
|
size_idx = 3;
|
||||||
padstr8(buf + 16, 16, "QEMU DVD-ROM");
|
|
||||||
padstr8(buf + 32, 4, s->version);
|
buf[idx++] = 0x05; /* CD-ROM */
|
||||||
ide_atapi_cmd_reply(s, 36, max_len);
|
buf[idx++] = page_code; /* Page Code */
|
||||||
|
buf[idx++] = 0x00; /* reserved */
|
||||||
|
idx++; /* length (set later) */
|
||||||
|
|
||||||
|
switch (page_code) {
|
||||||
|
case 0x00:
|
||||||
|
/* Supported Pages: List of supported VPD responses. */
|
||||||
|
buf[idx++] = 0x00; /* 0x00: Supported Pages, and: */
|
||||||
|
buf[idx++] = 0x83; /* 0x83: Device Identification. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x83:
|
||||||
|
/* Device Identification. Each entry is optional, but the entries
|
||||||
|
* included here are modeled after libata's VPD responses.
|
||||||
|
* If the response is given, at least one entry must be present. */
|
||||||
|
|
||||||
|
/* Entry 1: Serial */
|
||||||
|
if (idx + 24 > max_len) {
|
||||||
|
/* Not enough room for even the first entry: */
|
||||||
|
/* 4 byte header + 20 byte string */
|
||||||
|
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
|
||||||
|
ASC_DATA_PHASE_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buf[idx++] = 0x02; /* Ascii */
|
||||||
|
buf[idx++] = 0x00; /* Vendor Specific */
|
||||||
|
buf[idx++] = 0x00;
|
||||||
|
buf[idx++] = 20; /* Remaining length */
|
||||||
|
padstr8(buf + idx, 20, s->drive_serial_str);
|
||||||
|
idx += 20;
|
||||||
|
|
||||||
|
/* Entry 2: Drive Model and Serial */
|
||||||
|
if (idx + 72 > max_len) {
|
||||||
|
/* 4 (header) + 8 (vendor) + 60 (model & serial) */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
buf[idx++] = 0x02; /* Ascii */
|
||||||
|
buf[idx++] = 0x01; /* T10 Vendor */
|
||||||
|
buf[idx++] = 0x00;
|
||||||
|
buf[idx++] = 68;
|
||||||
|
padstr8(buf + idx, 8, "ATA"); /* Generic T10 vendor */
|
||||||
|
idx += 8;
|
||||||
|
padstr8(buf + idx, 40, s->drive_model_str);
|
||||||
|
idx += 40;
|
||||||
|
padstr8(buf + idx, 20, s->drive_serial_str);
|
||||||
|
idx += 20;
|
||||||
|
|
||||||
|
/* Entry 3: WWN */
|
||||||
|
if (s->wwn && (idx + 12 <= max_len)) {
|
||||||
|
/* 4 byte header + 8 byte wwn */
|
||||||
|
buf[idx++] = 0x01; /* Binary */
|
||||||
|
buf[idx++] = 0x03; /* NAA */
|
||||||
|
buf[idx++] = 0x00;
|
||||||
|
buf[idx++] = 0x08;
|
||||||
|
stq_be_p(&buf[idx], s->wwn);
|
||||||
|
idx += 8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* SPC-3, revision 23 sec. 6.4 */
|
||||||
|
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
|
||||||
|
ASC_INV_FIELD_IN_CMD_PACKET);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
preamble_len = 5;
|
||||||
|
size_idx = 4;
|
||||||
|
|
||||||
|
buf[0] = 0x05; /* CD-ROM */
|
||||||
|
buf[1] = 0x80; /* removable */
|
||||||
|
buf[2] = 0x00; /* ISO */
|
||||||
|
buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
|
||||||
|
/* buf[size_idx] set below. */
|
||||||
|
buf[5] = 0; /* reserved */
|
||||||
|
buf[6] = 0; /* reserved */
|
||||||
|
buf[7] = 0; /* reserved */
|
||||||
|
padstr8(buf + 8, 8, "QEMU");
|
||||||
|
padstr8(buf + 16, 16, "QEMU DVD-ROM");
|
||||||
|
padstr8(buf + 32, 4, s->version);
|
||||||
|
idx = 36;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
buf[size_idx] = idx - preamble_len;
|
||||||
|
ide_atapi_cmd_reply(s, idx, max_len);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_get_configuration(IDEState *s, uint8_t *buf)
|
static void cmd_get_configuration(IDEState *s, uint8_t *buf)
|
||||||
|
@@ -296,6 +296,7 @@ typedef struct IDEDMAOps IDEDMAOps;
|
|||||||
#define ASC_INCOMPATIBLE_FORMAT 0x30
|
#define ASC_INCOMPATIBLE_FORMAT 0x30
|
||||||
#define ASC_MEDIUM_NOT_PRESENT 0x3a
|
#define ASC_MEDIUM_NOT_PRESENT 0x3a
|
||||||
#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
|
#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
|
||||||
|
#define ASC_DATA_PHASE_ERROR 0x4b
|
||||||
#define ASC_MEDIA_REMOVAL_PREVENTED 0x53
|
#define ASC_MEDIA_REMOVAL_PREVENTED 0x53
|
||||||
|
|
||||||
#define CFA_NO_ERROR 0x00
|
#define CFA_NO_ERROR 0x00
|
||||||
|
@@ -163,6 +163,11 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->conf.logical_block_size != 512) {
|
||||||
|
error_report("logical_block_size must be 512 for IDE");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
blkconf_serial(&dev->conf, &dev->serial);
|
blkconf_serial(&dev->conf, &dev->serial);
|
||||||
if (kind != IDE_CD) {
|
if (kind != IDE_CD) {
|
||||||
blkconf_geometry(&dev->conf, &dev->chs_trans, 65536, 16, 255, &err);
|
blkconf_geometry(&dev->conf, &dev->chs_trans, 65536, 16, 255, &err);
|
||||||
|
@@ -514,6 +514,27 @@ static int hid_post_load(void *opaque, int version_id)
|
|||||||
HIDState *s = opaque;
|
HIDState *s = opaque;
|
||||||
|
|
||||||
hid_set_next_idle(s);
|
hid_set_next_idle(s);
|
||||||
|
|
||||||
|
if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET ||
|
||||||
|
s->kind == HID_MOUSE)) {
|
||||||
|
/*
|
||||||
|
* Handle ptr device migration from old qemu with full queue.
|
||||||
|
*
|
||||||
|
* Throw away everything but the last event, so we propagate
|
||||||
|
* at least the current button state to the guest. Also keep
|
||||||
|
* current position for the tablet, signal "no motion" for the
|
||||||
|
* mouse.
|
||||||
|
*/
|
||||||
|
HIDPointerEvent evt;
|
||||||
|
evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK];
|
||||||
|
if (s->kind == HID_MOUSE) {
|
||||||
|
evt.xdx = 0;
|
||||||
|
evt.ydy = 0;
|
||||||
|
}
|
||||||
|
s->ptr.queue[0] = evt;
|
||||||
|
s->head = 0;
|
||||||
|
s->n = 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -194,10 +194,13 @@ static void softusb_kbd_hid_datain(HIDState *hs)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
|
while (hid_has_events(hs)) {
|
||||||
|
len = hid_keyboard_poll(hs, s->kbd_hid_buffer,
|
||||||
|
sizeof(s->kbd_hid_buffer));
|
||||||
|
|
||||||
if (len == 8) {
|
if (len == 8) {
|
||||||
softusb_kbd_changed(s);
|
softusb_kbd_changed(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,11 +215,13 @@ static void softusb_mouse_hid_datain(HIDState *hs)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = hid_pointer_poll(hs, s->mouse_hid_buffer,
|
while (hid_has_events(hs)) {
|
||||||
sizeof(s->mouse_hid_buffer));
|
len = hid_pointer_poll(hs, s->mouse_hid_buffer,
|
||||||
|
sizeof(s->mouse_hid_buffer));
|
||||||
|
|
||||||
if (len == 4) {
|
if (len == 4) {
|
||||||
softusb_mouse_changed(s);
|
softusb_mouse_changed(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -92,6 +92,21 @@ static bool kvm_arm_gic_can_save_restore(GICState *s)
|
|||||||
return s->dev_fd >= 0;
|
return s->dev_fd >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool kvm_gic_supports_attr(GICState *s, int group, int attrnum)
|
||||||
|
{
|
||||||
|
struct kvm_device_attr attr = {
|
||||||
|
.group = group,
|
||||||
|
.attr = attrnum,
|
||||||
|
.flags = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (s->dev_fd == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kvm_device_ioctl(s->dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void kvm_gic_access(GICState *s, int group, int offset,
|
static void kvm_gic_access(GICState *s, int group, int offset,
|
||||||
int cpu, uint32_t *val, bool write)
|
int cpu, uint32_t *val, bool write)
|
||||||
{
|
{
|
||||||
@@ -553,6 +568,11 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) {
|
||||||
|
uint32_t numirqs = s->num_irq;
|
||||||
|
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, 0, &numirqs, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Distributor */
|
/* Distributor */
|
||||||
memory_region_init_reservation(&s->iomem, OBJECT(s),
|
memory_region_init_reservation(&s->iomem, OBJECT(s),
|
||||||
"kvm-gic_dist", 0x1000);
|
"kvm-gic_dist", 0x1000);
|
||||||
|
@@ -248,7 +248,6 @@ static void kvm_openpic_realize(DeviceState *dev, Error **errp)
|
|||||||
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
|
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
kvm_irqfds_allowed = true;
|
|
||||||
kvm_msi_via_irqfd_allowed = true;
|
kvm_msi_via_irqfd_allowed = true;
|
||||||
kvm_gsi_routing_allowed = true;
|
kvm_gsi_routing_allowed = true;
|
||||||
|
|
||||||
|
@@ -448,7 +448,6 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
kvm_kernel_irqchip = true;
|
kvm_kernel_irqchip = true;
|
||||||
kvm_irqfds_allowed = true;
|
|
||||||
kvm_msi_via_irqfd_allowed = true;
|
kvm_msi_via_irqfd_allowed = true;
|
||||||
kvm_gsi_direct_mapping = true;
|
kvm_gsi_direct_mapping = true;
|
||||||
|
|
||||||
|
@@ -50,13 +50,13 @@ typedef struct VT82C686BState {
|
|||||||
static void superio_ioport_writeb(void *opaque, hwaddr addr, uint64_t data,
|
static void superio_ioport_writeb(void *opaque, hwaddr addr, uint64_t data,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
int can_write;
|
|
||||||
SuperIOConfig *superio_conf = opaque;
|
SuperIOConfig *superio_conf = opaque;
|
||||||
|
|
||||||
DPRINTF("superio_ioport_writeb address 0x%x val 0x%x\n", addr, data);
|
DPRINTF("superio_ioport_writeb address 0x%x val 0x%x\n", addr, data);
|
||||||
if (addr == 0x3f0) {
|
if (addr == 0x3f0) {
|
||||||
superio_conf->index = data & 0xff;
|
superio_conf->index = data & 0xff;
|
||||||
} else {
|
} else {
|
||||||
|
bool can_write = true;
|
||||||
/* 0x3f1 */
|
/* 0x3f1 */
|
||||||
switch (superio_conf->index) {
|
switch (superio_conf->index) {
|
||||||
case 0x00 ... 0xdf:
|
case 0x00 ... 0xdf:
|
||||||
@@ -68,30 +68,27 @@ static void superio_ioport_writeb(void *opaque, hwaddr addr, uint64_t data,
|
|||||||
case 0xf7:
|
case 0xf7:
|
||||||
case 0xf9 ... 0xfb:
|
case 0xf9 ... 0xfb:
|
||||||
case 0xfd ... 0xff:
|
case 0xfd ... 0xff:
|
||||||
can_write = 0;
|
can_write = false;
|
||||||
|
break;
|
||||||
|
case 0xe7:
|
||||||
|
if ((data & 0xff) != 0xfe) {
|
||||||
|
DPRINTF("change uart 1 base. unsupported yet\n");
|
||||||
|
can_write = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xe8:
|
||||||
|
if ((data & 0xff) != 0xbe) {
|
||||||
|
DPRINTF("change uart 2 base. unsupported yet\n");
|
||||||
|
can_write = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
can_write = 1;
|
break;
|
||||||
|
|
||||||
if (can_write) {
|
|
||||||
switch (superio_conf->index) {
|
|
||||||
case 0xe7:
|
|
||||||
if ((data & 0xff) != 0xfe) {
|
|
||||||
DPRINTF("chage uart 1 base. unsupported yet\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0xe8:
|
|
||||||
if ((data & 0xff) != 0xbe) {
|
|
||||||
DPRINTF("chage uart 2 base. unsupported yet\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
superio_conf->config[superio_conf->index] = data & 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
superio_conf->config[superio_conf->index] = data & 0xff;
|
if (can_write) {
|
||||||
|
superio_conf->config[superio_conf->index] = data & 0xff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user