Compare commits
487 Commits
pull-input
...
pull-smbio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c97294ec1b | ||
|
|
2e6e8d7a25 | ||
|
|
cb36acb672 | ||
|
|
e41fca3da7 | ||
|
|
e6667f719c | ||
|
|
7bf8ef196e | ||
|
|
3458b2b075 | ||
|
|
fdaad4715a | ||
|
|
e50bf23438 | ||
|
|
c090c10dc4 | ||
|
|
87f6ede9bb | ||
|
|
f42c5c8ec8 | ||
|
|
3078e848fa | ||
|
|
6420474384 | ||
|
|
37f0806ed9 | ||
|
|
6ab9f49934 | ||
|
|
1b505f93bc | ||
|
|
fed3ffb9f1 | ||
|
|
252ec40576 | ||
|
|
e3da9921eb | ||
|
|
3b77157964 | ||
|
|
051b9980b9 | ||
|
|
52b08670e2 | ||
|
|
61e5b75c17 | ||
|
|
b7079df410 | ||
|
|
1f2cead324 | ||
|
|
838ef60249 | ||
|
|
b69cdef876 | ||
|
|
e466183718 | ||
|
|
38bbc0a580 | ||
|
|
9e550b3260 | ||
|
|
f6246509be | ||
|
|
0549ea8b6d | ||
|
|
e1b42f456f | ||
|
|
b93f995081 | ||
|
|
a49139af77 | ||
|
|
521b2b5df0 | ||
|
|
91f827dcff | ||
|
|
48add816cf | ||
|
|
e080f0fdff | ||
|
|
40f1ee27aa | ||
|
|
35d0d40a03 | ||
|
|
f1f25a2e2e | ||
|
|
7e3d98dd31 | ||
|
|
8bfea15dda | ||
|
|
5669b44de5 | ||
|
|
317fc44ef2 | ||
|
|
0b50cc8853 | ||
|
|
cffb12051a | ||
|
|
c883db0df9 | ||
|
|
cc8a7e560c | ||
|
|
c557527455 | ||
|
|
b006f8162e | ||
|
|
c3cc95bd15 | ||
|
|
373df5b135 | ||
|
|
e855e4fb7b | ||
|
|
3f2fde2a00 | ||
|
|
8b15d9f1d2 | ||
|
|
341a034742 | ||
|
|
d437074140 | ||
|
|
db1da1f2b5 | ||
|
|
3d914488ae | ||
|
|
105923e08c | ||
|
|
9068f20dfb | ||
|
|
a3f4d63d63 | ||
|
|
f92d61f336 | ||
|
|
4843877e5d | ||
|
|
5f6979cba9 | ||
|
|
ebd0c614d7 | ||
|
|
035b239826 | ||
|
|
35e2da1556 | ||
|
|
b357f902bf | ||
|
|
98b90bab3f | ||
|
|
425532d71d | ||
|
|
f4c166619e | ||
|
|
8b66eefe0d | ||
|
|
34b1a49cb1 | ||
|
|
a24fba935a | ||
|
|
9f44adc573 | ||
|
|
4bb7a41ed6 | ||
|
|
71b926992e | ||
|
|
f0e9736012 | ||
|
|
7db1689c35 | ||
|
|
e2da502c00 | ||
|
|
93156cef1c | ||
|
|
13de54eedd | ||
|
|
a41b2c995b | ||
|
|
d09a18d44d | ||
|
|
4a39cbb034 | ||
|
|
a889bc2bb2 | ||
|
|
0850fd583f | ||
|
|
63e3e24db2 | ||
|
|
e2bbfc8ee2 | ||
|
|
b87b8a8b32 | ||
|
|
7a30842186 | ||
|
|
b920cad669 | ||
|
|
00a9cacaea | ||
|
|
b0f9300ca3 | ||
|
|
9057698d93 | ||
|
|
d461863d3c | ||
|
|
7fb8b5d9c4 | ||
|
|
24c12b7923 | ||
|
|
6924bc1eef | ||
|
|
a629f2fdba | ||
|
|
5d77c8f9b6 | ||
|
|
a27b04577e | ||
|
|
296b14491a | ||
|
|
2d2ad6d090 | ||
|
|
6e1d3c1c85 | ||
|
|
e96e5ae880 | ||
|
|
eb6282f230 | ||
|
|
e3f9bb011a | ||
|
|
8439761852 | ||
|
|
172fc4dd33 | ||
|
|
f70edf9948 | ||
|
|
92de901290 | ||
|
|
4399c438a4 | ||
|
|
0fb6395c0c | ||
|
|
a28315ebaf | ||
|
|
460787605e | ||
|
|
9974ad40bf | ||
|
|
d1db760d7b | ||
|
|
1ba4b6a553 | ||
|
|
0b9f0e2fd7 | ||
|
|
1b7a0f758b | ||
|
|
c20499d985 | ||
|
|
c3481247e5 | ||
|
|
9083da1d4c | ||
|
|
638fb14169 | ||
|
|
2da1b3abbc | ||
|
|
bfa40f77af | ||
|
|
f7bdc41acc | ||
|
|
073a341151 | ||
|
|
0b15abfcbc | ||
|
|
f231b88db1 | ||
|
|
d73f0beadb | ||
|
|
4ad417baa4 | ||
|
|
4a66d3bf9a | ||
|
|
d876f60d14 | ||
|
|
027a79c373 | ||
|
|
02d1608980 | ||
|
|
411f491e0a | ||
|
|
f663faac3e | ||
|
|
b925965294 | ||
|
|
16cf0b2b34 | ||
|
|
13a12f869b | ||
|
|
7931b05987 | ||
|
|
44b0c0bbb5 | ||
|
|
860643bc5a | ||
|
|
9ffd26859d | ||
|
|
8c0124490b | ||
|
|
0e96643c98 | ||
|
|
ad600a4d49 | ||
|
|
ba3627ec38 | ||
|
|
4b8abfb78e | ||
|
|
370e681629 | ||
|
|
840a178c94 | ||
|
|
9b17031ac4 | ||
|
|
ac1307abfe | ||
|
|
409951f552 | ||
|
|
90d9d30152 | ||
|
|
f2d953ec31 | ||
|
|
9ffe333276 | ||
|
|
98522f63f4 | ||
|
|
5ff679b47d | ||
|
|
636ea3708c | ||
|
|
acd7fdc6d8 | ||
|
|
b8afb520e4 | ||
|
|
4ab9dab5b9 | ||
|
|
9ce10c0bdc | ||
|
|
da15ee5134 | ||
|
|
1dd3a44753 | ||
|
|
54db38a479 | ||
|
|
02eb19d0ec | ||
|
|
662deb908f | ||
|
|
f46fc4e6a9 | ||
|
|
df9ebea53e | ||
|
|
671c835b7d | ||
|
|
4b304cfae1 | ||
|
|
1194dcba22 | ||
|
|
170bf9315b | ||
|
|
f6c6afc1d4 | ||
|
|
d998e555d2 | ||
|
|
1976cccec8 | ||
|
|
50c5c4d125 | ||
|
|
20022fa15f | ||
|
|
ad5171dbd4 | ||
|
|
b36dc67b95 | ||
|
|
9d85d55732 | ||
|
|
2300aed15d | ||
|
|
e40cdb0e6e | ||
|
|
968fc24d84 | ||
|
|
423d00c857 | ||
|
|
ee25595f01 | ||
|
|
86e117724a | ||
|
|
d61ce900b9 | ||
|
|
1634df567d | ||
|
|
b321afbefd | ||
|
|
0374f5089a | ||
|
|
3bf16cb31a | ||
|
|
4bdd547aaa | ||
|
|
af9fe31070 | ||
|
|
1f91f39219 | ||
|
|
b672cf66c3 | ||
|
|
4c186ee2cf | ||
|
|
dcf91778ca | ||
|
|
2d03b49c3f | ||
|
|
e44a90c596 | ||
|
|
33bbd75a7c | ||
|
|
5538937368 | ||
|
|
6954a1cd97 | ||
|
|
15e3611e1c | ||
|
|
db302f8f93 | ||
|
|
6619bc5c55 | ||
|
|
103db49a10 | ||
|
|
286226a479 | ||
|
|
a63f9f85e3 | ||
|
|
323a8771cf | ||
|
|
2237094d96 | ||
|
|
1c70aa6264 | ||
|
|
f727d0e621 | ||
|
|
b5cde1da0a | ||
|
|
177311157c | ||
|
|
7633378d5f | ||
|
|
c29f9a0a29 | ||
|
|
f318cec6ad | ||
|
|
377a44ec8f | ||
|
|
3933443e38 | ||
|
|
19525524a7 | ||
|
|
f32cdad55d | ||
|
|
9449fdf61f | ||
|
|
00a29f3ddc | ||
|
|
85acfa9c38 | ||
|
|
1090b9c6cc | ||
|
|
2eef0bf821 | ||
|
|
014406b510 | ||
|
|
0ff644a786 | ||
|
|
cb1fa941c1 | ||
|
|
a50c0f5133 | ||
|
|
52e60cdd34 | ||
|
|
2f2a00aec9 | ||
|
|
a65f1de982 | ||
|
|
f502cfc207 | ||
|
|
a0618a1990 | ||
|
|
6cd8a2649a | ||
|
|
7e09797c29 | ||
|
|
aca3f40b37 | ||
|
|
9225d739e7 | ||
|
|
2c8dd31863 | ||
|
|
2c7ffc414d | ||
|
|
90e496386f | ||
|
|
8c6afa6ab1 | ||
|
|
00892383c9 | ||
|
|
d4a2dc675b | ||
|
|
8bcbf37caa | ||
|
|
abf1172fc6 | ||
|
|
c2b820fe58 | ||
|
|
ccd380876b | ||
|
|
c6138aabfb | ||
|
|
5149e557d7 | ||
|
|
06ef8604e9 | ||
|
|
39acc64741 | ||
|
|
e566be049a | ||
|
|
8f811b9a4a | ||
|
|
a9e05a1ceb | ||
|
|
0e154fe92c | ||
|
|
ef3765cb95 | ||
|
|
e8d8fef48f | ||
|
|
6580935246 | ||
|
|
76bff4f82f | ||
|
|
e20b8c04a3 | ||
|
|
8b0190bbde | ||
|
|
f477ed3c11 | ||
|
|
cd2754addc | ||
|
|
3d045dbca5 | ||
|
|
baee04abba | ||
|
|
b144be9e06 | ||
|
|
5e5863ecf1 | ||
|
|
9a734d64f9 | ||
|
|
9a8fa1bdad | ||
|
|
83ebb7cd01 | ||
|
|
42774a56ec | ||
|
|
958683482c | ||
|
|
cd2d46fd21 | ||
|
|
595b8fdd54 | ||
|
|
a4af30447b | ||
|
|
46010969f3 | ||
|
|
c67b67e511 | ||
|
|
1eaa1da7e4 | ||
|
|
8f56ced8aa | ||
|
|
89fe090bb3 | ||
|
|
6b88b37c0e | ||
|
|
075b8ddb9b | ||
|
|
de4d3555fa | ||
|
|
3bd67b7dab | ||
|
|
db4a16458c | ||
|
|
194cfb43d5 | ||
|
|
64f45e4991 | ||
|
|
5238c88657 | ||
|
|
67debe3ae5 | ||
|
|
a9e8aeb375 | ||
|
|
b825025f08 | ||
|
|
a056c9faa4 | ||
|
|
3d4299f425 | ||
|
|
dc73dfd4bc | ||
|
|
edd8824cd4 | ||
|
|
e81864a109 | ||
|
|
de61d14fa7 | ||
|
|
667b1cdd4e | ||
|
|
9e4177ad6d | ||
|
|
dc0c8aaf2c | ||
|
|
ae7ab46aa8 | ||
|
|
6f4724672c | ||
|
|
38d195aa05 | ||
|
|
95f72aa90a | ||
|
|
d82b78e48b | ||
|
|
3d9e69a238 | ||
|
|
cae1f6f3e6 | ||
|
|
81d8a5ee19 | ||
|
|
c6e310d938 | ||
|
|
d8918df577 | ||
|
|
4ec4f0bd56 | ||
|
|
dfeb5fe770 | ||
|
|
929f8b5550 | ||
|
|
8bf56493f1 | ||
|
|
661f7fa4b0 | ||
|
|
851627352c | ||
|
|
50212d6346 | ||
|
|
c2b9af1d6c | ||
|
|
940973ae0b | ||
|
|
8611224a7b | ||
|
|
482f38b948 | ||
|
|
590e5dd98f | ||
|
|
f12d048a52 | ||
|
|
3c99afc779 | ||
|
|
9878d173f5 | ||
|
|
8c6c047899 | ||
|
|
92b3eeadd9 | ||
|
|
edc2438512 | ||
|
|
21e2db7260 | ||
|
|
80fc7b1755 | ||
|
|
5450466394 | ||
|
|
cd82b6fb4d | ||
|
|
715c3f60ef | ||
|
|
28ec11bc88 | ||
|
|
2d968ffbae | ||
|
|
afbc0dd649 | ||
|
|
f516a5cc05 | ||
|
|
0a9077ea14 | ||
|
|
775478418a | ||
|
|
50329d3418 | ||
|
|
efcc87d9ae | ||
|
|
7dc176bce4 | ||
|
|
9bc1a1d817 | ||
|
|
f2ccc311df | ||
|
|
093de72b9c | ||
|
|
800b0e814b | ||
|
|
9a4fb6aa19 | ||
|
|
e792933ce1 | ||
|
|
06f6e12491 | ||
|
|
6a2b3d89fa | ||
|
|
05edc26c61 | ||
|
|
e81a982aa5 | ||
|
|
6cd7db3d92 | ||
|
|
d1dec5ef55 | ||
|
|
6bbad7a91e | ||
|
|
50fc89e7b1 | ||
|
|
bcb7652e8d | ||
|
|
d359db00e6 | ||
|
|
80189035de | ||
|
|
0453099b7d | ||
|
|
a13d448968 | ||
|
|
3636226ae4 | ||
|
|
6a450df9b8 | ||
|
|
9854202b57 | ||
|
|
577a67234d | ||
|
|
55519a4b24 | ||
|
|
f85e3457ce | ||
|
|
9c269f6d7b | ||
|
|
dffacd4654 | ||
|
|
20c50a955f | ||
|
|
bd7ce902ab | ||
|
|
e20c016e32 | ||
|
|
dc491cfc14 | ||
|
|
25eccc37ff | ||
|
|
ecce1929bc | ||
|
|
e61031cdd8 | ||
|
|
0d0e044dee | ||
|
|
466e6e9d13 | ||
|
|
8ae60ee85c | ||
|
|
54bee5c2b4 | ||
|
|
8c2664d869 | ||
|
|
4d1cb6e6f5 | ||
|
|
f187743acd | ||
|
|
b998875dcf | ||
|
|
bae2c27090 | ||
|
|
cd7ccc8351 | ||
|
|
d097696eba | ||
|
|
3b418d0c45 | ||
|
|
cd40890816 | ||
|
|
e3fa4bfa72 | ||
|
|
8885eadedd | ||
|
|
4c2e5f8f46 | ||
|
|
cbee81f6de | ||
|
|
5913815a17 | ||
|
|
888157fe96 | ||
|
|
de03c3164a | ||
|
|
87d8354de3 | ||
|
|
784a5592c9 | ||
|
|
97891afab8 | ||
|
|
c97ca29db0 | ||
|
|
b2f9c08a4f | ||
|
|
27898a5daa | ||
|
|
d581eb7ca4 | ||
|
|
82c6f51373 | ||
|
|
9bcec938aa | ||
|
|
53e11bd384 | ||
|
|
507979a8bd | ||
|
|
c792707f54 | ||
|
|
9302e863aa | ||
|
|
afbcc40bee | ||
|
|
5dae6e30c5 | ||
|
|
6a83f8b5be | ||
|
|
c05e4667be | ||
|
|
11b128f406 | ||
|
|
6b7d4c5558 | ||
|
|
8f4754ede5 | ||
|
|
1e7226f70c | ||
|
|
f0dce23475 | ||
|
|
686d7148ec | ||
|
|
c165f77580 | ||
|
|
eb71803b04 | ||
|
|
b404bf8542 | ||
|
|
73ed27ec28 | ||
|
|
2c1885adcf | ||
|
|
cab60de930 | ||
|
|
0abe740f1d | ||
|
|
bb572aefbd | ||
|
|
2b5d5953ee | ||
|
|
db8a31d11d | ||
|
|
b106ad9185 | ||
|
|
6d33e8e7dc | ||
|
|
2d51c32c4b | ||
|
|
ce48f2f441 | ||
|
|
8c7de28305 | ||
|
|
5dab2faddc | ||
|
|
a1b3955c94 | ||
|
|
24342f2cae | ||
|
|
6d4b9e55fc | ||
|
|
1d7678dec4 | ||
|
|
63fa06dc97 | ||
|
|
5e71dfad76 | ||
|
|
97f1c45c6f | ||
|
|
a9ba36a45d | ||
|
|
8e53abbc20 | ||
|
|
e3737b820b | ||
|
|
246f65838d | ||
|
|
3dd8a6763b | ||
|
|
24f3078a04 | ||
|
|
42d43d35d9 | ||
|
|
f56b9bc3ae | ||
|
|
7b103b36d6 | ||
|
|
509a41bab5 | ||
|
|
d65f97a82c | ||
|
|
05560fcebb | ||
|
|
47f73da0a7 | ||
|
|
c5a33ee9ee | ||
|
|
4c7096607d | ||
|
|
bdf866fe6c | ||
|
|
d25295d4ef | ||
|
|
95224e87a7 | ||
|
|
7373fc7693 | ||
|
|
a4ec5bb718 | ||
|
|
cebac61498 | ||
|
|
efdf6a56a7 | ||
|
|
e683eb9ecc | ||
|
|
627b1a17ce | ||
|
|
66e0c7b187 | ||
|
|
abc53733f3 | ||
|
|
2d888c099c | ||
|
|
fc9677915c | ||
|
|
592408b8ca | ||
|
|
5c4e24c151 | ||
|
|
d597a32a6d | ||
|
|
0875709429 | ||
|
|
d766825190 | ||
|
|
96b8ca47f8 |
18
.gitignore
vendored
18
.gitignore
vendored
@@ -18,8 +18,8 @@
|
|||||||
/*-darwin-user
|
/*-darwin-user
|
||||||
/*-linux-user
|
/*-linux-user
|
||||||
/*-bsd-user
|
/*-bsd-user
|
||||||
libdis*
|
/libdis*
|
||||||
libuser
|
/libuser
|
||||||
/linux-headers/asm
|
/linux-headers/asm
|
||||||
/qga/qapi-generated
|
/qga/qapi-generated
|
||||||
/qapi-generated
|
/qapi-generated
|
||||||
@@ -49,19 +49,9 @@ libuser
|
|||||||
/qemu-monitor.texi
|
/qemu-monitor.texi
|
||||||
/qmp-commands.txt
|
/qmp-commands.txt
|
||||||
/vscclient
|
/vscclient
|
||||||
/test-bitops
|
|
||||||
/test-coroutine
|
|
||||||
/test-int128
|
|
||||||
/test-opts-visitor
|
|
||||||
/test-qmp-input-visitor
|
|
||||||
/test-qmp-output-visitor
|
|
||||||
/test-string-input-visitor
|
|
||||||
/test-string-output-visitor
|
|
||||||
/test-visitor-serialization
|
|
||||||
/fsdev/virtfs-proxy-helper
|
/fsdev/virtfs-proxy-helper
|
||||||
/fsdev/virtfs-proxy-helper.1
|
/fsdev/virtfs-proxy-helper.1
|
||||||
/fsdev/virtfs-proxy-helper.pod
|
/fsdev/virtfs-proxy-helper.pod
|
||||||
/.gdbinit
|
|
||||||
*.a
|
*.a
|
||||||
*.aux
|
*.aux
|
||||||
*.cp
|
*.cp
|
||||||
@@ -90,12 +80,8 @@ libuser
|
|||||||
*.pc
|
*.pc
|
||||||
.libs
|
.libs
|
||||||
.sdk
|
.sdk
|
||||||
*.swp
|
|
||||||
*.orig
|
|
||||||
.pc
|
|
||||||
*.gcda
|
*.gcda
|
||||||
*.gcno
|
*.gcno
|
||||||
patches
|
|
||||||
/pc-bios/bios-pq/status
|
/pc-bios/bios-pq/status
|
||||||
/pc-bios/vgabios-pq/status
|
/pc-bios/vgabios-pq/status
|
||||||
/pc-bios/optionrom/linuxboot.asm
|
/pc-bios/optionrom/linuxboot.asm
|
||||||
|
|||||||
17
MAINTAINERS
17
MAINTAINERS
@@ -304,7 +304,7 @@ S: Maintained
|
|||||||
F: hw/*/versatile*
|
F: hw/*/versatile*
|
||||||
|
|
||||||
Xilinx Zynq
|
Xilinx Zynq
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/arm/xilinx_zynq.c
|
F: hw/arm/xilinx_zynq.c
|
||||||
F: hw/misc/zynq_slcr.c
|
F: hw/misc/zynq_slcr.c
|
||||||
@@ -353,7 +353,7 @@ S: Maintained
|
|||||||
F: hw/microblaze/petalogix_s3adsp1800_mmu.c
|
F: hw/microblaze/petalogix_s3adsp1800_mmu.c
|
||||||
|
|
||||||
petalogix_ml605
|
petalogix_ml605
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/microblaze/petalogix_ml605_mmu.c
|
F: hw/microblaze/petalogix_ml605_mmu.c
|
||||||
|
|
||||||
@@ -592,7 +592,7 @@ S: Orphan
|
|||||||
F: hw/scsi/lsi53c895a.c
|
F: hw/scsi/lsi53c895a.c
|
||||||
|
|
||||||
SSI
|
SSI
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/ssi/*
|
F: hw/ssi/*
|
||||||
F: hw/block/m25p80.c
|
F: hw/block/m25p80.c
|
||||||
@@ -623,6 +623,7 @@ M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: hw/9pfs/
|
F: hw/9pfs/
|
||||||
F: fsdev/
|
F: fsdev/
|
||||||
|
F: tests/virtio-9p-test.c
|
||||||
T: git git://github.com/kvaneesh/QEMU.git
|
T: git git://github.com/kvaneesh/QEMU.git
|
||||||
|
|
||||||
virtio-blk
|
virtio-blk
|
||||||
@@ -648,9 +649,10 @@ nvme
|
|||||||
M: Keith Busch <keith.busch@intel.com>
|
M: Keith Busch <keith.busch@intel.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: hw/block/nvme*
|
F: hw/block/nvme*
|
||||||
|
F: tests/nvme-test.c
|
||||||
|
|
||||||
Xilinx EDK
|
Xilinx EDK
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/*/xilinx_*
|
F: hw/*/xilinx_*
|
||||||
@@ -672,6 +674,8 @@ S: Supported
|
|||||||
F: block*
|
F: block*
|
||||||
F: block/
|
F: block/
|
||||||
F: hw/block/
|
F: hw/block/
|
||||||
|
F: qemu-img*
|
||||||
|
F: qemu-io*
|
||||||
T: git git://repo.or.cz/qemu/kevin.git block
|
T: git git://repo.or.cz/qemu/kevin.git block
|
||||||
T: git git://github.com/stefanha/qemu.git block
|
T: git git://github.com/stefanha/qemu.git block
|
||||||
|
|
||||||
@@ -694,7 +698,7 @@ F: include/hw/cpu/icc_bus.h
|
|||||||
F: hw/cpu/icc_bus.c
|
F: hw/cpu/icc_bus.c
|
||||||
|
|
||||||
Device Tree
|
Device Tree
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
M: Alexander Graf <agraf@suse.de>
|
M: Alexander Graf <agraf@suse.de>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: device_tree.[ch]
|
F: device_tree.[ch]
|
||||||
@@ -715,7 +719,8 @@ F: hw/display/qxl*
|
|||||||
|
|
||||||
Graphics
|
Graphics
|
||||||
M: Anthony Liguori <aliguori@amazon.com>
|
M: Anthony Liguori <aliguori@amazon.com>
|
||||||
S: Maintained
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
|
S: Odd Fixes
|
||||||
F: ui/
|
F: ui/
|
||||||
|
|
||||||
Cocoa graphics
|
Cocoa graphics
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -133,6 +133,7 @@ dummy := $(call unnest-vars,, \
|
|||||||
stub-obj-y \
|
stub-obj-y \
|
||||||
util-obj-y \
|
util-obj-y \
|
||||||
qga-obj-y \
|
qga-obj-y \
|
||||||
|
qga-vss-dll-obj-y \
|
||||||
block-obj-y \
|
block-obj-y \
|
||||||
block-obj-m \
|
block-obj-m \
|
||||||
common-obj-y \
|
common-obj-y \
|
||||||
@@ -376,7 +377,7 @@ endif
|
|||||||
ifneq ($(CONFIG_MODULES),)
|
ifneq ($(CONFIG_MODULES),)
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
||||||
for s in $(patsubst %.mo,%$(DSOSUF),$(modules-m)); do \
|
for s in $(patsubst %.mo,%$(DSOSUF),$(modules-m)); do \
|
||||||
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$${s//\//-}"; \
|
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \
|
||||||
done
|
done
|
||||||
endif
|
endif
|
||||||
ifneq ($(HELPERS-y),)
|
ifneq ($(HELPERS-y),)
|
||||||
|
|||||||
@@ -310,13 +310,28 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
|
|||||||
|
|
||||||
/* Called with iothread lock taken. */
|
/* Called with iothread lock taken. */
|
||||||
|
|
||||||
static void set_dirty_tracking(void)
|
static int set_dirty_tracking(void)
|
||||||
{
|
{
|
||||||
BlkMigDevState *bmds;
|
BlkMigDevState *bmds;
|
||||||
|
int ret;
|
||||||
|
|
||||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||||
bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE);
|
bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE,
|
||||||
|
NULL);
|
||||||
|
if (!bmds->dirty_bitmap) {
|
||||||
|
ret = -errno;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||||
|
if (bmds->dirty_bitmap) {
|
||||||
|
bdrv_release_dirty_bitmap(bmds->bs, bmds->dirty_bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unset_dirty_tracking(void)
|
static void unset_dirty_tracking(void)
|
||||||
@@ -611,10 +626,17 @@ static int block_save_setup(QEMUFile *f, void *opaque)
|
|||||||
block_mig_state.submitted, block_mig_state.transferred);
|
block_mig_state.submitted, block_mig_state.transferred);
|
||||||
|
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
init_blk_migration(f);
|
|
||||||
|
|
||||||
/* start track dirty blocks */
|
/* start track dirty blocks */
|
||||||
set_dirty_tracking();
|
ret = set_dirty_tracking();
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_blk_migration(f);
|
||||||
|
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
|
|
||||||
ret = flush_blks(f);
|
ret = flush_blks(f);
|
||||||
|
|||||||
351
block.c
351
block.c
@@ -332,10 +332,21 @@ void bdrv_register(BlockDriver *bdrv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* create a new block device (by default it is empty) */
|
/* create a new block device (by default it is empty) */
|
||||||
BlockDriverState *bdrv_new(const char *device_name)
|
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
|
||||||
|
if (bdrv_find(device_name)) {
|
||||||
|
error_setg(errp, "Device with id '%s' already exists",
|
||||||
|
device_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (bdrv_find_node(device_name)) {
|
||||||
|
error_setg(errp, "Device with node-name '%s' already exists",
|
||||||
|
device_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bs = g_malloc0(sizeof(BlockDriverState));
|
bs = g_malloc0(sizeof(BlockDriverState));
|
||||||
QLIST_INIT(&bs->dirty_bitmaps);
|
QLIST_INIT(&bs->dirty_bitmaps);
|
||||||
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
|
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
|
||||||
@@ -763,10 +774,54 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
|
|||||||
bs->copy_on_read--;
|
bs->copy_on_read--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the flags that bs->file should get, based on the given flags for
|
||||||
|
* the parent BDS
|
||||||
|
*/
|
||||||
|
static int bdrv_inherited_flags(int flags)
|
||||||
|
{
|
||||||
|
/* Enable protocol handling, disable format probing for bs->file */
|
||||||
|
flags |= BDRV_O_PROTOCOL;
|
||||||
|
|
||||||
|
/* Our block drivers take care to send flushes and respect unmap policy,
|
||||||
|
* so we can enable both unconditionally on lower layers. */
|
||||||
|
flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
|
||||||
|
|
||||||
|
/* The backing file of a temporary snapshot is read-only */
|
||||||
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
|
flags &= ~BDRV_O_RDWR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear flags that only apply to the top layer */
|
||||||
|
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the flags that bs->backing_hd should get, based on the given flags
|
||||||
|
* for the parent BDS
|
||||||
|
*/
|
||||||
|
static int bdrv_backing_flags(int flags)
|
||||||
|
{
|
||||||
|
/* backing files always opened read-only */
|
||||||
|
flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
|
||||||
|
|
||||||
|
/* snapshot=on is handled on the top layer */
|
||||||
|
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||||
{
|
{
|
||||||
int open_flags = flags | BDRV_O_CACHE_WB;
|
int open_flags = flags | BDRV_O_CACHE_WB;
|
||||||
|
|
||||||
|
/* The backing file of a temporary snapshot is read-only */
|
||||||
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
|
open_flags &= ~BDRV_O_RDWR;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear flags that are internal to the block layer before opening the
|
* Clear flags that are internal to the block layer before opening the
|
||||||
* image.
|
* image.
|
||||||
@@ -776,45 +831,43 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
|||||||
/*
|
/*
|
||||||
* Snapshots should be writable.
|
* Snapshots should be writable.
|
||||||
*/
|
*/
|
||||||
if (bs->is_temporary) {
|
if (flags & BDRV_O_TEMPORARY) {
|
||||||
open_flags |= BDRV_O_RDWR;
|
open_flags |= BDRV_O_RDWR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return open_flags;
|
return open_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bdrv_assign_node_name(BlockDriverState *bs,
|
static void bdrv_assign_node_name(BlockDriverState *bs,
|
||||||
const char *node_name,
|
const char *node_name,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
if (!node_name) {
|
if (!node_name) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* empty string node name is invalid */
|
/* empty string node name is invalid */
|
||||||
if (node_name[0] == '\0') {
|
if (node_name[0] == '\0') {
|
||||||
error_setg(errp, "Empty node name");
|
error_setg(errp, "Empty node name");
|
||||||
return -EINVAL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* takes care of avoiding namespaces collisions */
|
/* takes care of avoiding namespaces collisions */
|
||||||
if (bdrv_find(node_name)) {
|
if (bdrv_find(node_name)) {
|
||||||
error_setg(errp, "node-name=%s is conflicting with a device id",
|
error_setg(errp, "node-name=%s is conflicting with a device id",
|
||||||
node_name);
|
node_name);
|
||||||
return -EINVAL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* takes care of avoiding duplicates node names */
|
/* takes care of avoiding duplicates node names */
|
||||||
if (bdrv_find_node(node_name)) {
|
if (bdrv_find_node(node_name)) {
|
||||||
error_setg(errp, "Duplicate node name");
|
error_setg(errp, "Duplicate node name");
|
||||||
return -EINVAL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy node name into the bs and insert it into the graph list */
|
/* copy node name into the bs and insert it into the graph list */
|
||||||
pstrcpy(bs->node_name, sizeof(bs->node_name), node_name);
|
pstrcpy(bs->node_name, sizeof(bs->node_name), node_name);
|
||||||
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);
|
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -849,9 +902,10 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
|||||||
trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
|
trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
|
||||||
|
|
||||||
node_name = qdict_get_try_str(options, "node-name");
|
node_name = qdict_get_try_str(options, "node-name");
|
||||||
ret = bdrv_assign_node_name(bs, node_name, errp);
|
bdrv_assign_node_name(bs, node_name, &local_err);
|
||||||
if (ret < 0) {
|
if (local_err) {
|
||||||
return ret;
|
error_propagate(errp, local_err);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
qdict_del(options, "node-name");
|
qdict_del(options, "node-name");
|
||||||
|
|
||||||
@@ -936,13 +990,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
|||||||
bdrv_refresh_limits(bs);
|
bdrv_refresh_limits(bs);
|
||||||
assert(bdrv_opt_mem_align(bs) != 0);
|
assert(bdrv_opt_mem_align(bs) != 0);
|
||||||
assert((bs->request_alignment != 0) || bs->sg);
|
assert((bs->request_alignment != 0) || bs->sg);
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
if (bs->is_temporary) {
|
|
||||||
assert(bs->filename[0] != '\0');
|
|
||||||
unlink(bs->filename);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_and_fail:
|
free_and_fail:
|
||||||
@@ -968,7 +1015,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
{
|
{
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
const char *drvname;
|
const char *drvname;
|
||||||
bool allow_protocol_prefix = false;
|
bool parse_filename = false;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -977,7 +1024,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
filename = qdict_get_try_str(*options, "filename");
|
filename = qdict_get_try_str(*options, "filename");
|
||||||
} else if (filename && !qdict_haskey(*options, "filename")) {
|
} else if (filename && !qdict_haskey(*options, "filename")) {
|
||||||
qdict_put(*options, "filename", qstring_from_str(filename));
|
qdict_put(*options, "filename", qstring_from_str(filename));
|
||||||
allow_protocol_prefix = true;
|
parse_filename = true;
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "Can't specify 'file' and 'filename' options at the "
|
error_setg(errp, "Can't specify 'file' and 'filename' options at the "
|
||||||
"same time");
|
"same time");
|
||||||
@@ -994,7 +1041,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
}
|
}
|
||||||
qdict_del(*options, "driver");
|
qdict_del(*options, "driver");
|
||||||
} else if (filename) {
|
} else if (filename) {
|
||||||
drv = bdrv_find_protocol(filename, allow_protocol_prefix);
|
drv = bdrv_find_protocol(filename, parse_filename);
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_setg(errp, "Unknown protocol");
|
error_setg(errp, "Unknown protocol");
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1057,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the filename and open it */
|
/* Parse the filename and open it */
|
||||||
if (drv->bdrv_parse_filename && filename) {
|
if (drv->bdrv_parse_filename && parse_filename) {
|
||||||
drv->bdrv_parse_filename(filename, *options, &local_err);
|
drv->bdrv_parse_filename(filename, *options, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
@@ -1053,14 +1100,14 @@ fail:
|
|||||||
*/
|
*/
|
||||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||||
{
|
{
|
||||||
char backing_filename[PATH_MAX];
|
char *backing_filename = g_malloc0(PATH_MAX);
|
||||||
int back_flags, ret;
|
int ret = 0;
|
||||||
BlockDriver *back_drv = NULL;
|
BlockDriver *back_drv = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
if (bs->backing_hd != NULL) {
|
if (bs->backing_hd != NULL) {
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
return 0;
|
goto free_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NULL means an empty set of options */
|
/* NULL means an empty set of options */
|
||||||
@@ -1073,31 +1120,26 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
backing_filename[0] = '\0';
|
backing_filename[0] = '\0';
|
||||||
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
|
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
return 0;
|
goto free_exit;
|
||||||
} else {
|
} else {
|
||||||
bdrv_get_full_backing_filename(bs, backing_filename,
|
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX);
|
||||||
sizeof(backing_filename));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->backing_format[0] != '\0') {
|
if (bs->backing_format[0] != '\0') {
|
||||||
back_drv = bdrv_find_format(bs->backing_format);
|
back_drv = bdrv_find_format(bs->backing_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* backing files always opened read-only */
|
|
||||||
back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT |
|
|
||||||
BDRV_O_COPY_ON_READ);
|
|
||||||
|
|
||||||
assert(bs->backing_hd == NULL);
|
assert(bs->backing_hd == NULL);
|
||||||
ret = bdrv_open(&bs->backing_hd,
|
ret = bdrv_open(&bs->backing_hd,
|
||||||
*backing_filename ? backing_filename : NULL, NULL, options,
|
*backing_filename ? backing_filename : NULL, NULL, options,
|
||||||
back_flags, back_drv, &local_err);
|
bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bs->backing_hd = NULL;
|
bs->backing_hd = NULL;
|
||||||
bs->open_flags |= BDRV_O_NO_BACKING;
|
bs->open_flags |= BDRV_O_NO_BACKING;
|
||||||
error_setg(errp, "Could not open backing file: %s",
|
error_setg(errp, "Could not open backing file: %s",
|
||||||
error_get_pretty(local_err));
|
error_get_pretty(local_err));
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
return ret;
|
goto free_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->backing_hd->file) {
|
if (bs->backing_hd->file) {
|
||||||
@@ -1108,7 +1150,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
|||||||
/* Recalculate the BlockLimits with the backing file */
|
/* Recalculate the BlockLimits with the backing file */
|
||||||
bdrv_refresh_limits(bs);
|
bdrv_refresh_limits(bs);
|
||||||
|
|
||||||
return 0;
|
free_exit:
|
||||||
|
g_free(backing_filename);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1162,6 +1206,75 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||||
|
char *tmp_filename = g_malloc0(PATH_MAX + 1);
|
||||||
|
int64_t total_size;
|
||||||
|
BlockDriver *bdrv_qcow2;
|
||||||
|
QEMUOptionParameter *create_options;
|
||||||
|
QDict *snapshot_options;
|
||||||
|
BlockDriverState *bs_snapshot;
|
||||||
|
Error *local_err;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* if snapshot, we create a temporary backing file and open it
|
||||||
|
instead of opening 'filename' directly */
|
||||||
|
|
||||||
|
/* Get the required size from the image */
|
||||||
|
total_size = bdrv_getlength(bs);
|
||||||
|
if (total_size < 0) {
|
||||||
|
error_setg_errno(errp, -total_size, "Could not get image size");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
total_size &= BDRV_SECTOR_MASK;
|
||||||
|
|
||||||
|
/* Create the temporary image */
|
||||||
|
ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_qcow2 = bdrv_find_format("qcow2");
|
||||||
|
create_options = parse_option_parameters("", bdrv_qcow2->create_options,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
|
||||||
|
|
||||||
|
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
|
||||||
|
free_option_parameters(create_options);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
||||||
|
"'%s': %s", tmp_filename,
|
||||||
|
error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare a new options QDict for the temporary file */
|
||||||
|
snapshot_options = qdict_new();
|
||||||
|
qdict_put(snapshot_options, "file.driver",
|
||||||
|
qstring_from_str("file"));
|
||||||
|
qdict_put(snapshot_options, "file.filename",
|
||||||
|
qstring_from_str(tmp_filename));
|
||||||
|
|
||||||
|
bs_snapshot = bdrv_new("", &error_abort);
|
||||||
|
|
||||||
|
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||||
|
(bs->open_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY,
|
||||||
|
bdrv_qcow2, &local_err);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_append(bs_snapshot, bs);
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free(tmp_filename);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||||
*
|
*
|
||||||
@@ -1182,8 +1295,6 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
BlockDriver *drv, Error **errp)
|
BlockDriver *drv, Error **errp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
|
||||||
char tmp_filename[PATH_MAX + 1];
|
|
||||||
BlockDriverState *file = NULL, *bs;
|
BlockDriverState *file = NULL, *bs;
|
||||||
const char *drvname;
|
const char *drvname;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@@ -1218,7 +1329,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
if (*pbs) {
|
if (*pbs) {
|
||||||
bs = *pbs;
|
bs = *pbs;
|
||||||
} else {
|
} else {
|
||||||
bs = bdrv_new("");
|
bs = bdrv_new("", &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NULL means an empty set of options */
|
/* NULL means an empty set of options */
|
||||||
@@ -1243,74 +1354,6 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For snapshot=on, create a temporary qcow2 overlay */
|
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
|
||||||
BlockDriverState *bs1;
|
|
||||||
int64_t total_size;
|
|
||||||
BlockDriver *bdrv_qcow2;
|
|
||||||
QEMUOptionParameter *create_options;
|
|
||||||
QDict *snapshot_options;
|
|
||||||
|
|
||||||
/* if snapshot, we create a temporary backing file and open it
|
|
||||||
instead of opening 'filename' directly */
|
|
||||||
|
|
||||||
/* Get the required size from the image */
|
|
||||||
QINCREF(options);
|
|
||||||
bs1 = NULL;
|
|
||||||
ret = bdrv_open(&bs1, filename, NULL, options, BDRV_O_NO_BACKING,
|
|
||||||
drv, &local_err);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
|
|
||||||
|
|
||||||
bdrv_unref(bs1);
|
|
||||||
|
|
||||||
/* Create the temporary image */
|
|
||||||
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
bdrv_qcow2 = bdrv_find_format("qcow2");
|
|
||||||
create_options = parse_option_parameters("", bdrv_qcow2->create_options,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
|
|
||||||
|
|
||||||
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
|
|
||||||
free_option_parameters(create_options);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
|
||||||
"'%s': %s", tmp_filename,
|
|
||||||
error_get_pretty(local_err));
|
|
||||||
error_free(local_err);
|
|
||||||
local_err = NULL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare a new options QDict for the temporary file, where user
|
|
||||||
* options refer to the backing file */
|
|
||||||
if (filename) {
|
|
||||||
qdict_put(options, "file.filename", qstring_from_str(filename));
|
|
||||||
}
|
|
||||||
if (drv) {
|
|
||||||
qdict_put(options, "driver", qstring_from_str(drv->format_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
snapshot_options = qdict_new();
|
|
||||||
qdict_put(snapshot_options, "backing", options);
|
|
||||||
qdict_flatten(snapshot_options);
|
|
||||||
|
|
||||||
bs->options = snapshot_options;
|
|
||||||
options = qdict_clone_shallow(bs->options);
|
|
||||||
|
|
||||||
filename = tmp_filename;
|
|
||||||
drv = bdrv_qcow2;
|
|
||||||
bs->is_temporary = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open image file without format layer */
|
/* Open image file without format layer */
|
||||||
if (flags & BDRV_O_RDWR) {
|
if (flags & BDRV_O_RDWR) {
|
||||||
flags |= BDRV_O_ALLOW_RDWR;
|
flags |= BDRV_O_ALLOW_RDWR;
|
||||||
@@ -1318,10 +1361,10 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
|
|
||||||
assert(file == NULL);
|
assert(file == NULL);
|
||||||
ret = bdrv_open_image(&file, filename, options, "file",
|
ret = bdrv_open_image(&file, filename, options, "file",
|
||||||
bdrv_open_flags(bs, flags | BDRV_O_UNMAP) |
|
bdrv_inherited_flags(flags),
|
||||||
BDRV_O_PROTOCOL, true, &local_err);
|
true, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the right image format driver */
|
/* Find the right image format driver */
|
||||||
@@ -1332,7 +1375,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_setg(errp, "Invalid driver: '%s'", drvname);
|
error_setg(errp, "Invalid driver: '%s'", drvname);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1342,18 +1385,18 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
} else {
|
} else {
|
||||||
error_setg(errp, "Must specify either driver or file");
|
error_setg(errp, "Must specify either driver or file");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open the image */
|
/* Open the image */
|
||||||
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
|
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file && (bs->file != file)) {
|
if (file && (bs->file != file)) {
|
||||||
@@ -1372,6 +1415,17 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
|
||||||
|
* temporary snapshot afterwards. */
|
||||||
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
|
bdrv_append_temp_snapshot(bs, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
goto close_and_fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* Check if any unknown options were used */
|
/* Check if any unknown options were used */
|
||||||
if (options && (qdict_size(options) != 0)) {
|
if (options && (qdict_size(options) != 0)) {
|
||||||
@@ -1404,14 +1458,10 @@ done:
|
|||||||
*pbs = bs;
|
*pbs = bs;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unlink_and_fail:
|
fail:
|
||||||
if (file != NULL) {
|
if (file != NULL) {
|
||||||
bdrv_unref(file);
|
bdrv_unref(file);
|
||||||
}
|
}
|
||||||
if (bs->is_temporary) {
|
|
||||||
unlink(filename);
|
|
||||||
}
|
|
||||||
fail:
|
|
||||||
QDECREF(bs->options);
|
QDECREF(bs->options);
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
bs->options = NULL;
|
bs->options = NULL;
|
||||||
@@ -1475,8 +1525,11 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
|||||||
QSIMPLEQ_INIT(bs_queue);
|
QSIMPLEQ_INIT(bs_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* bdrv_open() masks this flag out */
|
||||||
|
flags &= ~BDRV_O_PROTOCOL;
|
||||||
|
|
||||||
if (bs->file) {
|
if (bs->file) {
|
||||||
bdrv_reopen_queue(bs_queue, bs->file, flags);
|
bdrv_reopen_queue(bs_queue, bs->file, bdrv_inherited_flags(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
||||||
@@ -1691,11 +1744,6 @@ void bdrv_close(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
bs->drv->bdrv_close(bs);
|
bs->drv->bdrv_close(bs);
|
||||||
g_free(bs->opaque);
|
g_free(bs->opaque);
|
||||||
#ifdef _WIN32
|
|
||||||
if (bs->is_temporary) {
|
|
||||||
unlink(bs->filename);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
bs->drv = NULL;
|
bs->drv = NULL;
|
||||||
bs->copy_on_read = 0;
|
bs->copy_on_read = 0;
|
||||||
@@ -1819,7 +1867,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
|||||||
BlockDriverState *bs_src)
|
BlockDriverState *bs_src)
|
||||||
{
|
{
|
||||||
/* move some fields that need to stay attached to the device */
|
/* move some fields that need to stay attached to the device */
|
||||||
bs_dest->open_flags = bs_src->open_flags;
|
|
||||||
|
|
||||||
/* dev info */
|
/* dev info */
|
||||||
bs_dest->dev_ops = bs_src->dev_ops;
|
bs_dest->dev_ops = bs_src->dev_ops;
|
||||||
@@ -2568,6 +2615,10 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
|||||||
{
|
{
|
||||||
int64_t len;
|
int64_t len;
|
||||||
|
|
||||||
|
if (size > INT_MAX) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
if (!bdrv_is_inserted(bs))
|
if (!bdrv_is_inserted(bs))
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
|
|
||||||
@@ -2588,6 +2639,10 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
|||||||
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors)
|
int nb_sectors)
|
||||||
{
|
{
|
||||||
|
if (nb_sectors < 0 || nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
|
return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
|
||||||
nb_sectors * BDRV_SECTOR_SIZE);
|
nb_sectors * BDRV_SECTOR_SIZE);
|
||||||
}
|
}
|
||||||
@@ -2669,6 +2724,10 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
|
|||||||
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
|
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (nb_sectors < 0 || nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
return bdrv_prwv_co(bs, sector_num << BDRV_SECTOR_BITS,
|
return bdrv_prwv_co(bs, sector_num << BDRV_SECTOR_BITS,
|
||||||
&qiov, is_write, flags);
|
&qiov, is_write, flags);
|
||||||
@@ -2724,10 +2783,16 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
|||||||
*/
|
*/
|
||||||
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
int64_t target_size = bdrv_getlength(bs) / BDRV_SECTOR_SIZE;
|
int64_t target_size;
|
||||||
int64_t ret, nb_sectors, sector_num = 0;
|
int64_t ret, nb_sectors, sector_num = 0;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
target_size = bdrv_getlength(bs);
|
||||||
|
if (target_size < 0) {
|
||||||
|
return target_size;
|
||||||
|
}
|
||||||
|
target_size /= BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
nb_sectors = target_size - sector_num;
|
nb_sectors = target_size - sector_num;
|
||||||
if (nb_sectors <= 0) {
|
if (nb_sectors <= 0) {
|
||||||
@@ -3557,10 +3622,25 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
|
|||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
|
int count = 0;
|
||||||
|
const char **formats = NULL;
|
||||||
|
|
||||||
QLIST_FOREACH(drv, &bdrv_drivers, list) {
|
QLIST_FOREACH(drv, &bdrv_drivers, list) {
|
||||||
it(opaque, drv->format_name);
|
if (drv->format_name) {
|
||||||
|
bool found = false;
|
||||||
|
int i = count;
|
||||||
|
while (formats && i && !found) {
|
||||||
|
found = !strcmp(formats[--i], drv->format_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
formats = g_realloc(formats, (count + 1) * sizeof(char *));
|
||||||
|
formats[count++] = drv->format_name;
|
||||||
|
it(opaque, drv->format_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
g_free(formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is to find block backend bs */
|
/* This function is to find block backend bs */
|
||||||
@@ -5079,7 +5159,8 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity)
|
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
int64_t bitmap_size;
|
int64_t bitmap_size;
|
||||||
BdrvDirtyBitmap *bitmap;
|
BdrvDirtyBitmap *bitmap;
|
||||||
@@ -5088,7 +5169,13 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity)
|
|||||||
|
|
||||||
granularity >>= BDRV_SECTOR_BITS;
|
granularity >>= BDRV_SECTOR_BITS;
|
||||||
assert(granularity);
|
assert(granularity);
|
||||||
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS);
|
bitmap_size = bdrv_getlength(bs);
|
||||||
|
if (bitmap_size < 0) {
|
||||||
|
error_setg_errno(errp, -bitmap_size, "could not get length of device");
|
||||||
|
errno = -bitmap_size;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
bitmap_size >>= BDRV_SECTOR_BITS;
|
||||||
bitmap = g_malloc0(sizeof(BdrvDirtyBitmap));
|
bitmap = g_malloc0(sizeof(BdrvDirtyBitmap));
|
||||||
bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
|
bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
|
||||||
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
|
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
|
||||||
|
|||||||
142
block/bochs.c
142
block/bochs.c
@@ -38,57 +38,42 @@
|
|||||||
|
|
||||||
// not allocated: 0xffffffff
|
// not allocated: 0xffffffff
|
||||||
|
|
||||||
// always little-endian
|
|
||||||
struct bochs_header_v1 {
|
|
||||||
char magic[32]; // "Bochs Virtual HD Image"
|
|
||||||
char type[16]; // "Redolog"
|
|
||||||
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
|
||||||
uint32_t version;
|
|
||||||
uint32_t header; // size of header
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint32_t catalog; // num of entries
|
|
||||||
uint32_t bitmap; // bitmap size
|
|
||||||
uint32_t extent; // extent size
|
|
||||||
uint64_t disk; // disk size
|
|
||||||
char padding[HEADER_SIZE - 64 - 8 - 20];
|
|
||||||
} redolog;
|
|
||||||
char padding[HEADER_SIZE - 64 - 8];
|
|
||||||
} extra;
|
|
||||||
};
|
|
||||||
|
|
||||||
// always little-endian
|
// always little-endian
|
||||||
struct bochs_header {
|
struct bochs_header {
|
||||||
char magic[32]; // "Bochs Virtual HD Image"
|
char magic[32]; /* "Bochs Virtual HD Image" */
|
||||||
char type[16]; // "Redolog"
|
char type[16]; /* "Redolog" */
|
||||||
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
char subtype[16]; /* "Undoable" / "Volatile" / "Growing" */
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t header; // size of header
|
uint32_t header; /* size of header */
|
||||||
|
|
||||||
|
uint32_t catalog; /* num of entries */
|
||||||
|
uint32_t bitmap; /* bitmap size */
|
||||||
|
uint32_t extent; /* extent size */
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t catalog; // num of entries
|
uint32_t reserved; /* for ??? */
|
||||||
uint32_t bitmap; // bitmap size
|
uint64_t disk; /* disk size */
|
||||||
uint32_t extent; // extent size
|
char padding[HEADER_SIZE - 64 - 20 - 12];
|
||||||
uint32_t reserved; // for ???
|
} QEMU_PACKED redolog;
|
||||||
uint64_t disk; // disk size
|
struct {
|
||||||
char padding[HEADER_SIZE - 64 - 8 - 24];
|
uint64_t disk; /* disk size */
|
||||||
} redolog;
|
char padding[HEADER_SIZE - 64 - 20 - 8];
|
||||||
char padding[HEADER_SIZE - 64 - 8];
|
} QEMU_PACKED redolog_v1;
|
||||||
|
char padding[HEADER_SIZE - 64 - 20];
|
||||||
} extra;
|
} extra;
|
||||||
};
|
} QEMU_PACKED;
|
||||||
|
|
||||||
typedef struct BDRVBochsState {
|
typedef struct BDRVBochsState {
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
uint32_t *catalog_bitmap;
|
uint32_t *catalog_bitmap;
|
||||||
int catalog_size;
|
uint32_t catalog_size;
|
||||||
|
|
||||||
int data_offset;
|
uint32_t data_offset;
|
||||||
|
|
||||||
int bitmap_blocks;
|
uint32_t bitmap_blocks;
|
||||||
int extent_blocks;
|
uint32_t extent_blocks;
|
||||||
int extent_size;
|
uint32_t extent_size;
|
||||||
} BDRVBochsState;
|
} BDRVBochsState;
|
||||||
|
|
||||||
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
@@ -112,9 +97,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BDRVBochsState *s = bs->opaque;
|
BDRVBochsState *s = bs->opaque;
|
||||||
int i;
|
uint32_t i;
|
||||||
struct bochs_header bochs;
|
struct bochs_header bochs;
|
||||||
struct bochs_header_v1 header_v1;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
bs->read_only = 1; // no write support yet
|
bs->read_only = 1; // no write support yet
|
||||||
@@ -134,13 +118,19 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (le32_to_cpu(bochs.version) == HEADER_V1) {
|
if (le32_to_cpu(bochs.version) == HEADER_V1) {
|
||||||
memcpy(&header_v1, &bochs, sizeof(bochs));
|
bs->total_sectors = le64_to_cpu(bochs.extra.redolog_v1.disk) / 512;
|
||||||
bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
|
|
||||||
} else {
|
} else {
|
||||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Limit to 1M entries to avoid unbounded allocation. This is what is
|
||||||
|
* needed for the largest image that bximage can create (~8 TB). */
|
||||||
|
s->catalog_size = le32_to_cpu(bochs.catalog);
|
||||||
|
if (s->catalog_size > 0x100000) {
|
||||||
|
error_setg(errp, "Catalog size is too large");
|
||||||
|
return -EFBIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
|
|
||||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
||||||
@@ -154,10 +144,34 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
|
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
|
||||||
|
|
||||||
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
|
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.bitmap) - 1) / 512;
|
||||||
s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
|
s->extent_blocks = 1 + (le32_to_cpu(bochs.extent) - 1) / 512;
|
||||||
|
|
||||||
s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
|
s->extent_size = le32_to_cpu(bochs.extent);
|
||||||
|
if (s->extent_size < BDRV_SECTOR_SIZE) {
|
||||||
|
/* bximage actually never creates extents smaller than 4k */
|
||||||
|
error_setg(errp, "Extent size must be at least 512");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
} else if (!is_power_of_2(s->extent_size)) {
|
||||||
|
error_setg(errp, "Extent size %" PRIu32 " is not a power of two",
|
||||||
|
s->extent_size);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
} else if (s->extent_size > 0x800000) {
|
||||||
|
error_setg(errp, "Extent size %" PRIu32 " is too large",
|
||||||
|
s->extent_size);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->catalog_size < DIV_ROUND_UP(bs->total_sectors,
|
||||||
|
s->extent_size / BDRV_SECTOR_SIZE))
|
||||||
|
{
|
||||||
|
error_setg(errp, "Catalog size is too small for this disk size");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_co_mutex_init(&s->lock);
|
qemu_co_mutex_init(&s->lock);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -170,29 +184,32 @@ fail:
|
|||||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||||
{
|
{
|
||||||
BDRVBochsState *s = bs->opaque;
|
BDRVBochsState *s = bs->opaque;
|
||||||
int64_t offset = sector_num * 512;
|
uint64_t offset = sector_num * 512;
|
||||||
int64_t extent_index, extent_offset, bitmap_offset;
|
uint64_t extent_index, extent_offset, bitmap_offset;
|
||||||
char bitmap_entry;
|
char bitmap_entry;
|
||||||
|
int ret;
|
||||||
|
|
||||||
// seek to sector
|
// seek to sector
|
||||||
extent_index = offset / s->extent_size;
|
extent_index = offset / s->extent_size;
|
||||||
extent_offset = (offset % s->extent_size) / 512;
|
extent_offset = (offset % s->extent_size) / 512;
|
||||||
|
|
||||||
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
||||||
return -1; /* not allocated */
|
return 0; /* not allocated */
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
|
bitmap_offset = s->data_offset +
|
||||||
(s->extent_blocks + s->bitmap_blocks));
|
(512 * (uint64_t) s->catalog_bitmap[extent_index] *
|
||||||
|
(s->extent_blocks + s->bitmap_blocks));
|
||||||
|
|
||||||
/* read in bitmap for current extent */
|
/* read in bitmap for current extent */
|
||||||
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||||
&bitmap_entry, 1) != 1) {
|
&bitmap_entry, 1);
|
||||||
return -1;
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
||||||
return -1; /* not allocated */
|
return 0; /* not allocated */
|
||||||
}
|
}
|
||||||
|
|
||||||
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
||||||
@@ -205,13 +222,16 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
int64_t block_offset = seek_to_sector(bs, sector_num);
|
int64_t block_offset = seek_to_sector(bs, sector_num);
|
||||||
if (block_offset >= 0) {
|
if (block_offset < 0) {
|
||||||
|
return block_offset;
|
||||||
|
} else if (block_offset > 0) {
|
||||||
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
||||||
if (ret != 512) {
|
if (ret < 0) {
|
||||||
return -1;
|
return ret;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
memset(buf, 0, 512);
|
memset(buf, 0, 512);
|
||||||
|
}
|
||||||
nb_sectors--;
|
nb_sectors--;
|
||||||
sector_num++;
|
sector_num++;
|
||||||
buf += 512;
|
buf += 512;
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
/* Maximum compressed block size */
|
||||||
|
#define MAX_BLOCK_SIZE (64 * 1024 * 1024)
|
||||||
|
|
||||||
typedef struct BDRVCloopState {
|
typedef struct BDRVCloopState {
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
@@ -68,6 +71,26 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
s->block_size = be32_to_cpu(s->block_size);
|
s->block_size = be32_to_cpu(s->block_size);
|
||||||
|
if (s->block_size % 512) {
|
||||||
|
error_setg(errp, "block_size %" PRIu32 " must be a multiple of 512",
|
||||||
|
s->block_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (s->block_size == 0) {
|
||||||
|
error_setg(errp, "block_size cannot be zero");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cloop's create_compressed_fs.c warns about block sizes beyond 256 KB but
|
||||||
|
* we can accept more. Prevent ridiculous values like 4 GB - 1 since we
|
||||||
|
* need a buffer this big.
|
||||||
|
*/
|
||||||
|
if (s->block_size > MAX_BLOCK_SIZE) {
|
||||||
|
error_setg(errp, "block_size %" PRIu32 " must be %u MB or less",
|
||||||
|
s->block_size,
|
||||||
|
MAX_BLOCK_SIZE / (1024 * 1024));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -76,7 +99,23 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->n_blocks = be32_to_cpu(s->n_blocks);
|
s->n_blocks = be32_to_cpu(s->n_blocks);
|
||||||
|
|
||||||
/* read offsets */
|
/* read offsets */
|
||||||
offsets_size = s->n_blocks * sizeof(uint64_t);
|
if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
||||||
|
/* Prevent integer overflow */
|
||||||
|
error_setg(errp, "n_blocks %" PRIu32 " must be %zu or less",
|
||||||
|
s->n_blocks,
|
||||||
|
(UINT32_MAX - 1) / sizeof(uint64_t));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
|
||||||
|
if (offsets_size > 512 * 1024 * 1024) {
|
||||||
|
/* Prevent ridiculous offsets_size which causes memory allocation to
|
||||||
|
* fail or overflows bdrv_pread() size. In practice the 512 MB
|
||||||
|
* offsets[] limit supports 16 TB images at 256 KB block size.
|
||||||
|
*/
|
||||||
|
error_setg(errp, "image requires too many offsets, "
|
||||||
|
"try increasing block size");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
s->offsets = g_malloc(offsets_size);
|
s->offsets = g_malloc(offsets_size);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
||||||
@@ -84,13 +123,37 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0;i<s->n_blocks;i++) {
|
for (i = 0; i < s->n_blocks + 1; i++) {
|
||||||
|
uint64_t size;
|
||||||
|
|
||||||
s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
||||||
if (i > 0) {
|
if (i == 0) {
|
||||||
uint32_t size = s->offsets[i] - s->offsets[i - 1];
|
continue;
|
||||||
if (size > max_compressed_block_size) {
|
}
|
||||||
max_compressed_block_size = size;
|
|
||||||
}
|
if (s->offsets[i] < s->offsets[i - 1]) {
|
||||||
|
error_setg(errp, "offsets not monotonically increasing at "
|
||||||
|
"index %" PRIu32 ", image file is corrupt", i);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = s->offsets[i] - s->offsets[i - 1];
|
||||||
|
|
||||||
|
/* Compressed blocks should be smaller than the uncompressed block size
|
||||||
|
* but maybe compression performed poorly so the compressed block is
|
||||||
|
* actually bigger. Clamp down on unrealistic values to prevent
|
||||||
|
* ridiculous s->compressed_block allocation.
|
||||||
|
*/
|
||||||
|
if (size > 2 * MAX_BLOCK_SIZE) {
|
||||||
|
error_setg(errp, "invalid compressed block size at index %" PRIu32
|
||||||
|
", image file is corrupt", i);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > max_compressed_block_size) {
|
||||||
|
max_compressed_block_size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,9 +243,7 @@ static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
static void cloop_close(BlockDriverState *bs)
|
static void cloop_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVCloopState *s = bs->opaque;
|
BDRVCloopState *s = bs->opaque;
|
||||||
if (s->n_blocks > 0) {
|
g_free(s->offsets);
|
||||||
g_free(s->offsets);
|
|
||||||
}
|
|
||||||
g_free(s->compressed_block);
|
g_free(s->compressed_block);
|
||||||
g_free(s->uncompressed_block);
|
g_free(s->uncompressed_block);
|
||||||
inflateEnd(&s->zstream);
|
inflateEnd(&s->zstream);
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
|||||||
if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
|
if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
|
||||||
on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
||||||
!bdrv_iostatus_is_enabled(bs)) {
|
!bdrv_iostatus_is_enabled(bs)) {
|
||||||
error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
|
error_setg(errp, "Invalid parameter combination");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
||||||
char version[64];
|
char version[64];
|
||||||
snprintf(version, sizeof(version),
|
snprintf(version, sizeof(version),
|
||||||
"COW version %d", cow_header.version);
|
"COW version %" PRIu32, cow_header.version);
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
bs->device_name, "cow", version);
|
bs->device_name, "cow", version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
|||||||
154
block/curl.c
154
block/curl.c
@@ -71,6 +71,7 @@ typedef struct CURLState
|
|||||||
struct BDRVCURLState *s;
|
struct BDRVCURLState *s;
|
||||||
CURLAIOCB *acb[CURL_NUM_ACB];
|
CURLAIOCB *acb[CURL_NUM_ACB];
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
|
curl_socket_t sock_fd;
|
||||||
char *orig_buf;
|
char *orig_buf;
|
||||||
size_t buf_start;
|
size_t buf_start;
|
||||||
size_t buf_off;
|
size_t buf_off;
|
||||||
@@ -92,6 +93,7 @@ typedef struct BDRVCURLState {
|
|||||||
|
|
||||||
static void curl_clean_state(CURLState *s);
|
static void curl_clean_state(CURLState *s);
|
||||||
static void curl_multi_do(void *arg);
|
static void curl_multi_do(void *arg);
|
||||||
|
static void curl_multi_read(void *arg);
|
||||||
|
|
||||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||||
@@ -113,16 +115,20 @@ static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
|||||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||||
void *s, void *sp)
|
void *s, void *sp)
|
||||||
{
|
{
|
||||||
|
CURLState *state = NULL;
|
||||||
|
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
|
||||||
|
state->sock_fd = fd;
|
||||||
|
|
||||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case CURL_POLL_IN:
|
case CURL_POLL_IN:
|
||||||
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, s);
|
qemu_aio_set_fd_handler(fd, curl_multi_read, NULL, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_OUT:
|
case CURL_POLL_OUT:
|
||||||
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, s);
|
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_INOUT:
|
case CURL_POLL_INOUT:
|
||||||
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, s);
|
qemu_aio_set_fd_handler(fd, curl_multi_read, curl_multi_do, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_REMOVE:
|
case CURL_POLL_REMOVE:
|
||||||
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
|
||||||
@@ -155,8 +161,13 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|||||||
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
||||||
|
|
||||||
if (!s || !s->orig_buf)
|
if (!s || !s->orig_buf)
|
||||||
goto read_end;
|
return 0;
|
||||||
|
|
||||||
|
if (s->buf_off >= s->buf_len) {
|
||||||
|
/* buffer full, read nothing */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
realsize = MIN(realsize, s->buf_len - s->buf_off);
|
||||||
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
|
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
|
||||||
s->buf_off += realsize;
|
s->buf_off += realsize;
|
||||||
|
|
||||||
@@ -175,7 +186,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read_end:
|
|
||||||
return realsize;
|
return realsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +220,8 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for unfinished chunks
|
// Wait for unfinished chunks
|
||||||
if ((start >= state->buf_start) &&
|
if (state->in_use &&
|
||||||
|
(start >= state->buf_start) &&
|
||||||
(start <= buf_fend) &&
|
(start <= buf_fend) &&
|
||||||
(end >= state->buf_start) &&
|
(end >= state->buf_start) &&
|
||||||
(end <= buf_fend))
|
(end <= buf_fend))
|
||||||
@@ -232,68 +243,69 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|||||||
return FIND_RET_NONE;
|
return FIND_RET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_read(BDRVCURLState *s)
|
static void curl_multi_check_completion(BDRVCURLState *s)
|
||||||
{
|
{
|
||||||
int msgs_in_queue;
|
int msgs_in_queue;
|
||||||
|
|
||||||
/* Try to find done transfers, so we can free the easy
|
/* Try to find done transfers, so we can free the easy
|
||||||
* handle again. */
|
* handle again. */
|
||||||
do {
|
for (;;) {
|
||||||
CURLMsg *msg;
|
CURLMsg *msg;
|
||||||
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
|
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
|
||||||
|
|
||||||
|
/* Quit when there are no more completions */
|
||||||
if (!msg)
|
if (!msg)
|
||||||
break;
|
break;
|
||||||
if (msg->msg == CURLMSG_NONE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (msg->msg) {
|
if (msg->msg == CURLMSG_DONE) {
|
||||||
case CURLMSG_DONE:
|
CURLState *state = NULL;
|
||||||
{
|
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
|
||||||
CURLState *state = NULL;
|
(char **)&state);
|
||||||
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
|
|
||||||
|
|
||||||
/* ACBs for successful messages get completed in curl_read_cb */
|
/* ACBs for successful messages get completed in curl_read_cb */
|
||||||
if (msg->data.result != CURLE_OK) {
|
if (msg->data.result != CURLE_OK) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < CURL_NUM_ACB; i++) {
|
for (i = 0; i < CURL_NUM_ACB; i++) {
|
||||||
CURLAIOCB *acb = state->acb[i];
|
CURLAIOCB *acb = state->acb[i];
|
||||||
|
|
||||||
if (acb == NULL) {
|
if (acb == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
acb->common.cb(acb->common.opaque, -EIO);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
state->acb[i] = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
curl_clean_state(state);
|
acb->common.cb(acb->common.opaque, -EIO);
|
||||||
break;
|
qemu_aio_release(acb);
|
||||||
|
state->acb[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
msgs_in_queue = 0;
|
curl_clean_state(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(msgs_in_queue);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_do(void *arg)
|
static void curl_multi_do(void *arg)
|
||||||
{
|
{
|
||||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
CURLState *s = (CURLState *)arg;
|
||||||
int running;
|
int running;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!s->multi) {
|
if (!s->s->multi) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = curl_multi_socket_all(s->multi, &running);
|
r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
|
||||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||||
|
|
||||||
curl_multi_read(s);
|
}
|
||||||
|
|
||||||
|
static void curl_multi_read(void *arg)
|
||||||
|
{
|
||||||
|
CURLState *s = (CURLState *)arg;
|
||||||
|
|
||||||
|
curl_multi_do(arg);
|
||||||
|
curl_multi_check_completion(s->s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_timeout_do(void *arg)
|
static void curl_multi_timeout_do(void *arg)
|
||||||
@@ -308,7 +320,7 @@ static void curl_multi_timeout_do(void *arg)
|
|||||||
|
|
||||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
|
|
||||||
curl_multi_read(s);
|
curl_multi_check_completion(s);
|
||||||
#else
|
#else
|
||||||
abort();
|
abort();
|
||||||
#endif
|
#endif
|
||||||
@@ -332,44 +344,42 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!state) {
|
if (!state) {
|
||||||
g_usleep(100);
|
qemu_aio_wait();
|
||||||
curl_multi_do(s);
|
|
||||||
}
|
}
|
||||||
} while(!state);
|
} while(!state);
|
||||||
|
|
||||||
if (state->curl)
|
if (!state->curl) {
|
||||||
goto has_curl;
|
state->curl = curl_easy_init();
|
||||||
|
if (!state->curl) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||||
|
(void *)curl_read_cb);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
|
||||||
|
|
||||||
state->curl = curl_easy_init();
|
/* Restrict supported protocols to avoid security issues in the more
|
||||||
if (!state->curl)
|
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
|
||||||
return NULL;
|
* CVE-2013-0249.
|
||||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
*
|
||||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
* Restricting protocols is only supported from 7.19.4 upwards.
|
||||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
|
*/
|
||||||
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
|
|
||||||
|
|
||||||
/* Restrict supported protocols to avoid security issues in the more
|
|
||||||
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
|
|
||||||
* CVE-2013-0249.
|
|
||||||
*
|
|
||||||
* Restricting protocols is only supported from 7.19.4 upwards.
|
|
||||||
*/
|
|
||||||
#if LIBCURL_VERSION_NUM >= 0x071304
|
#if LIBCURL_VERSION_NUM >= 0x071304
|
||||||
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
|
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
|
||||||
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
|
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
has_curl:
|
|
||||||
|
|
||||||
state->s = s;
|
state->s = s;
|
||||||
|
|
||||||
@@ -526,19 +536,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
// initialize the multi interface!
|
// initialize the multi interface!
|
||||||
|
|
||||||
s->multi = curl_multi_init();
|
s->multi = curl_multi_init();
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
||||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
||||||
#endif
|
#endif
|
||||||
curl_multi_do(s);
|
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg);
|
error_setg(errp, "CURL: Error opening file: %s", state->errmsg);
|
||||||
curl_easy_cleanup(state->curl);
|
curl_easy_cleanup(state->curl);
|
||||||
state->curl = NULL;
|
state->curl = NULL;
|
||||||
out_noclean:
|
out_noclean:
|
||||||
@@ -561,6 +569,7 @@ static const AIOCBInfo curl_aiocb_info = {
|
|||||||
static void curl_readv_bh_cb(void *p)
|
static void curl_readv_bh_cb(void *p)
|
||||||
{
|
{
|
||||||
CURLState *state;
|
CURLState *state;
|
||||||
|
int running;
|
||||||
|
|
||||||
CURLAIOCB *acb = p;
|
CURLAIOCB *acb = p;
|
||||||
BDRVCURLState *s = acb->common.bs->opaque;
|
BDRVCURLState *s = acb->common.bs->opaque;
|
||||||
@@ -609,8 +618,9 @@ static void curl_readv_bh_cb(void *p)
|
|||||||
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
||||||
|
|
||||||
curl_multi_add_handle(s->multi, state->curl);
|
curl_multi_add_handle(s->multi, state->curl);
|
||||||
curl_multi_do(s);
|
|
||||||
|
|
||||||
|
/* Tell curl it needs to kick things off */
|
||||||
|
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||||
|
|||||||
269
block/dmg.c
269
block/dmg.c
@@ -27,6 +27,14 @@
|
|||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* Limit chunk sizes to prevent unreasonable amounts of memory being used
|
||||||
|
* or truncating when converting to 32-bit types
|
||||||
|
*/
|
||||||
|
DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */
|
||||||
|
DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct BDRVDMGState {
|
typedef struct BDRVDMGState {
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
/* each chunk contains a certain number of sectors,
|
/* each chunk contains a certain number of sectors,
|
||||||
@@ -92,13 +100,44 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Increase max chunk sizes, if necessary. This function is used to calculate
|
||||||
|
* the buffer sizes needed for compressed/uncompressed chunk I/O.
|
||||||
|
*/
|
||||||
|
static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
|
||||||
|
uint32_t *max_compressed_size,
|
||||||
|
uint32_t *max_sectors_per_chunk)
|
||||||
|
{
|
||||||
|
uint32_t compressed_size = 0;
|
||||||
|
uint32_t uncompressed_sectors = 0;
|
||||||
|
|
||||||
|
switch (s->types[chunk]) {
|
||||||
|
case 0x80000005: /* zlib compressed */
|
||||||
|
compressed_size = s->lengths[chunk];
|
||||||
|
uncompressed_sectors = s->sectorcounts[chunk];
|
||||||
|
break;
|
||||||
|
case 1: /* copy */
|
||||||
|
uncompressed_sectors = (s->lengths[chunk] + 511) / 512;
|
||||||
|
break;
|
||||||
|
case 2: /* zero */
|
||||||
|
uncompressed_sectors = s->sectorcounts[chunk];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compressed_size > *max_compressed_size) {
|
||||||
|
*max_compressed_size = compressed_size;
|
||||||
|
}
|
||||||
|
if (uncompressed_sectors > *max_sectors_per_chunk) {
|
||||||
|
*max_sectors_per_chunk = uncompressed_sectors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BDRVDMGState *s = bs->opaque;
|
BDRVDMGState *s = bs->opaque;
|
||||||
uint64_t info_begin,info_end,last_in_offset,last_out_offset;
|
uint64_t info_begin, info_end, last_in_offset, last_out_offset;
|
||||||
uint32_t count, tmp;
|
uint32_t count, tmp;
|
||||||
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
|
uint32_t max_compressed_size = 1, max_sectors_per_chunk = 1, i;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -160,37 +199,40 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == 0x6d697368 && count >= 244) {
|
if (type == 0x6d697368 && count >= 244) {
|
||||||
int new_size, chunk_count;
|
size_t new_size;
|
||||||
|
uint32_t chunk_count;
|
||||||
|
|
||||||
offset += 4;
|
offset += 4;
|
||||||
offset += 200;
|
offset += 200;
|
||||||
|
|
||||||
chunk_count = (count-204)/40;
|
chunk_count = (count - 204) / 40;
|
||||||
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
||||||
s->types = g_realloc(s->types, new_size/2);
|
s->types = g_realloc(s->types, new_size / 2);
|
||||||
s->offsets = g_realloc(s->offsets, new_size);
|
s->offsets = g_realloc(s->offsets, new_size);
|
||||||
s->lengths = g_realloc(s->lengths, new_size);
|
s->lengths = g_realloc(s->lengths, new_size);
|
||||||
s->sectors = g_realloc(s->sectors, new_size);
|
s->sectors = g_realloc(s->sectors, new_size);
|
||||||
s->sectorcounts = g_realloc(s->sectorcounts, new_size);
|
s->sectorcounts = g_realloc(s->sectorcounts, new_size);
|
||||||
|
|
||||||
for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
|
for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
|
||||||
ret = read_uint32(bs, offset, &s->types[i]);
|
ret = read_uint32(bs, offset, &s->types[i]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
offset += 4;
|
offset += 4;
|
||||||
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
|
if (s->types[i] != 0x80000005 && s->types[i] != 1 &&
|
||||||
if(s->types[i]==0xffffffff) {
|
s->types[i] != 2) {
|
||||||
last_in_offset = s->offsets[i-1]+s->lengths[i-1];
|
if (s->types[i] == 0xffffffff && i > 0) {
|
||||||
last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
|
last_in_offset = s->offsets[i - 1] + s->lengths[i - 1];
|
||||||
}
|
last_out_offset = s->sectors[i - 1] +
|
||||||
chunk_count--;
|
s->sectorcounts[i - 1];
|
||||||
i--;
|
}
|
||||||
offset += 36;
|
chunk_count--;
|
||||||
continue;
|
i--;
|
||||||
}
|
offset += 36;
|
||||||
offset += 4;
|
continue;
|
||||||
|
}
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
ret = read_uint64(bs, offset, &s->sectors[i]);
|
ret = read_uint64(bs, offset, &s->sectors[i]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -205,6 +247,14 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
|
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
||||||
|
error_report("sector count %" PRIu64 " for chunk %" PRIu32
|
||||||
|
" is larger than max (%u)",
|
||||||
|
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
ret = read_uint64(bs, offset, &s->offsets[i]);
|
ret = read_uint64(bs, offset, &s->offsets[i]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -218,19 +268,25 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
if(s->lengths[i]>max_compressed_size)
|
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
||||||
max_compressed_size = s->lengths[i];
|
error_report("length %" PRIu64 " for chunk %" PRIu32
|
||||||
if(s->sectorcounts[i]>max_sectors_per_chunk)
|
" is larger than max (%u)",
|
||||||
max_sectors_per_chunk = s->sectorcounts[i];
|
s->lengths[i], i, DMG_LENGTHS_MAX);
|
||||||
}
|
ret = -EINVAL;
|
||||||
s->n_chunks+=chunk_count;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_max_chunk_size(s, i, &max_compressed_size,
|
||||||
|
&max_sectors_per_chunk);
|
||||||
|
}
|
||||||
|
s->n_chunks += chunk_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize zlib engine */
|
/* initialize zlib engine */
|
||||||
s->compressed_chunk = g_malloc(max_compressed_size+1);
|
s->compressed_chunk = g_malloc(max_compressed_size + 1);
|
||||||
s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
|
s->uncompressed_chunk = g_malloc(512 * max_sectors_per_chunk);
|
||||||
if(inflateInit(&s->zstream) != Z_OK) {
|
if (inflateInit(&s->zstream) != Z_OK) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -252,83 +308,82 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
||||||
uint32_t chunk_num,int sector_num)
|
uint32_t chunk_num, uint64_t sector_num)
|
||||||
{
|
{
|
||||||
if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num ||
|
if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num ||
|
||||||
s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
|
s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) {
|
||||||
return 0;
|
return 0;
|
||||||
else
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
|
static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num)
|
||||||
{
|
{
|
||||||
/* binary search */
|
/* binary search */
|
||||||
uint32_t chunk1=0,chunk2=s->n_chunks,chunk3;
|
uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3;
|
||||||
while(chunk1!=chunk2) {
|
while (chunk1 != chunk2) {
|
||||||
chunk3 = (chunk1+chunk2)/2;
|
chunk3 = (chunk1 + chunk2) / 2;
|
||||||
if(s->sectors[chunk3]>sector_num)
|
if (s->sectors[chunk3] > sector_num) {
|
||||||
chunk2 = chunk3;
|
chunk2 = chunk3;
|
||||||
else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
|
} else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) {
|
||||||
return chunk3;
|
return chunk3;
|
||||||
else
|
} else {
|
||||||
chunk1 = chunk3;
|
chunk1 = chunk3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s->n_chunks; /* error */
|
return s->n_chunks; /* error */
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
||||||
{
|
{
|
||||||
BDRVDMGState *s = bs->opaque;
|
BDRVDMGState *s = bs->opaque;
|
||||||
|
|
||||||
if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
|
if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) {
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t chunk = search_chunk(s,sector_num);
|
uint32_t chunk = search_chunk(s, sector_num);
|
||||||
|
|
||||||
if(chunk>=s->n_chunks)
|
if (chunk >= s->n_chunks) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
s->current_chunk = s->n_chunks;
|
s->current_chunk = s->n_chunks;
|
||||||
switch(s->types[chunk]) {
|
switch (s->types[chunk]) {
|
||||||
case 0x80000005: { /* zlib compressed */
|
case 0x80000005: { /* zlib compressed */
|
||||||
int i;
|
/* we need to buffer, because only the chunk as whole can be
|
||||||
|
* inflated. */
|
||||||
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
|
s->compressed_chunk, s->lengths[chunk]);
|
||||||
|
if (ret != s->lengths[chunk]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* we need to buffer, because only the chunk as whole can be
|
s->zstream.next_in = s->compressed_chunk;
|
||||||
* inflated. */
|
s->zstream.avail_in = s->lengths[chunk];
|
||||||
i=0;
|
s->zstream.next_out = s->uncompressed_chunk;
|
||||||
do {
|
s->zstream.avail_out = 512 * s->sectorcounts[chunk];
|
||||||
ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
|
ret = inflateReset(&s->zstream);
|
||||||
s->compressed_chunk+i, s->lengths[chunk]-i);
|
if (ret != Z_OK) {
|
||||||
if(ret<0 && errno==EINTR)
|
return -1;
|
||||||
ret=0;
|
}
|
||||||
i+=ret;
|
ret = inflate(&s->zstream, Z_FINISH);
|
||||||
} while(ret>=0 && ret+i<s->lengths[chunk]);
|
if (ret != Z_STREAM_END ||
|
||||||
|
s->zstream.total_out != 512 * s->sectorcounts[chunk]) {
|
||||||
if (ret != s->lengths[chunk])
|
return -1;
|
||||||
return -1;
|
}
|
||||||
|
break; }
|
||||||
s->zstream.next_in = s->compressed_chunk;
|
case 1: /* copy */
|
||||||
s->zstream.avail_in = s->lengths[chunk];
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
s->zstream.next_out = s->uncompressed_chunk;
|
|
||||||
s->zstream.avail_out = 512*s->sectorcounts[chunk];
|
|
||||||
ret = inflateReset(&s->zstream);
|
|
||||||
if(ret != Z_OK)
|
|
||||||
return -1;
|
|
||||||
ret = inflate(&s->zstream, Z_FINISH);
|
|
||||||
if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
|
|
||||||
return -1;
|
|
||||||
break; }
|
|
||||||
case 1: /* copy */
|
|
||||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
|
||||||
s->uncompressed_chunk, s->lengths[chunk]);
|
s->uncompressed_chunk, s->lengths[chunk]);
|
||||||
if (ret != s->lengths[chunk])
|
if (ret != s->lengths[chunk]) {
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
}
|
||||||
case 2: /* zero */
|
break;
|
||||||
memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]);
|
case 2: /* zero */
|
||||||
break;
|
memset(s->uncompressed_chunk, 0, 512 * s->sectorcounts[chunk]);
|
||||||
}
|
break;
|
||||||
s->current_chunk = chunk;
|
}
|
||||||
|
s->current_chunk = chunk;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -339,12 +394,14 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
BDRVDMGState *s = bs->opaque;
|
BDRVDMGState *s = bs->opaque;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0;i<nb_sectors;i++) {
|
for (i = 0; i < nb_sectors; i++) {
|
||||||
uint32_t sector_offset_in_chunk;
|
uint32_t sector_offset_in_chunk;
|
||||||
if(dmg_read_chunk(bs, sector_num+i) != 0)
|
if (dmg_read_chunk(bs, sector_num + i) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
|
}
|
||||||
memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
|
sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk];
|
||||||
|
memcpy(buf + i * 512,
|
||||||
|
s->uncompressed_chunk + sector_offset_in_chunk * 512, 512);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -376,12 +433,12 @@ static void dmg_close(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriver bdrv_dmg = {
|
static BlockDriver bdrv_dmg = {
|
||||||
.format_name = "dmg",
|
.format_name = "dmg",
|
||||||
.instance_size = sizeof(BDRVDMGState),
|
.instance_size = sizeof(BDRVDMGState),
|
||||||
.bdrv_probe = dmg_probe,
|
.bdrv_probe = dmg_probe,
|
||||||
.bdrv_open = dmg_open,
|
.bdrv_open = dmg_open,
|
||||||
.bdrv_read = dmg_co_read,
|
.bdrv_read = dmg_co_read,
|
||||||
.bdrv_close = dmg_close,
|
.bdrv_close = dmg_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_dmg_init(void)
|
static void bdrv_dmg_init(void)
|
||||||
|
|||||||
@@ -417,6 +417,10 @@ static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
|||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
struct IscsiTask iTask;
|
struct IscsiTask iTask;
|
||||||
|
|
||||||
|
if (bs->sg) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
@@ -838,7 +842,8 @@ retry:
|
|||||||
|
|
||||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
||||||
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
||||||
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
(iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE ||
|
||||||
|
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB)) {
|
||||||
/* WRITE SAME is not supported by the target */
|
/* WRITE SAME is not supported by the target */
|
||||||
iscsilun->has_write_same = false;
|
iscsilun->has_write_same = false;
|
||||||
scsi_free_scsi_task(iTask.task);
|
scsi_free_scsi_task(iTask.task);
|
||||||
@@ -1090,7 +1095,7 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
|||||||
*inq = scsi_datain_unmarshall(task);
|
*inq = scsi_datain_unmarshall(task);
|
||||||
if (*inq == NULL) {
|
if (*inq == NULL) {
|
||||||
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
||||||
goto fail;
|
goto fail_with_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
@@ -1098,6 +1103,7 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
|||||||
fail:
|
fail:
|
||||||
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
||||||
iscsi_get_error(iscsi));
|
iscsi_get_error(iscsi));
|
||||||
|
fail_with_err:
|
||||||
if (task != NULL) {
|
if (task != NULL) {
|
||||||
scsi_free_scsi_task(task);
|
scsi_free_scsi_task(task);
|
||||||
}
|
}
|
||||||
@@ -1226,6 +1232,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
iscsi_readcapacity_sync(iscsilun, &local_err);
|
iscsi_readcapacity_sync(iscsilun, &local_err);
|
||||||
if (local_err != NULL) {
|
if (local_err != NULL) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
||||||
@@ -1330,18 +1337,20 @@ static int iscsi_refresh_limits(BlockDriverState *bs)
|
|||||||
|
|
||||||
/* We don't actually refresh here, but just return data queried in
|
/* We don't actually refresh here, but just return data queried in
|
||||||
* iscsi_open(): iscsi targets don't change their limits. */
|
* iscsi_open(): iscsi targets don't change their limits. */
|
||||||
if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
|
if (iscsilun->lbp.lbpu) {
|
||||||
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
||||||
bs->bl.max_discard = sector_lun2qemu(iscsilun->bl.max_unmap,
|
bs->bl.max_discard = sector_lun2qemu(iscsilun->bl.max_unmap,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
}
|
}
|
||||||
bs->bl.discard_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
bs->bl.discard_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
|
}
|
||||||
|
|
||||||
if (iscsilun->bl.max_ws_len < 0xffffffff) {
|
if (iscsilun->bl.max_ws_len < 0xffffffff) {
|
||||||
bs->bl.max_write_zeroes = sector_lun2qemu(iscsilun->bl.max_ws_len,
|
bs->bl.max_write_zeroes = sector_lun2qemu(iscsilun->bl.max_ws_len,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
}
|
}
|
||||||
|
if (iscsilun->lbp.lbpws) {
|
||||||
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
}
|
}
|
||||||
@@ -1391,7 +1400,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
IscsiLun *iscsilun = NULL;
|
IscsiLun *iscsilun = NULL;
|
||||||
QDict *bs_options;
|
QDict *bs_options;
|
||||||
|
|
||||||
bs = bdrv_new("");
|
bs = bdrv_new("", &error_abort);
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
while (options && options->name) {
|
while (options && options->name) {
|
||||||
|
|||||||
@@ -325,11 +325,11 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
|
|
||||||
s->common.len = bdrv_getlength(bs);
|
s->common.len = bdrv_getlength(bs);
|
||||||
if (s->common.len <= 0) {
|
if (s->common.len <= 0) {
|
||||||
block_job_completed(&s->common, s->common.len);
|
ret = s->common.len;
|
||||||
return;
|
goto immediate_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity;
|
length = DIV_ROUND_UP(s->common.len, s->granularity);
|
||||||
s->in_flight_bitmap = bitmap_new(length);
|
s->in_flight_bitmap = bitmap_new(length);
|
||||||
|
|
||||||
/* If we have no backing file yet in the destination, we cannot let
|
/* If we have no backing file yet in the destination, we cannot let
|
||||||
@@ -339,7 +339,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
bdrv_get_backing_filename(s->target, backing_filename,
|
bdrv_get_backing_filename(s->target, backing_filename,
|
||||||
sizeof(backing_filename));
|
sizeof(backing_filename));
|
||||||
if (backing_filename[0] && !s->target->backing_hd) {
|
if (backing_filename[0] && !s->target->backing_hd) {
|
||||||
bdrv_get_info(s->target, &bdi);
|
ret = bdrv_get_info(s->target, &bdi);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto immediate_exit;
|
||||||
|
}
|
||||||
if (s->granularity < bdi.cluster_size) {
|
if (s->granularity < bdi.cluster_size) {
|
||||||
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
|
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
|
||||||
s->cow_bitmap = bitmap_new(length);
|
s->cow_bitmap = bitmap_new(length);
|
||||||
@@ -605,7 +608,10 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
|||||||
s->granularity = granularity;
|
s->granularity = granularity;
|
||||||
s->buf_size = MAX(buf_size, granularity);
|
s->buf_size = MAX(buf_size, granularity);
|
||||||
|
|
||||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity);
|
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp);
|
||||||
|
if (!s->dirty_bitmap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
bdrv_set_enable_write_cache(s->target, true);
|
bdrv_set_enable_write_cache(s->target, true);
|
||||||
bdrv_set_on_error(s->target, on_target_error, on_target_error);
|
bdrv_set_on_error(s->target, on_target_error, on_target_error);
|
||||||
bdrv_iostatus_enable(s->target);
|
bdrv_iostatus_enable(s->target);
|
||||||
@@ -677,7 +683,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base,
|
|||||||
mirror_start_job(bs, base, speed, 0, 0,
|
mirror_start_job(bs, base, speed, 0, 0,
|
||||||
on_error, on_error, cb, opaque, &local_err,
|
on_error, on_error, cb, opaque, &local_err,
|
||||||
&commit_active_job_driver, false, base);
|
&commit_active_job_driver, false, base);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto error_restore_flags;
|
goto error_restore_flags;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
|
|||||||
InetSocketAddress *addr = NULL;
|
InetSocketAddress *addr = NULL;
|
||||||
|
|
||||||
addr = inet_parse(host_spec, errp);
|
addr = inet_parse(host_spec, errp);
|
||||||
if (error_is_set(errp)) {
|
if (!addr) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ typedef struct BDRVParallelsState {
|
|||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
|
|
||||||
uint32_t *catalog_bitmap;
|
uint32_t *catalog_bitmap;
|
||||||
int catalog_size;
|
unsigned int catalog_size;
|
||||||
|
|
||||||
int tracks;
|
unsigned int tracks;
|
||||||
} BDRVParallelsState;
|
} BDRVParallelsState;
|
||||||
|
|
||||||
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
|
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
@@ -93,8 +93,18 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
bs->total_sectors = le32_to_cpu(ph.nb_sectors);
|
bs->total_sectors = le32_to_cpu(ph.nb_sectors);
|
||||||
|
|
||||||
s->tracks = le32_to_cpu(ph.tracks);
|
s->tracks = le32_to_cpu(ph.tracks);
|
||||||
|
if (s->tracks == 0) {
|
||||||
|
error_setg(errp, "Invalid image: Zero sectors per track");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
s->catalog_size = le32_to_cpu(ph.catalog_entries);
|
s->catalog_size = le32_to_cpu(ph.catalog_entries);
|
||||||
|
if (s->catalog_size > INT_MAX / 4) {
|
||||||
|
error_setg(errp, "Catalog too large");
|
||||||
|
ret = -EFBIG;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
|
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
|
||||||
|
|||||||
@@ -532,12 +532,11 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
|
|||||||
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
||||||
ImageInfoSpecific *info_spec)
|
ImageInfoSpecific *info_spec)
|
||||||
{
|
{
|
||||||
Error *local_err = NULL;
|
|
||||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||||
QObject *obj, *data;
|
QObject *obj, *data;
|
||||||
|
|
||||||
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
|
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
|
||||||
&local_err);
|
&error_abort);
|
||||||
obj = qmp_output_get_qobject(ov);
|
obj = qmp_output_get_qobject(ov);
|
||||||
assert(qobject_type(obj) == QTYPE_QDICT);
|
assert(qobject_type(obj) == QTYPE_QDICT);
|
||||||
data = qdict_get(qobject_to_qdict(obj), "data");
|
data = qdict_get(qobject_to_qdict(obj), "data");
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
if (header.version != QCOW_VERSION) {
|
if (header.version != QCOW_VERSION) {
|
||||||
char version[64];
|
char version[64];
|
||||||
snprintf(version, sizeof(version), "QCOW version %d", header.version);
|
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
|
||||||
|
header.version);
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
bs->device_name, "qcow", version);
|
bs->device_name, "qcow", version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
if (min_size <= s->l1_size)
|
if (min_size <= s->l1_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Do a sanity check on min_size before trying to calculate new_l1_size
|
||||||
|
* (this prevents overflows during the while loop for the calculation of
|
||||||
|
* new_l1_size) */
|
||||||
|
if (min_size > INT_MAX / sizeof(uint64_t)) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
if (exact_size) {
|
if (exact_size) {
|
||||||
new_l1_size = min_size;
|
new_l1_size = min_size;
|
||||||
} else {
|
} else {
|
||||||
@@ -55,7 +62,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_l1_size > INT_MAX) {
|
if (new_l1_size > INT_MAX / sizeof(uint64_t)) {
|
||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,15 +366,6 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
|||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
int n, ret;
|
int n, ret;
|
||||||
|
|
||||||
/*
|
|
||||||
* If this is the last cluster and it is only partially used, we must only
|
|
||||||
* copy until the end of the image, or bdrv_check_request will fail for the
|
|
||||||
* bdrv_read/write calls below.
|
|
||||||
*/
|
|
||||||
if (start_sect + n_end > bs->total_sectors) {
|
|
||||||
n_end = bs->total_sectors - start_sect;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = n_end - n_start;
|
n = n_end - n_start;
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -500,6 +498,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
break;
|
break;
|
||||||
case QCOW2_CLUSTER_ZERO:
|
case QCOW2_CLUSTER_ZERO:
|
||||||
if (s->qcow_version < 3) {
|
if (s->qcow_version < 3) {
|
||||||
|
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||||
@@ -1368,9 +1367,9 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
|||||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||||
|
|
||||||
for (i = 0; i < nb_clusters; i++) {
|
for (i = 0; i < nb_clusters; i++) {
|
||||||
uint64_t old_offset;
|
uint64_t old_l2_entry;
|
||||||
|
|
||||||
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that a discarded area reads back as zeroes for v3 images
|
* Make sure that a discarded area reads back as zeroes for v3 images
|
||||||
@@ -1381,12 +1380,22 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
|||||||
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
||||||
* holding s->lock, so that doesn't work today.
|
* holding s->lock, so that doesn't work today.
|
||||||
*/
|
*/
|
||||||
if (old_offset & QCOW_OFLAG_ZERO) {
|
switch (qcow2_get_cluster_type(old_l2_entry)) {
|
||||||
continue;
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
}
|
if (!bs->backing_hd) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if ((old_offset & L2E_OFFSET_MASK) == 0 && !bs->backing_hd) {
|
case QCOW2_CLUSTER_ZERO:
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First remove L2 entries */
|
/* First remove L2 entries */
|
||||||
@@ -1398,7 +1407,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Then decrease the refcount */
|
/* Then decrease the refcount */
|
||||||
qcow2_free_any_clusters(bs, old_offset, 1, type);
|
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
#include "qapi/qmp/types.h"
|
#include "qapi/qmp/types.h"
|
||||||
|
|
||||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
|
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
|
||||||
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||||
int64_t offset, int64_t length,
|
int64_t offset, int64_t length,
|
||||||
int addend, enum qcow2_discard_type type);
|
int addend, enum qcow2_discard_type type);
|
||||||
@@ -40,8 +40,10 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
|||||||
int qcow2_refcount_init(BlockDriverState *bs)
|
int qcow2_refcount_init(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int ret, refcount_table_size2, i;
|
unsigned int refcount_table_size2, i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
|
||||||
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
||||||
s->refcount_table = g_malloc(refcount_table_size2);
|
s->refcount_table = g_malloc(refcount_table_size2);
|
||||||
if (s->refcount_table_size > 0) {
|
if (s->refcount_table_size > 0) {
|
||||||
@@ -87,7 +89,7 @@ static int load_refcount_block(BlockDriverState *bs,
|
|||||||
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int refcount_table_index, block_index;
|
uint64_t refcount_table_index, block_index;
|
||||||
int64_t refcount_block_offset;
|
int64_t refcount_block_offset;
|
||||||
int ret;
|
int ret;
|
||||||
uint16_t *refcount_block;
|
uint16_t *refcount_block;
|
||||||
@@ -192,10 +194,11 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
* they can describe them themselves.
|
* they can describe them themselves.
|
||||||
*
|
*
|
||||||
* - We need to consider that at this point we are inside update_refcounts
|
* - We need to consider that at this point we are inside update_refcounts
|
||||||
* and doing the initial refcount increase. This means that some clusters
|
* and potentially doing an initial refcount increase. This means that
|
||||||
* have already been allocated by the caller, but their refcount isn't
|
* some clusters have already been allocated by the caller, but their
|
||||||
* accurate yet. free_cluster_index tells us where this allocation ends
|
* refcount isn't accurate yet. If we allocate clusters for metadata, we
|
||||||
* as long as we don't overwrite it by freeing clusters.
|
* need to return -EAGAIN to signal the caller that it needs to restart
|
||||||
|
* the search for free clusters.
|
||||||
*
|
*
|
||||||
* - alloc_clusters_noref and qcow2_free_clusters may load a different
|
* - alloc_clusters_noref and qcow2_free_clusters may load a different
|
||||||
* refcount block into the cache
|
* refcount block into the cache
|
||||||
@@ -280,7 +283,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->refcount_table[refcount_table_index] = new_block;
|
s->refcount_table[refcount_table_index] = new_block;
|
||||||
return 0;
|
|
||||||
|
/* The new refcount block may be where the caller intended to put its
|
||||||
|
* data, so let it restart the search. */
|
||||||
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
|
ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
|
||||||
@@ -303,8 +309,11 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
|
|
||||||
/* Calculate the number of refcount blocks needed so far */
|
/* Calculate the number of refcount blocks needed so far */
|
||||||
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
||||||
uint64_t blocks_used = (s->free_cluster_index +
|
uint64_t blocks_used = DIV_ROUND_UP(cluster_index, refcount_block_clusters);
|
||||||
refcount_block_clusters - 1) / refcount_block_clusters;
|
|
||||||
|
if (blocks_used > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
/* And now we need at least one block more for the new metadata */
|
/* And now we need at least one block more for the new metadata */
|
||||||
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
||||||
@@ -337,8 +346,6 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
|
uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
|
||||||
uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
|
uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
|
||||||
|
|
||||||
assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
|
|
||||||
|
|
||||||
/* Fill the new refcount table */
|
/* Fill the new refcount table */
|
||||||
memcpy(new_table, s->refcount_table,
|
memcpy(new_table, s->refcount_table,
|
||||||
s->refcount_table_size * sizeof(uint64_t));
|
s->refcount_table_size * sizeof(uint64_t));
|
||||||
@@ -401,18 +408,19 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
s->refcount_table_size = table_size;
|
s->refcount_table_size = table_size;
|
||||||
s->refcount_table_offset = table_offset;
|
s->refcount_table_offset = table_offset;
|
||||||
|
|
||||||
/* Free old table. Remember, we must not change free_cluster_index */
|
/* Free old table. */
|
||||||
uint64_t old_free_cluster_index = s->free_cluster_index;
|
|
||||||
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
|
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
|
||||||
QCOW2_DISCARD_OTHER);
|
QCOW2_DISCARD_OTHER);
|
||||||
s->free_cluster_index = old_free_cluster_index;
|
|
||||||
|
|
||||||
ret = load_refcount_block(bs, new_block, (void**) refcount_block);
|
ret = load_refcount_block(bs, new_block, (void**) refcount_block);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
/* If we were trying to do the initial refcount update for some cluster
|
||||||
|
* allocation, we might have used the same clusters to store newly
|
||||||
|
* allocated metadata. Make the caller search some new space. */
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
fail_table:
|
fail_table:
|
||||||
g_free(new_table);
|
g_free(new_table);
|
||||||
@@ -627,15 +635,16 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
|
|||||||
|
|
||||||
|
|
||||||
/* return < 0 if error */
|
/* return < 0 if error */
|
||||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
|
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int i, nb_clusters, refcount;
|
uint64_t i, nb_clusters;
|
||||||
|
int refcount;
|
||||||
|
|
||||||
nb_clusters = size_to_clusters(s, size);
|
nb_clusters = size_to_clusters(s, size);
|
||||||
retry:
|
retry:
|
||||||
for(i = 0; i < nb_clusters; i++) {
|
for(i = 0; i < nb_clusters; i++) {
|
||||||
int64_t next_cluster_index = s->free_cluster_index++;
|
uint64_t next_cluster_index = s->free_cluster_index++;
|
||||||
refcount = get_refcount(bs, next_cluster_index);
|
refcount = get_refcount(bs, next_cluster_index);
|
||||||
|
|
||||||
if (refcount < 0) {
|
if (refcount < 0) {
|
||||||
@@ -644,6 +653,13 @@ retry:
|
|||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure that all offsets in the "allocated" range are representable
|
||||||
|
* in an int64_t */
|
||||||
|
if (s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC2
|
#ifdef DEBUG_ALLOC2
|
||||||
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
||||||
size,
|
size,
|
||||||
@@ -652,18 +668,21 @@ retry:
|
|||||||
return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
|
return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
|
||||||
{
|
{
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
||||||
offset = alloc_clusters_noref(bs, size);
|
do {
|
||||||
if (offset < 0) {
|
offset = alloc_clusters_noref(bs, size);
|
||||||
return offset;
|
if (offset < 0) {
|
||||||
}
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
|
||||||
|
} while (ret == -EAGAIN);
|
||||||
|
|
||||||
ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -676,7 +695,6 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
|||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t cluster_index;
|
uint64_t cluster_index;
|
||||||
uint64_t old_free_cluster_index;
|
|
||||||
uint64_t i;
|
uint64_t i;
|
||||||
int refcount, ret;
|
int refcount, ret;
|
||||||
|
|
||||||
@@ -685,30 +703,28 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check how many clusters there are free */
|
do {
|
||||||
cluster_index = offset >> s->cluster_bits;
|
/* Check how many clusters there are free */
|
||||||
for(i = 0; i < nb_clusters; i++) {
|
cluster_index = offset >> s->cluster_bits;
|
||||||
refcount = get_refcount(bs, cluster_index++);
|
for(i = 0; i < nb_clusters; i++) {
|
||||||
|
refcount = get_refcount(bs, cluster_index++);
|
||||||
|
|
||||||
if (refcount < 0) {
|
if (refcount < 0) {
|
||||||
return refcount;
|
return refcount;
|
||||||
} else if (refcount != 0) {
|
} else if (refcount != 0) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* And then allocate them */
|
/* And then allocate them */
|
||||||
old_free_cluster_index = s->free_cluster_index;
|
ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
|
||||||
s->free_cluster_index = cluster_index + i;
|
QCOW2_DISCARD_NEVER);
|
||||||
|
} while (ret == -EAGAIN);
|
||||||
|
|
||||||
ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
|
|
||||||
QCOW2_DISCARD_NEVER);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free_cluster_index = old_free_cluster_index;
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1011,8 +1027,7 @@ static void inc_refcounts(BlockDriverState *bs,
|
|||||||
int64_t offset, int64_t size)
|
int64_t offset, int64_t size)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t start, last, cluster_offset;
|
uint64_t start, last, cluster_offset, k;
|
||||||
int k;
|
|
||||||
|
|
||||||
if (size <= 0)
|
if (size <= 0)
|
||||||
return;
|
return;
|
||||||
@@ -1022,11 +1037,7 @@ static void inc_refcounts(BlockDriverState *bs,
|
|||||||
for(cluster_offset = start; cluster_offset <= last;
|
for(cluster_offset = start; cluster_offset <= last;
|
||||||
cluster_offset += s->cluster_size) {
|
cluster_offset += s->cluster_size) {
|
||||||
k = cluster_offset >> s->cluster_bits;
|
k = cluster_offset >> s->cluster_bits;
|
||||||
if (k < 0) {
|
if (k >= refcount_table_size) {
|
||||||
fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
|
|
||||||
cluster_offset);
|
|
||||||
res->corruptions++;
|
|
||||||
} else if (k >= refcount_table_size) {
|
|
||||||
fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
|
fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
|
||||||
"the end of the image file, can't properly check refcounts.\n",
|
"the end of the image file, can't properly check refcounts.\n",
|
||||||
cluster_offset);
|
cluster_offset);
|
||||||
@@ -1469,14 +1480,24 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
BdrvCheckMode fix)
|
BdrvCheckMode fix)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t size, i, highest_cluster;
|
int64_t size, i, highest_cluster, nb_clusters;
|
||||||
int nb_clusters, refcount1, refcount2;
|
int refcount1, refcount2;
|
||||||
QCowSnapshot *sn;
|
QCowSnapshot *sn;
|
||||||
uint16_t *refcount_table;
|
uint16_t *refcount_table;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size = bdrv_getlength(bs->file);
|
size = bdrv_getlength(bs->file);
|
||||||
|
if (size < 0) {
|
||||||
|
res->check_errors++;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
nb_clusters = size_to_clusters(s, size);
|
nb_clusters = size_to_clusters(s, size);
|
||||||
|
if (nb_clusters > INT_MAX) {
|
||||||
|
res->check_errors++;
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
|
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
|
||||||
|
|
||||||
res->bfi.total_clusters =
|
res->bfi.total_clusters =
|
||||||
|
|||||||
@@ -26,31 +26,6 @@
|
|||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "block/qcow2.h"
|
#include "block/qcow2.h"
|
||||||
|
|
||||||
typedef struct QEMU_PACKED QCowSnapshotHeader {
|
|
||||||
/* header is 8 byte aligned */
|
|
||||||
uint64_t l1_table_offset;
|
|
||||||
|
|
||||||
uint32_t l1_size;
|
|
||||||
uint16_t id_str_size;
|
|
||||||
uint16_t name_size;
|
|
||||||
|
|
||||||
uint32_t date_sec;
|
|
||||||
uint32_t date_nsec;
|
|
||||||
|
|
||||||
uint64_t vm_clock_nsec;
|
|
||||||
|
|
||||||
uint32_t vm_state_size;
|
|
||||||
uint32_t extra_data_size; /* for extension */
|
|
||||||
/* extra data follows */
|
|
||||||
/* id_str follows */
|
|
||||||
/* name follows */
|
|
||||||
} QCowSnapshotHeader;
|
|
||||||
|
|
||||||
typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
|
||||||
uint64_t vm_state_size_large;
|
|
||||||
uint64_t disk_size;
|
|
||||||
} QCowSnapshotExtraData;
|
|
||||||
|
|
||||||
void qcow2_free_snapshots(BlockDriverState *bs)
|
void qcow2_free_snapshots(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
@@ -141,8 +116,14 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
offset += name_size;
|
offset += name_size;
|
||||||
sn->name[name_size] = '\0';
|
sn->name[name_size] = '\0';
|
||||||
|
|
||||||
|
if (offset - s->snapshots_offset > QCOW_MAX_SNAPSHOTS_SIZE) {
|
||||||
|
ret = -EFBIG;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(offset - s->snapshots_offset <= INT_MAX);
|
||||||
s->snapshots_size = offset - s->snapshots_offset;
|
s->snapshots_size = offset - s->snapshots_offset;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -163,7 +144,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
|||||||
uint32_t nb_snapshots;
|
uint32_t nb_snapshots;
|
||||||
uint64_t snapshots_offset;
|
uint64_t snapshots_offset;
|
||||||
} QEMU_PACKED header_data;
|
} QEMU_PACKED header_data;
|
||||||
int64_t offset, snapshots_offset;
|
int64_t offset, snapshots_offset = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* compute the size of the snapshots */
|
/* compute the size of the snapshots */
|
||||||
@@ -175,7 +156,14 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
|||||||
offset += sizeof(extra);
|
offset += sizeof(extra);
|
||||||
offset += strlen(sn->id_str);
|
offset += strlen(sn->id_str);
|
||||||
offset += strlen(sn->name);
|
offset += strlen(sn->name);
|
||||||
|
|
||||||
|
if (offset > QCOW_MAX_SNAPSHOTS_SIZE) {
|
||||||
|
ret = -EFBIG;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(offset <= INT_MAX);
|
||||||
snapshots_size = offset;
|
snapshots_size = offset;
|
||||||
|
|
||||||
/* Allocate space for the new snapshot list */
|
/* Allocate space for the new snapshot list */
|
||||||
@@ -357,6 +345,10 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
|||||||
uint64_t *l1_table = NULL;
|
uint64_t *l1_table = NULL;
|
||||||
int64_t l1_table_offset;
|
int64_t l1_table_offset;
|
||||||
|
|
||||||
|
if (s->nb_snapshots >= QCOW_MAX_SNAPSHOTS) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
memset(sn, 0, sizeof(*sn));
|
memset(sn, 0, sizeof(*sn));
|
||||||
|
|
||||||
/* Generate an ID if it wasn't passed */
|
/* Generate an ID if it wasn't passed */
|
||||||
@@ -701,7 +693,11 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
|||||||
sn = &s->snapshots[snapshot_index];
|
sn = &s->snapshots[snapshot_index];
|
||||||
|
|
||||||
/* Allocate and read in the snapshot's L1 table */
|
/* Allocate and read in the snapshot's L1 table */
|
||||||
new_l1_bytes = s->l1_size * sizeof(uint64_t);
|
if (sn->l1_size > QCOW_MAX_L1_SIZE) {
|
||||||
|
error_setg(errp, "Snapshot L1 table too large");
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
||||||
new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
|
new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
||||||
|
|||||||
180
block/qcow2.c
180
block/qcow2.c
@@ -124,8 +124,9 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
|||||||
|
|
||||||
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
|
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
|
||||||
if (ext.len >= sizeof(bs->backing_format)) {
|
if (ext.len >= sizeof(bs->backing_format)) {
|
||||||
error_setg(errp, "ERROR: ext_backing_format: len=%u too large"
|
error_setg(errp, "ERROR: ext_backing_format: len=%" PRIu32
|
||||||
" (>=%zu)", ext.len, sizeof(bs->backing_format));
|
" too large (>=%zu)", ext.len,
|
||||||
|
sizeof(bs->backing_format));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
||||||
@@ -269,12 +270,15 @@ static int qcow2_mark_clean(BlockDriverState *bs)
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
|
||||||
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
|
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
|
||||||
int ret = bdrv_flush(bs);
|
int ret;
|
||||||
|
|
||||||
|
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
|
||||||
|
|
||||||
|
ret = bdrv_flush(bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
|
|
||||||
return qcow2_update_header(bs);
|
return qcow2_update_header(bs);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -329,6 +333,32 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
|
uint64_t entries, size_t entry_len)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
uint64_t size;
|
||||||
|
|
||||||
|
/* Use signed INT64_MAX as the maximum even for uint64_t header fields,
|
||||||
|
* because values will be passed to qemu functions taking int64_t. */
|
||||||
|
if (entries > INT64_MAX / entry_len) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = entries * entry_len;
|
||||||
|
|
||||||
|
if (INT64_MAX - size < offset) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables must be cluster aligned */
|
||||||
|
if (offset & (s->cluster_size - 1)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static QemuOptsList qcow2_runtime_opts = {
|
static QemuOptsList qcow2_runtime_opts = {
|
||||||
.name = "qcow2",
|
.name = "qcow2",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
|
||||||
@@ -419,7 +449,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int len, i, ret = 0;
|
unsigned int len, i;
|
||||||
|
int ret = 0;
|
||||||
QCowHeader header;
|
QCowHeader header;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@@ -453,13 +484,26 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (header.version < 2 || header.version > 3) {
|
if (header.version < 2 || header.version > 3) {
|
||||||
report_unsupported(bs, errp, "QCOW version %d", header.version);
|
report_unsupported(bs, errp, "QCOW version %" PRIu32, header.version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->qcow_version = header.version;
|
s->qcow_version = header.version;
|
||||||
|
|
||||||
|
/* Initialise cluster size */
|
||||||
|
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||||
|
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||||
|
error_setg(errp, "Unsupported cluster size: 2^%" PRIu32,
|
||||||
|
header.cluster_bits);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->cluster_bits = header.cluster_bits;
|
||||||
|
s->cluster_size = 1 << s->cluster_bits;
|
||||||
|
s->cluster_sectors = 1 << (s->cluster_bits - 9);
|
||||||
|
|
||||||
/* Initialise version 3 header fields */
|
/* Initialise version 3 header fields */
|
||||||
if (header.version == 2) {
|
if (header.version == 2) {
|
||||||
header.incompatible_features = 0;
|
header.incompatible_features = 0;
|
||||||
@@ -473,6 +517,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
be64_to_cpus(&header.autoclear_features);
|
be64_to_cpus(&header.autoclear_features);
|
||||||
be32_to_cpus(&header.refcount_order);
|
be32_to_cpus(&header.refcount_order);
|
||||||
be32_to_cpus(&header.header_length);
|
be32_to_cpus(&header.header_length);
|
||||||
|
|
||||||
|
if (header.header_length < 104) {
|
||||||
|
error_setg(errp, "qcow2 header too short");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.header_length > s->cluster_size) {
|
||||||
|
error_setg(errp, "qcow2 header exceeds cluster size");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.header_length > sizeof(header)) {
|
if (header.header_length > sizeof(header)) {
|
||||||
@@ -487,6 +543,12 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (header.backing_file_offset > s->cluster_size) {
|
||||||
|
error_setg(errp, "Invalid backing file offset");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (header.backing_file_offset) {
|
if (header.backing_file_offset) {
|
||||||
ext_end = header.backing_file_offset;
|
ext_end = header.backing_file_offset;
|
||||||
} else {
|
} else {
|
||||||
@@ -506,6 +568,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->incompatible_features &
|
s->incompatible_features &
|
||||||
~QCOW2_INCOMPAT_MASK);
|
~QCOW2_INCOMPAT_MASK);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
g_free(feature_table);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,14 +592,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
s->refcount_order = header.refcount_order;
|
s->refcount_order = header.refcount_order;
|
||||||
|
|
||||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
|
||||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
|
||||||
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||||
error_setg(errp, "Unsupported encryption method: %i",
|
error_setg(errp, "Unsupported encryption method: %" PRIu32,
|
||||||
header.crypt_method);
|
header.crypt_method);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -545,23 +602,52 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
if (s->crypt_method_header) {
|
if (s->crypt_method_header) {
|
||||||
bs->encrypted = 1;
|
bs->encrypted = 1;
|
||||||
}
|
}
|
||||||
s->cluster_bits = header.cluster_bits;
|
|
||||||
s->cluster_size = 1 << s->cluster_bits;
|
|
||||||
s->cluster_sectors = 1 << (s->cluster_bits - 9);
|
|
||||||
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
||||||
s->l2_size = 1 << s->l2_bits;
|
s->l2_size = 1 << s->l2_bits;
|
||||||
bs->total_sectors = header.size / 512;
|
bs->total_sectors = header.size / 512;
|
||||||
s->csize_shift = (62 - (s->cluster_bits - 8));
|
s->csize_shift = (62 - (s->cluster_bits - 8));
|
||||||
s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
|
s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
|
||||||
s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
|
s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
|
||||||
|
|
||||||
s->refcount_table_offset = header.refcount_table_offset;
|
s->refcount_table_offset = header.refcount_table_offset;
|
||||||
s->refcount_table_size =
|
s->refcount_table_size =
|
||||||
header.refcount_table_clusters << (s->cluster_bits - 3);
|
header.refcount_table_clusters << (s->cluster_bits - 3);
|
||||||
|
|
||||||
s->snapshots_offset = header.snapshots_offset;
|
if (header.refcount_table_clusters > qcow2_max_refcount_clusters(s)) {
|
||||||
s->nb_snapshots = header.nb_snapshots;
|
error_setg(errp, "Reference count table too large");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = validate_table_offset(bs, s->refcount_table_offset,
|
||||||
|
s->refcount_table_size, sizeof(uint64_t));
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Invalid reference count table offset");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Snapshot table offset/length */
|
||||||
|
if (header.nb_snapshots > QCOW_MAX_SNAPSHOTS) {
|
||||||
|
error_setg(errp, "Too many snapshots");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = validate_table_offset(bs, header.snapshots_offset,
|
||||||
|
header.nb_snapshots,
|
||||||
|
sizeof(QCowSnapshotHeader));
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Invalid snapshot table offset");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* read the level 1 table */
|
/* read the level 1 table */
|
||||||
|
if (header.l1_size > QCOW_MAX_L1_SIZE) {
|
||||||
|
error_setg(errp, "Active L1 table too large");
|
||||||
|
ret = -EFBIG;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->l1_size = header.l1_size;
|
s->l1_size = header.l1_size;
|
||||||
|
|
||||||
l1_vm_state_index = size_to_l1(s, header.size);
|
l1_vm_state_index = size_to_l1(s, header.size);
|
||||||
@@ -579,7 +665,16 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = validate_table_offset(bs, header.l1_table_offset,
|
||||||
|
header.l1_size, sizeof(uint64_t));
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Invalid L1 table offset");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->l1_table_offset = header.l1_table_offset;
|
s->l1_table_offset = header.l1_table_offset;
|
||||||
|
|
||||||
|
|
||||||
if (s->l1_size > 0) {
|
if (s->l1_size > 0) {
|
||||||
s->l1_table = g_malloc0(
|
s->l1_table = g_malloc0(
|
||||||
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
||||||
@@ -625,8 +720,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
/* read the backing file name */
|
/* read the backing file name */
|
||||||
if (header.backing_file_offset != 0) {
|
if (header.backing_file_offset != 0) {
|
||||||
len = header.backing_file_size;
|
len = header.backing_file_size;
|
||||||
if (len > 1023) {
|
if (len > MIN(1023, s->cluster_size - header.backing_file_offset)) {
|
||||||
len = 1023;
|
error_setg(errp, "Backing file name too long");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||||
bs->backing_file, len);
|
bs->backing_file, len);
|
||||||
@@ -637,6 +734,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
bs->backing_file[len] = '\0';
|
bs->backing_file[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Internal snapshots */
|
||||||
|
s->snapshots_offset = header.snapshots_offset;
|
||||||
|
s->nb_snapshots = header.nb_snapshots;
|
||||||
|
|
||||||
ret = qcow2_read_snapshots(bs);
|
ret = qcow2_read_snapshots(bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not read snapshots");
|
error_setg_errno(errp, -ret, "Could not read snapshots");
|
||||||
@@ -745,6 +846,9 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
if (s->l2_table_cache) {
|
if (s->l2_table_cache) {
|
||||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||||
}
|
}
|
||||||
|
if (s->refcount_block_cache) {
|
||||||
|
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||||
|
}
|
||||||
g_free(s->cluster_cache);
|
g_free(s->cluster_cache);
|
||||||
qemu_vfree(s->cluster_data);
|
qemu_vfree(s->cluster_data);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -801,11 +905,25 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have nothing to do for QCOW2 reopen, stubs just return
|
/* We have no actual commit/abort logic for qcow2, but we need to write out any
|
||||||
* success */
|
* unwritten data if we reopen read-only. */
|
||||||
static int qcow2_reopen_prepare(BDRVReopenState *state,
|
static int qcow2_reopen_prepare(BDRVReopenState *state,
|
||||||
BlockReopenQueue *queue, Error **errp)
|
BlockReopenQueue *queue, Error **errp)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((state->flags & BDRV_O_RDWR) == 0) {
|
||||||
|
ret = bdrv_flush(state->bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qcow2_mark_clean(state->bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1432,7 +1550,9 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta != NULL) {
|
while (meta) {
|
||||||
|
QCowL2Meta *next = meta->next;
|
||||||
|
|
||||||
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qcow2_free_any_clusters(bs, meta->alloc_offset,
|
qcow2_free_any_clusters(bs, meta->alloc_offset,
|
||||||
@@ -1443,6 +1563,9 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
/* There are no dependent requests, but we need to remove our
|
/* There are no dependent requests, but we need to remove our
|
||||||
* request from the list of in-flight requests */
|
* request from the list of in-flight requests */
|
||||||
QLIST_REMOVE(meta, next_in_flight);
|
QLIST_REMOVE(meta, next_in_flight);
|
||||||
|
|
||||||
|
g_free(meta);
|
||||||
|
meta = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Preallocate data if requested */
|
/* TODO Preallocate data if requested */
|
||||||
@@ -1500,7 +1623,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
*/
|
*/
|
||||||
BlockDriverState* bs;
|
BlockDriverState* bs;
|
||||||
QCowHeader *header;
|
QCowHeader *header;
|
||||||
uint8_t* refcount_table;
|
uint64_t* refcount_table;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1552,9 +1675,10 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write an empty refcount table */
|
/* Write a refcount table with one refcount block */
|
||||||
refcount_table = g_malloc0(cluster_size);
|
refcount_table = g_malloc0(2 * cluster_size);
|
||||||
ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size);
|
refcount_table[0] = cpu_to_be64(2 * cluster_size);
|
||||||
|
ret = bdrv_pwrite(bs, cluster_size, refcount_table, 2 * cluster_size);
|
||||||
g_free(refcount_table);
|
g_free(refcount_table);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1579,7 +1703,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_alloc_clusters(bs, 2 * cluster_size);
|
ret = qcow2_alloc_clusters(bs, 3 * cluster_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not allocate clusters for qcow2 "
|
error_setg_errno(errp, -ret, "Could not allocate clusters for qcow2 "
|
||||||
"header and refcount table");
|
"header and refcount table");
|
||||||
|
|||||||
@@ -38,6 +38,19 @@
|
|||||||
#define QCOW_CRYPT_AES 1
|
#define QCOW_CRYPT_AES 1
|
||||||
|
|
||||||
#define QCOW_MAX_CRYPT_CLUSTERS 32
|
#define QCOW_MAX_CRYPT_CLUSTERS 32
|
||||||
|
#define QCOW_MAX_SNAPSHOTS 65536
|
||||||
|
|
||||||
|
/* 8 MB refcount table is enough for 2 PB images at 64k cluster size
|
||||||
|
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||||
|
#define QCOW_MAX_REFTABLE_SIZE 0x800000
|
||||||
|
|
||||||
|
/* 32 MB L1 table is enough for 2 PB images at 64k cluster size
|
||||||
|
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||||
|
#define QCOW_MAX_L1_SIZE 0x2000000
|
||||||
|
|
||||||
|
/* Allow for an average of 1k per snapshot table entry, should be plenty of
|
||||||
|
* space for snapshot names and IDs */
|
||||||
|
#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS)
|
||||||
|
|
||||||
/* indicate that the refcount of the referenced cluster is exactly one. */
|
/* indicate that the refcount of the referenced cluster is exactly one. */
|
||||||
#define QCOW_OFLAG_COPIED (1ULL << 63)
|
#define QCOW_OFLAG_COPIED (1ULL << 63)
|
||||||
@@ -97,6 +110,32 @@ typedef struct QCowHeader {
|
|||||||
uint32_t header_length;
|
uint32_t header_length;
|
||||||
} QEMU_PACKED QCowHeader;
|
} QEMU_PACKED QCowHeader;
|
||||||
|
|
||||||
|
typedef struct QEMU_PACKED QCowSnapshotHeader {
|
||||||
|
/* header is 8 byte aligned */
|
||||||
|
uint64_t l1_table_offset;
|
||||||
|
|
||||||
|
uint32_t l1_size;
|
||||||
|
uint16_t id_str_size;
|
||||||
|
uint16_t name_size;
|
||||||
|
|
||||||
|
uint32_t date_sec;
|
||||||
|
uint32_t date_nsec;
|
||||||
|
|
||||||
|
uint64_t vm_clock_nsec;
|
||||||
|
|
||||||
|
uint32_t vm_state_size;
|
||||||
|
uint32_t extra_data_size; /* for extension */
|
||||||
|
/* extra data follows */
|
||||||
|
/* id_str follows */
|
||||||
|
/* name follows */
|
||||||
|
} QCowSnapshotHeader;
|
||||||
|
|
||||||
|
typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
||||||
|
uint64_t vm_state_size_large;
|
||||||
|
uint64_t disk_size;
|
||||||
|
} QCowSnapshotExtraData;
|
||||||
|
|
||||||
|
|
||||||
typedef struct QCowSnapshot {
|
typedef struct QCowSnapshot {
|
||||||
uint64_t l1_table_offset;
|
uint64_t l1_table_offset;
|
||||||
uint32_t l1_size;
|
uint32_t l1_size;
|
||||||
@@ -191,8 +230,8 @@ typedef struct BDRVQcowState {
|
|||||||
uint64_t *refcount_table;
|
uint64_t *refcount_table;
|
||||||
uint64_t refcount_table_offset;
|
uint64_t refcount_table_offset;
|
||||||
uint32_t refcount_table_size;
|
uint32_t refcount_table_size;
|
||||||
int64_t free_cluster_index;
|
uint64_t free_cluster_index;
|
||||||
int64_t free_byte_offset;
|
uint64_t free_byte_offset;
|
||||||
|
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
|
|
||||||
@@ -202,7 +241,7 @@ typedef struct BDRVQcowState {
|
|||||||
AES_KEY aes_decrypt_key;
|
AES_KEY aes_decrypt_key;
|
||||||
uint64_t snapshots_offset;
|
uint64_t snapshots_offset;
|
||||||
int snapshots_size;
|
int snapshots_size;
|
||||||
int nb_snapshots;
|
unsigned int nb_snapshots;
|
||||||
QCowSnapshot *snapshots;
|
QCowSnapshot *snapshots;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
@@ -383,6 +422,11 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcowState *s)
|
|||||||
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
|
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t qcow2_max_refcount_clusters(BDRVQcowState *s)
|
||||||
|
{
|
||||||
|
return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int qcow2_get_cluster_type(uint64_t l2_entry)
|
static inline int qcow2_get_cluster_type(uint64_t l2_entry)
|
||||||
{
|
{
|
||||||
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
|
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
|
||||||
@@ -431,7 +475,7 @@ void qcow2_refcount_close(BlockDriverState *bs);
|
|||||||
int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
|
int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
|
||||||
int addend, enum qcow2_discard_type type);
|
int addend, enum qcow2_discard_type type);
|
||||||
|
|
||||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
|
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
|
||||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||||
int nb_clusters);
|
int nb_clusters);
|
||||||
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
||||||
|
|||||||
16
block/qed.c
16
block/qed.c
@@ -650,19 +650,21 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!qed_is_cluster_size_valid(cluster_size)) {
|
if (!qed_is_cluster_size_valid(cluster_size)) {
|
||||||
fprintf(stderr, "QED cluster size must be within range [%u, %u] and power of 2\n",
|
error_setg(errp, "QED cluster size must be within range [%u, %u] "
|
||||||
QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
|
"and power of 2",
|
||||||
|
QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (!qed_is_table_size_valid(table_size)) {
|
if (!qed_is_table_size_valid(table_size)) {
|
||||||
fprintf(stderr, "QED table size must be within range [%u, %u] and power of 2\n",
|
error_setg(errp, "QED table size must be within range [%u, %u] "
|
||||||
QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
|
"and power of 2",
|
||||||
|
QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
|
if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
|
||||||
fprintf(stderr, "QED image size must be a non-zero multiple of "
|
error_setg(errp, "QED image size must be a non-zero multiple of "
|
||||||
"cluster size and less than %" PRIu64 " bytes\n",
|
"cluster size and less than %" PRIu64 " bytes",
|
||||||
qed_max_image_size(cluster_size, table_size));
|
qed_max_image_size(cluster_size, table_size));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -753,7 +753,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
opts = qemu_opts_create(&quorum_runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&quorum_runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -828,7 +828,7 @@ close_exit:
|
|||||||
g_free(opened);
|
g_free(opened);
|
||||||
exit:
|
exit:
|
||||||
/* propagate error */
|
/* propagate error */
|
||||||
if (error_is_set(&local_err)) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
QDECREF(list);
|
QDECREF(list);
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename;
|
const char *filename = NULL;
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
@@ -446,6 +446,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
|
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
|
||||||
|
unlink(filename);
|
||||||
|
}
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,6 +390,9 @@ static void raw_close(BlockDriverState *bs)
|
|||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
CloseHandle(s->hfile);
|
CloseHandle(s->hfile);
|
||||||
|
if (bs->open_flags & BDRV_O_TEMPORARY) {
|
||||||
|
unlink(bs->filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
|
|||||||
@@ -1099,7 +1099,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rsp->result != SD_RES_SUCCESS) {
|
if (rsp->result != SD_RES_SUCCESS) {
|
||||||
error_report("cannot get vdi info, %s, %s %d %s",
|
error_report("cannot get vdi info, %s, %s %" PRIu32 " %s",
|
||||||
sd_strerror(rsp->result), filename, snapid, tag);
|
sd_strerror(rsp->result), filename, snapid, tag);
|
||||||
if (rsp->result == SD_RES_NO_VDI) {
|
if (rsp->result == SD_RES_NO_VDI) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
@@ -2316,8 +2316,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
|||||||
sn_tab[found].vm_state_size = inode.vm_state_size;
|
sn_tab[found].vm_state_size = inode.vm_state_size;
|
||||||
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
|
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
|
||||||
|
|
||||||
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
|
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str),
|
||||||
inode.snap_id);
|
"%" PRIu32, inode.snap_id);
|
||||||
pstrcpy(sn_tab[found].name,
|
pstrcpy(sn_tab[found].name,
|
||||||
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
|
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
|
||||||
inode.tag);
|
inode.tag);
|
||||||
|
|||||||
61
block/vdi.c
61
block/vdi.c
@@ -120,6 +120,11 @@ typedef unsigned char uuid_t[16];
|
|||||||
|
|
||||||
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
||||||
|
|
||||||
|
/* max blocks in image is (0xffffffff / 4) */
|
||||||
|
#define VDI_BLOCKS_IN_IMAGE_MAX 0x3fffffff
|
||||||
|
#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
|
||||||
|
(uint64_t)DEFAULT_CLUSTER_SIZE)
|
||||||
|
|
||||||
#if !defined(CONFIG_UUID)
|
#if !defined(CONFIG_UUID)
|
||||||
static inline void uuid_generate(uuid_t out)
|
static inline void uuid_generate(uuid_t out)
|
||||||
{
|
{
|
||||||
@@ -385,6 +390,14 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
vdi_header_print(&header);
|
vdi_header_print(&header);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (header.disk_size > VDI_DISK_SIZE_MAX) {
|
||||||
|
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
|
||||||
|
", max supported is 0x%" PRIx64 ")",
|
||||||
|
header.disk_size, VDI_DISK_SIZE_MAX);
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (header.disk_size % SECTOR_SIZE != 0) {
|
if (header.disk_size % SECTOR_SIZE != 0) {
|
||||||
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
|
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
|
||||||
We accept them but round the disk size to the next multiple of
|
We accept them but round the disk size to the next multiple of
|
||||||
@@ -395,34 +408,35 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (header.signature != VDI_SIGNATURE) {
|
if (header.signature != VDI_SIGNATURE) {
|
||||||
error_setg(errp, "Image not in VDI format (bad signature %08x)", header.signature);
|
error_setg(errp, "Image not in VDI format (bad signature %08" PRIx32
|
||||||
|
")", header.signature);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.version != VDI_VERSION_1_1) {
|
} else if (header.version != VDI_VERSION_1_1) {
|
||||||
error_setg(errp, "unsupported VDI image (version %u.%u)",
|
error_setg(errp, "unsupported VDI image (version %" PRIu32 ".%" PRIu32
|
||||||
header.version >> 16, header.version & 0xffff);
|
")", header.version >> 16, header.version & 0xffff);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
||||||
/* We only support block maps which start on a sector boundary. */
|
/* We only support block maps which start on a sector boundary. */
|
||||||
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
||||||
"0x%x)", header.offset_bmap);
|
"0x%" PRIx32 ")", header.offset_bmap);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
||||||
/* We only support data blocks which start on a sector boundary. */
|
/* We only support data blocks which start on a sector boundary. */
|
||||||
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%x)",
|
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%"
|
||||||
header.offset_data);
|
PRIx32 ")", header.offset_data);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.sector_size != SECTOR_SIZE) {
|
} else if (header.sector_size != SECTOR_SIZE) {
|
||||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
error_setg(errp, "unsupported VDI image (sector size %" PRIu32
|
||||||
header.sector_size, SECTOR_SIZE);
|
" is not %u)", header.sector_size, SECTOR_SIZE);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.block_size != 1 * MiB) {
|
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
||||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
error_setg(errp, "unsupported VDI image (block size %" PRIu32
|
||||||
header.block_size, 1 * MiB);
|
" is not %u)", header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.disk_size >
|
} else if (header.disk_size >
|
||||||
@@ -441,6 +455,12 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
error_setg(errp, "unsupported VDI image (non-NULL parent UUID)");
|
error_setg(errp, "unsupported VDI image (non-NULL parent UUID)");
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
} else if (header.blocks_in_image > VDI_BLOCKS_IN_IMAGE_MAX) {
|
||||||
|
error_setg(errp, "unsupported VDI image "
|
||||||
|
"(too many blocks %u, max is %u)",
|
||||||
|
header.blocks_in_image, VDI_BLOCKS_IN_IMAGE_MAX);
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->total_sectors = header.disk_size / SECTOR_SIZE;
|
bs->total_sectors = header.disk_size / SECTOR_SIZE;
|
||||||
@@ -689,11 +709,20 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
options++;
|
options++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bytes > VDI_DISK_SIZE_MAX) {
|
||||||
|
result = -ENOTSUP;
|
||||||
|
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
|
||||||
|
", max supported is 0x%" PRIx64 ")",
|
||||||
|
bytes, VDI_DISK_SIZE_MAX);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
fd = qemu_open(filename,
|
fd = qemu_open(filename,
|
||||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||||
0644);
|
0644);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return -errno;
|
result = -errno;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need enough blocks to store the given disk size,
|
/* We need enough blocks to store the given disk size,
|
||||||
@@ -727,6 +756,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
vdi_header_to_le(&header);
|
vdi_header_to_le(&header);
|
||||||
if (write(fd, &header, sizeof(header)) < 0) {
|
if (write(fd, &header, sizeof(header)) < 0) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bmap_size > 0) {
|
if (bmap_size > 0) {
|
||||||
@@ -740,6 +770,8 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
}
|
}
|
||||||
if (write(fd, bmap, bmap_size) < 0) {
|
if (write(fd, bmap, bmap_size) < 0) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
g_free(bmap);
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
g_free(bmap);
|
g_free(bmap);
|
||||||
}
|
}
|
||||||
@@ -747,13 +779,16 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
if (image_type == VDI_TYPE_STATIC) {
|
if (image_type == VDI_TYPE_STATIC) {
|
||||||
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (close(fd) < 0) {
|
close_and_exit:
|
||||||
|
if ((close(fd) < 0) && !result) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
block/vhdx.c
12
block/vhdx.c
@@ -780,12 +780,20 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
|||||||
le32_to_cpus(&s->logical_sector_size);
|
le32_to_cpus(&s->logical_sector_size);
|
||||||
le32_to_cpus(&s->physical_sector_size);
|
le32_to_cpus(&s->physical_sector_size);
|
||||||
|
|
||||||
if (s->logical_sector_size == 0 || s->params.block_size == 0) {
|
if (s->params.block_size < VHDX_BLOCK_SIZE_MIN ||
|
||||||
|
s->params.block_size > VHDX_BLOCK_SIZE_MAX) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* both block_size and sector_size are guaranteed powers of 2 */
|
/* only 2 supported sector sizes */
|
||||||
|
if (s->logical_sector_size != 512 && s->logical_sector_size != 4096) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Both block_size and sector_size are guaranteed powers of 2, below.
|
||||||
|
Due to range checks above, s->sectors_per_block can never be < 256 */
|
||||||
s->sectors_per_block = s->params.block_size / s->logical_sector_size;
|
s->sectors_per_block = s->params.block_size / s->logical_sector_size;
|
||||||
s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) *
|
s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) *
|
||||||
(uint64_t)s->logical_sector_size /
|
(uint64_t)s->logical_sector_size /
|
||||||
|
|||||||
23
block/vmdk.c
23
block/vmdk.c
@@ -262,7 +262,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
|
|||||||
p_name = strstr(desc, cid_str);
|
p_name = strstr(desc, cid_str);
|
||||||
if (p_name != NULL) {
|
if (p_name != NULL) {
|
||||||
p_name += cid_str_size;
|
p_name += cid_str_size;
|
||||||
sscanf(p_name, "%x", &cid);
|
sscanf(p_name, "%" SCNx32, &cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cid;
|
return cid;
|
||||||
@@ -290,7 +290,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
|||||||
p_name = strstr(desc, "CID");
|
p_name = strstr(desc, "CID");
|
||||||
if (p_name != NULL) {
|
if (p_name != NULL) {
|
||||||
p_name += sizeof("CID");
|
p_name += sizeof("CID");
|
||||||
snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
|
snprintf(p_name, sizeof(desc) - (p_name - desc), "%" PRIx32 "\n", cid);
|
||||||
pstrcat(desc, sizeof(desc), tmp_desc);
|
pstrcat(desc, sizeof(desc), tmp_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,7 +640,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
|
|
||||||
if (le32_to_cpu(header.version) > 3) {
|
if (le32_to_cpu(header.version) > 3) {
|
||||||
char buf[64];
|
char buf[64];
|
||||||
snprintf(buf, sizeof(buf), "VMDK version %d",
|
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
|
||||||
le32_to_cpu(header.version));
|
le32_to_cpu(header.version));
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
bs->device_name, "vmdk", buf);
|
bs->device_name, "vmdk", buf);
|
||||||
@@ -671,8 +671,9 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
if (bdrv_getlength(file) <
|
if (bdrv_getlength(file) <
|
||||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) {
|
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) {
|
||||||
error_setg(errp, "File truncated, expecting at least %lld bytes",
|
error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes",
|
||||||
le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE);
|
(int64_t)(le64_to_cpu(header.grain_offset)
|
||||||
|
* BDRV_SECTOR_SIZE));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1707,8 +1708,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
const char desc_template[] =
|
const char desc_template[] =
|
||||||
"# Disk DescriptorFile\n"
|
"# Disk DescriptorFile\n"
|
||||||
"version=1\n"
|
"version=1\n"
|
||||||
"CID=%x\n"
|
"CID=%" PRIx32 "\n"
|
||||||
"parentCID=%x\n"
|
"parentCID=%" PRIx32 "\n"
|
||||||
"createType=\"%s\"\n"
|
"createType=\"%s\"\n"
|
||||||
"%s"
|
"%s"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1720,7 +1721,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
"\n"
|
"\n"
|
||||||
"ddb.virtualHWVersion = \"%d\"\n"
|
"ddb.virtualHWVersion = \"%d\"\n"
|
||||||
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
|
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
|
||||||
"ddb.geometry.heads = \"%d\"\n"
|
"ddb.geometry.heads = \"%" PRIu32 "\"\n"
|
||||||
"ddb.geometry.sectors = \"63\"\n"
|
"ddb.geometry.sectors = \"63\"\n"
|
||||||
"ddb.adapterType = \"%s\"\n";
|
"ddb.adapterType = \"%s\"\n";
|
||||||
|
|
||||||
@@ -1780,9 +1781,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
strcmp(fmt, "twoGbMaxExtentFlat"));
|
strcmp(fmt, "twoGbMaxExtentFlat"));
|
||||||
compress = !strcmp(fmt, "streamOptimized");
|
compress = !strcmp(fmt, "streamOptimized");
|
||||||
if (flat) {
|
if (flat) {
|
||||||
desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
|
desc_extent_line = "RW %" PRId64 " FLAT \"%s\" 0\n";
|
||||||
} else {
|
} else {
|
||||||
desc_extent_line = "RW %lld SPARSE \"%s\"\n";
|
desc_extent_line = "RW %" PRId64 " SPARSE \"%s\"\n";
|
||||||
}
|
}
|
||||||
if (flat && backing_file) {
|
if (flat && backing_file) {
|
||||||
error_setg(errp, "Flat image can't have backing file");
|
error_setg(errp, "Flat image can't have backing file");
|
||||||
@@ -1850,7 +1851,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
}
|
}
|
||||||
/* generate descriptor file */
|
/* generate descriptor file */
|
||||||
desc = g_strdup_printf(desc_template,
|
desc = g_strdup_printf(desc_template,
|
||||||
(unsigned int)time(NULL),
|
(uint32_t)time(NULL),
|
||||||
parent_cid,
|
parent_cid,
|
||||||
fmt,
|
fmt,
|
||||||
parent_desc_line,
|
parent_desc_line,
|
||||||
|
|||||||
32
block/vpc.c
32
block/vpc.c
@@ -45,6 +45,8 @@ enum vhd_type {
|
|||||||
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
||||||
#define VHD_TIMESTAMP_BASE 946684800
|
#define VHD_TIMESTAMP_BASE 946684800
|
||||||
|
|
||||||
|
#define VHD_MAX_SECTORS (65535LL * 255 * 255)
|
||||||
|
|
||||||
// always big-endian
|
// always big-endian
|
||||||
typedef struct vhd_footer {
|
typedef struct vhd_footer {
|
||||||
char creator[8]; // "conectix"
|
char creator[8]; // "conectix"
|
||||||
@@ -164,6 +166,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
VHDDynDiskHeader *dyndisk_header;
|
VHDDynDiskHeader *dyndisk_header;
|
||||||
uint8_t buf[HEADER_SIZE];
|
uint8_t buf[HEADER_SIZE];
|
||||||
uint32_t checksum;
|
uint32_t checksum;
|
||||||
|
uint64_t computed_size;
|
||||||
int disk_type = VHD_DYNAMIC;
|
int disk_type = VHD_DYNAMIC;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -222,7 +225,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allow a maximum disk size of approximately 2 TB */
|
/* Allow a maximum disk size of approximately 2 TB */
|
||||||
if (bs->total_sectors >= 65535LL * 255 * 255) {
|
if (bs->total_sectors >= VHD_MAX_SECTORS) {
|
||||||
ret = -EFBIG;
|
ret = -EFBIG;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -242,10 +245,31 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->block_size = be32_to_cpu(dyndisk_header->block_size);
|
s->block_size = be32_to_cpu(dyndisk_header->block_size);
|
||||||
|
if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) {
|
||||||
|
error_setg(errp, "Invalid block size %" PRIu32, s->block_size);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
|
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
|
||||||
|
|
||||||
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
||||||
s->pagetable = g_malloc(s->max_table_entries * 4);
|
|
||||||
|
if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
computed_size = (uint64_t) s->max_table_entries * s->block_size;
|
||||||
|
if (computed_size < bs->total_sectors * 512) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->pagetable = qemu_blockalign(bs, s->max_table_entries * 4);
|
||||||
|
|
||||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||||
|
|
||||||
@@ -298,7 +322,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
g_free(s->pagetable);
|
qemu_vfree(s->pagetable);
|
||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
g_free(s->pageentry_u8);
|
g_free(s->pageentry_u8);
|
||||||
#endif
|
#endif
|
||||||
@@ -833,7 +857,7 @@ static int vpc_has_zero_init(BlockDriverState *bs)
|
|||||||
static void vpc_close(BlockDriverState *bs)
|
static void vpc_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVVPCState *s = bs->opaque;
|
BDRVVPCState *s = bs->opaque;
|
||||||
g_free(s->pagetable);
|
qemu_vfree(s->pagetable);
|
||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
g_free(s->pageentry_u8);
|
g_free(s->pageentry_u8);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1119,6 +1119,7 @@ DLOG(if (stderr == NULL) {
|
|||||||
if (!s->fat_type) {
|
if (!s->fat_type) {
|
||||||
s->fat_type = 16;
|
s->fat_type = 16;
|
||||||
}
|
}
|
||||||
|
s->first_sectors_number = 0x40;
|
||||||
cyls = s->fat_type == 12 ? 64 : 1024;
|
cyls = s->fat_type == 12 ? 64 : 1024;
|
||||||
heads = 16;
|
heads = 16;
|
||||||
secs = 63;
|
secs = 63;
|
||||||
@@ -1146,7 +1147,6 @@ DLOG(if (stderr == NULL) {
|
|||||||
|
|
||||||
s->current_cluster=0xffffffff;
|
s->current_cluster=0xffffffff;
|
||||||
|
|
||||||
s->first_sectors_number=0x40;
|
|
||||||
/* read only is the default for safety */
|
/* read only is the default for safety */
|
||||||
bs->read_only = 1;
|
bs->read_only = 1;
|
||||||
s->qcow = s->write_target = NULL;
|
s->qcow = s->write_target = NULL;
|
||||||
@@ -2947,7 +2947,7 @@ static int enable_write_target(BDRVVVFATState *s)
|
|||||||
unlink(s->qcow_filename);
|
unlink(s->qcow_filename);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s->bs->backing_hd = bdrv_new("");
|
s->bs->backing_hd = bdrv_new("", &error_abort);
|
||||||
s->bs->backing_hd->drv = &vvfat_write_target;
|
s->bs->backing_hd->drv = &vvfat_write_target;
|
||||||
s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
|
s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
|
||||||
*(void**)s->bs->backing_hd->opaque = s;
|
*(void**)s->bs->backing_hd->opaque = s;
|
||||||
|
|||||||
35
blockdev.c
35
blockdev.c
@@ -452,16 +452,14 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_find_node(qemu_opts_id(opts))) {
|
|
||||||
error_setg(errp, "device id=%s is conflicting with a node-name",
|
|
||||||
qemu_opts_id(opts));
|
|
||||||
goto early_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
dinfo = g_malloc0(sizeof(*dinfo));
|
dinfo = g_malloc0(sizeof(*dinfo));
|
||||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||||
dinfo->bdrv = bdrv_new(dinfo->id);
|
dinfo->bdrv = bdrv_new(dinfo->id, &error);
|
||||||
|
if (error) {
|
||||||
|
error_propagate(errp, error);
|
||||||
|
goto bdrv_new_err;
|
||||||
|
}
|
||||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||||
dinfo->bdrv->read_only = ro;
|
dinfo->bdrv->read_only = ro;
|
||||||
dinfo->refcount = 1;
|
dinfo->refcount = 1;
|
||||||
@@ -523,8 +521,9 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
bdrv_unref(dinfo->bdrv);
|
bdrv_unref(dinfo->bdrv);
|
||||||
g_free(dinfo->id);
|
|
||||||
QTAILQ_REMOVE(&drives, dinfo, next);
|
QTAILQ_REMOVE(&drives, dinfo, next);
|
||||||
|
bdrv_new_err:
|
||||||
|
g_free(dinfo->id);
|
||||||
g_free(dinfo);
|
g_free(dinfo);
|
||||||
early_err:
|
early_err:
|
||||||
QDECREF(bs_opts);
|
QDECREF(bs_opts);
|
||||||
@@ -1116,6 +1115,7 @@ typedef struct InternalSnapshotState {
|
|||||||
static void internal_snapshot_prepare(BlkTransactionState *common,
|
static void internal_snapshot_prepare(BlkTransactionState *common,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
const char *device;
|
const char *device;
|
||||||
const char *name;
|
const char *name;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
@@ -1164,8 +1164,10 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check whether a snapshot with name exist */
|
/* check whether a snapshot with name exist */
|
||||||
ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &old_sn, errp);
|
ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &old_sn,
|
||||||
if (error_is_set(errp)) {
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
} else if (ret) {
|
} else if (ret) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
@@ -1521,14 +1523,16 @@ static void eject_device(BlockDriverState *bs, int force, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!bdrv_dev_has_removable_media(bs)) {
|
if (!bdrv_dev_has_removable_media(bs)) {
|
||||||
error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
|
error_setg(errp, "Device '%s' is not removable",
|
||||||
|
bdrv_get_device_name(bs));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
|
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
|
||||||
bdrv_dev_eject_request(bs, force);
|
bdrv_dev_eject_request(bs, force);
|
||||||
if (!force) {
|
if (!force) {
|
||||||
error_set(errp, QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
|
error_setg(errp, "Device '%s' is locked",
|
||||||
|
bdrv_get_device_name(bs));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1876,6 +1880,10 @@ void qmp_block_commit(const char *device,
|
|||||||
*/
|
*/
|
||||||
BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT;
|
BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||||
|
|
||||||
|
if (!has_speed) {
|
||||||
|
speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* drain all i/o before commits */
|
/* drain all i/o before commits */
|
||||||
bdrv_drain_all();
|
bdrv_drain_all();
|
||||||
|
|
||||||
@@ -2216,7 +2224,8 @@ void qmp_block_job_cancel(const char *device,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (job->paused && !force) {
|
if (job->paused && !force) {
|
||||||
error_set(errp, QERR_BLOCK_JOB_PAUSED, device);
|
error_setg(errp, "The block job for device '%s' is currently paused",
|
||||||
|
device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
|||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
if (!job->driver->set_speed) {
|
if (!job->driver->set_speed) {
|
||||||
error_set(errp, QERR_NOT_SUPPORTED);
|
error_set(errp, QERR_UNSUPPORTED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
job->driver->set_speed(job, speed, &local_err);
|
job->driver->set_speed(job, speed, &local_err);
|
||||||
|
|||||||
20
configure
vendored
20
configure
vendored
@@ -1087,7 +1087,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-quorum) quorum="yes"
|
--enable-quorum) quorum="yes"
|
||||||
;;
|
;;
|
||||||
*) echo "ERROR: unknown option $opt"; show_help="yes"
|
*)
|
||||||
|
echo "ERROR: unknown option $opt"
|
||||||
|
echo "Try '$0 --help' for more information"
|
||||||
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -1217,8 +1220,8 @@ Advanced options (experts only):
|
|||||||
--enable-modules enable modules support
|
--enable-modules enable modules support
|
||||||
--enable-debug-tcg enable TCG debugging
|
--enable-debug-tcg enable TCG debugging
|
||||||
--disable-debug-tcg disable TCG debugging (default)
|
--disable-debug-tcg disable TCG debugging (default)
|
||||||
--enable-debug-info enable debugging information (default)
|
--enable-debug-info enable debugging information (default)
|
||||||
--disable-debug-info disable debugging information
|
--disable-debug-info disable debugging information
|
||||||
--enable-debug enable common debug build options
|
--enable-debug enable common debug build options
|
||||||
--enable-sparse enable sparse checker
|
--enable-sparse enable sparse checker
|
||||||
--disable-sparse disable sparse checker (default)
|
--disable-sparse disable sparse checker (default)
|
||||||
@@ -1230,6 +1233,7 @@ Advanced options (experts only):
|
|||||||
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
||||||
--disable-gtk disable gtk UI
|
--disable-gtk disable gtk UI
|
||||||
--enable-gtk enable gtk UI
|
--enable-gtk enable gtk UI
|
||||||
|
--with-gtkabi select preferred GTK ABI 2.0 or 3.0
|
||||||
--disable-virtfs disable VirtFS
|
--disable-virtfs disable VirtFS
|
||||||
--enable-virtfs enable VirtFS
|
--enable-virtfs enable VirtFS
|
||||||
--disable-vnc disable VNC
|
--disable-vnc disable VNC
|
||||||
@@ -1353,7 +1357,7 @@ Advanced options (experts only):
|
|||||||
|
|
||||||
NOTE: The object files are built at the place where configure is launched
|
NOTE: The object files are built at the place where configure is launched
|
||||||
EOF
|
EOF
|
||||||
exit 1
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Now we have handled --enable-tcg-interpreter and know we're not just
|
# Now we have handled --enable-tcg-interpreter and know we're not just
|
||||||
@@ -1448,7 +1452,10 @@ done
|
|||||||
if test "$stack_protector" != "no" ; then
|
if test "$stack_protector" != "no" ; then
|
||||||
gcc_flags="-fstack-protector-strong -fstack-protector-all"
|
gcc_flags="-fstack-protector-strong -fstack-protector-all"
|
||||||
for flag in $gcc_flags; do
|
for flag in $gcc_flags; do
|
||||||
if compile_prog "-Werror $flag" "" ; then
|
# We need to check both a compile and a link, since some compiler
|
||||||
|
# setups fail only on a .c->.o compile and some only at link time
|
||||||
|
if do_cc $QEMU_CFLAGS -Werror $flag -c -o $TMPO $TMPC &&
|
||||||
|
compile_prog "-Werror $flag" ""; then
|
||||||
QEMU_CFLAGS="$QEMU_CFLAGS $flag"
|
QEMU_CFLAGS="$QEMU_CFLAGS $flag"
|
||||||
LIBTOOLFLAGS="$LIBTOOLFLAGS -Wc,$flag"
|
LIBTOOLFLAGS="$LIBTOOLFLAGS -Wc,$flag"
|
||||||
break
|
break
|
||||||
@@ -4092,7 +4099,6 @@ echo "sparse enabled $sparse"
|
|||||||
echo "strip binaries $strip_opt"
|
echo "strip binaries $strip_opt"
|
||||||
echo "profiler $profiler"
|
echo "profiler $profiler"
|
||||||
echo "static build $static"
|
echo "static build $static"
|
||||||
echo "-Werror enabled $werror"
|
|
||||||
if test "$darwin" = "yes" ; then
|
if test "$darwin" = "yes" ; then
|
||||||
echo "Cocoa support $cocoa"
|
echo "Cocoa support $cocoa"
|
||||||
fi
|
fi
|
||||||
@@ -4344,6 +4350,7 @@ if test "$modules" = "yes"; then
|
|||||||
fi
|
fi
|
||||||
if test "$sdl" = "yes" ; then
|
if test "$sdl" = "yes" ; then
|
||||||
echo "CONFIG_SDL=y" >> $config_host_mak
|
echo "CONFIG_SDL=y" >> $config_host_mak
|
||||||
|
echo "CONFIG_SDLABI=$sdlabi" >> $config_host_mak
|
||||||
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
|
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$cocoa" = "yes" ; then
|
if test "$cocoa" = "yes" ; then
|
||||||
@@ -4427,6 +4434,7 @@ fi
|
|||||||
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
||||||
if test "$gtk" = "yes" ; then
|
if test "$gtk" = "yes" ; then
|
||||||
echo "CONFIG_GTK=y" >> $config_host_mak
|
echo "CONFIG_GTK=y" >> $config_host_mak
|
||||||
|
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
|
||||||
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$vte" = "yes" ; then
|
if test "$vte" = "yes" ; then
|
||||||
|
|||||||
@@ -227,6 +227,8 @@ int cpu_exec(CPUArchState *env)
|
|||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
uint8_t *tc_ptr;
|
uint8_t *tc_ptr;
|
||||||
uintptr_t next_tb;
|
uintptr_t next_tb;
|
||||||
|
/* This must be volatile so it is not trashed by longjmp() */
|
||||||
|
volatile bool have_tb_lock = false;
|
||||||
|
|
||||||
if (cpu->halted) {
|
if (cpu->halted) {
|
||||||
if (!cpu_has_work(cpu)) {
|
if (!cpu_has_work(cpu)) {
|
||||||
@@ -600,6 +602,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
|
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
|
||||||
|
have_tb_lock = true;
|
||||||
tb = tb_find_fast(env);
|
tb = tb_find_fast(env);
|
||||||
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
||||||
doing it in tb_find_slow */
|
doing it in tb_find_slow */
|
||||||
@@ -621,6 +624,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
|
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
|
||||||
next_tb & TB_EXIT_MASK, tb);
|
next_tb & TB_EXIT_MASK, tb);
|
||||||
}
|
}
|
||||||
|
have_tb_lock = false;
|
||||||
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
||||||
|
|
||||||
/* cpu_interrupt might be called while translating the
|
/* cpu_interrupt might be called while translating the
|
||||||
@@ -692,6 +696,10 @@ int cpu_exec(CPUArchState *env)
|
|||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
x86_cpu = X86_CPU(cpu);
|
x86_cpu = X86_CPU(cpu);
|
||||||
#endif
|
#endif
|
||||||
|
if (have_tb_lock) {
|
||||||
|
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
||||||
|
have_tb_lock = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} /* for(;;) */
|
} /* for(;;) */
|
||||||
|
|
||||||
|
|||||||
2
cpus.c
2
cpus.c
@@ -1454,7 +1454,7 @@ void qmp_pmemsave(int64_t addr, int64_t size, const char *filename,
|
|||||||
l = sizeof(buf);
|
l = sizeof(buf);
|
||||||
if (l > size)
|
if (l > size)
|
||||||
l = size;
|
l = size;
|
||||||
cpu_physical_memory_rw(addr, buf, l, 0);
|
cpu_physical_memory_read(addr, buf, l);
|
||||||
if (fwrite(buf, 1, l, f) != l) {
|
if (fwrite(buf, 1, l, f) != l) {
|
||||||
error_set(errp, QERR_IO_ERROR);
|
error_set(errp, QERR_IO_ERROR);
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
CONFIG_USB_TABLET_WACOM=y
|
CONFIG_USB_TABLET_WACOM=y
|
||||||
CONFIG_USB_STORAGE_BOT=y
|
CONFIG_USB_STORAGE_BOT=y
|
||||||
CONFIG_USB_STORAGE_UAS=y
|
CONFIG_USB_STORAGE_UAS=y
|
||||||
|
CONFIG_USB_STORAGE_MTP=y
|
||||||
CONFIG_USB_SMARTCARD=y
|
CONFIG_USB_SMARTCARD=y
|
||||||
CONFIG_USB_AUDIO=y
|
CONFIG_USB_AUDIO=y
|
||||||
CONFIG_USB_SERIAL=y
|
CONFIG_USB_SERIAL=y
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ BlockDriverAIOCB *dma_bdrv_io(
|
|||||||
dbs->sg_cur_index = 0;
|
dbs->sg_cur_index = 0;
|
||||||
dbs->sg_cur_byte = 0;
|
dbs->sg_cur_byte = 0;
|
||||||
dbs->dir = dir;
|
dbs->dir = dir;
|
||||||
|
dbs->in_cancel = false;
|
||||||
dbs->io_func = io_func;
|
dbs->io_func = io_func;
|
||||||
dbs->bh = NULL;
|
dbs->bh = NULL;
|
||||||
qemu_iovec_init(&dbs->iov, sg->nsg);
|
qemu_iovec_init(&dbs->iov, sg->nsg);
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ QEMU Standard VGA
|
|||||||
Exists in two variants, for isa and pci.
|
Exists in two variants, for isa and pci.
|
||||||
|
|
||||||
command line switches:
|
command line switches:
|
||||||
-vga std [ picks isa for -M isapc, otherwise pci ]
|
-vga std [ picks isa for -M isapc, otherwise pci ]
|
||||||
-device VGA [ pci variant ]
|
-device VGA [ pci variant ]
|
||||||
-device isa-vga [ isa variant ]
|
-device isa-vga [ isa variant ]
|
||||||
|
-device secondary-vga [ legacy-free pci variant ]
|
||||||
|
|
||||||
|
|
||||||
PCI spec
|
PCI spec
|
||||||
@@ -31,9 +32,15 @@ PCI ROM Region:
|
|||||||
Holds the vgabios (qemu 0.14+).
|
Holds the vgabios (qemu 0.14+).
|
||||||
|
|
||||||
|
|
||||||
|
The legacy-free variant has no ROM and has PCI_CLASS_DISPLAY_OTHER
|
||||||
|
instead of PCI_CLASS_DISPLAY_VGA.
|
||||||
|
|
||||||
|
|
||||||
IO ports used
|
IO ports used
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
Doesn't apply to the legacy-free pci variant, use the MMIO bar instead.
|
||||||
|
|
||||||
03c0 - 03df : standard vga ports
|
03c0 - 03df : standard vga ports
|
||||||
01ce : bochs vbe interface index port
|
01ce : bochs vbe interface index port
|
||||||
01cf : bochs vbe interface data port (x86 only)
|
01cf : bochs vbe interface data port (x86 only)
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ void hmp_hello_world(Monitor *mon, const QDict *qdict)
|
|||||||
Error *errp = NULL;
|
Error *errp = NULL;
|
||||||
|
|
||||||
qmp_hello_world(!!message, message, &errp);
|
qmp_hello_world(!!message, message, &errp);
|
||||||
if (error_is_set(&errp)) {
|
if (errp) {
|
||||||
monitor_printf(mon, "%s\n", error_get_pretty(errp));
|
monitor_printf(mon, "%s\n", error_get_pretty(errp));
|
||||||
error_free(errp);
|
error_free(errp);
|
||||||
return;
|
return;
|
||||||
@@ -483,7 +483,7 @@ void hmp_info_alarm_clock(Monitor *mon)
|
|||||||
Error *errp = NULL;
|
Error *errp = NULL;
|
||||||
|
|
||||||
clock = qmp_query_alarm_clock(&errp);
|
clock = qmp_query_alarm_clock(&errp);
|
||||||
if (error_is_set(&errp)) {
|
if (errp) {
|
||||||
monitor_printf(mon, "Could not query alarm clock information\n");
|
monitor_printf(mon, "Could not query alarm clock information\n");
|
||||||
error_free(errp);
|
error_free(errp);
|
||||||
return;
|
return;
|
||||||
@@ -634,7 +634,7 @@ void hmp_info_alarm_methods(Monitor *mon)
|
|||||||
Error *errp = NULL;
|
Error *errp = NULL;
|
||||||
|
|
||||||
method_list = qmp_query_alarm_methods(&errp);
|
method_list = qmp_query_alarm_methods(&errp);
|
||||||
if (error_is_set(&errp)) {
|
if (errp) {
|
||||||
monitor_printf(mon, "Could not query alarm methods\n");
|
monitor_printf(mon, "Could not query alarm methods\n");
|
||||||
error_free(errp);
|
error_free(errp);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1626,6 +1626,26 @@ uint64 float32_to_uint64(float32 a STATUS_PARAM)
|
|||||||
return roundAndPackUint64(aSign, aSig64, aSigExtra STATUS_VAR);
|
return roundAndPackUint64(aSign, aSig64, aSigExtra STATUS_VAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
| Returns the result of converting the single-precision floating-point value
|
||||||
|
| `a' to the 64-bit unsigned integer format. The conversion is
|
||||||
|
| performed according to the IEC/IEEE Standard for Binary Floating-Point
|
||||||
|
| Arithmetic, except that the conversion is always rounded toward zero. If
|
||||||
|
| `a' is a NaN, the largest unsigned integer is returned. Otherwise, if the
|
||||||
|
| conversion overflows, the largest unsigned integer is returned. If the
|
||||||
|
| 'a' is negative, the result is rounded and zero is returned; values that do
|
||||||
|
| not round to zero will raise the inexact flag.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint64 float32_to_uint64_round_to_zero(float32 a STATUS_PARAM)
|
||||||
|
{
|
||||||
|
signed char current_rounding_mode = STATUS(float_rounding_mode);
|
||||||
|
set_float_rounding_mode(float_round_to_zero STATUS_VAR);
|
||||||
|
int64_t v = float32_to_uint64(a STATUS_VAR);
|
||||||
|
set_float_rounding_mode(current_rounding_mode STATUS_VAR);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
| Returns the result of converting the single-precision floating-point value
|
| Returns the result of converting the single-precision floating-point value
|
||||||
| `a' to the 64-bit two's complement integer format. The conversion is
|
| `a' to the 64-bit two's complement integer format. The conversion is
|
||||||
|
|||||||
@@ -760,6 +760,7 @@ static int proxy_socket(const char *path, uid_t uid, gid_t gid)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size = sizeof(qemu);
|
||||||
client = accept(sock, (struct sockaddr *)&qemu, &size);
|
client = accept(sock, (struct sockaddr *)&qemu, &size);
|
||||||
if (client < 0) {
|
if (client < 0) {
|
||||||
do_perror("accept");
|
do_perror("accept");
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ ETEXI
|
|||||||
|
|
||||||
{
|
{
|
||||||
.name = "drive_del",
|
.name = "drive_del",
|
||||||
.args_type = "id:s",
|
.args_type = "id:B",
|
||||||
.params = "device",
|
.params = "device",
|
||||||
.help = "remove host block device",
|
.help = "remove host block device",
|
||||||
.user_print = monitor_user_noop,
|
.user_print = monitor_user_noop,
|
||||||
@@ -658,6 +658,7 @@ ETEXI
|
|||||||
.help = "add device, like -device on the command line",
|
.help = "add device, like -device on the command line",
|
||||||
.user_print = monitor_user_noop,
|
.user_print = monitor_user_noop,
|
||||||
.mhandler.cmd_new = do_device_add,
|
.mhandler.cmd_new = do_device_add,
|
||||||
|
.command_completion = device_add_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -673,6 +674,7 @@ ETEXI
|
|||||||
.params = "device",
|
.params = "device",
|
||||||
.help = "remove device",
|
.help = "remove device",
|
||||||
.mhandler.cmd = hmp_device_del,
|
.mhandler.cmd = hmp_device_del,
|
||||||
|
.command_completion = device_del_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -998,26 +1000,34 @@ ETEXI
|
|||||||
|
|
||||||
{
|
{
|
||||||
.name = "dump-guest-memory",
|
.name = "dump-guest-memory",
|
||||||
.args_type = "paging:-p,filename:F,begin:i?,length:i?",
|
.args_type = "paging:-p,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?",
|
||||||
.params = "[-p] filename [begin] [length]",
|
.params = "[-p] [-z|-l|-s] filename [begin length]",
|
||||||
.help = "dump guest memory to file"
|
.help = "dump guest memory into file 'filename'.\n\t\t\t"
|
||||||
"\n\t\t\t begin(optional): the starting physical address"
|
"-p: do paging to get guest's memory mapping.\n\t\t\t"
|
||||||
"\n\t\t\t length(optional): the memory size, in bytes",
|
"-z: dump in kdump-compressed format, with zlib compression.\n\t\t\t"
|
||||||
|
"-l: dump in kdump-compressed format, with lzo compression.\n\t\t\t"
|
||||||
|
"-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t"
|
||||||
|
"begin: the starting physical address.\n\t\t\t"
|
||||||
|
"length: the memory size, in bytes.",
|
||||||
.mhandler.cmd = hmp_dump_guest_memory,
|
.mhandler.cmd = hmp_dump_guest_memory,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@item dump-guest-memory [-p] @var{protocol} @var{begin} @var{length}
|
@item dump-guest-memory [-p] @var{filename} @var{begin} @var{length}
|
||||||
|
@item dump-guest-memory [-z|-l|-s] @var{filename}
|
||||||
@findex dump-guest-memory
|
@findex dump-guest-memory
|
||||||
Dump guest memory to @var{protocol}. The file can be processed with crash or
|
Dump guest memory to @var{protocol}. The file can be processed with crash or
|
||||||
gdb.
|
gdb. Without -z|-l|-s, the dump format is ELF.
|
||||||
filename: dump file name
|
-p: do paging to get guest's memory mapping.
|
||||||
paging: do paging to get guest's memory mapping
|
-z: dump in kdump-compressed format, with zlib compression.
|
||||||
|
-l: dump in kdump-compressed format, with lzo compression.
|
||||||
|
-s: dump in kdump-compressed format, with snappy compression.
|
||||||
|
filename: dump file name.
|
||||||
begin: the starting physical address. It's optional, and should be
|
begin: the starting physical address. It's optional, and should be
|
||||||
specified with length together.
|
specified together with length.
|
||||||
length: the memory size, in bytes. It's optional, and should be specified
|
length: the memory size, in bytes. It's optional, and should be specified
|
||||||
with begin together.
|
together with begin.
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1254,6 +1264,7 @@ ETEXI
|
|||||||
.params = "[qom-type=]type,id=str[,prop=value][,...]",
|
.params = "[qom-type=]type,id=str[,prop=value][,...]",
|
||||||
.help = "create QOM object",
|
.help = "create QOM object",
|
||||||
.mhandler.cmd = hmp_object_add,
|
.mhandler.cmd = hmp_object_add,
|
||||||
|
.command_completion = object_add_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -1268,6 +1279,7 @@ ETEXI
|
|||||||
.params = "id",
|
.params = "id",
|
||||||
.help = "destroy QOM object",
|
.help = "destroy QOM object",
|
||||||
.mhandler.cmd = hmp_object_del,
|
.mhandler.cmd = hmp_object_del,
|
||||||
|
.command_completion = object_del_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
|
|||||||
25
hmp.c
25
hmp.c
@@ -1308,16 +1308,35 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
|||||||
{
|
{
|
||||||
Error *errp = NULL;
|
Error *errp = NULL;
|
||||||
int paging = qdict_get_try_bool(qdict, "paging", 0);
|
int paging = qdict_get_try_bool(qdict, "paging", 0);
|
||||||
|
int zlib = qdict_get_try_bool(qdict, "zlib", 0);
|
||||||
|
int lzo = qdict_get_try_bool(qdict, "lzo", 0);
|
||||||
|
int snappy = qdict_get_try_bool(qdict, "snappy", 0);
|
||||||
const char *file = qdict_get_str(qdict, "filename");
|
const char *file = qdict_get_str(qdict, "filename");
|
||||||
bool has_begin = qdict_haskey(qdict, "begin");
|
bool has_begin = qdict_haskey(qdict, "begin");
|
||||||
bool has_length = qdict_haskey(qdict, "length");
|
bool has_length = qdict_haskey(qdict, "length");
|
||||||
/* kdump-compressed format is not supported for HMP */
|
|
||||||
bool has_format = false;
|
|
||||||
int64_t begin = 0;
|
int64_t begin = 0;
|
||||||
int64_t length = 0;
|
int64_t length = 0;
|
||||||
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
||||||
char *prot;
|
char *prot;
|
||||||
|
|
||||||
|
if (zlib + lzo + snappy > 1) {
|
||||||
|
error_setg(&errp, "only one of '-z|-l|-s' can be set");
|
||||||
|
hmp_handle_error(mon, &errp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zlib) {
|
||||||
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lzo) {
|
||||||
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snappy) {
|
||||||
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
|
||||||
|
}
|
||||||
|
|
||||||
if (has_begin) {
|
if (has_begin) {
|
||||||
begin = qdict_get_int(qdict, "begin");
|
begin = qdict_get_int(qdict, "begin");
|
||||||
}
|
}
|
||||||
@@ -1328,7 +1347,7 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
|||||||
prot = g_strconcat("file:", file, NULL);
|
prot = g_strconcat("file:", file, NULL);
|
||||||
|
|
||||||
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
||||||
has_format, dump_format, &errp);
|
true, dump_format, &errp);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &errp);
|
||||||
g_free(prot);
|
g_free(prot);
|
||||||
}
|
}
|
||||||
|
|||||||
5
hmp.h
5
hmp.h
@@ -15,6 +15,7 @@
|
|||||||
#define HMP_H
|
#define HMP_H
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
|
#include "qemu/readline.h"
|
||||||
#include "qapi-types.h"
|
#include "qapi-types.h"
|
||||||
#include "qapi/qmp/qdict.h"
|
#include "qapi/qmp/qdict.h"
|
||||||
|
|
||||||
@@ -92,5 +93,9 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict);
|
|||||||
void hmp_cpu_add(Monitor *mon, const QDict *qdict);
|
void hmp_cpu_add(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_object_add(Monitor *mon, const QDict *qdict);
|
void hmp_object_add(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
void hmp_object_del(Monitor *mon, const QDict *qdict);
|
||||||
|
void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -987,8 +987,9 @@ static void v9fs_attach(void *opaque)
|
|||||||
*/
|
*/
|
||||||
if (!s->migration_blocker) {
|
if (!s->migration_blocker) {
|
||||||
s->root_fid = fid;
|
s->root_fid = fid;
|
||||||
error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
|
error_setg(&s->migration_blocker,
|
||||||
s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
|
"Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
|
||||||
|
s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
|
||||||
migrate_add_blocker(s->migration_blocker);
|
migrate_add_blocker(s->migration_blocker);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
|||||||
@@ -43,6 +43,19 @@ static void cubieboard_init(QEMUMachineInitArgs *args)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_property_set_int(OBJECT(&s->a10->timer), 32768, "clk0-freq", &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_report("Couldn't set clk0 frequency: %s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
object_property_set_int(OBJECT(&s->a10->timer), 24000000, "clk1-freq",
|
||||||
|
&err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_report("Couldn't set clk1 frequency: %s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
|
object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_report("Couldn't realize Allwinner A10: %s",
|
error_report("Couldn't realize Allwinner A10: %s",
|
||||||
|
|||||||
@@ -230,18 +230,23 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
|||||||
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
for (n = 0; n < smp_cpus; n++) {
|
||||||
ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||||
|
Object *cpuobj;
|
||||||
ARMCPU *cpu;
|
ARMCPU *cpu;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
|
if (!oc) {
|
||||||
|
error_report("Unable to find CPU definition");
|
||||||
object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar",
|
|
||||||
&err);
|
|
||||||
if (err) {
|
|
||||||
error_report("%s", error_get_pretty(err));
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", &err);
|
|
||||||
|
cpuobj = object_new(object_class_get_name(oc));
|
||||||
|
cpu = ARM_CPU(cpuobj);
|
||||||
|
|
||||||
|
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||||
|
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
|
||||||
|
"reset-cbar", &error_abort);
|
||||||
|
}
|
||||||
|
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_report("%s", error_get_pretty(err));
|
error_report("%s", error_get_pretty(err));
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
@@ -192,10 +192,9 @@ 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;
|
||||||
|
|
||||||
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||||
if (err) {
|
object_property_set_int(cpuobj, periphbase,
|
||||||
error_report("%s", error_get_pretty(err));
|
"reset-cbar", &error_abort);
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@@ -75,8 +75,6 @@ typedef struct MemMapEntry {
|
|||||||
typedef struct VirtBoardInfo {
|
typedef struct VirtBoardInfo {
|
||||||
struct arm_boot_info bootinfo;
|
struct arm_boot_info bootinfo;
|
||||||
const char *cpu_model;
|
const char *cpu_model;
|
||||||
const char *qdevname;
|
|
||||||
const char *gic_compatible;
|
|
||||||
const MemMapEntry *memmap;
|
const MemMapEntry *memmap;
|
||||||
const int *irqmap;
|
const int *irqmap;
|
||||||
int smp_cpus;
|
int smp_cpus;
|
||||||
@@ -98,10 +96,10 @@ typedef struct VirtBoardInfo {
|
|||||||
static const MemMapEntry a15memmap[] = {
|
static const MemMapEntry a15memmap[] = {
|
||||||
/* Space up to 0x8000000 is reserved for a boot ROM */
|
/* Space up to 0x8000000 is reserved for a boot ROM */
|
||||||
[VIRT_FLASH] = { 0, 0x8000000 },
|
[VIRT_FLASH] = { 0, 0x8000000 },
|
||||||
[VIRT_CPUPERIPHS] = { 0x8000000, 0x8000 },
|
[VIRT_CPUPERIPHS] = { 0x8000000, 0x20000 },
|
||||||
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
||||||
[VIRT_GIC_DIST] = { 0x8001000, 0x1000 },
|
[VIRT_GIC_DIST] = { 0x8000000, 0x10000 },
|
||||||
[VIRT_GIC_CPU] = { 0x8002000, 0x1000 },
|
[VIRT_GIC_CPU] = { 0x8010000, 0x10000 },
|
||||||
[VIRT_UART] = { 0x9000000, 0x1000 },
|
[VIRT_UART] = { 0x9000000, 0x1000 },
|
||||||
[VIRT_MMIO] = { 0xa000000, 0x200 },
|
[VIRT_MMIO] = { 0xa000000, 0x200 },
|
||||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||||
@@ -117,16 +115,16 @@ static const int a15irqmap[] = {
|
|||||||
static VirtBoardInfo machines[] = {
|
static VirtBoardInfo machines[] = {
|
||||||
{
|
{
|
||||||
.cpu_model = "cortex-a15",
|
.cpu_model = "cortex-a15",
|
||||||
.qdevname = "a15mpcore_priv",
|
.memmap = a15memmap,
|
||||||
.gic_compatible = "arm,cortex-a15-gic",
|
.irqmap = a15irqmap,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cpu_model = "cortex-a57",
|
||||||
.memmap = a15memmap,
|
.memmap = a15memmap,
|
||||||
.irqmap = a15irqmap,
|
.irqmap = a15irqmap,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.cpu_model = "host",
|
.cpu_model = "host",
|
||||||
/* We use the A15 private peripheral model to get a V2 GIC */
|
|
||||||
.qdevname = "a15mpcore_priv",
|
|
||||||
.gic_compatible = "arm,cortex-a15-gic",
|
|
||||||
.memmap = a15memmap,
|
.memmap = a15memmap,
|
||||||
.irqmap = a15irqmap,
|
.irqmap = a15irqmap,
|
||||||
},
|
},
|
||||||
@@ -251,8 +249,9 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
|
|||||||
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
|
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
|
||||||
|
|
||||||
qemu_fdt_add_subnode(vbi->fdt, "/intc");
|
qemu_fdt_add_subnode(vbi->fdt, "/intc");
|
||||||
|
/* 'cortex-a15-gic' means 'GIC v2' */
|
||||||
qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
|
qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
|
||||||
vbi->gic_compatible);
|
"arm,cortex-a15-gic");
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
|
||||||
qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
|
qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
|
||||||
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
|
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
|
||||||
@@ -263,6 +262,56 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
|
|||||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
|
{
|
||||||
|
/* We create a standalone GIC v2 */
|
||||||
|
DeviceState *gicdev;
|
||||||
|
SysBusDevice *gicbusdev;
|
||||||
|
const char *gictype = "arm_gic";
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (kvm_irqchip_in_kernel()) {
|
||||||
|
gictype = "kvm-arm-gic";
|
||||||
|
}
|
||||||
|
|
||||||
|
gicdev = qdev_create(NULL, gictype);
|
||||||
|
qdev_prop_set_uint32(gicdev, "revision", 2);
|
||||||
|
qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
|
||||||
|
/* Note that the num-irq property counts both internal and external
|
||||||
|
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
||||||
|
*/
|
||||||
|
qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
|
||||||
|
qdev_init_nofail(gicdev);
|
||||||
|
gicbusdev = SYS_BUS_DEVICE(gicdev);
|
||||||
|
sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
|
||||||
|
sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
|
||||||
|
|
||||||
|
/* Wire the outputs from each CPU's generic timer to the
|
||||||
|
* appropriate GIC PPI inputs, and the GIC's IRQ output to
|
||||||
|
* the CPU's IRQ input.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
|
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||||
|
int ppibase = NUM_IRQS + i * 32;
|
||||||
|
/* physical timer; we wire it up to the non-secure timer's ID,
|
||||||
|
* since a real A15 always has TrustZone but QEMU doesn't.
|
||||||
|
*/
|
||||||
|
qdev_connect_gpio_out(cpudev, 0,
|
||||||
|
qdev_get_gpio_in(gicdev, ppibase + 30));
|
||||||
|
/* virtual timer */
|
||||||
|
qdev_connect_gpio_out(cpudev, 1,
|
||||||
|
qdev_get_gpio_in(gicdev, ppibase + 27));
|
||||||
|
|
||||||
|
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_IRQS; i++) {
|
||||||
|
pic[i] = qdev_get_gpio_in(gicdev, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt_add_gic_node(vbi);
|
||||||
|
}
|
||||||
|
|
||||||
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
{
|
{
|
||||||
char *nodename;
|
char *nodename;
|
||||||
@@ -340,8 +389,6 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
|||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
int n;
|
int n;
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
DeviceState *dev;
|
|
||||||
SysBusDevice *busdev;
|
|
||||||
const char *cpu_model = args->cpu_model;
|
const char *cpu_model = args->cpu_model;
|
||||||
VirtBoardInfo *vbi;
|
VirtBoardInfo *vbi;
|
||||||
|
|
||||||
@@ -404,25 +451,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
|||||||
vmstate_register_ram_global(ram);
|
vmstate_register_ram_global(ram);
|
||||||
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
||||||
|
|
||||||
dev = qdev_create(NULL, vbi->qdevname);
|
create_gic(vbi, pic);
|
||||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
|
||||||
/* Note that the num-irq property counts both internal and external
|
|
||||||
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
|
||||||
*/
|
|
||||||
qdev_prop_set_uint32(dev, "num-irq", NUM_IRQS + 32);
|
|
||||||
qdev_init_nofail(dev);
|
|
||||||
busdev = SYS_BUS_DEVICE(dev);
|
|
||||||
sysbus_mmio_map(busdev, 0, vbi->memmap[VIRT_CPUPERIPHS].base);
|
|
||||||
fdt_add_gic_node(vbi);
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
|
||||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
|
|
||||||
|
|
||||||
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n = 0; n < NUM_IRQS; n++) {
|
|
||||||
pic[n] = qdev_get_gpio_in(dev, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
create_uart(vbi, pic);
|
create_uart(vbi, pic);
|
||||||
|
|
||||||
|
|||||||
@@ -261,6 +261,9 @@ static void hda_audio_set_amp(HDAAudioStream *st)
|
|||||||
left = left * 255 / QEMU_HDA_AMP_STEPS;
|
left = left * 255 / QEMU_HDA_AMP_STEPS;
|
||||||
right = right * 255 / QEMU_HDA_AMP_STEPS;
|
right = right * 255 / QEMU_HDA_AMP_STEPS;
|
||||||
|
|
||||||
|
if (!st->state->mixer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (st->output) {
|
if (st->output) {
|
||||||
AUD_set_volume_out(st->voice.out, muted, left, right);
|
AUD_set_volume_out(st->voice.out, muted, left, right);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "virtio-blk.h"
|
#include "virtio-blk.h"
|
||||||
#include "block/aio.h"
|
#include "block/aio.h"
|
||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
#include "monitor/monitor.h" /* for object_add() */
|
#include "qom/object_interfaces.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SEG_MAX = 126, /* maximum number of I/O segments */
|
SEG_MAX = 126, /* maximum number of I/O segments */
|
||||||
@@ -59,7 +59,7 @@ struct VirtIOBlockDataPlane {
|
|||||||
* use it).
|
* use it).
|
||||||
*/
|
*/
|
||||||
IOThread *iothread;
|
IOThread *iothread;
|
||||||
bool internal_iothread;
|
IOThread internal_iothread_obj;
|
||||||
AioContext *ctx;
|
AioContext *ctx;
|
||||||
EventNotifier io_notifier; /* Linux AIO completion */
|
EventNotifier io_notifier; /* Linux AIO completion */
|
||||||
EventNotifier host_notifier; /* doorbell */
|
EventNotifier host_notifier; /* doorbell */
|
||||||
@@ -391,23 +391,19 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
|||||||
s->blk = blk;
|
s->blk = blk;
|
||||||
|
|
||||||
if (blk->iothread) {
|
if (blk->iothread) {
|
||||||
s->internal_iothread = false;
|
|
||||||
s->iothread = blk->iothread;
|
s->iothread = blk->iothread;
|
||||||
|
object_ref(OBJECT(s->iothread));
|
||||||
} else {
|
} else {
|
||||||
/* Create per-device IOThread if none specified */
|
/* Create per-device IOThread if none specified. This is for
|
||||||
Error *local_err = NULL;
|
* x-data-plane option compatibility. If x-data-plane is removed we
|
||||||
|
* can drop this.
|
||||||
s->internal_iothread = true;
|
*/
|
||||||
object_add(TYPE_IOTHREAD, vdev->name, NULL, NULL, &local_err);
|
object_initialize(&s->internal_iothread_obj,
|
||||||
if (error_is_set(&local_err)) {
|
sizeof(s->internal_iothread_obj),
|
||||||
error_propagate(errp, local_err);
|
TYPE_IOTHREAD);
|
||||||
g_free(s);
|
user_creatable_complete(OBJECT(&s->internal_iothread_obj), &error_abort);
|
||||||
return;
|
s->iothread = &s->internal_iothread_obj;
|
||||||
}
|
|
||||||
s->iothread = iothread_find(vdev->name);
|
|
||||||
assert(s->iothread);
|
|
||||||
}
|
}
|
||||||
object_ref(OBJECT(s->iothread));
|
|
||||||
s->ctx = iothread_get_aio_context(s->iothread);
|
s->ctx = iothread_get_aio_context(s->iothread);
|
||||||
|
|
||||||
/* Prevent block operations that conflict with data plane thread */
|
/* Prevent block operations that conflict with data plane thread */
|
||||||
@@ -426,9 +422,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
|
|||||||
virtio_blk_data_plane_stop(s);
|
virtio_blk_data_plane_stop(s);
|
||||||
bdrv_set_in_use(s->blk->conf.bs, 0);
|
bdrv_set_in_use(s->blk->conf.bs, 0);
|
||||||
object_unref(OBJECT(s->iothread));
|
object_unref(OBJECT(s->iothread));
|
||||||
if (s->internal_iothread) {
|
|
||||||
object_unparent(OBJECT(s->iothread));
|
|
||||||
}
|
|
||||||
g_free(s);
|
g_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -752,8 +752,8 @@ static int nvme_init(PCIDevice *pci_dev)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs_size = bdrv_getlength(n->conf.bs);
|
bs_size = bdrv_getlength(n->conf.bs);
|
||||||
if (bs_size <= 0) {
|
if (bs_size < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -817,11 +817,14 @@ static int blk_connect(struct XenDevice *xendev)
|
|||||||
index = (blkdev->xendev.dev - 202 * 256) / 16;
|
index = (blkdev->xendev.dev - 202 * 256) / 16;
|
||||||
blkdev->dinfo = drive_get(IF_XEN, 0, index);
|
blkdev->dinfo = drive_get(IF_XEN, 0, index);
|
||||||
if (!blkdev->dinfo) {
|
if (!blkdev->dinfo) {
|
||||||
|
Error *local_err = NULL;
|
||||||
/* setup via xenbus -> create new block driver instance */
|
/* setup via xenbus -> create new block driver instance */
|
||||||
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
||||||
blkdev->bs = bdrv_new(blkdev->dev);
|
blkdev->bs = bdrv_new(blkdev->dev, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
blkdev->bs = NULL;
|
||||||
|
}
|
||||||
if (blkdev->bs) {
|
if (blkdev->bs) {
|
||||||
Error *local_err = NULL;
|
|
||||||
BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto,
|
BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto,
|
||||||
readonly);
|
readonly);
|
||||||
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
|
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
|
||||||
|
|||||||
@@ -225,8 +225,10 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
|||||||
|
|
||||||
if (s->tsr_retry <= 0) {
|
if (s->tsr_retry <= 0) {
|
||||||
if (s->fcr & UART_FCR_FE) {
|
if (s->fcr & UART_FCR_FE) {
|
||||||
s->tsr = fifo8_is_empty(&s->xmit_fifo) ?
|
if (fifo8_is_empty(&s->xmit_fifo)) {
|
||||||
0 : fifo8_pop(&s->xmit_fifo);
|
return FALSE;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; under version 2 of the License.
|
* the Free Software Foundation; either version 2 of the License,
|
||||||
|
* or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
|||||||
@@ -587,8 +587,9 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque,
|
|||||||
|
|
||||||
/* We rely on power-of-2 blocksizes for bitmasks */
|
/* We rely on power-of-2 blocksizes for bitmasks */
|
||||||
if ((value & (value - 1)) != 0) {
|
if ((value & (value - 1)) != 0) {
|
||||||
error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
|
error_setg(errp,
|
||||||
dev->id?:"", name, (int64_t)value);
|
"Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2",
|
||||||
|
dev->id ?: "", name, (int64_t)value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,7 +854,7 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
|
|||||||
{
|
{
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case -EEXIST:
|
case -EEXIST:
|
||||||
error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
|
error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
|
||||||
object_get_typename(OBJECT(dev)), prop->name, value);
|
object_get_typename(OBJECT(dev)), prop->name, value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -862,7 +863,7 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
|
|||||||
object_get_typename(OBJECT(dev)), prop->name, value);
|
object_get_typename(OBJECT(dev)), prop->name, value);
|
||||||
break;
|
break;
|
||||||
case -ENOENT:
|
case -ENOENT:
|
||||||
error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
|
error_setg(errp, "Property '%s.%s' can't find value '%s'",
|
||||||
object_get_typename(OBJECT(dev)), prop->name, value);
|
object_get_typename(OBJECT(dev)), prop->name, value);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -2913,7 +2913,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
|
|||||||
ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
|
ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
|
||||||
VGACommonState *s = &d->cirrus_vga.vga;
|
VGACommonState *s = &d->cirrus_vga.vga;
|
||||||
|
|
||||||
vga_common_init(s, OBJECT(dev));
|
vga_common_init(s, OBJECT(dev), true);
|
||||||
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
|
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
|
||||||
isa_address_space(isadev),
|
isa_address_space(isadev),
|
||||||
isa_address_space_io(isadev));
|
isa_address_space_io(isadev));
|
||||||
@@ -2960,7 +2960,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
|
|||||||
int16_t device_id = pc->device_id;
|
int16_t device_id = pc->device_id;
|
||||||
|
|
||||||
/* setup VGA */
|
/* setup VGA */
|
||||||
vga_common_init(&s->vga, OBJECT(dev));
|
vga_common_init(&s->vga, OBJECT(dev), true);
|
||||||
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
|
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
|
||||||
pci_address_space_io(dev));
|
pci_address_space_io(dev));
|
||||||
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
|
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
|
||||||
|
|||||||
@@ -2061,7 +2061,7 @@ static int qxl_init_primary(PCIDevice *dev)
|
|||||||
qxl->id = 0;
|
qxl->id = 0;
|
||||||
qxl_init_ramsize(qxl);
|
qxl_init_ramsize(qxl);
|
||||||
vga->vram_size_mb = qxl->vga.vram_size >> 20;
|
vga->vram_size_mb = qxl->vga.vram_size >> 20;
|
||||||
vga_common_init(vga, OBJECT(dev));
|
vga_common_init(vga, OBJECT(dev), true);
|
||||||
vga_init(vga, OBJECT(dev),
|
vga_init(vga, OBJECT(dev),
|
||||||
pci_address_space(dev), pci_address_space_io(dev), false);
|
pci_address_space(dev), pci_address_space_io(dev), false);
|
||||||
portio_list_init(qxl_vga_port_list, OBJECT(dev), qxl_vga_portio_list,
|
portio_list_init(qxl_vga_port_list, OBJECT(dev), qxl_vga_portio_list,
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ int isa_vga_mm_init(hwaddr vram_base,
|
|||||||
s = g_malloc0(sizeof(*s));
|
s = g_malloc0(sizeof(*s));
|
||||||
|
|
||||||
s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
|
s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
|
||||||
vga_common_init(&s->vga, NULL);
|
vga_common_init(&s->vga, NULL, true);
|
||||||
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
|
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
|
||||||
|
|
||||||
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
|
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
|
|||||||
MemoryRegion *vga_io_memory;
|
MemoryRegion *vga_io_memory;
|
||||||
const MemoryRegionPortio *vga_ports, *vbe_ports;
|
const MemoryRegionPortio *vga_ports, *vbe_ports;
|
||||||
|
|
||||||
vga_common_init(s, OBJECT(dev));
|
vga_common_init(s, OBJECT(dev), true);
|
||||||
s->legacy_address_space = isa_address_space(isadev);
|
s->legacy_address_space = isa_address_space(isadev);
|
||||||
vga_io_memory = vga_init_io(s, OBJECT(dev), &vga_ports, &vbe_ports);
|
vga_io_memory = vga_init_io(s, OBJECT(dev), &vga_ports, &vbe_ports);
|
||||||
isa_register_portio_list(isadev, 0x3b0, vga_ports, s, "vga");
|
isa_register_portio_list(isadev, 0x3b0, vga_ports, s, "vga");
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
|
|||||||
VGACommonState *s = &d->vga;
|
VGACommonState *s = &d->vga;
|
||||||
|
|
||||||
/* vga + console init */
|
/* vga + console init */
|
||||||
vga_common_init(s, OBJECT(dev));
|
vga_common_init(s, OBJECT(dev), true);
|
||||||
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
|
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
@@ -179,12 +179,51 @@ static int pci_std_vga_initfn(PCIDevice *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pci_secondary_vga_initfn(PCIDevice *dev)
|
||||||
|
{
|
||||||
|
PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
|
||||||
|
VGACommonState *s = &d->vga;
|
||||||
|
|
||||||
|
/* vga + console init */
|
||||||
|
vga_common_init(s, OBJECT(dev), false);
|
||||||
|
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
|
||||||
|
|
||||||
|
/* mmio bar */
|
||||||
|
memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096);
|
||||||
|
memory_region_init_io(&d->ioport, OBJECT(dev), &pci_vga_ioport_ops, d,
|
||||||
|
"vga ioports remapped", PCI_VGA_IOPORT_SIZE);
|
||||||
|
memory_region_init_io(&d->bochs, OBJECT(dev), &pci_vga_bochs_ops, d,
|
||||||
|
"bochs dispi interface", PCI_VGA_BOCHS_SIZE);
|
||||||
|
|
||||||
|
memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET,
|
||||||
|
&d->ioport);
|
||||||
|
memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET,
|
||||||
|
&d->bochs);
|
||||||
|
|
||||||
|
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
|
||||||
|
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_secondary_vga_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
PCIVGAState *d = DO_UPCAST(PCIVGAState, dev.qdev, dev);
|
||||||
|
|
||||||
|
vga_common_reset(&d->vga);
|
||||||
|
}
|
||||||
|
|
||||||
static Property vga_pci_properties[] = {
|
static Property vga_pci_properties[] = {
|
||||||
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
|
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
|
||||||
DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
|
DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Property secondary_pci_properties[] = {
|
||||||
|
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
static void vga_class_init(ObjectClass *klass, void *data)
|
static void vga_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
@@ -201,6 +240,20 @@ static void vga_class_init(ObjectClass *klass, void *data)
|
|||||||
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void secondary_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
k->init = pci_secondary_vga_initfn;
|
||||||
|
k->vendor_id = PCI_VENDOR_ID_QEMU;
|
||||||
|
k->device_id = PCI_DEVICE_ID_QEMU_VGA;
|
||||||
|
k->class_id = PCI_CLASS_DISPLAY_OTHER;
|
||||||
|
dc->vmsd = &vmstate_vga_pci;
|
||||||
|
dc->props = secondary_pci_properties;
|
||||||
|
dc->reset = pci_secondary_vga_reset;
|
||||||
|
}
|
||||||
|
|
||||||
static const TypeInfo vga_info = {
|
static const TypeInfo vga_info = {
|
||||||
.name = "VGA",
|
.name = "VGA",
|
||||||
.parent = TYPE_PCI_DEVICE,
|
.parent = TYPE_PCI_DEVICE,
|
||||||
@@ -208,9 +261,17 @@ static const TypeInfo vga_info = {
|
|||||||
.class_init = vga_class_init,
|
.class_init = vga_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const TypeInfo secondary_info = {
|
||||||
|
.name = "secondary-vga",
|
||||||
|
.parent = TYPE_PCI_DEVICE,
|
||||||
|
.instance_size = sizeof(PCIVGAState),
|
||||||
|
.class_init = secondary_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void vga_register_types(void)
|
static void vga_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&vga_info);
|
type_register_static(&vga_info);
|
||||||
|
type_register_static(&secondary_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(vga_register_types)
|
type_init(vga_register_types)
|
||||||
|
|||||||
@@ -171,6 +171,10 @@ static void vga_update_memory_access(VGACommonState *s)
|
|||||||
MemoryRegion *region, *old_region = s->chain4_alias;
|
MemoryRegion *region, *old_region = s->chain4_alias;
|
||||||
hwaddr base, offset, size;
|
hwaddr base, offset, size;
|
||||||
|
|
||||||
|
if (s->legacy_address_space == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
s->chain4_alias = NULL;
|
s->chain4_alias = NULL;
|
||||||
|
|
||||||
if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
|
if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
|
||||||
@@ -2252,7 +2256,7 @@ static const GraphicHwOps vga_ops = {
|
|||||||
.text_update = vga_update_text,
|
.text_update = vga_update_text,
|
||||||
};
|
};
|
||||||
|
|
||||||
void vga_common_init(VGACommonState *s, Object *obj)
|
void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
|
||||||
{
|
{
|
||||||
int i, j, v, b;
|
int i, j, v, b;
|
||||||
|
|
||||||
@@ -2289,7 +2293,7 @@ void vga_common_init(VGACommonState *s, Object *obj)
|
|||||||
|
|
||||||
s->is_vbe_vmstate = 1;
|
s->is_vbe_vmstate = 1;
|
||||||
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
|
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
|
||||||
vmstate_register_ram_global(&s->vram);
|
vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
|
||||||
xen_register_framebuffer(&s->vram);
|
xen_register_framebuffer(&s->vram);
|
||||||
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
|
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
|
||||||
s->get_bpp = vga_get_bpp;
|
s->get_bpp = vga_get_bpp;
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ static inline int c6_to_8(int v)
|
|||||||
return (v << 2) | (b << 1) | b;
|
return (v << 2) | (b << 1) | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_common_init(VGACommonState *s, Object *obj);
|
void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate);
|
||||||
void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
|
void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
|
||||||
MemoryRegion *address_space_io, bool init_vga_ports);
|
MemoryRegion *address_space_io, bool init_vga_ports);
|
||||||
MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
|
MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
|
||||||
|
|||||||
@@ -1207,7 +1207,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
|
|||||||
vmstate_register_ram_global(&s->fifo_ram);
|
vmstate_register_ram_global(&s->fifo_ram);
|
||||||
s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
|
s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
|
||||||
|
|
||||||
vga_common_init(&s->vga, OBJECT(dev));
|
vga_common_init(&s->vga, OBJECT(dev), true);
|
||||||
vga_init(&s->vga, OBJECT(dev), address_space, io, true);
|
vga_init(&s->vga, OBJECT(dev), address_space, io, true);
|
||||||
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
|
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
|
||||||
s->new_depth = 32;
|
s->new_depth = 32;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int l
|
|||||||
printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
|
printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
|
||||||
dev->i2c.address, cmd, buf[0]);
|
dev->i2c.address, cmd, buf[0]);
|
||||||
#endif
|
#endif
|
||||||
/* An page write operation is not a valid SMBus command.
|
/* A page write operation is not a valid SMBus command.
|
||||||
It is a block write without a length byte. Fortunately we
|
It is a block write without a length byte. Fortunately we
|
||||||
get the full block anyway. */
|
get the full block anyway. */
|
||||||
/* TODO: Should this set the current location? */
|
/* TODO: Should this set the current location? */
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ static void build_append_int(GArray *table, uint32_t value)
|
|||||||
build_append_byte(table, 0x01); /* OneOp */
|
build_append_byte(table, 0x01); /* OneOp */
|
||||||
} else if (value <= 0xFF) {
|
} else if (value <= 0xFF) {
|
||||||
build_append_value(table, value, 1);
|
build_append_value(table, value, 1);
|
||||||
} else if (value <= 0xFFFFF) {
|
} else if (value <= 0xFFFF) {
|
||||||
build_append_value(table, value, 2);
|
build_append_value(table, value, 2);
|
||||||
} else {
|
} else {
|
||||||
build_append_value(table, value, 4);
|
build_append_value(table, value, 4);
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ Scope(\_SB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Device(CPU_HOTPLUG_RESOURCE_DEVICE) {
|
Device(CPU_HOTPLUG_RESOURCE_DEVICE) {
|
||||||
Name(_HID, "ACPI0004")
|
Name(_HID, EisaId("PNP0A06"))
|
||||||
|
|
||||||
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,
|
||||||
0x85,
|
0x80,
|
||||||
0x11,
|
0x11,
|
||||||
0x0,
|
0x0,
|
||||||
0x0,
|
0x0,
|
||||||
0x1,
|
0x1,
|
||||||
0x8b,
|
0x60,
|
||||||
0x42,
|
0x42,
|
||||||
0x58,
|
0x58,
|
||||||
0x50,
|
0x50,
|
||||||
@@ -31,8 +31,8 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x4e,
|
0x4e,
|
||||||
0x54,
|
0x54,
|
||||||
0x4c,
|
0x4c,
|
||||||
0x23,
|
0x15,
|
||||||
0x8,
|
0x11,
|
||||||
0x13,
|
0x13,
|
||||||
0x20,
|
0x20,
|
||||||
0x10,
|
0x10,
|
||||||
@@ -4010,7 +4010,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x53,
|
0x53,
|
||||||
0x1,
|
0x1,
|
||||||
0x10,
|
0x10,
|
||||||
0x47,
|
0x42,
|
||||||
0x11,
|
0x11,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x53,
|
0x53,
|
||||||
@@ -4243,7 +4243,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x60,
|
0x60,
|
||||||
0x5b,
|
0x5b,
|
||||||
0x82,
|
0x82,
|
||||||
0x2e,
|
0x29,
|
||||||
0x50,
|
0x50,
|
||||||
0x52,
|
0x52,
|
||||||
0x45,
|
0x45,
|
||||||
@@ -4253,16 +4253,11 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
|||||||
0x48,
|
0x48,
|
||||||
0x49,
|
0x49,
|
||||||
0x44,
|
0x44,
|
||||||
0xd,
|
0xc,
|
||||||
0x41,
|
0x41,
|
||||||
0x43,
|
0xd0,
|
||||||
0x50,
|
0xa,
|
||||||
0x49,
|
0x6,
|
||||||
0x30,
|
|
||||||
0x30,
|
|
||||||
0x30,
|
|
||||||
0x34,
|
|
||||||
0x0,
|
|
||||||
0x8,
|
0x8,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x43,
|
0x43,
|
||||||
|
|||||||
@@ -124,14 +124,14 @@ static const TPRInstruction tpr_instr[] = {
|
|||||||
|
|
||||||
static void read_guest_rom_state(VAPICROMState *s)
|
static void read_guest_rom_state(VAPICROMState *s)
|
||||||
{
|
{
|
||||||
cpu_physical_memory_rw(s->rom_state_paddr, (void *)&s->rom_state,
|
cpu_physical_memory_read(s->rom_state_paddr, &s->rom_state,
|
||||||
sizeof(GuestROMState), 0);
|
sizeof(GuestROMState));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_guest_rom_state(VAPICROMState *s)
|
static void write_guest_rom_state(VAPICROMState *s)
|
||||||
{
|
{
|
||||||
cpu_physical_memory_rw(s->rom_state_paddr, (void *)&s->rom_state,
|
cpu_physical_memory_write(s->rom_state_paddr, &s->rom_state,
|
||||||
sizeof(GuestROMState), 1);
|
sizeof(GuestROMState));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_guest_rom_state(VAPICROMState *s)
|
static void update_guest_rom_state(VAPICROMState *s)
|
||||||
@@ -311,16 +311,14 @@ static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong i
|
|||||||
for (pos = le32_to_cpu(s->rom_state.fixup_start);
|
for (pos = le32_to_cpu(s->rom_state.fixup_start);
|
||||||
pos < le32_to_cpu(s->rom_state.fixup_end);
|
pos < le32_to_cpu(s->rom_state.fixup_end);
|
||||||
pos += 4) {
|
pos += 4) {
|
||||||
cpu_physical_memory_rw(paddr + pos - s->rom_state.vaddr,
|
cpu_physical_memory_read(paddr + pos - s->rom_state.vaddr,
|
||||||
(void *)&offset, sizeof(offset), 0);
|
&offset, sizeof(offset));
|
||||||
offset = le32_to_cpu(offset);
|
offset = le32_to_cpu(offset);
|
||||||
cpu_physical_memory_rw(paddr + offset, (void *)&patch,
|
cpu_physical_memory_read(paddr + offset, &patch, sizeof(patch));
|
||||||
sizeof(patch), 0);
|
|
||||||
patch = le32_to_cpu(patch);
|
patch = le32_to_cpu(patch);
|
||||||
patch += rom_state_vaddr - le32_to_cpu(s->rom_state.vaddr);
|
patch += rom_state_vaddr - le32_to_cpu(s->rom_state.vaddr);
|
||||||
patch = cpu_to_le32(patch);
|
patch = cpu_to_le32(patch);
|
||||||
cpu_physical_memory_rw(paddr + offset, (void *)&patch,
|
cpu_physical_memory_write(paddr + offset, &patch, sizeof(patch));
|
||||||
sizeof(patch), 1);
|
|
||||||
}
|
}
|
||||||
read_guest_rom_state(s);
|
read_guest_rom_state(s);
|
||||||
s->vapic_paddr = paddr + le32_to_cpu(s->rom_state.vapic_vaddr) -
|
s->vapic_paddr = paddr + le32_to_cpu(s->rom_state.vapic_vaddr) -
|
||||||
@@ -364,8 +362,8 @@ static int vapic_enable(VAPICROMState *s, X86CPU *cpu)
|
|||||||
}
|
}
|
||||||
vapic_paddr = s->vapic_paddr +
|
vapic_paddr = s->vapic_paddr +
|
||||||
(((hwaddr)cpu_number) << VAPIC_CPU_SHIFT);
|
(((hwaddr)cpu_number) << VAPIC_CPU_SHIFT);
|
||||||
cpu_physical_memory_rw(vapic_paddr + offsetof(VAPICState, enabled),
|
cpu_physical_memory_write(vapic_paddr + offsetof(VAPICState, enabled),
|
||||||
(void *)&enabled, sizeof(enabled), 1);
|
&enabled, sizeof(enabled));
|
||||||
apic_enable_vapic(cpu->apic_state, vapic_paddr);
|
apic_enable_vapic(cpu->apic_state, vapic_paddr);
|
||||||
|
|
||||||
s->state = VAPIC_ACTIVE;
|
s->state = VAPIC_ACTIVE;
|
||||||
@@ -535,7 +533,7 @@ static int patch_hypercalls(VAPICROMState *s)
|
|||||||
uint8_t *rom;
|
uint8_t *rom;
|
||||||
|
|
||||||
rom = g_malloc(s->rom_size);
|
rom = g_malloc(s->rom_size);
|
||||||
cpu_physical_memory_rw(rom_paddr, rom, s->rom_size, 0);
|
cpu_physical_memory_read(rom_paddr, rom, s->rom_size);
|
||||||
|
|
||||||
for (pos = 0; pos < s->rom_size - sizeof(vmcall_pattern); pos++) {
|
for (pos = 0; pos < s->rom_size - sizeof(vmcall_pattern); pos++) {
|
||||||
if (kvm_irqchip_in_kernel()) {
|
if (kvm_irqchip_in_kernel()) {
|
||||||
@@ -551,8 +549,7 @@ static int patch_hypercalls(VAPICROMState *s)
|
|||||||
}
|
}
|
||||||
if (memcmp(rom + pos, pattern, 7) == 0 &&
|
if (memcmp(rom + pos, pattern, 7) == 0 &&
|
||||||
(rom[pos + 7] == alternates[0] || rom[pos + 7] == alternates[1])) {
|
(rom[pos + 7] == alternates[0] || rom[pos + 7] == alternates[1])) {
|
||||||
cpu_physical_memory_rw(rom_paddr + pos + 5, (uint8_t *)patch,
|
cpu_physical_memory_write(rom_paddr + pos + 5, patch, 3);
|
||||||
3, 1);
|
|
||||||
/*
|
/*
|
||||||
* Don't flush the tb here. Under ordinary conditions, the patched
|
* Don't flush the tb here. Under ordinary conditions, the patched
|
||||||
* calls are miles away from the current IP. Under malicious
|
* calls are miles away from the current IP. Under malicious
|
||||||
@@ -760,8 +757,8 @@ static int vapic_post_load(void *opaque, int version_id)
|
|||||||
run_on_cpu(first_cpu, do_vapic_enable, s);
|
run_on_cpu(first_cpu, do_vapic_enable, s);
|
||||||
} else {
|
} else {
|
||||||
zero = g_malloc0(s->rom_state.vapic_size);
|
zero = g_malloc0(s->rom_state.vapic_size);
|
||||||
cpu_physical_memory_rw(s->vapic_paddr, zero,
|
cpu_physical_memory_write(s->vapic_paddr, zero,
|
||||||
s->rom_state.vapic_size, 1);
|
s->rom_state.vapic_size);
|
||||||
g_free(zero);
|
g_free(zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
hw/i386/pc.c
39
hw/i386/pc.c
@@ -612,6 +612,21 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
|
|||||||
return e820_entries;
|
return e820_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int e820_get_num_entries(void)
|
||||||
|
{
|
||||||
|
return e820_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length)
|
||||||
|
{
|
||||||
|
if (idx < e820_entries && e820_table[idx].type == cpu_to_le32(type)) {
|
||||||
|
*address = le64_to_cpu(e820_table[idx].address);
|
||||||
|
*length = le64_to_cpu(e820_table[idx].length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculates the limit to CPU APIC ID values
|
/* Calculates the limit to CPU APIC ID values
|
||||||
*
|
*
|
||||||
* This function returns the limit for the APIC ID value, so that all
|
* This function returns the limit for the APIC ID value, so that all
|
||||||
@@ -627,8 +642,8 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus)
|
|||||||
static FWCfgState *bochs_bios_init(void)
|
static FWCfgState *bochs_bios_init(void)
|
||||||
{
|
{
|
||||||
FWCfgState *fw_cfg;
|
FWCfgState *fw_cfg;
|
||||||
uint8_t *smbios_table;
|
uint8_t *smbios_tables, *smbios_anchor;
|
||||||
size_t smbios_len;
|
size_t smbios_tables_len, smbios_anchor_len;
|
||||||
uint64_t *numa_fw_cfg;
|
uint64_t *numa_fw_cfg;
|
||||||
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);
|
||||||
@@ -655,10 +670,21 @@ static FWCfgState *bochs_bios_init(void)
|
|||||||
acpi_tables, acpi_tables_len);
|
acpi_tables, acpi_tables_len);
|
||||||
fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
|
fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
|
||||||
|
|
||||||
smbios_table = smbios_get_table(&smbios_len);
|
smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
|
||||||
if (smbios_table)
|
if (smbios_tables) {
|
||||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
|
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
|
||||||
smbios_table, smbios_len);
|
smbios_tables, smbios_tables_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
smbios_get_tables(&smbios_tables, &smbios_tables_len,
|
||||||
|
&smbios_anchor, &smbios_anchor_len);
|
||||||
|
if (smbios_anchor) {
|
||||||
|
fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
|
||||||
|
smbios_tables, smbios_tables_len);
|
||||||
|
fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
|
||||||
|
smbios_anchor, smbios_anchor_len);
|
||||||
|
}
|
||||||
|
|
||||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
|
fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
|
||||||
&e820_reserve, sizeof(e820_reserve));
|
&e820_reserve, sizeof(e820_reserve));
|
||||||
fw_cfg_add_file(fw_cfg, "etc/e820", e820_table,
|
fw_cfg_add_file(fw_cfg, "etc/e820", e820_table,
|
||||||
@@ -1027,6 +1053,9 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
|
|||||||
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(icc_bridge), 0,
|
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(icc_bridge), 0,
|
||||||
APIC_DEFAULT_ADDRESS, 0x1000);
|
APIC_DEFAULT_ADDRESS, 0x1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tell smbios about cpuid version and features */
|
||||||
|
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pci-info ROM file. Little endian format */
|
/* pci-info ROM file. Little endian format */
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
|||||||
|
|
||||||
static bool has_pci_info;
|
static bool has_pci_info;
|
||||||
static bool has_acpi_build = true;
|
static bool has_acpi_build = true;
|
||||||
static bool smbios_type1_defaults = true;
|
static bool smbios_defaults = true;
|
||||||
|
static bool smbios_legacy_mode;
|
||||||
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
||||||
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
|
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
|
||||||
* pages in the host.
|
* pages in the host.
|
||||||
@@ -143,10 +144,10 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
|||||||
guest_info->has_pci_info = has_pci_info;
|
guest_info->has_pci_info = has_pci_info;
|
||||||
guest_info->isapc_ram_fw = !pci_enabled;
|
guest_info->isapc_ram_fw = !pci_enabled;
|
||||||
|
|
||||||
if (smbios_type1_defaults) {
|
if (smbios_defaults) {
|
||||||
/* These values are guest ABI, do not change */
|
/* These values are guest ABI, do not change */
|
||||||
smbios_set_type1_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
|
smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
|
||||||
args->machine->name);
|
args->machine->name, smbios_legacy_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate ram and load rom/bios */
|
/* allocate ram and load rom/bios */
|
||||||
@@ -262,9 +263,15 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
|
|||||||
pc_init1(args, 1, 1);
|
pc_init1(args, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_compat_2_0(QEMUMachineInitArgs *args)
|
||||||
|
{
|
||||||
|
smbios_legacy_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
smbios_type1_defaults = false;
|
pc_compat_2_0(args);
|
||||||
|
smbios_defaults = false;
|
||||||
gigabyte_align = false;
|
gigabyte_align = false;
|
||||||
option_rom_has_mr = true;
|
option_rom_has_mr = true;
|
||||||
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
||||||
@@ -303,6 +310,12 @@ static void pc_compat_1_2(QEMUMachineInitArgs *args)
|
|||||||
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_init_pci_2_0(QEMUMachineInitArgs *args)
|
||||||
|
{
|
||||||
|
pc_compat_2_0(args);
|
||||||
|
pc_init_pci(args);
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_init_pci_1_7(QEMUMachineInitArgs *args)
|
static void pc_init_pci_1_7(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
pc_compat_1_7(args);
|
pc_compat_1_7(args);
|
||||||
@@ -345,7 +358,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
|
|||||||
{
|
{
|
||||||
has_pci_info = false;
|
has_pci_info = false;
|
||||||
has_acpi_build = false;
|
has_acpi_build = false;
|
||||||
smbios_type1_defaults = false;
|
smbios_defaults = false;
|
||||||
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||||
enable_compat_apic_id_mode();
|
enable_compat_apic_id_mode();
|
||||||
pc_init1(args, 1, 0);
|
pc_init1(args, 1, 0);
|
||||||
@@ -355,7 +368,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
|
|||||||
{
|
{
|
||||||
has_pci_info = false;
|
has_pci_info = false;
|
||||||
has_acpi_build = false;
|
has_acpi_build = false;
|
||||||
smbios_type1_defaults = false;
|
smbios_defaults = false;
|
||||||
if (!args->cpu_model) {
|
if (!args->cpu_model) {
|
||||||
args->cpu_model = "486";
|
args->cpu_model = "486";
|
||||||
}
|
}
|
||||||
@@ -383,16 +396,24 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
|
|||||||
.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_0_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"
|
||||||
|
|
||||||
|
static QEMUMachine pc_i440fx_machine_v2_1 = {
|
||||||
|
PC_I440FX_2_1_MACHINE_OPTIONS,
|
||||||
|
.name = "pc-i440fx-2.1",
|
||||||
|
.alias = "pc",
|
||||||
|
.init = pc_init_pci,
|
||||||
|
.is_default = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PC_I440FX_2_0_MACHINE_OPTIONS PC_I440FX_2_1_MACHINE_OPTIONS
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v2_0 = {
|
static QEMUMachine pc_i440fx_machine_v2_0 = {
|
||||||
PC_I440FX_2_0_MACHINE_OPTIONS,
|
PC_I440FX_2_0_MACHINE_OPTIONS,
|
||||||
.name = "pc-i440fx-2.0",
|
.name = "pc-i440fx-2.0",
|
||||||
.alias = "pc",
|
.init = pc_init_pci_2_0,
|
||||||
.init = pc_init_pci,
|
|
||||||
.is_default = 1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
||||||
@@ -817,6 +838,7 @@ static QEMUMachine xenfv_machine = {
|
|||||||
|
|
||||||
static void pc_machine_init(void)
|
static void pc_machine_init(void)
|
||||||
{
|
{
|
||||||
|
qemu_register_machine(&pc_i440fx_machine_v2_1);
|
||||||
qemu_register_machine(&pc_i440fx_machine_v2_0);
|
qemu_register_machine(&pc_i440fx_machine_v2_0);
|
||||||
qemu_register_machine(&pc_i440fx_machine_v1_7);
|
qemu_register_machine(&pc_i440fx_machine_v1_7);
|
||||||
qemu_register_machine(&pc_i440fx_machine_v1_6);
|
qemu_register_machine(&pc_i440fx_machine_v1_6);
|
||||||
|
|||||||
@@ -50,7 +50,8 @@
|
|||||||
|
|
||||||
static bool has_pci_info;
|
static bool has_pci_info;
|
||||||
static bool has_acpi_build = true;
|
static bool has_acpi_build = true;
|
||||||
static bool smbios_type1_defaults = true;
|
static bool smbios_defaults = true;
|
||||||
|
static bool smbios_legacy_mode;
|
||||||
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
||||||
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
|
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
|
||||||
* pages in the host.
|
* pages in the host.
|
||||||
@@ -130,10 +131,10 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
|||||||
guest_info->isapc_ram_fw = false;
|
guest_info->isapc_ram_fw = false;
|
||||||
guest_info->has_acpi_build = has_acpi_build;
|
guest_info->has_acpi_build = has_acpi_build;
|
||||||
|
|
||||||
if (smbios_type1_defaults) {
|
if (smbios_defaults) {
|
||||||
/* These values are guest ABI, do not change */
|
/* These values are guest ABI, do not change */
|
||||||
smbios_set_type1_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
||||||
args->machine->name);
|
args->machine->name, smbios_legacy_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate ram and load rom/bios */
|
/* allocate ram and load rom/bios */
|
||||||
@@ -240,9 +241,15 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pc_compat_2_0(QEMUMachineInitArgs *args)
|
||||||
|
{
|
||||||
|
smbios_legacy_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
smbios_type1_defaults = false;
|
pc_compat_2_0(args);
|
||||||
|
smbios_defaults = false;
|
||||||
gigabyte_align = false;
|
gigabyte_align = false;
|
||||||
option_rom_has_mr = true;
|
option_rom_has_mr = true;
|
||||||
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
||||||
@@ -268,6 +275,12 @@ static void pc_compat_1_4(QEMUMachineInitArgs *args)
|
|||||||
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_0(QEMUMachineInitArgs *args)
|
||||||
|
{
|
||||||
|
pc_compat_2_0(args);
|
||||||
|
pc_q35_init(args);
|
||||||
|
}
|
||||||
|
|
||||||
static void pc_q35_init_1_7(QEMUMachineInitArgs *args)
|
static void pc_q35_init_1_7(QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
pc_compat_1_7(args);
|
pc_compat_1_7(args);
|
||||||
@@ -297,15 +310,23 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
|
|||||||
.desc = "Standard PC (Q35 + ICH9, 2009)", \
|
.desc = "Standard PC (Q35 + ICH9, 2009)", \
|
||||||
.hot_add_cpu = pc_hot_add_cpu
|
.hot_add_cpu = pc_hot_add_cpu
|
||||||
|
|
||||||
#define PC_Q35_2_0_MACHINE_OPTIONS \
|
#define PC_Q35_2_1_MACHINE_OPTIONS \
|
||||||
PC_Q35_MACHINE_OPTIONS, \
|
PC_Q35_MACHINE_OPTIONS, \
|
||||||
.default_machine_opts = "firmware=bios-256k.bin"
|
.default_machine_opts = "firmware=bios-256k.bin"
|
||||||
|
|
||||||
|
static QEMUMachine pc_q35_machine_v2_1 = {
|
||||||
|
PC_Q35_2_1_MACHINE_OPTIONS,
|
||||||
|
.name = "pc-q35-2.1",
|
||||||
|
.alias = "q35",
|
||||||
|
.init = pc_q35_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PC_Q35_2_0_MACHINE_OPTIONS PC_Q35_2_1_MACHINE_OPTIONS
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v2_0 = {
|
static QEMUMachine pc_q35_machine_v2_0 = {
|
||||||
PC_Q35_2_0_MACHINE_OPTIONS,
|
PC_Q35_2_0_MACHINE_OPTIONS,
|
||||||
.name = "pc-q35-2.0",
|
.name = "pc-q35-2.0",
|
||||||
.alias = "q35",
|
.init = pc_q35_init_2_0,
|
||||||
.init = pc_q35_init,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
|
#define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
|
||||||
@@ -358,6 +379,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
|
|||||||
|
|
||||||
static void pc_q35_machine_init(void)
|
static void pc_q35_machine_init(void)
|
||||||
{
|
{
|
||||||
|
qemu_register_machine(&pc_q35_machine_v2_1);
|
||||||
qemu_register_machine(&pc_q35_machine_v2_0);
|
qemu_register_machine(&pc_q35_machine_v2_0);
|
||||||
qemu_register_machine(&pc_q35_machine_v1_7);
|
qemu_register_machine(&pc_q35_machine_v1_7);
|
||||||
qemu_register_machine(&pc_q35_machine_v1_6);
|
qemu_register_machine(&pc_q35_machine_v1_6);
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x53,
|
0x53,
|
||||||
0x44,
|
0x44,
|
||||||
0x54,
|
0x54,
|
||||||
0xd7,
|
0xd2,
|
||||||
0x1c,
|
0x1c,
|
||||||
0x0,
|
0x0,
|
||||||
0x0,
|
0x0,
|
||||||
0x1,
|
0x1,
|
||||||
0x3e,
|
0x13,
|
||||||
0x42,
|
0x42,
|
||||||
0x58,
|
0x58,
|
||||||
0x50,
|
0x50,
|
||||||
@@ -31,8 +31,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x4e,
|
0x4e,
|
||||||
0x54,
|
0x54,
|
||||||
0x4c,
|
0x4c,
|
||||||
0x23,
|
0x15,
|
||||||
0x8,
|
0x11,
|
||||||
0x13,
|
0x13,
|
||||||
0x20,
|
0x20,
|
||||||
0x10,
|
0x10,
|
||||||
@@ -6959,7 +6959,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x53,
|
0x53,
|
||||||
0x1,
|
0x1,
|
||||||
0x10,
|
0x10,
|
||||||
0x47,
|
0x42,
|
||||||
0x11,
|
0x11,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x53,
|
0x53,
|
||||||
@@ -7192,7 +7192,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x60,
|
0x60,
|
||||||
0x5b,
|
0x5b,
|
||||||
0x82,
|
0x82,
|
||||||
0x2e,
|
0x29,
|
||||||
0x50,
|
0x50,
|
||||||
0x52,
|
0x52,
|
||||||
0x45,
|
0x45,
|
||||||
@@ -7202,16 +7202,11 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
|||||||
0x48,
|
0x48,
|
||||||
0x49,
|
0x49,
|
||||||
0x44,
|
0x44,
|
||||||
0xd,
|
0xc,
|
||||||
0x41,
|
0x41,
|
||||||
0x43,
|
0xd0,
|
||||||
0x50,
|
0xa,
|
||||||
0x49,
|
0x6,
|
||||||
0x30,
|
|
||||||
0x30,
|
|
||||||
0x30,
|
|
||||||
0x34,
|
|
||||||
0x0,
|
|
||||||
0x8,
|
0x8,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x43,
|
0x43,
|
||||||
|
|||||||
789
hw/i386/smbios.c
789
hw/i386/smbios.c
@@ -18,12 +18,13 @@
|
|||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "sysemu/cpus.h"
|
||||||
|
#include "hw/i386/pc.h"
|
||||||
#include "hw/i386/smbios.h"
|
#include "hw/i386/smbios.h"
|
||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Structures shared with the BIOS
|
/* legacy structures and constants for <= 2.0 machines */
|
||||||
*/
|
|
||||||
struct smbios_header {
|
struct smbios_header {
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -46,14 +47,23 @@ struct smbios_table {
|
|||||||
|
|
||||||
static uint8_t *smbios_entries;
|
static uint8_t *smbios_entries;
|
||||||
static size_t smbios_entries_len;
|
static size_t smbios_entries_len;
|
||||||
|
static bool smbios_legacy = true;
|
||||||
|
/* end: legacy structures & constants for <= 2.0 machines */
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t *smbios_tables;
|
||||||
|
static size_t smbios_tables_len;
|
||||||
|
static unsigned smbios_table_max;
|
||||||
|
static unsigned smbios_table_cnt;
|
||||||
|
static struct smbios_entry_point ep;
|
||||||
|
|
||||||
static int smbios_type4_count = 0;
|
static int smbios_type4_count = 0;
|
||||||
static bool smbios_immutable;
|
static bool smbios_immutable;
|
||||||
|
static bool smbios_have_defaults;
|
||||||
|
static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets;
|
||||||
|
|
||||||
static struct {
|
static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
|
||||||
bool seen;
|
static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
|
||||||
int headertype;
|
|
||||||
Location loc;
|
|
||||||
} first_opt[2];
|
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
const char *vendor, *version, *date;
|
const char *vendor, *version, *date;
|
||||||
@@ -66,6 +76,22 @@ static struct {
|
|||||||
/* uuid is in qemu_uuid[] */
|
/* uuid is in qemu_uuid[] */
|
||||||
} type1;
|
} type1;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *manufacturer, *product, *version, *serial, *asset, *location;
|
||||||
|
} type2;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *manufacturer, *version, *serial, *asset, *sku;
|
||||||
|
} type3;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
|
||||||
|
} type4;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
|
||||||
|
} type17;
|
||||||
|
|
||||||
static QemuOptsList qemu_smbios_opts = {
|
static QemuOptsList qemu_smbios_opts = {
|
||||||
.name = "smbios",
|
.name = "smbios",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
|
||||||
@@ -149,6 +175,134 @@ static const QemuOptDesc qemu_smbios_type1_opts[] = {
|
|||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const QemuOptDesc qemu_smbios_type2_opts[] = {
|
||||||
|
{
|
||||||
|
.name = "type",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
.help = "SMBIOS element type",
|
||||||
|
},{
|
||||||
|
.name = "manufacturer",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "manufacturer name",
|
||||||
|
},{
|
||||||
|
.name = "product",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "product name",
|
||||||
|
},{
|
||||||
|
.name = "version",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "version number",
|
||||||
|
},{
|
||||||
|
.name = "serial",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "serial number",
|
||||||
|
},{
|
||||||
|
.name = "asset",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "asset tag number",
|
||||||
|
},{
|
||||||
|
.name = "location",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "location in chassis",
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QemuOptDesc qemu_smbios_type3_opts[] = {
|
||||||
|
{
|
||||||
|
.name = "type",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
.help = "SMBIOS element type",
|
||||||
|
},{
|
||||||
|
.name = "manufacturer",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "manufacturer name",
|
||||||
|
},{
|
||||||
|
.name = "version",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "version number",
|
||||||
|
},{
|
||||||
|
.name = "serial",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "serial number",
|
||||||
|
},{
|
||||||
|
.name = "asset",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "asset tag number",
|
||||||
|
},{
|
||||||
|
.name = "sku",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "SKU number",
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QemuOptDesc qemu_smbios_type4_opts[] = {
|
||||||
|
{
|
||||||
|
.name = "type",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
.help = "SMBIOS element type",
|
||||||
|
},{
|
||||||
|
.name = "sock_pfx",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "socket designation string prefix",
|
||||||
|
},{
|
||||||
|
.name = "manufacturer",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "manufacturer name",
|
||||||
|
},{
|
||||||
|
.name = "version",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "version number",
|
||||||
|
},{
|
||||||
|
.name = "serial",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "serial number",
|
||||||
|
},{
|
||||||
|
.name = "asset",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "asset tag number",
|
||||||
|
},{
|
||||||
|
.name = "part",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "part number",
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QemuOptDesc qemu_smbios_type17_opts[] = {
|
||||||
|
{
|
||||||
|
.name = "type",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
.help = "SMBIOS element type",
|
||||||
|
},{
|
||||||
|
.name = "loc_pfx",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "device locator string prefix",
|
||||||
|
},{
|
||||||
|
.name = "bank",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "bank locator string",
|
||||||
|
},{
|
||||||
|
.name = "manufacturer",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "manufacturer name",
|
||||||
|
},{
|
||||||
|
.name = "serial",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "serial number",
|
||||||
|
},{
|
||||||
|
.name = "asset",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "asset tag number",
|
||||||
|
},{
|
||||||
|
.name = "part",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "part number",
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
};
|
||||||
|
|
||||||
static void smbios_register_config(void)
|
static void smbios_register_config(void)
|
||||||
{
|
{
|
||||||
qemu_add_opts(&qemu_smbios_opts);
|
qemu_add_opts(&qemu_smbios_opts);
|
||||||
@@ -158,35 +312,17 @@ machine_init(smbios_register_config);
|
|||||||
|
|
||||||
static void smbios_validate_table(void)
|
static void smbios_validate_table(void)
|
||||||
{
|
{
|
||||||
if (smbios_type4_count && smbios_type4_count != smp_cpus) {
|
uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets;
|
||||||
error_report("Number of SMBIOS Type 4 tables must match cpu count");
|
|
||||||
|
if (smbios_type4_count && smbios_type4_count != expect_t4_count) {
|
||||||
|
error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
|
||||||
|
expect_t4_count, smbios_type4_count);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* To avoid unresolvable overlaps in data, don't allow both
|
|
||||||
* tables and fields for the same smbios type.
|
|
||||||
*/
|
|
||||||
static void smbios_check_collision(int type, int entry)
|
|
||||||
{
|
|
||||||
if (type < ARRAY_SIZE(first_opt)) {
|
|
||||||
if (first_opt[type].seen) {
|
|
||||||
if (first_opt[type].headertype != entry) {
|
|
||||||
error_report("Can't mix file= and type= for same type");
|
|
||||||
loc_push_restore(&first_opt[type].loc);
|
|
||||||
error_report("This is the conflicting setting");
|
|
||||||
loc_pop(&first_opt[type].loc);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
first_opt[type].seen = true;
|
|
||||||
first_opt[type].headertype = entry;
|
|
||||||
loc_save(&first_opt[type].loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* legacy setup functions for <= 2.0 machines */
|
||||||
static void smbios_add_field(int type, int offset, const void *data, size_t len)
|
static void smbios_add_field(int type, int offset, const void *data, size_t len)
|
||||||
{
|
{
|
||||||
struct smbios_field *field;
|
struct smbios_field *field;
|
||||||
@@ -256,22 +392,13 @@ static void smbios_build_type_1_fields(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void smbios_set_type1_defaults(const char *manufacturer,
|
uint8_t *smbios_get_table_legacy(size_t *length)
|
||||||
const char *product, const char *version)
|
|
||||||
{
|
{
|
||||||
if (!type1.manufacturer) {
|
if (!smbios_legacy) {
|
||||||
type1.manufacturer = manufacturer;
|
*length = 0;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!type1.product) {
|
|
||||||
type1.product = product;
|
|
||||||
}
|
|
||||||
if (!type1.version) {
|
|
||||||
type1.version = version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *smbios_get_table(size_t *length)
|
|
||||||
{
|
|
||||||
if (!smbios_immutable) {
|
if (!smbios_immutable) {
|
||||||
smbios_build_type_0_fields();
|
smbios_build_type_0_fields();
|
||||||
smbios_build_type_1_fields();
|
smbios_build_type_1_fields();
|
||||||
@@ -281,6 +408,458 @@ uint8_t *smbios_get_table(size_t *length)
|
|||||||
*length = smbios_entries_len;
|
*length = smbios_entries_len;
|
||||||
return smbios_entries;
|
return smbios_entries;
|
||||||
}
|
}
|
||||||
|
/* end: legacy setup functions for <= 2.0 machines */
|
||||||
|
|
||||||
|
|
||||||
|
static bool smbios_skip_table(uint8_t type, bool required_table)
|
||||||
|
{
|
||||||
|
if (test_bit(type, have_binfile_bitmap)) {
|
||||||
|
return true; /* user provided their own binary blob(s) */
|
||||||
|
}
|
||||||
|
if (test_bit(type, have_fields_bitmap)) {
|
||||||
|
return false; /* user provided fields via command line */
|
||||||
|
}
|
||||||
|
if (smbios_have_defaults && required_table) {
|
||||||
|
return false; /* we're building tables, and this one's required */
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \
|
||||||
|
struct smbios_type_##tbl_type *t; \
|
||||||
|
size_t t_off; /* table offset into smbios_tables */ \
|
||||||
|
int str_index = 0; \
|
||||||
|
do { \
|
||||||
|
/* should we skip building this table ? */ \
|
||||||
|
if (smbios_skip_table(tbl_type, tbl_required)) { \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* use offset of table t within smbios_tables */ \
|
||||||
|
/* (pointer must be updated after each realloc) */ \
|
||||||
|
t_off = smbios_tables_len; \
|
||||||
|
smbios_tables_len += sizeof(*t); \
|
||||||
|
smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \
|
||||||
|
t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
|
||||||
|
\
|
||||||
|
t->header.type = tbl_type; \
|
||||||
|
t->header.length = sizeof(*t); \
|
||||||
|
t->header.handle = tbl_handle; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \
|
||||||
|
do { \
|
||||||
|
int len = (value != NULL) ? strlen(value) + 1 : 0; \
|
||||||
|
if (len > 1) { \
|
||||||
|
smbios_tables = g_realloc(smbios_tables, \
|
||||||
|
smbios_tables_len + len); \
|
||||||
|
memcpy(smbios_tables + smbios_tables_len, value, len); \
|
||||||
|
smbios_tables_len += len; \
|
||||||
|
/* update pointer post-realloc */ \
|
||||||
|
t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
|
||||||
|
t->field = ++str_index; \
|
||||||
|
} else { \
|
||||||
|
t->field = 0; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SMBIOS_BUILD_TABLE_POST \
|
||||||
|
do { \
|
||||||
|
size_t term_cnt, t_size; \
|
||||||
|
\
|
||||||
|
/* add '\0' terminator (add two if no strings defined) */ \
|
||||||
|
term_cnt = (str_index == 0) ? 2 : 1; \
|
||||||
|
smbios_tables = g_realloc(smbios_tables, \
|
||||||
|
smbios_tables_len + term_cnt); \
|
||||||
|
memset(smbios_tables + smbios_tables_len, 0, term_cnt); \
|
||||||
|
smbios_tables_len += term_cnt; \
|
||||||
|
\
|
||||||
|
/* update smbios max. element size */ \
|
||||||
|
t_size = smbios_tables_len - t_off; \
|
||||||
|
if (t_size > smbios_table_max) { \
|
||||||
|
smbios_table_max = t_size; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* update smbios element count */ \
|
||||||
|
smbios_table_cnt++; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void smbios_build_type_0_table(void)
|
||||||
|
{
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */
|
||||||
|
|
||||||
|
SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
|
||||||
|
SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
|
||||||
|
|
||||||
|
t->bios_starting_address_segment = 0xE800; /* hardcoded in SeaBIOS */
|
||||||
|
|
||||||
|
SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
|
||||||
|
|
||||||
|
t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
|
||||||
|
|
||||||
|
/* BIOS characteristics not supported */
|
||||||
|
memset(t->bios_characteristics, 0, 8);
|
||||||
|
t->bios_characteristics[0] = 0x08;
|
||||||
|
|
||||||
|
/* Enable targeted content distribution (needed for SVVP, per SeaBIOS) */
|
||||||
|
t->bios_characteristics_extension_bytes[0] = 0;
|
||||||
|
t->bios_characteristics_extension_bytes[1] = 4;
|
||||||
|
|
||||||
|
if (type0.have_major_minor) {
|
||||||
|
t->system_bios_major_release = type0.major;
|
||||||
|
t->system_bios_minor_release = type0.minor;
|
||||||
|
} else {
|
||||||
|
t->system_bios_major_release = 0;
|
||||||
|
t->system_bios_minor_release = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hardcoded in SeaBIOS */
|
||||||
|
t->embedded_controller_major_release = 0xFF;
|
||||||
|
t->embedded_controller_minor_release = 0xFF;
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbios_build_type_1_table(void)
|
||||||
|
{
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
|
||||||
|
|
||||||
|
SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
|
||||||
|
SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
|
||||||
|
SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
|
||||||
|
SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
|
||||||
|
if (qemu_uuid_set) {
|
||||||
|
memcpy(t->uuid, qemu_uuid, 16);
|
||||||
|
} else {
|
||||||
|
memset(t->uuid, 0, 16);
|
||||||
|
}
|
||||||
|
t->wake_up_type = 0x06; /* power switch */
|
||||||
|
SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
|
||||||
|
SMBIOS_TABLE_SET_STR(1, family_str, type1.family);
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbios_build_type_2_table(void)
|
||||||
|
{
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */
|
||||||
|
|
||||||
|
SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
|
||||||
|
SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
|
||||||
|
SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
|
||||||
|
SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
|
||||||
|
SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
|
||||||
|
t->feature_flags = 0x01; /* Motherboard */
|
||||||
|
SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
|
||||||
|
t->chassis_handle = 0x300; /* Type 3 (System enclosure) */
|
||||||
|
t->board_type = 0x0A; /* Motherboard */
|
||||||
|
t->contained_element_count = 0;
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbios_build_type_3_table(void)
|
||||||
|
{
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */
|
||||||
|
|
||||||
|
SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
|
||||||
|
t->type = 0x01; /* Other */
|
||||||
|
SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
|
||||||
|
SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
|
||||||
|
SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
|
||||||
|
t->boot_up_state = 0x03; /* Safe */
|
||||||
|
t->power_supply_state = 0x03; /* Safe */
|
||||||
|
t->thermal_state = 0x03; /* Safe */
|
||||||
|
t->security_status = 0x02; /* Unknown */
|
||||||
|
t->oem_defined = 0;
|
||||||
|
t->height = 0;
|
||||||
|
t->number_of_power_cords = 0;
|
||||||
|
t->contained_element_count = 0;
|
||||||
|
SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbios_build_type_4_table(unsigned instance)
|
||||||
|
{
|
||||||
|
char sock_str[128];
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */
|
||||||
|
|
||||||
|
snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
|
||||||
|
SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
|
||||||
|
t->processor_type = 0x03; /* CPU */
|
||||||
|
SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
|
||||||
|
t->processor_id[0] = smbios_cpuid_version;
|
||||||
|
t->processor_id[1] = smbios_cpuid_features;
|
||||||
|
SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
|
||||||
|
t->voltage = 0;
|
||||||
|
t->external_clock = 0; /* Unknown */
|
||||||
|
t->max_speed = 0; /* Unknown */
|
||||||
|
t->current_speed = 0; /* Unknown */
|
||||||
|
t->status = 0x41; /* Socket populated, CPU enabled */
|
||||||
|
t->processor_upgrade = 0x01; /* Other */
|
||||||
|
t->l1_cache_handle = 0xFFFF; /* N/A */
|
||||||
|
t->l2_cache_handle = 0xFFFF; /* N/A */
|
||||||
|
t->l3_cache_handle = 0xFFFF; /* N/A */
|
||||||
|
SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
|
||||||
|
SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
|
||||||
|
SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
|
||||||
|
t->core_count = t->core_enabled = smp_cores;
|
||||||
|
t->thread_count = smp_threads;
|
||||||
|
t->processor_characteristics = 0x02; /* Unknown */
|
||||||
|
t->processor_family = t->processor_family2 = 0x01; /* Other */
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
smbios_type4_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ONE_KB ((ram_addr_t)1 << 10)
|
||||||
|
#define ONE_MB ((ram_addr_t)1 << 20)
|
||||||
|
#define ONE_GB ((ram_addr_t)1 << 30)
|
||||||
|
|
||||||
|
#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
|
||||||
|
|
||||||
|
static void smbios_build_type_16_table(unsigned dimm_cnt)
|
||||||
|
{
|
||||||
|
ram_addr_t size_kb;
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
|
||||||
|
|
||||||
|
t->location = 0x01; /* Other */
|
||||||
|
t->use = 0x03; /* System memory */
|
||||||
|
t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
|
||||||
|
size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
|
||||||
|
if (size_kb < MAX_T16_STD_SZ) {
|
||||||
|
t->maximum_capacity = size_kb;
|
||||||
|
t->extended_maximum_capacity = 0;
|
||||||
|
} else {
|
||||||
|
t->maximum_capacity = MAX_T16_STD_SZ;
|
||||||
|
t->extended_maximum_capacity = ram_size;
|
||||||
|
}
|
||||||
|
t->memory_error_information_handle = 0xFFFE; /* Not provided */
|
||||||
|
t->number_of_memory_devices = dimm_cnt;
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
|
||||||
|
#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
|
||||||
|
|
||||||
|
static void smbios_build_type_17_table(unsigned instance, ram_addr_t size)
|
||||||
|
{
|
||||||
|
char loc_str[128];
|
||||||
|
ram_addr_t size_mb;
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
|
||||||
|
|
||||||
|
t->physical_memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
|
||||||
|
t->memory_error_information_handle = 0xFFFE; /* Not provided */
|
||||||
|
t->total_width = 0xFFFF; /* Unknown */
|
||||||
|
t->data_width = 0xFFFF; /* Unknown */
|
||||||
|
size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
|
||||||
|
if (size_mb < MAX_T17_STD_SZ) {
|
||||||
|
t->size = size_mb;
|
||||||
|
t->extended_size = 0;
|
||||||
|
} else {
|
||||||
|
assert(size_mb < MAX_T17_EXT_SZ);
|
||||||
|
t->size = MAX_T17_STD_SZ;
|
||||||
|
t->extended_size = size_mb;
|
||||||
|
}
|
||||||
|
t->form_factor = 0x09; /* DIMM */
|
||||||
|
t->device_set = 0; /* Not in a set */
|
||||||
|
snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
|
||||||
|
SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
|
||||||
|
SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
|
||||||
|
t->memory_type = 0x07; /* RAM */
|
||||||
|
t->type_detail = 0x02; /* Other */
|
||||||
|
t->speed = 0; /* Unknown */
|
||||||
|
SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
|
||||||
|
SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
|
||||||
|
SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
|
||||||
|
SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
|
||||||
|
t->attributes = 0; /* Unknown */
|
||||||
|
t->configured_clock_speed = 0; /* Unknown */
|
||||||
|
t->minimum_voltage = 0; /* Unknown */
|
||||||
|
t->maximum_voltage = 0; /* Unknown */
|
||||||
|
t->configured_voltage = 0; /* Unknown */
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbios_build_type_19_table(unsigned instance,
|
||||||
|
ram_addr_t start, ram_addr_t size)
|
||||||
|
{
|
||||||
|
ram_addr_t end, start_kb, end_kb;
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */
|
||||||
|
|
||||||
|
end = start + size - 1;
|
||||||
|
assert(end > start);
|
||||||
|
start_kb = start / ONE_KB;
|
||||||
|
end_kb = end / ONE_KB;
|
||||||
|
if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
|
||||||
|
t->starting_address = start_kb;
|
||||||
|
t->ending_address = end_kb;
|
||||||
|
t->extended_starting_address = t->extended_ending_address = 0;
|
||||||
|
} else {
|
||||||
|
t->starting_address = t->ending_address = UINT32_MAX;
|
||||||
|
t->extended_starting_address = start;
|
||||||
|
t->extended_ending_address = end;
|
||||||
|
}
|
||||||
|
t->memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
|
||||||
|
t->partition_width = 1; /* One device per row */
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbios_build_type_32_table(void)
|
||||||
|
{
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */
|
||||||
|
|
||||||
|
memset(t->reserved, 0, 6);
|
||||||
|
t->boot_status = 0; /* No errors detected */
|
||||||
|
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbios_build_type_127_table(void)
|
||||||
|
{
|
||||||
|
SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
|
||||||
|
SMBIOS_BUILD_TABLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void smbios_set_cpuid(uint32_t version, uint32_t features)
|
||||||
|
{
|
||||||
|
smbios_cpuid_version = version;
|
||||||
|
smbios_cpuid_features = features;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SMBIOS_SET_DEFAULT(field, value) \
|
||||||
|
if (!field) { \
|
||||||
|
field = value; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define G_FREE_UNLESS_NULL(ptr) \
|
||||||
|
if (ptr != NULL) { \
|
||||||
|
g_free(ptr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||||
|
const char *version, bool legacy_mode)
|
||||||
|
{
|
||||||
|
smbios_have_defaults = true;
|
||||||
|
smbios_legacy = legacy_mode;
|
||||||
|
|
||||||
|
/* drop unwanted version of command-line file blob(s) */
|
||||||
|
if (smbios_legacy) {
|
||||||
|
G_FREE_UNLESS_NULL(smbios_tables);
|
||||||
|
/* in legacy mode, also complain if fields were given for types > 1 */
|
||||||
|
if (find_next_bit(have_fields_bitmap,
|
||||||
|
SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) {
|
||||||
|
error_report("can't process fields for smbios "
|
||||||
|
"types > 1 on machine versions < 2.1!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
G_FREE_UNLESS_NULL(smbios_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer);
|
||||||
|
SMBIOS_SET_DEFAULT(type1.product, product);
|
||||||
|
SMBIOS_SET_DEFAULT(type1.version, version);
|
||||||
|
SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
|
||||||
|
SMBIOS_SET_DEFAULT(type2.product, product);
|
||||||
|
SMBIOS_SET_DEFAULT(type2.version, version);
|
||||||
|
SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
|
||||||
|
SMBIOS_SET_DEFAULT(type3.version, version);
|
||||||
|
SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
|
||||||
|
SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
|
||||||
|
SMBIOS_SET_DEFAULT(type4.version, version);
|
||||||
|
SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
|
||||||
|
SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smbios_entry_point_setup(void)
|
||||||
|
{
|
||||||
|
memcpy(ep.anchor_string, "_SM_", 4);
|
||||||
|
memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
|
||||||
|
ep.length = sizeof(struct smbios_entry_point);
|
||||||
|
ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */
|
||||||
|
memset(ep.formatted_area, 0, 5);
|
||||||
|
|
||||||
|
/* compliant with smbios spec v2.8 */
|
||||||
|
ep.smbios_major_version = 2;
|
||||||
|
ep.smbios_minor_version = 8;
|
||||||
|
ep.smbios_bcd_revision = 0x28;
|
||||||
|
|
||||||
|
/* set during table construction, but BIOS may override: */
|
||||||
|
ep.structure_table_length = smbios_tables_len;
|
||||||
|
ep.max_structure_size = smbios_table_max;
|
||||||
|
ep.number_of_structures = smbios_table_cnt;
|
||||||
|
|
||||||
|
/* BIOS must recalculate: */
|
||||||
|
ep.checksum = 0;
|
||||||
|
ep.intermediate_checksum = 0;
|
||||||
|
ep.structure_table_address = 0; /* where BIOS has copied smbios_tables */
|
||||||
|
}
|
||||||
|
|
||||||
|
void smbios_get_tables(uint8_t **tables, size_t *tables_len,
|
||||||
|
uint8_t **anchor, size_t *anchor_len)
|
||||||
|
{
|
||||||
|
unsigned i, dimm_cnt, instance;
|
||||||
|
|
||||||
|
if (smbios_legacy) {
|
||||||
|
*tables = *anchor = NULL;
|
||||||
|
*tables_len = *anchor_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!smbios_immutable) {
|
||||||
|
smbios_build_type_0_table();
|
||||||
|
smbios_build_type_1_table();
|
||||||
|
smbios_build_type_2_table();
|
||||||
|
smbios_build_type_3_table();
|
||||||
|
|
||||||
|
smbios_smp_sockets = smp_cpus / (smp_cores * smp_threads);
|
||||||
|
assert(smbios_smp_sockets >= 1);
|
||||||
|
|
||||||
|
for (i = 0; i < smbios_smp_sockets; i++) {
|
||||||
|
smbios_build_type_4_table(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_DIMM_SZ (16ll * ONE_GB)
|
||||||
|
#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ : ram_size % MAX_DIMM_SZ)
|
||||||
|
|
||||||
|
dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
|
||||||
|
|
||||||
|
smbios_build_type_16_table(dimm_cnt);
|
||||||
|
|
||||||
|
for (i = 0; i < dimm_cnt; i++) {
|
||||||
|
smbios_build_type_17_table(i, GET_DIMM_SZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, instance = 0; i < e820_get_num_entries(); i++) {
|
||||||
|
uint64_t address, length;
|
||||||
|
if (e820_get_entry(i, E820_RAM, &address, &length)) {
|
||||||
|
smbios_build_type_19_table(instance++, address, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
smbios_build_type_32_table();
|
||||||
|
smbios_build_type_127_table();
|
||||||
|
|
||||||
|
smbios_validate_table();
|
||||||
|
smbios_entry_point_setup();
|
||||||
|
smbios_immutable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return tables blob and entry point (anchor), and their sizes */
|
||||||
|
*tables = smbios_tables;
|
||||||
|
*tables_len = smbios_tables_len;
|
||||||
|
*anchor = (uint8_t *)&ep;
|
||||||
|
*anchor_len = sizeof(struct smbios_entry_point);
|
||||||
|
}
|
||||||
|
|
||||||
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
|
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
|
||||||
{
|
{
|
||||||
@@ -297,11 +876,12 @@ void smbios_entry_add(QemuOpts *opts)
|
|||||||
const char *val;
|
const char *val;
|
||||||
|
|
||||||
assert(!smbios_immutable);
|
assert(!smbios_immutable);
|
||||||
|
|
||||||
val = qemu_opt_get(opts, "file");
|
val = qemu_opt_get(opts, "file");
|
||||||
if (val) {
|
if (val) {
|
||||||
struct smbios_structure_header *header;
|
struct smbios_structure_header *header;
|
||||||
struct smbios_table *table;
|
|
||||||
int size;
|
int size;
|
||||||
|
struct smbios_table *table; /* legacy mode only */
|
||||||
|
|
||||||
qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err);
|
qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
@@ -315,31 +895,60 @@ void smbios_entry_add(QemuOpts *opts)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!smbios_entries) {
|
/*
|
||||||
smbios_entries_len = sizeof(uint16_t);
|
* NOTE: standard double '\0' terminator expected, per smbios spec.
|
||||||
smbios_entries = g_malloc0(smbios_entries_len);
|
* (except in legacy mode, where the second '\0' is implicit and
|
||||||
}
|
* will be inserted by the BIOS).
|
||||||
|
*/
|
||||||
|
smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
|
||||||
|
header = (struct smbios_structure_header *)(smbios_tables +
|
||||||
|
smbios_tables_len);
|
||||||
|
|
||||||
smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
if (load_image(val, (uint8_t *)header) != size) {
|
||||||
sizeof(*table) + size);
|
|
||||||
table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
|
|
||||||
table->header.type = SMBIOS_TABLE_ENTRY;
|
|
||||||
table->header.length = cpu_to_le16(sizeof(*table) + size);
|
|
||||||
|
|
||||||
if (load_image(val, table->data) != size) {
|
|
||||||
error_report("Failed to load SMBIOS file %s", val);
|
error_report("Failed to load SMBIOS file %s", val);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
header = (struct smbios_structure_header *)(table->data);
|
if (test_bit(header->type, have_fields_bitmap)) {
|
||||||
smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
|
error_report("can't load type %d struct, fields already specified!",
|
||||||
|
header->type);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
set_bit(header->type, have_binfile_bitmap);
|
||||||
|
|
||||||
if (header->type == 4) {
|
if (header->type == 4) {
|
||||||
smbios_type4_count++;
|
smbios_type4_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
smbios_tables_len += size;
|
||||||
|
if (size > smbios_table_max) {
|
||||||
|
smbios_table_max = size;
|
||||||
|
}
|
||||||
|
smbios_table_cnt++;
|
||||||
|
|
||||||
|
/* add a copy of the newly loaded blob to legacy smbios_entries */
|
||||||
|
/* NOTE: This code runs before smbios_set_defaults(), so we don't
|
||||||
|
* yet know which mode (legacy vs. aggregate-table) will be
|
||||||
|
* required. We therefore add the binary blob to both legacy
|
||||||
|
* (smbios_entries) and aggregate (smbios_tables) tables, and
|
||||||
|
* delete the one we don't need from smbios_set_defaults(),
|
||||||
|
* once we know which machine version has been requested.
|
||||||
|
*/
|
||||||
|
if (!smbios_entries) {
|
||||||
|
smbios_entries_len = sizeof(uint16_t);
|
||||||
|
smbios_entries = g_malloc0(smbios_entries_len);
|
||||||
|
}
|
||||||
|
smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||||
|
size + sizeof(*table));
|
||||||
|
table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
|
||||||
|
table->header.type = SMBIOS_TABLE_ENTRY;
|
||||||
|
table->header.length = cpu_to_le16(sizeof(*table) + size);
|
||||||
|
memcpy(table->data, header, size);
|
||||||
smbios_entries_len += sizeof(*table) + size;
|
smbios_entries_len += sizeof(*table) + size;
|
||||||
(*(uint16_t *)smbios_entries) =
|
(*(uint16_t *)smbios_entries) =
|
||||||
cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
||||||
|
/* end: add a copy of the newly loaded blob to legacy smbios_entries */
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +956,16 @@ void smbios_entry_add(QemuOpts *opts)
|
|||||||
if (val) {
|
if (val) {
|
||||||
unsigned long type = strtoul(val, NULL, 0);
|
unsigned long type = strtoul(val, NULL, 0);
|
||||||
|
|
||||||
smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
|
if (type > SMBIOS_MAX_TYPE) {
|
||||||
|
error_report("out of range!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_bit(type, have_binfile_bitmap)) {
|
||||||
|
error_report("can't add fields, binary file already loaded!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
set_bit(type, have_fields_bitmap);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -391,6 +1009,57 @@ void smbios_entry_add(QemuOpts *opts)
|
|||||||
qemu_uuid_set = true;
|
qemu_uuid_set = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case 2:
|
||||||
|
qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report("%s", error_get_pretty(local_err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
save_opt(&type2.manufacturer, opts, "manufacturer");
|
||||||
|
save_opt(&type2.product, opts, "product");
|
||||||
|
save_opt(&type2.version, opts, "version");
|
||||||
|
save_opt(&type2.serial, opts, "serial");
|
||||||
|
save_opt(&type2.asset, opts, "asset");
|
||||||
|
save_opt(&type2.location, opts, "location");
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report("%s", error_get_pretty(local_err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
save_opt(&type3.manufacturer, opts, "manufacturer");
|
||||||
|
save_opt(&type3.version, opts, "version");
|
||||||
|
save_opt(&type3.serial, opts, "serial");
|
||||||
|
save_opt(&type3.asset, opts, "asset");
|
||||||
|
save_opt(&type3.sku, opts, "sku");
|
||||||
|
return;
|
||||||
|
case 4:
|
||||||
|
qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report("%s", error_get_pretty(local_err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
save_opt(&type4.sock_pfx, opts, "sock_pfx");
|
||||||
|
save_opt(&type4.manufacturer, opts, "manufacturer");
|
||||||
|
save_opt(&type4.version, opts, "version");
|
||||||
|
save_opt(&type4.serial, opts, "serial");
|
||||||
|
save_opt(&type4.asset, opts, "asset");
|
||||||
|
save_opt(&type4.part, opts, "part");
|
||||||
|
return;
|
||||||
|
case 17:
|
||||||
|
qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report("%s", error_get_pretty(local_err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
save_opt(&type17.loc_pfx, opts, "loc_pfx");
|
||||||
|
save_opt(&type17.bank, opts, "bank");
|
||||||
|
save_opt(&type17.manufacturer, opts, "manufacturer");
|
||||||
|
save_opt(&type17.serial, opts, "serial");
|
||||||
|
save_opt(&type17.asset, opts, "asset");
|
||||||
|
save_opt(&type17.part, opts, "part");
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
error_report("Don't know how to build fields for SMBIOS type %ld",
|
error_report("Don't know how to build fields for SMBIOS type %ld",
|
||||||
type);
|
type);
|
||||||
|
|||||||
@@ -438,9 +438,9 @@ static void check_cmd(AHCIState *s, int port)
|
|||||||
|
|
||||||
if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
|
if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
|
||||||
for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
|
for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
|
||||||
if ((pr->cmd_issue & (1 << slot)) &&
|
if ((pr->cmd_issue & (1U << slot)) &&
|
||||||
!handle_cmd(s, port, slot)) {
|
!handle_cmd(s, port, slot)) {
|
||||||
pr->cmd_issue &= ~(1 << slot);
|
pr->cmd_issue &= ~(1U << slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1602,7 +1602,7 @@ static bool cmd_smart(IDEState *s, uint8_t cmd)
|
|||||||
case 2: /* extended self test */
|
case 2: /* extended self test */
|
||||||
s->smart_selftest_count++;
|
s->smart_selftest_count++;
|
||||||
if (s->smart_selftest_count > 21) {
|
if (s->smart_selftest_count > 21) {
|
||||||
s->smart_selftest_count = 0;
|
s->smart_selftest_count = 1;
|
||||||
}
|
}
|
||||||
n = 2 + (s->smart_selftest_count - 1) * 24;
|
n = 2 + (s->smart_selftest_count - 1) * 24;
|
||||||
s->smart_selftest_data[n] = s->sector;
|
s->smart_selftest_data[n] = s->sector;
|
||||||
|
|||||||
@@ -23,11 +23,20 @@
|
|||||||
static void aw_a10_pic_update(AwA10PICState *s)
|
static void aw_a10_pic_update(AwA10PICState *s)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
int irq = 0, fiq = 0;
|
int irq = 0, fiq = 0, pending;
|
||||||
|
|
||||||
|
s->vector = 0;
|
||||||
|
|
||||||
for (i = 0; i < AW_A10_PIC_REG_NUM; i++) {
|
for (i = 0; i < AW_A10_PIC_REG_NUM; i++) {
|
||||||
irq |= s->irq_pending[i] & ~s->mask[i];
|
irq |= s->irq_pending[i] & ~s->mask[i];
|
||||||
fiq |= s->select[i] & s->irq_pending[i] & ~s->mask[i];
|
fiq |= s->select[i] & s->irq_pending[i] & ~s->mask[i];
|
||||||
|
|
||||||
|
if (!s->vector) {
|
||||||
|
pending = ffs(s->irq_pending[i] & ~s->mask[i]);
|
||||||
|
if (pending) {
|
||||||
|
s->vector = (i * 32 + pending - 1) * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_set_irq(s->parent_irq, !!irq);
|
qemu_set_irq(s->parent_irq, !!irq);
|
||||||
@@ -40,6 +49,8 @@ static void aw_a10_pic_set_irq(void *opaque, int irq, int level)
|
|||||||
|
|
||||||
if (level) {
|
if (level) {
|
||||||
set_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
|
set_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
|
||||||
|
} else {
|
||||||
|
clear_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
|
||||||
}
|
}
|
||||||
aw_a10_pic_update(s);
|
aw_a10_pic_update(s);
|
||||||
}
|
}
|
||||||
@@ -84,9 +95,6 @@ static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
|
|||||||
uint8_t index = (offset & 0xc) / 4;
|
uint8_t index = (offset & 0xc) / 4;
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case AW_A10_PIC_VECTOR:
|
|
||||||
s->vector = value & ~0x3;
|
|
||||||
break;
|
|
||||||
case AW_A10_PIC_BASE_ADDR:
|
case AW_A10_PIC_BASE_ADDR:
|
||||||
s->base_addr = value & ~0x3;
|
s->base_addr = value & ~0x3;
|
||||||
case AW_A10_PIC_PROTECT:
|
case AW_A10_PIC_PROTECT:
|
||||||
@@ -96,7 +104,11 @@ static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
|
|||||||
s->nmi = value;
|
s->nmi = value;
|
||||||
break;
|
break;
|
||||||
case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
|
case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
|
||||||
s->irq_pending[index] &= ~value;
|
/*
|
||||||
|
* The register is read-only; nevertheless, Linux (including
|
||||||
|
* the version originally shipped by Allwinner) pretends to
|
||||||
|
* write to the register. Just ignore it.
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
|
case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
|
||||||
s->fiq_pending[index] &= ~value;
|
s->fiq_pending[index] &= ~value;
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ static void apic_sync_vapic(APICCommonState *s, int sync_type)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sync_type & SYNC_FROM_VAPIC) {
|
if (sync_type & SYNC_FROM_VAPIC) {
|
||||||
cpu_physical_memory_rw(s->vapic_paddr, (void *)&vapic_state,
|
cpu_physical_memory_read(s->vapic_paddr, &vapic_state,
|
||||||
sizeof(vapic_state), 0);
|
sizeof(vapic_state));
|
||||||
s->tpr = vapic_state.tpr;
|
s->tpr = vapic_state.tpr;
|
||||||
}
|
}
|
||||||
if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
|
if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
|
||||||
|
|||||||
@@ -117,7 +117,12 @@ void apic_report_irq_delivered(int delivered)
|
|||||||
|
|
||||||
void apic_reset_irq_delivered(void)
|
void apic_reset_irq_delivered(void)
|
||||||
{
|
{
|
||||||
trace_apic_reset_irq_delivered(apic_irq_delivered);
|
/* Copy this into a local variable to encourage gcc to emit a plain
|
||||||
|
* register for a sys/sdt.h marker. For details on this workaround, see:
|
||||||
|
* https://sourceware.org/bugzilla/show_bug.cgi?id=13296
|
||||||
|
*/
|
||||||
|
volatile int a_i_d = apic_irq_delivered;
|
||||||
|
trace_apic_reset_irq_delivered(a_i_d);
|
||||||
|
|
||||||
apic_irq_delivered = 0;
|
apic_irq_delivered = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
|
|||||||
return 10000;
|
return 10000;
|
||||||
case 0xd00: /* CPUID Base. */
|
case 0xd00: /* CPUID Base. */
|
||||||
cpu = ARM_CPU(current_cpu);
|
cpu = ARM_CPU(current_cpu);
|
||||||
return cpu->env.cp15.c0_cpuid;
|
return cpu->midr;
|
||||||
case 0xd04: /* Interrupt Control State. */
|
case 0xd04: /* Interrupt Control State. */
|
||||||
/* VECTACTIVE */
|
/* VECTACTIVE */
|
||||||
val = s->gic.running_irq[0];
|
val = s->gic.running_irq[0];
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ static void kvm_openpic_region_add(MemoryListener *listener,
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ignore events on regions that are not us */
|
||||||
|
if (section->mr != &opp->mem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
reg_base = section->offset_within_address_space;
|
reg_base = section->offset_within_address_space;
|
||||||
|
|
||||||
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
||||||
@@ -140,6 +145,11 @@ static void kvm_openpic_region_del(MemoryListener *listener,
|
|||||||
uint64_t reg_base = 0;
|
uint64_t reg_base = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Ignore events on regions that are not us */
|
||||||
|
if (section->mr != &opp->mem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
||||||
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
||||||
attr.addr = (uint64_t)(unsigned long)®_base;
|
attr.addr = (uint64_t)(unsigned long)®_base;
|
||||||
@@ -224,13 +234,9 @@ static void kvm_openpic_realize(DeviceState *dev, Error **errp)
|
|||||||
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
|
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
|
||||||
{
|
{
|
||||||
KVMOpenPICState *opp = KVM_OPENPIC(d);
|
KVMOpenPICState *opp = KVM_OPENPIC(d);
|
||||||
struct kvm_enable_cap encap = {};
|
|
||||||
|
|
||||||
encap.cap = KVM_CAP_IRQ_MPIC;
|
return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
|
||||||
encap.args[0] = opp->fd;
|
kvm_arch_vcpu_id(cs));
|
||||||
encap.args[1] = kvm_arch_vcpu_id(cs);
|
|
||||||
|
|
||||||
return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property kvm_openpic_properties[] = {
|
static Property kvm_openpic_properties[] = {
|
||||||
|
|||||||
@@ -331,15 +331,11 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
|||||||
|
|
||||||
if (icpkvm->kernel_xics_fd != -1) {
|
if (icpkvm->kernel_xics_fd != -1) {
|
||||||
int ret;
|
int ret;
|
||||||
struct kvm_enable_cap xics_enable_cap = {
|
|
||||||
.cap = KVM_CAP_IRQ_XICS,
|
|
||||||
.flags = 0,
|
|
||||||
.args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
ss->cs = cs;
|
ss->cs = cs;
|
||||||
|
|
||||||
ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
|
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0,
|
||||||
|
icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("Unable to connect CPU%ld to kernel XICS: %s",
|
error_report("Unable to connect CPU%ld to kernel XICS: %s",
|
||||||
kvm_arch_vcpu_id(cs), strerror(errno));
|
kvm_arch_vcpu_id(cs), strerror(errno));
|
||||||
|
|||||||
@@ -684,8 +684,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (s->role_val == IVSHMEM_PEER) {
|
if (s->role_val == IVSHMEM_PEER) {
|
||||||
error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
|
error_setg(&s->migration_blocker,
|
||||||
"peer mode", "ivshmem");
|
"Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
|
||||||
migrate_add_blocker(s->migration_blocker);
|
migrate_add_blocker(s->migration_blocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,12 +56,14 @@ static void tmp105_get_temperature(Object *obj, Visitor *v, void *opaque,
|
|||||||
const char *name, Error **errp)
|
const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
TMP105State *s = TMP105(obj);
|
TMP105State *s = TMP105(obj);
|
||||||
int64_t value = s->temperature;
|
int64_t value = s->temperature * 1000 / 256;
|
||||||
|
|
||||||
visit_type_int(v, &value, name, errp);
|
visit_type_int(v, &value, name, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Units are 0.001 centigrades relative to 0 C. */
|
/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
|
||||||
|
* fixed point, so units are 1/256 centigrades. A simple ratio will do.
|
||||||
|
*/
|
||||||
static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
|
static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
|
||||||
const char *name, Error **errp)
|
const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -78,7 +80,7 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
|
s->temperature = (int16_t) (temp * 256 / 1000);
|
||||||
|
|
||||||
tmp105_alarm_update(s);
|
tmp105_alarm_update(s);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,102 +19,155 @@
|
|||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
#ifdef ZYNQ_ARM_SLCR_ERR_DEBUG
|
#ifndef ZYNQ_SLCR_ERR_DEBUG
|
||||||
#define DB_PRINT(...) do { \
|
#define ZYNQ_SLCR_ERR_DEBUG 0
|
||||||
fprintf(stderr, ": %s: ", __func__); \
|
|
||||||
fprintf(stderr, ## __VA_ARGS__); \
|
|
||||||
} while (0);
|
|
||||||
#else
|
|
||||||
#define DB_PRINT(...)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DB_PRINT(...) do { \
|
||||||
|
if (ZYNQ_SLCR_ERR_DEBUG) { \
|
||||||
|
fprintf(stderr, ": %s: ", __func__); \
|
||||||
|
fprintf(stderr, ## __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
#define XILINX_LOCK_KEY 0x767b
|
#define XILINX_LOCK_KEY 0x767b
|
||||||
#define XILINX_UNLOCK_KEY 0xdf0d
|
#define XILINX_UNLOCK_KEY 0xdf0d
|
||||||
|
|
||||||
#define R_PSS_RST_CTRL_SOFT_RST 0x1
|
#define R_PSS_RST_CTRL_SOFT_RST 0x1
|
||||||
|
|
||||||
typedef enum {
|
enum {
|
||||||
ARM_PLL_CTRL,
|
SCL = 0x000 / 4,
|
||||||
DDR_PLL_CTRL,
|
LOCK,
|
||||||
IO_PLL_CTRL,
|
UNLOCK,
|
||||||
PLL_STATUS,
|
LOCKSTA,
|
||||||
ARM_PPL_CFG,
|
|
||||||
DDR_PLL_CFG,
|
|
||||||
IO_PLL_CFG,
|
|
||||||
PLL_BG_CTRL,
|
|
||||||
PLL_MAX
|
|
||||||
} PLLValues;
|
|
||||||
|
|
||||||
typedef enum {
|
ARM_PLL_CTRL = 0x100 / 4,
|
||||||
ARM_CLK_CTRL,
|
DDR_PLL_CTRL,
|
||||||
DDR_CLK_CTRL,
|
IO_PLL_CTRL,
|
||||||
DCI_CLK_CTRL,
|
PLL_STATUS,
|
||||||
APER_CLK_CTRL,
|
ARM_PLL_CFG,
|
||||||
USB0_CLK_CTRL,
|
DDR_PLL_CFG,
|
||||||
USB1_CLK_CTRL,
|
IO_PLL_CFG,
|
||||||
GEM0_RCLK_CTRL,
|
|
||||||
GEM1_RCLK_CTRL,
|
|
||||||
GEM0_CLK_CTRL,
|
|
||||||
GEM1_CLK_CTRL,
|
|
||||||
SMC_CLK_CTRL,
|
|
||||||
LQSPI_CLK_CTRL,
|
|
||||||
SDIO_CLK_CTRL,
|
|
||||||
UART_CLK_CTRL,
|
|
||||||
SPI_CLK_CTRL,
|
|
||||||
CAN_CLK_CTRL,
|
|
||||||
CAN_MIOCLK_CTRL,
|
|
||||||
DBG_CLK_CTRL,
|
|
||||||
PCAP_CLK_CTRL,
|
|
||||||
TOPSW_CLK_CTRL,
|
|
||||||
CLK_MAX
|
|
||||||
} ClkValues;
|
|
||||||
|
|
||||||
typedef enum {
|
ARM_CLK_CTRL = 0x120 / 4,
|
||||||
CLK_CTRL,
|
DDR_CLK_CTRL,
|
||||||
THR_CTRL,
|
DCI_CLK_CTRL,
|
||||||
THR_CNT,
|
APER_CLK_CTRL,
|
||||||
THR_STA,
|
USB0_CLK_CTRL,
|
||||||
FPGA_MAX
|
USB1_CLK_CTRL,
|
||||||
} FPGAValues;
|
GEM0_RCLK_CTRL,
|
||||||
|
GEM1_RCLK_CTRL,
|
||||||
|
GEM0_CLK_CTRL,
|
||||||
|
GEM1_CLK_CTRL,
|
||||||
|
SMC_CLK_CTRL,
|
||||||
|
LQSPI_CLK_CTRL,
|
||||||
|
SDIO_CLK_CTRL,
|
||||||
|
UART_CLK_CTRL,
|
||||||
|
SPI_CLK_CTRL,
|
||||||
|
CAN_CLK_CTRL,
|
||||||
|
CAN_MIOCLK_CTRL,
|
||||||
|
DBG_CLK_CTRL,
|
||||||
|
PCAP_CLK_CTRL,
|
||||||
|
TOPSW_CLK_CTRL,
|
||||||
|
|
||||||
typedef enum {
|
#define FPGA_CTRL_REGS(n, start) \
|
||||||
SYNC_CTRL,
|
FPGA ## n ## _CLK_CTRL = (start) / 4, \
|
||||||
SYNC_STATUS,
|
FPGA ## n ## _THR_CTRL, \
|
||||||
BANDGAP_TRIP,
|
FPGA ## n ## _THR_CNT, \
|
||||||
CC_TEST,
|
FPGA ## n ## _THR_STA,
|
||||||
PLL_PREDIVISOR,
|
FPGA_CTRL_REGS(0, 0x170)
|
||||||
CLK_621_TRUE,
|
FPGA_CTRL_REGS(1, 0x180)
|
||||||
PICTURE_DBG,
|
FPGA_CTRL_REGS(2, 0x190)
|
||||||
PICTURE_DBG_UCNT,
|
FPGA_CTRL_REGS(3, 0x1a0)
|
||||||
PICTURE_DBG_LCNT,
|
|
||||||
MISC_MAX
|
|
||||||
} MiscValues;
|
|
||||||
|
|
||||||
typedef enum {
|
BANDGAP_TRIP = 0x1b8 / 4,
|
||||||
PSS,
|
PLL_PREDIVISOR = 0x1c0 / 4,
|
||||||
DDDR,
|
CLK_621_TRUE,
|
||||||
DMAC = 3,
|
|
||||||
USB,
|
PSS_RST_CTRL = 0x200 / 4,
|
||||||
GEM,
|
DDR_RST_CTRL,
|
||||||
SDIO,
|
TOPSW_RESET_CTRL,
|
||||||
SPI,
|
DMAC_RST_CTRL,
|
||||||
CAN,
|
USB_RST_CTRL,
|
||||||
I2C,
|
GEM_RST_CTRL,
|
||||||
UART,
|
SDIO_RST_CTRL,
|
||||||
GPIO,
|
SPI_RST_CTRL,
|
||||||
LQSPI,
|
CAN_RST_CTRL,
|
||||||
SMC,
|
I2C_RST_CTRL,
|
||||||
OCM,
|
UART_RST_CTRL,
|
||||||
DEVCI,
|
GPIO_RST_CTRL,
|
||||||
FPGA,
|
LQSPI_RST_CTRL,
|
||||||
A9_CPU,
|
SMC_RST_CTRL,
|
||||||
RS_AWDT,
|
OCM_RST_CTRL,
|
||||||
RST_REASON,
|
FPGA_RST_CTRL = 0x240 / 4,
|
||||||
RST_REASON_CLR,
|
A9_CPU_RST_CTRL,
|
||||||
REBOOT_STATUS,
|
|
||||||
BOOT_MODE,
|
RS_AWDT_CTRL = 0x24c / 4,
|
||||||
RESET_MAX
|
RST_REASON,
|
||||||
} ResetValues;
|
|
||||||
|
REBOOT_STATUS = 0x258 / 4,
|
||||||
|
BOOT_MODE,
|
||||||
|
|
||||||
|
APU_CTRL = 0x300 / 4,
|
||||||
|
WDT_CLK_SEL,
|
||||||
|
|
||||||
|
TZ_DMA_NS = 0x440 / 4,
|
||||||
|
TZ_DMA_IRQ_NS,
|
||||||
|
TZ_DMA_PERIPH_NS,
|
||||||
|
|
||||||
|
PSS_IDCODE = 0x530 / 4,
|
||||||
|
|
||||||
|
DDR_URGENT = 0x600 / 4,
|
||||||
|
DDR_CAL_START = 0x60c / 4,
|
||||||
|
DDR_REF_START = 0x614 / 4,
|
||||||
|
DDR_CMD_STA,
|
||||||
|
DDR_URGENT_SEL,
|
||||||
|
DDR_DFI_STATUS,
|
||||||
|
|
||||||
|
MIO = 0x700 / 4,
|
||||||
|
#define MIO_LENGTH 54
|
||||||
|
|
||||||
|
MIO_LOOPBACK = 0x804 / 4,
|
||||||
|
MIO_MST_TRI0,
|
||||||
|
MIO_MST_TRI1,
|
||||||
|
|
||||||
|
SD0_WP_CD_SEL = 0x830 / 4,
|
||||||
|
SD1_WP_CD_SEL,
|
||||||
|
|
||||||
|
LVL_SHFTR_EN = 0x900 / 4,
|
||||||
|
OCM_CFG = 0x910 / 4,
|
||||||
|
|
||||||
|
CPU_RAM = 0xa00 / 4,
|
||||||
|
|
||||||
|
IOU = 0xa30 / 4,
|
||||||
|
|
||||||
|
DMAC_RAM = 0xa50 / 4,
|
||||||
|
|
||||||
|
AFI0 = 0xa60 / 4,
|
||||||
|
AFI1 = AFI0 + 3,
|
||||||
|
AFI2 = AFI1 + 3,
|
||||||
|
AFI3 = AFI2 + 3,
|
||||||
|
#define AFI_LENGTH 3
|
||||||
|
|
||||||
|
OCM = 0xa90 / 4,
|
||||||
|
|
||||||
|
DEVCI_RAM = 0xaa0 / 4,
|
||||||
|
|
||||||
|
CSG_RAM = 0xab0 / 4,
|
||||||
|
|
||||||
|
GPIOB_CTRL = 0xb00 / 4,
|
||||||
|
GPIOB_CFG_CMOS18,
|
||||||
|
GPIOB_CFG_CMOS25,
|
||||||
|
GPIOB_CFG_CMOS33,
|
||||||
|
GPIOB_CFG_HSTL = 0xb14 / 4,
|
||||||
|
GPIOB_DRVR_BIAS_CTRL,
|
||||||
|
|
||||||
|
DDRIOB = 0xb40 / 4,
|
||||||
|
#define DDRIOB_LENGTH 14
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ZYNQ_SLCR_MMIO_SIZE 0x1000
|
||||||
|
#define ZYNQ_SLCR_NUM_REGS (ZYNQ_SLCR_MMIO_SIZE / 4)
|
||||||
|
|
||||||
#define TYPE_ZYNQ_SLCR "xilinx,zynq_slcr"
|
#define TYPE_ZYNQ_SLCR "xilinx,zynq_slcr"
|
||||||
#define ZYNQ_SLCR(obj) OBJECT_CHECK(ZynqSLCRState, (obj), TYPE_ZYNQ_SLCR)
|
#define ZYNQ_SLCR(obj) OBJECT_CHECK(ZynqSLCRState, (obj), TYPE_ZYNQ_SLCR)
|
||||||
@@ -124,42 +177,7 @@ typedef struct ZynqSLCRState {
|
|||||||
|
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
|
|
||||||
union {
|
uint32_t regs[ZYNQ_SLCR_NUM_REGS];
|
||||||
struct {
|
|
||||||
uint16_t scl;
|
|
||||||
uint16_t lockval;
|
|
||||||
uint32_t pll[PLL_MAX]; /* 0x100 - 0x11C */
|
|
||||||
uint32_t clk[CLK_MAX]; /* 0x120 - 0x16C */
|
|
||||||
uint32_t fpga[4][FPGA_MAX]; /* 0x170 - 0x1AC */
|
|
||||||
uint32_t misc[MISC_MAX]; /* 0x1B0 - 0x1D8 */
|
|
||||||
uint32_t reset[RESET_MAX]; /* 0x200 - 0x25C */
|
|
||||||
uint32_t apu_ctrl; /* 0x300 */
|
|
||||||
uint32_t wdt_clk_sel; /* 0x304 */
|
|
||||||
uint32_t tz_ocm[3]; /* 0x400 - 0x408 */
|
|
||||||
uint32_t tz_ddr; /* 0x430 */
|
|
||||||
uint32_t tz_dma[3]; /* 0x440 - 0x448 */
|
|
||||||
uint32_t tz_misc[3]; /* 0x450 - 0x458 */
|
|
||||||
uint32_t tz_fpga[2]; /* 0x484 - 0x488 */
|
|
||||||
uint32_t dbg_ctrl; /* 0x500 */
|
|
||||||
uint32_t pss_idcode; /* 0x530 */
|
|
||||||
uint32_t ddr[8]; /* 0x600 - 0x620 - 0x604-missing */
|
|
||||||
uint32_t mio[54]; /* 0x700 - 0x7D4 */
|
|
||||||
uint32_t mio_func[4]; /* 0x800 - 0x810 */
|
|
||||||
uint32_t sd[2]; /* 0x830 - 0x834 */
|
|
||||||
uint32_t lvl_shftr_en; /* 0x900 */
|
|
||||||
uint32_t ocm_cfg; /* 0x910 */
|
|
||||||
uint32_t cpu_ram[8]; /* 0xA00 - 0xA1C */
|
|
||||||
uint32_t iou[7]; /* 0xA30 - 0xA48 */
|
|
||||||
uint32_t dmac_ram; /* 0xA50 */
|
|
||||||
uint32_t afi[4][3]; /* 0xA60 - 0xA8C */
|
|
||||||
uint32_t ocm[3]; /* 0xA90 - 0xA98 */
|
|
||||||
uint32_t devci_ram; /* 0xAA0 */
|
|
||||||
uint32_t csg_ram; /* 0xAB0 */
|
|
||||||
uint32_t gpiob[12]; /* 0xB00 - 0xB2C */
|
|
||||||
uint32_t ddriob[14]; /* 0xB40 - 0xB74 */
|
|
||||||
};
|
|
||||||
uint8_t data[0x1000];
|
|
||||||
};
|
|
||||||
} ZynqSLCRState;
|
} ZynqSLCRState;
|
||||||
|
|
||||||
static void zynq_slcr_reset(DeviceState *d)
|
static void zynq_slcr_reset(DeviceState *d)
|
||||||
@@ -169,177 +187,169 @@ static void zynq_slcr_reset(DeviceState *d)
|
|||||||
|
|
||||||
DB_PRINT("RESET\n");
|
DB_PRINT("RESET\n");
|
||||||
|
|
||||||
s->lockval = 1;
|
s->regs[LOCKSTA] = 1;
|
||||||
/* 0x100 - 0x11C */
|
/* 0x100 - 0x11C */
|
||||||
s->pll[ARM_PLL_CTRL] = 0x0001A008;
|
s->regs[ARM_PLL_CTRL] = 0x0001A008;
|
||||||
s->pll[DDR_PLL_CTRL] = 0x0001A008;
|
s->regs[DDR_PLL_CTRL] = 0x0001A008;
|
||||||
s->pll[IO_PLL_CTRL] = 0x0001A008;
|
s->regs[IO_PLL_CTRL] = 0x0001A008;
|
||||||
s->pll[PLL_STATUS] = 0x0000003F;
|
s->regs[PLL_STATUS] = 0x0000003F;
|
||||||
s->pll[ARM_PPL_CFG] = 0x00014000;
|
s->regs[ARM_PLL_CFG] = 0x00014000;
|
||||||
s->pll[DDR_PLL_CFG] = 0x00014000;
|
s->regs[DDR_PLL_CFG] = 0x00014000;
|
||||||
s->pll[IO_PLL_CFG] = 0x00014000;
|
s->regs[IO_PLL_CFG] = 0x00014000;
|
||||||
|
|
||||||
/* 0x120 - 0x16C */
|
/* 0x120 - 0x16C */
|
||||||
s->clk[ARM_CLK_CTRL] = 0x1F000400;
|
s->regs[ARM_CLK_CTRL] = 0x1F000400;
|
||||||
s->clk[DDR_CLK_CTRL] = 0x18400003;
|
s->regs[DDR_CLK_CTRL] = 0x18400003;
|
||||||
s->clk[DCI_CLK_CTRL] = 0x01E03201;
|
s->regs[DCI_CLK_CTRL] = 0x01E03201;
|
||||||
s->clk[APER_CLK_CTRL] = 0x01FFCCCD;
|
s->regs[APER_CLK_CTRL] = 0x01FFCCCD;
|
||||||
s->clk[USB0_CLK_CTRL] = s->clk[USB1_CLK_CTRL] = 0x00101941;
|
s->regs[USB0_CLK_CTRL] = s->regs[USB1_CLK_CTRL] = 0x00101941;
|
||||||
s->clk[GEM0_RCLK_CTRL] = s->clk[GEM1_RCLK_CTRL] = 0x00000001;
|
s->regs[GEM0_RCLK_CTRL] = s->regs[GEM1_RCLK_CTRL] = 0x00000001;
|
||||||
s->clk[GEM0_CLK_CTRL] = s->clk[GEM1_CLK_CTRL] = 0x00003C01;
|
s->regs[GEM0_CLK_CTRL] = s->regs[GEM1_CLK_CTRL] = 0x00003C01;
|
||||||
s->clk[SMC_CLK_CTRL] = 0x00003C01;
|
s->regs[SMC_CLK_CTRL] = 0x00003C01;
|
||||||
s->clk[LQSPI_CLK_CTRL] = 0x00002821;
|
s->regs[LQSPI_CLK_CTRL] = 0x00002821;
|
||||||
s->clk[SDIO_CLK_CTRL] = 0x00001E03;
|
s->regs[SDIO_CLK_CTRL] = 0x00001E03;
|
||||||
s->clk[UART_CLK_CTRL] = 0x00003F03;
|
s->regs[UART_CLK_CTRL] = 0x00003F03;
|
||||||
s->clk[SPI_CLK_CTRL] = 0x00003F03;
|
s->regs[SPI_CLK_CTRL] = 0x00003F03;
|
||||||
s->clk[CAN_CLK_CTRL] = 0x00501903;
|
s->regs[CAN_CLK_CTRL] = 0x00501903;
|
||||||
s->clk[DBG_CLK_CTRL] = 0x00000F03;
|
s->regs[DBG_CLK_CTRL] = 0x00000F03;
|
||||||
s->clk[PCAP_CLK_CTRL] = 0x00000F01;
|
s->regs[PCAP_CLK_CTRL] = 0x00000F01;
|
||||||
|
|
||||||
/* 0x170 - 0x1AC */
|
/* 0x170 - 0x1AC */
|
||||||
s->fpga[0][CLK_CTRL] = s->fpga[1][CLK_CTRL] = s->fpga[2][CLK_CTRL] =
|
s->regs[FPGA0_CLK_CTRL] = s->regs[FPGA1_CLK_CTRL] = s->regs[FPGA2_CLK_CTRL]
|
||||||
s->fpga[3][CLK_CTRL] = 0x00101800;
|
= s->regs[FPGA3_CLK_CTRL] = 0x00101800;
|
||||||
s->fpga[0][THR_STA] = s->fpga[1][THR_STA] = s->fpga[2][THR_STA] =
|
s->regs[FPGA0_THR_STA] = s->regs[FPGA1_THR_STA] = s->regs[FPGA2_THR_STA]
|
||||||
s->fpga[3][THR_STA] = 0x00010000;
|
= s->regs[FPGA3_THR_STA] = 0x00010000;
|
||||||
|
|
||||||
/* 0x1B0 - 0x1D8 */
|
/* 0x1B0 - 0x1D8 */
|
||||||
s->misc[BANDGAP_TRIP] = 0x0000001F;
|
s->regs[BANDGAP_TRIP] = 0x0000001F;
|
||||||
s->misc[PLL_PREDIVISOR] = 0x00000001;
|
s->regs[PLL_PREDIVISOR] = 0x00000001;
|
||||||
s->misc[CLK_621_TRUE] = 0x00000001;
|
s->regs[CLK_621_TRUE] = 0x00000001;
|
||||||
|
|
||||||
/* 0x200 - 0x25C */
|
/* 0x200 - 0x25C */
|
||||||
s->reset[FPGA] = 0x01F33F0F;
|
s->regs[FPGA_RST_CTRL] = 0x01F33F0F;
|
||||||
s->reset[RST_REASON] = 0x00000040;
|
s->regs[RST_REASON] = 0x00000040;
|
||||||
|
|
||||||
|
s->regs[BOOT_MODE] = 0x00000001;
|
||||||
|
|
||||||
/* 0x700 - 0x7D4 */
|
/* 0x700 - 0x7D4 */
|
||||||
for (i = 0; i < 54; i++) {
|
for (i = 0; i < 54; i++) {
|
||||||
s->mio[i] = 0x00001601;
|
s->regs[MIO + i] = 0x00001601;
|
||||||
}
|
}
|
||||||
for (i = 2; i <= 8; i++) {
|
for (i = 2; i <= 8; i++) {
|
||||||
s->mio[i] = 0x00000601;
|
s->regs[MIO + i] = 0x00000601;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIO_MST_TRI0, MIO_MST_TRI1 */
|
s->regs[MIO_MST_TRI0] = s->regs[MIO_MST_TRI1] = 0xFFFFFFFF;
|
||||||
s->mio_func[2] = s->mio_func[3] = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
s->cpu_ram[0] = s->cpu_ram[1] = s->cpu_ram[3] =
|
s->regs[CPU_RAM + 0] = s->regs[CPU_RAM + 1] = s->regs[CPU_RAM + 3]
|
||||||
s->cpu_ram[4] = s->cpu_ram[7] = 0x00010101;
|
= s->regs[CPU_RAM + 4] = s->regs[CPU_RAM + 7]
|
||||||
s->cpu_ram[2] = s->cpu_ram[5] = 0x01010101;
|
= 0x00010101;
|
||||||
s->cpu_ram[6] = 0x00000001;
|
s->regs[CPU_RAM + 2] = s->regs[CPU_RAM + 5] = 0x01010101;
|
||||||
|
s->regs[CPU_RAM + 6] = 0x00000001;
|
||||||
|
|
||||||
s->iou[0] = s->iou[1] = s->iou[2] = s->iou[3] = 0x09090909;
|
s->regs[IOU + 0] = s->regs[IOU + 1] = s->regs[IOU + 2] = s->regs[IOU + 3]
|
||||||
s->iou[4] = s->iou[5] = 0x00090909;
|
= 0x09090909;
|
||||||
s->iou[6] = 0x00000909;
|
s->regs[IOU + 4] = s->regs[IOU + 5] = 0x00090909;
|
||||||
|
s->regs[IOU + 6] = 0x00000909;
|
||||||
|
|
||||||
s->dmac_ram = 0x00000009;
|
s->regs[DMAC_RAM] = 0x00000009;
|
||||||
|
|
||||||
s->afi[0][0] = s->afi[0][1] = 0x09090909;
|
s->regs[AFI0 + 0] = s->regs[AFI0 + 1] = 0x09090909;
|
||||||
s->afi[1][0] = s->afi[1][1] = 0x09090909;
|
s->regs[AFI1 + 0] = s->regs[AFI1 + 1] = 0x09090909;
|
||||||
s->afi[2][0] = s->afi[2][1] = 0x09090909;
|
s->regs[AFI2 + 0] = s->regs[AFI2 + 1] = 0x09090909;
|
||||||
s->afi[3][0] = s->afi[3][1] = 0x09090909;
|
s->regs[AFI3 + 0] = s->regs[AFI3 + 1] = 0x09090909;
|
||||||
s->afi[0][2] = s->afi[1][2] = s->afi[2][2] = s->afi[3][2] = 0x00000909;
|
s->regs[AFI0 + 2] = s->regs[AFI1 + 2] = s->regs[AFI2 + 2]
|
||||||
|
= s->regs[AFI3 + 2] = 0x00000909;
|
||||||
|
|
||||||
s->ocm[0] = 0x01010101;
|
s->regs[OCM + 0] = 0x01010101;
|
||||||
s->ocm[1] = s->ocm[2] = 0x09090909;
|
s->regs[OCM + 1] = s->regs[OCM + 2] = 0x09090909;
|
||||||
|
|
||||||
s->devci_ram = 0x00000909;
|
s->regs[DEVCI_RAM] = 0x00000909;
|
||||||
s->csg_ram = 0x00000001;
|
s->regs[CSG_RAM] = 0x00000001;
|
||||||
|
|
||||||
s->ddriob[0] = s->ddriob[1] = s->ddriob[2] = s->ddriob[3] = 0x00000e00;
|
s->regs[DDRIOB + 0] = s->regs[DDRIOB + 1] = s->regs[DDRIOB + 2]
|
||||||
s->ddriob[4] = s->ddriob[5] = s->ddriob[6] = 0x00000e00;
|
= s->regs[DDRIOB + 3] = 0x00000e00;
|
||||||
s->ddriob[12] = 0x00000021;
|
s->regs[DDRIOB + 4] = s->regs[DDRIOB + 5] = s->regs[DDRIOB + 6]
|
||||||
|
= 0x00000e00;
|
||||||
|
s->regs[DDRIOB + 12] = 0x00000021;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t zynq_slcr_read_imp(void *opaque,
|
|
||||||
hwaddr offset)
|
|
||||||
{
|
|
||||||
ZynqSLCRState *s = (ZynqSLCRState *)opaque;
|
|
||||||
|
|
||||||
|
static bool zynq_slcr_check_offset(hwaddr offset, bool rnw)
|
||||||
|
{
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 0x0: /* SCL */
|
case LOCK:
|
||||||
return s->scl;
|
case UNLOCK:
|
||||||
case 0x4: /* LOCK */
|
case DDR_CAL_START:
|
||||||
case 0x8: /* UNLOCK */
|
case DDR_REF_START:
|
||||||
DB_PRINT("Reading SCLR_LOCK/UNLOCK is not enabled\n");
|
return !rnw; /* Write only */
|
||||||
return 0;
|
case LOCKSTA:
|
||||||
case 0x0C: /* LOCKSTA */
|
case FPGA0_THR_STA:
|
||||||
return s->lockval;
|
case FPGA1_THR_STA:
|
||||||
case 0x100 ... 0x11C:
|
case FPGA2_THR_STA:
|
||||||
return s->pll[(offset - 0x100) / 4];
|
case FPGA3_THR_STA:
|
||||||
case 0x120 ... 0x16C:
|
case BOOT_MODE:
|
||||||
return s->clk[(offset - 0x120) / 4];
|
case PSS_IDCODE:
|
||||||
case 0x170 ... 0x1AC:
|
case DDR_CMD_STA:
|
||||||
return s->fpga[0][(offset - 0x170) / 4];
|
case DDR_DFI_STATUS:
|
||||||
case 0x1B0 ... 0x1D8:
|
case PLL_STATUS:
|
||||||
return s->misc[(offset - 0x1B0) / 4];
|
return rnw;/* read only */
|
||||||
case 0x200 ... 0x258:
|
case SCL:
|
||||||
return s->reset[(offset - 0x200) / 4];
|
case ARM_PLL_CTRL ... IO_PLL_CTRL:
|
||||||
case 0x25c:
|
case ARM_PLL_CFG ... IO_PLL_CFG:
|
||||||
return 1;
|
case ARM_CLK_CTRL ... TOPSW_CLK_CTRL:
|
||||||
case 0x300:
|
case FPGA0_CLK_CTRL ... FPGA0_THR_CNT:
|
||||||
return s->apu_ctrl;
|
case FPGA1_CLK_CTRL ... FPGA1_THR_CNT:
|
||||||
case 0x304:
|
case FPGA2_CLK_CTRL ... FPGA2_THR_CNT:
|
||||||
return s->wdt_clk_sel;
|
case FPGA3_CLK_CTRL ... FPGA3_THR_CNT:
|
||||||
case 0x400 ... 0x408:
|
case BANDGAP_TRIP:
|
||||||
return s->tz_ocm[(offset - 0x400) / 4];
|
case PLL_PREDIVISOR:
|
||||||
case 0x430:
|
case CLK_621_TRUE:
|
||||||
return s->tz_ddr;
|
case PSS_RST_CTRL ... A9_CPU_RST_CTRL:
|
||||||
case 0x440 ... 0x448:
|
case RS_AWDT_CTRL:
|
||||||
return s->tz_dma[(offset - 0x440) / 4];
|
case RST_REASON:
|
||||||
case 0x450 ... 0x458:
|
case REBOOT_STATUS:
|
||||||
return s->tz_misc[(offset - 0x450) / 4];
|
case APU_CTRL:
|
||||||
case 0x484 ... 0x488:
|
case WDT_CLK_SEL:
|
||||||
return s->tz_fpga[(offset - 0x484) / 4];
|
case TZ_DMA_NS ... TZ_DMA_PERIPH_NS:
|
||||||
case 0x500:
|
case DDR_URGENT:
|
||||||
return s->dbg_ctrl;
|
case DDR_URGENT_SEL:
|
||||||
case 0x530:
|
case MIO ... MIO + MIO_LENGTH - 1:
|
||||||
return s->pss_idcode;
|
case MIO_LOOPBACK ... MIO_MST_TRI1:
|
||||||
case 0x600 ... 0x620:
|
case SD0_WP_CD_SEL:
|
||||||
if (offset == 0x604) {
|
case SD1_WP_CD_SEL:
|
||||||
goto bad_reg;
|
case LVL_SHFTR_EN:
|
||||||
}
|
case OCM_CFG:
|
||||||
return s->ddr[(offset - 0x600) / 4];
|
case CPU_RAM:
|
||||||
case 0x700 ... 0x7D4:
|
case IOU:
|
||||||
return s->mio[(offset - 0x700) / 4];
|
case DMAC_RAM:
|
||||||
case 0x800 ... 0x810:
|
case AFI0 ... AFI3 + AFI_LENGTH - 1:
|
||||||
return s->mio_func[(offset - 0x800) / 4];
|
case OCM:
|
||||||
case 0x830 ... 0x834:
|
case DEVCI_RAM:
|
||||||
return s->sd[(offset - 0x830) / 4];
|
case CSG_RAM:
|
||||||
case 0x900:
|
case GPIOB_CTRL ... GPIOB_CFG_CMOS33:
|
||||||
return s->lvl_shftr_en;
|
case GPIOB_CFG_HSTL:
|
||||||
case 0x910:
|
case GPIOB_DRVR_BIAS_CTRL:
|
||||||
return s->ocm_cfg;
|
case DDRIOB ... DDRIOB + DDRIOB_LENGTH - 1:
|
||||||
case 0xA00 ... 0xA1C:
|
return true;
|
||||||
return s->cpu_ram[(offset - 0xA00) / 4];
|
|
||||||
case 0xA30 ... 0xA48:
|
|
||||||
return s->iou[(offset - 0xA30) / 4];
|
|
||||||
case 0xA50:
|
|
||||||
return s->dmac_ram;
|
|
||||||
case 0xA60 ... 0xA8C:
|
|
||||||
return s->afi[0][(offset - 0xA60) / 4];
|
|
||||||
case 0xA90 ... 0xA98:
|
|
||||||
return s->ocm[(offset - 0xA90) / 4];
|
|
||||||
case 0xAA0:
|
|
||||||
return s->devci_ram;
|
|
||||||
case 0xAB0:
|
|
||||||
return s->csg_ram;
|
|
||||||
case 0xB00 ... 0xB2C:
|
|
||||||
return s->gpiob[(offset - 0xB00) / 4];
|
|
||||||
case 0xB40 ... 0xB74:
|
|
||||||
return s->ddriob[(offset - 0xB40) / 4];
|
|
||||||
default:
|
default:
|
||||||
bad_reg:
|
return false;
|
||||||
DB_PRINT("Bad register offset 0x%x\n", (int)offset);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t zynq_slcr_read(void *opaque, hwaddr offset,
|
static uint64_t zynq_slcr_read(void *opaque, hwaddr offset,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
uint32_t ret = zynq_slcr_read_imp(opaque, offset);
|
ZynqSLCRState *s = opaque;
|
||||||
|
offset /= 4;
|
||||||
|
uint32_t ret = s->regs[offset];
|
||||||
|
|
||||||
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
|
if (!zynq_slcr_check_offset(offset, true)) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to "
|
||||||
|
" addr %" HWADDR_PRIx "\n", offset * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset * 4, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,148 +357,55 @@ static void zynq_slcr_write(void *opaque, hwaddr offset,
|
|||||||
uint64_t val, unsigned size)
|
uint64_t val, unsigned size)
|
||||||
{
|
{
|
||||||
ZynqSLCRState *s = (ZynqSLCRState *)opaque;
|
ZynqSLCRState *s = (ZynqSLCRState *)opaque;
|
||||||
|
offset /= 4;
|
||||||
|
|
||||||
DB_PRINT("offset: %08x data: %08x\n", (unsigned)offset, (unsigned)val);
|
DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx64 "\n", offset * 4, val);
|
||||||
|
|
||||||
|
if (!zynq_slcr_check_offset(offset, false)) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid write access to "
|
||||||
|
"addr %" HWADDR_PRIx "\n", offset * 4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 0x00: /* SCL */
|
case SCL:
|
||||||
s->scl = val & 0x1;
|
s->regs[SCL] = val & 0x1;
|
||||||
return;
|
return;
|
||||||
case 0x4: /* SLCR_LOCK */
|
case LOCK:
|
||||||
if ((val & 0xFFFF) == XILINX_LOCK_KEY) {
|
if ((val & 0xFFFF) == XILINX_LOCK_KEY) {
|
||||||
DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
|
DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
|
||||||
(unsigned)val & 0xFFFF);
|
(unsigned)val & 0xFFFF);
|
||||||
s->lockval = 1;
|
s->regs[LOCKSTA] = 1;
|
||||||
} else {
|
} else {
|
||||||
DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
|
DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
|
||||||
(int)offset, (unsigned)val & 0xFFFF);
|
(int)offset, (unsigned)val & 0xFFFF);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 0x8: /* SLCR_UNLOCK */
|
case UNLOCK:
|
||||||
if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) {
|
if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) {
|
||||||
DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
|
DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
|
||||||
(unsigned)val & 0xFFFF);
|
(unsigned)val & 0xFFFF);
|
||||||
s->lockval = 0;
|
s->regs[LOCKSTA] = 0;
|
||||||
} else {
|
} else {
|
||||||
DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
|
DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
|
||||||
(int)offset, (unsigned)val & 0xFFFF);
|
(int)offset, (unsigned)val & 0xFFFF);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 0xc: /* LOCKSTA */
|
}
|
||||||
DB_PRINT("Writing SCLR_LOCKSTA is not enabled\n");
|
|
||||||
|
if (!s->regs[LOCKSTA]) {
|
||||||
|
s->regs[offset / 4] = val;
|
||||||
|
} else {
|
||||||
|
DB_PRINT("SCLR registers are locked. Unlock them first\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s->lockval) {
|
switch (offset) {
|
||||||
switch (offset) {
|
case PSS_RST_CTRL:
|
||||||
case 0x100 ... 0x11C:
|
if (val & R_PSS_RST_CTRL_SOFT_RST) {
|
||||||
if (offset == 0x10C) {
|
qemu_system_reset_request();
|
||||||
goto bad_reg;
|
|
||||||
}
|
|
||||||
s->pll[(offset - 0x100) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x120 ... 0x16C:
|
|
||||||
s->clk[(offset - 0x120) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x170 ... 0x1AC:
|
|
||||||
s->fpga[0][(offset - 0x170) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x1B0 ... 0x1D8:
|
|
||||||
s->misc[(offset - 0x1B0) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x200 ... 0x25C:
|
|
||||||
if (offset == 0x250) {
|
|
||||||
goto bad_reg;
|
|
||||||
}
|
|
||||||
s->reset[(offset - 0x200) / 4] = val;
|
|
||||||
if (offset == 0x200 && (val & R_PSS_RST_CTRL_SOFT_RST)) {
|
|
||||||
qemu_system_reset_request();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x300:
|
|
||||||
s->apu_ctrl = val;
|
|
||||||
break;
|
|
||||||
case 0x304:
|
|
||||||
s->wdt_clk_sel = val;
|
|
||||||
break;
|
|
||||||
case 0x400 ... 0x408:
|
|
||||||
s->tz_ocm[(offset - 0x400) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x430:
|
|
||||||
s->tz_ddr = val;
|
|
||||||
break;
|
|
||||||
case 0x440 ... 0x448:
|
|
||||||
s->tz_dma[(offset - 0x440) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x450 ... 0x458:
|
|
||||||
s->tz_misc[(offset - 0x450) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x484 ... 0x488:
|
|
||||||
s->tz_fpga[(offset - 0x484) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x500:
|
|
||||||
s->dbg_ctrl = val;
|
|
||||||
break;
|
|
||||||
case 0x530:
|
|
||||||
s->pss_idcode = val;
|
|
||||||
break;
|
|
||||||
case 0x600 ... 0x620:
|
|
||||||
if (offset == 0x604) {
|
|
||||||
goto bad_reg;
|
|
||||||
}
|
|
||||||
s->ddr[(offset - 0x600) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x700 ... 0x7D4:
|
|
||||||
s->mio[(offset - 0x700) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x800 ... 0x810:
|
|
||||||
s->mio_func[(offset - 0x800) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x830 ... 0x834:
|
|
||||||
s->sd[(offset - 0x830) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0x900:
|
|
||||||
s->lvl_shftr_en = val;
|
|
||||||
break;
|
|
||||||
case 0x910:
|
|
||||||
break;
|
|
||||||
case 0xA00 ... 0xA1C:
|
|
||||||
s->cpu_ram[(offset - 0xA00) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0xA30 ... 0xA48:
|
|
||||||
s->iou[(offset - 0xA30) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0xA50:
|
|
||||||
s->dmac_ram = val;
|
|
||||||
break;
|
|
||||||
case 0xA60 ... 0xA8C:
|
|
||||||
s->afi[0][(offset - 0xA60) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0xA90:
|
|
||||||
s->ocm[0] = val;
|
|
||||||
break;
|
|
||||||
case 0xAA0:
|
|
||||||
s->devci_ram = val;
|
|
||||||
break;
|
|
||||||
case 0xAB0:
|
|
||||||
s->csg_ram = val;
|
|
||||||
break;
|
|
||||||
case 0xB00 ... 0xB2C:
|
|
||||||
if (offset == 0xB20 || offset == 0xB2C) {
|
|
||||||
goto bad_reg;
|
|
||||||
}
|
|
||||||
s->gpiob[(offset - 0xB00) / 4] = val;
|
|
||||||
break;
|
|
||||||
case 0xB40 ... 0xB74:
|
|
||||||
s->ddriob[(offset - 0xB40) / 4] = val;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
bad_reg:
|
|
||||||
DB_PRINT("Bad register write %x <= %08x\n", (int)offset,
|
|
||||||
(unsigned)val);
|
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
DB_PRINT("SCLR registers are locked. Unlock them first\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,23 +415,22 @@ static const MemoryRegionOps slcr_ops = {
|
|||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int zynq_slcr_init(SysBusDevice *dev)
|
static void zynq_slcr_init(Object *obj)
|
||||||
{
|
{
|
||||||
ZynqSLCRState *s = ZYNQ_SLCR(dev);
|
ZynqSLCRState *s = ZYNQ_SLCR(obj);
|
||||||
|
|
||||||
memory_region_init_io(&s->iomem, OBJECT(s), &slcr_ops, s, "slcr", 0x1000);
|
memory_region_init_io(&s->iomem, obj, &slcr_ops, s, "slcr",
|
||||||
sysbus_init_mmio(dev, &s->iomem);
|
ZYNQ_SLCR_MMIO_SIZE);
|
||||||
|
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_zynq_slcr = {
|
static const VMStateDescription vmstate_zynq_slcr = {
|
||||||
.name = "zynq_slcr",
|
.name = "zynq_slcr",
|
||||||
.version_id = 1,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 2,
|
||||||
.minimum_version_id_old = 1,
|
.minimum_version_id_old = 2,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT8_ARRAY(data, ZynqSLCRState, 0x1000),
|
VMSTATE_UINT32_ARRAY(regs, ZynqSLCRState, ZYNQ_SLCR_NUM_REGS),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -522,9 +438,7 @@ static const VMStateDescription vmstate_zynq_slcr = {
|
|||||||
static void zynq_slcr_class_init(ObjectClass *klass, void *data)
|
static void zynq_slcr_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
|
||||||
|
|
||||||
sdc->init = zynq_slcr_init;
|
|
||||||
dc->vmsd = &vmstate_zynq_slcr;
|
dc->vmsd = &vmstate_zynq_slcr;
|
||||||
dc->reset = zynq_slcr_reset;
|
dc->reset = zynq_slcr_reset;
|
||||||
}
|
}
|
||||||
@@ -534,6 +448,7 @@ static const TypeInfo zynq_slcr_info = {
|
|||||||
.name = TYPE_ZYNQ_SLCR,
|
.name = TYPE_ZYNQ_SLCR,
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(ZynqSLCRState),
|
.instance_size = sizeof(ZynqSLCRState),
|
||||||
|
.instance_init = zynq_slcr_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void zynq_slcr_register_types(void)
|
static void zynq_slcr_register_types(void)
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ static uint8_t padding[60];
|
|||||||
static void mii_set_link(RTL8201CPState *mii, bool link_ok)
|
static void mii_set_link(RTL8201CPState *mii, bool link_ok)
|
||||||
{
|
{
|
||||||
if (link_ok) {
|
if (link_ok) {
|
||||||
mii->bmsr |= MII_BMSR_LINK_ST;
|
mii->bmsr |= MII_BMSR_LINK_ST | MII_BMSR_AN_COMP;
|
||||||
mii->anlpar |= MII_ANAR_TXFD | MII_ANAR_10FD | MII_ANAR_10 |
|
mii->anlpar |= MII_ANAR_TXFD | MII_ANAR_10FD | MII_ANAR_10 |
|
||||||
MII_ANAR_CSMACD;
|
MII_ANAR_CSMACD;
|
||||||
} else {
|
} else {
|
||||||
mii->bmsr &= ~MII_BMSR_LINK_ST;
|
mii->bmsr &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
|
||||||
mii->anlpar = MII_ANAR_TX;
|
mii->anlpar = MII_ANAR_TX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,9 +391,11 @@ static void aw_emac_write(void *opaque, hwaddr offset, uint64_t value,
|
|||||||
break;
|
break;
|
||||||
case EMAC_INT_CTL_REG:
|
case EMAC_INT_CTL_REG:
|
||||||
s->int_ctl = value;
|
s->int_ctl = value;
|
||||||
|
aw_emac_update_irq(s);
|
||||||
break;
|
break;
|
||||||
case EMAC_INT_STA_REG:
|
case EMAC_INT_STA_REG:
|
||||||
s->int_sta &= ~value;
|
s->int_sta &= ~value;
|
||||||
|
aw_emac_update_irq(s);
|
||||||
break;
|
break;
|
||||||
case EMAC_MAC_MADR_REG:
|
case EMAC_MAC_MADR_REG:
|
||||||
s->phy_target = value;
|
s->phy_target = value;
|
||||||
|
|||||||
@@ -1093,7 +1093,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
|||||||
uint32_t phy_addr, reg_num;
|
uint32_t phy_addr, reg_num;
|
||||||
|
|
||||||
phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
|
phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
|
||||||
if (phy_addr == BOARD_PHY_ADDRESS) {
|
if (phy_addr == BOARD_PHY_ADDRESS || phy_addr == 0) {
|
||||||
reg_num = (retval & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
|
reg_num = (retval & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
|
||||||
retval &= 0xFFFF0000;
|
retval &= 0xFFFF0000;
|
||||||
retval |= gem_phy_read(s, reg_num);
|
retval |= gem_phy_read(s, reg_num);
|
||||||
@@ -1193,7 +1193,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|||||||
uint32_t phy_addr, reg_num;
|
uint32_t phy_addr, reg_num;
|
||||||
|
|
||||||
phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
|
phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
|
||||||
if (phy_addr == BOARD_PHY_ADDRESS) {
|
if (phy_addr == BOARD_PHY_ADDRESS || phy_addr == 0) {
|
||||||
reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
|
reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
|
||||||
gem_phy_write(s, reg_num, val);
|
gem_phy_write(s, reg_num, val);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -718,7 +718,6 @@ static void pcnet_s_reset(PCNetState *s)
|
|||||||
s->csr[94] = 0x0000;
|
s->csr[94] = 0x0000;
|
||||||
s->csr[100] = 0x0200;
|
s->csr[100] = 0x0200;
|
||||||
s->csr[103] = 0x0105;
|
s->csr[103] = 0x0105;
|
||||||
s->csr[103] = 0x0105;
|
|
||||||
s->csr[112] = 0x0000;
|
s->csr[112] = 0x0000;
|
||||||
s->csr[114] = 0x0000;
|
s->csr[114] = 0x0000;
|
||||||
s->csr[122] = 0x0000;
|
s->csr[122] = 0x0000;
|
||||||
|
|||||||
@@ -677,7 +677,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
if (mac_data.entries <= MAC_TABLE_ENTRIES - in_use) {
|
||||||
s = iov_to_buf(iov, iov_cnt, 0, &macs[in_use * ETH_ALEN],
|
s = iov_to_buf(iov, iov_cnt, 0, &macs[in_use * ETH_ALEN],
|
||||||
mac_data.entries * ETH_ALEN);
|
mac_data.entries * ETH_ALEN);
|
||||||
if (s != mac_data.entries * ETH_ALEN) {
|
if (s != mac_data.entries * ETH_ALEN) {
|
||||||
|
|||||||
@@ -52,6 +52,9 @@
|
|||||||
#define VMXNET3_DEVICE_VERSION 0x1
|
#define VMXNET3_DEVICE_VERSION 0x1
|
||||||
#define VMXNET3_DEVICE_REVISION 0x1
|
#define VMXNET3_DEVICE_REVISION 0x1
|
||||||
|
|
||||||
|
/* Number of interrupt vectors for non-MSIx modes */
|
||||||
|
#define VMXNET3_MAX_NMSIX_INTRS (1)
|
||||||
|
|
||||||
/* Macros for rings descriptors access */
|
/* Macros for rings descriptors access */
|
||||||
#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \
|
#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \
|
||||||
(vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
|
(vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
|
||||||
@@ -1305,6 +1308,51 @@ static bool vmxnet3_verify_intx(VMXNET3State *s, int intx)
|
|||||||
(pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1));
|
(pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx)
|
||||||
|
{
|
||||||
|
int max_ints = is_msix ? VMXNET3_MAX_INTRS : VMXNET3_MAX_NMSIX_INTRS;
|
||||||
|
if (idx >= max_ints) {
|
||||||
|
hw_error("Bad interrupt index: %d\n", idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vmxnet3_validate_interrupts(VMXNET3State *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VMW_CFPRN("Verifying event interrupt index (%d)", s->event_int_idx);
|
||||||
|
vmxnet3_validate_interrupt_idx(s->msix_used, s->event_int_idx);
|
||||||
|
|
||||||
|
for (i = 0; i < s->txq_num; i++) {
|
||||||
|
int idx = s->txq_descr[i].intr_idx;
|
||||||
|
VMW_CFPRN("Verifying TX queue %d interrupt index (%d)", i, idx);
|
||||||
|
vmxnet3_validate_interrupt_idx(s->msix_used, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < s->rxq_num; i++) {
|
||||||
|
int idx = s->rxq_descr[i].intr_idx;
|
||||||
|
VMW_CFPRN("Verifying RX queue %d interrupt index (%d)", i, idx);
|
||||||
|
vmxnet3_validate_interrupt_idx(s->msix_used, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vmxnet3_validate_queues(VMXNET3State *s)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* txq_num and rxq_num are total number of queues
|
||||||
|
* configured by guest. These numbers must not
|
||||||
|
* exceed corresponding maximal values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (s->txq_num > VMXNET3_DEVICE_MAX_TX_QUEUES) {
|
||||||
|
hw_error("Bad TX queues number: %d\n", s->txq_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->rxq_num > VMXNET3_DEVICE_MAX_RX_QUEUES) {
|
||||||
|
hw_error("Bad RX queues number: %d\n", s->rxq_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void vmxnet3_activate_device(VMXNET3State *s)
|
static void vmxnet3_activate_device(VMXNET3State *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -1351,7 +1399,7 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
|||||||
VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numRxQueues);
|
VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numRxQueues);
|
||||||
|
|
||||||
VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num);
|
VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num);
|
||||||
assert(s->txq_num <= VMXNET3_DEVICE_MAX_TX_QUEUES);
|
vmxnet3_validate_queues(s);
|
||||||
|
|
||||||
qdescr_table_pa =
|
qdescr_table_pa =
|
||||||
VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.misc.queueDescPA);
|
VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.misc.queueDescPA);
|
||||||
@@ -1447,6 +1495,8 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
|||||||
sizeof(s->rxq_descr[i].rxq_stats));
|
sizeof(s->rxq_descr[i].rxq_stats));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vmxnet3_validate_interrupts(s);
|
||||||
|
|
||||||
/* Make sure everything is in place before device activation */
|
/* Make sure everything is in place before device activation */
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
|
|
||||||
@@ -2005,7 +2055,6 @@ vmxnet3_cleanup_msix(VMXNET3State *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VMXNET3_MSI_NUM_VECTORS (1)
|
|
||||||
#define VMXNET3_MSI_OFFSET (0x50)
|
#define VMXNET3_MSI_OFFSET (0x50)
|
||||||
#define VMXNET3_USE_64BIT (true)
|
#define VMXNET3_USE_64BIT (true)
|
||||||
#define VMXNET3_PER_VECTOR_MASK (false)
|
#define VMXNET3_PER_VECTOR_MASK (false)
|
||||||
@@ -2016,7 +2065,7 @@ vmxnet3_init_msi(VMXNET3State *s)
|
|||||||
PCIDevice *d = PCI_DEVICE(s);
|
PCIDevice *d = PCI_DEVICE(s);
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MSI_NUM_VECTORS,
|
res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MAX_NMSIX_INTRS,
|
||||||
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
|
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
|
||||||
if (0 > res) {
|
if (0 > res) {
|
||||||
VMW_WRPRN("Failed to initialize MSI, error %d", res);
|
VMW_WRPRN("Failed to initialize MSI, error %d", res);
|
||||||
@@ -2342,6 +2391,9 @@ static int vmxnet3_post_load(void *opaque, int version_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vmxnet3_validate_queues(s);
|
||||||
|
vmxnet3_validate_interrupts(s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ static unsigned int tdk_read(struct PHY *phy, unsigned int req)
|
|||||||
r |= 1;
|
r |= 1;
|
||||||
break;
|
break;
|
||||||
case 17:
|
case 17:
|
||||||
/* Marvel PHY on many xilinx boards. */
|
/* Marvell PHY on many xilinx boards. */
|
||||||
r = 0x8000; /* 1000Mb */
|
r = 0x8000; /* 1000Mb */
|
||||||
break;
|
break;
|
||||||
case 18:
|
case 18:
|
||||||
@@ -142,6 +142,9 @@ tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
|
|||||||
phy->regs[regnum] = data;
|
phy->regs[regnum] = data;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unconditionally clear regs[BMCR][BMCR_RESET] */
|
||||||
|
phy->regs[0] &= ~0x8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -145,9 +145,9 @@ static uint64_t raven_io_read(void *opaque, hwaddr addr,
|
|||||||
if (size == 1) {
|
if (size == 1) {
|
||||||
return buf[0];
|
return buf[0];
|
||||||
} else if (size == 2) {
|
} else if (size == 2) {
|
||||||
return lduw_p(buf);
|
return lduw_le_p(buf);
|
||||||
} else if (size == 4) {
|
} else if (size == 4) {
|
||||||
return ldl_p(buf);
|
return ldl_le_p(buf);
|
||||||
} else {
|
} else {
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
@@ -164,9 +164,9 @@ static void raven_io_write(void *opaque, hwaddr addr,
|
|||||||
if (size == 1) {
|
if (size == 1) {
|
||||||
buf[0] = val;
|
buf[0] = val;
|
||||||
} else if (size == 2) {
|
} else if (size == 2) {
|
||||||
stw_p(buf, val);
|
stw_le_p(buf, val);
|
||||||
} else if (size == 4) {
|
} else if (size == 4) {
|
||||||
stl_p(buf, val);
|
stl_le_p(buf, val);
|
||||||
} else {
|
} else {
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -649,7 +649,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
|||||||
input = (qemu_irq *)env->irq_inputs;
|
input = (qemu_irq *)env->irq_inputs;
|
||||||
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
|
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
|
||||||
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
|
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
|
||||||
env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i;
|
env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
|
||||||
env->mpic_iack = MPC8544_CCSRBAR_BASE +
|
env->mpic_iack = MPC8544_CCSRBAR_BASE +
|
||||||
MPC8544_MPIC_REGS_OFFSET + 0xa0;
|
MPC8544_MPIC_REGS_OFFSET + 0xa0;
|
||||||
|
|
||||||
|
|||||||
92
hw/ppc/ppc.c
92
hw/ppc/ppc.c
@@ -620,6 +620,13 @@ static void cpu_ppc_tb_start (CPUPPCState *env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ppc_decr_clear_on_delivery(CPUPPCState *env)
|
||||||
|
{
|
||||||
|
ppc_tb_t *tb_env = env->tb_env;
|
||||||
|
int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
|
||||||
|
return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
|
static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
|
||||||
{
|
{
|
||||||
ppc_tb_t *tb_env = env->tb_env;
|
ppc_tb_t *tb_env = env->tb_env;
|
||||||
@@ -677,6 +684,11 @@ static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
|
|||||||
ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
|
ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
|
||||||
|
{
|
||||||
|
ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
|
static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
/* Raise it */
|
/* Raise it */
|
||||||
@@ -684,11 +696,16 @@ static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
|
|||||||
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
|
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
|
||||||
|
{
|
||||||
|
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
|
static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
|
||||||
QEMUTimer *timer,
|
QEMUTimer *timer,
|
||||||
void (*raise_excp)(PowerPCCPU *),
|
void (*raise_excp)(void *),
|
||||||
uint32_t decr, uint32_t value,
|
void (*lower_excp)(PowerPCCPU *),
|
||||||
int is_excp)
|
uint32_t decr, uint32_t value)
|
||||||
{
|
{
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
ppc_tb_t *tb_env = env->tb_env;
|
ppc_tb_t *tb_env = env->tb_env;
|
||||||
@@ -702,59 +719,74 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC
|
||||||
|
* interrupt.
|
||||||
|
*
|
||||||
|
* If we get a really small DEC value, we can assume that by the time we
|
||||||
|
* handled it we should inject an interrupt already.
|
||||||
|
*
|
||||||
|
* On MSB level based DEC implementations the MSB always means the interrupt
|
||||||
|
* is pending, so raise it on those.
|
||||||
|
*
|
||||||
|
* On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
|
||||||
|
* an edge interrupt, so raise it here too.
|
||||||
|
*/
|
||||||
|
if ((value < 3) ||
|
||||||
|
((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) ||
|
||||||
|
((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000)
|
||||||
|
&& !(decr & 0x80000000))) {
|
||||||
|
(*raise_excp)(cpu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On MSB level based systems a 0 for the MSB stops interrupt delivery */
|
||||||
|
if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
|
||||||
|
(*lower_excp)(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the next timer event */
|
||||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
|
next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
|
||||||
if (is_excp) {
|
|
||||||
next += *nextp - now;
|
|
||||||
}
|
|
||||||
if (next == now) {
|
|
||||||
next++;
|
|
||||||
}
|
|
||||||
*nextp = next;
|
*nextp = next;
|
||||||
|
|
||||||
/* Adjust timer */
|
/* Adjust timer */
|
||||||
timer_mod(timer, next);
|
timer_mod(timer, next);
|
||||||
|
|
||||||
/* If we set a negative value and the decrementer was positive, raise an
|
|
||||||
* exception.
|
|
||||||
*/
|
|
||||||
if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED)
|
|
||||||
&& (value & 0x80000000)
|
|
||||||
&& !(decr & 0x80000000)) {
|
|
||||||
(*raise_excp)(cpu);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
|
static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
|
||||||
uint32_t value, int is_excp)
|
uint32_t value)
|
||||||
{
|
{
|
||||||
ppc_tb_t *tb_env = cpu->env.tb_env;
|
ppc_tb_t *tb_env = cpu->env.tb_env;
|
||||||
|
|
||||||
__cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
|
__cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
|
||||||
&cpu_ppc_decr_excp, decr, value, is_excp);
|
tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
|
||||||
|
value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
|
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||||
|
|
||||||
_cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0);
|
_cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_ppc_decr_cb(void *opaque)
|
static void cpu_ppc_decr_cb(void *opaque)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = opaque;
|
PowerPCCPU *cpu = opaque;
|
||||||
|
|
||||||
_cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1);
|
cpu_ppc_decr_excp(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
|
static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
|
||||||
uint32_t value, int is_excp)
|
uint32_t value)
|
||||||
{
|
{
|
||||||
ppc_tb_t *tb_env = cpu->env.tb_env;
|
ppc_tb_t *tb_env = cpu->env.tb_env;
|
||||||
|
|
||||||
if (tb_env->hdecr_timer != NULL) {
|
if (tb_env->hdecr_timer != NULL) {
|
||||||
__cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
|
__cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
|
||||||
&cpu_ppc_hdecr_excp, hdecr, value, is_excp);
|
tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
|
||||||
|
hdecr, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,14 +794,14 @@ void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
|
|||||||
{
|
{
|
||||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||||
|
|
||||||
_cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0);
|
_cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_ppc_hdecr_cb(void *opaque)
|
static void cpu_ppc_hdecr_cb(void *opaque)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = opaque;
|
PowerPCCPU *cpu = opaque;
|
||||||
|
|
||||||
_cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1);
|
cpu_ppc_hdecr_excp(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
|
static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
|
||||||
@@ -792,8 +824,8 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
|
|||||||
* if a decrementer exception is pending when it enables msr_ee at startup,
|
* if a decrementer exception is pending when it enables msr_ee at startup,
|
||||||
* it's not ready to handle it...
|
* it's not ready to handle it...
|
||||||
*/
|
*/
|
||||||
_cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
|
_cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||||
_cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
|
_cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||||
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
|
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,6 +838,10 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
|||||||
tb_env = g_malloc0(sizeof(ppc_tb_t));
|
tb_env = g_malloc0(sizeof(ppc_tb_t));
|
||||||
env->tb_env = tb_env;
|
env->tb_env = tb_env;
|
||||||
tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
|
tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
|
||||||
|
if (env->insns_flags & PPC_SEGMENT_64B) {
|
||||||
|
/* All Book3S 64bit CPUs implement level based DEC logic */
|
||||||
|
tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
|
||||||
|
}
|
||||||
/* Create new timer */
|
/* Create new timer */
|
||||||
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
|
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
|
||||||
if (0) {
|
if (0) {
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ static void spin_reset(void *opaque)
|
|||||||
for (i = 0; i < MAX_CPUS; i++) {
|
for (i = 0; i < MAX_CPUS; i++) {
|
||||||
SpinInfo *info = &s->spin[i];
|
SpinInfo *info = &s->spin[i];
|
||||||
|
|
||||||
info->pir = i;
|
stl_p(&info->pir, i);
|
||||||
info->r3 = i;
|
stq_p(&info->r3, i);
|
||||||
info->addr = 1;
|
stq_p(&info->addr, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ static void scsi_dma_restart_bh(void *opaque)
|
|||||||
scsi_req_continue(req);
|
scsi_req_continue(req);
|
||||||
break;
|
break;
|
||||||
case SCSI_XFER_NONE:
|
case SCSI_XFER_NONE:
|
||||||
assert(!req->sg);
|
|
||||||
scsi_req_dequeue(req);
|
scsi_req_dequeue(req);
|
||||||
scsi_req_enqueue(req);
|
scsi_req_enqueue(req);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user