Compare commits
239 Commits
v2.8.1
...
master-201
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b44486dfb9 | ||
|
|
41a0e54756 | ||
|
|
e934644126 | ||
|
|
f27ff81070 | ||
|
|
97efe4f961 | ||
|
|
c952b71582 | ||
|
|
6250dff39a | ||
|
|
d825367172 | ||
|
|
f29b3431f6 | ||
|
|
b3cb21b9b5 | ||
|
|
a8ffb372a2 | ||
|
|
3d4da9d6f3 | ||
|
|
987da7be99 | ||
|
|
e1a58fc05a | ||
|
|
80db0e7822 | ||
|
|
c9c0854580 | ||
|
|
d1957dac34 | ||
|
|
8b35ab271c | ||
|
|
8dfba500af | ||
|
|
75ff0f0c90 | ||
|
|
a2088da36e | ||
|
|
4462fc604a | ||
|
|
a93e599d4a | ||
|
|
45a368ad4f | ||
|
|
c5f048d8fb | ||
|
|
283e2c2adc | ||
|
|
54e17709ac | ||
|
|
aa94d52142 | ||
|
|
312d3b3534 | ||
|
|
f2fd57db36 | ||
|
|
e66bcc4081 | ||
|
|
f18c697b55 | ||
|
|
33848ceed7 | ||
|
|
02ed3e7c16 | ||
|
|
ef69d971cd | ||
|
|
b89f8c80cc | ||
|
|
305f5131ac | ||
|
|
6138dbda5a | ||
|
|
46fd170545 | ||
|
|
c159a4d1d0 | ||
|
|
2e41dfe152 | ||
|
|
12d37882f0 | ||
|
|
efcd38c529 | ||
|
|
bd2baaccd5 | ||
|
|
615c4ed205 | ||
|
|
554f5e1604 | ||
|
|
052c8fa998 | ||
|
|
2d3fc5816e | ||
|
|
e0a3c8ccaa | ||
|
|
8607f5c307 | ||
|
|
a08aaff811 | ||
|
|
8cdcf3c1e5 | ||
|
|
f37bc03623 | ||
|
|
f634151b02 | ||
|
|
77424a452a | ||
|
|
dba5c337c8 | ||
|
|
c1bb86cd8a | ||
|
|
2e6fc7eb1a | ||
|
|
44b6789299 | ||
|
|
7c3a998531 | ||
|
|
7c37f941d0 | ||
|
|
a7e159025e | ||
|
|
6847da3808 | ||
|
|
dee66e2882 | ||
|
|
7cd9b3964e | ||
|
|
0f31977d9d | ||
|
|
ce15dc08ef | ||
|
|
10c8551968 | ||
|
|
536fca7f7e | ||
|
|
4baaa8c3d8 | ||
|
|
8305f9bdf7 | ||
|
|
556899fc19 | ||
|
|
24cb2e0d57 | ||
|
|
8dd845d3c4 | ||
|
|
af1f60a402 | ||
|
|
4dad9e7478 | ||
|
|
da4f09a7dc | ||
|
|
e9a8e474fb | ||
|
|
a72d436387 | ||
|
|
d05fdab46d | ||
|
|
054f4dc961 | ||
|
|
055a7f2b0a | ||
|
|
0127937b20 | ||
|
|
8c92c6a43e | ||
|
|
aca4bbf4a3 | ||
|
|
6e2ed65f4a | ||
|
|
330afe0599 | ||
|
|
156bc9a5ea | ||
|
|
c8ef2bda05 | ||
|
|
9ac4ef77c1 | ||
|
|
5b982482c1 | ||
|
|
d307c28ca9 | ||
|
|
f68808c749 | ||
|
|
f0d703314e | ||
|
|
999b941633 | ||
|
|
98d690761a | ||
|
|
0973b1cff8 | ||
|
|
32b69707df | ||
|
|
2294d05dab | ||
|
|
7f54eaa3b7 | ||
|
|
0119b1927d | ||
|
|
57a701fc2b | ||
|
|
bb08afe9f0 | ||
|
|
ffe22bf510 | ||
|
|
a01b1e9a00 | ||
|
|
7e354ed4df | ||
|
|
30a3e70167 | ||
|
|
646c5478c0 | ||
|
|
e92fbc753d | ||
|
|
9c904a7581 | ||
|
|
12597061b3 | ||
|
|
5e5db49953 | ||
|
|
82a4118694 | ||
|
|
a7c8215e3b | ||
|
|
684e508c23 | ||
|
|
aff8fd18f1 | ||
|
|
23425cc2b7 | ||
|
|
9ef9d40261 | ||
|
|
0d9d86fb4d | ||
|
|
ee68697551 | ||
|
|
0062ea0fd6 | ||
|
|
4a1cba3802 | ||
|
|
f6a51c84cd | ||
|
|
721671ade7 | ||
|
|
0891ee1112 | ||
|
|
a37c07022b | ||
|
|
ba0d10378c | ||
|
|
04b88c84a1 | ||
|
|
5c3df1f096 | ||
|
|
6cc9906b4c | ||
|
|
baecbde6d7 | ||
|
|
1211d81b17 | ||
|
|
d5ebc8272b | ||
|
|
f2b58c4375 | ||
|
|
88da0b0301 | ||
|
|
bcb8998fac | ||
|
|
ea83441cc4 | ||
|
|
583f21f8b9 | ||
|
|
204f01b309 | ||
|
|
33243031da | ||
|
|
b8e23926c5 | ||
|
|
dbe2b65566 | ||
|
|
2b5e217067 | ||
|
|
0194cf31cf | ||
|
|
367790cce8 | ||
|
|
72d2e4b6a4 | ||
|
|
7b542eb96d | ||
|
|
14f944063a | ||
|
|
fb5543d820 | ||
|
|
0ccb9c1d81 | ||
|
|
8be95defd6 | ||
|
|
817af1c72d | ||
|
|
f84aab269d | ||
|
|
8a1e52b69d | ||
|
|
0f72559fbc | ||
|
|
91db4642f8 | ||
|
|
9e41bade85 | ||
|
|
8e953a658f | ||
|
|
26d5df9578 | ||
|
|
0584d3c33f | ||
|
|
c491e1521f | ||
|
|
bd407a21a9 | ||
|
|
6efbac908f | ||
|
|
74af4eec29 | ||
|
|
ef17f83661 | ||
|
|
6a0e947b12 | ||
|
|
bd673bd8ab | ||
|
|
4c3386f421 | ||
|
|
2d105bd6b5 | ||
|
|
e03192fd62 | ||
|
|
e353aac51b | ||
|
|
0bfa02595a | ||
|
|
e971fa0422 | ||
|
|
c9b61d9aa1 | ||
|
|
92204403ef | ||
|
|
0a97c40f8e | ||
|
|
416d72b97b | ||
|
|
0f1944735b | ||
|
|
2494c9f640 | ||
|
|
450aaae863 | ||
|
|
e5fdf663cf | ||
|
|
48ae36c0ad | ||
|
|
d7a2127a4c | ||
|
|
eaa5740304 | ||
|
|
465f2fedd2 | ||
|
|
e45d4ef6e3 | ||
|
|
65839b56b9 | ||
|
|
a470b33259 | ||
|
|
c76904ef2f | ||
|
|
6c7c3c21f9 | ||
|
|
c52ab08aee | ||
|
|
6053a86fe7 | ||
|
|
bc20403598 | ||
|
|
166dbda7e1 | ||
|
|
8929fc3a55 | ||
|
|
96a3d39277 | ||
|
|
e3592bc9d8 | ||
|
|
feddd2fd91 | ||
|
|
272f042877 | ||
|
|
be232eb076 | ||
|
|
638cbd452d | ||
|
|
722f8d9099 | ||
|
|
11717bc93a | ||
|
|
45241cf9d7 | ||
|
|
8caa05d889 | ||
|
|
e7a9f35321 | ||
|
|
c17a18ef30 | ||
|
|
a273f4cedf | ||
|
|
5ffb350541 | ||
|
|
eb7a20a361 | ||
|
|
1f4e496e1f | ||
|
|
715c31ec8e | ||
|
|
0ce265ffef | ||
|
|
2651efe7f5 | ||
|
|
225adf16d2 | ||
|
|
4fd460bf25 | ||
|
|
f4d7674722 | ||
|
|
e11680524a | ||
|
|
5ce9cfe737 | ||
|
|
12a4f2162a | ||
|
|
1f923c70bd | ||
|
|
d1e8e8ecc3 | ||
|
|
ffb7bf452a | ||
|
|
d4c64800bb | ||
|
|
9443598d7e | ||
|
|
893dcdbfa9 | ||
|
|
fcf5ef2ab5 | ||
|
|
82ecffa8c0 | ||
|
|
9b7621bca2 | ||
|
|
abd7f08b23 | ||
|
|
2858bc6870 | ||
|
|
d93ddfb1f8 | ||
|
|
d9429b84af | ||
|
|
e10e798c85 | ||
|
|
7b2e5c65f4 | ||
|
|
98206d4e6b | ||
|
|
9652f5785e | ||
|
|
4e4212d056 | ||
|
|
3d1ad18c42 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -82,10 +82,6 @@
|
||||
*.d
|
||||
!/scripts/qemu-guest-agent/fsfreeze-hook.d
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.pc
|
||||
.libs
|
||||
.sdk
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
||||
18
HACKING
18
HACKING
@@ -1,10 +1,28 @@
|
||||
1. Preprocessor
|
||||
|
||||
1.1. Variadic macros
|
||||
|
||||
For variadic macros, stick with this C99-like syntax:
|
||||
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0)
|
||||
|
||||
1.2. Include directives
|
||||
|
||||
Order include directives as follows:
|
||||
|
||||
#include "qemu/osdep.h" /* Always first... */
|
||||
#include <...> /* then system headers... */
|
||||
#include "..." /* and finally QEMU headers. */
|
||||
|
||||
The "qemu/osdep.h" header contains preprocessor macros that affect the behavior
|
||||
of core system headers like <stdint.h>. It must be the first include so that
|
||||
core system headers included by external libraries get the preprocessor macros
|
||||
that QEMU depends on.
|
||||
|
||||
Do not include "qemu/osdep.h" from header files since the .c file will have
|
||||
already included it.
|
||||
|
||||
2. C types
|
||||
|
||||
It should be common sense to use the right type, but we have collected
|
||||
|
||||
56
MAINTAINERS
56
MAINTAINERS
@@ -106,7 +106,7 @@ F: include/fpu/
|
||||
Alpha
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
F: target-alpha/
|
||||
F: target/alpha/
|
||||
F: hw/alpha/
|
||||
F: tests/tcg/alpha/
|
||||
F: disas/alpha.c
|
||||
@@ -115,7 +115,7 @@ ARM
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: target-arm/
|
||||
F: target/arm/
|
||||
F: hw/arm/
|
||||
F: hw/cpu/a*mpcore.c
|
||||
F: include/hw/cpu/a*mpcore.h
|
||||
@@ -126,7 +126,7 @@ F: disas/libvixl/
|
||||
CRIS
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
S: Maintained
|
||||
F: target-cris/
|
||||
F: target/cris/
|
||||
F: hw/cris/
|
||||
F: include/hw/cris/
|
||||
F: tests/tcg/cris/
|
||||
@@ -135,7 +135,7 @@ F: disas/cris.c
|
||||
LM32
|
||||
M: Michael Walle <michael@walle.cc>
|
||||
S: Maintained
|
||||
F: target-lm32/
|
||||
F: target/lm32/
|
||||
F: disas/lm32.c
|
||||
F: hw/lm32/
|
||||
F: hw/*/lm32_*
|
||||
@@ -147,13 +147,13 @@ F: tests/tcg/lm32/
|
||||
M68K
|
||||
M: Laurent Vivier <laurent@vivier.eu>
|
||||
S: Maintained
|
||||
F: target-m68k/
|
||||
F: target/m68k/
|
||||
F: disas/m68k.c
|
||||
|
||||
MicroBlaze
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
S: Maintained
|
||||
F: target-microblaze/
|
||||
F: target/microblaze/
|
||||
F: hw/microblaze/
|
||||
F: disas/microblaze.c
|
||||
|
||||
@@ -161,7 +161,7 @@ MIPS
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
M: Yongbok Kim <yongbok.kim@imgtec.com>
|
||||
S: Maintained
|
||||
F: target-mips/
|
||||
F: target/mips/
|
||||
F: hw/mips/
|
||||
F: hw/misc/mips_*
|
||||
F: hw/intc/mips_gic.c
|
||||
@@ -176,7 +176,7 @@ F: disas/mips.c
|
||||
Moxie
|
||||
M: Anthony Green <green@moxielogic.com>
|
||||
S: Maintained
|
||||
F: target-moxie/
|
||||
F: target/moxie/
|
||||
F: disas/moxie.c
|
||||
F: hw/moxie/
|
||||
F: default-configs/moxie-softmmu.mak
|
||||
@@ -184,7 +184,7 @@ F: default-configs/moxie-softmmu.mak
|
||||
OpenRISC
|
||||
M: Jia Liu <proljc@gmail.com>
|
||||
S: Maintained
|
||||
F: target-openrisc/
|
||||
F: target/openrisc/
|
||||
F: hw/openrisc/
|
||||
F: tests/tcg/openrisc/
|
||||
|
||||
@@ -193,7 +193,7 @@ M: David Gibson <david@gibson.dropbear.id.au>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Maintained
|
||||
F: target-ppc/
|
||||
F: target/ppc/
|
||||
F: hw/ppc/
|
||||
F: include/hw/ppc/
|
||||
F: disas/ppc.c
|
||||
@@ -202,14 +202,14 @@ S390
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: target-s390x/
|
||||
F: target/s390x/
|
||||
F: hw/s390x/
|
||||
F: disas/s390.c
|
||||
|
||||
SH4
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
S: Odd Fixes
|
||||
F: target-sh4/
|
||||
F: target/sh4/
|
||||
F: hw/sh4/
|
||||
F: disas/sh4.c
|
||||
F: include/hw/sh4/
|
||||
@@ -218,7 +218,7 @@ SPARC
|
||||
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
|
||||
M: Artyom Tarasenko <atar4qemu@gmail.com>
|
||||
S: Maintained
|
||||
F: target-sparc/
|
||||
F: target/sparc/
|
||||
F: hw/sparc/
|
||||
F: hw/sparc64/
|
||||
F: disas/sparc.c
|
||||
@@ -226,7 +226,7 @@ F: disas/sparc.c
|
||||
UniCore32
|
||||
M: Guan Xuetao <gxt@mprc.pku.edu.cn>
|
||||
S: Maintained
|
||||
F: target-unicore32/
|
||||
F: target/unicore32/
|
||||
F: hw/unicore32/
|
||||
F: include/hw/unicore32/
|
||||
|
||||
@@ -235,7 +235,7 @@ M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
S: Maintained
|
||||
F: target-i386/
|
||||
F: target/i386/
|
||||
F: hw/i386/
|
||||
F: disas/i386.c
|
||||
|
||||
@@ -243,14 +243,14 @@ Xtensa
|
||||
M: Max Filippov <jcmvbkbc@gmail.com>
|
||||
W: http://wiki.osll.spb.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
|
||||
S: Maintained
|
||||
F: target-xtensa/
|
||||
F: target/xtensa/
|
||||
F: hw/xtensa/
|
||||
F: tests/tcg/xtensa/
|
||||
|
||||
TriCore
|
||||
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
|
||||
S: Maintained
|
||||
F: target-tricore/
|
||||
F: target/tricore/
|
||||
F: hw/tricore/
|
||||
F: include/hw/tricore/
|
||||
|
||||
@@ -269,26 +269,26 @@ ARM
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: target-arm/kvm.c
|
||||
F: target/arm/kvm.c
|
||||
|
||||
MIPS
|
||||
M: James Hogan <james.hogan@imgtec.com>
|
||||
S: Maintained
|
||||
F: target-mips/kvm.c
|
||||
F: target/mips/kvm.c
|
||||
|
||||
PPC
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: target-ppc/kvm.c
|
||||
F: target/ppc/kvm.c
|
||||
|
||||
S390
|
||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: target-s390x/kvm.c
|
||||
F: target-s390x/ioinst.[ch]
|
||||
F: target-s390x/machine.c
|
||||
F: target/s390x/kvm.c
|
||||
F: target/s390x/ioinst.[ch]
|
||||
F: target/s390x/machine.c
|
||||
F: hw/intc/s390_flic.c
|
||||
F: hw/intc/s390_flic_kvm.c
|
||||
F: include/hw/s390x/s390_flic.h
|
||||
@@ -301,7 +301,7 @@ M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
S: Supported
|
||||
F: target-i386/kvm.c
|
||||
F: target/i386/kvm.c
|
||||
|
||||
Guest CPU Cores (Xen):
|
||||
----------------------
|
||||
@@ -508,7 +508,6 @@ M: Shannon Zhao <shannon.zhao@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
F: include/hw/arm/virt-acpi-build.h
|
||||
|
||||
STM32F205
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
@@ -885,7 +884,6 @@ F: hw/acpi/*
|
||||
F: hw/smbios/*
|
||||
F: hw/i386/acpi-build.[hc]
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
F: include/hw/arm/virt-acpi-build.h
|
||||
|
||||
ppc4xx
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
@@ -1720,9 +1718,9 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/linux-aio.c
|
||||
F: include/block/raw-aio.h
|
||||
F: block/raw-posix.c
|
||||
F: block/raw-win32.c
|
||||
F: block/raw_bsd.c
|
||||
F: block/raw-format.c
|
||||
F: block/file-posix.c
|
||||
F: block/file-win32.c
|
||||
F: block/win32-aio.c
|
||||
|
||||
qcow2
|
||||
|
||||
10
Makefile
10
Makefile
@@ -149,6 +149,7 @@ dummy := $(call unnest-vars,, \
|
||||
qga-obj-y \
|
||||
ivshmem-client-obj-y \
|
||||
ivshmem-server-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
@@ -231,12 +232,10 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
|
||||
|
||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
||||
|
||||
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h | $(BUILD_DIR)/version.lo
|
||||
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h
|
||||
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o")
|
||||
$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc config-host.h
|
||||
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.lo")
|
||||
|
||||
Makefile: $(version-obj-y) $(version-lobj-y)
|
||||
Makefile: $(version-obj-y)
|
||||
|
||||
######################################################################
|
||||
# Build libraries
|
||||
@@ -358,10 +357,9 @@ clean:
|
||||
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 *.msi
|
||||
find . \( -name '*.l[oa]' -o -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||
find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||
rm -f fsdev/*.pod
|
||||
rm -rf .libs */.libs
|
||||
rm -f qemu-img-cmds.h
|
||||
rm -f ui/shader/*-vert.h ui/shader/*-frag.h
|
||||
@# May not be present in GENERATED_HEADERS
|
||||
|
||||
@@ -97,7 +97,6 @@ common-obj-y += disas/
|
||||
######################################################################
|
||||
# Resource file for Windows executables
|
||||
version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o
|
||||
version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo
|
||||
|
||||
######################################################################
|
||||
# tracing
|
||||
@@ -116,7 +115,7 @@ qga-vss-dll-obj-y = qga/
|
||||
# contrib
|
||||
ivshmem-client-obj-y = contrib/ivshmem-client/
|
||||
ivshmem-server-obj-y = contrib/ivshmem-server/
|
||||
|
||||
libvhost-user-obj-y = contrib/libvhost-user/
|
||||
|
||||
######################################################################
|
||||
trace-events-y = trace-events
|
||||
@@ -155,11 +154,11 @@ trace-events-y += hw/alpha/trace-events
|
||||
trace-events-y += ui/trace-events
|
||||
trace-events-y += audio/trace-events
|
||||
trace-events-y += net/trace-events
|
||||
trace-events-y += target-arm/trace-events
|
||||
trace-events-y += target-i386/trace-events
|
||||
trace-events-y += target-sparc/trace-events
|
||||
trace-events-y += target-s390x/trace-events
|
||||
trace-events-y += target-ppc/trace-events
|
||||
trace-events-y += target/arm/trace-events
|
||||
trace-events-y += target/i386/trace-events
|
||||
trace-events-y += target/sparc/trace-events
|
||||
trace-events-y += target/s390x/trace-events
|
||||
trace-events-y += target/ppc/trace-events
|
||||
trace-events-y += qom/trace-events
|
||||
trace-events-y += linux-user/trace-events
|
||||
trace-events-y += qapi/trace-events
|
||||
|
||||
@@ -11,7 +11,7 @@ $(call set-vpath, $(SRC_PATH):$(BUILD_DIR))
|
||||
ifdef CONFIG_LINUX
|
||||
QEMU_CFLAGS += -I../linux-headers
|
||||
endif
|
||||
QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -DNEED_CPU_H
|
||||
QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target/$(TARGET_BASE_ARCH) -DNEED_CPU_H
|
||||
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/include
|
||||
|
||||
@@ -76,6 +76,7 @@ $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all
|
||||
else
|
||||
stap:
|
||||
endif
|
||||
.PHONY: stap
|
||||
|
||||
all: $(PROGS) stap
|
||||
|
||||
@@ -92,7 +93,7 @@ obj-$(CONFIG_TCG_INTERPRETER) += tci.o
|
||||
obj-y += tcg/tcg-common.o
|
||||
obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
|
||||
obj-y += fpu/softfloat.o
|
||||
obj-y += target-$(TARGET_BASE_ARCH)/
|
||||
obj-y += target/$(TARGET_BASE_ARCH)/
|
||||
obj-y += disas.o
|
||||
obj-y += tcg-runtime.o
|
||||
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
|
||||
|
||||
312
aio-posix.c
312
aio-posix.c
@@ -18,6 +18,8 @@
|
||||
#include "block/block.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "trace.h"
|
||||
#ifdef CONFIG_EPOLL_CREATE1
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
@@ -27,6 +29,9 @@ struct AioHandler
|
||||
GPollFD pfd;
|
||||
IOHandler *io_read;
|
||||
IOHandler *io_write;
|
||||
AioPollFn *io_poll;
|
||||
IOHandler *io_poll_begin;
|
||||
IOHandler *io_poll_end;
|
||||
int deleted;
|
||||
void *opaque;
|
||||
bool is_external;
|
||||
@@ -200,6 +205,7 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
bool is_external,
|
||||
IOHandler *io_read,
|
||||
IOHandler *io_write,
|
||||
AioPollFn *io_poll,
|
||||
void *opaque)
|
||||
{
|
||||
AioHandler *node;
|
||||
@@ -209,7 +215,7 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
node = find_aio_handler(ctx, fd);
|
||||
|
||||
/* Are we deleting the fd handler? */
|
||||
if (!io_read && !io_write) {
|
||||
if (!io_read && !io_write && !io_poll) {
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -228,6 +234,10 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
QLIST_REMOVE(node, node);
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
if (!node->io_poll) {
|
||||
ctx->poll_disable_cnt--;
|
||||
}
|
||||
} else {
|
||||
if (node == NULL) {
|
||||
/* Alloc and insert if it's not already there */
|
||||
@@ -237,10 +247,16 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
|
||||
g_source_add_poll(&ctx->source, &node->pfd);
|
||||
is_new = true;
|
||||
|
||||
ctx->poll_disable_cnt += !io_poll;
|
||||
} else {
|
||||
ctx->poll_disable_cnt += !io_poll - !node->io_poll;
|
||||
}
|
||||
|
||||
/* Update handler with latest information */
|
||||
node->io_read = io_read;
|
||||
node->io_write = io_write;
|
||||
node->io_poll = io_poll;
|
||||
node->opaque = opaque;
|
||||
node->is_external = is_external;
|
||||
|
||||
@@ -250,22 +266,83 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
|
||||
aio_epoll_update(ctx, node, is_new);
|
||||
aio_notify(ctx);
|
||||
|
||||
if (deleted) {
|
||||
g_free(node);
|
||||
}
|
||||
}
|
||||
|
||||
void aio_set_fd_poll(AioContext *ctx, int fd,
|
||||
IOHandler *io_poll_begin,
|
||||
IOHandler *io_poll_end)
|
||||
{
|
||||
AioHandler *node = find_aio_handler(ctx, fd);
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->io_poll_begin = io_poll_begin;
|
||||
node->io_poll_end = io_poll_end;
|
||||
}
|
||||
|
||||
void aio_set_event_notifier(AioContext *ctx,
|
||||
EventNotifier *notifier,
|
||||
bool is_external,
|
||||
EventNotifierHandler *io_read)
|
||||
EventNotifierHandler *io_read,
|
||||
AioPollFn *io_poll)
|
||||
{
|
||||
aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
|
||||
is_external, (IOHandler *)io_read, NULL, notifier);
|
||||
aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), is_external,
|
||||
(IOHandler *)io_read, NULL, io_poll, notifier);
|
||||
}
|
||||
|
||||
void aio_set_event_notifier_poll(AioContext *ctx,
|
||||
EventNotifier *notifier,
|
||||
EventNotifierHandler *io_poll_begin,
|
||||
EventNotifierHandler *io_poll_end)
|
||||
{
|
||||
aio_set_fd_poll(ctx, event_notifier_get_fd(notifier),
|
||||
(IOHandler *)io_poll_begin,
|
||||
(IOHandler *)io_poll_end);
|
||||
}
|
||||
|
||||
static void poll_set_started(AioContext *ctx, bool started)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
if (started == ctx->poll_started) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->poll_started = started;
|
||||
|
||||
ctx->walking_handlers++;
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
IOHandler *fn;
|
||||
|
||||
if (node->deleted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (started) {
|
||||
fn = node->io_poll_begin;
|
||||
} else {
|
||||
fn = node->io_poll_end;
|
||||
}
|
||||
|
||||
if (fn) {
|
||||
fn(node->opaque);
|
||||
}
|
||||
}
|
||||
ctx->walking_handlers--;
|
||||
}
|
||||
|
||||
|
||||
bool aio_prepare(AioContext *ctx)
|
||||
{
|
||||
/* Poll mode cannot be used with glib's event loop, disable it. */
|
||||
poll_set_started(ctx, false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -290,9 +367,13 @@ bool aio_pending(AioContext *ctx)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool aio_dispatch(AioContext *ctx)
|
||||
/*
|
||||
* Note that dispatch_fds == false has the side-effect of post-poning the
|
||||
* freeing of deleted handlers.
|
||||
*/
|
||||
bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
|
||||
{
|
||||
AioHandler *node;
|
||||
AioHandler *node = NULL;
|
||||
bool progress = false;
|
||||
|
||||
/*
|
||||
@@ -308,7 +389,9 @@ bool aio_dispatch(AioContext *ctx)
|
||||
* We have to walk very carefully in case aio_set_fd_handler is
|
||||
* called while we're walking.
|
||||
*/
|
||||
node = QLIST_FIRST(&ctx->aio_handlers);
|
||||
if (dispatch_fds) {
|
||||
node = QLIST_FIRST(&ctx->aio_handlers);
|
||||
}
|
||||
while (node) {
|
||||
AioHandler *tmp;
|
||||
int revents;
|
||||
@@ -400,12 +483,100 @@ static void add_pollfd(AioHandler *node)
|
||||
npfd++;
|
||||
}
|
||||
|
||||
static bool run_poll_handlers_once(AioContext *ctx)
|
||||
{
|
||||
bool progress = false;
|
||||
AioHandler *node;
|
||||
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
if (!node->deleted && node->io_poll &&
|
||||
node->io_poll(node->opaque)) {
|
||||
progress = true;
|
||||
}
|
||||
|
||||
/* Caller handles freeing deleted nodes. Don't do it here. */
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* run_poll_handlers:
|
||||
* @ctx: the AioContext
|
||||
* @max_ns: maximum time to poll for, in nanoseconds
|
||||
*
|
||||
* Polls for a given time.
|
||||
*
|
||||
* Note that ctx->notify_me must be non-zero so this function can detect
|
||||
* aio_notify().
|
||||
*
|
||||
* Note that the caller must have incremented ctx->walking_handlers.
|
||||
*
|
||||
* Returns: true if progress was made, false otherwise
|
||||
*/
|
||||
static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
|
||||
{
|
||||
bool progress;
|
||||
int64_t end_time;
|
||||
|
||||
assert(ctx->notify_me);
|
||||
assert(ctx->walking_handlers > 0);
|
||||
assert(ctx->poll_disable_cnt == 0);
|
||||
|
||||
trace_run_poll_handlers_begin(ctx, max_ns);
|
||||
|
||||
end_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + max_ns;
|
||||
|
||||
do {
|
||||
progress = run_poll_handlers_once(ctx);
|
||||
} while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time);
|
||||
|
||||
trace_run_poll_handlers_end(ctx, progress);
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* try_poll_mode:
|
||||
* @ctx: the AioContext
|
||||
* @blocking: busy polling is only attempted when blocking is true
|
||||
*
|
||||
* ctx->notify_me must be non-zero so this function can detect aio_notify().
|
||||
*
|
||||
* Note that the caller must have incremented ctx->walking_handlers.
|
||||
*
|
||||
* Returns: true if progress was made, false otherwise
|
||||
*/
|
||||
static bool try_poll_mode(AioContext *ctx, bool blocking)
|
||||
{
|
||||
if (blocking && ctx->poll_max_ns && ctx->poll_disable_cnt == 0) {
|
||||
/* See qemu_soonest_timeout() uint64_t hack */
|
||||
int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx),
|
||||
(uint64_t)ctx->poll_ns);
|
||||
|
||||
if (max_ns) {
|
||||
poll_set_started(ctx, true);
|
||||
|
||||
if (run_poll_handlers(ctx, max_ns)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
poll_set_started(ctx, false);
|
||||
|
||||
/* Even if we don't run busy polling, try polling once in case it can make
|
||||
* progress and the caller will be able to avoid ppoll(2)/epoll_wait(2).
|
||||
*/
|
||||
return run_poll_handlers_once(ctx);
|
||||
}
|
||||
|
||||
bool aio_poll(AioContext *ctx, bool blocking)
|
||||
{
|
||||
AioHandler *node;
|
||||
int i, ret;
|
||||
int i;
|
||||
int ret = 0;
|
||||
bool progress;
|
||||
int64_t timeout;
|
||||
int64_t start = 0;
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
progress = false;
|
||||
@@ -423,41 +594,91 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
|
||||
ctx->walking_handlers++;
|
||||
|
||||
assert(npfd == 0);
|
||||
if (ctx->poll_max_ns) {
|
||||
start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
}
|
||||
|
||||
/* fill pollfds */
|
||||
if (try_poll_mode(ctx, blocking)) {
|
||||
progress = true;
|
||||
} else {
|
||||
assert(npfd == 0);
|
||||
|
||||
if (!aio_epoll_enabled(ctx)) {
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
if (!node->deleted && node->pfd.events
|
||||
&& aio_node_check(ctx, node->is_external)) {
|
||||
add_pollfd(node);
|
||||
/* fill pollfds */
|
||||
|
||||
if (!aio_epoll_enabled(ctx)) {
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
if (!node->deleted && node->pfd.events
|
||||
&& aio_node_check(ctx, node->is_external)) {
|
||||
add_pollfd(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timeout = blocking ? aio_compute_timeout(ctx) : 0;
|
||||
|
||||
/* wait until next event */
|
||||
if (timeout) {
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
if (aio_epoll_check_poll(ctx, pollfds, npfd, timeout)) {
|
||||
AioHandler epoll_handler;
|
||||
|
||||
epoll_handler.pfd.fd = ctx->epollfd;
|
||||
epoll_handler.pfd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR;
|
||||
npfd = 0;
|
||||
add_pollfd(&epoll_handler);
|
||||
ret = aio_epoll(ctx, pollfds, npfd, timeout);
|
||||
} else {
|
||||
ret = qemu_poll_ns(pollfds, npfd, timeout);
|
||||
}
|
||||
if (timeout) {
|
||||
aio_context_acquire(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
timeout = blocking ? aio_compute_timeout(ctx) : 0;
|
||||
|
||||
/* wait until next event */
|
||||
if (timeout) {
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
if (aio_epoll_check_poll(ctx, pollfds, npfd, timeout)) {
|
||||
AioHandler epoll_handler;
|
||||
|
||||
epoll_handler.pfd.fd = ctx->epollfd;
|
||||
epoll_handler.pfd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR;
|
||||
npfd = 0;
|
||||
add_pollfd(&epoll_handler);
|
||||
ret = aio_epoll(ctx, pollfds, npfd, timeout);
|
||||
} else {
|
||||
ret = qemu_poll_ns(pollfds, npfd, timeout);
|
||||
}
|
||||
if (blocking) {
|
||||
atomic_sub(&ctx->notify_me, 2);
|
||||
}
|
||||
if (timeout) {
|
||||
aio_context_acquire(ctx);
|
||||
|
||||
/* Adjust polling time */
|
||||
if (ctx->poll_max_ns) {
|
||||
int64_t block_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start;
|
||||
|
||||
if (block_ns <= ctx->poll_ns) {
|
||||
/* This is the sweet spot, no adjustment needed */
|
||||
} else if (block_ns > ctx->poll_max_ns) {
|
||||
/* We'd have to poll for too long, poll less */
|
||||
int64_t old = ctx->poll_ns;
|
||||
|
||||
if (ctx->poll_shrink) {
|
||||
ctx->poll_ns /= ctx->poll_shrink;
|
||||
} else {
|
||||
ctx->poll_ns = 0;
|
||||
}
|
||||
|
||||
trace_poll_shrink(ctx, old, ctx->poll_ns);
|
||||
} else if (ctx->poll_ns < ctx->poll_max_ns &&
|
||||
block_ns < ctx->poll_max_ns) {
|
||||
/* There is room to grow, poll longer */
|
||||
int64_t old = ctx->poll_ns;
|
||||
int64_t grow = ctx->poll_grow;
|
||||
|
||||
if (grow == 0) {
|
||||
grow = 2;
|
||||
}
|
||||
|
||||
if (ctx->poll_ns) {
|
||||
ctx->poll_ns *= grow;
|
||||
} else {
|
||||
ctx->poll_ns = 4000; /* start polling at 4 microseconds */
|
||||
}
|
||||
|
||||
if (ctx->poll_ns > ctx->poll_max_ns) {
|
||||
ctx->poll_ns = ctx->poll_max_ns;
|
||||
}
|
||||
|
||||
trace_poll_grow(ctx, old, ctx->poll_ns);
|
||||
}
|
||||
}
|
||||
|
||||
aio_notify_accept(ctx);
|
||||
@@ -473,7 +694,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
ctx->walking_handlers--;
|
||||
|
||||
/* Run dispatch even if there were no readable fds to run timers */
|
||||
if (aio_dispatch(ctx)) {
|
||||
if (aio_dispatch(ctx, ret > 0)) {
|
||||
progress = true;
|
||||
}
|
||||
|
||||
@@ -484,6 +705,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
|
||||
void aio_context_setup(AioContext *ctx)
|
||||
{
|
||||
/* TODO remove this in final patch submission */
|
||||
if (getenv("QEMU_AIO_POLL_MAX_NS")) {
|
||||
fprintf(stderr, "The QEMU_AIO_POLL_MAX_NS environment variable has "
|
||||
"been replaced with -object iothread,poll-max-ns=NUM\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EPOLL_CREATE1
|
||||
assert(!ctx->epollfd);
|
||||
ctx->epollfd = epoll_create1(EPOLL_CLOEXEC);
|
||||
@@ -495,3 +723,17 @@ void aio_context_setup(AioContext *ctx)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
|
||||
int64_t grow, int64_t shrink, Error **errp)
|
||||
{
|
||||
/* No thread synchronization here, it doesn't matter if an incorrect value
|
||||
* is used once.
|
||||
*/
|
||||
ctx->poll_max_ns = max_ns;
|
||||
ctx->poll_ns = 0;
|
||||
ctx->poll_grow = grow;
|
||||
ctx->poll_shrink = shrink;
|
||||
|
||||
aio_notify(ctx);
|
||||
}
|
||||
|
||||
32
aio-win32.c
32
aio-win32.c
@@ -20,6 +20,7 @@
|
||||
#include "block/block.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
struct AioHandler {
|
||||
EventNotifier *e;
|
||||
@@ -38,6 +39,7 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
bool is_external,
|
||||
IOHandler *io_read,
|
||||
IOHandler *io_write,
|
||||
AioPollFn *io_poll,
|
||||
void *opaque)
|
||||
{
|
||||
/* fd is a SOCKET in our case */
|
||||
@@ -100,10 +102,18 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
aio_notify(ctx);
|
||||
}
|
||||
|
||||
void aio_set_fd_poll(AioContext *ctx, int fd,
|
||||
IOHandler *io_poll_begin,
|
||||
IOHandler *io_poll_end)
|
||||
{
|
||||
/* Not implemented */
|
||||
}
|
||||
|
||||
void aio_set_event_notifier(AioContext *ctx,
|
||||
EventNotifier *e,
|
||||
bool is_external,
|
||||
EventNotifierHandler *io_notify)
|
||||
EventNotifierHandler *io_notify,
|
||||
AioPollFn *io_poll)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
@@ -150,6 +160,14 @@ void aio_set_event_notifier(AioContext *ctx,
|
||||
aio_notify(ctx);
|
||||
}
|
||||
|
||||
void aio_set_event_notifier_poll(AioContext *ctx,
|
||||
EventNotifier *notifier,
|
||||
EventNotifierHandler *io_poll_begin,
|
||||
EventNotifierHandler *io_poll_end)
|
||||
{
|
||||
/* Not implemented */
|
||||
}
|
||||
|
||||
bool aio_prepare(AioContext *ctx)
|
||||
{
|
||||
static struct timeval tv0;
|
||||
@@ -271,12 +289,14 @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
|
||||
return progress;
|
||||
}
|
||||
|
||||
bool aio_dispatch(AioContext *ctx)
|
||||
bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
|
||||
{
|
||||
bool progress;
|
||||
|
||||
progress = aio_bh_poll(ctx);
|
||||
progress |= aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE);
|
||||
if (dispatch_fds) {
|
||||
progress |= aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
progress |= timerlistgroup_run_timers(&ctx->tlg);
|
||||
return progress;
|
||||
}
|
||||
@@ -374,3 +394,9 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
void aio_context_setup(AioContext *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
|
||||
int64_t grow, int64_t shrink, Error **errp)
|
||||
{
|
||||
error_setg(errp, "AioContext polling is not implemented on Windows");
|
||||
}
|
||||
|
||||
21
async.c
21
async.c
@@ -251,7 +251,7 @@ aio_ctx_dispatch(GSource *source,
|
||||
AioContext *ctx = (AioContext *) source;
|
||||
|
||||
assert(callback == NULL);
|
||||
aio_dispatch(ctx);
|
||||
aio_dispatch(ctx, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ aio_ctx_finalize(GSource *source)
|
||||
}
|
||||
qemu_mutex_unlock(&ctx->bh_lock);
|
||||
|
||||
aio_set_event_notifier(ctx, &ctx->notifier, false, NULL);
|
||||
aio_set_event_notifier(ctx, &ctx->notifier, false, NULL, NULL);
|
||||
event_notifier_cleanup(&ctx->notifier);
|
||||
qemu_rec_mutex_destroy(&ctx->lock);
|
||||
qemu_mutex_destroy(&ctx->bh_lock);
|
||||
@@ -349,6 +349,15 @@ static void event_notifier_dummy_cb(EventNotifier *e)
|
||||
{
|
||||
}
|
||||
|
||||
/* Returns true if aio_notify() was called (e.g. a BH was scheduled) */
|
||||
static bool event_notifier_poll(void *opaque)
|
||||
{
|
||||
EventNotifier *e = opaque;
|
||||
AioContext *ctx = container_of(e, AioContext, notifier);
|
||||
|
||||
return atomic_read(&ctx->notified);
|
||||
}
|
||||
|
||||
AioContext *aio_context_new(Error **errp)
|
||||
{
|
||||
int ret;
|
||||
@@ -366,7 +375,8 @@ AioContext *aio_context_new(Error **errp)
|
||||
aio_set_event_notifier(ctx, &ctx->notifier,
|
||||
false,
|
||||
(EventNotifierHandler *)
|
||||
event_notifier_dummy_cb);
|
||||
event_notifier_dummy_cb,
|
||||
event_notifier_poll);
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
ctx->linux_aio = NULL;
|
||||
#endif
|
||||
@@ -375,6 +385,11 @@ AioContext *aio_context_new(Error **errp)
|
||||
qemu_rec_mutex_init(&ctx->lock);
|
||||
timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);
|
||||
|
||||
ctx->poll_ns = 0;
|
||||
ctx->poll_max_ns = 0;
|
||||
ctx->poll_grow = 0;
|
||||
ctx->poll_shrink = 0;
|
||||
|
||||
return ctx;
|
||||
fail:
|
||||
g_source_destroy(&ctx->source);
|
||||
|
||||
@@ -27,12 +27,10 @@
|
||||
#include "sysemu/char.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/usb.h"
|
||||
#include "ui/console.h"
|
||||
#include <brlapi.h>
|
||||
#include <brlapi_constants.h>
|
||||
#include <brlapi_keycodes.h>
|
||||
#ifdef CONFIG_SDL
|
||||
#include <SDL_syswm.h>
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define DPRINTF(fmt, ...) \
|
||||
@@ -227,12 +225,8 @@ static const uint8_t nabcc_translation[2][256] = {
|
||||
/* The guest OS has started discussing with us, finish initializing BrlAPI */
|
||||
static int baum_deferred_init(BaumDriverState *baum)
|
||||
{
|
||||
#if defined(CONFIG_SDL)
|
||||
#if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||
SDL_SysWMinfo info;
|
||||
#endif
|
||||
#endif
|
||||
int tty;
|
||||
int tty = BRLAPI_TTY_DEFAULT;
|
||||
QemuConsole *con;
|
||||
|
||||
if (baum->deferred_init) {
|
||||
return 1;
|
||||
@@ -243,21 +237,12 @@ static int baum_deferred_init(BaumDriverState *baum)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SDL)
|
||||
#if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||
memset(&info, 0, sizeof(info));
|
||||
SDL_VERSION(&info.version);
|
||||
if (SDL_GetWMInfo(&info)) {
|
||||
tty = info.info.x11.wmwindow;
|
||||
} else {
|
||||
#endif
|
||||
#endif
|
||||
tty = BRLAPI_TTY_DEFAULT;
|
||||
#if defined(CONFIG_SDL)
|
||||
#if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||
con = qemu_console_lookup_by_index(0);
|
||||
if (con && qemu_console_is_graphic(con)) {
|
||||
tty = qemu_console_get_window_id(con);
|
||||
if (tty == -1)
|
||||
tty = BRLAPI_TTY_DEFAULT;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (brlapi__enterTtyMode(baum->brlapi, tty, NULL) == -1) {
|
||||
brlapi_perror("baum: brlapi__enterTtyMode");
|
||||
|
||||
@@ -94,6 +94,8 @@ static void cryptodev_builtin_init(
|
||||
backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo);
|
||||
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
|
||||
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
|
||||
|
||||
cryptodev_backend_set_ready(backend, true);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -111,23 +113,42 @@ cryptodev_builtin_get_unused_session_index(
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define AES_KEYSIZE_128 16
|
||||
#define AES_KEYSIZE_192 24
|
||||
#define AES_KEYSIZE_256 32
|
||||
#define AES_KEYSIZE_128_XTS AES_KEYSIZE_256
|
||||
#define AES_KEYSIZE_256_XTS 64
|
||||
|
||||
static int
|
||||
cryptodev_builtin_get_aes_algo(uint32_t key_len, Error **errp)
|
||||
cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp)
|
||||
{
|
||||
int algo;
|
||||
|
||||
if (key_len == 128 / 8) {
|
||||
if (key_len == AES_KEYSIZE_128) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_128;
|
||||
} else if (key_len == 192 / 8) {
|
||||
} else if (key_len == AES_KEYSIZE_192) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_192;
|
||||
} else if (key_len == 256 / 8) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_256;
|
||||
} else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_128;
|
||||
} else {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_256;
|
||||
}
|
||||
} else if (key_len == AES_KEYSIZE_256_XTS) {
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_256;
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
error_setg(errp, "Unsupported key length :%u", key_len);
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return algo;
|
||||
|
||||
err:
|
||||
error_setg(errp, "Unsupported key length :%u", key_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int cryptodev_builtin_create_cipher_session(
|
||||
@@ -155,32 +176,48 @@ static int cryptodev_builtin_create_cipher_session(
|
||||
|
||||
switch (sess_info->cipher_alg) {
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_ECB:
|
||||
mode = QCRYPTO_CIPHER_MODE_ECB;
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
mode, errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_ECB;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_CBC:
|
||||
mode = QCRYPTO_CIPHER_MODE_CBC;
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
mode, errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_CBC;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_CTR:
|
||||
mode = QCRYPTO_CIPHER_MODE_CTR;
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
mode, errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_CTR;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_DES_ECB:
|
||||
algo = QCRYPTO_CIPHER_ALG_DES_RFB;
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_XTS:
|
||||
mode = QCRYPTO_CIPHER_MODE_XTS;
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
mode, errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_3DES_ECB:
|
||||
mode = QCRYPTO_CIPHER_MODE_ECB;
|
||||
algo = QCRYPTO_CIPHER_ALG_3DES;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_3DES_CBC:
|
||||
mode = QCRYPTO_CIPHER_MODE_CBC;
|
||||
algo = QCRYPTO_CIPHER_ALG_3DES;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_3DES_CTR:
|
||||
mode = QCRYPTO_CIPHER_MODE_CTR;
|
||||
algo = QCRYPTO_CIPHER_ALG_3DES;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher alg :%u",
|
||||
@@ -331,6 +368,8 @@ static void cryptodev_builtin_cleanup(
|
||||
backend->conf.peers.ccs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cryptodev_backend_set_ready(backend, false);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -73,8 +73,6 @@ void cryptodev_backend_cleanup(
|
||||
if (bc->cleanup) {
|
||||
bc->cleanup(backend, errp);
|
||||
}
|
||||
|
||||
backend->ready = false;
|
||||
}
|
||||
|
||||
int64_t cryptodev_backend_sym_create_session(
|
||||
@@ -189,14 +187,39 @@ cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
backend->ready = true;
|
||||
|
||||
return;
|
||||
|
||||
out:
|
||||
backend->ready = false;
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
||||
{
|
||||
backend->is_used = used;
|
||||
}
|
||||
|
||||
bool cryptodev_backend_is_used(CryptoDevBackend *backend)
|
||||
{
|
||||
return backend->is_used;
|
||||
}
|
||||
|
||||
void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready)
|
||||
{
|
||||
backend->ready = ready;
|
||||
}
|
||||
|
||||
bool cryptodev_backend_is_ready(CryptoDevBackend *backend)
|
||||
{
|
||||
return backend->ready;
|
||||
}
|
||||
|
||||
static bool
|
||||
cryptodev_backend_can_be_deleted(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
return !cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc));
|
||||
}
|
||||
|
||||
static void cryptodev_backend_instance_init(Object *obj)
|
||||
{
|
||||
object_property_add(obj, "queues", "int",
|
||||
@@ -209,7 +232,9 @@ static void cryptodev_backend_instance_init(Object *obj)
|
||||
|
||||
static void cryptodev_backend_finalize(Object *obj)
|
||||
{
|
||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
||||
|
||||
cryptodev_backend_cleanup(backend, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -218,6 +243,7 @@ cryptodev_backend_class_init(ObjectClass *oc, void *data)
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
|
||||
ucc->complete = cryptodev_backend_complete;
|
||||
ucc->can_be_deleted = cryptodev_backend_can_be_deleted;
|
||||
|
||||
QTAILQ_INIT(&crypto_clients);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
|
||||
block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
|
||||
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
|
||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||
block-obj-y += qed-check.o
|
||||
@@ -6,8 +6,8 @@ block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
|
||||
block-obj-y += quorum.o
|
||||
block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
|
||||
block-obj-y += block-backend.o snapshot.o qapi.o
|
||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
||||
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += file-posix.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-y += null.o mirror.o commit.o io.o
|
||||
block-obj-y += throttle-groups.o
|
||||
|
||||
@@ -58,10 +58,6 @@ typedef struct BlkdebugSuspendedReq {
|
||||
QLIST_ENTRY(BlkdebugSuspendedReq) next;
|
||||
} BlkdebugSuspendedReq;
|
||||
|
||||
static const AIOCBInfo blkdebug_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlkdebugAIOCB),
|
||||
};
|
||||
|
||||
enum {
|
||||
ACTION_INJECT_ERROR,
|
||||
ACTION_SET_STATE,
|
||||
@@ -77,7 +73,7 @@ typedef struct BlkdebugRule {
|
||||
int error;
|
||||
int immediately;
|
||||
int once;
|
||||
int64_t sector;
|
||||
int64_t offset;
|
||||
} inject;
|
||||
struct {
|
||||
int new_state;
|
||||
@@ -174,6 +170,7 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
|
||||
const char* event_name;
|
||||
BlkdebugEvent event;
|
||||
struct BlkdebugRule *rule;
|
||||
int64_t sector;
|
||||
|
||||
/* Find the right event for the rule */
|
||||
event_name = qemu_opt_get(opts, "event");
|
||||
@@ -200,7 +197,9 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
|
||||
rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0);
|
||||
rule->options.inject.immediately =
|
||||
qemu_opt_get_bool(opts, "immediately", 0);
|
||||
rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
|
||||
sector = qemu_opt_get_number(opts, "sector", -1);
|
||||
rule->options.inject.offset =
|
||||
sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
|
||||
break;
|
||||
|
||||
case ACTION_SET_STATE:
|
||||
@@ -408,17 +407,14 @@ out:
|
||||
|
||||
static void error_callback_bh(void *opaque)
|
||||
{
|
||||
struct BlkdebugAIOCB *acb = opaque;
|
||||
acb->common.cb(acb->common.opaque, acb->ret);
|
||||
qemu_aio_unref(acb);
|
||||
Coroutine *co = opaque;
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
static BlockAIOCB *inject_error(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
|
||||
static int inject_error(BlockDriverState *bs, BlkdebugRule *rule)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
int error = rule->options.inject.error;
|
||||
struct BlkdebugAIOCB *acb;
|
||||
bool immediately = rule->options.inject.immediately;
|
||||
|
||||
if (rule->options.inject.once) {
|
||||
@@ -426,81 +422,79 @@ static BlockAIOCB *inject_error(BlockDriverState *bs,
|
||||
remove_rule(rule);
|
||||
}
|
||||
|
||||
if (immediately) {
|
||||
return NULL;
|
||||
if (!immediately) {
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh,
|
||||
qemu_coroutine_self());
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
|
||||
acb->ret = -error;
|
||||
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh, acb);
|
||||
|
||||
return &acb->common;
|
||||
return -error;
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
static int coroutine_fn
|
||||
blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
|
||||
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
|
||||
if (rule->options.inject.sector == -1 ||
|
||||
(rule->options.inject.sector >= sector_num &&
|
||||
rule->options.inject.sector < sector_num + nb_sectors)) {
|
||||
uint64_t inject_offset = rule->options.inject.offset;
|
||||
|
||||
if (inject_offset == -1 ||
|
||||
(inject_offset >= offset && inject_offset < offset + bytes))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rule && rule->options.inject.error) {
|
||||
return inject_error(bs, cb, opaque, rule);
|
||||
return inject_error(bs, rule);
|
||||
}
|
||||
|
||||
return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
|
||||
cb, opaque);
|
||||
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
static int coroutine_fn
|
||||
blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
|
||||
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
|
||||
if (rule->options.inject.sector == -1 ||
|
||||
(rule->options.inject.sector >= sector_num &&
|
||||
rule->options.inject.sector < sector_num + nb_sectors)) {
|
||||
uint64_t inject_offset = rule->options.inject.offset;
|
||||
|
||||
if (inject_offset == -1 ||
|
||||
(inject_offset >= offset && inject_offset < offset + bytes))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rule && rule->options.inject.error) {
|
||||
return inject_error(bs, cb, opaque, rule);
|
||||
return inject_error(bs, rule);
|
||||
}
|
||||
|
||||
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
|
||||
cb, opaque);
|
||||
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
static int blkdebug_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
|
||||
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
|
||||
if (rule->options.inject.sector == -1) {
|
||||
if (rule->options.inject.offset == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rule && rule->options.inject.error) {
|
||||
return inject_error(bs, cb, opaque, rule);
|
||||
return inject_error(bs, rule);
|
||||
}
|
||||
|
||||
return bdrv_aio_flush(bs->file->bs, cb, opaque);
|
||||
return bdrv_co_flush(bs->file->bs);
|
||||
}
|
||||
|
||||
|
||||
@@ -752,9 +746,9 @@ static BlockDriver bdrv_blkdebug = {
|
||||
.bdrv_refresh_filename = blkdebug_refresh_filename,
|
||||
.bdrv_refresh_limits = blkdebug_refresh_limits,
|
||||
|
||||
.bdrv_aio_readv = blkdebug_aio_readv,
|
||||
.bdrv_aio_writev = blkdebug_aio_writev,
|
||||
.bdrv_aio_flush = blkdebug_aio_flush,
|
||||
.bdrv_co_preadv = blkdebug_co_preadv,
|
||||
.bdrv_co_pwritev = blkdebug_co_pwritev,
|
||||
.bdrv_co_flush_to_disk = blkdebug_co_flush,
|
||||
|
||||
.bdrv_debug_event = blkdebug_debug_event,
|
||||
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
|
||||
|
||||
@@ -19,38 +19,36 @@ typedef struct {
|
||||
BdrvChild *test_file;
|
||||
} BDRVBlkverifyState;
|
||||
|
||||
typedef struct BlkverifyAIOCB BlkverifyAIOCB;
|
||||
struct BlkverifyAIOCB {
|
||||
BlockAIOCB common;
|
||||
typedef struct BlkverifyRequest {
|
||||
Coroutine *co;
|
||||
BlockDriverState *bs;
|
||||
|
||||
/* Request metadata */
|
||||
bool is_write;
|
||||
int64_t sector_num;
|
||||
int nb_sectors;
|
||||
uint64_t offset;
|
||||
uint64_t bytes;
|
||||
int flags;
|
||||
|
||||
int (*request_fn)(BdrvChild *, int64_t, unsigned int, QEMUIOVector *,
|
||||
BdrvRequestFlags);
|
||||
|
||||
int ret; /* test image result */
|
||||
int raw_ret; /* raw image result */
|
||||
|
||||
int ret; /* first completed request's result */
|
||||
unsigned int done; /* completion counter */
|
||||
|
||||
QEMUIOVector *qiov; /* user I/O vector */
|
||||
QEMUIOVector raw_qiov; /* cloned I/O vector for raw file */
|
||||
void *buf; /* buffer for raw file I/O */
|
||||
QEMUIOVector *raw_qiov; /* cloned I/O vector for raw file */
|
||||
} BlkverifyRequest;
|
||||
|
||||
void (*verify)(BlkverifyAIOCB *acb);
|
||||
};
|
||||
|
||||
static const AIOCBInfo blkverify_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlkverifyAIOCB),
|
||||
};
|
||||
|
||||
static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
|
||||
static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyRequest *r,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ",
|
||||
acb->is_write ? "write" : "read", acb->sector_num,
|
||||
acb->nb_sectors);
|
||||
fprintf(stderr, "blkverify: %s offset=%" PRId64 " bytes=%" PRId64 " ",
|
||||
r->is_write ? "write" : "read", r->offset, r->bytes);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
@@ -166,113 +164,106 @@ static int64_t blkverify_getlength(BlockDriverState *bs)
|
||||
return bdrv_getlength(s->test_file->bs);
|
||||
}
|
||||
|
||||
static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
|
||||
int64_t sector_num, QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static void coroutine_fn blkverify_do_test_req(void *opaque)
|
||||
{
|
||||
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
|
||||
BlkverifyRequest *r = opaque;
|
||||
BDRVBlkverifyState *s = r->bs->opaque;
|
||||
|
||||
acb->is_write = is_write;
|
||||
acb->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
acb->ret = -EINPROGRESS;
|
||||
acb->done = 0;
|
||||
acb->qiov = qiov;
|
||||
acb->buf = NULL;
|
||||
acb->verify = NULL;
|
||||
return acb;
|
||||
r->ret = r->request_fn(s->test_file, r->offset, r->bytes, r->qiov,
|
||||
r->flags);
|
||||
r->done++;
|
||||
qemu_coroutine_enter_if_inactive(r->co);
|
||||
}
|
||||
|
||||
static void blkverify_aio_bh(void *opaque)
|
||||
static void coroutine_fn blkverify_do_raw_req(void *opaque)
|
||||
{
|
||||
BlkverifyAIOCB *acb = opaque;
|
||||
BlkverifyRequest *r = opaque;
|
||||
|
||||
if (acb->buf) {
|
||||
qemu_iovec_destroy(&acb->raw_qiov);
|
||||
qemu_vfree(acb->buf);
|
||||
r->raw_ret = r->request_fn(r->bs->file, r->offset, r->bytes, r->raw_qiov,
|
||||
r->flags);
|
||||
r->done++;
|
||||
qemu_coroutine_enter_if_inactive(r->co);
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, QEMUIOVector *raw_qiov,
|
||||
int flags, bool is_write)
|
||||
{
|
||||
Coroutine *co_a, *co_b;
|
||||
|
||||
*r = (BlkverifyRequest) {
|
||||
.co = qemu_coroutine_self(),
|
||||
.bs = bs,
|
||||
.offset = offset,
|
||||
.bytes = bytes,
|
||||
.qiov = qiov,
|
||||
.raw_qiov = raw_qiov,
|
||||
.flags = flags,
|
||||
.is_write = is_write,
|
||||
.request_fn = is_write ? bdrv_co_pwritev : bdrv_co_preadv,
|
||||
};
|
||||
|
||||
co_a = qemu_coroutine_create(blkverify_do_test_req, r);
|
||||
co_b = qemu_coroutine_create(blkverify_do_raw_req, r);
|
||||
|
||||
qemu_coroutine_enter(co_a);
|
||||
qemu_coroutine_enter(co_b);
|
||||
|
||||
while (r->done < 2) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
acb->common.cb(acb->common.opaque, acb->ret);
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
|
||||
static void blkverify_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
BlkverifyAIOCB *acb = opaque;
|
||||
|
||||
switch (++acb->done) {
|
||||
case 1:
|
||||
acb->ret = ret;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (acb->ret != ret) {
|
||||
blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret);
|
||||
}
|
||||
|
||||
if (acb->verify) {
|
||||
acb->verify(acb);
|
||||
}
|
||||
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
|
||||
blkverify_aio_bh, acb);
|
||||
break;
|
||||
if (r->ret != r->raw_ret) {
|
||||
blkverify_err(r, "return value mismatch %d != %d", r->ret, r->raw_ret);
|
||||
}
|
||||
|
||||
return r->ret;
|
||||
}
|
||||
|
||||
static void blkverify_verify_readv(BlkverifyAIOCB *acb)
|
||||
static int coroutine_fn
|
||||
blkverify_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
ssize_t offset = qemu_iovec_compare(acb->qiov, &acb->raw_qiov);
|
||||
if (offset != -1) {
|
||||
blkverify_err(acb, "contents mismatch in sector %" PRId64,
|
||||
acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
|
||||
BlkverifyRequest r;
|
||||
QEMUIOVector raw_qiov;
|
||||
void *buf;
|
||||
ssize_t cmp_offset;
|
||||
int ret;
|
||||
|
||||
buf = qemu_blockalign(bs->file->bs, qiov->size);
|
||||
qemu_iovec_init(&raw_qiov, qiov->niov);
|
||||
qemu_iovec_clone(&raw_qiov, qiov, buf);
|
||||
|
||||
ret = blkverify_co_prwv(bs, &r, offset, bytes, qiov, &raw_qiov, flags,
|
||||
false);
|
||||
|
||||
cmp_offset = qemu_iovec_compare(qiov, &raw_qiov);
|
||||
if (cmp_offset != -1) {
|
||||
blkverify_err(&r, "contents mismatch at offset %" PRId64,
|
||||
offset + cmp_offset);
|
||||
}
|
||||
|
||||
qemu_iovec_destroy(&raw_qiov);
|
||||
qemu_vfree(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
static int coroutine_fn
|
||||
blkverify_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
|
||||
nb_sectors, cb, opaque);
|
||||
|
||||
acb->verify = blkverify_verify_readv;
|
||||
acb->buf = qemu_blockalign(bs->file->bs, qiov->size);
|
||||
qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
|
||||
qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
|
||||
|
||||
bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
return &acb->common;
|
||||
BlkverifyRequest r;
|
||||
return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true);
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
|
||||
nb_sectors, cb, opaque);
|
||||
|
||||
bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkverify_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static int blkverify_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
|
||||
/* Only flush test file, the raw file is not important */
|
||||
return bdrv_aio_flush(s->test_file->bs, cb, opaque);
|
||||
return bdrv_co_flush(s->test_file->bs);
|
||||
}
|
||||
|
||||
static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
@@ -332,9 +323,9 @@ static BlockDriver bdrv_blkverify = {
|
||||
.bdrv_getlength = blkverify_getlength,
|
||||
.bdrv_refresh_filename = blkverify_refresh_filename,
|
||||
|
||||
.bdrv_aio_readv = blkverify_aio_readv,
|
||||
.bdrv_aio_writev = blkverify_aio_writev,
|
||||
.bdrv_aio_flush = blkverify_aio_flush,
|
||||
.bdrv_co_preadv = blkverify_co_preadv,
|
||||
.bdrv_co_pwritev = blkverify_co_pwritev,
|
||||
.bdrv_co_flush = blkverify_co_flush,
|
||||
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
|
||||
|
||||
@@ -192,19 +192,19 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
curl_multi_read, NULL, state);
|
||||
curl_multi_read, NULL, NULL, state);
|
||||
break;
|
||||
case CURL_POLL_OUT:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
NULL, curl_multi_do, state);
|
||||
NULL, curl_multi_do, NULL, state);
|
||||
break;
|
||||
case CURL_POLL_INOUT:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
curl_multi_read, curl_multi_do, state);
|
||||
curl_multi_read, curl_multi_do, NULL, state);
|
||||
break;
|
||||
case CURL_POLL_REMOVE:
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1253,7 +1253,7 @@ static int qemu_gluster_has_zero_init(BlockDriverState *bs)
|
||||
* If @start is in a trailing hole or beyond EOF, return -ENXIO.
|
||||
* If we can't find out, return a negative errno other than -ENXIO.
|
||||
*
|
||||
* (Shamefully copied from raw-posix.c, only miniscule adaptions.)
|
||||
* (Shamefully copied from file-posix.c, only miniscule adaptions.)
|
||||
*/
|
||||
static int find_allocation(BlockDriverState *bs, off_t start,
|
||||
off_t *data, off_t *hole)
|
||||
@@ -1349,7 +1349,7 @@ exit:
|
||||
* 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
|
||||
* beyond the end of the disk image it will be clamped.
|
||||
*
|
||||
* (Based on raw_co_get_block_status() from raw-posix.c.)
|
||||
* (Based on raw_co_get_block_status() from file-posix.c.)
|
||||
*/
|
||||
static int64_t coroutine_fn qemu_gluster_co_get_block_status(
|
||||
BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
|
||||
|
||||
@@ -362,6 +362,7 @@ iscsi_set_events(IscsiLun *iscsilun)
|
||||
false,
|
||||
(ev & POLLIN) ? iscsi_process_read : NULL,
|
||||
(ev & POLLOUT) ? iscsi_process_write : NULL,
|
||||
NULL,
|
||||
iscsilun);
|
||||
iscsilun->events = ev;
|
||||
}
|
||||
@@ -498,18 +499,14 @@ iscsi_allocmap_update(IscsiLun *iscsilun, int64_t sector_num,
|
||||
if (allocated) {
|
||||
bitmap_set(iscsilun->allocmap, cl_num_expanded, nb_cls_expanded);
|
||||
} else {
|
||||
if (nb_cls_shrunk > 0) {
|
||||
bitmap_clear(iscsilun->allocmap, cl_num_shrunk, nb_cls_shrunk);
|
||||
}
|
||||
bitmap_clear(iscsilun->allocmap, cl_num_shrunk, nb_cls_shrunk);
|
||||
}
|
||||
|
||||
if (iscsilun->allocmap_valid == NULL) {
|
||||
return;
|
||||
}
|
||||
if (valid) {
|
||||
if (nb_cls_shrunk > 0) {
|
||||
bitmap_set(iscsilun->allocmap_valid, cl_num_shrunk, nb_cls_shrunk);
|
||||
}
|
||||
bitmap_set(iscsilun->allocmap_valid, cl_num_shrunk, nb_cls_shrunk);
|
||||
} else {
|
||||
bitmap_clear(iscsilun->allocmap_valid, cl_num_expanded,
|
||||
nb_cls_expanded);
|
||||
@@ -1530,7 +1527,7 @@ static void iscsi_detach_aio_context(BlockDriverState *bs)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsilun->iscsi),
|
||||
false, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
iscsilun->events = 0;
|
||||
|
||||
if (iscsilun->nop_timer) {
|
||||
|
||||
@@ -255,6 +255,20 @@ static void qemu_laio_completion_cb(EventNotifier *e)
|
||||
}
|
||||
}
|
||||
|
||||
static bool qemu_laio_poll_cb(void *opaque)
|
||||
{
|
||||
EventNotifier *e = opaque;
|
||||
LinuxAioState *s = container_of(e, LinuxAioState, e);
|
||||
struct io_event *events;
|
||||
|
||||
if (!io_getevents_peek(s->ctx, &events)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
qemu_laio_process_completions_and_submit(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void laio_cancel(BlockAIOCB *blockacb)
|
||||
{
|
||||
struct qemu_laiocb *laiocb = (struct qemu_laiocb *)blockacb;
|
||||
@@ -439,7 +453,7 @@ BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
|
||||
|
||||
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
|
||||
{
|
||||
aio_set_event_notifier(old_context, &s->e, false, NULL);
|
||||
aio_set_event_notifier(old_context, &s->e, false, NULL, NULL);
|
||||
qemu_bh_delete(s->completion_bh);
|
||||
}
|
||||
|
||||
@@ -448,7 +462,8 @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
|
||||
s->aio_context = new_context;
|
||||
s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s);
|
||||
aio_set_event_notifier(new_context, &s->e, false,
|
||||
qemu_laio_completion_cb);
|
||||
qemu_laio_completion_cb,
|
||||
qemu_laio_poll_cb);
|
||||
}
|
||||
|
||||
LinuxAioState *laio_init(void)
|
||||
|
||||
@@ -145,7 +145,7 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_set_fd_handler(aio_context, s->sioc->fd, false,
|
||||
nbd_reply_ready, nbd_restart_write, bs);
|
||||
nbd_reply_ready, nbd_restart_write, NULL, bs);
|
||||
if (qiov) {
|
||||
qio_channel_set_cork(s->ioc, true);
|
||||
rc = nbd_send_request(s->ioc, request);
|
||||
@@ -161,7 +161,7 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
rc = nbd_send_request(s->ioc, request);
|
||||
}
|
||||
aio_set_fd_handler(aio_context, s->sioc->fd, false,
|
||||
nbd_reply_ready, NULL, bs);
|
||||
nbd_reply_ready, NULL, NULL, bs);
|
||||
s->send_coroutine = NULL;
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
return rc;
|
||||
@@ -366,14 +366,14 @@ void nbd_client_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs),
|
||||
nbd_get_client_session(bs)->sioc->fd,
|
||||
false, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void nbd_client_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sioc->fd,
|
||||
false, nbd_reply_ready, NULL, bs);
|
||||
false, nbd_reply_ready, NULL, NULL, bs);
|
||||
}
|
||||
|
||||
void nbd_client_close(BlockDriverState *bs)
|
||||
|
||||
56
block/nfs.c
56
block/nfs.c
@@ -108,13 +108,12 @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
|
||||
qdict_put(options, "path", qstring_from_str(uri->path));
|
||||
|
||||
for (i = 0; i < qp->n; i++) {
|
||||
unsigned long long val;
|
||||
if (!qp->p[i].value) {
|
||||
error_setg(errp, "Value for NFS parameter expected: %s",
|
||||
qp->p[i].name);
|
||||
goto out;
|
||||
}
|
||||
if (parse_uint_full(qp->p[i].value, &val, 0)) {
|
||||
if (parse_uint_full(qp->p[i].value, NULL, 0)) {
|
||||
error_setg(errp, "Illegal value for NFS parameter: %s",
|
||||
qp->p[i].name);
|
||||
goto out;
|
||||
@@ -198,7 +197,8 @@ static void nfs_set_events(NFSClient *client)
|
||||
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
|
||||
false,
|
||||
(ev & POLLIN) ? nfs_process_read : NULL,
|
||||
(ev & POLLOUT) ? nfs_process_write : NULL, client);
|
||||
(ev & POLLOUT) ? nfs_process_write : NULL,
|
||||
NULL, client);
|
||||
|
||||
}
|
||||
client->events = ev;
|
||||
@@ -358,27 +358,27 @@ static QemuOptsList runtime_opts = {
|
||||
.help = "Path of the image on the host",
|
||||
},
|
||||
{
|
||||
.name = "user",
|
||||
.name = "uid",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "UID value to use when talking to the server",
|
||||
},
|
||||
{
|
||||
.name = "group",
|
||||
.name = "gid",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "GID value to use when talking to the server",
|
||||
},
|
||||
{
|
||||
.name = "tcp-syn-count",
|
||||
.name = "tcp-syncnt",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Number of SYNs to send during the session establish",
|
||||
},
|
||||
{
|
||||
.name = "readahead-size",
|
||||
.name = "readahead",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Set the readahead size in bytes",
|
||||
},
|
||||
{
|
||||
.name = "page-cache-size",
|
||||
.name = "pagecache",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Set the pagecache size in bytes",
|
||||
},
|
||||
@@ -396,7 +396,7 @@ static void nfs_detach_aio_context(BlockDriverState *bs)
|
||||
NFSClient *client = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
|
||||
false, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
client->events = 0;
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ static void nfs_client_close(NFSClient *client)
|
||||
nfs_close(client->context, client->fh);
|
||||
}
|
||||
aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
|
||||
false, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
nfs_destroy_context(client->context);
|
||||
}
|
||||
memset(client, 0, sizeof(NFSClient));
|
||||
@@ -507,29 +507,29 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (qemu_opt_get(opts, "user")) {
|
||||
client->uid = qemu_opt_get_number(opts, "user", 0);
|
||||
if (qemu_opt_get(opts, "uid")) {
|
||||
client->uid = qemu_opt_get_number(opts, "uid", 0);
|
||||
nfs_set_uid(client->context, client->uid);
|
||||
}
|
||||
|
||||
if (qemu_opt_get(opts, "group")) {
|
||||
client->gid = qemu_opt_get_number(opts, "group", 0);
|
||||
if (qemu_opt_get(opts, "gid")) {
|
||||
client->gid = qemu_opt_get_number(opts, "gid", 0);
|
||||
nfs_set_gid(client->context, client->gid);
|
||||
}
|
||||
|
||||
if (qemu_opt_get(opts, "tcp-syn-count")) {
|
||||
client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
|
||||
if (qemu_opt_get(opts, "tcp-syncnt")) {
|
||||
client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syncnt", 0);
|
||||
nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
|
||||
}
|
||||
|
||||
#ifdef LIBNFS_FEATURE_READAHEAD
|
||||
if (qemu_opt_get(opts, "readahead-size")) {
|
||||
if (qemu_opt_get(opts, "readahead")) {
|
||||
if (open_flags & BDRV_O_NOCACHE) {
|
||||
error_setg(errp, "Cannot enable NFS readahead "
|
||||
"if cache.direct = on");
|
||||
goto fail;
|
||||
}
|
||||
client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
|
||||
client->readahead = qemu_opt_get_number(opts, "readahead", 0);
|
||||
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
|
||||
error_report("NFS Warning: Truncating NFS readahead "
|
||||
"size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
|
||||
@@ -544,13 +544,13 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
|
||||
#endif
|
||||
|
||||
#ifdef LIBNFS_FEATURE_PAGECACHE
|
||||
if (qemu_opt_get(opts, "page-cache-size")) {
|
||||
if (qemu_opt_get(opts, "pagecache")) {
|
||||
if (open_flags & BDRV_O_NOCACHE) {
|
||||
error_setg(errp, "Cannot enable NFS pagecache "
|
||||
"if cache.direct = on");
|
||||
goto fail;
|
||||
}
|
||||
client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
|
||||
client->pagecache = qemu_opt_get_number(opts, "pagecache", 0);
|
||||
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
|
||||
error_report("NFS Warning: Truncating NFS pagecache "
|
||||
"size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE);
|
||||
@@ -803,22 +803,22 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
qdict_put(opts, "path", qstring_from_str(client->path));
|
||||
|
||||
if (client->uid) {
|
||||
qdict_put(opts, "user", qint_from_int(client->uid));
|
||||
qdict_put(opts, "uid", qint_from_int(client->uid));
|
||||
}
|
||||
if (client->gid) {
|
||||
qdict_put(opts, "group", qint_from_int(client->gid));
|
||||
qdict_put(opts, "gid", qint_from_int(client->gid));
|
||||
}
|
||||
if (client->tcp_syncnt) {
|
||||
qdict_put(opts, "tcp-syn-cnt",
|
||||
qint_from_int(client->tcp_syncnt));
|
||||
qdict_put(opts, "tcp-syncnt",
|
||||
qint_from_int(client->tcp_syncnt));
|
||||
}
|
||||
if (client->readahead) {
|
||||
qdict_put(opts, "readahead-size",
|
||||
qint_from_int(client->readahead));
|
||||
qdict_put(opts, "readahead",
|
||||
qint_from_int(client->readahead));
|
||||
}
|
||||
if (client->pagecache) {
|
||||
qdict_put(opts, "page-cache-size",
|
||||
qint_from_int(client->pagecache));
|
||||
qdict_put(opts, "pagecache",
|
||||
qint_from_int(client->pagecache));
|
||||
}
|
||||
if (client->debug) {
|
||||
qdict_put(opts, "debug", qint_from_int(client->debug));
|
||||
|
||||
410
block/quorum.c
410
block/quorum.c
@@ -97,7 +97,7 @@ typedef struct QuorumAIOCB QuorumAIOCB;
|
||||
* $children_count QuorumChildRequest.
|
||||
*/
|
||||
typedef struct QuorumChildRequest {
|
||||
BlockAIOCB *aiocb;
|
||||
BlockDriverState *bs;
|
||||
QEMUIOVector qiov;
|
||||
uint8_t *buf;
|
||||
int ret;
|
||||
@@ -110,11 +110,12 @@ typedef struct QuorumChildRequest {
|
||||
* used to do operations on each children and track overall progress.
|
||||
*/
|
||||
struct QuorumAIOCB {
|
||||
BlockAIOCB common;
|
||||
BlockDriverState *bs;
|
||||
Coroutine *co;
|
||||
|
||||
/* Request metadata */
|
||||
uint64_t sector_num;
|
||||
int nb_sectors;
|
||||
uint64_t offset;
|
||||
uint64_t bytes;
|
||||
|
||||
QEMUIOVector *qiov; /* calling IOV */
|
||||
|
||||
@@ -133,32 +134,15 @@ struct QuorumAIOCB {
|
||||
int children_read; /* how many children have been read from */
|
||||
};
|
||||
|
||||
static bool quorum_vote(QuorumAIOCB *acb);
|
||||
|
||||
static void quorum_aio_cancel(BlockAIOCB *blockacb)
|
||||
{
|
||||
QuorumAIOCB *acb = container_of(blockacb, QuorumAIOCB, common);
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int i;
|
||||
|
||||
/* cancel all callbacks */
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
if (acb->qcrs[i].aiocb) {
|
||||
bdrv_aio_cancel_async(acb->qcrs[i].aiocb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AIOCBInfo quorum_aiocb_info = {
|
||||
.aiocb_size = sizeof(QuorumAIOCB),
|
||||
.cancel_async = quorum_aio_cancel,
|
||||
};
|
||||
typedef struct QuorumCo {
|
||||
QuorumAIOCB *acb;
|
||||
int idx;
|
||||
} QuorumCo;
|
||||
|
||||
static void quorum_aio_finalize(QuorumAIOCB *acb)
|
||||
{
|
||||
acb->common.cb(acb->common.opaque, acb->vote_ret);
|
||||
g_free(acb->qcrs);
|
||||
qemu_aio_unref(acb);
|
||||
g_free(acb);
|
||||
}
|
||||
|
||||
static bool quorum_sha256_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
||||
@@ -171,30 +155,26 @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
||||
return a->l == b->l;
|
||||
}
|
||||
|
||||
static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s,
|
||||
BlockDriverState *bs,
|
||||
static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs,
|
||||
QEMUIOVector *qiov,
|
||||
uint64_t sector_num,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
uint64_t offset,
|
||||
uint64_t bytes)
|
||||
{
|
||||
QuorumAIOCB *acb = qemu_aio_get(&quorum_aiocb_info, bs, cb, opaque);
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = g_new(QuorumAIOCB, 1);
|
||||
int i;
|
||||
|
||||
acb->common.bs->opaque = s;
|
||||
acb->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
acb->qiov = qiov;
|
||||
acb->qcrs = g_new0(QuorumChildRequest, s->num_children);
|
||||
acb->count = 0;
|
||||
acb->success_count = 0;
|
||||
acb->rewrite_count = 0;
|
||||
acb->votes.compare = quorum_sha256_compare;
|
||||
QLIST_INIT(&acb->votes.vote_list);
|
||||
acb->is_read = false;
|
||||
acb->vote_ret = 0;
|
||||
*acb = (QuorumAIOCB) {
|
||||
.co = qemu_coroutine_self(),
|
||||
.bs = bs,
|
||||
.offset = offset,
|
||||
.bytes = bytes,
|
||||
.qiov = qiov,
|
||||
.votes.compare = quorum_sha256_compare,
|
||||
.votes.vote_list = QLIST_HEAD_INITIALIZER(acb.votes.vote_list),
|
||||
};
|
||||
|
||||
acb->qcrs = g_new0(QuorumChildRequest, s->num_children);
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].buf = NULL;
|
||||
acb->qcrs[i].ret = 0;
|
||||
@@ -204,30 +184,37 @@ static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s,
|
||||
return acb;
|
||||
}
|
||||
|
||||
static void quorum_report_bad(QuorumOpType type, uint64_t sector_num,
|
||||
int nb_sectors, char *node_name, int ret)
|
||||
static void quorum_report_bad(QuorumOpType type, uint64_t offset,
|
||||
uint64_t bytes, char *node_name, int ret)
|
||||
{
|
||||
const char *msg = NULL;
|
||||
int64_t start_sector = offset / BDRV_SECTOR_SIZE;
|
||||
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
|
||||
|
||||
if (ret < 0) {
|
||||
msg = strerror(-ret);
|
||||
}
|
||||
|
||||
qapi_event_send_quorum_report_bad(type, !!msg, msg, node_name,
|
||||
sector_num, nb_sectors, &error_abort);
|
||||
qapi_event_send_quorum_report_bad(type, !!msg, msg, node_name, start_sector,
|
||||
end_sector - start_sector, &error_abort);
|
||||
}
|
||||
|
||||
static void quorum_report_failure(QuorumAIOCB *acb)
|
||||
{
|
||||
const char *reference = bdrv_get_device_or_node_name(acb->common.bs);
|
||||
qapi_event_send_quorum_failure(reference, acb->sector_num,
|
||||
acb->nb_sectors, &error_abort);
|
||||
const char *reference = bdrv_get_device_or_node_name(acb->bs);
|
||||
int64_t start_sector = acb->offset / BDRV_SECTOR_SIZE;
|
||||
int64_t end_sector = DIV_ROUND_UP(acb->offset + acb->bytes,
|
||||
BDRV_SECTOR_SIZE);
|
||||
|
||||
qapi_event_send_quorum_failure(reference, start_sector,
|
||||
end_sector - start_sector, &error_abort);
|
||||
}
|
||||
|
||||
static int quorum_vote_error(QuorumAIOCB *acb);
|
||||
|
||||
static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
|
||||
if (acb->success_count < s->threshold) {
|
||||
acb->vote_ret = quorum_vote_error(acb);
|
||||
@@ -238,22 +225,7 @@ static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void quorum_rewrite_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
QuorumAIOCB *acb = opaque;
|
||||
|
||||
/* one less rewrite to do */
|
||||
acb->rewrite_count--;
|
||||
|
||||
/* wait until all rewrite callbacks have completed */
|
||||
if (acb->rewrite_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
quorum_aio_finalize(acb);
|
||||
}
|
||||
|
||||
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb);
|
||||
static int read_fifo_child(QuorumAIOCB *acb);
|
||||
|
||||
static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source)
|
||||
{
|
||||
@@ -272,70 +244,7 @@ static void quorum_report_bad_acb(QuorumChildRequest *sacb, int ret)
|
||||
{
|
||||
QuorumAIOCB *acb = sacb->parent;
|
||||
QuorumOpType type = acb->is_read ? QUORUM_OP_TYPE_READ : QUORUM_OP_TYPE_WRITE;
|
||||
quorum_report_bad(type, acb->sector_num, acb->nb_sectors,
|
||||
sacb->aiocb->bs->node_name, ret);
|
||||
}
|
||||
|
||||
static void quorum_fifo_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
QuorumChildRequest *sacb = opaque;
|
||||
QuorumAIOCB *acb = sacb->parent;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
|
||||
assert(acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO);
|
||||
|
||||
if (ret < 0) {
|
||||
quorum_report_bad_acb(sacb, ret);
|
||||
|
||||
/* We try to read next child in FIFO order if we fail to read */
|
||||
if (acb->children_read < s->num_children) {
|
||||
read_fifo_child(acb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
acb->vote_ret = ret;
|
||||
|
||||
/* FIXME: rewrite failed children if acb->children_read > 1? */
|
||||
quorum_aio_finalize(acb);
|
||||
}
|
||||
|
||||
static void quorum_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
QuorumChildRequest *sacb = opaque;
|
||||
QuorumAIOCB *acb = sacb->parent;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
bool rewrite = false;
|
||||
int i;
|
||||
|
||||
sacb->ret = ret;
|
||||
if (ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
quorum_report_bad_acb(sacb, ret);
|
||||
}
|
||||
acb->count++;
|
||||
assert(acb->count <= s->num_children);
|
||||
assert(acb->success_count <= s->num_children);
|
||||
if (acb->count < s->num_children) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do the vote on read */
|
||||
if (acb->is_read) {
|
||||
rewrite = quorum_vote(acb);
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
qemu_vfree(acb->qcrs[i].buf);
|
||||
qemu_iovec_destroy(&acb->qcrs[i].qiov);
|
||||
}
|
||||
} else {
|
||||
quorum_has_too_much_io_failed(acb);
|
||||
}
|
||||
|
||||
/* if no rewrite is done the code will finish right away */
|
||||
if (!rewrite) {
|
||||
quorum_aio_finalize(acb);
|
||||
}
|
||||
quorum_report_bad(type, acb->offset, acb->bytes, sacb->bs->node_name, ret);
|
||||
}
|
||||
|
||||
static void quorum_report_bad_versions(BDRVQuorumState *s,
|
||||
@@ -350,14 +259,31 @@ static void quorum_report_bad_versions(BDRVQuorumState *s,
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(item, &version->items, next) {
|
||||
quorum_report_bad(QUORUM_OP_TYPE_READ, acb->sector_num,
|
||||
acb->nb_sectors,
|
||||
quorum_report_bad(QUORUM_OP_TYPE_READ, acb->offset, acb->bytes,
|
||||
s->children[item->index]->bs->node_name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb,
|
||||
static void quorum_rewrite_entry(void *opaque)
|
||||
{
|
||||
QuorumCo *co = opaque;
|
||||
QuorumAIOCB *acb = co->acb;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
|
||||
/* Ignore any errors, it's just a correction attempt for already
|
||||
* corrupted data. */
|
||||
bdrv_co_pwritev(s->children[co->idx], acb->offset, acb->bytes,
|
||||
acb->qiov, 0);
|
||||
|
||||
/* Wake up the caller after the last rewrite */
|
||||
acb->rewrite_count--;
|
||||
if (!acb->rewrite_count) {
|
||||
qemu_coroutine_enter_if_inactive(acb->co);
|
||||
}
|
||||
}
|
||||
|
||||
static bool quorum_rewrite_bad_versions(QuorumAIOCB *acb,
|
||||
QuorumVoteValue *value)
|
||||
{
|
||||
QuorumVoteVersion *version;
|
||||
@@ -376,7 +302,7 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb,
|
||||
}
|
||||
}
|
||||
|
||||
/* quorum_rewrite_aio_cb will count down this to zero */
|
||||
/* quorum_rewrite_entry will count down this to zero */
|
||||
acb->rewrite_count = count;
|
||||
|
||||
/* now fire the correcting rewrites */
|
||||
@@ -385,9 +311,14 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb,
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(item, &version->items, next) {
|
||||
bdrv_aio_writev(s->children[item->index], acb->sector_num,
|
||||
acb->qiov, acb->nb_sectors, quorum_rewrite_aio_cb,
|
||||
acb);
|
||||
Coroutine *co;
|
||||
QuorumCo data = {
|
||||
.acb = acb,
|
||||
.idx = item->index,
|
||||
};
|
||||
|
||||
co = qemu_coroutine_create(quorum_rewrite_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,8 +438,8 @@ static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb,
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "quorum: sector_num=%" PRId64 " nb_sectors=%d ",
|
||||
acb->sector_num, acb->nb_sectors);
|
||||
fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64 " ",
|
||||
acb->offset, acb->bytes);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
@@ -519,16 +450,15 @@ static bool quorum_compare(QuorumAIOCB *acb,
|
||||
QEMUIOVector *a,
|
||||
QEMUIOVector *b)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
ssize_t offset;
|
||||
|
||||
/* This driver will replace blkverify in this particular case */
|
||||
if (s->is_blkverify) {
|
||||
offset = qemu_iovec_compare(a, b);
|
||||
if (offset != -1) {
|
||||
quorum_err(acb, "contents mismatch in sector %" PRId64,
|
||||
acb->sector_num +
|
||||
(uint64_t)(offset / BDRV_SECTOR_SIZE));
|
||||
quorum_err(acb, "contents mismatch at offset %" PRIu64,
|
||||
acb->offset + offset);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -539,7 +469,7 @@ static bool quorum_compare(QuorumAIOCB *acb,
|
||||
/* Do a vote to get the error code */
|
||||
static int quorum_vote_error(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
QuorumVoteVersion *winner = NULL;
|
||||
QuorumVotes error_votes;
|
||||
QuorumVoteValue result_value;
|
||||
@@ -568,17 +498,16 @@ static int quorum_vote_error(QuorumAIOCB *acb)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool quorum_vote(QuorumAIOCB *acb)
|
||||
static void quorum_vote(QuorumAIOCB *acb)
|
||||
{
|
||||
bool quorum = true;
|
||||
bool rewrite = false;
|
||||
int i, j, ret;
|
||||
QuorumVoteValue hash;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
QuorumVoteVersion *winner;
|
||||
|
||||
if (quorum_has_too_much_io_failed(acb)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the index of the first successful read */
|
||||
@@ -606,7 +535,7 @@ static bool quorum_vote(QuorumAIOCB *acb)
|
||||
/* Every successful read agrees */
|
||||
if (quorum) {
|
||||
quorum_copy_qiov(acb->qiov, &acb->qcrs[i].qiov);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* compute hashes for each successful read, also store indexes */
|
||||
@@ -641,19 +570,46 @@ static bool quorum_vote(QuorumAIOCB *acb)
|
||||
|
||||
/* corruption correction is enabled */
|
||||
if (s->rewrite_corrupted) {
|
||||
rewrite = quorum_rewrite_bad_versions(s, acb, &winner->value);
|
||||
quorum_rewrite_bad_versions(acb, &winner->value);
|
||||
}
|
||||
|
||||
free_exit:
|
||||
/* free lists */
|
||||
quorum_free_vote_list(&acb->votes);
|
||||
return rewrite;
|
||||
}
|
||||
|
||||
static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
||||
static void read_quorum_children_entry(void *opaque)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int i;
|
||||
QuorumCo *co = opaque;
|
||||
QuorumAIOCB *acb = co->acb;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
int i = co->idx;
|
||||
QuorumChildRequest *sacb = &acb->qcrs[i];
|
||||
|
||||
sacb->bs = s->children[i]->bs;
|
||||
sacb->ret = bdrv_co_preadv(s->children[i], acb->offset, acb->bytes,
|
||||
&acb->qcrs[i].qiov, 0);
|
||||
|
||||
if (sacb->ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
quorum_report_bad_acb(sacb, sacb->ret);
|
||||
}
|
||||
|
||||
acb->count++;
|
||||
assert(acb->count <= s->num_children);
|
||||
assert(acb->success_count <= s->num_children);
|
||||
|
||||
/* Wake up the caller after the last read */
|
||||
if (acb->count == s->num_children) {
|
||||
qemu_coroutine_enter_if_inactive(acb->co);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_quorum_children(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
int i, ret;
|
||||
|
||||
acb->children_read = s->num_children;
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
@@ -663,65 +619,131 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].aiocb = bdrv_aio_readv(s->children[i], acb->sector_num,
|
||||
&acb->qcrs[i].qiov, acb->nb_sectors,
|
||||
quorum_aio_cb, &acb->qcrs[i]);
|
||||
Coroutine *co;
|
||||
QuorumCo data = {
|
||||
.acb = acb,
|
||||
.idx = i,
|
||||
};
|
||||
|
||||
co = qemu_coroutine_create(read_quorum_children_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
while (acb->count < s->num_children) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
/* Do the vote on read */
|
||||
quorum_vote(acb);
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
qemu_vfree(acb->qcrs[i].buf);
|
||||
qemu_iovec_destroy(&acb->qcrs[i].qiov);
|
||||
}
|
||||
|
||||
while (acb->rewrite_count) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
ret = acb->vote_ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb)
|
||||
static int read_fifo_child(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int n = acb->children_read++;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
int n, ret;
|
||||
|
||||
acb->qcrs[n].aiocb = bdrv_aio_readv(s->children[n], acb->sector_num,
|
||||
acb->qiov, acb->nb_sectors,
|
||||
quorum_fifo_aio_cb, &acb->qcrs[n]);
|
||||
/* We try to read the next child in FIFO order if we failed to read */
|
||||
do {
|
||||
n = acb->children_read++;
|
||||
acb->qcrs[n].bs = s->children[n]->bs;
|
||||
ret = bdrv_co_preadv(s->children[n], acb->offset, acb->bytes,
|
||||
acb->qiov, 0);
|
||||
if (ret < 0) {
|
||||
quorum_report_bad_acb(&acb->qcrs[n], ret);
|
||||
}
|
||||
} while (ret < 0 && acb->children_read < s->num_children);
|
||||
|
||||
return &acb->common;
|
||||
/* FIXME: rewrite failed children if acb->children_read > 1? */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockAIOCB *quorum_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static int quorum_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num,
|
||||
nb_sectors, cb, opaque);
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes);
|
||||
int ret;
|
||||
|
||||
acb->is_read = true;
|
||||
acb->children_read = 0;
|
||||
|
||||
if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
|
||||
return read_quorum_children(acb);
|
||||
ret = read_quorum_children(acb);
|
||||
} else {
|
||||
ret = read_fifo_child(acb);
|
||||
}
|
||||
quorum_aio_finalize(acb);
|
||||
|
||||
return read_fifo_child(acb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static void write_quorum_entry(void *opaque)
|
||||
{
|
||||
QuorumCo *co = opaque;
|
||||
QuorumAIOCB *acb = co->acb;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
int i = co->idx;
|
||||
QuorumChildRequest *sacb = &acb->qcrs[i];
|
||||
|
||||
sacb->bs = s->children[i]->bs;
|
||||
sacb->ret = bdrv_co_pwritev(s->children[i], acb->offset, acb->bytes,
|
||||
acb->qiov, 0);
|
||||
if (sacb->ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
quorum_report_bad_acb(sacb, sacb->ret);
|
||||
}
|
||||
acb->count++;
|
||||
assert(acb->count <= s->num_children);
|
||||
assert(acb->success_count <= s->num_children);
|
||||
|
||||
/* Wake up the caller after the last write */
|
||||
if (acb->count == s->num_children) {
|
||||
qemu_coroutine_enter_if_inactive(acb->co);
|
||||
}
|
||||
}
|
||||
|
||||
static int quorum_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num, nb_sectors,
|
||||
cb, opaque);
|
||||
int i;
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes);
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i], sector_num,
|
||||
qiov, nb_sectors, &quorum_aio_cb,
|
||||
&acb->qcrs[i]);
|
||||
Coroutine *co;
|
||||
QuorumCo data = {
|
||||
.acb = acb,
|
||||
.idx = i,
|
||||
};
|
||||
|
||||
co = qemu_coroutine_create(write_quorum_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
while (acb->count < s->num_children) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
quorum_has_too_much_io_failed(acb);
|
||||
|
||||
ret = acb->vote_ret;
|
||||
quorum_aio_finalize(acb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int64_t quorum_getlength(BlockDriverState *bs)
|
||||
@@ -765,7 +787,7 @@ static coroutine_fn int quorum_co_flush(BlockDriverState *bs)
|
||||
result = bdrv_co_flush(s->children[i]->bs);
|
||||
if (result) {
|
||||
quorum_report_bad(QUORUM_OP_TYPE_FLUSH, 0,
|
||||
bdrv_nb_sectors(s->children[i]->bs),
|
||||
bdrv_getlength(s->children[i]->bs),
|
||||
s->children[i]->bs->node_name, result);
|
||||
result_value.l = result;
|
||||
quorum_count_vote(&error_votes, &result_value, i);
|
||||
@@ -1098,8 +1120,8 @@ static BlockDriver bdrv_quorum = {
|
||||
|
||||
.bdrv_getlength = quorum_getlength,
|
||||
|
||||
.bdrv_aio_readv = quorum_aio_readv,
|
||||
.bdrv_aio_writev = quorum_aio_writev,
|
||||
.bdrv_co_preadv = quorum_co_preadv,
|
||||
.bdrv_co_pwritev = quorum_co_pwritev,
|
||||
|
||||
.bdrv_add_child = quorum_add_child,
|
||||
.bdrv_del_child = quorum_del_child,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* BlockDriver implementation for "raw"
|
||||
/* BlockDriver implementation for "raw" format driver
|
||||
*
|
||||
* Copyright (C) 2010-2016 Red Hat, Inc.
|
||||
* Copyright (C) 2010, Blue Swirl <blauwirbel@gmail.com>
|
||||
@@ -664,7 +664,7 @@ static coroutine_fn void do_co_req(void *opaque)
|
||||
|
||||
co = qemu_coroutine_self();
|
||||
aio_set_fd_handler(srco->aio_context, sockfd, false,
|
||||
NULL, restart_co_req, co);
|
||||
NULL, restart_co_req, NULL, co);
|
||||
|
||||
ret = send_co_req(sockfd, hdr, data, wlen);
|
||||
if (ret < 0) {
|
||||
@@ -672,7 +672,7 @@ static coroutine_fn void do_co_req(void *opaque)
|
||||
}
|
||||
|
||||
aio_set_fd_handler(srco->aio_context, sockfd, false,
|
||||
restart_co_req, NULL, co);
|
||||
restart_co_req, NULL, NULL, co);
|
||||
|
||||
ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
|
||||
if (ret != sizeof(*hdr)) {
|
||||
@@ -698,7 +698,7 @@ out:
|
||||
/* there is at most one request for this sockfd, so it is safe to
|
||||
* set each handler to NULL. */
|
||||
aio_set_fd_handler(srco->aio_context, sockfd, false,
|
||||
NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
srco->ret = ret;
|
||||
srco->finished = true;
|
||||
@@ -760,7 +760,7 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
|
||||
AIOReq *aio_req, *next;
|
||||
|
||||
aio_set_fd_handler(s->aio_context, s->fd, false, NULL,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
|
||||
@@ -964,7 +964,7 @@ static int get_sheep_fd(BDRVSheepdogState *s, Error **errp)
|
||||
}
|
||||
|
||||
aio_set_fd_handler(s->aio_context, fd, false,
|
||||
co_read_response, NULL, s);
|
||||
co_read_response, NULL, NULL, s);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -1226,7 +1226,7 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
s->co_send = qemu_coroutine_self();
|
||||
aio_set_fd_handler(s->aio_context, s->fd, false,
|
||||
co_read_response, co_write_request, s);
|
||||
co_read_response, co_write_request, NULL, s);
|
||||
socket_set_cork(s->fd, 1);
|
||||
|
||||
/* send a header */
|
||||
@@ -1245,7 +1245,7 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
out:
|
||||
socket_set_cork(s->fd, 0);
|
||||
aio_set_fd_handler(s->aio_context, s->fd, false,
|
||||
co_read_response, NULL, s);
|
||||
co_read_response, NULL, NULL, s);
|
||||
s->co_send = NULL;
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
}
|
||||
@@ -1396,7 +1396,7 @@ static void sd_detach_aio_context(BlockDriverState *bs)
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
|
||||
aio_set_fd_handler(s->aio_context, s->fd, false, NULL,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void sd_attach_aio_context(BlockDriverState *bs,
|
||||
@@ -1406,7 +1406,7 @@ static void sd_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
s->aio_context = new_context;
|
||||
aio_set_fd_handler(new_context, s->fd, false,
|
||||
co_read_response, NULL, s);
|
||||
co_read_response, NULL, NULL, s);
|
||||
}
|
||||
|
||||
/* TODO Convert to fine grained options */
|
||||
@@ -1520,7 +1520,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return 0;
|
||||
out:
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd,
|
||||
false, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
if (s->fd >= 0) {
|
||||
closesocket(s->fd);
|
||||
}
|
||||
@@ -1559,7 +1559,7 @@ static void sd_reopen_commit(BDRVReopenState *state)
|
||||
|
||||
if (s->fd) {
|
||||
aio_set_fd_handler(s->aio_context, s->fd, false,
|
||||
NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL);
|
||||
closesocket(s->fd);
|
||||
}
|
||||
|
||||
@@ -1583,7 +1583,7 @@ static void sd_reopen_abort(BDRVReopenState *state)
|
||||
|
||||
if (re_s->fd) {
|
||||
aio_set_fd_handler(s->aio_context, re_s->fd, false,
|
||||
NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL);
|
||||
closesocket(re_s->fd);
|
||||
}
|
||||
|
||||
@@ -1972,7 +1972,7 @@ static void sd_close(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd,
|
||||
false, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
closesocket(s->fd);
|
||||
g_free(s->host_spec);
|
||||
}
|
||||
|
||||
@@ -911,7 +911,7 @@ static coroutine_fn void set_fd_handler(BDRVSSHState *s, BlockDriverState *bs)
|
||||
rd_handler, wr_handler);
|
||||
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
|
||||
false, rd_handler, wr_handler, co);
|
||||
false, rd_handler, wr_handler, NULL, co);
|
||||
}
|
||||
|
||||
static coroutine_fn void clear_fd_handler(BDRVSSHState *s,
|
||||
@@ -919,7 +919,7 @@ static coroutine_fn void clear_fd_handler(BDRVSSHState *s,
|
||||
{
|
||||
DPRINTF("s->sock=%d", s->sock);
|
||||
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
|
||||
false, NULL, NULL, NULL);
|
||||
false, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* A non-blocking call returned EAGAIN, so yield, ensuring the
|
||||
|
||||
@@ -53,8 +53,8 @@ qmp_block_job_resume(void *job) "job %p"
|
||||
qmp_block_job_complete(void *job) "job %p"
|
||||
qmp_block_stream(void *bs, void *job) "bs %p job %p"
|
||||
|
||||
# block/raw-win32.c
|
||||
# block/raw-posix.c
|
||||
# block/file-win32.c
|
||||
# block/file-posix.c
|
||||
paio_submit_co(int64_t offset, int count, int type) "offset %"PRId64" count %d type %d"
|
||||
paio_submit(void *acb, void *opaque, int64_t offset, int count, int type) "acb %p opaque %p offset %"PRId64" count %d type %d"
|
||||
|
||||
|
||||
@@ -1354,8 +1354,8 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
goto out;
|
||||
}
|
||||
|
||||
data->lba = cpu_to_le64(offset >> BDRV_SECTOR_BITS);
|
||||
data->size = cpu_to_le32(buf_len);
|
||||
data->lba = offset >> BDRV_SECTOR_BITS;
|
||||
data->size = buf_len;
|
||||
|
||||
n_bytes = buf_len + sizeof(VmdkGrainMarker);
|
||||
iov = (struct iovec) {
|
||||
|
||||
@@ -175,7 +175,7 @@ int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
|
||||
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
|
||||
AioContext *old_context)
|
||||
{
|
||||
aio_set_event_notifier(old_context, &aio->e, false, NULL);
|
||||
aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL);
|
||||
aio->is_aio_context_attached = false;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
|
||||
{
|
||||
aio->is_aio_context_attached = true;
|
||||
aio_set_event_notifier(new_context, &aio->e, false,
|
||||
win32_aio_completion_cb);
|
||||
win32_aio_completion_cb, NULL);
|
||||
}
|
||||
|
||||
QEMUWin32AIOState *win32_aio_init(void)
|
||||
|
||||
21
configure
vendored
21
configure
vendored
@@ -28,8 +28,6 @@ TMPB="qemu-conf"
|
||||
TMPC="${TMPDIR1}/${TMPB}.c"
|
||||
TMPO="${TMPDIR1}/${TMPB}.o"
|
||||
TMPCXX="${TMPDIR1}/${TMPB}.cxx"
|
||||
TMPL="${TMPDIR1}/${TMPB}.lo"
|
||||
TMPA="${TMPDIR1}/lib${TMPB}.la"
|
||||
TMPE="${TMPDIR1}/${TMPB}.exe"
|
||||
TMPMO="${TMPDIR1}/${TMPB}.mo"
|
||||
|
||||
@@ -313,6 +311,7 @@ gnutls_rnd=""
|
||||
nettle=""
|
||||
nettle_kdf="no"
|
||||
gcrypt=""
|
||||
gcrypt_hmac="no"
|
||||
gcrypt_kdf="no"
|
||||
vte=""
|
||||
virglrenderer=""
|
||||
@@ -2417,6 +2416,19 @@ EOF
|
||||
if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
||||
gcrypt_kdf=yes
|
||||
fi
|
||||
|
||||
cat > $TMPC << EOF
|
||||
#include <gcrypt.h>
|
||||
int main(void) {
|
||||
gcry_mac_hd_t handle;
|
||||
gcry_mac_open(&handle, GCRY_MAC_HMAC_MD5,
|
||||
GCRY_MAC_FLAG_SECURE, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
||||
gcrypt_hmac=yes
|
||||
fi
|
||||
else
|
||||
if test "$gcrypt" = "yes"; then
|
||||
feature_not_found "gcrypt" "Install gcrypt devel"
|
||||
@@ -2738,7 +2750,7 @@ if compile_prog "" "" ; then
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# xfsctl() probe, used for raw-posix
|
||||
# xfsctl() probe, used for file-posix.c
|
||||
if test "$xfs" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <stddef.h> /* NULL */
|
||||
@@ -5387,6 +5399,9 @@ if test "$gnutls_rnd" = "yes" ; then
|
||||
fi
|
||||
if test "$gcrypt" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT=y" >> $config_host_mak
|
||||
if test "$gcrypt_hmac" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT_HMAC=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$gcrypt_kdf" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT_KDF=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
1
contrib/libvhost-user/Makefile.objs
Normal file
1
contrib/libvhost-user/Makefile.objs
Normal file
@@ -0,0 +1 @@
|
||||
libvhost-user-obj-y = libvhost-user.o
|
||||
1499
contrib/libvhost-user/libvhost-user.c
Normal file
1499
contrib/libvhost-user/libvhost-user.c
Normal file
File diff suppressed because it is too large
Load Diff
435
contrib/libvhost-user/libvhost-user.h
Normal file
435
contrib/libvhost-user/libvhost-user.h
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Vhost User library
|
||||
*
|
||||
* Copyright (c) 2016 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Victor Kaplansky <victork@redhat.com>
|
||||
* Marc-André Lureau <mlureau@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef LIBVHOST_USER_H
|
||||
#define LIBVHOST_USER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <linux/vhost.h>
|
||||
#include "standard-headers/linux/virtio_ring.h"
|
||||
|
||||
/* Based on qemu/hw/virtio/vhost-user.c */
|
||||
#define VHOST_USER_F_PROTOCOL_FEATURES 30
|
||||
#define VHOST_LOG_PAGE 4096
|
||||
|
||||
#define VHOST_MAX_NR_VIRTQUEUE 8
|
||||
#define VIRTQUEUE_MAX_SIZE 1024
|
||||
|
||||
#define VHOST_MEMORY_MAX_NREGIONS 8
|
||||
|
||||
enum VhostUserProtocolFeature {
|
||||
VHOST_USER_PROTOCOL_F_MQ = 0,
|
||||
VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
|
||||
VHOST_USER_PROTOCOL_F_RARP = 2,
|
||||
|
||||
VHOST_USER_PROTOCOL_F_MAX
|
||||
};
|
||||
|
||||
#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
|
||||
|
||||
typedef enum VhostUserRequest {
|
||||
VHOST_USER_NONE = 0,
|
||||
VHOST_USER_GET_FEATURES = 1,
|
||||
VHOST_USER_SET_FEATURES = 2,
|
||||
VHOST_USER_SET_OWNER = 3,
|
||||
VHOST_USER_RESET_OWNER = 4,
|
||||
VHOST_USER_SET_MEM_TABLE = 5,
|
||||
VHOST_USER_SET_LOG_BASE = 6,
|
||||
VHOST_USER_SET_LOG_FD = 7,
|
||||
VHOST_USER_SET_VRING_NUM = 8,
|
||||
VHOST_USER_SET_VRING_ADDR = 9,
|
||||
VHOST_USER_SET_VRING_BASE = 10,
|
||||
VHOST_USER_GET_VRING_BASE = 11,
|
||||
VHOST_USER_SET_VRING_KICK = 12,
|
||||
VHOST_USER_SET_VRING_CALL = 13,
|
||||
VHOST_USER_SET_VRING_ERR = 14,
|
||||
VHOST_USER_GET_PROTOCOL_FEATURES = 15,
|
||||
VHOST_USER_SET_PROTOCOL_FEATURES = 16,
|
||||
VHOST_USER_GET_QUEUE_NUM = 17,
|
||||
VHOST_USER_SET_VRING_ENABLE = 18,
|
||||
VHOST_USER_SEND_RARP = 19,
|
||||
VHOST_USER_INPUT_GET_CONFIG = 20,
|
||||
VHOST_USER_MAX
|
||||
} VhostUserRequest;
|
||||
|
||||
typedef struct VhostUserMemoryRegion {
|
||||
uint64_t guest_phys_addr;
|
||||
uint64_t memory_size;
|
||||
uint64_t userspace_addr;
|
||||
uint64_t mmap_offset;
|
||||
} VhostUserMemoryRegion;
|
||||
|
||||
typedef struct VhostUserMemory {
|
||||
uint32_t nregions;
|
||||
uint32_t padding;
|
||||
VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
|
||||
} VhostUserMemory;
|
||||
|
||||
typedef struct VhostUserLog {
|
||||
uint64_t mmap_size;
|
||||
uint64_t mmap_offset;
|
||||
} VhostUserLog;
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define VU_PACKED __attribute__((gcc_struct, packed))
|
||||
#else
|
||||
# define VU_PACKED __attribute__((packed))
|
||||
#endif
|
||||
|
||||
typedef struct VhostUserMsg {
|
||||
VhostUserRequest request;
|
||||
|
||||
#define VHOST_USER_VERSION_MASK (0x3)
|
||||
#define VHOST_USER_REPLY_MASK (0x1 << 2)
|
||||
uint32_t flags;
|
||||
uint32_t size; /* the following payload size */
|
||||
|
||||
union {
|
||||
#define VHOST_USER_VRING_IDX_MASK (0xff)
|
||||
#define VHOST_USER_VRING_NOFD_MASK (0x1 << 8)
|
||||
uint64_t u64;
|
||||
struct vhost_vring_state state;
|
||||
struct vhost_vring_addr addr;
|
||||
VhostUserMemory memory;
|
||||
VhostUserLog log;
|
||||
} payload;
|
||||
|
||||
int fds[VHOST_MEMORY_MAX_NREGIONS];
|
||||
int fd_num;
|
||||
uint8_t *data;
|
||||
} VU_PACKED VhostUserMsg;
|
||||
|
||||
typedef struct VuDevRegion {
|
||||
/* Guest Physical address. */
|
||||
uint64_t gpa;
|
||||
/* Memory region size. */
|
||||
uint64_t size;
|
||||
/* QEMU virtual address (userspace). */
|
||||
uint64_t qva;
|
||||
/* Starting offset in our mmaped space. */
|
||||
uint64_t mmap_offset;
|
||||
/* Start address of mmaped space. */
|
||||
uint64_t mmap_addr;
|
||||
} VuDevRegion;
|
||||
|
||||
typedef struct VuDev VuDev;
|
||||
|
||||
typedef uint64_t (*vu_get_features_cb) (VuDev *dev);
|
||||
typedef void (*vu_set_features_cb) (VuDev *dev, uint64_t features);
|
||||
typedef int (*vu_process_msg_cb) (VuDev *dev, VhostUserMsg *vmsg,
|
||||
int *do_reply);
|
||||
typedef void (*vu_queue_set_started_cb) (VuDev *dev, int qidx, bool started);
|
||||
|
||||
typedef struct VuDevIface {
|
||||
/* called by VHOST_USER_GET_FEATURES to get the features bitmask */
|
||||
vu_get_features_cb get_features;
|
||||
/* enable vhost implementation features */
|
||||
vu_set_features_cb set_features;
|
||||
/* get the protocol feature bitmask from the underlying vhost
|
||||
* implementation */
|
||||
vu_get_features_cb get_protocol_features;
|
||||
/* enable protocol features in the underlying vhost implementation. */
|
||||
vu_set_features_cb set_protocol_features;
|
||||
/* process_msg is called for each vhost-user message received */
|
||||
/* skip libvhost-user processing if return value != 0 */
|
||||
vu_process_msg_cb process_msg;
|
||||
/* tells when queues can be processed */
|
||||
vu_queue_set_started_cb queue_set_started;
|
||||
} VuDevIface;
|
||||
|
||||
typedef void (*vu_queue_handler_cb) (VuDev *dev, int qidx);
|
||||
|
||||
typedef struct VuRing {
|
||||
unsigned int num;
|
||||
struct vring_desc *desc;
|
||||
struct vring_avail *avail;
|
||||
struct vring_used *used;
|
||||
uint64_t log_guest_addr;
|
||||
uint32_t flags;
|
||||
} VuRing;
|
||||
|
||||
typedef struct VuVirtq {
|
||||
VuRing vring;
|
||||
|
||||
/* Next head to pop */
|
||||
uint16_t last_avail_idx;
|
||||
|
||||
/* Last avail_idx read from VQ. */
|
||||
uint16_t shadow_avail_idx;
|
||||
|
||||
uint16_t used_idx;
|
||||
|
||||
/* Last used index value we have signalled on */
|
||||
uint16_t signalled_used;
|
||||
|
||||
/* Last used index value we have signalled on */
|
||||
bool signalled_used_valid;
|
||||
|
||||
/* Notification enabled? */
|
||||
bool notification;
|
||||
|
||||
int inuse;
|
||||
|
||||
vu_queue_handler_cb handler;
|
||||
|
||||
int call_fd;
|
||||
int kick_fd;
|
||||
int err_fd;
|
||||
unsigned int enable;
|
||||
bool started;
|
||||
} VuVirtq;
|
||||
|
||||
enum VuWatchCondtion {
|
||||
VU_WATCH_IN = 1 << 0,
|
||||
VU_WATCH_OUT = 1 << 1,
|
||||
VU_WATCH_PRI = 1 << 2,
|
||||
VU_WATCH_ERR = 1 << 3,
|
||||
VU_WATCH_HUP = 1 << 4,
|
||||
};
|
||||
|
||||
typedef void (*vu_panic_cb) (VuDev *dev, const char *err);
|
||||
typedef void (*vu_watch_cb) (VuDev *dev, int condition, void *data);
|
||||
typedef void (*vu_set_watch_cb) (VuDev *dev, int fd, int condition,
|
||||
vu_watch_cb cb, void *data);
|
||||
typedef void (*vu_remove_watch_cb) (VuDev *dev, int fd);
|
||||
|
||||
struct VuDev {
|
||||
int sock;
|
||||
uint32_t nregions;
|
||||
VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS];
|
||||
VuVirtq vq[VHOST_MAX_NR_VIRTQUEUE];
|
||||
int log_call_fd;
|
||||
uint64_t log_size;
|
||||
uint8_t *log_table;
|
||||
uint64_t features;
|
||||
uint64_t protocol_features;
|
||||
bool broken;
|
||||
|
||||
/* @set_watch: add or update the given fd to the watch set,
|
||||
* call cb when condition is met */
|
||||
vu_set_watch_cb set_watch;
|
||||
|
||||
/* @remove_watch: remove the given fd from the watch set */
|
||||
vu_remove_watch_cb remove_watch;
|
||||
|
||||
/* @panic: encountered an unrecoverable error, you may try to
|
||||
* re-initialize */
|
||||
vu_panic_cb panic;
|
||||
const VuDevIface *iface;
|
||||
};
|
||||
|
||||
typedef struct VuVirtqElement {
|
||||
unsigned int index;
|
||||
unsigned int out_num;
|
||||
unsigned int in_num;
|
||||
struct iovec *in_sg;
|
||||
struct iovec *out_sg;
|
||||
} VuVirtqElement;
|
||||
|
||||
/**
|
||||
* vu_init:
|
||||
* @dev: a VuDev context
|
||||
* @socket: the socket connected to vhost-user master
|
||||
* @panic: a panic callback
|
||||
* @set_watch: a set_watch callback
|
||||
* @remove_watch: a remove_watch callback
|
||||
* @iface: a VuDevIface structure with vhost-user device callbacks
|
||||
*
|
||||
* Intializes a VuDev vhost-user context.
|
||||
**/
|
||||
void vu_init(VuDev *dev,
|
||||
int socket,
|
||||
vu_panic_cb panic,
|
||||
vu_set_watch_cb set_watch,
|
||||
vu_remove_watch_cb remove_watch,
|
||||
const VuDevIface *iface);
|
||||
|
||||
|
||||
/**
|
||||
* vu_deinit:
|
||||
* @dev: a VuDev context
|
||||
*
|
||||
* Cleans up the VuDev context
|
||||
*/
|
||||
void vu_deinit(VuDev *dev);
|
||||
|
||||
/**
|
||||
* vu_dispatch:
|
||||
* @dev: a VuDev context
|
||||
*
|
||||
* Process one vhost-user message.
|
||||
*
|
||||
* Returns: TRUE on success, FALSE on failure.
|
||||
*/
|
||||
bool vu_dispatch(VuDev *dev);
|
||||
|
||||
/**
|
||||
* vu_gpa_to_va:
|
||||
* @dev: a VuDev context
|
||||
* @guest_addr: guest address
|
||||
*
|
||||
* Translate a guest address to a pointer. Returns NULL on failure.
|
||||
*/
|
||||
void *vu_gpa_to_va(VuDev *dev, uint64_t guest_addr);
|
||||
|
||||
/**
|
||||
* vu_get_queue:
|
||||
* @dev: a VuDev context
|
||||
* @qidx: queue index
|
||||
*
|
||||
* Returns the queue number @qidx.
|
||||
*/
|
||||
VuVirtq *vu_get_queue(VuDev *dev, int qidx);
|
||||
|
||||
/**
|
||||
* vu_set_queue_handler:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @handler: the queue handler callback
|
||||
*
|
||||
* Set the queue handler. This function may be called several times
|
||||
* for the same queue. If called with NULL @handler, the handler is
|
||||
* removed.
|
||||
*/
|
||||
void vu_set_queue_handler(VuDev *dev, VuVirtq *vq,
|
||||
vu_queue_handler_cb handler);
|
||||
|
||||
|
||||
/**
|
||||
* vu_queue_set_notification:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @enable: state
|
||||
*
|
||||
* Set whether the queue notifies (via event index or interrupt)
|
||||
*/
|
||||
void vu_queue_set_notification(VuDev *dev, VuVirtq *vq, int enable);
|
||||
|
||||
/**
|
||||
* vu_queue_enabled:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
*
|
||||
* Returns: whether the queue is enabled.
|
||||
*/
|
||||
bool vu_queue_enabled(VuDev *dev, VuVirtq *vq);
|
||||
|
||||
/**
|
||||
* vu_queue_enabled:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
*
|
||||
* Returns: whether the queue is empty.
|
||||
*/
|
||||
int vu_queue_empty(VuDev *dev, VuVirtq *vq);
|
||||
|
||||
/**
|
||||
* vu_queue_notify:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
*
|
||||
* Request to notify the queue via callfd (skipped if unnecessary)
|
||||
*/
|
||||
void vu_queue_notify(VuDev *dev, VuVirtq *vq);
|
||||
|
||||
/**
|
||||
* vu_queue_pop:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @sz: the size of struct to return (must be >= VuVirtqElement)
|
||||
*
|
||||
* Returns: a VuVirtqElement filled from the queue or NULL.
|
||||
*/
|
||||
void *vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz);
|
||||
|
||||
/**
|
||||
* vu_queue_rewind:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @num: number of elements to push back
|
||||
*
|
||||
* Pretend that elements weren't popped from the virtqueue. The next
|
||||
* virtqueue_pop() will refetch the oldest element.
|
||||
*
|
||||
* Returns: true on success, false if @num is greater than the number of in use
|
||||
* elements.
|
||||
*/
|
||||
bool vu_queue_rewind(VuDev *dev, VuVirtq *vq, unsigned int num);
|
||||
|
||||
/**
|
||||
* vu_queue_fill:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @elem: a VuVirtqElement
|
||||
* @len: length in bytes to write
|
||||
* @idx: optional offset for the used ring index (0 in general)
|
||||
*
|
||||
* Fill the used ring with @elem element.
|
||||
*/
|
||||
void vu_queue_fill(VuDev *dev, VuVirtq *vq,
|
||||
const VuVirtqElement *elem,
|
||||
unsigned int len, unsigned int idx);
|
||||
|
||||
/**
|
||||
* vu_queue_push:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @elem: a VuVirtqElement
|
||||
* @len: length in bytes to write
|
||||
*
|
||||
* Helper that combines vu_queue_fill() with a vu_queue_flush().
|
||||
*/
|
||||
void vu_queue_push(VuDev *dev, VuVirtq *vq,
|
||||
const VuVirtqElement *elem, unsigned int len);
|
||||
|
||||
/**
|
||||
* vu_queue_flush:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @num: number of elements to flush
|
||||
*
|
||||
* Mark the last number of elements as done (used.idx is updated by
|
||||
* num elements).
|
||||
*/
|
||||
void vu_queue_flush(VuDev *dev, VuVirtq *vq, unsigned int num);
|
||||
|
||||
/**
|
||||
* vu_queue_get_avail_bytes:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @in_bytes: in bytes
|
||||
* @out_bytes: out bytes
|
||||
* @max_in_bytes: stop counting after max_in_bytes
|
||||
* @max_out_bytes: stop counting after max_out_bytes
|
||||
*
|
||||
* Count the number of available bytes, up to max_in_bytes/max_out_bytes.
|
||||
*/
|
||||
void vu_queue_get_avail_bytes(VuDev *vdev, VuVirtq *vq, unsigned int *in_bytes,
|
||||
unsigned int *out_bytes,
|
||||
unsigned max_in_bytes, unsigned max_out_bytes);
|
||||
|
||||
/**
|
||||
* vu_queue_avail_bytes:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @in_bytes: expected in bytes
|
||||
* @out_bytes: expected out bytes
|
||||
*
|
||||
* Returns: true if in_bytes <= in_total && out_bytes <= out_total
|
||||
*/
|
||||
bool vu_queue_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int in_bytes,
|
||||
unsigned int out_bytes);
|
||||
|
||||
#endif /* LIBVHOST_USER_H */
|
||||
@@ -491,7 +491,7 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
|
||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||
CPUArchState *env = &x86_cpu->env;
|
||||
replay_interrupt();
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0, 0);
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
||||
do_cpu_init(x86_cpu);
|
||||
cpu->exception_index = EXCP_HALTED;
|
||||
cpu_loop_exit(cpu);
|
||||
@@ -542,7 +542,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
|
||||
trace_exec_tb(tb, tb->pc);
|
||||
ret = cpu_tb_exec(cpu, tb);
|
||||
tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
||||
*last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
||||
*tb_exit = ret & TB_EXIT_MASK;
|
||||
switch (*tb_exit) {
|
||||
case TB_EXIT_REQUESTED:
|
||||
@@ -566,7 +566,6 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
abort();
|
||||
#else
|
||||
int insns_left = cpu->icount_decr.u32;
|
||||
*last_tb = NULL;
|
||||
if (cpu->icount_extra && insns_left >= 0) {
|
||||
/* Refill decrementer and continue execution. */
|
||||
cpu->icount_extra += insns_left;
|
||||
@@ -576,17 +575,17 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
} else {
|
||||
if (insns_left > 0) {
|
||||
/* Execute remaining instructions. */
|
||||
cpu_exec_nocache(cpu, insns_left, tb, false);
|
||||
cpu_exec_nocache(cpu, insns_left, *last_tb, false);
|
||||
align_clocks(sc, cpu);
|
||||
}
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
*last_tb = NULL;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
default:
|
||||
*last_tb = tb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ crypto-obj-y += hash.o
|
||||
crypto-obj-$(CONFIG_NETTLE) += hash-nettle.o
|
||||
crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT)) += hash-gcrypt.o
|
||||
crypto-obj-$(if $(CONFIG_NETTLE),n,$(if $(CONFIG_GCRYPT),n,y)) += hash-glib.o
|
||||
crypto-obj-y += hmac.o
|
||||
crypto-obj-$(CONFIG_NETTLE) += hmac-nettle.o
|
||||
crypto-obj-$(CONFIG_GCRYPT_HMAC) += hmac-gcrypt.o
|
||||
crypto-obj-$(if $(CONFIG_NETTLE),n,$(if $(CONFIG_GCRYPT_HMAC),n,y)) += hmac-glib.o
|
||||
crypto-obj-y += aes.o
|
||||
crypto-obj-y += desrfb.o
|
||||
crypto-obj-y += cipher.o
|
||||
|
||||
@@ -29,6 +29,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
||||
{
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
case QCRYPTO_CIPHER_ALG_3DES:
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
@@ -99,6 +100,10 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
gcryalg = GCRY_CIPHER_DES;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_3DES:
|
||||
gcryalg = GCRY_CIPHER_3DES;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
gcryalg = GCRY_CIPHER_AES128;
|
||||
break;
|
||||
@@ -200,6 +205,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
ctx->blocksize = 16;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_ALG_3DES:
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
ctx->blocksize = 8;
|
||||
break;
|
||||
|
||||
@@ -78,6 +78,18 @@ static void des_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
des_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void des3_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
des3_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void des3_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
des3_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
@@ -140,6 +152,18 @@ static void des_decrypt_wrapper(const void *ctx, size_t length,
|
||||
des_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void des3_encrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
des3_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void des3_decrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
des3_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_encrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
@@ -197,6 +221,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
||||
{
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
case QCRYPTO_CIPHER_ALG_3DES:
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
@@ -254,6 +279,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
cipher->mode = mode;
|
||||
|
||||
ctx = g_new0(QCryptoCipherNettle, 1);
|
||||
cipher->opaque = ctx;
|
||||
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
@@ -270,6 +296,18 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
ctx->blocksize = DES_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_3DES:
|
||||
ctx->ctx = g_new0(struct des3_ctx, 1);
|
||||
des3_set_key(ctx->ctx, key);
|
||||
|
||||
ctx->alg_encrypt_native = des3_encrypt_native;
|
||||
ctx->alg_decrypt_native = des3_decrypt_native;
|
||||
ctx->alg_encrypt_wrapper = des3_encrypt_wrapper;
|
||||
ctx->alg_decrypt_wrapper = des3_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = DES3_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
@@ -384,13 +422,11 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
}
|
||||
|
||||
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||
cipher->opaque = ctx;
|
||||
|
||||
return cipher;
|
||||
|
||||
error:
|
||||
g_free(cipher);
|
||||
g_free(ctx);
|
||||
qcrypto_cipher_free(cipher);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
[QCRYPTO_CIPHER_ALG_AES_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
|
||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_3DES] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_192] = 24,
|
||||
@@ -42,6 +43,7 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
[QCRYPTO_CIPHER_ALG_AES_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_3DES] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_192] = 16,
|
||||
@@ -107,8 +109,9 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||
}
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||
error_setg(errp, "XTS mode not compatible with DES-RFB");
|
||||
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB
|
||||
|| alg == QCRYPTO_CIPHER_ALG_3DES) {
|
||||
error_setg(errp, "XTS mode not compatible with DES-RFB/3DES");
|
||||
return false;
|
||||
}
|
||||
if (nkey % 2) {
|
||||
|
||||
152
crypto/hmac-gcrypt.c
Normal file
152
crypto/hmac-gcrypt.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* QEMU Crypto hmac algorithms (based on libgcrypt)
|
||||
*
|
||||
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||
*
|
||||
* Authors:
|
||||
* Longpeng(Mike) <longpeng2@huawei.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "crypto/hmac.h"
|
||||
#include <gcrypt.h>
|
||||
|
||||
static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = GCRY_MAC_HMAC_MD5,
|
||||
[QCRYPTO_HASH_ALG_SHA1] = GCRY_MAC_HMAC_SHA1,
|
||||
[QCRYPTO_HASH_ALG_SHA224] = GCRY_MAC_HMAC_SHA224,
|
||||
[QCRYPTO_HASH_ALG_SHA256] = GCRY_MAC_HMAC_SHA256,
|
||||
[QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384,
|
||||
[QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512,
|
||||
[QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160,
|
||||
};
|
||||
|
||||
typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt;
|
||||
struct QCryptoHmacGcrypt {
|
||||
gcry_mac_hd_t handle;
|
||||
};
|
||||
|
||||
bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
|
||||
{
|
||||
if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
|
||||
qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoHmac *hmac;
|
||||
QCryptoHmacGcrypt *ctx;
|
||||
gcry_error_t err;
|
||||
|
||||
if (!qcrypto_hmac_supports(alg)) {
|
||||
error_setg(errp, "Unsupported hmac algorithm %s",
|
||||
QCryptoHashAlgorithm_lookup[alg]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hmac = g_new0(QCryptoHmac, 1);
|
||||
hmac->alg = alg;
|
||||
|
||||
ctx = g_new0(QCryptoHmacGcrypt, 1);
|
||||
|
||||
err = gcry_mac_open(&ctx->handle, qcrypto_hmac_alg_map[alg],
|
||||
GCRY_MAC_FLAG_SECURE, NULL);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot initialize hmac: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = gcry_mac_setkey(ctx->handle, (const void *)key, nkey);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
|
||||
hmac->opaque = ctx;
|
||||
return hmac;
|
||||
|
||||
error:
|
||||
g_free(ctx);
|
||||
g_free(hmac);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qcrypto_hmac_free(QCryptoHmac *hmac)
|
||||
{
|
||||
QCryptoHmacGcrypt *ctx;
|
||||
|
||||
if (!hmac) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = hmac->opaque;
|
||||
gcry_mac_close(ctx->handle);
|
||||
|
||||
g_free(ctx);
|
||||
g_free(hmac);
|
||||
}
|
||||
|
||||
int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoHmacGcrypt *ctx;
|
||||
gcry_error_t err;
|
||||
uint32_t ret;
|
||||
int i;
|
||||
|
||||
ctx = hmac->opaque;
|
||||
|
||||
for (i = 0; i < niov; i++) {
|
||||
gcry_mac_write(ctx->handle, iov[i].iov_base, iov[i].iov_len);
|
||||
}
|
||||
|
||||
ret = gcry_mac_get_algo_maclen(qcrypto_hmac_alg_map[hmac->alg]);
|
||||
if (ret <= 0) {
|
||||
error_setg(errp, "Unable to get hmac length: %s",
|
||||
gcry_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*resultlen == 0) {
|
||||
*resultlen = ret;
|
||||
*result = g_new0(uint8_t, *resultlen);
|
||||
} else if (*resultlen != ret) {
|
||||
error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
|
||||
*resultlen, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_mac_read(ctx->handle, *result, resultlen);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot get result: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_mac_reset(ctx->handle);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot reset hmac context: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
166
crypto/hmac-glib.c
Normal file
166
crypto/hmac-glib.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* QEMU Crypto hmac algorithms (based on glib)
|
||||
*
|
||||
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||
*
|
||||
* Authors:
|
||||
* Longpeng(Mike) <longpeng2@huawei.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "crypto/hmac.h"
|
||||
|
||||
/* Support for HMAC Algos has been added in GLib 2.30 */
|
||||
#if GLIB_CHECK_VERSION(2, 30, 0)
|
||||
|
||||
static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = G_CHECKSUM_MD5,
|
||||
[QCRYPTO_HASH_ALG_SHA1] = G_CHECKSUM_SHA1,
|
||||
[QCRYPTO_HASH_ALG_SHA256] = G_CHECKSUM_SHA256,
|
||||
/* Support for HMAC SHA-512 in GLib 2.42 */
|
||||
#if GLIB_CHECK_VERSION(2, 42, 0)
|
||||
[QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512,
|
||||
#else
|
||||
[QCRYPTO_HASH_ALG_SHA512] = -1,
|
||||
#endif
|
||||
[QCRYPTO_HASH_ALG_SHA224] = -1,
|
||||
[QCRYPTO_HASH_ALG_SHA384] = -1,
|
||||
[QCRYPTO_HASH_ALG_RIPEMD160] = -1,
|
||||
};
|
||||
|
||||
typedef struct QCryptoHmacGlib QCryptoHmacGlib;
|
||||
struct QCryptoHmacGlib {
|
||||
GHmac *ghmac;
|
||||
};
|
||||
|
||||
bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
|
||||
{
|
||||
if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
|
||||
qcrypto_hmac_alg_map[alg] != -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoHmac *hmac;
|
||||
QCryptoHmacGlib *ctx;
|
||||
|
||||
if (!qcrypto_hmac_supports(alg)) {
|
||||
error_setg(errp, "Unsupported hmac algorithm %s",
|
||||
QCryptoHashAlgorithm_lookup[alg]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hmac = g_new0(QCryptoHmac, 1);
|
||||
hmac->alg = alg;
|
||||
|
||||
ctx = g_new0(QCryptoHmacGlib, 1);
|
||||
|
||||
ctx->ghmac = g_hmac_new(qcrypto_hmac_alg_map[alg],
|
||||
(const uint8_t *)key, nkey);
|
||||
if (!ctx->ghmac) {
|
||||
error_setg(errp, "Cannot initialize hmac and set key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
hmac->opaque = ctx;
|
||||
return hmac;
|
||||
|
||||
error:
|
||||
g_free(ctx);
|
||||
g_free(hmac);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qcrypto_hmac_free(QCryptoHmac *hmac)
|
||||
{
|
||||
QCryptoHmacGlib *ctx;
|
||||
|
||||
if (!hmac) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = hmac->opaque;
|
||||
g_hmac_unref(ctx->ghmac);
|
||||
|
||||
g_free(ctx);
|
||||
g_free(hmac);
|
||||
}
|
||||
|
||||
int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoHmacGlib *ctx;
|
||||
int i, ret;
|
||||
|
||||
ctx = hmac->opaque;
|
||||
|
||||
for (i = 0; i < niov; i++) {
|
||||
g_hmac_update(ctx->ghmac, iov[i].iov_base, iov[i].iov_len);
|
||||
}
|
||||
|
||||
ret = g_checksum_type_get_length(qcrypto_hmac_alg_map[hmac->alg]);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to get hmac length");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*resultlen == 0) {
|
||||
*resultlen = ret;
|
||||
*result = g_new0(uint8_t, *resultlen);
|
||||
} else if (*resultlen != ret) {
|
||||
error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
|
||||
*resultlen, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_hmac_get_digest(ctx->ghmac, *result, resultlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qcrypto_hmac_free(QCryptoHmac *hmac)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
175
crypto/hmac-nettle.c
Normal file
175
crypto/hmac-nettle.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* QEMU Crypto hmac algorithms (based on nettle)
|
||||
*
|
||||
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||
*
|
||||
* Authors:
|
||||
* Longpeng(Mike) <longpeng2@huawei.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "crypto/hmac.h"
|
||||
#include <nettle/hmac.h>
|
||||
|
||||
typedef void (*qcrypto_nettle_hmac_setkey)(void *ctx,
|
||||
size_t key_length, const uint8_t *key);
|
||||
|
||||
typedef void (*qcrypto_nettle_hmac_update)(void *ctx,
|
||||
size_t length, const uint8_t *data);
|
||||
|
||||
typedef void (*qcrypto_nettle_hmac_digest)(void *ctx,
|
||||
size_t length, uint8_t *digest);
|
||||
|
||||
typedef struct QCryptoHmacNettle QCryptoHmacNettle;
|
||||
struct QCryptoHmacNettle {
|
||||
union qcrypto_nettle_hmac_ctx {
|
||||
struct hmac_md5_ctx md5_ctx;
|
||||
struct hmac_sha1_ctx sha1_ctx;
|
||||
struct hmac_sha256_ctx sha256_ctx; /* equals hmac_sha224_ctx */
|
||||
struct hmac_sha512_ctx sha512_ctx; /* equals hmac_sha384_ctx */
|
||||
struct hmac_ripemd160_ctx ripemd160_ctx;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct qcrypto_nettle_hmac_alg {
|
||||
qcrypto_nettle_hmac_setkey setkey;
|
||||
qcrypto_nettle_hmac_update update;
|
||||
qcrypto_nettle_hmac_digest digest;
|
||||
size_t len;
|
||||
} qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = {
|
||||
.setkey = (qcrypto_nettle_hmac_setkey)hmac_md5_set_key,
|
||||
.update = (qcrypto_nettle_hmac_update)hmac_md5_update,
|
||||
.digest = (qcrypto_nettle_hmac_digest)hmac_md5_digest,
|
||||
.len = MD5_DIGEST_SIZE,
|
||||
},
|
||||
[QCRYPTO_HASH_ALG_SHA1] = {
|
||||
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha1_set_key,
|
||||
.update = (qcrypto_nettle_hmac_update)hmac_sha1_update,
|
||||
.digest = (qcrypto_nettle_hmac_digest)hmac_sha1_digest,
|
||||
.len = SHA1_DIGEST_SIZE,
|
||||
},
|
||||
[QCRYPTO_HASH_ALG_SHA224] = {
|
||||
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha224_set_key,
|
||||
.update = (qcrypto_nettle_hmac_update)hmac_sha224_update,
|
||||
.digest = (qcrypto_nettle_hmac_digest)hmac_sha224_digest,
|
||||
.len = SHA224_DIGEST_SIZE,
|
||||
},
|
||||
[QCRYPTO_HASH_ALG_SHA256] = {
|
||||
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha256_set_key,
|
||||
.update = (qcrypto_nettle_hmac_update)hmac_sha256_update,
|
||||
.digest = (qcrypto_nettle_hmac_digest)hmac_sha256_digest,
|
||||
.len = SHA256_DIGEST_SIZE,
|
||||
},
|
||||
[QCRYPTO_HASH_ALG_SHA384] = {
|
||||
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha384_set_key,
|
||||
.update = (qcrypto_nettle_hmac_update)hmac_sha384_update,
|
||||
.digest = (qcrypto_nettle_hmac_digest)hmac_sha384_digest,
|
||||
.len = SHA384_DIGEST_SIZE,
|
||||
},
|
||||
[QCRYPTO_HASH_ALG_SHA512] = {
|
||||
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha512_set_key,
|
||||
.update = (qcrypto_nettle_hmac_update)hmac_sha512_update,
|
||||
.digest = (qcrypto_nettle_hmac_digest)hmac_sha512_digest,
|
||||
.len = SHA512_DIGEST_SIZE,
|
||||
},
|
||||
[QCRYPTO_HASH_ALG_RIPEMD160] = {
|
||||
.setkey = (qcrypto_nettle_hmac_setkey)hmac_ripemd160_set_key,
|
||||
.update = (qcrypto_nettle_hmac_update)hmac_ripemd160_update,
|
||||
.digest = (qcrypto_nettle_hmac_digest)hmac_ripemd160_digest,
|
||||
.len = RIPEMD160_DIGEST_SIZE,
|
||||
},
|
||||
};
|
||||
|
||||
bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
|
||||
{
|
||||
if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
|
||||
qcrypto_hmac_alg_map[alg].setkey != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoHmac *hmac;
|
||||
QCryptoHmacNettle *ctx;
|
||||
|
||||
if (!qcrypto_hmac_supports(alg)) {
|
||||
error_setg(errp, "Unsupported hmac algorithm %s",
|
||||
QCryptoHashAlgorithm_lookup[alg]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hmac = g_new0(QCryptoHmac, 1);
|
||||
hmac->alg = alg;
|
||||
|
||||
ctx = g_new0(QCryptoHmacNettle, 1);
|
||||
|
||||
qcrypto_hmac_alg_map[alg].setkey(&ctx->u, nkey, key);
|
||||
|
||||
hmac->opaque = ctx;
|
||||
|
||||
return hmac;
|
||||
}
|
||||
|
||||
void qcrypto_hmac_free(QCryptoHmac *hmac)
|
||||
{
|
||||
QCryptoHmacNettle *ctx;
|
||||
|
||||
if (!hmac) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = hmac->opaque;
|
||||
|
||||
g_free(ctx);
|
||||
g_free(hmac);
|
||||
}
|
||||
|
||||
int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoHmacNettle *ctx;
|
||||
int i;
|
||||
|
||||
ctx = (QCryptoHmacNettle *)hmac->opaque;
|
||||
|
||||
for (i = 0; i < niov; ++i) {
|
||||
size_t len = iov[i].iov_len;
|
||||
uint8_t *base = iov[i].iov_base;
|
||||
while (len) {
|
||||
size_t shortlen = MIN(len, UINT_MAX);
|
||||
qcrypto_hmac_alg_map[hmac->alg].update(&ctx->u, len, base);
|
||||
len -= shortlen;
|
||||
base += len;
|
||||
}
|
||||
}
|
||||
|
||||
if (*resultlen == 0) {
|
||||
*resultlen = qcrypto_hmac_alg_map[hmac->alg].len;
|
||||
*result = g_new0(uint8_t, *resultlen);
|
||||
} else if (*resultlen != qcrypto_hmac_alg_map[hmac->alg].len) {
|
||||
error_setg(errp,
|
||||
"Result buffer size %zu is smaller than hash %zu",
|
||||
*resultlen, qcrypto_hmac_alg_map[hmac->alg].len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
qcrypto_hmac_alg_map[hmac->alg].digest(&ctx->u, *resultlen, *result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
72
crypto/hmac.c
Normal file
72
crypto/hmac.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* QEMU Crypto hmac algorithms
|
||||
*
|
||||
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "crypto/hmac.h"
|
||||
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
|
||||
int qcrypto_hmac_bytes(QCryptoHmac *hmac,
|
||||
const char *buf,
|
||||
size_t len,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp)
|
||||
{
|
||||
struct iovec iov = {
|
||||
.iov_base = (char *)buf,
|
||||
.iov_len = len
|
||||
};
|
||||
|
||||
return qcrypto_hmac_bytesv(hmac, &iov, 1, result, resultlen, errp);
|
||||
}
|
||||
|
||||
int qcrypto_hmac_digestv(QCryptoHmac *hmac,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
char **digest,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *result = NULL;
|
||||
size_t resultlen = 0;
|
||||
size_t i;
|
||||
|
||||
if (qcrypto_hmac_bytesv(hmac, iov, niov, &result, &resultlen, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*digest = g_new0(char, (resultlen * 2) + 1);
|
||||
|
||||
for (i = 0 ; i < resultlen ; i++) {
|
||||
(*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
|
||||
(*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
|
||||
}
|
||||
|
||||
(*digest)[resultlen * 2] = '\0';
|
||||
|
||||
g_free(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qcrypto_hmac_digest(QCryptoHmac *hmac,
|
||||
const char *buf,
|
||||
size_t len,
|
||||
char **digest,
|
||||
Error **errp)
|
||||
{
|
||||
struct iovec iov = {
|
||||
.iov_base = (char *)buf,
|
||||
.iov_len = len
|
||||
};
|
||||
|
||||
return qcrypto_hmac_digestv(hmac, &iov, 1, digest, errp);
|
||||
}
|
||||
166
crypto/hmac.h
Normal file
166
crypto/hmac.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* QEMU Crypto hmac algorithms
|
||||
*
|
||||
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_HMAC_H
|
||||
#define QCRYPTO_HMAC_H
|
||||
|
||||
#include "qapi-types.h"
|
||||
|
||||
typedef struct QCryptoHmac QCryptoHmac;
|
||||
struct QCryptoHmac {
|
||||
QCryptoHashAlgorithm alg;
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
/**
|
||||
* qcrypto_hmac_supports:
|
||||
* @alg: the hmac algorithm
|
||||
*
|
||||
* Determine if @alg hmac algorithm is supported by
|
||||
* the current configured build
|
||||
*
|
||||
* Returns:
|
||||
* true if the algorithm is supported, false otherwise
|
||||
*/
|
||||
bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg);
|
||||
|
||||
/**
|
||||
* qcrypto_hmac_new:
|
||||
* @alg: the hmac algorithm
|
||||
* @key: the key bytes
|
||||
* @nkey: the length of @key
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Creates a new hmac object with the algorithm @alg
|
||||
*
|
||||
* The @key parameter provides the bytes representing
|
||||
* the secret key to use. The @nkey parameter specifies
|
||||
* the length of @key in bytes
|
||||
*
|
||||
* Note: must use qcrypto_hmac_free() to release the
|
||||
* returned hmac object when no longer required
|
||||
*
|
||||
* Returns:
|
||||
* a new hmac object, or NULL on error
|
||||
*/
|
||||
QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_hmac_free:
|
||||
* @hmac: the hmac object
|
||||
*
|
||||
* Release the memory associated with @hmac that was
|
||||
* previously allocated by qcrypto_hmac_new()
|
||||
*/
|
||||
void qcrypto_hmac_free(QCryptoHmac *hmac);
|
||||
|
||||
/**
|
||||
* qcrypto_hmac_bytesv:
|
||||
* @hmac: the hmac object
|
||||
* @iov: the array of memory regions to hmac
|
||||
* @niov: the length of @iov
|
||||
* @result: pointer to hold output hmac
|
||||
* @resultlen: pointer to hold length of @result
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hmac across all the memory regions
|
||||
* present in @iov. The @result pointer will be
|
||||
* filled with raw bytes representing the computed
|
||||
* hmac, which will have length @resultlen. The
|
||||
* memory pointer in @result must be released
|
||||
* with a call to g_free() when no longer required.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_hmac_bytes:
|
||||
* @hmac: the hmac object
|
||||
* @buf: the memory region to hmac
|
||||
* @len: the length of @buf
|
||||
* @result: pointer to hold output hmac
|
||||
* @resultlen: pointer to hold length of @result
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hmac across all the memory region
|
||||
* @buf of length @len. The @result pointer will be
|
||||
* filled with raw bytes representing the computed
|
||||
* hmac, which will have length @resultlen. The
|
||||
* memory pointer in @result must be released
|
||||
* with a call to g_free() when no longer required.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hmac_bytes(QCryptoHmac *hmac,
|
||||
const char *buf,
|
||||
size_t len,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_hmac_digestv:
|
||||
* @hmac: the hmac object
|
||||
* @iov: the array of memory regions to hmac
|
||||
* @niov: the length of @iov
|
||||
* @digest: pointer to hold output hmac
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hmac across all the memory regions
|
||||
* present in @iov. The @digest pointer will be
|
||||
* filled with the printable hex digest of the computed
|
||||
* hmac, which will be terminated by '\0'. The
|
||||
* memory pointer in @digest must be released
|
||||
* with a call to g_free() when no longer required.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hmac_digestv(QCryptoHmac *hmac,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
char **digest,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_hmac_digest:
|
||||
* @hmac: the hmac object
|
||||
* @buf: the memory region to hmac
|
||||
* @len: the length of @buf
|
||||
* @digest: pointer to hold output hmac
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hmac across all the memory region
|
||||
* @buf of length @len. The @digest pointer will be
|
||||
* filled with the printable hex digest of the computed
|
||||
* hmac, which will be terminated by '\0'. The
|
||||
* memory pointer in @digest must be released
|
||||
* with a call to g_free() when no longer required.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hmac_digest(QCryptoHmac *hmac,
|
||||
const char *buf,
|
||||
size_t len,
|
||||
char **digest,
|
||||
Error **errp);
|
||||
|
||||
#endif
|
||||
@@ -21,9 +21,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "disas/bfd.h"
|
||||
//#include "sysdep.h"
|
||||
#include "target-cris/opcode-cris.h"
|
||||
//#include "libiberty.h"
|
||||
#include "target/cris/opcode-cris.h"
|
||||
|
||||
#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0)
|
||||
|
||||
|
||||
@@ -4698,10 +4698,6 @@ get_field (const unsigned char *data, enum floatformat_byteorders order,
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/* Convert from FMT to a double.
|
||||
FROM is the address of the extended float.
|
||||
Store the double in *TO. */
|
||||
@@ -4733,7 +4729,7 @@ floatformat_to_double (const struct floatformat *fmt,
|
||||
nan = 0;
|
||||
while (mant_bits_left > 0)
|
||||
{
|
||||
mant_bits = min (mant_bits_left, 32);
|
||||
mant_bits = MIN(mant_bits_left, 32);
|
||||
|
||||
if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
|
||||
mant_off, mant_bits) != 0)
|
||||
@@ -4793,7 +4789,7 @@ floatformat_to_double (const struct floatformat *fmt,
|
||||
|
||||
while (mant_bits_left > 0)
|
||||
{
|
||||
mant_bits = min (mant_bits_left, 32);
|
||||
mant_bits = MIN(mant_bits_left, 32);
|
||||
|
||||
mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
|
||||
mant_off, mant_bits);
|
||||
|
||||
@@ -110,18 +110,18 @@ Plug only PCI Express devices into PCI Express Ports.
|
||||
-device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
|
||||
-device <dev>,bus=root_port1
|
||||
2.2.2 Using multi-function PCI Express Root Ports:
|
||||
-device ioh3420,id=root_port1,multifunction=on,chassis=x,slot=y[,bus=pcie.0][,addr=z.0] \
|
||||
-device ioh3420,id=root_port2,chassis=x1,slot=y1[,bus=pcie.0][,addr=z.1] \
|
||||
-device ioh3420,id=root_port3,chassis=x2,slot=y2[,bus=pcie.0][,addr=z.2] \
|
||||
2.2.2 Plugging a PCI Express device into a Switch:
|
||||
-device ioh3420,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \
|
||||
-device ioh3420,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \
|
||||
-device ioh3420,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \
|
||||
2.2.3 Plugging a PCI Express device into a Switch:
|
||||
-device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
|
||||
-device x3130-upstream,id=upstream_port1,bus=root_port1[,addr=x] \
|
||||
-device xio3130-downstream,id=downstream_port1,bus=upstream_port1,chassis=x1,slot=y1[,addr=z1]] \
|
||||
-device <dev>,bus=downstream_port1
|
||||
|
||||
Notes:
|
||||
- (slot, chassis) pair is mandatory and must be
|
||||
unique for each PCI Express Root Port.
|
||||
- (slot, chassis) pair is mandatory and must be unique for each
|
||||
PCI Express Root Port. slot defaults to 0 when not specified.
|
||||
- 'addr' parameter can be 0 for all the examples above.
|
||||
|
||||
|
||||
|
||||
@@ -195,3 +195,17 @@ Queue is flushed at checkpoints and information about processed requests
|
||||
is recorded to the log. In replay phase the queue is matched with
|
||||
events read from the log. Therefore block devices requests are processed
|
||||
deterministically.
|
||||
|
||||
Network devices
|
||||
---------------
|
||||
|
||||
Record and replay for network interactions is performed with the network filter.
|
||||
Each backend must have its own instance of the replay filter as follows:
|
||||
-netdev user,id=net1 -device rtl8139,netdev=net1
|
||||
-object filter-replay,id=replay,netdev=net1
|
||||
|
||||
Replay network filter is used to record and replay network packets. While
|
||||
recording the virtual machine this filter puts all packets coming from
|
||||
the outer world into the log. In replay mode packets from the log are
|
||||
injected into the network device. All interactions with network backend
|
||||
in replay mode are disabled.
|
||||
|
||||
@@ -259,6 +259,7 @@ Protocol features
|
||||
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
|
||||
#define VHOST_USER_PROTOCOL_F_RARP 2
|
||||
#define VHOST_USER_PROTOCOL_F_REPLY_ACK 3
|
||||
#define VHOST_USER_PROTOCOL_F_MTU 4
|
||||
|
||||
Message types
|
||||
-------------
|
||||
@@ -470,6 +471,21 @@ Message types
|
||||
The first 6 bytes of the payload contain the mac address of the guest to
|
||||
allow the vhost user backend to construct and broadcast the fake RARP.
|
||||
|
||||
* VHOST_USER_NET_SET_MTU
|
||||
|
||||
Id: 20
|
||||
Equivalent ioctl: N/A
|
||||
Master payload: u64
|
||||
|
||||
Set host MTU value exposed to the guest.
|
||||
This request should be sent only when VIRTIO_NET_F_MTU feature has been
|
||||
successfully negotiated, VHOST_USER_F_PROTOCOL_FEATURES is present in
|
||||
VHOST_USER_GET_FEATURES and protocol feature bit
|
||||
VHOST_USER_PROTOCOL_F_NET_MTU is present in
|
||||
VHOST_USER_GET_PROTOCOL_FEATURES.
|
||||
If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, slave must respond
|
||||
with zero in case the specified MTU is valid, or non-zero otherwise.
|
||||
|
||||
VHOST_USER_PROTOCOL_F_REPLY_ACK:
|
||||
-------------------------------
|
||||
The original vhost-user specification only demands replies for certain
|
||||
|
||||
737
exec.c
737
exec.c
@@ -448,6 +448,39 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
||||
return section;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
|
||||
bool is_write)
|
||||
{
|
||||
IOMMUTLBEntry iotlb = {0};
|
||||
MemoryRegionSection *section;
|
||||
MemoryRegion *mr;
|
||||
|
||||
for (;;) {
|
||||
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
|
||||
section = address_space_lookup_region(d, addr, false);
|
||||
addr = addr - section->offset_within_address_space
|
||||
+ section->offset_within_region;
|
||||
mr = section->mr;
|
||||
|
||||
if (!mr->iommu_ops) {
|
||||
break;
|
||||
}
|
||||
|
||||
iotlb = mr->iommu_ops->translate(mr, addr, is_write);
|
||||
if (!(iotlb.perm & (1 << is_write))) {
|
||||
iotlb.target_as = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
|
||||
| (addr & iotlb.addr_mask));
|
||||
as = iotlb.target_as;
|
||||
}
|
||||
|
||||
return iotlb;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
hwaddr *xlat, hwaddr *plen,
|
||||
@@ -2927,7 +2960,6 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
l = memory_access_size(mr, l, addr);
|
||||
if (!memory_region_access_valid(mr, xlat, l, is_write)) {
|
||||
rcu_read_unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2939,6 +2971,31 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
|
||||
return true;
|
||||
}
|
||||
|
||||
static hwaddr
|
||||
address_space_extend_translation(AddressSpace *as, hwaddr addr, hwaddr target_len,
|
||||
MemoryRegion *mr, hwaddr base, hwaddr len,
|
||||
bool is_write)
|
||||
{
|
||||
hwaddr done = 0;
|
||||
hwaddr xlat;
|
||||
MemoryRegion *this_mr;
|
||||
|
||||
for (;;) {
|
||||
target_len -= len;
|
||||
addr += len;
|
||||
done += len;
|
||||
if (target_len == 0) {
|
||||
return done;
|
||||
}
|
||||
|
||||
len = target_len;
|
||||
this_mr = address_space_translate(as, addr, &xlat, &len, is_write);
|
||||
if (this_mr != mr || xlat != base + done) {
|
||||
return done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Map a physical memory region into a host virtual address.
|
||||
* May map a subset of the requested range, given by and returned in *plen.
|
||||
* May return NULL if resources needed to perform the mapping are exhausted.
|
||||
@@ -2952,9 +3009,8 @@ void *address_space_map(AddressSpace *as,
|
||||
bool is_write)
|
||||
{
|
||||
hwaddr len = *plen;
|
||||
hwaddr done = 0;
|
||||
hwaddr l, xlat, base;
|
||||
MemoryRegion *mr, *this_mr;
|
||||
hwaddr l, xlat;
|
||||
MemoryRegion *mr;
|
||||
void *ptr;
|
||||
|
||||
if (len == 0) {
|
||||
@@ -2988,26 +3044,10 @@ void *address_space_map(AddressSpace *as,
|
||||
return bounce.buffer;
|
||||
}
|
||||
|
||||
base = xlat;
|
||||
|
||||
for (;;) {
|
||||
len -= l;
|
||||
addr += l;
|
||||
done += l;
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
l = len;
|
||||
this_mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
||||
if (this_mr != mr || xlat != base + done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memory_region_ref(mr);
|
||||
*plen = done;
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, base, plen);
|
||||
*plen = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ptr;
|
||||
@@ -3059,597 +3099,92 @@ void cpu_physical_memory_unmap(void *buffer, hwaddr len,
|
||||
return address_space_unmap(&address_space_memory, buffer, len, is_write, access_len);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
#define ARG1_DECL AddressSpace *as
|
||||
#define ARG1 as
|
||||
#define SUFFIX
|
||||
#define TRANSLATE(...) address_space_translate(as, __VA_ARGS__)
|
||||
#define IS_DIRECT(mr, is_write) memory_access_is_direct(mr, is_write)
|
||||
#define MAP_RAM(mr, ofs) qemu_map_ram_ptr((mr)->ram_block, ofs)
|
||||
#define INVALIDATE(mr, ofs, len) invalidate_and_set_dirty(mr, ofs, len)
|
||||
#define RCU_READ_LOCK(...) rcu_read_lock()
|
||||
#define RCU_READ_UNLOCK(...) rcu_read_unlock()
|
||||
#include "memory_ldst.inc.c"
|
||||
|
||||
int64_t address_space_cache_init(MemoryRegionCache *cache,
|
||||
AddressSpace *as,
|
||||
hwaddr addr,
|
||||
hwaddr len,
|
||||
bool is_write)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
hwaddr l, xlat;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 4;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
bool release_lock = false;
|
||||
void *ptr;
|
||||
|
||||
rcu_read_lock();
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
if (l < 4 || !memory_access_is_direct(mr, false)) {
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
assert(len > 0);
|
||||
|
||||
/* I/O case */
|
||||
r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = ldl_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = ldl_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = ldl_p(ptr);
|
||||
break;
|
||||
}
|
||||
r = MEMTX_OK;
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
|
||||
l = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, xlat, &l);
|
||||
|
||||
cache->xlat = xlat;
|
||||
cache->is_write = is_write;
|
||||
cache->mr = mr;
|
||||
cache->ptr = ptr;
|
||||
cache->len = l;
|
||||
memory_region_ref(cache->mr);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
void address_space_cache_invalidate(MemoryRegionCache *cache,
|
||||
hwaddr addr,
|
||||
hwaddr access_len)
|
||||
{
|
||||
assert(cache->is_write);
|
||||
invalidate_and_set_dirty(cache->mr, addr + cache->xlat, access_len);
|
||||
}
|
||||
|
||||
void address_space_cache_destroy(MemoryRegionCache *cache)
|
||||
{
|
||||
if (!cache->mr) {
|
||||
return;
|
||||
}
|
||||
if (release_lock) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
if (xen_enabled()) {
|
||||
xen_invalidate_map_cache_entry(cache->ptr);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return val;
|
||||
memory_region_unref(cache->mr);
|
||||
}
|
||||
|
||||
uint32_t address_space_ldl(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
/* Called from RCU critical section. This function has the same
|
||||
* semantics as address_space_translate, but it only works on a
|
||||
* predefined range of a MemoryRegion that was mapped with
|
||||
* address_space_cache_init.
|
||||
*/
|
||||
static inline MemoryRegion *address_space_translate_cached(
|
||||
MemoryRegionCache *cache, hwaddr addr, hwaddr *xlat,
|
||||
hwaddr *plen, bool is_write)
|
||||
{
|
||||
return address_space_ldl_internal(as, addr, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
assert(addr < cache->len && *plen <= cache->len - addr);
|
||||
*xlat = addr + cache->xlat;
|
||||
return cache->mr;
|
||||
}
|
||||
|
||||
uint32_t address_space_ldl_le(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldl_internal(as, addr, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t address_space_ldl_be(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldl_internal(as, addr, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t ldl_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_ldl(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_ldl_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 8;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
bool release_lock = false;
|
||||
|
||||
rcu_read_lock();
|
||||
mr = address_space_translate(as, addr, &addr1, &l,
|
||||
false);
|
||||
if (l < 8 || !memory_access_is_direct(mr, false)) {
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
|
||||
/* I/O case */
|
||||
r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap64(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap64(val);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = ldq_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = ldq_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = ldq_p(ptr);
|
||||
break;
|
||||
}
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
if (release_lock) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return val;
|
||||
}
|
||||
|
||||
uint64_t address_space_ldq(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldq_internal(as, addr, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t address_space_ldq_le(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldq_internal(as, addr, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t address_space_ldq_be(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldq_internal(as, addr, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t ldq_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_ldq(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_ldq_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_ldq_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
uint32_t address_space_ldub(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
uint8_t val;
|
||||
MemTxResult r;
|
||||
|
||||
r = address_space_rw(as, addr, attrs, &val, 1, 0);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t ldub_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline uint32_t address_space_lduw_internal(AddressSpace *as,
|
||||
hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 2;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
bool release_lock = false;
|
||||
|
||||
rcu_read_lock();
|
||||
mr = address_space_translate(as, addr, &addr1, &l,
|
||||
false);
|
||||
if (l < 2 || !memory_access_is_direct(mr, false)) {
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
|
||||
/* I/O case */
|
||||
r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = lduw_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = lduw_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = lduw_p(ptr);
|
||||
break;
|
||||
}
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
if (release_lock) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t address_space_lduw(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_lduw_internal(as, addr, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t address_space_lduw_le(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_lduw_internal(as, addr, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t address_space_lduw_be(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_lduw_internal(as, addr, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t lduw_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_lduw(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_lduw_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned. The ram page is not masked as dirty
|
||||
and the code inside is not invalidated. It is useful if the dirty
|
||||
bits are used to track modified PTEs */
|
||||
void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 4;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
uint8_t dirty_log_mask;
|
||||
bool release_lock = false;
|
||||
|
||||
rcu_read_lock();
|
||||
mr = address_space_translate(as, addr, &addr1, &l,
|
||||
true);
|
||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
|
||||
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
|
||||
} else {
|
||||
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
stl_p(ptr, val);
|
||||
|
||||
dirty_log_mask = memory_region_get_dirty_log_mask(mr);
|
||||
dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
|
||||
cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr,
|
||||
4, dirty_log_mask);
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
if (release_lock) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stl_notdirty(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline void address_space_stl_internal(AddressSpace *as,
|
||||
hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 4;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
bool release_lock = false;
|
||||
|
||||
rcu_read_lock();
|
||||
mr = address_space_translate(as, addr, &addr1, &l,
|
||||
true);
|
||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#endif
|
||||
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
stl_le_p(ptr, val);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
stl_be_p(ptr, val);
|
||||
break;
|
||||
default:
|
||||
stl_p(ptr, val);
|
||||
break;
|
||||
}
|
||||
invalidate_and_set_dirty(mr, addr1, 4);
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
if (release_lock) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stl_internal(as, addr, val, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
void address_space_stl_le(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stl_internal(as, addr, val, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void address_space_stl_be(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stl_internal(as, addr, val, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
void stl_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stl(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stl_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
void address_space_stb(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
uint8_t v = val;
|
||||
MemTxResult r;
|
||||
|
||||
r = address_space_rw(as, addr, attrs, &v, 1, 1);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline void address_space_stw_internal(AddressSpace *as,
|
||||
hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 2;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
bool release_lock = false;
|
||||
|
||||
rcu_read_lock();
|
||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||
if (l < 2 || !memory_access_is_direct(mr, true)) {
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#endif
|
||||
r = memory_region_dispatch_write(mr, addr1, val, 2, attrs);
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
stw_le_p(ptr, val);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
stw_be_p(ptr, val);
|
||||
break;
|
||||
default:
|
||||
stw_p(ptr, val);
|
||||
break;
|
||||
}
|
||||
invalidate_and_set_dirty(mr, addr1, 2);
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
if (release_lock) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void address_space_stw(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stw_internal(as, addr, val, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
void address_space_stw_le(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stw_internal(as, addr, val, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void address_space_stw_be(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stw_internal(as, addr, val, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
void stw_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stw(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stw_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
MemTxResult r;
|
||||
val = tswap64(val);
|
||||
r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void address_space_stq_le(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
MemTxResult r;
|
||||
val = cpu_to_le64(val);
|
||||
r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
void address_space_stq_be(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
MemTxResult r;
|
||||
val = cpu_to_be64(val);
|
||||
r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void stq_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||
{
|
||||
address_space_stq(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||
{
|
||||
address_space_stq_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||
{
|
||||
address_space_stq_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
#define ARG1_DECL MemoryRegionCache *cache
|
||||
#define ARG1 cache
|
||||
#define SUFFIX _cached
|
||||
#define TRANSLATE(...) address_space_translate_cached(cache, __VA_ARGS__)
|
||||
#define IS_DIRECT(mr, is_write) true
|
||||
#define MAP_RAM(mr, ofs) (cache->ptr + (ofs - cache->xlat))
|
||||
#define INVALIDATE(mr, ofs, len) ((void)0)
|
||||
#define RCU_READ_LOCK() ((void)0)
|
||||
#define RCU_READ_UNLOCK() ((void)0)
|
||||
#include "memory_ldst.inc.c"
|
||||
|
||||
/* virtual memory access for debug (includes writing to ROM) */
|
||||
int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
||||
|
||||
6
hmp.c
6
hmp.c
@@ -1551,7 +1551,6 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
BlockIOThrottle throttle = {
|
||||
.has_device = true,
|
||||
.device = (char *) qdict_get_str(qdict, "device"),
|
||||
.bps = qdict_get_int(qdict, "bps"),
|
||||
.bps_rd = qdict_get_int(qdict, "bps_rd"),
|
||||
@@ -1809,6 +1808,7 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
QemuOpts *opts;
|
||||
Visitor *v;
|
||||
Object *obj = NULL;
|
||||
|
||||
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
||||
@@ -1817,7 +1817,9 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||
return;
|
||||
}
|
||||
|
||||
obj = user_creatable_add_opts(opts, &err);
|
||||
v = opts_visitor_new(opts);
|
||||
obj = user_creatable_add(qdict, v, &err);
|
||||
visit_free(v);
|
||||
qemu_opts_del(opts);
|
||||
|
||||
if (err) {
|
||||
|
||||
1045
hw/9pfs/9p-local.c
1045
hw/9pfs/9p-local.c
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 9p local backend utilities
|
||||
*
|
||||
* Copyright IBM, Corp. 2017
|
||||
*
|
||||
* Authors:
|
||||
* Greg Kurz <groug@kaod.org>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_9P_LOCAL_H
|
||||
#define QEMU_9P_LOCAL_H
|
||||
|
||||
int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
|
||||
mode_t mode);
|
||||
int local_opendir_nofollow(FsContext *fs_ctx, const char *path);
|
||||
|
||||
#endif
|
||||
@@ -25,7 +25,13 @@
|
||||
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
return local_getxattr_nofollow(ctx, path, MAP_ACL_ACCESS, value, size);
|
||||
char *buffer;
|
||||
ssize_t ret;
|
||||
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
|
||||
@@ -50,16 +56,23 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
|
||||
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags)
|
||||
{
|
||||
return local_setxattr_nofollow(ctx, path, MAP_ACL_ACCESS, value, size,
|
||||
flags);
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mp_pacl_removexattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
int ret;
|
||||
char *buffer;
|
||||
|
||||
ret = local_removexattr_nofollow(ctx, path, MAP_ACL_ACCESS);
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lremovexattr(buffer, MAP_ACL_ACCESS);
|
||||
if (ret == -1 && errno == ENODATA) {
|
||||
/*
|
||||
* We don't get ENODATA error when trying to remove a
|
||||
@@ -69,13 +82,20 @@ static int mp_pacl_removexattr(FsContext *ctx,
|
||||
errno = 0;
|
||||
ret = 0;
|
||||
}
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
return local_getxattr_nofollow(ctx, path, MAP_ACL_DEFAULT, value, size);
|
||||
char *buffer;
|
||||
ssize_t ret;
|
||||
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
|
||||
@@ -100,16 +120,23 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
|
||||
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags)
|
||||
{
|
||||
return local_setxattr_nofollow(ctx, path, MAP_ACL_DEFAULT, value, size,
|
||||
flags);
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mp_dacl_removexattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
int ret;
|
||||
char *buffer;
|
||||
|
||||
ret = local_removexattr_nofollow(ctx, path, MAP_ACL_DEFAULT);
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lremovexattr(buffer, MAP_ACL_DEFAULT);
|
||||
if (ret == -1 && errno == ENODATA) {
|
||||
/*
|
||||
* We don't get ENODATA error when trying to remove a
|
||||
@@ -119,6 +146,7 @@ static int mp_dacl_removexattr(FsContext *ctx,
|
||||
errno = 0;
|
||||
ret = 0;
|
||||
}
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 9p utilities
|
||||
*
|
||||
* Copyright IBM, Corp. 2017
|
||||
*
|
||||
* Authors:
|
||||
* Greg Kurz <groug@kaod.org>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/xattr.h"
|
||||
#include "9p-util.h"
|
||||
|
||||
int relative_openat_nofollow(int dirfd, const char *path, int flags,
|
||||
mode_t mode)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dup(dirfd);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (*path) {
|
||||
const char *c;
|
||||
int next_fd;
|
||||
char *head;
|
||||
|
||||
/* Only relative paths without consecutive slashes */
|
||||
assert(path[0] != '/');
|
||||
|
||||
head = g_strdup(path);
|
||||
c = strchr(path, '/');
|
||||
if (c) {
|
||||
head[c - path] = 0;
|
||||
next_fd = openat_dir(fd, head);
|
||||
} else {
|
||||
next_fd = openat_file(fd, head, flags, mode);
|
||||
}
|
||||
g_free(head);
|
||||
if (next_fd == -1) {
|
||||
close_preserve_errno(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
fd = next_fd;
|
||||
|
||||
if (!c) {
|
||||
break;
|
||||
}
|
||||
path = c + 1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
|
||||
int ret;
|
||||
|
||||
ret = lgetxattr(proc_path, name, value, size);
|
||||
g_free(proc_path);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 9p utilities
|
||||
*
|
||||
* Copyright IBM, Corp. 2017
|
||||
*
|
||||
* Authors:
|
||||
* Greg Kurz <groug@kaod.org>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_9P_UTIL_H
|
||||
#define QEMU_9P_UTIL_H
|
||||
|
||||
static inline void close_preserve_errno(int fd)
|
||||
{
|
||||
int serrno = errno;
|
||||
close(fd);
|
||||
errno = serrno;
|
||||
}
|
||||
|
||||
static inline int openat_dir(int dirfd, const char *name)
|
||||
{
|
||||
#ifdef O_PATH
|
||||
#define OPENAT_DIR_O_PATH O_PATH
|
||||
#else
|
||||
#define OPENAT_DIR_O_PATH 0
|
||||
#endif
|
||||
return openat(dirfd, name,
|
||||
O_DIRECTORY | O_RDONLY | O_NOFOLLOW | OPENAT_DIR_O_PATH);
|
||||
}
|
||||
|
||||
static inline int openat_file(int dirfd, const char *name, int flags,
|
||||
mode_t mode)
|
||||
{
|
||||
int fd, serrno, ret;
|
||||
|
||||
fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
|
||||
mode);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
serrno = errno;
|
||||
/* O_NONBLOCK was only needed to open the file. Let's drop it. */
|
||||
ret = fcntl(fd, F_SETFL, flags);
|
||||
assert(!ret);
|
||||
errno = serrno;
|
||||
return fd;
|
||||
}
|
||||
|
||||
int relative_openat_nofollow(int dirfd, const char *path, int flags,
|
||||
mode_t mode);
|
||||
ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
|
||||
void *value, size_t size);
|
||||
int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
|
||||
void *value, size_t size, int flags);
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,9 @@
|
||||
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
char *buffer;
|
||||
ssize_t ret;
|
||||
|
||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
@@ -28,7 +31,10 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
||||
errno = ENOATTR;
|
||||
return -1;
|
||||
}
|
||||
return local_getxattr_nofollow(ctx, path, name, value, size);
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lgetxattr(buffer, name, value, size);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
||||
@@ -67,6 +73,9 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
||||
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags)
|
||||
{
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
@@ -75,12 +84,18 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
return local_setxattr_nofollow(ctx, path, name, value, size, flags);
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lsetxattr(buffer, name, value, size, flags);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mp_user_removexattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
@@ -89,7 +104,10 @@ static int mp_user_removexattr(FsContext *ctx,
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
return local_removexattr_nofollow(ctx, path, name);
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lremovexattr(buffer, name);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
XattrOperations mapped_user_xattr = {
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#include "9p.h"
|
||||
#include "fsdev/file-op-9p.h"
|
||||
#include "9p-xattr.h"
|
||||
#include "9p-util.h"
|
||||
#include "9p-local.h"
|
||||
|
||||
|
||||
static XattrOperations *get_xattr_operations(XattrOperations **h,
|
||||
@@ -60,16 +58,6 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path,
|
||||
return name_size;
|
||||
}
|
||||
|
||||
static ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
|
||||
char *list, size_t size)
|
||||
{
|
||||
char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
|
||||
int ret;
|
||||
|
||||
ret = llistxattr(proc_path, list, size);
|
||||
g_free(proc_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the list and pass to each layer to find out whether
|
||||
@@ -79,37 +67,24 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
|
||||
void *value, size_t vsize)
|
||||
{
|
||||
ssize_t size = 0;
|
||||
char *buffer;
|
||||
void *ovalue = value;
|
||||
XattrOperations *xops;
|
||||
char *orig_value, *orig_value_start;
|
||||
ssize_t xattr_len, parsed_len = 0, attr_len;
|
||||
char *dirpath, *name;
|
||||
int dirfd;
|
||||
|
||||
/* Get the actual len */
|
||||
dirpath = g_path_get_dirname(path);
|
||||
dirfd = local_opendir_nofollow(ctx, dirpath);
|
||||
g_free(dirpath);
|
||||
if (dirfd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = g_path_get_basename(path);
|
||||
xattr_len = flistxattrat_nofollow(dirfd, name, value, 0);
|
||||
buffer = rpath(ctx, path);
|
||||
xattr_len = llistxattr(buffer, value, 0);
|
||||
if (xattr_len <= 0) {
|
||||
g_free(name);
|
||||
close_preserve_errno(dirfd);
|
||||
g_free(buffer);
|
||||
return xattr_len;
|
||||
}
|
||||
|
||||
/* Now fetch the xattr and find the actual size */
|
||||
orig_value = g_malloc(xattr_len);
|
||||
xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len);
|
||||
g_free(name);
|
||||
close_preserve_errno(dirfd);
|
||||
if (xattr_len < 0) {
|
||||
return -1;
|
||||
}
|
||||
xattr_len = llistxattr(buffer, orig_value, xattr_len);
|
||||
g_free(buffer);
|
||||
|
||||
/* store the orig pointer */
|
||||
orig_value_start = orig_value;
|
||||
@@ -168,135 +143,6 @@ int v9fs_remove_xattr(FsContext *ctx,
|
||||
|
||||
}
|
||||
|
||||
ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
char *dirpath = g_path_get_dirname(path);
|
||||
char *filename = g_path_get_basename(path);
|
||||
int dirfd;
|
||||
ssize_t ret = -1;
|
||||
|
||||
dirfd = local_opendir_nofollow(ctx, dirpath);
|
||||
if (dirfd == -1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fgetxattrat_nofollow(dirfd, filename, name, value, size);
|
||||
close_preserve_errno(dirfd);
|
||||
out:
|
||||
g_free(dirpath);
|
||||
g_free(filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
return local_getxattr_nofollow(ctx, path, name, value, size);
|
||||
}
|
||||
|
||||
int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
|
||||
void *value, size_t size, int flags)
|
||||
{
|
||||
char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
|
||||
int ret;
|
||||
|
||||
ret = lsetxattr(proc_path, name, value, size, flags);
|
||||
g_free(proc_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size,
|
||||
int flags)
|
||||
{
|
||||
char *dirpath = g_path_get_dirname(path);
|
||||
char *filename = g_path_get_basename(path);
|
||||
int dirfd;
|
||||
ssize_t ret = -1;
|
||||
|
||||
dirfd = local_opendir_nofollow(ctx, dirpath);
|
||||
if (dirfd == -1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags);
|
||||
close_preserve_errno(dirfd);
|
||||
out:
|
||||
g_free(dirpath);
|
||||
g_free(filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
return local_setxattr_nofollow(ctx, path, name, value, size, flags);
|
||||
}
|
||||
|
||||
static ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
|
||||
const char *name)
|
||||
{
|
||||
char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
|
||||
int ret;
|
||||
|
||||
ret = lremovexattr(proc_path, name);
|
||||
g_free(proc_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
|
||||
const char *name)
|
||||
{
|
||||
char *dirpath = g_path_get_dirname(path);
|
||||
char *filename = g_path_get_basename(path);
|
||||
int dirfd;
|
||||
ssize_t ret = -1;
|
||||
|
||||
dirfd = local_opendir_nofollow(ctx, dirpath);
|
||||
if (dirfd == -1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fremovexattrat_nofollow(dirfd, filename, name);
|
||||
close_preserve_errno(dirfd);
|
||||
out:
|
||||
g_free(dirpath);
|
||||
g_free(filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pt_removexattr(FsContext *ctx, const char *path, const char *name)
|
||||
{
|
||||
return local_removexattr_nofollow(ctx, path, name);
|
||||
}
|
||||
|
||||
ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int notsup_removexattr(FsContext *ctx, const char *path, const char *name)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
XattrOperations *mapped_xattr_ops[] = {
|
||||
&mapped_user_xattr,
|
||||
&mapped_pacl_xattr,
|
||||
|
||||
@@ -29,13 +29,6 @@ typedef struct xattr_operations
|
||||
const char *path, const char *name);
|
||||
} XattrOperations;
|
||||
|
||||
ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size);
|
||||
ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size,
|
||||
int flags);
|
||||
ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
|
||||
const char *name);
|
||||
|
||||
extern XattrOperations mapped_user_xattr;
|
||||
extern XattrOperations passthrough_user_xattr;
|
||||
@@ -56,21 +49,73 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value,
|
||||
int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags);
|
||||
int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
|
||||
|
||||
ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
|
||||
size_t size);
|
||||
ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size);
|
||||
int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
|
||||
size_t size, int flags);
|
||||
int pt_removexattr(FsContext *ctx, const char *path, const char *name);
|
||||
|
||||
ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size);
|
||||
int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags);
|
||||
ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
|
||||
void *value, size_t size);
|
||||
int notsup_removexattr(FsContext *ctx, const char *path, const char *name);
|
||||
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
char *buffer;
|
||||
ssize_t ret;
|
||||
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lgetxattr(buffer, name, value, size);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int pt_setxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lsetxattr(buffer, name, value, size, flags);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int pt_removexattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
char *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = rpath(ctx, path);
|
||||
ret = lremovexattr(path, name);
|
||||
g_free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value,
|
||||
size_t size)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int notsup_setxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
|
||||
char *name, void *value, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int notsup_removexattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
90
hw/9pfs/9p.c
90
hw/9pfs/9p.c
@@ -47,7 +47,7 @@ ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = virtio_pdu_vmarshal(pdu, offset, fmt, ap);
|
||||
ret = pdu->s->transport->pdu_vmarshal(pdu, offset, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
@@ -59,7 +59,7 @@ ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = virtio_pdu_vunmarshal(pdu, offset, fmt, ap);
|
||||
ret = pdu->s->transport->pdu_vunmarshal(pdu, offset, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
@@ -67,7 +67,7 @@ ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
|
||||
|
||||
static void pdu_push_and_notify(V9fsPDU *pdu)
|
||||
{
|
||||
virtio_9p_push_and_notify(pdu);
|
||||
pdu->s->transport->push_and_notify(pdu);
|
||||
}
|
||||
|
||||
static int omode_to_uflags(int8_t mode)
|
||||
@@ -1633,14 +1633,43 @@ out_nofid:
|
||||
pdu_complete(pdu, err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a QEMUIOVector for a sub-region of PDU iovecs
|
||||
*
|
||||
* @qiov: uninitialized QEMUIOVector
|
||||
* @skip: number of bytes to skip from beginning of PDU
|
||||
* @size: number of bytes to include
|
||||
* @is_write: true - write, false - read
|
||||
*
|
||||
* The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
|
||||
* with qemu_iovec_destroy().
|
||||
*/
|
||||
static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
|
||||
size_t skip, size_t size,
|
||||
bool is_write)
|
||||
{
|
||||
QEMUIOVector elem;
|
||||
struct iovec *iov;
|
||||
unsigned int niov;
|
||||
|
||||
if (is_write) {
|
||||
pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov);
|
||||
} else {
|
||||
pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size);
|
||||
}
|
||||
|
||||
qemu_iovec_init_external(&elem, iov, niov);
|
||||
qemu_iovec_init(qiov, niov);
|
||||
qemu_iovec_concat(qiov, &elem, skip, size);
|
||||
}
|
||||
|
||||
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
|
||||
uint64_t off, uint32_t max_count)
|
||||
{
|
||||
ssize_t err;
|
||||
size_t offset = 7;
|
||||
uint64_t read_count;
|
||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
||||
QEMUIOVector qiov_full;
|
||||
|
||||
if (fidp->fs.xattr.len < off) {
|
||||
read_count = 0;
|
||||
@@ -1656,9 +1685,11 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
|
||||
}
|
||||
offset += err;
|
||||
|
||||
err = v9fs_pack(elem->in_sg, elem->in_num, offset,
|
||||
v9fs_init_qiov_from_pdu(&qiov_full, pdu, 0, read_count, false);
|
||||
err = v9fs_pack(qiov_full.iov, qiov_full.niov, offset,
|
||||
((char *)fidp->fs.xattr.value) + off,
|
||||
read_count);
|
||||
qemu_iovec_destroy(&qiov_full);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
@@ -1732,32 +1763,6 @@ static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu,
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a QEMUIOVector for a sub-region of PDU iovecs
|
||||
*
|
||||
* @qiov: uninitialized QEMUIOVector
|
||||
* @skip: number of bytes to skip from beginning of PDU
|
||||
* @size: number of bytes to include
|
||||
* @is_write: true - write, false - read
|
||||
*
|
||||
* The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
|
||||
* with qemu_iovec_destroy().
|
||||
*/
|
||||
static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
|
||||
size_t skip, size_t size,
|
||||
bool is_write)
|
||||
{
|
||||
QEMUIOVector elem;
|
||||
struct iovec *iov;
|
||||
unsigned int niov;
|
||||
|
||||
virtio_init_iov_from_pdu(pdu, &iov, &niov, is_write);
|
||||
|
||||
qemu_iovec_init_external(&elem, iov, niov);
|
||||
qemu_iovec_init(qiov, niov);
|
||||
qemu_iovec_concat(qiov, &elem, skip, size);
|
||||
}
|
||||
|
||||
static void coroutine_fn v9fs_read(void *opaque)
|
||||
{
|
||||
int32_t fid;
|
||||
@@ -2337,7 +2342,7 @@ static void v9fs_flush(void *opaque)
|
||||
ssize_t err;
|
||||
int16_t tag;
|
||||
size_t offset = 7;
|
||||
V9fsPDU *cancel_pdu = NULL;
|
||||
V9fsPDU *cancel_pdu;
|
||||
V9fsPDU *pdu = opaque;
|
||||
V9fsState *s = pdu->s;
|
||||
|
||||
@@ -2348,13 +2353,9 @@ static void v9fs_flush(void *opaque)
|
||||
}
|
||||
trace_v9fs_flush(pdu->tag, pdu->id, tag);
|
||||
|
||||
if (pdu->tag == tag) {
|
||||
error_report("Warning: the guest sent a self-referencing 9P flush request");
|
||||
} else {
|
||||
QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
|
||||
if (cancel_pdu->tag == tag) {
|
||||
break;
|
||||
}
|
||||
QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
|
||||
if (cancel_pdu->tag == tag) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cancel_pdu) {
|
||||
@@ -3444,7 +3445,6 @@ void pdu_submit(V9fsPDU *pdu)
|
||||
/* Returns 0 on success, 1 on failure. */
|
||||
int v9fs_device_realize_common(V9fsState *s, Error **errp)
|
||||
{
|
||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||
int i, len;
|
||||
struct stat stat;
|
||||
FsDriverEntry *fse;
|
||||
@@ -3454,10 +3454,10 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)
|
||||
/* initialize pdu allocator */
|
||||
QLIST_INIT(&s->free_list);
|
||||
QLIST_INIT(&s->active_list);
|
||||
for (i = 0; i < MAX_REQ; i++) {
|
||||
QLIST_INSERT_HEAD(&s->free_list, &v->pdus[i], next);
|
||||
v->pdus[i].s = s;
|
||||
v->pdus[i].idx = i;
|
||||
for (i = 0; i < (MAX_REQ - 1); i++) {
|
||||
QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
|
||||
s->pdus[i].s = s;
|
||||
s->pdus[i].idx = i;
|
||||
}
|
||||
|
||||
v9fs_path_init(&path);
|
||||
|
||||
26
hw/9pfs/9p.h
26
hw/9pfs/9p.h
@@ -99,8 +99,8 @@ enum p9_proto_version {
|
||||
V9FS_PROTO_2000L = 0x02,
|
||||
};
|
||||
|
||||
#define P9_NOTAG (u16)(~0)
|
||||
#define P9_NOFID (u32)(~0)
|
||||
#define P9_NOTAG UINT16_MAX
|
||||
#define P9_NOFID UINT32_MAX
|
||||
#define P9_MAXWELEM 16
|
||||
|
||||
#define FID_REFERENCED 0x1
|
||||
@@ -229,6 +229,8 @@ typedef struct V9fsState
|
||||
char *tag;
|
||||
enum p9_proto_version proto_version;
|
||||
int32_t msize;
|
||||
V9fsPDU pdus[MAX_REQ];
|
||||
const struct V9fsTransport *transport;
|
||||
/*
|
||||
* lock ensuring atomic path update
|
||||
* on rename.
|
||||
@@ -342,4 +344,24 @@ void pdu_free(V9fsPDU *pdu);
|
||||
void pdu_submit(V9fsPDU *pdu);
|
||||
void v9fs_reset(V9fsState *s);
|
||||
|
||||
struct V9fsTransport {
|
||||
ssize_t (*pdu_vmarshal)(V9fsPDU *pdu, size_t offset, const char *fmt,
|
||||
va_list ap);
|
||||
ssize_t (*pdu_vunmarshal)(V9fsPDU *pdu, size_t offset, const char *fmt,
|
||||
va_list ap);
|
||||
void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
||||
unsigned int *pniov, size_t size);
|
||||
void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
||||
unsigned int *pniov);
|
||||
void (*push_and_notify)(V9fsPDU *pdu);
|
||||
};
|
||||
|
||||
static inline int v9fs_register_transport(V9fsState *s,
|
||||
const struct V9fsTransport *t)
|
||||
{
|
||||
assert(!s->transport);
|
||||
s->transport = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
common-obj-y = 9p.o 9p-util.o
|
||||
common-obj-y = 9p.o
|
||||
common-obj-y += 9p-local.o 9p-xattr.o
|
||||
common-obj-y += 9p-xattr-user.o 9p-posix-acl.o
|
||||
common-obj-y += coth.o cofs.o codir.o cofile.o
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "qemu/iov.h"
|
||||
|
||||
void virtio_9p_push_and_notify(V9fsPDU *pdu)
|
||||
static const struct V9fsTransport virtio_9p_transport;
|
||||
|
||||
static void virtio_9p_push_and_notify(V9fsPDU *pdu)
|
||||
{
|
||||
V9fsState *s = pdu->s;
|
||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||
@@ -126,6 +128,7 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
|
||||
v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
|
||||
virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
|
||||
v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
|
||||
v9fs_register_transport(s, &virtio_9p_transport);
|
||||
|
||||
out:
|
||||
return;
|
||||
@@ -148,8 +151,8 @@ static void virtio_9p_reset(VirtIODevice *vdev)
|
||||
v9fs_reset(&v->state);
|
||||
}
|
||||
|
||||
ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
|
||||
const char *fmt, va_list ap)
|
||||
static ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
V9fsState *s = pdu->s;
|
||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||
@@ -158,8 +161,8 @@ ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
|
||||
return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
|
||||
}
|
||||
|
||||
ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
|
||||
const char *fmt, va_list ap)
|
||||
static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
V9fsState *s = pdu->s;
|
||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||
@@ -168,22 +171,37 @@ ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
|
||||
return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
|
||||
}
|
||||
|
||||
void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
||||
unsigned int *pniov, bool is_write)
|
||||
/* The size parameter is used by other transports. Do not drop it. */
|
||||
static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
||||
unsigned int *pniov, size_t size)
|
||||
{
|
||||
V9fsState *s = pdu->s;
|
||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
||||
|
||||
if (is_write) {
|
||||
*piov = elem->out_sg;
|
||||
*pniov = elem->out_num;
|
||||
} else {
|
||||
*piov = elem->in_sg;
|
||||
*pniov = elem->in_num;
|
||||
}
|
||||
*piov = elem->in_sg;
|
||||
*pniov = elem->in_num;
|
||||
}
|
||||
|
||||
static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
||||
unsigned int *pniov)
|
||||
{
|
||||
V9fsState *s = pdu->s;
|
||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
||||
|
||||
*piov = elem->out_sg;
|
||||
*pniov = elem->out_num;
|
||||
}
|
||||
|
||||
static const struct V9fsTransport virtio_9p_transport = {
|
||||
.pdu_vmarshal = virtio_pdu_vmarshal,
|
||||
.pdu_vunmarshal = virtio_pdu_vunmarshal,
|
||||
.init_in_iov_from_pdu = virtio_init_in_iov_from_pdu,
|
||||
.init_out_iov_from_pdu = virtio_init_out_iov_from_pdu,
|
||||
.push_and_notify = virtio_9p_push_and_notify,
|
||||
};
|
||||
|
||||
/* virtio-9p device */
|
||||
|
||||
static const VMStateDescription vmstate_virtio_9p = {
|
||||
|
||||
@@ -10,20 +10,10 @@ typedef struct V9fsVirtioState
|
||||
VirtIODevice parent_obj;
|
||||
VirtQueue *vq;
|
||||
size_t config_size;
|
||||
V9fsPDU pdus[MAX_REQ];
|
||||
VirtQueueElement *elems[MAX_REQ];
|
||||
V9fsState state;
|
||||
} V9fsVirtioState;
|
||||
|
||||
void virtio_9p_push_and_notify(V9fsPDU *pdu);
|
||||
|
||||
ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
|
||||
const char *fmt, va_list ap);
|
||||
ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
|
||||
const char *fmt, va_list ap);
|
||||
void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
||||
unsigned int *pniov, bool is_write);
|
||||
|
||||
#define TYPE_VIRTIO_9P "virtio-9p-device"
|
||||
#define VIRTIO_9P(obj) \
|
||||
OBJECT_CHECK(V9fsVirtioState, (obj), TYPE_VIRTIO_9P)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o
|
||||
common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
|
||||
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
|
||||
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o
|
||||
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
|
||||
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
|
||||
common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
|
||||
common-obj-$(CONFIG_ACPI) += acpi_interface.o
|
||||
|
||||
@@ -306,7 +306,8 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
||||
|
||||
if (pm->acpi_memory_hotplug.is_enabled) {
|
||||
acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
|
||||
&pm->acpi_memory_hotplug);
|
||||
&pm->acpi_memory_hotplug,
|
||||
ACPI_MEMORY_HOTPLUG_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,34 @@
|
||||
#include "trace.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
#define MEMORY_SLOTS_NUMBER "MDNR"
|
||||
#define MEMORY_HOTPLUG_IO_REGION "HPMR"
|
||||
#define MEMORY_SLOT_ADDR_LOW "MRBL"
|
||||
#define MEMORY_SLOT_ADDR_HIGH "MRBH"
|
||||
#define MEMORY_SLOT_SIZE_LOW "MRLL"
|
||||
#define MEMORY_SLOT_SIZE_HIGH "MRLH"
|
||||
#define MEMORY_SLOT_PROXIMITY "MPX"
|
||||
#define MEMORY_SLOT_ENABLED "MES"
|
||||
#define MEMORY_SLOT_INSERT_EVENT "MINS"
|
||||
#define MEMORY_SLOT_REMOVE_EVENT "MRMV"
|
||||
#define MEMORY_SLOT_EJECT "MEJ"
|
||||
#define MEMORY_SLOT_SLECTOR "MSEL"
|
||||
#define MEMORY_SLOT_OST_EVENT "MOEV"
|
||||
#define MEMORY_SLOT_OST_STATUS "MOSC"
|
||||
#define MEMORY_SLOT_LOCK "MLCK"
|
||||
#define MEMORY_SLOT_STATUS_METHOD "MRST"
|
||||
#define MEMORY_SLOT_CRS_METHOD "MCRS"
|
||||
#define MEMORY_SLOT_OST_METHOD "MOST"
|
||||
#define MEMORY_SLOT_PROXIMITY_METHOD "MPXM"
|
||||
#define MEMORY_SLOT_EJECT_METHOD "MEJ0"
|
||||
#define MEMORY_SLOT_NOTIFY_METHOD "MTFY"
|
||||
#define MEMORY_SLOT_SCAN_METHOD "MSCN"
|
||||
#define MEMORY_HOTPLUG_DEVICE "MHPD"
|
||||
#define MEMORY_HOTPLUG_IO_LEN 24
|
||||
#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC"
|
||||
|
||||
static uint16_t memhp_io_base;
|
||||
|
||||
static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev)
|
||||
{
|
||||
ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1);
|
||||
@@ -178,7 +206,7 @@ static const MemoryRegionOps acpi_memory_hotplug_ops = {
|
||||
};
|
||||
|
||||
void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
MemHotplugState *state)
|
||||
MemHotplugState *state, uint16_t io_base)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
||||
@@ -187,10 +215,12 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!memhp_io_base);
|
||||
memhp_io_base = io_base;
|
||||
state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count);
|
||||
memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state,
|
||||
"acpi-mem-hotplug", ACPI_MEMORY_HOTPLUG_IO_LEN);
|
||||
memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io);
|
||||
"acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN);
|
||||
memory_region_add_subregion(as, memhp_io_base, &state->io);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,3 +336,387 @@ const VMStateDescription vmstate_memory_hotplug = {
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
||||
const char *res_root,
|
||||
const char *event_handler_method)
|
||||
{
|
||||
int i;
|
||||
Aml *ifctx;
|
||||
Aml *method;
|
||||
Aml *dev_container;
|
||||
Aml *mem_ctrl_dev;
|
||||
char *mhp_res_path;
|
||||
|
||||
if (!memhp_io_base) {
|
||||
return;
|
||||
}
|
||||
|
||||
mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root);
|
||||
mem_ctrl_dev = aml_device("%s", mhp_res_path);
|
||||
{
|
||||
Aml *crs;
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06")));
|
||||
aml_append(mem_ctrl_dev,
|
||||
aml_name_decl("_UID", aml_string("Memory hotplug resources")));
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs,
|
||||
aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0,
|
||||
MEMORY_HOTPLUG_IO_LEN)
|
||||
);
|
||||
aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_operation_region(
|
||||
MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO,
|
||||
aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN)
|
||||
);
|
||||
|
||||
}
|
||||
aml_append(table, mem_ctrl_dev);
|
||||
|
||||
dev_container = aml_device(MEMORY_DEVICES_CONTAINER);
|
||||
{
|
||||
Aml *field;
|
||||
Aml *one = aml_int(1);
|
||||
Aml *zero = aml_int(0);
|
||||
Aml *ret_val = aml_local(0);
|
||||
Aml *slot_arg0 = aml_arg(0);
|
||||
Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER);
|
||||
Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK);
|
||||
Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR);
|
||||
char *mmio_path = g_strdup_printf("%s." MEMORY_HOTPLUG_IO_REGION,
|
||||
mhp_res_path);
|
||||
|
||||
aml_append(dev_container, aml_name_decl("_HID", aml_string("PNP0A06")));
|
||||
aml_append(dev_container,
|
||||
aml_name_decl("_UID", aml_string("DIMM devices")));
|
||||
|
||||
assert(nr_mem <= ACPI_MAX_RAM_SLOTS);
|
||||
aml_append(dev_container,
|
||||
aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem))
|
||||
);
|
||||
|
||||
field = aml_field(mmio_path, AML_DWORD_ACC,
|
||||
AML_NOLOCK, AML_PRESERVE);
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_ADDR_LOW, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_SIZE_LOW, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_PROXIMITY, 32));
|
||||
aml_append(dev_container, field);
|
||||
|
||||
field = aml_field(mmio_path, AML_BYTE_ACC,
|
||||
AML_NOLOCK, AML_WRITE_AS_ZEROS);
|
||||
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
|
||||
aml_append(field, /* 1 if enabled, read only */
|
||||
aml_named_field(MEMORY_SLOT_ENABLED, 1));
|
||||
aml_append(field,
|
||||
/*(read) 1 if has a insert event. (write) 1 to clear event */
|
||||
aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1));
|
||||
aml_append(field,
|
||||
/* (read) 1 if has a remove event. (write) 1 to clear event */
|
||||
aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1));
|
||||
aml_append(field,
|
||||
/* initiates device eject, write only */
|
||||
aml_named_field(MEMORY_SLOT_EJECT, 1));
|
||||
aml_append(dev_container, field);
|
||||
|
||||
field = aml_field(mmio_path, AML_DWORD_ACC,
|
||||
AML_NOLOCK, AML_PRESERVE);
|
||||
aml_append(field, /* DIMM selector, write only */
|
||||
aml_named_field(MEMORY_SLOT_SLECTOR, 32));
|
||||
aml_append(field, /* _OST event code, write only */
|
||||
aml_named_field(MEMORY_SLOT_OST_EVENT, 32));
|
||||
aml_append(field, /* _OST status code, write only */
|
||||
aml_named_field(MEMORY_SLOT_OST_STATUS, 32));
|
||||
aml_append(dev_container, field);
|
||||
g_free(mmio_path);
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
ifctx = aml_if(aml_equal(slots_nr, zero));
|
||||
{
|
||||
aml_append(ifctx, aml_return(zero));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
/* present, functioning, decoding, not shown in UI */
|
||||
aml_append(method, aml_return(aml_int(0xB)));
|
||||
aml_append(dev_container, method);
|
||||
|
||||
aml_append(dev_container, aml_mutex(MEMORY_SLOT_LOCK, 0));
|
||||
|
||||
method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *else_ctx;
|
||||
Aml *while_ctx;
|
||||
Aml *idx = aml_local(0);
|
||||
Aml *eject_req = aml_int(3);
|
||||
Aml *dev_chk = aml_int(1);
|
||||
|
||||
ifctx = aml_if(aml_equal(slots_nr, zero));
|
||||
{
|
||||
aml_append(ifctx, aml_return(zero));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_store(zero, idx));
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
/* build AML that:
|
||||
* loops over all slots and Notifies DIMMs with
|
||||
* Device Check or Eject Request notifications if
|
||||
* slot has corresponding status bit set and clears
|
||||
* slot status.
|
||||
*/
|
||||
while_ctx = aml_while(aml_lless(idx, slots_nr));
|
||||
{
|
||||
Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT);
|
||||
Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT);
|
||||
|
||||
aml_append(while_ctx, aml_store(idx, slot_selector));
|
||||
ifctx = aml_if(aml_equal(ins_evt, one));
|
||||
{
|
||||
aml_append(ifctx,
|
||||
aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
|
||||
idx, dev_chk));
|
||||
aml_append(ifctx, aml_store(one, ins_evt));
|
||||
}
|
||||
aml_append(while_ctx, ifctx);
|
||||
|
||||
else_ctx = aml_else();
|
||||
ifctx = aml_if(aml_equal(rm_evt, one));
|
||||
{
|
||||
aml_append(ifctx,
|
||||
aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
|
||||
idx, eject_req));
|
||||
aml_append(ifctx, aml_store(one, rm_evt));
|
||||
}
|
||||
aml_append(else_ctx, ifctx);
|
||||
aml_append(while_ctx, else_ctx);
|
||||
|
||||
aml_append(while_ctx, aml_add(idx, one, idx));
|
||||
}
|
||||
aml_append(method, while_ctx);
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(one));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED);
|
||||
|
||||
aml_append(method, aml_store(zero, ret_val));
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method,
|
||||
aml_store(aml_to_integer(slot_arg0), slot_selector));
|
||||
|
||||
ifctx = aml_if(aml_equal(slot_enabled, one));
|
||||
{
|
||||
aml_append(ifctx, aml_store(aml_int(0xF), ret_val));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(ret_val));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED);
|
||||
{
|
||||
Aml *mr64 = aml_name("MR64");
|
||||
Aml *mr32 = aml_name("MR32");
|
||||
Aml *crs_tmpl = aml_resource_template();
|
||||
Aml *minl = aml_name("MINL");
|
||||
Aml *minh = aml_name("MINH");
|
||||
Aml *maxl = aml_name("MAXL");
|
||||
Aml *maxh = aml_name("MAXH");
|
||||
Aml *lenl = aml_name("LENL");
|
||||
Aml *lenh = aml_name("LENH");
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
|
||||
aml_append(crs_tmpl,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_CACHEABLE, AML_READ_WRITE,
|
||||
0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0,
|
||||
0xFFFFFFFFFFFFFFFFULL));
|
||||
aml_append(method, aml_name_decl("MR64", crs_tmpl));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(14), "MINL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(18), "MINH"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(38), "LENL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(42), "LENH"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(22), "MAXL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(26), "MAXH"));
|
||||
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl));
|
||||
|
||||
/* 64-bit math: MAX = MIN + LEN - 1 */
|
||||
aml_append(method, aml_add(minl, lenl, maxl));
|
||||
aml_append(method, aml_add(minh, lenh, maxh));
|
||||
ifctx = aml_if(aml_lless(maxl, minl));
|
||||
{
|
||||
aml_append(ifctx, aml_add(maxh, one, maxh));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
ifctx = aml_if(aml_lless(maxl, one));
|
||||
{
|
||||
aml_append(ifctx, aml_subtract(maxh, one, maxh));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
aml_append(method, aml_subtract(maxl, one, maxl));
|
||||
|
||||
/* return 32-bit _CRS if addr/size is in low mem */
|
||||
/* TODO: remove it since all hotplugged DIMMs are in high mem */
|
||||
ifctx = aml_if(aml_equal(maxh, zero));
|
||||
{
|
||||
crs_tmpl = aml_resource_template();
|
||||
aml_append(crs_tmpl,
|
||||
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED, AML_CACHEABLE,
|
||||
AML_READ_WRITE,
|
||||
0, 0x0, 0xFFFFFFFE, 0,
|
||||
0xFFFFFFFF));
|
||||
aml_append(ifctx, aml_name_decl("MR32", crs_tmpl));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(10), "MIN"));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(14), "MAX"));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(22), "LEN"));
|
||||
aml_append(ifctx, aml_store(minl, aml_name("MIN")));
|
||||
aml_append(ifctx, aml_store(maxl, aml_name("MAX")));
|
||||
aml_append(ifctx, aml_store(lenl, aml_name("LEN")));
|
||||
|
||||
aml_append(ifctx, aml_release(ctrl_lock));
|
||||
aml_append(ifctx, aml_return(mr32));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(mr64));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1,
|
||||
AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(proximity, ret_val));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(ret_val));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT);
|
||||
Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(aml_arg(1), ost_evt));
|
||||
aml_append(method, aml_store(aml_arg(2), ost_status));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *eject = aml_name(MEMORY_SLOT_EJECT);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(one, eject));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
/* build memory devices */
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
Aml *dev;
|
||||
const char *s;
|
||||
|
||||
dev = aml_device("MP%02X", i);
|
||||
aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i)));
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80")));
|
||||
|
||||
method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_CRS_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_STATUS_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_PXM", 0, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_PROXIMITY_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_OST", 3, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_OST_METHOD;
|
||||
aml_append(method, aml_return(aml_call4(
|
||||
s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2)
|
||||
)));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_EJECT_METHOD;
|
||||
aml_append(method, aml_return(aml_call2(
|
||||
s, aml_name("_UID"), aml_arg(0))));
|
||||
aml_append(dev, method);
|
||||
|
||||
aml_append(dev_container, dev);
|
||||
}
|
||||
|
||||
/* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
|
||||
* If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
|
||||
*/
|
||||
method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
|
||||
aml_append(ifctx,
|
||||
aml_notify(aml_name("MP%.02X", i), aml_arg(1))
|
||||
);
|
||||
aml_append(method, ifctx);
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
}
|
||||
aml_append(table, dev_container);
|
||||
|
||||
method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
|
||||
aml_append(method,
|
||||
aml_call0(MEMORY_DEVICES_CONTAINER "." MEMORY_SLOT_SCAN_METHOD));
|
||||
aml_append(table, method);
|
||||
|
||||
g_free(mhp_res_path);
|
||||
}
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
/*
|
||||
* Memory hotplug AML code of DSDT ACPI table
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat Inc
|
||||
*
|
||||
* Author: Igor Mammedov <imammedo@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
#include "include/hw/acpi/pc-hotplug.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem,
|
||||
uint16_t io_base, uint16_t io_len)
|
||||
{
|
||||
Aml *ifctx;
|
||||
Aml *method;
|
||||
Aml *pci_scope;
|
||||
Aml *mem_ctrl_dev;
|
||||
|
||||
/* scope for memory hotplug controller device node */
|
||||
pci_scope = aml_scope("_SB.PCI0");
|
||||
mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE);
|
||||
{
|
||||
Aml *one = aml_int(1);
|
||||
Aml *zero = aml_int(0);
|
||||
Aml *ret_val = aml_local(0);
|
||||
Aml *slot_arg0 = aml_arg(0);
|
||||
Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER);
|
||||
Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK);
|
||||
Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR);
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06")));
|
||||
aml_append(mem_ctrl_dev,
|
||||
aml_name_decl("_UID", aml_string("Memory hotplug resources")));
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
ifctx = aml_if(aml_equal(slots_nr, zero));
|
||||
{
|
||||
aml_append(ifctx, aml_return(zero));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
/* present, functioning, decoding, not shown in UI */
|
||||
aml_append(method, aml_return(aml_int(0xB)));
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0));
|
||||
|
||||
method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *else_ctx;
|
||||
Aml *while_ctx;
|
||||
Aml *idx = aml_local(0);
|
||||
Aml *eject_req = aml_int(3);
|
||||
Aml *dev_chk = aml_int(1);
|
||||
|
||||
ifctx = aml_if(aml_equal(slots_nr, zero));
|
||||
{
|
||||
aml_append(ifctx, aml_return(zero));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_store(zero, idx));
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
/* build AML that:
|
||||
* loops over all slots and Notifies DIMMs with
|
||||
* Device Check or Eject Request notifications if
|
||||
* slot has corresponding status bit set and clears
|
||||
* slot status.
|
||||
*/
|
||||
while_ctx = aml_while(aml_lless(idx, slots_nr));
|
||||
{
|
||||
Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT);
|
||||
Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT);
|
||||
|
||||
aml_append(while_ctx, aml_store(idx, slot_selector));
|
||||
ifctx = aml_if(aml_equal(ins_evt, one));
|
||||
{
|
||||
aml_append(ifctx,
|
||||
aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
|
||||
idx, dev_chk));
|
||||
aml_append(ifctx, aml_store(one, ins_evt));
|
||||
}
|
||||
aml_append(while_ctx, ifctx);
|
||||
|
||||
else_ctx = aml_else();
|
||||
ifctx = aml_if(aml_equal(rm_evt, one));
|
||||
{
|
||||
aml_append(ifctx,
|
||||
aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
|
||||
idx, eject_req));
|
||||
aml_append(ifctx, aml_store(one, rm_evt));
|
||||
}
|
||||
aml_append(else_ctx, ifctx);
|
||||
aml_append(while_ctx, else_ctx);
|
||||
|
||||
aml_append(while_ctx, aml_add(idx, one, idx));
|
||||
}
|
||||
aml_append(method, while_ctx);
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(one));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED);
|
||||
|
||||
aml_append(method, aml_store(zero, ret_val));
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method,
|
||||
aml_store(aml_to_integer(slot_arg0), slot_selector));
|
||||
|
||||
ifctx = aml_if(aml_equal(slot_enabled, one));
|
||||
{
|
||||
aml_append(ifctx, aml_store(aml_int(0xF), ret_val));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(ret_val));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED);
|
||||
{
|
||||
Aml *mr64 = aml_name("MR64");
|
||||
Aml *mr32 = aml_name("MR32");
|
||||
Aml *crs_tmpl = aml_resource_template();
|
||||
Aml *minl = aml_name("MINL");
|
||||
Aml *minh = aml_name("MINH");
|
||||
Aml *maxl = aml_name("MAXL");
|
||||
Aml *maxh = aml_name("MAXH");
|
||||
Aml *lenl = aml_name("LENL");
|
||||
Aml *lenh = aml_name("LENH");
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
|
||||
aml_append(crs_tmpl,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_CACHEABLE, AML_READ_WRITE,
|
||||
0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0,
|
||||
0xFFFFFFFFFFFFFFFFULL));
|
||||
aml_append(method, aml_name_decl("MR64", crs_tmpl));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(14), "MINL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(18), "MINH"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(38), "LENL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(42), "LENH"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(22), "MAXL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(26), "MAXH"));
|
||||
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl));
|
||||
|
||||
/* 64-bit math: MAX = MIN + LEN - 1 */
|
||||
aml_append(method, aml_add(minl, lenl, maxl));
|
||||
aml_append(method, aml_add(minh, lenh, maxh));
|
||||
ifctx = aml_if(aml_lless(maxl, minl));
|
||||
{
|
||||
aml_append(ifctx, aml_add(maxh, one, maxh));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
ifctx = aml_if(aml_lless(maxl, one));
|
||||
{
|
||||
aml_append(ifctx, aml_subtract(maxh, one, maxh));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
aml_append(method, aml_subtract(maxl, one, maxl));
|
||||
|
||||
/* return 32-bit _CRS if addr/size is in low mem */
|
||||
/* TODO: remove it since all hotplugged DIMMs are in high mem */
|
||||
ifctx = aml_if(aml_equal(maxh, zero));
|
||||
{
|
||||
crs_tmpl = aml_resource_template();
|
||||
aml_append(crs_tmpl,
|
||||
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED, AML_CACHEABLE,
|
||||
AML_READ_WRITE,
|
||||
0, 0x0, 0xFFFFFFFE, 0,
|
||||
0xFFFFFFFF));
|
||||
aml_append(ifctx, aml_name_decl("MR32", crs_tmpl));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(10), "MIN"));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(14), "MAX"));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(22), "LEN"));
|
||||
aml_append(ifctx, aml_store(minl, aml_name("MIN")));
|
||||
aml_append(ifctx, aml_store(maxl, aml_name("MAX")));
|
||||
aml_append(ifctx, aml_store(lenl, aml_name("LEN")));
|
||||
|
||||
aml_append(ifctx, aml_release(ctrl_lock));
|
||||
aml_append(ifctx, aml_return(mr32));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(mr64));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1,
|
||||
AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(proximity, ret_val));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(ret_val));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT);
|
||||
Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(aml_arg(1), ost_evt));
|
||||
aml_append(method, aml_store(aml_arg(2), ost_status));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *eject = aml_name(MEMORY_SLOT_EJECT);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(one, eject));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
}
|
||||
aml_append(pci_scope, mem_ctrl_dev);
|
||||
aml_append(ctx, pci_scope);
|
||||
}
|
||||
@@ -644,7 +644,8 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
|
||||
PIIX4_CPU_HOTPLUG_IO_BASE);
|
||||
|
||||
if (s->acpi_memory_hotplug.is_enabled) {
|
||||
acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug);
|
||||
acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug,
|
||||
ACPI_MEMORY_HOTPLUG_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifndef HW_ALPHA_SYS_H
|
||||
#define HW_ALPHA_SYS_H
|
||||
|
||||
#include "target-alpha/cpu-qom.h"
|
||||
#include "target/alpha/cpu-qom.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "hw/ide.h"
|
||||
|
||||
@@ -34,13 +34,18 @@ typedef struct AspeedBoardState {
|
||||
typedef struct AspeedBoardConfig {
|
||||
const char *soc_name;
|
||||
uint32_t hw_strap1;
|
||||
const char *fmc_model;
|
||||
const char *spi_model;
|
||||
uint32_t num_cs;
|
||||
} AspeedBoardConfig;
|
||||
|
||||
enum {
|
||||
PALMETTO_BMC,
|
||||
AST2500_EVB,
|
||||
ROMULUS_BMC,
|
||||
};
|
||||
|
||||
/* Palmetto hardware value: 0x120CE416 */
|
||||
#define PALMETTO_BMC_HW_STRAP1 ( \
|
||||
SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \
|
||||
SCU_AST2400_HW_STRAP_DRAM_CONFIG(2 /* DDR3 with CL=6, CWL=5 */) | \
|
||||
@@ -54,6 +59,7 @@ enum {
|
||||
SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \
|
||||
SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT))
|
||||
|
||||
/* AST2500 evb hardware value: 0xF100C2E6 */
|
||||
#define AST2500_EVB_HW_STRAP1 (( \
|
||||
AST2500_HW_STRAP1_DEFAULTS | \
|
||||
SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \
|
||||
@@ -64,9 +70,38 @@ enum {
|
||||
SCU_HW_STRAP_MAC0_RGMII) & \
|
||||
~SCU_HW_STRAP_2ND_BOOT_WDT)
|
||||
|
||||
/* Romulus hardware value: 0xF10AD206 */
|
||||
#define ROMULUS_BMC_HW_STRAP1 ( \
|
||||
AST2500_HW_STRAP1_DEFAULTS | \
|
||||
SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_UART_DEBUG | \
|
||||
SCU_AST2500_HW_STRAP_DDR4_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
|
||||
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
|
||||
|
||||
static const AspeedBoardConfig aspeed_boards[] = {
|
||||
[PALMETTO_BMC] = { "ast2400-a0", PALMETTO_BMC_HW_STRAP1 },
|
||||
[AST2500_EVB] = { "ast2500-a1", AST2500_EVB_HW_STRAP1 },
|
||||
[PALMETTO_BMC] = {
|
||||
.soc_name = "ast2400-a1",
|
||||
.hw_strap1 = PALMETTO_BMC_HW_STRAP1,
|
||||
.fmc_model = "n25q256a",
|
||||
.spi_model = "mx25l25635e",
|
||||
.num_cs = 1,
|
||||
},
|
||||
[AST2500_EVB] = {
|
||||
.soc_name = "ast2500-a1",
|
||||
.hw_strap1 = AST2500_EVB_HW_STRAP1,
|
||||
.fmc_model = "n25q256a",
|
||||
.spi_model = "mx25l25635e",
|
||||
.num_cs = 1,
|
||||
},
|
||||
[ROMULUS_BMC] = {
|
||||
.soc_name = "ast2500-a1",
|
||||
.hw_strap1 = ROMULUS_BMC_HW_STRAP1,
|
||||
.fmc_model = "n25q256a",
|
||||
.spi_model = "mx66l1g45g",
|
||||
.num_cs = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
@@ -112,6 +147,8 @@ static void aspeed_board_init(MachineState *machine,
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1",
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
@@ -128,8 +165,8 @@ static void aspeed_board_init(MachineState *machine,
|
||||
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
|
||||
&error_abort);
|
||||
|
||||
aspeed_board_init_flashes(&bmc->soc.fmc, "n25q256a", &error_abort);
|
||||
aspeed_board_init_flashes(&bmc->soc.spi[0], "mx25l25635e", &error_abort);
|
||||
aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort);
|
||||
aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort);
|
||||
|
||||
aspeed_board_binfo.kernel_filename = machine->kernel_filename;
|
||||
aspeed_board_binfo.initrd_filename = machine->initrd_filename;
|
||||
@@ -188,10 +225,35 @@ static const TypeInfo ast2500_evb_type = {
|
||||
.class_init = ast2500_evb_class_init,
|
||||
};
|
||||
|
||||
static void romulus_bmc_init(MachineState *machine)
|
||||
{
|
||||
aspeed_board_init(machine, &aspeed_boards[ROMULUS_BMC]);
|
||||
}
|
||||
|
||||
static void romulus_bmc_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "OpenPOWER Romulus BMC (ARM1176)";
|
||||
mc->init = romulus_bmc_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo romulus_bmc_type = {
|
||||
.name = MACHINE_TYPE_NAME("romulus-bmc"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = romulus_bmc_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_machine_init(void)
|
||||
{
|
||||
type_register_static(&palmetto_bmc_type);
|
||||
type_register_static(&ast2500_evb_type);
|
||||
type_register_static(&romulus_bmc_type);
|
||||
}
|
||||
|
||||
type_init(aspeed_machine_init)
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define ASPEED_SOC_VIC_BASE 0x1E6C0000
|
||||
#define ASPEED_SOC_SDMC_BASE 0x1E6E0000
|
||||
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
|
||||
#define ASPEED_SOC_SRAM_BASE 0x1E720000
|
||||
#define ASPEED_SOC_TIMER_BASE 0x1E782000
|
||||
#define ASPEED_SOC_I2C_BASE 0x1E78A000
|
||||
|
||||
@@ -47,15 +48,47 @@ static const char *aspeed_soc_ast2500_typenames[] = {
|
||||
"aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" };
|
||||
|
||||
static const AspeedSoCInfo aspeed_socs[] = {
|
||||
{ "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE,
|
||||
1, aspeed_soc_ast2400_spi_bases,
|
||||
"aspeed.smc.fmc", aspeed_soc_ast2400_typenames },
|
||||
{ "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE,
|
||||
1, aspeed_soc_ast2400_spi_bases,
|
||||
"aspeed.smc.fmc", aspeed_soc_ast2400_typenames },
|
||||
{ "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE,
|
||||
2, aspeed_soc_ast2500_spi_bases,
|
||||
"aspeed.smc.ast2500-fmc", aspeed_soc_ast2500_typenames },
|
||||
{
|
||||
.name = "ast2400-a0",
|
||||
.cpu_model = "arm926",
|
||||
.silicon_rev = AST2400_A0_SILICON_REV,
|
||||
.sdram_base = AST2400_SDRAM_BASE,
|
||||
.sram_size = 0x8000,
|
||||
.spis_num = 1,
|
||||
.spi_bases = aspeed_soc_ast2400_spi_bases,
|
||||
.fmc_typename = "aspeed.smc.fmc",
|
||||
.spi_typename = aspeed_soc_ast2400_typenames,
|
||||
}, {
|
||||
.name = "ast2400-a1",
|
||||
.cpu_model = "arm926",
|
||||
.silicon_rev = AST2400_A1_SILICON_REV,
|
||||
.sdram_base = AST2400_SDRAM_BASE,
|
||||
.sram_size = 0x8000,
|
||||
.spis_num = 1,
|
||||
.spi_bases = aspeed_soc_ast2400_spi_bases,
|
||||
.fmc_typename = "aspeed.smc.fmc",
|
||||
.spi_typename = aspeed_soc_ast2400_typenames,
|
||||
}, {
|
||||
.name = "ast2400",
|
||||
.cpu_model = "arm926",
|
||||
.silicon_rev = AST2400_A0_SILICON_REV,
|
||||
.sdram_base = AST2400_SDRAM_BASE,
|
||||
.sram_size = 0x8000,
|
||||
.spis_num = 1,
|
||||
.spi_bases = aspeed_soc_ast2400_spi_bases,
|
||||
.fmc_typename = "aspeed.smc.fmc",
|
||||
.spi_typename = aspeed_soc_ast2400_typenames,
|
||||
}, {
|
||||
.name = "ast2500-a1",
|
||||
.cpu_model = "arm1176",
|
||||
.silicon_rev = AST2500_A1_SILICON_REV,
|
||||
.sdram_base = AST2500_SDRAM_BASE,
|
||||
.sram_size = 0x9000,
|
||||
.spis_num = 2,
|
||||
.spi_bases = aspeed_soc_ast2500_spi_bases,
|
||||
.fmc_typename = "aspeed.smc.ast2500-fmc",
|
||||
.spi_typename = aspeed_soc_ast2500_typenames,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -87,9 +120,13 @@ static void aspeed_soc_init(Object *obj)
|
||||
{
|
||||
AspeedSoCState *s = ASPEED_SOC(obj);
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
char *cpu_typename;
|
||||
int i;
|
||||
|
||||
s->cpu = cpu_arm_init(sc->info->cpu_model);
|
||||
cpu_typename = g_strdup_printf("%s-" TYPE_ARM_CPU, sc->info->cpu_model);
|
||||
object_initialize(&s->cpu, sizeof(s->cpu), cpu_typename);
|
||||
object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
|
||||
g_free(cpu_typename);
|
||||
|
||||
object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC);
|
||||
object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL);
|
||||
@@ -116,11 +153,13 @@ static void aspeed_soc_init(Object *obj)
|
||||
object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename);
|
||||
object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default());
|
||||
object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs",
|
||||
&error_abort);
|
||||
|
||||
for (i = 0; i < sc->info->spis_num; i++) {
|
||||
object_initialize(&s->spi[i], sizeof(s->spi[i]),
|
||||
sc->info->spi_typename[i]);
|
||||
object_property_add_child(obj, "spi", OBJECT(&s->spi[i]), NULL);
|
||||
object_property_add_child(obj, "spi[*]", OBJECT(&s->spi[i]), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
|
||||
}
|
||||
|
||||
@@ -146,6 +185,24 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_add_subregion_overlap(get_system_memory(),
|
||||
ASPEED_SOC_IOMEM_BASE, &s->iomem, -1);
|
||||
|
||||
/* CPU */
|
||||
object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* SRAM */
|
||||
memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
|
||||
sc->info->sram_size, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
vmstate_register_ram_global(&s->sram);
|
||||
memory_region_add_subregion(get_system_memory(), ASPEED_SOC_SRAM_BASE,
|
||||
&s->sram);
|
||||
|
||||
/* VIC */
|
||||
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
|
||||
if (err) {
|
||||
@@ -154,9 +211,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
|
||||
|
||||
/* Timer */
|
||||
object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
|
||||
@@ -195,10 +252,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->vic), 12));
|
||||
|
||||
/* FMC */
|
||||
object_property_set_int(OBJECT(&s->fmc), 1, "num-cs", &err);
|
||||
object_property_set_bool(OBJECT(&s->fmc), true, "realized", &local_err);
|
||||
error_propagate(&err, local_err);
|
||||
/* FMC, The number of CS is set at the board level */
|
||||
object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
@@ -240,12 +295,6 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
sc->info = (AspeedSoCInfo *) data;
|
||||
dc->realize = aspeed_soc_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_soc_type_info = {
|
||||
|
||||
@@ -1258,7 +1258,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s)
|
||||
}
|
||||
|
||||
/* These are only stubs now. */
|
||||
static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
|
||||
PXA2xxI2CState *s = slave->host;
|
||||
@@ -1280,6 +1280,8 @@ static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
break;
|
||||
}
|
||||
pxa2xx_i2c_update(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa2xx_i2c_rx(I2CSlave *i2c)
|
||||
@@ -1449,17 +1451,10 @@ static const VMStateDescription vmstate_pxa2xx_i2c = {
|
||||
}
|
||||
};
|
||||
|
||||
static int pxa2xx_i2c_slave_init(I2CSlave *i2c)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
k->init = pxa2xx_i2c_slave_init;
|
||||
k->event = pxa2xx_i2c_event;
|
||||
k->recv = pxa2xx_i2c_rx;
|
||||
k->send = pxa2xx_i2c_tx;
|
||||
@@ -2070,7 +2065,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
|
||||
}
|
||||
if (!revision)
|
||||
revision = "pxa270";
|
||||
|
||||
|
||||
s->cpu = cpu_arm_init(revision);
|
||||
if (s->cpu == NULL) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define STRONGARM_H
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "target-arm/cpu-qom.h"
|
||||
#include "target/arm/cpu-qom.h"
|
||||
|
||||
#define SA_CS0 0x00000000
|
||||
#define SA_CS1 0x08000000
|
||||
|
||||
@@ -172,7 +172,7 @@ static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
TosaDACState *s = TOSA_DAC(i2c);
|
||||
|
||||
@@ -194,6 +194,8 @@ static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tosa_dac_recv(I2CSlave *s)
|
||||
@@ -202,12 +204,6 @@ static int tosa_dac_recv(I2CSlave *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int tosa_dac_init(I2CSlave *i2c)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tosa_tg_init(PXA2xxState *cpu)
|
||||
{
|
||||
I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
|
||||
@@ -275,7 +271,6 @@ static void tosa_dac_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
k->init = tosa_dac_init;
|
||||
k->event = tosa_dac_event;
|
||||
k->recv = tosa_dac_recv;
|
||||
k->send = tosa_dac_send;
|
||||
|
||||
@@ -29,11 +29,10 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/arm/virt-acpi-build.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "trace.h"
|
||||
#include "qom/cpu.h"
|
||||
#include "target-arm/cpu.h"
|
||||
#include "target/arm/cpu.h"
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
@@ -43,6 +42,7 @@
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/arm/virt.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "kvm_arm.h"
|
||||
|
||||
@@ -384,7 +384,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
|
||||
}
|
||||
|
||||
static void
|
||||
build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_iort(GArray *table_data, BIOSLinker *linker)
|
||||
{
|
||||
int iort_start = table_data->len;
|
||||
AcpiIortIdMapping *idmap;
|
||||
@@ -439,11 +439,11 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
}
|
||||
|
||||
static void
|
||||
build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
AcpiSerialPortConsoleRedirection *spcr;
|
||||
const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART];
|
||||
int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE;
|
||||
const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART];
|
||||
int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE;
|
||||
|
||||
spcr = acpi_data_push(table_data, sizeof(*spcr));
|
||||
|
||||
@@ -472,16 +472,16 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
}
|
||||
|
||||
static void
|
||||
build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
AcpiSystemResourceAffinityTable *srat;
|
||||
AcpiSratProcessorGiccAffinity *core;
|
||||
AcpiSratMemoryAffinity *numamem;
|
||||
int i, j, srat_start;
|
||||
uint64_t mem_base;
|
||||
uint32_t *cpu_node = g_malloc0(guest_info->smp_cpus * sizeof(uint32_t));
|
||||
uint32_t *cpu_node = g_malloc0(vms->smp_cpus * sizeof(uint32_t));
|
||||
|
||||
for (i = 0; i < guest_info->smp_cpus; i++) {
|
||||
for (i = 0; i < vms->smp_cpus; i++) {
|
||||
j = numa_get_node_for_cpu(i);
|
||||
if (j < nb_numa_nodes) {
|
||||
cpu_node[i] = j;
|
||||
@@ -492,7 +492,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
srat = acpi_data_push(table_data, sizeof(*srat));
|
||||
srat->reserved1 = cpu_to_le32(1);
|
||||
|
||||
for (i = 0; i < guest_info->smp_cpus; ++i) {
|
||||
for (i = 0; i < vms->smp_cpus; ++i) {
|
||||
core = acpi_data_push(table_data, sizeof(*core));
|
||||
core->type = ACPI_SRAT_PROCESSOR_GICC;
|
||||
core->length = sizeof(*core);
|
||||
@@ -502,7 +502,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
}
|
||||
g_free(cpu_node);
|
||||
|
||||
mem_base = guest_info->memmap[VIRT_MEM].base;
|
||||
mem_base = vms->memmap[VIRT_MEM].base;
|
||||
for (i = 0; i < nb_numa_nodes; ++i) {
|
||||
numamem = acpi_data_push(table_data, sizeof(*numamem));
|
||||
build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i,
|
||||
@@ -515,10 +515,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
}
|
||||
|
||||
static void
|
||||
build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
AcpiTableMcfg *mcfg;
|
||||
const MemMapEntry *memmap = guest_info->memmap;
|
||||
const MemMapEntry *memmap = vms->memmap;
|
||||
int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
|
||||
|
||||
mcfg = acpi_data_push(table_data, len);
|
||||
@@ -535,24 +535,33 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
|
||||
/* GTDT */
|
||||
static void
|
||||
build_gtdt(GArray *table_data, BIOSLinker *linker)
|
||||
build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
int gtdt_start = table_data->len;
|
||||
AcpiGenericTimerTable *gtdt;
|
||||
uint32_t irqflags;
|
||||
|
||||
if (vmc->claim_edge_triggered_timers) {
|
||||
irqflags = ACPI_GTDT_INTERRUPT_MODE_EDGE;
|
||||
} else {
|
||||
irqflags = ACPI_GTDT_INTERRUPT_MODE_LEVEL;
|
||||
}
|
||||
|
||||
gtdt = acpi_data_push(table_data, sizeof *gtdt);
|
||||
/* The interrupt values are the same with the device tree when adding 16 */
|
||||
gtdt->secure_el1_interrupt = ARCH_TIMER_S_EL1_IRQ + 16;
|
||||
gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE;
|
||||
gtdt->secure_el1_interrupt = cpu_to_le32(ARCH_TIMER_S_EL1_IRQ + 16);
|
||||
gtdt->secure_el1_flags = cpu_to_le32(irqflags);
|
||||
|
||||
gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16;
|
||||
gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE | ACPI_GTDT_ALWAYS_ON;
|
||||
gtdt->non_secure_el1_interrupt = cpu_to_le32(ARCH_TIMER_NS_EL1_IRQ + 16);
|
||||
gtdt->non_secure_el1_flags = cpu_to_le32(irqflags |
|
||||
ACPI_GTDT_CAP_ALWAYS_ON);
|
||||
|
||||
gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16;
|
||||
gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE;
|
||||
gtdt->virtual_timer_interrupt = cpu_to_le32(ARCH_TIMER_VIRT_IRQ + 16);
|
||||
gtdt->virtual_timer_flags = cpu_to_le32(irqflags);
|
||||
|
||||
gtdt->non_secure_el2_interrupt = ARCH_TIMER_NS_EL2_IRQ + 16;
|
||||
gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE;
|
||||
gtdt->non_secure_el2_interrupt = cpu_to_le32(ARCH_TIMER_NS_EL2_IRQ + 16);
|
||||
gtdt->non_secure_el2_flags = cpu_to_le32(irqflags);
|
||||
|
||||
build_header(linker, table_data,
|
||||
(void *)(table_data->data + gtdt_start), "GTDT",
|
||||
@@ -561,11 +570,12 @@ build_gtdt(GArray *table_data, BIOSLinker *linker)
|
||||
|
||||
/* MADT */
|
||||
static void
|
||||
build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
int madt_start = table_data->len;
|
||||
const MemMapEntry *memmap = guest_info->memmap;
|
||||
const int *irqmap = guest_info->irqmap;
|
||||
const MemMapEntry *memmap = vms->memmap;
|
||||
const int *irqmap = vms->irqmap;
|
||||
AcpiMultipleApicTable *madt;
|
||||
AcpiMadtGenericDistributor *gicd;
|
||||
AcpiMadtGenericMsiFrame *gic_msi;
|
||||
@@ -576,30 +586,30 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
gicd = acpi_data_push(table_data, sizeof *gicd);
|
||||
gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR;
|
||||
gicd->length = sizeof(*gicd);
|
||||
gicd->base_address = memmap[VIRT_GIC_DIST].base;
|
||||
gicd->version = guest_info->gic_version;
|
||||
gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base);
|
||||
gicd->version = vms->gic_version;
|
||||
|
||||
for (i = 0; i < guest_info->smp_cpus; i++) {
|
||||
AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
|
||||
sizeof *gicc);
|
||||
for (i = 0; i < vms->smp_cpus; i++) {
|
||||
AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data,
|
||||
sizeof(*gicc));
|
||||
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i));
|
||||
|
||||
gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
|
||||
gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE;
|
||||
gicc->length = sizeof(*gicc);
|
||||
if (guest_info->gic_version == 2) {
|
||||
gicc->base_address = memmap[VIRT_GIC_CPU].base;
|
||||
if (vms->gic_version == 2) {
|
||||
gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base);
|
||||
}
|
||||
gicc->cpu_interface_number = i;
|
||||
gicc->arm_mpidr = armcpu->mp_affinity;
|
||||
gicc->uid = i;
|
||||
gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
|
||||
gicc->cpu_interface_number = cpu_to_le32(i);
|
||||
gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity);
|
||||
gicc->uid = cpu_to_le32(i);
|
||||
gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
|
||||
|
||||
if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
|
||||
gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
|
||||
}
|
||||
}
|
||||
|
||||
if (guest_info->gic_version == 3) {
|
||||
if (vms->gic_version == 3) {
|
||||
AcpiMadtGenericTranslator *gic_its;
|
||||
AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
|
||||
sizeof *gicr);
|
||||
@@ -609,7 +619,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base);
|
||||
gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size);
|
||||
|
||||
if (its_class_name() && !guest_info->no_its) {
|
||||
if (its_class_name() && !vmc->no_its) {
|
||||
gic_its = acpi_data_push(table_data, sizeof *gic_its);
|
||||
gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR;
|
||||
gic_its->length = sizeof(*gic_its);
|
||||
@@ -641,8 +651,8 @@ build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset)
|
||||
|
||||
/* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */
|
||||
fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI);
|
||||
fadt->arm_boot_flags = cpu_to_le16((1 << ACPI_FADT_ARM_USE_PSCI_G_0_2) |
|
||||
(1 << ACPI_FADT_ARM_PSCI_USE_HVC));
|
||||
fadt->arm_boot_flags = cpu_to_le16(ACPI_FADT_ARM_PSCI_COMPLIANT |
|
||||
ACPI_FADT_ARM_PSCI_USE_HVC);
|
||||
|
||||
/* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
|
||||
fadt->minor_revision = 0x1;
|
||||
@@ -658,11 +668,11 @@ build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset)
|
||||
|
||||
/* DSDT */
|
||||
static void
|
||||
build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
Aml *scope, *dsdt;
|
||||
const MemMapEntry *memmap = guest_info->memmap;
|
||||
const int *irqmap = guest_info->irqmap;
|
||||
const MemMapEntry *memmap = vms->memmap;
|
||||
const int *irqmap = vms->irqmap;
|
||||
|
||||
dsdt = init_aml_allocator();
|
||||
/* Reserve space for header */
|
||||
@@ -674,7 +684,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
* the RTC ACPI device at all when using UEFI.
|
||||
*/
|
||||
scope = aml_scope("\\_SB");
|
||||
acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);
|
||||
acpi_dsdt_add_cpus(scope, vms->smp_cpus);
|
||||
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
|
||||
(irqmap[VIRT_UART] + ARM_SPI_BASE));
|
||||
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
|
||||
@@ -682,7 +692,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
|
||||
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
|
||||
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
|
||||
guest_info->use_highmem);
|
||||
vms->highmem);
|
||||
acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
|
||||
(irqmap[VIRT_GPIO] + ARM_SPI_BASE));
|
||||
acpi_dsdt_add_power_button(scope);
|
||||
@@ -705,12 +715,12 @@ struct AcpiBuildState {
|
||||
MemoryRegion *linker_mr;
|
||||
/* Is table patched? */
|
||||
bool patched;
|
||||
VirtGuestInfo *guest_info;
|
||||
} AcpiBuildState;
|
||||
|
||||
static
|
||||
void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
GArray *table_offsets;
|
||||
unsigned dsdt, rsdt;
|
||||
GArray *tables_blob = tables->table_data;
|
||||
@@ -724,32 +734,32 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
|
||||
/* DSDT is pointed to by FADT */
|
||||
dsdt = tables_blob->len;
|
||||
build_dsdt(tables_blob, tables->linker, guest_info);
|
||||
build_dsdt(tables_blob, tables->linker, vms);
|
||||
|
||||
/* FADT MADT GTDT MCFG SPCR pointed to by RSDT */
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_fadt(tables_blob, tables->linker, dsdt);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_madt(tables_blob, tables->linker, guest_info);
|
||||
build_madt(tables_blob, tables->linker, vms);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_gtdt(tables_blob, tables->linker);
|
||||
build_gtdt(tables_blob, tables->linker, vms);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_mcfg(tables_blob, tables->linker, guest_info);
|
||||
build_mcfg(tables_blob, tables->linker, vms);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_spcr(tables_blob, tables->linker, guest_info);
|
||||
build_spcr(tables_blob, tables->linker, vms);
|
||||
|
||||
if (nb_numa_nodes > 0) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_srat(tables_blob, tables->linker, guest_info);
|
||||
build_srat(tables_blob, tables->linker, vms);
|
||||
}
|
||||
|
||||
if (its_class_name() && !guest_info->no_its) {
|
||||
if (its_class_name() && !vmc->no_its) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_iort(tables_blob, tables->linker, guest_info);
|
||||
build_iort(tables_blob, tables->linker);
|
||||
}
|
||||
|
||||
/* RSDT is pointed to by RSDP */
|
||||
@@ -788,13 +798,12 @@ static void virt_acpi_build_update(void *build_opaque)
|
||||
|
||||
acpi_build_tables_init(&tables);
|
||||
|
||||
virt_acpi_build(build_state->guest_info, &tables);
|
||||
virt_acpi_build(VIRT_MACHINE(qdev_get_machine()), &tables);
|
||||
|
||||
acpi_ram_update(build_state->table_mr, tables.table_data);
|
||||
acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
|
||||
acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
|
||||
|
||||
|
||||
acpi_build_tables_cleanup(&tables, true);
|
||||
}
|
||||
|
||||
@@ -822,12 +831,12 @@ static const VMStateDescription vmstate_virt_acpi_build = {
|
||||
},
|
||||
};
|
||||
|
||||
void virt_acpi_setup(VirtGuestInfo *guest_info)
|
||||
void virt_acpi_setup(VirtMachineState *vms)
|
||||
{
|
||||
AcpiBuildTables tables;
|
||||
AcpiBuildState *build_state;
|
||||
|
||||
if (!guest_info->fw_cfg) {
|
||||
if (!vms->fw_cfg) {
|
||||
trace_virt_acpi_setup();
|
||||
return;
|
||||
}
|
||||
@@ -838,10 +847,9 @@ void virt_acpi_setup(VirtGuestInfo *guest_info)
|
||||
}
|
||||
|
||||
build_state = g_malloc0(sizeof *build_state);
|
||||
build_state->guest_info = guest_info;
|
||||
|
||||
acpi_build_tables_init(&tables);
|
||||
virt_acpi_build(build_state->guest_info, &tables);
|
||||
virt_acpi_build(vms, &tables);
|
||||
|
||||
/* Now expose it all to Guest */
|
||||
build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
|
||||
@@ -853,8 +861,8 @@ void virt_acpi_setup(VirtGuestInfo *guest_info)
|
||||
acpi_add_rom_blob(build_state, tables.linker->cmd_blob,
|
||||
"etc/table-loader", 0);
|
||||
|
||||
fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
|
||||
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
|
||||
fw_cfg_add_file(vms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
|
||||
acpi_data_len(tables.tcpalog));
|
||||
|
||||
build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
|
||||
ACPI_BUILD_RSDP_FILE, 0);
|
||||
|
||||
706
hw/arm/virt.c
706
hw/arm/virt.c
File diff suppressed because it is too large
Load Diff
11
hw/arm/z2.c
11
hw/arm/z2.c
@@ -220,7 +220,7 @@ static int aer915_send(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aer915_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int aer915_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
AER915State *s = AER915(i2c);
|
||||
|
||||
@@ -238,6 +238,8 @@ static void aer915_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aer915_recv(I2CSlave *slave)
|
||||
@@ -263,12 +265,6 @@ static int aer915_recv(I2CSlave *slave)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int aer915_init(I2CSlave *i2c)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VMStateDescription vmstate_aer915_state = {
|
||||
.name = "aer915",
|
||||
.version_id = 1,
|
||||
@@ -285,7 +281,6 @@ static void aer915_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
k->init = aer915_init;
|
||||
k->event = aer915_event;
|
||||
k->recv = aer915_recv;
|
||||
k->send = aer915_send;
|
||||
|
||||
@@ -303,7 +303,7 @@ static void wm8750_reset(I2CSlave *i2c)
|
||||
s->i2c_len = 0;
|
||||
}
|
||||
|
||||
static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int wm8750_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
WM8750State *s = WM8750(i2c);
|
||||
|
||||
@@ -321,6 +321,8 @@ static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WM8750_LINVOL 0x00
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#ifndef M25P80_ERR_DEBUG
|
||||
@@ -203,6 +204,7 @@ static const FlashPartInfo known_devices[] = {
|
||||
{ INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) },
|
||||
{ INFO("mx66u51235f", 0xc2253a, 0, 64 << 10, 1024, ER_4K | ER_32K) },
|
||||
{ INFO("mx66u1g45g", 0xc2253b, 0, 64 << 10, 2048, ER_4K | ER_32K) },
|
||||
{ INFO("mx66l1g45g", 0xc2201b, 0, 64 << 10, 2048, ER_4K | ER_32K) },
|
||||
|
||||
/* Micron */
|
||||
{ INFO("n25q032a11", 0x20bb16, 0, 64 << 10, 64, ER_4K) },
|
||||
@@ -376,6 +378,8 @@ typedef enum {
|
||||
MAN_GENERIC,
|
||||
} Manufacturer;
|
||||
|
||||
#define M25P80_INTERNAL_DATA_BUFFER_SZ 16
|
||||
|
||||
typedef struct Flash {
|
||||
SSISlave parent_obj;
|
||||
|
||||
@@ -386,7 +390,7 @@ typedef struct Flash {
|
||||
int page_size;
|
||||
|
||||
uint8_t state;
|
||||
uint8_t data[16];
|
||||
uint8_t data[M25P80_INTERNAL_DATA_BUFFER_SZ];
|
||||
uint32_t len;
|
||||
uint32_t pos;
|
||||
uint8_t needed_bytes;
|
||||
@@ -1114,6 +1118,17 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
|
||||
|
||||
case STATE_COLLECTING_DATA:
|
||||
case STATE_COLLECTING_VAR_LEN_DATA:
|
||||
|
||||
if (s->len >= M25P80_INTERNAL_DATA_BUFFER_SZ) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"M25P80: Write overrun internal data buffer. "
|
||||
"SPI controller (QEMU emulator or guest driver) "
|
||||
"is misbehaving\n");
|
||||
s->len = s->pos = 0;
|
||||
s->state = STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
s->data[s->len] = (uint8_t)tx;
|
||||
s->len++;
|
||||
|
||||
@@ -1123,6 +1138,17 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
|
||||
break;
|
||||
|
||||
case STATE_READING_DATA:
|
||||
|
||||
if (s->pos >= M25P80_INTERNAL_DATA_BUFFER_SZ) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"M25P80: Read overrun internal data buffer. "
|
||||
"SPI controller (QEMU emulator or guest driver) "
|
||||
"is misbehaving\n");
|
||||
s->len = s->pos = 0;
|
||||
s->state = STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
r = s->data[s->pos];
|
||||
s->pos++;
|
||||
if (s->pos == s->len) {
|
||||
@@ -1195,7 +1221,7 @@ static const VMStateDescription vmstate_m25p80 = {
|
||||
.pre_save = m25p80_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(state, Flash),
|
||||
VMSTATE_UINT8_ARRAY(data, Flash, 16),
|
||||
VMSTATE_UINT8_ARRAY(data, Flash, M25P80_INTERNAL_DATA_BUFFER_SZ),
|
||||
VMSTATE_UINT32(len, Flash),
|
||||
VMSTATE_UINT32(pos, Flash),
|
||||
VMSTATE_UINT8(needed_bytes, Flash),
|
||||
|
||||
@@ -707,6 +707,19 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
||||
int num_devices;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (pfl->sector_len == 0) {
|
||||
error_setg(errp, "attribute \"sector-length\" not specified or zero.");
|
||||
return;
|
||||
}
|
||||
if (pfl->nb_blocs == 0) {
|
||||
error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
|
||||
return;
|
||||
}
|
||||
if (pfl->name == NULL) {
|
||||
error_setg(errp, "attribute \"name\" not specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
total_len = pfl->sector_len * pfl->nb_blocs;
|
||||
|
||||
/* These are only used to expose the parameters of each device
|
||||
|
||||
@@ -600,6 +600,19 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (pfl->sector_len == 0) {
|
||||
error_setg(errp, "attribute \"sector-length\" not specified or zero.");
|
||||
return;
|
||||
}
|
||||
if (pfl->nb_blocs == 0) {
|
||||
error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
|
||||
return;
|
||||
}
|
||||
if (pfl->name == NULL) {
|
||||
error_setg(errp, "attribute \"name\" not specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
chip_len = pfl->sector_len * pfl->nb_blocs;
|
||||
/* XXX: to be fixed */
|
||||
#if 0
|
||||
|
||||
@@ -588,13 +588,19 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
|
||||
|
||||
blk_io_plug(s->blk);
|
||||
|
||||
while ((req = virtio_blk_get_request(s, vq))) {
|
||||
if (virtio_blk_handle_request(req, &mrb)) {
|
||||
virtqueue_detach_element(req->vq, &req->elem, 0);
|
||||
virtio_blk_free_request(req);
|
||||
break;
|
||||
do {
|
||||
virtio_queue_set_notification(vq, 0);
|
||||
|
||||
while ((req = virtio_blk_get_request(s, vq))) {
|
||||
if (virtio_blk_handle_request(req, &mrb)) {
|
||||
virtqueue_detach_element(req->vq, &req->elem, 0);
|
||||
virtio_blk_free_request(req);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtio_queue_set_notification(vq, 1);
|
||||
} while (!virtio_queue_empty(vq));
|
||||
|
||||
if (mrb.num_reqs) {
|
||||
virtio_blk_submit_multireq(s->blk, &mrb);
|
||||
@@ -857,7 +863,7 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
}
|
||||
}
|
||||
|
||||
req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq));
|
||||
req = qemu_get_virtqueue_element(vdev, f, sizeof(VirtIOBlockReq));
|
||||
virtio_blk_init_request(s, virtio_get_queue(vdev, vq_idx), req);
|
||||
req->next = s->rq;
|
||||
s->rq = req;
|
||||
|
||||
@@ -138,9 +138,10 @@ static void fifo_trigger_update(void *opaque)
|
||||
{
|
||||
CadenceUARTState *s = opaque;
|
||||
|
||||
s->r[R_CISR] |= UART_INTR_TIMEOUT;
|
||||
|
||||
uart_update_status(s);
|
||||
if (s->r[R_RTOR]) {
|
||||
s->r[R_CISR] |= UART_INTR_TIMEOUT;
|
||||
uart_update_status(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_rx_reset(CadenceUARTState *s)
|
||||
@@ -502,6 +503,13 @@ static int cadence_uart_post_load(void *opaque, int version_id)
|
||||
{
|
||||
CadenceUARTState *s = opaque;
|
||||
|
||||
/* Ensure these two aren't invalid numbers */
|
||||
if (s->r[R_BRGR] < 1 || s->r[R_BRGR] & ~0xFFFF ||
|
||||
s->r[R_BDIV] <= 3 || s->r[R_BDIV] & ~0xFF) {
|
||||
/* Value is invalid, abort */
|
||||
return 1;
|
||||
}
|
||||
|
||||
uart_parameters_setup(s);
|
||||
uart_update_status(s);
|
||||
return 0;
|
||||
|
||||
@@ -629,22 +629,26 @@ DeviceState *exynos4210_uart_create(hwaddr addr,
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int exynos4210_uart_init(SysBusDevice *dev)
|
||||
static void exynos4210_uart_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
Exynos4210UartState *s = EXYNOS4210_UART(dev);
|
||||
|
||||
/* memory mapping */
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_uart_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &exynos4210_uart_ops, s,
|
||||
"exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
}
|
||||
|
||||
static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
Exynos4210UartState *s = EXYNOS4210_UART(dev);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
|
||||
exynos4210_uart_receive, exynos4210_uart_event,
|
||||
s, NULL, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property exynos4210_uart_properties[] = {
|
||||
@@ -658,9 +662,8 @@ static Property exynos4210_uart_properties[] = {
|
||||
static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = exynos4210_uart_init;
|
||||
dc->realize = exynos4210_uart_realize;
|
||||
dc->reset = exynos4210_uart_reset;
|
||||
dc->props = exynos4210_uart_properties;
|
||||
dc->vmsd = &vmstate_exynos4210_uart;
|
||||
@@ -670,6 +673,7 @@ static const TypeInfo exynos4210_uart_info = {
|
||||
.name = TYPE_EXYNOS4210_UART,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Exynos4210UartState),
|
||||
.instance_init = exynos4210_uart_init,
|
||||
.class_init = exynos4210_uart_class_init,
|
||||
};
|
||||
|
||||
|
||||
@@ -732,6 +732,7 @@ static void virtio_serial_post_load_timer_cb(void *opaque)
|
||||
static int fetch_active_ports_list(QEMUFile *f,
|
||||
VirtIOSerial *s, uint32_t nr_active_ports)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
uint32_t i;
|
||||
|
||||
s->post_load = g_malloc0(sizeof(*s->post_load));
|
||||
@@ -765,7 +766,7 @@ static int fetch_active_ports_list(QEMUFile *f,
|
||||
qemu_get_be64s(f, &port->iov_offset);
|
||||
|
||||
port->elem =
|
||||
qemu_get_virtqueue_element(f, sizeof(VirtQueueElement));
|
||||
qemu_get_virtqueue_element(vdev, f, sizeof(VirtQueueElement));
|
||||
|
||||
/*
|
||||
* Port was throttled on source machine. Let's
|
||||
|
||||
@@ -554,31 +554,11 @@ static void machine_class_finalize(ObjectClass *klass, void *data)
|
||||
g_free(mc->name);
|
||||
}
|
||||
|
||||
static void register_compat_prop(const char *driver,
|
||||
const char *property,
|
||||
const char *value)
|
||||
{
|
||||
GlobalProperty *p = g_new0(GlobalProperty, 1);
|
||||
/* Machine compat_props must never cause errors: */
|
||||
p->errp = &error_abort;
|
||||
p->driver = driver;
|
||||
p->property = property;
|
||||
p->value = value;
|
||||
qdev_prop_register_global(p);
|
||||
}
|
||||
|
||||
static void machine_register_compat_for_subclass(ObjectClass *oc, void *opaque)
|
||||
{
|
||||
GlobalProperty *p = opaque;
|
||||
register_compat_prop(object_class_get_name(oc), p->property, p->value);
|
||||
}
|
||||
|
||||
void machine_register_compat_props(MachineState *machine)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
int i;
|
||||
GlobalProperty *p;
|
||||
ObjectClass *oc;
|
||||
|
||||
if (!mc->compat_props) {
|
||||
return;
|
||||
@@ -586,22 +566,9 @@ void machine_register_compat_props(MachineState *machine)
|
||||
|
||||
for (i = 0; i < mc->compat_props->len; i++) {
|
||||
p = g_array_index(mc->compat_props, GlobalProperty *, i);
|
||||
oc = object_class_by_name(p->driver);
|
||||
if (oc && object_class_is_abstract(oc)) {
|
||||
/* temporary hack to make sure we do not override
|
||||
* globals set explicitly on -global: if an abstract class
|
||||
* is on compat_props, register globals for all its
|
||||
* non-abstract subtypes instead.
|
||||
*
|
||||
* This doesn't solve the problem for cases where
|
||||
* a non-abstract typename mentioned on compat_props
|
||||
* has subclasses, like spapr-pci-host-bridge.
|
||||
*/
|
||||
object_class_foreach(machine_register_compat_for_subclass,
|
||||
p->driver, false, p);
|
||||
} else {
|
||||
register_compat_prop(p->driver, p->property, p->value);
|
||||
}
|
||||
/* Machine compat_props must never cause errors: */
|
||||
p->errp = &error_abort;
|
||||
qdev_prop_register_global(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -177,12 +177,11 @@
|
||||
|
||||
struct CirrusVGAState;
|
||||
typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
|
||||
uint32_t dstaddr, uint32_t srcaddr,
|
||||
uint8_t * dst, const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight);
|
||||
typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
|
||||
uint32_t dstaddr, int dst_pitch,
|
||||
int width, int height);
|
||||
uint8_t *dst, int dst_pitch, int width, int height);
|
||||
|
||||
typedef struct CirrusVGAState {
|
||||
VGACommonState vga;
|
||||
@@ -278,9 +277,10 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
}
|
||||
if (pitch < 0) {
|
||||
int64_t min = addr
|
||||
+ ((int64_t)s->cirrus_blt_height - 1) * pitch
|
||||
- s->cirrus_blt_width;
|
||||
if (min < -1 || addr >= s->vga.vram_size) {
|
||||
+ ((int64_t)s->cirrus_blt_height-1) * pitch;
|
||||
int32_t max = addr
|
||||
+ s->cirrus_blt_width;
|
||||
if (min < 0 || max > s->vga.vram_size) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@@ -294,7 +294,7 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
|
||||
static bool blit_is_unsafe(struct CirrusVGAState *s)
|
||||
{
|
||||
/* should be the case, see cirrus_bitblt_start */
|
||||
assert(s->cirrus_blt_width > 0);
|
||||
@@ -305,14 +305,11 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
|
||||
}
|
||||
|
||||
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
|
||||
s->cirrus_blt_dstaddr)) {
|
||||
s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
|
||||
return true;
|
||||
}
|
||||
if (dst_only) {
|
||||
return false;
|
||||
}
|
||||
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
|
||||
s->cirrus_blt_srcaddr)) {
|
||||
s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -320,57 +317,18 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
|
||||
}
|
||||
|
||||
static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
|
||||
uint32_t dstaddr, uint32_t srcaddr,
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
}
|
||||
|
||||
static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
|
||||
uint32_t dstaddr,
|
||||
uint8_t *dst,
|
||||
int dstpitch, int bltwidth,int bltheight)
|
||||
{
|
||||
}
|
||||
|
||||
static inline uint8_t cirrus_src(CirrusVGAState *s, uint32_t srcaddr)
|
||||
{
|
||||
if (s->cirrus_srccounter) {
|
||||
/* cputovideo */
|
||||
return s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1)];
|
||||
} else {
|
||||
/* videotovideo */
|
||||
return s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask];
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint16_t cirrus_src16(CirrusVGAState *s, uint32_t srcaddr)
|
||||
{
|
||||
uint16_t *src;
|
||||
|
||||
if (s->cirrus_srccounter) {
|
||||
/* cputovideo */
|
||||
src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~1];
|
||||
} else {
|
||||
/* videotovideo */
|
||||
src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~1];
|
||||
}
|
||||
return *src;
|
||||
}
|
||||
|
||||
static inline uint32_t cirrus_src32(CirrusVGAState *s, uint32_t srcaddr)
|
||||
{
|
||||
uint32_t *src;
|
||||
|
||||
if (s->cirrus_srccounter) {
|
||||
/* cputovideo */
|
||||
src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~3];
|
||||
} else {
|
||||
/* videotovideo */
|
||||
src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~3];
|
||||
}
|
||||
return *src;
|
||||
}
|
||||
|
||||
#define ROP_NAME 0
|
||||
#define ROP_FN(d, s) 0
|
||||
#include "cirrus_vga_rop.h"
|
||||
@@ -700,51 +658,25 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
|
||||
int off_cur;
|
||||
int off_cur_end;
|
||||
|
||||
if (off_pitch < 0) {
|
||||
off_begin -= bytesperline - 1;
|
||||
}
|
||||
|
||||
for (y = 0; y < lines; y++) {
|
||||
off_cur = off_begin;
|
||||
off_cur_end = ((off_cur + bytesperline - 1) & s->cirrus_addr_mask) + 1;
|
||||
assert(off_cur_end >= off_cur);
|
||||
off_cur = off_begin;
|
||||
off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
|
||||
memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
|
||||
off_begin += off_pitch;
|
||||
off_begin += off_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s)
|
||||
static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
|
||||
const uint8_t * src)
|
||||
{
|
||||
uint32_t patternsize;
|
||||
bool videosrc = !s->cirrus_srccounter;
|
||||
uint8_t *dst;
|
||||
|
||||
if (videosrc) {
|
||||
switch (s->vga.get_bpp(&s->vga)) {
|
||||
case 8:
|
||||
patternsize = 64;
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
patternsize = 128;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
default:
|
||||
patternsize = 256;
|
||||
break;
|
||||
}
|
||||
s->cirrus_blt_srcaddr &= ~(patternsize - 1);
|
||||
if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
|
||||
|
||||
if (blit_is_unsafe(s, true)) {
|
||||
if (blit_is_unsafe(s))
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*s->cirrus_rop) (s, s->cirrus_blt_dstaddr,
|
||||
videosrc ? s->cirrus_blt_srcaddr : 0,
|
||||
(*s->cirrus_rop) (s, dst, src,
|
||||
s->cirrus_blt_dstpitch, 0,
|
||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
||||
@@ -759,11 +691,11 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||
{
|
||||
cirrus_fill_t rop_func;
|
||||
|
||||
if (blit_is_unsafe(s, true)) {
|
||||
if (blit_is_unsafe(s)) {
|
||||
return 0;
|
||||
}
|
||||
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
|
||||
rop_func(s, s->cirrus_blt_dstaddr,
|
||||
rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
||||
s->cirrus_blt_dstpitch,
|
||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
||||
@@ -781,7 +713,9 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||
|
||||
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
||||
{
|
||||
return cirrus_bitblt_common_patterncopy(s);
|
||||
return cirrus_bitblt_common_patterncopy(s,
|
||||
s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
|
||||
s->cirrus_addr_mask));
|
||||
}
|
||||
|
||||
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
@@ -830,15 +764,23 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
}
|
||||
}
|
||||
|
||||
(*s->cirrus_rop) (s, s->cirrus_blt_dstaddr,
|
||||
s->cirrus_blt_srcaddr,
|
||||
/* we have to flush all pending changes so that the copy
|
||||
is generated at the appropriate moment in time */
|
||||
if (notify)
|
||||
graphic_hw_update(s->vga.con);
|
||||
|
||||
(*s->cirrus_rop) (s, s->vga.vram_ptr +
|
||||
(s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
||||
s->vga.vram_ptr +
|
||||
(s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
|
||||
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
|
||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||
|
||||
if (notify) {
|
||||
dpy_gfx_update(s->vga.con, dx, dy,
|
||||
s->cirrus_blt_width / depth,
|
||||
s->cirrus_blt_height);
|
||||
qemu_console_copy(s->vga.con,
|
||||
sx, sy, dx, dy,
|
||||
s->cirrus_blt_width / depth,
|
||||
s->cirrus_blt_height);
|
||||
}
|
||||
|
||||
/* we don't have to notify the display that this portion has
|
||||
@@ -853,7 +795,7 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
|
||||
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||
{
|
||||
if (blit_is_unsafe(s, false))
|
||||
if (blit_is_unsafe(s))
|
||||
return 0;
|
||||
|
||||
return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
|
||||
@@ -874,15 +816,16 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
|
||||
|
||||
if (s->cirrus_srccounter > 0) {
|
||||
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
|
||||
cirrus_bitblt_common_patterncopy(s);
|
||||
cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
|
||||
the_end:
|
||||
s->cirrus_srccounter = 0;
|
||||
cirrus_bitblt_reset(s);
|
||||
} else {
|
||||
/* at least one scan line */
|
||||
do {
|
||||
(*s->cirrus_rop)(s, s->cirrus_blt_dstaddr,
|
||||
0, 0, 0, s->cirrus_blt_width, 1);
|
||||
(*s->cirrus_rop)(s, s->vga.vram_ptr +
|
||||
(s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
||||
s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
|
||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
|
||||
s->cirrus_blt_width, 1);
|
||||
s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
|
||||
@@ -928,10 +871,6 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
|
||||
{
|
||||
int w;
|
||||
|
||||
if (blit_is_unsafe(s, true)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
|
||||
s->cirrus_srcptr = &s->cirrus_bltbuf[0];
|
||||
s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
|
||||
@@ -957,10 +896,6 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
|
||||
}
|
||||
s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
|
||||
}
|
||||
|
||||
/* the blit_is_unsafe call above should catch this */
|
||||
assert(s->cirrus_blt_srcpitch <= CIRRUS_BLTBUFSIZE);
|
||||
|
||||
s->cirrus_srcptr = s->cirrus_bltbuf;
|
||||
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
|
||||
cirrus_update_memory_access(s);
|
||||
@@ -1008,9 +943,6 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
|
||||
s->cirrus_blt_modeext = s->vga.gr[0x33];
|
||||
blt_rop = s->vga.gr[0x32];
|
||||
|
||||
s->cirrus_blt_dstaddr &= s->cirrus_addr_mask;
|
||||
s->cirrus_blt_srcaddr &= s->cirrus_addr_mask;
|
||||
|
||||
#ifdef DEBUG_BITBLT
|
||||
printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
|
||||
blt_rop,
|
||||
|
||||
@@ -22,65 +22,31 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
static inline void glue(rop_8_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint32_t dstaddr, uint8_t src)
|
||||
static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
|
||||
{
|
||||
uint8_t *dst = &s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask];
|
||||
*dst = ROP_FN(*dst, src);
|
||||
}
|
||||
|
||||
static inline void glue(rop_tr_8_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint32_t dstaddr, uint8_t src,
|
||||
uint8_t transp)
|
||||
static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
|
||||
{
|
||||
uint8_t *dst = &s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask];
|
||||
uint8_t pixel = ROP_FN(*dst, src);
|
||||
if (pixel != transp) {
|
||||
*dst = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void glue(rop_16_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint32_t dstaddr, uint16_t src)
|
||||
{
|
||||
uint16_t *dst = (uint16_t *)
|
||||
(&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~1]);
|
||||
*dst = ROP_FN(*dst, src);
|
||||
}
|
||||
|
||||
static inline void glue(rop_tr_16_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint32_t dstaddr, uint16_t src,
|
||||
uint16_t transp)
|
||||
static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
|
||||
{
|
||||
uint16_t *dst = (uint16_t *)
|
||||
(&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~1]);
|
||||
uint16_t pixel = ROP_FN(*dst, src);
|
||||
if (pixel != transp) {
|
||||
*dst = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void glue(rop_32_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint32_t dstaddr, uint32_t src)
|
||||
{
|
||||
uint32_t *dst = (uint32_t *)
|
||||
(&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~3]);
|
||||
*dst = ROP_FN(*dst, src);
|
||||
}
|
||||
|
||||
#define ROP_OP(st, d, s) glue(rop_8_, ROP_NAME)(st, d, s)
|
||||
#define ROP_OP_TR(st, d, s, t) glue(rop_tr_8_, ROP_NAME)(st, d, s, t)
|
||||
#define ROP_OP_16(st, d, s) glue(rop_16_, ROP_NAME)(st, d, s)
|
||||
#define ROP_OP_TR_16(st, d, s, t) glue(rop_tr_16_, ROP_NAME)(st, d, s, t)
|
||||
#define ROP_OP_32(st, d, s) glue(rop_32_, ROP_NAME)(st, d, s)
|
||||
#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
|
||||
#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
|
||||
#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
|
||||
#undef ROP_FN
|
||||
|
||||
static void
|
||||
glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
dstpitch -= bltwidth;
|
||||
@@ -92,139 +58,134 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
|
||||
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x++) {
|
||||
ROP_OP(s, dstaddr, cirrus_src(s, srcaddr));
|
||||
dstaddr++;
|
||||
srcaddr++;
|
||||
ROP_OP(dst, *src);
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
dstaddr += dstpitch;
|
||||
srcaddr += srcpitch;
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
|
||||
uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
dstpitch += bltwidth;
|
||||
srcpitch += bltwidth;
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x++) {
|
||||
ROP_OP(s, dstaddr, cirrus_src(s, srcaddr));
|
||||
dstaddr--;
|
||||
srcaddr--;
|
||||
ROP_OP(dst, *src);
|
||||
dst--;
|
||||
src--;
|
||||
}
|
||||
dstaddr += dstpitch;
|
||||
srcaddr += srcpitch;
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
||||
uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
int dstpitch,
|
||||
int srcpitch,
|
||||
int bltwidth,
|
||||
int bltheight)
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
uint8_t transp = s->vga.gr[0x34];
|
||||
uint8_t p;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
|
||||
if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x++) {
|
||||
ROP_OP_TR(s, dstaddr, cirrus_src(s, srcaddr), transp);
|
||||
dstaddr++;
|
||||
srcaddr++;
|
||||
p = *dst;
|
||||
ROP_OP(&p, *src);
|
||||
if (p != s->vga.gr[0x34]) *dst = p;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
dstaddr += dstpitch;
|
||||
srcaddr += srcpitch;
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
||||
uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
int dstpitch,
|
||||
int srcpitch,
|
||||
int bltwidth,
|
||||
int bltheight)
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
uint8_t transp = s->vga.gr[0x34];
|
||||
uint8_t p;
|
||||
dstpitch += bltwidth;
|
||||
srcpitch += bltwidth;
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x++) {
|
||||
ROP_OP_TR(s, dstaddr, cirrus_src(s, srcaddr), transp);
|
||||
dstaddr--;
|
||||
srcaddr--;
|
||||
p = *dst;
|
||||
ROP_OP(&p, *src);
|
||||
if (p != s->vga.gr[0x34]) *dst = p;
|
||||
dst--;
|
||||
src--;
|
||||
}
|
||||
dstaddr += dstpitch;
|
||||
srcaddr += srcpitch;
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
||||
uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
int dstpitch,
|
||||
int srcpitch,
|
||||
int bltwidth,
|
||||
int bltheight)
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
uint16_t transp = s->vga.gr[0x34] | (uint16_t)s->vga.gr[0x35] << 8;
|
||||
uint8_t p1, p2;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
|
||||
if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x+=2) {
|
||||
ROP_OP_TR_16(s, dstaddr, cirrus_src16(s, srcaddr), transp);
|
||||
dstaddr += 2;
|
||||
srcaddr += 2;
|
||||
p1 = *dst;
|
||||
p2 = *(dst+1);
|
||||
ROP_OP(&p1, *src);
|
||||
ROP_OP(&p2, *(src + 1));
|
||||
if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
|
||||
*dst = p1;
|
||||
*(dst+1) = p2;
|
||||
}
|
||||
dst+=2;
|
||||
src+=2;
|
||||
}
|
||||
dstaddr += dstpitch;
|
||||
srcaddr += srcpitch;
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
||||
uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
int dstpitch,
|
||||
int srcpitch,
|
||||
int bltwidth,
|
||||
int bltheight)
|
||||
uint8_t *dst,const uint8_t *src,
|
||||
int dstpitch,int srcpitch,
|
||||
int bltwidth,int bltheight)
|
||||
{
|
||||
int x,y;
|
||||
uint16_t transp = s->vga.gr[0x34] | (uint16_t)s->vga.gr[0x35] << 8;
|
||||
uint8_t p1, p2;
|
||||
dstpitch += bltwidth;
|
||||
srcpitch += bltwidth;
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x+=2) {
|
||||
ROP_OP_TR_16(s, dstaddr - 1, cirrus_src16(s, srcaddr - 1), transp);
|
||||
dstaddr -= 2;
|
||||
srcaddr -= 2;
|
||||
p1 = *(dst-1);
|
||||
p2 = *dst;
|
||||
ROP_OP(&p1, *(src - 1));
|
||||
ROP_OP(&p2, *src);
|
||||
if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
|
||||
*(dst-1) = p1;
|
||||
*dst = p2;
|
||||
}
|
||||
dst-=2;
|
||||
src-=2;
|
||||
}
|
||||
dstaddr += dstpitch;
|
||||
srcaddr += srcpitch;
|
||||
dst += dstpitch;
|
||||
src += srcpitch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,32 +23,30 @@
|
||||
*/
|
||||
|
||||
#if DEPTH == 8
|
||||
#define PUTPIXEL(s, a, c) ROP_OP(s, a, c)
|
||||
#define PUTPIXEL() ROP_OP(&d[0], col)
|
||||
#elif DEPTH == 16
|
||||
#define PUTPIXEL(s, a, c) ROP_OP_16(s, a, c)
|
||||
#define PUTPIXEL() ROP_OP_16((uint16_t *)&d[0], col)
|
||||
#elif DEPTH == 24
|
||||
#define PUTPIXEL(s, a, c) do { \
|
||||
ROP_OP(s, a, c); \
|
||||
ROP_OP(s, a + 1, (col >> 8)); \
|
||||
ROP_OP(s, a + 2, (col >> 16)); \
|
||||
} while (0)
|
||||
#define PUTPIXEL() ROP_OP(&d[0], col); \
|
||||
ROP_OP(&d[1], (col >> 8)); \
|
||||
ROP_OP(&d[2], (col >> 16))
|
||||
#elif DEPTH == 32
|
||||
#define PUTPIXEL(s, a, c) ROP_OP_32(s, a, c)
|
||||
#define PUTPIXEL() ROP_OP_32(((uint32_t *)&d[0]), col)
|
||||
#else
|
||||
#error unsupported DEPTH
|
||||
#endif
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState *s, uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint8_t *d;
|
||||
int x, y, pattern_y, pattern_pitch, pattern_x;
|
||||
unsigned int col;
|
||||
uint32_t src1addr;
|
||||
const uint8_t *src1;
|
||||
#if DEPTH == 24
|
||||
int skipleft = s->vga.gr[0x2f] & 0x1f;
|
||||
#else
|
||||
@@ -65,44 +63,42 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
|
||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
pattern_x = skipleft;
|
||||
addr = dstaddr + skipleft;
|
||||
src1addr = srcaddr + pattern_y * pattern_pitch;
|
||||
d = dst + skipleft;
|
||||
src1 = src + pattern_y * pattern_pitch;
|
||||
for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
#if DEPTH == 8
|
||||
col = cirrus_src(s, src1addr + pattern_x);
|
||||
col = src1[pattern_x];
|
||||
pattern_x = (pattern_x + 1) & 7;
|
||||
#elif DEPTH == 16
|
||||
col = cirrus_src16(s, src1addr + pattern_x);
|
||||
col = ((uint16_t *)(src1 + pattern_x))[0];
|
||||
pattern_x = (pattern_x + 2) & 15;
|
||||
#elif DEPTH == 24
|
||||
{
|
||||
uint32_t src2addr = src1addr + pattern_x * 3;
|
||||
col = cirrus_src(s, src2addr) |
|
||||
(cirrus_src(s, src2addr + 1) << 8) |
|
||||
(cirrus_src(s, src2addr + 2) << 16);
|
||||
const uint8_t *src2 = src1 + pattern_x * 3;
|
||||
col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
|
||||
pattern_x = (pattern_x + 1) & 7;
|
||||
}
|
||||
#else
|
||||
col = cirrus_src32(s, src1addr + pattern_x);
|
||||
col = ((uint32_t *)(src1 + pattern_x))[0];
|
||||
pattern_x = (pattern_x + 4) & 31;
|
||||
#endif
|
||||
PUTPIXEL(s, addr, col);
|
||||
addr += (DEPTH / 8);
|
||||
PUTPIXEL();
|
||||
d += (DEPTH / 8);
|
||||
}
|
||||
pattern_y = (pattern_y + 1) & 7;
|
||||
dstaddr += dstpitch;
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: srcpitch is ignored */
|
||||
static void
|
||||
glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState *s, uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint8_t *d;
|
||||
int x, y;
|
||||
unsigned bits, bits_xor;
|
||||
unsigned int col;
|
||||
@@ -126,33 +122,33 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
|
||||
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
bitmask = 0x80 >> srcskipleft;
|
||||
bits = cirrus_src(s, srcaddr++) ^ bits_xor;
|
||||
addr = dstaddr + dstskipleft;
|
||||
bits = *src++ ^ bits_xor;
|
||||
d = dst + dstskipleft;
|
||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
if ((bitmask & 0xff) == 0) {
|
||||
bitmask = 0x80;
|
||||
bits = cirrus_src(s, srcaddr++) ^ bits_xor;
|
||||
bits = *src++ ^ bits_xor;
|
||||
}
|
||||
index = (bits & bitmask);
|
||||
if (index) {
|
||||
PUTPIXEL(s, addr, col);
|
||||
PUTPIXEL();
|
||||
}
|
||||
addr += (DEPTH / 8);
|
||||
d += (DEPTH / 8);
|
||||
bitmask >>= 1;
|
||||
}
|
||||
dstaddr += dstpitch;
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState *s, uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint32_t colors[2];
|
||||
uint32_t addr;
|
||||
uint8_t *d;
|
||||
int x, y;
|
||||
unsigned bits;
|
||||
unsigned int col;
|
||||
@@ -164,30 +160,30 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
|
||||
colors[1] = s->cirrus_blt_fgcol;
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
bitmask = 0x80 >> srcskipleft;
|
||||
bits = cirrus_src(s, srcaddr++);
|
||||
addr = dstaddr + dstskipleft;
|
||||
bits = *src++;
|
||||
d = dst + dstskipleft;
|
||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
if ((bitmask & 0xff) == 0) {
|
||||
bitmask = 0x80;
|
||||
bits = cirrus_src(s, srcaddr++);
|
||||
bits = *src++;
|
||||
}
|
||||
col = colors[!!(bits & bitmask)];
|
||||
PUTPIXEL(s, addr, col);
|
||||
addr += (DEPTH / 8);
|
||||
PUTPIXEL();
|
||||
d += (DEPTH / 8);
|
||||
bitmask >>= 1;
|
||||
}
|
||||
dstaddr += dstpitch;
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState *s, uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint8_t *d;
|
||||
int x, y, bitpos, pattern_y;
|
||||
unsigned int bits, bits_xor;
|
||||
unsigned int col;
|
||||
@@ -209,30 +205,30 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
|
||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
bits = cirrus_src(s, srcaddr + pattern_y) ^ bits_xor;
|
||||
bits = src[pattern_y] ^ bits_xor;
|
||||
bitpos = 7 - srcskipleft;
|
||||
addr = dstaddr + dstskipleft;
|
||||
d = dst + dstskipleft;
|
||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
if ((bits >> bitpos) & 1) {
|
||||
PUTPIXEL(s, addr, col);
|
||||
PUTPIXEL();
|
||||
}
|
||||
addr += (DEPTH / 8);
|
||||
d += (DEPTH / 8);
|
||||
bitpos = (bitpos - 1) & 7;
|
||||
}
|
||||
pattern_y = (pattern_y + 1) & 7;
|
||||
dstaddr += dstpitch;
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState *s, uint32_t dstaddr,
|
||||
uint32_t srcaddr,
|
||||
(CirrusVGAState * s, uint8_t * dst,
|
||||
const uint8_t * src,
|
||||
int dstpitch, int srcpitch,
|
||||
int bltwidth, int bltheight)
|
||||
{
|
||||
uint32_t colors[2];
|
||||
uint32_t addr;
|
||||
uint8_t *d;
|
||||
int x, y, bitpos, pattern_y;
|
||||
unsigned int bits;
|
||||
unsigned int col;
|
||||
@@ -244,39 +240,40 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
|
||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
bits = cirrus_src(s, srcaddr + pattern_y);
|
||||
bits = src[pattern_y];
|
||||
bitpos = 7 - srcskipleft;
|
||||
addr = dstaddr + dstskipleft;
|
||||
d = dst + dstskipleft;
|
||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
col = colors[(bits >> bitpos) & 1];
|
||||
PUTPIXEL(s, addr, col);
|
||||
addr += (DEPTH / 8);
|
||||
PUTPIXEL();
|
||||
d += (DEPTH / 8);
|
||||
bitpos = (bitpos - 1) & 7;
|
||||
}
|
||||
pattern_y = (pattern_y + 1) & 7;
|
||||
dstaddr += dstpitch;
|
||||
dst += dstpitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
|
||||
(CirrusVGAState *s,
|
||||
uint32_t dstaddr, int dst_pitch,
|
||||
uint8_t *dst, int dst_pitch,
|
||||
int width, int height)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint8_t *d, *d1;
|
||||
uint32_t col;
|
||||
int x, y;
|
||||
|
||||
col = s->cirrus_blt_fgcol;
|
||||
|
||||
d1 = dst;
|
||||
for(y = 0; y < height; y++) {
|
||||
addr = dstaddr;
|
||||
d = d1;
|
||||
for(x = 0; x < width; x += (DEPTH / 8)) {
|
||||
PUTPIXEL(s, addr, col);
|
||||
addr += (DEPTH / 8);
|
||||
PUTPIXEL();
|
||||
d += (DEPTH / 8);
|
||||
}
|
||||
dstaddr += dst_pitch;
|
||||
d1 += dst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ static int ssd0303_send(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int ssd0303_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
ssd0303_state *s = SSD0303(i2c);
|
||||
|
||||
@@ -193,6 +193,8 @@ static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
|
||||
/* Nothing to do. */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssd0303_update_display(void *opaque)
|
||||
|
||||
@@ -291,8 +291,11 @@ static void virgl_resource_attach_backing(VirtIOGPU *g,
|
||||
return;
|
||||
}
|
||||
|
||||
virgl_renderer_resource_attach_iov(att_rb.resource_id,
|
||||
res_iovs, att_rb.nr_entries);
|
||||
ret = virgl_renderer_resource_attach_iov(att_rb.resource_id,
|
||||
res_iovs, att_rb.nr_entries);
|
||||
|
||||
if (ret != 0)
|
||||
virtio_gpu_cleanup_mapping_iov(res_iovs, att_rb.nr_entries);
|
||||
}
|
||||
|
||||
static void virgl_resource_detach_backing(VirtIOGPU *g,
|
||||
@@ -371,8 +374,12 @@ static void virgl_cmd_get_capset(VirtIOGPU *g,
|
||||
|
||||
virgl_renderer_get_cap_set(gc.capset_id, &max_ver,
|
||||
&max_size);
|
||||
resp = g_malloc(sizeof(*resp) + max_size);
|
||||
if (!max_size) {
|
||||
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
resp = g_malloc(sizeof(*resp) + max_size);
|
||||
resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
|
||||
virgl_renderer_fill_caps(gc.capset_id,
|
||||
gc.capset_version,
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
static struct virtio_gpu_simple_resource*
|
||||
virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
|
||||
|
||||
static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res);
|
||||
|
||||
#ifdef CONFIG_VIRGL
|
||||
#include <virglrenderer.h>
|
||||
#define VIRGL(_g, _virgl, _simple, ...) \
|
||||
@@ -338,10 +340,14 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
|
||||
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
res->image = pixman_image_create_bits(pformat,
|
||||
c2d.width,
|
||||
c2d.height,
|
||||
NULL, 0);
|
||||
|
||||
res->hostmem = PIXMAN_FORMAT_BPP(pformat) * c2d.width * c2d.height;
|
||||
if (res->hostmem + g->hostmem < g->conf.max_hostmem) {
|
||||
res->image = pixman_image_create_bits(pformat,
|
||||
c2d.width,
|
||||
c2d.height,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
if (!res->image) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
@@ -353,13 +359,16 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
|
||||
}
|
||||
|
||||
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
|
||||
g->hostmem += res->hostmem;
|
||||
}
|
||||
|
||||
static void virtio_gpu_resource_destroy(VirtIOGPU *g,
|
||||
struct virtio_gpu_simple_resource *res)
|
||||
{
|
||||
pixman_image_unref(res->image);
|
||||
virtio_gpu_cleanup_mapping(res);
|
||||
QTAILQ_REMOVE(&g->reslist, res, next);
|
||||
g->hostmem -= res->hostmem;
|
||||
g_free(res);
|
||||
}
|
||||
|
||||
@@ -705,6 +714,11 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
|
||||
return;
|
||||
}
|
||||
|
||||
if (res->iov) {
|
||||
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->addrs, &res->iov);
|
||||
if (ret != 0) {
|
||||
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||
@@ -1241,6 +1255,8 @@ static const VMStateDescription vmstate_virtio_gpu = {
|
||||
|
||||
static Property virtio_gpu_properties[] = {
|
||||
DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
|
||||
DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf.max_hostmem,
|
||||
256 * 1024 * 1024),
|
||||
#ifdef CONFIG_VIRGL
|
||||
DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags,
|
||||
VIRTIO_GPU_FLAG_VIRGL_ENABLED, true),
|
||||
|
||||
@@ -129,7 +129,7 @@ static int max7310_tx(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max7310_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int max7310_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
MAX7310State *s = MAX7310(i2c);
|
||||
s->len = 0;
|
||||
@@ -147,6 +147,8 @@ static void max7310_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_max7310 = {
|
||||
|
||||
@@ -88,18 +88,26 @@ int i2c_bus_busy(I2CBus *bus)
|
||||
return !QLIST_EMPTY(&bus->current_devs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns non-zero if the address is not valid. If this is called
|
||||
* again without an intervening i2c_end_transfer(), like in the SMBus
|
||||
* case where the operation is switched from write to read, this
|
||||
* function will not rescan the bus and thus cannot fail.
|
||||
*/
|
||||
/* TODO: Make this handle multiple masters. */
|
||||
/*
|
||||
* Start or continue an i2c transaction. When this is called for the
|
||||
* first time or after an i2c_end_transfer(), if it returns an error
|
||||
* the bus transaction is terminated (or really never started). If
|
||||
* this is called after another i2c_start_transfer() without an
|
||||
* intervening i2c_end_transfer(), and it returns an error, the
|
||||
* transaction will not be terminated. The caller must do it.
|
||||
*
|
||||
* This corresponds with the way real hardware works. The SMBus
|
||||
* protocol uses a start transfer to switch from write to read mode
|
||||
* without releasing the bus. If that fails, the bus is still
|
||||
* in a transaction.
|
||||
*/
|
||||
int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
|
||||
{
|
||||
BusChild *kid;
|
||||
I2CSlaveClass *sc;
|
||||
I2CNode *node;
|
||||
bool bus_scanned = false;
|
||||
|
||||
if (address == I2C_BROADCAST) {
|
||||
/*
|
||||
@@ -130,6 +138,7 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
|
||||
}
|
||||
}
|
||||
}
|
||||
bus_scanned = true;
|
||||
}
|
||||
|
||||
if (QLIST_EMPTY(&bus->current_devs)) {
|
||||
@@ -137,11 +146,21 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
|
||||
}
|
||||
|
||||
QLIST_FOREACH(node, &bus->current_devs, next) {
|
||||
int rv;
|
||||
|
||||
sc = I2C_SLAVE_GET_CLASS(node->elt);
|
||||
/* If the bus is already busy, assume this is a repeated
|
||||
start condition. */
|
||||
|
||||
if (sc->event) {
|
||||
sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND);
|
||||
rv = sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND);
|
||||
if (rv && !bus->broadcast) {
|
||||
if (bus_scanned) {
|
||||
/* First call, terminate the transfer. */
|
||||
i2c_end_transfer(bus);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -260,7 +279,11 @@ static int i2c_slave_qdev_init(DeviceState *dev)
|
||||
I2CSlave *s = I2C_SLAVE(dev);
|
||||
I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
|
||||
|
||||
return sc->init(s);
|
||||
if (sc->init) {
|
||||
return sc->init(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr)
|
||||
|
||||
@@ -230,13 +230,15 @@ static void i2c_ddc_reset(DeviceState *ds)
|
||||
s->reg = 0;
|
||||
}
|
||||
|
||||
static void i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
I2CDDCState *s = I2CDDC(i2c);
|
||||
|
||||
if (event == I2C_START_SEND) {
|
||||
s->firstbyte = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_ddc_rx(I2CSlave *i2c)
|
||||
|
||||
@@ -67,7 +67,7 @@ static void smbus_do_write(SMBusDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
|
||||
static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
|
||||
{
|
||||
SMBusDevice *dev = SMBUS_DEVICE(s);
|
||||
|
||||
@@ -148,6 +148,8 @@ static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smbus_i2c_recv(I2CSlave *s)
|
||||
@@ -249,7 +251,8 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
assert(0);
|
||||
i2c_end_transfer(bus);
|
||||
return -1;
|
||||
}
|
||||
data = i2c_recv(bus);
|
||||
i2c_nack(bus);
|
||||
@@ -276,7 +279,8 @@ int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
assert(0);
|
||||
i2c_end_transfer(bus);
|
||||
return -1;
|
||||
}
|
||||
data = i2c_recv(bus);
|
||||
data |= i2c_recv(bus) << 8;
|
||||
@@ -307,7 +311,8 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data)
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
assert(0);
|
||||
i2c_end_transfer(bus);
|
||||
return -1;
|
||||
}
|
||||
len = i2c_recv(bus);
|
||||
if (len > 32) {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qom/cpu.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "target-i386/cpu.h"
|
||||
#include "target/i386/cpu.h"
|
||||
#include "hw/timer/hpet.h"
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
@@ -101,8 +101,6 @@ typedef struct AcpiPmInfo {
|
||||
uint32_t gpe0_blk_len;
|
||||
uint32_t io_base;
|
||||
uint16_t cpu_hp_io_base;
|
||||
uint16_t mem_hp_io_base;
|
||||
uint16_t mem_hp_io_len;
|
||||
uint16_t pcihp_io_base;
|
||||
uint16_t pcihp_io_len;
|
||||
} AcpiPmInfo;
|
||||
@@ -148,9 +146,6 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
|
||||
}
|
||||
assert(obj);
|
||||
|
||||
pm->mem_hp_io_base = ACPI_MEMORY_HOTPLUG_BASE;
|
||||
pm->mem_hp_io_len = ACPI_MEMORY_HOTPLUG_IO_LEN;
|
||||
|
||||
/* Fill in optional s3/s4 related properties */
|
||||
o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL);
|
||||
if (o) {
|
||||
@@ -1038,130 +1033,6 @@ static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set)
|
||||
return crs;
|
||||
}
|
||||
|
||||
static void build_memory_devices(Aml *sb_scope, int nr_mem,
|
||||
uint16_t io_base, uint16_t io_len)
|
||||
{
|
||||
int i;
|
||||
Aml *scope;
|
||||
Aml *crs;
|
||||
Aml *field;
|
||||
Aml *dev;
|
||||
Aml *method;
|
||||
Aml *ifctx;
|
||||
|
||||
/* build memory devices */
|
||||
assert(nr_mem <= ACPI_MAX_RAM_SLOTS);
|
||||
scope = aml_scope("\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE);
|
||||
aml_append(scope,
|
||||
aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem))
|
||||
);
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs,
|
||||
aml_io(AML_DECODE16, io_base, io_base, 0, io_len)
|
||||
);
|
||||
aml_append(scope, aml_name_decl("_CRS", crs));
|
||||
|
||||
aml_append(scope, aml_operation_region(
|
||||
MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO,
|
||||
aml_int(io_base), io_len)
|
||||
);
|
||||
|
||||
field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC,
|
||||
AML_NOLOCK, AML_PRESERVE);
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_ADDR_LOW, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_SIZE_LOW, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_PROXIMITY, 32));
|
||||
aml_append(scope, field);
|
||||
|
||||
field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_BYTE_ACC,
|
||||
AML_NOLOCK, AML_WRITE_AS_ZEROS);
|
||||
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
|
||||
aml_append(field, /* 1 if enabled, read only */
|
||||
aml_named_field(MEMORY_SLOT_ENABLED, 1));
|
||||
aml_append(field,
|
||||
/*(read) 1 if has a insert event. (write) 1 to clear event */
|
||||
aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1));
|
||||
aml_append(field,
|
||||
/* (read) 1 if has a remove event. (write) 1 to clear event */
|
||||
aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1));
|
||||
aml_append(field,
|
||||
/* initiates device eject, write only */
|
||||
aml_named_field(MEMORY_SLOT_EJECT, 1));
|
||||
aml_append(scope, field);
|
||||
|
||||
field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC,
|
||||
AML_NOLOCK, AML_PRESERVE);
|
||||
aml_append(field, /* DIMM selector, write only */
|
||||
aml_named_field(MEMORY_SLOT_SLECTOR, 32));
|
||||
aml_append(field, /* _OST event code, write only */
|
||||
aml_named_field(MEMORY_SLOT_OST_EVENT, 32));
|
||||
aml_append(field, /* _OST status code, write only */
|
||||
aml_named_field(MEMORY_SLOT_OST_STATUS, 32));
|
||||
aml_append(scope, field);
|
||||
aml_append(sb_scope, scope);
|
||||
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
#define BASEPATH "\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE "."
|
||||
const char *s;
|
||||
|
||||
dev = aml_device("MP%02X", i);
|
||||
aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i)));
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80")));
|
||||
|
||||
method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_CRS_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_STATUS_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_PXM", 0, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_PROXIMITY_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_OST", 3, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_OST_METHOD;
|
||||
|
||||
aml_append(method, aml_return(aml_call4(
|
||||
s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2)
|
||||
)));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_EJECT_METHOD;
|
||||
aml_append(method, aml_return(aml_call2(
|
||||
s, aml_name("_UID"), aml_arg(0))));
|
||||
aml_append(dev, method);
|
||||
|
||||
aml_append(sb_scope, dev);
|
||||
}
|
||||
|
||||
/* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
|
||||
* If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
|
||||
*/
|
||||
method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
|
||||
aml_append(ifctx,
|
||||
aml_notify(aml_name("MP%.02X", i), aml_arg(1))
|
||||
);
|
||||
aml_append(method, ifctx);
|
||||
}
|
||||
aml_append(sb_scope, method);
|
||||
}
|
||||
|
||||
static void build_hpet_aml(Aml *table)
|
||||
{
|
||||
Aml *crs;
|
||||
@@ -2049,8 +1920,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
|
||||
"\\_SB.PCI0", "\\_GPE._E02");
|
||||
}
|
||||
build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base,
|
||||
pm->mem_hp_io_len);
|
||||
build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", "\\_GPE._E03");
|
||||
|
||||
scope = aml_scope("_GPE");
|
||||
{
|
||||
@@ -2065,10 +1935,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
aml_append(scope, method);
|
||||
}
|
||||
|
||||
method = aml_method("_E03", 0, AML_NOTSERIALIZED);
|
||||
aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH));
|
||||
aml_append(scope, method);
|
||||
|
||||
if (pcms->acpi_nvdimm_state.is_enabled) {
|
||||
method = aml_method("_E04", 0, AML_NOTSERIALIZED);
|
||||
aml_append(method, aml_notify(aml_name("\\_SB.NVDR"),
|
||||
@@ -2321,45 +2187,40 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
|
||||
sb_scope = aml_scope("\\_SB");
|
||||
{
|
||||
build_memory_devices(sb_scope, nr_mem, pm->mem_hp_io_base,
|
||||
pm->mem_hp_io_len);
|
||||
Object *pci_host;
|
||||
PCIBus *bus = NULL;
|
||||
|
||||
{
|
||||
Object *pci_host;
|
||||
PCIBus *bus = NULL;
|
||||
|
||||
pci_host = acpi_get_i386_pci_host();
|
||||
if (pci_host) {
|
||||
bus = PCI_HOST_BRIDGE(pci_host)->bus;
|
||||
}
|
||||
|
||||
if (bus) {
|
||||
Aml *scope = aml_scope("PCI0");
|
||||
/* Scan all PCI buses. Generate tables to support hotplug. */
|
||||
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
|
||||
|
||||
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
|
||||
dev = aml_device("ISA.TPM");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
|
||||
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
|
||||
/*
|
||||
FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs,
|
||||
Rewrite to take IRQ from TPM device model and
|
||||
fix default IRQ value there to use some unused IRQ
|
||||
*/
|
||||
/* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
aml_append(sb_scope, scope);
|
||||
}
|
||||
pci_host = acpi_get_i386_pci_host();
|
||||
if (pci_host) {
|
||||
bus = PCI_HOST_BRIDGE(pci_host)->bus;
|
||||
}
|
||||
|
||||
if (bus) {
|
||||
Aml *scope = aml_scope("PCI0");
|
||||
/* Scan all PCI buses. Generate tables to support hotplug. */
|
||||
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
|
||||
|
||||
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
|
||||
dev = aml_device("ISA.TPM");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
|
||||
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
|
||||
/*
|
||||
FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs,
|
||||
Rewrite to take IRQ from TPM device model and
|
||||
fix default IRQ value there to use some unused IRQ
|
||||
*/
|
||||
/* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
aml_append(sb_scope, scope);
|
||||
}
|
||||
aml_append(dsdt, sb_scope);
|
||||
}
|
||||
aml_append(dsdt, sb_scope);
|
||||
|
||||
/* copy AML table into ACPI tables blob and patch header there */
|
||||
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
|
||||
@@ -2575,6 +2436,7 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
|
||||
|
||||
AcpiTableDmar *dmar;
|
||||
AcpiDmarHardwareUnit *drhd;
|
||||
AcpiDmarRootPortATS *atsr;
|
||||
uint8_t dmar_flags = 0;
|
||||
X86IOMMUState *iommu = x86_iommu_get_default();
|
||||
AcpiDmarDeviceScope *scope = NULL;
|
||||
@@ -2608,6 +2470,14 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
|
||||
scope->path[0].device = PCI_SLOT(Q35_PSEUDO_DEVFN_IOAPIC);
|
||||
scope->path[0].function = PCI_FUNC(Q35_PSEUDO_DEVFN_IOAPIC);
|
||||
|
||||
if (iommu->dt_supported) {
|
||||
atsr = acpi_data_push(table_data, sizeof(*atsr));
|
||||
atsr->type = cpu_to_le16(ACPI_DMAR_TYPE_ATSR);
|
||||
atsr->length = cpu_to_le16(sizeof(*atsr));
|
||||
atsr->flags = ACPI_DMAR_ATSR_ALL_PORTS;
|
||||
atsr->pci_segment = cpu_to_le16(0);
|
||||
}
|
||||
|
||||
build_header(linker, table_data, (void *)(table_data->data + dmar_start),
|
||||
"DMAR", table_data->len - dmar_start, 1, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -562,7 +562,7 @@ static void amdvi_mmio_trace(hwaddr addr, unsigned size)
|
||||
trace_amdvi_mmio_read(amdvi_mmio_high[index], addr, size, addr & ~0x07);
|
||||
} else {
|
||||
index = index >= AMDVI_MMIO_REGS_LOW ? AMDVI_MMIO_REGS_LOW : index;
|
||||
trace_amdvi_mmio_read(amdvi_mmio_high[index], addr, size, addr & ~0x07);
|
||||
trace_amdvi_mmio_read(amdvi_mmio_low[index], addr, size, addr & ~0x07);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user