Compare commits
383 Commits
pull-input
...
pull-ui-20
Author | SHA1 | Date | |
---|---|---|---|
|
2a57c55f26 | ||
|
dbee9897d5 | ||
|
90cd03a30e | ||
|
2df2041036 | ||
|
f54195ddf7 | ||
|
eda24e1886 | ||
|
bf01c1794e | ||
|
38e5756a61 | ||
|
12b2806761 | ||
|
ecccaea2f5 | ||
|
c264a88072 | ||
|
d5c42857d6 | ||
|
6998b6c7c7 | ||
|
0136464d10 | ||
|
070eeef9e0 | ||
|
d6fcb2936f | ||
|
3a533ee8fd | ||
|
5612564ea9 | ||
|
94b037f2a4 | ||
|
7512b13dd7 | ||
|
1fe163feeb | ||
|
05f43d44e4 | ||
|
ae4b28ace9 | ||
|
f5e2b3be82 | ||
|
80dd5c4918 | ||
|
0bc6484d58 | ||
|
9096b78a38 | ||
|
d1b97bcea3 | ||
|
347701879c | ||
|
ca3fa0e88f | ||
|
b7d48952c3 | ||
|
fe4db84d49 | ||
|
8ed5372874 | ||
|
7f1b588f20 | ||
|
ef4c9fc854 | ||
|
79218be42b | ||
|
a82417b50b | ||
|
99672c7167 | ||
|
9397740244 | ||
|
599ab2f241 | ||
|
0d4e995c73 | ||
|
6a1b0f3aea | ||
|
170f75ad80 | ||
|
6b39b06339 | ||
|
627eae7d72 | ||
|
0f183e679d | ||
|
a20fd901af | ||
|
0cb0155711 | ||
|
86e121ae75 | ||
|
dea651a95a | ||
|
5705653ff8 | ||
|
81cc8a6566 | ||
|
b7de81f697 | ||
|
c5dc16b726 | ||
|
f20476b9e4 | ||
|
73a17349ff | ||
|
8a502efd0c | ||
|
97eed24ff1 | ||
|
dcaf8dda4b | ||
|
4d45dcfbf2 | ||
|
977a117f78 | ||
|
1a665855d7 | ||
|
0a73336d96 | ||
|
ad14a46a36 | ||
|
661e32fb3c | ||
|
fa5e56c2a7 | ||
|
ba10b9c003 | ||
|
ba7eadb592 | ||
|
20ea686a0c | ||
|
d3d74d6fe0 | ||
|
d14dde5ec7 | ||
|
e8582891cb | ||
|
d4c19cdeeb | ||
|
97b93c8ad2 | ||
|
2640d2a5ff | ||
|
af78c91f57 | ||
|
d6309c170e | ||
|
271119313c | ||
|
6bea1ddf8b | ||
|
a06b1dae47 | ||
|
09da01c3f2 | ||
|
17871f71fd | ||
|
52cfcb4642 | ||
|
7a25126d8a | ||
|
0839f11cda | ||
|
660a2d83e0 | ||
|
56bef8511a | ||
|
cb57fb3705 | ||
|
88071589e8 | ||
|
cbf061bd1f | ||
|
efee678d6d | ||
|
b16c129daf | ||
|
a43edcf20a | ||
7a488b5b24 | |||
|
81527b94ad | ||
|
5995db8871 | ||
|
ccf0a57b45 | ||
|
03972660f7 | ||
|
de85094825 | ||
|
c9b900903b | ||
|
72fa605dec | ||
|
c10a1c787b | ||
|
a2b245ae2f | ||
|
c13e9912d9 | ||
|
a3ccdfb5bb | ||
|
496e079813 | ||
|
a1c2bbc87b | ||
|
e69f7d2510 | ||
|
77a6da267c | ||
|
fd11080b9f | ||
|
728b1429b1 | ||
|
daf5dc7806 | ||
|
c833fb4aeb | ||
|
1382d4abdf | ||
|
eac8e79ff7 | ||
|
5d0cbbcfeb | ||
|
48f592118a | ||
|
9c7f3fcae7 | ||
|
27685a8dd0 | ||
|
dffa41b486 | ||
|
159975f38b | ||
|
2d76e724cf | ||
|
bbc8ea98bc | ||
|
2bf7e10f78 | ||
|
c5f3014b82 | ||
|
fffb6e1223 | ||
|
5b8bb3595a | ||
|
818bbc86c9 | ||
|
78e87797ba | ||
|
36e4970e9d | ||
|
77d47e1692 | ||
|
72bd94c578 | ||
|
0722cc42d4 | ||
|
c3ce5a2357 | ||
|
bf28a69eeb | ||
|
81f265a8a4 | ||
|
1f3e7e41bb | ||
|
f91c7e5235 | ||
|
9c7d64eb2a | ||
|
76b553b308 | ||
|
f555a9d0b3 | ||
|
e424b6550f | ||
|
bce3035a44 | ||
|
c489780203 | ||
|
e64c75a975 | ||
|
e902754e3d | ||
|
0bdb12c7c5 | ||
|
3daa4a9f95 | ||
|
ef6c47f1d7 | ||
|
e17a87792d | ||
|
aa9026fd5e | ||
|
61ae5cf3a2 | ||
|
2ecd7e2f25 | ||
|
cf716b31cb | ||
|
2020b67d85 | ||
|
7f516c9675 | ||
|
96c9cff0ab | ||
|
835c42d34e | ||
|
1a136cdce0 | ||
|
4879538c99 | ||
|
0fa5936434 | ||
|
4aaefd93b9 | ||
|
f3333ce0b5 | ||
|
8ee38face9 | ||
|
0b8ac648ec | ||
|
1c0744190c | ||
|
0aec21d8fa | ||
|
f34001ec96 | ||
|
b9731075b3 | ||
|
6358320228 | ||
|
bac3bf287a | ||
|
4cbec30d76 | ||
|
230bf719d3 | ||
|
db800b21d8 | ||
|
1485ef1c45 | ||
|
196fe23734 | ||
|
a65b6f27ce | ||
|
456d97d364 | ||
|
bbc4c3f4f3 | ||
|
6e11eb2d2b | ||
|
9b6a3ea7a6 | ||
|
173ff58580 | ||
|
79b2ac8f28 | ||
|
03bf19535c | ||
|
e481a1f63c | ||
|
13e5c54d30 | ||
|
1c2e4ea7b6 | ||
|
02f9873180 | ||
|
0c9f302ea2 | ||
|
767a554a0c | ||
|
1b20616f26 | ||
|
386ce3c7fc | ||
|
d19a4d4ef4 | ||
|
96b0439bbe | ||
|
fa53b7f047 | ||
|
a321bb51fa | ||
|
e9d9ee234f | ||
|
0c74e95bf8 | ||
|
8cb2d2db50 | ||
|
a1f8193bb4 | ||
|
540a8f34b4 | ||
|
b63041c8f6 | ||
|
1b25567765 | ||
|
5ae74402d1 | ||
|
d1f711d407 | ||
|
cbcb93e802 | ||
|
81fed1d017 | ||
|
1bb4710705 | ||
|
d681127d37 | ||
|
fbe7e3327a | ||
|
7dc9ae4339 | ||
|
6a7b2b2100 | ||
|
949055a254 | ||
|
25a8535943 | ||
|
32265288a9 | ||
|
a31393e7a5 | ||
|
dd1f63493a | ||
|
a890643958 | ||
|
027d9a7d29 | ||
|
ce7cf6a973 | ||
|
b6b3ccfda0 | ||
|
f96a8cc3c6 | ||
|
550276ae0a | ||
|
e653bc6b0f | ||
|
23ea7f5794 | ||
|
254316fa1f | ||
|
61b97833b3 | ||
|
7c468ec54c | ||
|
148fbe9504 | ||
|
4f2e39e103 | ||
|
120e512b7f | ||
|
eabb5782f7 | ||
|
3cf294eebc | ||
|
1d5b128cbe | ||
|
339892d758 | ||
|
6fb2fff75d | ||
|
c16fe84f07 | ||
|
c5d128ffeb | ||
|
c69e3cef21 | ||
|
49540a1f65 | ||
|
ca44141d5f | ||
|
c9f7acd575 | ||
|
df403bc588 | ||
|
9da82227ca | ||
|
7d992e4d5a | ||
|
2f4aa23299 | ||
|
ddba15919b | ||
|
8adcd6fb6d | ||
|
be87a393f9 | ||
|
8737d9e0c4 | ||
|
74e1ae7c0b | ||
|
818584a43a | ||
|
b85114f8cf | ||
|
692e01a27c | ||
|
0a4279d97c | ||
|
685552850b | ||
|
0ffcdd9c06 | ||
|
24df38b00e | ||
|
49137bf684 | ||
|
22af08eacf | ||
|
4085f5c7a2 | ||
|
73bfa8c0e0 | ||
|
78851fa529 | ||
|
664ee76891 | ||
|
84d0984dfe | ||
|
cc9a366d3b | ||
|
c640f2849e | ||
|
bc63afaf5f | ||
|
43e21e4907 | ||
|
2cc2d082b5 | ||
|
b9d7221524 | ||
|
2bfe11c8fa | ||
|
331f5eb28a | ||
|
e97eb6f7f0 | ||
|
a409aada20 | ||
|
2c7c4cf0c4 | ||
|
4af27939e5 | ||
|
79907e688d | ||
|
fe121b9d3c | ||
|
afe16f3f47 | ||
|
f643e469f3 | ||
|
3c87fafb90 | ||
|
794afd7096 | ||
|
c679e74d2e | ||
|
6b5ffb14b7 | ||
|
9c9f5f311a | ||
|
f9530c3242 | ||
|
bfcec59a23 | ||
|
8f95595072 | ||
|
205e5de425 | ||
|
d9d2663c33 | ||
|
4423184376 | ||
|
f607867cef | ||
|
cd958edb1f | ||
|
844c82296f | ||
eb7b5c3511 | |||
|
6b9424689a | ||
|
e7e4f9f950 | ||
|
4a58f35b79 | ||
|
ceffd34e85 | ||
|
17bc37b75e | ||
|
85b3ed1db5 | ||
|
d10a0102b3 | ||
|
f278d5cbe5 | ||
|
21ce148c7e | ||
|
b6eb9b45f7 | ||
|
25930ed60a | ||
|
4f01a63779 | ||
|
55c911a580 | ||
|
aec661de86 | ||
|
3ddcd2edc8 | ||
|
2d5aa8728b | ||
|
1eabfce6d5 | ||
|
96193c22ab | ||
|
2ca8a8becc | ||
|
1fda6198e4 | ||
|
8057c621b1 | ||
|
4928cd6de6 | ||
|
9646f4927f | ||
|
2d5312da56 | ||
|
eab60fb9f5 | ||
|
0c3d7c0051 | ||
|
c39c0edf9b | ||
|
df3e9af8fd | ||
|
6efef58ed1 | ||
|
5e992a8e33 | ||
|
0456441b5e | ||
|
333ec4ca6a | ||
|
6d0ceb80ff | ||
|
306e196fa2 | ||
|
f186d64d8f | ||
|
c265e976f4 | ||
|
3359baad36 | ||
|
53f5ed9506 | ||
|
758e1b2b62 | ||
|
cf07da65f3 | ||
|
c978b31687 | ||
|
a200f2fb57 | ||
|
ab129972c8 | ||
|
0e55539c07 | ||
|
d148d90ee8 | ||
|
267f685b8b | ||
|
178f94297a | ||
|
959f593c0e | ||
|
a5403c69fc | ||
|
fd38b25103 | ||
|
e0eeb4a21a | ||
|
4a0588996a | ||
|
1f04b992cf | ||
|
9c1f8f4493 | ||
|
cc9d8a3b2c | ||
|
63ae8b942d | ||
|
048a2e8869 | ||
|
a3276f786c | ||
|
fa26f01839 | ||
|
a16d8ef54b | ||
|
070c4b92b8 | ||
|
b38636b837 | ||
|
4100c026b6 | ||
|
8b54c6e187 | ||
|
680e60b6ba | ||
|
2d803144a6 | ||
|
40364748dd | ||
|
6ee0e20b65 | ||
|
47f9f15831 | ||
|
584613eacb | ||
|
fb56d323e2 | ||
|
46cca4ecb2 | ||
|
88f82ed1a7 | ||
|
30656b097e | ||
|
afe4612409 | ||
|
e6eee8ab51 | ||
|
f4b618360e | ||
|
0682e15b19 | ||
|
b6540d403d | ||
|
ccf0426c09 | ||
|
59509ec16b | ||
|
7dce4e6fd2 | ||
|
e92aa36ac8 | ||
|
a4543b1b37 | ||
|
1c0fbfa3de | ||
|
5bf3d31903 | ||
|
cdb3081269 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -39,9 +39,7 @@
|
|||||||
/qmp-introspect.[ch]
|
/qmp-introspect.[ch]
|
||||||
/qmp-marshal.c
|
/qmp-marshal.c
|
||||||
/qemu-doc.html
|
/qemu-doc.html
|
||||||
/qemu-tech.html
|
|
||||||
/qemu-doc.info
|
/qemu-doc.info
|
||||||
/qemu-tech.info
|
|
||||||
/qemu-img
|
/qemu-img
|
||||||
/qemu-nbd
|
/qemu-nbd
|
||||||
/qemu-options.def
|
/qemu-options.def
|
||||||
@@ -55,6 +53,7 @@
|
|||||||
/qemu-monitor-info.texi
|
/qemu-monitor-info.texi
|
||||||
/qemu-version.h
|
/qemu-version.h
|
||||||
/qemu-version.h.tmp
|
/qemu-version.h.tmp
|
||||||
|
/module_block.h
|
||||||
/vscclient
|
/vscclient
|
||||||
/fsdev/virtfs-proxy-helper
|
/fsdev/virtfs-proxy-helper
|
||||||
*.[1-9]
|
*.[1-9]
|
||||||
|
45
.travis.yml
45
.travis.yml
@@ -9,6 +9,7 @@ cache: ccache
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
|
# Build dependencies
|
||||||
- libaio-dev
|
- libaio-dev
|
||||||
- libattr1-dev
|
- libattr1-dev
|
||||||
- libbrlapi-dev
|
- libbrlapi-dev
|
||||||
@@ -89,6 +90,7 @@ matrix:
|
|||||||
- env: CONFIG=""
|
- env: CONFIG=""
|
||||||
os: osx
|
os: osx
|
||||||
compiler: clang
|
compiler: clang
|
||||||
|
# Plain Trusty Build
|
||||||
- env: CONFIG=""
|
- env: CONFIG=""
|
||||||
sudo: required
|
sudo: required
|
||||||
addons:
|
addons:
|
||||||
@@ -99,3 +101,46 @@ matrix:
|
|||||||
- sudo apt-get build-dep -qq qemu
|
- sudo apt-get build-dep -qq qemu
|
||||||
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
|
# Using newer GCC with sanitizers
|
||||||
|
- addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
# PPAs for newer toolchains
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
# Extra toolchains
|
||||||
|
- gcc-5
|
||||||
|
- g++-5
|
||||||
|
# Build dependencies
|
||||||
|
- libaio-dev
|
||||||
|
- libattr1-dev
|
||||||
|
- libbrlapi-dev
|
||||||
|
- libcap-ng-dev
|
||||||
|
- libgnutls-dev
|
||||||
|
- libgtk-3-dev
|
||||||
|
- libiscsi-dev
|
||||||
|
- liblttng-ust-dev
|
||||||
|
- libnfs-dev
|
||||||
|
- libncurses5-dev
|
||||||
|
- libnss3-dev
|
||||||
|
- libpixman-1-dev
|
||||||
|
- libpng12-dev
|
||||||
|
- librados-dev
|
||||||
|
- libsdl1.2-dev
|
||||||
|
- libseccomp-dev
|
||||||
|
- libspice-protocol-dev
|
||||||
|
- libspice-server-dev
|
||||||
|
- libssh2-1-dev
|
||||||
|
- liburcu-dev
|
||||||
|
- libusb-1.0-0-dev
|
||||||
|
- libvte-2.90-dev
|
||||||
|
- sparse
|
||||||
|
- uuid-dev
|
||||||
|
language: generic
|
||||||
|
compiler: none
|
||||||
|
env:
|
||||||
|
- COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5
|
||||||
|
- CONFIG="--cc=gcc-5 --cxx=g++-5 --disable-pie --disable-linux-user --with-coroutine=gthread"
|
||||||
|
- TEST_CMD=""
|
||||||
|
before_script:
|
||||||
|
- ./configure ${CONFIG} --extra-cflags="-g3 -O0 -fsanitize=thread -fuse-ld=gold" || cat config.log
|
||||||
|
@@ -9,7 +9,7 @@ patches before submitting.
|
|||||||
Of course, the most important aspect in any coding style is whitespace.
|
Of course, the most important aspect in any coding style is whitespace.
|
||||||
Crusty old coders who have trouble spotting the glasses on their noses
|
Crusty old coders who have trouble spotting the glasses on their noses
|
||||||
can tell the difference between a tab and eight spaces from a distance
|
can tell the difference between a tab and eight spaces from a distance
|
||||||
of approximately fifteen parsecs. Many a flamewar have been fought and
|
of approximately fifteen parsecs. Many a flamewar has been fought and
|
||||||
lost on this issue.
|
lost on this issue.
|
||||||
|
|
||||||
QEMU indents are four spaces. Tabs are never used, except in Makefiles
|
QEMU indents are four spaces. Tabs are never used, except in Makefiles
|
||||||
|
82
MAINTAINERS
82
MAINTAINERS
@@ -116,6 +116,7 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: target-cris/
|
F: target-cris/
|
||||||
F: hw/cris/
|
F: hw/cris/
|
||||||
|
F: include/hw/cris/
|
||||||
F: tests/tcg/cris/
|
F: tests/tcg/cris/
|
||||||
F: disas/cris.c
|
F: disas/cris.c
|
||||||
|
|
||||||
@@ -145,10 +146,17 @@ F: disas/microblaze.c
|
|||||||
|
|
||||||
MIPS
|
MIPS
|
||||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||||
M: Leon Alrae <leon.alrae@imgtec.com>
|
M: Yongbok Kim <yongbok.kim@imgtec.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: target-mips/
|
F: target-mips/
|
||||||
F: hw/mips/
|
F: hw/mips/
|
||||||
|
F: hw/misc/mips_*
|
||||||
|
F: hw/intc/mips_gic.c
|
||||||
|
F: hw/timer/mips_gictimer.c
|
||||||
|
F: include/hw/mips/
|
||||||
|
F: include/hw/misc/mips_*
|
||||||
|
F: include/hw/intc/mips_gic.h
|
||||||
|
F: include/hw/timer/mips_gictimer.h
|
||||||
F: tests/tcg/mips/
|
F: tests/tcg/mips/
|
||||||
F: disas/mips.c
|
F: disas/mips.c
|
||||||
|
|
||||||
@@ -157,6 +165,8 @@ M: Anthony Green <green@moxielogic.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: target-moxie/
|
F: target-moxie/
|
||||||
F: disas/moxie.c
|
F: disas/moxie.c
|
||||||
|
F: hw/moxie/
|
||||||
|
F: default-configs/moxie-softmmu.mak
|
||||||
|
|
||||||
OpenRISC
|
OpenRISC
|
||||||
M: Jia Liu <proljc@gmail.com>
|
M: Jia Liu <proljc@gmail.com>
|
||||||
@@ -319,6 +329,9 @@ L: qemu-devel@nongnu.org
|
|||||||
M: Stefan Weil <sw@weilnetz.de>
|
M: Stefan Weil <sw@weilnetz.de>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: *win32*
|
F: *win32*
|
||||||
|
F: */*win32*
|
||||||
|
F: include/*/*win32*
|
||||||
|
X: qga/*win32*
|
||||||
F: qemu.nsi
|
F: qemu.nsi
|
||||||
|
|
||||||
ARM Machines
|
ARM Machines
|
||||||
@@ -479,6 +492,21 @@ S: Maintained
|
|||||||
F: hw/arm/virt-acpi-build.c
|
F: hw/arm/virt-acpi-build.c
|
||||||
F: include/hw/arm/virt-acpi-build.h
|
F: include/hw/arm/virt-acpi-build.h
|
||||||
|
|
||||||
|
STM32F205
|
||||||
|
M: Alistair Francis <alistair@alistair23.me>
|
||||||
|
S: Maintained
|
||||||
|
F: hw/arm/stm32f205_soc.c
|
||||||
|
F: hw/misc/stm32f2xx_syscfg.c
|
||||||
|
F: hw/char/stm32f2xx_usart.c
|
||||||
|
F: hw/timer/stm32f2xx_timer.c
|
||||||
|
F: hw/adc/*
|
||||||
|
F: hw/ssi/stm32f2xx_spi.c
|
||||||
|
|
||||||
|
Netduino 2
|
||||||
|
M: Alistair Francis <alistair@alistair23.me>
|
||||||
|
S: Maintained
|
||||||
|
F: hw/arm/netduino2.c
|
||||||
|
|
||||||
CRIS Machines
|
CRIS Machines
|
||||||
-------------
|
-------------
|
||||||
Axis Dev88
|
Axis Dev88
|
||||||
@@ -605,6 +633,7 @@ S: Maintained
|
|||||||
F: hw/ppc/mac_oldworld.c
|
F: hw/ppc/mac_oldworld.c
|
||||||
F: hw/pci-host/grackle.c
|
F: hw/pci-host/grackle.c
|
||||||
F: hw/misc/macio/
|
F: hw/misc/macio/
|
||||||
|
F: hw/intc/heathrow_pic.c
|
||||||
|
|
||||||
PReP
|
PReP
|
||||||
L: qemu-devel@nongnu.org
|
L: qemu-devel@nongnu.org
|
||||||
@@ -613,6 +642,7 @@ S: Odd Fixes
|
|||||||
F: hw/ppc/prep.c
|
F: hw/ppc/prep.c
|
||||||
F: hw/pci-host/prep.[hc]
|
F: hw/pci-host/prep.[hc]
|
||||||
F: hw/isa/pc87312.[hc]
|
F: hw/isa/pc87312.[hc]
|
||||||
|
F: pc-bios/ppc_rom.bin
|
||||||
|
|
||||||
sPAPR
|
sPAPR
|
||||||
M: David Gibson <david@gibson.dropbear.id.au>
|
M: David Gibson <david@gibson.dropbear.id.au>
|
||||||
@@ -645,31 +675,38 @@ R2D
|
|||||||
M: Magnus Damm <magnus.damm@gmail.com>
|
M: Magnus Damm <magnus.damm@gmail.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/sh4/r2d.c
|
F: hw/sh4/r2d.c
|
||||||
|
F: hw/intc/sh_intc.c
|
||||||
|
F: hw/timer/sh_timer.c
|
||||||
|
|
||||||
Shix
|
Shix
|
||||||
M: Magnus Damm <magnus.damm@gmail.com>
|
M: Magnus Damm <magnus.damm@gmail.com>
|
||||||
S: Orphan
|
S: Odd Fixes
|
||||||
F: hw/sh4/shix.c
|
F: hw/sh4/shix.c
|
||||||
|
|
||||||
SPARC Machines
|
SPARC Machines
|
||||||
--------------
|
--------------
|
||||||
Sun4m
|
Sun4m
|
||||||
M: Blue Swirl <blauwirbel@gmail.com>
|
|
||||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/sparc/sun4m.c
|
F: hw/sparc/sun4m.c
|
||||||
|
F: hw/dma/sparc32_dma.c
|
||||||
|
F: hw/dma/sun4m_iommu.c
|
||||||
|
F: include/hw/sparc/sparc32_dma.h
|
||||||
|
F: include/hw/sparc/sun4m.h
|
||||||
|
F: pc-bios/openbios-sparc32
|
||||||
|
|
||||||
Sun4u
|
Sun4u
|
||||||
M: Blue Swirl <blauwirbel@gmail.com>
|
|
||||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/sparc64/sun4u.c
|
F: hw/sparc64/sun4u.c
|
||||||
|
F: pc-bios/openbios-sparc64
|
||||||
|
|
||||||
Leon3
|
Leon3
|
||||||
M: Fabien Chouteau <chouteau@adacore.com>
|
M: Fabien Chouteau <chouteau@adacore.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/sparc/leon3.c
|
F: hw/sparc/leon3.c
|
||||||
F: hw/*/grlib*
|
F: hw/*/grlib*
|
||||||
|
F: include/hw/sparc/grlib.h
|
||||||
|
|
||||||
S390 Machines
|
S390 Machines
|
||||||
-------------
|
-------------
|
||||||
@@ -772,6 +809,7 @@ M: John Snow <jsnow@redhat.com>
|
|||||||
L: qemu-block@nongnu.org
|
L: qemu-block@nongnu.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: include/hw/ide.h
|
F: include/hw/ide.h
|
||||||
|
F: include/hw/ide/
|
||||||
F: hw/ide/
|
F: hw/ide/
|
||||||
F: hw/block/block.c
|
F: hw/block/block.c
|
||||||
F: hw/block/cdrom.c
|
F: hw/block/cdrom.c
|
||||||
@@ -908,6 +946,8 @@ virtio
|
|||||||
M: Michael S. Tsirkin <mst@redhat.com>
|
M: Michael S. Tsirkin <mst@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: hw/*/virtio*
|
F: hw/*/virtio*
|
||||||
|
F: hw/virtio/Makefile.objs
|
||||||
|
F: hw/virtio/trace-events
|
||||||
F: net/vhost-user.c
|
F: net/vhost-user.c
|
||||||
F: include/hw/virtio/
|
F: include/hw/virtio/
|
||||||
F: tests/virtio-balloon-test.c
|
F: tests/virtio-balloon-test.c
|
||||||
@@ -995,6 +1035,8 @@ Rocker
|
|||||||
M: Jiri Pirko <jiri@resnulli.us>
|
M: Jiri Pirko <jiri@resnulli.us>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/net/rocker/
|
F: hw/net/rocker/
|
||||||
|
F: tests/rocker/
|
||||||
|
F: docs/specs/rocker.txt
|
||||||
|
|
||||||
NVDIMM
|
NVDIMM
|
||||||
M: Xiao Guangrong <guangrong.xiao@linux.intel.com>
|
M: Xiao Guangrong <guangrong.xiao@linux.intel.com>
|
||||||
@@ -1013,6 +1055,12 @@ M: Dmitry Fleytman <dmitry@daynix.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/net/e1000e*
|
F: hw/net/e1000e*
|
||||||
|
|
||||||
|
Generic Loader
|
||||||
|
M: Alistair Francis <alistair.francis@xilinx.com>
|
||||||
|
S: Maintained
|
||||||
|
F: hw/core/generic-loader.c
|
||||||
|
F: include/hw/core/generic-loader.h
|
||||||
|
|
||||||
Subsystems
|
Subsystems
|
||||||
----------
|
----------
|
||||||
Audio
|
Audio
|
||||||
@@ -1020,6 +1068,7 @@ M: Gerd Hoffmann <kraxel@redhat.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: audio/
|
F: audio/
|
||||||
F: hw/audio/
|
F: hw/audio/
|
||||||
|
F: include/hw/audio/
|
||||||
F: tests/ac97-test.c
|
F: tests/ac97-test.c
|
||||||
F: tests/es1370-test.c
|
F: tests/es1370-test.c
|
||||||
F: tests/intel-hda-test.c
|
F: tests/intel-hda-test.c
|
||||||
@@ -1154,12 +1203,12 @@ F: qemu-timer.c
|
|||||||
F: vl.c
|
F: vl.c
|
||||||
|
|
||||||
Human Monitor (HMP)
|
Human Monitor (HMP)
|
||||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: monitor.c
|
F: monitor.c
|
||||||
F: hmp.c
|
F: hmp.[ch]
|
||||||
F: hmp-commands.hx
|
F: hmp-commands*.hx
|
||||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
F: include/monitor/hmp-target.h
|
||||||
|
|
||||||
Network device backends
|
Network device backends
|
||||||
M: Jason Wang <jasowang@redhat.com>
|
M: Jason Wang <jasowang@redhat.com>
|
||||||
@@ -1224,8 +1273,8 @@ F: qapi/*.json
|
|||||||
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
||||||
|
|
||||||
QObject
|
QObject
|
||||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
M: Markus Armbruster <armbru@redhat.com>
|
||||||
S: Maintained
|
S: Supported
|
||||||
F: qobject/
|
F: qobject/
|
||||||
F: include/qapi/qmp/
|
F: include/qapi/qmp/
|
||||||
X: include/qapi/qmp/dispatch.h
|
X: include/qapi/qmp/dispatch.h
|
||||||
@@ -1235,7 +1284,7 @@ F: tests/check-qint.c
|
|||||||
F: tests/check-qjson.c
|
F: tests/check-qjson.c
|
||||||
F: tests/check-qlist.c
|
F: tests/check-qlist.c
|
||||||
F: tests/check-qstring.c
|
F: tests/check-qstring.c
|
||||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
||||||
|
|
||||||
QEMU Guest Agent
|
QEMU Guest Agent
|
||||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||||
@@ -1364,6 +1413,15 @@ F: util/uuid.c
|
|||||||
F: include/qemu/uuid.h
|
F: include/qemu/uuid.h
|
||||||
F: tests/test-uuid.c
|
F: tests/test-uuid.c
|
||||||
|
|
||||||
|
COLO Proxy
|
||||||
|
M: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
|
||||||
|
M: Li Zhijian <lizhijian@cn.fujitsu.com>
|
||||||
|
S: Supported
|
||||||
|
F: docs/colo-proxy.txt
|
||||||
|
F: net/colo*
|
||||||
|
F: net/filter-rewriter.c
|
||||||
|
F: net/filter-mirror.c
|
||||||
|
|
||||||
Usermode Emulation
|
Usermode Emulation
|
||||||
------------------
|
------------------
|
||||||
Overall
|
Overall
|
||||||
@@ -1375,11 +1433,13 @@ F: user-exec.c
|
|||||||
BSD user
|
BSD user
|
||||||
S: Orphan
|
S: Orphan
|
||||||
F: bsd-user/
|
F: bsd-user/
|
||||||
|
F: default-configs/*-bsd-user.mak
|
||||||
|
|
||||||
Linux user
|
Linux user
|
||||||
M: Riku Voipio <riku.voipio@iki.fi>
|
M: Riku Voipio <riku.voipio@iki.fi>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: linux-user/
|
F: linux-user/
|
||||||
|
F: default-configs/*-linux-user.mak
|
||||||
|
|
||||||
Tiny Code Generator (TCG)
|
Tiny Code Generator (TCG)
|
||||||
-------------------------
|
-------------------------
|
||||||
|
82
Makefile
82
Makefile
@@ -56,9 +56,6 @@ GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
|
|||||||
GENERATED_HEADERS += qmp-introspect.h
|
GENERATED_HEADERS += qmp-introspect.h
|
||||||
GENERATED_SOURCES += qmp-introspect.c
|
GENERATED_SOURCES += qmp-introspect.c
|
||||||
|
|
||||||
GENERATED_HEADERS += trace/generated-events.h
|
|
||||||
GENERATED_SOURCES += trace/generated-events.c
|
|
||||||
|
|
||||||
GENERATED_HEADERS += trace/generated-tracers.h
|
GENERATED_HEADERS += trace/generated-tracers.h
|
||||||
ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace)
|
ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace)
|
||||||
GENERATED_HEADERS += trace/generated-tracers-dtrace.h
|
GENERATED_HEADERS += trace/generated-tracers-dtrace.h
|
||||||
@@ -93,7 +90,7 @@ LIBS+=-lz $(LIBS_TOOLS)
|
|||||||
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
|
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
|
||||||
|
|
||||||
ifdef BUILD_DOCS
|
ifdef BUILD_DOCS
|
||||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
|
DOCS=qemu-doc.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
|
||||||
ifdef CONFIG_VIRTFS
|
ifdef CONFIG_VIRTFS
|
||||||
DOCS+=fsdev/virtfs-proxy-helper.1
|
DOCS+=fsdev/virtfs-proxy-helper.1
|
||||||
endif
|
endif
|
||||||
@@ -107,20 +104,20 @@ SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS))
|
|||||||
|
|
||||||
ifeq ($(SUBDIR_DEVICES_MAK),)
|
ifeq ($(SUBDIR_DEVICES_MAK),)
|
||||||
config-all-devices.mak:
|
config-all-devices.mak:
|
||||||
$(call quiet-command,echo '# no devices' > $@," GEN $@")
|
$(call quiet-command,echo '# no devices' > $@,"GEN","$@")
|
||||||
else
|
else
|
||||||
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
|
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
|
||||||
$(call quiet-command, sed -n \
|
$(call quiet-command, sed -n \
|
||||||
's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \
|
's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \
|
||||||
$(SUBDIR_DEVICES_MAK) | sort -u > $@, \
|
$(SUBDIR_DEVICES_MAK) | sort -u > $@, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
-include $(SUBDIR_DEVICES_MAK_DEP)
|
-include $(SUBDIR_DEVICES_MAK_DEP)
|
||||||
|
|
||||||
%/config-devices.mak: default-configs/%.mak $(SRC_PATH)/scripts/make_device_config.sh
|
%/config-devices.mak: default-configs/%.mak $(SRC_PATH)/scripts/make_device_config.sh
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp, " GEN $@.tmp")
|
$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp,"GEN","$@.tmp")
|
||||||
$(call quiet-command, if test -f $@; then \
|
$(call quiet-command, if test -f $@; then \
|
||||||
if cmp -s $@.old $@; then \
|
if cmp -s $@.old $@; then \
|
||||||
mv $@.tmp $@; \
|
mv $@.tmp $@; \
|
||||||
@@ -137,7 +134,7 @@ endif
|
|||||||
else \
|
else \
|
||||||
mv $@.tmp $@; \
|
mv $@.tmp $@; \
|
||||||
cp -p $@ $@.old; \
|
cp -p $@ $@.old; \
|
||||||
fi, " GEN $@");
|
fi,"GEN","$@");
|
||||||
|
|
||||||
defconfig:
|
defconfig:
|
||||||
rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK)
|
rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK)
|
||||||
@@ -191,7 +188,7 @@ qemu-version.h: FORCE
|
|||||||
config-host.h: config-host.h-timestamp
|
config-host.h: config-host.h-timestamp
|
||||||
config-host.h-timestamp: config-host.mak
|
config-host.h-timestamp: config-host.mak
|
||||||
qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
|
||||||
|
|
||||||
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||||
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
|
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
|
||||||
@@ -235,9 +232,9 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
|
|||||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
||||||
|
|
||||||
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h | $(BUILD_DIR)/version.lo
|
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h | $(BUILD_DIR)/version.lo
|
||||||
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o")
|
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o")
|
||||||
$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc config-host.h
|
$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc config-host.h
|
||||||
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.lo")
|
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.lo")
|
||||||
|
|
||||||
Makefile: $(version-obj-y) $(version-lobj-y)
|
Makefile: $(version-obj-y) $(version-lobj-y)
|
||||||
|
|
||||||
@@ -261,7 +258,7 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal
|
|||||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||||
|
|
||||||
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
|
||||||
|
|
||||||
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
|
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
|
||||||
qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
|
qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
|
||||||
@@ -274,17 +271,17 @@ qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
|
|||||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
|
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
|
||||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
|
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
|
||||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||||
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
|
|
||||||
qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
|
qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
|
||||||
$(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
|
$(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
|
||||||
@@ -296,27 +293,27 @@ qapi-types.c qapi-types.h :\
|
|||||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||||
$(gen-out-type) -o "." -b $<, \
|
$(gen-out-type) -o "." -b $<, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
qapi-visit.c qapi-visit.h :\
|
qapi-visit.c qapi-visit.h :\
|
||||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||||
$(gen-out-type) -o "." -b $<, \
|
$(gen-out-type) -o "." -b $<, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
qapi-event.c qapi-event.h :\
|
qapi-event.c qapi-event.h :\
|
||||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
|
$(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
|
||||||
$(gen-out-type) -o "." $<, \
|
$(gen-out-type) -o "." $<, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
qmp-commands.h qmp-marshal.c :\
|
qmp-commands.h qmp-marshal.c :\
|
||||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
|
||||||
$(gen-out-type) -o "." $<, \
|
$(gen-out-type) -o "." $<, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
qmp-introspect.h qmp-introspect.c :\
|
qmp-introspect.h qmp-introspect.c :\
|
||||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
|
$(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
|
||||||
$(gen-out-type) -o "." $<, \
|
$(gen-out-type) -o "." $<, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
|
|
||||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
||||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
||||||
@@ -335,7 +332,7 @@ $(QEMU_GA_MSI): config-host.mak
|
|||||||
|
|
||||||
$(QEMU_GA_MSI): $(SRC_PATH)/qga/installer/qemu-ga.wxs
|
$(QEMU_GA_MSI): $(SRC_PATH)/qga/installer/qemu-ga.wxs
|
||||||
$(call quiet-command,QEMU_GA_VERSION="$(QEMU_GA_VERSION)" QEMU_GA_MANUFACTURER="$(QEMU_GA_MANUFACTURER)" QEMU_GA_DISTRO="$(QEMU_GA_DISTRO)" BUILD_DIR="$(BUILD_DIR)" \
|
$(call quiet-command,QEMU_GA_VERSION="$(QEMU_GA_VERSION)" QEMU_GA_MANUFACTURER="$(QEMU_GA_MANUFACTURER)" QEMU_GA_DISTRO="$(QEMU_GA_DISTRO)" BUILD_DIR="$(BUILD_DIR)" \
|
||||||
wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<, " WIXL $@")
|
wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<,"WIXL","$@")
|
||||||
else
|
else
|
||||||
msi:
|
msi:
|
||||||
@echo "MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)"
|
@echo "MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)"
|
||||||
@@ -354,7 +351,7 @@ ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a
|
|||||||
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
||||||
$(call quiet-command,$(PYTHON) $< $@ \
|
$(call quiet-command,$(PYTHON) $< $@ \
|
||||||
$(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \
|
$(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
# avoid old build problems by removing potentially incorrect old files
|
# avoid old build problems by removing potentially incorrect old files
|
||||||
@@ -398,7 +395,6 @@ distclean: clean
|
|||||||
rm -f qemu-doc.vr
|
rm -f qemu-doc.vr
|
||||||
rm -f config.log
|
rm -f config.log
|
||||||
rm -f linux-headers/asm
|
rm -f linux-headers/asm
|
||||||
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
|
|
||||||
for d in $(TARGET_DIRS); do \
|
for d in $(TARGET_DIRS); do \
|
||||||
rm -rf $$d || exit 1 ; \
|
rm -rf $$d || exit 1 ; \
|
||||||
done
|
done
|
||||||
@@ -434,7 +430,7 @@ endif
|
|||||||
|
|
||||||
install-doc: $(DOCS)
|
install-doc: $(DOCS)
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||||
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
|
$(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
|
||||||
$(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
|
$(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
|
||||||
ifdef CONFIG_POSIX
|
ifdef CONFIG_POSIX
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||||
@@ -521,13 +517,13 @@ ui/shader/%-vert.h: $(SRC_PATH)/ui/shader/%.vert $(SRC_PATH)/scripts/shaderinclu
|
|||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(call quiet-command,\
|
$(call quiet-command,\
|
||||||
perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\
|
perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\
|
||||||
" VERT $@")
|
"VERT","$@")
|
||||||
|
|
||||||
ui/shader/%-frag.h: $(SRC_PATH)/ui/shader/%.frag $(SRC_PATH)/scripts/shaderinclude.pl
|
ui/shader/%-frag.h: $(SRC_PATH)/ui/shader/%.frag $(SRC_PATH)/scripts/shaderinclude.pl
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(call quiet-command,\
|
$(call quiet-command,\
|
||||||
perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\
|
perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\
|
||||||
" FRAG $@")
|
"FRAG","$@")
|
||||||
|
|
||||||
ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
|
ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
|
||||||
ui/shader/texture-blit-vert.h ui/shader/texture-blit-frag.h
|
ui/shader/texture-blit-vert.h ui/shader/texture-blit-frag.h
|
||||||
@@ -537,65 +533,65 @@ MAKEINFO=makeinfo
|
|||||||
MAKEINFOFLAGS=--no-headers --no-split --number-sections
|
MAKEINFOFLAGS=--no-headers --no-split --number-sections
|
||||||
TEXIFLAG=$(if $(V),,--quiet)
|
TEXIFLAG=$(if $(V),,--quiet)
|
||||||
%.dvi: %.texi
|
%.dvi: %.texi
|
||||||
$(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<," GEN $@")
|
$(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<,"GEN","$@")
|
||||||
|
|
||||||
%.html: %.texi
|
%.html: %.texi
|
||||||
$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \
|
$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
|
|
||||||
%.info: %.texi
|
%.info: %.texi
|
||||||
$(call quiet-command,$(MAKEINFO) $< -o $@," GEN $@")
|
$(call quiet-command,$(MAKEINFO) $< -o $@,"GEN","$@")
|
||||||
|
|
||||||
%.pdf: %.texi
|
%.pdf: %.texi
|
||||||
$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<," GEN $@")
|
$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<,"GEN","$@")
|
||||||
|
|
||||||
qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||||
|
|
||||||
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||||
|
|
||||||
qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||||
|
|
||||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||||
|
|
||||||
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
|
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
|
||||||
$(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
|
$(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
qemu.1: qemu-option-trace.texi
|
qemu.1: qemu-option-trace.texi
|
||||||
|
|
||||||
qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi
|
qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
|
||||||
$(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \
|
$(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
|
|
||||||
fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
|
fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \
|
||||||
$(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
|
$(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
|
|
||||||
qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
|
qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
|
||||||
$(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
|
$(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
|
|
||||||
qemu-ga.8: qemu-ga.texi
|
qemu-ga.8: qemu-ga.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-ga.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-ga.pod && \
|
||||||
$(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \
|
$(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \
|
||||||
" GEN $@")
|
"GEN","$@")
|
||||||
|
|
||||||
dvi: qemu-doc.dvi qemu-tech.dvi
|
dvi: qemu-doc.dvi
|
||||||
html: qemu-doc.html qemu-tech.html
|
html: qemu-doc.html
|
||||||
info: qemu-doc.info qemu-tech.info
|
info: qemu-doc.info
|
||||||
pdf: qemu-doc.pdf qemu-tech.pdf
|
pdf: qemu-doc.pdf
|
||||||
|
|
||||||
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
|
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
|
||||||
qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
|
qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
|
||||||
|
@@ -89,7 +89,7 @@ endif
|
|||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# Target-independent parts used in system and user emulation
|
# Target-independent parts used in system and user emulation
|
||||||
common-obj-y += tcg-runtime.o
|
common-obj-y += tcg-runtime.o cpus-common.o
|
||||||
common-obj-y += hw/
|
common-obj-y += hw/
|
||||||
common-obj-y += qom/
|
common-obj-y += qom/
|
||||||
common-obj-y += disas/
|
common-obj-y += disas/
|
||||||
@@ -142,6 +142,7 @@ trace-events-y += hw/dma/trace-events
|
|||||||
trace-events-y += hw/sparc/trace-events
|
trace-events-y += hw/sparc/trace-events
|
||||||
trace-events-y += hw/sd/trace-events
|
trace-events-y += hw/sd/trace-events
|
||||||
trace-events-y += hw/isa/trace-events
|
trace-events-y += hw/isa/trace-events
|
||||||
|
trace-events-y += hw/mem/trace-events
|
||||||
trace-events-y += hw/i386/trace-events
|
trace-events-y += hw/i386/trace-events
|
||||||
trace-events-y += hw/9pfs/trace-events
|
trace-events-y += hw/9pfs/trace-events
|
||||||
trace-events-y += hw/ppc/trace-events
|
trace-events-y += hw/ppc/trace-events
|
||||||
|
@@ -26,7 +26,7 @@ ifneq (,$(findstring -mwindows,$(libs_softmmu)))
|
|||||||
# Terminate program name with a 'w' because the linker builds a windows executable.
|
# Terminate program name with a 'w' because the linker builds a windows executable.
|
||||||
QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF)
|
QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF)
|
||||||
$(QEMU_PROG): $(QEMU_PROGW)
|
$(QEMU_PROG): $(QEMU_PROGW)
|
||||||
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
|
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG),"GEN","$(TARGET_DIR)$(QEMU_PROG)")
|
||||||
QEMU_PROG_BUILD = $(QEMU_PROGW)
|
QEMU_PROG_BUILD = $(QEMU_PROGW)
|
||||||
else
|
else
|
||||||
QEMU_PROG_BUILD = $(QEMU_PROG)
|
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||||
@@ -55,7 +55,7 @@ $(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all
|
|||||||
--binary=$(bindir)/$(QEMU_PROG) \
|
--binary=$(bindir)/$(QEMU_PROG) \
|
||||||
--target-name=$(TARGET_NAME) \
|
--target-name=$(TARGET_NAME) \
|
||||||
--target-type=$(TARGET_TYPE) \
|
--target-type=$(TARGET_TYPE) \
|
||||||
< $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp-installed")
|
$< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp-installed")
|
||||||
|
|
||||||
$(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all
|
$(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all
|
||||||
$(call quiet-command,$(TRACETOOL) \
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
@@ -64,14 +64,14 @@ $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all
|
|||||||
--binary=$(realpath .)/$(QEMU_PROG) \
|
--binary=$(realpath .)/$(QEMU_PROG) \
|
||||||
--target-name=$(TARGET_NAME) \
|
--target-name=$(TARGET_NAME) \
|
||||||
--target-type=$(TARGET_TYPE) \
|
--target-type=$(TARGET_TYPE) \
|
||||||
< $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp")
|
$< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp")
|
||||||
|
|
||||||
$(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all
|
$(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all
|
||||||
$(call quiet-command,$(TRACETOOL) \
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
--format=simpletrace-stap \
|
--format=simpletrace-stap \
|
||||||
--backends=$(TRACE_BACKENDS) \
|
--backends=$(TRACE_BACKENDS) \
|
||||||
--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \
|
--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \
|
||||||
< $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp")
|
$< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp")
|
||||||
|
|
||||||
else
|
else
|
||||||
stap:
|
stap:
|
||||||
@@ -196,18 +196,18 @@ $(QEMU_PROG_BUILD): config-devices.mak
|
|||||||
$(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
$(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
||||||
$(call LINK, $(filter-out %.mak, $^))
|
$(call LINK, $(filter-out %.mak, $^))
|
||||||
ifdef CONFIG_DARWIN
|
ifdef CONFIG_DARWIN
|
||||||
$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@," REZ $(TARGET_DIR)$@")
|
$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@")
|
||||||
$(call quiet-command,SetFile -a C $@," SETFILE $(TARGET_DIR)$@")
|
$(call quiet-command,SetFile -a C $@,"SETFILE","$(TARGET_DIR)$@")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
|
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
|
||||||
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
|
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"GEN","$(TARGET_DIR)$@")
|
||||||
|
|
||||||
hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@")
|
||||||
|
|
||||||
hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@")
|
||||||
|
|
||||||
clean: clean-target
|
clean: clean-target
|
||||||
rm -f *.a *~ $(PROGS)
|
rm -f *.a *~ $(PROGS)
|
||||||
|
2
README
2
README
@@ -42,8 +42,6 @@ of other UNIX targets. The simple steps to build QEMU are:
|
|||||||
../configure
|
../configure
|
||||||
make
|
make
|
||||||
|
|
||||||
Complete details of the process for building and configuring QEMU for
|
|
||||||
all supported host platforms can be found in the qemu-tech.html file.
|
|
||||||
Additional information can also be found online via the QEMU website:
|
Additional information can also be found online via the QEMU website:
|
||||||
|
|
||||||
http://qemu-project.org/Hosts/Linux
|
http://qemu-project.org/Hosts/Linux
|
||||||
|
@@ -431,13 +431,15 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
|||||||
assert(npfd == 0);
|
assert(npfd == 0);
|
||||||
|
|
||||||
/* fill pollfds */
|
/* fill pollfds */
|
||||||
|
|
||||||
|
if (!aio_epoll_enabled(ctx)) {
|
||||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||||
if (!node->deleted && node->pfd.events
|
if (!node->deleted && node->pfd.events
|
||||||
&& !aio_epoll_enabled(ctx)
|
|
||||||
&& aio_node_check(ctx, node->is_external)) {
|
&& aio_node_check(ctx, node->is_external)) {
|
||||||
add_pollfd(node);
|
add_pollfd(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
timeout = blocking ? aio_compute_timeout(ctx) : 0;
|
timeout = blocking ? aio_compute_timeout(ctx) : 0;
|
||||||
|
|
||||||
|
27
async.c
27
async.c
@@ -44,6 +44,25 @@ struct QEMUBH {
|
|||||||
bool deleted;
|
bool deleted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
||||||
|
{
|
||||||
|
QEMUBH *bh;
|
||||||
|
bh = g_new(QEMUBH, 1);
|
||||||
|
*bh = (QEMUBH){
|
||||||
|
.ctx = ctx,
|
||||||
|
.cb = cb,
|
||||||
|
.opaque = opaque,
|
||||||
|
};
|
||||||
|
qemu_mutex_lock(&ctx->bh_lock);
|
||||||
|
bh->next = ctx->first_bh;
|
||||||
|
bh->scheduled = 1;
|
||||||
|
bh->deleted = 1;
|
||||||
|
/* Make sure that the members are ready before putting bh into list */
|
||||||
|
smp_wmb();
|
||||||
|
ctx->first_bh = bh;
|
||||||
|
qemu_mutex_unlock(&ctx->bh_lock);
|
||||||
|
}
|
||||||
|
|
||||||
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
QEMUBH *bh;
|
QEMUBH *bh;
|
||||||
@@ -86,7 +105,7 @@ int aio_bh_poll(AioContext *ctx)
|
|||||||
* thread sees the zero before bh->cb has run, and thus will call
|
* thread sees the zero before bh->cb has run, and thus will call
|
||||||
* aio_notify again if necessary.
|
* aio_notify again if necessary.
|
||||||
*/
|
*/
|
||||||
if (!bh->deleted && atomic_xchg(&bh->scheduled, 0)) {
|
if (atomic_xchg(&bh->scheduled, 0)) {
|
||||||
/* Idle BHs and the notify BH don't count as progress */
|
/* Idle BHs and the notify BH don't count as progress */
|
||||||
if (!bh->idle && bh != ctx->notify_dummy_bh) {
|
if (!bh->idle && bh != ctx->notify_dummy_bh) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
@@ -104,7 +123,7 @@ int aio_bh_poll(AioContext *ctx)
|
|||||||
bhp = &ctx->first_bh;
|
bhp = &ctx->first_bh;
|
||||||
while (*bhp) {
|
while (*bhp) {
|
||||||
bh = *bhp;
|
bh = *bhp;
|
||||||
if (bh->deleted) {
|
if (bh->deleted && !bh->scheduled) {
|
||||||
*bhp = bh->next;
|
*bhp = bh->next;
|
||||||
g_free(bh);
|
g_free(bh);
|
||||||
} else {
|
} else {
|
||||||
@@ -168,7 +187,7 @@ aio_compute_timeout(AioContext *ctx)
|
|||||||
QEMUBH *bh;
|
QEMUBH *bh;
|
||||||
|
|
||||||
for (bh = ctx->first_bh; bh; bh = bh->next) {
|
for (bh = ctx->first_bh; bh; bh = bh->next) {
|
||||||
if (!bh->deleted && bh->scheduled) {
|
if (bh->scheduled) {
|
||||||
if (bh->idle) {
|
if (bh->idle) {
|
||||||
/* idle bottom halves will be polled at least
|
/* idle bottom halves will be polled at least
|
||||||
* every 10ms */
|
* every 10ms */
|
||||||
@@ -216,7 +235,7 @@ aio_ctx_check(GSource *source)
|
|||||||
aio_notify_accept(ctx);
|
aio_notify_accept(ctx);
|
||||||
|
|
||||||
for (bh = ctx->first_bh; bh; bh = bh->next) {
|
for (bh = ctx->first_bh; bh; bh = bh->next) {
|
||||||
if (!bh->deleted && bh->scheduled) {
|
if (bh->scheduled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
block.c
59
block.c
@@ -42,6 +42,7 @@
|
|||||||
#include "qapi-event.h"
|
#include "qapi-event.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/id.h"
|
#include "qemu/id.h"
|
||||||
|
#include "qapi/util.h"
|
||||||
|
|
||||||
#ifdef CONFIG_BSD
|
#ifdef CONFIG_BSD
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
@@ -764,7 +765,7 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
|
|||||||
/* Our block drivers take care to send flushes and respect unmap policy,
|
/* Our block drivers take care to send flushes and respect unmap policy,
|
||||||
* so we can default to enable both on lower layers regardless of the
|
* so we can default to enable both on lower layers regardless of the
|
||||||
* corresponding parent options. */
|
* corresponding parent options. */
|
||||||
flags |= BDRV_O_UNMAP;
|
qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap");
|
||||||
|
|
||||||
/* Clear flags that only apply to the top layer */
|
/* Clear flags that only apply to the top layer */
|
||||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ |
|
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ |
|
||||||
@@ -925,7 +926,7 @@ out:
|
|||||||
g_free(gen_node_name);
|
g_free(gen_node_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QemuOptsList bdrv_runtime_opts = {
|
QemuOptsList bdrv_runtime_opts = {
|
||||||
.name = "bdrv_common",
|
.name = "bdrv_common",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
|
||||||
.desc = {
|
.desc = {
|
||||||
@@ -954,6 +955,16 @@ static QemuOptsList bdrv_runtime_opts = {
|
|||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
.help = "Node is opened in read-only mode",
|
.help = "Node is opened in read-only mode",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "detect-zeroes",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "try to optimize zero writes (off, on, unmap)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "discard",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "discard operation (ignore/off, unmap/on)",
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -970,6 +981,8 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
|
|||||||
const char *filename;
|
const char *filename;
|
||||||
const char *driver_name = NULL;
|
const char *driver_name = NULL;
|
||||||
const char *node_name = NULL;
|
const char *node_name = NULL;
|
||||||
|
const char *discard;
|
||||||
|
const char *detect_zeroes;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@@ -1038,6 +1051,41 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
discard = qemu_opt_get(opts, "discard");
|
||||||
|
if (discard != NULL) {
|
||||||
|
if (bdrv_parse_discard_flags(discard, &bs->open_flags) != 0) {
|
||||||
|
error_setg(errp, "Invalid discard option");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail_opts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_zeroes = qemu_opt_get(opts, "detect-zeroes");
|
||||||
|
if (detect_zeroes) {
|
||||||
|
BlockdevDetectZeroesOptions value =
|
||||||
|
qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
|
||||||
|
detect_zeroes,
|
||||||
|
BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX,
|
||||||
|
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail_opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
|
||||||
|
!(bs->open_flags & BDRV_O_UNMAP))
|
||||||
|
{
|
||||||
|
error_setg(errp, "setting detect-zeroes to unmap is not allowed "
|
||||||
|
"without setting discard operation to unmap");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail_opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs->detect_zeroes = value;
|
||||||
|
}
|
||||||
|
|
||||||
if (filename != NULL) {
|
if (filename != NULL) {
|
||||||
pstrcpy(bs->filename, sizeof(bs->filename), filename);
|
pstrcpy(bs->filename, sizeof(bs->filename), filename);
|
||||||
} else {
|
} else {
|
||||||
@@ -3312,17 +3360,10 @@ int bdrv_media_changed(BlockDriverState *bs)
|
|||||||
void bdrv_eject(BlockDriverState *bs, bool eject_flag)
|
void bdrv_eject(BlockDriverState *bs, bool eject_flag)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
const char *device_name;
|
|
||||||
|
|
||||||
if (drv && drv->bdrv_eject) {
|
if (drv && drv->bdrv_eject) {
|
||||||
drv->bdrv_eject(bs, eject_flag);
|
drv->bdrv_eject(bs, eject_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
device_name = bdrv_get_device_name(bs);
|
|
||||||
if (device_name[0] != '\0') {
|
|
||||||
qapi_event_send_device_tray_moved(device_name,
|
|
||||||
eject_flag, &error_abort);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -41,6 +41,7 @@ gluster.o-libs := $(GLUSTERFS_LIBS)
|
|||||||
ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
||||||
ssh.o-libs := $(LIBSSH2_LIBS)
|
ssh.o-libs := $(LIBSSH2_LIBS)
|
||||||
archipelago.o-libs := $(ARCHIPELAGO_LIBS)
|
archipelago.o-libs := $(ARCHIPELAGO_LIBS)
|
||||||
dmg.o-libs := $(BZIP2_LIBS)
|
block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
|
||||||
|
dmg-bz2.o-libs := $(BZIP2_LIBS)
|
||||||
qcow.o-libs := -lz
|
qcow.o-libs := -lz
|
||||||
linux-aio.o-libs := -laio
|
linux-aio.o-libs := -laio
|
||||||
|
@@ -87,7 +87,6 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct ArchipelagoAIOCB {
|
typedef struct ArchipelagoAIOCB {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
QEMUBH *bh;
|
|
||||||
struct BDRVArchipelagoState *s;
|
struct BDRVArchipelagoState *s;
|
||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
ARCHIPCmd cmd;
|
ARCHIPCmd cmd;
|
||||||
@@ -154,11 +153,10 @@ static void archipelago_finish_aiocb(AIORequestData *reqdata)
|
|||||||
} else if (reqdata->aio_cb->ret == reqdata->segreq->total) {
|
} else if (reqdata->aio_cb->ret == reqdata->segreq->total) {
|
||||||
reqdata->aio_cb->ret = 0;
|
reqdata->aio_cb->ret = 0;
|
||||||
}
|
}
|
||||||
reqdata->aio_cb->bh = aio_bh_new(
|
aio_bh_schedule_oneshot(
|
||||||
bdrv_get_aio_context(reqdata->aio_cb->common.bs),
|
bdrv_get_aio_context(reqdata->aio_cb->common.bs),
|
||||||
qemu_archipelago_complete_aio, reqdata
|
qemu_archipelago_complete_aio, reqdata
|
||||||
);
|
);
|
||||||
qemu_bh_schedule(reqdata->aio_cb->bh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wait_reply(struct xseg *xseg, xport srcport, struct xseg_port *port,
|
static int wait_reply(struct xseg *xseg, xport srcport, struct xseg_port *port,
|
||||||
@@ -313,7 +311,6 @@ static void qemu_archipelago_complete_aio(void *opaque)
|
|||||||
AIORequestData *reqdata = (AIORequestData *) opaque;
|
AIORequestData *reqdata = (AIORequestData *) opaque;
|
||||||
ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) reqdata->aio_cb;
|
ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) reqdata->aio_cb;
|
||||||
|
|
||||||
qemu_bh_delete(aio_cb->bh);
|
|
||||||
aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
|
aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
|
||||||
aio_cb->status = 0;
|
aio_cb->status = 0;
|
||||||
|
|
||||||
|
@@ -49,7 +49,6 @@ typedef struct BDRVBlkdebugState {
|
|||||||
|
|
||||||
typedef struct BlkdebugAIOCB {
|
typedef struct BlkdebugAIOCB {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
QEMUBH *bh;
|
|
||||||
int ret;
|
int ret;
|
||||||
} BlkdebugAIOCB;
|
} BlkdebugAIOCB;
|
||||||
|
|
||||||
@@ -410,7 +409,6 @@ out:
|
|||||||
static void error_callback_bh(void *opaque)
|
static void error_callback_bh(void *opaque)
|
||||||
{
|
{
|
||||||
struct BlkdebugAIOCB *acb = opaque;
|
struct BlkdebugAIOCB *acb = opaque;
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
acb->common.cb(acb->common.opaque, acb->ret);
|
acb->common.cb(acb->common.opaque, acb->ret);
|
||||||
qemu_aio_unref(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
@@ -421,7 +419,6 @@ static BlockAIOCB *inject_error(BlockDriverState *bs,
|
|||||||
BDRVBlkdebugState *s = bs->opaque;
|
BDRVBlkdebugState *s = bs->opaque;
|
||||||
int error = rule->options.inject.error;
|
int error = rule->options.inject.error;
|
||||||
struct BlkdebugAIOCB *acb;
|
struct BlkdebugAIOCB *acb;
|
||||||
QEMUBH *bh;
|
|
||||||
bool immediately = rule->options.inject.immediately;
|
bool immediately = rule->options.inject.immediately;
|
||||||
|
|
||||||
if (rule->options.inject.once) {
|
if (rule->options.inject.once) {
|
||||||
@@ -436,9 +433,7 @@ static BlockAIOCB *inject_error(BlockDriverState *bs,
|
|||||||
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
|
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
|
||||||
acb->ret = -error;
|
acb->ret = -error;
|
||||||
|
|
||||||
bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh, acb);
|
||||||
acb->bh = bh;
|
|
||||||
qemu_bh_schedule(bh);
|
|
||||||
|
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
|
@@ -20,11 +20,6 @@ typedef struct Request {
|
|||||||
QEMUBH *bh;
|
QEMUBH *bh;
|
||||||
} Request;
|
} Request;
|
||||||
|
|
||||||
/* Next request id.
|
|
||||||
This counter is global, because requests from different
|
|
||||||
block devices should not get overlapping ids. */
|
|
||||||
static uint64_t request_id;
|
|
||||||
|
|
||||||
static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
|
static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@@ -84,7 +79,7 @@ static void block_request_create(uint64_t reqid, BlockDriverState *bs,
|
|||||||
static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
|
static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
|
||||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||||
{
|
{
|
||||||
uint64_t reqid = request_id++;
|
uint64_t reqid = blkreplay_next_id();
|
||||||
int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
@@ -95,7 +90,7 @@ static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
|
|||||||
static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
|
static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
|
||||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||||
{
|
{
|
||||||
uint64_t reqid = request_id++;
|
uint64_t reqid = blkreplay_next_id();
|
||||||
int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
||||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
@@ -106,7 +101,7 @@ static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
|
|||||||
static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
|
static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
|
||||||
int64_t offset, int count, BdrvRequestFlags flags)
|
int64_t offset, int count, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
uint64_t reqid = request_id++;
|
uint64_t reqid = blkreplay_next_id();
|
||||||
int ret = bdrv_co_pwrite_zeroes(bs->file, offset, count, flags);
|
int ret = bdrv_co_pwrite_zeroes(bs->file, offset, count, flags);
|
||||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
@@ -117,7 +112,7 @@ static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
|
static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
|
||||||
int64_t offset, int count)
|
int64_t offset, int count)
|
||||||
{
|
{
|
||||||
uint64_t reqid = request_id++;
|
uint64_t reqid = blkreplay_next_id();
|
||||||
int ret = bdrv_co_pdiscard(bs->file->bs, offset, count);
|
int ret = bdrv_co_pdiscard(bs->file->bs, offset, count);
|
||||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
@@ -127,7 +122,7 @@ static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
|
|||||||
|
|
||||||
static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
|
static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
uint64_t reqid = request_id++;
|
uint64_t reqid = blkreplay_next_id();
|
||||||
int ret = bdrv_co_flush(bs->file->bs);
|
int ret = bdrv_co_flush(bs->file->bs);
|
||||||
block_request_create(reqid, bs, qemu_coroutine_self());
|
block_request_create(reqid, bs, qemu_coroutine_self());
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
|
@@ -22,7 +22,6 @@ typedef struct {
|
|||||||
typedef struct BlkverifyAIOCB BlkverifyAIOCB;
|
typedef struct BlkverifyAIOCB BlkverifyAIOCB;
|
||||||
struct BlkverifyAIOCB {
|
struct BlkverifyAIOCB {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
QEMUBH *bh;
|
|
||||||
|
|
||||||
/* Request metadata */
|
/* Request metadata */
|
||||||
bool is_write;
|
bool is_write;
|
||||||
@@ -175,7 +174,6 @@ static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
|
|||||||
{
|
{
|
||||||
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
|
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
|
||||||
|
|
||||||
acb->bh = NULL;
|
|
||||||
acb->is_write = is_write;
|
acb->is_write = is_write;
|
||||||
acb->sector_num = sector_num;
|
acb->sector_num = sector_num;
|
||||||
acb->nb_sectors = nb_sectors;
|
acb->nb_sectors = nb_sectors;
|
||||||
@@ -191,7 +189,6 @@ static void blkverify_aio_bh(void *opaque)
|
|||||||
{
|
{
|
||||||
BlkverifyAIOCB *acb = opaque;
|
BlkverifyAIOCB *acb = opaque;
|
||||||
|
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
if (acb->buf) {
|
if (acb->buf) {
|
||||||
qemu_iovec_destroy(&acb->raw_qiov);
|
qemu_iovec_destroy(&acb->raw_qiov);
|
||||||
qemu_vfree(acb->buf);
|
qemu_vfree(acb->buf);
|
||||||
@@ -218,9 +215,8 @@ static void blkverify_aio_cb(void *opaque, int ret)
|
|||||||
acb->verify(acb);
|
acb->verify(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
|
||||||
blkverify_aio_bh, acb);
|
blkverify_aio_bh, acb);
|
||||||
qemu_bh_schedule(acb->bh);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,7 @@ struct BlockBackend {
|
|||||||
BlockBackendPublic public;
|
BlockBackendPublic public;
|
||||||
|
|
||||||
void *dev; /* attached device model, if any */
|
void *dev; /* attached device model, if any */
|
||||||
|
bool legacy_dev; /* true if dev is not a DeviceState */
|
||||||
/* TODO change to DeviceState when all users are qdevified */
|
/* TODO change to DeviceState when all users are qdevified */
|
||||||
const BlockDevOps *dev_ops;
|
const BlockDevOps *dev_ops;
|
||||||
void *dev_opaque;
|
void *dev_opaque;
|
||||||
@@ -65,7 +66,6 @@ struct BlockBackend {
|
|||||||
|
|
||||||
typedef struct BlockBackendAIOCB {
|
typedef struct BlockBackendAIOCB {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
QEMUBH *bh;
|
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
int ret;
|
int ret;
|
||||||
} BlockBackendAIOCB;
|
} BlockBackendAIOCB;
|
||||||
@@ -507,32 +507,38 @@ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int blk_do_attach_dev(BlockBackend *blk, void *dev)
|
||||||
* Attach device model @dev to @blk.
|
|
||||||
* Return 0 on success, -EBUSY when a device model is attached already.
|
|
||||||
*/
|
|
||||||
int blk_attach_dev(BlockBackend *blk, void *dev)
|
|
||||||
/* TODO change to DeviceState *dev when all users are qdevified */
|
|
||||||
{
|
{
|
||||||
if (blk->dev) {
|
if (blk->dev) {
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
blk_ref(blk);
|
blk_ref(blk);
|
||||||
blk->dev = dev;
|
blk->dev = dev;
|
||||||
|
blk->legacy_dev = false;
|
||||||
blk_iostatus_reset(blk);
|
blk_iostatus_reset(blk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attach device model @dev to @blk.
|
||||||
|
* Return 0 on success, -EBUSY when a device model is attached already.
|
||||||
|
*/
|
||||||
|
int blk_attach_dev(BlockBackend *blk, DeviceState *dev)
|
||||||
|
{
|
||||||
|
return blk_do_attach_dev(blk, dev);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attach device model @dev to @blk.
|
* Attach device model @dev to @blk.
|
||||||
* @blk must not have a device model attached already.
|
* @blk must not have a device model attached already.
|
||||||
* TODO qdevified devices don't use this, remove when devices are qdevified
|
* TODO qdevified devices don't use this, remove when devices are qdevified
|
||||||
*/
|
*/
|
||||||
void blk_attach_dev_nofail(BlockBackend *blk, void *dev)
|
void blk_attach_dev_legacy(BlockBackend *blk, void *dev)
|
||||||
{
|
{
|
||||||
if (blk_attach_dev(blk, dev) < 0) {
|
if (blk_do_attach_dev(blk, dev) < 0) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
blk->legacy_dev = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -559,6 +565,23 @@ void *blk_get_attached_dev(BlockBackend *blk)
|
|||||||
return blk->dev;
|
return blk->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the qdev ID, or if no ID is assigned the QOM path, of the block
|
||||||
|
* device attached to the BlockBackend. */
|
||||||
|
static char *blk_get_attached_dev_id(BlockBackend *blk)
|
||||||
|
{
|
||||||
|
DeviceState *dev;
|
||||||
|
|
||||||
|
assert(!blk->legacy_dev);
|
||||||
|
dev = blk->dev;
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
return g_strdup("");
|
||||||
|
} else if (dev->id) {
|
||||||
|
return g_strdup(dev->id);
|
||||||
|
}
|
||||||
|
return object_get_canonical_path(OBJECT(dev));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the BlockBackend which has the device model @dev attached if it
|
* Return the BlockBackend which has the device model @dev attached if it
|
||||||
* exists, else null.
|
* exists, else null.
|
||||||
@@ -586,6 +609,11 @@ BlockBackend *blk_by_dev(void *dev)
|
|||||||
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
|
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
|
/* All drivers that use blk_set_dev_ops() are qdevified and we want to keep
|
||||||
|
* it that way, so we can assume blk->dev is a DeviceState if blk->dev_ops
|
||||||
|
* is set. */
|
||||||
|
assert(!blk->legacy_dev);
|
||||||
|
|
||||||
blk->dev_ops = ops;
|
blk->dev_ops = ops;
|
||||||
blk->dev_opaque = opaque;
|
blk->dev_opaque = opaque;
|
||||||
}
|
}
|
||||||
@@ -601,13 +629,17 @@ void blk_dev_change_media_cb(BlockBackend *blk, bool load)
|
|||||||
if (blk->dev_ops && blk->dev_ops->change_media_cb) {
|
if (blk->dev_ops && blk->dev_ops->change_media_cb) {
|
||||||
bool tray_was_open, tray_is_open;
|
bool tray_was_open, tray_is_open;
|
||||||
|
|
||||||
|
assert(!blk->legacy_dev);
|
||||||
|
|
||||||
tray_was_open = blk_dev_is_tray_open(blk);
|
tray_was_open = blk_dev_is_tray_open(blk);
|
||||||
blk->dev_ops->change_media_cb(blk->dev_opaque, load);
|
blk->dev_ops->change_media_cb(blk->dev_opaque, load);
|
||||||
tray_is_open = blk_dev_is_tray_open(blk);
|
tray_is_open = blk_dev_is_tray_open(blk);
|
||||||
|
|
||||||
if (tray_was_open != tray_is_open) {
|
if (tray_was_open != tray_is_open) {
|
||||||
qapi_event_send_device_tray_moved(blk_name(blk), tray_is_open,
|
char *id = blk_get_attached_dev_id(blk);
|
||||||
|
qapi_event_send_device_tray_moved(blk_name(blk), id, tray_is_open,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
|
g_free(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -898,7 +930,6 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
|
|||||||
static void error_callback_bh(void *opaque)
|
static void error_callback_bh(void *opaque)
|
||||||
{
|
{
|
||||||
struct BlockBackendAIOCB *acb = opaque;
|
struct BlockBackendAIOCB *acb = opaque;
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
acb->common.cb(acb->common.opaque, acb->ret);
|
acb->common.cb(acb->common.opaque, acb->ret);
|
||||||
qemu_aio_unref(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
@@ -908,16 +939,12 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
|
|||||||
void *opaque, int ret)
|
void *opaque, int ret)
|
||||||
{
|
{
|
||||||
struct BlockBackendAIOCB *acb;
|
struct BlockBackendAIOCB *acb;
|
||||||
QEMUBH *bh;
|
|
||||||
|
|
||||||
acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque);
|
acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque);
|
||||||
acb->blk = blk;
|
acb->blk = blk;
|
||||||
acb->ret = ret;
|
acb->ret = ret;
|
||||||
|
|
||||||
bh = aio_bh_new(blk_get_aio_context(blk), error_callback_bh, acb);
|
aio_bh_schedule_oneshot(blk_get_aio_context(blk), error_callback_bh, acb);
|
||||||
acb->bh = bh;
|
|
||||||
qemu_bh_schedule(bh);
|
|
||||||
|
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -926,7 +953,6 @@ typedef struct BlkAioEmAIOCB {
|
|||||||
BlkRwCo rwco;
|
BlkRwCo rwco;
|
||||||
int bytes;
|
int bytes;
|
||||||
bool has_returned;
|
bool has_returned;
|
||||||
QEMUBH* bh;
|
|
||||||
} BlkAioEmAIOCB;
|
} BlkAioEmAIOCB;
|
||||||
|
|
||||||
static const AIOCBInfo blk_aio_em_aiocb_info = {
|
static const AIOCBInfo blk_aio_em_aiocb_info = {
|
||||||
@@ -935,10 +961,6 @@ static const AIOCBInfo blk_aio_em_aiocb_info = {
|
|||||||
|
|
||||||
static void blk_aio_complete(BlkAioEmAIOCB *acb)
|
static void blk_aio_complete(BlkAioEmAIOCB *acb)
|
||||||
{
|
{
|
||||||
if (acb->bh) {
|
|
||||||
assert(acb->has_returned);
|
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
}
|
|
||||||
if (acb->has_returned) {
|
if (acb->has_returned) {
|
||||||
acb->common.cb(acb->common.opaque, acb->rwco.ret);
|
acb->common.cb(acb->common.opaque, acb->rwco.ret);
|
||||||
qemu_aio_unref(acb);
|
qemu_aio_unref(acb);
|
||||||
@@ -947,7 +969,10 @@ static void blk_aio_complete(BlkAioEmAIOCB *acb)
|
|||||||
|
|
||||||
static void blk_aio_complete_bh(void *opaque)
|
static void blk_aio_complete_bh(void *opaque)
|
||||||
{
|
{
|
||||||
blk_aio_complete(opaque);
|
BlkAioEmAIOCB *acb = opaque;
|
||||||
|
|
||||||
|
assert(acb->has_returned);
|
||||||
|
blk_aio_complete(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
||||||
@@ -967,7 +992,6 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
|||||||
.ret = NOT_DONE,
|
.ret = NOT_DONE,
|
||||||
};
|
};
|
||||||
acb->bytes = bytes;
|
acb->bytes = bytes;
|
||||||
acb->bh = NULL;
|
|
||||||
acb->has_returned = false;
|
acb->has_returned = false;
|
||||||
|
|
||||||
co = qemu_coroutine_create(co_entry, acb);
|
co = qemu_coroutine_create(co_entry, acb);
|
||||||
@@ -975,8 +999,8 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
|||||||
|
|
||||||
acb->has_returned = true;
|
acb->has_returned = true;
|
||||||
if (acb->rwco.ret != NOT_DONE) {
|
if (acb->rwco.ret != NOT_DONE) {
|
||||||
acb->bh = aio_bh_new(blk_get_aio_context(blk), blk_aio_complete_bh, acb);
|
aio_bh_schedule_oneshot(blk_get_aio_context(blk),
|
||||||
qemu_bh_schedule(acb->bh);
|
blk_aio_complete_bh, acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
@@ -1206,8 +1230,9 @@ static void send_qmp_error_event(BlockBackend *blk,
|
|||||||
IoOperationType optype;
|
IoOperationType optype;
|
||||||
|
|
||||||
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
|
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
|
||||||
qapi_event_send_block_io_error(blk_name(blk), optype, action,
|
qapi_event_send_block_io_error(blk_name(blk),
|
||||||
blk_iostatus_is_enabled(blk),
|
bdrv_get_node_name(blk_bs(blk)), optype,
|
||||||
|
action, blk_iostatus_is_enabled(blk),
|
||||||
error == ENOSPC, strerror(error),
|
error == ENOSPC, strerror(error),
|
||||||
&error_abort);
|
&error_abort);
|
||||||
}
|
}
|
||||||
@@ -1312,9 +1337,19 @@ void blk_lock_medium(BlockBackend *blk, bool locked)
|
|||||||
void blk_eject(BlockBackend *blk, bool eject_flag)
|
void blk_eject(BlockBackend *blk, bool eject_flag)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = blk_bs(blk);
|
BlockDriverState *bs = blk_bs(blk);
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
/* blk_eject is only called by qdevified devices */
|
||||||
|
assert(!blk->legacy_dev);
|
||||||
|
|
||||||
if (bs) {
|
if (bs) {
|
||||||
bdrv_eject(bs, eject_flag);
|
bdrv_eject(bs, eject_flag);
|
||||||
|
|
||||||
|
id = blk_get_attached_dev_id(blk);
|
||||||
|
qapi_event_send_device_tray_moved(blk_name(blk), id,
|
||||||
|
eject_flag, &error_abort);
|
||||||
|
g_free(id);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1592,13 +1627,12 @@ void blk_update_root_state(BlockBackend *blk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Applies the information in the root state to the given BlockDriverState. This
|
* Returns the detect-zeroes setting to be used for bdrv_open() of a
|
||||||
* does not include the flags which have to be specified for bdrv_open(), use
|
* BlockDriverState which is supposed to inherit the root state.
|
||||||
* blk_get_open_flags_from_root_state() to inquire them.
|
|
||||||
*/
|
*/
|
||||||
void blk_apply_root_state(BlockBackend *blk, BlockDriverState *bs)
|
bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk)
|
||||||
{
|
{
|
||||||
bs->detect_zeroes = blk->root_state.detect_zeroes;
|
return blk->root_state.detect_zeroes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1640,28 +1674,6 @@ int blk_commit_all(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int blk_flush_all(void)
|
|
||||||
{
|
|
||||||
BlockBackend *blk = NULL;
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
while ((blk = blk_all_next(blk)) != NULL) {
|
|
||||||
AioContext *aio_context = blk_get_aio_context(blk);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
aio_context_acquire(aio_context);
|
|
||||||
if (blk_is_inserted(blk)) {
|
|
||||||
ret = blk_flush(blk);
|
|
||||||
if (ret < 0 && !result) {
|
|
||||||
result = ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
aio_context_release(aio_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* throttling disk I/O limits */
|
/* throttling disk I/O limits */
|
||||||
void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
|
void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
|
||||||
|
@@ -96,7 +96,6 @@ struct BDRVCURLState;
|
|||||||
|
|
||||||
typedef struct CURLAIOCB {
|
typedef struct CURLAIOCB {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
QEMUBH *bh;
|
|
||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
|
|
||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
@@ -739,9 +738,6 @@ static void curl_readv_bh_cb(void *p)
|
|||||||
CURLAIOCB *acb = p;
|
CURLAIOCB *acb = p;
|
||||||
BDRVCURLState *s = acb->common.bs->opaque;
|
BDRVCURLState *s = acb->common.bs->opaque;
|
||||||
|
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
acb->bh = NULL;
|
|
||||||
|
|
||||||
size_t start = acb->sector_num * SECTOR_SIZE;
|
size_t start = acb->sector_num * SECTOR_SIZE;
|
||||||
size_t end;
|
size_t end;
|
||||||
|
|
||||||
@@ -805,8 +801,7 @@ static BlockAIOCB *curl_aio_readv(BlockDriverState *bs,
|
|||||||
acb->sector_num = sector_num;
|
acb->sector_num = sector_num;
|
||||||
acb->nb_sectors = nb_sectors;
|
acb->nb_sectors = nb_sectors;
|
||||||
|
|
||||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb);
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb);
|
||||||
qemu_bh_schedule(acb->bh);
|
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
61
block/dmg-bz2.c
Normal file
61
block/dmg-bz2.c
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* DMG bzip2 uncompression
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004 Johannes E. Schindelin
|
||||||
|
* Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "dmg.h"
|
||||||
|
#include <bzlib.h>
|
||||||
|
|
||||||
|
static int dmg_uncompress_bz2_do(char *next_in, unsigned int avail_in,
|
||||||
|
char *next_out, unsigned int avail_out)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint64_t total_out;
|
||||||
|
bz_stream bzstream = {};
|
||||||
|
|
||||||
|
ret = BZ2_bzDecompressInit(&bzstream, 0, 0);
|
||||||
|
if (ret != BZ_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
bzstream.next_in = next_in;
|
||||||
|
bzstream.avail_in = avail_in;
|
||||||
|
bzstream.next_out = next_out;
|
||||||
|
bzstream.avail_out = avail_out;
|
||||||
|
ret = BZ2_bzDecompress(&bzstream);
|
||||||
|
total_out = ((uint64_t)bzstream.total_out_hi32 << 32) +
|
||||||
|
bzstream.total_out_lo32;
|
||||||
|
BZ2_bzDecompressEnd(&bzstream);
|
||||||
|
if (ret != BZ_STREAM_END ||
|
||||||
|
total_out != avail_out) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void dmg_bz2_init(void)
|
||||||
|
{
|
||||||
|
assert(!dmg_uncompress_bz2);
|
||||||
|
dmg_uncompress_bz2 = dmg_uncompress_bz2_do;
|
||||||
|
}
|
69
block/dmg.c
69
block/dmg.c
@@ -28,10 +28,10 @@
|
|||||||
#include "qemu/bswap.h"
|
#include "qemu/bswap.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include <zlib.h>
|
#include "dmg.h"
|
||||||
#ifdef CONFIG_BZIP2
|
|
||||||
#include <bzlib.h>
|
int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
|
||||||
#endif
|
char *next_out, unsigned int avail_out);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* Limit chunk sizes to prevent unreasonable amounts of memory being used
|
/* Limit chunk sizes to prevent unreasonable amounts of memory being used
|
||||||
@@ -41,31 +41,6 @@ enum {
|
|||||||
DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
|
DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BDRVDMGState {
|
|
||||||
CoMutex lock;
|
|
||||||
/* each chunk contains a certain number of sectors,
|
|
||||||
* offsets[i] is the offset in the .dmg file,
|
|
||||||
* lengths[i] is the length of the compressed chunk,
|
|
||||||
* sectors[i] is the sector beginning at offsets[i],
|
|
||||||
* sectorcounts[i] is the number of sectors in that chunk,
|
|
||||||
* the sectors array is ordered
|
|
||||||
* 0<=i<n_chunks */
|
|
||||||
|
|
||||||
uint32_t n_chunks;
|
|
||||||
uint32_t* types;
|
|
||||||
uint64_t* offsets;
|
|
||||||
uint64_t* lengths;
|
|
||||||
uint64_t* sectors;
|
|
||||||
uint64_t* sectorcounts;
|
|
||||||
uint32_t current_chunk;
|
|
||||||
uint8_t *compressed_chunk;
|
|
||||||
uint8_t *uncompressed_chunk;
|
|
||||||
z_stream zstream;
|
|
||||||
#ifdef CONFIG_BZIP2
|
|
||||||
bz_stream bzstream;
|
|
||||||
#endif
|
|
||||||
} BDRVDMGState;
|
|
||||||
|
|
||||||
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
|
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@@ -210,10 +185,9 @@ static bool dmg_is_known_block_type(uint32_t entry_type)
|
|||||||
case 0x00000001: /* uncompressed */
|
case 0x00000001: /* uncompressed */
|
||||||
case 0x00000002: /* zeroes */
|
case 0x00000002: /* zeroes */
|
||||||
case 0x80000005: /* zlib */
|
case 0x80000005: /* zlib */
|
||||||
#ifdef CONFIG_BZIP2
|
|
||||||
case 0x80000006: /* bzip2 */
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
|
case 0x80000006: /* bzip2 */
|
||||||
|
return !!dmg_uncompress_bz2;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -439,6 +413,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
int64_t offset;
|
int64_t offset;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
block_module_load_one("dmg-bz2");
|
||||||
bs->read_only = true;
|
bs->read_only = true;
|
||||||
|
|
||||||
s->n_chunks = 0;
|
s->n_chunks = 0;
|
||||||
@@ -587,9 +562,6 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
|||||||
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);
|
||||||
#ifdef CONFIG_BZIP2
|
|
||||||
uint64_t total_out;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (chunk >= s->n_chunks) {
|
if (chunk >= s->n_chunks) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -620,8 +592,10 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break; }
|
break; }
|
||||||
#ifdef CONFIG_BZIP2
|
|
||||||
case 0x80000006: /* bzip2 compressed */
|
case 0x80000006: /* bzip2 compressed */
|
||||||
|
if (!dmg_uncompress_bz2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* we need to buffer, because only the chunk as whole can be
|
/* we need to buffer, because only the chunk as whole can be
|
||||||
* inflated. */
|
* inflated. */
|
||||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
@@ -630,24 +604,15 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = BZ2_bzDecompressInit(&s->bzstream, 0, 0);
|
ret = dmg_uncompress_bz2((char *)s->compressed_chunk,
|
||||||
if (ret != BZ_OK) {
|
(unsigned int) s->lengths[chunk],
|
||||||
return -1;
|
(char *)s->uncompressed_chunk,
|
||||||
}
|
(unsigned int)
|
||||||
s->bzstream.next_in = (char *)s->compressed_chunk;
|
(512 * s->sectorcounts[chunk]));
|
||||||
s->bzstream.avail_in = (unsigned int) s->lengths[chunk];
|
if (ret < 0) {
|
||||||
s->bzstream.next_out = (char *)s->uncompressed_chunk;
|
return ret;
|
||||||
s->bzstream.avail_out = (unsigned int) 512 * s->sectorcounts[chunk];
|
|
||||||
ret = BZ2_bzDecompress(&s->bzstream);
|
|
||||||
total_out = ((uint64_t)s->bzstream.total_out_hi32 << 32) +
|
|
||||||
s->bzstream.total_out_lo32;
|
|
||||||
BZ2_bzDecompressEnd(&s->bzstream);
|
|
||||||
if (ret != BZ_STREAM_END ||
|
|
||||||
total_out != 512 * s->sectorcounts[chunk]) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BZIP2 */
|
|
||||||
case 1: /* copy */
|
case 1: /* copy */
|
||||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
s->uncompressed_chunk, s->lengths[chunk]);
|
s->uncompressed_chunk, s->lengths[chunk]);
|
||||||
|
59
block/dmg.h
Normal file
59
block/dmg.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Header for DMG driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2006 Fabrice Bellard
|
||||||
|
* Copyright (c) 2016 Red hat, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BLOCK_DMG_H
|
||||||
|
#define BLOCK_DMG_H
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "block/block_int.h"
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
typedef struct BDRVDMGState {
|
||||||
|
CoMutex lock;
|
||||||
|
/* each chunk contains a certain number of sectors,
|
||||||
|
* offsets[i] is the offset in the .dmg file,
|
||||||
|
* lengths[i] is the length of the compressed chunk,
|
||||||
|
* sectors[i] is the sector beginning at offsets[i],
|
||||||
|
* sectorcounts[i] is the number of sectors in that chunk,
|
||||||
|
* the sectors array is ordered
|
||||||
|
* 0<=i<n_chunks */
|
||||||
|
|
||||||
|
uint32_t n_chunks;
|
||||||
|
uint32_t *types;
|
||||||
|
uint64_t *offsets;
|
||||||
|
uint64_t *lengths;
|
||||||
|
uint64_t *sectors;
|
||||||
|
uint64_t *sectorcounts;
|
||||||
|
uint32_t current_chunk;
|
||||||
|
uint8_t *compressed_chunk;
|
||||||
|
uint8_t *uncompressed_chunk;
|
||||||
|
z_stream zstream;
|
||||||
|
} BDRVDMGState;
|
||||||
|
|
||||||
|
extern int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
|
||||||
|
char *next_out, unsigned int avail_out);
|
||||||
|
|
||||||
|
#endif
|
@@ -38,7 +38,6 @@
|
|||||||
typedef struct GlusterAIOCB {
|
typedef struct GlusterAIOCB {
|
||||||
int64_t size;
|
int64_t size;
|
||||||
int ret;
|
int ret;
|
||||||
QEMUBH *bh;
|
|
||||||
Coroutine *coroutine;
|
Coroutine *coroutine;
|
||||||
AioContext *aio_context;
|
AioContext *aio_context;
|
||||||
} GlusterAIOCB;
|
} GlusterAIOCB;
|
||||||
@@ -622,8 +621,6 @@ static void qemu_gluster_complete_aio(void *opaque)
|
|||||||
{
|
{
|
||||||
GlusterAIOCB *acb = (GlusterAIOCB *)opaque;
|
GlusterAIOCB *acb = (GlusterAIOCB *)opaque;
|
||||||
|
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
acb->bh = NULL;
|
|
||||||
qemu_coroutine_enter(acb->coroutine);
|
qemu_coroutine_enter(acb->coroutine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,8 +639,7 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
|||||||
acb->ret = -EIO; /* Partial read/write - fail it */
|
acb->ret = -EIO; /* Partial read/write - fail it */
|
||||||
}
|
}
|
||||||
|
|
||||||
acb->bh = aio_bh_new(acb->aio_context, qemu_gluster_complete_aio, acb);
|
aio_bh_schedule_oneshot(acb->aio_context, qemu_gluster_complete_aio, acb);
|
||||||
qemu_bh_schedule(acb->bh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
|
static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
|
||||||
|
36
block/io.c
36
block/io.c
@@ -171,7 +171,6 @@ static void bdrv_drain_recurse(BlockDriverState *bs)
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
Coroutine *co;
|
Coroutine *co;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
QEMUBH *bh;
|
|
||||||
bool done;
|
bool done;
|
||||||
} BdrvCoDrainData;
|
} BdrvCoDrainData;
|
||||||
|
|
||||||
@@ -191,7 +190,6 @@ static void bdrv_co_drain_bh_cb(void *opaque)
|
|||||||
BdrvCoDrainData *data = opaque;
|
BdrvCoDrainData *data = opaque;
|
||||||
Coroutine *co = data->co;
|
Coroutine *co = data->co;
|
||||||
|
|
||||||
qemu_bh_delete(data->bh);
|
|
||||||
bdrv_drain_poll(data->bs);
|
bdrv_drain_poll(data->bs);
|
||||||
data->done = true;
|
data->done = true;
|
||||||
qemu_coroutine_enter(co);
|
qemu_coroutine_enter(co);
|
||||||
@@ -210,9 +208,9 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs)
|
|||||||
.co = qemu_coroutine_self(),
|
.co = qemu_coroutine_self(),
|
||||||
.bs = bs,
|
.bs = bs,
|
||||||
.done = false,
|
.done = false,
|
||||||
.bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_drain_bh_cb, &data),
|
|
||||||
};
|
};
|
||||||
qemu_bh_schedule(data.bh);
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
|
||||||
|
bdrv_co_drain_bh_cb, &data);
|
||||||
|
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
/* If we are resumed from some other event (such as an aio completion or a
|
/* If we are resumed from some other event (such as an aio completion or a
|
||||||
@@ -1619,6 +1617,31 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
|||||||
BDRV_REQ_ZERO_WRITE | flags);
|
BDRV_REQ_ZERO_WRITE | flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush ALL BDSes regardless of if they are reachable via a BlkBackend or not.
|
||||||
|
*/
|
||||||
|
int bdrv_flush_all(void)
|
||||||
|
{
|
||||||
|
BdrvNextIterator it;
|
||||||
|
BlockDriverState *bs = NULL;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||||
|
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
aio_context_acquire(aio_context);
|
||||||
|
ret = bdrv_flush(bs);
|
||||||
|
if (ret < 0 && !result) {
|
||||||
|
result = ret;
|
||||||
|
}
|
||||||
|
aio_context_release(aio_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct BdrvCoGetBlockStatusData {
|
typedef struct BdrvCoGetBlockStatusData {
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
BlockDriverState *base;
|
BlockDriverState *base;
|
||||||
@@ -2070,7 +2093,6 @@ typedef struct BlockAIOCBCoroutine {
|
|||||||
bool is_write;
|
bool is_write;
|
||||||
bool need_bh;
|
bool need_bh;
|
||||||
bool *done;
|
bool *done;
|
||||||
QEMUBH* bh;
|
|
||||||
} BlockAIOCBCoroutine;
|
} BlockAIOCBCoroutine;
|
||||||
|
|
||||||
static const AIOCBInfo bdrv_em_co_aiocb_info = {
|
static const AIOCBInfo bdrv_em_co_aiocb_info = {
|
||||||
@@ -2090,7 +2112,6 @@ static void bdrv_co_em_bh(void *opaque)
|
|||||||
BlockAIOCBCoroutine *acb = opaque;
|
BlockAIOCBCoroutine *acb = opaque;
|
||||||
|
|
||||||
assert(!acb->need_bh);
|
assert(!acb->need_bh);
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
bdrv_co_complete(acb);
|
bdrv_co_complete(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2100,8 +2121,7 @@ static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb)
|
|||||||
if (acb->req.error != -EINPROGRESS) {
|
if (acb->req.error != -EINPROGRESS) {
|
||||||
BlockDriverState *bs = acb->common.bs;
|
BlockDriverState *bs = acb->common.bs;
|
||||||
|
|
||||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
|
||||||
qemu_bh_schedule(acb->bh);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -95,7 +95,6 @@ typedef struct IscsiTask {
|
|||||||
int do_retry;
|
int do_retry;
|
||||||
struct scsi_task *task;
|
struct scsi_task *task;
|
||||||
Coroutine *co;
|
Coroutine *co;
|
||||||
QEMUBH *bh;
|
|
||||||
IscsiLun *iscsilun;
|
IscsiLun *iscsilun;
|
||||||
QEMUTimer retry_timer;
|
QEMUTimer retry_timer;
|
||||||
int err_code;
|
int err_code;
|
||||||
@@ -167,7 +166,6 @@ static void iscsi_co_generic_bh_cb(void *opaque)
|
|||||||
{
|
{
|
||||||
struct IscsiTask *iTask = opaque;
|
struct IscsiTask *iTask = opaque;
|
||||||
iTask->complete = 1;
|
iTask->complete = 1;
|
||||||
qemu_bh_delete(iTask->bh);
|
|
||||||
qemu_coroutine_enter(iTask->co);
|
qemu_coroutine_enter(iTask->co);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,9 +297,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
if (iTask->co) {
|
if (iTask->co) {
|
||||||
iTask->bh = aio_bh_new(iTask->iscsilun->aio_context,
|
aio_bh_schedule_oneshot(iTask->iscsilun->aio_context,
|
||||||
iscsi_co_generic_bh_cb, iTask);
|
iscsi_co_generic_bh_cb, iTask);
|
||||||
qemu_bh_schedule(iTask->bh);
|
|
||||||
} else {
|
} else {
|
||||||
iTask->complete = 1;
|
iTask->complete = 1;
|
||||||
}
|
}
|
||||||
|
@@ -94,9 +94,12 @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
|
|||||||
|
|
||||||
laiocb->ret = ret;
|
laiocb->ret = ret;
|
||||||
if (laiocb->co) {
|
if (laiocb->co) {
|
||||||
/* Jump and continue completion for foreign requests, don't do
|
/* If the coroutine is already entered it must be in ioq_submit() and
|
||||||
* anything for current request, it will be completed shortly. */
|
* will notice laio->ret has been filled in when it eventually runs
|
||||||
if (laiocb->co != qemu_coroutine_self()) {
|
* later. Coroutines cannot be entered recursively so avoid doing
|
||||||
|
* that!
|
||||||
|
*/
|
||||||
|
if (!qemu_coroutine_entered(laiocb->co)) {
|
||||||
qemu_coroutine_enter(laiocb->co);
|
qemu_coroutine_enter(laiocb->co);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@@ -57,7 +57,6 @@ typedef struct NFSRPC {
|
|||||||
QEMUIOVector *iov;
|
QEMUIOVector *iov;
|
||||||
struct stat *st;
|
struct stat *st;
|
||||||
Coroutine *co;
|
Coroutine *co;
|
||||||
QEMUBH *bh;
|
|
||||||
NFSClient *client;
|
NFSClient *client;
|
||||||
} NFSRPC;
|
} NFSRPC;
|
||||||
|
|
||||||
@@ -103,7 +102,6 @@ static void nfs_co_generic_bh_cb(void *opaque)
|
|||||||
{
|
{
|
||||||
NFSRPC *task = opaque;
|
NFSRPC *task = opaque;
|
||||||
task->complete = 1;
|
task->complete = 1;
|
||||||
qemu_bh_delete(task->bh);
|
|
||||||
qemu_coroutine_enter(task->co);
|
qemu_coroutine_enter(task->co);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,9 +125,8 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
|
|||||||
error_report("NFS Error: %s", nfs_get_error(nfs));
|
error_report("NFS Error: %s", nfs_get_error(nfs));
|
||||||
}
|
}
|
||||||
if (task->co) {
|
if (task->co) {
|
||||||
task->bh = aio_bh_new(task->client->aio_context,
|
aio_bh_schedule_oneshot(task->client->aio_context,
|
||||||
nfs_co_generic_bh_cb, task);
|
nfs_co_generic_bh_cb, task);
|
||||||
qemu_bh_schedule(task->bh);
|
|
||||||
} else {
|
} else {
|
||||||
task->complete = 1;
|
task->complete = 1;
|
||||||
}
|
}
|
||||||
|
@@ -124,7 +124,6 @@ static coroutine_fn int null_co_flush(BlockDriverState *bs)
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
QEMUBH *bh;
|
|
||||||
QEMUTimer timer;
|
QEMUTimer timer;
|
||||||
} NullAIOCB;
|
} NullAIOCB;
|
||||||
|
|
||||||
@@ -136,7 +135,6 @@ static void null_bh_cb(void *opaque)
|
|||||||
{
|
{
|
||||||
NullAIOCB *acb = opaque;
|
NullAIOCB *acb = opaque;
|
||||||
acb->common.cb(acb->common.opaque, 0);
|
acb->common.cb(acb->common.opaque, 0);
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
qemu_aio_unref(acb);
|
qemu_aio_unref(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +162,7 @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
|
|||||||
timer_mod_ns(&acb->timer,
|
timer_mod_ns(&acb->timer,
|
||||||
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
|
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
|
||||||
} else {
|
} else {
|
||||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb);
|
||||||
qemu_bh_schedule(acb->bh);
|
|
||||||
}
|
}
|
||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
|
@@ -909,7 +909,6 @@ static void qed_aio_complete_bh(void *opaque)
|
|||||||
void *user_opaque = acb->common.opaque;
|
void *user_opaque = acb->common.opaque;
|
||||||
int ret = acb->bh_ret;
|
int ret = acb->bh_ret;
|
||||||
|
|
||||||
qemu_bh_delete(acb->bh);
|
|
||||||
qemu_aio_unref(acb);
|
qemu_aio_unref(acb);
|
||||||
|
|
||||||
/* Invoke callback */
|
/* Invoke callback */
|
||||||
@@ -934,9 +933,8 @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
|
|||||||
|
|
||||||
/* Arrange for a bh to invoke the completion function */
|
/* Arrange for a bh to invoke the completion function */
|
||||||
acb->bh_ret = ret;
|
acb->bh_ret = ret;
|
||||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
|
||||||
qed_aio_complete_bh, acb);
|
qed_aio_complete_bh, acb);
|
||||||
qemu_bh_schedule(acb->bh);
|
|
||||||
|
|
||||||
/* Start next allocating write request waiting behind this one. Note that
|
/* Start next allocating write request waiting behind this one. Note that
|
||||||
* requests enqueue themselves when they first hit an unallocated cluster
|
* requests enqueue themselves when they first hit an unallocated cluster
|
||||||
|
@@ -130,7 +130,6 @@ enum {
|
|||||||
|
|
||||||
typedef struct QEDAIOCB {
|
typedef struct QEDAIOCB {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
QEMUBH *bh;
|
|
||||||
int bh_ret; /* final return status for completion bh */
|
int bh_ret; /* final return status for completion bh */
|
||||||
QSIMPLEQ_ENTRY(QEDAIOCB) next; /* next request */
|
QSIMPLEQ_ENTRY(QEDAIOCB) next; /* next request */
|
||||||
int flags; /* QED_AIOCB_* bits ORed together */
|
int flags; /* QED_AIOCB_* bits ORed together */
|
||||||
|
@@ -143,6 +143,7 @@ typedef struct BDRVRawState {
|
|||||||
bool has_discard:1;
|
bool has_discard:1;
|
||||||
bool has_write_zeroes:1;
|
bool has_write_zeroes:1;
|
||||||
bool discard_zeroes:1;
|
bool discard_zeroes:1;
|
||||||
|
bool use_linux_aio:1;
|
||||||
bool has_fallocate;
|
bool has_fallocate;
|
||||||
bool needs_alignment;
|
bool needs_alignment;
|
||||||
} BDRVRawState;
|
} BDRVRawState;
|
||||||
@@ -367,18 +368,6 @@ static void raw_parse_flags(int bdrv_flags, int *open_flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_LINUX_AIO
|
|
||||||
static bool raw_use_aio(int bdrv_flags)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Currently Linux do AIO only for files opened with O_DIRECT
|
|
||||||
* specified so check NOCACHE flag too
|
|
||||||
*/
|
|
||||||
return (bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
|
|
||||||
(BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void raw_parse_filename(const char *filename, QDict *options,
|
static void raw_parse_filename(const char *filename, QDict *options,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@@ -399,6 +388,11 @@ static QemuOptsList raw_runtime_opts = {
|
|||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "File name of the image",
|
.help = "File name of the image",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "aio",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "host AIO implementation (threads, native)",
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -410,6 +404,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename = NULL;
|
const char *filename = NULL;
|
||||||
|
BlockdevAioOptions aio, aio_default;
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
@@ -429,6 +424,18 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aio_default = (bdrv_flags & BDRV_O_NATIVE_AIO)
|
||||||
|
? BLOCKDEV_AIO_OPTIONS_NATIVE
|
||||||
|
: BLOCKDEV_AIO_OPTIONS_THREADS;
|
||||||
|
aio = qapi_enum_parse(BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"),
|
||||||
|
BLOCKDEV_AIO_OPTIONS__MAX, aio_default, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
s->use_linux_aio = (aio == BLOCKDEV_AIO_OPTIONS_NATIVE);
|
||||||
|
|
||||||
s->open_flags = open_flags;
|
s->open_flags = open_flags;
|
||||||
raw_parse_flags(bdrv_flags, &s->open_flags);
|
raw_parse_flags(bdrv_flags, &s->open_flags);
|
||||||
|
|
||||||
@@ -444,14 +451,15 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
|
|
||||||
#ifdef CONFIG_LINUX_AIO
|
#ifdef CONFIG_LINUX_AIO
|
||||||
if (!raw_use_aio(bdrv_flags) && (bdrv_flags & BDRV_O_NATIVE_AIO)) {
|
/* Currently Linux does AIO only for files opened with O_DIRECT */
|
||||||
|
if (s->use_linux_aio && !(s->open_flags & O_DIRECT)) {
|
||||||
error_setg(errp, "aio=native was specified, but it requires "
|
error_setg(errp, "aio=native was specified, but it requires "
|
||||||
"cache.direct=on, which was not specified.");
|
"cache.direct=on, which was not specified.");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (bdrv_flags & BDRV_O_NATIVE_AIO) {
|
if (s->use_linux_aio) {
|
||||||
error_setg(errp, "aio=native was specified, but is not supported "
|
error_setg(errp, "aio=native was specified, but is not supported "
|
||||||
"in this build.");
|
"in this build.");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@@ -1256,7 +1264,7 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
|
|||||||
if (!bdrv_qiov_is_aligned(bs, qiov)) {
|
if (!bdrv_qiov_is_aligned(bs, qiov)) {
|
||||||
type |= QEMU_AIO_MISALIGNED;
|
type |= QEMU_AIO_MISALIGNED;
|
||||||
#ifdef CONFIG_LINUX_AIO
|
#ifdef CONFIG_LINUX_AIO
|
||||||
} else if (bs->open_flags & BDRV_O_NATIVE_AIO) {
|
} else if (s->use_linux_aio) {
|
||||||
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
||||||
assert(qiov->size == bytes);
|
assert(qiov->size == bytes);
|
||||||
return laio_co_submit(bs, aio, s->fd, offset, qiov, type);
|
return laio_co_submit(bs, aio, s->fd, offset, qiov, type);
|
||||||
@@ -1285,7 +1293,8 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
|||||||
static void raw_aio_plug(BlockDriverState *bs)
|
static void raw_aio_plug(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_LINUX_AIO
|
#ifdef CONFIG_LINUX_AIO
|
||||||
if (bs->open_flags & BDRV_O_NATIVE_AIO) {
|
BDRVRawState *s = bs->opaque;
|
||||||
|
if (s->use_linux_aio) {
|
||||||
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
||||||
laio_io_plug(bs, aio);
|
laio_io_plug(bs, aio);
|
||||||
}
|
}
|
||||||
@@ -1295,7 +1304,8 @@ static void raw_aio_plug(BlockDriverState *bs)
|
|||||||
static void raw_aio_unplug(BlockDriverState *bs)
|
static void raw_aio_unplug(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_LINUX_AIO
|
#ifdef CONFIG_LINUX_AIO
|
||||||
if (bs->open_flags & BDRV_O_NATIVE_AIO) {
|
BDRVRawState *s = bs->opaque;
|
||||||
|
if (s->use_linux_aio) {
|
||||||
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
|
||||||
laio_io_unplug(bs, aio);
|
laio_io_unplug(bs, aio);
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include "block/thread-pool.h"
|
#include "block/thread-pool.h"
|
||||||
#include "qemu/iov.h"
|
#include "qemu/iov.h"
|
||||||
#include "qapi/qmp/qstring.h"
|
#include "qapi/qmp/qstring.h"
|
||||||
|
#include "qapi/util.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winioctl.h>
|
#include <winioctl.h>
|
||||||
|
|
||||||
@@ -252,7 +253,8 @@ static void raw_probe_alignment(BlockDriverState *bs, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
|
static void raw_parse_flags(int flags, bool use_aio, int *access_flags,
|
||||||
|
DWORD *overlapped)
|
||||||
{
|
{
|
||||||
assert(access_flags != NULL);
|
assert(access_flags != NULL);
|
||||||
assert(overlapped != NULL);
|
assert(overlapped != NULL);
|
||||||
@@ -264,7 +266,7 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
|
|||||||
}
|
}
|
||||||
|
|
||||||
*overlapped = FILE_ATTRIBUTE_NORMAL;
|
*overlapped = FILE_ATTRIBUTE_NORMAL;
|
||||||
if (flags & BDRV_O_NATIVE_AIO) {
|
if (use_aio) {
|
||||||
*overlapped |= FILE_FLAG_OVERLAPPED;
|
*overlapped |= FILE_FLAG_OVERLAPPED;
|
||||||
}
|
}
|
||||||
if (flags & BDRV_O_NOCACHE) {
|
if (flags & BDRV_O_NOCACHE) {
|
||||||
@@ -292,10 +294,35 @@ static QemuOptsList raw_runtime_opts = {
|
|||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "File name of the image",
|
.help = "File name of the image",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "aio",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "host AIO implementation (threads, native)",
|
||||||
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool get_aio_option(QemuOpts *opts, int flags, Error **errp)
|
||||||
|
{
|
||||||
|
BlockdevAioOptions aio, aio_default;
|
||||||
|
|
||||||
|
aio_default = (flags & BDRV_O_NATIVE_AIO) ? BLOCKDEV_AIO_OPTIONS_NATIVE
|
||||||
|
: BLOCKDEV_AIO_OPTIONS_THREADS;
|
||||||
|
aio = qapi_enum_parse(BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"),
|
||||||
|
BLOCKDEV_AIO_OPTIONS__MAX, aio_default, errp);
|
||||||
|
|
||||||
|
switch (aio) {
|
||||||
|
case BLOCKDEV_AIO_OPTIONS_NATIVE:
|
||||||
|
return true;
|
||||||
|
case BLOCKDEV_AIO_OPTIONS_THREADS:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Invalid AIO option");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@@ -305,6 +332,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
bool use_aio;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
s->type = FTYPE_FILE;
|
s->type = FTYPE_FILE;
|
||||||
@@ -319,7 +347,14 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
filename = qemu_opt_get(opts, "filename");
|
filename = qemu_opt_get(opts, "filename");
|
||||||
|
|
||||||
raw_parse_flags(flags, &access_flags, &overlapped);
|
use_aio = get_aio_option(opts, flags, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_parse_flags(flags, use_aio, &access_flags, &overlapped);
|
||||||
|
|
||||||
if (filename[0] && filename[1] == ':') {
|
if (filename[0] && filename[1] == ':') {
|
||||||
snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]);
|
snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]);
|
||||||
@@ -346,7 +381,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & BDRV_O_NATIVE_AIO) {
|
if (use_aio) {
|
||||||
s->aio = win32_aio_init();
|
s->aio = win32_aio_init();
|
||||||
if (s->aio == NULL) {
|
if (s->aio == NULL) {
|
||||||
CloseHandle(s->hfile);
|
CloseHandle(s->hfile);
|
||||||
@@ -647,6 +682,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
bool use_aio;
|
||||||
|
|
||||||
QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0,
|
QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
@@ -659,6 +695,16 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
filename = qemu_opt_get(opts, "filename");
|
filename = qemu_opt_get(opts, "filename");
|
||||||
|
|
||||||
|
use_aio = get_aio_option(opts, flags, &local_err);
|
||||||
|
if (!local_err && use_aio) {
|
||||||
|
error_setg(&local_err, "AIO is not supported on Windows host devices");
|
||||||
|
}
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||||
if (find_cdrom(device_name, sizeof(device_name)) < 0) {
|
if (find_cdrom(device_name, sizeof(device_name)) < 0) {
|
||||||
error_setg(errp, "Could not open CD-ROM drive");
|
error_setg(errp, "Could not open CD-ROM drive");
|
||||||
@@ -677,7 +723,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
s->type = find_device_type(bs, filename);
|
s->type = find_device_type(bs, filename);
|
||||||
|
|
||||||
raw_parse_flags(flags, &access_flags, &overlapped);
|
raw_parse_flags(flags, use_aio, &access_flags, &overlapped);
|
||||||
|
|
||||||
create_flags = OPEN_EXISTING;
|
create_flags = OPEN_EXISTING;
|
||||||
|
|
||||||
|
@@ -71,7 +71,6 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct RBDAIOCB {
|
typedef struct RBDAIOCB {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
QEMUBH *bh;
|
|
||||||
int64_t ret;
|
int64_t ret;
|
||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
char *bounce;
|
char *bounce;
|
||||||
@@ -602,7 +601,6 @@ static const AIOCBInfo rbd_aiocb_info = {
|
|||||||
static void rbd_finish_bh(void *opaque)
|
static void rbd_finish_bh(void *opaque)
|
||||||
{
|
{
|
||||||
RADOSCB *rcb = opaque;
|
RADOSCB *rcb = opaque;
|
||||||
qemu_bh_delete(rcb->acb->bh);
|
|
||||||
qemu_rbd_complete_aio(rcb);
|
qemu_rbd_complete_aio(rcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,9 +619,8 @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
|
|||||||
rcb->ret = rbd_aio_get_return_value(c);
|
rcb->ret = rbd_aio_get_return_value(c);
|
||||||
rbd_aio_release(c);
|
rbd_aio_release(c);
|
||||||
|
|
||||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
|
||||||
rbd_finish_bh, rcb);
|
rbd_finish_bh, rcb);
|
||||||
qemu_bh_schedule(acb->bh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rbd_aio_discard_wrapper(rbd_image_t image,
|
static int rbd_aio_discard_wrapper(rbd_image_t image,
|
||||||
@@ -679,7 +676,6 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
|
|||||||
acb->ret = 0;
|
acb->ret = 0;
|
||||||
acb->error = 0;
|
acb->error = 0;
|
||||||
acb->s = s;
|
acb->s = s;
|
||||||
acb->bh = NULL;
|
|
||||||
|
|
||||||
if (cmd == RBD_AIO_WRITE) {
|
if (cmd == RBD_AIO_WRITE) {
|
||||||
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
|
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
|
||||||
|
@@ -76,8 +76,7 @@ static int coroutine_fn before_write_notify(NotifierWithReturn *notifier,
|
|||||||
static void write_threshold_register_notifier(BlockDriverState *bs)
|
static void write_threshold_register_notifier(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
bs->write_threshold_notifier.notify = before_write_notify;
|
bs->write_threshold_notifier.notify = before_write_notify;
|
||||||
notifier_with_return_list_add(&bs->before_write_notifiers,
|
bdrv_add_before_write_notifier(bs, &bs->write_threshold_notifier);
|
||||||
&bs->write_threshold_notifier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_threshold_update(BlockDriverState *bs,
|
static void write_threshold_update(BlockDriverState *bs,
|
||||||
|
112
blockdev.c
112
blockdev.c
@@ -356,7 +356,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
|
|||||||
const char **throttling_group, ThrottleConfig *throttle_cfg,
|
const char **throttling_group, ThrottleConfig *throttle_cfg,
|
||||||
BlockdevDetectZeroesOptions *detect_zeroes, Error **errp)
|
BlockdevDetectZeroesOptions *detect_zeroes, Error **errp)
|
||||||
{
|
{
|
||||||
const char *discard;
|
|
||||||
Error *local_error = NULL;
|
Error *local_error = NULL;
|
||||||
const char *aio;
|
const char *aio;
|
||||||
|
|
||||||
@@ -365,13 +364,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
|
|||||||
*bdrv_flags |= BDRV_O_COPY_ON_READ;
|
*bdrv_flags |= BDRV_O_COPY_ON_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((discard = qemu_opt_get(opts, "discard")) != NULL) {
|
|
||||||
if (bdrv_parse_discard_flags(discard, bdrv_flags) != 0) {
|
|
||||||
error_setg(errp, "Invalid discard option");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((aio = qemu_opt_get(opts, "aio")) != NULL) {
|
if ((aio = qemu_opt_get(opts, "aio")) != NULL) {
|
||||||
if (!strcmp(aio, "native")) {
|
if (!strcmp(aio, "native")) {
|
||||||
*bdrv_flags |= BDRV_O_NATIVE_AIO;
|
*bdrv_flags |= BDRV_O_NATIVE_AIO;
|
||||||
@@ -449,15 +441,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
|
|||||||
error_propagate(errp, local_error);
|
error_propagate(errp, local_error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_flags &&
|
|
||||||
*detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
|
|
||||||
!(*bdrv_flags & BDRV_O_UNMAP))
|
|
||||||
{
|
|
||||||
error_setg(errp, "setting detect-zeroes to unmap is not allowed "
|
|
||||||
"without setting discard operation to unmap");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,35 +633,11 @@ err_no_opts:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QemuOptsList qemu_root_bds_opts;
|
|
||||||
|
|
||||||
/* Takes the ownership of bs_opts */
|
/* Takes the ownership of bs_opts */
|
||||||
static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
|
static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
|
||||||
QemuOpts *opts;
|
|
||||||
Error *local_error = NULL;
|
|
||||||
BlockdevDetectZeroesOptions detect_zeroes;
|
|
||||||
int bdrv_flags = 0;
|
int bdrv_flags = 0;
|
||||||
|
|
||||||
opts = qemu_opts_create(&qemu_root_bds_opts, NULL, 1, errp);
|
|
||||||
if (!opts) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_opts_absorb_qdict(opts, bs_opts, &local_error);
|
|
||||||
if (local_error) {
|
|
||||||
error_propagate(errp, local_error);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
extract_common_blockdev_options(opts, &bdrv_flags, NULL, NULL,
|
|
||||||
&detect_zeroes, &local_error);
|
|
||||||
if (local_error) {
|
|
||||||
error_propagate(errp, local_error);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* bdrv_open() defaults to the values in bdrv_flags (for compatibility
|
/* bdrv_open() defaults to the values in bdrv_flags (for compatibility
|
||||||
* with other callers) rather than what we want as the real defaults.
|
* with other callers) rather than what we want as the real defaults.
|
||||||
* Apply the defaults here instead. */
|
* Apply the defaults here instead. */
|
||||||
@@ -690,21 +649,7 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
|
|||||||
bdrv_flags |= BDRV_O_INACTIVE;
|
bdrv_flags |= BDRV_O_INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs = bdrv_open(NULL, NULL, bs_opts, bdrv_flags, errp);
|
return bdrv_open(NULL, NULL, bs_opts, bdrv_flags, errp);
|
||||||
if (!bs) {
|
|
||||||
goto fail_no_bs_opts;
|
|
||||||
}
|
|
||||||
|
|
||||||
bs->detect_zeroes = detect_zeroes;
|
|
||||||
|
|
||||||
fail_no_bs_opts:
|
|
||||||
qemu_opts_del(opts);
|
|
||||||
return bs;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
qemu_opts_del(opts);
|
|
||||||
QDECREF(bs_opts);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockdev_close_all_bdrv_states(void)
|
void blockdev_close_all_bdrv_states(void)
|
||||||
@@ -2549,6 +2494,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
|
|||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
BlockDriverState *medium_bs = NULL;
|
BlockDriverState *medium_bs = NULL;
|
||||||
int bdrv_flags;
|
int bdrv_flags;
|
||||||
|
bool detect_zeroes;
|
||||||
int rc;
|
int rc;
|
||||||
QDict *options = NULL;
|
QDict *options = NULL;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
@@ -2588,8 +2534,12 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_format) {
|
|
||||||
options = qdict_new();
|
options = qdict_new();
|
||||||
|
detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
|
||||||
|
qdict_put(options, "detect-zeroes",
|
||||||
|
qstring_from_str(detect_zeroes ? "on" : "off"));
|
||||||
|
|
||||||
|
if (has_format) {
|
||||||
qdict_put(options, "driver", qstring_from_str(format));
|
qdict_put(options, "driver", qstring_from_str(format));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2614,7 +2564,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
|
|||||||
error_free(err);
|
error_free(err);
|
||||||
err = NULL;
|
err = NULL;
|
||||||
|
|
||||||
qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp);
|
qmp_x_blockdev_remove_medium(has_device, device, has_id, id, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -2626,8 +2576,6 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
blk_apply_root_state(blk, medium_bs);
|
|
||||||
|
|
||||||
qmp_blockdev_close_tray(has_device, device, has_id, id, errp);
|
qmp_blockdev_close_tray(has_device, device, has_id, id, errp);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@@ -3832,21 +3780,6 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
QDict *qdict;
|
QDict *qdict;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
/* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with
|
|
||||||
* cache.direct=false instead of silently switching to aio=threads, except
|
|
||||||
* when called from drive_new().
|
|
||||||
*
|
|
||||||
* For now, simply forbidding the combination for all drivers will do. */
|
|
||||||
if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
|
|
||||||
bool direct = options->has_cache &&
|
|
||||||
options->cache->has_direct &&
|
|
||||||
options->cache->direct;
|
|
||||||
if (!direct) {
|
|
||||||
error_setg(errp, "aio=native requires cache.direct=true");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
|
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
@@ -4004,10 +3937,6 @@ QemuOptsList qemu_common_drive_opts = {
|
|||||||
.name = "snapshot",
|
.name = "snapshot",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
.help = "enable/disable snapshot mode",
|
.help = "enable/disable snapshot mode",
|
||||||
},{
|
|
||||||
.name = "discard",
|
|
||||||
.type = QEMU_OPT_STRING,
|
|
||||||
.help = "discard operation (ignore/off, unmap/on)",
|
|
||||||
},{
|
},{
|
||||||
.name = "aio",
|
.name = "aio",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
@@ -4135,31 +4064,6 @@ QemuOptsList qemu_common_drive_opts = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static QemuOptsList qemu_root_bds_opts = {
|
|
||||||
.name = "root-bds",
|
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_root_bds_opts.head),
|
|
||||||
.desc = {
|
|
||||||
{
|
|
||||||
.name = "discard",
|
|
||||||
.type = QEMU_OPT_STRING,
|
|
||||||
.help = "discard operation (ignore/off, unmap/on)",
|
|
||||||
},{
|
|
||||||
.name = "aio",
|
|
||||||
.type = QEMU_OPT_STRING,
|
|
||||||
.help = "host AIO implementation (threads, native)",
|
|
||||||
},{
|
|
||||||
.name = "copy-on-read",
|
|
||||||
.type = QEMU_OPT_BOOL,
|
|
||||||
.help = "copy read data from backing file into image file",
|
|
||||||
},{
|
|
||||||
.name = "detect-zeroes",
|
|
||||||
.type = QEMU_OPT_STRING,
|
|
||||||
.help = "try to optimize zero writes (off, on, unmap)",
|
|
||||||
},
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
QemuOptsList qemu_drive_opts = {
|
QemuOptsList qemu_drive_opts = {
|
||||||
.name = "drive",
|
.name = "drive",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
|
||||||
|
@@ -588,7 +588,6 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BlockJob *job;
|
BlockJob *job;
|
||||||
QEMUBH *bh;
|
|
||||||
AioContext *aio_context;
|
AioContext *aio_context;
|
||||||
BlockJobDeferToMainLoopFn *fn;
|
BlockJobDeferToMainLoopFn *fn;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
@@ -599,8 +598,6 @@ static void block_job_defer_to_main_loop_bh(void *opaque)
|
|||||||
BlockJobDeferToMainLoopData *data = opaque;
|
BlockJobDeferToMainLoopData *data = opaque;
|
||||||
AioContext *aio_context;
|
AioContext *aio_context;
|
||||||
|
|
||||||
qemu_bh_delete(data->bh);
|
|
||||||
|
|
||||||
/* Prevent race with block_job_defer_to_main_loop() */
|
/* Prevent race with block_job_defer_to_main_loop() */
|
||||||
aio_context_acquire(data->aio_context);
|
aio_context_acquire(data->aio_context);
|
||||||
|
|
||||||
@@ -624,13 +621,13 @@ void block_job_defer_to_main_loop(BlockJob *job,
|
|||||||
{
|
{
|
||||||
BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
|
BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
|
||||||
data->job = job;
|
data->job = job;
|
||||||
data->bh = qemu_bh_new(block_job_defer_to_main_loop_bh, data);
|
|
||||||
data->aio_context = blk_get_aio_context(job->blk);
|
data->aio_context = blk_get_aio_context(job->blk);
|
||||||
data->fn = fn;
|
data->fn = fn;
|
||||||
data->opaque = opaque;
|
data->opaque = opaque;
|
||||||
job->deferred_to_main_loop = true;
|
job->deferred_to_main_loop = true;
|
||||||
|
|
||||||
qemu_bh_schedule(data->bh);
|
aio_bh_schedule_oneshot(qemu_get_aio_context(),
|
||||||
|
block_job_defer_to_main_loop_bh, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockJobTxn *block_job_txn_new(void)
|
BlockJobTxn *block_job_txn_new(void)
|
||||||
|
@@ -67,23 +67,6 @@ int cpu_get_pic_interrupt(CPUX86State *env)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* These are no-ops because we are not threadsafe. */
|
|
||||||
static inline void cpu_exec_start(CPUArchState *env)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void cpu_exec_end(CPUArchState *env)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void start_exclusive(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void end_exclusive(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void fork_start(void)
|
void fork_start(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -95,14 +78,6 @@ void fork_end(int child)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_list_lock(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_list_unlock(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* CPUX86 core interface */
|
/* CPUX86 core interface */
|
||||||
@@ -172,7 +147,11 @@ void cpu_loop(CPUX86State *env)
|
|||||||
//target_siginfo_t info;
|
//target_siginfo_t info;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
cpu_exec_start(cs);
|
||||||
trapnr = cpu_exec(cs);
|
trapnr = cpu_exec(cs);
|
||||||
|
cpu_exec_end(cs);
|
||||||
|
process_queued_cpu_work(cs);
|
||||||
|
|
||||||
switch(trapnr) {
|
switch(trapnr) {
|
||||||
case 0x80:
|
case 0x80:
|
||||||
/* syscall from int $0x80 */
|
/* syscall from int $0x80 */
|
||||||
@@ -513,7 +492,10 @@ void cpu_loop(CPUSPARCState *env)
|
|||||||
//target_siginfo_t info;
|
//target_siginfo_t info;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
cpu_exec_start(cs);
|
||||||
trapnr = cpu_exec(cs);
|
trapnr = cpu_exec(cs);
|
||||||
|
cpu_exec_end(cs);
|
||||||
|
process_queued_cpu_work(cs);
|
||||||
|
|
||||||
switch (trapnr) {
|
switch (trapnr) {
|
||||||
#ifndef TARGET_SPARC64
|
#ifndef TARGET_SPARC64
|
||||||
@@ -713,6 +695,16 @@ static void usage(void)
|
|||||||
|
|
||||||
THREAD CPUState *thread_cpu;
|
THREAD CPUState *thread_cpu;
|
||||||
|
|
||||||
|
bool qemu_cpu_is_self(CPUState *cpu)
|
||||||
|
{
|
||||||
|
return thread_cpu == cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_cpu_kick(CPUState *cpu)
|
||||||
|
{
|
||||||
|
cpu_exit(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
/* Assumes contents are already zeroed. */
|
/* Assumes contents are already zeroed. */
|
||||||
void init_task_state(TaskState *ts)
|
void init_task_state(TaskState *ts)
|
||||||
{
|
{
|
||||||
@@ -748,6 +740,8 @@ int main(int argc, char **argv)
|
|||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
|
module_call_init(MODULE_INIT_TRACE);
|
||||||
|
qemu_init_cpu_list();
|
||||||
module_call_init(MODULE_INIT_QOM);
|
module_call_init(MODULE_INIT_QOM);
|
||||||
|
|
||||||
if ((envlist = envlist_create()) == NULL) {
|
if ((envlist = envlist_create()) == NULL) {
|
||||||
@@ -1133,7 +1127,6 @@ int main(int argc, char **argv)
|
|||||||
gdbserver_start (gdbstub_port);
|
gdbserver_start (gdbstub_port);
|
||||||
gdb_handlesig(cpu, 0);
|
gdb_handlesig(cpu, 0);
|
||||||
}
|
}
|
||||||
trace_init_vcpu_events();
|
|
||||||
cpu_loop(env);
|
cpu_loop(env);
|
||||||
/* never exits */
|
/* never exits */
|
||||||
return 0;
|
return 0;
|
||||||
|
93
configure
vendored
93
configure
vendored
@@ -296,6 +296,7 @@ libiscsi=""
|
|||||||
libnfs=""
|
libnfs=""
|
||||||
coroutine=""
|
coroutine=""
|
||||||
coroutine_pool=""
|
coroutine_pool=""
|
||||||
|
debug_stack_usage="no"
|
||||||
seccomp=""
|
seccomp=""
|
||||||
glusterfs=""
|
glusterfs=""
|
||||||
glusterfs_xlator_opt="no"
|
glusterfs_xlator_opt="no"
|
||||||
@@ -1004,6 +1005,8 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-coroutine-pool) coroutine_pool="yes"
|
--enable-coroutine-pool) coroutine_pool="yes"
|
||||||
;;
|
;;
|
||||||
|
--enable-debug-stack-usage) debug_stack_usage="yes"
|
||||||
|
;;
|
||||||
--disable-docs) docs="no"
|
--disable-docs) docs="no"
|
||||||
;;
|
;;
|
||||||
--enable-docs) docs="yes"
|
--enable-docs) docs="yes"
|
||||||
@@ -1722,6 +1725,19 @@ if test "$cocoa" = "yes"; then
|
|||||||
sdl=no
|
sdl=no
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Some versions of Mac OS X incorrectly define SIZE_MAX
|
||||||
|
cat > $TMPC << EOF
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
return printf("%zu", SIZE_MAX);
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
have_broken_size_max=no
|
||||||
|
if ! compile_object -Werror ; then
|
||||||
|
have_broken_size_max=yes
|
||||||
|
fi
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# L2TPV3 probe
|
# L2TPV3 probe
|
||||||
|
|
||||||
@@ -1952,6 +1968,61 @@ EOF
|
|||||||
# Xen unstable
|
# Xen unstable
|
||||||
elif
|
elif
|
||||||
cat > $TMPC <<EOF &&
|
cat > $TMPC <<EOF &&
|
||||||
|
/*
|
||||||
|
* If we have stable libs the we don't want the libxc compat
|
||||||
|
* layers, regardless of what CFLAGS we may have been given.
|
||||||
|
*
|
||||||
|
* Also, check if xengnttab_grant_copy_segment_t is defined and
|
||||||
|
* grant copy operation is implemented.
|
||||||
|
*/
|
||||||
|
#undef XC_WANT_COMPAT_EVTCHN_API
|
||||||
|
#undef XC_WANT_COMPAT_GNTTAB_API
|
||||||
|
#undef XC_WANT_COMPAT_MAP_FOREIGN_API
|
||||||
|
#include <xenctrl.h>
|
||||||
|
#include <xenstore.h>
|
||||||
|
#include <xenevtchn.h>
|
||||||
|
#include <xengnttab.h>
|
||||||
|
#include <xenforeignmemory.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <xen/hvm/hvm_info_table.h>
|
||||||
|
#if !defined(HVM_MAX_VCPUS)
|
||||||
|
# error HVM_MAX_VCPUS not defined
|
||||||
|
#endif
|
||||||
|
int main(void) {
|
||||||
|
xc_interface *xc = NULL;
|
||||||
|
xenforeignmemory_handle *xfmem;
|
||||||
|
xenevtchn_handle *xe;
|
||||||
|
xengnttab_handle *xg;
|
||||||
|
xen_domain_handle_t handle;
|
||||||
|
xengnttab_grant_copy_segment_t* seg = NULL;
|
||||||
|
|
||||||
|
xs_daemon_open();
|
||||||
|
|
||||||
|
xc = xc_interface_open(0, 0, 0);
|
||||||
|
xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
|
||||||
|
xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
|
||||||
|
xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000);
|
||||||
|
xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL);
|
||||||
|
xc_domain_create(xc, 0, handle, 0, NULL, NULL);
|
||||||
|
|
||||||
|
xfmem = xenforeignmemory_open(0, 0);
|
||||||
|
xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
xe = xenevtchn_open(0, 0);
|
||||||
|
xenevtchn_fd(xe);
|
||||||
|
|
||||||
|
xg = xengnttab_open(0, 0);
|
||||||
|
xengnttab_grant_copy(xg, 0, seg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
compile_prog "" "$xen_libs $xen_stable_libs"
|
||||||
|
then
|
||||||
|
xen_ctrl_version=480
|
||||||
|
xen=yes
|
||||||
|
elif
|
||||||
|
cat > $TMPC <<EOF &&
|
||||||
/*
|
/*
|
||||||
* If we have stable libs the we don't want the libxc compat
|
* If we have stable libs the we don't want the libxc compat
|
||||||
* layers, regardless of what CFLAGS we may have been given.
|
* layers, regardless of what CFLAGS we may have been given.
|
||||||
@@ -2933,7 +3004,7 @@ for i in $glib_modules; do
|
|||||||
if $pkg_config --atleast-version=$glib_req_ver $i; then
|
if $pkg_config --atleast-version=$glib_req_ver $i; then
|
||||||
glib_cflags=$($pkg_config --cflags $i)
|
glib_cflags=$($pkg_config --cflags $i)
|
||||||
glib_libs=$($pkg_config --libs $i)
|
glib_libs=$($pkg_config --libs $i)
|
||||||
CFLAGS="$glib_cflags $CFLAGS"
|
QEMU_CFLAGS="$glib_cflags $QEMU_CFLAGS"
|
||||||
LIBS="$glib_libs $LIBS"
|
LIBS="$glib_libs $LIBS"
|
||||||
libs_qga="$glib_libs $libs_qga"
|
libs_qga="$glib_libs $libs_qga"
|
||||||
else
|
else
|
||||||
@@ -4276,6 +4347,17 @@ if test "$coroutine" = "gthread" -a "$coroutine_pool" = "yes"; then
|
|||||||
error_exit "'gthread' coroutine backend does not support pool (use --disable-coroutine-pool)"
|
error_exit "'gthread' coroutine backend does not support pool (use --disable-coroutine-pool)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$debug_stack_usage" = "yes"; then
|
||||||
|
if test "$cpu" = "ia64" -o "$cpu" = "hppa"; then
|
||||||
|
error_exit "stack usage debugging is not supported for $cpu"
|
||||||
|
fi
|
||||||
|
if test "$coroutine_pool" = "yes"; then
|
||||||
|
echo "WARN: disabling coroutine pool for stack usage debugging"
|
||||||
|
coroutine_pool=no
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# check if we have open_by_handle_at
|
# check if we have open_by_handle_at
|
||||||
|
|
||||||
@@ -4861,6 +4943,7 @@ echo "QGA MSI support $guest_agent_msi"
|
|||||||
echo "seccomp support $seccomp"
|
echo "seccomp support $seccomp"
|
||||||
echo "coroutine backend $coroutine"
|
echo "coroutine backend $coroutine"
|
||||||
echo "coroutine pool $coroutine_pool"
|
echo "coroutine pool $coroutine_pool"
|
||||||
|
echo "debug stack usage $debug_stack_usage"
|
||||||
echo "GlusterFS support $glusterfs"
|
echo "GlusterFS support $glusterfs"
|
||||||
echo "Archipelago support $archipelago"
|
echo "Archipelago support $archipelago"
|
||||||
echo "gcov $gcov_tool"
|
echo "gcov $gcov_tool"
|
||||||
@@ -5140,7 +5223,6 @@ fi
|
|||||||
if test "$glib_subprocess" = "yes" ; then
|
if test "$glib_subprocess" = "yes" ; then
|
||||||
echo "CONFIG_HAS_GLIB_SUBPROCESS_TESTS=y" >> $config_host_mak
|
echo "CONFIG_HAS_GLIB_SUBPROCESS_TESTS=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
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 "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
|
||||||
@@ -5176,6 +5258,9 @@ fi
|
|||||||
if test "$have_ifaddrs_h" = "yes" ; then
|
if test "$have_ifaddrs_h" = "yes" ; then
|
||||||
echo "HAVE_IFADDRS_H=y" >> $config_host_mak
|
echo "HAVE_IFADDRS_H=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$have_broken_size_max" = "yes" ; then
|
||||||
|
echo "HAVE_BROKEN_SIZE_MAX=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
# Work around a system header bug with some kernel/XFS header
|
# Work around a system header bug with some kernel/XFS header
|
||||||
# versions where they both try to define 'struct fsxattr':
|
# versions where they both try to define 'struct fsxattr':
|
||||||
@@ -5330,6 +5415,10 @@ else
|
|||||||
echo "CONFIG_COROUTINE_POOL=0" >> $config_host_mak
|
echo "CONFIG_COROUTINE_POOL=0" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$debug_stack_usage" = "yes" ; then
|
||||||
|
echo "CONFIG_DEBUG_STACK_USAGE=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$open_by_handle_at" = "yes" ; then
|
if test "$open_by_handle_at" = "yes" ; then
|
||||||
echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
|
echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
20
cpu-exec.c
20
cpu-exec.c
@@ -192,7 +192,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
|||||||
/* We were asked to stop executing TBs (probably a pending
|
/* We were asked to stop executing TBs (probably a pending
|
||||||
* interrupt. We've now stopped, so clear the flag.
|
* interrupt. We've now stopped, so clear the flag.
|
||||||
*/
|
*/
|
||||||
cpu->tcg_exit_req = 0;
|
atomic_set(&cpu->tcg_exit_req, 0);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -204,20 +204,16 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
|
|||||||
TranslationBlock *orig_tb, bool ignore_icount)
|
TranslationBlock *orig_tb, bool ignore_icount)
|
||||||
{
|
{
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
bool old_tb_flushed;
|
|
||||||
|
|
||||||
/* Should never happen.
|
/* Should never happen.
|
||||||
We only end up here when an existing TB is too long. */
|
We only end up here when an existing TB is too long. */
|
||||||
if (max_cycles > CF_COUNT_MASK)
|
if (max_cycles > CF_COUNT_MASK)
|
||||||
max_cycles = CF_COUNT_MASK;
|
max_cycles = CF_COUNT_MASK;
|
||||||
|
|
||||||
old_tb_flushed = cpu->tb_flushed;
|
|
||||||
cpu->tb_flushed = false;
|
|
||||||
tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
|
tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
|
||||||
max_cycles | CF_NOCACHE
|
max_cycles | CF_NOCACHE
|
||||||
| (ignore_icount ? CF_IGNORE_ICOUNT : 0));
|
| (ignore_icount ? CF_IGNORE_ICOUNT : 0));
|
||||||
tb->orig_tb = cpu->tb_flushed ? NULL : orig_tb;
|
tb->orig_tb = orig_tb;
|
||||||
cpu->tb_flushed |= old_tb_flushed;
|
|
||||||
/* execute the generated code */
|
/* execute the generated code */
|
||||||
trace_exec_tb_nocache(tb, tb->pc);
|
trace_exec_tb_nocache(tb, tb->pc);
|
||||||
cpu_tb_exec(cpu, tb);
|
cpu_tb_exec(cpu, tb);
|
||||||
@@ -338,10 +334,7 @@ static inline TranslationBlock *tb_find(CPUState *cpu,
|
|||||||
tb_lock();
|
tb_lock();
|
||||||
have_tb_lock = true;
|
have_tb_lock = true;
|
||||||
}
|
}
|
||||||
/* Check if translation buffer has been flushed */
|
if (!tb->invalid) {
|
||||||
if (cpu->tb_flushed) {
|
|
||||||
cpu->tb_flushed = false;
|
|
||||||
} else if (!tb->invalid) {
|
|
||||||
tb_add_jump(last_tb, tb_exit, tb);
|
tb_add_jump(last_tb, tb_exit, tb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,8 +490,8 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
|
|||||||
*last_tb = NULL;
|
*last_tb = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unlikely(cpu->exit_request || replay_has_interrupt())) {
|
if (unlikely(atomic_read(&cpu->exit_request) || replay_has_interrupt())) {
|
||||||
cpu->exit_request = 0;
|
atomic_set(&cpu->exit_request, 0);
|
||||||
cpu->exception_index = EXCP_INTERRUPT;
|
cpu->exception_index = EXCP_INTERRUPT;
|
||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
@@ -510,7 +503,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
|||||||
{
|
{
|
||||||
uintptr_t ret;
|
uintptr_t ret;
|
||||||
|
|
||||||
if (unlikely(cpu->exit_request)) {
|
if (unlikely(atomic_read(&cpu->exit_request))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,7 +599,6 @@ int cpu_exec(CPUState *cpu)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_mb_set(&cpu->tb_flushed, false); /* reset before first TB lookup */
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
cpu_handle_interrupt(cpu, &last_tb);
|
cpu_handle_interrupt(cpu, &last_tb);
|
||||||
tb = tb_find(cpu, last_tb, tb_exit);
|
tb = tb_find(cpu, last_tb, tb_exit);
|
||||||
|
352
cpus-common.c
Normal file
352
cpus-common.c
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
/*
|
||||||
|
* CPU thread main loop - common bits for user and system mode emulation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/main-loop.h"
|
||||||
|
#include "exec/cpu-common.h"
|
||||||
|
#include "qom/cpu.h"
|
||||||
|
#include "sysemu/cpus.h"
|
||||||
|
|
||||||
|
static QemuMutex qemu_cpu_list_lock;
|
||||||
|
static QemuCond exclusive_cond;
|
||||||
|
static QemuCond exclusive_resume;
|
||||||
|
static QemuCond qemu_work_cond;
|
||||||
|
|
||||||
|
/* >= 1 if a thread is inside start_exclusive/end_exclusive. Written
|
||||||
|
* under qemu_cpu_list_lock, read with atomic operations.
|
||||||
|
*/
|
||||||
|
static int pending_cpus;
|
||||||
|
|
||||||
|
void qemu_init_cpu_list(void)
|
||||||
|
{
|
||||||
|
/* This is needed because qemu_init_cpu_list is also called by the
|
||||||
|
* child process in a fork. */
|
||||||
|
pending_cpus = 0;
|
||||||
|
|
||||||
|
qemu_mutex_init(&qemu_cpu_list_lock);
|
||||||
|
qemu_cond_init(&exclusive_cond);
|
||||||
|
qemu_cond_init(&exclusive_resume);
|
||||||
|
qemu_cond_init(&qemu_work_cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_list_lock(void)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_list_unlock(void)
|
||||||
|
{
|
||||||
|
qemu_mutex_unlock(&qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cpu_index_auto_assigned;
|
||||||
|
|
||||||
|
static int cpu_get_free_index(void)
|
||||||
|
{
|
||||||
|
CPUState *some_cpu;
|
||||||
|
int cpu_index = 0;
|
||||||
|
|
||||||
|
cpu_index_auto_assigned = true;
|
||||||
|
CPU_FOREACH(some_cpu) {
|
||||||
|
cpu_index++;
|
||||||
|
}
|
||||||
|
return cpu_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void finish_safe_work(CPUState *cpu)
|
||||||
|
{
|
||||||
|
cpu_exec_start(cpu);
|
||||||
|
cpu_exec_end(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_list_add(CPUState *cpu)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&qemu_cpu_list_lock);
|
||||||
|
if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) {
|
||||||
|
cpu->cpu_index = cpu_get_free_index();
|
||||||
|
assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
|
||||||
|
} else {
|
||||||
|
assert(!cpu_index_auto_assigned);
|
||||||
|
}
|
||||||
|
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
|
||||||
|
qemu_mutex_unlock(&qemu_cpu_list_lock);
|
||||||
|
|
||||||
|
finish_safe_work(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_list_remove(CPUState *cpu)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&qemu_cpu_list_lock);
|
||||||
|
if (!QTAILQ_IN_USE(cpu, node)) {
|
||||||
|
/* there is nothing to undo since cpu_exec_init() hasn't been called */
|
||||||
|
qemu_mutex_unlock(&qemu_cpu_list_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
|
||||||
|
|
||||||
|
QTAILQ_REMOVE(&cpus, cpu, node);
|
||||||
|
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
|
||||||
|
qemu_mutex_unlock(&qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct qemu_work_item {
|
||||||
|
struct qemu_work_item *next;
|
||||||
|
run_on_cpu_func func;
|
||||||
|
void *data;
|
||||||
|
bool free, exclusive, done;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&cpu->work_mutex);
|
||||||
|
if (cpu->queued_work_first == NULL) {
|
||||||
|
cpu->queued_work_first = wi;
|
||||||
|
} else {
|
||||||
|
cpu->queued_work_last->next = wi;
|
||||||
|
}
|
||||||
|
cpu->queued_work_last = wi;
|
||||||
|
wi->next = NULL;
|
||||||
|
wi->done = false;
|
||||||
|
qemu_mutex_unlock(&cpu->work_mutex);
|
||||||
|
|
||||||
|
qemu_cpu_kick(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
|
||||||
|
QemuMutex *mutex)
|
||||||
|
{
|
||||||
|
struct qemu_work_item wi;
|
||||||
|
|
||||||
|
if (qemu_cpu_is_self(cpu)) {
|
||||||
|
func(cpu, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wi.func = func;
|
||||||
|
wi.data = data;
|
||||||
|
wi.done = false;
|
||||||
|
wi.free = false;
|
||||||
|
wi.exclusive = false;
|
||||||
|
|
||||||
|
queue_work_on_cpu(cpu, &wi);
|
||||||
|
while (!atomic_mb_read(&wi.done)) {
|
||||||
|
CPUState *self_cpu = current_cpu;
|
||||||
|
|
||||||
|
qemu_cond_wait(&qemu_work_cond, mutex);
|
||||||
|
current_cpu = self_cpu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
|
||||||
|
{
|
||||||
|
struct qemu_work_item *wi;
|
||||||
|
|
||||||
|
wi = g_malloc0(sizeof(struct qemu_work_item));
|
||||||
|
wi->func = func;
|
||||||
|
wi->data = data;
|
||||||
|
wi->free = true;
|
||||||
|
|
||||||
|
queue_work_on_cpu(cpu, wi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for pending exclusive operations to complete. The CPU list lock
|
||||||
|
must be held. */
|
||||||
|
static inline void exclusive_idle(void)
|
||||||
|
{
|
||||||
|
while (pending_cpus) {
|
||||||
|
qemu_cond_wait(&exclusive_resume, &qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start an exclusive operation.
|
||||||
|
Must only be called from outside cpu_exec. */
|
||||||
|
void start_exclusive(void)
|
||||||
|
{
|
||||||
|
CPUState *other_cpu;
|
||||||
|
int running_cpus;
|
||||||
|
|
||||||
|
qemu_mutex_lock(&qemu_cpu_list_lock);
|
||||||
|
exclusive_idle();
|
||||||
|
|
||||||
|
/* Make all other cpus stop executing. */
|
||||||
|
atomic_set(&pending_cpus, 1);
|
||||||
|
|
||||||
|
/* Write pending_cpus before reading other_cpu->running. */
|
||||||
|
smp_mb();
|
||||||
|
running_cpus = 0;
|
||||||
|
CPU_FOREACH(other_cpu) {
|
||||||
|
if (atomic_read(&other_cpu->running)) {
|
||||||
|
other_cpu->has_waiter = true;
|
||||||
|
running_cpus++;
|
||||||
|
qemu_cpu_kick(other_cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_set(&pending_cpus, running_cpus + 1);
|
||||||
|
while (pending_cpus > 1) {
|
||||||
|
qemu_cond_wait(&exclusive_cond, &qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can release mutex, no one will enter another exclusive
|
||||||
|
* section until end_exclusive resets pending_cpus to 0.
|
||||||
|
*/
|
||||||
|
qemu_mutex_unlock(&qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finish an exclusive operation. */
|
||||||
|
void end_exclusive(void)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&qemu_cpu_list_lock);
|
||||||
|
atomic_set(&pending_cpus, 0);
|
||||||
|
qemu_cond_broadcast(&exclusive_resume);
|
||||||
|
qemu_mutex_unlock(&qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for exclusive ops to finish, and begin cpu execution. */
|
||||||
|
void cpu_exec_start(CPUState *cpu)
|
||||||
|
{
|
||||||
|
atomic_set(&cpu->running, true);
|
||||||
|
|
||||||
|
/* Write cpu->running before reading pending_cpus. */
|
||||||
|
smp_mb();
|
||||||
|
|
||||||
|
/* 1. start_exclusive saw cpu->running == true and pending_cpus >= 1.
|
||||||
|
* After taking the lock we'll see cpu->has_waiter == true and run---not
|
||||||
|
* for long because start_exclusive kicked us. cpu_exec_end will
|
||||||
|
* decrement pending_cpus and signal the waiter.
|
||||||
|
*
|
||||||
|
* 2. start_exclusive saw cpu->running == false but pending_cpus >= 1.
|
||||||
|
* This includes the case when an exclusive item is running now.
|
||||||
|
* Then we'll see cpu->has_waiter == false and wait for the item to
|
||||||
|
* complete.
|
||||||
|
*
|
||||||
|
* 3. pending_cpus == 0. Then start_exclusive is definitely going to
|
||||||
|
* see cpu->running == true, and it will kick the CPU.
|
||||||
|
*/
|
||||||
|
if (unlikely(atomic_read(&pending_cpus))) {
|
||||||
|
qemu_mutex_lock(&qemu_cpu_list_lock);
|
||||||
|
if (!cpu->has_waiter) {
|
||||||
|
/* Not counted in pending_cpus, let the exclusive item
|
||||||
|
* run. Since we have the lock, just set cpu->running to true
|
||||||
|
* while holding it; no need to check pending_cpus again.
|
||||||
|
*/
|
||||||
|
atomic_set(&cpu->running, false);
|
||||||
|
exclusive_idle();
|
||||||
|
/* Now pending_cpus is zero. */
|
||||||
|
atomic_set(&cpu->running, true);
|
||||||
|
} else {
|
||||||
|
/* Counted in pending_cpus, go ahead and release the
|
||||||
|
* waiter at cpu_exec_end.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
qemu_mutex_unlock(&qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark cpu as not executing, and release pending exclusive ops. */
|
||||||
|
void cpu_exec_end(CPUState *cpu)
|
||||||
|
{
|
||||||
|
atomic_set(&cpu->running, false);
|
||||||
|
|
||||||
|
/* Write cpu->running before reading pending_cpus. */
|
||||||
|
smp_mb();
|
||||||
|
|
||||||
|
/* 1. start_exclusive saw cpu->running == true. Then it will increment
|
||||||
|
* pending_cpus and wait for exclusive_cond. After taking the lock
|
||||||
|
* we'll see cpu->has_waiter == true.
|
||||||
|
*
|
||||||
|
* 2. start_exclusive saw cpu->running == false but here pending_cpus >= 1.
|
||||||
|
* This includes the case when an exclusive item started after setting
|
||||||
|
* cpu->running to false and before we read pending_cpus. Then we'll see
|
||||||
|
* cpu->has_waiter == false and not touch pending_cpus. The next call to
|
||||||
|
* cpu_exec_start will run exclusive_idle if still necessary, thus waiting
|
||||||
|
* for the item to complete.
|
||||||
|
*
|
||||||
|
* 3. pending_cpus == 0. Then start_exclusive is definitely going to
|
||||||
|
* see cpu->running == false, and it can ignore this CPU until the
|
||||||
|
* next cpu_exec_start.
|
||||||
|
*/
|
||||||
|
if (unlikely(atomic_read(&pending_cpus))) {
|
||||||
|
qemu_mutex_lock(&qemu_cpu_list_lock);
|
||||||
|
if (cpu->has_waiter) {
|
||||||
|
cpu->has_waiter = false;
|
||||||
|
atomic_set(&pending_cpus, pending_cpus - 1);
|
||||||
|
if (pending_cpus == 1) {
|
||||||
|
qemu_cond_signal(&exclusive_cond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qemu_mutex_unlock(&qemu_cpu_list_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
|
||||||
|
{
|
||||||
|
struct qemu_work_item *wi;
|
||||||
|
|
||||||
|
wi = g_malloc0(sizeof(struct qemu_work_item));
|
||||||
|
wi->func = func;
|
||||||
|
wi->data = data;
|
||||||
|
wi->free = true;
|
||||||
|
wi->exclusive = true;
|
||||||
|
|
||||||
|
queue_work_on_cpu(cpu, wi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_queued_cpu_work(CPUState *cpu)
|
||||||
|
{
|
||||||
|
struct qemu_work_item *wi;
|
||||||
|
|
||||||
|
if (cpu->queued_work_first == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_mutex_lock(&cpu->work_mutex);
|
||||||
|
while (cpu->queued_work_first != NULL) {
|
||||||
|
wi = cpu->queued_work_first;
|
||||||
|
cpu->queued_work_first = wi->next;
|
||||||
|
if (!cpu->queued_work_first) {
|
||||||
|
cpu->queued_work_last = NULL;
|
||||||
|
}
|
||||||
|
qemu_mutex_unlock(&cpu->work_mutex);
|
||||||
|
if (wi->exclusive) {
|
||||||
|
/* Running work items outside the BQL avoids the following deadlock:
|
||||||
|
* 1) start_exclusive() is called with the BQL taken while another
|
||||||
|
* CPU is running; 2) cpu_exec in the other CPU tries to takes the
|
||||||
|
* BQL, so it goes to sleep; start_exclusive() is sleeping too, so
|
||||||
|
* neither CPU can proceed.
|
||||||
|
*/
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
start_exclusive();
|
||||||
|
wi->func(cpu, wi->data);
|
||||||
|
end_exclusive();
|
||||||
|
qemu_mutex_lock_iothread();
|
||||||
|
} else {
|
||||||
|
wi->func(cpu, wi->data);
|
||||||
|
}
|
||||||
|
qemu_mutex_lock(&cpu->work_mutex);
|
||||||
|
if (wi->free) {
|
||||||
|
g_free(wi);
|
||||||
|
} else {
|
||||||
|
atomic_mb_set(&wi->done, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qemu_mutex_unlock(&cpu->work_mutex);
|
||||||
|
qemu_cond_broadcast(&qemu_work_cond);
|
||||||
|
}
|
104
cpus.c
104
cpus.c
@@ -557,9 +557,8 @@ static const VMStateDescription vmstate_timers = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cpu_throttle_thread(void *opaque)
|
static void cpu_throttle_thread(CPUState *cpu, void *opaque)
|
||||||
{
|
{
|
||||||
CPUState *cpu = opaque;
|
|
||||||
double pct;
|
double pct;
|
||||||
double throttle_ratio;
|
double throttle_ratio;
|
||||||
long sleeptime_ns;
|
long sleeptime_ns;
|
||||||
@@ -589,7 +588,7 @@ static void cpu_throttle_timer_tick(void *opaque)
|
|||||||
}
|
}
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) {
|
if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) {
|
||||||
async_run_on_cpu(cpu, cpu_throttle_thread, cpu);
|
async_run_on_cpu(cpu, cpu_throttle_thread, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,7 +750,8 @@ static int do_vm_stop(RunState state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bdrv_drain_all();
|
bdrv_drain_all();
|
||||||
ret = blk_flush_all();
|
replay_disable_events();
|
||||||
|
ret = bdrv_flush_all();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -903,79 +903,21 @@ static QemuThread io_thread;
|
|||||||
static QemuCond qemu_cpu_cond;
|
static QemuCond qemu_cpu_cond;
|
||||||
/* system init */
|
/* system init */
|
||||||
static QemuCond qemu_pause_cond;
|
static QemuCond qemu_pause_cond;
|
||||||
static QemuCond qemu_work_cond;
|
|
||||||
|
|
||||||
void qemu_init_cpu_loop(void)
|
void qemu_init_cpu_loop(void)
|
||||||
{
|
{
|
||||||
qemu_init_sigbus();
|
qemu_init_sigbus();
|
||||||
qemu_cond_init(&qemu_cpu_cond);
|
qemu_cond_init(&qemu_cpu_cond);
|
||||||
qemu_cond_init(&qemu_pause_cond);
|
qemu_cond_init(&qemu_pause_cond);
|
||||||
qemu_cond_init(&qemu_work_cond);
|
|
||||||
qemu_cond_init(&qemu_io_proceeded_cond);
|
qemu_cond_init(&qemu_io_proceeded_cond);
|
||||||
qemu_mutex_init(&qemu_global_mutex);
|
qemu_mutex_init(&qemu_global_mutex);
|
||||||
|
|
||||||
qemu_thread_get_self(&io_thread);
|
qemu_thread_get_self(&io_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
|
void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
|
||||||
{
|
{
|
||||||
struct qemu_work_item wi;
|
do_run_on_cpu(cpu, func, data, &qemu_global_mutex);
|
||||||
|
|
||||||
if (qemu_cpu_is_self(cpu)) {
|
|
||||||
func(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wi.func = func;
|
|
||||||
wi.data = data;
|
|
||||||
wi.free = false;
|
|
||||||
|
|
||||||
qemu_mutex_lock(&cpu->work_mutex);
|
|
||||||
if (cpu->queued_work_first == NULL) {
|
|
||||||
cpu->queued_work_first = &wi;
|
|
||||||
} else {
|
|
||||||
cpu->queued_work_last->next = &wi;
|
|
||||||
}
|
|
||||||
cpu->queued_work_last = &wi;
|
|
||||||
wi.next = NULL;
|
|
||||||
wi.done = false;
|
|
||||||
qemu_mutex_unlock(&cpu->work_mutex);
|
|
||||||
|
|
||||||
qemu_cpu_kick(cpu);
|
|
||||||
while (!atomic_mb_read(&wi.done)) {
|
|
||||||
CPUState *self_cpu = current_cpu;
|
|
||||||
|
|
||||||
qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex);
|
|
||||||
current_cpu = self_cpu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
|
|
||||||
{
|
|
||||||
struct qemu_work_item *wi;
|
|
||||||
|
|
||||||
if (qemu_cpu_is_self(cpu)) {
|
|
||||||
func(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wi = g_malloc0(sizeof(struct qemu_work_item));
|
|
||||||
wi->func = func;
|
|
||||||
wi->data = data;
|
|
||||||
wi->free = true;
|
|
||||||
|
|
||||||
qemu_mutex_lock(&cpu->work_mutex);
|
|
||||||
if (cpu->queued_work_first == NULL) {
|
|
||||||
cpu->queued_work_first = wi;
|
|
||||||
} else {
|
|
||||||
cpu->queued_work_last->next = wi;
|
|
||||||
}
|
|
||||||
cpu->queued_work_last = wi;
|
|
||||||
wi->next = NULL;
|
|
||||||
wi->done = false;
|
|
||||||
qemu_mutex_unlock(&cpu->work_mutex);
|
|
||||||
|
|
||||||
qemu_cpu_kick(cpu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_kvm_destroy_vcpu(CPUState *cpu)
|
static void qemu_kvm_destroy_vcpu(CPUState *cpu)
|
||||||
@@ -990,34 +932,6 @@ static void qemu_tcg_destroy_vcpu(CPUState *cpu)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_queued_work(CPUState *cpu)
|
|
||||||
{
|
|
||||||
struct qemu_work_item *wi;
|
|
||||||
|
|
||||||
if (cpu->queued_work_first == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_mutex_lock(&cpu->work_mutex);
|
|
||||||
while (cpu->queued_work_first != NULL) {
|
|
||||||
wi = cpu->queued_work_first;
|
|
||||||
cpu->queued_work_first = wi->next;
|
|
||||||
if (!cpu->queued_work_first) {
|
|
||||||
cpu->queued_work_last = NULL;
|
|
||||||
}
|
|
||||||
qemu_mutex_unlock(&cpu->work_mutex);
|
|
||||||
wi->func(wi->data);
|
|
||||||
qemu_mutex_lock(&cpu->work_mutex);
|
|
||||||
if (wi->free) {
|
|
||||||
g_free(wi);
|
|
||||||
} else {
|
|
||||||
atomic_mb_set(&wi->done, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qemu_mutex_unlock(&cpu->work_mutex);
|
|
||||||
qemu_cond_broadcast(&qemu_work_cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qemu_wait_io_event_common(CPUState *cpu)
|
static void qemu_wait_io_event_common(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (cpu->stop) {
|
if (cpu->stop) {
|
||||||
@@ -1025,7 +939,7 @@ static void qemu_wait_io_event_common(CPUState *cpu)
|
|||||||
cpu->stopped = true;
|
cpu->stopped = true;
|
||||||
qemu_cond_broadcast(&qemu_pause_cond);
|
qemu_cond_broadcast(&qemu_pause_cond);
|
||||||
}
|
}
|
||||||
flush_queued_work(cpu);
|
process_queued_cpu_work(cpu);
|
||||||
cpu->thread_kicked = false;
|
cpu->thread_kicked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1494,7 +1408,7 @@ int vm_stop_force_state(RunState state)
|
|||||||
bdrv_drain_all();
|
bdrv_drain_all();
|
||||||
/* Make sure to return an error if the flush in a previous vm_stop()
|
/* Make sure to return an error if the flush in a previous vm_stop()
|
||||||
* failed. */
|
* failed. */
|
||||||
return blk_flush_all();
|
return bdrv_flush_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1544,7 +1458,9 @@ static int tcg_cpu_exec(CPUState *cpu)
|
|||||||
cpu->icount_decr.u16.low = decr;
|
cpu->icount_decr.u16.low = decr;
|
||||||
cpu->icount_extra = count;
|
cpu->icount_extra = count;
|
||||||
}
|
}
|
||||||
|
cpu_exec_start(cpu);
|
||||||
ret = cpu_exec(cpu);
|
ret = cpu_exec(cpu);
|
||||||
|
cpu_exec_end(cpu);
|
||||||
#ifdef CONFIG_PROFILER
|
#ifdef CONFIG_PROFILER
|
||||||
tcg_time += profile_getclock() - ti;
|
tcg_time += profile_getclock() - ti;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -86,6 +86,8 @@ CONFIG_ZYNQ=y
|
|||||||
CONFIG_STM32F2XX_TIMER=y
|
CONFIG_STM32F2XX_TIMER=y
|
||||||
CONFIG_STM32F2XX_USART=y
|
CONFIG_STM32F2XX_USART=y
|
||||||
CONFIG_STM32F2XX_SYSCFG=y
|
CONFIG_STM32F2XX_SYSCFG=y
|
||||||
|
CONFIG_STM32F2XX_ADC=y
|
||||||
|
CONFIG_STM32F2XX_SPI=y
|
||||||
CONFIG_STM32F205_SOC=y
|
CONFIG_STM32F205_SOC=y
|
||||||
|
|
||||||
CONFIG_VERSATILE_PCI=y
|
CONFIG_VERSATILE_PCI=y
|
||||||
|
188
docs/colo-proxy.txt
Normal file
188
docs/colo-proxy.txt
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
COLO-proxy
|
||||||
|
----------
|
||||||
|
Copyright (c) 2016 Intel Corporation
|
||||||
|
Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||||
|
Copyright (c) 2016 Fujitsu, Corp.
|
||||||
|
|
||||||
|
This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
See the COPYING file in the top-level directory.
|
||||||
|
|
||||||
|
This document gives an overview of COLO proxy's design.
|
||||||
|
|
||||||
|
== Background ==
|
||||||
|
COLO-proxy is a part of COLO project. It is used
|
||||||
|
to compare the network package to help COLO decide
|
||||||
|
whether to do checkpoint. With COLO-proxy's help,
|
||||||
|
COLO greatly improves the performance.
|
||||||
|
|
||||||
|
The filter-redirector, filter-mirror, colo-compare
|
||||||
|
and filter-rewriter compose the COLO-proxy.
|
||||||
|
|
||||||
|
== Architecture ==
|
||||||
|
|
||||||
|
COLO-Proxy is based on qemu netfilter and it's a plugin for qemu netfilter
|
||||||
|
(except colo-compare). It keep Secondary VM connect normally to
|
||||||
|
client and compare packets sent by PVM with sent by SVM.
|
||||||
|
If the packet difference, notify COLO-frame to do checkpoint and send
|
||||||
|
all primary packet has queued. Otherwise just send the queued primary
|
||||||
|
packet and drop the queued secondary packet.
|
||||||
|
|
||||||
|
Below is a COLO proxy ascii figure:
|
||||||
|
|
||||||
|
Primary qemu Secondary qemu
|
||||||
|
+--------------------------------------------------------------+ +----------------------------------------------------------------+
|
||||||
|
| +----------------------------------------------------------+ | | +-----------------------------------------------------------+ |
|
||||||
|
| | | | | | | |
|
||||||
|
| | guest | | | | guest | |
|
||||||
|
| | | | | | | |
|
||||||
|
| +-------^--------------------------+-----------------------+ | | +---------------------+--------+----------------------------+ |
|
||||||
|
| | | | | ^ | |
|
||||||
|
| | | | | | | |
|
||||||
|
| | +------------------------------------------------------+ | | | |
|
||||||
|
|netfilter| | | | | | netfilter | | |
|
||||||
|
| +----------+ +----------------------------+ | | | +-----------------------------------------------------------+ |
|
||||||
|
| | | | | | out | | | | | | filter excute order | |
|
||||||
|
| | | | +-----------------------------+ | | | | | | +-------------------> | |
|
||||||
|
| | | | | | | | | | | | | | TCP | |
|
||||||
|
| | +-----+--+-+ +-----v----+ +-----v----+ |pri +----+----+sec| | | | +------------+ +---+----+---v+rewriter++ +------------+ | |
|
||||||
|
| | | | | | | | |in | |in | | | | | | | | | | | | |
|
||||||
|
| | | filter | | filter | | filter +------> colo <------+ +--------> filter +--> adjust | adjust +--> filter | | |
|
||||||
|
| | | mirror | |redirector| |redirector| | | compare | | | | | | redirector | | ack | seq | | redirector | | |
|
||||||
|
| | | | | | | | | | | | | | | | | | | | | | | |
|
||||||
|
| | +----^-----+ +----+-----+ +----------+ | +---------+ | | | | +------------+ +--------+--------------+ +---+--------+ | |
|
||||||
|
| | | tx | rx rx | | | | | tx all | rx | |
|
||||||
|
| | | | | | | | +-----------------------------------------------------------+ |
|
||||||
|
| | | +--------------+ | | | | | |
|
||||||
|
| | | filter excute order | | | | | | |
|
||||||
|
| | | +----------------> | | | +--------------------------------------------------------+ |
|
||||||
|
| +-----------------------------------------+ | | |
|
||||||
|
| | | | | |
|
||||||
|
+--------------------------------------------------------------+ +----------------------------------------------------------------+
|
||||||
|
|guest receive | guest send
|
||||||
|
| |
|
||||||
|
+--------+----------------------------v------------------------+
|
||||||
|
| | NOTE: filter direction is rx/tx/all
|
||||||
|
| tap | rx:receive packets sent to the netdev
|
||||||
|
| | tx:receive packets sent by the netdev
|
||||||
|
+--------------------------------------------------------------+
|
||||||
|
|
||||||
|
1.Guest receive packet route:
|
||||||
|
|
||||||
|
Primary:
|
||||||
|
|
||||||
|
Tap --> Mirror Client Filter
|
||||||
|
Mirror client will send packet to guest,at the
|
||||||
|
same time, copy and forward packet to secondary
|
||||||
|
mirror server.
|
||||||
|
|
||||||
|
Secondary:
|
||||||
|
|
||||||
|
Mirror Server Filter --> TCP Rewriter
|
||||||
|
If receive packet is TCP packet,we will adjust ack
|
||||||
|
and update TCP checksum, then send to secondary
|
||||||
|
guest. Otherwise directly send to guest.
|
||||||
|
|
||||||
|
2.Guest send packet route:
|
||||||
|
|
||||||
|
Primary:
|
||||||
|
|
||||||
|
Guest --> Redirect Server Filter
|
||||||
|
Redirect server filter receive primary guest packet
|
||||||
|
but do nothing, just pass to next filter.
|
||||||
|
|
||||||
|
Redirect Server Filter --> COLO-Compare
|
||||||
|
COLO-compare receive primary guest packet then
|
||||||
|
waiting scondary redirect packet to compare it.
|
||||||
|
If packet same,send queued primary packet and clear
|
||||||
|
queued secondary packet, Otherwise send primary packet
|
||||||
|
and do checkpoint.
|
||||||
|
|
||||||
|
COLO-Compare --> Another Redirector Filter
|
||||||
|
The redirector get packet from colo-compare by use
|
||||||
|
chardev socket.
|
||||||
|
|
||||||
|
Redirector Filter --> Tap
|
||||||
|
Send the packet.
|
||||||
|
|
||||||
|
Secondary:
|
||||||
|
|
||||||
|
Guest --> TCP Rewriter Filter
|
||||||
|
If the packet is TCP packet,we will adjust seq
|
||||||
|
and update TCP checksum. Then send it to
|
||||||
|
redirect client filter. Otherwise directly send to
|
||||||
|
redirect client filter.
|
||||||
|
|
||||||
|
Redirect Client Filter --> Redirect Server Filter
|
||||||
|
Forward packet to primary.
|
||||||
|
|
||||||
|
== Components introduction ==
|
||||||
|
|
||||||
|
Filter-mirror is a netfilter plugin.
|
||||||
|
It gives qemu the ability to mirror
|
||||||
|
packets to a chardev.
|
||||||
|
|
||||||
|
Filter-redirector is a netfilter plugin.
|
||||||
|
It gives qemu the ability to redirect net packet.
|
||||||
|
Redirector can redirect filter's net packet to outdev,
|
||||||
|
and redirect indev's packet to filter.
|
||||||
|
|
||||||
|
filter
|
||||||
|
+
|
||||||
|
redirector |
|
||||||
|
+--------------+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
indev +---------+ +----------> outdev
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
+--------------+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
filter
|
||||||
|
|
||||||
|
COLO-compare, we do packet comparing job.
|
||||||
|
Packets coming from the primary char indev will be sent to outdev.
|
||||||
|
Packets coming from the secondary char dev will be dropped after comparing.
|
||||||
|
COLO-comapre need two input chardev and one output chardev:
|
||||||
|
primary_in=chardev1-id (source: primary send packet)
|
||||||
|
secondary_in=chardev2-id (source: secondary send packet)
|
||||||
|
outdev=chardev3-id
|
||||||
|
|
||||||
|
Filter-rewriter will rewrite some of secondary packet to make
|
||||||
|
secondary guest's tcp connection established successfully.
|
||||||
|
In this module we will rewrite tcp packet's ack to the secondary
|
||||||
|
from primary,and rewrite tcp packet's seq to the primary from
|
||||||
|
secondary.
|
||||||
|
|
||||||
|
== Usage ==
|
||||||
|
|
||||||
|
Here, we use demo ip and port discribe more clearly.
|
||||||
|
Primary(ip:3.3.3.3):
|
||||||
|
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
|
||||||
|
-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66
|
||||||
|
-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait
|
||||||
|
-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait
|
||||||
|
-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait
|
||||||
|
-chardev socket,id=compare0-0,host=3.3.3.3,port=9001
|
||||||
|
-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait
|
||||||
|
-chardev socket,id=compare_out0,host=3.3.3.3,port=9005
|
||||||
|
-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0
|
||||||
|
-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out
|
||||||
|
-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0
|
||||||
|
-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0
|
||||||
|
|
||||||
|
Secondary(ip:3.3.3.8):
|
||||||
|
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown
|
||||||
|
-device e1000,netdev=hn0,mac=52:a4:00:12:78:66
|
||||||
|
-chardev socket,id=red0,host=3.3.3.3,port=9003
|
||||||
|
-chardev socket,id=red1,host=3.3.3.3,port=9004
|
||||||
|
-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0
|
||||||
|
-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
|
||||||
|
|
||||||
|
Note:
|
||||||
|
a.COLO-proxy must work with COLO-frame and Block-replication.
|
||||||
|
b.Primary COLO must be started firstly, because COLO-proxy needs
|
||||||
|
chardev socket server running before secondary started.
|
||||||
|
c.Filter-rewriter only rewrite tcp packet.
|
84
docs/generic-loader.txt
Normal file
84
docs/generic-loader.txt
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
Copyright (c) 2016 Xilinx Inc.
|
||||||
|
|
||||||
|
This work is licensed under the terms of the GNU GPL, version 2 or later. See
|
||||||
|
the COPYING file in the top-level directory.
|
||||||
|
|
||||||
|
|
||||||
|
The 'loader' device allows the user to load multiple images or values into
|
||||||
|
QEMU at startup.
|
||||||
|
|
||||||
|
Loading Data into Memory Values
|
||||||
|
---------------------
|
||||||
|
The loader device allows memory values to be set from the command line. This
|
||||||
|
can be done by following the syntax below:
|
||||||
|
|
||||||
|
-device loader,addr=<addr>,data=<data>,data-len=<data-len>
|
||||||
|
[,data-be=<data-be>][,cpu-num=<cpu-num>]
|
||||||
|
|
||||||
|
<addr> - The address to store the data in.
|
||||||
|
<data> - The value to be written to the address. The maximum size of
|
||||||
|
the data is 8 bytes.
|
||||||
|
<data-len> - The length of the data in bytes. This argument must be
|
||||||
|
included if the data argument is.
|
||||||
|
<data-be> - Set to true if the data to be stored on the guest should be
|
||||||
|
written as big endian data. The default is to write little
|
||||||
|
endian data.
|
||||||
|
<cpu-num> - The number of the CPU's address space where the data should
|
||||||
|
be loaded. If not specified the address space of the first
|
||||||
|
CPU is used.
|
||||||
|
|
||||||
|
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||||
|
to specify any values in any format supported. By default the values
|
||||||
|
will be parsed as decimal. To use hex values the user should prefix the number
|
||||||
|
with a '0x'.
|
||||||
|
|
||||||
|
An example of loading value 0x8000000e to address 0xfd1a0104 is:
|
||||||
|
-device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4
|
||||||
|
|
||||||
|
Setting a CPU's Program Counter
|
||||||
|
---------------------
|
||||||
|
The loader device allows the CPU's PC to be set from the command line. This
|
||||||
|
can be done by following the syntax below:
|
||||||
|
|
||||||
|
-device loader,addr=<addr>,cpu-num=<cpu-num>
|
||||||
|
|
||||||
|
<addr> - The value to use as the CPU's PC.
|
||||||
|
<cpu-num> - The number of the CPU whose PC should be set to the
|
||||||
|
specified value.
|
||||||
|
|
||||||
|
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||||
|
to specify any values in any format supported. By default the values
|
||||||
|
will be parsed as decimal. To use hex values the user should prefix the number
|
||||||
|
with a '0x'.
|
||||||
|
|
||||||
|
An example of setting CPU 0's PC to 0x8000 is:
|
||||||
|
-device loader,addr=0x8000,cpu-num=0
|
||||||
|
|
||||||
|
Loading Files
|
||||||
|
---------------------
|
||||||
|
The loader device also allows files to be loaded into memory. This can be done
|
||||||
|
similarly to setting memory values. The syntax is shown below:
|
||||||
|
|
||||||
|
-device loader,file=<file>[,addr=<addr>][,cpu-num=<cpu-num>][,force-raw=<raw>]
|
||||||
|
|
||||||
|
<file> - A file to be loaded into memory
|
||||||
|
<addr> - The addr in memory that the file should be loaded. This is
|
||||||
|
ignored if you are using an ELF (unless force-raw is true).
|
||||||
|
This is required if you aren't loading an ELF.
|
||||||
|
<cpu-num> - This specifies the CPU that should be used. This is an
|
||||||
|
optional argument and will cause the CPU's PC to be set to
|
||||||
|
where the image is stored or in the case of an ELF file to
|
||||||
|
the value in the header. This option should only be used
|
||||||
|
for the boot image.
|
||||||
|
This will also cause the image to be written to the specified
|
||||||
|
CPU's address space. If not specified, the default is CPU 0.
|
||||||
|
<force-raw> - Forces the file to be treated as a raw image. This can be
|
||||||
|
used to specify the load address of ELF files.
|
||||||
|
|
||||||
|
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||||
|
to specify any values in any format supported. By default the values
|
||||||
|
will be parsed as decimal. To use hex values the user should prefix the number
|
||||||
|
with a '0x'.
|
||||||
|
|
||||||
|
An example of loading an ELF file which CPU0 will boot is shown below:
|
||||||
|
-device loader,file=./images/boot.elf,cpu-num=0
|
@@ -20,7 +20,7 @@ Also, the following notation is used to denote data flow:
|
|||||||
-> data issued by the Client
|
-> data issued by the Client
|
||||||
<- Server data response
|
<- Server data response
|
||||||
|
|
||||||
Please, refer to the QMP specification (QMP/qmp-spec.txt) for detailed
|
Please, refer to the QMP specification (docs/qmp-spec.txt) for detailed
|
||||||
information on the Server command and response formats.
|
information on the Server command and response formats.
|
||||||
|
|
||||||
NOTE: This document is temporary and will be replaced soon.
|
NOTE: This document is temporary and will be replaced soon.
|
||||||
@@ -3239,6 +3239,7 @@ Example:
|
|||||||
"microseconds": 716996 },
|
"microseconds": 716996 },
|
||||||
"event": "DEVICE_TRAY_MOVED",
|
"event": "DEVICE_TRAY_MOVED",
|
||||||
"data": { "device": "ide1-cd0",
|
"data": { "device": "ide1-cd0",
|
||||||
|
"id": "ide0-1-0",
|
||||||
"tray-open": true } }
|
"tray-open": true } }
|
||||||
|
|
||||||
<- { "return": {} }
|
<- { "return": {} }
|
||||||
@@ -3267,6 +3268,7 @@ Example:
|
|||||||
"microseconds": 272147 },
|
"microseconds": 272147 },
|
||||||
"event": "DEVICE_TRAY_MOVED",
|
"event": "DEVICE_TRAY_MOVED",
|
||||||
"data": { "device": "ide1-cd0",
|
"data": { "device": "ide1-cd0",
|
||||||
|
"id": "ide0-1-0",
|
||||||
"tray-open": false } }
|
"tray-open": false } }
|
||||||
|
|
||||||
<- { "return": {} }
|
<- { "return": {} }
|
||||||
@@ -3303,6 +3305,7 @@ Example:
|
|||||||
"microseconds": 549958 },
|
"microseconds": 549958 },
|
||||||
"event": "DEVICE_TRAY_MOVED",
|
"event": "DEVICE_TRAY_MOVED",
|
||||||
"data": { "device": "ide1-cd0",
|
"data": { "device": "ide1-cd0",
|
||||||
|
"id": "ide0-1-0",
|
||||||
"tray-open": true } }
|
"tray-open": true } }
|
||||||
|
|
||||||
<- { "return": {} }
|
<- { "return": {} }
|
||||||
|
@@ -65,7 +65,12 @@ Emitted when a disk I/O error occurs.
|
|||||||
|
|
||||||
Data:
|
Data:
|
||||||
|
|
||||||
- "device": device name (json-string)
|
- "device": device name. This is always present for compatibility
|
||||||
|
reasons, but it can be empty ("") if the image does not
|
||||||
|
have a device name associated. (json-string)
|
||||||
|
- "node-name": node name. Note that errors may be reported for the root node
|
||||||
|
that is directly attached to a guest device rather than for the
|
||||||
|
node where the error occurred. (json-string)
|
||||||
- "operation": I/O operation (json-string, "read" or "write")
|
- "operation": I/O operation (json-string, "read" or "write")
|
||||||
- "action": action that has been taken, it's one of the following (json-string):
|
- "action": action that has been taken, it's one of the following (json-string):
|
||||||
"ignore": error has been ignored
|
"ignore": error has been ignored
|
||||||
@@ -76,6 +81,7 @@ Example:
|
|||||||
|
|
||||||
{ "event": "BLOCK_IO_ERROR",
|
{ "event": "BLOCK_IO_ERROR",
|
||||||
"data": { "device": "ide0-hd1",
|
"data": { "device": "ide0-hd1",
|
||||||
|
"node-name": "#block212",
|
||||||
"operation": "write",
|
"operation": "write",
|
||||||
"action": "stop" },
|
"action": "stop" },
|
||||||
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||||
@@ -214,12 +220,16 @@ or by HMP/QMP commands.
|
|||||||
|
|
||||||
Data:
|
Data:
|
||||||
|
|
||||||
- "device": device name (json-string)
|
- "device": Block device name. This is always present for compatibility
|
||||||
|
reasons, but it can be empty ("") if the image does not have a
|
||||||
|
device name associated. (json-string)
|
||||||
|
- "id": The name or QOM path of the guest device (json-string)
|
||||||
- "tray-open": true if the tray has been opened or false if it has been closed
|
- "tray-open": true if the tray has been opened or false if it has been closed
|
||||||
(json-bool)
|
(json-bool)
|
||||||
|
|
||||||
{ "event": "DEVICE_TRAY_MOVED",
|
{ "event": "DEVICE_TRAY_MOVED",
|
||||||
"data": { "device": "ide1-cd0",
|
"data": { "device": "ide1-cd0",
|
||||||
|
"id": "/machine/unattached/device[22]",
|
||||||
"tray-open": true
|
"tray-open": true
|
||||||
},
|
},
|
||||||
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||||
|
@@ -52,7 +52,7 @@ size == 8 for the rest.
|
|||||||
|
|
||||||
0x20 (RW) : status register, bitwise OR
|
0x20 (RW) : status register, bitwise OR
|
||||||
0x01 -- computing factorial (RO)
|
0x01 -- computing factorial (RO)
|
||||||
0x80 -- raise interrupt 0x01 after finishing factorial computation
|
0x80 -- raise interrupt after finishing factorial computation
|
||||||
|
|
||||||
0x24 (RO) : interrupt status register
|
0x24 (RO) : interrupt status register
|
||||||
It contains values which raised the interrupt (see interrupt raise
|
It contains values which raised the interrupt (see interrupt raise
|
||||||
@@ -87,6 +87,11 @@ An IRQ is generated when written to the interrupt raise register. The value
|
|||||||
appears in interrupt status register when the interrupt is raised and has to
|
appears in interrupt status register when the interrupt is raised and has to
|
||||||
be written to the interrupt acknowledge register to lower it.
|
be written to the interrupt acknowledge register to lower it.
|
||||||
|
|
||||||
|
The device supports both INTx and MSI interrupt. By default, INTx is
|
||||||
|
used. Even if the driver disabled INTx and only uses MSI, it still
|
||||||
|
needs to update the acknowledge register at the end of the IRQ handler
|
||||||
|
routine.
|
||||||
|
|
||||||
DMA controller
|
DMA controller
|
||||||
--------------
|
--------------
|
||||||
One has to specify, source, destination, size, and start the transfer. One
|
One has to specify, source, destination, size, and start the transfer. One
|
||||||
|
225
docs/tcg-exclusive.promela
Normal file
225
docs/tcg-exclusive.promela
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* This model describes the implementation of exclusive sections in
|
||||||
|
* cpus-common.c (start_exclusive, end_exclusive, cpu_exec_start,
|
||||||
|
* cpu_exec_end).
|
||||||
|
*
|
||||||
|
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
|
*
|
||||||
|
* This file is in the public domain. If you really want a license,
|
||||||
|
* the WTFPL will do.
|
||||||
|
*
|
||||||
|
* To verify it:
|
||||||
|
* spin -a docs/tcg-exclusive.promela
|
||||||
|
* gcc pan.c -O2
|
||||||
|
* ./a.out -a
|
||||||
|
*
|
||||||
|
* Tunable processor macros: N_CPUS, N_EXCLUSIVE, N_CYCLES, USE_MUTEX,
|
||||||
|
* TEST_EXPENSIVE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Define the missing parameters for the model
|
||||||
|
#ifndef N_CPUS
|
||||||
|
#define N_CPUS 2
|
||||||
|
#warning defaulting to 2 CPU processes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// the expensive test is not so expensive for <= 2 CPUs
|
||||||
|
// If the mutex is used, it's also cheap (300 MB / 4 seconds) for 3 CPUs
|
||||||
|
// For 3 CPUs and the lock-free option it needs 1.5 GB of RAM
|
||||||
|
#if N_CPUS <= 2 || (N_CPUS <= 3 && defined USE_MUTEX)
|
||||||
|
#define TEST_EXPENSIVE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef N_EXCLUSIVE
|
||||||
|
# if !defined N_CYCLES || N_CYCLES <= 1 || defined TEST_EXPENSIVE
|
||||||
|
# define N_EXCLUSIVE 2
|
||||||
|
# warning defaulting to 2 concurrent exclusive sections
|
||||||
|
# else
|
||||||
|
# define N_EXCLUSIVE 1
|
||||||
|
# warning defaulting to 1 concurrent exclusive sections
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef N_CYCLES
|
||||||
|
# if N_EXCLUSIVE <= 1 || defined TEST_EXPENSIVE
|
||||||
|
# define N_CYCLES 2
|
||||||
|
# warning defaulting to 2 CPU cycles
|
||||||
|
# else
|
||||||
|
# define N_CYCLES 1
|
||||||
|
# warning defaulting to 1 CPU cycles
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// synchronization primitives. condition variables require a
|
||||||
|
// process-local "cond_t saved;" variable.
|
||||||
|
|
||||||
|
#define mutex_t byte
|
||||||
|
#define MUTEX_LOCK(m) atomic { m == 0 -> m = 1 }
|
||||||
|
#define MUTEX_UNLOCK(m) m = 0
|
||||||
|
|
||||||
|
#define cond_t int
|
||||||
|
#define COND_WAIT(c, m) { \
|
||||||
|
saved = c; \
|
||||||
|
MUTEX_UNLOCK(m); \
|
||||||
|
c != saved -> MUTEX_LOCK(m); \
|
||||||
|
}
|
||||||
|
#define COND_BROADCAST(c) c++
|
||||||
|
|
||||||
|
// this is the logic from cpus-common.c
|
||||||
|
|
||||||
|
mutex_t mutex;
|
||||||
|
cond_t exclusive_cond;
|
||||||
|
cond_t exclusive_resume;
|
||||||
|
byte pending_cpus;
|
||||||
|
|
||||||
|
byte running[N_CPUS];
|
||||||
|
byte has_waiter[N_CPUS];
|
||||||
|
|
||||||
|
#define exclusive_idle() \
|
||||||
|
do \
|
||||||
|
:: pending_cpus -> COND_WAIT(exclusive_resume, mutex); \
|
||||||
|
:: else -> break; \
|
||||||
|
od
|
||||||
|
|
||||||
|
#define start_exclusive() \
|
||||||
|
MUTEX_LOCK(mutex); \
|
||||||
|
exclusive_idle(); \
|
||||||
|
pending_cpus = 1; \
|
||||||
|
\
|
||||||
|
i = 0; \
|
||||||
|
do \
|
||||||
|
:: i < N_CPUS -> { \
|
||||||
|
if \
|
||||||
|
:: running[i] -> has_waiter[i] = 1; pending_cpus++; \
|
||||||
|
:: else -> skip; \
|
||||||
|
fi; \
|
||||||
|
i++; \
|
||||||
|
} \
|
||||||
|
:: else -> break; \
|
||||||
|
od; \
|
||||||
|
\
|
||||||
|
do \
|
||||||
|
:: pending_cpus > 1 -> COND_WAIT(exclusive_cond, mutex); \
|
||||||
|
:: else -> break; \
|
||||||
|
od; \
|
||||||
|
MUTEX_UNLOCK(mutex);
|
||||||
|
|
||||||
|
#define end_exclusive() \
|
||||||
|
MUTEX_LOCK(mutex); \
|
||||||
|
pending_cpus = 0; \
|
||||||
|
COND_BROADCAST(exclusive_resume); \
|
||||||
|
MUTEX_UNLOCK(mutex);
|
||||||
|
|
||||||
|
#ifdef USE_MUTEX
|
||||||
|
// Simple version using mutexes
|
||||||
|
#define cpu_exec_start(id) \
|
||||||
|
MUTEX_LOCK(mutex); \
|
||||||
|
exclusive_idle(); \
|
||||||
|
running[id] = 1; \
|
||||||
|
MUTEX_UNLOCK(mutex);
|
||||||
|
|
||||||
|
#define cpu_exec_end(id) \
|
||||||
|
MUTEX_LOCK(mutex); \
|
||||||
|
running[id] = 0; \
|
||||||
|
if \
|
||||||
|
:: pending_cpus -> { \
|
||||||
|
pending_cpus--; \
|
||||||
|
if \
|
||||||
|
:: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \
|
||||||
|
:: else -> skip; \
|
||||||
|
fi; \
|
||||||
|
} \
|
||||||
|
:: else -> skip; \
|
||||||
|
fi; \
|
||||||
|
MUTEX_UNLOCK(mutex);
|
||||||
|
#else
|
||||||
|
// Wait-free fast path, only needs mutex when concurrent with
|
||||||
|
// an exclusive section
|
||||||
|
#define cpu_exec_start(id) \
|
||||||
|
running[id] = 1; \
|
||||||
|
if \
|
||||||
|
:: pending_cpus -> { \
|
||||||
|
MUTEX_LOCK(mutex); \
|
||||||
|
if \
|
||||||
|
:: !has_waiter[id] -> { \
|
||||||
|
running[id] = 0; \
|
||||||
|
exclusive_idle(); \
|
||||||
|
running[id] = 1; \
|
||||||
|
} \
|
||||||
|
:: else -> skip; \
|
||||||
|
fi; \
|
||||||
|
MUTEX_UNLOCK(mutex); \
|
||||||
|
} \
|
||||||
|
:: else -> skip; \
|
||||||
|
fi;
|
||||||
|
|
||||||
|
#define cpu_exec_end(id) \
|
||||||
|
running[id] = 0; \
|
||||||
|
if \
|
||||||
|
:: pending_cpus -> { \
|
||||||
|
MUTEX_LOCK(mutex); \
|
||||||
|
if \
|
||||||
|
:: has_waiter[id] -> { \
|
||||||
|
has_waiter[id] = 0; \
|
||||||
|
pending_cpus--; \
|
||||||
|
if \
|
||||||
|
:: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \
|
||||||
|
:: else -> skip; \
|
||||||
|
fi; \
|
||||||
|
} \
|
||||||
|
:: else -> skip; \
|
||||||
|
fi; \
|
||||||
|
MUTEX_UNLOCK(mutex); \
|
||||||
|
} \
|
||||||
|
:: else -> skip; \
|
||||||
|
fi
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Promela processes
|
||||||
|
|
||||||
|
byte done_cpu;
|
||||||
|
byte in_cpu;
|
||||||
|
active[N_CPUS] proctype cpu()
|
||||||
|
{
|
||||||
|
byte id = _pid % N_CPUS;
|
||||||
|
byte cycles = 0;
|
||||||
|
cond_t saved;
|
||||||
|
|
||||||
|
do
|
||||||
|
:: cycles == N_CYCLES -> break;
|
||||||
|
:: else -> {
|
||||||
|
cycles++;
|
||||||
|
cpu_exec_start(id)
|
||||||
|
in_cpu++;
|
||||||
|
done_cpu++;
|
||||||
|
in_cpu--;
|
||||||
|
cpu_exec_end(id)
|
||||||
|
}
|
||||||
|
od;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte done_exclusive;
|
||||||
|
byte in_exclusive;
|
||||||
|
active[N_EXCLUSIVE] proctype exclusive()
|
||||||
|
{
|
||||||
|
cond_t saved;
|
||||||
|
byte i;
|
||||||
|
|
||||||
|
start_exclusive();
|
||||||
|
in_exclusive = 1;
|
||||||
|
done_exclusive++;
|
||||||
|
in_exclusive = 0;
|
||||||
|
end_exclusive();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIVENESS (done_cpu == N_CPUS * N_CYCLES && done_exclusive == N_EXCLUSIVE)
|
||||||
|
#define SAFETY !(in_exclusive && in_cpu)
|
||||||
|
|
||||||
|
never { /* ! ([] SAFETY && <> [] LIVENESS) */
|
||||||
|
do
|
||||||
|
// once the liveness property is satisfied, this is not executable
|
||||||
|
// and the never clause is not accepted
|
||||||
|
:: ! LIVENESS -> accept_liveness: skip
|
||||||
|
:: 1 -> assert(SAFETY)
|
||||||
|
od;
|
||||||
|
}
|
@@ -7,8 +7,8 @@ This document doesn't discuss QMP protocol level details, nor does it dive
|
|||||||
into the QAPI framework implementation.
|
into the QAPI framework implementation.
|
||||||
|
|
||||||
For an in-depth introduction to the QAPI framework, please refer to
|
For an in-depth introduction to the QAPI framework, please refer to
|
||||||
docs/qapi-code-gen.txt. For documentation about the QMP protocol, please
|
docs/qapi-code-gen.txt. For documentation about the QMP protocol,
|
||||||
check the files in QMP/.
|
start with docs/qmp-intro.txt.
|
||||||
|
|
||||||
== Overview ==
|
== Overview ==
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@ however it is also possible to save the state of all devices to file,
|
|||||||
without saving the RAM or the block devices of the VM.
|
without saving the RAM or the block devices of the VM.
|
||||||
|
|
||||||
This operation is called "xen-save-devices-state" (see
|
This operation is called "xen-save-devices-state" (see
|
||||||
QMP/qmp-commands.txt)
|
qmp-commands.txt)
|
||||||
|
|
||||||
|
|
||||||
The binary format used in the file is the following:
|
The binary format used in the file is the following:
|
||||||
|
45
exec.c
45
exec.c
@@ -255,7 +255,7 @@ static void phys_page_set(AddressSpaceDispatch *d,
|
|||||||
/* Compact a non leaf page entry. Simply detect that the entry has a single child,
|
/* Compact a non leaf page entry. Simply detect that the entry has a single child,
|
||||||
* and update our entry so we can skip it and go directly to the destination.
|
* and update our entry so we can skip it and go directly to the destination.
|
||||||
*/
|
*/
|
||||||
static void phys_page_compact(PhysPageEntry *lp, Node *nodes, unsigned long *compacted)
|
static void phys_page_compact(PhysPageEntry *lp, Node *nodes)
|
||||||
{
|
{
|
||||||
unsigned valid_ptr = P_L2_SIZE;
|
unsigned valid_ptr = P_L2_SIZE;
|
||||||
int valid = 0;
|
int valid = 0;
|
||||||
@@ -275,7 +275,7 @@ static void phys_page_compact(PhysPageEntry *lp, Node *nodes, unsigned long *com
|
|||||||
valid_ptr = i;
|
valid_ptr = i;
|
||||||
valid++;
|
valid++;
|
||||||
if (p[i].skip) {
|
if (p[i].skip) {
|
||||||
phys_page_compact(&p[i], nodes, compacted);
|
phys_page_compact(&p[i], nodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,10 +307,8 @@ static void phys_page_compact(PhysPageEntry *lp, Node *nodes, unsigned long *com
|
|||||||
|
|
||||||
static void phys_page_compact_all(AddressSpaceDispatch *d, int nodes_nb)
|
static void phys_page_compact_all(AddressSpaceDispatch *d, int nodes_nb)
|
||||||
{
|
{
|
||||||
DECLARE_BITMAP(compacted, nodes_nb);
|
|
||||||
|
|
||||||
if (d->phys_map.skip) {
|
if (d->phys_map.skip) {
|
||||||
phys_page_compact(&d->phys_map, d->map.nodes, compacted);
|
phys_page_compact(&d->phys_map, d->map.nodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,36 +596,11 @@ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool cpu_index_auto_assigned;
|
|
||||||
|
|
||||||
static int cpu_get_free_index(void)
|
|
||||||
{
|
|
||||||
CPUState *some_cpu;
|
|
||||||
int cpu_index = 0;
|
|
||||||
|
|
||||||
cpu_index_auto_assigned = true;
|
|
||||||
CPU_FOREACH(some_cpu) {
|
|
||||||
cpu_index++;
|
|
||||||
}
|
|
||||||
return cpu_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_exec_exit(CPUState *cpu)
|
void cpu_exec_exit(CPUState *cpu)
|
||||||
{
|
{
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
|
||||||
cpu_list_lock();
|
cpu_list_remove(cpu);
|
||||||
if (!QTAILQ_IN_USE(cpu, node)) {
|
|
||||||
/* there is nothing to undo since cpu_exec_init() hasn't been called */
|
|
||||||
cpu_list_unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
|
|
||||||
|
|
||||||
QTAILQ_REMOVE(&cpus, cpu, node);
|
|
||||||
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
|
|
||||||
cpu_list_unlock();
|
|
||||||
|
|
||||||
if (cc->vmsd != NULL) {
|
if (cc->vmsd != NULL) {
|
||||||
vmstate_unregister(NULL, cc->vmsd, cpu);
|
vmstate_unregister(NULL, cc->vmsd, cpu);
|
||||||
@@ -663,15 +636,7 @@ void cpu_exec_init(CPUState *cpu, Error **errp)
|
|||||||
object_ref(OBJECT(cpu->memory));
|
object_ref(OBJECT(cpu->memory));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cpu_list_lock();
|
cpu_list_add(cpu);
|
||||||
if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) {
|
|
||||||
cpu->cpu_index = cpu_get_free_index();
|
|
||||||
assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
|
|
||||||
} else {
|
|
||||||
assert(!cpu_index_auto_assigned);
|
|
||||||
}
|
|
||||||
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
|
|
||||||
cpu_list_unlock();
|
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
|
if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
|
||||||
|
@@ -172,20 +172,12 @@ STEXI
|
|||||||
Show the command line history.
|
Show the command line history.
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_MIPS) || \
|
|
||||||
defined(TARGET_LM32) || (defined(TARGET_SPARC) && !defined(TARGET_SPARC64))
|
|
||||||
{
|
{
|
||||||
.name = "irq",
|
.name = "irq",
|
||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show the interrupts statistics (if available)",
|
.help = "show the interrupts statistics (if available)",
|
||||||
#ifdef TARGET_SPARC
|
|
||||||
.cmd = sun4m_hmp_info_irq,
|
|
||||||
#elif defined(TARGET_LM32)
|
|
||||||
.cmd = lm32_hmp_info_irq,
|
|
||||||
#else
|
|
||||||
.cmd = hmp_info_irq,
|
.cmd = hmp_info_irq,
|
||||||
#endif
|
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -198,16 +190,9 @@ ETEXI
|
|||||||
.name = "pic",
|
.name = "pic",
|
||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show i8259 (PIC) state",
|
.help = "show PIC state",
|
||||||
#ifdef TARGET_SPARC
|
|
||||||
.cmd = sun4m_hmp_info_pic,
|
|
||||||
#elif defined(TARGET_LM32)
|
|
||||||
.cmd = lm32_hmp_info_pic,
|
|
||||||
#else
|
|
||||||
.cmd = hmp_info_pic,
|
.cmd = hmp_info_pic,
|
||||||
#endif
|
|
||||||
},
|
},
|
||||||
#endif
|
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@item info pic
|
@item info pic
|
||||||
|
66
hmp.c
66
hmp.c
@@ -36,6 +36,7 @@
|
|||||||
#include "qemu-io.h"
|
#include "qemu-io.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/intc/intc.h"
|
||||||
|
|
||||||
#ifdef CONFIG_SPICE
|
#ifdef CONFIG_SPICE
|
||||||
#include <spice/enums.h>
|
#include <spice/enums.h>
|
||||||
@@ -787,6 +788,70 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hmp_info_irq_foreach(Object *obj, void *opaque)
|
||||||
|
{
|
||||||
|
InterruptStatsProvider *intc;
|
||||||
|
InterruptStatsProviderClass *k;
|
||||||
|
Monitor *mon = opaque;
|
||||||
|
|
||||||
|
if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
|
||||||
|
intc = INTERRUPT_STATS_PROVIDER(obj);
|
||||||
|
k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
|
||||||
|
uint64_t *irq_counts;
|
||||||
|
unsigned int nb_irqs, i;
|
||||||
|
if (k->get_statistics &&
|
||||||
|
k->get_statistics(intc, &irq_counts, &nb_irqs)) {
|
||||||
|
if (nb_irqs > 0) {
|
||||||
|
monitor_printf(mon, "IRQ statistics for %s:\n",
|
||||||
|
object_get_typename(obj));
|
||||||
|
for (i = 0; i < nb_irqs; i++) {
|
||||||
|
if (irq_counts[i] > 0) {
|
||||||
|
monitor_printf(mon, "%2d: %" PRId64 "\n", i,
|
||||||
|
irq_counts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
monitor_printf(mon, "IRQ statistics not available for %s.\n",
|
||||||
|
object_get_typename(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmp_info_irq(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
object_child_foreach_recursive(object_get_root(),
|
||||||
|
hmp_info_irq_foreach, mon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hmp_info_pic_foreach(Object *obj, void *opaque)
|
||||||
|
{
|
||||||
|
InterruptStatsProvider *intc;
|
||||||
|
InterruptStatsProviderClass *k;
|
||||||
|
Monitor *mon = opaque;
|
||||||
|
|
||||||
|
if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
|
||||||
|
intc = INTERRUPT_STATS_PROVIDER(obj);
|
||||||
|
k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
|
||||||
|
if (k->print_info) {
|
||||||
|
k->print_info(intc, mon);
|
||||||
|
} else {
|
||||||
|
monitor_printf(mon, "Interrupt controller information not available for %s.\n",
|
||||||
|
object_get_typename(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmp_info_pic(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
object_child_foreach_recursive(object_get_root(),
|
||||||
|
hmp_info_pic_foreach, mon);
|
||||||
|
}
|
||||||
|
|
||||||
void hmp_info_pci(Monitor *mon, const QDict *qdict)
|
void hmp_info_pci(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
PciInfoList *info_list, *info;
|
PciInfoList *info_list, *info;
|
||||||
@@ -1909,6 +1974,7 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict)
|
|||||||
error_setg(&err, "Parsing chardev args failed");
|
error_setg(&err, "Parsing chardev args failed");
|
||||||
} else {
|
} else {
|
||||||
qemu_chr_new_from_opts(opts, NULL, &err);
|
qemu_chr_new_from_opts(opts, NULL, &err);
|
||||||
|
qemu_opts_del(opts);
|
||||||
}
|
}
|
||||||
hmp_handle_error(mon, &err);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
2
hmp.h
2
hmp.h
@@ -36,6 +36,8 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
|
|||||||
void hmp_info_vnc(Monitor *mon, const QDict *qdict);
|
void hmp_info_vnc(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_info_spice(Monitor *mon, const QDict *qdict);
|
void hmp_info_spice(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_info_balloon(Monitor *mon, const QDict *qdict);
|
void hmp_info_balloon(Monitor *mon, const QDict *qdict);
|
||||||
|
void hmp_info_irq(Monitor *mon, const QDict *qdict);
|
||||||
|
void hmp_info_pic(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_info_pci(Monitor *mon, const QDict *qdict);
|
void hmp_info_pci(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
|
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_info_tpm(Monitor *mon, const QDict *qdict);
|
void hmp_info_tpm(Monitor *mon, const QDict *qdict);
|
||||||
|
@@ -41,6 +41,7 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
V9fsState *s = &v->state;
|
V9fsState *s = &v->state;
|
||||||
V9fsPDU *pdu;
|
V9fsPDU *pdu;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
VirtQueueElement *elem;
|
||||||
|
|
||||||
while ((pdu = pdu_alloc(s))) {
|
while ((pdu = pdu_alloc(s))) {
|
||||||
struct {
|
struct {
|
||||||
@@ -48,21 +49,28 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
uint8_t id;
|
uint8_t id;
|
||||||
uint16_t tag_le;
|
uint16_t tag_le;
|
||||||
} QEMU_PACKED out;
|
} QEMU_PACKED out;
|
||||||
VirtQueueElement *elem;
|
|
||||||
|
|
||||||
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
||||||
if (!elem) {
|
if (!elem) {
|
||||||
pdu_free(pdu);
|
goto out_free_pdu;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(elem->out_num == 0 || elem->in_num == 0);
|
if (elem->in_num == 0) {
|
||||||
QEMU_BUILD_BUG_ON(sizeof out != 7);
|
virtio_error(vdev,
|
||||||
|
"The guest sent a VirtFS request without space for "
|
||||||
|
"the reply");
|
||||||
|
goto out_free_req;
|
||||||
|
}
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(out) != 7);
|
||||||
|
|
||||||
v->elems[pdu->idx] = elem;
|
v->elems[pdu->idx] = elem;
|
||||||
len = iov_to_buf(elem->out_sg, elem->out_num, 0,
|
len = iov_to_buf(elem->out_sg, elem->out_num, 0,
|
||||||
&out, sizeof out);
|
&out, sizeof(out));
|
||||||
BUG_ON(len != sizeof out);
|
if (len != sizeof(out)) {
|
||||||
|
virtio_error(vdev, "The guest sent a malformed VirtFS request: "
|
||||||
|
"header size is %zd, should be 7", len);
|
||||||
|
goto out_free_req;
|
||||||
|
}
|
||||||
|
|
||||||
pdu->size = le32_to_cpu(out.size_le);
|
pdu->size = le32_to_cpu(out.size_le);
|
||||||
|
|
||||||
@@ -72,6 +80,14 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
qemu_co_queue_init(&pdu->complete);
|
qemu_co_queue_init(&pdu->complete);
|
||||||
pdu_submit(pdu);
|
pdu_submit(pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
out_free_req:
|
||||||
|
virtqueue_detach_element(vq, elem, 0);
|
||||||
|
g_free(elem);
|
||||||
|
out_free_pdu:
|
||||||
|
pdu_free(pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features,
|
static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features,
|
||||||
@@ -97,11 +113,6 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
|
|||||||
g_free(cfg);
|
g_free(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_9p_load(QEMUFile *f, void *opaque, size_t size)
|
|
||||||
{
|
|
||||||
return virtio_load(VIRTIO_DEVICE(opaque), f, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
|
static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||||
@@ -168,7 +179,15 @@ void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
|||||||
|
|
||||||
/* virtio-9p device */
|
/* virtio-9p device */
|
||||||
|
|
||||||
VMSTATE_VIRTIO_DEVICE(9p, 1, virtio_9p_load, virtio_vmstate_save);
|
static const VMStateDescription vmstate_virtio_9p = {
|
||||||
|
.name = "virtio-9p",
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_VIRTIO_DEVICE,
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static Property virtio_9p_properties[] = {
|
static Property virtio_9p_properties[] = {
|
||||||
DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag),
|
DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag),
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
|
devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
|
||||||
devices-dirs-$(CONFIG_ACPI) += acpi/
|
devices-dirs-$(CONFIG_ACPI) += acpi/
|
||||||
|
devices-dirs-$(CONFIG_SOFTMMU) += adc/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += audio/
|
devices-dirs-$(CONFIG_SOFTMMU) += audio/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += block/
|
devices-dirs-$(CONFIG_SOFTMMU) += block/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += bt/
|
devices-dirs-$(CONFIG_SOFTMMU) += bt/
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qapi-event.h"
|
#include "qapi-event.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#include "sysemu/numa.h"
|
||||||
|
|
||||||
#define ACPI_CPU_HOTPLUG_REG_LEN 12
|
#define ACPI_CPU_HOTPLUG_REG_LEN 12
|
||||||
#define ACPI_CPU_SELECTOR_OFFSET_WR 0
|
#define ACPI_CPU_SELECTOR_OFFSET_WR 0
|
||||||
@@ -503,6 +504,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
|||||||
|
|
||||||
/* build Processor object for each processor */
|
/* build Processor object for each processor */
|
||||||
for (i = 0; i < arch_ids->len; i++) {
|
for (i = 0; i < arch_ids->len; i++) {
|
||||||
|
int j;
|
||||||
Aml *dev;
|
Aml *dev;
|
||||||
Aml *uid = aml_int(i);
|
Aml *uid = aml_int(i);
|
||||||
GArray *madt_buf = g_array_new(0, 1, 1);
|
GArray *madt_buf = g_array_new(0, 1, 1);
|
||||||
@@ -546,6 +548,16 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
|||||||
aml_arg(1), aml_arg(2))
|
aml_arg(1), aml_arg(2))
|
||||||
);
|
);
|
||||||
aml_append(dev, method);
|
aml_append(dev, method);
|
||||||
|
|
||||||
|
/* Linux guests discard SRAT info for non-present CPUs
|
||||||
|
* as a result _PXM is required for all CPUs which might
|
||||||
|
* be hot-plugged. For simplicity, add it for all CPUs.
|
||||||
|
*/
|
||||||
|
j = numa_get_node_for_cpu(i);
|
||||||
|
if (j < nb_numa_nodes) {
|
||||||
|
aml_append(dev, aml_name_decl("_PXM", aml_int(j)));
|
||||||
|
}
|
||||||
|
|
||||||
aml_append(cpus_dev, dev);
|
aml_append(cpus_dev, dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
hw/adc/Makefile.objs
Normal file
1
hw/adc/Makefile.objs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o
|
306
hw/adc/stm32f2xx_adc.c
Normal file
306
hw/adc/stm32f2xx_adc.c
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
* STM32F2XX ADC
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "hw/hw.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu/log.h"
|
||||||
|
#include "hw/adc/stm32f2xx_adc.h"
|
||||||
|
|
||||||
|
#ifndef STM_ADC_ERR_DEBUG
|
||||||
|
#define STM_ADC_ERR_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DB_PRINT_L(lvl, fmt, args...) do { \
|
||||||
|
if (STM_ADC_ERR_DEBUG >= lvl) { \
|
||||||
|
qemu_log("%s: " fmt, __func__, ## args); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
|
||||||
|
|
||||||
|
static void stm32f2xx_adc_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
STM32F2XXADCState *s = STM32F2XX_ADC(dev);
|
||||||
|
|
||||||
|
s->adc_sr = 0x00000000;
|
||||||
|
s->adc_cr1 = 0x00000000;
|
||||||
|
s->adc_cr2 = 0x00000000;
|
||||||
|
s->adc_smpr1 = 0x00000000;
|
||||||
|
s->adc_smpr2 = 0x00000000;
|
||||||
|
s->adc_jofr[0] = 0x00000000;
|
||||||
|
s->adc_jofr[1] = 0x00000000;
|
||||||
|
s->adc_jofr[2] = 0x00000000;
|
||||||
|
s->adc_jofr[3] = 0x00000000;
|
||||||
|
s->adc_htr = 0x00000FFF;
|
||||||
|
s->adc_ltr = 0x00000000;
|
||||||
|
s->adc_sqr1 = 0x00000000;
|
||||||
|
s->adc_sqr2 = 0x00000000;
|
||||||
|
s->adc_sqr3 = 0x00000000;
|
||||||
|
s->adc_jsqr = 0x00000000;
|
||||||
|
s->adc_jdr[0] = 0x00000000;
|
||||||
|
s->adc_jdr[1] = 0x00000000;
|
||||||
|
s->adc_jdr[2] = 0x00000000;
|
||||||
|
s->adc_jdr[3] = 0x00000000;
|
||||||
|
s->adc_dr = 0x00000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t stm32f2xx_adc_generate_value(STM32F2XXADCState *s)
|
||||||
|
{
|
||||||
|
/* Attempts to fake some ADC values */
|
||||||
|
s->adc_dr = s->adc_dr + 7;
|
||||||
|
|
||||||
|
switch ((s->adc_cr1 & ADC_CR1_RES) >> 24) {
|
||||||
|
case 0:
|
||||||
|
/* 12-bit */
|
||||||
|
s->adc_dr &= 0xFFF;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* 10-bit */
|
||||||
|
s->adc_dr &= 0x3FF;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* 8-bit */
|
||||||
|
s->adc_dr &= 0xFF;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* 6-bit */
|
||||||
|
s->adc_dr &= 0x3F;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->adc_cr2 & ADC_CR2_ALIGN) {
|
||||||
|
return (s->adc_dr << 1) & 0xFFF0;
|
||||||
|
} else {
|
||||||
|
return s->adc_dr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t stm32f2xx_adc_read(void *opaque, hwaddr addr,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
STM32F2XXADCState *s = opaque;
|
||||||
|
|
||||||
|
DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
|
||||||
|
|
||||||
|
if (addr >= ADC_COMMON_ADDRESS) {
|
||||||
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"%s: ADC Common Register Unsupported\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case ADC_SR:
|
||||||
|
return s->adc_sr;
|
||||||
|
case ADC_CR1:
|
||||||
|
return s->adc_cr1;
|
||||||
|
case ADC_CR2:
|
||||||
|
return s->adc_cr2 & 0xFFFFFFF;
|
||||||
|
case ADC_SMPR1:
|
||||||
|
return s->adc_smpr1;
|
||||||
|
case ADC_SMPR2:
|
||||||
|
return s->adc_smpr2;
|
||||||
|
case ADC_JOFR1:
|
||||||
|
case ADC_JOFR2:
|
||||||
|
case ADC_JOFR3:
|
||||||
|
case ADC_JOFR4:
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||||
|
"Injection ADC is not implemented, the registers are " \
|
||||||
|
"included for compatibility\n", __func__);
|
||||||
|
return s->adc_jofr[(addr - ADC_JOFR1) / 4];
|
||||||
|
case ADC_HTR:
|
||||||
|
return s->adc_htr;
|
||||||
|
case ADC_LTR:
|
||||||
|
return s->adc_ltr;
|
||||||
|
case ADC_SQR1:
|
||||||
|
return s->adc_sqr1;
|
||||||
|
case ADC_SQR2:
|
||||||
|
return s->adc_sqr2;
|
||||||
|
case ADC_SQR3:
|
||||||
|
return s->adc_sqr3;
|
||||||
|
case ADC_JSQR:
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||||
|
"Injection ADC is not implemented, the registers are " \
|
||||||
|
"included for compatibility\n", __func__);
|
||||||
|
return s->adc_jsqr;
|
||||||
|
case ADC_JDR1:
|
||||||
|
case ADC_JDR2:
|
||||||
|
case ADC_JDR3:
|
||||||
|
case ADC_JDR4:
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||||
|
"Injection ADC is not implemented, the registers are " \
|
||||||
|
"included for compatibility\n", __func__);
|
||||||
|
return s->adc_jdr[(addr - ADC_JDR1) / 4] -
|
||||||
|
s->adc_jofr[(addr - ADC_JDR1) / 4];
|
||||||
|
case ADC_DR:
|
||||||
|
if ((s->adc_cr2 & ADC_CR2_ADON) && (s->adc_cr2 & ADC_CR2_SWSTART)) {
|
||||||
|
s->adc_cr2 ^= ADC_CR2_SWSTART;
|
||||||
|
return stm32f2xx_adc_generate_value(s);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stm32f2xx_adc_write(void *opaque, hwaddr addr,
|
||||||
|
uint64_t val64, unsigned int size)
|
||||||
|
{
|
||||||
|
STM32F2XXADCState *s = opaque;
|
||||||
|
uint32_t value = (uint32_t) val64;
|
||||||
|
|
||||||
|
DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n",
|
||||||
|
addr, value);
|
||||||
|
|
||||||
|
if (addr >= 0x100) {
|
||||||
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"%s: ADC Common Register Unsupported\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case ADC_SR:
|
||||||
|
s->adc_sr &= (value & 0x3F);
|
||||||
|
break;
|
||||||
|
case ADC_CR1:
|
||||||
|
s->adc_cr1 = value;
|
||||||
|
break;
|
||||||
|
case ADC_CR2:
|
||||||
|
s->adc_cr2 = value;
|
||||||
|
break;
|
||||||
|
case ADC_SMPR1:
|
||||||
|
s->adc_smpr1 = value;
|
||||||
|
break;
|
||||||
|
case ADC_SMPR2:
|
||||||
|
s->adc_smpr2 = value;
|
||||||
|
break;
|
||||||
|
case ADC_JOFR1:
|
||||||
|
case ADC_JOFR2:
|
||||||
|
case ADC_JOFR3:
|
||||||
|
case ADC_JOFR4:
|
||||||
|
s->adc_jofr[(addr - ADC_JOFR1) / 4] = (value & 0xFFF);
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||||
|
"Injection ADC is not implemented, the registers are " \
|
||||||
|
"included for compatibility\n", __func__);
|
||||||
|
break;
|
||||||
|
case ADC_HTR:
|
||||||
|
s->adc_htr = value;
|
||||||
|
break;
|
||||||
|
case ADC_LTR:
|
||||||
|
s->adc_ltr = value;
|
||||||
|
break;
|
||||||
|
case ADC_SQR1:
|
||||||
|
s->adc_sqr1 = value;
|
||||||
|
break;
|
||||||
|
case ADC_SQR2:
|
||||||
|
s->adc_sqr2 = value;
|
||||||
|
break;
|
||||||
|
case ADC_SQR3:
|
||||||
|
s->adc_sqr3 = value;
|
||||||
|
break;
|
||||||
|
case ADC_JSQR:
|
||||||
|
s->adc_jsqr = value;
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||||
|
"Injection ADC is not implemented, the registers are " \
|
||||||
|
"included for compatibility\n", __func__);
|
||||||
|
break;
|
||||||
|
case ADC_JDR1:
|
||||||
|
case ADC_JDR2:
|
||||||
|
case ADC_JDR3:
|
||||||
|
case ADC_JDR4:
|
||||||
|
s->adc_jdr[(addr - ADC_JDR1) / 4] = value;
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||||
|
"Injection ADC is not implemented, the registers are " \
|
||||||
|
"included for compatibility\n", __func__);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps stm32f2xx_adc_ops = {
|
||||||
|
.read = stm32f2xx_adc_read,
|
||||||
|
.write = stm32f2xx_adc_write,
|
||||||
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_stm32f2xx_adc = {
|
||||||
|
.name = TYPE_STM32F2XX_ADC,
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(adc_sr, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_cr1, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_cr2, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_smpr1, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_smpr2, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32_ARRAY(adc_jofr, STM32F2XXADCState, 4),
|
||||||
|
VMSTATE_UINT32(adc_htr, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_ltr, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_sqr1, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_sqr2, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_sqr3, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32(adc_jsqr, STM32F2XXADCState),
|
||||||
|
VMSTATE_UINT32_ARRAY(adc_jdr, STM32F2XXADCState, 4),
|
||||||
|
VMSTATE_UINT32(adc_dr, STM32F2XXADCState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void stm32f2xx_adc_init(Object *obj)
|
||||||
|
{
|
||||||
|
STM32F2XXADCState *s = STM32F2XX_ADC(obj);
|
||||||
|
|
||||||
|
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
|
||||||
|
|
||||||
|
memory_region_init_io(&s->mmio, obj, &stm32f2xx_adc_ops, s,
|
||||||
|
TYPE_STM32F2XX_ADC, 0xFF);
|
||||||
|
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stm32f2xx_adc_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->reset = stm32f2xx_adc_reset;
|
||||||
|
dc->vmsd = &vmstate_stm32f2xx_adc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo stm32f2xx_adc_info = {
|
||||||
|
.name = TYPE_STM32F2XX_ADC,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(STM32F2XXADCState),
|
||||||
|
.instance_init = stm32f2xx_adc_init,
|
||||||
|
.class_init = stm32f2xx_adc_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void stm32f2xx_adc_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&stm32f2xx_adc_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(stm32f2xx_adc_register_types)
|
@@ -252,6 +252,26 @@ static void integratorcm_init(Object *obj)
|
|||||||
/* ??? What should the high bits of this value be? */
|
/* ??? What should the high bits of this value be? */
|
||||||
s->cm_auxosc = 0x0007feff;
|
s->cm_auxosc = 0x0007feff;
|
||||||
s->cm_sdram = 0x00011122;
|
s->cm_sdram = 0x00011122;
|
||||||
|
memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
|
||||||
|
s->cm_init = 0x00000112;
|
||||||
|
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
||||||
|
1000);
|
||||||
|
memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
|
||||||
|
&error_fatal);
|
||||||
|
vmstate_register_ram_global(&s->flash);
|
||||||
|
|
||||||
|
memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s,
|
||||||
|
"integratorcm", 0x00800000);
|
||||||
|
sysbus_init_mmio(dev, &s->iomem);
|
||||||
|
|
||||||
|
integratorcm_do_remap(s);
|
||||||
|
/* ??? Save/restore. */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void integratorcm_realize(DeviceState *d, Error **errp)
|
||||||
|
{
|
||||||
|
IntegratorCMState *s = INTEGRATOR_CM(d);
|
||||||
|
|
||||||
if (s->memsz >= 256) {
|
if (s->memsz >= 256) {
|
||||||
integrator_spd[31] = 64;
|
integrator_spd[31] = 64;
|
||||||
s->cm_sdram |= 0x10;
|
s->cm_sdram |= 0x10;
|
||||||
@@ -267,20 +287,6 @@ static void integratorcm_init(Object *obj)
|
|||||||
} else {
|
} else {
|
||||||
integrator_spd[31] = 2;
|
integrator_spd[31] = 2;
|
||||||
}
|
}
|
||||||
memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
|
|
||||||
s->cm_init = 0x00000112;
|
|
||||||
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
|
||||||
1000);
|
|
||||||
memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
|
|
||||||
&error_fatal);
|
|
||||||
vmstate_register_ram_global(&s->flash);
|
|
||||||
|
|
||||||
memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s,
|
|
||||||
"integratorcm", 0x00800000);
|
|
||||||
sysbus_init_mmio(dev, &s->iomem);
|
|
||||||
|
|
||||||
integratorcm_do_remap(s);
|
|
||||||
/* ??? Save/restore. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Integrator/CP hardware emulation. */
|
/* Integrator/CP hardware emulation. */
|
||||||
@@ -633,6 +639,7 @@ static void core_class_init(ObjectClass *klass, void *data)
|
|||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
dc->props = core_properties;
|
dc->props = core_properties;
|
||||||
|
dc->realize = integratorcm_realize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo core_info = {
|
static const TypeInfo core_info = {
|
||||||
|
@@ -73,8 +73,10 @@ static const struct keymap map[0xE0] = {
|
|||||||
[0x2f] = {3,3}, /* v */
|
[0x2f] = {3,3}, /* v */
|
||||||
[0x11] = {3,4}, /* w */
|
[0x11] = {3,4}, /* w */
|
||||||
[0x2d] = {3,5}, /* x */
|
[0x2d] = {3,5}, /* x */
|
||||||
|
[0x34] = {4,0}, /* . */
|
||||||
[0x15] = {4,2}, /* y */
|
[0x15] = {4,2}, /* y */
|
||||||
[0x2c] = {4,3}, /* z */
|
[0x2c] = {4,3}, /* z */
|
||||||
|
[0x35] = {4,4}, /* / */
|
||||||
[0xc7] = {5,0}, /* Home */
|
[0xc7] = {5,0}, /* Home */
|
||||||
[0x2a] = {5,1}, /* shift */
|
[0x2a] = {5,1}, /* shift */
|
||||||
/*
|
/*
|
||||||
@@ -88,7 +90,8 @@ static const struct keymap map[0xE0] = {
|
|||||||
* Matrix position {5,4} and other keys are missing here.
|
* Matrix position {5,4} and other keys are missing here.
|
||||||
* TODO: Compare with Linux code and test real hardware.
|
* TODO: Compare with Linux code and test real hardware.
|
||||||
*/
|
*/
|
||||||
[0x1c] = {5,5}, /* enter (TODO: might be wrong) */
|
[0x1c] = {5,4}, /* enter */
|
||||||
|
[0x0e] = {5,5}, /* backspace */
|
||||||
[0xc8] = {6,0}, /* up */
|
[0xc8] = {6,0}, /* up */
|
||||||
[0xd0] = {6,1}, /* down */
|
[0xd0] = {6,1}, /* down */
|
||||||
[0xcb] = {6,2}, /* left */
|
[0xcb] = {6,2}, /* left */
|
||||||
|
@@ -786,8 +786,7 @@ static void n8x0_cbus_setup(struct n800_s *s)
|
|||||||
|
|
||||||
static void n8x0_uart_setup(struct n800_s *s)
|
static void n8x0_uart_setup(struct n800_s *s)
|
||||||
{
|
{
|
||||||
CharDriverState *radio = uart_hci_init(
|
CharDriverState *radio = uart_hci_init();
|
||||||
qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO));
|
|
||||||
|
|
||||||
qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO,
|
qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO,
|
||||||
csrhci_pins_get(radio)[csrhci_pin_reset]);
|
csrhci_pins_get(radio)[csrhci_pin_reset]);
|
||||||
|
@@ -34,9 +34,15 @@ static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
|
|||||||
0x40000800, 0x40000C00 };
|
0x40000800, 0x40000C00 };
|
||||||
static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
|
static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
|
||||||
0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
|
0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
|
||||||
|
static const uint32_t adc_addr[STM_NUM_ADCS] = { 0x40012000, 0x40012100,
|
||||||
|
0x40012200 };
|
||||||
|
static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800,
|
||||||
|
0x40003C00 };
|
||||||
|
|
||||||
static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
|
static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
|
||||||
static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
|
static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
|
||||||
|
#define ADC_IRQ 18
|
||||||
|
static const int spi_irq[STM_NUM_SPIS] = {35, 36, 51};
|
||||||
|
|
||||||
static void stm32f205_soc_initfn(Object *obj)
|
static void stm32f205_soc_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
@@ -57,13 +63,27 @@ static void stm32f205_soc_initfn(Object *obj)
|
|||||||
TYPE_STM32F2XX_TIMER);
|
TYPE_STM32F2XX_TIMER);
|
||||||
qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default());
|
qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->adc_irqs = OR_IRQ(object_new(TYPE_OR_IRQ));
|
||||||
|
|
||||||
|
for (i = 0; i < STM_NUM_ADCS; i++) {
|
||||||
|
object_initialize(&s->adc[i], sizeof(s->adc[i]),
|
||||||
|
TYPE_STM32F2XX_ADC);
|
||||||
|
qdev_set_parent_bus(DEVICE(&s->adc[i]), sysbus_get_default());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < STM_NUM_SPIS; i++) {
|
||||||
|
object_initialize(&s->spi[i], sizeof(s->spi[i]),
|
||||||
|
TYPE_STM32F2XX_SPI);
|
||||||
|
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||||
{
|
{
|
||||||
STM32F205State *s = STM32F205_SOC(dev_soc);
|
STM32F205State *s = STM32F205_SOC(dev_soc);
|
||||||
DeviceState *syscfgdev, *usartdev, *timerdev, *nvic;
|
DeviceState *dev, *nvic;
|
||||||
SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev;
|
SysBusDevice *busdev;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -94,44 +114,80 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||||||
s->kernel_filename, s->cpu_model);
|
s->kernel_filename, s->cpu_model);
|
||||||
|
|
||||||
/* System configuration controller */
|
/* System configuration controller */
|
||||||
syscfgdev = DEVICE(&s->syscfg);
|
dev = DEVICE(&s->syscfg);
|
||||||
object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
|
object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
syscfgbusdev = SYS_BUS_DEVICE(syscfgdev);
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
sysbus_mmio_map(syscfgbusdev, 0, 0x40013800);
|
sysbus_mmio_map(busdev, 0, 0x40013800);
|
||||||
sysbus_connect_irq(syscfgbusdev, 0, qdev_get_gpio_in(nvic, 71));
|
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, 71));
|
||||||
|
|
||||||
/* Attach UART (uses USART registers) and USART controllers */
|
/* Attach UART (uses USART registers) and USART controllers */
|
||||||
for (i = 0; i < STM_NUM_USARTS; i++) {
|
for (i = 0; i < STM_NUM_USARTS; i++) {
|
||||||
usartdev = DEVICE(&(s->usart[i]));
|
dev = DEVICE(&(s->usart[i]));
|
||||||
qdev_prop_set_chr(usartdev, "chardev", i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL);
|
qdev_prop_set_chr(dev, "chardev",
|
||||||
|
i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL);
|
||||||
object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err);
|
object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
usartbusdev = SYS_BUS_DEVICE(usartdev);
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
sysbus_mmio_map(usartbusdev, 0, usart_addr[i]);
|
sysbus_mmio_map(busdev, 0, usart_addr[i]);
|
||||||
sysbus_connect_irq(usartbusdev, 0,
|
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, usart_irq[i]));
|
||||||
qdev_get_gpio_in(nvic, usart_irq[i]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Timer 2 to 5 */
|
/* Timer 2 to 5 */
|
||||||
for (i = 0; i < STM_NUM_TIMERS; i++) {
|
for (i = 0; i < STM_NUM_TIMERS; i++) {
|
||||||
timerdev = DEVICE(&(s->timer[i]));
|
dev = DEVICE(&(s->timer[i]));
|
||||||
qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000);
|
qdev_prop_set_uint64(dev, "clock-frequency", 1000000000);
|
||||||
object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
|
object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
timerbusdev = SYS_BUS_DEVICE(timerdev);
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
sysbus_mmio_map(timerbusdev, 0, timer_addr[i]);
|
sysbus_mmio_map(busdev, 0, timer_addr[i]);
|
||||||
sysbus_connect_irq(timerbusdev, 0,
|
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
|
||||||
qdev_get_gpio_in(nvic, timer_irq[i]));
|
}
|
||||||
|
|
||||||
|
/* ADC 1 to 3 */
|
||||||
|
object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS,
|
||||||
|
"num-lines", &err);
|
||||||
|
object_property_set_bool(OBJECT(s->adc_irqs), true, "realized", &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qdev_connect_gpio_out(DEVICE(s->adc_irqs), 0,
|
||||||
|
qdev_get_gpio_in(nvic, ADC_IRQ));
|
||||||
|
|
||||||
|
for (i = 0; i < STM_NUM_ADCS; i++) {
|
||||||
|
dev = DEVICE(&(s->adc[i]));
|
||||||
|
object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
|
sysbus_mmio_map(busdev, 0, adc_addr[i]);
|
||||||
|
sysbus_connect_irq(busdev, 0,
|
||||||
|
qdev_get_gpio_in(DEVICE(s->adc_irqs), i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SPI 1 and 2 */
|
||||||
|
for (i = 0; i < STM_NUM_SPIS; i++) {
|
||||||
|
dev = DEVICE(&(s->spi[i]));
|
||||||
|
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
|
||||||
|
if (err != NULL) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
|
sysbus_mmio_map(busdev, 0, spi_addr[i]);
|
||||||
|
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, spi_irq[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -436,7 +436,7 @@ static const NodeCreationPair add_fdt_node_functions[] = {
|
|||||||
* are dynamically instantiable and if so call the node creation
|
* are dynamically instantiable and if so call the node creation
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
static int add_fdt_node(SysBusDevice *sbdev, void *opaque)
|
static void add_fdt_node(SysBusDevice *sbdev, void *opaque)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
@@ -445,7 +445,7 @@ static int add_fdt_node(SysBusDevice *sbdev, void *opaque)
|
|||||||
add_fdt_node_functions[i].typename)) {
|
add_fdt_node_functions[i].typename)) {
|
||||||
ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque);
|
ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque);
|
||||||
assert(!ret);
|
assert(!ret);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error_report("Device %s can not be dynamically instantiated",
|
error_report("Device %s can not be dynamically instantiated",
|
||||||
|
@@ -44,6 +44,7 @@
|
|||||||
#include "hw/pci/pcie_host.h"
|
#include "hw/pci/pcie_host.h"
|
||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
#include "sysemu/numa.h"
|
#include "sysemu/numa.h"
|
||||||
|
#include "kvm_arm.h"
|
||||||
|
|
||||||
#define ARM_SPI_BASE 32
|
#define ARM_SPI_BASE 32
|
||||||
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
|
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
|
||||||
@@ -426,11 +427,9 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
|||||||
uint32_t *cpu_node = g_malloc0(guest_info->smp_cpus * sizeof(uint32_t));
|
uint32_t *cpu_node = g_malloc0(guest_info->smp_cpus * sizeof(uint32_t));
|
||||||
|
|
||||||
for (i = 0; i < guest_info->smp_cpus; i++) {
|
for (i = 0; i < guest_info->smp_cpus; i++) {
|
||||||
for (j = 0; j < nb_numa_nodes; j++) {
|
j = numa_get_node_for_cpu(i);
|
||||||
if (test_bit(i, numa_info[j].node_cpu)) {
|
if (j < nb_numa_nodes) {
|
||||||
cpu_node[i] = j;
|
cpu_node[i] = j;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,6 +545,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (guest_info->gic_version == 3) {
|
if (guest_info->gic_version == 3) {
|
||||||
|
AcpiMadtGenericTranslator *gic_its;
|
||||||
AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
|
AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
|
||||||
sizeof *gicr);
|
sizeof *gicr);
|
||||||
|
|
||||||
@@ -553,6 +553,16 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
|||||||
gicr->length = sizeof(*gicr);
|
gicr->length = sizeof(*gicr);
|
||||||
gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base);
|
gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base);
|
||||||
gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size);
|
gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size);
|
||||||
|
|
||||||
|
if (!its_class_name()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gic_its = acpi_data_push(table_data, sizeof *gic_its);
|
||||||
|
gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR;
|
||||||
|
gic_its->length = sizeof(*gic_its);
|
||||||
|
gic_its->translation_id = 0;
|
||||||
|
gic_its->base_address = cpu_to_le64(memmap[VIRT_GIC_ITS].base);
|
||||||
} else {
|
} else {
|
||||||
gic_msi = acpi_data_push(table_data, sizeof *gic_msi);
|
gic_msi = acpi_data_push(table_data, sizeof *gic_msi);
|
||||||
gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME;
|
gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME;
|
||||||
|
@@ -76,7 +76,7 @@ typedef struct VirtBoardInfo {
|
|||||||
int fdt_size;
|
int fdt_size;
|
||||||
uint32_t clock_phandle;
|
uint32_t clock_phandle;
|
||||||
uint32_t gic_phandle;
|
uint32_t gic_phandle;
|
||||||
uint32_t v2m_phandle;
|
uint32_t msi_phandle;
|
||||||
bool using_psci;
|
bool using_psci;
|
||||||
} VirtBoardInfo;
|
} VirtBoardInfo;
|
||||||
|
|
||||||
@@ -413,19 +413,31 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
|||||||
armcpu->mp_affinity);
|
armcpu->mp_affinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < nb_numa_nodes; i++) {
|
i = numa_get_node_for_cpu(cpu);
|
||||||
if (test_bit(cpu, numa_info[i].node_cpu)) {
|
if (i < nb_numa_nodes) {
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "numa-node-id", i);
|
qemu_fdt_setprop_cell(vbi->fdt, nodename, "numa-node-id", i);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fdt_add_its_gic_node(VirtBoardInfo *vbi)
|
||||||
|
{
|
||||||
|
vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
||||||
|
qemu_fdt_add_subnode(vbi->fdt, "/intc/its");
|
||||||
|
qemu_fdt_setprop_string(vbi->fdt, "/intc/its", "compatible",
|
||||||
|
"arm,gic-v3-its");
|
||||||
|
qemu_fdt_setprop(vbi->fdt, "/intc/its", "msi-controller", NULL, 0);
|
||||||
|
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/its", "reg",
|
||||||
|
2, vbi->memmap[VIRT_GIC_ITS].base,
|
||||||
|
2, vbi->memmap[VIRT_GIC_ITS].size);
|
||||||
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc/its", "phandle", vbi->msi_phandle);
|
||||||
|
}
|
||||||
|
|
||||||
static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
|
static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
|
||||||
{
|
{
|
||||||
vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
||||||
qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m");
|
qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m");
|
||||||
qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible",
|
qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible",
|
||||||
"arm,gic-v2m-frame");
|
"arm,gic-v2m-frame");
|
||||||
@@ -433,7 +445,7 @@ static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
|
|||||||
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg",
|
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg",
|
||||||
2, vbi->memmap[VIRT_GIC_V2M].base,
|
2, vbi->memmap[VIRT_GIC_V2M].base,
|
||||||
2, vbi->memmap[VIRT_GIC_V2M].size);
|
2, vbi->memmap[VIRT_GIC_V2M].size);
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->msi_phandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdt_add_gic_node(VirtBoardInfo *vbi, int type)
|
static void fdt_add_gic_node(VirtBoardInfo *vbi, int type)
|
||||||
@@ -500,6 +512,26 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_its(VirtBoardInfo *vbi, DeviceState *gicdev)
|
||||||
|
{
|
||||||
|
const char *itsclass = its_class_name();
|
||||||
|
DeviceState *dev;
|
||||||
|
|
||||||
|
if (!itsclass) {
|
||||||
|
/* Do nothing if not supported */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = qdev_create(NULL, itsclass);
|
||||||
|
|
||||||
|
object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3",
|
||||||
|
&error_abort);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_ITS].base);
|
||||||
|
|
||||||
|
fdt_add_its_gic_node(vbi);
|
||||||
|
}
|
||||||
|
|
||||||
static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
|
static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -583,7 +615,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure)
|
|||||||
|
|
||||||
fdt_add_gic_node(vbi, type);
|
fdt_add_gic_node(vbi, type);
|
||||||
|
|
||||||
if (type == 2) {
|
if (type == 3) {
|
||||||
|
create_its(vbi, gicdev);
|
||||||
|
} else {
|
||||||
create_v2m(vbi, pic);
|
create_v2m(vbi, pic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1025,9 +1059,9 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
|
|||||||
nr_pcie_buses - 1);
|
nr_pcie_buses - 1);
|
||||||
qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0);
|
qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0);
|
||||||
|
|
||||||
if (vbi->v2m_phandle) {
|
if (vbi->msi_phandle) {
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
|
||||||
vbi->v2m_phandle);
|
vbi->msi_phandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||||
@@ -1479,7 +1513,7 @@ static void machvirt_machine_init(void)
|
|||||||
}
|
}
|
||||||
type_init(machvirt_machine_init);
|
type_init(machvirt_machine_init);
|
||||||
|
|
||||||
static void virt_2_7_instance_init(Object *obj)
|
static void virt_2_8_instance_init(Object *obj)
|
||||||
{
|
{
|
||||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||||
|
|
||||||
@@ -1512,10 +1546,25 @@ static void virt_2_7_instance_init(Object *obj)
|
|||||||
"Valid values are 2, 3 and host", NULL);
|
"Valid values are 2, 3 and host", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virt_machine_2_7_options(MachineClass *mc)
|
static void virt_machine_2_8_options(MachineClass *mc)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
DEFINE_VIRT_MACHINE_AS_LATEST(2, 7)
|
DEFINE_VIRT_MACHINE_AS_LATEST(2, 8)
|
||||||
|
|
||||||
|
#define VIRT_COMPAT_2_7 \
|
||||||
|
HW_COMPAT_2_7
|
||||||
|
|
||||||
|
static void virt_2_7_instance_init(Object *obj)
|
||||||
|
{
|
||||||
|
virt_2_8_instance_init(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virt_machine_2_7_options(MachineClass *mc)
|
||||||
|
{
|
||||||
|
virt_machine_2_8_options(mc);
|
||||||
|
SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7);
|
||||||
|
}
|
||||||
|
DEFINE_VIRT_MACHINE(2, 7)
|
||||||
|
|
||||||
#define VIRT_COMPAT_2_6 \
|
#define VIRT_COMPAT_2_6 \
|
||||||
HW_COMPAT_2_6
|
HW_COMPAT_2_6
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
#include "hw/virtio/virtio-access.h"
|
#include "hw/virtio/virtio-access.h"
|
||||||
|
|
||||||
void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
|
static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
|
||||||
VirtIOBlockReq *req)
|
VirtIOBlockReq *req)
|
||||||
{
|
{
|
||||||
req->dev = s;
|
req->dev = s;
|
||||||
@@ -40,7 +40,7 @@ void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
|
|||||||
req->mr_next = NULL;
|
req->mr_next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_blk_free_request(VirtIOBlockReq *req)
|
static void virtio_blk_free_request(VirtIOBlockReq *req)
|
||||||
{
|
{
|
||||||
if (req) {
|
if (req) {
|
||||||
g_free(req);
|
g_free(req);
|
||||||
@@ -381,7 +381,7 @@ static int multireq_compare(const void *a, const void *b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb)
|
static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb)
|
||||||
{
|
{
|
||||||
int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0;
|
int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0;
|
||||||
uint32_t max_transfer;
|
uint32_t max_transfer;
|
||||||
@@ -468,30 +468,32 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||||
{
|
{
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
struct iovec *in_iov = req->elem.in_sg;
|
struct iovec *in_iov = req->elem.in_sg;
|
||||||
struct iovec *iov = req->elem.out_sg;
|
struct iovec *iov = req->elem.out_sg;
|
||||||
unsigned in_num = req->elem.in_num;
|
unsigned in_num = req->elem.in_num;
|
||||||
unsigned out_num = req->elem.out_num;
|
unsigned out_num = req->elem.out_num;
|
||||||
|
VirtIOBlock *s = req->dev;
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||||
|
|
||||||
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
||||||
error_report("virtio-blk missing headers");
|
virtio_error(vdev, "virtio-blk missing headers");
|
||||||
exit(1);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(iov_to_buf(iov, out_num, 0, &req->out,
|
if (unlikely(iov_to_buf(iov, out_num, 0, &req->out,
|
||||||
sizeof(req->out)) != sizeof(req->out))) {
|
sizeof(req->out)) != sizeof(req->out))) {
|
||||||
error_report("virtio-blk request outhdr too short");
|
virtio_error(vdev, "virtio-blk request outhdr too short");
|
||||||
exit(1);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
iov_discard_front(&iov, &out_num, sizeof(req->out));
|
iov_discard_front(&iov, &out_num, sizeof(req->out));
|
||||||
|
|
||||||
if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
|
if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
|
||||||
error_report("virtio-blk request inhdr too short");
|
virtio_error(vdev, "virtio-blk request inhdr too short");
|
||||||
exit(1);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We always touch the last byte, so just see how big in_iov is. */
|
/* We always touch the last byte, so just see how big in_iov is. */
|
||||||
@@ -529,7 +531,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
|||||||
block_acct_invalid(blk_get_stats(req->dev->blk),
|
block_acct_invalid(blk_get_stats(req->dev->blk),
|
||||||
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
||||||
virtio_blk_free_request(req);
|
virtio_blk_free_request(req);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
block_acct_start(blk_get_stats(req->dev->blk),
|
block_acct_start(blk_get_stats(req->dev->blk),
|
||||||
@@ -576,6 +578,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
|||||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
||||||
virtio_blk_free_request(req);
|
virtio_blk_free_request(req);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
|
void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
|
||||||
@@ -586,7 +589,11 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
|
|||||||
blk_io_plug(s->blk);
|
blk_io_plug(s->blk);
|
||||||
|
|
||||||
while ((req = virtio_blk_get_request(s, vq))) {
|
while ((req = virtio_blk_get_request(s, vq))) {
|
||||||
virtio_blk_handle_request(req, &mrb);
|
if (virtio_blk_handle_request(req, &mrb)) {
|
||||||
|
virtqueue_detach_element(req->vq, &req->elem, 0);
|
||||||
|
virtio_blk_free_request(req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mrb.num_reqs) {
|
if (mrb.num_reqs) {
|
||||||
@@ -625,7 +632,18 @@ static void virtio_blk_dma_restart_bh(void *opaque)
|
|||||||
|
|
||||||
while (req) {
|
while (req) {
|
||||||
VirtIOBlockReq *next = req->next;
|
VirtIOBlockReq *next = req->next;
|
||||||
virtio_blk_handle_request(req, &mrb);
|
if (virtio_blk_handle_request(req, &mrb)) {
|
||||||
|
/* Device is now broken and won't do any processing until it gets
|
||||||
|
* reset. Already queued requests will be lost: let's purge them.
|
||||||
|
*/
|
||||||
|
while (req) {
|
||||||
|
next = req->next;
|
||||||
|
virtqueue_detach_element(req->vq, &req->elem, 0);
|
||||||
|
virtio_blk_free_request(req);
|
||||||
|
req = next;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
req = next;
|
req = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,6 +683,7 @@ static void virtio_blk_reset(VirtIODevice *vdev)
|
|||||||
while (s->rq) {
|
while (s->rq) {
|
||||||
req = s->rq;
|
req = s->rq;
|
||||||
s->rq = req->next;
|
s->rq = req->next;
|
||||||
|
virtqueue_detach_element(req->vq, &req->elem, 0);
|
||||||
virtio_blk_free_request(req);
|
virtio_blk_free_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,13 +822,6 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_blk_save(QEMUFile *f, void *opaque, size_t size)
|
|
||||||
{
|
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
|
|
||||||
|
|
||||||
virtio_save(vdev, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
|
static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
|
||||||
{
|
{
|
||||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||||
@@ -828,14 +840,6 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
|
|||||||
qemu_put_sbyte(f, 0);
|
qemu_put_sbyte(f, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_blk_load(QEMUFile *f, void *opaque, size_t size)
|
|
||||||
{
|
|
||||||
VirtIOBlock *s = opaque;
|
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
|
||||||
|
|
||||||
return virtio_load(vdev, f, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
|
static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||||
int version_id)
|
int version_id)
|
||||||
{
|
{
|
||||||
@@ -956,7 +960,15 @@ static void virtio_blk_instance_init(Object *obj)
|
|||||||
DEVICE(obj), NULL);
|
DEVICE(obj), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMSTATE_VIRTIO_DEVICE(blk, 2, virtio_blk_load, virtio_blk_save);
|
static const VMStateDescription vmstate_virtio_blk = {
|
||||||
|
.name = "virtio-blk",
|
||||||
|
.minimum_version_id = 2,
|
||||||
|
.version_id = 2,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_VIRTIO_DEVICE,
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static Property virtio_blk_properties[] = {
|
static Property virtio_blk_properties[] = {
|
||||||
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf),
|
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf),
|
||||||
|
@@ -119,6 +119,9 @@ struct XenBlkDev {
|
|||||||
unsigned int persistent_gnt_count;
|
unsigned int persistent_gnt_count;
|
||||||
unsigned int max_grants;
|
unsigned int max_grants;
|
||||||
|
|
||||||
|
/* Grant copy */
|
||||||
|
gboolean feature_grant_copy;
|
||||||
|
|
||||||
/* qemu block driver */
|
/* qemu block driver */
|
||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
@@ -489,6 +492,106 @@ static int ioreq_map(struct ioreq *ioreq)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 480
|
||||||
|
|
||||||
|
static void ioreq_free_copy_buffers(struct ioreq *ioreq)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ioreq->v.niov; i++) {
|
||||||
|
ioreq->page[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_vfree(ioreq->pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioreq_init_copy_buffers(struct ioreq *ioreq)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (ioreq->v.niov == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ioreq->pages = qemu_memalign(XC_PAGE_SIZE, ioreq->v.niov * XC_PAGE_SIZE);
|
||||||
|
|
||||||
|
for (i = 0; i < ioreq->v.niov; i++) {
|
||||||
|
ioreq->page[i] = ioreq->pages + i * XC_PAGE_SIZE;
|
||||||
|
ioreq->v.iov[i].iov_base = ioreq->page[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioreq_grant_copy(struct ioreq *ioreq)
|
||||||
|
{
|
||||||
|
xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev;
|
||||||
|
xengnttab_grant_copy_segment_t segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||||
|
int i, count, rc;
|
||||||
|
int64_t file_blk = ioreq->blkdev->file_blk;
|
||||||
|
|
||||||
|
if (ioreq->v.niov == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = ioreq->v.niov;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (ioreq->req.operation == BLKIF_OP_READ) {
|
||||||
|
segs[i].flags = GNTCOPY_dest_gref;
|
||||||
|
segs[i].dest.foreign.ref = ioreq->refs[i];
|
||||||
|
segs[i].dest.foreign.domid = ioreq->domids[i];
|
||||||
|
segs[i].dest.foreign.offset = ioreq->req.seg[i].first_sect * file_blk;
|
||||||
|
segs[i].source.virt = ioreq->v.iov[i].iov_base;
|
||||||
|
} else {
|
||||||
|
segs[i].flags = GNTCOPY_source_gref;
|
||||||
|
segs[i].source.foreign.ref = ioreq->refs[i];
|
||||||
|
segs[i].source.foreign.domid = ioreq->domids[i];
|
||||||
|
segs[i].source.foreign.offset = ioreq->req.seg[i].first_sect * file_blk;
|
||||||
|
segs[i].dest.virt = ioreq->v.iov[i].iov_base;
|
||||||
|
}
|
||||||
|
segs[i].len = (ioreq->req.seg[i].last_sect
|
||||||
|
- ioreq->req.seg[i].first_sect + 1) * file_blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = xengnttab_grant_copy(gnt, count, segs);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
xen_be_printf(&ioreq->blkdev->xendev, 0,
|
||||||
|
"failed to copy data %d\n", rc);
|
||||||
|
ioreq->aio_errors++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (segs[i].status != GNTST_okay) {
|
||||||
|
xen_be_printf(&ioreq->blkdev->xendev, 3,
|
||||||
|
"failed to copy data %d for gref %d, domid %d\n",
|
||||||
|
segs[i].status, ioreq->refs[i], ioreq->domids[i]);
|
||||||
|
ioreq->aio_errors++;
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void ioreq_free_copy_buffers(struct ioreq *ioreq)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioreq_init_copy_buffers(struct ioreq *ioreq)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioreq_grant_copy(struct ioreq *ioreq)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
|
static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
|
||||||
|
|
||||||
static void qemu_aio_complete(void *opaque, int ret)
|
static void qemu_aio_complete(void *opaque, int ret)
|
||||||
@@ -511,8 +614,31 @@ static void qemu_aio_complete(void *opaque, int ret)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ioreq->blkdev->feature_grant_copy) {
|
||||||
|
switch (ioreq->req.operation) {
|
||||||
|
case BLKIF_OP_READ:
|
||||||
|
/* in case of failure ioreq->aio_errors is increased */
|
||||||
|
if (ret == 0) {
|
||||||
|
ioreq_grant_copy(ioreq);
|
||||||
|
}
|
||||||
|
ioreq_free_copy_buffers(ioreq);
|
||||||
|
break;
|
||||||
|
case BLKIF_OP_WRITE:
|
||||||
|
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||||
|
if (!ioreq->req.nr_segments) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ioreq_free_copy_buffers(ioreq);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
||||||
|
if (!ioreq->blkdev->feature_grant_copy) {
|
||||||
ioreq_unmap(ioreq);
|
ioreq_unmap(ioreq);
|
||||||
|
}
|
||||||
ioreq_finish(ioreq);
|
ioreq_finish(ioreq);
|
||||||
switch (ioreq->req.operation) {
|
switch (ioreq->req.operation) {
|
||||||
case BLKIF_OP_WRITE:
|
case BLKIF_OP_WRITE:
|
||||||
@@ -538,8 +664,18 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
|||||||
{
|
{
|
||||||
struct XenBlkDev *blkdev = ioreq->blkdev;
|
struct XenBlkDev *blkdev = ioreq->blkdev;
|
||||||
|
|
||||||
if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
|
if (ioreq->blkdev->feature_grant_copy) {
|
||||||
goto err_no_map;
|
ioreq_init_copy_buffers(ioreq);
|
||||||
|
if (ioreq->req.nr_segments && (ioreq->req.operation == BLKIF_OP_WRITE ||
|
||||||
|
ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
|
||||||
|
ioreq_grant_copy(ioreq)) {
|
||||||
|
ioreq_free_copy_buffers(ioreq);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ioreq->req.nr_segments && ioreq_map(ioreq)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ioreq->aio_inflight++;
|
ioreq->aio_inflight++;
|
||||||
@@ -582,6 +718,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
/* unknown operation (shouldn't happen -- parse catches this) */
|
/* unknown operation (shouldn't happen -- parse catches this) */
|
||||||
|
if (!ioreq->blkdev->feature_grant_copy) {
|
||||||
|
ioreq_unmap(ioreq);
|
||||||
|
}
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,8 +729,6 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
ioreq_unmap(ioreq);
|
|
||||||
err_no_map:
|
|
||||||
ioreq_finish(ioreq);
|
ioreq_finish(ioreq);
|
||||||
ioreq->status = BLKIF_RSP_ERROR;
|
ioreq->status = BLKIF_RSP_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -942,7 +1079,7 @@ static int blk_connect(struct XenDevice *xendev)
|
|||||||
* so we can blk_unref() unconditionally */
|
* so we can blk_unref() unconditionally */
|
||||||
blk_ref(blkdev->blk);
|
blk_ref(blkdev->blk);
|
||||||
}
|
}
|
||||||
blk_attach_dev_nofail(blkdev->blk, blkdev);
|
blk_attach_dev_legacy(blkdev->blk, blkdev);
|
||||||
blkdev->file_size = blk_getlength(blkdev->blk);
|
blkdev->file_size = blk_getlength(blkdev->blk);
|
||||||
if (blkdev->file_size < 0) {
|
if (blkdev->file_size < 0) {
|
||||||
BlockDriverState *bs = blk_bs(blkdev->blk);
|
BlockDriverState *bs = blk_bs(blkdev->blk);
|
||||||
@@ -1034,6 +1171,12 @@ static int blk_connect(struct XenDevice *xendev)
|
|||||||
|
|
||||||
xen_be_bind_evtchn(&blkdev->xendev);
|
xen_be_bind_evtchn(&blkdev->xendev);
|
||||||
|
|
||||||
|
blkdev->feature_grant_copy =
|
||||||
|
(xengnttab_grant_copy(blkdev->xendev.gnttabdev, 0, NULL) == 0);
|
||||||
|
|
||||||
|
xen_be_printf(&blkdev->xendev, 3, "grant copy operation %s\n",
|
||||||
|
blkdev->feature_grant_copy ? "enabled" : "disabled");
|
||||||
|
|
||||||
xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
|
xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
|
||||||
"remote port %d, local port %d\n",
|
"remote port %d, local port %d\n",
|
||||||
blkdev->xendev.protocol, blkdev->ring_ref,
|
blkdev->xendev.protocol, blkdev->ring_ref,
|
||||||
|
@@ -458,7 +458,7 @@ qemu_irq *csrhci_pins_get(CharDriverState *chr)
|
|||||||
return s->pins;
|
return s->pins;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharDriverState *uart_hci_init(qemu_irq wakeup)
|
CharDriverState *uart_hci_init(void)
|
||||||
{
|
{
|
||||||
struct csrhci_s *s = (struct csrhci_s *)
|
struct csrhci_s *s = (struct csrhci_s *)
|
||||||
g_malloc0(sizeof(struct csrhci_s));
|
g_malloc0(sizeof(struct csrhci_s));
|
||||||
|
@@ -75,6 +75,19 @@ static VirtIOSerialPort *find_port_by_name(char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VirtIOSerialPort *find_first_connected_console(VirtIOSerial *vser)
|
||||||
|
{
|
||||||
|
VirtIOSerialPort *port;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH(port, &vser->ports, next) {
|
||||||
|
VirtIOSerialPortClass const *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
|
if (vsc->is_console && port->host_connected) {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static bool use_multiport(VirtIOSerial *vser)
|
static bool use_multiport(VirtIOSerial *vser)
|
||||||
{
|
{
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
|
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
|
||||||
@@ -132,6 +145,15 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
|
|||||||
virtio_notify(vdev, vq);
|
virtio_notify(vdev, vq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void discard_throttle_data(VirtIOSerialPort *port)
|
||||||
|
{
|
||||||
|
if (port->elem) {
|
||||||
|
virtqueue_detach_element(port->ovq, port->elem, 0);
|
||||||
|
g_free(port->elem);
|
||||||
|
port->elem = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
||||||
VirtIODevice *vdev)
|
VirtIODevice *vdev)
|
||||||
{
|
{
|
||||||
@@ -254,6 +276,7 @@ int virtio_serial_close(VirtIOSerialPort *port)
|
|||||||
* consume, reset the throttling flag and discard the data.
|
* consume, reset the throttling flag and discard the data.
|
||||||
*/
|
*/
|
||||||
port->throttled = false;
|
port->throttled = false;
|
||||||
|
discard_throttle_data(port);
|
||||||
discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser));
|
discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser));
|
||||||
|
|
||||||
send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0);
|
send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0);
|
||||||
@@ -528,6 +551,7 @@ static uint64_t get_features(VirtIODevice *vdev, uint64_t features,
|
|||||||
|
|
||||||
vser = VIRTIO_SERIAL(vdev);
|
vser = VIRTIO_SERIAL(vdev);
|
||||||
|
|
||||||
|
features |= vser->host_features;
|
||||||
if (vser->bus.max_nr_ports > 1) {
|
if (vser->bus.max_nr_ports > 1) {
|
||||||
virtio_add_feature(&features, VIRTIO_CONSOLE_F_MULTIPORT);
|
virtio_add_feature(&features, VIRTIO_CONSOLE_F_MULTIPORT);
|
||||||
}
|
}
|
||||||
@@ -547,6 +571,29 @@ static void get_config(VirtIODevice *vdev, uint8_t *config_data)
|
|||||||
vser->serial.max_virtserial_ports);
|
vser->serial.max_virtserial_ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Guest sent new config info */
|
||||||
|
static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
|
||||||
|
{
|
||||||
|
VirtIOSerial *vser = VIRTIO_SERIAL(vdev);
|
||||||
|
struct virtio_console_config *config =
|
||||||
|
(struct virtio_console_config *)config_data;
|
||||||
|
uint8_t emerg_wr_lo = le32_to_cpu(config->emerg_wr);
|
||||||
|
VirtIOSerialPort *port = find_first_connected_console(vser);
|
||||||
|
VirtIOSerialPortClass *vsc;
|
||||||
|
|
||||||
|
if (!config->emerg_wr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Make sure we don't misdetect an emergency write when the guest
|
||||||
|
* does a short config write after an emergency write. */
|
||||||
|
config->emerg_wr = 0;
|
||||||
|
if (!port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
|
(void)vsc->have_data(port, &emerg_wr_lo, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static void guest_reset(VirtIOSerial *vser)
|
static void guest_reset(VirtIOSerial *vser)
|
||||||
{
|
{
|
||||||
VirtIOSerialPort *port;
|
VirtIOSerialPort *port;
|
||||||
@@ -554,6 +601,9 @@ static void guest_reset(VirtIOSerial *vser)
|
|||||||
|
|
||||||
QTAILQ_FOREACH(port, &vser->ports, next) {
|
QTAILQ_FOREACH(port, &vser->ports, next) {
|
||||||
vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
|
|
||||||
|
discard_throttle_data(port);
|
||||||
|
|
||||||
if (port->guest_connected) {
|
if (port->guest_connected) {
|
||||||
port->guest_connected = false;
|
port->guest_connected = false;
|
||||||
if (vsc->set_guest_connected) {
|
if (vsc->set_guest_connected) {
|
||||||
@@ -728,12 +778,6 @@ static int fetch_active_ports_list(QEMUFile *f,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_serial_load(QEMUFile *f, void *opaque, size_t size)
|
|
||||||
{
|
|
||||||
/* The virtio device */
|
|
||||||
return virtio_load(VIRTIO_DEVICE(opaque), f, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
|
static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||||
int version_id)
|
int version_id)
|
||||||
{
|
{
|
||||||
@@ -864,6 +908,7 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id)
|
|||||||
assert(port);
|
assert(port);
|
||||||
|
|
||||||
/* Flush out any unconsumed buffers first */
|
/* Flush out any unconsumed buffers first */
|
||||||
|
discard_throttle_data(port);
|
||||||
discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser));
|
discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser));
|
||||||
|
|
||||||
send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1);
|
send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1);
|
||||||
@@ -967,6 +1012,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
|
|||||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||||
VirtIOSerial *vser = VIRTIO_SERIAL(dev);
|
VirtIOSerial *vser = VIRTIO_SERIAL(dev);
|
||||||
uint32_t i, max_supported_ports;
|
uint32_t i, max_supported_ports;
|
||||||
|
size_t config_size = sizeof(struct virtio_console_config);
|
||||||
|
|
||||||
if (!vser->serial.max_virtserial_ports) {
|
if (!vser->serial.max_virtserial_ports) {
|
||||||
error_setg(errp, "Maximum number of serial ports not specified");
|
error_setg(errp, "Maximum number of serial ports not specified");
|
||||||
@@ -981,10 +1027,12 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't support emergency write, skip it for now. */
|
if (!virtio_has_feature(vser->host_features,
|
||||||
/* TODO: cleaner fix, depending on host features. */
|
VIRTIO_CONSOLE_F_EMERG_WRITE)) {
|
||||||
|
config_size = offsetof(struct virtio_console_config, emerg_wr);
|
||||||
|
}
|
||||||
virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE,
|
virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE,
|
||||||
offsetof(struct virtio_console_config, emerg_wr));
|
config_size);
|
||||||
|
|
||||||
/* Spawn a new virtio-serial bus on which the ports will ride as devices */
|
/* Spawn a new virtio-serial bus on which the ports will ride as devices */
|
||||||
qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
|
qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
|
||||||
@@ -1075,11 +1123,21 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Note: 'console' is used for backwards compatibility */
|
/* Note: 'console' is used for backwards compatibility */
|
||||||
VMSTATE_VIRTIO_DEVICE(console, 3, virtio_serial_load, virtio_vmstate_save);
|
static const VMStateDescription vmstate_virtio_console = {
|
||||||
|
.name = "virtio-console",
|
||||||
|
.minimum_version_id = 3,
|
||||||
|
.version_id = 3,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_VIRTIO_DEVICE,
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static Property virtio_serial_properties[] = {
|
static Property virtio_serial_properties[] = {
|
||||||
DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports,
|
DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports,
|
||||||
31),
|
31),
|
||||||
|
DEFINE_PROP_BIT64("emergency-write", VirtIOSerial, host_features,
|
||||||
|
VIRTIO_CONSOLE_F_EMERG_WRITE, true),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1098,6 +1156,7 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
|
|||||||
vdc->unrealize = virtio_serial_device_unrealize;
|
vdc->unrealize = virtio_serial_device_unrealize;
|
||||||
vdc->get_features = get_features;
|
vdc->get_features = get_features;
|
||||||
vdc->get_config = get_config;
|
vdc->get_config = get_config;
|
||||||
|
vdc->set_config = set_config;
|
||||||
vdc->set_status = set_status;
|
vdc->set_status = set_status;
|
||||||
vdc->reset = vser_reset;
|
vdc->reset = vser_reset;
|
||||||
vdc->save = virtio_serial_save_device;
|
vdc->save = virtio_serial_save_device;
|
||||||
|
@@ -16,4 +16,7 @@ common-obj-$(CONFIG_SOFTMMU) += null-machine.o
|
|||||||
common-obj-$(CONFIG_SOFTMMU) += loader.o
|
common-obj-$(CONFIG_SOFTMMU) += loader.o
|
||||||
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
|
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
|
||||||
common-obj-$(CONFIG_SOFTMMU) += register.o
|
common-obj-$(CONFIG_SOFTMMU) += register.o
|
||||||
|
common-obj-$(CONFIG_SOFTMMU) += or-irq.o
|
||||||
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
|
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_SOFTMMU) += generic-loader.o
|
||||||
|
211
hw/core/generic-loader.c
Normal file
211
hw/core/generic-loader.c
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Generic Loader
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Li Guang
|
||||||
|
* Copyright (C) 2016 Xilinx Inc.
|
||||||
|
* Written by Li Guang <lig.fnst@cn.fujitsu.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internally inside QEMU this is a device. It is a strange device that
|
||||||
|
* provides no hardware interface but allows QEMU to monkey patch memory
|
||||||
|
* specified when it is created. To be able to do this it has a reset
|
||||||
|
* callback that does the memory operations.
|
||||||
|
|
||||||
|
* This device allows the user to monkey patch memory. To be able to do
|
||||||
|
* this it needs a backend to manage the datas, the same as other
|
||||||
|
* memory-related devices. In this case as the backend is so trivial we
|
||||||
|
* have merged it with the frontend instead of creating and maintaining a
|
||||||
|
* seperate backend.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qom/cpu.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "sysemu/dma.h"
|
||||||
|
#include "hw/loader.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "hw/core/generic-loader.h"
|
||||||
|
|
||||||
|
#define CPU_NONE 0xFFFFFFFF
|
||||||
|
|
||||||
|
static void generic_loader_reset(void *opaque)
|
||||||
|
{
|
||||||
|
GenericLoaderState *s = GENERIC_LOADER(opaque);
|
||||||
|
|
||||||
|
if (s->set_pc) {
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(s->cpu);
|
||||||
|
cpu_reset(s->cpu);
|
||||||
|
if (cc) {
|
||||||
|
cc->set_pc(s->cpu, s->addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->data_len) {
|
||||||
|
assert(s->data_len < sizeof(s->data));
|
||||||
|
dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generic_loader_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
GenericLoaderState *s = GENERIC_LOADER(dev);
|
||||||
|
hwaddr entry;
|
||||||
|
int big_endian;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
s->set_pc = false;
|
||||||
|
|
||||||
|
/* Perform some error checking on the user's options */
|
||||||
|
if (s->data || s->data_len || s->data_be) {
|
||||||
|
/* User is loading memory values */
|
||||||
|
if (s->file) {
|
||||||
|
error_setg(errp, "Specifying a file is not supported when loading "
|
||||||
|
"memory values");
|
||||||
|
return;
|
||||||
|
} else if (s->force_raw) {
|
||||||
|
error_setg(errp, "Specifying force-raw is not supported when "
|
||||||
|
"loading memory values");
|
||||||
|
return;
|
||||||
|
} else if (!s->data_len) {
|
||||||
|
/* We cant' check for !data here as a value of 0 is still valid. */
|
||||||
|
error_setg(errp, "Both data and data-len must be specified");
|
||||||
|
return;
|
||||||
|
} else if (s->data_len > 8) {
|
||||||
|
error_setg(errp, "data-len cannot be greater then 8 bytes");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (s->file || s->force_raw) {
|
||||||
|
/* User is loading an image */
|
||||||
|
if (s->data || s->data_len || s->data_be) {
|
||||||
|
error_setg(errp, "data can not be specified when loading an "
|
||||||
|
"image");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s->set_pc = true;
|
||||||
|
} else if (s->addr) {
|
||||||
|
/* User is setting the PC */
|
||||||
|
if (s->data || s->data_len || s->data_be) {
|
||||||
|
error_setg(errp, "data can not be specified when setting a "
|
||||||
|
"program counter");
|
||||||
|
return;
|
||||||
|
} else if (!s->cpu_num) {
|
||||||
|
error_setg(errp, "cpu_num must be specified when setting a "
|
||||||
|
"program counter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s->set_pc = true;
|
||||||
|
} else {
|
||||||
|
/* Did the user specify anything? */
|
||||||
|
error_setg(errp, "please include valid arguments");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_register_reset(generic_loader_reset, dev);
|
||||||
|
|
||||||
|
if (s->cpu_num != CPU_NONE) {
|
||||||
|
s->cpu = qemu_get_cpu(s->cpu_num);
|
||||||
|
if (!s->cpu) {
|
||||||
|
error_setg(errp, "Specified boot CPU#%d is nonexistent",
|
||||||
|
s->cpu_num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s->cpu = first_cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
|
big_endian = 1;
|
||||||
|
#else
|
||||||
|
big_endian = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (s->file) {
|
||||||
|
if (!s->force_raw) {
|
||||||
|
size = load_elf_as(s->file, NULL, NULL, &entry, NULL, NULL,
|
||||||
|
big_endian, 0, 0, 0, s->cpu->as);
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL,
|
||||||
|
s->cpu->as);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < 0 || s->force_raw) {
|
||||||
|
/* Default to the maximum size being the machine's ram size */
|
||||||
|
size = load_image_targphys_as(s->file, s->addr, ram_size,
|
||||||
|
s->cpu->as);
|
||||||
|
} else {
|
||||||
|
s->addr = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
error_setg(errp, "Cannot load specified image %s", s->file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the data endiannes */
|
||||||
|
if (s->data_be) {
|
||||||
|
s->data = cpu_to_be64(s->data);
|
||||||
|
} else {
|
||||||
|
s->data = cpu_to_le64(s->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generic_loader_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
qemu_unregister_reset(generic_loader_reset, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property generic_loader_props[] = {
|
||||||
|
DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0),
|
||||||
|
DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0),
|
||||||
|
DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0),
|
||||||
|
DEFINE_PROP_BOOL("data-be", GenericLoaderState, data_be, false),
|
||||||
|
DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE),
|
||||||
|
DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false),
|
||||||
|
DEFINE_PROP_STRING("file", GenericLoaderState, file),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void generic_loader_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
/* The reset function is not registered here and is instead registered in
|
||||||
|
* the realize function to allow this device to be added via the device_add
|
||||||
|
* command in the QEMU monitor.
|
||||||
|
* TODO: Improve the device_add functionality to allow resets to be
|
||||||
|
* connected
|
||||||
|
*/
|
||||||
|
dc->realize = generic_loader_realize;
|
||||||
|
dc->unrealize = generic_loader_unrealize;
|
||||||
|
dc->props = generic_loader_props;
|
||||||
|
dc->desc = "Generic Loader";
|
||||||
|
}
|
||||||
|
|
||||||
|
static TypeInfo generic_loader_info = {
|
||||||
|
.name = TYPE_GENERIC_LOADER,
|
||||||
|
.parent = TYPE_DEVICE,
|
||||||
|
.instance_size = sizeof(GenericLoaderState),
|
||||||
|
.class_init = generic_loader_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void generic_loader_register_type(void)
|
||||||
|
{
|
||||||
|
type_register_static(&generic_loader_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(generic_loader_register_type)
|
@@ -332,7 +332,7 @@ static bool machine_get_enforce_config_section(Object *obj, Error **errp)
|
|||||||
return ms->enforce_config_section;
|
return ms->enforce_config_section;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
static void error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
||||||
{
|
{
|
||||||
error_report("Option '-device %s' cannot be handled by this machine",
|
error_report("Option '-device %s' cannot be handled by this machine",
|
||||||
object_class_get_name(object_get_class(OBJECT(sbdev))));
|
object_class_get_name(object_get_class(OBJECT(sbdev))));
|
||||||
|
107
hw/core/or-irq.c
Normal file
107
hw/core/or-irq.c
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* QEMU IRQ/GPIO common code.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Alistair Francis <alistair@alistair23.me>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/or-irq.h"
|
||||||
|
|
||||||
|
static void or_irq_handler(void *opaque, int n, int level)
|
||||||
|
{
|
||||||
|
qemu_or_irq *s = OR_IRQ(opaque);
|
||||||
|
int or_level = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
s->levels[n] = level;
|
||||||
|
|
||||||
|
for (i = 0; i < s->num_lines; i++) {
|
||||||
|
or_level |= s->levels[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_set_irq(s->out_irq, or_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void or_irq_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
qemu_or_irq *s = OR_IRQ(dev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_OR_LINES; i++) {
|
||||||
|
s->levels[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void or_irq_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
qemu_or_irq *s = OR_IRQ(dev);
|
||||||
|
|
||||||
|
assert(s->num_lines < MAX_OR_LINES);
|
||||||
|
|
||||||
|
qdev_init_gpio_in(dev, or_irq_handler, s->num_lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void or_irq_init(Object *obj)
|
||||||
|
{
|
||||||
|
qemu_or_irq *s = OR_IRQ(obj);
|
||||||
|
|
||||||
|
qdev_init_gpio_out(DEVICE(obj), &s->out_irq, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_or_irq = {
|
||||||
|
.name = TYPE_OR_IRQ,
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_BOOL_ARRAY(levels, qemu_or_irq, MAX_OR_LINES),
|
||||||
|
VMSTATE_END_OF_LIST(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static Property or_irq_properties[] = {
|
||||||
|
DEFINE_PROP_UINT16("num-lines", qemu_or_irq, num_lines, 1),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void or_irq_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->reset = or_irq_reset;
|
||||||
|
dc->props = or_irq_properties;
|
||||||
|
dc->realize = or_irq_realize;
|
||||||
|
dc->vmsd = &vmstate_or_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo or_irq_type_info = {
|
||||||
|
.name = TYPE_OR_IRQ,
|
||||||
|
.parent = TYPE_DEVICE,
|
||||||
|
.instance_size = sizeof(qemu_or_irq),
|
||||||
|
.instance_init = or_irq_init,
|
||||||
|
.class_init = or_irq_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void or_irq_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&or_irq_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(or_irq_register_types)
|
@@ -74,7 +74,7 @@ hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
|||||||
return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);
|
return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
|
static void platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
|
||||||
{
|
{
|
||||||
PlatformBusDevice *pbus = opaque;
|
PlatformBusDevice *pbus = opaque;
|
||||||
qemu_irq sbirq;
|
qemu_irq sbirq;
|
||||||
@@ -93,8 +93,6 @@ static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -168,7 +166,7 @@ static void platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
|
|||||||
* For each sysbus device, look for unassigned IRQ lines as well as
|
* For each sysbus device, look for unassigned IRQ lines as well as
|
||||||
* unassociated MMIO regions. Connect them to the platform bus if available.
|
* unassociated MMIO regions. Connect them to the platform bus if available.
|
||||||
*/
|
*/
|
||||||
static int link_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
static void link_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
||||||
{
|
{
|
||||||
PlatformBusDevice *pbus = opaque;
|
PlatformBusDevice *pbus = opaque;
|
||||||
int i;
|
int i;
|
||||||
@@ -180,8 +178,6 @@ static int link_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
|||||||
for (i = 0; sysbus_has_mmio(sbdev, i); i++) {
|
for (i = 0; sysbus_has_mmio(sbdev, i); i++) {
|
||||||
platform_bus_map_mmio(pbus, sbdev, i);
|
platform_bus_map_mmio(pbus, sbdev, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void platform_bus_init_notify(Notifier *notifier, void *data)
|
static void platform_bus_init_notify(Notifier *notifier, void *data)
|
||||||
|
@@ -990,12 +990,9 @@ static const VMStateDescription vmstate_virtio_gpu_scanouts = {
|
|||||||
static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size)
|
static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size)
|
||||||
{
|
{
|
||||||
VirtIOGPU *g = opaque;
|
VirtIOGPU *g = opaque;
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(g);
|
|
||||||
struct virtio_gpu_simple_resource *res;
|
struct virtio_gpu_simple_resource *res;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
virtio_save(vdev, f);
|
|
||||||
|
|
||||||
/* in 2d mode we should never find unprocessed commands here */
|
/* in 2d mode we should never find unprocessed commands here */
|
||||||
assert(QTAILQ_EMPTY(&g->cmdq));
|
assert(QTAILQ_EMPTY(&g->cmdq));
|
||||||
|
|
||||||
@@ -1020,16 +1017,10 @@ static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size)
|
|||||||
static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size)
|
static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size)
|
||||||
{
|
{
|
||||||
VirtIOGPU *g = opaque;
|
VirtIOGPU *g = opaque;
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(g);
|
|
||||||
struct virtio_gpu_simple_resource *res;
|
struct virtio_gpu_simple_resource *res;
|
||||||
struct virtio_gpu_scanout *scanout;
|
struct virtio_gpu_scanout *scanout;
|
||||||
uint32_t resource_id, pformat;
|
uint32_t resource_id, pformat;
|
||||||
int i, ret;
|
int i;
|
||||||
|
|
||||||
ret = virtio_load(vdev, f, VIRTIO_GPU_VM_VERSION);
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
resource_id = qemu_get_be32(f);
|
resource_id = qemu_get_be32(f);
|
||||||
while (resource_id != 0) {
|
while (resource_id != 0) {
|
||||||
@@ -1219,8 +1210,32 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
VMSTATE_VIRTIO_DEVICE(gpu, VIRTIO_GPU_VM_VERSION, virtio_gpu_load,
|
/*
|
||||||
virtio_gpu_save);
|
* For historical reasons virtio_gpu does not adhere to virtio migration
|
||||||
|
* scheme as described in doc/virtio-migration.txt, in a sense that no
|
||||||
|
* save/load callback are provided to the core. Instead the device data
|
||||||
|
* is saved/loaded after the core data.
|
||||||
|
*
|
||||||
|
* Because of this we need a special vmsd.
|
||||||
|
*/
|
||||||
|
static const VMStateDescription vmstate_virtio_gpu = {
|
||||||
|
.name = "virtio-gpu",
|
||||||
|
.minimum_version_id = VIRTIO_GPU_VM_VERSION,
|
||||||
|
.version_id = VIRTIO_GPU_VM_VERSION,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_VIRTIO_DEVICE /* core */,
|
||||||
|
{
|
||||||
|
.name = "virtio-gpu",
|
||||||
|
.info = &(const VMStateInfo) {
|
||||||
|
.name = "virtio-gpu",
|
||||||
|
.get = virtio_gpu_load,
|
||||||
|
.put = virtio_gpu_save,
|
||||||
|
},
|
||||||
|
.flags = VMS_SINGLE,
|
||||||
|
} /* device */,
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static Property virtio_gpu_properties[] = {
|
static Property virtio_gpu_properties[] = {
|
||||||
DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
|
DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
|
||||||
|
@@ -120,8 +120,8 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
|||||||
* virtio regions are moved to the end of bar #2, to make room for
|
* virtio regions are moved to the end of bar #2, to make room for
|
||||||
* the stdvga mmio registers at the start of bar #2.
|
* the stdvga mmio registers at the start of bar #2.
|
||||||
*/
|
*/
|
||||||
vpci_dev->modern_mem_bar = 2;
|
vpci_dev->modern_mem_bar_idx = 2;
|
||||||
vpci_dev->msix_bar = 4;
|
vpci_dev->msix_bar_idx = 4;
|
||||||
|
|
||||||
if (!(vpci_dev->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ)) {
|
if (!(vpci_dev->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ)) {
|
||||||
/*
|
/*
|
||||||
|
@@ -616,34 +616,9 @@ static void rc4030_reset(DeviceState *dev)
|
|||||||
qemu_irq_lower(s->jazz_bus_irq);
|
qemu_irq_lower(s->jazz_bus_irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
|
static int rc4030_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
rc4030State* s = opaque;
|
rc4030State* s = opaque;
|
||||||
int i, j;
|
|
||||||
|
|
||||||
if (version_id != 2)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
s->config = qemu_get_be32(f);
|
|
||||||
s->invalid_address_register = qemu_get_be32(f);
|
|
||||||
for (i = 0; i < 8; i++)
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
s->dma_regs[i][j] = qemu_get_be32(f);
|
|
||||||
s->dma_tl_base = qemu_get_be32(f);
|
|
||||||
s->dma_tl_limit = qemu_get_be32(f);
|
|
||||||
s->cache_maint = qemu_get_be32(f);
|
|
||||||
s->remote_failed_address = qemu_get_be32(f);
|
|
||||||
s->memory_failed_address = qemu_get_be32(f);
|
|
||||||
s->cache_ptag = qemu_get_be32(f);
|
|
||||||
s->cache_ltag = qemu_get_be32(f);
|
|
||||||
s->cache_bmask = qemu_get_be32(f);
|
|
||||||
s->memory_refresh_rate = qemu_get_be32(f);
|
|
||||||
s->nvram_protect = qemu_get_be32(f);
|
|
||||||
for (i = 0; i < 15; i++)
|
|
||||||
s->rem_speed[i] = qemu_get_be32(f);
|
|
||||||
s->imr_jazz = qemu_get_be32(f);
|
|
||||||
s->isr_jazz = qemu_get_be32(f);
|
|
||||||
s->itr = qemu_get_be32(f);
|
|
||||||
|
|
||||||
set_next_tick(s);
|
set_next_tick(s);
|
||||||
update_jazz_irq(s);
|
update_jazz_irq(s);
|
||||||
@@ -651,32 +626,31 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc4030_save(QEMUFile *f, void *opaque)
|
static const VMStateDescription vmstate_rc4030 = {
|
||||||
{
|
.name = "rc4030",
|
||||||
rc4030State* s = opaque;
|
.version_id = 3,
|
||||||
int i, j;
|
.post_load = rc4030_post_load,
|
||||||
|
.fields = (VMStateField []) {
|
||||||
qemu_put_be32(f, s->config);
|
VMSTATE_UINT32(config, rc4030State),
|
||||||
qemu_put_be32(f, s->invalid_address_register);
|
VMSTATE_UINT32(invalid_address_register, rc4030State),
|
||||||
for (i = 0; i < 8; i++)
|
VMSTATE_UINT32_2DARRAY(dma_regs, rc4030State, 8, 4),
|
||||||
for (j = 0; j < 4; j++)
|
VMSTATE_UINT32(dma_tl_base, rc4030State),
|
||||||
qemu_put_be32(f, s->dma_regs[i][j]);
|
VMSTATE_UINT32(dma_tl_limit, rc4030State),
|
||||||
qemu_put_be32(f, s->dma_tl_base);
|
VMSTATE_UINT32(cache_maint, rc4030State),
|
||||||
qemu_put_be32(f, s->dma_tl_limit);
|
VMSTATE_UINT32(remote_failed_address, rc4030State),
|
||||||
qemu_put_be32(f, s->cache_maint);
|
VMSTATE_UINT32(memory_failed_address, rc4030State),
|
||||||
qemu_put_be32(f, s->remote_failed_address);
|
VMSTATE_UINT32(cache_ptag, rc4030State),
|
||||||
qemu_put_be32(f, s->memory_failed_address);
|
VMSTATE_UINT32(cache_ltag, rc4030State),
|
||||||
qemu_put_be32(f, s->cache_ptag);
|
VMSTATE_UINT32(cache_bmask, rc4030State),
|
||||||
qemu_put_be32(f, s->cache_ltag);
|
VMSTATE_UINT32(memory_refresh_rate, rc4030State),
|
||||||
qemu_put_be32(f, s->cache_bmask);
|
VMSTATE_UINT32(nvram_protect, rc4030State),
|
||||||
qemu_put_be32(f, s->memory_refresh_rate);
|
VMSTATE_UINT32_ARRAY(rem_speed, rc4030State, 16),
|
||||||
qemu_put_be32(f, s->nvram_protect);
|
VMSTATE_UINT32(imr_jazz, rc4030State),
|
||||||
for (i = 0; i < 15; i++)
|
VMSTATE_UINT32(isr_jazz, rc4030State),
|
||||||
qemu_put_be32(f, s->rem_speed[i]);
|
VMSTATE_UINT32(itr, rc4030State),
|
||||||
qemu_put_be32(f, s->imr_jazz);
|
VMSTATE_END_OF_LIST()
|
||||||
qemu_put_be32(f, s->isr_jazz);
|
}
|
||||||
qemu_put_be32(f, s->itr);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
|
static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
|
||||||
{
|
{
|
||||||
@@ -753,8 +727,6 @@ static void rc4030_initfn(Object *obj)
|
|||||||
sysbus_init_irq(sysbus, &s->timer_irq);
|
sysbus_init_irq(sysbus, &s->timer_irq);
|
||||||
sysbus_init_irq(sysbus, &s->jazz_bus_irq);
|
sysbus_init_irq(sysbus, &s->jazz_bus_irq);
|
||||||
|
|
||||||
register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
|
|
||||||
|
|
||||||
sysbus_init_mmio(sysbus, &s->iomem_chipset);
|
sysbus_init_mmio(sysbus, &s->iomem_chipset);
|
||||||
sysbus_init_mmio(sysbus, &s->iomem_jazzio);
|
sysbus_init_mmio(sysbus, &s->iomem_jazzio);
|
||||||
}
|
}
|
||||||
@@ -813,6 +785,7 @@ static void rc4030_class_init(ObjectClass *klass, void *class_data)
|
|||||||
dc->realize = rc4030_realize;
|
dc->realize = rc4030_realize;
|
||||||
dc->unrealize = rc4030_unrealize;
|
dc->unrealize = rc4030_unrealize;
|
||||||
dc->reset = rc4030_reset;
|
dc->reset = rc4030_reset;
|
||||||
|
dc->vmsd = &vmstate_rc4030;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo rc4030_info = {
|
static const TypeInfo rc4030_info = {
|
||||||
|
@@ -2410,18 +2410,15 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
|
|||||||
srat->reserved1 = cpu_to_le32(1);
|
srat->reserved1 = cpu_to_le32(1);
|
||||||
|
|
||||||
for (i = 0; i < apic_ids->len; i++) {
|
for (i = 0; i < apic_ids->len; i++) {
|
||||||
int j;
|
int j = numa_get_node_for_cpu(i);
|
||||||
int apic_id = apic_ids->cpus[i].arch_id;
|
int apic_id = apic_ids->cpus[i].arch_id;
|
||||||
|
|
||||||
core = acpi_data_push(table_data, sizeof *core);
|
core = acpi_data_push(table_data, sizeof *core);
|
||||||
core->type = ACPI_SRAT_PROCESSOR_APIC;
|
core->type = ACPI_SRAT_PROCESSOR_APIC;
|
||||||
core->length = sizeof(*core);
|
core->length = sizeof(*core);
|
||||||
core->local_apic_id = apic_id;
|
core->local_apic_id = apic_id;
|
||||||
for (j = 0; j < nb_numa_nodes; j++) {
|
if (j < nb_numa_nodes) {
|
||||||
if (test_bit(i, numa_info[j].node_cpu)) {
|
|
||||||
core->proximity_lo = j;
|
core->proximity_lo = j;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
memset(core->proximity_hi, 0, 3);
|
memset(core->proximity_hi, 0, 3);
|
||||||
core->local_sapic_eid = 0;
|
core->local_sapic_eid = 0;
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "hw/i386/amd_iommu.h"
|
#include "hw/i386/amd_iommu.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
/* used AMD-Vi MMIO registers */
|
/* used AMD-Vi MMIO registers */
|
||||||
@@ -142,10 +143,10 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val)
|
|||||||
|
|
||||||
static void amdvi_generate_msi_interrupt(AMDVIState *s)
|
static void amdvi_generate_msi_interrupt(AMDVIState *s)
|
||||||
{
|
{
|
||||||
MSIMessage msg;
|
MSIMessage msg = {};
|
||||||
MemTxAttrs attrs;
|
MemTxAttrs attrs = {
|
||||||
|
.requester_id = pci_requester_id(&s->pci.dev)
|
||||||
attrs.requester_id = pci_requester_id(&s->pci.dev);
|
};
|
||||||
|
|
||||||
if (msi_enabled(&s->pci.dev)) {
|
if (msi_enabled(&s->pci.dev)) {
|
||||||
msg = msi_get_message(&s->pci.dev, 0);
|
msg = msi_get_message(&s->pci.dev, 0);
|
||||||
@@ -184,7 +185,7 @@ static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start,
|
|||||||
int length)
|
int length)
|
||||||
{
|
{
|
||||||
int index = start / 64, bitpos = start % 64;
|
int index = start / 64, bitpos = start % 64;
|
||||||
uint64_t mask = ((1 << length) - 1) << bitpos;
|
uint64_t mask = MAKE_64BIT_MASK(start, length);
|
||||||
buffer[index] &= ~mask;
|
buffer[index] &= ~mask;
|
||||||
buffer[index] |= (value << bitpos) & mask;
|
buffer[index] |= (value << bitpos) & mask;
|
||||||
}
|
}
|
||||||
@@ -332,8 +333,8 @@ static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid,
|
|||||||
uint64_t gpa, IOMMUTLBEntry to_cache,
|
uint64_t gpa, IOMMUTLBEntry to_cache,
|
||||||
uint16_t domid)
|
uint16_t domid)
|
||||||
{
|
{
|
||||||
AMDVIIOTLBEntry *entry = g_malloc(sizeof(*entry));
|
AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1);
|
||||||
uint64_t *key = g_malloc(sizeof(key));
|
uint64_t *key = g_new(uint64_t, 1);
|
||||||
uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K;
|
uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K;
|
||||||
|
|
||||||
/* don't cache erroneous translations */
|
/* don't cache erroneous translations */
|
||||||
@@ -1066,13 +1067,18 @@ static const MemoryRegionOps mmio_mem_ops = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void amdvi_iommu_notify_started(MemoryRegion *iommu)
|
static void amdvi_iommu_notify_flag_changed(MemoryRegion *iommu,
|
||||||
|
IOMMUNotifierFlag old,
|
||||||
|
IOMMUNotifierFlag new)
|
||||||
{
|
{
|
||||||
AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
|
AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
|
||||||
|
|
||||||
hw_error("device %02x.%02x.%x requires iommu notifier which is not "
|
if (new & IOMMU_NOTIFIER_MAP) {
|
||||||
|
error_report("device %02x.%02x.%x requires iommu notifier which is not "
|
||||||
"currently supported", as->bus_num, PCI_SLOT(as->devfn),
|
"currently supported", as->bus_num, PCI_SLOT(as->devfn),
|
||||||
PCI_FUNC(as->devfn));
|
PCI_FUNC(as->devfn));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void amdvi_init(AMDVIState *s)
|
static void amdvi_init(AMDVIState *s)
|
||||||
@@ -1080,7 +1086,7 @@ static void amdvi_init(AMDVIState *s)
|
|||||||
amdvi_iotlb_reset(s);
|
amdvi_iotlb_reset(s);
|
||||||
|
|
||||||
s->iommu_ops.translate = amdvi_translate;
|
s->iommu_ops.translate = amdvi_translate;
|
||||||
s->iommu_ops.notify_started = amdvi_iommu_notify_started;
|
s->iommu_ops.notify_flag_changed = amdvi_iommu_notify_flag_changed;
|
||||||
s->devtab_len = 0;
|
s->devtab_len = 0;
|
||||||
s->cmdbuf_len = 0;
|
s->cmdbuf_len = 0;
|
||||||
s->cmdbuf_head = 0;
|
s->cmdbuf_head = 0;
|
||||||
@@ -1129,6 +1135,7 @@ static void amdvi_reset(DeviceState *dev)
|
|||||||
|
|
||||||
static void amdvi_realize(DeviceState *dev, Error **err)
|
static void amdvi_realize(DeviceState *dev, Error **err)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
AMDVIState *s = AMD_IOMMU_DEVICE(dev);
|
AMDVIState *s = AMD_IOMMU_DEVICE(dev);
|
||||||
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
|
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
|
||||||
PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
|
PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
|
||||||
@@ -1141,8 +1148,11 @@ static void amdvi_realize(DeviceState *dev, Error **err)
|
|||||||
object_property_set_bool(OBJECT(&s->pci), true, "realized", err);
|
object_property_set_bool(OBJECT(&s->pci), true, "realized", err);
|
||||||
s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0,
|
s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0,
|
||||||
AMDVI_CAPAB_SIZE);
|
AMDVI_CAPAB_SIZE);
|
||||||
pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE);
|
assert(s->capab_offset > 0);
|
||||||
pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE);
|
ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE);
|
||||||
|
assert(ret > 0);
|
||||||
|
ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE);
|
||||||
|
assert(ret > 0);
|
||||||
|
|
||||||
/* set up MMIO */
|
/* set up MMIO */
|
||||||
memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
|
memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
#include "hw/pci/pci_bus.h"
|
#include "hw/pci/pci_bus.h"
|
||||||
#include "hw/i386/pc.h"
|
#include "hw/i386/pc.h"
|
||||||
|
#include "hw/i386/apic-msidef.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/i386/x86-iommu.h"
|
#include "hw/i386/x86-iommu.h"
|
||||||
#include "hw/pci-host/q35.h"
|
#include "hw/pci-host/q35.h"
|
||||||
@@ -1974,14 +1975,20 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vtd_iommu_notify_started(MemoryRegion *iommu)
|
static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
|
||||||
|
IOMMUNotifierFlag old,
|
||||||
|
IOMMUNotifierFlag new)
|
||||||
{
|
{
|
||||||
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
|
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
|
||||||
|
|
||||||
hw_error("Device at bus %s addr %02x.%d requires iommu notifier which "
|
if (new & IOMMU_NOTIFIER_MAP) {
|
||||||
"is currently not supported by intel-iommu emulation",
|
error_report("Device at bus %s addr %02x.%d requires iommu "
|
||||||
|
"notifier which is currently not supported by "
|
||||||
|
"intel-iommu emulation",
|
||||||
vtd_as->bus->qbus.name, PCI_SLOT(vtd_as->devfn),
|
vtd_as->bus->qbus.name, PCI_SLOT(vtd_as->devfn),
|
||||||
PCI_FUNC(vtd_as->devfn));
|
PCI_FUNC(vtd_as->devfn));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vtd_vmstate = {
|
static const VMStateDescription vtd_vmstate = {
|
||||||
@@ -2203,6 +2210,8 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint8_t vector = origin->data & 0xff;
|
uint8_t vector = origin->data & 0xff;
|
||||||
|
uint8_t trigger_mode = (origin->data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
|
||||||
|
|
||||||
VTD_DPRINTF(IR, "received IOAPIC interrupt");
|
VTD_DPRINTF(IR, "received IOAPIC interrupt");
|
||||||
/* IOAPIC entry vector should be aligned with IRTE vector
|
/* IOAPIC entry vector should be aligned with IRTE vector
|
||||||
* (see vt-d spec 5.1.5.1). */
|
* (see vt-d spec 5.1.5.1). */
|
||||||
@@ -2211,6 +2220,15 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu,
|
|||||||
"entry: %d, IRTE: %d, index: %d",
|
"entry: %d, IRTE: %d, index: %d",
|
||||||
vector, irq.vector, index);
|
vector, irq.vector, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The Trigger Mode field must match the Trigger Mode in the IRTE.
|
||||||
|
* (see vt-d spec 5.1.5.1). */
|
||||||
|
if (trigger_mode != irq.trigger_mode) {
|
||||||
|
VTD_DPRINTF(GENERAL, "IOAPIC trigger mode inconsistent: "
|
||||||
|
"entry: %u, IRTE: %u, index: %d",
|
||||||
|
trigger_mode, irq.trigger_mode, index);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2348,7 +2366,7 @@ static void vtd_init(IntelIOMMUState *s)
|
|||||||
memset(s->womask, 0, DMAR_REG_SIZE);
|
memset(s->womask, 0, DMAR_REG_SIZE);
|
||||||
|
|
||||||
s->iommu_ops.translate = vtd_iommu_translate;
|
s->iommu_ops.translate = vtd_iommu_translate;
|
||||||
s->iommu_ops.notify_started = vtd_iommu_notify_started;
|
s->iommu_ops.notify_flag_changed = vtd_iommu_notify_flag_changed;
|
||||||
s->root = 0;
|
s->root = 0;
|
||||||
s->root_extended = false;
|
s->root_extended = false;
|
||||||
s->dmar_enabled = false;
|
s->dmar_enabled = false;
|
||||||
|
@@ -125,7 +125,7 @@ static void kvm_apic_vapic_base_update(APICCommonState *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_apic_put(void *data)
|
static void kvm_apic_put(CPUState *cs, void *data)
|
||||||
{
|
{
|
||||||
APICCommonState *s = data;
|
APICCommonState *s = data;
|
||||||
struct kvm_lapic_state kapic;
|
struct kvm_lapic_state kapic;
|
||||||
@@ -146,10 +146,9 @@ static void kvm_apic_post_load(APICCommonState *s)
|
|||||||
run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
|
run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_inject_external_nmi(void *data)
|
static void do_inject_external_nmi(CPUState *cpu, void *data)
|
||||||
{
|
{
|
||||||
APICCommonState *s = data;
|
APICCommonState *s = data;
|
||||||
CPUState *cpu = CPU(s->cpu);
|
|
||||||
uint32_t lvt;
|
uint32_t lvt;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@@ -483,7 +483,7 @@ typedef struct VAPICEnableTPRReporting {
|
|||||||
bool enable;
|
bool enable;
|
||||||
} VAPICEnableTPRReporting;
|
} VAPICEnableTPRReporting;
|
||||||
|
|
||||||
static void vapic_do_enable_tpr_reporting(void *data)
|
static void vapic_do_enable_tpr_reporting(CPUState *cpu, void *data)
|
||||||
{
|
{
|
||||||
VAPICEnableTPRReporting *info = data;
|
VAPICEnableTPRReporting *info = data;
|
||||||
|
|
||||||
@@ -734,10 +734,10 @@ static void vapic_realize(DeviceState *dev, Error **errp)
|
|||||||
nb_option_roms++;
|
nb_option_roms++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_vapic_enable(void *data)
|
static void do_vapic_enable(CPUState *cs, void *data)
|
||||||
{
|
{
|
||||||
VAPICROMState *s = data;
|
VAPICROMState *s = data;
|
||||||
X86CPU *cpu = X86_CPU(first_cpu);
|
X86CPU *cpu = X86_CPU(cs);
|
||||||
|
|
||||||
static const uint8_t enabled = 1;
|
static const uint8_t enabled = 1;
|
||||||
cpu_physical_memory_write(s->vapic_paddr + offsetof(VAPICState, enabled),
|
cpu_physical_memory_write(s->vapic_paddr + offsetof(VAPICState, enabled),
|
||||||
|
@@ -779,11 +779,9 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
|
|||||||
for (i = 0; i < max_cpus; i++) {
|
for (i = 0; i < max_cpus; i++) {
|
||||||
unsigned int apic_id = x86_cpu_apic_id_from_index(i);
|
unsigned int apic_id = x86_cpu_apic_id_from_index(i);
|
||||||
assert(apic_id < pcms->apic_id_limit);
|
assert(apic_id < pcms->apic_id_limit);
|
||||||
for (j = 0; j < nb_numa_nodes; j++) {
|
j = numa_get_node_for_cpu(i);
|
||||||
if (test_bit(i, numa_info[j].node_cpu)) {
|
if (j < nb_numa_nodes) {
|
||||||
numa_fw_cfg[apic_id + 1] = cpu_to_le64(j);
|
numa_fw_cfg[apic_id + 1] = cpu_to_le64(j);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < nb_numa_nodes; i++) {
|
for (i = 0; i < nb_numa_nodes; i++) {
|
||||||
|
@@ -7,10 +7,6 @@ xen_platform_log(char *s) "xen platform: %s"
|
|||||||
xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")"
|
xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")"
|
||||||
xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")"
|
xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")"
|
||||||
|
|
||||||
# hw/i386/pc.c
|
|
||||||
mhp_pc_dimm_assigned_slot(int slot) "%d"
|
|
||||||
mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64
|
|
||||||
|
|
||||||
# hw/i386/x86-iommu.c
|
# hw/i386/x86-iommu.c
|
||||||
x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
|
x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
|
||||||
|
|
||||||
|
@@ -134,8 +134,6 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
|
|||||||
devices, and bit 2 the non-primary-master IDE devices. */
|
devices, and bit 2 the non-primary-master IDE devices. */
|
||||||
if (val & UNPLUG_ALL_IDE_DISKS) {
|
if (val & UNPLUG_ALL_IDE_DISKS) {
|
||||||
DPRINTF("unplug disks\n");
|
DPRINTF("unplug disks\n");
|
||||||
blk_drain_all();
|
|
||||||
blk_flush_all();
|
|
||||||
pci_unplug_disks(pci_dev->bus);
|
pci_unplug_disks(pci_dev->bus);
|
||||||
}
|
}
|
||||||
if (val & UNPLUG_ALL_NICS) {
|
if (val & UNPLUG_ALL_NICS) {
|
||||||
|
@@ -948,6 +948,7 @@ static void ncq_cb(void *opaque, int ret)
|
|||||||
NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
|
NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
|
||||||
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
|
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
|
||||||
|
|
||||||
|
ncq_tfs->aiocb = NULL;
|
||||||
if (ret == -ECANCELED) {
|
if (ret == -ECANCELED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -908,7 +908,7 @@ eot:
|
|||||||
|
|
||||||
static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
|
static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
|
||||||
{
|
{
|
||||||
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
|
s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
|
||||||
s->io_buffer_size = 0;
|
s->io_buffer_size = 0;
|
||||||
s->dma_cmd = dma_cmd;
|
s->dma_cmd = dma_cmd;
|
||||||
|
|
||||||
@@ -2582,7 +2582,7 @@ static void ide_restart_cb(void *opaque, int running, RunState state)
|
|||||||
void ide_register_restart_cb(IDEBus *bus)
|
void ide_register_restart_cb(IDEBus *bus)
|
||||||
{
|
{
|
||||||
if (bus->dma->ops->restart_dma) {
|
if (bus->dma->ops->restart_dma) {
|
||||||
qemu_add_vm_change_state_handler(ide_restart_cb, bus);
|
bus->vmstate = qemu_add_vm_change_state_handler(ide_restart_cb, bus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -179,6 +179,10 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
|||||||
if (di != NULL && !di->media_cd) {
|
if (di != NULL && !di->media_cd) {
|
||||||
BlockBackend *blk = blk_by_legacy_dinfo(di);
|
BlockBackend *blk = blk_by_legacy_dinfo(di);
|
||||||
DeviceState *ds = blk_get_attached_dev(blk);
|
DeviceState *ds = blk_get_attached_dev(blk);
|
||||||
|
|
||||||
|
blk_drain(blk);
|
||||||
|
blk_flush(blk);
|
||||||
|
|
||||||
if (ds) {
|
if (ds) {
|
||||||
blk_detach_dev(blk, ds);
|
blk_detach_dev(blk, ds);
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
/* --------------------------------- */
|
/* --------------------------------- */
|
||||||
|
|
||||||
static char *idebus_get_fw_dev_path(DeviceState *dev);
|
static char *idebus_get_fw_dev_path(DeviceState *dev);
|
||||||
|
static void idebus_unrealize(DeviceState *qdev, Error **errp);
|
||||||
|
|
||||||
static Property ide_props[] = {
|
static Property ide_props[] = {
|
||||||
DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
|
DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
|
||||||
@@ -44,6 +45,15 @@ static void ide_bus_class_init(ObjectClass *klass, void *data)
|
|||||||
k->get_fw_dev_path = idebus_get_fw_dev_path;
|
k->get_fw_dev_path = idebus_get_fw_dev_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void idebus_unrealize(DeviceState *qdev, Error **errp)
|
||||||
|
{
|
||||||
|
IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
|
||||||
|
|
||||||
|
if (bus->vmstate) {
|
||||||
|
qemu_del_vm_change_state_handler(bus->vmstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const TypeInfo ide_bus_info = {
|
static const TypeInfo ide_bus_info = {
|
||||||
.name = TYPE_IDE_BUS,
|
.name = TYPE_IDE_BUS,
|
||||||
.parent = TYPE_BUS,
|
.parent = TYPE_BUS,
|
||||||
@@ -355,6 +365,7 @@ static void ide_device_class_init(ObjectClass *klass, void *data)
|
|||||||
k->init = ide_qdev_init;
|
k->init = ide_qdev_init;
|
||||||
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
|
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
|
||||||
k->bus_type = TYPE_IDE_BUS;
|
k->bus_type = TYPE_IDE_BUS;
|
||||||
|
k->unrealize = idebus_unrealize;
|
||||||
k->props = ide_props;
|
k->props = ide_props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,30 +31,31 @@ typedef struct {
|
|||||||
QEMUTimer *timer;
|
QEMUTimer *timer;
|
||||||
uint16_t model;
|
uint16_t model;
|
||||||
|
|
||||||
int x, y;
|
int32_t x, y;
|
||||||
int pressure;
|
bool pressure;
|
||||||
|
|
||||||
int state, reg, irq, command;
|
uint8_t reg, state;
|
||||||
|
bool irq, command;
|
||||||
uint16_t data, dav;
|
uint16_t data, dav;
|
||||||
|
|
||||||
int busy;
|
bool busy;
|
||||||
int enabled;
|
bool enabled;
|
||||||
int host_mode;
|
bool host_mode;
|
||||||
int function;
|
int8_t function;
|
||||||
int nextfunction;
|
int8_t nextfunction;
|
||||||
int precision;
|
bool precision;
|
||||||
int nextprecision;
|
bool nextprecision;
|
||||||
int filter;
|
uint16_t filter;
|
||||||
int pin_func;
|
uint8_t pin_func;
|
||||||
int timing[2];
|
uint16_t timing[2];
|
||||||
int noise;
|
uint8_t noise;
|
||||||
int reset;
|
bool reset;
|
||||||
int pdst;
|
bool pdst;
|
||||||
int pnd0;
|
bool pnd0;
|
||||||
uint16_t temp_thr[2];
|
uint16_t temp_thr[2];
|
||||||
uint16_t aux_thr[2];
|
uint16_t aux_thr[2];
|
||||||
|
|
||||||
int tr[8];
|
int32_t tr[8];
|
||||||
} TSC2005State;
|
} TSC2005State;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -149,7 +150,7 @@ static uint16_t tsc2005_read(TSC2005State *s, int reg)
|
|||||||
ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
|
ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
|
||||||
s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
|
s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
|
||||||
mode_regs[TSC_MODE_TS_TEST]);
|
mode_regs[TSC_MODE_TS_TEST]);
|
||||||
s->reset = 1;
|
s->reset = true;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
case 0x8: /* AUX high treshold */
|
case 0x8: /* AUX high treshold */
|
||||||
@@ -196,14 +197,14 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xc: /* CFR0 */
|
case 0xc: /* CFR0 */
|
||||||
s->host_mode = data >> 15;
|
s->host_mode = (data >> 15) != 0;
|
||||||
if (s->enabled != !(data & 0x4000)) {
|
if (s->enabled != !(data & 0x4000)) {
|
||||||
s->enabled = !(data & 0x4000);
|
s->enabled = !(data & 0x4000);
|
||||||
fprintf(stderr, "%s: touchscreen sense %sabled\n",
|
fprintf(stderr, "%s: touchscreen sense %sabled\n",
|
||||||
__FUNCTION__, s->enabled ? "en" : "dis");
|
__FUNCTION__, s->enabled ? "en" : "dis");
|
||||||
if (s->busy && !s->enabled)
|
if (s->busy && !s->enabled)
|
||||||
timer_del(s->timer);
|
timer_del(s->timer);
|
||||||
s->busy &= s->enabled;
|
s->busy = s->busy && s->enabled;
|
||||||
}
|
}
|
||||||
s->nextprecision = (data >> 13) & 1;
|
s->nextprecision = (data >> 13) & 1;
|
||||||
s->timing[0] = data & 0x1fff;
|
s->timing[0] = data & 0x1fff;
|
||||||
@@ -229,7 +230,7 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
|
|||||||
static void tsc2005_pin_update(TSC2005State *s)
|
static void tsc2005_pin_update(TSC2005State *s)
|
||||||
{
|
{
|
||||||
int64_t expires;
|
int64_t expires;
|
||||||
int pin_state;
|
bool pin_state;
|
||||||
|
|
||||||
switch (s->pin_func) {
|
switch (s->pin_func) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -253,7 +254,7 @@ static void tsc2005_pin_update(TSC2005State *s)
|
|||||||
case TSC_MODE_XYZ_SCAN:
|
case TSC_MODE_XYZ_SCAN:
|
||||||
case TSC_MODE_XY_SCAN:
|
case TSC_MODE_XY_SCAN:
|
||||||
if (!s->host_mode && s->dav)
|
if (!s->host_mode && s->dav)
|
||||||
s->enabled = 0;
|
s->enabled = false;
|
||||||
if (!s->pressure)
|
if (!s->pressure)
|
||||||
return;
|
return;
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
@@ -273,7 +274,7 @@ static void tsc2005_pin_update(TSC2005State *s)
|
|||||||
case TSC_MODE_Y_TEST:
|
case TSC_MODE_Y_TEST:
|
||||||
case TSC_MODE_TS_TEST:
|
case TSC_MODE_TS_TEST:
|
||||||
if (s->dav)
|
if (s->dav)
|
||||||
s->enabled = 0;
|
s->enabled = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSC_MODE_RESERVED:
|
case TSC_MODE_RESERVED:
|
||||||
@@ -287,7 +288,7 @@ static void tsc2005_pin_update(TSC2005State *s)
|
|||||||
if (!s->enabled || s->busy)
|
if (!s->enabled || s->busy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
s->busy = 1;
|
s->busy = true;
|
||||||
s->precision = s->nextprecision;
|
s->precision = s->nextprecision;
|
||||||
s->function = s->nextfunction;
|
s->function = s->nextfunction;
|
||||||
s->pdst = !s->pnd0; /* Synchronised on internal clock */
|
s->pdst = !s->pnd0; /* Synchronised on internal clock */
|
||||||
@@ -300,17 +301,17 @@ static void tsc2005_reset(TSC2005State *s)
|
|||||||
{
|
{
|
||||||
s->state = 0;
|
s->state = 0;
|
||||||
s->pin_func = 0;
|
s->pin_func = 0;
|
||||||
s->enabled = 0;
|
s->enabled = false;
|
||||||
s->busy = 0;
|
s->busy = false;
|
||||||
s->nextprecision = 0;
|
s->nextprecision = false;
|
||||||
s->nextfunction = 0;
|
s->nextfunction = 0;
|
||||||
s->timing[0] = 0;
|
s->timing[0] = 0;
|
||||||
s->timing[1] = 0;
|
s->timing[1] = 0;
|
||||||
s->irq = 0;
|
s->irq = false;
|
||||||
s->dav = 0;
|
s->dav = 0;
|
||||||
s->reset = 0;
|
s->reset = false;
|
||||||
s->pdst = 1;
|
s->pdst = true;
|
||||||
s->pnd0 = 0;
|
s->pnd0 = false;
|
||||||
s->function = -1;
|
s->function = -1;
|
||||||
s->temp_thr[0] = 0x000;
|
s->temp_thr[0] = 0x000;
|
||||||
s->temp_thr[1] = 0xfff;
|
s->temp_thr[1] = 0xfff;
|
||||||
@@ -340,7 +341,7 @@ static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
|
|||||||
__FUNCTION__, s->enabled ? "en" : "dis");
|
__FUNCTION__, s->enabled ? "en" : "dis");
|
||||||
if (s->busy && !s->enabled)
|
if (s->busy && !s->enabled)
|
||||||
timer_del(s->timer);
|
timer_del(s->timer);
|
||||||
s->busy &= s->enabled;
|
s->busy = s->busy && s->enabled;
|
||||||
}
|
}
|
||||||
tsc2005_pin_update(s);
|
tsc2005_pin_update(s);
|
||||||
}
|
}
|
||||||
@@ -407,7 +408,7 @@ static void tsc2005_timer_tick(void *opaque)
|
|||||||
if (!s->busy)
|
if (!s->busy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
s->busy = 0;
|
s->busy = false;
|
||||||
s->dav |= mode_regs[s->function];
|
s->dav |= mode_regs[s->function];
|
||||||
s->function = -1;
|
s->function = -1;
|
||||||
tsc2005_pin_update(s);
|
tsc2005_pin_update(s);
|
||||||
@@ -434,86 +435,9 @@ static void tsc2005_touchscreen_event(void *opaque,
|
|||||||
tsc2005_pin_update(s);
|
tsc2005_pin_update(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tsc2005_save(QEMUFile *f, void *opaque)
|
static int tsc2005_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
TSC2005State *s = (TSC2005State *) opaque;
|
TSC2005State *s = (TSC2005State *) opaque;
|
||||||
int i;
|
|
||||||
|
|
||||||
qemu_put_be16(f, s->x);
|
|
||||||
qemu_put_be16(f, s->y);
|
|
||||||
qemu_put_byte(f, s->pressure);
|
|
||||||
|
|
||||||
qemu_put_byte(f, s->state);
|
|
||||||
qemu_put_byte(f, s->reg);
|
|
||||||
qemu_put_byte(f, s->command);
|
|
||||||
|
|
||||||
qemu_put_byte(f, s->irq);
|
|
||||||
qemu_put_be16s(f, &s->dav);
|
|
||||||
qemu_put_be16s(f, &s->data);
|
|
||||||
|
|
||||||
timer_put(f, s->timer);
|
|
||||||
qemu_put_byte(f, s->enabled);
|
|
||||||
qemu_put_byte(f, s->host_mode);
|
|
||||||
qemu_put_byte(f, s->function);
|
|
||||||
qemu_put_byte(f, s->nextfunction);
|
|
||||||
qemu_put_byte(f, s->precision);
|
|
||||||
qemu_put_byte(f, s->nextprecision);
|
|
||||||
qemu_put_be16(f, s->filter);
|
|
||||||
qemu_put_byte(f, s->pin_func);
|
|
||||||
qemu_put_be16(f, s->timing[0]);
|
|
||||||
qemu_put_be16(f, s->timing[1]);
|
|
||||||
qemu_put_be16s(f, &s->temp_thr[0]);
|
|
||||||
qemu_put_be16s(f, &s->temp_thr[1]);
|
|
||||||
qemu_put_be16s(f, &s->aux_thr[0]);
|
|
||||||
qemu_put_be16s(f, &s->aux_thr[1]);
|
|
||||||
qemu_put_be32(f, s->noise);
|
|
||||||
qemu_put_byte(f, s->reset);
|
|
||||||
qemu_put_byte(f, s->pdst);
|
|
||||||
qemu_put_byte(f, s->pnd0);
|
|
||||||
|
|
||||||
for (i = 0; i < 8; i ++)
|
|
||||||
qemu_put_be32(f, s->tr[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
|
|
||||||
{
|
|
||||||
TSC2005State *s = (TSC2005State *) opaque;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
s->x = qemu_get_be16(f);
|
|
||||||
s->y = qemu_get_be16(f);
|
|
||||||
s->pressure = qemu_get_byte(f);
|
|
||||||
|
|
||||||
s->state = qemu_get_byte(f);
|
|
||||||
s->reg = qemu_get_byte(f);
|
|
||||||
s->command = qemu_get_byte(f);
|
|
||||||
|
|
||||||
s->irq = qemu_get_byte(f);
|
|
||||||
qemu_get_be16s(f, &s->dav);
|
|
||||||
qemu_get_be16s(f, &s->data);
|
|
||||||
|
|
||||||
timer_get(f, s->timer);
|
|
||||||
s->enabled = qemu_get_byte(f);
|
|
||||||
s->host_mode = qemu_get_byte(f);
|
|
||||||
s->function = qemu_get_byte(f);
|
|
||||||
s->nextfunction = qemu_get_byte(f);
|
|
||||||
s->precision = qemu_get_byte(f);
|
|
||||||
s->nextprecision = qemu_get_byte(f);
|
|
||||||
s->filter = qemu_get_be16(f);
|
|
||||||
s->pin_func = qemu_get_byte(f);
|
|
||||||
s->timing[0] = qemu_get_be16(f);
|
|
||||||
s->timing[1] = qemu_get_be16(f);
|
|
||||||
qemu_get_be16s(f, &s->temp_thr[0]);
|
|
||||||
qemu_get_be16s(f, &s->temp_thr[1]);
|
|
||||||
qemu_get_be16s(f, &s->aux_thr[0]);
|
|
||||||
qemu_get_be16s(f, &s->aux_thr[1]);
|
|
||||||
s->noise = qemu_get_be32(f);
|
|
||||||
s->reset = qemu_get_byte(f);
|
|
||||||
s->pdst = qemu_get_byte(f);
|
|
||||||
s->pnd0 = qemu_get_byte(f);
|
|
||||||
|
|
||||||
for (i = 0; i < 8; i ++)
|
|
||||||
s->tr[i] = qemu_get_be32(f);
|
|
||||||
|
|
||||||
s->busy = timer_pending(s->timer);
|
s->busy = timer_pending(s->timer);
|
||||||
tsc2005_pin_update(s);
|
tsc2005_pin_update(s);
|
||||||
@@ -521,6 +445,42 @@ static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_tsc2005 = {
|
||||||
|
.name = "tsc2005",
|
||||||
|
.version_id = 2,
|
||||||
|
.minimum_version_id = 2,
|
||||||
|
.post_load = tsc2005_post_load,
|
||||||
|
.fields = (VMStateField []) {
|
||||||
|
VMSTATE_BOOL(pressure, TSC2005State),
|
||||||
|
VMSTATE_BOOL(irq, TSC2005State),
|
||||||
|
VMSTATE_BOOL(command, TSC2005State),
|
||||||
|
VMSTATE_BOOL(enabled, TSC2005State),
|
||||||
|
VMSTATE_BOOL(host_mode, TSC2005State),
|
||||||
|
VMSTATE_BOOL(reset, TSC2005State),
|
||||||
|
VMSTATE_BOOL(pdst, TSC2005State),
|
||||||
|
VMSTATE_BOOL(pnd0, TSC2005State),
|
||||||
|
VMSTATE_BOOL(precision, TSC2005State),
|
||||||
|
VMSTATE_BOOL(nextprecision, TSC2005State),
|
||||||
|
VMSTATE_UINT8(reg, TSC2005State),
|
||||||
|
VMSTATE_UINT8(state, TSC2005State),
|
||||||
|
VMSTATE_UINT16(data, TSC2005State),
|
||||||
|
VMSTATE_UINT16(dav, TSC2005State),
|
||||||
|
VMSTATE_UINT16(filter, TSC2005State),
|
||||||
|
VMSTATE_INT8(nextfunction, TSC2005State),
|
||||||
|
VMSTATE_INT8(function, TSC2005State),
|
||||||
|
VMSTATE_INT32(x, TSC2005State),
|
||||||
|
VMSTATE_INT32(y, TSC2005State),
|
||||||
|
VMSTATE_TIMER_PTR(timer, TSC2005State),
|
||||||
|
VMSTATE_UINT8(pin_func, TSC2005State),
|
||||||
|
VMSTATE_UINT16_ARRAY(timing, TSC2005State, 2),
|
||||||
|
VMSTATE_UINT8(noise, TSC2005State),
|
||||||
|
VMSTATE_UINT16_ARRAY(temp_thr, TSC2005State, 2),
|
||||||
|
VMSTATE_UINT16_ARRAY(aux_thr, TSC2005State, 2),
|
||||||
|
VMSTATE_INT32_ARRAY(tr, TSC2005State, 8),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void *tsc2005_init(qemu_irq pintdav)
|
void *tsc2005_init(qemu_irq pintdav)
|
||||||
{
|
{
|
||||||
TSC2005State *s;
|
TSC2005State *s;
|
||||||
@@ -529,8 +489,8 @@ void *tsc2005_init(qemu_irq pintdav)
|
|||||||
g_malloc0(sizeof(TSC2005State));
|
g_malloc0(sizeof(TSC2005State));
|
||||||
s->x = 400;
|
s->x = 400;
|
||||||
s->y = 240;
|
s->y = 240;
|
||||||
s->pressure = 0;
|
s->pressure = false;
|
||||||
s->precision = s->nextprecision = 0;
|
s->precision = s->nextprecision = false;
|
||||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s);
|
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s);
|
||||||
s->pint = pintdav;
|
s->pint = pintdav;
|
||||||
s->model = 0x2005;
|
s->model = 0x2005;
|
||||||
@@ -550,7 +510,7 @@ void *tsc2005_init(qemu_irq pintdav)
|
|||||||
"QEMU TSC2005-driven Touchscreen");
|
"QEMU TSC2005-driven Touchscreen");
|
||||||
|
|
||||||
qemu_register_reset((void *) tsc2005_reset, s);
|
qemu_register_reset((void *) tsc2005_reset, s);
|
||||||
register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s);
|
vmstate_register(NULL, 0, &vmstate_tsc2005, s);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@@ -47,24 +47,25 @@ typedef struct {
|
|||||||
uint8_t out_fifo[16384];
|
uint8_t out_fifo[16384];
|
||||||
uint16_t model;
|
uint16_t model;
|
||||||
|
|
||||||
int x, y;
|
int32_t x, y;
|
||||||
int pressure;
|
bool pressure;
|
||||||
|
|
||||||
int state, page, offset, irq;
|
uint8_t page, offset;
|
||||||
uint16_t command, dav;
|
uint16_t dav;
|
||||||
|
|
||||||
int busy;
|
bool state;
|
||||||
int enabled;
|
bool irq;
|
||||||
int host_mode;
|
bool command;
|
||||||
int function;
|
bool busy;
|
||||||
int nextfunction;
|
bool enabled;
|
||||||
int precision;
|
bool host_mode;
|
||||||
int nextprecision;
|
uint8_t function, nextfunction;
|
||||||
int filter;
|
uint8_t precision, nextprecision;
|
||||||
int pin_func;
|
uint8_t filter;
|
||||||
int ref;
|
uint8_t pin_func;
|
||||||
int timing;
|
uint8_t ref;
|
||||||
int noise;
|
uint8_t timing;
|
||||||
|
uint8_t noise;
|
||||||
|
|
||||||
uint16_t audio_ctrl1;
|
uint16_t audio_ctrl1;
|
||||||
uint16_t audio_ctrl2;
|
uint16_t audio_ctrl2;
|
||||||
@@ -72,7 +73,7 @@ typedef struct {
|
|||||||
uint16_t pll[3];
|
uint16_t pll[3];
|
||||||
uint16_t volume;
|
uint16_t volume;
|
||||||
int64_t volume_change;
|
int64_t volume_change;
|
||||||
int softstep;
|
bool softstep;
|
||||||
uint16_t dac_power;
|
uint16_t dac_power;
|
||||||
int64_t powerdown;
|
int64_t powerdown;
|
||||||
uint16_t filter_data[0x14];
|
uint16_t filter_data[0x14];
|
||||||
@@ -93,6 +94,7 @@ typedef struct {
|
|||||||
int mode;
|
int mode;
|
||||||
int intr;
|
int intr;
|
||||||
} kb;
|
} kb;
|
||||||
|
int64_t now; /* Time at migration */
|
||||||
} TSC210xState;
|
} TSC210xState;
|
||||||
|
|
||||||
static const int resolution[4] = { 12, 8, 10, 12 };
|
static const int resolution[4] = { 12, 8, 10, 12 };
|
||||||
@@ -154,14 +156,14 @@ static const uint16_t mode_regs[16] = {
|
|||||||
|
|
||||||
static void tsc210x_reset(TSC210xState *s)
|
static void tsc210x_reset(TSC210xState *s)
|
||||||
{
|
{
|
||||||
s->state = 0;
|
s->state = false;
|
||||||
s->pin_func = 2;
|
s->pin_func = 2;
|
||||||
s->enabled = 0;
|
s->enabled = false;
|
||||||
s->busy = 0;
|
s->busy = false;
|
||||||
s->nextfunction = 0;
|
s->nextfunction = 0;
|
||||||
s->ref = 0;
|
s->ref = 0;
|
||||||
s->timing = 0;
|
s->timing = 0;
|
||||||
s->irq = 0;
|
s->irq = false;
|
||||||
s->dav = 0;
|
s->dav = 0;
|
||||||
|
|
||||||
s->audio_ctrl1 = 0x0000;
|
s->audio_ctrl1 = 0x0000;
|
||||||
@@ -172,7 +174,7 @@ static void tsc210x_reset(TSC210xState *s)
|
|||||||
s->pll[2] = 0x1fff;
|
s->pll[2] = 0x1fff;
|
||||||
s->volume = 0xffff;
|
s->volume = 0xffff;
|
||||||
s->dac_power = 0x8540;
|
s->dac_power = 0x8540;
|
||||||
s->softstep = 1;
|
s->softstep = true;
|
||||||
s->volume_change = 0;
|
s->volume_change = 0;
|
||||||
s->powerdown = 0;
|
s->powerdown = 0;
|
||||||
s->filter_data[0x00] = 0x6be3;
|
s->filter_data[0x00] = 0x6be3;
|
||||||
@@ -566,7 +568,7 @@ static void tsc2102_control_register_write(
|
|||||||
s->enabled = !(value & 0x4000);
|
s->enabled = !(value & 0x4000);
|
||||||
if (s->busy && !s->enabled)
|
if (s->busy && !s->enabled)
|
||||||
timer_del(s->timer);
|
timer_del(s->timer);
|
||||||
s->busy &= s->enabled;
|
s->busy = s->busy && s->enabled;
|
||||||
s->nextfunction = (value >> 10) & 0xf;
|
s->nextfunction = (value >> 10) & 0xf;
|
||||||
s->nextprecision = (value >> 8) & 3;
|
s->nextprecision = (value >> 8) & 3;
|
||||||
s->filter = value & 0xff;
|
s->filter = value & 0xff;
|
||||||
@@ -773,7 +775,7 @@ static void tsc2102_audio_register_write(
|
|||||||
static void tsc210x_pin_update(TSC210xState *s)
|
static void tsc210x_pin_update(TSC210xState *s)
|
||||||
{
|
{
|
||||||
int64_t expires;
|
int64_t expires;
|
||||||
int pin_state;
|
bool pin_state;
|
||||||
|
|
||||||
switch (s->pin_func) {
|
switch (s->pin_func) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -788,7 +790,7 @@ static void tsc210x_pin_update(TSC210xState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!s->enabled)
|
if (!s->enabled)
|
||||||
pin_state = 0;
|
pin_state = false;
|
||||||
|
|
||||||
if (pin_state != s->irq) {
|
if (pin_state != s->irq) {
|
||||||
s->irq = pin_state;
|
s->irq = pin_state;
|
||||||
@@ -814,7 +816,7 @@ static void tsc210x_pin_update(TSC210xState *s)
|
|||||||
case TSC_MODE_TEMP1:
|
case TSC_MODE_TEMP1:
|
||||||
case TSC_MODE_TEMP2:
|
case TSC_MODE_TEMP2:
|
||||||
if (s->dav)
|
if (s->dav)
|
||||||
s->enabled = 0;
|
s->enabled = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSC_MODE_AUX_SCAN:
|
case TSC_MODE_AUX_SCAN:
|
||||||
@@ -832,7 +834,7 @@ static void tsc210x_pin_update(TSC210xState *s)
|
|||||||
if (!s->enabled || s->busy || s->dav)
|
if (!s->enabled || s->busy || s->dav)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
s->busy = 1;
|
s->busy = true;
|
||||||
s->precision = s->nextprecision;
|
s->precision = s->nextprecision;
|
||||||
s->function = s->nextfunction;
|
s->function = s->nextfunction;
|
||||||
expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||||
@@ -867,7 +869,7 @@ static uint16_t tsc210x_read(TSC210xState *s)
|
|||||||
|
|
||||||
/* Allow sequential reads. */
|
/* Allow sequential reads. */
|
||||||
s->offset ++;
|
s->offset ++;
|
||||||
s->state = 0;
|
s->state = false;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -878,10 +880,10 @@ static void tsc210x_write(TSC210xState *s, uint16_t value)
|
|||||||
* command and data every second time.
|
* command and data every second time.
|
||||||
*/
|
*/
|
||||||
if (!s->state) {
|
if (!s->state) {
|
||||||
s->command = value >> 15;
|
s->command = (value >> 15) != 0;
|
||||||
s->page = (value >> 11) & 0x0f;
|
s->page = (value >> 11) & 0x0f;
|
||||||
s->offset = (value >> 5) & 0x3f;
|
s->offset = (value >> 5) & 0x3f;
|
||||||
s->state = 1;
|
s->state = true;
|
||||||
} else {
|
} else {
|
||||||
if (s->command)
|
if (s->command)
|
||||||
fprintf(stderr, "tsc210x_write: SPI overrun!\n");
|
fprintf(stderr, "tsc210x_write: SPI overrun!\n");
|
||||||
@@ -901,7 +903,7 @@ static void tsc210x_write(TSC210xState *s, uint16_t value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tsc210x_pin_update(s);
|
tsc210x_pin_update(s);
|
||||||
s->state = 0;
|
s->state = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -933,7 +935,7 @@ static void tsc210x_timer_tick(void *opaque)
|
|||||||
if (!s->busy)
|
if (!s->busy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
s->busy = 0;
|
s->busy = false;
|
||||||
s->dav |= mode_regs[s->function];
|
s->dav |= mode_regs[s->function];
|
||||||
tsc210x_pin_update(s);
|
tsc210x_pin_update(s);
|
||||||
qemu_irq_lower(s->davint);
|
qemu_irq_lower(s->davint);
|
||||||
@@ -974,108 +976,34 @@ static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
|
|||||||
s->i2s_rx_rate = in;
|
s->i2s_rx_rate = in;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tsc210x_save(QEMUFile *f, void *opaque)
|
static void tsc210x_pre_save(void *opaque)
|
||||||
{
|
{
|
||||||
TSC210xState *s = (TSC210xState *) opaque;
|
TSC210xState *s = (TSC210xState *) opaque;
|
||||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
s->now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
int i;
|
|
||||||
|
|
||||||
qemu_put_be16(f, s->x);
|
|
||||||
qemu_put_be16(f, s->y);
|
|
||||||
qemu_put_byte(f, s->pressure);
|
|
||||||
|
|
||||||
qemu_put_byte(f, s->state);
|
|
||||||
qemu_put_byte(f, s->page);
|
|
||||||
qemu_put_byte(f, s->offset);
|
|
||||||
qemu_put_byte(f, s->command);
|
|
||||||
|
|
||||||
qemu_put_byte(f, s->irq);
|
|
||||||
qemu_put_be16s(f, &s->dav);
|
|
||||||
|
|
||||||
timer_put(f, s->timer);
|
|
||||||
qemu_put_byte(f, s->enabled);
|
|
||||||
qemu_put_byte(f, s->host_mode);
|
|
||||||
qemu_put_byte(f, s->function);
|
|
||||||
qemu_put_byte(f, s->nextfunction);
|
|
||||||
qemu_put_byte(f, s->precision);
|
|
||||||
qemu_put_byte(f, s->nextprecision);
|
|
||||||
qemu_put_byte(f, s->filter);
|
|
||||||
qemu_put_byte(f, s->pin_func);
|
|
||||||
qemu_put_byte(f, s->ref);
|
|
||||||
qemu_put_byte(f, s->timing);
|
|
||||||
qemu_put_be32(f, s->noise);
|
|
||||||
|
|
||||||
qemu_put_be16s(f, &s->audio_ctrl1);
|
|
||||||
qemu_put_be16s(f, &s->audio_ctrl2);
|
|
||||||
qemu_put_be16s(f, &s->audio_ctrl3);
|
|
||||||
qemu_put_be16s(f, &s->pll[0]);
|
|
||||||
qemu_put_be16s(f, &s->pll[1]);
|
|
||||||
qemu_put_be16s(f, &s->volume);
|
|
||||||
qemu_put_sbe64(f, (s->volume_change - now));
|
|
||||||
qemu_put_sbe64(f, (s->powerdown - now));
|
|
||||||
qemu_put_byte(f, s->softstep);
|
|
||||||
qemu_put_be16s(f, &s->dac_power);
|
|
||||||
|
|
||||||
for (i = 0; i < 0x14; i ++)
|
|
||||||
qemu_put_be16s(f, &s->filter_data[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
|
static int tsc210x_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
TSC210xState *s = (TSC210xState *) opaque;
|
TSC210xState *s = (TSC210xState *) opaque;
|
||||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
int i;
|
|
||||||
|
|
||||||
s->x = qemu_get_be16(f);
|
if (s->function >= ARRAY_SIZE(mode_regs)) {
|
||||||
s->y = qemu_get_be16(f);
|
|
||||||
s->pressure = qemu_get_byte(f);
|
|
||||||
|
|
||||||
s->state = qemu_get_byte(f);
|
|
||||||
s->page = qemu_get_byte(f);
|
|
||||||
s->offset = qemu_get_byte(f);
|
|
||||||
s->command = qemu_get_byte(f);
|
|
||||||
|
|
||||||
s->irq = qemu_get_byte(f);
|
|
||||||
qemu_get_be16s(f, &s->dav);
|
|
||||||
|
|
||||||
timer_get(f, s->timer);
|
|
||||||
s->enabled = qemu_get_byte(f);
|
|
||||||
s->host_mode = qemu_get_byte(f);
|
|
||||||
s->function = qemu_get_byte(f);
|
|
||||||
if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) {
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
s->nextfunction = qemu_get_byte(f);
|
if (s->nextfunction >= ARRAY_SIZE(mode_regs)) {
|
||||||
if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) {
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
s->precision = qemu_get_byte(f);
|
if (s->precision >= ARRAY_SIZE(resolution)) {
|
||||||
if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) {
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
s->nextprecision = qemu_get_byte(f);
|
if (s->nextprecision >= ARRAY_SIZE(resolution)) {
|
||||||
if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) {
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
s->filter = qemu_get_byte(f);
|
|
||||||
s->pin_func = qemu_get_byte(f);
|
|
||||||
s->ref = qemu_get_byte(f);
|
|
||||||
s->timing = qemu_get_byte(f);
|
|
||||||
s->noise = qemu_get_be32(f);
|
|
||||||
|
|
||||||
qemu_get_be16s(f, &s->audio_ctrl1);
|
s->volume_change -= s->now;
|
||||||
qemu_get_be16s(f, &s->audio_ctrl2);
|
s->volume_change += now;
|
||||||
qemu_get_be16s(f, &s->audio_ctrl3);
|
s->powerdown -= s->now;
|
||||||
qemu_get_be16s(f, &s->pll[0]);
|
s->powerdown += now;
|
||||||
qemu_get_be16s(f, &s->pll[1]);
|
|
||||||
qemu_get_be16s(f, &s->volume);
|
|
||||||
s->volume_change = qemu_get_sbe64(f) + now;
|
|
||||||
s->powerdown = qemu_get_sbe64(f) + now;
|
|
||||||
s->softstep = qemu_get_byte(f);
|
|
||||||
qemu_get_be16s(f, &s->dac_power);
|
|
||||||
|
|
||||||
for (i = 0; i < 0x14; i ++)
|
|
||||||
qemu_get_be16s(f, &s->filter_data[i]);
|
|
||||||
|
|
||||||
s->busy = timer_pending(s->timer);
|
s->busy = timer_pending(s->timer);
|
||||||
qemu_set_irq(s->pint, !s->irq);
|
qemu_set_irq(s->pint, !s->irq);
|
||||||
@@ -1084,6 +1012,60 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VMStateField vmstatefields_tsc210x[] = {
|
||||||
|
VMSTATE_BOOL(enabled, TSC210xState),
|
||||||
|
VMSTATE_BOOL(host_mode, TSC210xState),
|
||||||
|
VMSTATE_BOOL(irq, TSC210xState),
|
||||||
|
VMSTATE_BOOL(command, TSC210xState),
|
||||||
|
VMSTATE_BOOL(pressure, TSC210xState),
|
||||||
|
VMSTATE_BOOL(softstep, TSC210xState),
|
||||||
|
VMSTATE_BOOL(state, TSC210xState),
|
||||||
|
VMSTATE_UINT16(dav, TSC210xState),
|
||||||
|
VMSTATE_INT32(x, TSC210xState),
|
||||||
|
VMSTATE_INT32(y, TSC210xState),
|
||||||
|
VMSTATE_UINT8(offset, TSC210xState),
|
||||||
|
VMSTATE_UINT8(page, TSC210xState),
|
||||||
|
VMSTATE_UINT8(filter, TSC210xState),
|
||||||
|
VMSTATE_UINT8(pin_func, TSC210xState),
|
||||||
|
VMSTATE_UINT8(ref, TSC210xState),
|
||||||
|
VMSTATE_UINT8(timing, TSC210xState),
|
||||||
|
VMSTATE_UINT8(noise, TSC210xState),
|
||||||
|
VMSTATE_UINT8(function, TSC210xState),
|
||||||
|
VMSTATE_UINT8(nextfunction, TSC210xState),
|
||||||
|
VMSTATE_UINT8(precision, TSC210xState),
|
||||||
|
VMSTATE_UINT8(nextprecision, TSC210xState),
|
||||||
|
VMSTATE_UINT16(audio_ctrl1, TSC210xState),
|
||||||
|
VMSTATE_UINT16(audio_ctrl2, TSC210xState),
|
||||||
|
VMSTATE_UINT16(audio_ctrl3, TSC210xState),
|
||||||
|
VMSTATE_UINT16_ARRAY(pll, TSC210xState, 3),
|
||||||
|
VMSTATE_UINT16(volume, TSC210xState),
|
||||||
|
VMSTATE_UINT16(dac_power, TSC210xState),
|
||||||
|
VMSTATE_INT64(volume_change, TSC210xState),
|
||||||
|
VMSTATE_INT64(powerdown, TSC210xState),
|
||||||
|
VMSTATE_INT64(now, TSC210xState),
|
||||||
|
VMSTATE_UINT16_ARRAY(filter_data, TSC210xState, 0x14),
|
||||||
|
VMSTATE_TIMER_PTR(timer, TSC210xState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
};
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_tsc2102 = {
|
||||||
|
.name = "tsc2102",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.pre_save = tsc210x_pre_save,
|
||||||
|
.post_load = tsc210x_post_load,
|
||||||
|
.fields = vmstatefields_tsc210x,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_tsc2301 = {
|
||||||
|
.name = "tsc2301",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.pre_save = tsc210x_pre_save,
|
||||||
|
.post_load = tsc210x_post_load,
|
||||||
|
.fields = vmstatefields_tsc210x,
|
||||||
|
};
|
||||||
|
|
||||||
uWireSlave *tsc2102_init(qemu_irq pint)
|
uWireSlave *tsc2102_init(qemu_irq pint)
|
||||||
{
|
{
|
||||||
TSC210xState *s;
|
TSC210xState *s;
|
||||||
@@ -1125,8 +1107,7 @@ uWireSlave *tsc2102_init(qemu_irq pint)
|
|||||||
AUD_register_card(s->name, &s->card);
|
AUD_register_card(s->name, &s->card);
|
||||||
|
|
||||||
qemu_register_reset((void *) tsc210x_reset, s);
|
qemu_register_reset((void *) tsc210x_reset, s);
|
||||||
register_savevm(NULL, s->name, -1, 0,
|
vmstate_register(NULL, 0, &vmstate_tsc2102, s);
|
||||||
tsc210x_save, tsc210x_load, s);
|
|
||||||
|
|
||||||
return &s->chip;
|
return &s->chip;
|
||||||
}
|
}
|
||||||
@@ -1174,7 +1155,7 @@ uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
|
|||||||
AUD_register_card(s->name, &s->card);
|
AUD_register_card(s->name, &s->card);
|
||||||
|
|
||||||
qemu_register_reset((void *) tsc210x_reset, s);
|
qemu_register_reset((void *) tsc210x_reset, s);
|
||||||
register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
|
vmstate_register(NULL, 0, &vmstate_tsc2301, s);
|
||||||
|
|
||||||
return &s->chip;
|
return &s->chip;
|
||||||
}
|
}
|
||||||
|
@@ -217,19 +217,12 @@ static void virtio_input_reset(VirtIODevice *vdev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_input_load(QEMUFile *f, void *opaque, size_t size)
|
static int virtio_input_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
VirtIOInput *vinput = opaque;
|
VirtIOInput *vinput = opaque;
|
||||||
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput);
|
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput);
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(vinput);
|
VirtIODevice *vdev = VIRTIO_DEVICE(vinput);
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = virtio_load(vdev, f, VIRTIO_INPUT_VM_VERSION);
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* post_load() */
|
|
||||||
vinput->active = vdev->status & VIRTIO_CONFIG_S_DRIVER_OK;
|
vinput->active = vdev->status & VIRTIO_CONFIG_S_DRIVER_OK;
|
||||||
if (vic->change_active) {
|
if (vic->change_active) {
|
||||||
vic->change_active(vinput);
|
vic->change_active(vinput);
|
||||||
@@ -296,8 +289,16 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
|
|||||||
virtio_cleanup(vdev);
|
virtio_cleanup(vdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMSTATE_VIRTIO_DEVICE(input, VIRTIO_INPUT_VM_VERSION, virtio_input_load,
|
static const VMStateDescription vmstate_virtio_input = {
|
||||||
virtio_vmstate_save);
|
.name = "virtio-input",
|
||||||
|
.minimum_version_id = VIRTIO_INPUT_VM_VERSION,
|
||||||
|
.version_id = VIRTIO_INPUT_VM_VERSION,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_VIRTIO_DEVICE,
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
.post_load = virtio_input_post_load,
|
||||||
|
};
|
||||||
|
|
||||||
static Property virtio_input_properties[] = {
|
static Property virtio_input_properties[] = {
|
||||||
DEFINE_PROP_STRING("serial", VirtIOInput, serial),
|
DEFINE_PROP_STRING("serial", VirtIOInput, serial),
|
||||||
|
@@ -16,11 +16,14 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
|
|||||||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
|
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
|
||||||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
|
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
|
||||||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
|
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
|
||||||
|
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_its_common.o
|
||||||
common-obj-$(CONFIG_OPENPIC) += openpic.o
|
common-obj-$(CONFIG_OPENPIC) += openpic.o
|
||||||
|
common-obj-y += intc.o
|
||||||
|
|
||||||
obj-$(CONFIG_APIC) += apic.o apic_common.o
|
obj-$(CONFIG_APIC) += apic.o apic_common.o
|
||||||
obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
|
obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
|
||||||
obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
|
obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
|
||||||
|
obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_its_kvm.o
|
||||||
obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
|
obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
|
||||||
obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
|
obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
|
||||||
obj-$(CONFIG_GRLIB) += grlib_irqmp.o
|
obj-$(CONFIG_GRLIB) += grlib_irqmp.o
|
||||||
|
@@ -577,6 +577,18 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
|||||||
"not support vGICv2 migration");
|
"not support vGICv2 migration");
|
||||||
migrate_add_blocker(s->migration_blocker);
|
migrate_add_blocker(s->migration_blocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kvm_has_gsi_routing()) {
|
||||||
|
/* set up irq routing */
|
||||||
|
kvm_init_irq_routing(kvm_state);
|
||||||
|
for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) {
|
||||||
|
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
kvm_gsi_routing_allowed = true;
|
||||||
|
|
||||||
|
kvm_irqchip_commit_routes(kvm_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
|
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
|
||||||
|
148
hw/intc/arm_gicv3_its_common.c
Normal file
148
hw/intc/arm_gicv3_its_common.c
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* ITS base class for a GICv3-based system
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
|
||||||
|
* Written by Pavel Fedin
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/pci/msi.h"
|
||||||
|
#include "hw/intc/arm_gicv3_its_common.h"
|
||||||
|
#include "qemu/log.h"
|
||||||
|
|
||||||
|
static void gicv3_its_pre_save(void *opaque)
|
||||||
|
{
|
||||||
|
GICv3ITSState *s = (GICv3ITSState *)opaque;
|
||||||
|
GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
|
||||||
|
|
||||||
|
if (c->pre_save) {
|
||||||
|
c->pre_save(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gicv3_its_post_load(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
GICv3ITSState *s = (GICv3ITSState *)opaque;
|
||||||
|
GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
|
||||||
|
|
||||||
|
if (c->post_load) {
|
||||||
|
c->post_load(s);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_its = {
|
||||||
|
.name = "arm_gicv3_its",
|
||||||
|
.pre_save = gicv3_its_pre_save,
|
||||||
|
.post_load = gicv3_its_post_load,
|
||||||
|
.unmigratable = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
|
||||||
|
uint64_t *data, unsigned size,
|
||||||
|
MemTxAttrs attrs)
|
||||||
|
{
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "ITS read at offset 0x%"PRIx64"\n", offset);
|
||||||
|
return MEMTX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
|
||||||
|
uint64_t value, unsigned size,
|
||||||
|
MemTxAttrs attrs)
|
||||||
|
{
|
||||||
|
if (offset == 0x0040 && ((size == 2) || (size == 4))) {
|
||||||
|
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(opaque);
|
||||||
|
GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
|
||||||
|
int ret = c->send_msi(s, le64_to_cpu(value), attrs.requester_id);
|
||||||
|
|
||||||
|
if (ret <= 0) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"ITS: Error sending MSI: %s\n", strerror(-ret));
|
||||||
|
return MEMTX_DECODE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MEMTX_OK;
|
||||||
|
} else {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"ITS write at bad offset 0x%"PRIx64"\n", offset);
|
||||||
|
return MEMTX_DECODE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps gicv3_its_trans_ops = {
|
||||||
|
.read_with_attrs = gicv3_its_trans_read,
|
||||||
|
.write_with_attrs = gicv3_its_trans_write,
|
||||||
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops)
|
||||||
|
{
|
||||||
|
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
|
||||||
|
|
||||||
|
memory_region_init_io(&s->iomem_its_cntrl, OBJECT(s), ops, s,
|
||||||
|
"control", ITS_CONTROL_SIZE);
|
||||||
|
memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
|
||||||
|
&gicv3_its_trans_ops, s,
|
||||||
|
"translation", ITS_TRANS_SIZE);
|
||||||
|
|
||||||
|
/* Our two regions are always adjacent, therefore we now combine them
|
||||||
|
* into a single one in order to make our users' life easier.
|
||||||
|
*/
|
||||||
|
memory_region_init(&s->iomem_main, OBJECT(s), "gicv3_its", ITS_SIZE);
|
||||||
|
memory_region_add_subregion(&s->iomem_main, 0, &s->iomem_its_cntrl);
|
||||||
|
memory_region_add_subregion(&s->iomem_main, ITS_CONTROL_SIZE,
|
||||||
|
&s->iomem_its_translation);
|
||||||
|
sysbus_init_mmio(sbd, &s->iomem_main);
|
||||||
|
|
||||||
|
msi_nonbroken = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gicv3_its_common_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
||||||
|
|
||||||
|
s->ctlr = 0;
|
||||||
|
s->cbaser = 0;
|
||||||
|
s->cwriter = 0;
|
||||||
|
s->creadr = 0;
|
||||||
|
memset(&s->baser, 0, sizeof(s->baser));
|
||||||
|
|
||||||
|
gicv3_its_post_load(s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gicv3_its_common_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->reset = gicv3_its_common_reset;
|
||||||
|
dc->vmsd = &vmstate_its;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo gicv3_its_common_info = {
|
||||||
|
.name = TYPE_ARM_GICV3_ITS_COMMON,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(GICv3ITSState),
|
||||||
|
.class_size = sizeof(GICv3ITSCommonClass),
|
||||||
|
.class_init = gicv3_its_common_class_init,
|
||||||
|
.abstract = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gicv3_its_common_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&gicv3_its_common_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(gicv3_its_common_register_types)
|
121
hw/intc/arm_gicv3_its_kvm.c
Normal file
121
hw/intc/arm_gicv3_its_kvm.c
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* KVM-based ITS implementation for a GICv3-based system
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
|
||||||
|
* Written by Pavel Fedin <p.fedin@samsung.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "hw/intc/arm_gicv3_its_common.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "sysemu/kvm.h"
|
||||||
|
#include "kvm_arm.h"
|
||||||
|
#include "migration/migration.h"
|
||||||
|
|
||||||
|
#define TYPE_KVM_ARM_ITS "arm-its-kvm"
|
||||||
|
#define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS)
|
||||||
|
|
||||||
|
static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
|
||||||
|
{
|
||||||
|
struct kvm_msi msi;
|
||||||
|
|
||||||
|
if (unlikely(!s->translater_gpa_known)) {
|
||||||
|
MemoryRegion *mr = &s->iomem_its_translation;
|
||||||
|
MemoryRegionSection mrs;
|
||||||
|
|
||||||
|
mrs = memory_region_find(mr, 0, 1);
|
||||||
|
memory_region_unref(mrs.mr);
|
||||||
|
s->gits_translater_gpa = mrs.offset_within_address_space + 0x40;
|
||||||
|
s->translater_gpa_known = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
msi.address_lo = extract64(s->gits_translater_gpa, 0, 32);
|
||||||
|
msi.address_hi = extract64(s->gits_translater_gpa, 32, 32);
|
||||||
|
msi.data = le32_to_cpu(value);
|
||||||
|
msi.flags = KVM_MSI_VALID_DEVID;
|
||||||
|
msi.devid = devid;
|
||||||
|
memset(msi.pad, 0, sizeof(msi.pad));
|
||||||
|
|
||||||
|
return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
||||||
|
|
||||||
|
s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false);
|
||||||
|
if (s->dev_fd < 0) {
|
||||||
|
error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* explicit init of the ITS */
|
||||||
|
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||||
|
KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
|
||||||
|
|
||||||
|
/* register the base address */
|
||||||
|
kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
|
KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd);
|
||||||
|
|
||||||
|
gicv3_its_init_mmio(s, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Block migration of a KVM GICv3 ITS device: the API for saving and
|
||||||
|
* restoring the state in the kernel is not yet available
|
||||||
|
*/
|
||||||
|
error_setg(&s->migration_blocker, "vITS migration is not implemented");
|
||||||
|
migrate_add_blocker(s->migration_blocker);
|
||||||
|
|
||||||
|
kvm_msi_use_devid = true;
|
||||||
|
kvm_gsi_direct_mapping = false;
|
||||||
|
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_arm_its_init(Object *obj)
|
||||||
|
{
|
||||||
|
GICv3ITSState *s = KVM_ARM_ITS(obj);
|
||||||
|
|
||||||
|
object_property_add_link(obj, "parent-gicv3",
|
||||||
|
"kvm-arm-gicv3", (Object **)&s->gicv3,
|
||||||
|
object_property_allow_set_link,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
|
||||||
|
|
||||||
|
dc->realize = kvm_arm_its_realize;
|
||||||
|
icc->send_msi = kvm_its_send_msi;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo kvm_arm_its_info = {
|
||||||
|
.name = TYPE_KVM_ARM_ITS,
|
||||||
|
.parent = TYPE_ARM_GICV3_ITS_COMMON,
|
||||||
|
.instance_size = sizeof(GICv3ITSState),
|
||||||
|
.instance_init = kvm_arm_its_init,
|
||||||
|
.class_init = kvm_arm_its_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void kvm_arm_its_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&kvm_arm_its_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(kvm_arm_its_register_types)
|
@@ -85,6 +85,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||||||
GICv3State *s = KVM_ARM_GICV3(dev);
|
GICv3State *s = KVM_ARM_GICV3(dev);
|
||||||
KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
|
KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
DPRINTF("kvm_arm_gicv3_realize\n");
|
DPRINTF("kvm_arm_gicv3_realize\n");
|
||||||
|
|
||||||
@@ -127,6 +128,18 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||||||
*/
|
*/
|
||||||
error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
|
error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
|
||||||
migrate_add_blocker(s->migration_blocker);
|
migrate_add_blocker(s->migration_blocker);
|
||||||
|
|
||||||
|
if (kvm_has_gsi_routing()) {
|
||||||
|
/* set up irq routing */
|
||||||
|
kvm_init_irq_routing(kvm_state);
|
||||||
|
for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) {
|
||||||
|
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
kvm_gsi_routing_allowed = true;
|
||||||
|
|
||||||
|
kvm_irqchip_commit_routes(kvm_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
|
static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "hw/isa/i8259_internal.h"
|
#include "hw/isa/i8259_internal.h"
|
||||||
|
#include "hw/intc/intc.h"
|
||||||
|
|
||||||
/* debug PIC */
|
/* debug PIC */
|
||||||
//#define DEBUG_PIC
|
//#define DEBUG_PIC
|
||||||
@@ -251,6 +252,35 @@ static void pic_reset(DeviceState *dev)
|
|||||||
pic_init_reset(s);
|
pic_init_reset(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool pic_get_statistics(InterruptStatsProvider *obj,
|
||||||
|
uint64_t **irq_counts, unsigned int *nb_irqs)
|
||||||
|
{
|
||||||
|
PICCommonState *s = PIC_COMMON(obj);
|
||||||
|
|
||||||
|
if (s->master) {
|
||||||
|
#ifdef DEBUG_IRQ_COUNT
|
||||||
|
*irq_counts = irq_count;
|
||||||
|
*nb_irqs = ARRAY_SIZE(irq_count);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
*irq_counts = NULL;
|
||||||
|
*nb_irqs = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
|
||||||
|
{
|
||||||
|
PICCommonState *s = PIC_COMMON(obj);
|
||||||
|
monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
|
||||||
|
"irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
|
||||||
|
s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add,
|
||||||
|
s->irq_base, s->read_reg_select, s->elcr,
|
||||||
|
s->special_fully_nested_mode);
|
||||||
|
}
|
||||||
|
|
||||||
static void pic_ioport_write(void *opaque, hwaddr addr64,
|
static void pic_ioport_write(void *opaque, hwaddr addr64,
|
||||||
uint64_t val64, unsigned size)
|
uint64_t val64, unsigned size)
|
||||||
{
|
{
|
||||||
@@ -431,42 +461,6 @@ static void pic_realize(DeviceState *dev, Error **errp)
|
|||||||
pc->parent_realize(dev, errp);
|
pc->parent_realize(dev, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_info_pic(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
PICCommonState *s;
|
|
||||||
|
|
||||||
if (!isa_pic) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (i = 0; i < 2; i++) {
|
|
||||||
s = i == 0 ? PIC_COMMON(isa_pic) : slave_pic;
|
|
||||||
monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
|
|
||||||
"irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
|
|
||||||
i, s->irr, s->imr, s->isr, s->priority_add,
|
|
||||||
s->irq_base, s->read_reg_select, s->elcr,
|
|
||||||
s->special_fully_nested_mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmp_info_irq(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
#ifndef DEBUG_IRQ_COUNT
|
|
||||||
monitor_printf(mon, "irq statistic code not compiled.\n");
|
|
||||||
#else
|
|
||||||
int i;
|
|
||||||
int64_t count;
|
|
||||||
|
|
||||||
monitor_printf(mon, "IRQ statistics:\n");
|
|
||||||
for (i = 0; i < 16; i++) {
|
|
||||||
count = irq_count[i];
|
|
||||||
if (count > 0) {
|
|
||||||
monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
|
qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
|
||||||
{
|
{
|
||||||
qemu_irq *irq_set;
|
qemu_irq *irq_set;
|
||||||
@@ -503,10 +497,13 @@ static void i8259_class_init(ObjectClass *klass, void *data)
|
|||||||
{
|
{
|
||||||
PICClass *k = PIC_CLASS(klass);
|
PICClass *k = PIC_CLASS(klass);
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
|
||||||
|
|
||||||
k->parent_realize = dc->realize;
|
k->parent_realize = dc->realize;
|
||||||
dc->realize = pic_realize;
|
dc->realize = pic_realize;
|
||||||
dc->reset = pic_reset;
|
dc->reset = pic_reset;
|
||||||
|
ic->get_statistics = pic_get_statistics;
|
||||||
|
ic->print_info = pic_print_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo i8259_info = {
|
static const TypeInfo i8259_info = {
|
||||||
@@ -515,6 +512,10 @@ static const TypeInfo i8259_info = {
|
|||||||
.parent = TYPE_PIC_COMMON,
|
.parent = TYPE_PIC_COMMON,
|
||||||
.class_init = i8259_class_init,
|
.class_init = i8259_class_init,
|
||||||
.class_size = sizeof(PICClass),
|
.class_size = sizeof(PICClass),
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
|
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
||||||
|
{ }
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pic_register_types(void)
|
static void pic_register_types(void)
|
||||||
|
@@ -70,10 +70,11 @@ static int pic_dispatch_post_load(void *opaque, int version_id)
|
|||||||
static void pic_common_realize(DeviceState *dev, Error **errp)
|
static void pic_common_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
PICCommonState *s = PIC_COMMON(dev);
|
PICCommonState *s = PIC_COMMON(dev);
|
||||||
|
ISADevice *isa = ISA_DEVICE(dev);
|
||||||
|
|
||||||
isa_register_ioport(NULL, &s->base_io, s->iobase);
|
isa_register_ioport(isa, &s->base_io, s->iobase);
|
||||||
if (s->elcr_addr != -1) {
|
if (s->elcr_addr != -1) {
|
||||||
isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
|
isa_register_ioport(isa, &s->elcr_io, s->elcr_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
qdev_set_legacy_instance_id(dev, s->iobase, 1);
|
qdev_set_legacy_instance_id(dev, s->iobase, 1);
|
||||||
|
41
hw/intc/intc.c
Normal file
41
hw/intc/intc.c
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Generic Interrupt Controller
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Hervé Poussineau
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/intc/intc.h"
|
||||||
|
#include "qemu/module.h"
|
||||||
|
|
||||||
|
static const TypeInfo intctrl_info = {
|
||||||
|
.name = TYPE_INTERRUPT_STATS_PROVIDER,
|
||||||
|
.parent = TYPE_INTERFACE,
|
||||||
|
.class_size = sizeof(InterruptStatsProviderClass),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void intc_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&intctrl_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(intc_register_types)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user