Compare commits
361 Commits
qemu-2.0.0
...
pull-gtk-4
Author | SHA1 | Date | |
---|---|---|---|
|
25eccc37ff | ||
|
ecce1929bc | ||
|
e61031cdd8 | ||
|
0d0e044dee | ||
|
466e6e9d13 | ||
|
8ae60ee85c | ||
|
54bee5c2b4 | ||
|
8c2664d869 | ||
|
4d1cb6e6f5 | ||
|
f187743acd | ||
|
b998875dcf | ||
|
bae2c27090 | ||
|
cd7ccc8351 | ||
|
d097696eba | ||
|
3b418d0c45 | ||
|
cd40890816 | ||
|
e3fa4bfa72 | ||
|
8885eadedd | ||
|
4c2e5f8f46 | ||
|
cbee81f6de | ||
|
5913815a17 | ||
|
888157fe96 | ||
|
de03c3164a | ||
|
87d8354de3 | ||
|
784a5592c9 | ||
|
97891afab8 | ||
|
c97ca29db0 | ||
|
b2f9c08a4f | ||
|
27898a5daa | ||
|
d581eb7ca4 | ||
|
82c6f51373 | ||
|
9bcec938aa | ||
|
53e11bd384 | ||
|
507979a8bd | ||
|
c792707f54 | ||
|
9302e863aa | ||
|
afbcc40bee | ||
|
5dae6e30c5 | ||
|
6a83f8b5be | ||
|
c05e4667be | ||
|
11b128f406 | ||
|
6b7d4c5558 | ||
|
8f4754ede5 | ||
|
1e7226f70c | ||
|
f0dce23475 | ||
|
686d7148ec | ||
|
c165f77580 | ||
|
eb71803b04 | ||
|
b404bf8542 | ||
|
73ed27ec28 | ||
|
2c1885adcf | ||
|
cab60de930 | ||
|
0abe740f1d | ||
|
bb572aefbd | ||
|
2b5d5953ee | ||
|
db8a31d11d | ||
|
b106ad9185 | ||
|
6d33e8e7dc | ||
|
2d51c32c4b | ||
|
ce48f2f441 | ||
|
8c7de28305 | ||
|
5dab2faddc | ||
|
a1b3955c94 | ||
|
24342f2cae | ||
|
6d4b9e55fc | ||
|
1d7678dec4 | ||
|
63fa06dc97 | ||
|
5e71dfad76 | ||
|
97f1c45c6f | ||
|
a9ba36a45d | ||
|
8e53abbc20 | ||
|
e3737b820b | ||
|
246f65838d | ||
|
3dd8a6763b | ||
|
24f3078a04 | ||
|
42d43d35d9 | ||
|
f56b9bc3ae | ||
|
7b103b36d6 | ||
|
509a41bab5 | ||
|
d65f97a82c | ||
|
05560fcebb | ||
|
47f73da0a7 | ||
|
c5a33ee9ee | ||
|
4c7096607d | ||
|
bdf866fe6c | ||
|
bdcc3a28b7 | ||
|
0419f78fae | ||
|
e82597f6f8 | ||
|
d25295d4ef | ||
|
95224e87a7 | ||
|
7373fc7693 | ||
|
a4ec5bb718 | ||
|
cebac61498 | ||
|
efdf6a56a7 | ||
|
e683eb9ecc | ||
|
627b1a17ce | ||
|
66e0c7b187 | ||
|
abc53733f3 | ||
|
2d888c099c | ||
|
fc9677915c | ||
|
592408b8ca | ||
|
5c4e24c151 | ||
|
d597a32a6d | ||
|
0875709429 | ||
|
d766825190 | ||
|
96b8ca47f8 | ||
|
63678e17cf | ||
|
58b590148c | ||
|
7d4d7975e5 | ||
|
0d6d1ab499 | ||
|
c8c14bcb72 | ||
|
8648fcd52a | ||
|
b3706faf0d | ||
|
3b6144bdbb | ||
|
b89834f4d7 | ||
|
1a8e80d7e8 | ||
|
9c5793c503 | ||
|
c6c09ba995 | ||
|
c36ad13fe9 | ||
|
5c31207941 | ||
|
6ff45f01c7 | ||
|
3768d505ad | ||
|
c9f2d70cc8 | ||
|
af23906d50 | ||
|
0bc60bd7b3 | ||
|
7d45e78401 | ||
|
a879125b47 | ||
|
a1f7f97b95 | ||
|
def6029882 | ||
|
00b0179347 | ||
|
f45cb2f43f | ||
|
d9631b90da | ||
|
ac43fa508c | ||
|
6d55574a65 | ||
|
2cd49cbfab | ||
|
e939c6ed61 | ||
|
340fb41b31 | ||
|
3363278808 | ||
|
b533f658a9 | ||
|
a443bc3496 | ||
|
08cf99629d | ||
|
06ab66cfab | ||
|
6df05bdd17 | ||
|
ecb4e01e34 | ||
|
76ac9940c3 | ||
|
5b2b7dc4e5 | ||
|
536492ebb3 | ||
|
d6fb330f70 | ||
|
6f1834a2ba | ||
|
9ad665df2a | ||
|
a7a5544a3a | ||
|
d4715c4183 | ||
|
bea4acda3b | ||
|
9013dca553 | ||
|
4297c8ee6f | ||
|
6a5b69a959 | ||
|
db237e33c0 | ||
|
61898bc020 | ||
|
0a87466ef3 | ||
|
0acf0a50c8 | ||
|
ec8929a555 | ||
|
b0f49d1387 | ||
|
ad1c7e0faa | ||
|
f7bc8ef809 | ||
|
0b1eaa8803 | ||
|
53a786acac | ||
|
b4f4d54812 | ||
|
bbbf9bfb9c | ||
|
7f6613cedc | ||
|
b9bf8a1abb | ||
|
4e505ddd9a | ||
|
169e4878ee | ||
|
d4cc1a213f | ||
|
db01eedb6d | ||
|
7b770c720b | ||
|
cc8c9d6c6f | ||
|
dc6fb73d21 | ||
|
4fd6a984b9 | ||
|
ae2990c259 | ||
|
131e744a15 | ||
|
839a554757 | ||
|
90c49ef165 | ||
|
e12b2a4fab | ||
|
e279e252ac | ||
|
da0af40dd7 | ||
|
d108609bf9 | ||
|
dac23a6c05 | ||
|
b2c494c3a4 | ||
|
3a87f8b685 | ||
|
71461b0fef | ||
|
29ee324740 | ||
|
5a06393f1d | ||
|
ad4f62d015 | ||
|
6b1566cbe3 | ||
|
30e32af746 | ||
|
a46622fd07 | ||
|
df99d30d4e | ||
|
5ec83c73e5 | ||
|
a80172a476 | ||
|
d197fdbc3b | ||
|
7aaf4957ef | ||
|
06c1bee85a | ||
|
f205da688b | ||
|
2403837e67 | ||
|
d16644ec4c | ||
|
1fe9e2626f | ||
|
1ae1dc5ba2 | ||
|
9a1839164c | ||
|
49a4e21251 | ||
|
d1a1451cd3 | ||
|
037b7addb7 | ||
|
abdffd1fb7 | ||
|
39f72ef94b | ||
|
7e4fb26d75 | ||
|
9561fda8d9 | ||
|
c6aed98334 | ||
|
f5ec6704c7 | ||
|
c8897e8eb9 | ||
|
f5946dbab3 | ||
|
f71e769d07 | ||
|
c01a71c1a5 | ||
|
ec864874bd | ||
|
cfd54a0409 | ||
|
4c8821d134 | ||
|
c1b94a0ed2 | ||
|
319c66d5ab | ||
|
af67ee9264 | ||
|
d2995916ea | ||
|
198fd05c35 | ||
|
20fccb187c | ||
|
b7d769c932 | ||
|
a134d90f50 | ||
|
8a15b813e6 | ||
|
d208cc353a | ||
|
6e6507c06b | ||
|
5a8a30db47 | ||
|
09e037354b | ||
|
0a79bc87c3 | ||
|
f72dbf3d26 | ||
|
ce8f0905a5 | ||
|
22709e90a2 | ||
|
bd16430777 | ||
|
059b3527f0 | ||
|
821e322786 | ||
|
c225aa3c6d | ||
|
2dda43bacc | ||
|
2fd71f1be2 | ||
|
d07e0e9cdd | ||
|
9bcc80cd71 | ||
|
f03bd716a2 | ||
|
798325ed38 | ||
|
39ee3af3a8 | ||
|
5ff020b7b0 | ||
|
1d14ac5af0 | ||
|
3dd46eb496 | ||
|
2f487a3d40 | ||
|
315b593441 | ||
|
cdf0592cb8 | ||
|
4f3ed190a6 | ||
|
b074e62205 | ||
|
7b53f2940e | ||
|
0a1bec8a4e | ||
|
cab0a7ea00 | ||
|
7ea5d7256d | ||
|
a8b12c108c | ||
|
eef0d9e740 | ||
|
a9c7d27bd1 | ||
|
1d0a60681a | ||
|
5f9eb02555 | ||
|
c8fc56cedd | ||
|
aad2f06a7f | ||
|
d801a8f2ce | ||
|
e7bc9004e7 | ||
|
1ed27a17cd | ||
|
c2fb418e35 | ||
|
5553955eb6 | ||
|
5201c13654 | ||
|
8b092ca9ef | ||
|
b6d4443a7b | ||
|
7baeabce1d | ||
|
2ed3ea110f | ||
|
a847f32c04 | ||
|
14dcdac82f | ||
|
03df01ed9a | ||
|
37a706adbf | ||
|
8f0c6758b0 | ||
|
a566da1b02 | ||
|
931c8cc270 | ||
|
261a5b4dd1 | ||
|
04c7c6c261 | ||
|
73a81d10fd | ||
|
6781fa119f | ||
|
c1b876b2e9 | ||
|
b05c306857 | ||
|
f612537e07 | ||
|
10113b6903 | ||
|
cf4ab1af29 | ||
|
a984e42c91 | ||
|
d6d60581f3 | ||
|
ba7500852d | ||
|
4719ab918a | ||
|
b5a3ca3e30 | ||
|
9948c38bd9 | ||
|
87f6396293 | ||
|
2bda66028b | ||
|
298526fe92 | ||
|
881249c792 | ||
|
e0eb210ec0 | ||
|
087edb503a | ||
|
025172d56e | ||
|
83d1c8ae88 | ||
|
0c544d73bb | ||
|
6295b98d7b | ||
|
f4b11eee2f | ||
|
a7ec0f98e3 | ||
|
1c275925bf | ||
|
6b1275ff15 | ||
8d5d30046b | |||
|
3b899ea7d4 | ||
|
7f72cd235f | ||
|
6fffa26244 | ||
|
e638308097 | ||
|
9c749e4dbe | ||
|
379e21c258 | ||
|
a00f66ab9b | ||
|
69df1c3c9d | ||
|
6d4adef48d | ||
|
3b163b0165 | ||
|
f214530f56 | ||
|
9d5614d582 | ||
|
39d16d29c8 | ||
|
cc13eead53 | ||
|
86c3b20a5f | ||
|
6d585ca559 | ||
|
dfb3804d47 | ||
|
4191d0eb41 | ||
|
03d51428e2 | ||
|
582ab779c5 | ||
|
8678b71ce6 | ||
|
1fcc9ddfb3 | ||
|
c6e929e784 | ||
|
b3c56df769 | ||
|
ed7a0aa8bc | ||
|
04ce397b33 | ||
|
14b155ddc4 | ||
|
e029f29385 | ||
|
90f1cd9138 | ||
|
7d11fc7c2b | ||
|
096c46c0ff | ||
|
df9351e372 | ||
|
50573c66eb | ||
|
46dea4160d | ||
|
dc668ded10 | ||
|
1e8ece0db3 | ||
|
4a41a2d68a | ||
|
62e466e845 | ||
|
c3adb58fe0 | ||
|
aa7a6a399f | ||
|
2e323f03bf | ||
|
22956a3755 | ||
|
eee822e359 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,7 @@
|
|||||||
libdis*
|
libdis*
|
||||||
libuser
|
libuser
|
||||||
/linux-headers/asm
|
/linux-headers/asm
|
||||||
|
/qga/qapi-generated
|
||||||
/qapi-generated
|
/qapi-generated
|
||||||
/qapi-types.[ch]
|
/qapi-types.[ch]
|
||||||
/qapi-visit.[ch]
|
/qapi-visit.[ch]
|
||||||
|
53
.travis.yml
53
.travis.yml
@@ -4,6 +4,12 @@ python:
|
|||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- gcc
|
||||||
- clang
|
- clang
|
||||||
|
notifications:
|
||||||
|
irc:
|
||||||
|
channels:
|
||||||
|
- "irc.oftc.net#qemu"
|
||||||
|
on_success: change
|
||||||
|
on_failure: always
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- TEST_CMD="make check"
|
- TEST_CMD="make check"
|
||||||
@@ -14,23 +20,23 @@ env:
|
|||||||
- GUI_PKGS="libgtk-3-dev libvte-2.90-dev libsdl1.2-dev libpng12-dev libpixman-1-dev"
|
- GUI_PKGS="libgtk-3-dev libvte-2.90-dev libsdl1.2-dev libpng12-dev libpixman-1-dev"
|
||||||
- EXTRA_PKGS=""
|
- EXTRA_PKGS=""
|
||||||
matrix:
|
matrix:
|
||||||
- TARGETS=alpha-softmmu,alpha-linux-user
|
- TARGETS=alpha-softmmu,alpha-linux-user
|
||||||
- TARGETS=arm-softmmu,arm-linux-user
|
- TARGETS=arm-softmmu,arm-linux-user
|
||||||
- TARGETS=aarch64-softmmu,aarch64-linux-user
|
- TARGETS=aarch64-softmmu,aarch64-linux-user
|
||||||
- TARGETS=cris-softmmu
|
- TARGETS=cris-softmmu
|
||||||
- TARGETS=i386-softmmu,x86_64-softmmu
|
- TARGETS=i386-softmmu,x86_64-softmmu
|
||||||
- TARGETS=lm32-softmmu
|
- TARGETS=lm32-softmmu
|
||||||
- TARGETS=m68k-softmmu
|
- TARGETS=m68k-softmmu
|
||||||
- TARGETS=microblaze-softmmu,microblazeel-softmmu
|
- TARGETS=microblaze-softmmu,microblazeel-softmmu
|
||||||
- TARGETS=mips-softmmu,mips64-softmmu,mips64el-softmmu,mipsel-softmmu
|
- TARGETS=mips-softmmu,mips64-softmmu,mips64el-softmmu,mipsel-softmmu
|
||||||
- TARGETS=moxie-softmmu
|
- TARGETS=moxie-softmmu
|
||||||
- TARGETS=or32-softmmu,
|
- TARGETS=or32-softmmu,
|
||||||
- TARGETS=ppc-softmmu,ppc64-softmmu,ppcemb-softmmu
|
- TARGETS=ppc-softmmu,ppc64-softmmu,ppcemb-softmmu
|
||||||
- TARGETS=s390x-softmmu
|
- TARGETS=s390x-softmmu
|
||||||
- TARGETS=sh4-softmmu,sh4eb-softmmu
|
- TARGETS=sh4-softmmu,sh4eb-softmmu
|
||||||
- TARGETS=sparc-softmmu,sparc64-softmmu
|
- TARGETS=sparc-softmmu,sparc64-softmmu
|
||||||
- TARGETS=unicore32-softmmu
|
- TARGETS=unicore32-softmmu
|
||||||
- TARGETS=xtensa-softmmu,xtensaeb-softmmu
|
- TARGETS=xtensa-softmmu,xtensaeb-softmmu
|
||||||
before_install:
|
before_install:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
@@ -46,6 +52,10 @@ matrix:
|
|||||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||||
EXTRA_CONFIG="--enable-debug --enable-tcg-interpreter"
|
EXTRA_CONFIG="--enable-debug --enable-tcg-interpreter"
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
|
# All the extra -dev packages
|
||||||
|
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||||
|
EXTRA_PKGS="libaio-dev libcap-ng-dev libattr1-dev libbrlapi-dev uuid-dev libusb-1.0.0-dev"
|
||||||
|
compiler: gcc
|
||||||
# Currently configure doesn't force --disable-pie
|
# Currently configure doesn't force --disable-pie
|
||||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||||
EXTRA_CONFIG="--enable-gprof --enable-gcov --disable-pie"
|
EXTRA_CONFIG="--enable-gprof --enable-gcov --disable-pie"
|
||||||
@@ -65,8 +75,7 @@ matrix:
|
|||||||
EXTRA_CONFIG="--enable-trace-backend=ftrace"
|
EXTRA_CONFIG="--enable-trace-backend=ftrace"
|
||||||
TEST_CMD=""
|
TEST_CMD=""
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
# This disabled make check for the ftrace backend which needs more setting up
|
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||||
# Currently broken on 12.04 due to mis-packaged liburcu and changed API, will be pulled.
|
EXTRA_PKGS="liblttng-ust-dev liburcu-dev"
|
||||||
#- env: TARGETS=i386-softmmu,x86_64-softmmu
|
EXTRA_CONFIG="--enable-trace-backend=ust"
|
||||||
# EXTRA_PKGS="liblttng-ust-dev liburcu-dev"
|
compiler: gcc
|
||||||
# EXTRA_CONFIG="--enable-trace-backend=ust"
|
|
||||||
|
@@ -84,3 +84,10 @@ and clarity it comes on a line by itself:
|
|||||||
Rationale: a consistent (except for functions...) bracing style reduces
|
Rationale: a consistent (except for functions...) bracing style reduces
|
||||||
ambiguity and avoids needless churn when lines are added or removed.
|
ambiguity and avoids needless churn when lines are added or removed.
|
||||||
Furthermore, it is the QEMU coding style.
|
Furthermore, it is the QEMU coding style.
|
||||||
|
|
||||||
|
5. Declarations
|
||||||
|
|
||||||
|
Mixed declarations (interleaving statements and declarations within blocks)
|
||||||
|
are not allowed; declarations should be at the beginning of blocks. In other
|
||||||
|
words, the code should not generate warnings if using GCC's
|
||||||
|
-Wdeclaration-after-statement option.
|
||||||
|
15
MAINTAINERS
15
MAINTAINERS
@@ -304,7 +304,7 @@ S: Maintained
|
|||||||
F: hw/*/versatile*
|
F: hw/*/versatile*
|
||||||
|
|
||||||
Xilinx Zynq
|
Xilinx Zynq
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/arm/xilinx_zynq.c
|
F: hw/arm/xilinx_zynq.c
|
||||||
F: hw/misc/zynq_slcr.c
|
F: hw/misc/zynq_slcr.c
|
||||||
@@ -353,7 +353,7 @@ S: Maintained
|
|||||||
F: hw/microblaze/petalogix_s3adsp1800_mmu.c
|
F: hw/microblaze/petalogix_s3adsp1800_mmu.c
|
||||||
|
|
||||||
petalogix_ml605
|
petalogix_ml605
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/microblaze/petalogix_ml605_mmu.c
|
F: hw/microblaze/petalogix_ml605_mmu.c
|
||||||
|
|
||||||
@@ -592,7 +592,7 @@ S: Orphan
|
|||||||
F: hw/scsi/lsi53c895a.c
|
F: hw/scsi/lsi53c895a.c
|
||||||
|
|
||||||
SSI
|
SSI
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/ssi/*
|
F: hw/ssi/*
|
||||||
F: hw/block/m25p80.c
|
F: hw/block/m25p80.c
|
||||||
@@ -623,6 +623,7 @@ M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: hw/9pfs/
|
F: hw/9pfs/
|
||||||
F: fsdev/
|
F: fsdev/
|
||||||
|
F: tests/virtio-9p-test.c
|
||||||
T: git git://github.com/kvaneesh/QEMU.git
|
T: git git://github.com/kvaneesh/QEMU.git
|
||||||
|
|
||||||
virtio-blk
|
virtio-blk
|
||||||
@@ -648,9 +649,10 @@ nvme
|
|||||||
M: Keith Busch <keith.busch@intel.com>
|
M: Keith Busch <keith.busch@intel.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: hw/block/nvme*
|
F: hw/block/nvme*
|
||||||
|
F: tests/nvme-test.c
|
||||||
|
|
||||||
Xilinx EDK
|
Xilinx EDK
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/*/xilinx_*
|
F: hw/*/xilinx_*
|
||||||
@@ -694,7 +696,7 @@ F: include/hw/cpu/icc_bus.h
|
|||||||
F: hw/cpu/icc_bus.c
|
F: hw/cpu/icc_bus.c
|
||||||
|
|
||||||
Device Tree
|
Device Tree
|
||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
M: Alexander Graf <agraf@suse.de>
|
M: Alexander Graf <agraf@suse.de>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: device_tree.[ch]
|
F: device_tree.[ch]
|
||||||
@@ -715,7 +717,8 @@ F: hw/display/qxl*
|
|||||||
|
|
||||||
Graphics
|
Graphics
|
||||||
M: Anthony Liguori <aliguori@amazon.com>
|
M: Anthony Liguori <aliguori@amazon.com>
|
||||||
S: Maintained
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
|
S: Odd Fixes
|
||||||
F: ui/
|
F: ui/
|
||||||
|
|
||||||
Cocoa graphics
|
Cocoa graphics
|
||||||
|
5
Makefile
5
Makefile
@@ -265,10 +265,7 @@ clean:
|
|||||||
# avoid old build problems by removing potentially incorrect old files
|
# avoid old build problems by removing potentially incorrect old files
|
||||||
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||||
rm -f qemu-options.def
|
rm -f qemu-options.def
|
||||||
find . -name '*.[oda]' -type f -exec rm -f {} +
|
find . \( -name '*.l[oa]' -o -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||||
find . -name '*.l[oa]' -type f -exec rm -f {} +
|
|
||||||
find . -name '*$(DSOSUF)' -type f -exec rm -f {} +
|
|
||||||
find . -name '*.mo' -type f -exec rm -f {} +
|
|
||||||
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||||
rm -f fsdev/*.pod
|
rm -f fsdev/*.pod
|
||||||
rm -rf .libs */.libs
|
rm -rf .libs */.libs
|
||||||
|
@@ -566,8 +566,10 @@ CharDriverState *chr_baum_init(void)
|
|||||||
BaumDriverState *baum;
|
BaumDriverState *baum;
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
brlapi_handle_t *handle;
|
brlapi_handle_t *handle;
|
||||||
#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
#if defined(CONFIG_SDL)
|
||||||
|
#if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||||
SDL_SysWMinfo info;
|
SDL_SysWMinfo info;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
int tty;
|
int tty;
|
||||||
|
|
||||||
@@ -595,12 +597,14 @@ CharDriverState *chr_baum_init(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
#if defined(CONFIG_SDL)
|
||||||
|
#if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
SDL_VERSION(&info.version);
|
SDL_VERSION(&info.version);
|
||||||
if (SDL_GetWMInfo(&info))
|
if (SDL_GetWMInfo(&info))
|
||||||
tty = info.info.x11.wmwindow;
|
tty = info.info.x11.wmwindow;
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
tty = BRLAPI_TTY_DEFAULT;
|
tty = BRLAPI_TTY_DEFAULT;
|
||||||
|
|
||||||
|
202
block.c
202
block.c
@@ -767,6 +767,11 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
|||||||
{
|
{
|
||||||
int open_flags = flags | BDRV_O_CACHE_WB;
|
int open_flags = flags | BDRV_O_CACHE_WB;
|
||||||
|
|
||||||
|
/* The backing file of a temporary snapshot is read-only */
|
||||||
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
|
open_flags &= ~BDRV_O_RDWR;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear flags that are internal to the block layer before opening the
|
* Clear flags that are internal to the block layer before opening the
|
||||||
* image.
|
* image.
|
||||||
@@ -968,7 +973,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
{
|
{
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
const char *drvname;
|
const char *drvname;
|
||||||
bool allow_protocol_prefix = false;
|
bool parse_filename = false;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -977,7 +982,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
filename = qdict_get_try_str(*options, "filename");
|
filename = qdict_get_try_str(*options, "filename");
|
||||||
} else if (filename && !qdict_haskey(*options, "filename")) {
|
} else if (filename && !qdict_haskey(*options, "filename")) {
|
||||||
qdict_put(*options, "filename", qstring_from_str(filename));
|
qdict_put(*options, "filename", qstring_from_str(filename));
|
||||||
allow_protocol_prefix = true;
|
parse_filename = true;
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "Can't specify 'file' and 'filename' options at the "
|
error_setg(errp, "Can't specify 'file' and 'filename' options at the "
|
||||||
"same time");
|
"same time");
|
||||||
@@ -994,7 +999,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
}
|
}
|
||||||
qdict_del(*options, "driver");
|
qdict_del(*options, "driver");
|
||||||
} else if (filename) {
|
} else if (filename) {
|
||||||
drv = bdrv_find_protocol(filename, allow_protocol_prefix);
|
drv = bdrv_find_protocol(filename, parse_filename);
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_setg(errp, "Unknown protocol");
|
error_setg(errp, "Unknown protocol");
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1015,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the filename and open it */
|
/* Parse the filename and open it */
|
||||||
if (drv->bdrv_parse_filename && filename) {
|
if (drv->bdrv_parse_filename && parse_filename) {
|
||||||
drv->bdrv_parse_filename(filename, *options, &local_err);
|
drv->bdrv_parse_filename(filename, *options, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
@@ -1162,6 +1167,73 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||||
|
char tmp_filename[PATH_MAX + 1];
|
||||||
|
|
||||||
|
int64_t total_size;
|
||||||
|
BlockDriver *bdrv_qcow2;
|
||||||
|
QEMUOptionParameter *create_options;
|
||||||
|
QDict *snapshot_options;
|
||||||
|
BlockDriverState *bs_snapshot;
|
||||||
|
Error *local_err;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* if snapshot, we create a temporary backing file and open it
|
||||||
|
instead of opening 'filename' directly */
|
||||||
|
|
||||||
|
/* Get the required size from the image */
|
||||||
|
total_size = bdrv_getlength(bs);
|
||||||
|
if (total_size < 0) {
|
||||||
|
error_setg_errno(errp, -total_size, "Could not get image size");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
total_size &= BDRV_SECTOR_MASK;
|
||||||
|
|
||||||
|
/* Create the temporary image */
|
||||||
|
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_qcow2 = bdrv_find_format("qcow2");
|
||||||
|
create_options = parse_option_parameters("", bdrv_qcow2->create_options,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
|
||||||
|
|
||||||
|
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
|
||||||
|
free_option_parameters(create_options);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
||||||
|
"'%s': %s", tmp_filename,
|
||||||
|
error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare a new options QDict for the temporary file */
|
||||||
|
snapshot_options = qdict_new();
|
||||||
|
qdict_put(snapshot_options, "file.driver",
|
||||||
|
qstring_from_str("file"));
|
||||||
|
qdict_put(snapshot_options, "file.filename",
|
||||||
|
qstring_from_str(tmp_filename));
|
||||||
|
|
||||||
|
bs_snapshot = bdrv_new("");
|
||||||
|
bs_snapshot->is_temporary = 1;
|
||||||
|
|
||||||
|
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||||
|
bs->open_flags & ~BDRV_O_SNAPSHOT, bdrv_qcow2, &local_err);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_append(bs_snapshot, bs);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||||
*
|
*
|
||||||
@@ -1182,8 +1254,6 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
BlockDriver *drv, Error **errp)
|
BlockDriver *drv, Error **errp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
|
||||||
char tmp_filename[PATH_MAX + 1];
|
|
||||||
BlockDriverState *file = NULL, *bs;
|
BlockDriverState *file = NULL, *bs;
|
||||||
const char *drvname;
|
const char *drvname;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@@ -1243,74 +1313,6 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For snapshot=on, create a temporary qcow2 overlay */
|
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
|
||||||
BlockDriverState *bs1;
|
|
||||||
int64_t total_size;
|
|
||||||
BlockDriver *bdrv_qcow2;
|
|
||||||
QEMUOptionParameter *create_options;
|
|
||||||
QDict *snapshot_options;
|
|
||||||
|
|
||||||
/* if snapshot, we create a temporary backing file and open it
|
|
||||||
instead of opening 'filename' directly */
|
|
||||||
|
|
||||||
/* Get the required size from the image */
|
|
||||||
QINCREF(options);
|
|
||||||
bs1 = NULL;
|
|
||||||
ret = bdrv_open(&bs1, filename, NULL, options, BDRV_O_NO_BACKING,
|
|
||||||
drv, &local_err);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
|
|
||||||
|
|
||||||
bdrv_unref(bs1);
|
|
||||||
|
|
||||||
/* Create the temporary image */
|
|
||||||
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
bdrv_qcow2 = bdrv_find_format("qcow2");
|
|
||||||
create_options = parse_option_parameters("", bdrv_qcow2->create_options,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
|
|
||||||
|
|
||||||
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
|
|
||||||
free_option_parameters(create_options);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
|
||||||
"'%s': %s", tmp_filename,
|
|
||||||
error_get_pretty(local_err));
|
|
||||||
error_free(local_err);
|
|
||||||
local_err = NULL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare a new options QDict for the temporary file, where user
|
|
||||||
* options refer to the backing file */
|
|
||||||
if (filename) {
|
|
||||||
qdict_put(options, "file.filename", qstring_from_str(filename));
|
|
||||||
}
|
|
||||||
if (drv) {
|
|
||||||
qdict_put(options, "driver", qstring_from_str(drv->format_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
snapshot_options = qdict_new();
|
|
||||||
qdict_put(snapshot_options, "backing", options);
|
|
||||||
qdict_flatten(snapshot_options);
|
|
||||||
|
|
||||||
bs->options = snapshot_options;
|
|
||||||
options = qdict_clone_shallow(bs->options);
|
|
||||||
|
|
||||||
filename = tmp_filename;
|
|
||||||
drv = bdrv_qcow2;
|
|
||||||
bs->is_temporary = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open image file without format layer */
|
/* Open image file without format layer */
|
||||||
if (flags & BDRV_O_RDWR) {
|
if (flags & BDRV_O_RDWR) {
|
||||||
flags |= BDRV_O_ALLOW_RDWR;
|
flags |= BDRV_O_ALLOW_RDWR;
|
||||||
@@ -1372,6 +1374,17 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
|
||||||
|
* temporary snapshot afterwards. */
|
||||||
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
|
bdrv_append_temp_snapshot(bs, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
goto close_and_fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* Check if any unknown options were used */
|
/* Check if any unknown options were used */
|
||||||
if (options && (qdict_size(options) != 0)) {
|
if (options && (qdict_size(options) != 0)) {
|
||||||
@@ -1388,12 +1401,19 @@ done:
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto close_and_fail;
|
goto close_and_fail;
|
||||||
}
|
}
|
||||||
QDECREF(options);
|
|
||||||
|
|
||||||
if (!bdrv_key_required(bs)) {
|
if (!bdrv_key_required(bs)) {
|
||||||
bdrv_dev_change_media_cb(bs, true);
|
bdrv_dev_change_media_cb(bs, true);
|
||||||
|
} else if (!runstate_check(RUN_STATE_PRELAUNCH)
|
||||||
|
&& !runstate_check(RUN_STATE_INMIGRATE)
|
||||||
|
&& !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
|
||||||
|
error_setg(errp,
|
||||||
|
"Guest must be stopped for opening of encrypted image");
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto close_and_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDECREF(options);
|
||||||
*pbs = bs;
|
*pbs = bs;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -2581,6 +2601,10 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
|||||||
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors)
|
int nb_sectors)
|
||||||
{
|
{
|
||||||
|
if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
|
return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
|
||||||
nb_sectors * BDRV_SECTOR_SIZE);
|
nb_sectors * BDRV_SECTOR_SIZE);
|
||||||
}
|
}
|
||||||
@@ -4774,27 +4798,43 @@ flush_parent:
|
|||||||
return bdrv_co_flush(bs->file);
|
return bdrv_co_flush(bs->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_invalidate_cache(BlockDriverState *bs)
|
void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!bs->drv) {
|
if (!bs->drv) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->drv->bdrv_invalidate_cache) {
|
if (bs->drv->bdrv_invalidate_cache) {
|
||||||
bs->drv->bdrv_invalidate_cache(bs);
|
bs->drv->bdrv_invalidate_cache(bs, &local_err);
|
||||||
} else if (bs->file) {
|
} else if (bs->file) {
|
||||||
bdrv_invalidate_cache(bs->file);
|
bdrv_invalidate_cache(bs->file, &local_err);
|
||||||
|
}
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh_total_sectors(bs, bs->total_sectors);
|
ret = refresh_total_sectors(bs, bs->total_sectors);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Could not refresh total sector count");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_invalidate_cache_all(void)
|
void bdrv_invalidate_cache_all(Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||||
bdrv_invalidate_cache(bs);
|
bdrv_invalidate_cache(bs, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
109
block/bochs.c
109
block/bochs.c
@@ -38,57 +38,42 @@
|
|||||||
|
|
||||||
// not allocated: 0xffffffff
|
// not allocated: 0xffffffff
|
||||||
|
|
||||||
// always little-endian
|
|
||||||
struct bochs_header_v1 {
|
|
||||||
char magic[32]; // "Bochs Virtual HD Image"
|
|
||||||
char type[16]; // "Redolog"
|
|
||||||
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
|
||||||
uint32_t version;
|
|
||||||
uint32_t header; // size of header
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint32_t catalog; // num of entries
|
|
||||||
uint32_t bitmap; // bitmap size
|
|
||||||
uint32_t extent; // extent size
|
|
||||||
uint64_t disk; // disk size
|
|
||||||
char padding[HEADER_SIZE - 64 - 8 - 20];
|
|
||||||
} redolog;
|
|
||||||
char padding[HEADER_SIZE - 64 - 8];
|
|
||||||
} extra;
|
|
||||||
};
|
|
||||||
|
|
||||||
// always little-endian
|
// always little-endian
|
||||||
struct bochs_header {
|
struct bochs_header {
|
||||||
char magic[32]; // "Bochs Virtual HD Image"
|
char magic[32]; /* "Bochs Virtual HD Image" */
|
||||||
char type[16]; // "Redolog"
|
char type[16]; /* "Redolog" */
|
||||||
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
char subtype[16]; /* "Undoable" / "Volatile" / "Growing" */
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t header; // size of header
|
uint32_t header; /* size of header */
|
||||||
|
|
||||||
|
uint32_t catalog; /* num of entries */
|
||||||
|
uint32_t bitmap; /* bitmap size */
|
||||||
|
uint32_t extent; /* extent size */
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t catalog; // num of entries
|
uint32_t reserved; /* for ??? */
|
||||||
uint32_t bitmap; // bitmap size
|
uint64_t disk; /* disk size */
|
||||||
uint32_t extent; // extent size
|
char padding[HEADER_SIZE - 64 - 20 - 12];
|
||||||
uint32_t reserved; // for ???
|
} QEMU_PACKED redolog;
|
||||||
uint64_t disk; // disk size
|
struct {
|
||||||
char padding[HEADER_SIZE - 64 - 8 - 24];
|
uint64_t disk; /* disk size */
|
||||||
} redolog;
|
char padding[HEADER_SIZE - 64 - 20 - 8];
|
||||||
char padding[HEADER_SIZE - 64 - 8];
|
} QEMU_PACKED redolog_v1;
|
||||||
|
char padding[HEADER_SIZE - 64 - 20];
|
||||||
} extra;
|
} extra;
|
||||||
};
|
} QEMU_PACKED;
|
||||||
|
|
||||||
typedef struct BDRVBochsState {
|
typedef struct BDRVBochsState {
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
uint32_t *catalog_bitmap;
|
uint32_t *catalog_bitmap;
|
||||||
int catalog_size;
|
uint32_t catalog_size;
|
||||||
|
|
||||||
int data_offset;
|
uint32_t data_offset;
|
||||||
|
|
||||||
int bitmap_blocks;
|
uint32_t bitmap_blocks;
|
||||||
int extent_blocks;
|
uint32_t extent_blocks;
|
||||||
int extent_size;
|
uint32_t extent_size;
|
||||||
} BDRVBochsState;
|
} BDRVBochsState;
|
||||||
|
|
||||||
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
@@ -112,9 +97,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BDRVBochsState *s = bs->opaque;
|
BDRVBochsState *s = bs->opaque;
|
||||||
int i;
|
uint32_t i;
|
||||||
struct bochs_header bochs;
|
struct bochs_header bochs;
|
||||||
struct bochs_header_v1 header_v1;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
bs->read_only = 1; // no write support yet
|
bs->read_only = 1; // no write support yet
|
||||||
@@ -134,13 +118,19 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (le32_to_cpu(bochs.version) == HEADER_V1) {
|
if (le32_to_cpu(bochs.version) == HEADER_V1) {
|
||||||
memcpy(&header_v1, &bochs, sizeof(bochs));
|
bs->total_sectors = le64_to_cpu(bochs.extra.redolog_v1.disk) / 512;
|
||||||
bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
|
|
||||||
} else {
|
} else {
|
||||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Limit to 1M entries to avoid unbounded allocation. This is what is
|
||||||
|
* needed for the largest image that bximage can create (~8 TB). */
|
||||||
|
s->catalog_size = le32_to_cpu(bochs.catalog);
|
||||||
|
if (s->catalog_size > 0x100000) {
|
||||||
|
error_setg(errp, "Catalog size is too large");
|
||||||
|
return -EFBIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
|
|
||||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
||||||
@@ -154,10 +144,24 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
|
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
|
||||||
|
|
||||||
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
|
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.bitmap) - 1) / 512;
|
||||||
s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
|
s->extent_blocks = 1 + (le32_to_cpu(bochs.extent) - 1) / 512;
|
||||||
|
|
||||||
s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
|
s->extent_size = le32_to_cpu(bochs.extent);
|
||||||
|
if (s->extent_size == 0) {
|
||||||
|
error_setg(errp, "Extent size may not be zero");
|
||||||
|
return -EINVAL;
|
||||||
|
} else if (s->extent_size > 0x800000) {
|
||||||
|
error_setg(errp, "Extent size %" PRIu32 " is too large",
|
||||||
|
s->extent_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->catalog_size < bs->total_sectors / s->extent_size) {
|
||||||
|
error_setg(errp, "Catalog size is too small for this disk size");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_co_mutex_init(&s->lock);
|
qemu_co_mutex_init(&s->lock);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -170,8 +174,8 @@ fail:
|
|||||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||||
{
|
{
|
||||||
BDRVBochsState *s = bs->opaque;
|
BDRVBochsState *s = bs->opaque;
|
||||||
int64_t offset = sector_num * 512;
|
uint64_t offset = sector_num * 512;
|
||||||
int64_t extent_index, extent_offset, bitmap_offset;
|
uint64_t extent_index, extent_offset, bitmap_offset;
|
||||||
char bitmap_entry;
|
char bitmap_entry;
|
||||||
|
|
||||||
// seek to sector
|
// seek to sector
|
||||||
@@ -182,8 +186,9 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
|||||||
return -1; /* not allocated */
|
return -1; /* not allocated */
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
|
bitmap_offset = s->data_offset +
|
||||||
(s->extent_blocks + s->bitmap_blocks));
|
(512 * (uint64_t) s->catalog_bitmap[extent_index] *
|
||||||
|
(s->extent_blocks + s->bitmap_blocks));
|
||||||
|
|
||||||
/* read in bitmap for current extent */
|
/* read in bitmap for current extent */
|
||||||
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||||
|
@@ -26,6 +26,9 @@
|
|||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
/* Maximum compressed block size */
|
||||||
|
#define MAX_BLOCK_SIZE (64 * 1024 * 1024)
|
||||||
|
|
||||||
typedef struct BDRVCloopState {
|
typedef struct BDRVCloopState {
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
@@ -68,6 +71,26 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
s->block_size = be32_to_cpu(s->block_size);
|
s->block_size = be32_to_cpu(s->block_size);
|
||||||
|
if (s->block_size % 512) {
|
||||||
|
error_setg(errp, "block_size %u must be a multiple of 512",
|
||||||
|
s->block_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (s->block_size == 0) {
|
||||||
|
error_setg(errp, "block_size cannot be zero");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cloop's create_compressed_fs.c warns about block sizes beyond 256 KB but
|
||||||
|
* we can accept more. Prevent ridiculous values like 4 GB - 1 since we
|
||||||
|
* need a buffer this big.
|
||||||
|
*/
|
||||||
|
if (s->block_size > MAX_BLOCK_SIZE) {
|
||||||
|
error_setg(errp, "block_size %u must be %u MB or less",
|
||||||
|
s->block_size,
|
||||||
|
MAX_BLOCK_SIZE / (1024 * 1024));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -76,7 +99,23 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->n_blocks = be32_to_cpu(s->n_blocks);
|
s->n_blocks = be32_to_cpu(s->n_blocks);
|
||||||
|
|
||||||
/* read offsets */
|
/* read offsets */
|
||||||
offsets_size = s->n_blocks * sizeof(uint64_t);
|
if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
||||||
|
/* Prevent integer overflow */
|
||||||
|
error_setg(errp, "n_blocks %u must be %zu or less",
|
||||||
|
s->n_blocks,
|
||||||
|
(UINT32_MAX - 1) / sizeof(uint64_t));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
|
||||||
|
if (offsets_size > 512 * 1024 * 1024) {
|
||||||
|
/* Prevent ridiculous offsets_size which causes memory allocation to
|
||||||
|
* fail or overflows bdrv_pread() size. In practice the 512 MB
|
||||||
|
* offsets[] limit supports 16 TB images at 256 KB block size.
|
||||||
|
*/
|
||||||
|
error_setg(errp, "image requires too many offsets, "
|
||||||
|
"try increasing block size");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
s->offsets = g_malloc(offsets_size);
|
s->offsets = g_malloc(offsets_size);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
||||||
@@ -84,13 +123,37 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0;i<s->n_blocks;i++) {
|
for (i = 0; i < s->n_blocks + 1; i++) {
|
||||||
|
uint64_t size;
|
||||||
|
|
||||||
s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
||||||
if (i > 0) {
|
if (i == 0) {
|
||||||
uint32_t size = s->offsets[i] - s->offsets[i - 1];
|
continue;
|
||||||
if (size > max_compressed_block_size) {
|
}
|
||||||
max_compressed_block_size = size;
|
|
||||||
}
|
if (s->offsets[i] < s->offsets[i - 1]) {
|
||||||
|
error_setg(errp, "offsets not monotonically increasing at "
|
||||||
|
"index %u, image file is corrupt", i);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = s->offsets[i] - s->offsets[i - 1];
|
||||||
|
|
||||||
|
/* Compressed blocks should be smaller than the uncompressed block size
|
||||||
|
* but maybe compression performed poorly so the compressed block is
|
||||||
|
* actually bigger. Clamp down on unrealistic values to prevent
|
||||||
|
* ridiculous s->compressed_block allocation.
|
||||||
|
*/
|
||||||
|
if (size > 2 * MAX_BLOCK_SIZE) {
|
||||||
|
error_setg(errp, "invalid compressed block size at index %u, "
|
||||||
|
"image file is corrupt", i);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > max_compressed_block_size) {
|
||||||
|
max_compressed_block_size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,9 +243,7 @@ static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
static void cloop_close(BlockDriverState *bs)
|
static void cloop_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVCloopState *s = bs->opaque;
|
BDRVCloopState *s = bs->opaque;
|
||||||
if (s->n_blocks > 0) {
|
g_free(s->offsets);
|
||||||
g_free(s->offsets);
|
|
||||||
}
|
|
||||||
g_free(s->compressed_block);
|
g_free(s->compressed_block);
|
||||||
g_free(s->uncompressed_block);
|
g_free(s->uncompressed_block);
|
||||||
inflateEnd(&s->zstream);
|
inflateEnd(&s->zstream);
|
||||||
|
@@ -157,6 +157,11 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|||||||
if (!s || !s->orig_buf)
|
if (!s || !s->orig_buf)
|
||||||
goto read_end;
|
goto read_end;
|
||||||
|
|
||||||
|
if (s->buf_off >= s->buf_len) {
|
||||||
|
/* buffer full, read nothing */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
realsize = MIN(realsize, s->buf_len - s->buf_off);
|
||||||
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
|
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
|
||||||
s->buf_off += realsize;
|
s->buf_off += realsize;
|
||||||
|
|
||||||
|
269
block/dmg.c
269
block/dmg.c
@@ -27,6 +27,14 @@
|
|||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* Limit chunk sizes to prevent unreasonable amounts of memory being used
|
||||||
|
* or truncating when converting to 32-bit types
|
||||||
|
*/
|
||||||
|
DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */
|
||||||
|
DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct BDRVDMGState {
|
typedef struct BDRVDMGState {
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
/* each chunk contains a certain number of sectors,
|
/* each chunk contains a certain number of sectors,
|
||||||
@@ -92,13 +100,44 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Increase max chunk sizes, if necessary. This function is used to calculate
|
||||||
|
* the buffer sizes needed for compressed/uncompressed chunk I/O.
|
||||||
|
*/
|
||||||
|
static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
|
||||||
|
uint32_t *max_compressed_size,
|
||||||
|
uint32_t *max_sectors_per_chunk)
|
||||||
|
{
|
||||||
|
uint32_t compressed_size = 0;
|
||||||
|
uint32_t uncompressed_sectors = 0;
|
||||||
|
|
||||||
|
switch (s->types[chunk]) {
|
||||||
|
case 0x80000005: /* zlib compressed */
|
||||||
|
compressed_size = s->lengths[chunk];
|
||||||
|
uncompressed_sectors = s->sectorcounts[chunk];
|
||||||
|
break;
|
||||||
|
case 1: /* copy */
|
||||||
|
uncompressed_sectors = (s->lengths[chunk] + 511) / 512;
|
||||||
|
break;
|
||||||
|
case 2: /* zero */
|
||||||
|
uncompressed_sectors = s->sectorcounts[chunk];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compressed_size > *max_compressed_size) {
|
||||||
|
*max_compressed_size = compressed_size;
|
||||||
|
}
|
||||||
|
if (uncompressed_sectors > *max_sectors_per_chunk) {
|
||||||
|
*max_sectors_per_chunk = uncompressed_sectors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BDRVDMGState *s = bs->opaque;
|
BDRVDMGState *s = bs->opaque;
|
||||||
uint64_t info_begin,info_end,last_in_offset,last_out_offset;
|
uint64_t info_begin, info_end, last_in_offset, last_out_offset;
|
||||||
uint32_t count, tmp;
|
uint32_t count, tmp;
|
||||||
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
|
uint32_t max_compressed_size = 1, max_sectors_per_chunk = 1, i;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -160,37 +199,40 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == 0x6d697368 && count >= 244) {
|
if (type == 0x6d697368 && count >= 244) {
|
||||||
int new_size, chunk_count;
|
size_t new_size;
|
||||||
|
uint32_t chunk_count;
|
||||||
|
|
||||||
offset += 4;
|
offset += 4;
|
||||||
offset += 200;
|
offset += 200;
|
||||||
|
|
||||||
chunk_count = (count-204)/40;
|
chunk_count = (count - 204) / 40;
|
||||||
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
||||||
s->types = g_realloc(s->types, new_size/2);
|
s->types = g_realloc(s->types, new_size / 2);
|
||||||
s->offsets = g_realloc(s->offsets, new_size);
|
s->offsets = g_realloc(s->offsets, new_size);
|
||||||
s->lengths = g_realloc(s->lengths, new_size);
|
s->lengths = g_realloc(s->lengths, new_size);
|
||||||
s->sectors = g_realloc(s->sectors, new_size);
|
s->sectors = g_realloc(s->sectors, new_size);
|
||||||
s->sectorcounts = g_realloc(s->sectorcounts, new_size);
|
s->sectorcounts = g_realloc(s->sectorcounts, new_size);
|
||||||
|
|
||||||
for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
|
for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
|
||||||
ret = read_uint32(bs, offset, &s->types[i]);
|
ret = read_uint32(bs, offset, &s->types[i]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
offset += 4;
|
offset += 4;
|
||||||
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
|
if (s->types[i] != 0x80000005 && s->types[i] != 1 &&
|
||||||
if(s->types[i]==0xffffffff) {
|
s->types[i] != 2) {
|
||||||
last_in_offset = s->offsets[i-1]+s->lengths[i-1];
|
if (s->types[i] == 0xffffffff && i > 0) {
|
||||||
last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
|
last_in_offset = s->offsets[i - 1] + s->lengths[i - 1];
|
||||||
}
|
last_out_offset = s->sectors[i - 1] +
|
||||||
chunk_count--;
|
s->sectorcounts[i - 1];
|
||||||
i--;
|
}
|
||||||
offset += 36;
|
chunk_count--;
|
||||||
continue;
|
i--;
|
||||||
}
|
offset += 36;
|
||||||
offset += 4;
|
continue;
|
||||||
|
}
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
ret = read_uint64(bs, offset, &s->sectors[i]);
|
ret = read_uint64(bs, offset, &s->sectors[i]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -205,6 +247,14 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
|
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
||||||
|
error_report("sector count %" PRIu64 " for chunk %u is "
|
||||||
|
"larger than max (%u)",
|
||||||
|
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
ret = read_uint64(bs, offset, &s->offsets[i]);
|
ret = read_uint64(bs, offset, &s->offsets[i]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -218,19 +268,25 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
if(s->lengths[i]>max_compressed_size)
|
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
||||||
max_compressed_size = s->lengths[i];
|
error_report("length %" PRIu64 " for chunk %u is larger "
|
||||||
if(s->sectorcounts[i]>max_sectors_per_chunk)
|
"than max (%u)",
|
||||||
max_sectors_per_chunk = s->sectorcounts[i];
|
s->lengths[i], i, DMG_LENGTHS_MAX);
|
||||||
}
|
ret = -EINVAL;
|
||||||
s->n_chunks+=chunk_count;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_max_chunk_size(s, i, &max_compressed_size,
|
||||||
|
&max_sectors_per_chunk);
|
||||||
|
}
|
||||||
|
s->n_chunks += chunk_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize zlib engine */
|
/* initialize zlib engine */
|
||||||
s->compressed_chunk = g_malloc(max_compressed_size+1);
|
s->compressed_chunk = g_malloc(max_compressed_size + 1);
|
||||||
s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
|
s->uncompressed_chunk = g_malloc(512 * max_sectors_per_chunk);
|
||||||
if(inflateInit(&s->zstream) != Z_OK) {
|
if (inflateInit(&s->zstream) != Z_OK) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -252,83 +308,82 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
||||||
uint32_t chunk_num,int sector_num)
|
uint32_t chunk_num, uint64_t sector_num)
|
||||||
{
|
{
|
||||||
if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num ||
|
if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num ||
|
||||||
s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
|
s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) {
|
||||||
return 0;
|
return 0;
|
||||||
else
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
|
static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num)
|
||||||
{
|
{
|
||||||
/* binary search */
|
/* binary search */
|
||||||
uint32_t chunk1=0,chunk2=s->n_chunks,chunk3;
|
uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3;
|
||||||
while(chunk1!=chunk2) {
|
while (chunk1 != chunk2) {
|
||||||
chunk3 = (chunk1+chunk2)/2;
|
chunk3 = (chunk1 + chunk2) / 2;
|
||||||
if(s->sectors[chunk3]>sector_num)
|
if (s->sectors[chunk3] > sector_num) {
|
||||||
chunk2 = chunk3;
|
chunk2 = chunk3;
|
||||||
else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
|
} else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) {
|
||||||
return chunk3;
|
return chunk3;
|
||||||
else
|
} else {
|
||||||
chunk1 = chunk3;
|
chunk1 = chunk3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s->n_chunks; /* error */
|
return s->n_chunks; /* error */
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
||||||
{
|
{
|
||||||
BDRVDMGState *s = bs->opaque;
|
BDRVDMGState *s = bs->opaque;
|
||||||
|
|
||||||
if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
|
if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) {
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t chunk = search_chunk(s,sector_num);
|
uint32_t chunk = search_chunk(s, sector_num);
|
||||||
|
|
||||||
if(chunk>=s->n_chunks)
|
if (chunk >= s->n_chunks) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
s->current_chunk = s->n_chunks;
|
s->current_chunk = s->n_chunks;
|
||||||
switch(s->types[chunk]) {
|
switch (s->types[chunk]) {
|
||||||
case 0x80000005: { /* zlib compressed */
|
case 0x80000005: { /* zlib compressed */
|
||||||
int i;
|
/* we need to buffer, because only the chunk as whole can be
|
||||||
|
* inflated. */
|
||||||
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
|
s->compressed_chunk, s->lengths[chunk]);
|
||||||
|
if (ret != s->lengths[chunk]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* we need to buffer, because only the chunk as whole can be
|
s->zstream.next_in = s->compressed_chunk;
|
||||||
* inflated. */
|
s->zstream.avail_in = s->lengths[chunk];
|
||||||
i=0;
|
s->zstream.next_out = s->uncompressed_chunk;
|
||||||
do {
|
s->zstream.avail_out = 512 * s->sectorcounts[chunk];
|
||||||
ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
|
ret = inflateReset(&s->zstream);
|
||||||
s->compressed_chunk+i, s->lengths[chunk]-i);
|
if (ret != Z_OK) {
|
||||||
if(ret<0 && errno==EINTR)
|
return -1;
|
||||||
ret=0;
|
}
|
||||||
i+=ret;
|
ret = inflate(&s->zstream, Z_FINISH);
|
||||||
} while(ret>=0 && ret+i<s->lengths[chunk]);
|
if (ret != Z_STREAM_END ||
|
||||||
|
s->zstream.total_out != 512 * s->sectorcounts[chunk]) {
|
||||||
if (ret != s->lengths[chunk])
|
return -1;
|
||||||
return -1;
|
}
|
||||||
|
break; }
|
||||||
s->zstream.next_in = s->compressed_chunk;
|
case 1: /* copy */
|
||||||
s->zstream.avail_in = s->lengths[chunk];
|
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||||
s->zstream.next_out = s->uncompressed_chunk;
|
|
||||||
s->zstream.avail_out = 512*s->sectorcounts[chunk];
|
|
||||||
ret = inflateReset(&s->zstream);
|
|
||||||
if(ret != Z_OK)
|
|
||||||
return -1;
|
|
||||||
ret = inflate(&s->zstream, Z_FINISH);
|
|
||||||
if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
|
|
||||||
return -1;
|
|
||||||
break; }
|
|
||||||
case 1: /* copy */
|
|
||||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
|
||||||
s->uncompressed_chunk, s->lengths[chunk]);
|
s->uncompressed_chunk, s->lengths[chunk]);
|
||||||
if (ret != s->lengths[chunk])
|
if (ret != s->lengths[chunk]) {
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
}
|
||||||
case 2: /* zero */
|
break;
|
||||||
memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]);
|
case 2: /* zero */
|
||||||
break;
|
memset(s->uncompressed_chunk, 0, 512 * s->sectorcounts[chunk]);
|
||||||
}
|
break;
|
||||||
s->current_chunk = chunk;
|
}
|
||||||
|
s->current_chunk = chunk;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -339,12 +394,14 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
BDRVDMGState *s = bs->opaque;
|
BDRVDMGState *s = bs->opaque;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0;i<nb_sectors;i++) {
|
for (i = 0; i < nb_sectors; i++) {
|
||||||
uint32_t sector_offset_in_chunk;
|
uint32_t sector_offset_in_chunk;
|
||||||
if(dmg_read_chunk(bs, sector_num+i) != 0)
|
if (dmg_read_chunk(bs, sector_num + i) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
|
}
|
||||||
memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
|
sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk];
|
||||||
|
memcpy(buf + i * 512,
|
||||||
|
s->uncompressed_chunk + sector_offset_in_chunk * 512, 512);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -376,12 +433,12 @@ static void dmg_close(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriver bdrv_dmg = {
|
static BlockDriver bdrv_dmg = {
|
||||||
.format_name = "dmg",
|
.format_name = "dmg",
|
||||||
.instance_size = sizeof(BDRVDMGState),
|
.instance_size = sizeof(BDRVDMGState),
|
||||||
.bdrv_probe = dmg_probe,
|
.bdrv_probe = dmg_probe,
|
||||||
.bdrv_open = dmg_open,
|
.bdrv_open = dmg_open,
|
||||||
.bdrv_read = dmg_co_read,
|
.bdrv_read = dmg_co_read,
|
||||||
.bdrv_close = dmg_close,
|
.bdrv_close = dmg_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_dmg_init(void)
|
static void bdrv_dmg_init(void)
|
||||||
|
@@ -80,7 +80,7 @@ static int parse_volume_options(GlusterConf *gconf, char *path)
|
|||||||
* 'server' specifies the server where the volume file specification for
|
* 'server' specifies the server where the volume file specification for
|
||||||
* the given volume resides. This can be either hostname, ipv4 address
|
* the given volume resides. This can be either hostname, ipv4 address
|
||||||
* or ipv6 address. ipv6 address needs to be within square brackets [ ].
|
* or ipv6 address. ipv6 address needs to be within square brackets [ ].
|
||||||
* If transport type is 'unix', then 'server' field should not be specifed.
|
* If transport type is 'unix', then 'server' field should not be specified.
|
||||||
* The 'socket' field needs to be populated with the path to unix domain
|
* The 'socket' field needs to be populated with the path to unix domain
|
||||||
* socket.
|
* socket.
|
||||||
*
|
*
|
||||||
|
@@ -417,6 +417,10 @@ static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
|||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
struct IscsiTask iTask;
|
struct IscsiTask iTask;
|
||||||
|
|
||||||
|
if (bs->sg) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
@@ -838,7 +842,8 @@ retry:
|
|||||||
|
|
||||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
||||||
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
||||||
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
(iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE ||
|
||||||
|
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB)) {
|
||||||
/* WRITE SAME is not supported by the target */
|
/* WRITE SAME is not supported by the target */
|
||||||
iscsilun->has_write_same = false;
|
iscsilun->has_write_same = false;
|
||||||
scsi_free_scsi_task(iTask.task);
|
scsi_free_scsi_task(iTask.task);
|
||||||
@@ -1096,8 +1101,10 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
|||||||
return task;
|
return task;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
if (!error_is_set(errp)) {
|
||||||
iscsi_get_error(iscsi));
|
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
||||||
|
iscsi_get_error(iscsi));
|
||||||
|
}
|
||||||
if (task != NULL) {
|
if (task != NULL) {
|
||||||
scsi_free_scsi_task(task);
|
scsi_free_scsi_task(task);
|
||||||
}
|
}
|
||||||
@@ -1330,18 +1337,20 @@ static int iscsi_refresh_limits(BlockDriverState *bs)
|
|||||||
|
|
||||||
/* We don't actually refresh here, but just return data queried in
|
/* We don't actually refresh here, but just return data queried in
|
||||||
* iscsi_open(): iscsi targets don't change their limits. */
|
* iscsi_open(): iscsi targets don't change their limits. */
|
||||||
if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
|
if (iscsilun->lbp.lbpu) {
|
||||||
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
||||||
bs->bl.max_discard = sector_lun2qemu(iscsilun->bl.max_unmap,
|
bs->bl.max_discard = sector_lun2qemu(iscsilun->bl.max_unmap,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
}
|
}
|
||||||
bs->bl.discard_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
bs->bl.discard_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
|
}
|
||||||
|
|
||||||
if (iscsilun->bl.max_ws_len < 0xffffffff) {
|
if (iscsilun->bl.max_ws_len < 0xffffffff) {
|
||||||
bs->bl.max_write_zeroes = sector_lun2qemu(iscsilun->bl.max_ws_len,
|
bs->bl.max_write_zeroes = sector_lun2qemu(iscsilun->bl.max_ws_len,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
}
|
}
|
||||||
|
if (iscsilun->lbp.lbpws) {
|
||||||
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
}
|
}
|
||||||
|
@@ -98,7 +98,14 @@ static void mirror_iteration_done(MirrorOp *op, int ret)
|
|||||||
|
|
||||||
qemu_iovec_destroy(&op->qiov);
|
qemu_iovec_destroy(&op->qiov);
|
||||||
g_slice_free(MirrorOp, op);
|
g_slice_free(MirrorOp, op);
|
||||||
qemu_coroutine_enter(s->common.co, NULL);
|
|
||||||
|
/* Enter coroutine when it is not sleeping. The coroutine sleeps to
|
||||||
|
* rate-limit itself. The coroutine will eventually resume since there is
|
||||||
|
* a sleep timeout so don't wake it early.
|
||||||
|
*/
|
||||||
|
if (s->common.busy) {
|
||||||
|
qemu_coroutine_enter(s->common.co, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mirror_write_complete(void *opaque, int ret)
|
static void mirror_write_complete(void *opaque, int ret)
|
||||||
@@ -139,11 +146,12 @@ static void mirror_read_complete(void *opaque, int ret)
|
|||||||
mirror_write_complete, op);
|
mirror_write_complete, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||||
{
|
{
|
||||||
BlockDriverState *source = s->common.bs;
|
BlockDriverState *source = s->common.bs;
|
||||||
int nb_sectors, sectors_per_chunk, nb_chunks;
|
int nb_sectors, sectors_per_chunk, nb_chunks;
|
||||||
int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector;
|
int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector;
|
||||||
|
uint64_t delay_ns;
|
||||||
MirrorOp *op;
|
MirrorOp *op;
|
||||||
|
|
||||||
s->sector_num = hbitmap_iter_next(&s->hbi);
|
s->sector_num = hbitmap_iter_next(&s->hbi);
|
||||||
@@ -231,7 +239,12 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
nb_chunks += added_chunks;
|
nb_chunks += added_chunks;
|
||||||
next_sector += added_sectors;
|
next_sector += added_sectors;
|
||||||
next_chunk += added_chunks;
|
next_chunk += added_chunks;
|
||||||
} while (next_sector < end);
|
if (!s->synced && s->common.speed) {
|
||||||
|
delay_ns = ratelimit_calculate_delay(&s->limit, added_sectors);
|
||||||
|
} else {
|
||||||
|
delay_ns = 0;
|
||||||
|
}
|
||||||
|
} while (delay_ns == 0 && next_sector < end);
|
||||||
|
|
||||||
/* Allocate a MirrorOp that is used as an AIO callback. */
|
/* Allocate a MirrorOp that is used as an AIO callback. */
|
||||||
op = g_slice_new(MirrorOp);
|
op = g_slice_new(MirrorOp);
|
||||||
@@ -268,6 +281,7 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
trace_mirror_one_iteration(s, sector_num, nb_sectors);
|
trace_mirror_one_iteration(s, sector_num, nb_sectors);
|
||||||
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
|
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
|
||||||
mirror_read_complete, op);
|
mirror_read_complete, op);
|
||||||
|
return delay_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mirror_free_init(MirrorBlockJob *s)
|
static void mirror_free_init(MirrorBlockJob *s)
|
||||||
@@ -362,7 +376,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
bdrv_dirty_iter_init(bs, s->dirty_bitmap, &s->hbi);
|
bdrv_dirty_iter_init(bs, s->dirty_bitmap, &s->hbi);
|
||||||
last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint64_t delay_ns;
|
uint64_t delay_ns = 0;
|
||||||
int64_t cnt;
|
int64_t cnt;
|
||||||
bool should_complete;
|
bool should_complete;
|
||||||
|
|
||||||
@@ -386,8 +400,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
continue;
|
continue;
|
||||||
} else if (cnt != 0) {
|
} else if (cnt != 0) {
|
||||||
mirror_iteration(s);
|
delay_ns = mirror_iteration(s);
|
||||||
continue;
|
if (delay_ns == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,17 +448,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
trace_mirror_before_sleep(s, cnt, s->synced);
|
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
|
||||||
if (!s->synced) {
|
if (!s->synced) {
|
||||||
/* Publish progress */
|
/* Publish progress */
|
||||||
s->common.offset = (end - cnt) * BDRV_SECTOR_SIZE;
|
s->common.offset = (end - cnt) * BDRV_SECTOR_SIZE;
|
||||||
|
|
||||||
if (s->common.speed) {
|
|
||||||
delay_ns = ratelimit_calculate_delay(&s->limit, sectors_per_chunk);
|
|
||||||
} else {
|
|
||||||
delay_ns = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
|
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
|
||||||
if (block_job_is_cancelled(&s->common)) {
|
if (block_job_is_cancelled(&s->common)) {
|
||||||
break;
|
break;
|
||||||
|
@@ -43,6 +43,17 @@ static void nbd_recv_coroutines_enter_all(NbdClientSession *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nbd_teardown_connection(NbdClientSession *client)
|
||||||
|
{
|
||||||
|
/* finish any pending coroutines */
|
||||||
|
shutdown(client->sock, 2);
|
||||||
|
nbd_recv_coroutines_enter_all(client);
|
||||||
|
|
||||||
|
qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL);
|
||||||
|
closesocket(client->sock);
|
||||||
|
client->sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void nbd_reply_ready(void *opaque)
|
static void nbd_reply_ready(void *opaque)
|
||||||
{
|
{
|
||||||
NbdClientSession *s = opaque;
|
NbdClientSession *s = opaque;
|
||||||
@@ -78,7 +89,7 @@ static void nbd_reply_ready(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
nbd_recv_coroutines_enter_all(s);
|
nbd_teardown_connection(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nbd_restart_write(void *opaque)
|
static void nbd_restart_write(void *opaque)
|
||||||
@@ -324,7 +335,7 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nbd_teardown_connection(NbdClientSession *client)
|
void nbd_client_session_close(NbdClientSession *client)
|
||||||
{
|
{
|
||||||
struct nbd_request request = {
|
struct nbd_request request = {
|
||||||
.type = NBD_CMD_DISC,
|
.type = NBD_CMD_DISC,
|
||||||
@@ -332,22 +343,14 @@ static void nbd_teardown_connection(NbdClientSession *client)
|
|||||||
.len = 0
|
.len = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
nbd_send_request(client->sock, &request);
|
|
||||||
|
|
||||||
/* finish any pending coroutines */
|
|
||||||
shutdown(client->sock, 2);
|
|
||||||
nbd_recv_coroutines_enter_all(client);
|
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL);
|
|
||||||
closesocket(client->sock);
|
|
||||||
client->sock = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nbd_client_session_close(NbdClientSession *client)
|
|
||||||
{
|
|
||||||
if (!client->bs) {
|
if (!client->bs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (client->sock == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nbd_send_request(client->sock, &request);
|
||||||
|
|
||||||
nbd_teardown_connection(client);
|
nbd_teardown_connection(client);
|
||||||
client->bs = NULL;
|
client->bs = NULL;
|
||||||
|
@@ -112,6 +112,9 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
|
|||||||
if (task->ret == 0 && task->st) {
|
if (task->ret == 0 && task->st) {
|
||||||
memcpy(task->st, data, sizeof(struct stat));
|
memcpy(task->st, data, sizeof(struct stat));
|
||||||
}
|
}
|
||||||
|
if (task->ret < 0) {
|
||||||
|
error_report("NFS Error: %s", nfs_get_error(nfs));
|
||||||
|
}
|
||||||
if (task->co) {
|
if (task->co) {
|
||||||
task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task);
|
task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task);
|
||||||
qemu_bh_schedule(task->bh);
|
qemu_bh_schedule(task->bh);
|
||||||
|
@@ -49,9 +49,9 @@ typedef struct BDRVParallelsState {
|
|||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
|
|
||||||
uint32_t *catalog_bitmap;
|
uint32_t *catalog_bitmap;
|
||||||
int catalog_size;
|
unsigned int catalog_size;
|
||||||
|
|
||||||
int tracks;
|
unsigned int tracks;
|
||||||
} BDRVParallelsState;
|
} BDRVParallelsState;
|
||||||
|
|
||||||
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
|
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
@@ -93,8 +93,18 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
bs->total_sectors = le32_to_cpu(ph.nb_sectors);
|
bs->total_sectors = le32_to_cpu(ph.nb_sectors);
|
||||||
|
|
||||||
s->tracks = le32_to_cpu(ph.tracks);
|
s->tracks = le32_to_cpu(ph.tracks);
|
||||||
|
if (s->tracks == 0) {
|
||||||
|
error_setg(errp, "Invalid image: Zero sectors per track");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
s->catalog_size = le32_to_cpu(ph.catalog_entries);
|
s->catalog_size = le32_to_cpu(ph.catalog_entries);
|
||||||
|
if (s->catalog_size > INT_MAX / 4) {
|
||||||
|
error_setg(errp, "Catalog too large");
|
||||||
|
ret = -EFBIG;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
|
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
|
||||||
|
@@ -723,7 +723,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
backing_file = NULL;
|
backing_file = NULL;
|
||||||
}
|
}
|
||||||
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
|
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
|
||||||
unmodifyed sectors */
|
unmodified sectors */
|
||||||
header.l2_bits = 12; /* 32 KB L2 tables */
|
header.l2_bits = 12; /* 32 KB L2 tables */
|
||||||
} else {
|
} else {
|
||||||
header.cluster_bits = 12; /* 4 KB clusters */
|
header.cluster_bits = 12; /* 4 KB clusters */
|
||||||
|
@@ -55,7 +55,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_l1_size > INT_MAX) {
|
if (new_l1_size > INT_MAX / sizeof(uint64_t)) {
|
||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,15 +359,6 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
|||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
int n, ret;
|
int n, ret;
|
||||||
|
|
||||||
/*
|
|
||||||
* If this is the last cluster and it is only partially used, we must only
|
|
||||||
* copy until the end of the image, or bdrv_check_request will fail for the
|
|
||||||
* bdrv_read/write calls below.
|
|
||||||
*/
|
|
||||||
if (start_sect + n_end > bs->total_sectors) {
|
|
||||||
n_end = bs->total_sectors - start_sect;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = n_end - n_start;
|
n = n_end - n_start;
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -500,6 +491,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
break;
|
break;
|
||||||
case QCOW2_CLUSTER_ZERO:
|
case QCOW2_CLUSTER_ZERO:
|
||||||
if (s->qcow_version < 3) {
|
if (s->qcow_version < 3) {
|
||||||
|
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
#include "qapi/qmp/types.h"
|
#include "qapi/qmp/types.h"
|
||||||
|
|
||||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
|
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
|
||||||
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||||
int64_t offset, int64_t length,
|
int64_t offset, int64_t length,
|
||||||
int addend, enum qcow2_discard_type type);
|
int addend, enum qcow2_discard_type type);
|
||||||
@@ -40,8 +40,10 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
|||||||
int qcow2_refcount_init(BlockDriverState *bs)
|
int qcow2_refcount_init(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int ret, refcount_table_size2, i;
|
unsigned int refcount_table_size2, i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
|
||||||
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
||||||
s->refcount_table = g_malloc(refcount_table_size2);
|
s->refcount_table = g_malloc(refcount_table_size2);
|
||||||
if (s->refcount_table_size > 0) {
|
if (s->refcount_table_size > 0) {
|
||||||
@@ -87,7 +89,7 @@ static int load_refcount_block(BlockDriverState *bs,
|
|||||||
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int refcount_table_index, block_index;
|
uint64_t refcount_table_index, block_index;
|
||||||
int64_t refcount_block_offset;
|
int64_t refcount_block_offset;
|
||||||
int ret;
|
int ret;
|
||||||
uint16_t *refcount_block;
|
uint16_t *refcount_block;
|
||||||
@@ -192,10 +194,11 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
* they can describe them themselves.
|
* they can describe them themselves.
|
||||||
*
|
*
|
||||||
* - We need to consider that at this point we are inside update_refcounts
|
* - We need to consider that at this point we are inside update_refcounts
|
||||||
* and doing the initial refcount increase. This means that some clusters
|
* and potentially doing an initial refcount increase. This means that
|
||||||
* have already been allocated by the caller, but their refcount isn't
|
* some clusters have already been allocated by the caller, but their
|
||||||
* accurate yet. free_cluster_index tells us where this allocation ends
|
* refcount isn't accurate yet. If we allocate clusters for metadata, we
|
||||||
* as long as we don't overwrite it by freeing clusters.
|
* need to return -EAGAIN to signal the caller that it needs to restart
|
||||||
|
* the search for free clusters.
|
||||||
*
|
*
|
||||||
* - alloc_clusters_noref and qcow2_free_clusters may load a different
|
* - alloc_clusters_noref and qcow2_free_clusters may load a different
|
||||||
* refcount block into the cache
|
* refcount block into the cache
|
||||||
@@ -280,7 +283,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->refcount_table[refcount_table_index] = new_block;
|
s->refcount_table[refcount_table_index] = new_block;
|
||||||
return 0;
|
|
||||||
|
/* The new refcount block may be where the caller intended to put its
|
||||||
|
* data, so let it restart the search. */
|
||||||
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
|
ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
|
||||||
@@ -303,8 +309,11 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
|
|
||||||
/* Calculate the number of refcount blocks needed so far */
|
/* Calculate the number of refcount blocks needed so far */
|
||||||
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
||||||
uint64_t blocks_used = (s->free_cluster_index +
|
uint64_t blocks_used = DIV_ROUND_UP(cluster_index, refcount_block_clusters);
|
||||||
refcount_block_clusters - 1) / refcount_block_clusters;
|
|
||||||
|
if (blocks_used > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
/* And now we need at least one block more for the new metadata */
|
/* And now we need at least one block more for the new metadata */
|
||||||
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
||||||
@@ -337,8 +346,6 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
|
uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
|
||||||
uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
|
uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
|
||||||
|
|
||||||
assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
|
|
||||||
|
|
||||||
/* Fill the new refcount table */
|
/* Fill the new refcount table */
|
||||||
memcpy(new_table, s->refcount_table,
|
memcpy(new_table, s->refcount_table,
|
||||||
s->refcount_table_size * sizeof(uint64_t));
|
s->refcount_table_size * sizeof(uint64_t));
|
||||||
@@ -401,18 +408,19 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
s->refcount_table_size = table_size;
|
s->refcount_table_size = table_size;
|
||||||
s->refcount_table_offset = table_offset;
|
s->refcount_table_offset = table_offset;
|
||||||
|
|
||||||
/* Free old table. Remember, we must not change free_cluster_index */
|
/* Free old table. */
|
||||||
uint64_t old_free_cluster_index = s->free_cluster_index;
|
|
||||||
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
|
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
|
||||||
QCOW2_DISCARD_OTHER);
|
QCOW2_DISCARD_OTHER);
|
||||||
s->free_cluster_index = old_free_cluster_index;
|
|
||||||
|
|
||||||
ret = load_refcount_block(bs, new_block, (void**) refcount_block);
|
ret = load_refcount_block(bs, new_block, (void**) refcount_block);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
/* If we were trying to do the initial refcount update for some cluster
|
||||||
|
* allocation, we might have used the same clusters to store newly
|
||||||
|
* allocated metadata. Make the caller search some new space. */
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
fail_table:
|
fail_table:
|
||||||
g_free(new_table);
|
g_free(new_table);
|
||||||
@@ -627,15 +635,16 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
|
|||||||
|
|
||||||
|
|
||||||
/* return < 0 if error */
|
/* return < 0 if error */
|
||||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
|
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int i, nb_clusters, refcount;
|
uint64_t i, nb_clusters;
|
||||||
|
int refcount;
|
||||||
|
|
||||||
nb_clusters = size_to_clusters(s, size);
|
nb_clusters = size_to_clusters(s, size);
|
||||||
retry:
|
retry:
|
||||||
for(i = 0; i < nb_clusters; i++) {
|
for(i = 0; i < nb_clusters; i++) {
|
||||||
int64_t next_cluster_index = s->free_cluster_index++;
|
uint64_t next_cluster_index = s->free_cluster_index++;
|
||||||
refcount = get_refcount(bs, next_cluster_index);
|
refcount = get_refcount(bs, next_cluster_index);
|
||||||
|
|
||||||
if (refcount < 0) {
|
if (refcount < 0) {
|
||||||
@@ -652,18 +661,21 @@ retry:
|
|||||||
return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
|
return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
|
||||||
{
|
{
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
||||||
offset = alloc_clusters_noref(bs, size);
|
do {
|
||||||
if (offset < 0) {
|
offset = alloc_clusters_noref(bs, size);
|
||||||
return offset;
|
if (offset < 0) {
|
||||||
}
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
|
||||||
|
} while (ret == -EAGAIN);
|
||||||
|
|
||||||
ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -676,7 +688,6 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
|||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t cluster_index;
|
uint64_t cluster_index;
|
||||||
uint64_t old_free_cluster_index;
|
|
||||||
uint64_t i;
|
uint64_t i;
|
||||||
int refcount, ret;
|
int refcount, ret;
|
||||||
|
|
||||||
@@ -685,30 +696,28 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check how many clusters there are free */
|
do {
|
||||||
cluster_index = offset >> s->cluster_bits;
|
/* Check how many clusters there are free */
|
||||||
for(i = 0; i < nb_clusters; i++) {
|
cluster_index = offset >> s->cluster_bits;
|
||||||
refcount = get_refcount(bs, cluster_index++);
|
for(i = 0; i < nb_clusters; i++) {
|
||||||
|
refcount = get_refcount(bs, cluster_index++);
|
||||||
|
|
||||||
if (refcount < 0) {
|
if (refcount < 0) {
|
||||||
return refcount;
|
return refcount;
|
||||||
} else if (refcount != 0) {
|
} else if (refcount != 0) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* And then allocate them */
|
/* And then allocate them */
|
||||||
old_free_cluster_index = s->free_cluster_index;
|
ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
|
||||||
s->free_cluster_index = cluster_index + i;
|
QCOW2_DISCARD_NEVER);
|
||||||
|
} while (ret == -EAGAIN);
|
||||||
|
|
||||||
ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
|
|
||||||
QCOW2_DISCARD_NEVER);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free_cluster_index = old_free_cluster_index;
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1011,8 +1020,7 @@ static void inc_refcounts(BlockDriverState *bs,
|
|||||||
int64_t offset, int64_t size)
|
int64_t offset, int64_t size)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t start, last, cluster_offset;
|
uint64_t start, last, cluster_offset, k;
|
||||||
int k;
|
|
||||||
|
|
||||||
if (size <= 0)
|
if (size <= 0)
|
||||||
return;
|
return;
|
||||||
@@ -1022,11 +1030,7 @@ static void inc_refcounts(BlockDriverState *bs,
|
|||||||
for(cluster_offset = start; cluster_offset <= last;
|
for(cluster_offset = start; cluster_offset <= last;
|
||||||
cluster_offset += s->cluster_size) {
|
cluster_offset += s->cluster_size) {
|
||||||
k = cluster_offset >> s->cluster_bits;
|
k = cluster_offset >> s->cluster_bits;
|
||||||
if (k < 0) {
|
if (k >= refcount_table_size) {
|
||||||
fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
|
|
||||||
cluster_offset);
|
|
||||||
res->corruptions++;
|
|
||||||
} else if (k >= refcount_table_size) {
|
|
||||||
fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
|
fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
|
||||||
"the end of the image file, can't properly check refcounts.\n",
|
"the end of the image file, can't properly check refcounts.\n",
|
||||||
cluster_offset);
|
cluster_offset);
|
||||||
@@ -1383,7 +1387,7 @@ static int write_reftable_entry(BlockDriverState *bs, int rt_index)
|
|||||||
* does _not_ decrement the reference count for the currently occupied cluster.
|
* does _not_ decrement the reference count for the currently occupied cluster.
|
||||||
*
|
*
|
||||||
* This function prints an informative message to stderr on error (and returns
|
* This function prints an informative message to stderr on error (and returns
|
||||||
* -errno); on success, 0 is returned.
|
* -errno); on success, the offset of the newly allocated cluster is returned.
|
||||||
*/
|
*/
|
||||||
static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
||||||
uint64_t offset)
|
uint64_t offset)
|
||||||
@@ -1399,14 +1403,14 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
|||||||
fprintf(stderr, "Could not allocate new cluster: %s\n",
|
fprintf(stderr, "Could not allocate new cluster: %s\n",
|
||||||
strerror(-new_offset));
|
strerror(-new_offset));
|
||||||
ret = new_offset;
|
ret = new_offset;
|
||||||
goto fail;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fetch current refcount block content */
|
/* fetch current refcount block content */
|
||||||
ret = qcow2_cache_get(bs, s->refcount_block_cache, offset, &refcount_block);
|
ret = qcow2_cache_get(bs, s->refcount_block_cache, offset, &refcount_block);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "Could not fetch refcount block: %s\n", strerror(-ret));
|
fprintf(stderr, "Could not fetch refcount block: %s\n", strerror(-ret));
|
||||||
goto fail;
|
goto fail_free_cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* new block has not yet been entered into refcount table, therefore it is
|
/* new block has not yet been entered into refcount table, therefore it is
|
||||||
@@ -1417,8 +1421,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
|||||||
"check failed: %s\n", strerror(-ret));
|
"check failed: %s\n", strerror(-ret));
|
||||||
/* the image will be marked corrupt, so don't even attempt on freeing
|
/* the image will be marked corrupt, so don't even attempt on freeing
|
||||||
* the cluster */
|
* the cluster */
|
||||||
new_offset = 0;
|
goto done;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write to new block */
|
/* write to new block */
|
||||||
@@ -1426,7 +1429,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
|||||||
s->cluster_sectors);
|
s->cluster_sectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "Could not write refcount block: %s\n", strerror(-ret));
|
fprintf(stderr, "Could not write refcount block: %s\n", strerror(-ret));
|
||||||
goto fail;
|
goto fail_free_cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update refcount table */
|
/* update refcount table */
|
||||||
@@ -1436,24 +1439,27 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "Could not update refcount table: %s\n",
|
fprintf(stderr, "Could not update refcount table: %s\n",
|
||||||
strerror(-ret));
|
strerror(-ret));
|
||||||
goto fail;
|
goto fail_free_cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
goto done;
|
||||||
if (new_offset && (ret < 0)) {
|
|
||||||
qcow2_free_clusters(bs, new_offset, s->cluster_size,
|
fail_free_cluster:
|
||||||
QCOW2_DISCARD_ALWAYS);
|
qcow2_free_clusters(bs, new_offset, s->cluster_size, QCOW2_DISCARD_OTHER);
|
||||||
}
|
|
||||||
|
done:
|
||||||
if (refcount_block) {
|
if (refcount_block) {
|
||||||
if (ret < 0) {
|
/* This should never fail, as it would only do so if the given refcount
|
||||||
qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
* block cannot be found in the cache. As this is impossible as long as
|
||||||
} else {
|
* there are no bugs, assert the success. */
|
||||||
ret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
int tmp = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
||||||
}
|
assert(tmp == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_offset;
|
return new_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1467,14 +1473,19 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
BdrvCheckMode fix)
|
BdrvCheckMode fix)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t size, i, highest_cluster;
|
int64_t size, i, highest_cluster, nb_clusters;
|
||||||
int nb_clusters, refcount1, refcount2;
|
int refcount1, refcount2;
|
||||||
QCowSnapshot *sn;
|
QCowSnapshot *sn;
|
||||||
uint16_t *refcount_table;
|
uint16_t *refcount_table;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size = bdrv_getlength(bs->file);
|
size = bdrv_getlength(bs->file);
|
||||||
nb_clusters = size_to_clusters(s, size);
|
nb_clusters = size_to_clusters(s, size);
|
||||||
|
if (nb_clusters > INT_MAX) {
|
||||||
|
res->check_errors++;
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
|
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
|
||||||
|
|
||||||
res->bfi.total_clusters =
|
res->bfi.total_clusters =
|
||||||
|
@@ -26,31 +26,6 @@
|
|||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "block/qcow2.h"
|
#include "block/qcow2.h"
|
||||||
|
|
||||||
typedef struct QEMU_PACKED QCowSnapshotHeader {
|
|
||||||
/* header is 8 byte aligned */
|
|
||||||
uint64_t l1_table_offset;
|
|
||||||
|
|
||||||
uint32_t l1_size;
|
|
||||||
uint16_t id_str_size;
|
|
||||||
uint16_t name_size;
|
|
||||||
|
|
||||||
uint32_t date_sec;
|
|
||||||
uint32_t date_nsec;
|
|
||||||
|
|
||||||
uint64_t vm_clock_nsec;
|
|
||||||
|
|
||||||
uint32_t vm_state_size;
|
|
||||||
uint32_t extra_data_size; /* for extension */
|
|
||||||
/* extra data follows */
|
|
||||||
/* id_str follows */
|
|
||||||
/* name follows */
|
|
||||||
} QCowSnapshotHeader;
|
|
||||||
|
|
||||||
typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
|
||||||
uint64_t vm_state_size_large;
|
|
||||||
uint64_t disk_size;
|
|
||||||
} QCowSnapshotExtraData;
|
|
||||||
|
|
||||||
void qcow2_free_snapshots(BlockDriverState *bs)
|
void qcow2_free_snapshots(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
@@ -141,8 +116,14 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
offset += name_size;
|
offset += name_size;
|
||||||
sn->name[name_size] = '\0';
|
sn->name[name_size] = '\0';
|
||||||
|
|
||||||
|
if (offset - s->snapshots_offset > QCOW_MAX_SNAPSHOTS_SIZE) {
|
||||||
|
ret = -EFBIG;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(offset - s->snapshots_offset <= INT_MAX);
|
||||||
s->snapshots_size = offset - s->snapshots_offset;
|
s->snapshots_size = offset - s->snapshots_offset;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -163,7 +144,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
|||||||
uint32_t nb_snapshots;
|
uint32_t nb_snapshots;
|
||||||
uint64_t snapshots_offset;
|
uint64_t snapshots_offset;
|
||||||
} QEMU_PACKED header_data;
|
} QEMU_PACKED header_data;
|
||||||
int64_t offset, snapshots_offset;
|
int64_t offset, snapshots_offset = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* compute the size of the snapshots */
|
/* compute the size of the snapshots */
|
||||||
@@ -175,7 +156,14 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
|||||||
offset += sizeof(extra);
|
offset += sizeof(extra);
|
||||||
offset += strlen(sn->id_str);
|
offset += strlen(sn->id_str);
|
||||||
offset += strlen(sn->name);
|
offset += strlen(sn->name);
|
||||||
|
|
||||||
|
if (offset > QCOW_MAX_SNAPSHOTS_SIZE) {
|
||||||
|
ret = -EFBIG;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(offset <= INT_MAX);
|
||||||
snapshots_size = offset;
|
snapshots_size = offset;
|
||||||
|
|
||||||
/* Allocate space for the new snapshot list */
|
/* Allocate space for the new snapshot list */
|
||||||
@@ -357,6 +345,10 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
|||||||
uint64_t *l1_table = NULL;
|
uint64_t *l1_table = NULL;
|
||||||
int64_t l1_table_offset;
|
int64_t l1_table_offset;
|
||||||
|
|
||||||
|
if (s->nb_snapshots >= QCOW_MAX_SNAPSHOTS) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
memset(sn, 0, sizeof(*sn));
|
memset(sn, 0, sizeof(*sn));
|
||||||
|
|
||||||
/* Generate an ID if it wasn't passed */
|
/* Generate an ID if it wasn't passed */
|
||||||
@@ -701,7 +693,11 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
|||||||
sn = &s->snapshots[snapshot_index];
|
sn = &s->snapshots[snapshot_index];
|
||||||
|
|
||||||
/* Allocate and read in the snapshot's L1 table */
|
/* Allocate and read in the snapshot's L1 table */
|
||||||
new_l1_bytes = s->l1_size * sizeof(uint64_t);
|
if (sn->l1_size > QCOW_MAX_L1_SIZE) {
|
||||||
|
error_setg(errp, "Snapshot L1 table too large");
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
||||||
new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
|
new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
||||||
|
192
block/qcow2.c
192
block/qcow2.c
@@ -269,12 +269,15 @@ static int qcow2_mark_clean(BlockDriverState *bs)
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
|
||||||
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
|
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
|
||||||
int ret = bdrv_flush(bs);
|
int ret;
|
||||||
|
|
||||||
|
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
|
||||||
|
|
||||||
|
ret = bdrv_flush(bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
|
|
||||||
return qcow2_update_header(bs);
|
return qcow2_update_header(bs);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -329,6 +332,32 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
|
uint64_t entries, size_t entry_len)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
uint64_t size;
|
||||||
|
|
||||||
|
/* Use signed INT64_MAX as the maximum even for uint64_t header fields,
|
||||||
|
* because values will be passed to qemu functions taking int64_t. */
|
||||||
|
if (entries > INT64_MAX / entry_len) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = entries * entry_len;
|
||||||
|
|
||||||
|
if (INT64_MAX - size < offset) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables must be cluster aligned */
|
||||||
|
if (offset & (s->cluster_size - 1)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static QemuOptsList qcow2_runtime_opts = {
|
static QemuOptsList qcow2_runtime_opts = {
|
||||||
.name = "qcow2",
|
.name = "qcow2",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
|
||||||
@@ -419,7 +448,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int len, i, ret = 0;
|
unsigned int len, i;
|
||||||
|
int ret = 0;
|
||||||
QCowHeader header;
|
QCowHeader header;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@@ -460,6 +490,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
s->qcow_version = header.version;
|
s->qcow_version = header.version;
|
||||||
|
|
||||||
|
/* Initialise cluster size */
|
||||||
|
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||||
|
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||||
|
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->cluster_bits = header.cluster_bits;
|
||||||
|
s->cluster_size = 1 << s->cluster_bits;
|
||||||
|
s->cluster_sectors = 1 << (s->cluster_bits - 9);
|
||||||
|
|
||||||
/* Initialise version 3 header fields */
|
/* Initialise version 3 header fields */
|
||||||
if (header.version == 2) {
|
if (header.version == 2) {
|
||||||
header.incompatible_features = 0;
|
header.incompatible_features = 0;
|
||||||
@@ -473,6 +515,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
be64_to_cpus(&header.autoclear_features);
|
be64_to_cpus(&header.autoclear_features);
|
||||||
be32_to_cpus(&header.refcount_order);
|
be32_to_cpus(&header.refcount_order);
|
||||||
be32_to_cpus(&header.header_length);
|
be32_to_cpus(&header.header_length);
|
||||||
|
|
||||||
|
if (header.header_length < 104) {
|
||||||
|
error_setg(errp, "qcow2 header too short");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.header_length > s->cluster_size) {
|
||||||
|
error_setg(errp, "qcow2 header exceeds cluster size");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.header_length > sizeof(header)) {
|
if (header.header_length > sizeof(header)) {
|
||||||
@@ -487,6 +541,12 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (header.backing_file_offset > s->cluster_size) {
|
||||||
|
error_setg(errp, "Invalid backing file offset");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (header.backing_file_offset) {
|
if (header.backing_file_offset) {
|
||||||
ext_end = header.backing_file_offset;
|
ext_end = header.backing_file_offset;
|
||||||
} else {
|
} else {
|
||||||
@@ -506,6 +566,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
s->incompatible_features &
|
s->incompatible_features &
|
||||||
~QCOW2_INCOMPAT_MASK);
|
~QCOW2_INCOMPAT_MASK);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
g_free(feature_table);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,12 +590,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
s->refcount_order = header.refcount_order;
|
s->refcount_order = header.refcount_order;
|
||||||
|
|
||||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
|
||||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
|
||||||
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||||
error_setg(errp, "Unsupported encryption method: %i",
|
error_setg(errp, "Unsupported encryption method: %i",
|
||||||
header.crypt_method);
|
header.crypt_method);
|
||||||
@@ -545,23 +600,52 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
if (s->crypt_method_header) {
|
if (s->crypt_method_header) {
|
||||||
bs->encrypted = 1;
|
bs->encrypted = 1;
|
||||||
}
|
}
|
||||||
s->cluster_bits = header.cluster_bits;
|
|
||||||
s->cluster_size = 1 << s->cluster_bits;
|
|
||||||
s->cluster_sectors = 1 << (s->cluster_bits - 9);
|
|
||||||
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
||||||
s->l2_size = 1 << s->l2_bits;
|
s->l2_size = 1 << s->l2_bits;
|
||||||
bs->total_sectors = header.size / 512;
|
bs->total_sectors = header.size / 512;
|
||||||
s->csize_shift = (62 - (s->cluster_bits - 8));
|
s->csize_shift = (62 - (s->cluster_bits - 8));
|
||||||
s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
|
s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
|
||||||
s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
|
s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
|
||||||
|
|
||||||
s->refcount_table_offset = header.refcount_table_offset;
|
s->refcount_table_offset = header.refcount_table_offset;
|
||||||
s->refcount_table_size =
|
s->refcount_table_size =
|
||||||
header.refcount_table_clusters << (s->cluster_bits - 3);
|
header.refcount_table_clusters << (s->cluster_bits - 3);
|
||||||
|
|
||||||
s->snapshots_offset = header.snapshots_offset;
|
if (header.refcount_table_clusters > qcow2_max_refcount_clusters(s)) {
|
||||||
s->nb_snapshots = header.nb_snapshots;
|
error_setg(errp, "Reference count table too large");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = validate_table_offset(bs, s->refcount_table_offset,
|
||||||
|
s->refcount_table_size, sizeof(uint64_t));
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Invalid reference count table offset");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Snapshot table offset/length */
|
||||||
|
if (header.nb_snapshots > QCOW_MAX_SNAPSHOTS) {
|
||||||
|
error_setg(errp, "Too many snapshots");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = validate_table_offset(bs, header.snapshots_offset,
|
||||||
|
header.nb_snapshots,
|
||||||
|
sizeof(QCowSnapshotHeader));
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Invalid snapshot table offset");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* read the level 1 table */
|
/* read the level 1 table */
|
||||||
|
if (header.l1_size > QCOW_MAX_L1_SIZE) {
|
||||||
|
error_setg(errp, "Active L1 table too large");
|
||||||
|
ret = -EFBIG;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->l1_size = header.l1_size;
|
s->l1_size = header.l1_size;
|
||||||
|
|
||||||
l1_vm_state_index = size_to_l1(s, header.size);
|
l1_vm_state_index = size_to_l1(s, header.size);
|
||||||
@@ -579,7 +663,16 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = validate_table_offset(bs, header.l1_table_offset,
|
||||||
|
header.l1_size, sizeof(uint64_t));
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Invalid L1 table offset");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->l1_table_offset = header.l1_table_offset;
|
s->l1_table_offset = header.l1_table_offset;
|
||||||
|
|
||||||
|
|
||||||
if (s->l1_size > 0) {
|
if (s->l1_size > 0) {
|
||||||
s->l1_table = g_malloc0(
|
s->l1_table = g_malloc0(
|
||||||
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
||||||
@@ -625,8 +718,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
/* read the backing file name */
|
/* read the backing file name */
|
||||||
if (header.backing_file_offset != 0) {
|
if (header.backing_file_offset != 0) {
|
||||||
len = header.backing_file_size;
|
len = header.backing_file_size;
|
||||||
if (len > 1023) {
|
if (len > MIN(1023, s->cluster_size - header.backing_file_offset)) {
|
||||||
len = 1023;
|
error_setg(errp, "Backing file name too long");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||||
bs->backing_file, len);
|
bs->backing_file, len);
|
||||||
@@ -637,6 +732,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
bs->backing_file[len] = '\0';
|
bs->backing_file[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Internal snapshots */
|
||||||
|
s->snapshots_offset = header.snapshots_offset;
|
||||||
|
s->nb_snapshots = header.nb_snapshots;
|
||||||
|
|
||||||
ret = qcow2_read_snapshots(bs);
|
ret = qcow2_read_snapshots(bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not read snapshots");
|
error_setg_errno(errp, -ret, "Could not read snapshots");
|
||||||
@@ -745,6 +844,9 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
if (s->l2_table_cache) {
|
if (s->l2_table_cache) {
|
||||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||||
}
|
}
|
||||||
|
if (s->refcount_block_cache) {
|
||||||
|
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||||
|
}
|
||||||
g_free(s->cluster_cache);
|
g_free(s->cluster_cache);
|
||||||
qemu_vfree(s->cluster_data);
|
qemu_vfree(s->cluster_data);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -801,11 +903,25 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have nothing to do for QCOW2 reopen, stubs just return
|
/* We have no actual commit/abort logic for qcow2, but we need to write out any
|
||||||
* success */
|
* unwritten data if we reopen read-only. */
|
||||||
static int qcow2_reopen_prepare(BDRVReopenState *state,
|
static int qcow2_reopen_prepare(BDRVReopenState *state,
|
||||||
BlockReopenQueue *queue, Error **errp)
|
BlockReopenQueue *queue, Error **errp)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((state->flags & BDRV_O_RDWR) == 0) {
|
||||||
|
ret = bdrv_flush(state->bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qcow2_mark_clean(state->bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1156,7 +1272,7 @@ static void qcow2_close(BlockDriverState *bs)
|
|||||||
qcow2_free_snapshots(bs);
|
qcow2_free_snapshots(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qcow2_invalidate_cache(BlockDriverState *bs)
|
static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int flags = s->flags;
|
int flags = s->flags;
|
||||||
@@ -1164,6 +1280,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs)
|
|||||||
AES_KEY aes_decrypt_key;
|
AES_KEY aes_decrypt_key;
|
||||||
uint32_t crypt_method = 0;
|
uint32_t crypt_method = 0;
|
||||||
QDict *options;
|
QDict *options;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Backing files are read-only which makes all of their metadata immutable,
|
* Backing files are read-only which makes all of their metadata immutable,
|
||||||
@@ -1178,11 +1296,25 @@ static void qcow2_invalidate_cache(BlockDriverState *bs)
|
|||||||
|
|
||||||
qcow2_close(bs);
|
qcow2_close(bs);
|
||||||
|
|
||||||
bdrv_invalidate_cache(bs->file);
|
bdrv_invalidate_cache(bs->file, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memset(s, 0, sizeof(BDRVQcowState));
|
memset(s, 0, sizeof(BDRVQcowState));
|
||||||
options = qdict_clone_shallow(bs->options);
|
options = qdict_clone_shallow(bs->options);
|
||||||
qcow2_open(bs, options, flags, NULL);
|
|
||||||
|
ret = qcow2_open(bs, options, flags, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_setg(errp, "Could not reopen qcow2 layer: %s",
|
||||||
|
error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
return;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Could not reopen qcow2 layer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
|
|
||||||
@@ -1416,7 +1548,9 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta != NULL) {
|
while (meta) {
|
||||||
|
QCowL2Meta *next = meta->next;
|
||||||
|
|
||||||
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qcow2_free_any_clusters(bs, meta->alloc_offset,
|
qcow2_free_any_clusters(bs, meta->alloc_offset,
|
||||||
@@ -1427,6 +1561,9 @@ static int preallocate(BlockDriverState *bs)
|
|||||||
/* There are no dependent requests, but we need to remove our
|
/* There are no dependent requests, but we need to remove our
|
||||||
* request from the list of in-flight requests */
|
* request from the list of in-flight requests */
|
||||||
QLIST_REMOVE(meta, next_in_flight);
|
QLIST_REMOVE(meta, next_in_flight);
|
||||||
|
|
||||||
|
g_free(meta);
|
||||||
|
meta = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Preallocate data if requested */
|
/* TODO Preallocate data if requested */
|
||||||
@@ -1484,7 +1621,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
*/
|
*/
|
||||||
BlockDriverState* bs;
|
BlockDriverState* bs;
|
||||||
QCowHeader *header;
|
QCowHeader *header;
|
||||||
uint8_t* refcount_table;
|
uint64_t* refcount_table;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1536,9 +1673,10 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write an empty refcount table */
|
/* Write a refcount table with one refcount block */
|
||||||
refcount_table = g_malloc0(cluster_size);
|
refcount_table = g_malloc0(2 * cluster_size);
|
||||||
ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size);
|
refcount_table[0] = cpu_to_be64(2 * cluster_size);
|
||||||
|
ret = bdrv_pwrite(bs, cluster_size, refcount_table, 2 * cluster_size);
|
||||||
g_free(refcount_table);
|
g_free(refcount_table);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1563,7 +1701,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_alloc_clusters(bs, 2 * cluster_size);
|
ret = qcow2_alloc_clusters(bs, 3 * cluster_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not allocate clusters for qcow2 "
|
error_setg_errno(errp, -ret, "Could not allocate clusters for qcow2 "
|
||||||
"header and refcount table");
|
"header and refcount table");
|
||||||
|
@@ -38,6 +38,19 @@
|
|||||||
#define QCOW_CRYPT_AES 1
|
#define QCOW_CRYPT_AES 1
|
||||||
|
|
||||||
#define QCOW_MAX_CRYPT_CLUSTERS 32
|
#define QCOW_MAX_CRYPT_CLUSTERS 32
|
||||||
|
#define QCOW_MAX_SNAPSHOTS 65536
|
||||||
|
|
||||||
|
/* 8 MB refcount table is enough for 2 PB images at 64k cluster size
|
||||||
|
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||||
|
#define QCOW_MAX_REFTABLE_SIZE 0x800000
|
||||||
|
|
||||||
|
/* 32 MB L1 table is enough for 2 PB images at 64k cluster size
|
||||||
|
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||||
|
#define QCOW_MAX_L1_SIZE 0x2000000
|
||||||
|
|
||||||
|
/* Allow for an average of 1k per snapshot table entry, should be plenty of
|
||||||
|
* space for snapshot names and IDs */
|
||||||
|
#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS)
|
||||||
|
|
||||||
/* indicate that the refcount of the referenced cluster is exactly one. */
|
/* indicate that the refcount of the referenced cluster is exactly one. */
|
||||||
#define QCOW_OFLAG_COPIED (1ULL << 63)
|
#define QCOW_OFLAG_COPIED (1ULL << 63)
|
||||||
@@ -97,6 +110,32 @@ typedef struct QCowHeader {
|
|||||||
uint32_t header_length;
|
uint32_t header_length;
|
||||||
} QEMU_PACKED QCowHeader;
|
} QEMU_PACKED QCowHeader;
|
||||||
|
|
||||||
|
typedef struct QEMU_PACKED QCowSnapshotHeader {
|
||||||
|
/* header is 8 byte aligned */
|
||||||
|
uint64_t l1_table_offset;
|
||||||
|
|
||||||
|
uint32_t l1_size;
|
||||||
|
uint16_t id_str_size;
|
||||||
|
uint16_t name_size;
|
||||||
|
|
||||||
|
uint32_t date_sec;
|
||||||
|
uint32_t date_nsec;
|
||||||
|
|
||||||
|
uint64_t vm_clock_nsec;
|
||||||
|
|
||||||
|
uint32_t vm_state_size;
|
||||||
|
uint32_t extra_data_size; /* for extension */
|
||||||
|
/* extra data follows */
|
||||||
|
/* id_str follows */
|
||||||
|
/* name follows */
|
||||||
|
} QCowSnapshotHeader;
|
||||||
|
|
||||||
|
typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
||||||
|
uint64_t vm_state_size_large;
|
||||||
|
uint64_t disk_size;
|
||||||
|
} QCowSnapshotExtraData;
|
||||||
|
|
||||||
|
|
||||||
typedef struct QCowSnapshot {
|
typedef struct QCowSnapshot {
|
||||||
uint64_t l1_table_offset;
|
uint64_t l1_table_offset;
|
||||||
uint32_t l1_size;
|
uint32_t l1_size;
|
||||||
@@ -191,8 +230,8 @@ typedef struct BDRVQcowState {
|
|||||||
uint64_t *refcount_table;
|
uint64_t *refcount_table;
|
||||||
uint64_t refcount_table_offset;
|
uint64_t refcount_table_offset;
|
||||||
uint32_t refcount_table_size;
|
uint32_t refcount_table_size;
|
||||||
int64_t free_cluster_index;
|
uint64_t free_cluster_index;
|
||||||
int64_t free_byte_offset;
|
uint64_t free_byte_offset;
|
||||||
|
|
||||||
CoMutex lock;
|
CoMutex lock;
|
||||||
|
|
||||||
@@ -202,7 +241,7 @@ typedef struct BDRVQcowState {
|
|||||||
AES_KEY aes_decrypt_key;
|
AES_KEY aes_decrypt_key;
|
||||||
uint64_t snapshots_offset;
|
uint64_t snapshots_offset;
|
||||||
int snapshots_size;
|
int snapshots_size;
|
||||||
int nb_snapshots;
|
unsigned int nb_snapshots;
|
||||||
QCowSnapshot *snapshots;
|
QCowSnapshot *snapshots;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
@@ -383,6 +422,11 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcowState *s)
|
|||||||
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
|
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t qcow2_max_refcount_clusters(BDRVQcowState *s)
|
||||||
|
{
|
||||||
|
return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int qcow2_get_cluster_type(uint64_t l2_entry)
|
static inline int qcow2_get_cluster_type(uint64_t l2_entry)
|
||||||
{
|
{
|
||||||
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
|
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
|
||||||
@@ -431,7 +475,7 @@ void qcow2_refcount_close(BlockDriverState *bs);
|
|||||||
int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
|
int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
|
||||||
int addend, enum qcow2_discard_type type);
|
int addend, enum qcow2_discard_type type);
|
||||||
|
|
||||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
|
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
|
||||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||||
int nb_clusters);
|
int nb_clusters);
|
||||||
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
||||||
|
21
block/qed.c
21
block/qed.c
@@ -1558,16 +1558,31 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_qed_invalidate_cache(BlockDriverState *bs)
|
static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
BDRVQEDState *s = bs->opaque;
|
BDRVQEDState *s = bs->opaque;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
bdrv_qed_close(bs);
|
bdrv_qed_close(bs);
|
||||||
|
|
||||||
bdrv_invalidate_cache(bs->file);
|
bdrv_invalidate_cache(bs->file, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memset(s, 0, sizeof(BDRVQEDState));
|
memset(s, 0, sizeof(BDRVQEDState));
|
||||||
bdrv_qed_open(bs, NULL, bs->open_flags, NULL);
|
ret = bdrv_qed_open(bs, NULL, bs->open_flags, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_setg(errp, "Could not reopen qed layer: %s",
|
||||||
|
error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
return;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Could not reopen qed layer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
|
static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
|
||||||
|
@@ -625,13 +625,18 @@ static int64_t quorum_getlength(BlockDriverState *bs)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quorum_invalidate_cache(BlockDriverState *bs)
|
static void quorum_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
BDRVQuorumState *s = bs->opaque;
|
BDRVQuorumState *s = bs->opaque;
|
||||||
|
Error *local_err = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < s->num_children; i++) {
|
for (i = 0; i < s->num_children; i++) {
|
||||||
bdrv_invalidate_cache(s->bs[i]);
|
bdrv_invalidate_cache(s->bs[i], &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -909,9 +909,9 @@ static void co_write_request(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a socket discriptor to read/write objects.
|
* Return a socket descriptor to read/write objects.
|
||||||
*
|
*
|
||||||
* We cannot use this discriptor for other operations because
|
* We cannot use this descriptor for other operations because
|
||||||
* the block driver may be on waiting response from the server.
|
* the block driver may be on waiting response from the server.
|
||||||
*/
|
*/
|
||||||
static int get_sheep_fd(BDRVSheepdogState *s)
|
static int get_sheep_fd(BDRVSheepdogState *s)
|
||||||
@@ -1896,7 +1896,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Even If deletion fails, we will just create extra snapshot based on
|
* Even If deletion fails, we will just create extra snapshot based on
|
||||||
* the workding VDI which was supposed to be deleted. So no need to
|
* the working VDI which was supposed to be deleted. So no need to
|
||||||
* false bail out.
|
* false bail out.
|
||||||
*/
|
*/
|
||||||
deleted = sd_delete(s);
|
deleted = sd_delete(s);
|
||||||
@@ -2194,7 +2194,7 @@ cleanup:
|
|||||||
* We implement rollback(loadvm) operation to the specified snapshot by
|
* We implement rollback(loadvm) operation to the specified snapshot by
|
||||||
* 1) switch to the snapshot
|
* 1) switch to the snapshot
|
||||||
* 2) rely on sd_create_branch to delete working VDI and
|
* 2) rely on sd_create_branch to delete working VDI and
|
||||||
* 3) create a new working VDI based on the speicified snapshot
|
* 3) create a new working VDI based on the specified snapshot
|
||||||
*/
|
*/
|
||||||
static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||||
{
|
{
|
||||||
|
39
block/vdi.c
39
block/vdi.c
@@ -31,7 +31,7 @@
|
|||||||
* Allocation of blocks could be optimized (less writes to block map and
|
* Allocation of blocks could be optimized (less writes to block map and
|
||||||
* header).
|
* header).
|
||||||
*
|
*
|
||||||
* Read and write of adjacents blocks could be done in one operation
|
* Read and write of adjacent blocks could be done in one operation
|
||||||
* (current code uses one operation per block (1 MiB).
|
* (current code uses one operation per block (1 MiB).
|
||||||
*
|
*
|
||||||
* The code is not thread safe (missing locks for changes in header and
|
* The code is not thread safe (missing locks for changes in header and
|
||||||
@@ -120,6 +120,11 @@ typedef unsigned char uuid_t[16];
|
|||||||
|
|
||||||
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
||||||
|
|
||||||
|
/* max blocks in image is (0xffffffff / 4) */
|
||||||
|
#define VDI_BLOCKS_IN_IMAGE_MAX 0x3fffffff
|
||||||
|
#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
|
||||||
|
(uint64_t)DEFAULT_CLUSTER_SIZE)
|
||||||
|
|
||||||
#if !defined(CONFIG_UUID)
|
#if !defined(CONFIG_UUID)
|
||||||
static inline void uuid_generate(uuid_t out)
|
static inline void uuid_generate(uuid_t out)
|
||||||
{
|
{
|
||||||
@@ -385,6 +390,14 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
vdi_header_print(&header);
|
vdi_header_print(&header);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (header.disk_size > VDI_DISK_SIZE_MAX) {
|
||||||
|
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
|
||||||
|
", max supported is 0x%" PRIx64 ")",
|
||||||
|
header.disk_size, VDI_DISK_SIZE_MAX);
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (header.disk_size % SECTOR_SIZE != 0) {
|
if (header.disk_size % SECTOR_SIZE != 0) {
|
||||||
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
|
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
|
||||||
We accept them but round the disk size to the next multiple of
|
We accept them but round the disk size to the next multiple of
|
||||||
@@ -420,9 +433,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
header.sector_size, SECTOR_SIZE);
|
header.sector_size, SECTOR_SIZE);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.block_size != 1 * MiB) {
|
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
||||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
error_setg(errp, "unsupported VDI image (block size %u is not %u)",
|
||||||
header.block_size, 1 * MiB);
|
header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.disk_size >
|
} else if (header.disk_size >
|
||||||
@@ -441,6 +454,12 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
error_setg(errp, "unsupported VDI image (non-NULL parent UUID)");
|
error_setg(errp, "unsupported VDI image (non-NULL parent UUID)");
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
} else if (header.blocks_in_image > VDI_BLOCKS_IN_IMAGE_MAX) {
|
||||||
|
error_setg(errp, "unsupported VDI image "
|
||||||
|
"(too many blocks %u, max is %u)",
|
||||||
|
header.blocks_in_image, VDI_BLOCKS_IN_IMAGE_MAX);
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->total_sectors = header.disk_size / SECTOR_SIZE;
|
bs->total_sectors = header.disk_size / SECTOR_SIZE;
|
||||||
@@ -689,11 +708,20 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
options++;
|
options++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bytes > VDI_DISK_SIZE_MAX) {
|
||||||
|
result = -ENOTSUP;
|
||||||
|
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
|
||||||
|
", max supported is 0x%" PRIx64 ")",
|
||||||
|
bytes, VDI_DISK_SIZE_MAX);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
fd = qemu_open(filename,
|
fd = qemu_open(filename,
|
||||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||||
0644);
|
0644);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return -errno;
|
result = -errno;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need enough blocks to store the given disk size,
|
/* We need enough blocks to store the given disk size,
|
||||||
@@ -754,6 +782,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
result = -errno;
|
result = -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -578,7 +578,7 @@ static int vhdx_validate_log_entry(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
total_sectors = hdr.entry_length / VHDX_LOG_SECTOR_SIZE;
|
total_sectors = hdr.entry_length / VHDX_LOG_SECTOR_SIZE;
|
||||||
|
|
||||||
|
|
||||||
/* read_desc() will incrememnt the read idx */
|
/* read_desc() will increment the read idx */
|
||||||
ret = vhdx_log_read_desc(bs, s, log, &desc_buffer);
|
ret = vhdx_log_read_desc(bs, s, log, &desc_buffer);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto free_and_exit;
|
goto free_and_exit;
|
||||||
|
12
block/vhdx.c
12
block/vhdx.c
@@ -780,12 +780,20 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
|||||||
le32_to_cpus(&s->logical_sector_size);
|
le32_to_cpus(&s->logical_sector_size);
|
||||||
le32_to_cpus(&s->physical_sector_size);
|
le32_to_cpus(&s->physical_sector_size);
|
||||||
|
|
||||||
if (s->logical_sector_size == 0 || s->params.block_size == 0) {
|
if (s->params.block_size < VHDX_BLOCK_SIZE_MIN ||
|
||||||
|
s->params.block_size > VHDX_BLOCK_SIZE_MAX) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* both block_size and sector_size are guaranteed powers of 2 */
|
/* only 2 supported sector sizes */
|
||||||
|
if (s->logical_sector_size != 512 && s->logical_sector_size != 4096) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Both block_size and sector_size are guaranteed powers of 2, below.
|
||||||
|
Due to range checks above, s->sectors_per_block can never be < 256 */
|
||||||
s->sectors_per_block = s->params.block_size / s->logical_sector_size;
|
s->sectors_per_block = s->params.block_size / s->logical_sector_size;
|
||||||
s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) *
|
s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) *
|
||||||
(uint64_t)s->logical_sector_size /
|
(uint64_t)s->logical_sector_size /
|
||||||
|
@@ -61,7 +61,7 @@
|
|||||||
/* These structures are ones that are defined in the VHDX specification
|
/* These structures are ones that are defined in the VHDX specification
|
||||||
* document */
|
* document */
|
||||||
|
|
||||||
#define VHDX_FILE_SIGNATURE 0x656C696678646876 /* "vhdxfile" in ASCII */
|
#define VHDX_FILE_SIGNATURE 0x656C696678646876ULL /* "vhdxfile" in ASCII */
|
||||||
typedef struct VHDXFileIdentifier {
|
typedef struct VHDXFileIdentifier {
|
||||||
uint64_t signature; /* "vhdxfile" in ASCII */
|
uint64_t signature; /* "vhdxfile" in ASCII */
|
||||||
uint16_t creator[256]; /* optional; utf-16 string to identify
|
uint16_t creator[256]; /* optional; utf-16 string to identify
|
||||||
@@ -238,7 +238,7 @@ typedef struct QEMU_PACKED VHDXLogDataSector {
|
|||||||
/* upper 44 bits are the file offset in 1MB units lower 3 bits are the state
|
/* upper 44 bits are the file offset in 1MB units lower 3 bits are the state
|
||||||
other bits are reserved */
|
other bits are reserved */
|
||||||
#define VHDX_BAT_STATE_BIT_MASK 0x07
|
#define VHDX_BAT_STATE_BIT_MASK 0x07
|
||||||
#define VHDX_BAT_FILE_OFF_MASK 0xFFFFFFFFFFF00000 /* upper 44 bits */
|
#define VHDX_BAT_FILE_OFF_MASK 0xFFFFFFFFFFF00000ULL /* upper 44 bits */
|
||||||
typedef uint64_t VHDXBatEntry;
|
typedef uint64_t VHDXBatEntry;
|
||||||
|
|
||||||
/* ---- METADATA REGION STRUCTURES ---- */
|
/* ---- METADATA REGION STRUCTURES ---- */
|
||||||
@@ -247,7 +247,7 @@ typedef uint64_t VHDXBatEntry;
|
|||||||
#define VHDX_METADATA_MAX_ENTRIES 2047 /* not including the header */
|
#define VHDX_METADATA_MAX_ENTRIES 2047 /* not including the header */
|
||||||
#define VHDX_METADATA_TABLE_MAX_SIZE \
|
#define VHDX_METADATA_TABLE_MAX_SIZE \
|
||||||
(VHDX_METADATA_ENTRY_SIZE * (VHDX_METADATA_MAX_ENTRIES+1))
|
(VHDX_METADATA_ENTRY_SIZE * (VHDX_METADATA_MAX_ENTRIES+1))
|
||||||
#define VHDX_METADATA_SIGNATURE 0x617461646174656D /* "metadata" in ASCII */
|
#define VHDX_METADATA_SIGNATURE 0x617461646174656DULL /* "metadata" in ASCII */
|
||||||
typedef struct QEMU_PACKED VHDXMetadataTableHeader {
|
typedef struct QEMU_PACKED VHDXMetadataTableHeader {
|
||||||
uint64_t signature; /* "metadata" in ASCII */
|
uint64_t signature; /* "metadata" in ASCII */
|
||||||
uint16_t reserved;
|
uint16_t reserved;
|
||||||
|
32
block/vpc.c
32
block/vpc.c
@@ -45,6 +45,8 @@ enum vhd_type {
|
|||||||
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
||||||
#define VHD_TIMESTAMP_BASE 946684800
|
#define VHD_TIMESTAMP_BASE 946684800
|
||||||
|
|
||||||
|
#define VHD_MAX_SECTORS (65535LL * 255 * 255)
|
||||||
|
|
||||||
// always big-endian
|
// always big-endian
|
||||||
typedef struct vhd_footer {
|
typedef struct vhd_footer {
|
||||||
char creator[8]; // "conectix"
|
char creator[8]; // "conectix"
|
||||||
@@ -164,6 +166,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
VHDDynDiskHeader *dyndisk_header;
|
VHDDynDiskHeader *dyndisk_header;
|
||||||
uint8_t buf[HEADER_SIZE];
|
uint8_t buf[HEADER_SIZE];
|
||||||
uint32_t checksum;
|
uint32_t checksum;
|
||||||
|
uint64_t computed_size;
|
||||||
int disk_type = VHD_DYNAMIC;
|
int disk_type = VHD_DYNAMIC;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -222,7 +225,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allow a maximum disk size of approximately 2 TB */
|
/* Allow a maximum disk size of approximately 2 TB */
|
||||||
if (bs->total_sectors >= 65535LL * 255 * 255) {
|
if (bs->total_sectors >= VHD_MAX_SECTORS) {
|
||||||
ret = -EFBIG;
|
ret = -EFBIG;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -242,10 +245,31 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->block_size = be32_to_cpu(dyndisk_header->block_size);
|
s->block_size = be32_to_cpu(dyndisk_header->block_size);
|
||||||
|
if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) {
|
||||||
|
error_setg(errp, "Invalid block size %" PRIu32, s->block_size);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
|
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
|
||||||
|
|
||||||
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
||||||
s->pagetable = g_malloc(s->max_table_entries * 4);
|
|
||||||
|
if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
computed_size = (uint64_t) s->max_table_entries * s->block_size;
|
||||||
|
if (computed_size < bs->total_sectors * 512) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->pagetable = qemu_blockalign(bs, s->max_table_entries * 4);
|
||||||
|
|
||||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||||
|
|
||||||
@@ -298,7 +322,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
g_free(s->pagetable);
|
qemu_vfree(s->pagetable);
|
||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
g_free(s->pageentry_u8);
|
g_free(s->pageentry_u8);
|
||||||
#endif
|
#endif
|
||||||
@@ -833,7 +857,7 @@ static int vpc_has_zero_init(BlockDriverState *bs)
|
|||||||
static void vpc_close(BlockDriverState *bs)
|
static void vpc_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVVPCState *s = bs->opaque;
|
BDRVVPCState *s = bs->opaque;
|
||||||
g_free(s->pagetable);
|
qemu_vfree(s->pagetable);
|
||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
g_free(s->pageentry_u8);
|
g_free(s->pageentry_u8);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1119,6 +1119,7 @@ DLOG(if (stderr == NULL) {
|
|||||||
if (!s->fat_type) {
|
if (!s->fat_type) {
|
||||||
s->fat_type = 16;
|
s->fat_type = 16;
|
||||||
}
|
}
|
||||||
|
s->first_sectors_number = 0x40;
|
||||||
cyls = s->fat_type == 12 ? 64 : 1024;
|
cyls = s->fat_type == 12 ? 64 : 1024;
|
||||||
heads = 16;
|
heads = 16;
|
||||||
secs = 63;
|
secs = 63;
|
||||||
@@ -1146,7 +1147,6 @@ DLOG(if (stderr == NULL) {
|
|||||||
|
|
||||||
s->current_cluster=0xffffffff;
|
s->current_cluster=0xffffffff;
|
||||||
|
|
||||||
s->first_sectors_number=0x40;
|
|
||||||
/* read only is the default for safety */
|
/* read only is the default for safety */
|
||||||
bs->read_only = 1;
|
bs->read_only = 1;
|
||||||
s->qcow = s->write_target = NULL;
|
s->qcow = s->write_target = NULL;
|
||||||
|
107
configure
vendored
107
configure
vendored
@@ -198,6 +198,7 @@ audio_win_int=""
|
|||||||
cc_i386=i386-pc-linux-gnu-gcc
|
cc_i386=i386-pc-linux-gnu-gcc
|
||||||
libs_qga=""
|
libs_qga=""
|
||||||
debug_info="yes"
|
debug_info="yes"
|
||||||
|
stack_protector=""
|
||||||
|
|
||||||
# Don't accept a target_list environment variable.
|
# Don't accept a target_list environment variable.
|
||||||
unset target_list
|
unset target_list
|
||||||
@@ -318,6 +319,7 @@ glusterfs_zerofill="no"
|
|||||||
virtio_blk_data_plane=""
|
virtio_blk_data_plane=""
|
||||||
gtk=""
|
gtk=""
|
||||||
gtkabi="2.0"
|
gtkabi="2.0"
|
||||||
|
vte=""
|
||||||
tpm="no"
|
tpm="no"
|
||||||
libssh2=""
|
libssh2=""
|
||||||
vhdx=""
|
vhdx=""
|
||||||
@@ -949,6 +951,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--disable-werror) werror="no"
|
--disable-werror) werror="no"
|
||||||
;;
|
;;
|
||||||
|
--enable-stack-protector) stack_protector="yes"
|
||||||
|
;;
|
||||||
|
--disable-stack-protector) stack_protector="no"
|
||||||
|
;;
|
||||||
--disable-curses) curses="no"
|
--disable-curses) curses="no"
|
||||||
;;
|
;;
|
||||||
--enable-curses) curses="yes"
|
--enable-curses) curses="yes"
|
||||||
@@ -1063,6 +1069,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--with-gtkabi=*) gtkabi="$optarg"
|
--with-gtkabi=*) gtkabi="$optarg"
|
||||||
;;
|
;;
|
||||||
|
--disable-vte) vte="no"
|
||||||
|
;;
|
||||||
|
--enable-vte) vte="yes"
|
||||||
|
;;
|
||||||
--enable-tpm) tpm="yes"
|
--enable-tpm) tpm="yes"
|
||||||
;;
|
;;
|
||||||
--disable-libssh2) libssh2="no"
|
--disable-libssh2) libssh2="no"
|
||||||
@@ -1214,6 +1224,7 @@ Advanced options (experts only):
|
|||||||
--disable-sparse disable sparse checker (default)
|
--disable-sparse disable sparse checker (default)
|
||||||
--disable-strip disable stripping binaries
|
--disable-strip disable stripping binaries
|
||||||
--disable-werror disable compilation abort on warning
|
--disable-werror disable compilation abort on warning
|
||||||
|
--disable-stack-protector disable compiler-provided stack protection
|
||||||
--disable-sdl disable SDL
|
--disable-sdl disable SDL
|
||||||
--enable-sdl enable SDL
|
--enable-sdl enable SDL
|
||||||
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
||||||
@@ -1434,9 +1445,15 @@ for flag in $gcc_flags; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if compile_prog "-Werror -fstack-protector-all" "" ; then
|
if test "$stack_protector" != "no" ; then
|
||||||
QEMU_CFLAGS="$QEMU_CFLAGS -fstack-protector-all"
|
gcc_flags="-fstack-protector-strong -fstack-protector-all"
|
||||||
LIBTOOLFLAGS="$LIBTOOLFLAGS -Wc,-fstack-protector-all"
|
for flag in $gcc_flags; do
|
||||||
|
if compile_prog "-Werror $flag" "" ; then
|
||||||
|
QEMU_CFLAGS="$QEMU_CFLAGS $flag"
|
||||||
|
LIBTOOLFLAGS="$LIBTOOLFLAGS -Wc,$flag"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Workaround for http://gcc.gnu.org/PR55489. Happens with -fPIE/-fPIC and
|
# Workaround for http://gcc.gnu.org/PR55489. Happens with -fPIE/-fPIC and
|
||||||
@@ -1946,30 +1963,41 @@ if test "$gtk" != "no"; then
|
|||||||
gtkpackage="gtk+-$gtkabi"
|
gtkpackage="gtk+-$gtkabi"
|
||||||
if test "$gtkabi" = "3.0" ; then
|
if test "$gtkabi" = "3.0" ; then
|
||||||
gtkversion="3.0.0"
|
gtkversion="3.0.0"
|
||||||
|
else
|
||||||
|
gtkversion="2.18.0"
|
||||||
|
fi
|
||||||
|
if $pkg_config --exists "$gtkpackage >= $gtkversion"; then
|
||||||
|
gtk_cflags=`$pkg_config --cflags $gtkpackage`
|
||||||
|
gtk_libs=`$pkg_config --libs $gtkpackage`
|
||||||
|
libs_softmmu="$gtk_libs $libs_softmmu"
|
||||||
|
gtk="yes"
|
||||||
|
elif test "$gtk" = "yes"; then
|
||||||
|
feature_not_found "gtk" "Install gtk2 or gtk3 (requires --with-gtkabi=3.0 option to configure) devel"
|
||||||
|
else
|
||||||
|
gtk="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# VTE probe
|
||||||
|
|
||||||
|
if test "$vte" != "no"; then
|
||||||
|
if test "$gtkabi" = "3.0"; then
|
||||||
vtepackage="vte-2.90"
|
vtepackage="vte-2.90"
|
||||||
vteversion="0.32.0"
|
vteversion="0.32.0"
|
||||||
else
|
else
|
||||||
gtkversion="2.18.0"
|
|
||||||
vtepackage="vte"
|
vtepackage="vte"
|
||||||
vteversion="0.24.0"
|
vteversion="0.24.0"
|
||||||
fi
|
fi
|
||||||
if ! $pkg_config --exists "$gtkpackage >= $gtkversion"; then
|
if $pkg_config --exists "$vtepackage >= $vteversion"; then
|
||||||
if test "$gtk" = "yes" ; then
|
vte_cflags=`$pkg_config --cflags $vtepackage`
|
||||||
feature_not_found "gtk" "Install gtk2 or gtk3 (requires --with-gtkabi=3.0 option to configure) devel"
|
vte_libs=`$pkg_config --libs $vtepackage`
|
||||||
fi
|
libs_softmmu="$vte_libs $libs_softmmu"
|
||||||
gtk="no"
|
vte="yes"
|
||||||
elif ! $pkg_config --exists "$vtepackage >= $vteversion"; then
|
elif test "$vte" = "yes"; then
|
||||||
if test "$gtk" = "yes" ; then
|
feature_not_found "vte" "Install libvte or libvte-2.90 (requires --with-gtkabi=3.0 option to configure) devel"
|
||||||
error_exit "libvte not found (required for gtk support)"
|
|
||||||
fi
|
|
||||||
gtk="no"
|
|
||||||
else
|
else
|
||||||
gtk_cflags=`$pkg_config --cflags $gtkpackage`
|
vte="no"
|
||||||
gtk_libs=`$pkg_config --libs $gtkpackage`
|
|
||||||
vte_cflags=`$pkg_config --cflags $vtepackage`
|
|
||||||
vte_libs=`$pkg_config --libs $vtepackage`
|
|
||||||
libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
|
|
||||||
gtk="yes"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -2696,6 +2724,24 @@ if test "$mingw32" != yes -a "$pthread" = no; then
|
|||||||
"Make sure to have the pthread libs and headers installed."
|
"Make sure to have the pthread libs and headers installed."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# check for pthread_setname_np
|
||||||
|
pthread_setname_np=no
|
||||||
|
cat > $TMPC << EOF
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
static void *f(void *p) { return NULL; }
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, 0, f, 0);
|
||||||
|
pthread_setname_np(thread, "QEMU");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
if compile_prog "" "$pthread_lib" ; then
|
||||||
|
pthread_setname_np=yes
|
||||||
|
fi
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# rbd probe
|
# rbd probe
|
||||||
if test "$rbd" != "no" ; then
|
if test "$rbd" != "no" ; then
|
||||||
@@ -3822,6 +3868,11 @@ fi
|
|||||||
|
|
||||||
int128=no
|
int128=no
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
|
#if defined(__clang_major__) && defined(__clang_minor__)
|
||||||
|
# if ((__clang_major__ < 3) || (__clang_major__ == 3) && (__clang_minor__ < 2))
|
||||||
|
# error __int128_t does not work in CLANG before 3.2
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
__int128_t a;
|
__int128_t a;
|
||||||
__uint128_t b;
|
__uint128_t b;
|
||||||
int main (void) {
|
int main (void) {
|
||||||
@@ -3863,7 +3914,7 @@ fi
|
|||||||
##########################################
|
##########################################
|
||||||
# Do we have libnfs
|
# Do we have libnfs
|
||||||
if test "$libnfs" != "no" ; then
|
if test "$libnfs" != "no" ; then
|
||||||
if $pkg_config --atleast-version=1.9.2 libnfs; then
|
if $pkg_config --atleast-version=1.9.3 libnfs; then
|
||||||
libnfs="yes"
|
libnfs="yes"
|
||||||
libnfs_libs=$($pkg_config --libs libnfs)
|
libnfs_libs=$($pkg_config --libs libnfs)
|
||||||
LIBS="$LIBS $libnfs_libs"
|
LIBS="$LIBS $libnfs_libs"
|
||||||
@@ -4048,6 +4099,7 @@ fi
|
|||||||
echo "pixman $pixman"
|
echo "pixman $pixman"
|
||||||
echo "SDL support $sdl"
|
echo "SDL support $sdl"
|
||||||
echo "GTK support $gtk"
|
echo "GTK support $gtk"
|
||||||
|
echo "VTE support $vte"
|
||||||
echo "curses support $curses"
|
echo "curses support $curses"
|
||||||
echo "curl support $curl"
|
echo "curl support $curl"
|
||||||
echo "mingw32 support $mingw32"
|
echo "mingw32 support $mingw32"
|
||||||
@@ -4376,6 +4428,9 @@ 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 "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
if test "$vte" = "yes" ; then
|
||||||
|
echo "CONFIG_VTE=y" >> $config_host_mak
|
||||||
echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
|
echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$xen" = "yes" ; then
|
if test "$xen" = "yes" ; then
|
||||||
@@ -4623,6 +4678,16 @@ if test "$rdma" = "yes" ; then
|
|||||||
echo "CONFIG_RDMA=y" >> $config_host_mak
|
echo "CONFIG_RDMA=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Hold two types of flag:
|
||||||
|
# CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on
|
||||||
|
# a thread we have a handle to
|
||||||
|
# CONFIG_PTHREAD_SETNAME_NP - A way of doing it on a particular
|
||||||
|
# platform
|
||||||
|
if test "$pthread_setname_np" = "yes" ; then
|
||||||
|
echo "CONFIG_THREAD_SETNAME_BYTHREAD=y" >> $config_host_mak
|
||||||
|
echo "CONFIG_PTHREAD_SETNAME_NP=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$tcg_interpreter" = "yes"; then
|
if test "$tcg_interpreter" = "yes"; then
|
||||||
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
|
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
|
||||||
elif test "$ARCH" = "sparc64" ; then
|
elif test "$ARCH" = "sparc64" ; then
|
||||||
|
@@ -227,6 +227,8 @@ int cpu_exec(CPUArchState *env)
|
|||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
uint8_t *tc_ptr;
|
uint8_t *tc_ptr;
|
||||||
uintptr_t next_tb;
|
uintptr_t next_tb;
|
||||||
|
/* This must be volatile so it is not trashed by longjmp() */
|
||||||
|
volatile bool have_tb_lock = false;
|
||||||
|
|
||||||
if (cpu->halted) {
|
if (cpu->halted) {
|
||||||
if (!cpu_has_work(cpu)) {
|
if (!cpu_has_work(cpu)) {
|
||||||
@@ -600,6 +602,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
|
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
|
||||||
|
have_tb_lock = true;
|
||||||
tb = tb_find_fast(env);
|
tb = tb_find_fast(env);
|
||||||
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
||||||
doing it in tb_find_slow */
|
doing it in tb_find_slow */
|
||||||
@@ -621,6 +624,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
|
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
|
||||||
next_tb & TB_EXIT_MASK, tb);
|
next_tb & TB_EXIT_MASK, tb);
|
||||||
}
|
}
|
||||||
|
have_tb_lock = false;
|
||||||
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
||||||
|
|
||||||
/* cpu_interrupt might be called while translating the
|
/* cpu_interrupt might be called while translating the
|
||||||
@@ -692,6 +696,10 @@ int cpu_exec(CPUArchState *env)
|
|||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
x86_cpu = X86_CPU(cpu);
|
x86_cpu = X86_CPU(cpu);
|
||||||
#endif
|
#endif
|
||||||
|
if (have_tb_lock) {
|
||||||
|
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
||||||
|
have_tb_lock = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} /* for(;;) */
|
} /* for(;;) */
|
||||||
|
|
||||||
|
@@ -213,6 +213,7 @@ BlockDriverAIOCB *dma_bdrv_io(
|
|||||||
dbs->sg_cur_index = 0;
|
dbs->sg_cur_index = 0;
|
||||||
dbs->sg_cur_byte = 0;
|
dbs->sg_cur_byte = 0;
|
||||||
dbs->dir = dir;
|
dbs->dir = dir;
|
||||||
|
dbs->in_cancel = false;
|
||||||
dbs->io_func = io_func;
|
dbs->io_func = io_func;
|
||||||
dbs->bh = NULL;
|
dbs->bh = NULL;
|
||||||
qemu_iovec_init(&dbs->iov, sg->nsg);
|
qemu_iovec_init(&dbs->iov, sg->nsg);
|
||||||
|
2
exec.c
2
exec.c
@@ -420,7 +420,7 @@ static int cpu_common_post_load(void *opaque, int version_id)
|
|||||||
/* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
|
/* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
|
||||||
version_id is increased. */
|
version_id is increased. */
|
||||||
cpu->interrupt_request &= ~0x01;
|
cpu->interrupt_request &= ~0x01;
|
||||||
tlb_flush(cpu->env_ptr, 1);
|
tlb_flush(cpu, 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -288,7 +288,7 @@ INLINE flag extractFloat32Sign( float32 a )
|
|||||||
| If `a' is denormal and we are in flush-to-zero mode then set the
|
| If `a' is denormal and we are in flush-to-zero mode then set the
|
||||||
| input-denormal exception and return zero. Otherwise just return the value.
|
| input-denormal exception and return zero. Otherwise just return the value.
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
static float32 float32_squash_input_denormal(float32 a STATUS_PARAM)
|
float32 float32_squash_input_denormal(float32 a STATUS_PARAM)
|
||||||
{
|
{
|
||||||
if (STATUS(flush_inputs_to_zero)) {
|
if (STATUS(flush_inputs_to_zero)) {
|
||||||
if (extractFloat32Exp(a) == 0 && extractFloat32Frac(a) != 0) {
|
if (extractFloat32Exp(a) == 0 && extractFloat32Frac(a) != 0) {
|
||||||
@@ -473,7 +473,7 @@ INLINE flag extractFloat64Sign( float64 a )
|
|||||||
| If `a' is denormal and we are in flush-to-zero mode then set the
|
| If `a' is denormal and we are in flush-to-zero mode then set the
|
||||||
| input-denormal exception and return zero. Otherwise just return the value.
|
| input-denormal exception and return zero. Otherwise just return the value.
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
static float64 float64_squash_input_denormal(float64 a STATUS_PARAM)
|
float64 float64_squash_input_denormal(float64 a STATUS_PARAM)
|
||||||
{
|
{
|
||||||
if (STATUS(flush_inputs_to_zero)) {
|
if (STATUS(flush_inputs_to_zero)) {
|
||||||
if (extractFloat64Exp(a) == 0 && extractFloat64Frac(a) != 0) {
|
if (extractFloat64Exp(a) == 0 && extractFloat64Frac(a) != 0) {
|
||||||
|
@@ -43,6 +43,7 @@ void AcpiCpuHotplug_add(ACPIGPE *gpe, AcpiCpuHotplug *g, CPUState *cpu)
|
|||||||
|
|
||||||
*gpe->sts = *gpe->sts | ACPI_CPU_HOTPLUG_STATUS;
|
*gpe->sts = *gpe->sts | ACPI_CPU_HOTPLUG_STATUS;
|
||||||
cpu_id = k->get_arch_id(CPU(cpu));
|
cpu_id = k->get_arch_id(CPU(cpu));
|
||||||
|
g_assert((cpu_id / 8) < ACPI_GPE_PROC_LEN);
|
||||||
g->sts[cpu_id / 8] |= (1 << (cpu_id % 8));
|
g->sts[cpu_id / 8] |= (1 << (cpu_id % 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -448,6 +448,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
int initrd_size;
|
int initrd_size;
|
||||||
int is_linux = 0;
|
int is_linux = 0;
|
||||||
uint64_t elf_entry;
|
uint64_t elf_entry;
|
||||||
|
int elf_machine;
|
||||||
hwaddr entry, kernel_load_offset;
|
hwaddr entry, kernel_load_offset;
|
||||||
int big_endian;
|
int big_endian;
|
||||||
static const ARMInsnFixup *primary_loader;
|
static const ARMInsnFixup *primary_loader;
|
||||||
@@ -463,9 +464,11 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
||||||
primary_loader = bootloader_aarch64;
|
primary_loader = bootloader_aarch64;
|
||||||
kernel_load_offset = KERNEL64_LOAD_ADDR;
|
kernel_load_offset = KERNEL64_LOAD_ADDR;
|
||||||
|
elf_machine = EM_AARCH64;
|
||||||
} else {
|
} else {
|
||||||
primary_loader = bootloader;
|
primary_loader = bootloader;
|
||||||
kernel_load_offset = KERNEL_LOAD_ADDR;
|
kernel_load_offset = KERNEL_LOAD_ADDR;
|
||||||
|
elf_machine = EM_ARM;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
|
info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
|
||||||
@@ -501,7 +504,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
|
|
||||||
/* Assume that raw images are linux kernels, and ELF images are not. */
|
/* Assume that raw images are linux kernels, and ELF images are not. */
|
||||||
kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
|
kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
|
||||||
NULL, NULL, big_endian, ELF_MACHINE, 1);
|
NULL, NULL, big_endian, elf_machine, 1);
|
||||||
entry = elf_entry;
|
entry = elf_entry;
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
|
kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
|
||||||
|
@@ -143,11 +143,21 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
|||||||
unsigned long mem_size;
|
unsigned long mem_size;
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
SysBusDevice *busdev;
|
SysBusDevice *busdev;
|
||||||
|
ObjectClass *cpu_oc;
|
||||||
|
|
||||||
|
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9");
|
||||||
|
assert(cpu_oc);
|
||||||
|
|
||||||
for (n = 0; n < EXYNOS4210_NCPUS; n++) {
|
for (n = 0; n < EXYNOS4210_NCPUS; n++) {
|
||||||
s->cpu[n] = cpu_arm_init("cortex-a9");
|
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||||
if (!s->cpu[n]) {
|
Error *err = NULL;
|
||||||
fprintf(stderr, "Unable to find CPU %d definition\n", n);
|
|
||||||
|
s->cpu[n] = ARM_CPU(cpuobj);
|
||||||
|
object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
|
||||||
|
"reset-cbar", &error_abort);
|
||||||
|
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -230,18 +230,23 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
|||||||
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
for (n = 0; n < smp_cpus; n++) {
|
||||||
ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||||
|
Object *cpuobj;
|
||||||
ARMCPU *cpu;
|
ARMCPU *cpu;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
|
if (!oc) {
|
||||||
|
error_report("Unable to find CPU definition");
|
||||||
object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar",
|
|
||||||
&err);
|
|
||||||
if (err) {
|
|
||||||
error_report("%s", error_get_pretty(err));
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", &err);
|
|
||||||
|
cpuobj = object_new(object_class_get_name(oc));
|
||||||
|
cpu = ARM_CPU(cpuobj);
|
||||||
|
|
||||||
|
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||||
|
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
|
||||||
|
"reset-cbar", &error_abort);
|
||||||
|
}
|
||||||
|
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_report("%s", error_get_pretty(err));
|
error_report("%s", error_get_pretty(err));
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@@ -534,7 +534,6 @@ static QEMUMachine integratorcp_machine = {
|
|||||||
.name = "integratorcp",
|
.name = "integratorcp",
|
||||||
.desc = "ARM Integrator/CP (ARM926EJ-S)",
|
.desc = "ARM Integrator/CP (ARM926EJ-S)",
|
||||||
.init = integratorcp_init,
|
.init = integratorcp_init,
|
||||||
.is_default = 1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void integratorcp_machine_init(void)
|
static void integratorcp_machine_init(void)
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include "hw/i2c/i2c.h"
|
#include "hw/i2c/i2c.h"
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
#define SMP_BOOT_ADDR 0xe0000000
|
#define SMP_BOOT_ADDR 0xe0000000
|
||||||
#define SMP_BOOTREG_ADDR 0x10000030
|
#define SMP_BOOTREG_ADDR 0x10000030
|
||||||
@@ -49,6 +50,7 @@ static void realview_init(QEMUMachineInitArgs *args,
|
|||||||
{
|
{
|
||||||
ARMCPU *cpu = NULL;
|
ARMCPU *cpu = NULL;
|
||||||
CPUARMState *env;
|
CPUARMState *env;
|
||||||
|
ObjectClass *cpu_oc;
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
|
MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
|
MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
|
||||||
@@ -70,12 +72,14 @@ static void realview_init(QEMUMachineInitArgs *args,
|
|||||||
uint32_t sys_id;
|
uint32_t sys_id;
|
||||||
ram_addr_t low_ram_size;
|
ram_addr_t low_ram_size;
|
||||||
ram_addr_t ram_size = args->ram_size;
|
ram_addr_t ram_size = args->ram_size;
|
||||||
|
hwaddr periphbase = 0;
|
||||||
|
|
||||||
switch (board_type) {
|
switch (board_type) {
|
||||||
case BOARD_EB:
|
case BOARD_EB:
|
||||||
break;
|
break;
|
||||||
case BOARD_EB_MPCORE:
|
case BOARD_EB_MPCORE:
|
||||||
is_mpcore = 1;
|
is_mpcore = 1;
|
||||||
|
periphbase = 0x10100000;
|
||||||
break;
|
break;
|
||||||
case BOARD_PB_A8:
|
case BOARD_PB_A8:
|
||||||
is_pb = 1;
|
is_pb = 1;
|
||||||
@@ -83,16 +87,37 @@ static void realview_init(QEMUMachineInitArgs *args,
|
|||||||
case BOARD_PBX_A9:
|
case BOARD_PBX_A9:
|
||||||
is_mpcore = 1;
|
is_mpcore = 1;
|
||||||
is_pb = 1;
|
is_pb = 1;
|
||||||
|
periphbase = 0x1f000000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, args->cpu_model);
|
||||||
|
if (!cpu_oc) {
|
||||||
|
fprintf(stderr, "Unable to find CPU definition\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
for (n = 0; n < smp_cpus; n++) {
|
||||||
cpu = cpu_arm_init(args->cpu_model);
|
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||||
if (!cpu) {
|
Error *err = NULL;
|
||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
|
||||||
|
if (is_pb && is_mpcore) {
|
||||||
|
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
|
||||||
|
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ);
|
||||||
}
|
}
|
||||||
|
cpu = ARM_CPU(first_cpu);
|
||||||
env = &cpu->env;
|
env = &cpu->env;
|
||||||
if (arm_feature(env, ARM_FEATURE_V7)) {
|
if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||||
if (is_mpcore) {
|
if (is_mpcore) {
|
||||||
@@ -141,16 +166,10 @@ static void realview_init(QEMUMachineInitArgs *args,
|
|||||||
sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
|
sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
|
||||||
|
|
||||||
if (is_mpcore) {
|
if (is_mpcore) {
|
||||||
hwaddr periphbase;
|
|
||||||
dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
|
dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
|
||||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
busdev = SYS_BUS_DEVICE(dev);
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
if (is_pb) {
|
|
||||||
periphbase = 0x1f000000;
|
|
||||||
} else {
|
|
||||||
periphbase = 0x10100000;
|
|
||||||
}
|
|
||||||
sysbus_mmio_map(busdev, 0, periphbase);
|
sysbus_mmio_map(busdev, 0, periphbase);
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
for (n = 0; n < smp_cpus; n++) {
|
||||||
sysbus_connect_irq(busdev, n, cpu_irq[n]);
|
sysbus_connect_irq(busdev, n, cpu_irq[n]);
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
#include "hw/block/flash.h"
|
#include "hw/block/flash.h"
|
||||||
#include "sysemu/device_tree.h"
|
#include "sysemu/device_tree.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
#define VEXPRESS_BOARD_ID 0x8e0
|
#define VEXPRESS_BOARD_ID 0x8e0
|
||||||
@@ -173,6 +174,63 @@ struct VEDBoardInfo {
|
|||||||
DBoardInitFn *init;
|
DBoardInitFn *init;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void init_cpus(const char *cpu_model, const char *privdev,
|
||||||
|
hwaddr periphbase, qemu_irq *pic)
|
||||||
|
{
|
||||||
|
ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||||
|
DeviceState *dev;
|
||||||
|
SysBusDevice *busdev;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (!cpu_oc) {
|
||||||
|
fprintf(stderr, "Unable to find CPU definition\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the actual CPUs */
|
||||||
|
for (n = 0; n < smp_cpus; n++) {
|
||||||
|
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||||
|
object_property_set_int(cpuobj, periphbase,
|
||||||
|
"reset-cbar", &error_abort);
|
||||||
|
}
|
||||||
|
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_report("%s", error_get_pretty(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the private peripheral devices (including the GIC);
|
||||||
|
* this must happen after the CPUs are created because a15mpcore_priv
|
||||||
|
* wires itself up to the CPU's generic_timer gpio out lines.
|
||||||
|
*/
|
||||||
|
dev = qdev_create(NULL, privdev);
|
||||||
|
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
busdev = SYS_BUS_DEVICE(dev);
|
||||||
|
sysbus_mmio_map(busdev, 0, periphbase);
|
||||||
|
|
||||||
|
/* Interrupts [42:0] are from the motherboard;
|
||||||
|
* [47:43] are reserved; [63:48] are daughterboard
|
||||||
|
* peripherals. Note that some documentation numbers
|
||||||
|
* external interrupts starting from 32 (because there
|
||||||
|
* are internal interrupts 0..31).
|
||||||
|
*/
|
||||||
|
for (n = 0; n < 64; n++) {
|
||||||
|
pic[n] = qdev_get_gpio_in(dev, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect the CPUs to the GIC */
|
||||||
|
for (n = 0; n < smp_cpus; n++) {
|
||||||
|
DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
|
||||||
|
|
||||||
|
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||||
ram_addr_t ram_size,
|
ram_addr_t ram_size,
|
||||||
const char *cpu_model,
|
const char *cpu_model,
|
||||||
@@ -181,25 +239,12 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *lowram = g_new(MemoryRegion, 1);
|
MemoryRegion *lowram = g_new(MemoryRegion, 1);
|
||||||
DeviceState *dev;
|
|
||||||
SysBusDevice *busdev;
|
|
||||||
int n;
|
|
||||||
qemu_irq cpu_irq[4];
|
|
||||||
ram_addr_t low_ram_size;
|
ram_addr_t low_ram_size;
|
||||||
|
|
||||||
if (!cpu_model) {
|
if (!cpu_model) {
|
||||||
cpu_model = "cortex-a9";
|
cpu_model = "cortex-a9";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
|
||||||
ARMCPU *cpu = cpu_arm_init(cpu_model);
|
|
||||||
if (!cpu) {
|
|
||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ram_size > 0x40000000) {
|
if (ram_size > 0x40000000) {
|
||||||
/* 1GB is the maximum the address space permits */
|
/* 1GB is the maximum the address space permits */
|
||||||
fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n");
|
fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n");
|
||||||
@@ -221,23 +266,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
memory_region_add_subregion(sysmem, 0x60000000, ram);
|
memory_region_add_subregion(sysmem, 0x60000000, ram);
|
||||||
|
|
||||||
/* 0x1e000000 A9MPCore (SCU) private memory region */
|
/* 0x1e000000 A9MPCore (SCU) private memory region */
|
||||||
dev = qdev_create(NULL, "a9mpcore_priv");
|
init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic);
|
||||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
|
||||||
qdev_init_nofail(dev);
|
|
||||||
busdev = SYS_BUS_DEVICE(dev);
|
|
||||||
sysbus_mmio_map(busdev, 0, 0x1e000000);
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
|
||||||
sysbus_connect_irq(busdev, n, cpu_irq[n]);
|
|
||||||
}
|
|
||||||
/* Interrupts [42:0] are from the motherboard;
|
|
||||||
* [47:43] are reserved; [63:48] are daughterboard
|
|
||||||
* peripherals. Note that some documentation numbers
|
|
||||||
* external interrupts starting from 32 (because the
|
|
||||||
* A9MP has internal interrupts 0..31).
|
|
||||||
*/
|
|
||||||
for (n = 0; n < 64; n++) {
|
|
||||||
pic[n] = qdev_get_gpio_in(dev, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
|
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
|
||||||
|
|
||||||
@@ -296,29 +325,14 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
const char *cpu_model,
|
const char *cpu_model,
|
||||||
qemu_irq *pic)
|
qemu_irq *pic)
|
||||||
{
|
{
|
||||||
int n;
|
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||||
qemu_irq cpu_irq[4];
|
|
||||||
DeviceState *dev;
|
|
||||||
SysBusDevice *busdev;
|
|
||||||
|
|
||||||
if (!cpu_model) {
|
if (!cpu_model) {
|
||||||
cpu_model = "cortex-a15";
|
cpu_model = "cortex-a15";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
|
||||||
ARMCPU *cpu;
|
|
||||||
|
|
||||||
cpu = cpu_arm_init(cpu_model);
|
|
||||||
if (!cpu) {
|
|
||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
/* We have to use a separate 64 bit variable here to avoid the gcc
|
/* We have to use a separate 64 bit variable here to avoid the gcc
|
||||||
* "comparison is always false due to limited range of data type"
|
* "comparison is always false due to limited range of data type"
|
||||||
@@ -337,23 +351,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
|||||||
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
||||||
|
|
||||||
/* 0x2c000000 A15MPCore private memory region (GIC) */
|
/* 0x2c000000 A15MPCore private memory region (GIC) */
|
||||||
dev = qdev_create(NULL, "a15mpcore_priv");
|
init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic);
|
||||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
|
||||||
qdev_init_nofail(dev);
|
|
||||||
busdev = SYS_BUS_DEVICE(dev);
|
|
||||||
sysbus_mmio_map(busdev, 0, 0x2c000000);
|
|
||||||
for (n = 0; n < smp_cpus; n++) {
|
|
||||||
sysbus_connect_irq(busdev, n, cpu_irq[n]);
|
|
||||||
}
|
|
||||||
/* Interrupts [42:0] are from the motherboard;
|
|
||||||
* [47:43] are reserved; [63:48] are daughterboard
|
|
||||||
* peripherals. Note that some documentation numbers
|
|
||||||
* external interrupts starting from 32 (because there
|
|
||||||
* are internal interrupts 0..31).
|
|
||||||
*/
|
|
||||||
for (n = 0; n < 64; n++) {
|
|
||||||
pic[n] = qdev_get_gpio_in(dev, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A15 daughterboard peripherals: */
|
/* A15 daughterboard peripherals: */
|
||||||
|
|
||||||
|
@@ -390,6 +390,12 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
|||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
|
object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||||
|
object_property_set_int(cpuobj, vbi->memmap[VIRT_CPUPERIPHS].base,
|
||||||
|
"reset-cbar", &error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
object_property_set_bool(cpuobj, true, "realized", NULL);
|
object_property_set_bool(cpuobj, true, "realized", NULL);
|
||||||
}
|
}
|
||||||
fdt_add_cpu_nodes(vbi);
|
fdt_add_cpu_nodes(vbi);
|
||||||
|
@@ -223,13 +223,13 @@ static void *cur_chip = NULL; /* current chip point */
|
|||||||
/* static OPLSAMPLE *bufL,*bufR; */
|
/* static OPLSAMPLE *bufL,*bufR; */
|
||||||
static OPL_CH *S_CH;
|
static OPL_CH *S_CH;
|
||||||
static OPL_CH *E_CH;
|
static OPL_CH *E_CH;
|
||||||
OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
|
static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2;
|
||||||
|
|
||||||
static INT32 outd[1];
|
static INT32 outd[1];
|
||||||
static INT32 ams;
|
static INT32 ams;
|
||||||
static INT32 vib;
|
static INT32 vib;
|
||||||
INT32 *ams_table;
|
static INT32 *ams_table;
|
||||||
INT32 *vib_table;
|
static INT32 *vib_table;
|
||||||
static INT32 amsIncr;
|
static INT32 amsIncr;
|
||||||
static INT32 vibIncr;
|
static INT32 vibIncr;
|
||||||
static INT32 feedback2; /* connect for SLOT 2 */
|
static INT32 feedback2; /* connect for SLOT 2 */
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
#include "virtio-blk.h"
|
#include "virtio-blk.h"
|
||||||
#include "block/aio.h"
|
#include "block/aio.h"
|
||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
#include "monitor/monitor.h" /* for object_add() */
|
#include "qom/object_interfaces.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SEG_MAX = 126, /* maximum number of I/O segments */
|
SEG_MAX = 126, /* maximum number of I/O segments */
|
||||||
@@ -59,7 +59,7 @@ struct VirtIOBlockDataPlane {
|
|||||||
* use it).
|
* use it).
|
||||||
*/
|
*/
|
||||||
IOThread *iothread;
|
IOThread *iothread;
|
||||||
bool internal_iothread;
|
IOThread internal_iothread_obj;
|
||||||
AioContext *ctx;
|
AioContext *ctx;
|
||||||
EventNotifier io_notifier; /* Linux AIO completion */
|
EventNotifier io_notifier; /* Linux AIO completion */
|
||||||
EventNotifier host_notifier; /* doorbell */
|
EventNotifier host_notifier; /* doorbell */
|
||||||
@@ -391,22 +391,18 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
|||||||
s->blk = blk;
|
s->blk = blk;
|
||||||
|
|
||||||
if (blk->iothread) {
|
if (blk->iothread) {
|
||||||
s->internal_iothread = false;
|
|
||||||
s->iothread = blk->iothread;
|
s->iothread = blk->iothread;
|
||||||
object_ref(OBJECT(s->iothread));
|
object_ref(OBJECT(s->iothread));
|
||||||
} else {
|
} else {
|
||||||
/* Create per-device IOThread if none specified */
|
/* Create per-device IOThread if none specified. This is for
|
||||||
Error *local_err = NULL;
|
* x-data-plane option compatibility. If x-data-plane is removed we
|
||||||
|
* can drop this.
|
||||||
s->internal_iothread = true;
|
*/
|
||||||
object_add(TYPE_IOTHREAD, vdev->name, NULL, NULL, &local_err);
|
object_initialize(&s->internal_iothread_obj,
|
||||||
if (error_is_set(&local_err)) {
|
sizeof(s->internal_iothread_obj),
|
||||||
error_propagate(errp, local_err);
|
TYPE_IOTHREAD);
|
||||||
g_free(s);
|
user_creatable_complete(OBJECT(&s->internal_iothread_obj), &error_abort);
|
||||||
return;
|
s->iothread = &s->internal_iothread_obj;
|
||||||
}
|
|
||||||
s->iothread = iothread_find(vdev->name);
|
|
||||||
assert(s->iothread);
|
|
||||||
}
|
}
|
||||||
s->ctx = iothread_get_aio_context(s->iothread);
|
s->ctx = iothread_get_aio_context(s->iothread);
|
||||||
|
|
||||||
@@ -426,9 +422,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
|
|||||||
virtio_blk_data_plane_stop(s);
|
virtio_blk_data_plane_stop(s);
|
||||||
bdrv_set_in_use(s->blk->conf.bs, 0);
|
bdrv_set_in_use(s->blk->conf.bs, 0);
|
||||||
object_unref(OBJECT(s->iothread));
|
object_unref(OBJECT(s->iothread));
|
||||||
if (s->internal_iothread) {
|
|
||||||
object_unparent(OBJECT(s->iothread));
|
|
||||||
}
|
|
||||||
g_free(s);
|
g_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -752,8 +752,8 @@ static int nvme_init(PCIDevice *pci_dev)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs_size = bdrv_getlength(n->conf.bs);
|
bs_size = bdrv_getlength(n->conf.bs);
|
||||||
if (bs_size <= 0) {
|
if (bs_size < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@ typedef struct PL011State {
|
|||||||
uint32_t readbuff;
|
uint32_t readbuff;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint32_t lcr;
|
uint32_t lcr;
|
||||||
|
uint32_t rsr;
|
||||||
uint32_t cr;
|
uint32_t cr;
|
||||||
uint32_t dmacr;
|
uint32_t dmacr;
|
||||||
uint32_t int_enabled;
|
uint32_t int_enabled;
|
||||||
@@ -81,13 +82,14 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
|
|||||||
}
|
}
|
||||||
if (s->read_count == s->read_trigger - 1)
|
if (s->read_count == s->read_trigger - 1)
|
||||||
s->int_level &= ~ PL011_INT_RX;
|
s->int_level &= ~ PL011_INT_RX;
|
||||||
|
s->rsr = c >> 8;
|
||||||
pl011_update(s);
|
pl011_update(s);
|
||||||
if (s->chr) {
|
if (s->chr) {
|
||||||
qemu_chr_accept_input(s->chr);
|
qemu_chr_accept_input(s->chr);
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
case 1: /* UARTCR */
|
case 1: /* UARTRSR */
|
||||||
return 0;
|
return s->rsr;
|
||||||
case 6: /* UARTFR */
|
case 6: /* UARTFR */
|
||||||
return s->flags;
|
return s->flags;
|
||||||
case 8: /* UARTILPR */
|
case 8: /* UARTILPR */
|
||||||
@@ -146,8 +148,8 @@ static void pl011_write(void *opaque, hwaddr offset,
|
|||||||
s->int_level |= PL011_INT_TX;
|
s->int_level |= PL011_INT_TX;
|
||||||
pl011_update(s);
|
pl011_update(s);
|
||||||
break;
|
break;
|
||||||
case 1: /* UARTCR */
|
case 1: /* UARTRSR/UARTECR */
|
||||||
s->cr = value;
|
s->rsr = 0;
|
||||||
break;
|
break;
|
||||||
case 6: /* UARTFR */
|
case 6: /* UARTFR */
|
||||||
/* Writes to Flag register are ignored. */
|
/* Writes to Flag register are ignored. */
|
||||||
@@ -162,6 +164,11 @@ static void pl011_write(void *opaque, hwaddr offset,
|
|||||||
s->fbrd = value;
|
s->fbrd = value;
|
||||||
break;
|
break;
|
||||||
case 11: /* UARTLCR_H */
|
case 11: /* UARTLCR_H */
|
||||||
|
/* Reset the FIFO state on FIFO enable or disable */
|
||||||
|
if ((s->lcr ^ value) & 0x10) {
|
||||||
|
s->read_count = 0;
|
||||||
|
s->read_pos = 0;
|
||||||
|
}
|
||||||
s->lcr = value;
|
s->lcr = value;
|
||||||
pl011_set_read_trigger(s);
|
pl011_set_read_trigger(s);
|
||||||
break;
|
break;
|
||||||
@@ -214,7 +221,7 @@ static void pl011_put_fifo(void *opaque, uint32_t value)
|
|||||||
s->read_fifo[slot] = value;
|
s->read_fifo[slot] = value;
|
||||||
s->read_count++;
|
s->read_count++;
|
||||||
s->flags &= ~PL011_FLAG_RXFE;
|
s->flags &= ~PL011_FLAG_RXFE;
|
||||||
if (s->cr & 0x10 || s->read_count == 16) {
|
if (!(s->lcr & 0x10) || s->read_count == 16) {
|
||||||
s->flags |= PL011_FLAG_RXFF;
|
s->flags |= PL011_FLAG_RXFF;
|
||||||
}
|
}
|
||||||
if (s->read_count == s->read_trigger) {
|
if (s->read_count == s->read_trigger) {
|
||||||
@@ -242,13 +249,14 @@ static const MemoryRegionOps pl011_ops = {
|
|||||||
|
|
||||||
static const VMStateDescription vmstate_pl011 = {
|
static const VMStateDescription vmstate_pl011 = {
|
||||||
.name = "pl011",
|
.name = "pl011",
|
||||||
.version_id = 1,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 2,
|
||||||
.minimum_version_id_old = 1,
|
.minimum_version_id_old = 2,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(readbuff, PL011State),
|
VMSTATE_UINT32(readbuff, PL011State),
|
||||||
VMSTATE_UINT32(flags, PL011State),
|
VMSTATE_UINT32(flags, PL011State),
|
||||||
VMSTATE_UINT32(lcr, PL011State),
|
VMSTATE_UINT32(lcr, PL011State),
|
||||||
|
VMSTATE_UINT32(rsr, PL011State),
|
||||||
VMSTATE_UINT32(cr, PL011State),
|
VMSTATE_UINT32(cr, PL011State),
|
||||||
VMSTATE_UINT32(dmacr, PL011State),
|
VMSTATE_UINT32(dmacr, PL011State),
|
||||||
VMSTATE_UINT32(int_enabled, PL011State),
|
VMSTATE_UINT32(int_enabled, PL011State),
|
||||||
|
@@ -41,7 +41,6 @@ typedef struct SCLPConsoleLM {
|
|||||||
uint32_t write_errors; /* errors writing to char layer */
|
uint32_t write_errors; /* errors writing to char layer */
|
||||||
uint32_t length; /* length of byte stream in buffer */
|
uint32_t length; /* length of byte stream in buffer */
|
||||||
uint8_t buf[SIZE_CONSOLE_BUFFER];
|
uint8_t buf[SIZE_CONSOLE_BUFFER];
|
||||||
qemu_irq irq_console_read;
|
|
||||||
} SCLPConsoleLM;
|
} SCLPConsoleLM;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -68,13 +67,15 @@ static int chr_can_read(void *opaque)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void receive_from_chr_layer(SCLPConsoleLM *scon, const uint8_t *buf,
|
static void chr_read(void *opaque, const uint8_t *buf, int size)
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
|
SCLPConsoleLM *scon = opaque;
|
||||||
|
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
if (*buf == '\r' || *buf == '\n') {
|
if (*buf == '\r' || *buf == '\n') {
|
||||||
scon->event.event_pending = true;
|
scon->event.event_pending = true;
|
||||||
|
sclp_service_interrupt(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scon->buf[scon->length] = *buf;
|
scon->buf[scon->length] = *buf;
|
||||||
@@ -84,20 +85,6 @@ static void receive_from_chr_layer(SCLPConsoleLM *scon, const uint8_t *buf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Send data from a char device over to the guest
|
|
||||||
*/
|
|
||||||
static void chr_read(void *opaque, const uint8_t *buf, int size)
|
|
||||||
{
|
|
||||||
SCLPConsoleLM *scon = opaque;
|
|
||||||
|
|
||||||
receive_from_chr_layer(scon, buf, size);
|
|
||||||
if (scon->event.event_pending) {
|
|
||||||
/* trigger SCLP read operation */
|
|
||||||
qemu_irq_raise(scon->irq_console_read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* functions to be called by event facility */
|
/* functions to be called by event facility */
|
||||||
|
|
||||||
static bool can_handle_event(uint8_t type)
|
static bool can_handle_event(uint8_t type)
|
||||||
@@ -298,11 +285,6 @@ static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
|
|||||||
return SCLP_RC_NORMAL_COMPLETION;
|
return SCLP_RC_NORMAL_COMPLETION;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trigger_console_data(void *opaque, int n, int level)
|
|
||||||
{
|
|
||||||
sclp_service_interrupt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* functions for live migration */
|
/* functions for live migration */
|
||||||
|
|
||||||
static const VMStateDescription vmstate_sclplmconsole = {
|
static const VMStateDescription vmstate_sclplmconsole = {
|
||||||
@@ -338,7 +320,6 @@ static int console_init(SCLPEvent *event)
|
|||||||
if (scon->chr) {
|
if (scon->chr) {
|
||||||
qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon);
|
qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon);
|
||||||
}
|
}
|
||||||
scon->irq_console_read = *qemu_allocate_irqs(trigger_console_data, NULL, 1);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,6 @@ typedef struct SCLPConsole {
|
|||||||
uint32_t iov_bs; /* offset in buf for char layer read operation */
|
uint32_t iov_bs; /* offset in buf for char layer read operation */
|
||||||
uint32_t iov_data_len; /* length of byte stream in buffer */
|
uint32_t iov_data_len; /* length of byte stream in buffer */
|
||||||
uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
|
uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
|
||||||
qemu_irq irq_read_vt220;
|
|
||||||
} SCLPConsole;
|
} SCLPConsole;
|
||||||
|
|
||||||
/* character layer call-back functions */
|
/* character layer call-back functions */
|
||||||
@@ -49,11 +48,12 @@ static int chr_can_read(void *opaque)
|
|||||||
return SIZE_BUFFER_VT220 - scon->iov_data_len;
|
return SIZE_BUFFER_VT220 - scon->iov_data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Receive n bytes from character layer, save in iov buffer,
|
/* Send data from a char device over to the guest */
|
||||||
* and set event pending */
|
static void chr_read(void *opaque, const uint8_t *buf, int size)
|
||||||
static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
|
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
|
SCLPConsole *scon = opaque;
|
||||||
|
|
||||||
|
assert(scon);
|
||||||
/* read data must fit into current buffer */
|
/* read data must fit into current buffer */
|
||||||
assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
|
assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
|
||||||
|
|
||||||
@@ -63,18 +63,7 @@ static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
|
|||||||
scon->iov_sclp_rest += size;
|
scon->iov_sclp_rest += size;
|
||||||
scon->iov_bs += size;
|
scon->iov_bs += size;
|
||||||
scon->event.event_pending = true;
|
scon->event.event_pending = true;
|
||||||
}
|
sclp_service_interrupt(0);
|
||||||
|
|
||||||
/* Send data from a char device over to the guest */
|
|
||||||
static void chr_read(void *opaque, const uint8_t *buf, int size)
|
|
||||||
{
|
|
||||||
SCLPConsole *scon = opaque;
|
|
||||||
|
|
||||||
assert(scon);
|
|
||||||
|
|
||||||
receive_from_chr_layer(scon, buf, size);
|
|
||||||
/* trigger SCLP read operation */
|
|
||||||
qemu_irq_raise(scon->irq_read_vt220);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* functions to be called by event facility */
|
/* functions to be called by event facility */
|
||||||
@@ -192,11 +181,6 @@ static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trigger_ascii_console_data(void *opaque, int n, int level)
|
|
||||||
{
|
|
||||||
sclp_service_interrupt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const VMStateDescription vmstate_sclpconsole = {
|
static const VMStateDescription vmstate_sclpconsole = {
|
||||||
.name = "sclpconsole",
|
.name = "sclpconsole",
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
@@ -232,8 +216,6 @@ static int console_init(SCLPEvent *event)
|
|||||||
qemu_chr_add_handlers(scon->chr, chr_can_read,
|
qemu_chr_add_handlers(scon->chr, chr_can_read,
|
||||||
chr_read, NULL, scon);
|
chr_read, NULL, scon);
|
||||||
}
|
}
|
||||||
scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
|
|
||||||
NULL, 1);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
# core qdev-related obj files, also used by *-user:
|
# core qdev-related obj files, also used by *-user:
|
||||||
common-obj-y += qdev.o qdev-properties.o
|
common-obj-y += qdev.o qdev-properties.o
|
||||||
|
common-obj-y += fw-path-provider.o
|
||||||
# irq.o needed for qdev GPIO handling:
|
# irq.o needed for qdev GPIO handling:
|
||||||
common-obj-y += irq.o
|
common-obj-y += irq.o
|
||||||
common-obj-y += hotplug.o
|
common-obj-y += hotplug.o
|
||||||
|
51
hw/core/fw-path-provider.c
Normal file
51
hw/core/fw-path-provider.c
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Firmware patch provider class and helpers.
|
||||||
|
*
|
||||||
|
* 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; under version 2 of the License.
|
||||||
|
*
|
||||||
|
* 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 "hw/fw-path-provider.h"
|
||||||
|
|
||||||
|
char *fw_path_provider_get_dev_path(FWPathProvider *p, BusState *bus,
|
||||||
|
DeviceState *dev)
|
||||||
|
{
|
||||||
|
FWPathProviderClass *k = FW_PATH_PROVIDER_GET_CLASS(p);
|
||||||
|
|
||||||
|
return k->get_dev_path(p, bus, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fw_path_provider_try_get_dev_path(Object *o, BusState *bus,
|
||||||
|
DeviceState *dev)
|
||||||
|
{
|
||||||
|
FWPathProvider *p = (FWPathProvider *)
|
||||||
|
object_dynamic_cast(o, TYPE_FW_PATH_PROVIDER);
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
return fw_path_provider_get_dev_path(p, bus, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo fw_path_provider_info = {
|
||||||
|
.name = TYPE_FW_PATH_PROVIDER,
|
||||||
|
.parent = TYPE_INTERFACE,
|
||||||
|
.class_size = sizeof(FWPathProviderClass),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void fw_path_provider_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&fw_path_provider_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(fw_path_provider_register_types)
|
@@ -21,6 +21,18 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name,
|
||||||
|
Object *val, Error **errp)
|
||||||
|
{
|
||||||
|
DeviceState *dev = DEVICE(obj);
|
||||||
|
|
||||||
|
if (dev->realized) {
|
||||||
|
error_setg(errp, "Attempt to set link property '%s' on device '%s' "
|
||||||
|
"(type '%s') after it was realized",
|
||||||
|
name, dev->id, object_get_typename(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
|
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
|
||||||
{
|
{
|
||||||
void *ptr = dev;
|
void *ptr = dev;
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
this API directly. */
|
this API directly. */
|
||||||
|
|
||||||
#include "hw/qdev.h"
|
#include "hw/qdev.h"
|
||||||
|
#include "hw/fw-path-provider.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
@@ -98,6 +99,8 @@ static void bus_add_child(BusState *bus, DeviceState *child)
|
|||||||
object_property_add_link(OBJECT(bus), name,
|
object_property_add_link(OBJECT(bus), name,
|
||||||
object_get_typename(OBJECT(child)),
|
object_get_typename(OBJECT(child)),
|
||||||
(Object **)&kid->child,
|
(Object **)&kid->child,
|
||||||
|
NULL, /* read-only property */
|
||||||
|
0, /* return ownership on prop deletion */
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,6 +571,18 @@ static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *qdev_get_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
|
||||||
|
{
|
||||||
|
Object *obj = OBJECT(dev);
|
||||||
|
char *d = NULL;
|
||||||
|
|
||||||
|
while (!d && obj->parent) {
|
||||||
|
obj = obj->parent;
|
||||||
|
d = fw_path_provider_try_get_dev_path(obj, bus, dev);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
|
static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
|
||||||
{
|
{
|
||||||
int l = 0;
|
int l = 0;
|
||||||
@@ -575,7 +590,10 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
|
|||||||
if (dev && dev->parent_bus) {
|
if (dev && dev->parent_bus) {
|
||||||
char *d;
|
char *d;
|
||||||
l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
|
l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
|
||||||
d = bus_get_fw_dev_path(dev->parent_bus, dev);
|
d = qdev_get_fw_dev_path_from_handler(dev->parent_bus, dev);
|
||||||
|
if (!d) {
|
||||||
|
d = bus_get_fw_dev_path(dev->parent_bus, dev);
|
||||||
|
}
|
||||||
if (d) {
|
if (d) {
|
||||||
l += snprintf(p + l, size - l, "%s", d);
|
l += snprintf(p + l, size - l, "%s", d);
|
||||||
g_free(d);
|
g_free(d);
|
||||||
@@ -824,7 +842,8 @@ static void device_initfn(Object *obj)
|
|||||||
} while (class != object_class_by_name(TYPE_DEVICE));
|
} while (class != object_class_by_name(TYPE_DEVICE));
|
||||||
|
|
||||||
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
||||||
(Object **)&dev->parent_bus, &error_abort);
|
(Object **)&dev->parent_bus, NULL, 0,
|
||||||
|
&error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_post_init(Object *obj)
|
static void device_post_init(Object *obj)
|
||||||
@@ -944,7 +963,10 @@ static void qbus_initfn(Object *obj)
|
|||||||
QTAILQ_INIT(&bus->children);
|
QTAILQ_INIT(&bus->children);
|
||||||
object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
|
object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
|
||||||
TYPE_HOTPLUG_HANDLER,
|
TYPE_HOTPLUG_HANDLER,
|
||||||
(Object **)&bus->hotplug_handler, NULL);
|
(Object **)&bus->hotplug_handler,
|
||||||
|
object_property_allow_set_link,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
NULL);
|
||||||
object_property_add_bool(obj, "realized",
|
object_property_add_bool(obj, "realized",
|
||||||
bus_get_realized, bus_set_realized, NULL);
|
bus_get_realized, bus_set_realized, NULL);
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
|
#include "ui/vnc.h"
|
||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
|
|
||||||
#undef VERBOSE
|
#undef VERBOSE
|
||||||
@@ -218,7 +219,7 @@ enum {
|
|||||||
|
|
||||||
/* These values can probably be changed arbitrarily. */
|
/* These values can probably be changed arbitrarily. */
|
||||||
#define SVGA_SCRATCH_SIZE 0x8000
|
#define SVGA_SCRATCH_SIZE 0x8000
|
||||||
#define SVGA_MAX_WIDTH 2360
|
#define SVGA_MAX_WIDTH ROUND_UP(2360, VNC_DIRTY_PIXELS_PER_BIT)
|
||||||
#define SVGA_MAX_HEIGHT 1770
|
#define SVGA_MAX_HEIGHT 1770
|
||||||
|
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
|
@@ -537,9 +537,15 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
|
|||||||
Error *local_errp = NULL;
|
Error *local_errp = NULL;
|
||||||
|
|
||||||
object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
|
object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
|
||||||
(Object **)&ds->dma, &local_errp);
|
(Object **)&ds->dma,
|
||||||
|
object_property_allow_set_link,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&local_errp);
|
||||||
object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
|
object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
|
||||||
(Object **)&cs->dma, &local_errp);
|
(Object **)&cs->dma,
|
||||||
|
object_property_allow_set_link,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&local_errp);
|
||||||
if (local_errp) {
|
if (local_errp) {
|
||||||
goto xilinx_axidma_realize_fail;
|
goto xilinx_axidma_realize_fail;
|
||||||
}
|
}
|
||||||
@@ -571,10 +577,16 @@ static void xilinx_axidma_init(Object *obj)
|
|||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
|
|
||||||
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
|
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
|
||||||
(Object **)&s->tx_data_dev, &error_abort);
|
(Object **)&s->tx_data_dev,
|
||||||
|
qdev_prop_allow_set_link_before_realize,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&error_abort);
|
||||||
object_property_add_link(obj, "axistream-control-connected",
|
object_property_add_link(obj, "axistream-control-connected",
|
||||||
TYPE_STREAM_SLAVE,
|
TYPE_STREAM_SLAVE,
|
||||||
(Object **)&s->tx_control_dev, &error_abort);
|
(Object **)&s->tx_control_dev,
|
||||||
|
qdev_prop_allow_set_link_before_realize,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||||
TYPE_XILINX_AXI_DMA_DATA_STREAM);
|
TYPE_XILINX_AXI_DMA_DATA_STREAM);
|
||||||
|
@@ -52,7 +52,7 @@
|
|||||||
#include "qom/qom-qobject.h"
|
#include "qom/qom-qobject.h"
|
||||||
|
|
||||||
typedef struct AcpiCpuInfo {
|
typedef struct AcpiCpuInfo {
|
||||||
DECLARE_BITMAP(found_cpus, MAX_CPUMASK_BITS + 1);
|
DECLARE_BITMAP(found_cpus, ACPI_CPU_HOTPLUG_ID_LIMIT);
|
||||||
} AcpiCpuInfo;
|
} AcpiCpuInfo;
|
||||||
|
|
||||||
typedef struct AcpiMcfgInfo {
|
typedef struct AcpiMcfgInfo {
|
||||||
@@ -117,7 +117,7 @@ int acpi_add_cpu_info(Object *o, void *opaque)
|
|||||||
|
|
||||||
if (object_dynamic_cast(o, TYPE_CPU)) {
|
if (object_dynamic_cast(o, TYPE_CPU)) {
|
||||||
apic_id = object_property_get_int(o, "apic-id", NULL);
|
apic_id = object_property_get_int(o, "apic-id", NULL);
|
||||||
assert(apic_id <= MAX_CPUMASK_BITS);
|
assert(apic_id < ACPI_CPU_HOTPLUG_ID_LIMIT);
|
||||||
|
|
||||||
set_bit(apic_id, cpu->found_cpus);
|
set_bit(apic_id, cpu->found_cpus);
|
||||||
}
|
}
|
||||||
@@ -226,14 +226,14 @@ static void acpi_get_pci_info(PcPciInfo *info)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
build_header(GArray *linker, GArray *table_data,
|
build_header(GArray *linker, GArray *table_data,
|
||||||
AcpiTableHeader *h, uint32_t sig, int len, uint8_t rev)
|
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
|
||||||
{
|
{
|
||||||
h->signature = cpu_to_le32(sig);
|
memcpy(&h->signature, sig, 4);
|
||||||
h->length = cpu_to_le32(len);
|
h->length = cpu_to_le32(len);
|
||||||
h->revision = rev;
|
h->revision = rev;
|
||||||
memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
|
memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
|
||||||
memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
|
memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
|
||||||
memcpy(h->oem_table_id + 4, (void *)&sig, 4);
|
memcpy(h->oem_table_id + 4, sig, 4);
|
||||||
h->oem_revision = cpu_to_le32(1);
|
h->oem_revision = cpu_to_le32(1);
|
||||||
memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
|
memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
|
||||||
h->asl_compiler_revision = cpu_to_le32(1);
|
h->asl_compiler_revision = cpu_to_le32(1);
|
||||||
@@ -495,7 +495,7 @@ static void
|
|||||||
build_facs(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
|
build_facs(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
|
||||||
{
|
{
|
||||||
AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs);
|
AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs);
|
||||||
facs->signature = cpu_to_le32(ACPI_FACS_SIGNATURE);
|
memcpy(&facs->signature, "FACS", 4);
|
||||||
facs->length = cpu_to_le32(sizeof(*facs));
|
facs->length = cpu_to_le32(sizeof(*facs));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,7 +552,7 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm,
|
|||||||
fadt_setup(fadt, pm);
|
fadt_setup(fadt, pm);
|
||||||
|
|
||||||
build_header(linker, table_data,
|
build_header(linker, table_data,
|
||||||
(void *)fadt, ACPI_FACP_SIGNATURE, sizeof(*fadt), 1);
|
(void *)fadt, "FACP", sizeof(*fadt), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -621,7 +621,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu,
|
|||||||
local_nmi->lint = 1; /* ACPI_LINT1 */
|
local_nmi->lint = 1; /* ACPI_LINT1 */
|
||||||
|
|
||||||
build_header(linker, table_data,
|
build_header(linker, table_data,
|
||||||
(void *)(table_data->data + madt_start), ACPI_APIC_SIGNATURE,
|
(void *)(table_data->data + madt_start), "APIC",
|
||||||
table_data->len - madt_start, 1);
|
table_data->len - madt_start, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -841,7 +841,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
|
|||||||
pc = PCI_DEVICE_GET_CLASS(pdev);
|
pc = PCI_DEVICE_GET_CLASS(pdev);
|
||||||
dc = DEVICE_GET_CLASS(pdev);
|
dc = DEVICE_GET_CLASS(pdev);
|
||||||
|
|
||||||
if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
|
if (pc->class_id == PCI_CLASS_BRIDGE_ISA || pc->is_bridge) {
|
||||||
set_bit(slot, slot_device_system);
|
set_bit(slot, slot_device_system);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -882,7 +882,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
|
|||||||
memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF);
|
memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF);
|
||||||
patch_pcivga(i, pcihp);
|
patch_pcivga(i, pcihp);
|
||||||
} else if (system) {
|
} else if (system) {
|
||||||
/* Nothing to do: system devices are in DSDT. */
|
/* Nothing to do: system devices are in DSDT or in SSDT above. */
|
||||||
} else if (present) {
|
} else if (present) {
|
||||||
void *pcihp = acpi_data_push(bus_table,
|
void *pcihp = acpi_data_push(bus_table,
|
||||||
ACPI_PCINOHP_SIZEOF);
|
ACPI_PCINOHP_SIZEOF);
|
||||||
@@ -907,7 +907,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
|
|||||||
|
|
||||||
build_append_byte(notify, 0x7B); /* AndOp */
|
build_append_byte(notify, 0x7B); /* AndOp */
|
||||||
build_append_byte(notify, 0x68); /* Arg0Op */
|
build_append_byte(notify, 0x68); /* Arg0Op */
|
||||||
build_append_int(notify, 0x1 << i);
|
build_append_int(notify, 0x1U << i);
|
||||||
build_append_byte(notify, 0x00); /* NullName */
|
build_append_byte(notify, 0x00); /* NullName */
|
||||||
build_append_byte(notify, 0x86); /* NotifyOp */
|
build_append_byte(notify, 0x86); /* NotifyOp */
|
||||||
build_append_nameseg(notify, "S%.02X_", PCI_DEVFN(i, 0));
|
build_append_nameseg(notify, "S%.02X_", PCI_DEVFN(i, 0));
|
||||||
@@ -999,11 +999,16 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
|
AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
|
||||||
PcPciInfo *pci, PcGuestInfo *guest_info)
|
PcPciInfo *pci, PcGuestInfo *guest_info)
|
||||||
{
|
{
|
||||||
int acpi_cpus = MIN(0xff, guest_info->apic_id_limit);
|
unsigned acpi_cpus = guest_info->apic_id_limit;
|
||||||
int ssdt_start = table_data->len;
|
int ssdt_start = table_data->len;
|
||||||
uint8_t *ssdt_ptr;
|
uint8_t *ssdt_ptr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* The current AML generator can cover the APIC ID range [0..255],
|
||||||
|
* inclusive, for VCPU hotplug. */
|
||||||
|
QEMU_BUILD_BUG_ON(ACPI_CPU_HOTPLUG_ID_LIMIT > 256);
|
||||||
|
g_assert(acpi_cpus <= ACPI_CPU_HOTPLUG_ID_LIMIT);
|
||||||
|
|
||||||
/* Copy header and patch values in the S3_ / S4_ / S5_ packages */
|
/* Copy header and patch values in the S3_ / S4_ / S5_ packages */
|
||||||
ssdt_ptr = acpi_data_push(table_data, sizeof(ssdp_misc_aml));
|
ssdt_ptr = acpi_data_push(table_data, sizeof(ssdp_misc_aml));
|
||||||
memcpy(ssdt_ptr, ssdp_misc_aml, sizeof(ssdp_misc_aml));
|
memcpy(ssdt_ptr, ssdp_misc_aml, sizeof(ssdp_misc_aml));
|
||||||
@@ -1019,8 +1024,8 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
|
|
||||||
patch_pci_windows(pci, ssdt_ptr, sizeof(ssdp_misc_aml));
|
patch_pci_windows(pci, ssdt_ptr, sizeof(ssdp_misc_aml));
|
||||||
|
|
||||||
*(uint16_t *)(ssdt_ptr + *ssdt_isa_pest) =
|
ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml),
|
||||||
cpu_to_le16(misc->pvpanic_port);
|
ssdt_isa_pest[0], 16, misc->pvpanic_port);
|
||||||
|
|
||||||
{
|
{
|
||||||
GArray *sb_scope = build_alloc_array();
|
GArray *sb_scope = build_alloc_array();
|
||||||
@@ -1050,9 +1055,21 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
|
|
||||||
{
|
{
|
||||||
GArray *package = build_alloc_array();
|
GArray *package = build_alloc_array();
|
||||||
uint8_t op = 0x12; /* PackageOp */
|
uint8_t op;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: The ability to create variable-sized packages was first introduced in ACPI 2.0. ACPI 1.0 only
|
||||||
|
* allowed fixed-size packages with up to 255 elements.
|
||||||
|
* Windows guests up to win2k8 fail when VarPackageOp is used.
|
||||||
|
*/
|
||||||
|
if (acpi_cpus <= 255) {
|
||||||
|
op = 0x12; /* PackageOp */
|
||||||
|
build_append_byte(package, acpi_cpus); /* NumElements */
|
||||||
|
} else {
|
||||||
|
op = 0x13; /* VarPackageOp */
|
||||||
|
build_append_int(package, acpi_cpus); /* VarNumElements */
|
||||||
|
}
|
||||||
|
|
||||||
build_append_byte(package, acpi_cpus); /* NumElements */
|
|
||||||
for (i = 0; i < acpi_cpus; i++) {
|
for (i = 0; i < acpi_cpus; i++) {
|
||||||
uint8_t b = test_bit(i, cpu->found_cpus) ? 0x01 : 0x00;
|
uint8_t b = test_bit(i, cpu->found_cpus) ? 0x01 : 0x00;
|
||||||
build_append_byte(package, b);
|
build_append_byte(package, b);
|
||||||
@@ -1093,7 +1110,7 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
|
|
||||||
build_header(linker, table_data,
|
build_header(linker, table_data,
|
||||||
(void *)(table_data->data + ssdt_start),
|
(void *)(table_data->data + ssdt_start),
|
||||||
ACPI_SSDT_SIGNATURE, table_data->len - ssdt_start, 1);
|
"SSDT", table_data->len - ssdt_start, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1108,7 +1125,7 @@ build_hpet(GArray *table_data, GArray *linker)
|
|||||||
hpet->timer_block_id = cpu_to_le32(0x8086a201);
|
hpet->timer_block_id = cpu_to_le32(0x8086a201);
|
||||||
hpet->addr.address = cpu_to_le64(HPET_BASE);
|
hpet->addr.address = cpu_to_le64(HPET_BASE);
|
||||||
build_header(linker, table_data,
|
build_header(linker, table_data,
|
||||||
(void *)hpet, ACPI_HPET_SIGNATURE, sizeof(*hpet), 1);
|
(void *)hpet, "HPET", sizeof(*hpet), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1200,7 +1217,7 @@ build_srat(GArray *table_data, GArray *linker,
|
|||||||
|
|
||||||
build_header(linker, table_data,
|
build_header(linker, table_data,
|
||||||
(void *)(table_data->data + srat_start),
|
(void *)(table_data->data + srat_start),
|
||||||
ACPI_SRAT_SIGNATURE,
|
"SRAT",
|
||||||
table_data->len - srat_start, 1);
|
table_data->len - srat_start, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1208,7 +1225,7 @@ static void
|
|||||||
build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info)
|
build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info)
|
||||||
{
|
{
|
||||||
AcpiTableMcfg *mcfg;
|
AcpiTableMcfg *mcfg;
|
||||||
uint32_t sig;
|
const char *sig;
|
||||||
int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
|
int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
|
||||||
|
|
||||||
mcfg = acpi_data_push(table_data, len);
|
mcfg = acpi_data_push(table_data, len);
|
||||||
@@ -1225,9 +1242,10 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info)
|
|||||||
* ACPI spec requires OSPMs to ignore such tables.
|
* ACPI spec requires OSPMs to ignore such tables.
|
||||||
*/
|
*/
|
||||||
if (info->mcfg_base == PCIE_BASE_ADDR_UNMAPPED) {
|
if (info->mcfg_base == PCIE_BASE_ADDR_UNMAPPED) {
|
||||||
sig = ACPI_RSRV_SIGNATURE;
|
/* Reserved signature: ignored by OSPM */
|
||||||
|
sig = "QEMU";
|
||||||
} else {
|
} else {
|
||||||
sig = ACPI_MCFG_SIGNATURE;
|
sig = "MCFG";
|
||||||
}
|
}
|
||||||
build_header(linker, table_data, (void *)mcfg, sig, len, 1);
|
build_header(linker, table_data, (void *)mcfg, sig, len, 1);
|
||||||
}
|
}
|
||||||
@@ -1243,7 +1261,7 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc)
|
|||||||
memcpy(dsdt, misc->dsdt_code, misc->dsdt_size);
|
memcpy(dsdt, misc->dsdt_code, misc->dsdt_size);
|
||||||
|
|
||||||
memset(dsdt, 0, sizeof *dsdt);
|
memset(dsdt, 0, sizeof *dsdt);
|
||||||
build_header(linker, table_data, dsdt, ACPI_DSDT_SIGNATURE,
|
build_header(linker, table_data, dsdt, "DSDT",
|
||||||
misc->dsdt_size, 1);
|
misc->dsdt_size, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1268,7 +1286,7 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
|
|||||||
sizeof(uint32_t));
|
sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
build_header(linker, table_data,
|
build_header(linker, table_data,
|
||||||
(void *)rsdt, ACPI_RSDT_SIGNATURE, rsdt_len, 1);
|
(void *)rsdt, "RSDT", rsdt_len, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GArray *
|
static GArray *
|
||||||
@@ -1279,7 +1297,7 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
|
|||||||
bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 1,
|
bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 1,
|
||||||
true /* fseg memory */);
|
true /* fseg memory */);
|
||||||
|
|
||||||
rsdp->signature = cpu_to_le64(ACPI_RSDP_SIGNATURE);
|
memcpy(&rsdp->signature, "RSD PTR ", 8);
|
||||||
memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6);
|
memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6);
|
||||||
rsdp->rsdt_physical_address = cpu_to_le32(rsdt);
|
rsdp->rsdt_physical_address = cpu_to_le32(rsdt);
|
||||||
/* Address to be filled by Guest linker */
|
/* Address to be filled by Guest linker */
|
||||||
|
@@ -52,8 +52,6 @@ struct Acpi20GenericAddress {
|
|||||||
} QEMU_PACKED;
|
} QEMU_PACKED;
|
||||||
typedef struct Acpi20GenericAddress Acpi20GenericAddress;
|
typedef struct Acpi20GenericAddress Acpi20GenericAddress;
|
||||||
|
|
||||||
#define ACPI_RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR "
|
|
||||||
|
|
||||||
struct AcpiRsdpDescriptor { /* Root System Descriptor Pointer */
|
struct AcpiRsdpDescriptor { /* Root System Descriptor Pointer */
|
||||||
uint64_t signature; /* ACPI signature, contains "RSD PTR " */
|
uint64_t signature; /* ACPI signature, contains "RSD PTR " */
|
||||||
uint8_t checksum; /* To make sum of struct == 0 */
|
uint8_t checksum; /* To make sum of struct == 0 */
|
||||||
@@ -92,7 +90,6 @@ typedef struct AcpiTableHeader AcpiTableHeader;
|
|||||||
/*
|
/*
|
||||||
* ACPI 1.0 Fixed ACPI Description Table (FADT)
|
* ACPI 1.0 Fixed ACPI Description Table (FADT)
|
||||||
*/
|
*/
|
||||||
#define ACPI_FACP_SIGNATURE 0x50434146 // FACP
|
|
||||||
struct AcpiFadtDescriptorRev1
|
struct AcpiFadtDescriptorRev1
|
||||||
{
|
{
|
||||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||||
@@ -141,7 +138,6 @@ typedef struct AcpiFadtDescriptorRev1 AcpiFadtDescriptorRev1;
|
|||||||
/*
|
/*
|
||||||
* ACPI 1.0 Root System Description Table (RSDT)
|
* ACPI 1.0 Root System Description Table (RSDT)
|
||||||
*/
|
*/
|
||||||
#define ACPI_RSDT_SIGNATURE 0x54445352 // RSDT
|
|
||||||
struct AcpiRsdtDescriptorRev1
|
struct AcpiRsdtDescriptorRev1
|
||||||
{
|
{
|
||||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||||
@@ -153,7 +149,6 @@ typedef struct AcpiRsdtDescriptorRev1 AcpiRsdtDescriptorRev1;
|
|||||||
/*
|
/*
|
||||||
* ACPI 1.0 Firmware ACPI Control Structure (FACS)
|
* ACPI 1.0 Firmware ACPI Control Structure (FACS)
|
||||||
*/
|
*/
|
||||||
#define ACPI_FACS_SIGNATURE 0x53434146 // FACS
|
|
||||||
struct AcpiFacsDescriptorRev1
|
struct AcpiFacsDescriptorRev1
|
||||||
{
|
{
|
||||||
uint32_t signature; /* ACPI Signature */
|
uint32_t signature; /* ACPI Signature */
|
||||||
@@ -169,7 +164,6 @@ typedef struct AcpiFacsDescriptorRev1 AcpiFacsDescriptorRev1;
|
|||||||
/*
|
/*
|
||||||
* Differentiated System Description Table (DSDT)
|
* Differentiated System Description Table (DSDT)
|
||||||
*/
|
*/
|
||||||
#define ACPI_DSDT_SIGNATURE 0x54445344 // DSDT
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MADT values and structures
|
* MADT values and structures
|
||||||
@@ -182,7 +176,6 @@ typedef struct AcpiFacsDescriptorRev1 AcpiFacsDescriptorRev1;
|
|||||||
|
|
||||||
/* Master MADT */
|
/* Master MADT */
|
||||||
|
|
||||||
#define ACPI_APIC_SIGNATURE 0x43495041 // APIC
|
|
||||||
struct AcpiMultipleApicTable
|
struct AcpiMultipleApicTable
|
||||||
{
|
{
|
||||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||||
@@ -253,7 +246,6 @@ typedef struct AcpiMadtLocalNmi AcpiMadtLocalNmi;
|
|||||||
/*
|
/*
|
||||||
* HPET Description Table
|
* HPET Description Table
|
||||||
*/
|
*/
|
||||||
#define ACPI_HPET_SIGNATURE 0x54455048 // HPET
|
|
||||||
struct Acpi20Hpet {
|
struct Acpi20Hpet {
|
||||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||||
uint32_t timer_block_id;
|
uint32_t timer_block_id;
|
||||||
@@ -268,7 +260,6 @@ typedef struct Acpi20Hpet Acpi20Hpet;
|
|||||||
* SRAT (NUMA topology description) table
|
* SRAT (NUMA topology description) table
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ACPI_SRAT_SIGNATURE 0x54415253 // SRAT
|
|
||||||
struct AcpiSystemResourceAffinityTable
|
struct AcpiSystemResourceAffinityTable
|
||||||
{
|
{
|
||||||
ACPI_TABLE_HEADER_DEF
|
ACPI_TABLE_HEADER_DEF
|
||||||
@@ -316,11 +307,6 @@ struct AcpiMcfgAllocation {
|
|||||||
} QEMU_PACKED;
|
} QEMU_PACKED;
|
||||||
typedef struct AcpiMcfgAllocation AcpiMcfgAllocation;
|
typedef struct AcpiMcfgAllocation AcpiMcfgAllocation;
|
||||||
|
|
||||||
#define ACPI_MCFG_SIGNATURE 0x4746434d // MCFG
|
|
||||||
|
|
||||||
/* Reserved signature: ignored by OSPM */
|
|
||||||
#define ACPI_RSRV_SIGNATURE 0x554d4551 // QEMU
|
|
||||||
|
|
||||||
struct AcpiTableMcfg {
|
struct AcpiTableMcfg {
|
||||||
ACPI_TABLE_HEADER_DEF;
|
ACPI_TABLE_HEADER_DEF;
|
||||||
uint8_t reserved[8];
|
uint8_t reserved[8];
|
||||||
|
16
hw/i386/pc.c
16
hw/i386/pc.c
@@ -53,6 +53,7 @@
|
|||||||
#include "qemu/bitmap.h"
|
#include "qemu/bitmap.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "hw/acpi/acpi.h"
|
#include "hw/acpi/acpi.h"
|
||||||
|
#include "hw/acpi/cpu_hotplug.h"
|
||||||
#include "hw/cpu/icc_bus.h"
|
#include "hw/cpu/icc_bus.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/pci/pci_host.h"
|
#include "hw/pci/pci_host.h"
|
||||||
@@ -974,6 +975,13 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (apic_id >= ACPI_CPU_HOTPLUG_ID_LIMIT) {
|
||||||
|
error_setg(errp, "Unable to add CPU: %" PRIi64
|
||||||
|
", resulting APIC ID (%" PRIi64 ") is too large",
|
||||||
|
id, apic_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
icc_bridge = DEVICE(object_resolve_path_type("icc-bridge",
|
icc_bridge = DEVICE(object_resolve_path_type("icc-bridge",
|
||||||
TYPE_ICC_BRIDGE, NULL));
|
TYPE_ICC_BRIDGE, NULL));
|
||||||
pc_new_cpu(current_cpu_model, apic_id, icc_bridge, errp);
|
pc_new_cpu(current_cpu_model, apic_id, icc_bridge, errp);
|
||||||
@@ -984,6 +992,7 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
|
|||||||
int i;
|
int i;
|
||||||
X86CPU *cpu = NULL;
|
X86CPU *cpu = NULL;
|
||||||
Error *error = NULL;
|
Error *error = NULL;
|
||||||
|
unsigned long apic_id_limit;
|
||||||
|
|
||||||
/* init CPUs */
|
/* init CPUs */
|
||||||
if (cpu_model == NULL) {
|
if (cpu_model == NULL) {
|
||||||
@@ -995,6 +1004,13 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
|
|||||||
}
|
}
|
||||||
current_cpu_model = cpu_model;
|
current_cpu_model = cpu_model;
|
||||||
|
|
||||||
|
apic_id_limit = pc_apic_id_limit(max_cpus);
|
||||||
|
if (apic_id_limit > ACPI_CPU_HOTPLUG_ID_LIMIT) {
|
||||||
|
error_report("max_cpus is too large. APIC ID of last CPU is %lu",
|
||||||
|
apic_id_limit - 1);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < smp_cpus; i++) {
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i),
|
cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i),
|
||||||
icc_bridge, &error);
|
icc_bridge, &error);
|
||||||
|
@@ -118,11 +118,12 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
|||||||
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
||||||
{
|
{
|
||||||
AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
||||||
PCIDevice *pci_dev = PCI_DEVICE(d);
|
PCIDevice *pci_dev =
|
||||||
|
(PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE);
|
||||||
|
|
||||||
DPRINTF(0, "raise irq\n");
|
DPRINTF(0, "raise irq\n");
|
||||||
|
|
||||||
if (msi_enabled(pci_dev)) {
|
if (pci_dev && msi_enabled(pci_dev)) {
|
||||||
msi_notify(pci_dev, 0);
|
msi_notify(pci_dev, 0);
|
||||||
} else {
|
} else {
|
||||||
qemu_irq_raise(s->irq);
|
qemu_irq_raise(s->irq);
|
||||||
@@ -132,10 +133,12 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
|||||||
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
|
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
|
||||||
{
|
{
|
||||||
AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
||||||
|
PCIDevice *pci_dev =
|
||||||
|
(PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE);
|
||||||
|
|
||||||
DPRINTF(0, "lower irq\n");
|
DPRINTF(0, "lower irq\n");
|
||||||
|
|
||||||
if (!msi_enabled(PCI_DEVICE(d))) {
|
if (!pci_dev || !msi_enabled(pci_dev)) {
|
||||||
qemu_irq_lower(s->irq);
|
qemu_irq_lower(s->irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1311,7 +1314,7 @@ static const VMStateDescription vmstate_sysbus_ahci = {
|
|||||||
.name = "sysbus-ahci",
|
.name = "sysbus-ahci",
|
||||||
.unmigratable = 1, /* Still buggy under I/O load */
|
.unmigratable = 1, /* Still buggy under I/O load */
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField []) {
|
||||||
VMSTATE_AHCI(ahci, AHCIPCIState),
|
VMSTATE_AHCI(ahci, SysbusAHCIState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -1328,7 +1331,7 @@ static void sysbus_ahci_realize(DeviceState *dev, Error **errp)
|
|||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||||
SysbusAHCIState *s = SYSBUS_AHCI(dev);
|
SysbusAHCIState *s = SYSBUS_AHCI(dev);
|
||||||
|
|
||||||
ahci_init(&s->ahci, dev, NULL, s->num_ports);
|
ahci_init(&s->ahci, dev, &address_space_memory, s->num_ports);
|
||||||
|
|
||||||
sysbus_init_mmio(sbd, &s->ahci.mem);
|
sysbus_init_mmio(sbd, &s->ahci.mem);
|
||||||
sysbus_init_irq(sbd, &s->ahci.irq);
|
sysbus_init_irq(sbd, &s->ahci.irq);
|
||||||
|
@@ -421,7 +421,7 @@ static const VMStateDescription vmstate_bmdma_current = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_bmdma_status = {
|
static const VMStateDescription vmstate_bmdma_status = {
|
||||||
.name ="ide bmdma/status",
|
.name ="ide bmdma/status",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
|
@@ -201,12 +201,12 @@ static void apic_external_nmi(APICCommonState *s)
|
|||||||
|
|
||||||
#define foreach_apic(apic, deliver_bitmask, code) \
|
#define foreach_apic(apic, deliver_bitmask, code) \
|
||||||
{\
|
{\
|
||||||
int __i, __j, __mask;\
|
int __i, __j;\
|
||||||
for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
|
for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
|
||||||
__mask = deliver_bitmask[__i];\
|
uint32_t __mask = deliver_bitmask[__i];\
|
||||||
if (__mask) {\
|
if (__mask) {\
|
||||||
for(__j = 0; __j < 32; __j++) {\
|
for(__j = 0; __j < 32; __j++) {\
|
||||||
if (__mask & (1 << __j)) {\
|
if (__mask & (1U << __j)) {\
|
||||||
apic = local_apics[__i * 32 + __j];\
|
apic = local_apics[__i * 32 + __j];\
|
||||||
if (apic) {\
|
if (apic) {\
|
||||||
code;\
|
code;\
|
||||||
|
@@ -117,7 +117,12 @@ void apic_report_irq_delivered(int delivered)
|
|||||||
|
|
||||||
void apic_reset_irq_delivered(void)
|
void apic_reset_irq_delivered(void)
|
||||||
{
|
{
|
||||||
trace_apic_reset_irq_delivered(apic_irq_delivered);
|
/* Copy this into a local variable to encourage gcc to emit a plain
|
||||||
|
* register for a sys/sdt.h marker. For details on this workaround, see:
|
||||||
|
* https://sourceware.org/bugzilla/show_bug.cgi?id=13296
|
||||||
|
*/
|
||||||
|
volatile int a_i_d = apic_irq_delivered;
|
||||||
|
trace_apic_reset_irq_delivered(a_i_d);
|
||||||
|
|
||||||
apic_irq_delivered = 0;
|
apic_irq_delivered = 0;
|
||||||
}
|
}
|
||||||
|
@@ -148,7 +148,7 @@ typedef void (*vgic_translate_fn)(GICState *s, int irq, int cpu,
|
|||||||
uint32_t *field, bool to_kernel);
|
uint32_t *field, bool to_kernel);
|
||||||
|
|
||||||
/* synthetic translate function used for clear/set registers to completely
|
/* synthetic translate function used for clear/set registers to completely
|
||||||
* clear a setting using a clear-register before setting the remaing bits
|
* clear a setting using a clear-register before setting the remaining bits
|
||||||
* using a set-register */
|
* using a set-register */
|
||||||
static void translate_clear(GICState *s, int irq, int cpu,
|
static void translate_clear(GICState *s, int irq, int cpu,
|
||||||
uint32_t *field, bool to_kernel)
|
uint32_t *field, bool to_kernel)
|
||||||
|
@@ -123,7 +123,7 @@ static FslMpicInfo fsl_mpic_42 = {
|
|||||||
#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */
|
#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */
|
||||||
|
|
||||||
#define IDR_EP_SHIFT 31
|
#define IDR_EP_SHIFT 31
|
||||||
#define IDR_EP_MASK (1 << IDR_EP_SHIFT)
|
#define IDR_EP_MASK (1U << IDR_EP_SHIFT)
|
||||||
#define IDR_CI0_SHIFT 30
|
#define IDR_CI0_SHIFT 30
|
||||||
#define IDR_CI1_SHIFT 29
|
#define IDR_CI1_SHIFT 29
|
||||||
#define IDR_P1_SHIFT 1
|
#define IDR_P1_SHIFT 1
|
||||||
@@ -220,17 +220,17 @@ typedef struct IRQSource {
|
|||||||
} IRQSource;
|
} IRQSource;
|
||||||
|
|
||||||
#define IVPR_MASK_SHIFT 31
|
#define IVPR_MASK_SHIFT 31
|
||||||
#define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT)
|
#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
|
||||||
#define IVPR_ACTIVITY_SHIFT 30
|
#define IVPR_ACTIVITY_SHIFT 30
|
||||||
#define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT)
|
#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
|
||||||
#define IVPR_MODE_SHIFT 29
|
#define IVPR_MODE_SHIFT 29
|
||||||
#define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT)
|
#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
|
||||||
#define IVPR_POLARITY_SHIFT 23
|
#define IVPR_POLARITY_SHIFT 23
|
||||||
#define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT)
|
#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
|
||||||
#define IVPR_SENSE_SHIFT 22
|
#define IVPR_SENSE_SHIFT 22
|
||||||
#define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT)
|
#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
|
||||||
|
|
||||||
#define IVPR_PRIORITY_MASK (0xF << 16)
|
#define IVPR_PRIORITY_MASK (0xFU << 16)
|
||||||
#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
|
#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
|
||||||
#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
|
#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
|
||||||
|
|
||||||
|
@@ -118,6 +118,11 @@ static void kvm_openpic_region_add(MemoryListener *listener,
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ignore events on regions that are not us */
|
||||||
|
if (section->mr != &opp->mem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
reg_base = section->offset_within_address_space;
|
reg_base = section->offset_within_address_space;
|
||||||
|
|
||||||
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
||||||
@@ -140,6 +145,11 @@ static void kvm_openpic_region_del(MemoryListener *listener,
|
|||||||
uint64_t reg_base = 0;
|
uint64_t reg_base = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Ignore events on regions that are not us */
|
||||||
|
if (section->mr != &opp->mem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
||||||
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
||||||
attr.addr = (uint64_t)(unsigned long)®_base;
|
attr.addr = (uint64_t)(unsigned long)®_base;
|
||||||
@@ -200,7 +210,7 @@ static void kvm_openpic_realize(DeviceState *dev, Error **errp)
|
|||||||
qdev_init_gpio_in(dev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ);
|
qdev_init_gpio_in(dev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ);
|
||||||
|
|
||||||
opp->mem_listener.region_add = kvm_openpic_region_add;
|
opp->mem_listener.region_add = kvm_openpic_region_add;
|
||||||
opp->mem_listener.region_add = kvm_openpic_region_del;
|
opp->mem_listener.region_del = kvm_openpic_region_del;
|
||||||
memory_listener_register(&opp->mem_listener, &address_space_memory);
|
memory_listener_register(&opp->mem_listener, &address_space_memory);
|
||||||
|
|
||||||
/* indicate pic capabilities */
|
/* indicate pic capabilities */
|
||||||
|
@@ -272,7 +272,7 @@ static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
|
|||||||
CPU_IRQ_TIMER_IN;
|
CPU_IRQ_TIMER_IN;
|
||||||
if (i == s->target_cpu) {
|
if (i == s->target_cpu) {
|
||||||
for (j = 0; j < 32; j++) {
|
for (j = 0; j < 32; j++) {
|
||||||
if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
|
if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
|
||||||
s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
|
s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -71,8 +71,9 @@ static void update_irq(struct xlx_pic *p)
|
|||||||
|
|
||||||
/* Update the vector register. */
|
/* Update the vector register. */
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
if (p->regs[R_IPR] & (1 << i))
|
if (p->regs[R_IPR] & (1U << i)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (i == 32)
|
if (i == 32)
|
||||||
i = ~0;
|
i = ~0;
|
||||||
|
@@ -56,12 +56,14 @@ static void tmp105_get_temperature(Object *obj, Visitor *v, void *opaque,
|
|||||||
const char *name, Error **errp)
|
const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
TMP105State *s = TMP105(obj);
|
TMP105State *s = TMP105(obj);
|
||||||
int64_t value = s->temperature;
|
int64_t value = s->temperature * 1000 / 256;
|
||||||
|
|
||||||
visit_type_int(v, &value, name, errp);
|
visit_type_int(v, &value, name, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Units are 0.001 centigrades relative to 0 C. */
|
/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
|
||||||
|
* fixed point, so units are 1/256 centigrades. A simple ratio will do.
|
||||||
|
*/
|
||||||
static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
|
static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
|
||||||
const char *name, Error **errp)
|
const char *name, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -78,7 +80,7 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
|
s->temperature = (int16_t) (temp * 256 / 1000);
|
||||||
|
|
||||||
tmp105_alarm_update(s);
|
tmp105_alarm_update(s);
|
||||||
}
|
}
|
||||||
|
@@ -1043,7 +1043,7 @@ static void vfio_bar_write(void *opaque, hwaddr addr,
|
|||||||
buf.dword = cpu_to_le32(data);
|
buf.dword = cpu_to_le32(data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("vfio: unsupported write size, %d bytes\n", size);
|
hw_error("vfio: unsupported write size, %d bytes", size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1103,7 +1103,7 @@ static uint64_t vfio_bar_read(void *opaque,
|
|||||||
data = le32_to_cpu(buf.dword);
|
data = le32_to_cpu(buf.dword);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("vfio: unsupported read size, %d bytes\n", size);
|
hw_error("vfio: unsupported read size, %d bytes", size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1157,7 +1157,7 @@ static void vfio_pci_load_rom(VFIODevice *vdev)
|
|||||||
if (!vdev->rom_size) {
|
if (!vdev->rom_size) {
|
||||||
vdev->rom_read_failed = true;
|
vdev->rom_read_failed = true;
|
||||||
error_report("vfio-pci: Cannot read device rom at "
|
error_report("vfio-pci: Cannot read device rom at "
|
||||||
"%04x:%02x:%02x.%x\n",
|
"%04x:%02x:%02x.%x",
|
||||||
vdev->host.domain, vdev->host.bus, vdev->host.slot,
|
vdev->host.domain, vdev->host.bus, vdev->host.slot,
|
||||||
vdev->host.function);
|
vdev->host.function);
|
||||||
error_printf("Device option ROM contents are probably invalid "
|
error_printf("Device option ROM contents are probably invalid "
|
||||||
@@ -1192,11 +1192,8 @@ static uint64_t vfio_rom_read(void *opaque, hwaddr addr, unsigned size)
|
|||||||
uint64_t val = ((uint64_t)1 << (size * 8)) - 1;
|
uint64_t val = ((uint64_t)1 << (size * 8)) - 1;
|
||||||
|
|
||||||
/* Load the ROM lazily when the guest tries to read it */
|
/* Load the ROM lazily when the guest tries to read it */
|
||||||
if (unlikely(!vdev->rom)) {
|
if (unlikely(!vdev->rom && !vdev->rom_read_failed)) {
|
||||||
vfio_pci_load_rom(vdev);
|
vfio_pci_load_rom(vdev);
|
||||||
if (unlikely(!vdev->rom && !vdev->rom_read_failed)) {
|
|
||||||
vfio_pci_load_rom(vdev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&val, vdev->rom + addr,
|
memcpy(&val, vdev->rom + addr,
|
||||||
@@ -1341,7 +1338,7 @@ static void vfio_vga_write(void *opaque, hwaddr addr,
|
|||||||
buf.dword = cpu_to_le32(data);
|
buf.dword = cpu_to_le32(data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("vfio: unsupported write size, %d bytes\n", size);
|
hw_error("vfio: unsupported write size, %d bytes", size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1384,7 +1381,7 @@ static uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size)
|
|||||||
data = le32_to_cpu(buf.dword);
|
data = le32_to_cpu(buf.dword);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hw_error("vfio: unsupported read size, %d bytes\n", size);
|
hw_error("vfio: unsupported read size, %d bytes", size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1429,7 +1426,7 @@ static uint64_t vfio_generic_window_quirk_read(void *opaque,
|
|||||||
|
|
||||||
if (!vfio_range_contained(addr, size, quirk->data.data_offset,
|
if (!vfio_range_contained(addr, size, quirk->data.data_offset,
|
||||||
quirk->data.data_size)) {
|
quirk->data.data_size)) {
|
||||||
hw_error("%s: window data read not fully contained: %s\n",
|
hw_error("%s: window data read not fully contained: %s",
|
||||||
__func__, memory_region_name(&quirk->mem));
|
__func__, memory_region_name(&quirk->mem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1458,7 +1455,7 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr,
|
|||||||
quirk->data.address_offset, quirk->data.address_size)) {
|
quirk->data.address_offset, quirk->data.address_size)) {
|
||||||
|
|
||||||
if (addr != quirk->data.address_offset) {
|
if (addr != quirk->data.address_offset) {
|
||||||
hw_error("%s: offset write into address window: %s\n",
|
hw_error("%s: offset write into address window: %s",
|
||||||
__func__, memory_region_name(&quirk->mem));
|
__func__, memory_region_name(&quirk->mem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1479,7 +1476,7 @@ static void vfio_generic_window_quirk_write(void *opaque, hwaddr addr,
|
|||||||
|
|
||||||
if (!vfio_range_contained(addr, size, quirk->data.data_offset,
|
if (!vfio_range_contained(addr, size, quirk->data.data_offset,
|
||||||
quirk->data.data_size)) {
|
quirk->data.data_size)) {
|
||||||
hw_error("%s: window data write not fully contained: %s\n",
|
hw_error("%s: window data write not fully contained: %s",
|
||||||
__func__, memory_region_name(&quirk->mem));
|
__func__, memory_region_name(&quirk->mem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1515,7 +1512,7 @@ static uint64_t vfio_generic_quirk_read(void *opaque,
|
|||||||
ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) {
|
ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) {
|
||||||
if (!vfio_range_contained(addr, size, offset,
|
if (!vfio_range_contained(addr, size, offset,
|
||||||
quirk->data.address_mask + 1)) {
|
quirk->data.address_mask + 1)) {
|
||||||
hw_error("%s: read not fully contained: %s\n",
|
hw_error("%s: read not fully contained: %s",
|
||||||
__func__, memory_region_name(&quirk->mem));
|
__func__, memory_region_name(&quirk->mem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1544,7 +1541,7 @@ static void vfio_generic_quirk_write(void *opaque, hwaddr addr,
|
|||||||
ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) {
|
ranges_overlap(addr, size, offset, quirk->data.address_mask + 1)) {
|
||||||
if (!vfio_range_contained(addr, size, offset,
|
if (!vfio_range_contained(addr, size, offset,
|
||||||
quirk->data.address_mask + 1)) {
|
quirk->data.address_mask + 1)) {
|
||||||
hw_error("%s: write not fully contained: %s\n",
|
hw_error("%s: write not fully contained: %s",
|
||||||
__func__, memory_region_name(&quirk->mem));
|
__func__, memory_region_name(&quirk->mem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2302,7 +2299,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
|||||||
container->iommu_data.type1.error = ret;
|
container->iommu_data.type1.error = ret;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hw_error("vfio: DMA mapping failed, unable to continue\n");
|
hw_error("vfio: DMA mapping failed, unable to continue");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2972,7 +2969,7 @@ static void vfio_pci_pre_reset(VFIODevice *vdev)
|
|||||||
pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
|
pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
|
||||||
state = pmcsr & PCI_PM_CTRL_STATE_MASK;
|
state = pmcsr & PCI_PM_CTRL_STATE_MASK;
|
||||||
if (state) {
|
if (state) {
|
||||||
error_report("vfio: Unable to power on device, stuck in D%d\n",
|
error_report("vfio: Unable to power on device, stuck in D%d",
|
||||||
state);
|
state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3271,7 +3268,7 @@ static void vfio_kvm_device_del_group(VFIOGroup *group)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
|
if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
|
||||||
error_report("Failed to remove group %d to KVM VFIO device: %m",
|
error_report("Failed to remove group %d from KVM VFIO device: %m",
|
||||||
group->groupid);
|
group->groupid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -3339,7 +3336,7 @@ static int vfio_connect_container(VFIOGroup *group)
|
|||||||
vfio_listener_release(container);
|
vfio_listener_release(container);
|
||||||
g_free(container);
|
g_free(container);
|
||||||
close(fd);
|
close(fd);
|
||||||
error_report("vfio: memory listener initialization failed for container\n");
|
error_report("vfio: memory listener initialization failed for container");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -195,8 +195,8 @@ static void process_tx_fcb(eTSEC *etsec)
|
|||||||
|
|
||||||
/* if packet is IP4 and IP checksum is requested */
|
/* if packet is IP4 and IP checksum is requested */
|
||||||
if (flags & FCB_TX_IP && flags & FCB_TX_CIP) {
|
if (flags & FCB_TX_IP && flags & FCB_TX_CIP) {
|
||||||
/* do IP4 checksum (TODO This funtion does TCP/UDP checksum but not sure
|
/* do IP4 checksum (TODO This function does TCP/UDP checksum
|
||||||
* if it also does IP4 checksum. */
|
* but not sure if it also does IP4 checksum.) */
|
||||||
net_checksum_calculate(etsec->tx_buffer + 8,
|
net_checksum_calculate(etsec->tx_buffer + 8,
|
||||||
etsec->tx_buffer_len - 8);
|
etsec->tx_buffer_len - 8);
|
||||||
}
|
}
|
||||||
@@ -592,7 +592,7 @@ void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
|
|||||||
|
|
||||||
/* TODO: Broadcast and Multicast */
|
/* TODO: Broadcast and Multicast */
|
||||||
|
|
||||||
if (bd.flags | BD_INTERRUPT) {
|
if (bd.flags & BD_INTERRUPT) {
|
||||||
/* Set RXFx */
|
/* Set RXFx */
|
||||||
etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr);
|
etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr);
|
||||||
|
|
||||||
@@ -601,7 +601,7 @@ void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (bd.flags | BD_INTERRUPT) {
|
if (bd.flags & BD_INTERRUPT) {
|
||||||
/* Set IEVENT */
|
/* Set IEVENT */
|
||||||
ievent_set(etsec, IEVENT_RXB);
|
ievent_set(etsec, IEVENT_RXB);
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
#include "hw/qdev.h"
|
#include "hw/qdev.h"
|
||||||
#include "hw/ppc/spapr.h"
|
#include "hw/ppc/spapr.h"
|
||||||
#include "hw/ppc/spapr_vio.h"
|
#include "hw/ppc/spapr_vio.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
@@ -213,6 +214,8 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev)
|
|||||||
object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
|
object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
|
||||||
qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
|
qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
|
||||||
|
|
||||||
|
add_boot_device_path(dev->nicconf.bootindex, DEVICE(dev), "");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -222,13 +222,33 @@ static char *mac_strdup_printf(const uint8_t *mac)
|
|||||||
mac[1], mac[2], mac[3], mac[4], mac[5]);
|
mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static intList *get_vlan_table(VirtIONet *n)
|
||||||
|
{
|
||||||
|
intList *list, *entry;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
list = NULL;
|
||||||
|
for (i = 0; i < MAX_VLAN >> 5; i++) {
|
||||||
|
for (j = 0; n->vlans[i] && j <= 0x1f; j++) {
|
||||||
|
if (n->vlans[i] & (1U << j)) {
|
||||||
|
entry = g_malloc0(sizeof(*entry));
|
||||||
|
entry->value = (i << 5) + j;
|
||||||
|
entry->next = list;
|
||||||
|
list = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
|
static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
|
||||||
{
|
{
|
||||||
VirtIONet *n = qemu_get_nic_opaque(nc);
|
VirtIONet *n = qemu_get_nic_opaque(nc);
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
||||||
RxFilterInfo *info;
|
RxFilterInfo *info;
|
||||||
strList *str_list, *entry;
|
strList *str_list, *entry;
|
||||||
intList *int_list, *int_entry;
|
int i;
|
||||||
int i, j;
|
|
||||||
|
|
||||||
info = g_malloc0(sizeof(*info));
|
info = g_malloc0(sizeof(*info));
|
||||||
info->name = g_strdup(nc->name);
|
info->name = g_strdup(nc->name);
|
||||||
@@ -273,19 +293,15 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
|
|||||||
str_list = entry;
|
str_list = entry;
|
||||||
}
|
}
|
||||||
info->multicast_table = str_list;
|
info->multicast_table = str_list;
|
||||||
|
info->vlan_table = get_vlan_table(n);
|
||||||
|
|
||||||
int_list = NULL;
|
if (!((1 << VIRTIO_NET_F_CTRL_VLAN) & vdev->guest_features)) {
|
||||||
for (i = 0; i < MAX_VLAN >> 5; i++) {
|
info->vlan = RX_STATE_ALL;
|
||||||
for (j = 0; n->vlans[i] && j < 0x1f; j++) {
|
} else if (!info->vlan_table) {
|
||||||
if (n->vlans[i] & (1U << j)) {
|
info->vlan = RX_STATE_NONE;
|
||||||
int_entry = g_malloc0(sizeof(*int_entry));
|
} else {
|
||||||
int_entry->value = (i << 5) + j;
|
info->vlan = RX_STATE_NORMAL;
|
||||||
int_entry->next = int_list;
|
|
||||||
int_list = int_entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
info->vlan_table = int_list;
|
|
||||||
|
|
||||||
/* enable event notification after query */
|
/* enable event notification after query */
|
||||||
nc->rxfilter_notify_enabled = 1;
|
nc->rxfilter_notify_enabled = 1;
|
||||||
@@ -514,6 +530,12 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
|
|||||||
}
|
}
|
||||||
vhost_net_ack_features(tap_get_vhost_net(nc->peer), features);
|
vhost_net_ack_features(tap_get_vhost_net(nc->peer), features);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((1 << VIRTIO_NET_F_CTRL_VLAN) & features) {
|
||||||
|
memset(n->vlans, 0, MAX_VLAN >> 3);
|
||||||
|
} else {
|
||||||
|
memset(n->vlans, 0xff, MAX_VLAN >> 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
|
static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
|
||||||
|
@@ -945,9 +945,15 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
|
|||||||
Error *local_errp = NULL;
|
Error *local_errp = NULL;
|
||||||
|
|
||||||
object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
|
object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
|
||||||
(Object **) &ds->enet, &local_errp);
|
(Object **) &ds->enet,
|
||||||
|
object_property_allow_set_link,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&local_errp);
|
||||||
object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
|
object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
|
||||||
(Object **) &cs->enet, &local_errp);
|
(Object **) &cs->enet,
|
||||||
|
object_property_allow_set_link,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&local_errp);
|
||||||
if (local_errp) {
|
if (local_errp) {
|
||||||
goto xilinx_enet_realize_fail;
|
goto xilinx_enet_realize_fail;
|
||||||
}
|
}
|
||||||
@@ -982,10 +988,16 @@ static void xilinx_enet_init(Object *obj)
|
|||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
|
|
||||||
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
|
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
|
||||||
(Object **) &s->tx_data_dev, &error_abort);
|
(Object **) &s->tx_data_dev,
|
||||||
|
qdev_prop_allow_set_link_before_realize,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&error_abort);
|
||||||
object_property_add_link(obj, "axistream-control-connected",
|
object_property_add_link(obj, "axistream-control-connected",
|
||||||
TYPE_STREAM_SLAVE,
|
TYPE_STREAM_SLAVE,
|
||||||
(Object **) &s->tx_control_dev, &error_abort);
|
(Object **) &s->tx_control_dev,
|
||||||
|
qdev_prop_allow_set_link_before_realize,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||||
TYPE_XILINX_AXI_ENET_DATA_STREAM);
|
TYPE_XILINX_AXI_ENET_DATA_STREAM);
|
||||||
|
@@ -504,7 +504,7 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
|
|||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
FWCfgState *s = container_of(n, FWCfgState, machine_ready);
|
FWCfgState *s = container_of(n, FWCfgState, machine_ready);
|
||||||
char *bootindex = get_boot_devices_list(&len);
|
char *bootindex = get_boot_devices_list(&len, false);
|
||||||
|
|
||||||
fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len);
|
fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len);
|
||||||
}
|
}
|
||||||
|
@@ -58,11 +58,11 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
|
|||||||
#define PBM_PCI_IMR_MASK 0x7fffffff
|
#define PBM_PCI_IMR_MASK 0x7fffffff
|
||||||
#define PBM_PCI_IMR_ENABLED 0x80000000
|
#define PBM_PCI_IMR_ENABLED 0x80000000
|
||||||
|
|
||||||
#define POR (1 << 31)
|
#define POR (1U << 31)
|
||||||
#define SOFT_POR (1 << 30)
|
#define SOFT_POR (1U << 30)
|
||||||
#define SOFT_XIR (1 << 29)
|
#define SOFT_XIR (1U << 29)
|
||||||
#define BTN_POR (1 << 28)
|
#define BTN_POR (1U << 28)
|
||||||
#define BTN_XIR (1 << 27)
|
#define BTN_XIR (1U << 27)
|
||||||
#define RESET_MASK 0xf8000000
|
#define RESET_MASK 0xf8000000
|
||||||
#define RESET_WCMASK 0x98000000
|
#define RESET_WCMASK 0x98000000
|
||||||
#define RESET_WMASK 0x60000000
|
#define RESET_WMASK 0x60000000
|
||||||
|
@@ -52,15 +52,25 @@ typedef struct RavenPCIState {
|
|||||||
typedef struct PRePPCIState {
|
typedef struct PRePPCIState {
|
||||||
PCIHostState parent_obj;
|
PCIHostState parent_obj;
|
||||||
|
|
||||||
MemoryRegion intack;
|
|
||||||
qemu_irq irq[PCI_NUM_PINS];
|
qemu_irq irq[PCI_NUM_PINS];
|
||||||
PCIBus pci_bus;
|
PCIBus pci_bus;
|
||||||
|
AddressSpace pci_io_as;
|
||||||
|
MemoryRegion pci_io;
|
||||||
|
MemoryRegion pci_io_non_contiguous;
|
||||||
|
MemoryRegion pci_memory;
|
||||||
|
MemoryRegion pci_intack;
|
||||||
|
MemoryRegion bm;
|
||||||
|
MemoryRegion bm_ram_alias;
|
||||||
|
MemoryRegion bm_pci_memory_alias;
|
||||||
|
AddressSpace bm_as;
|
||||||
RavenPCIState pci_dev;
|
RavenPCIState pci_dev;
|
||||||
|
|
||||||
|
int contiguous_map;
|
||||||
} PREPPCIState;
|
} PREPPCIState;
|
||||||
|
|
||||||
#define BIOS_SIZE (1024 * 1024)
|
#define BIOS_SIZE (1024 * 1024)
|
||||||
|
|
||||||
static inline uint32_t PPC_PCIIO_config(hwaddr addr)
|
static inline uint32_t raven_pci_io_config(hwaddr addr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -72,53 +82,133 @@ static inline uint32_t PPC_PCIIO_config(hwaddr addr)
|
|||||||
return (addr & 0x7ff) | (i << 11);
|
return (addr & 0x7ff) | (i << 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ppc_pci_io_write(void *opaque, hwaddr addr,
|
static void raven_pci_io_write(void *opaque, hwaddr addr,
|
||||||
uint64_t val, unsigned int size)
|
uint64_t val, unsigned int size)
|
||||||
{
|
{
|
||||||
PREPPCIState *s = opaque;
|
PREPPCIState *s = opaque;
|
||||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||||
pci_data_write(phb->bus, PPC_PCIIO_config(addr), val, size);
|
pci_data_write(phb->bus, raven_pci_io_config(addr), val, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t ppc_pci_io_read(void *opaque, hwaddr addr,
|
static uint64_t raven_pci_io_read(void *opaque, hwaddr addr,
|
||||||
unsigned int size)
|
unsigned int size)
|
||||||
{
|
{
|
||||||
PREPPCIState *s = opaque;
|
PREPPCIState *s = opaque;
|
||||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||||
return pci_data_read(phb->bus, PPC_PCIIO_config(addr), size);
|
return pci_data_read(phb->bus, raven_pci_io_config(addr), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps PPC_PCIIO_ops = {
|
static const MemoryRegionOps raven_pci_io_ops = {
|
||||||
.read = ppc_pci_io_read,
|
.read = raven_pci_io_read,
|
||||||
.write = ppc_pci_io_write,
|
.write = raven_pci_io_write,
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint64_t ppc_intack_read(void *opaque, hwaddr addr,
|
static uint64_t raven_intack_read(void *opaque, hwaddr addr,
|
||||||
unsigned int size)
|
unsigned int size)
|
||||||
{
|
{
|
||||||
return pic_read_irq(isa_pic);
|
return pic_read_irq(isa_pic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps PPC_intack_ops = {
|
static const MemoryRegionOps raven_intack_ops = {
|
||||||
.read = ppc_intack_read,
|
.read = raven_intack_read,
|
||||||
.valid = {
|
.valid = {
|
||||||
.max_access_size = 1,
|
.max_access_size = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
|
static inline hwaddr raven_io_address(PREPPCIState *s,
|
||||||
|
hwaddr addr)
|
||||||
|
{
|
||||||
|
if (s->contiguous_map == 0) {
|
||||||
|
/* 64 KB contiguous space for IOs */
|
||||||
|
addr &= 0xFFFF;
|
||||||
|
} else {
|
||||||
|
/* 8 MB non-contiguous space for IOs */
|
||||||
|
addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: handle endianness switch */
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t raven_io_read(void *opaque, hwaddr addr,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
PREPPCIState *s = opaque;
|
||||||
|
uint8_t buf[4];
|
||||||
|
|
||||||
|
addr = raven_io_address(s, addr);
|
||||||
|
address_space_read(&s->pci_io_as, addr + 0x80000000, buf, size);
|
||||||
|
|
||||||
|
if (size == 1) {
|
||||||
|
return buf[0];
|
||||||
|
} else if (size == 2) {
|
||||||
|
return lduw_p(buf);
|
||||||
|
} else if (size == 4) {
|
||||||
|
return ldl_p(buf);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void raven_io_write(void *opaque, hwaddr addr,
|
||||||
|
uint64_t val, unsigned int size)
|
||||||
|
{
|
||||||
|
PREPPCIState *s = opaque;
|
||||||
|
uint8_t buf[4];
|
||||||
|
|
||||||
|
addr = raven_io_address(s, addr);
|
||||||
|
|
||||||
|
if (size == 1) {
|
||||||
|
buf[0] = val;
|
||||||
|
} else if (size == 2) {
|
||||||
|
stw_p(buf, val);
|
||||||
|
} else if (size == 4) {
|
||||||
|
stl_p(buf, val);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
address_space_write(&s->pci_io_as, addr + 0x80000000, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps raven_io_ops = {
|
||||||
|
.read = raven_io_read,
|
||||||
|
.write = raven_io_write,
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
.impl.max_access_size = 4,
|
||||||
|
.valid.unaligned = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int raven_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||||
{
|
{
|
||||||
return (irq_num + (pci_dev->devfn >> 3)) & 1;
|
return (irq_num + (pci_dev->devfn >> 3)) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prep_set_irq(void *opaque, int irq_num, int level)
|
static void raven_set_irq(void *opaque, int irq_num, int level)
|
||||||
{
|
{
|
||||||
qemu_irq *pic = opaque;
|
qemu_irq *pic = opaque;
|
||||||
|
|
||||||
qemu_set_irq(pic[irq_num] , level);
|
qemu_set_irq(pic[irq_num] , level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AddressSpace *raven_pcihost_set_iommu(PCIBus *bus, void *opaque,
|
||||||
|
int devfn)
|
||||||
|
{
|
||||||
|
PREPPCIState *s = opaque;
|
||||||
|
|
||||||
|
return &s->bm_as;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void raven_change_gpio(void *opaque, int n, int level)
|
||||||
|
{
|
||||||
|
PREPPCIState *s = opaque;
|
||||||
|
|
||||||
|
s->contiguous_map = level;
|
||||||
|
}
|
||||||
|
|
||||||
static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
|
static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
|
||||||
{
|
{
|
||||||
SysBusDevice *dev = SYS_BUS_DEVICE(d);
|
SysBusDevice *dev = SYS_BUS_DEVICE(d);
|
||||||
@@ -127,29 +217,30 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
|
|||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
isa_mem_base = 0xc0000000;
|
|
||||||
|
|
||||||
for (i = 0; i < PCI_NUM_PINS; i++) {
|
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||||
sysbus_init_irq(dev, &s->irq[i]);
|
sysbus_init_irq(dev, &s->irq[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_bus_irqs(&s->pci_bus, prep_set_irq, prep_map_irq, s->irq, PCI_NUM_PINS);
|
qdev_init_gpio_in(d, raven_change_gpio, 1);
|
||||||
|
|
||||||
memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_be_ops, s,
|
pci_bus_irqs(&s->pci_bus, raven_set_irq, raven_map_irq, s->irq,
|
||||||
"pci-conf-idx", 1);
|
PCI_NUM_PINS);
|
||||||
sysbus_add_io(dev, 0xcf8, &h->conf_mem);
|
|
||||||
sysbus_init_ioports(&h->busdev, 0xcf8, 1);
|
|
||||||
|
|
||||||
memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_be_ops, s,
|
memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, s,
|
||||||
"pci-conf-data", 1);
|
"pci-conf-idx", 4);
|
||||||
sysbus_add_io(dev, 0xcfc, &h->data_mem);
|
memory_region_add_subregion(&s->pci_io, 0xcf8, &h->conf_mem);
|
||||||
sysbus_init_ioports(&h->busdev, 0xcfc, 1);
|
|
||||||
|
|
||||||
memory_region_init_io(&h->mmcfg, OBJECT(s), &PPC_PCIIO_ops, s, "pciio", 0x00400000);
|
memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, s,
|
||||||
|
"pci-conf-data", 4);
|
||||||
|
memory_region_add_subregion(&s->pci_io, 0xcfc, &h->data_mem);
|
||||||
|
|
||||||
|
memory_region_init_io(&h->mmcfg, OBJECT(s), &raven_pci_io_ops, s,
|
||||||
|
"pciio", 0x00400000);
|
||||||
memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
|
memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
|
||||||
|
|
||||||
memory_region_init_io(&s->intack, OBJECT(s), &PPC_intack_ops, s, "pci-intack", 1);
|
memory_region_init_io(&s->pci_intack, OBJECT(s), &raven_intack_ops, s,
|
||||||
memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->intack);
|
"pci-intack", 1);
|
||||||
|
memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack);
|
||||||
|
|
||||||
/* TODO Remove once realize propagates to child devices. */
|
/* TODO Remove once realize propagates to child devices. */
|
||||||
object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
|
object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
|
||||||
@@ -160,11 +251,36 @@ static void raven_pcihost_initfn(Object *obj)
|
|||||||
PCIHostState *h = PCI_HOST_BRIDGE(obj);
|
PCIHostState *h = PCI_HOST_BRIDGE(obj);
|
||||||
PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
|
PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
MemoryRegion *address_space_io = get_system_io();
|
|
||||||
DeviceState *pci_dev;
|
DeviceState *pci_dev;
|
||||||
|
|
||||||
|
memory_region_init(&s->pci_io, obj, "pci-io", 0x3f800000);
|
||||||
|
memory_region_init_io(&s->pci_io_non_contiguous, obj, &raven_io_ops, s,
|
||||||
|
"pci-io-non-contiguous", 0x00800000);
|
||||||
|
/* Open Hack'Ware hack: real size should be only 0x3f000000 bytes */
|
||||||
|
memory_region_init(&s->pci_memory, obj, "pci-memory",
|
||||||
|
0x3f000000 + 0xc0000000ULL);
|
||||||
|
address_space_init(&s->pci_io_as, &s->pci_io, "raven-io");
|
||||||
|
|
||||||
|
/* CPU address space */
|
||||||
|
memory_region_add_subregion(address_space_mem, 0x80000000, &s->pci_io);
|
||||||
|
memory_region_add_subregion_overlap(address_space_mem, 0x80000000,
|
||||||
|
&s->pci_io_non_contiguous, 1);
|
||||||
|
memory_region_add_subregion(address_space_mem, 0xc0000000, &s->pci_memory);
|
||||||
pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
|
pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
|
||||||
address_space_mem, address_space_io, 0, TYPE_PCI_BUS);
|
&s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS);
|
||||||
|
|
||||||
|
/* Bus master address space */
|
||||||
|
memory_region_init(&s->bm, obj, "bm-raven", UINT32_MAX);
|
||||||
|
memory_region_init_alias(&s->bm_pci_memory_alias, obj, "bm-pci-memory",
|
||||||
|
&s->pci_memory, 0,
|
||||||
|
memory_region_size(&s->pci_memory));
|
||||||
|
memory_region_init_alias(&s->bm_ram_alias, obj, "bm-system",
|
||||||
|
get_system_memory(), 0, 0x80000000);
|
||||||
|
memory_region_add_subregion(&s->bm, 0 , &s->bm_pci_memory_alias);
|
||||||
|
memory_region_add_subregion(&s->bm, 0x80000000, &s->bm_ram_alias);
|
||||||
|
address_space_init(&s->bm_as, &s->bm, "raven-bm");
|
||||||
|
pci_setup_iommu(&s->pci_bus, raven_pcihost_set_iommu, s);
|
||||||
|
|
||||||
h->bus = &s->pci_bus;
|
h->bus = &s->pci_bus;
|
||||||
|
|
||||||
object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE);
|
object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE);
|
||||||
|
@@ -189,9 +189,9 @@ static void pci_do_device_reset(PCIDevice *dev)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
dev->irq_state = 0;
|
|
||||||
pci_update_irq_status(dev);
|
|
||||||
pci_device_deassert_intx(dev);
|
pci_device_deassert_intx(dev);
|
||||||
|
assert(dev->irq_state == 0);
|
||||||
|
|
||||||
/* Clear all writable bits */
|
/* Clear all writable bits */
|
||||||
pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
|
pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
|
||||||
pci_get_word(dev->wmask + PCI_COMMAND) |
|
pci_get_word(dev->wmask + PCI_COMMAND) |
|
||||||
|
@@ -142,8 +142,9 @@ static uint64_t pci_host_data_read(void *opaque,
|
|||||||
{
|
{
|
||||||
PCIHostState *s = opaque;
|
PCIHostState *s = opaque;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
if (!(s->config_reg & (1 << 31)))
|
if (!(s->config_reg & (1U << 31))) {
|
||||||
return 0xffffffff;
|
return 0xffffffff;
|
||||||
|
}
|
||||||
val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
|
val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
|
||||||
PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
|
PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
|
||||||
addr, len, val);
|
addr, len, val);
|
||||||
|
@@ -198,7 +198,9 @@ static void pxa2xx_pcmcia_initfn(Object *obj)
|
|||||||
s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
|
s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
|
||||||
|
|
||||||
object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
|
object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
|
||||||
(Object **)&s->card, NULL);
|
(Object **)&s->card,
|
||||||
|
NULL, /* read-only property */
|
||||||
|
0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert a new card into a slot */
|
/* Insert a new card into a slot */
|
||||||
|
@@ -1002,7 +1002,7 @@ static void cpu_4xx_wdt_cb (void *opaque)
|
|||||||
case 0x1:
|
case 0x1:
|
||||||
timer_mod(ppc40x_timer->wdt_timer, next);
|
timer_mod(ppc40x_timer->wdt_timer, next);
|
||||||
ppc40x_timer->wdt_next = next;
|
ppc40x_timer->wdt_next = next;
|
||||||
env->spr[SPR_40x_TSR] |= 1 << 31;
|
env->spr[SPR_40x_TSR] |= 1U << 31;
|
||||||
break;
|
break;
|
||||||
case 0x2:
|
case 0x2:
|
||||||
timer_mod(ppc40x_timer->wdt_timer, next);
|
timer_mod(ppc40x_timer->wdt_timer, next);
|
||||||
|
@@ -128,7 +128,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
|||||||
|
|
||||||
tlb->attr = 0;
|
tlb->attr = 0;
|
||||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||||
tlb->size = 1 << 31; /* up to 0x80000000 */
|
tlb->size = 1U << 31; /* up to 0x80000000 */
|
||||||
tlb->EPN = va & TARGET_PAGE_MASK;
|
tlb->EPN = va & TARGET_PAGE_MASK;
|
||||||
tlb->RPN = pa & TARGET_PAGE_MASK;
|
tlb->RPN = pa & TARGET_PAGE_MASK;
|
||||||
tlb->PID = 0;
|
tlb->PID = 0;
|
||||||
@@ -136,7 +136,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
|||||||
tlb = &env->tlb.tlbe[1];
|
tlb = &env->tlb.tlbe[1];
|
||||||
tlb->attr = 0;
|
tlb->attr = 0;
|
||||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||||
tlb->size = 1 << 31; /* up to 0xffffffff */
|
tlb->size = 1U << 31; /* up to 0xffffffff */
|
||||||
tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
|
tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
|
||||||
tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
|
tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
|
||||||
tlb->PID = 0;
|
tlb->PID = 0;
|
||||||
|
@@ -161,7 +161,7 @@ static void ppcuic_set_irq (void *opaque, int irq_num, int level)
|
|||||||
uint32_t mask, sr;
|
uint32_t mask, sr;
|
||||||
|
|
||||||
uic = opaque;
|
uic = opaque;
|
||||||
mask = 1 << (31-irq_num);
|
mask = 1U << (31-irq_num);
|
||||||
LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
|
LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
|
||||||
" mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
|
" mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
|
||||||
__func__, irq_num, level,
|
__func__, irq_num, level,
|
||||||
|
@@ -34,15 +34,15 @@
|
|||||||
/* Timer Control Register */
|
/* Timer Control Register */
|
||||||
|
|
||||||
#define TCR_WP_SHIFT 30 /* Watchdog Timer Period */
|
#define TCR_WP_SHIFT 30 /* Watchdog Timer Period */
|
||||||
#define TCR_WP_MASK (0x3 << TCR_WP_SHIFT)
|
#define TCR_WP_MASK (0x3U << TCR_WP_SHIFT)
|
||||||
#define TCR_WRC_SHIFT 28 /* Watchdog Timer Reset Control */
|
#define TCR_WRC_SHIFT 28 /* Watchdog Timer Reset Control */
|
||||||
#define TCR_WRC_MASK (0x3 << TCR_WRC_SHIFT)
|
#define TCR_WRC_MASK (0x3U << TCR_WRC_SHIFT)
|
||||||
#define TCR_WIE (1 << 27) /* Watchdog Timer Interrupt Enable */
|
#define TCR_WIE (1U << 27) /* Watchdog Timer Interrupt Enable */
|
||||||
#define TCR_DIE (1 << 26) /* Decrementer Interrupt Enable */
|
#define TCR_DIE (1U << 26) /* Decrementer Interrupt Enable */
|
||||||
#define TCR_FP_SHIFT 24 /* Fixed-Interval Timer Period */
|
#define TCR_FP_SHIFT 24 /* Fixed-Interval Timer Period */
|
||||||
#define TCR_FP_MASK (0x3 << TCR_FP_SHIFT)
|
#define TCR_FP_MASK (0x3U << TCR_FP_SHIFT)
|
||||||
#define TCR_FIE (1 << 23) /* Fixed-Interval Timer Interrupt Enable */
|
#define TCR_FIE (1U << 23) /* Fixed-Interval Timer Interrupt Enable */
|
||||||
#define TCR_ARE (1 << 22) /* Auto-Reload Enable */
|
#define TCR_ARE (1U << 22) /* Auto-Reload Enable */
|
||||||
|
|
||||||
/* Timer Control Register (e500 specific fields) */
|
/* Timer Control Register (e500 specific fields) */
|
||||||
|
|
||||||
@@ -53,12 +53,12 @@
|
|||||||
|
|
||||||
/* Timer Status Register */
|
/* Timer Status Register */
|
||||||
|
|
||||||
#define TSR_FIS (1 << 26) /* Fixed-Interval Timer Interrupt Status */
|
#define TSR_FIS (1U << 26) /* Fixed-Interval Timer Interrupt Status */
|
||||||
#define TSR_DIS (1 << 27) /* Decrementer Interrupt Status */
|
#define TSR_DIS (1U << 27) /* Decrementer Interrupt Status */
|
||||||
#define TSR_WRS_SHIFT 28 /* Watchdog Timer Reset Status */
|
#define TSR_WRS_SHIFT 28 /* Watchdog Timer Reset Status */
|
||||||
#define TSR_WRS_MASK (0x3 << TSR_WRS_SHIFT)
|
#define TSR_WRS_MASK (0x3U << TSR_WRS_SHIFT)
|
||||||
#define TSR_WIS (1 << 30) /* Watchdog Timer Interrupt Status */
|
#define TSR_WIS (1U << 30) /* Watchdog Timer Interrupt Status */
|
||||||
#define TSR_ENW (1 << 31) /* Enable Next Watchdog Timer */
|
#define TSR_ENW (1U << 31) /* Enable Next Watchdog Timer */
|
||||||
|
|
||||||
typedef struct booke_timer_t booke_timer_t;
|
typedef struct booke_timer_t booke_timer_t;
|
||||||
struct booke_timer_t {
|
struct booke_timer_t {
|
||||||
|
103
hw/ppc/prep.c
103
hw/ppc/prep.c
@@ -185,6 +185,7 @@ typedef struct sysctrl_t {
|
|||||||
uint8_t state;
|
uint8_t state;
|
||||||
uint8_t syscontrol;
|
uint8_t syscontrol;
|
||||||
int contiguous_map;
|
int contiguous_map;
|
||||||
|
qemu_irq contiguous_map_irq;
|
||||||
int endian;
|
int endian;
|
||||||
} sysctrl_t;
|
} sysctrl_t;
|
||||||
|
|
||||||
@@ -253,6 +254,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
|
|||||||
case 0x0850:
|
case 0x0850:
|
||||||
/* I/O map type register */
|
/* I/O map type register */
|
||||||
sysctrl->contiguous_map = val & 0x01;
|
sysctrl->contiguous_map = val & 0x01;
|
||||||
|
qemu_set_irq(sysctrl->contiguous_map_irq, sysctrl->contiguous_map);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("ERROR: unaffected IO port write: %04" PRIx32
|
printf("ERROR: unaffected IO port write: %04" PRIx32
|
||||||
@@ -327,91 +329,6 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline hwaddr prep_IO_address(sysctrl_t *sysctrl,
|
|
||||||
hwaddr addr)
|
|
||||||
{
|
|
||||||
if (sysctrl->contiguous_map == 0) {
|
|
||||||
/* 64 KB contiguous space for IOs */
|
|
||||||
addr &= 0xFFFF;
|
|
||||||
} else {
|
|
||||||
/* 8 MB non-contiguous space for IOs */
|
|
||||||
addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PPC_prep_io_writeb (void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
sysctrl_t *sysctrl = opaque;
|
|
||||||
|
|
||||||
addr = prep_IO_address(sysctrl, addr);
|
|
||||||
cpu_outb(addr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t PPC_prep_io_readb (void *opaque, hwaddr addr)
|
|
||||||
{
|
|
||||||
sysctrl_t *sysctrl = opaque;
|
|
||||||
uint32_t ret;
|
|
||||||
|
|
||||||
addr = prep_IO_address(sysctrl, addr);
|
|
||||||
ret = cpu_inb(addr);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PPC_prep_io_writew (void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
sysctrl_t *sysctrl = opaque;
|
|
||||||
|
|
||||||
addr = prep_IO_address(sysctrl, addr);
|
|
||||||
PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
|
|
||||||
cpu_outw(addr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t PPC_prep_io_readw (void *opaque, hwaddr addr)
|
|
||||||
{
|
|
||||||
sysctrl_t *sysctrl = opaque;
|
|
||||||
uint32_t ret;
|
|
||||||
|
|
||||||
addr = prep_IO_address(sysctrl, addr);
|
|
||||||
ret = cpu_inw(addr);
|
|
||||||
PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PPC_prep_io_writel (void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
sysctrl_t *sysctrl = opaque;
|
|
||||||
|
|
||||||
addr = prep_IO_address(sysctrl, addr);
|
|
||||||
PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
|
|
||||||
cpu_outl(addr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t PPC_prep_io_readl (void *opaque, hwaddr addr)
|
|
||||||
{
|
|
||||||
sysctrl_t *sysctrl = opaque;
|
|
||||||
uint32_t ret;
|
|
||||||
|
|
||||||
addr = prep_IO_address(sysctrl, addr);
|
|
||||||
ret = cpu_inl(addr);
|
|
||||||
PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const MemoryRegionOps PPC_prep_io_ops = {
|
|
||||||
.old_mmio = {
|
|
||||||
.read = { PPC_prep_io_readb, PPC_prep_io_readw, PPC_prep_io_readl },
|
|
||||||
.write = { PPC_prep_io_writeb, PPC_prep_io_writew, PPC_prep_io_writel },
|
|
||||||
},
|
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NVRAM_SIZE 0x2000
|
#define NVRAM_SIZE 0x2000
|
||||||
|
|
||||||
@@ -458,13 +375,13 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
|
|||||||
CPUPPCState *env = NULL;
|
CPUPPCState *env = NULL;
|
||||||
nvram_t nvram;
|
nvram_t nvram;
|
||||||
M48t59State *m48t59;
|
M48t59State *m48t59;
|
||||||
MemoryRegion *PPC_io_memory = g_new(MemoryRegion, 1);
|
|
||||||
PortioList *port_list = g_new(PortioList, 1);
|
PortioList *port_list = g_new(PortioList, 1);
|
||||||
#if 0
|
#if 0
|
||||||
MemoryRegion *xcsr = g_new(MemoryRegion, 1);
|
MemoryRegion *xcsr = g_new(MemoryRegion, 1);
|
||||||
#endif
|
#endif
|
||||||
int linux_boot, i, nb_nics1;
|
int linux_boot, i, nb_nics1;
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
|
MemoryRegion *vga = g_new(MemoryRegion, 1);
|
||||||
uint32_t kernel_base, initrd_base;
|
uint32_t kernel_base, initrd_base;
|
||||||
long kernel_size, initrd_size;
|
long kernel_size, initrd_size;
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
@@ -567,6 +484,7 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
|
|||||||
fprintf(stderr, "Couldn't create PCI host controller.\n");
|
fprintf(stderr, "Couldn't create PCI host controller.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
sysctrl->contiguous_map_irq = qdev_get_gpio_in(dev, 0);
|
||||||
|
|
||||||
/* PCI -> ISA bridge */
|
/* PCI -> ISA bridge */
|
||||||
pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
|
pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
|
||||||
@@ -587,13 +505,16 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
|
|||||||
qdev_prop_set_uint8(dev, "config", 13); /* fdc, ser0, ser1, par0 */
|
qdev_prop_set_uint8(dev, "config", 13); /* fdc, ser0, ser1, par0 */
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
/* Register 8 MB of ISA IO space (needed for non-contiguous map) */
|
|
||||||
memory_region_init_io(PPC_io_memory, NULL, &PPC_prep_io_ops, sysctrl,
|
|
||||||
"ppc-io", 0x00800000);
|
|
||||||
memory_region_add_subregion(sysmem, 0x80000000, PPC_io_memory);
|
|
||||||
|
|
||||||
/* init basic PC hardware */
|
/* init basic PC hardware */
|
||||||
pci_vga_init(pci_bus);
|
pci_vga_init(pci_bus);
|
||||||
|
/* Open Hack'Ware hack: PCI BAR#0 is programmed to 0xf0000000.
|
||||||
|
* While bios will access framebuffer at 0xf0000000, real physical
|
||||||
|
* address is 0xf0000000 + 0xc0000000 (PCI memory base).
|
||||||
|
* Alias the wrong memory accesses to the right place.
|
||||||
|
*/
|
||||||
|
memory_region_init_alias(vga, NULL, "vga-alias", pci_address_space(pci),
|
||||||
|
0xf0000000, 0x1000000);
|
||||||
|
memory_region_add_subregion_overlap(sysmem, 0xf0000000, vga, 10);
|
||||||
|
|
||||||
nb_nics1 = nb_nics;
|
nb_nics1 = nb_nics;
|
||||||
if (nb_nics1 > NE2000_NB_MAX)
|
if (nb_nics1 > NE2000_NB_MAX)
|
||||||
|
107
hw/ppc/spapr.c
107
hw/ppc/spapr.c
@@ -26,6 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
|
#include "hw/fw-path-provider.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
@@ -45,6 +46,8 @@
|
|||||||
#include "hw/pci/msi.h"
|
#include "hw/pci/msi.h"
|
||||||
|
|
||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
|
#include "hw/scsi/scsi.h"
|
||||||
|
#include "hw/virtio/virtio-scsi.h"
|
||||||
|
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "hw/usb.h"
|
#include "hw/usb.h"
|
||||||
@@ -81,6 +84,8 @@
|
|||||||
|
|
||||||
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
||||||
|
|
||||||
|
#define TYPE_SPAPR_MACHINE "spapr-machine"
|
||||||
|
|
||||||
sPAPREnvironment *spapr;
|
sPAPREnvironment *spapr;
|
||||||
|
|
||||||
int spapr_allocate_irq(int hint, bool lsi)
|
int spapr_allocate_irq(int hint, bool lsi)
|
||||||
@@ -598,7 +603,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
|||||||
hwaddr rtas_addr,
|
hwaddr rtas_addr,
|
||||||
hwaddr rtas_size)
|
hwaddr rtas_size)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret, i;
|
||||||
|
size_t cb = 0;
|
||||||
|
char *bootlist;
|
||||||
void *fdt;
|
void *fdt;
|
||||||
sPAPRPHBState *phb;
|
sPAPRPHBState *phb;
|
||||||
|
|
||||||
@@ -640,6 +647,21 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
|
|||||||
fprintf(stderr, "Couldn't finalize CPU device tree properties\n");
|
fprintf(stderr, "Couldn't finalize CPU device tree properties\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bootlist = get_boot_devices_list(&cb, true);
|
||||||
|
if (cb && bootlist) {
|
||||||
|
int offset = fdt_path_offset(fdt, "/chosen");
|
||||||
|
if (offset < 0) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
for (i = 0; i < cb; i++) {
|
||||||
|
if (bootlist[i] == '\n') {
|
||||||
|
bootlist[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ret = fdt_setprop_string(fdt, offset, "qemu,boot-list", bootlist);
|
||||||
|
}
|
||||||
|
|
||||||
if (!spapr->has_graphics) {
|
if (!spapr->has_graphics) {
|
||||||
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
|
||||||
}
|
}
|
||||||
@@ -1410,9 +1432,86 @@ static QEMUMachine spapr_machine = {
|
|||||||
.kvm_type = spapr_kvm_type,
|
.kvm_type = spapr_kvm_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void spapr_machine_init(void)
|
/*
|
||||||
|
* Implementation of an interface to adjust firmware patch
|
||||||
|
* for the bootindex property handling.
|
||||||
|
*/
|
||||||
|
static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
||||||
|
DeviceState *dev)
|
||||||
{
|
{
|
||||||
qemu_register_machine(&spapr_machine);
|
#define CAST(type, obj, name) \
|
||||||
|
((type *)object_dynamic_cast(OBJECT(obj), (name)))
|
||||||
|
SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE);
|
||||||
|
sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
|
||||||
|
|
||||||
|
if (d) {
|
||||||
|
void *spapr = CAST(void, bus->parent, "spapr-vscsi");
|
||||||
|
VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
|
||||||
|
USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
|
||||||
|
|
||||||
|
if (spapr) {
|
||||||
|
/*
|
||||||
|
* Replace "channel@0/disk@0,0" with "disk@8000000000000000":
|
||||||
|
* We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun
|
||||||
|
* in the top 16 bits of the 64-bit LUN
|
||||||
|
*/
|
||||||
|
unsigned id = 0x8000 | (d->id << 8) | d->lun;
|
||||||
|
return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
|
||||||
|
(uint64_t)id << 48);
|
||||||
|
} else if (virtio) {
|
||||||
|
/*
|
||||||
|
* We use SRP luns of the form 01000000 | (target << 8) | lun
|
||||||
|
* in the top 32 bits of the 64-bit LUN
|
||||||
|
* Note: the quote above is from SLOF and it is wrong,
|
||||||
|
* the actual binding is:
|
||||||
|
* swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
|
||||||
|
*/
|
||||||
|
unsigned id = 0x1000000 | (d->id << 16) | d->lun;
|
||||||
|
return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
|
||||||
|
(uint64_t)id << 32);
|
||||||
|
} else if (usb) {
|
||||||
|
/*
|
||||||
|
* We use SRP luns of the form 01000000 | (usb-port << 16) | lun
|
||||||
|
* in the top 32 bits of the 64-bit LUN
|
||||||
|
*/
|
||||||
|
unsigned usb_port = atoi(usb->port->path);
|
||||||
|
unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
|
||||||
|
return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
|
||||||
|
(uint64_t)id << 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phb) {
|
||||||
|
/* Replace "pci" with "pci@800000020000000" */
|
||||||
|
return g_strdup_printf("pci@%"PRIX64, phb->buid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_init(spapr_machine_init);
|
static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
|
||||||
|
|
||||||
|
mc->qemu_machine = data;
|
||||||
|
fwc->get_dev_path = spapr_get_fw_dev_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo spapr_machine_info = {
|
||||||
|
.name = TYPE_SPAPR_MACHINE,
|
||||||
|
.parent = TYPE_MACHINE,
|
||||||
|
.class_init = spapr_machine_class_init,
|
||||||
|
.class_data = &spapr_machine,
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
|
{ TYPE_FW_PATH_PROVIDER },
|
||||||
|
{ }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void spapr_machine_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&spapr_machine_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(spapr_machine_register_types)
|
||||||
|
@@ -4,6 +4,36 @@
|
|||||||
#include "hw/ppc/spapr.h"
|
#include "hw/ppc/spapr.h"
|
||||||
#include "mmu-hash64.h"
|
#include "mmu-hash64.h"
|
||||||
|
|
||||||
|
struct SPRSyncState {
|
||||||
|
CPUState *cs;
|
||||||
|
int spr;
|
||||||
|
target_ulong value;
|
||||||
|
target_ulong mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void do_spr_sync(void *arg)
|
||||||
|
{
|
||||||
|
struct SPRSyncState *s = arg;
|
||||||
|
PowerPCCPU *cpu = POWERPC_CPU(s->cs);
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
|
||||||
|
cpu_synchronize_state(s->cs);
|
||||||
|
env->spr[s->spr] &= ~s->mask;
|
||||||
|
env->spr[s->spr] |= s->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_spr(CPUState *cs, int spr, target_ulong value,
|
||||||
|
target_ulong mask)
|
||||||
|
{
|
||||||
|
struct SPRSyncState s = {
|
||||||
|
.cs = cs,
|
||||||
|
.spr = spr,
|
||||||
|
.value = value,
|
||||||
|
.mask = mask
|
||||||
|
};
|
||||||
|
run_on_cpu(cs, do_spr_sync, &s);
|
||||||
|
}
|
||||||
|
|
||||||
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
|
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
|
||||||
target_ulong pte_index)
|
target_ulong pte_index)
|
||||||
{
|
{
|
||||||
@@ -110,16 +140,15 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
if (likely((flags & H_EXACT) == 0)) {
|
if (likely((flags & H_EXACT) == 0)) {
|
||||||
pte_index &= ~7ULL;
|
pte_index &= ~7ULL;
|
||||||
token = ppc_hash64_start_access(cpu, pte_index);
|
token = ppc_hash64_start_access(cpu, pte_index);
|
||||||
do {
|
for (; index < 8; index++) {
|
||||||
if (index == 8) {
|
|
||||||
ppc_hash64_stop_access(token);
|
|
||||||
return H_PTEG_FULL;
|
|
||||||
}
|
|
||||||
if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
|
if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (index++);
|
}
|
||||||
ppc_hash64_stop_access(token);
|
ppc_hash64_stop_access(token);
|
||||||
|
if (index == 8) {
|
||||||
|
return H_PTEG_FULL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
token = ppc_hash64_start_access(cpu, pte_index);
|
token = ppc_hash64_start_access(cpu, pte_index);
|
||||||
if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
|
if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
|
||||||
@@ -690,7 +719,7 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
target_ulong value2 = args[3];
|
target_ulong value2 = args[3];
|
||||||
target_ulong ret = H_P2;
|
target_ulong ret = H_P2;
|
||||||
|
|
||||||
if (resource == H_SET_MODE_ENDIAN) {
|
if (resource == H_SET_MODE_RESOURCE_LE) {
|
||||||
if (value1) {
|
if (value1) {
|
||||||
ret = H_P3;
|
ret = H_P3;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -699,22 +728,17 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
ret = H_P4;
|
ret = H_P4;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mflags) {
|
switch (mflags) {
|
||||||
case H_SET_MODE_ENDIAN_BIG:
|
case H_SET_MODE_ENDIAN_BIG:
|
||||||
CPU_FOREACH(cs) {
|
CPU_FOREACH(cs) {
|
||||||
PowerPCCPU *cp = POWERPC_CPU(cs);
|
set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
|
||||||
CPUPPCState *env = &cp->env;
|
|
||||||
env->spr[SPR_LPCR] &= ~LPCR_ILE;
|
|
||||||
}
|
}
|
||||||
ret = H_SUCCESS;
|
ret = H_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case H_SET_MODE_ENDIAN_LITTLE:
|
case H_SET_MODE_ENDIAN_LITTLE:
|
||||||
CPU_FOREACH(cs) {
|
CPU_FOREACH(cs) {
|
||||||
PowerPCCPU *cp = POWERPC_CPU(cs);
|
set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
|
||||||
CPUPPCState *env = &cp->env;
|
|
||||||
env->spr[SPR_LPCR] |= LPCR_ILE;
|
|
||||||
}
|
}
|
||||||
ret = H_SUCCESS;
|
ret = H_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
@@ -68,6 +68,7 @@ static void spapr_vio_bus_class_init(ObjectClass *klass, void *data)
|
|||||||
BusClass *k = BUS_CLASS(klass);
|
BusClass *k = BUS_CLASS(klass);
|
||||||
|
|
||||||
k->get_dev_path = spapr_vio_get_dev_name;
|
k->get_dev_path = spapr_vio_get_dev_name;
|
||||||
|
k->get_fw_dev_path = spapr_vio_get_dev_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo spapr_vio_bus_info = {
|
static const TypeInfo spapr_vio_bus_info = {
|
||||||
@@ -529,7 +530,9 @@ static int spapr_vio_bridge_init(SysBusDevice *dev)
|
|||||||
static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
|
static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->fw_name = "vdevice";
|
||||||
k->init = spapr_vio_bridge_init;
|
k->init = spapr_vio_bridge_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -71,7 +71,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
|||||||
|
|
||||||
tlb->attr = 0;
|
tlb->attr = 0;
|
||||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||||
tlb->size = 1 << 31; /* up to 0x80000000 */
|
tlb->size = 1U << 31; /* up to 0x80000000 */
|
||||||
tlb->EPN = va & TARGET_PAGE_MASK;
|
tlb->EPN = va & TARGET_PAGE_MASK;
|
||||||
tlb->RPN = pa & TARGET_PAGE_MASK;
|
tlb->RPN = pa & TARGET_PAGE_MASK;
|
||||||
tlb->PID = 0;
|
tlb->PID = 0;
|
||||||
@@ -79,7 +79,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
|||||||
tlb = &env->tlb.tlbe[1];
|
tlb = &env->tlb.tlbe[1];
|
||||||
tlb->attr = 0;
|
tlb->attr = 0;
|
||||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||||
tlb->size = 1 << 31; /* up to 0xffffffff */
|
tlb->size = 1U << 31; /* up to 0xffffffff */
|
||||||
tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
|
tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
|
||||||
tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
|
tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
|
||||||
tlb->PID = 0;
|
tlb->PID = 0;
|
||||||
|
@@ -80,7 +80,7 @@ static int s390_ipl_init(SysBusDevice *dev)
|
|||||||
|
|
||||||
bios_size = load_elf(bios_filename, NULL, NULL, &ipl->start_addr, NULL,
|
bios_size = load_elf(bios_filename, NULL, NULL, &ipl->start_addr, NULL,
|
||||||
NULL, 1, ELF_MACHINE, 0);
|
NULL, 1, ELF_MACHINE, 0);
|
||||||
if (bios_size == -1) {
|
if (bios_size < 0) {
|
||||||
bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
|
bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
|
||||||
4096);
|
4096);
|
||||||
ipl->start_addr = ZIPL_IMAGE_START;
|
ipl->start_addr = ZIPL_IMAGE_START;
|
||||||
|
@@ -313,7 +313,9 @@ static void s390_virtio_rng_instance_init(Object *obj)
|
|||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||||
(Object **)&dev->vdev.conf.rng, NULL);
|
(Object **)&dev->vdev.conf.rng,
|
||||||
|
qdev_prop_allow_set_link_before_realize,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
|
static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
|
||||||
|
@@ -25,13 +25,13 @@ typedef struct ConfigMgtData {
|
|||||||
uint8_t event_qualifier;
|
uint8_t event_qualifier;
|
||||||
} QEMU_PACKED ConfigMgtData;
|
} QEMU_PACKED ConfigMgtData;
|
||||||
|
|
||||||
static qemu_irq irq_cpu_hotplug; /* Only used in this file */
|
static qemu_irq *irq_cpu_hotplug; /* Only used in this file */
|
||||||
|
|
||||||
#define EVENT_QUAL_CPU_CHANGE 1
|
#define EVENT_QUAL_CPU_CHANGE 1
|
||||||
|
|
||||||
void raise_irq_cpu_hotplug(void)
|
void raise_irq_cpu_hotplug(void)
|
||||||
{
|
{
|
||||||
qemu_irq_raise(irq_cpu_hotplug);
|
qemu_irq_raise(*irq_cpu_hotplug);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int send_mask(void)
|
static unsigned int send_mask(void)
|
||||||
@@ -81,7 +81,7 @@ static void trigger_signal(void *opaque, int n, int level)
|
|||||||
|
|
||||||
static int irq_cpu_hotplug_init(SCLPEvent *event)
|
static int irq_cpu_hotplug_init(SCLPEvent *event)
|
||||||
{
|
{
|
||||||
irq_cpu_hotplug = *qemu_allocate_irqs(trigger_signal, event, 1);
|
irq_cpu_hotplug = qemu_allocate_irqs(trigger_signal, event, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1272,7 +1272,9 @@ static void virtio_ccw_rng_instance_init(Object *obj)
|
|||||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
||||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||||
(Object **)&dev->vdev.conf.rng, NULL);
|
(Object **)&dev->vdev.conf.rng,
|
||||||
|
qdev_prop_allow_set_link_before_realize,
|
||||||
|
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property virtio_ccw_rng_properties[] = {
|
static Property virtio_ccw_rng_properties[] = {
|
||||||
|
@@ -101,7 +101,6 @@ static void scsi_dma_restart_bh(void *opaque)
|
|||||||
scsi_req_continue(req);
|
scsi_req_continue(req);
|
||||||
break;
|
break;
|
||||||
case SCSI_XFER_NONE:
|
case SCSI_XFER_NONE:
|
||||||
assert(!req->sg);
|
|
||||||
scsi_req_dequeue(req);
|
scsi_req_dequeue(req);
|
||||||
scsi_req_enqueue(req);
|
scsi_req_enqueue(req);
|
||||||
break;
|
break;
|
||||||
@@ -1905,6 +1904,26 @@ static const VMStateInfo vmstate_info_scsi_requests = {
|
|||||||
.put = put_scsi_requests,
|
.put = put_scsi_requests,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool scsi_sense_state_needed(void *opaque)
|
||||||
|
{
|
||||||
|
SCSIDevice *s = opaque;
|
||||||
|
|
||||||
|
return s->sense_len > SCSI_SENSE_BUF_SIZE_OLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_scsi_sense_state = {
|
||||||
|
.name = "SCSIDevice/sense",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.fields = (VMStateField []) {
|
||||||
|
VMSTATE_UINT8_SUB_ARRAY(sense, SCSIDevice,
|
||||||
|
SCSI_SENSE_BUF_SIZE_OLD,
|
||||||
|
SCSI_SENSE_BUF_SIZE - SCSI_SENSE_BUF_SIZE_OLD),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_scsi_device = {
|
const VMStateDescription vmstate_scsi_device = {
|
||||||
.name = "SCSIDevice",
|
.name = "SCSIDevice",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
@@ -1915,7 +1934,7 @@ const VMStateDescription vmstate_scsi_device = {
|
|||||||
VMSTATE_UINT8(unit_attention.asc, SCSIDevice),
|
VMSTATE_UINT8(unit_attention.asc, SCSIDevice),
|
||||||
VMSTATE_UINT8(unit_attention.ascq, SCSIDevice),
|
VMSTATE_UINT8(unit_attention.ascq, SCSIDevice),
|
||||||
VMSTATE_BOOL(sense_is_ua, SCSIDevice),
|
VMSTATE_BOOL(sense_is_ua, SCSIDevice),
|
||||||
VMSTATE_UINT8_ARRAY(sense, SCSIDevice, SCSI_SENSE_BUF_SIZE),
|
VMSTATE_UINT8_SUB_ARRAY(sense, SCSIDevice, 0, SCSI_SENSE_BUF_SIZE_OLD),
|
||||||
VMSTATE_UINT32(sense_len, SCSIDevice),
|
VMSTATE_UINT32(sense_len, SCSIDevice),
|
||||||
{
|
{
|
||||||
.name = "requests",
|
.name = "requests",
|
||||||
@@ -1927,6 +1946,14 @@ const VMStateDescription vmstate_scsi_device = {
|
|||||||
.offset = 0,
|
.offset = 0,
|
||||||
},
|
},
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
.subsections = (VMStateSubsection []) {
|
||||||
|
{
|
||||||
|
.vmsd = &vmstate_scsi_sense_state,
|
||||||
|
.needed = scsi_sense_state_needed,
|
||||||
|
}, {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -195,9 +195,9 @@ static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
|
|||||||
req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
|
req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
req->crq.s.status = 0x99; /* Just needs to be non-zero */
|
req->crq.s.status = VIOSRP_OK;
|
||||||
} else {
|
} else {
|
||||||
req->crq.s.status = 0x00;
|
req->crq.s.status = VIOSRP_ADAPTER_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
|
rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
|
||||||
@@ -690,7 +690,7 @@ static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
|
|||||||
int rc, len, alen;
|
int rc, len, alen;
|
||||||
|
|
||||||
/* We dont do EVPD. Also check that page_code is 0 */
|
/* We dont do EVPD. Also check that page_code is 0 */
|
||||||
if ((cdb[1] & 0x01) || (cdb[1] & 0x01) || cdb[2] != 0) {
|
if ((cdb[1] & 0x01) || cdb[2] != 0) {
|
||||||
/* Send INVALID FIELD IN CDB */
|
/* Send INVALID FIELD IN CDB */
|
||||||
vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
|
vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
|
||||||
vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
|
vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
|
||||||
|
@@ -304,6 +304,8 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
|||||||
size_t resid)
|
size_t resid)
|
||||||
{
|
{
|
||||||
VirtIOSCSIReq *req = r->hba_private;
|
VirtIOSCSIReq *req = r->hba_private;
|
||||||
|
VirtIOSCSI *s = req->dev;
|
||||||
|
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||||
uint32_t sense_len;
|
uint32_t sense_len;
|
||||||
|
|
||||||
if (r->io_canceled) {
|
if (r->io_canceled) {
|
||||||
@@ -317,7 +319,7 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
|||||||
} else {
|
} else {
|
||||||
req->resp.cmd->resid = 0;
|
req->resp.cmd->resid = 0;
|
||||||
sense_len = scsi_req_get_sense(r, req->resp.cmd->sense,
|
sense_len = scsi_req_get_sense(r, req->resp.cmd->sense,
|
||||||
VIRTIO_SCSI_SENSE_SIZE);
|
vs->sense_size);
|
||||||
req->resp.cmd->sense_len = tswap32(sense_len);
|
req->resp.cmd->sense_len = tswap32(sense_len);
|
||||||
}
|
}
|
||||||
virtio_scsi_complete_req(req);
|
virtio_scsi_complete_req(req);
|
||||||
|
@@ -479,12 +479,13 @@ static void
|
|||||||
pvscsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
|
pvscsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
|
||||||
{
|
{
|
||||||
PVSCSIRequest *pvscsi_req = req->hba_private;
|
PVSCSIRequest *pvscsi_req = req->hba_private;
|
||||||
PVSCSIState *s = pvscsi_req->dev;
|
PVSCSIState *s;
|
||||||
|
|
||||||
if (!pvscsi_req) {
|
if (!pvscsi_req) {
|
||||||
trace_pvscsi_command_complete_not_found(req->tag);
|
trace_pvscsi_command_complete_not_found(req->tag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
s = pvscsi_req->dev;
|
||||||
|
|
||||||
if (resid) {
|
if (resid) {
|
||||||
/* Short transfer. */
|
/* Short transfer. */
|
||||||
|
@@ -106,9 +106,9 @@ static void grlib_gptimer_enable(GPTimer *timer)
|
|||||||
/* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
|
/* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
|
||||||
underflow. Set count + 1 to simulate the GPTimer behavior. */
|
underflow. Set count + 1 to simulate the GPTimer behavior. */
|
||||||
|
|
||||||
trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
|
trace_grlib_gptimer_enable(timer->id, timer->counter);
|
||||||
|
|
||||||
ptimer_set_count(timer->ptimer, timer->counter + 1);
|
ptimer_set_count(timer->ptimer, (uint64_t)timer->counter + 1);
|
||||||
ptimer_run(timer->ptimer, 1);
|
ptimer_run(timer->ptimer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +328,6 @@ static void grlib_gptimer_reset(DeviceState *d)
|
|||||||
|
|
||||||
unit->scaler = 0;
|
unit->scaler = 0;
|
||||||
unit->reload = 0;
|
unit->reload = 0;
|
||||||
unit->config = 0;
|
|
||||||
|
|
||||||
unit->config = unit->nr_timers;
|
unit->config = unit->nr_timers;
|
||||||
unit->config |= unit->irq_line << 3;
|
unit->config |= unit->irq_line << 3;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user