Compare commits
271 Commits
pull-ui-20
...
pull-vga-2
Author | SHA1 | Date | |
---|---|---|---|
|
12e97ec399 | ||
|
95280c31cd | ||
|
ec87f206d7 | ||
|
cf7dabeebc | ||
|
5e8e3c4c75 | ||
|
dd248ed7e2 | ||
|
33d076ebd0 | ||
|
78a22af040 | ||
|
fed5364971 | ||
|
8b1897725d | ||
|
396f935a9a | ||
|
e998e2090f | ||
|
57a6d6d538 | ||
|
8bd22f477f | ||
|
275e0d616b | ||
|
4ee74fa708 | ||
|
2a7e6857cd | ||
|
1b1aeb5828 | ||
|
537848ee62 | ||
|
c3ff04b60d | ||
|
f073cd3a2b | ||
|
aecfbbc97a | ||
|
f5095aa380 | ||
|
394c8bbfb7 | ||
|
9bb6558a21 | ||
|
63f26fcfda | ||
|
4061200059 | ||
|
f7478a92dd | ||
|
3a062d5730 | ||
|
00909b5858 | ||
|
42922105be | ||
|
013befe1ca | ||
|
854123bf8d | ||
|
26d3202207 | ||
|
d0dff238a8 | ||
|
3c457da147 | ||
|
ac7568bd3f | ||
|
6836a8fb96 | ||
|
a881c8e73f | ||
|
3d96995dec | ||
|
40493c5f2b | ||
|
e4d966cc65 | ||
|
ef8d6488d2 | ||
|
328d4d8528 | ||
|
67980031d2 | ||
|
581f08bac2 | ||
|
bc5c4f2196 | ||
|
b4b076daf3 | ||
|
7d2c6c9551 | ||
|
7da76e12cc | ||
|
c192325242 | ||
|
c7dfbf3225 | ||
|
96d87bdda3 | ||
|
ddb603ab6c | ||
|
13e8ff7abb | ||
|
f94d18d6c6 | ||
|
811ad5d8f1 | ||
|
e306b2fd3b | ||
|
0cd089e937 | ||
|
c124c4d13b | ||
|
1fc125f567 | ||
|
1401c322c8 | ||
|
a951316b8a | ||
|
cdd7abfdba | ||
|
4100a344eb | ||
|
77e217d1bf | ||
|
5b66d7ae89 | ||
|
5459ef3bff | ||
|
e9dcbc86d6 | ||
|
4e9f5244e1 | ||
|
0b17d809b0 | ||
|
62d4c6bd52 | ||
|
53761caf17 | ||
|
e905587b75 | ||
|
2d6752d38d | ||
|
7c6e879733 | ||
|
715d4b96a4 | ||
|
6925f12f4f | ||
|
76134d48b3 | ||
|
b8b4576e09 | ||
|
d801a61e98 | ||
|
78241762c4 | ||
|
403a884a40 | ||
|
00469dc373 | ||
|
60cd23e851 | ||
|
5858dd1801 | ||
|
f153b563f8 | ||
|
d8923bc754 | ||
|
1a0e4c8b02 | ||
|
2034ee5152 | ||
|
acf6e5f096 | ||
|
c4080e9391 | ||
|
28ddd08cd6 | ||
|
e80ab33dc0 | ||
|
a71264f9f5 | ||
|
1b28762a33 | ||
|
705ae59fec | ||
|
dc0ae76770 | ||
|
e0b283e7c5 | ||
|
d56ec1e98c | ||
|
c25d97c4ff | ||
|
ee640c625e | ||
|
20729dbd01 | ||
|
9348243687 | ||
|
e987c37aee | ||
|
f7d6f3fac8 | ||
|
fed23cb4e8 | ||
|
9d5154d753 | ||
|
04eb6247eb | ||
|
ec42813028 | ||
|
ed63ec0d22 | ||
|
d757573e69 | ||
|
f291887e8e | ||
|
60abf0a5e0 | ||
|
32f825dece | ||
|
213dcb060f | ||
|
6aa0f0c900 | ||
|
2b2f23dae7 | ||
|
c3b7d62097 | ||
|
1fcb3841d0 | ||
|
7c7b2db0bd | ||
|
d180081525 | ||
|
6fdafac1c1 | ||
|
3b4482a26d | ||
|
d24ca4b8c5 | ||
|
0e58f17777 | ||
|
503ebefe0a | ||
|
894593afbe | ||
|
a6da7ffa38 | ||
|
09fbe4e3e1 | ||
|
f612143a03 | ||
|
bf51f62869 | ||
|
df85a78bf8 | ||
|
247c92af2b | ||
|
eb314a9497 | ||
|
32d955a422 | ||
|
6fe791b5e3 | ||
|
7f4076c1bb | ||
|
6514532f73 | ||
|
25d54654da | ||
|
d4fa8436ce | ||
|
0ab8ed18a6 | ||
|
2098c56a9b | ||
|
9c5826306d | ||
|
1416f9ea6d | ||
|
de928314aa | ||
|
ba78db44f6 | ||
|
df45892c12 | ||
|
f298318284 | ||
|
178fe0ae9d | ||
|
0b663b7d77 | ||
|
279b066e4c | ||
|
88cace9f11 | ||
|
8cddc46990 | ||
|
7f2fe073f3 | ||
|
53a5736f94 | ||
|
c266d94e7b | ||
|
1566b0c455 | ||
|
4d833ada52 | ||
|
c930572883 | ||
|
9fa2f7a4ed | ||
|
fa943b5ea0 | ||
|
2c3a5dcbf8 | ||
|
819aad230a | ||
|
980d0414ce | ||
|
8955e8914c | ||
|
e96ebf494a | ||
|
18c508acdb | ||
|
55fc84a7a3 | ||
|
25e6a11832 | ||
|
c636367311 | ||
|
6a07692ffa | ||
|
42043e4f12 | ||
|
d9d6e78ea8 | ||
|
216c944eeb | ||
|
c104949f64 | ||
|
8b920d8abc | ||
|
a811ec0491 | ||
|
314c116347 | ||
|
48ef23cb26 | ||
|
c6d8c5ba5a | ||
|
5c32e2e4a0 | ||
|
31bc4d114a | ||
|
8178e89cbc | ||
|
05590b9252 | ||
|
cf9465a166 | ||
|
c5969d2eb1 | ||
|
46804e2875 | ||
|
08f1ee5a09 | ||
|
e385e4b7db | ||
|
d9031405a7 | ||
|
8a9472ec38 | ||
|
1b8d663d62 | ||
|
a54238adac | ||
|
a49a95e9e4 | ||
|
e04797f79e | ||
|
f539fbe337 | ||
|
6758c192b0 | ||
|
5d51eaea84 | ||
|
c3e4293ac9 | ||
|
365206aeb3 | ||
|
0dfe952dc5 | ||
|
2a084dadcb | ||
|
e548780359 | ||
|
07bdd2478b | ||
|
f6f242c757 | ||
|
152ef803ce | ||
|
ef29122649 | ||
|
29f8ddb72f | ||
|
05538220ac | ||
|
9eceae320e | ||
|
08e149869e | ||
|
9aeae8e16e | ||
|
f566c0474a | ||
|
ffc67420f9 | ||
|
5dc22bf581 | ||
|
1383602e0d | ||
|
34b9b5575b | ||
|
79623312c6 | ||
|
d2f8415226 | ||
|
3398b7428b | ||
|
8ad901e558 | ||
|
0f358a0710 | ||
|
09a7eb978f | ||
|
d0c2b0d089 | ||
|
396781f627 | ||
|
2bf25e07bb | ||
|
d69487d573 | ||
|
b84541693b | ||
|
f38a0b2fd7 | ||
|
2f8e4906ff | ||
|
9d2179d6f9 | ||
|
12dbeb16d0 | ||
|
9d6f106552 | ||
|
fa325e6cbf | ||
|
5904bca84e | ||
|
b99260ebbb | ||
|
e122090df3 | ||
|
681c247833 | ||
|
176e44e7eb | ||
|
6914bc4fb5 | ||
|
234068abfb | ||
|
014ed3bb20 | ||
|
8497d7fc69 | ||
|
071663dfc3 | ||
|
3259dbd9df | ||
|
cdee0e72d0 | ||
|
f9f2ed5ae0 | ||
|
1c7ad77e56 | ||
|
d6e166c082 | ||
|
1d1be34d26 | ||
|
5b120785e7 | ||
|
0c86d0fd92 | ||
|
60caf2216b | ||
|
466a3f9ca3 | ||
|
c3025c3b0a | ||
|
c85bc7dd90 | ||
|
a406c058e7 | ||
|
d59ba58380 | ||
|
e3001664f1 | ||
|
5cb091a4fd | ||
|
be0a4faf35 | ||
|
3a20d11d45 | ||
|
855f7a657e | ||
|
efa7319619 | ||
|
985e3023f7 | ||
|
bd97a59eec | ||
|
6d06220ad9 | ||
|
ae4d2eb273 | ||
|
090fa1c8c8 | ||
|
3d89e3f7e8 |
22
.gitignore
vendored
22
.gitignore
vendored
@@ -6,18 +6,12 @@
|
|||||||
/config.status
|
/config.status
|
||||||
/config-temp
|
/config-temp
|
||||||
/trace-events-all
|
/trace-events-all
|
||||||
/trace/generated-tracers.h
|
|
||||||
/trace/generated-tracers.c
|
|
||||||
/trace/generated-tracers-dtrace.h
|
|
||||||
/trace/generated-tracers.dtrace
|
|
||||||
/trace/generated-events.h
|
/trace/generated-events.h
|
||||||
/trace/generated-events.c
|
/trace/generated-events.c
|
||||||
/trace/generated-helpers-wrappers.h
|
/trace/generated-helpers-wrappers.h
|
||||||
/trace/generated-helpers.h
|
/trace/generated-helpers.h
|
||||||
/trace/generated-helpers.c
|
/trace/generated-helpers.c
|
||||||
/trace/generated-tcg-tracers.h
|
/trace/generated-tcg-tracers.h
|
||||||
/trace/generated-ust-provider.h
|
|
||||||
/trace/generated-ust.c
|
|
||||||
/ui/shader/texture-blit-frag.h
|
/ui/shader/texture-blit-frag.h
|
||||||
/ui/shader/texture-blit-vert.h
|
/ui/shader/texture-blit-vert.h
|
||||||
*-timestamp
|
*-timestamp
|
||||||
@@ -120,3 +114,19 @@ tags
|
|||||||
TAGS
|
TAGS
|
||||||
docker-src.*
|
docker-src.*
|
||||||
*~
|
*~
|
||||||
|
trace.h
|
||||||
|
trace.c
|
||||||
|
trace-ust.h
|
||||||
|
trace-ust.h
|
||||||
|
trace-dtrace.h
|
||||||
|
trace-dtrace.dtrace
|
||||||
|
trace-root.h
|
||||||
|
trace-root.c
|
||||||
|
trace-ust-root.h
|
||||||
|
trace-ust-root.h
|
||||||
|
trace-ust-all.h
|
||||||
|
trace-ust-all.c
|
||||||
|
trace-dtrace-root.h
|
||||||
|
trace-dtrace-root.dtrace
|
||||||
|
trace-ust-all.h
|
||||||
|
trace-ust-all.c
|
||||||
|
39
.travis.yml
39
.travis.yml
@@ -92,8 +92,8 @@ matrix:
|
|||||||
- env: CONFIG=""
|
- env: CONFIG=""
|
||||||
os: osx
|
os: osx
|
||||||
compiler: clang
|
compiler: clang
|
||||||
# Plain Trusty Build
|
# Plain Trusty System Build
|
||||||
- env: CONFIG=""
|
- env: CONFIG="--disable-linux-user"
|
||||||
sudo: required
|
sudo: required
|
||||||
addons:
|
addons:
|
||||||
dist: trusty
|
dist: trusty
|
||||||
@@ -103,16 +103,45 @@ matrix:
|
|||||||
- sudo apt-get build-dep -qq qemu
|
- sudo apt-get build-dep -qq qemu
|
||||||
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
# Trusty build with latest stable clang
|
# Plain Trusty Linux User Build
|
||||||
- env: CONFIG=""
|
- env: CONFIG="--disable-system"
|
||||||
sudo: required
|
sudo: required
|
||||||
|
addons:
|
||||||
|
dist: trusty
|
||||||
|
compiler: gcc
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
- sudo apt-get build-dep -qq qemu
|
||||||
|
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||||
|
- git submodule update --init --recursive
|
||||||
|
# Trusty System build with latest stable clang
|
||||||
|
- sudo: required
|
||||||
addons:
|
addons:
|
||||||
dist: trusty
|
dist: trusty
|
||||||
language: generic
|
language: generic
|
||||||
compiler: none
|
compiler: none
|
||||||
env:
|
env:
|
||||||
- COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
|
- COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
|
||||||
- CONFIG="--cc=clang-3.9 --cxx=clang++-3.9"
|
- CONFIG="--disable-linux-user --cc=clang-3.9 --cxx=clang++-3.9"
|
||||||
|
before_install:
|
||||||
|
- wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
|
- sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
- sudo apt-get install -qq -y clang-3.9
|
||||||
|
- sudo apt-get build-dep -qq qemu
|
||||||
|
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||||
|
- git submodule update --init --recursive
|
||||||
|
before_script:
|
||||||
|
- ./configure ${CONFIG} || cat config.log
|
||||||
|
# Trusty Linux User build with latest stable clang
|
||||||
|
- sudo: required
|
||||||
|
addons:
|
||||||
|
dist: trusty
|
||||||
|
language: generic
|
||||||
|
compiler: none
|
||||||
|
env:
|
||||||
|
- COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
|
||||||
|
- CONFIG="--disable-system --cc=clang-3.9 --cxx=clang++-3.9"
|
||||||
before_install:
|
before_install:
|
||||||
- wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
|
- wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
- sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
|
- sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
|
||||||
|
10
MAINTAINERS
10
MAINTAINERS
@@ -323,7 +323,7 @@ Guest CPU Cores (Xen):
|
|||||||
X86
|
X86
|
||||||
M: Stefano Stabellini <sstabellini@kernel.org>
|
M: Stefano Stabellini <sstabellini@kernel.org>
|
||||||
M: Anthony Perard <anthony.perard@citrix.com>
|
M: Anthony Perard <anthony.perard@citrix.com>
|
||||||
L: xen-devel@lists.xensource.com
|
L: xen-devel@lists.xenproject.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: xen-*
|
F: xen-*
|
||||||
F: */xen*
|
F: */xen*
|
||||||
@@ -671,10 +671,13 @@ F: hw/misc/macio/
|
|||||||
F: hw/intc/heathrow_pic.c
|
F: hw/intc/heathrow_pic.c
|
||||||
|
|
||||||
PReP
|
PReP
|
||||||
|
M: Hervé Poussineau <hpoussin@reactos.org>
|
||||||
L: qemu-devel@nongnu.org
|
L: qemu-devel@nongnu.org
|
||||||
L: qemu-ppc@nongnu.org
|
L: qemu-ppc@nongnu.org
|
||||||
S: Odd Fixes
|
S: Maintained
|
||||||
F: hw/ppc/prep.c
|
F: hw/ppc/prep.c
|
||||||
|
F: hw/ppc/prep_systemio.c
|
||||||
|
F: hw/ppc/rs6000_mc.c
|
||||||
F: hw/pci-host/prep.[hc]
|
F: hw/pci-host/prep.[hc]
|
||||||
F: hw/isa/pc87312.[hc]
|
F: hw/isa/pc87312.[hc]
|
||||||
F: pc-bios/ppc_rom.bin
|
F: pc-bios/ppc_rom.bin
|
||||||
@@ -1194,8 +1197,9 @@ T: git git://github.com/jnsnow/qemu.git bitmaps
|
|||||||
|
|
||||||
Character device backends
|
Character device backends
|
||||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
|
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: qemu-char.c
|
F: chardev/
|
||||||
F: backends/msmouse.c
|
F: backends/msmouse.c
|
||||||
F: backends/testdev.c
|
F: backends/testdev.c
|
||||||
|
|
||||||
|
158
Makefile
158
Makefile
@@ -56,25 +56,136 @@ GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
|
|||||||
GENERATED_HEADERS += qmp-introspect.h
|
GENERATED_HEADERS += qmp-introspect.h
|
||||||
GENERATED_SOURCES += qmp-introspect.c
|
GENERATED_SOURCES += qmp-introspect.c
|
||||||
|
|
||||||
GENERATED_HEADERS += trace/generated-tracers.h
|
|
||||||
ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace)
|
|
||||||
GENERATED_HEADERS += trace/generated-tracers-dtrace.h
|
|
||||||
endif
|
|
||||||
GENERATED_SOURCES += trace/generated-tracers.c
|
|
||||||
|
|
||||||
GENERATED_HEADERS += trace/generated-tcg-tracers.h
|
GENERATED_HEADERS += trace/generated-tcg-tracers.h
|
||||||
|
|
||||||
GENERATED_HEADERS += trace/generated-helpers-wrappers.h
|
GENERATED_HEADERS += trace/generated-helpers-wrappers.h
|
||||||
GENERATED_HEADERS += trace/generated-helpers.h
|
GENERATED_HEADERS += trace/generated-helpers.h
|
||||||
GENERATED_SOURCES += trace/generated-helpers.c
|
GENERATED_SOURCES += trace/generated-helpers.c
|
||||||
|
|
||||||
ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust)
|
ifdef CONFIG_TRACE_UST
|
||||||
GENERATED_HEADERS += trace/generated-ust-provider.h
|
GENERATED_HEADERS += trace-ust-all.h
|
||||||
GENERATED_SOURCES += trace/generated-ust.c
|
GENERATED_SOURCES += trace-ust-all.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
GENERATED_HEADERS += module_block.h
|
GENERATED_HEADERS += module_block.h
|
||||||
|
|
||||||
|
TRACE_HEADERS = trace-root.h $(trace-events-subdirs:%=%/trace.h)
|
||||||
|
TRACE_SOURCES = trace-root.c $(trace-events-subdirs:%=%/trace.c)
|
||||||
|
TRACE_DTRACE =
|
||||||
|
ifdef CONFIG_TRACE_DTRACE
|
||||||
|
TRACE_HEADERS += trace-dtrace-root.h $(trace-events-subdirs:%=%/trace-dtrace.h)
|
||||||
|
TRACE_DTRACE += trace-dtrace-root.dtrace $(trace-events-subdirs:%=%/trace-dtrace.dtrace)
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_TRACE_UST
|
||||||
|
TRACE_HEADERS += trace-ust-root.h $(trace-events-subdirs:%=%/trace-ust.h)
|
||||||
|
endif
|
||||||
|
|
||||||
|
GENERATED_HEADERS += $(TRACE_HEADERS)
|
||||||
|
GENERATED_SOURCES += $(TRACE_SOURCES)
|
||||||
|
|
||||||
|
trace-group-name = $(shell dirname $1 | sed -e 's/[^a-zA-Z0-9]/_/g')
|
||||||
|
|
||||||
|
%/trace.h: %/trace.h-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
%/trace.h-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=$(call trace-group-name,$@) \
|
||||||
|
--format=h \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$< > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
%/trace.c: %/trace.c-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
%/trace.c-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=$(call trace-group-name,$@) \
|
||||||
|
--format=c \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$< > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
%/trace-ust.h: %/trace-ust.h-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
%/trace-ust.h-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=$(call trace-group-name,$@) \
|
||||||
|
--format=ust-events-h \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$< > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
%/trace-dtrace.dtrace: %/trace-dtrace.dtrace-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
%/trace-dtrace.dtrace-timestamp: $(SRC_PATH)/%/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=$(call trace-group-name,$@) \
|
||||||
|
--format=d \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$< > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
%/trace-dtrace.h: %/trace-dtrace.dtrace $(tracetool-y)
|
||||||
|
$(call quiet-command,dtrace -o $@ -h -s $<, "GEN","$@")
|
||||||
|
|
||||||
|
%/trace-dtrace.o: %/trace-dtrace.dtrace $(tracetool-y)
|
||||||
|
|
||||||
|
|
||||||
|
trace-root.h: trace-root.h-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
trace-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=root \
|
||||||
|
--format=h \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$< > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
trace-root.c: trace-root.c-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
trace-root.c-timestamp: $(SRC_PATH)/trace-events $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=root \
|
||||||
|
--format=c \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$< > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
trace-ust-root.h: trace-ust-root.h-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
trace-ust-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=root \
|
||||||
|
--format=ust-events-h \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$< > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
trace-ust-all.h: trace-ust-all.h-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
trace-ust-all.h-timestamp: $(trace-events-files) $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=all \
|
||||||
|
--format=ust-events-h \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$(trace-events-files) > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
trace-ust-all.c: trace-ust-all.c-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
trace-ust-all.c-timestamp: $(trace-events-files) $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=all \
|
||||||
|
--format=ust-events-c \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$(trace-events-files) > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
trace-dtrace-root.dtrace: trace-dtrace-root.dtrace-timestamp
|
||||||
|
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||||
|
trace-dtrace-root.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y)
|
||||||
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=root \
|
||||||
|
--format=d \
|
||||||
|
--backends=$(TRACE_BACKENDS) \
|
||||||
|
$< > $@,"GEN","$(@:%-timestamp=%)")
|
||||||
|
|
||||||
|
trace-dtrace-root.h: trace-dtrace-root.dtrace
|
||||||
|
$(call quiet-command,dtrace -o $@ -h -s $<, "GEN","$@")
|
||||||
|
|
||||||
|
trace-dtrace-root.o: trace-dtrace-root.dtrace
|
||||||
|
|
||||||
# Don't try to regenerate Makefile or configure
|
# Don't try to regenerate Makefile or configure
|
||||||
# We don't generate any of them
|
# We don't generate any of them
|
||||||
Makefile: ;
|
Makefile: ;
|
||||||
@@ -147,6 +258,7 @@ endif
|
|||||||
|
|
||||||
dummy := $(call unnest-vars,, \
|
dummy := $(call unnest-vars,, \
|
||||||
stub-obj-y \
|
stub-obj-y \
|
||||||
|
chardev-obj-y \
|
||||||
util-obj-y \
|
util-obj-y \
|
||||||
qga-obj-y \
|
qga-obj-y \
|
||||||
ivshmem-client-obj-y \
|
ivshmem-client-obj-y \
|
||||||
@@ -160,7 +272,8 @@ dummy := $(call unnest-vars,, \
|
|||||||
qom-obj-y \
|
qom-obj-y \
|
||||||
io-obj-y \
|
io-obj-y \
|
||||||
common-obj-y \
|
common-obj-y \
|
||||||
common-obj-m)
|
common-obj-m \
|
||||||
|
trace-obj-y)
|
||||||
|
|
||||||
ifneq ($(wildcard config-host.mak),)
|
ifneq ($(wildcard config-host.mak),)
|
||||||
include $(SRC_PATH)/tests/Makefile.include
|
include $(SRC_PATH)/tests/Makefile.include
|
||||||
@@ -223,7 +336,8 @@ subdir-dtc:dtc/libfdt dtc/tests
|
|||||||
dtc/%:
|
dtc/%:
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
|
$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(chardev-obj-y) \
|
||||||
|
$(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY)) $(trace-obj-y)
|
||||||
|
|
||||||
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
|
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
|
||||||
# Only keep -O and -g cflags
|
# Only keep -O and -g cflags
|
||||||
@@ -247,15 +361,17 @@ libqemuutil.a: $(util-obj-y)
|
|||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
COMMON_LDADDS = $(trace-obj-y) libqemuutil.a libqemustub.a
|
||||||
|
|
||||||
qemu-img.o: qemu-img-cmds.h
|
qemu-img.o: qemu-img-cmds.h
|
||||||
|
|
||||||
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
|
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||||
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
|
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||||
qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
|
qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||||
|
|
||||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o libqemuutil.a libqemustub.a
|
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
|
||||||
|
|
||||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o libqemuutil.a libqemustub.a
|
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
|
||||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||||
|
|
||||||
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||||
@@ -320,7 +436,7 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
|
|||||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
||||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
||||||
|
|
||||||
qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a
|
qemu-ga$(EXESUF): $(qga-obj-y) $(COMMON_LDADDS)
|
||||||
$(call LINK, $^)
|
$(call LINK, $^)
|
||||||
|
|
||||||
ifdef QEMU_GA_MSI_ENABLED
|
ifdef QEMU_GA_MSI_ENABLED
|
||||||
@@ -345,9 +461,9 @@ ifneq ($(EXESUF),)
|
|||||||
qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
|
qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) libqemuutil.a libqemustub.a
|
ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) $(COMMON_LDADDS)
|
||||||
$(call LINK, $^)
|
$(call LINK, $^)
|
||||||
ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a
|
ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) $(COMMON_LDADDS)
|
||||||
$(call LINK, $^)
|
$(call LINK, $^)
|
||||||
|
|
||||||
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
||||||
@@ -664,6 +780,10 @@ ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fa
|
|||||||
Makefile: $(GENERATED_HEADERS)
|
Makefile: $(GENERATED_HEADERS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
.SECONDARY: $(TRACE_HEADERS) $(TRACE_HEADERS:%=%-timestamp) \
|
||||||
|
$(TRACE_SOURCES) $(TRACE_SOURCES:%=%-timestamp) \
|
||||||
|
$(TRACE_DTRACE) $(TRACE_DTRACE:%=%-timestamp)
|
||||||
|
|
||||||
# Include automatically generated dependency files
|
# Include automatically generated dependency files
|
||||||
# Dependencies in Makefile.objs files come from our recursive subdir rules
|
# Dependencies in Makefile.objs files come from our recursive subdir rules
|
||||||
-include $(wildcard *.d tests/*.d)
|
-include $(wildcard *.d tests/*.d)
|
||||||
|
104
Makefile.objs
104
Makefile.objs
@@ -4,6 +4,8 @@ stub-obj-y = stubs/ crypto/
|
|||||||
util-obj-y = util/ qobject/ qapi/
|
util-obj-y = util/ qobject/ qapi/
|
||||||
util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
|
util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
|
||||||
|
|
||||||
|
chardev-obj-y = chardev/
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||||
|
|
||||||
@@ -51,8 +53,7 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
|
|||||||
common-obj-$(CONFIG_LINUX) += fsdev/
|
common-obj-$(CONFIG_LINUX) += fsdev/
|
||||||
|
|
||||||
common-obj-y += migration/
|
common-obj-y += migration/
|
||||||
common-obj-y += qemu-char.o #aio.o
|
common-obj-y += page_cache.o #aio.o
|
||||||
common-obj-y += page_cache.o
|
|
||||||
|
|
||||||
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
|
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
|
||||||
|
|
||||||
@@ -118,47 +119,58 @@ ivshmem-server-obj-y = contrib/ivshmem-server/
|
|||||||
libvhost-user-obj-y = contrib/libvhost-user/
|
libvhost-user-obj-y = contrib/libvhost-user/
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
trace-events-y = trace-events
|
trace-events-subdirs =
|
||||||
trace-events-y += util/trace-events
|
trace-events-subdirs += util
|
||||||
trace-events-y += crypto/trace-events
|
trace-events-subdirs += crypto
|
||||||
trace-events-y += io/trace-events
|
trace-events-subdirs += io
|
||||||
trace-events-y += migration/trace-events
|
trace-events-subdirs += migration
|
||||||
trace-events-y += block/trace-events
|
trace-events-subdirs += block
|
||||||
trace-events-y += hw/block/trace-events
|
trace-events-subdirs += hw/block
|
||||||
trace-events-y += hw/char/trace-events
|
trace-events-subdirs += hw/block/dataplane
|
||||||
trace-events-y += hw/intc/trace-events
|
trace-events-subdirs += hw/char
|
||||||
trace-events-y += hw/net/trace-events
|
trace-events-subdirs += hw/intc
|
||||||
trace-events-y += hw/virtio/trace-events
|
trace-events-subdirs += hw/net
|
||||||
trace-events-y += hw/audio/trace-events
|
trace-events-subdirs += hw/virtio
|
||||||
trace-events-y += hw/misc/trace-events
|
trace-events-subdirs += hw/audio
|
||||||
trace-events-y += hw/usb/trace-events
|
trace-events-subdirs += hw/misc
|
||||||
trace-events-y += hw/scsi/trace-events
|
trace-events-subdirs += hw/usb
|
||||||
trace-events-y += hw/nvram/trace-events
|
trace-events-subdirs += hw/scsi
|
||||||
trace-events-y += hw/display/trace-events
|
trace-events-subdirs += hw/nvram
|
||||||
trace-events-y += hw/input/trace-events
|
trace-events-subdirs += hw/display
|
||||||
trace-events-y += hw/timer/trace-events
|
trace-events-subdirs += hw/input
|
||||||
trace-events-y += hw/dma/trace-events
|
trace-events-subdirs += hw/timer
|
||||||
trace-events-y += hw/sparc/trace-events
|
trace-events-subdirs += hw/dma
|
||||||
trace-events-y += hw/sd/trace-events
|
trace-events-subdirs += hw/sparc
|
||||||
trace-events-y += hw/isa/trace-events
|
trace-events-subdirs += hw/sd
|
||||||
trace-events-y += hw/mem/trace-events
|
trace-events-subdirs += hw/isa
|
||||||
trace-events-y += hw/i386/trace-events
|
trace-events-subdirs += hw/mem
|
||||||
trace-events-y += hw/9pfs/trace-events
|
trace-events-subdirs += hw/i386
|
||||||
trace-events-y += hw/ppc/trace-events
|
trace-events-subdirs += hw/i386/xen
|
||||||
trace-events-y += hw/pci/trace-events
|
trace-events-subdirs += hw/9pfs
|
||||||
trace-events-y += hw/s390x/trace-events
|
trace-events-subdirs += hw/ppc
|
||||||
trace-events-y += hw/vfio/trace-events
|
trace-events-subdirs += hw/pci
|
||||||
trace-events-y += hw/acpi/trace-events
|
trace-events-subdirs += hw/s390x
|
||||||
trace-events-y += hw/arm/trace-events
|
trace-events-subdirs += hw/vfio
|
||||||
trace-events-y += hw/alpha/trace-events
|
trace-events-subdirs += hw/acpi
|
||||||
trace-events-y += ui/trace-events
|
trace-events-subdirs += hw/arm
|
||||||
trace-events-y += audio/trace-events
|
trace-events-subdirs += hw/alpha
|
||||||
trace-events-y += net/trace-events
|
trace-events-subdirs += hw/xen
|
||||||
trace-events-y += target/arm/trace-events
|
trace-events-subdirs += ui
|
||||||
trace-events-y += target/i386/trace-events
|
trace-events-subdirs += audio
|
||||||
trace-events-y += target/sparc/trace-events
|
trace-events-subdirs += net
|
||||||
trace-events-y += target/s390x/trace-events
|
trace-events-subdirs += target/arm
|
||||||
trace-events-y += target/ppc/trace-events
|
trace-events-subdirs += target/i386
|
||||||
trace-events-y += qom/trace-events
|
trace-events-subdirs += target/sparc
|
||||||
trace-events-y += linux-user/trace-events
|
trace-events-subdirs += target/s390x
|
||||||
trace-events-y += qapi/trace-events
|
trace-events-subdirs += target/ppc
|
||||||
|
trace-events-subdirs += qom
|
||||||
|
trace-events-subdirs += linux-user
|
||||||
|
trace-events-subdirs += qapi
|
||||||
|
|
||||||
|
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
|
||||||
|
|
||||||
|
trace-obj-y = trace-root.o
|
||||||
|
trace-obj-y += $(trace-events-subdirs:%=%/trace.o)
|
||||||
|
trace-obj-$(CONFIG_TRACE_UST) += trace-ust-all.o
|
||||||
|
trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace-root.o
|
||||||
|
trace-obj-$(CONFIG_TRACE_DTRACE) += $(trace-events-subdirs:%=%/trace-dtrace.o)
|
||||||
|
@@ -50,6 +50,7 @@ endif
|
|||||||
|
|
||||||
$(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all
|
$(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all
|
||||||
$(call quiet-command,$(TRACETOOL) \
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=all \
|
||||||
--format=stap \
|
--format=stap \
|
||||||
--backends=$(TRACE_BACKENDS) \
|
--backends=$(TRACE_BACKENDS) \
|
||||||
--binary=$(bindir)/$(QEMU_PROG) \
|
--binary=$(bindir)/$(QEMU_PROG) \
|
||||||
@@ -59,6 +60,7 @@ $(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all
|
|||||||
|
|
||||||
$(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all
|
$(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all
|
||||||
$(call quiet-command,$(TRACETOOL) \
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=all \
|
||||||
--format=stap \
|
--format=stap \
|
||||||
--backends=$(TRACE_BACKENDS) \
|
--backends=$(TRACE_BACKENDS) \
|
||||||
--binary=$(realpath .)/$(QEMU_PROG) \
|
--binary=$(realpath .)/$(QEMU_PROG) \
|
||||||
@@ -68,6 +70,7 @@ $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all
|
|||||||
|
|
||||||
$(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all
|
$(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all
|
||||||
$(call quiet-command,$(TRACETOOL) \
|
$(call quiet-command,$(TRACETOOL) \
|
||||||
|
--group=all \
|
||||||
--format=simpletrace-stap \
|
--format=simpletrace-stap \
|
||||||
--backends=$(TRACE_BACKENDS) \
|
--backends=$(TRACE_BACKENDS) \
|
||||||
--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \
|
--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \
|
||||||
@@ -172,31 +175,36 @@ all-obj-y := $(obj-y)
|
|||||||
target-obj-y :=
|
target-obj-y :=
|
||||||
block-obj-y :=
|
block-obj-y :=
|
||||||
common-obj-y :=
|
common-obj-y :=
|
||||||
|
chardev-obj-y :=
|
||||||
include $(SRC_PATH)/Makefile.objs
|
include $(SRC_PATH)/Makefile.objs
|
||||||
dummy := $(call unnest-vars,,target-obj-y)
|
dummy := $(call unnest-vars,,target-obj-y)
|
||||||
target-obj-y-save := $(target-obj-y)
|
target-obj-y-save := $(target-obj-y)
|
||||||
dummy := $(call unnest-vars,.., \
|
dummy := $(call unnest-vars,.., \
|
||||||
block-obj-y \
|
block-obj-y \
|
||||||
block-obj-m \
|
block-obj-m \
|
||||||
|
chardev-obj-y \
|
||||||
crypto-obj-y \
|
crypto-obj-y \
|
||||||
crypto-aes-obj-y \
|
crypto-aes-obj-y \
|
||||||
qom-obj-y \
|
qom-obj-y \
|
||||||
io-obj-y \
|
io-obj-y \
|
||||||
common-obj-y \
|
common-obj-y \
|
||||||
common-obj-m)
|
common-obj-m \
|
||||||
|
trace-obj-y)
|
||||||
target-obj-y := $(target-obj-y-save)
|
target-obj-y := $(target-obj-y-save)
|
||||||
all-obj-y += $(common-obj-y)
|
all-obj-y += $(common-obj-y)
|
||||||
all-obj-y += $(target-obj-y)
|
all-obj-y += $(target-obj-y)
|
||||||
all-obj-y += $(qom-obj-y)
|
all-obj-y += $(qom-obj-y)
|
||||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
|
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y)
|
||||||
all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y)
|
all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y)
|
||||||
all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
|
all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
|
||||||
all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
|
all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
|
||||||
|
|
||||||
$(QEMU_PROG_BUILD): config-devices.mak
|
$(QEMU_PROG_BUILD): config-devices.mak
|
||||||
|
|
||||||
|
COMMON_LDADDS = $(trace-obj-y) ../libqemuutil.a ../libqemustub.a
|
||||||
|
|
||||||
# build either PROG or PROGW
|
# build either PROG or PROGW
|
||||||
$(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a
|
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
|
||||||
$(call LINK, $(filter-out %.mak, $^))
|
$(call LINK, $(filter-out %.mak, $^))
|
||||||
ifdef CONFIG_DARWIN
|
ifdef CONFIG_DARWIN
|
||||||
$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@")
|
$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@")
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
#include "qemu/rcu_queue.h"
|
#include "qemu/rcu_queue.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "trace.h"
|
#include "trace-root.h"
|
||||||
#ifdef CONFIG_EPOLL_CREATE1
|
#ifdef CONFIG_EPOLL_CREATE1
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#endif
|
#endif
|
||||||
|
@@ -616,9 +616,9 @@ static void baum_chr_read(void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void baum_chr_free(Chardev *chr)
|
static void char_braille_finalize(Object *obj)
|
||||||
{
|
{
|
||||||
BaumChardev *baum = BAUM_CHARDEV(chr);
|
BaumChardev *baum = BAUM_CHARDEV(obj);
|
||||||
|
|
||||||
timer_free(baum->cellCount_timer);
|
timer_free(baum->cellCount_timer);
|
||||||
if (baum->brlapi) {
|
if (baum->brlapi) {
|
||||||
@@ -659,23 +659,18 @@ static void char_braille_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->open = baum_chr_open;
|
cc->open = baum_chr_open;
|
||||||
cc->chr_write = baum_chr_write;
|
cc->chr_write = baum_chr_write;
|
||||||
cc->chr_accept_input = baum_chr_accept_input;
|
cc->chr_accept_input = baum_chr_accept_input;
|
||||||
cc->chr_free = baum_chr_free;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo char_braille_type_info = {
|
static const TypeInfo char_braille_type_info = {
|
||||||
.name = TYPE_CHARDEV_BRAILLE,
|
.name = TYPE_CHARDEV_BRAILLE,
|
||||||
.parent = TYPE_CHARDEV,
|
.parent = TYPE_CHARDEV,
|
||||||
.instance_size = sizeof(BaumChardev),
|
.instance_size = sizeof(BaumChardev),
|
||||||
|
.instance_finalize = char_braille_finalize,
|
||||||
.class_init = char_braille_class_init,
|
.class_init = char_braille_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
static const CharDriver driver = {
|
|
||||||
.kind = CHARDEV_BACKEND_KIND_BRAILLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
register_char_driver(&driver);
|
|
||||||
type_register_static(&char_braille_type_info);
|
type_register_static(&char_braille_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -139,9 +139,9 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msmouse_chr_free(struct Chardev *chr)
|
static void char_msmouse_finalize(Object *obj)
|
||||||
{
|
{
|
||||||
MouseChardev *mouse = MOUSE_CHARDEV(chr);
|
MouseChardev *mouse = MOUSE_CHARDEV(obj);
|
||||||
|
|
||||||
qemu_input_handler_unregister(mouse->hs);
|
qemu_input_handler_unregister(mouse->hs);
|
||||||
}
|
}
|
||||||
@@ -172,23 +172,18 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->open = msmouse_chr_open;
|
cc->open = msmouse_chr_open;
|
||||||
cc->chr_write = msmouse_chr_write;
|
cc->chr_write = msmouse_chr_write;
|
||||||
cc->chr_accept_input = msmouse_chr_accept_input;
|
cc->chr_accept_input = msmouse_chr_accept_input;
|
||||||
cc->chr_free = msmouse_chr_free;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo char_msmouse_type_info = {
|
static const TypeInfo char_msmouse_type_info = {
|
||||||
.name = TYPE_CHARDEV_MSMOUSE,
|
.name = TYPE_CHARDEV_MSMOUSE,
|
||||||
.parent = TYPE_CHARDEV,
|
.parent = TYPE_CHARDEV,
|
||||||
.instance_size = sizeof(MouseChardev),
|
.instance_size = sizeof(MouseChardev),
|
||||||
|
.instance_finalize = char_msmouse_finalize,
|
||||||
.class_init = char_msmouse_class_init,
|
.class_init = char_msmouse_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
static const CharDriver driver = {
|
|
||||||
.kind = CHARDEV_BACKEND_KIND_MSMOUSE,
|
|
||||||
};
|
|
||||||
|
|
||||||
register_char_driver(&driver);
|
|
||||||
type_register_static(&char_msmouse_type_info);
|
type_register_static(&char_msmouse_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -123,11 +123,6 @@ static const TypeInfo char_testdev_type_info = {
|
|||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
static const CharDriver driver = {
|
|
||||||
.kind = CHARDEV_BACKEND_KIND_TESTDEV,
|
|
||||||
};
|
|
||||||
|
|
||||||
register_char_driver(&driver);
|
|
||||||
type_register_static(&char_testdev_type_info);
|
type_register_static(&char_testdev_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
#include "exec/cpu-common.h"
|
#include "exec/cpu-common.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "sysemu/balloon.h"
|
#include "sysemu/balloon.h"
|
||||||
#include "trace.h"
|
#include "trace-root.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qapi/qmp/qjson.h"
|
#include "qapi/qmp/qjson.h"
|
||||||
|
2
block.c
2
block.c
@@ -22,7 +22,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "trace.h"
|
#include "block/trace.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "block/blockjob.h"
|
#include "block/blockjob.h"
|
||||||
#include "block/nbd.h"
|
#include "block/nbd.h"
|
||||||
|
289
block/sheepdog.c
289
block/sheepdog.c
@@ -306,6 +306,7 @@ static inline size_t count_data_objs(const struct SheepdogInode *inode)
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
typedef struct SheepdogAIOCB SheepdogAIOCB;
|
typedef struct SheepdogAIOCB SheepdogAIOCB;
|
||||||
|
typedef struct BDRVSheepdogState BDRVSheepdogState;
|
||||||
|
|
||||||
typedef struct AIOReq {
|
typedef struct AIOReq {
|
||||||
SheepdogAIOCB *aiocb;
|
SheepdogAIOCB *aiocb;
|
||||||
@@ -334,7 +335,7 @@ enum AIOCBState {
|
|||||||
|| y->max_affect_data_idx < x->min_affect_data_idx))
|
|| y->max_affect_data_idx < x->min_affect_data_idx))
|
||||||
|
|
||||||
struct SheepdogAIOCB {
|
struct SheepdogAIOCB {
|
||||||
BlockAIOCB common;
|
BDRVSheepdogState *s;
|
||||||
|
|
||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
|
|
||||||
@@ -345,9 +346,6 @@ struct SheepdogAIOCB {
|
|||||||
enum AIOCBState aiocb_type;
|
enum AIOCBState aiocb_type;
|
||||||
|
|
||||||
Coroutine *coroutine;
|
Coroutine *coroutine;
|
||||||
void (*aio_done_func)(SheepdogAIOCB *);
|
|
||||||
|
|
||||||
bool cancelable;
|
|
||||||
int nr_pending;
|
int nr_pending;
|
||||||
|
|
||||||
uint32_t min_affect_data_idx;
|
uint32_t min_affect_data_idx;
|
||||||
@@ -365,7 +363,7 @@ struct SheepdogAIOCB {
|
|||||||
QLIST_ENTRY(SheepdogAIOCB) aiocb_siblings;
|
QLIST_ENTRY(SheepdogAIOCB) aiocb_siblings;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BDRVSheepdogState {
|
struct BDRVSheepdogState {
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
AioContext *aio_context;
|
AioContext *aio_context;
|
||||||
|
|
||||||
@@ -392,7 +390,7 @@ typedef struct BDRVSheepdogState {
|
|||||||
|
|
||||||
CoQueue overlapping_queue;
|
CoQueue overlapping_queue;
|
||||||
QLIST_HEAD(inflight_aiocb_head, SheepdogAIOCB) inflight_aiocb_head;
|
QLIST_HEAD(inflight_aiocb_head, SheepdogAIOCB) inflight_aiocb_head;
|
||||||
} BDRVSheepdogState;
|
};
|
||||||
|
|
||||||
typedef struct BDRVSheepdogReopenState {
|
typedef struct BDRVSheepdogReopenState {
|
||||||
int fd;
|
int fd;
|
||||||
@@ -450,14 +448,13 @@ static const char * sd_strerror(int err)
|
|||||||
*
|
*
|
||||||
* 1. In sd_co_rw_vector, we send the I/O requests to the server and
|
* 1. In sd_co_rw_vector, we send the I/O requests to the server and
|
||||||
* link the requests to the inflight_list in the
|
* link the requests to the inflight_list in the
|
||||||
* BDRVSheepdogState. The function exits without waiting for
|
* BDRVSheepdogState. The function yields while waiting for
|
||||||
* receiving the response.
|
* receiving the response.
|
||||||
*
|
*
|
||||||
* 2. We receive the response in aio_read_response, the fd handler to
|
* 2. We receive the response in aio_read_response, the fd handler to
|
||||||
* the sheepdog connection. If metadata update is needed, we send
|
* the sheepdog connection. We switch back to sd_co_readv/sd_writev
|
||||||
* the write request to the vdi object in sd_write_done, the write
|
* after all the requests belonging to the AIOCB are finished. If
|
||||||
* completion function. We switch back to sd_co_readv/writev after
|
* needed, sd_co_writev will send another requests for the vdi object.
|
||||||
* all the requests belonging to the AIOCB are finished.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
|
static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
|
||||||
@@ -482,94 +479,34 @@ static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
|
|||||||
return aio_req;
|
return aio_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
|
static void wait_for_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *acb)
|
||||||
{
|
{
|
||||||
SheepdogAIOCB *acb = aio_req->aiocb;
|
SheepdogAIOCB *cb;
|
||||||
|
|
||||||
acb->cancelable = false;
|
retry:
|
||||||
QLIST_REMOVE(aio_req, aio_siblings);
|
QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) {
|
||||||
g_free(aio_req);
|
if (AIOCBOverlapping(acb, cb)) {
|
||||||
|
qemu_co_queue_wait(&s->overlapping_queue);
|
||||||
acb->nr_pending--;
|
goto retry;
|
||||||
}
|
|
||||||
|
|
||||||
static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb)
|
|
||||||
{
|
|
||||||
qemu_coroutine_enter(acb->coroutine);
|
|
||||||
qemu_aio_unref(acb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether the specified acb can be canceled
|
|
||||||
*
|
|
||||||
* We can cancel aio when any request belonging to the acb is:
|
|
||||||
* - Not processed by the sheepdog server.
|
|
||||||
* - Not linked to the inflight queue.
|
|
||||||
*/
|
|
||||||
static bool sd_acb_cancelable(const SheepdogAIOCB *acb)
|
|
||||||
{
|
|
||||||
BDRVSheepdogState *s = acb->common.bs->opaque;
|
|
||||||
AIOReq *aioreq;
|
|
||||||
|
|
||||||
if (!acb->cancelable) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QLIST_FOREACH(aioreq, &s->inflight_aio_head, aio_siblings) {
|
|
||||||
if (aioreq->aiocb == acb) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sd_aio_cancel(BlockAIOCB *blockacb)
|
static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
|
||||||
|
QEMUIOVector *qiov, int64_t sector_num, int nb_sectors,
|
||||||
|
int type)
|
||||||
{
|
{
|
||||||
SheepdogAIOCB *acb = (SheepdogAIOCB *)blockacb;
|
|
||||||
BDRVSheepdogState *s = acb->common.bs->opaque;
|
|
||||||
AIOReq *aioreq, *next;
|
|
||||||
|
|
||||||
if (sd_acb_cancelable(acb)) {
|
|
||||||
/* Remove outstanding requests from failed queue. */
|
|
||||||
QLIST_FOREACH_SAFE(aioreq, &s->failed_aio_head, aio_siblings,
|
|
||||||
next) {
|
|
||||||
if (aioreq->aiocb == acb) {
|
|
||||||
free_aio_req(s, aioreq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(acb->nr_pending == 0);
|
|
||||||
if (acb->common.cb) {
|
|
||||||
acb->common.cb(acb->common.opaque, -ECANCELED);
|
|
||||||
}
|
|
||||||
sd_finish_aiocb(acb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const AIOCBInfo sd_aiocb_info = {
|
|
||||||
.aiocb_size = sizeof(SheepdogAIOCB),
|
|
||||||
.cancel_async = sd_aio_cancel,
|
|
||||||
};
|
|
||||||
|
|
||||||
static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
|
||||||
int64_t sector_num, int nb_sectors)
|
|
||||||
{
|
|
||||||
SheepdogAIOCB *acb;
|
|
||||||
uint32_t object_size;
|
uint32_t object_size;
|
||||||
BDRVSheepdogState *s = bs->opaque;
|
|
||||||
|
|
||||||
object_size = (UINT32_C(1) << s->inode.block_size_shift);
|
object_size = (UINT32_C(1) << s->inode.block_size_shift);
|
||||||
|
|
||||||
acb = qemu_aio_get(&sd_aiocb_info, bs, NULL, NULL);
|
acb->s = s;
|
||||||
|
|
||||||
acb->qiov = qiov;
|
acb->qiov = qiov;
|
||||||
|
|
||||||
acb->sector_num = sector_num;
|
acb->sector_num = sector_num;
|
||||||
acb->nb_sectors = nb_sectors;
|
acb->nb_sectors = nb_sectors;
|
||||||
|
|
||||||
acb->aio_done_func = NULL;
|
|
||||||
acb->cancelable = true;
|
|
||||||
acb->coroutine = qemu_coroutine_self();
|
acb->coroutine = qemu_coroutine_self();
|
||||||
acb->ret = 0;
|
acb->ret = 0;
|
||||||
acb->nr_pending = 0;
|
acb->nr_pending = 0;
|
||||||
@@ -580,8 +517,14 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
|||||||
|
|
||||||
acb->min_dirty_data_idx = UINT32_MAX;
|
acb->min_dirty_data_idx = UINT32_MAX;
|
||||||
acb->max_dirty_data_idx = 0;
|
acb->max_dirty_data_idx = 0;
|
||||||
|
acb->aiocb_type = type;
|
||||||
|
|
||||||
return acb;
|
if (type == AIOCB_FLUSH_CACHE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_overlapping_aiocb(s, acb);
|
||||||
|
QLIST_INSERT_HEAD(&s->inflight_aiocb_head, acb, aiocb_siblings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return -EIO in case of error, file descriptor on success */
|
/* Return -EIO in case of error, file descriptor on success */
|
||||||
@@ -797,7 +740,6 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
|
|||||||
while (!QLIST_EMPTY(&s->failed_aio_head)) {
|
while (!QLIST_EMPTY(&s->failed_aio_head)) {
|
||||||
aio_req = QLIST_FIRST(&s->failed_aio_head);
|
aio_req = QLIST_FIRST(&s->failed_aio_head);
|
||||||
QLIST_REMOVE(aio_req, aio_siblings);
|
QLIST_REMOVE(aio_req, aio_siblings);
|
||||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
|
||||||
resend_aioreq(s, aio_req);
|
resend_aioreq(s, aio_req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -840,9 +782,6 @@ static void coroutine_fn aio_read_response(void *opaque)
|
|||||||
|
|
||||||
switch (acb->aiocb_type) {
|
switch (acb->aiocb_type) {
|
||||||
case AIOCB_WRITE_UDATA:
|
case AIOCB_WRITE_UDATA:
|
||||||
/* this coroutine context is no longer suitable for co_recv
|
|
||||||
* because we may send data to update vdi objects */
|
|
||||||
s->co_recv = NULL;
|
|
||||||
if (!is_data_obj(aio_req->oid)) {
|
if (!is_data_obj(aio_req->oid)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -890,6 +829,12 @@ static void coroutine_fn aio_read_response(void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* No more data for this aio_req (reload_inode below uses its own file
|
||||||
|
* descriptor handler which doesn't use co_recv).
|
||||||
|
*/
|
||||||
|
s->co_recv = NULL;
|
||||||
|
|
||||||
|
QLIST_REMOVE(aio_req, aio_siblings);
|
||||||
switch (rsp.result) {
|
switch (rsp.result) {
|
||||||
case SD_RES_SUCCESS:
|
case SD_RES_SUCCESS:
|
||||||
break;
|
break;
|
||||||
@@ -907,26 +852,26 @@ static void coroutine_fn aio_read_response(void *opaque)
|
|||||||
aio_req->oid = vid_to_vdi_oid(s->inode.vdi_id);
|
aio_req->oid = vid_to_vdi_oid(s->inode.vdi_id);
|
||||||
}
|
}
|
||||||
resend_aioreq(s, aio_req);
|
resend_aioreq(s, aio_req);
|
||||||
goto out;
|
return;
|
||||||
default:
|
default:
|
||||||
acb->ret = -EIO;
|
acb->ret = -EIO;
|
||||||
error_report("%s", sd_strerror(rsp.result));
|
error_report("%s", sd_strerror(rsp.result));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_aio_req(s, aio_req);
|
g_free(aio_req);
|
||||||
if (!acb->nr_pending) {
|
|
||||||
|
if (!--acb->nr_pending) {
|
||||||
/*
|
/*
|
||||||
* We've finished all requests which belong to the AIOCB, so
|
* We've finished all requests which belong to the AIOCB, so
|
||||||
* we can switch back to sd_co_readv/writev now.
|
* we can switch back to sd_co_readv/writev now.
|
||||||
*/
|
*/
|
||||||
acb->aio_done_func(acb);
|
qemu_coroutine_enter(acb->coroutine);
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
s->co_recv = NULL;
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
s->co_recv = NULL;
|
|
||||||
reconnect_to_sdog(opaque);
|
reconnect_to_sdog(opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1176,6 +1121,8 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
|||||||
uint64_t old_oid = aio_req->base_oid;
|
uint64_t old_oid = aio_req->base_oid;
|
||||||
bool create = aio_req->create;
|
bool create = aio_req->create;
|
||||||
|
|
||||||
|
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||||
|
|
||||||
if (!nr_copies) {
|
if (!nr_copies) {
|
||||||
error_report("bug");
|
error_report("bug");
|
||||||
}
|
}
|
||||||
@@ -2025,11 +1972,10 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
|||||||
/*
|
/*
|
||||||
* This function is called after writing data objects. If we need to
|
* This function is called after writing data objects. If we need to
|
||||||
* update metadata, this sends a write request to the vdi object.
|
* update metadata, this sends a write request to the vdi object.
|
||||||
* Otherwise, this switches back to sd_co_readv/writev.
|
|
||||||
*/
|
*/
|
||||||
static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
|
static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
|
||||||
{
|
{
|
||||||
BDRVSheepdogState *s = acb->common.bs->opaque;
|
BDRVSheepdogState *s = acb->s;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
AIOReq *aio_req;
|
AIOReq *aio_req;
|
||||||
uint32_t offset, data_len, mn, mx;
|
uint32_t offset, data_len, mn, mx;
|
||||||
@@ -2038,6 +1984,7 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
|
|||||||
mx = acb->max_dirty_data_idx;
|
mx = acb->max_dirty_data_idx;
|
||||||
if (mn <= mx) {
|
if (mn <= mx) {
|
||||||
/* we need to update the vdi object. */
|
/* we need to update the vdi object. */
|
||||||
|
++acb->nr_pending;
|
||||||
offset = sizeof(s->inode) - sizeof(s->inode.data_vdi_id) +
|
offset = sizeof(s->inode) - sizeof(s->inode.data_vdi_id) +
|
||||||
mn * sizeof(s->inode.data_vdi_id[0]);
|
mn * sizeof(s->inode.data_vdi_id[0]);
|
||||||
data_len = (mx - mn + 1) * sizeof(s->inode.data_vdi_id[0]);
|
data_len = (mx - mn + 1) * sizeof(s->inode.data_vdi_id[0]);
|
||||||
@@ -2049,15 +1996,11 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
|
|||||||
iov.iov_len = sizeof(s->inode);
|
iov.iov_len = sizeof(s->inode);
|
||||||
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
|
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
|
||||||
data_len, offset, 0, false, 0, offset);
|
data_len, offset, 0, false, 0, offset);
|
||||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
|
||||||
add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA);
|
add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA);
|
||||||
|
if (--acb->nr_pending) {
|
||||||
acb->aio_done_func = sd_finish_aiocb;
|
qemu_coroutine_yield();
|
||||||
acb->aiocb_type = AIOCB_WRITE_UDATA;
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_finish_aiocb(acb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete current working VDI on the snapshot chain */
|
/* Delete current working VDI on the snapshot chain */
|
||||||
@@ -2169,16 +2112,15 @@ out:
|
|||||||
* Returns 1 when we need to wait a response, 0 when there is no sent
|
* Returns 1 when we need to wait a response, 0 when there is no sent
|
||||||
* request and -errno in error cases.
|
* request and -errno in error cases.
|
||||||
*/
|
*/
|
||||||
static int coroutine_fn sd_co_rw_vector(void *p)
|
static void coroutine_fn sd_co_rw_vector(SheepdogAIOCB *acb)
|
||||||
{
|
{
|
||||||
SheepdogAIOCB *acb = p;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned long len, done = 0, total = acb->nb_sectors * BDRV_SECTOR_SIZE;
|
unsigned long len, done = 0, total = acb->nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
unsigned long idx;
|
unsigned long idx;
|
||||||
uint32_t object_size;
|
uint32_t object_size;
|
||||||
uint64_t oid;
|
uint64_t oid;
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
BDRVSheepdogState *s = acb->common.bs->opaque;
|
BDRVSheepdogState *s = acb->s;
|
||||||
SheepdogInode *inode = &s->inode;
|
SheepdogInode *inode = &s->inode;
|
||||||
AIOReq *aio_req;
|
AIOReq *aio_req;
|
||||||
|
|
||||||
@@ -2190,7 +2132,7 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
|||||||
ret = sd_create_branch(s);
|
ret = sd_create_branch(s);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
acb->ret = -EIO;
|
acb->ret = -EIO;
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2255,8 +2197,6 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
|||||||
old_oid,
|
old_oid,
|
||||||
acb->aiocb_type == AIOCB_DISCARD_OBJ ?
|
acb->aiocb_type == AIOCB_DISCARD_OBJ ?
|
||||||
0 : done);
|
0 : done);
|
||||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
|
||||||
|
|
||||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
|
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
|
||||||
acb->aiocb_type);
|
acb->aiocb_type);
|
||||||
done:
|
done:
|
||||||
@@ -2264,31 +2204,25 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
|||||||
idx++;
|
idx++;
|
||||||
done += len;
|
done += len;
|
||||||
}
|
}
|
||||||
out:
|
if (--acb->nr_pending) {
|
||||||
if (!--acb->nr_pending) {
|
qemu_coroutine_yield();
|
||||||
return acb->ret;
|
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *aiocb)
|
static void sd_aio_complete(SheepdogAIOCB *acb)
|
||||||
{
|
{
|
||||||
SheepdogAIOCB *cb;
|
if (acb->aiocb_type == AIOCB_FLUSH_CACHE) {
|
||||||
|
return;
|
||||||
QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) {
|
|
||||||
if (AIOCBOverlapping(aiocb, cb)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QLIST_INSERT_HEAD(&s->inflight_aiocb_head, aiocb, aiocb_siblings);
|
QLIST_REMOVE(acb, aiocb_siblings);
|
||||||
return false;
|
qemu_co_queue_restart_all(&acb->s->overlapping_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors, QEMUIOVector *qiov)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
SheepdogAIOCB *acb;
|
SheepdogAIOCB acb;
|
||||||
int ret;
|
int ret;
|
||||||
int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE;
|
int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE;
|
||||||
BDRVSheepdogState *s = bs->opaque;
|
BDRVSheepdogState *s = bs->opaque;
|
||||||
@@ -2300,85 +2234,50 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors);
|
sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_WRITE_UDATA);
|
||||||
acb->aio_done_func = sd_write_done;
|
sd_co_rw_vector(&acb);
|
||||||
acb->aiocb_type = AIOCB_WRITE_UDATA;
|
sd_write_done(&acb);
|
||||||
|
sd_aio_complete(&acb);
|
||||||
|
|
||||||
retry:
|
return acb.ret;
|
||||||
if (check_overlapping_aiocb(s, acb)) {
|
|
||||||
qemu_co_queue_wait(&s->overlapping_queue);
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sd_co_rw_vector(acb);
|
|
||||||
if (ret <= 0) {
|
|
||||||
QLIST_REMOVE(acb, aiocb_siblings);
|
|
||||||
qemu_co_queue_restart_all(&s->overlapping_queue);
|
|
||||||
qemu_aio_unref(acb);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_coroutine_yield();
|
|
||||||
|
|
||||||
QLIST_REMOVE(acb, aiocb_siblings);
|
|
||||||
qemu_co_queue_restart_all(&s->overlapping_queue);
|
|
||||||
|
|
||||||
return acb->ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
|
static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors, QEMUIOVector *qiov)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
SheepdogAIOCB *acb;
|
SheepdogAIOCB acb;
|
||||||
int ret;
|
|
||||||
BDRVSheepdogState *s = bs->opaque;
|
BDRVSheepdogState *s = bs->opaque;
|
||||||
|
|
||||||
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors);
|
sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_READ_UDATA);
|
||||||
acb->aiocb_type = AIOCB_READ_UDATA;
|
sd_co_rw_vector(&acb);
|
||||||
acb->aio_done_func = sd_finish_aiocb;
|
sd_aio_complete(&acb);
|
||||||
|
|
||||||
retry:
|
return acb.ret;
|
||||||
if (check_overlapping_aiocb(s, acb)) {
|
|
||||||
qemu_co_queue_wait(&s->overlapping_queue);
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sd_co_rw_vector(acb);
|
|
||||||
if (ret <= 0) {
|
|
||||||
QLIST_REMOVE(acb, aiocb_siblings);
|
|
||||||
qemu_co_queue_restart_all(&s->overlapping_queue);
|
|
||||||
qemu_aio_unref(acb);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_coroutine_yield();
|
|
||||||
|
|
||||||
QLIST_REMOVE(acb, aiocb_siblings);
|
|
||||||
qemu_co_queue_restart_all(&s->overlapping_queue);
|
|
||||||
return acb->ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
|
static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVSheepdogState *s = bs->opaque;
|
BDRVSheepdogState *s = bs->opaque;
|
||||||
SheepdogAIOCB *acb;
|
SheepdogAIOCB acb;
|
||||||
AIOReq *aio_req;
|
AIOReq *aio_req;
|
||||||
|
|
||||||
if (s->cache_flags != SD_FLAG_CMD_CACHE) {
|
if (s->cache_flags != SD_FLAG_CMD_CACHE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
acb = sd_aio_setup(bs, NULL, 0, 0);
|
sd_aio_setup(&acb, s, NULL, 0, 0, AIOCB_FLUSH_CACHE);
|
||||||
acb->aiocb_type = AIOCB_FLUSH_CACHE;
|
|
||||||
acb->aio_done_func = sd_finish_aiocb;
|
|
||||||
|
|
||||||
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
|
acb.nr_pending++;
|
||||||
|
aio_req = alloc_aio_req(s, &acb, vid_to_vdi_oid(s->inode.vdi_id),
|
||||||
0, 0, 0, false, 0, 0);
|
0, 0, 0, false, 0, 0);
|
||||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
add_aio_request(s, aio_req, NULL, 0, acb.aiocb_type);
|
||||||
add_aio_request(s, aio_req, NULL, 0, acb->aiocb_type);
|
|
||||||
|
|
||||||
qemu_coroutine_yield();
|
if (--acb.nr_pending) {
|
||||||
return acb->ret;
|
qemu_coroutine_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_aio_complete(&acb);
|
||||||
|
return acb.ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||||
@@ -2812,9 +2711,8 @@ static int sd_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
|||||||
static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
SheepdogAIOCB *acb;
|
SheepdogAIOCB acb;
|
||||||
BDRVSheepdogState *s = bs->opaque;
|
BDRVSheepdogState *s = bs->opaque;
|
||||||
int ret;
|
|
||||||
QEMUIOVector discard_iov;
|
QEMUIOVector discard_iov;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
uint32_t zero = 0;
|
uint32_t zero = 0;
|
||||||
@@ -2832,31 +2730,12 @@ static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
|||||||
if (!QEMU_IS_ALIGNED(offset | count, BDRV_SECTOR_SIZE)) {
|
if (!QEMU_IS_ALIGNED(offset | count, BDRV_SECTOR_SIZE)) {
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
acb = sd_aio_setup(bs, &discard_iov, offset >> BDRV_SECTOR_BITS,
|
sd_aio_setup(&acb, s, &discard_iov, offset >> BDRV_SECTOR_BITS,
|
||||||
count >> BDRV_SECTOR_BITS);
|
count >> BDRV_SECTOR_BITS, AIOCB_DISCARD_OBJ);
|
||||||
acb->aiocb_type = AIOCB_DISCARD_OBJ;
|
sd_co_rw_vector(&acb);
|
||||||
acb->aio_done_func = sd_finish_aiocb;
|
sd_aio_complete(&acb);
|
||||||
|
|
||||||
retry:
|
return acb.ret;
|
||||||
if (check_overlapping_aiocb(s, acb)) {
|
|
||||||
qemu_co_queue_wait(&s->overlapping_queue);
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sd_co_rw_vector(acb);
|
|
||||||
if (ret <= 0) {
|
|
||||||
QLIST_REMOVE(acb, aiocb_siblings);
|
|
||||||
qemu_co_queue_restart_all(&s->overlapping_queue);
|
|
||||||
qemu_aio_unref(acb);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_coroutine_yield();
|
|
||||||
|
|
||||||
QLIST_REMOVE(acb, aiocb_siblings);
|
|
||||||
qemu_co_queue_restart_all(&s->overlapping_queue);
|
|
||||||
|
|
||||||
return acb->ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static coroutine_fn int64_t
|
static coroutine_fn int64_t
|
||||||
|
@@ -35,8 +35,6 @@ mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_n
|
|||||||
mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d"
|
mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d"
|
||||||
mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d"
|
mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d"
|
||||||
mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d"
|
mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d"
|
||||||
mirror_yield_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d"
|
|
||||||
mirror_break_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d"
|
|
||||||
|
|
||||||
# block/backup.c
|
# block/backup.c
|
||||||
backup_do_cow_enter(void *job, int64_t start, int64_t sector_num, int nb_sectors) "job %p start %"PRId64" sector_num %"PRId64" nb_sectors %d"
|
backup_do_cow_enter(void *job, int64_t start, int64_t sector_num, int nb_sectors) "job %p start %"PRId64" sector_num %"PRId64" nb_sectors %d"
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
#include "trace.h"
|
|
||||||
#include "block/nbd.h"
|
#include "block/nbd.h"
|
||||||
#include "io/channel-socket.h"
|
#include "io/channel-socket.h"
|
||||||
|
|
||||||
|
@@ -48,7 +48,7 @@
|
|||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
#include "trace.h"
|
#include "block/trace.h"
|
||||||
#include "sysemu/arch_init.h"
|
#include "sysemu/arch_init.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/help_option.h"
|
#include "qemu/help_option.h"
|
||||||
|
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "trace.h"
|
|
||||||
#include "block/block.h"
|
#include "block/block.h"
|
||||||
#include "block/blockjob_int.h"
|
#include "block/blockjob_int.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
|
17
chardev/Makefile.objs
Normal file
17
chardev/Makefile.objs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
chardev-obj-y += char.o
|
||||||
|
chardev-obj-$(CONFIG_WIN32) += char-console.o
|
||||||
|
chardev-obj-$(CONFIG_POSIX) += char-fd.o
|
||||||
|
chardev-obj-y += char-file.o
|
||||||
|
chardev-obj-y += char-io.o
|
||||||
|
chardev-obj-y += char-mux.o
|
||||||
|
chardev-obj-y += char-null.o
|
||||||
|
chardev-obj-$(CONFIG_POSIX) += char-parallel.o
|
||||||
|
chardev-obj-y += char-pipe.o
|
||||||
|
chardev-obj-$(CONFIG_POSIX) += char-pty.o
|
||||||
|
chardev-obj-y += char-ringbuf.o
|
||||||
|
chardev-obj-y += char-serial.o
|
||||||
|
chardev-obj-y += char-socket.o
|
||||||
|
chardev-obj-y += char-stdio.o
|
||||||
|
chardev-obj-y += char-udp.o
|
||||||
|
chardev-obj-$(CONFIG_WIN32) += char-win.o
|
||||||
|
chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o
|
53
chardev/char-console.c
Normal file
53
chardev/char-console.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "char-win.h"
|
||||||
|
|
||||||
|
static void qemu_chr_open_win_con(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_console_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = qemu_chr_open_win_con;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_console_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_CONSOLE,
|
||||||
|
.parent = TYPE_CHARDEV_WIN,
|
||||||
|
.class_init = char_console_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_console_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
170
chardev/char-fd.c
Normal file
170
chardev/char-fd.c
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/sockets.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
#include "io/channel-file.h"
|
||||||
|
|
||||||
|
#include "char-fd.h"
|
||||||
|
#include "char-io.h"
|
||||||
|
|
||||||
|
/* Called with chr_write_lock held. */
|
||||||
|
static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
FDChardev *s = FD_CHARDEV(chr);
|
||||||
|
|
||||||
|
return io_channel_send(s->ioc_out, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
FDChardev *s = FD_CHARDEV(opaque);
|
||||||
|
int len;
|
||||||
|
uint8_t buf[CHR_READ_BUF_LEN];
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
len = sizeof(buf);
|
||||||
|
if (len > s->max_size) {
|
||||||
|
len = s->max_size;
|
||||||
|
}
|
||||||
|
if (len == 0) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qio_channel_read(
|
||||||
|
chan, (gchar *)buf, len, NULL);
|
||||||
|
if (ret == 0) {
|
||||||
|
remove_fd_in_watch(chr);
|
||||||
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (ret > 0) {
|
||||||
|
qemu_chr_be_write(chr, buf, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fd_chr_read_poll(void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
FDChardev *s = FD_CHARDEV(opaque);
|
||||||
|
|
||||||
|
s->max_size = qemu_chr_be_can_write(chr);
|
||||||
|
return s->max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
|
||||||
|
{
|
||||||
|
FDChardev *s = FD_CHARDEV(chr);
|
||||||
|
return qio_channel_create_watch(s->ioc_out, cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fd_chr_update_read_handler(Chardev *chr,
|
||||||
|
GMainContext *context)
|
||||||
|
{
|
||||||
|
FDChardev *s = FD_CHARDEV(chr);
|
||||||
|
|
||||||
|
remove_fd_in_watch(chr);
|
||||||
|
if (s->ioc_in) {
|
||||||
|
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in,
|
||||||
|
fd_chr_read_poll,
|
||||||
|
fd_chr_read, chr,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_fd_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(obj);
|
||||||
|
FDChardev *s = FD_CHARDEV(obj);
|
||||||
|
|
||||||
|
remove_fd_in_watch(chr);
|
||||||
|
if (s->ioc_in) {
|
||||||
|
object_unref(OBJECT(s->ioc_in));
|
||||||
|
}
|
||||||
|
if (s->ioc_out) {
|
||||||
|
object_unref(OBJECT(s->ioc_out));
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
int qmp_chardev_open_file_source(char *src, int flags, Error **errp)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
TFR(fd = qemu_open(src, flags, 0666));
|
||||||
|
if (fd == -1) {
|
||||||
|
error_setg_file_open(errp, errno, src);
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open a character device to a unix fd */
|
||||||
|
void qemu_chr_open_fd(Chardev *chr,
|
||||||
|
int fd_in, int fd_out)
|
||||||
|
{
|
||||||
|
FDChardev *s = FD_CHARDEV(chr);
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
|
||||||
|
name = g_strdup_printf("chardev-file-in-%s", chr->label);
|
||||||
|
qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
|
||||||
|
g_free(name);
|
||||||
|
s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
|
||||||
|
name = g_strdup_printf("chardev-file-out-%s", chr->label);
|
||||||
|
qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
|
||||||
|
g_free(name);
|
||||||
|
qemu_set_nonblock(fd_out);
|
||||||
|
s->chr = chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_fd_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->chr_add_watch = fd_chr_add_watch;
|
||||||
|
cc->chr_write = fd_chr_write;
|
||||||
|
cc->chr_update_read_handler = fd_chr_update_read_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_fd_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_FD,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(FDChardev),
|
||||||
|
.instance_finalize = char_fd_finalize,
|
||||||
|
.class_init = char_fd_class_init,
|
||||||
|
.abstract = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_fd_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
44
chardev/char-fd.h
Normal file
44
chardev/char-fd.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CHAR_FD_H
|
||||||
|
#define CHAR_FD_H
|
||||||
|
|
||||||
|
#include "io/channel.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
|
typedef struct FDChardev {
|
||||||
|
Chardev parent;
|
||||||
|
Chardev *chr;
|
||||||
|
QIOChannel *ioc_in, *ioc_out;
|
||||||
|
int max_size;
|
||||||
|
} FDChardev;
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_FD "chardev-fd"
|
||||||
|
|
||||||
|
#define FD_CHARDEV(obj) OBJECT_CHECK(FDChardev, (obj), TYPE_CHARDEV_FD)
|
||||||
|
|
||||||
|
void qemu_chr_open_fd(Chardev *chr, int fd_in, int fd_out);
|
||||||
|
int qmp_chardev_open_file_source(char *src, int flags, Error **errp);
|
||||||
|
|
||||||
|
#endif /* CHAR_FD_H */
|
139
chardev/char-file.c
Normal file
139
chardev/char-file.c
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "char-win.h"
|
||||||
|
#else
|
||||||
|
#include "char-fd.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void qmp_chardev_open_file(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevFile *file = backend->u.file.data;
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE out;
|
||||||
|
DWORD accessmode;
|
||||||
|
DWORD flags;
|
||||||
|
|
||||||
|
if (file->has_in) {
|
||||||
|
error_setg(errp, "input file not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file->has_append && file->append) {
|
||||||
|
/* Append to file if it already exists. */
|
||||||
|
accessmode = FILE_GENERIC_WRITE & ~FILE_WRITE_DATA;
|
||||||
|
flags = OPEN_ALWAYS;
|
||||||
|
} else {
|
||||||
|
/* Truncate file if it already exists. */
|
||||||
|
accessmode = GENERIC_WRITE;
|
||||||
|
flags = CREATE_ALWAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = CreateFile(file->out, accessmode, FILE_SHARE_READ, NULL, flags,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (out == INVALID_HANDLE_VALUE) {
|
||||||
|
error_setg(errp, "open %s failed", file->out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_chr_open_win_file(chr, out);
|
||||||
|
#else
|
||||||
|
int flags, in = -1, out;
|
||||||
|
|
||||||
|
flags = O_WRONLY | O_CREAT | O_BINARY;
|
||||||
|
if (file->has_append && file->append) {
|
||||||
|
flags |= O_APPEND;
|
||||||
|
} else {
|
||||||
|
flags |= O_TRUNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = qmp_chardev_open_file_source(file->out, flags, errp);
|
||||||
|
if (out < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file->has_in) {
|
||||||
|
flags = O_RDONLY;
|
||||||
|
in = qmp_chardev_open_file_source(file->in, flags, errp);
|
||||||
|
if (in < 0) {
|
||||||
|
qemu_close(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_chr_open_fd(chr, in, out);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
const char *path = qemu_opt_get(opts, "path");
|
||||||
|
ChardevFile *file;
|
||||||
|
|
||||||
|
backend->type = CHARDEV_BACKEND_KIND_FILE;
|
||||||
|
if (path == NULL) {
|
||||||
|
error_setg(errp, "chardev: file: no filename given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file = backend->u.file.data = g_new0(ChardevFile, 1);
|
||||||
|
qemu_chr_parse_common(opts, qapi_ChardevFile_base(file));
|
||||||
|
file->out = g_strdup(path);
|
||||||
|
|
||||||
|
file->has_append = true;
|
||||||
|
file->append = qemu_opt_get_bool(opts, "append", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_file_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->parse = qemu_chr_parse_file_out;
|
||||||
|
cc->open = qmp_chardev_open_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_file_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_FILE,
|
||||||
|
#ifdef _WIN32
|
||||||
|
.parent = TYPE_CHARDEV_WIN,
|
||||||
|
#else
|
||||||
|
.parent = TYPE_CHARDEV_FD,
|
||||||
|
#endif
|
||||||
|
.class_init = char_file_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_file_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
192
chardev/char-io.c
Normal file
192
chardev/char-io.c
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "char-io.h"
|
||||||
|
|
||||||
|
typedef struct IOWatchPoll {
|
||||||
|
GSource parent;
|
||||||
|
|
||||||
|
QIOChannel *ioc;
|
||||||
|
GSource *src;
|
||||||
|
|
||||||
|
IOCanReadHandler *fd_can_read;
|
||||||
|
GSourceFunc fd_read;
|
||||||
|
void *opaque;
|
||||||
|
GMainContext *context;
|
||||||
|
} IOWatchPoll;
|
||||||
|
|
||||||
|
static IOWatchPoll *io_watch_poll_from_source(GSource *source)
|
||||||
|
{
|
||||||
|
return container_of(source, IOWatchPoll, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean io_watch_poll_prepare(GSource *source,
|
||||||
|
gint *timeout)
|
||||||
|
{
|
||||||
|
IOWatchPoll *iwp = io_watch_poll_from_source(source);
|
||||||
|
bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
|
||||||
|
bool was_active = iwp->src != NULL;
|
||||||
|
if (was_active == now_active) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (now_active) {
|
||||||
|
iwp->src = qio_channel_create_watch(
|
||||||
|
iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
|
||||||
|
g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
|
||||||
|
g_source_attach(iwp->src, iwp->context);
|
||||||
|
} else {
|
||||||
|
g_source_destroy(iwp->src);
|
||||||
|
g_source_unref(iwp->src);
|
||||||
|
iwp->src = NULL;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean io_watch_poll_check(GSource *source)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void io_watch_poll_finalize(GSource *source)
|
||||||
|
{
|
||||||
|
/* Due to a glib bug, removing the last reference to a source
|
||||||
|
* inside a finalize callback causes recursive locking (and a
|
||||||
|
* deadlock). This is not a problem inside other callbacks,
|
||||||
|
* including dispatch callbacks, so we call io_remove_watch_poll
|
||||||
|
* to remove this source. At this point, iwp->src must
|
||||||
|
* be NULL, or we would leak it.
|
||||||
|
*
|
||||||
|
* This would be solved much more elegantly by child sources,
|
||||||
|
* but we support older glib versions that do not have them.
|
||||||
|
*/
|
||||||
|
IOWatchPoll *iwp = io_watch_poll_from_source(source);
|
||||||
|
assert(iwp->src == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSourceFuncs io_watch_poll_funcs = {
|
||||||
|
.prepare = io_watch_poll_prepare,
|
||||||
|
.check = io_watch_poll_check,
|
||||||
|
.dispatch = io_watch_poll_dispatch,
|
||||||
|
.finalize = io_watch_poll_finalize,
|
||||||
|
};
|
||||||
|
|
||||||
|
guint io_add_watch_poll(Chardev *chr,
|
||||||
|
QIOChannel *ioc,
|
||||||
|
IOCanReadHandler *fd_can_read,
|
||||||
|
QIOChannelFunc fd_read,
|
||||||
|
gpointer user_data,
|
||||||
|
GMainContext *context)
|
||||||
|
{
|
||||||
|
IOWatchPoll *iwp;
|
||||||
|
int tag;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
|
||||||
|
sizeof(IOWatchPoll));
|
||||||
|
iwp->fd_can_read = fd_can_read;
|
||||||
|
iwp->opaque = user_data;
|
||||||
|
iwp->ioc = ioc;
|
||||||
|
iwp->fd_read = (GSourceFunc) fd_read;
|
||||||
|
iwp->src = NULL;
|
||||||
|
iwp->context = context;
|
||||||
|
|
||||||
|
name = g_strdup_printf("chardev-iowatch-%s", chr->label);
|
||||||
|
g_source_set_name((GSource *)iwp, name);
|
||||||
|
g_free(name);
|
||||||
|
|
||||||
|
tag = g_source_attach(&iwp->parent, context);
|
||||||
|
g_source_unref(&iwp->parent);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void io_remove_watch_poll(guint tag)
|
||||||
|
{
|
||||||
|
GSource *source;
|
||||||
|
IOWatchPoll *iwp;
|
||||||
|
|
||||||
|
g_return_if_fail(tag > 0);
|
||||||
|
|
||||||
|
source = g_main_context_find_source_by_id(NULL, tag);
|
||||||
|
g_return_if_fail(source != NULL);
|
||||||
|
|
||||||
|
iwp = io_watch_poll_from_source(source);
|
||||||
|
if (iwp->src) {
|
||||||
|
g_source_destroy(iwp->src);
|
||||||
|
g_source_unref(iwp->src);
|
||||||
|
iwp->src = NULL;
|
||||||
|
}
|
||||||
|
g_source_destroy(&iwp->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_fd_in_watch(Chardev *chr)
|
||||||
|
{
|
||||||
|
if (chr->fd_in_tag) {
|
||||||
|
io_remove_watch_poll(chr->fd_in_tag);
|
||||||
|
chr->fd_in_tag = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int io_channel_send_full(QIOChannel *ioc,
|
||||||
|
const void *buf, size_t len,
|
||||||
|
int *fds, size_t nfds)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
while (offset < len) {
|
||||||
|
ssize_t ret = 0;
|
||||||
|
struct iovec iov = { .iov_base = (char *)buf + offset,
|
||||||
|
.iov_len = len - offset };
|
||||||
|
|
||||||
|
ret = qio_channel_writev_full(
|
||||||
|
ioc, &iov, 1,
|
||||||
|
fds, nfds, NULL);
|
||||||
|
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||||
|
if (offset) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = EAGAIN;
|
||||||
|
return -1;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
return io_channel_send_full(ioc, buf, len, NULL, 0);
|
||||||
|
}
|
46
chardev/char-io.h
Normal file
46
chardev/char-io.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CHAR_IO_H
|
||||||
|
#define CHAR_IO_H
|
||||||
|
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "io/channel.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
|
/* Can only be used for read */
|
||||||
|
guint io_add_watch_poll(Chardev *chr,
|
||||||
|
QIOChannel *ioc,
|
||||||
|
IOCanReadHandler *fd_can_read,
|
||||||
|
QIOChannelFunc fd_read,
|
||||||
|
gpointer user_data,
|
||||||
|
GMainContext *context);
|
||||||
|
|
||||||
|
void remove_fd_in_watch(Chardev *chr);
|
||||||
|
|
||||||
|
int io_channel_send(QIOChannel *ioc, const void *buf, size_t len);
|
||||||
|
|
||||||
|
int io_channel_send_full(QIOChannel *ioc, const void *buf, size_t len,
|
||||||
|
int *fds, size_t nfds);
|
||||||
|
|
||||||
|
#endif /* CHAR_IO_H */
|
358
chardev/char-mux.c
Normal file
358
chardev/char-mux.c
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
#include "sysemu/block-backend.h"
|
||||||
|
#include "char-mux.h"
|
||||||
|
|
||||||
|
/* MUX driver for serial I/O splitting */
|
||||||
|
|
||||||
|
/* Called with chr_write_lock held. */
|
||||||
|
static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
MuxChardev *d = MUX_CHARDEV(chr);
|
||||||
|
int ret;
|
||||||
|
if (!d->timestamps) {
|
||||||
|
ret = qemu_chr_fe_write(&d->chr, buf, len);
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (d->linestart) {
|
||||||
|
char buf1[64];
|
||||||
|
int64_t ti;
|
||||||
|
int secs;
|
||||||
|
|
||||||
|
ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
|
||||||
|
if (d->timestamps_start == -1) {
|
||||||
|
d->timestamps_start = ti;
|
||||||
|
}
|
||||||
|
ti -= d->timestamps_start;
|
||||||
|
secs = ti / 1000;
|
||||||
|
snprintf(buf1, sizeof(buf1),
|
||||||
|
"[%02d:%02d:%02d.%03d] ",
|
||||||
|
secs / 3600,
|
||||||
|
(secs / 60) % 60,
|
||||||
|
secs % 60,
|
||||||
|
(int)(ti % 1000));
|
||||||
|
/* XXX this blocks entire thread. Rewrite to use
|
||||||
|
* qemu_chr_fe_write and background I/O callbacks */
|
||||||
|
qemu_chr_fe_write_all(&d->chr,
|
||||||
|
(uint8_t *)buf1, strlen(buf1));
|
||||||
|
d->linestart = 0;
|
||||||
|
}
|
||||||
|
ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
|
||||||
|
if (buf[i] == '\n') {
|
||||||
|
d->linestart = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const mux_help[] = {
|
||||||
|
"% h print this help\n\r",
|
||||||
|
"% x exit emulator\n\r",
|
||||||
|
"% s save disk data back to file (if -snapshot)\n\r",
|
||||||
|
"% t toggle console timestamps\n\r",
|
||||||
|
"% b send break (magic sysrq)\n\r",
|
||||||
|
"% c switch between console and monitor\n\r",
|
||||||
|
"% % sends %\n\r",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
int term_escape_char = 0x01; /* ctrl-a is used for escape */
|
||||||
|
static void mux_print_help(Chardev *chr)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
char ebuf[15] = "Escape-Char";
|
||||||
|
char cbuf[50] = "\n\r";
|
||||||
|
|
||||||
|
if (term_escape_char > 0 && term_escape_char < 26) {
|
||||||
|
snprintf(cbuf, sizeof(cbuf), "\n\r");
|
||||||
|
snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
|
||||||
|
} else {
|
||||||
|
snprintf(cbuf, sizeof(cbuf),
|
||||||
|
"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
|
||||||
|
term_escape_char);
|
||||||
|
}
|
||||||
|
/* XXX this blocks entire thread. Rewrite to use
|
||||||
|
* qemu_chr_fe_write and background I/O callbacks */
|
||||||
|
qemu_chr_write_all(chr, (uint8_t *)cbuf, strlen(cbuf));
|
||||||
|
for (i = 0; mux_help[i] != NULL; i++) {
|
||||||
|
for (j = 0; mux_help[i][j] != '\0'; j++) {
|
||||||
|
if (mux_help[i][j] == '%') {
|
||||||
|
qemu_chr_write_all(chr, (uint8_t *)ebuf, strlen(ebuf));
|
||||||
|
} else {
|
||||||
|
qemu_chr_write_all(chr, (uint8_t *)&mux_help[i][j], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
|
||||||
|
{
|
||||||
|
CharBackend *be = d->backends[mux_nr];
|
||||||
|
|
||||||
|
if (be && be->chr_event) {
|
||||||
|
be->chr_event(be->opaque, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
|
||||||
|
{
|
||||||
|
if (d->term_got_escape) {
|
||||||
|
d->term_got_escape = 0;
|
||||||
|
if (ch == term_escape_char) {
|
||||||
|
goto send_char;
|
||||||
|
}
|
||||||
|
switch (ch) {
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
mux_print_help(chr);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
{
|
||||||
|
const char *term = "QEMU: Terminated\n\r";
|
||||||
|
qemu_chr_write_all(chr, (uint8_t *)term, strlen(term));
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
blk_commit_all();
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
qemu_chr_be_event(chr, CHR_EVENT_BREAK);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
assert(d->mux_cnt > 0); /* handler registered with first fe */
|
||||||
|
/* Switch to the next registered device */
|
||||||
|
mux_set_focus(chr, (d->focus + 1) % d->mux_cnt);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
d->timestamps = !d->timestamps;
|
||||||
|
d->timestamps_start = -1;
|
||||||
|
d->linestart = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (ch == term_escape_char) {
|
||||||
|
d->term_got_escape = 1;
|
||||||
|
} else {
|
||||||
|
send_char:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mux_chr_accept_input(Chardev *chr)
|
||||||
|
{
|
||||||
|
MuxChardev *d = MUX_CHARDEV(chr);
|
||||||
|
int m = d->focus;
|
||||||
|
CharBackend *be = d->backends[m];
|
||||||
|
|
||||||
|
while (be && d->prod[m] != d->cons[m] &&
|
||||||
|
be->chr_can_read && be->chr_can_read(be->opaque)) {
|
||||||
|
be->chr_read(be->opaque,
|
||||||
|
&d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mux_chr_can_read(void *opaque)
|
||||||
|
{
|
||||||
|
MuxChardev *d = MUX_CHARDEV(opaque);
|
||||||
|
int m = d->focus;
|
||||||
|
CharBackend *be = d->backends[m];
|
||||||
|
|
||||||
|
if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (be && be->chr_can_read) {
|
||||||
|
return be->chr_can_read(be->opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
MuxChardev *d = MUX_CHARDEV(opaque);
|
||||||
|
int m = d->focus;
|
||||||
|
CharBackend *be = d->backends[m];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mux_chr_accept_input(opaque);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
if (mux_proc_byte(chr, d, buf[i])) {
|
||||||
|
if (d->prod[m] == d->cons[m] &&
|
||||||
|
be && be->chr_can_read &&
|
||||||
|
be->chr_can_read(be->opaque)) {
|
||||||
|
be->chr_read(be->opaque, &buf[i], 1);
|
||||||
|
} else {
|
||||||
|
d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool muxes_realized;
|
||||||
|
|
||||||
|
static void mux_chr_event(void *opaque, int event)
|
||||||
|
{
|
||||||
|
MuxChardev *d = MUX_CHARDEV(opaque);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!muxes_realized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the event to all registered listeners */
|
||||||
|
for (i = 0; i < d->mux_cnt; i++) {
|
||||||
|
mux_chr_send_event(d, i, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
|
||||||
|
{
|
||||||
|
MuxChardev *d = MUX_CHARDEV(s);
|
||||||
|
Chardev *chr = qemu_chr_fe_get_driver(&d->chr);
|
||||||
|
ChardevClass *cc = CHARDEV_GET_CLASS(chr);
|
||||||
|
|
||||||
|
if (!cc->chr_add_watch) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cc->chr_add_watch(chr, cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_mux_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
MuxChardev *d = MUX_CHARDEV(obj);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < d->mux_cnt; i++) {
|
||||||
|
CharBackend *be = d->backends[i];
|
||||||
|
if (be) {
|
||||||
|
be->chr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qemu_chr_fe_deinit(&d->chr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
|
||||||
|
{
|
||||||
|
MuxChardev *d = MUX_CHARDEV(chr);
|
||||||
|
|
||||||
|
/* Fix up the real driver with mux routines */
|
||||||
|
qemu_chr_fe_set_handlers(&d->chr,
|
||||||
|
mux_chr_can_read,
|
||||||
|
mux_chr_read,
|
||||||
|
mux_chr_event,
|
||||||
|
chr,
|
||||||
|
context, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mux_set_focus(Chardev *chr, int focus)
|
||||||
|
{
|
||||||
|
MuxChardev *d = MUX_CHARDEV(chr);
|
||||||
|
|
||||||
|
assert(focus >= 0);
|
||||||
|
assert(focus < d->mux_cnt);
|
||||||
|
|
||||||
|
if (d->focus != -1) {
|
||||||
|
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->focus = focus;
|
||||||
|
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_open_mux(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevMux *mux = backend->u.mux.data;
|
||||||
|
Chardev *drv;
|
||||||
|
MuxChardev *d = MUX_CHARDEV(chr);
|
||||||
|
|
||||||
|
drv = qemu_chr_find(mux->chardev);
|
||||||
|
if (drv == NULL) {
|
||||||
|
error_setg(errp, "mux: base chardev %s not found", mux->chardev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->focus = -1;
|
||||||
|
/* only default to opened state if we've realized the initial
|
||||||
|
* set of muxes
|
||||||
|
*/
|
||||||
|
*be_opened = muxes_realized;
|
||||||
|
qemu_chr_fe_init(&d->chr, drv, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
const char *chardev = qemu_opt_get(opts, "chardev");
|
||||||
|
ChardevMux *mux;
|
||||||
|
|
||||||
|
if (chardev == NULL) {
|
||||||
|
error_setg(errp, "chardev: mux: no chardev given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backend->type = CHARDEV_BACKEND_KIND_MUX;
|
||||||
|
mux = backend->u.mux.data = g_new0(ChardevMux, 1);
|
||||||
|
qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux));
|
||||||
|
mux->chardev = g_strdup(chardev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_mux_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->parse = qemu_chr_parse_mux;
|
||||||
|
cc->open = qemu_chr_open_mux;
|
||||||
|
cc->chr_write = mux_chr_write;
|
||||||
|
cc->chr_accept_input = mux_chr_accept_input;
|
||||||
|
cc->chr_add_watch = mux_chr_add_watch;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_mux_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_MUX,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.class_init = char_mux_class_init,
|
||||||
|
.instance_size = sizeof(MuxChardev),
|
||||||
|
.instance_finalize = char_mux_finalize,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_mux_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
63
chardev/char-mux.h
Normal file
63
chardev/char-mux.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CHAR_MUX_H
|
||||||
|
#define CHAR_MUX_H
|
||||||
|
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
|
extern bool muxes_realized;
|
||||||
|
|
||||||
|
#define MAX_MUX 4
|
||||||
|
#define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */
|
||||||
|
#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
|
||||||
|
typedef struct MuxChardev {
|
||||||
|
Chardev parent;
|
||||||
|
CharBackend *backends[MAX_MUX];
|
||||||
|
CharBackend chr;
|
||||||
|
int focus;
|
||||||
|
int mux_cnt;
|
||||||
|
int term_got_escape;
|
||||||
|
int max_size;
|
||||||
|
/* Intermediate input buffer catches escape sequences even if the
|
||||||
|
currently active device is not accepting any input - but only until it
|
||||||
|
is full as well. */
|
||||||
|
unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
|
||||||
|
int prod[MAX_MUX];
|
||||||
|
int cons[MAX_MUX];
|
||||||
|
int timestamps;
|
||||||
|
|
||||||
|
/* Protected by the Chardev chr_write_lock. */
|
||||||
|
int linestart;
|
||||||
|
int64_t timestamps_start;
|
||||||
|
} MuxChardev;
|
||||||
|
|
||||||
|
#define MUX_CHARDEV(obj) OBJECT_CHECK(MuxChardev, (obj), TYPE_CHARDEV_MUX)
|
||||||
|
#define CHARDEV_IS_MUX(chr) \
|
||||||
|
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
|
||||||
|
|
||||||
|
void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
|
||||||
|
void mux_set_focus(Chardev *chr, int focus);
|
||||||
|
void mux_chr_send_event(MuxChardev *d, int mux_nr, int event);
|
||||||
|
|
||||||
|
#endif /* CHAR_MUX_H */
|
54
chardev/char-null.c
Normal file
54
chardev/char-null.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
|
static void null_chr_open(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
*be_opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_null_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = null_chr_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_null_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_NULL,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(Chardev),
|
||||||
|
.class_init = char_null_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_null_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
316
chardev/char-parallel.c
Normal file
316
chardev/char-parallel.c
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_BSD
|
||||||
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
#include <dev/ppbus/ppi.h>
|
||||||
|
#include <dev/ppbus/ppbconf.h>
|
||||||
|
#elif defined(__DragonFly__)
|
||||||
|
#include <dev/misc/ppi/ppi.h>
|
||||||
|
#include <bus/ppbus/ppbconf.h>
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <linux/ppdev.h>
|
||||||
|
#include <linux/parport.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "char-fd.h"
|
||||||
|
#include "char-parallel.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Chardev parent;
|
||||||
|
int fd;
|
||||||
|
int mode;
|
||||||
|
} ParallelChardev;
|
||||||
|
|
||||||
|
#define PARALLEL_CHARDEV(obj) \
|
||||||
|
OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
|
||||||
|
|
||||||
|
static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
|
||||||
|
{
|
||||||
|
if (s->mode != mode) {
|
||||||
|
int m = mode;
|
||||||
|
if (ioctl(s->fd, PPSETMODE, &m) < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
s->mode = mode;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pp_ioctl(Chardev *chr, int cmd, void *arg)
|
||||||
|
{
|
||||||
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
||||||
|
int fd = drv->fd;
|
||||||
|
uint8_t b;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CHR_IOCTL_PP_READ_DATA:
|
||||||
|
if (ioctl(fd, PPRDATA, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
*(uint8_t *)arg = b;
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_WRITE_DATA:
|
||||||
|
b = *(uint8_t *)arg;
|
||||||
|
if (ioctl(fd, PPWDATA, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_READ_CONTROL:
|
||||||
|
if (ioctl(fd, PPRCONTROL, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
/* Linux gives only the lowest bits, and no way to know data
|
||||||
|
direction! For better compatibility set the fixed upper
|
||||||
|
bits. */
|
||||||
|
*(uint8_t *)arg = b | 0xc0;
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_WRITE_CONTROL:
|
||||||
|
b = *(uint8_t *)arg;
|
||||||
|
if (ioctl(fd, PPWCONTROL, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_READ_STATUS:
|
||||||
|
if (ioctl(fd, PPRSTATUS, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
*(uint8_t *)arg = b;
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_DATA_DIR:
|
||||||
|
if (ioctl(fd, PPDATADIR, (int *)arg) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_EPP_READ_ADDR:
|
||||||
|
if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
|
||||||
|
struct ParallelIOArg *parg = arg;
|
||||||
|
int n = read(fd, parg->buffer, parg->count);
|
||||||
|
if (n != parg->count) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_EPP_READ:
|
||||||
|
if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
|
||||||
|
struct ParallelIOArg *parg = arg;
|
||||||
|
int n = read(fd, parg->buffer, parg->count);
|
||||||
|
if (n != parg->count) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_EPP_WRITE_ADDR:
|
||||||
|
if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) {
|
||||||
|
struct ParallelIOArg *parg = arg;
|
||||||
|
int n = write(fd, parg->buffer, parg->count);
|
||||||
|
if (n != parg->count) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_EPP_WRITE:
|
||||||
|
if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
|
||||||
|
struct ParallelIOArg *parg = arg;
|
||||||
|
int n = write(fd, parg->buffer, parg->count);
|
||||||
|
if (n != parg->count) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_open_pp_fd(Chardev *chr,
|
||||||
|
int fd,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
||||||
|
|
||||||
|
if (ioctl(fd, PPCLAIM) < 0) {
|
||||||
|
error_setg_errno(errp, errno, "not a parallel port");
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv->fd = fd;
|
||||||
|
drv->mode = IEEE1284_MODE_COMPAT;
|
||||||
|
}
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Chardev parent;
|
||||||
|
int fd;
|
||||||
|
} ParallelChardev;
|
||||||
|
|
||||||
|
#define PARALLEL_CHARDEV(obj) \
|
||||||
|
OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
|
||||||
|
|
||||||
|
static int pp_ioctl(Chardev *chr, int cmd, void *arg)
|
||||||
|
{
|
||||||
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
||||||
|
uint8_t b;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CHR_IOCTL_PP_READ_DATA:
|
||||||
|
if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
*(uint8_t *)arg = b;
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_WRITE_DATA:
|
||||||
|
b = *(uint8_t *)arg;
|
||||||
|
if (ioctl(drv->fd, PPISDATA, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_READ_CONTROL:
|
||||||
|
if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
*(uint8_t *)arg = b;
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_WRITE_CONTROL:
|
||||||
|
b = *(uint8_t *)arg;
|
||||||
|
if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_PP_READ_STATUS:
|
||||||
|
if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
*(uint8_t *)arg = b;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_open_pp_fd(Chardev *chr,
|
||||||
|
int fd,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
||||||
|
drv->fd = fd;
|
||||||
|
*be_opened = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_CHARDEV_PARPORT
|
||||||
|
static void qmp_chardev_open_parallel(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevHostdev *parallel = backend->u.parallel.data;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
|
||||||
|
if (fd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
const char *device = qemu_opt_get(opts, "path");
|
||||||
|
ChardevHostdev *parallel;
|
||||||
|
|
||||||
|
if (device == NULL) {
|
||||||
|
error_setg(errp, "chardev: parallel: no device path given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backend->type = CHARDEV_BACKEND_KIND_PARALLEL;
|
||||||
|
parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
|
||||||
|
qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
|
||||||
|
parallel->device = g_strdup(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_parallel_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->parse = qemu_chr_parse_parallel;
|
||||||
|
cc->open = qmp_chardev_open_parallel;
|
||||||
|
#if defined(__linux__)
|
||||||
|
cc->chr_ioctl = pp_ioctl;
|
||||||
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||||
|
defined(__DragonFly__)
|
||||||
|
cc->chr_ioctl = pp_ioctl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_parallel_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
#if defined(__linux__)
|
||||||
|
Chardev *chr = CHARDEV(obj);
|
||||||
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
||||||
|
int fd = drv->fd;
|
||||||
|
|
||||||
|
pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
|
||||||
|
ioctl(fd, PPRELEASE);
|
||||||
|
close(fd);
|
||||||
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||||
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||||
|
defined(__DragonFly__)
|
||||||
|
/* FIXME: close fd? */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_parallel_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_PARALLEL,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(ParallelChardev),
|
||||||
|
.instance_finalize = char_parallel_finalize,
|
||||||
|
.class_init = char_parallel_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_parallel_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
||||||
|
|
||||||
|
#endif
|
32
chardev/char-parallel.h
Normal file
32
chardev/char-parallel.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CHAR_PARALLEL_H
|
||||||
|
#define CHAR_PARALLEL_H
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__FreeBSD__) || \
|
||||||
|
defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||||
|
#define HAVE_CHARDEV_PARPORT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CHAR_PARALLEL_H */
|
191
chardev/char-pipe.c
Normal file
191
chardev/char-pipe.c
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "char-win.h"
|
||||||
|
#else
|
||||||
|
#include "char-fd.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define MAXCONNECT 1
|
||||||
|
#define NTIMEOUT 5000
|
||||||
|
|
||||||
|
static int win_chr_pipe_init(Chardev *chr, const char *filename,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
WinChardev *s = WIN_CHARDEV(chr);
|
||||||
|
OVERLAPPED ov;
|
||||||
|
int ret;
|
||||||
|
DWORD size;
|
||||||
|
char *openname;
|
||||||
|
|
||||||
|
s->fpipe = TRUE;
|
||||||
|
|
||||||
|
s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (!s->hsend) {
|
||||||
|
error_setg(errp, "Failed CreateEvent");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (!s->hrecv) {
|
||||||
|
error_setg(errp, "Failed CreateEvent");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
openname = g_strdup_printf("\\\\.\\pipe\\%s", filename);
|
||||||
|
s->hcom = CreateNamedPipe(openname,
|
||||||
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||||
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
|
||||||
|
PIPE_WAIT,
|
||||||
|
MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
|
||||||
|
g_free(openname);
|
||||||
|
if (s->hcom == INVALID_HANDLE_VALUE) {
|
||||||
|
error_setg(errp, "Failed CreateNamedPipe (%lu)", GetLastError());
|
||||||
|
s->hcom = NULL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory(&ov, sizeof(ov));
|
||||||
|
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
ret = ConnectNamedPipe(s->hcom, &ov);
|
||||||
|
if (ret) {
|
||||||
|
error_setg(errp, "Failed ConnectNamedPipe");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
|
||||||
|
if (!ret) {
|
||||||
|
error_setg(errp, "Failed GetOverlappedResult");
|
||||||
|
if (ov.hEvent) {
|
||||||
|
CloseHandle(ov.hEvent);
|
||||||
|
ov.hEvent = NULL;
|
||||||
|
}
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ov.hEvent) {
|
||||||
|
CloseHandle(ov.hEvent);
|
||||||
|
ov.hEvent = NULL;
|
||||||
|
}
|
||||||
|
qemu_add_polling_cb(win_chr_pipe_poll, chr);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_open_pipe(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevHostdev *opts = backend->u.pipe.data;
|
||||||
|
const char *filename = opts->device;
|
||||||
|
|
||||||
|
if (win_chr_pipe_init(chr, filename, errp) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void qemu_chr_open_pipe(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevHostdev *opts = backend->u.pipe.data;
|
||||||
|
int fd_in, fd_out;
|
||||||
|
char *filename_in;
|
||||||
|
char *filename_out;
|
||||||
|
const char *filename = opts->device;
|
||||||
|
|
||||||
|
filename_in = g_strdup_printf("%s.in", filename);
|
||||||
|
filename_out = g_strdup_printf("%s.out", filename);
|
||||||
|
TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY));
|
||||||
|
TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY));
|
||||||
|
g_free(filename_in);
|
||||||
|
g_free(filename_out);
|
||||||
|
if (fd_in < 0 || fd_out < 0) {
|
||||||
|
if (fd_in >= 0) {
|
||||||
|
close(fd_in);
|
||||||
|
}
|
||||||
|
if (fd_out >= 0) {
|
||||||
|
close(fd_out);
|
||||||
|
}
|
||||||
|
TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
|
||||||
|
if (fd_in < 0) {
|
||||||
|
error_setg_file_open(errp, errno, filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qemu_chr_open_fd(chr, fd_in, fd_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !_WIN32 */
|
||||||
|
|
||||||
|
static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
const char *device = qemu_opt_get(opts, "path");
|
||||||
|
ChardevHostdev *dev;
|
||||||
|
|
||||||
|
if (device == NULL) {
|
||||||
|
error_setg(errp, "chardev: pipe: no device path given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backend->type = CHARDEV_BACKEND_KIND_PIPE;
|
||||||
|
dev = backend->u.pipe.data = g_new0(ChardevHostdev, 1);
|
||||||
|
qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
|
||||||
|
dev->device = g_strdup(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_pipe_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->parse = qemu_chr_parse_pipe;
|
||||||
|
cc->open = qemu_chr_open_pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_pipe_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_PIPE,
|
||||||
|
#ifdef _WIN32
|
||||||
|
.parent = TYPE_CHARDEV_WIN,
|
||||||
|
#else
|
||||||
|
.parent = TYPE_CHARDEV_FD,
|
||||||
|
#endif
|
||||||
|
.class_init = char_pipe_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_pipe_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
300
chardev/char-pty.c
Normal file
300
chardev/char-pty.c
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
#include "io/channel-file.h"
|
||||||
|
#include "qemu/sockets.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
|
#include "char-io.h"
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|
||||||
|
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
|
||||||
|
|| defined(__GLIBC__)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Chardev parent;
|
||||||
|
QIOChannel *ioc;
|
||||||
|
int read_bytes;
|
||||||
|
|
||||||
|
/* Protected by the Chardev chr_write_lock. */
|
||||||
|
int connected;
|
||||||
|
guint timer_tag;
|
||||||
|
guint open_tag;
|
||||||
|
} PtyChardev;
|
||||||
|
|
||||||
|
#define PTY_CHARDEV(obj) OBJECT_CHECK(PtyChardev, (obj), TYPE_CHARDEV_PTY)
|
||||||
|
|
||||||
|
static void pty_chr_update_read_handler_locked(Chardev *chr);
|
||||||
|
static void pty_chr_state(Chardev *chr, int connected);
|
||||||
|
|
||||||
|
static gboolean pty_chr_timer(gpointer opaque)
|
||||||
|
{
|
||||||
|
struct Chardev *chr = CHARDEV(opaque);
|
||||||
|
PtyChardev *s = PTY_CHARDEV(opaque);
|
||||||
|
|
||||||
|
qemu_mutex_lock(&chr->chr_write_lock);
|
||||||
|
s->timer_tag = 0;
|
||||||
|
s->open_tag = 0;
|
||||||
|
if (!s->connected) {
|
||||||
|
/* Next poll ... */
|
||||||
|
pty_chr_update_read_handler_locked(chr);
|
||||||
|
}
|
||||||
|
qemu_mutex_unlock(&chr->chr_write_lock);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called with chr_write_lock held. */
|
||||||
|
static void pty_chr_rearm_timer(Chardev *chr, int ms)
|
||||||
|
{
|
||||||
|
PtyChardev *s = PTY_CHARDEV(chr);
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
if (s->timer_tag) {
|
||||||
|
g_source_remove(s->timer_tag);
|
||||||
|
s->timer_tag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ms == 1000) {
|
||||||
|
name = g_strdup_printf("pty-timer-secs-%s", chr->label);
|
||||||
|
s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr);
|
||||||
|
} else {
|
||||||
|
name = g_strdup_printf("pty-timer-ms-%s", chr->label);
|
||||||
|
s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr);
|
||||||
|
}
|
||||||
|
g_source_set_name_by_id(s->timer_tag, name);
|
||||||
|
g_free(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called with chr_write_lock held. */
|
||||||
|
static void pty_chr_update_read_handler_locked(Chardev *chr)
|
||||||
|
{
|
||||||
|
PtyChardev *s = PTY_CHARDEV(chr);
|
||||||
|
GPollFD pfd;
|
||||||
|
int rc;
|
||||||
|
QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
|
||||||
|
|
||||||
|
pfd.fd = fioc->fd;
|
||||||
|
pfd.events = G_IO_OUT;
|
||||||
|
pfd.revents = 0;
|
||||||
|
do {
|
||||||
|
rc = g_poll(&pfd, 1, 0);
|
||||||
|
} while (rc == -1 && errno == EINTR);
|
||||||
|
assert(rc >= 0);
|
||||||
|
|
||||||
|
if (pfd.revents & G_IO_HUP) {
|
||||||
|
pty_chr_state(chr, 0);
|
||||||
|
} else {
|
||||||
|
pty_chr_state(chr, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pty_chr_update_read_handler(Chardev *chr,
|
||||||
|
GMainContext *context)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&chr->chr_write_lock);
|
||||||
|
pty_chr_update_read_handler_locked(chr);
|
||||||
|
qemu_mutex_unlock(&chr->chr_write_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called with chr_write_lock held. */
|
||||||
|
static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
PtyChardev *s = PTY_CHARDEV(chr);
|
||||||
|
|
||||||
|
if (!s->connected) {
|
||||||
|
/* guest sends data, check for (re-)connect */
|
||||||
|
pty_chr_update_read_handler_locked(chr);
|
||||||
|
if (!s->connected) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return io_channel_send(s->ioc, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
|
||||||
|
{
|
||||||
|
PtyChardev *s = PTY_CHARDEV(chr);
|
||||||
|
if (!s->connected) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return qio_channel_create_watch(s->ioc, cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pty_chr_read_poll(void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
PtyChardev *s = PTY_CHARDEV(opaque);
|
||||||
|
|
||||||
|
s->read_bytes = qemu_chr_be_can_write(chr);
|
||||||
|
return s->read_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
PtyChardev *s = PTY_CHARDEV(opaque);
|
||||||
|
gsize len;
|
||||||
|
uint8_t buf[CHR_READ_BUF_LEN];
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
len = sizeof(buf);
|
||||||
|
if (len > s->read_bytes) {
|
||||||
|
len = s->read_bytes;
|
||||||
|
}
|
||||||
|
if (len == 0) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
ret = qio_channel_read(s->ioc, (char *)buf, len, NULL);
|
||||||
|
if (ret <= 0) {
|
||||||
|
pty_chr_state(chr, 0);
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
pty_chr_state(chr, 1);
|
||||||
|
qemu_chr_be_write(chr, buf, ret);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
PtyChardev *s = PTY_CHARDEV(opaque);
|
||||||
|
|
||||||
|
s->open_tag = 0;
|
||||||
|
qemu_chr_be_generic_open(chr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called with chr_write_lock held. */
|
||||||
|
static void pty_chr_state(Chardev *chr, int connected)
|
||||||
|
{
|
||||||
|
PtyChardev *s = PTY_CHARDEV(chr);
|
||||||
|
|
||||||
|
if (!connected) {
|
||||||
|
if (s->open_tag) {
|
||||||
|
g_source_remove(s->open_tag);
|
||||||
|
s->open_tag = 0;
|
||||||
|
}
|
||||||
|
remove_fd_in_watch(chr);
|
||||||
|
s->connected = 0;
|
||||||
|
/* (re-)connect poll interval for idle guests: once per second.
|
||||||
|
* We check more frequently in case the guests sends data to
|
||||||
|
* the virtual device linked to our pty. */
|
||||||
|
pty_chr_rearm_timer(chr, 1000);
|
||||||
|
} else {
|
||||||
|
if (s->timer_tag) {
|
||||||
|
g_source_remove(s->timer_tag);
|
||||||
|
s->timer_tag = 0;
|
||||||
|
}
|
||||||
|
if (!s->connected) {
|
||||||
|
g_assert(s->open_tag == 0);
|
||||||
|
s->connected = 1;
|
||||||
|
s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr);
|
||||||
|
}
|
||||||
|
if (!chr->fd_in_tag) {
|
||||||
|
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
||||||
|
pty_chr_read_poll,
|
||||||
|
pty_chr_read,
|
||||||
|
chr, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_pty_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(obj);
|
||||||
|
PtyChardev *s = PTY_CHARDEV(obj);
|
||||||
|
|
||||||
|
qemu_mutex_lock(&chr->chr_write_lock);
|
||||||
|
pty_chr_state(chr, 0);
|
||||||
|
object_unref(OBJECT(s->ioc));
|
||||||
|
if (s->timer_tag) {
|
||||||
|
g_source_remove(s->timer_tag);
|
||||||
|
s->timer_tag = 0;
|
||||||
|
}
|
||||||
|
qemu_mutex_unlock(&chr->chr_write_lock);
|
||||||
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_pty_open(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
PtyChardev *s;
|
||||||
|
int master_fd, slave_fd;
|
||||||
|
char pty_name[PATH_MAX];
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
master_fd = qemu_openpty_raw(&slave_fd, pty_name);
|
||||||
|
if (master_fd < 0) {
|
||||||
|
error_setg_errno(errp, errno, "Failed to create PTY");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(slave_fd);
|
||||||
|
qemu_set_nonblock(master_fd);
|
||||||
|
|
||||||
|
chr->filename = g_strdup_printf("pty:%s", pty_name);
|
||||||
|
error_report("char device redirected to %s (label %s)",
|
||||||
|
pty_name, chr->label);
|
||||||
|
|
||||||
|
s = PTY_CHARDEV(chr);
|
||||||
|
s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
|
||||||
|
name = g_strdup_printf("chardev-pty-%s", chr->label);
|
||||||
|
qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
|
||||||
|
g_free(name);
|
||||||
|
s->timer_tag = 0;
|
||||||
|
*be_opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_pty_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = char_pty_open;
|
||||||
|
cc->chr_write = char_pty_chr_write;
|
||||||
|
cc->chr_update_read_handler = pty_chr_update_read_handler;
|
||||||
|
cc->chr_add_watch = pty_chr_add_watch;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_pty_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_PTY,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(PtyChardev),
|
||||||
|
.instance_finalize = char_pty_finalize,
|
||||||
|
.class_init = char_pty_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_pty_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
||||||
|
|
||||||
|
#endif
|
249
chardev/char-ringbuf.c
Normal file
249
chardev/char-ringbuf.c
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
#include "qmp-commands.h"
|
||||||
|
#include "qemu/base64.h"
|
||||||
|
|
||||||
|
/* Ring buffer chardev */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Chardev parent;
|
||||||
|
size_t size;
|
||||||
|
size_t prod;
|
||||||
|
size_t cons;
|
||||||
|
uint8_t *cbuf;
|
||||||
|
} RingBufChardev;
|
||||||
|
|
||||||
|
#define RINGBUF_CHARDEV(obj) \
|
||||||
|
OBJECT_CHECK(RingBufChardev, (obj), TYPE_CHARDEV_RINGBUF)
|
||||||
|
|
||||||
|
static size_t ringbuf_count(const Chardev *chr)
|
||||||
|
{
|
||||||
|
const RingBufChardev *d = RINGBUF_CHARDEV(chr);
|
||||||
|
|
||||||
|
return d->prod - d->cons;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
RingBufChardev *d = RINGBUF_CHARDEV(chr);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!buf || (len < 0)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
d->cbuf[d->prod++ & (d->size - 1)] = buf[i];
|
||||||
|
if (d->prod - d->cons > d->size) {
|
||||||
|
d->cons = d->prod - d->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
RingBufChardev *d = RINGBUF_CHARDEV(chr);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
qemu_mutex_lock(&chr->chr_write_lock);
|
||||||
|
for (i = 0; i < len && d->cons != d->prod; i++) {
|
||||||
|
buf[i] = d->cbuf[d->cons++ & (d->size - 1)];
|
||||||
|
}
|
||||||
|
qemu_mutex_unlock(&chr->chr_write_lock);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_ringbuf_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
RingBufChardev *d = RINGBUF_CHARDEV(obj);
|
||||||
|
|
||||||
|
g_free(d->cbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_open_ringbuf(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevRingbuf *opts = backend->u.ringbuf.data;
|
||||||
|
RingBufChardev *d = RINGBUF_CHARDEV(chr);
|
||||||
|
|
||||||
|
d->size = opts->has_size ? opts->size : 65536;
|
||||||
|
|
||||||
|
/* The size must be power of 2 */
|
||||||
|
if (d->size & (d->size - 1)) {
|
||||||
|
error_setg(errp, "size of ringbuf chardev must be power of two");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->prod = 0;
|
||||||
|
d->cons = 0;
|
||||||
|
d->cbuf = g_malloc0(d->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qmp_ringbuf_write(const char *device, const char *data,
|
||||||
|
bool has_format, enum DataFormat format,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
Chardev *chr;
|
||||||
|
const uint8_t *write_data;
|
||||||
|
int ret;
|
||||||
|
gsize write_count;
|
||||||
|
|
||||||
|
chr = qemu_chr_find(device);
|
||||||
|
if (!chr) {
|
||||||
|
error_setg(errp, "Device '%s' not found", device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CHARDEV_IS_RINGBUF(chr)) {
|
||||||
|
error_setg(errp, "%s is not a ringbuf device", device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_format && (format == DATA_FORMAT_BASE64)) {
|
||||||
|
write_data = qbase64_decode(data, -1,
|
||||||
|
&write_count,
|
||||||
|
errp);
|
||||||
|
if (!write_data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
write_data = (uint8_t *)data;
|
||||||
|
write_count = strlen(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ringbuf_chr_write(chr, write_data, write_count);
|
||||||
|
|
||||||
|
if (write_data != (uint8_t *)data) {
|
||||||
|
g_free((void *)write_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Failed to write to device %s", device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *qmp_ringbuf_read(const char *device, int64_t size,
|
||||||
|
bool has_format, enum DataFormat format,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
Chardev *chr;
|
||||||
|
uint8_t *read_data;
|
||||||
|
size_t count;
|
||||||
|
char *data;
|
||||||
|
|
||||||
|
chr = qemu_chr_find(device);
|
||||||
|
if (!chr) {
|
||||||
|
error_setg(errp, "Device '%s' not found", device);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CHARDEV_IS_RINGBUF(chr)) {
|
||||||
|
error_setg(errp, "%s is not a ringbuf device", device);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size <= 0) {
|
||||||
|
error_setg(errp, "size must be greater than zero");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = ringbuf_count(chr);
|
||||||
|
size = size > count ? count : size;
|
||||||
|
read_data = g_malloc(size + 1);
|
||||||
|
|
||||||
|
ringbuf_chr_read(chr, read_data, size);
|
||||||
|
|
||||||
|
if (has_format && (format == DATA_FORMAT_BASE64)) {
|
||||||
|
data = g_base64_encode(read_data, size);
|
||||||
|
g_free(read_data);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* FIXME should read only complete, valid UTF-8 characters up
|
||||||
|
* to @size bytes. Invalid sequences should be replaced by a
|
||||||
|
* suitable replacement character. Except when (and only
|
||||||
|
* when) ring buffer lost characters since last read, initial
|
||||||
|
* continuation characters should be dropped.
|
||||||
|
*/
|
||||||
|
read_data[size] = 0;
|
||||||
|
data = (char *)read_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
ChardevRingbuf *ringbuf;
|
||||||
|
|
||||||
|
backend->type = CHARDEV_BACKEND_KIND_RINGBUF;
|
||||||
|
ringbuf = backend->u.ringbuf.data = g_new0(ChardevRingbuf, 1);
|
||||||
|
qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf));
|
||||||
|
|
||||||
|
val = qemu_opt_get_size(opts, "size", 0);
|
||||||
|
if (val != 0) {
|
||||||
|
ringbuf->has_size = true;
|
||||||
|
ringbuf->size = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_ringbuf_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->parse = qemu_chr_parse_ringbuf;
|
||||||
|
cc->open = qemu_chr_open_ringbuf;
|
||||||
|
cc->chr_write = ringbuf_chr_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_ringbuf_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_RINGBUF,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.class_init = char_ringbuf_class_init,
|
||||||
|
.instance_size = sizeof(RingBufChardev),
|
||||||
|
.instance_finalize = char_ringbuf_finalize,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Bug-compatibility: */
|
||||||
|
static const TypeInfo char_memory_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_MEMORY,
|
||||||
|
.parent = TYPE_CHARDEV_RINGBUF,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_ringbuf_type_info);
|
||||||
|
type_register_static(&char_memory_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
318
chardev/char-serial.c
Normal file
318
chardev/char-serial.c
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/sockets.h"
|
||||||
|
#include "io/channel-file.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "char-win.h"
|
||||||
|
#else
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include "char-fd.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "char-serial.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
static void qmp_chardev_open_serial(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevHostdev *serial = backend->u.serial.data;
|
||||||
|
|
||||||
|
win_chr_init(chr, serial->device, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|
||||||
|
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
|
||||||
|
|| defined(__GLIBC__)
|
||||||
|
|
||||||
|
static void tty_serial_init(int fd, int speed,
|
||||||
|
int parity, int data_bits, int stop_bits)
|
||||||
|
{
|
||||||
|
struct termios tty;
|
||||||
|
speed_t spd;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
|
||||||
|
speed, parity, data_bits, stop_bits);
|
||||||
|
#endif
|
||||||
|
tcgetattr(fd, &tty);
|
||||||
|
|
||||||
|
#define check_speed(val) if (speed <= val) { spd = B##val; break; }
|
||||||
|
speed = speed * 10 / 11;
|
||||||
|
do {
|
||||||
|
check_speed(50);
|
||||||
|
check_speed(75);
|
||||||
|
check_speed(110);
|
||||||
|
check_speed(134);
|
||||||
|
check_speed(150);
|
||||||
|
check_speed(200);
|
||||||
|
check_speed(300);
|
||||||
|
check_speed(600);
|
||||||
|
check_speed(1200);
|
||||||
|
check_speed(1800);
|
||||||
|
check_speed(2400);
|
||||||
|
check_speed(4800);
|
||||||
|
check_speed(9600);
|
||||||
|
check_speed(19200);
|
||||||
|
check_speed(38400);
|
||||||
|
/* Non-Posix values follow. They may be unsupported on some systems. */
|
||||||
|
check_speed(57600);
|
||||||
|
check_speed(115200);
|
||||||
|
#ifdef B230400
|
||||||
|
check_speed(230400);
|
||||||
|
#endif
|
||||||
|
#ifdef B460800
|
||||||
|
check_speed(460800);
|
||||||
|
#endif
|
||||||
|
#ifdef B500000
|
||||||
|
check_speed(500000);
|
||||||
|
#endif
|
||||||
|
#ifdef B576000
|
||||||
|
check_speed(576000);
|
||||||
|
#endif
|
||||||
|
#ifdef B921600
|
||||||
|
check_speed(921600);
|
||||||
|
#endif
|
||||||
|
#ifdef B1000000
|
||||||
|
check_speed(1000000);
|
||||||
|
#endif
|
||||||
|
#ifdef B1152000
|
||||||
|
check_speed(1152000);
|
||||||
|
#endif
|
||||||
|
#ifdef B1500000
|
||||||
|
check_speed(1500000);
|
||||||
|
#endif
|
||||||
|
#ifdef B2000000
|
||||||
|
check_speed(2000000);
|
||||||
|
#endif
|
||||||
|
#ifdef B2500000
|
||||||
|
check_speed(2500000);
|
||||||
|
#endif
|
||||||
|
#ifdef B3000000
|
||||||
|
check_speed(3000000);
|
||||||
|
#endif
|
||||||
|
#ifdef B3500000
|
||||||
|
check_speed(3500000);
|
||||||
|
#endif
|
||||||
|
#ifdef B4000000
|
||||||
|
check_speed(4000000);
|
||||||
|
#endif
|
||||||
|
spd = B115200;
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
cfsetispeed(&tty, spd);
|
||||||
|
cfsetospeed(&tty, spd);
|
||||||
|
|
||||||
|
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
|
||||||
|
| INLCR | IGNCR | ICRNL | IXON);
|
||||||
|
tty.c_oflag |= OPOST;
|
||||||
|
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
|
||||||
|
tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB);
|
||||||
|
switch (data_bits) {
|
||||||
|
default:
|
||||||
|
case 8:
|
||||||
|
tty.c_cflag |= CS8;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
tty.c_cflag |= CS7;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
tty.c_cflag |= CS6;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
tty.c_cflag |= CS5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (parity) {
|
||||||
|
default:
|
||||||
|
case 'N':
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
tty.c_cflag |= PARENB;
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
tty.c_cflag |= PARENB | PARODD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (stop_bits == 2) {
|
||||||
|
tty.c_cflag |= CSTOPB;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcsetattr(fd, TCSANOW, &tty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
|
||||||
|
{
|
||||||
|
FDChardev *s = FD_CHARDEV(chr);
|
||||||
|
QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CHR_IOCTL_SERIAL_SET_PARAMS:
|
||||||
|
{
|
||||||
|
QEMUSerialSetParams *ssp = arg;
|
||||||
|
tty_serial_init(fioc->fd,
|
||||||
|
ssp->speed, ssp->parity,
|
||||||
|
ssp->data_bits, ssp->stop_bits);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_SERIAL_SET_BREAK:
|
||||||
|
{
|
||||||
|
int enable = *(int *)arg;
|
||||||
|
if (enable) {
|
||||||
|
tcsendbreak(fioc->fd, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_SERIAL_GET_TIOCM:
|
||||||
|
{
|
||||||
|
int sarg = 0;
|
||||||
|
int *targ = (int *)arg;
|
||||||
|
ioctl(fioc->fd, TIOCMGET, &sarg);
|
||||||
|
*targ = 0;
|
||||||
|
if (sarg & TIOCM_CTS) {
|
||||||
|
*targ |= CHR_TIOCM_CTS;
|
||||||
|
}
|
||||||
|
if (sarg & TIOCM_CAR) {
|
||||||
|
*targ |= CHR_TIOCM_CAR;
|
||||||
|
}
|
||||||
|
if (sarg & TIOCM_DSR) {
|
||||||
|
*targ |= CHR_TIOCM_DSR;
|
||||||
|
}
|
||||||
|
if (sarg & TIOCM_RI) {
|
||||||
|
*targ |= CHR_TIOCM_RI;
|
||||||
|
}
|
||||||
|
if (sarg & TIOCM_DTR) {
|
||||||
|
*targ |= CHR_TIOCM_DTR;
|
||||||
|
}
|
||||||
|
if (sarg & TIOCM_RTS) {
|
||||||
|
*targ |= CHR_TIOCM_RTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHR_IOCTL_SERIAL_SET_TIOCM:
|
||||||
|
{
|
||||||
|
int sarg = *(int *)arg;
|
||||||
|
int targ = 0;
|
||||||
|
ioctl(fioc->fd, TIOCMGET, &targ);
|
||||||
|
targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
|
||||||
|
| CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
|
||||||
|
if (sarg & CHR_TIOCM_CTS) {
|
||||||
|
targ |= TIOCM_CTS;
|
||||||
|
}
|
||||||
|
if (sarg & CHR_TIOCM_CAR) {
|
||||||
|
targ |= TIOCM_CAR;
|
||||||
|
}
|
||||||
|
if (sarg & CHR_TIOCM_DSR) {
|
||||||
|
targ |= TIOCM_DSR;
|
||||||
|
}
|
||||||
|
if (sarg & CHR_TIOCM_RI) {
|
||||||
|
targ |= TIOCM_RI;
|
||||||
|
}
|
||||||
|
if (sarg & CHR_TIOCM_DTR) {
|
||||||
|
targ |= TIOCM_DTR;
|
||||||
|
}
|
||||||
|
if (sarg & CHR_TIOCM_RTS) {
|
||||||
|
targ |= TIOCM_RTS;
|
||||||
|
}
|
||||||
|
ioctl(fioc->fd, TIOCMSET, &targ);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmp_chardev_open_serial(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevHostdev *serial = backend->u.serial.data;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
|
||||||
|
if (fd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qemu_set_nonblock(fd);
|
||||||
|
tty_serial_init(fd, 115200, 'N', 8, 1);
|
||||||
|
|
||||||
|
qemu_chr_open_fd(chr, fd, fd);
|
||||||
|
}
|
||||||
|
#endif /* __linux__ || __sun__ */
|
||||||
|
|
||||||
|
#ifdef HAVE_CHARDEV_SERIAL
|
||||||
|
static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
const char *device = qemu_opt_get(opts, "path");
|
||||||
|
ChardevHostdev *serial;
|
||||||
|
|
||||||
|
if (device == NULL) {
|
||||||
|
error_setg(errp, "chardev: serial/tty: no device path given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backend->type = CHARDEV_BACKEND_KIND_SERIAL;
|
||||||
|
serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
|
||||||
|
qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
|
||||||
|
serial->device = g_strdup(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_serial_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->parse = qemu_chr_parse_serial;
|
||||||
|
cc->open = qmp_chardev_open_serial;
|
||||||
|
#ifndef _WIN32
|
||||||
|
cc->chr_ioctl = tty_serial_ioctl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const TypeInfo char_serial_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_SERIAL,
|
||||||
|
#ifdef _WIN32
|
||||||
|
.parent = TYPE_CHARDEV_WIN,
|
||||||
|
#else
|
||||||
|
.parent = TYPE_CHARDEV_FD,
|
||||||
|
#endif
|
||||||
|
.class_init = char_serial_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_serial_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
||||||
|
|
||||||
|
#endif
|
35
chardev/char-serial.h
Normal file
35
chardev/char-serial.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CHAR_SERIAL_H
|
||||||
|
#define CHAR_SERIAL_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define HAVE_CHARDEV_SERIAL 1
|
||||||
|
#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|
||||||
|
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
|
||||||
|
|| defined(__GLIBC__)
|
||||||
|
#define HAVE_CHARDEV_SERIAL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
1017
chardev/char-socket.c
Normal file
1017
chardev/char-socket.c
Normal file
File diff suppressed because it is too large
Load Diff
164
chardev/char-stdio.c
Normal file
164
chardev/char-stdio.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/sockets.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "char-win.h"
|
||||||
|
#include "char-win-stdio.h"
|
||||||
|
#else
|
||||||
|
#include <termios.h>
|
||||||
|
#include "char-fd.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
/* init terminal so that we can grab keys */
|
||||||
|
static struct termios oldtty;
|
||||||
|
static int old_fd0_flags;
|
||||||
|
static bool stdio_in_use;
|
||||||
|
static bool stdio_allow_signal;
|
||||||
|
static bool stdio_echo_state;
|
||||||
|
|
||||||
|
static void term_exit(void)
|
||||||
|
{
|
||||||
|
tcsetattr(0, TCSANOW, &oldtty);
|
||||||
|
fcntl(0, F_SETFL, old_fd0_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo)
|
||||||
|
{
|
||||||
|
struct termios tty;
|
||||||
|
|
||||||
|
stdio_echo_state = echo;
|
||||||
|
tty = oldtty;
|
||||||
|
if (!echo) {
|
||||||
|
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
|
||||||
|
| INLCR | IGNCR | ICRNL | IXON);
|
||||||
|
tty.c_oflag |= OPOST;
|
||||||
|
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
|
||||||
|
tty.c_cflag &= ~(CSIZE | PARENB);
|
||||||
|
tty.c_cflag |= CS8;
|
||||||
|
tty.c_cc[VMIN] = 1;
|
||||||
|
tty.c_cc[VTIME] = 0;
|
||||||
|
}
|
||||||
|
if (!stdio_allow_signal) {
|
||||||
|
tty.c_lflag &= ~ISIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcsetattr(0, TCSANOW, &tty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void term_stdio_handler(int sig)
|
||||||
|
{
|
||||||
|
/* restore echo after resume from suspend. */
|
||||||
|
qemu_chr_set_echo_stdio(NULL, stdio_echo_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_open_stdio(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevStdio *opts = backend->u.stdio.data;
|
||||||
|
struct sigaction act;
|
||||||
|
|
||||||
|
if (is_daemonized()) {
|
||||||
|
error_setg(errp, "cannot use stdio with -daemonize");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdio_in_use) {
|
||||||
|
error_setg(errp, "cannot use stdio by multiple character devices");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stdio_in_use = true;
|
||||||
|
old_fd0_flags = fcntl(0, F_GETFL);
|
||||||
|
tcgetattr(0, &oldtty);
|
||||||
|
qemu_set_nonblock(0);
|
||||||
|
atexit(term_exit);
|
||||||
|
|
||||||
|
memset(&act, 0, sizeof(act));
|
||||||
|
act.sa_handler = term_stdio_handler;
|
||||||
|
sigaction(SIGCONT, &act, NULL);
|
||||||
|
|
||||||
|
qemu_chr_open_fd(chr, 0, 1);
|
||||||
|
|
||||||
|
if (opts->has_signal) {
|
||||||
|
stdio_allow_signal = opts->signal;
|
||||||
|
}
|
||||||
|
qemu_chr_set_echo_stdio(chr, false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevStdio *stdio;
|
||||||
|
|
||||||
|
backend->type = CHARDEV_BACKEND_KIND_STDIO;
|
||||||
|
stdio = backend->u.stdio.data = g_new0(ChardevStdio, 1);
|
||||||
|
qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio));
|
||||||
|
stdio->has_signal = true;
|
||||||
|
stdio->signal = qemu_opt_get_bool(opts, "signal", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_stdio_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->parse = qemu_chr_parse_stdio;
|
||||||
|
#ifndef _WIN32
|
||||||
|
cc->open = qemu_chr_open_stdio;
|
||||||
|
cc->chr_set_echo = qemu_chr_set_echo_stdio;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_stdio_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
term_exit();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_stdio_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_STDIO,
|
||||||
|
#ifdef _WIN32
|
||||||
|
.parent = TYPE_CHARDEV_WIN_STDIO,
|
||||||
|
#else
|
||||||
|
.parent = TYPE_CHARDEV_FD,
|
||||||
|
#endif
|
||||||
|
.instance_finalize = char_stdio_finalize,
|
||||||
|
.class_init = char_stdio_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_stdio_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
233
chardev/char-udp.c
Normal file
233
chardev/char-udp.c
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
#include "io/channel-socket.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "char-io.h"
|
||||||
|
|
||||||
|
/***********************************************************/
|
||||||
|
/* UDP Net console */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Chardev parent;
|
||||||
|
QIOChannel *ioc;
|
||||||
|
uint8_t buf[CHR_READ_BUF_LEN];
|
||||||
|
int bufcnt;
|
||||||
|
int bufptr;
|
||||||
|
int max_size;
|
||||||
|
} UdpChardev;
|
||||||
|
|
||||||
|
#define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP)
|
||||||
|
|
||||||
|
/* Called with chr_write_lock held. */
|
||||||
|
static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
UdpChardev *s = UDP_CHARDEV(chr);
|
||||||
|
|
||||||
|
return qio_channel_write(
|
||||||
|
s->ioc, (const char *)buf, len, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int udp_chr_read_poll(void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
UdpChardev *s = UDP_CHARDEV(opaque);
|
||||||
|
|
||||||
|
s->max_size = qemu_chr_be_can_write(chr);
|
||||||
|
|
||||||
|
/* If there were any stray characters in the queue process them
|
||||||
|
* first
|
||||||
|
*/
|
||||||
|
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
|
||||||
|
qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
|
||||||
|
s->bufptr++;
|
||||||
|
s->max_size = qemu_chr_be_can_write(chr);
|
||||||
|
}
|
||||||
|
return s->max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
UdpChardev *s = UDP_CHARDEV(opaque);
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
if (s->max_size == 0) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
ret = qio_channel_read(
|
||||||
|
s->ioc, (char *)s->buf, sizeof(s->buf), NULL);
|
||||||
|
if (ret <= 0) {
|
||||||
|
remove_fd_in_watch(chr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
s->bufcnt = ret;
|
||||||
|
|
||||||
|
s->bufptr = 0;
|
||||||
|
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
|
||||||
|
qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
|
||||||
|
s->bufptr++;
|
||||||
|
s->max_size = qemu_chr_be_can_write(chr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void udp_chr_update_read_handler(Chardev *chr,
|
||||||
|
GMainContext *context)
|
||||||
|
{
|
||||||
|
UdpChardev *s = UDP_CHARDEV(chr);
|
||||||
|
|
||||||
|
remove_fd_in_watch(chr);
|
||||||
|
if (s->ioc) {
|
||||||
|
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
||||||
|
udp_chr_read_poll,
|
||||||
|
udp_chr_read, chr,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_udp_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(obj);
|
||||||
|
UdpChardev *s = UDP_CHARDEV(obj);
|
||||||
|
|
||||||
|
remove_fd_in_watch(chr);
|
||||||
|
if (s->ioc) {
|
||||||
|
object_unref(OBJECT(s->ioc));
|
||||||
|
}
|
||||||
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
const char *host = qemu_opt_get(opts, "host");
|
||||||
|
const char *port = qemu_opt_get(opts, "port");
|
||||||
|
const char *localaddr = qemu_opt_get(opts, "localaddr");
|
||||||
|
const char *localport = qemu_opt_get(opts, "localport");
|
||||||
|
bool has_local = false;
|
||||||
|
SocketAddress *addr;
|
||||||
|
ChardevUdp *udp;
|
||||||
|
|
||||||
|
backend->type = CHARDEV_BACKEND_KIND_UDP;
|
||||||
|
if (host == NULL || strlen(host) == 0) {
|
||||||
|
host = "localhost";
|
||||||
|
}
|
||||||
|
if (port == NULL || strlen(port) == 0) {
|
||||||
|
error_setg(errp, "chardev: udp: remote port not specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (localport == NULL || strlen(localport) == 0) {
|
||||||
|
localport = "0";
|
||||||
|
} else {
|
||||||
|
has_local = true;
|
||||||
|
}
|
||||||
|
if (localaddr == NULL || strlen(localaddr) == 0) {
|
||||||
|
localaddr = "";
|
||||||
|
} else {
|
||||||
|
has_local = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
udp = backend->u.udp.data = g_new0(ChardevUdp, 1);
|
||||||
|
qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp));
|
||||||
|
|
||||||
|
addr = g_new0(SocketAddress, 1);
|
||||||
|
addr->type = SOCKET_ADDRESS_KIND_INET;
|
||||||
|
addr->u.inet.data = g_new(InetSocketAddress, 1);
|
||||||
|
*addr->u.inet.data = (InetSocketAddress) {
|
||||||
|
.host = g_strdup(host),
|
||||||
|
.port = g_strdup(port),
|
||||||
|
.has_ipv4 = qemu_opt_get(opts, "ipv4"),
|
||||||
|
.ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
|
||||||
|
.has_ipv6 = qemu_opt_get(opts, "ipv6"),
|
||||||
|
.ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
|
||||||
|
};
|
||||||
|
udp->remote = addr;
|
||||||
|
|
||||||
|
if (has_local) {
|
||||||
|
udp->has_local = true;
|
||||||
|
addr = g_new0(SocketAddress, 1);
|
||||||
|
addr->type = SOCKET_ADDRESS_KIND_INET;
|
||||||
|
addr->u.inet.data = g_new(InetSocketAddress, 1);
|
||||||
|
*addr->u.inet.data = (InetSocketAddress) {
|
||||||
|
.host = g_strdup(localaddr),
|
||||||
|
.port = g_strdup(localport),
|
||||||
|
};
|
||||||
|
udp->local = addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qmp_chardev_open_udp(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
ChardevUdp *udp = backend->u.udp.data;
|
||||||
|
QIOChannelSocket *sioc = qio_channel_socket_new();
|
||||||
|
char *name;
|
||||||
|
UdpChardev *s = UDP_CHARDEV(chr);
|
||||||
|
|
||||||
|
if (qio_channel_socket_dgram_sync(sioc,
|
||||||
|
udp->local, udp->remote,
|
||||||
|
errp) < 0) {
|
||||||
|
object_unref(OBJECT(sioc));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = g_strdup_printf("chardev-udp-%s", chr->label);
|
||||||
|
qio_channel_set_name(QIO_CHANNEL(sioc), name);
|
||||||
|
g_free(name);
|
||||||
|
|
||||||
|
s->ioc = QIO_CHANNEL(sioc);
|
||||||
|
/* be isn't opened until we get a connection */
|
||||||
|
*be_opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_udp_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->parse = qemu_chr_parse_udp;
|
||||||
|
cc->open = qmp_chardev_open_udp;
|
||||||
|
cc->chr_write = udp_chr_write;
|
||||||
|
cc->chr_update_read_handler = udp_chr_update_read_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_udp_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_UDP,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(UdpChardev),
|
||||||
|
.instance_finalize = char_udp_finalize,
|
||||||
|
.class_init = char_udp_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_udp_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
266
chardev/char-win-stdio.c
Normal file
266
chardev/char-win-stdio.c
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "char-win.h"
|
||||||
|
#include "char-win-stdio.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Chardev parent;
|
||||||
|
HANDLE hStdIn;
|
||||||
|
HANDLE hInputReadyEvent;
|
||||||
|
HANDLE hInputDoneEvent;
|
||||||
|
HANDLE hInputThread;
|
||||||
|
uint8_t win_stdio_buf;
|
||||||
|
} WinStdioChardev;
|
||||||
|
|
||||||
|
#define WIN_STDIO_CHARDEV(obj) \
|
||||||
|
OBJECT_CHECK(WinStdioChardev, (obj), TYPE_CHARDEV_WIN_STDIO)
|
||||||
|
|
||||||
|
static void win_stdio_wait_func(void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
|
||||||
|
INPUT_RECORD buf[4];
|
||||||
|
int ret;
|
||||||
|
DWORD dwSize;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ret = ReadConsoleInput(stdio->hStdIn, buf, ARRAY_SIZE(buf), &dwSize);
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
/* Avoid error storm */
|
||||||
|
qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < dwSize; i++) {
|
||||||
|
KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent;
|
||||||
|
|
||||||
|
if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) {
|
||||||
|
int j;
|
||||||
|
if (kev->uChar.AsciiChar != 0) {
|
||||||
|
for (j = 0; j < kev->wRepeatCount; j++) {
|
||||||
|
if (qemu_chr_be_can_write(chr)) {
|
||||||
|
uint8_t c = kev->uChar.AsciiChar;
|
||||||
|
qemu_chr_be_write(chr, &c, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD WINAPI win_stdio_thread(LPVOID param)
|
||||||
|
{
|
||||||
|
WinStdioChardev *stdio = WIN_STDIO_CHARDEV(param);
|
||||||
|
int ret;
|
||||||
|
DWORD dwSize;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
/* Wait for one byte */
|
||||||
|
ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL);
|
||||||
|
|
||||||
|
/* Exit in case of error, continue if nothing read */
|
||||||
|
if (!ret) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!dwSize) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some terminal emulator returns \r\n for Enter, just pass \n */
|
||||||
|
if (stdio->win_stdio_buf == '\r') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Signal the main thread and wait until the byte was eaten */
|
||||||
|
if (!SetEvent(stdio->hInputReadyEvent)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE)
|
||||||
|
!= WAIT_OBJECT_0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void win_stdio_thread_wait_func(void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
|
||||||
|
|
||||||
|
if (qemu_chr_be_can_write(chr)) {
|
||||||
|
qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetEvent(stdio->hInputDoneEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
|
||||||
|
{
|
||||||
|
WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
|
||||||
|
DWORD dwMode = 0;
|
||||||
|
|
||||||
|
GetConsoleMode(stdio->hStdIn, &dwMode);
|
||||||
|
|
||||||
|
if (echo) {
|
||||||
|
SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT);
|
||||||
|
} else {
|
||||||
|
SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_chr_open_stdio(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
|
||||||
|
DWORD dwMode;
|
||||||
|
int is_console = 0;
|
||||||
|
|
||||||
|
stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
|
||||||
|
error_setg(errp, "cannot open stdio: invalid handle");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
|
||||||
|
|
||||||
|
if (is_console) {
|
||||||
|
if (qemu_add_wait_object(stdio->hStdIn,
|
||||||
|
win_stdio_wait_func, chr)) {
|
||||||
|
error_setg(errp, "qemu_add_wait_object: failed");
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DWORD dwId;
|
||||||
|
|
||||||
|
stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
if (stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
|
||||||
|
|| stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
|
||||||
|
error_setg(errp, "cannot create event");
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
if (qemu_add_wait_object(stdio->hInputReadyEvent,
|
||||||
|
win_stdio_thread_wait_func, chr)) {
|
||||||
|
error_setg(errp, "qemu_add_wait_object: failed");
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread,
|
||||||
|
chr, 0, &dwId);
|
||||||
|
|
||||||
|
if (stdio->hInputThread == INVALID_HANDLE_VALUE) {
|
||||||
|
error_setg(errp, "cannot create stdio thread");
|
||||||
|
goto err3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dwMode |= ENABLE_LINE_INPUT;
|
||||||
|
|
||||||
|
if (is_console) {
|
||||||
|
/* set the terminal in raw mode */
|
||||||
|
/* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
|
||||||
|
dwMode |= ENABLE_PROCESSED_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetConsoleMode(stdio->hStdIn, dwMode);
|
||||||
|
|
||||||
|
qemu_chr_set_echo_win_stdio(chr, false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err3:
|
||||||
|
qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
|
||||||
|
err2:
|
||||||
|
CloseHandle(stdio->hInputReadyEvent);
|
||||||
|
CloseHandle(stdio->hInputDoneEvent);
|
||||||
|
err1:
|
||||||
|
qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_win_stdio_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj);
|
||||||
|
|
||||||
|
if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(stdio->hInputReadyEvent);
|
||||||
|
}
|
||||||
|
if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(stdio->hInputDoneEvent);
|
||||||
|
}
|
||||||
|
if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
|
||||||
|
TerminateThread(stdio->hInputThread, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
DWORD dwSize;
|
||||||
|
int len1;
|
||||||
|
|
||||||
|
len1 = len;
|
||||||
|
|
||||||
|
while (len1 > 0) {
|
||||||
|
if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf += dwSize;
|
||||||
|
len1 -= dwSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len - len1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_win_stdio_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = qemu_chr_open_stdio;
|
||||||
|
cc->chr_write = win_stdio_write;
|
||||||
|
cc->chr_set_echo = qemu_chr_set_echo_win_stdio;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_win_stdio_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_WIN_STDIO,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(WinStdioChardev),
|
||||||
|
.instance_finalize = char_win_stdio_finalize,
|
||||||
|
.class_init = char_win_stdio_class_init,
|
||||||
|
.abstract = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_win_stdio_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
29
chardev/char-win-stdio.h
Normal file
29
chardev/char-win-stdio.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CHAR_WIN_STDIO_H
|
||||||
|
#define CHAR_WIN_STDIO_H
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_WIN_STDIO "chardev-win-stdio"
|
||||||
|
|
||||||
|
#endif /* CHAR_WIN_STDIO_H */
|
265
chardev/char-win.c
Normal file
265
chardev/char-win.c
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "char-win.h"
|
||||||
|
|
||||||
|
static void win_chr_readfile(Chardev *chr)
|
||||||
|
{
|
||||||
|
WinChardev *s = WIN_CHARDEV(chr);
|
||||||
|
|
||||||
|
int ret, err;
|
||||||
|
uint8_t buf[CHR_READ_BUF_LEN];
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
ZeroMemory(&s->orecv, sizeof(s->orecv));
|
||||||
|
s->orecv.hEvent = s->hrecv;
|
||||||
|
ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
|
||||||
|
if (!ret) {
|
||||||
|
err = GetLastError();
|
||||||
|
if (err == ERROR_IO_PENDING) {
|
||||||
|
ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
qemu_chr_be_write(chr, buf, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void win_chr_read(Chardev *chr)
|
||||||
|
{
|
||||||
|
WinChardev *s = WIN_CHARDEV(chr);
|
||||||
|
|
||||||
|
if (s->len > s->max_size) {
|
||||||
|
s->len = s->max_size;
|
||||||
|
}
|
||||||
|
if (s->len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
win_chr_readfile(chr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int win_chr_read_poll(Chardev *chr)
|
||||||
|
{
|
||||||
|
WinChardev *s = WIN_CHARDEV(chr);
|
||||||
|
|
||||||
|
s->max_size = qemu_chr_be_can_write(chr);
|
||||||
|
return s->max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int win_chr_poll(void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
WinChardev *s = WIN_CHARDEV(opaque);
|
||||||
|
COMSTAT status;
|
||||||
|
DWORD comerr;
|
||||||
|
|
||||||
|
ClearCommError(s->hcom, &comerr, &status);
|
||||||
|
if (status.cbInQue > 0) {
|
||||||
|
s->len = status.cbInQue;
|
||||||
|
win_chr_read_poll(chr);
|
||||||
|
win_chr_read(chr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int win_chr_init(Chardev *chr, const char *filename, Error **errp)
|
||||||
|
{
|
||||||
|
WinChardev *s = WIN_CHARDEV(chr);
|
||||||
|
COMMCONFIG comcfg;
|
||||||
|
COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
|
||||||
|
COMSTAT comstat;
|
||||||
|
DWORD size;
|
||||||
|
DWORD err;
|
||||||
|
|
||||||
|
s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (!s->hsend) {
|
||||||
|
error_setg(errp, "Failed CreateEvent");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (!s->hrecv) {
|
||||||
|
error_setg(errp, "Failed CreateEvent");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->hcom = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
||||||
|
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||||
|
if (s->hcom == INVALID_HANDLE_VALUE) {
|
||||||
|
error_setg(errp, "Failed CreateFile (%lu)", GetLastError());
|
||||||
|
s->hcom = NULL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
|
||||||
|
error_setg(errp, "Failed SetupComm");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory(&comcfg, sizeof(COMMCONFIG));
|
||||||
|
size = sizeof(COMMCONFIG);
|
||||||
|
GetDefaultCommConfig(filename, &comcfg, &size);
|
||||||
|
comcfg.dcb.DCBlength = sizeof(DCB);
|
||||||
|
CommConfigDialog(filename, NULL, &comcfg);
|
||||||
|
|
||||||
|
if (!SetCommState(s->hcom, &comcfg.dcb)) {
|
||||||
|
error_setg(errp, "Failed SetCommState");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetCommMask(s->hcom, EV_ERR)) {
|
||||||
|
error_setg(errp, "Failed SetCommMask");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
cto.ReadIntervalTimeout = MAXDWORD;
|
||||||
|
if (!SetCommTimeouts(s->hcom, &cto)) {
|
||||||
|
error_setg(errp, "Failed SetCommTimeouts");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ClearCommError(s->hcom, &err, &comstat)) {
|
||||||
|
error_setg(errp, "Failed ClearCommError");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
qemu_add_polling_cb(win_chr_poll, chr);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int win_chr_pipe_poll(void *opaque)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
WinChardev *s = WIN_CHARDEV(opaque);
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
|
||||||
|
if (size > 0) {
|
||||||
|
s->len = size;
|
||||||
|
win_chr_read_poll(chr);
|
||||||
|
win_chr_read(chr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called with chr_write_lock held. */
|
||||||
|
static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
|
||||||
|
{
|
||||||
|
WinChardev *s = WIN_CHARDEV(chr);
|
||||||
|
DWORD len, ret, size, err;
|
||||||
|
|
||||||
|
len = len1;
|
||||||
|
ZeroMemory(&s->osend, sizeof(s->osend));
|
||||||
|
s->osend.hEvent = s->hsend;
|
||||||
|
while (len > 0) {
|
||||||
|
if (s->hsend) {
|
||||||
|
ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
|
||||||
|
} else {
|
||||||
|
ret = WriteFile(s->hcom, buf, len, &size, NULL);
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
err = GetLastError();
|
||||||
|
if (err == ERROR_IO_PENDING) {
|
||||||
|
ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
|
||||||
|
if (ret) {
|
||||||
|
buf += size;
|
||||||
|
len -= size;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf += size;
|
||||||
|
len -= size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len1 - len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_win_finalize(Object *obj)
|
||||||
|
{
|
||||||
|
Chardev *chr = CHARDEV(obj);
|
||||||
|
WinChardev *s = WIN_CHARDEV(chr);
|
||||||
|
|
||||||
|
if (s->skip_free) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->hsend) {
|
||||||
|
CloseHandle(s->hsend);
|
||||||
|
}
|
||||||
|
if (s->hrecv) {
|
||||||
|
CloseHandle(s->hrecv);
|
||||||
|
}
|
||||||
|
if (s->hcom) {
|
||||||
|
CloseHandle(s->hcom);
|
||||||
|
}
|
||||||
|
if (s->fpipe) {
|
||||||
|
qemu_del_polling_cb(win_chr_pipe_poll, chr);
|
||||||
|
} else {
|
||||||
|
qemu_del_polling_cb(win_chr_poll, chr);
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out)
|
||||||
|
{
|
||||||
|
WinChardev *s = WIN_CHARDEV(chr);
|
||||||
|
|
||||||
|
s->skip_free = true;
|
||||||
|
s->hcom = fd_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_win_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->chr_write = win_chr_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_win_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_WIN,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(WinChardev),
|
||||||
|
.instance_finalize = char_win_finalize,
|
||||||
|
.class_init = char_win_class_init,
|
||||||
|
.abstract = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_win_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
53
chardev/char-win.h
Normal file
53
chardev/char-win.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* QEMU System Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CHAR_WIN_H
|
||||||
|
#define CHAR_WIN_H
|
||||||
|
|
||||||
|
#include "sysemu/char.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Chardev parent;
|
||||||
|
int max_size;
|
||||||
|
HANDLE hcom, hrecv, hsend;
|
||||||
|
OVERLAPPED orecv;
|
||||||
|
BOOL fpipe;
|
||||||
|
DWORD len;
|
||||||
|
|
||||||
|
/* Protected by the Chardev chr_write_lock. */
|
||||||
|
OVERLAPPED osend;
|
||||||
|
/* FIXME: file/console do not finalize */
|
||||||
|
bool skip_free;
|
||||||
|
} WinChardev;
|
||||||
|
|
||||||
|
#define NSENDBUF 2048
|
||||||
|
#define NRECVBUF 2048
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_WIN "chardev-win"
|
||||||
|
#define WIN_CHARDEV(obj) OBJECT_CHECK(WinChardev, (obj), TYPE_CHARDEV_WIN)
|
||||||
|
|
||||||
|
void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out);
|
||||||
|
int win_chr_init(Chardev *chr, const char *filename, Error **errp);
|
||||||
|
int win_chr_pipe_poll(void *opaque);
|
||||||
|
|
||||||
|
#endif /* CHAR_WIN_H */
|
1334
chardev/char.c
Normal file
1334
chardev/char.c
Normal file
File diff suppressed because it is too large
Load Diff
2
configure
vendored
2
configure
vendored
@@ -1474,7 +1474,7 @@ fi
|
|||||||
|
|
||||||
gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
|
gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
|
||||||
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
|
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
|
||||||
gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
|
gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
|
||||||
gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags"
|
gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags"
|
||||||
gcc_flags="-Wno-initializer-overrides $gcc_flags"
|
gcc_flags="-Wno-initializer-overrides $gcc_flags"
|
||||||
gcc_flags="-Wno-string-plus-int $gcc_flags"
|
gcc_flags="-Wno-string-plus-int $gcc_flags"
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "trace.h"
|
#include "trace-root.h"
|
||||||
#include "disas/disas.h"
|
#include "disas/disas.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg.h"
|
#include "tcg.h"
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
include pci.mak
|
include pci.mak
|
||||||
include usb.mak
|
include usb.mak
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_I8254=y
|
CONFIG_I8254=y
|
||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
CONFIG_VGA_CIRRUS=y
|
CONFIG_VGA_CIRRUS=y
|
||||||
|
@@ -6,6 +6,7 @@ CONFIG_VGA=y
|
|||||||
CONFIG_NAND=y
|
CONFIG_NAND=y
|
||||||
CONFIG_ECC=y
|
CONFIG_ECC=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
CONFIG_SD=y
|
CONFIG_SD=y
|
||||||
CONFIG_MAX7310=y
|
CONFIG_MAX7310=y
|
||||||
@@ -108,6 +109,7 @@ CONFIG_FSL_IMX25=y
|
|||||||
|
|
||||||
CONFIG_IMX_I2C=y
|
CONFIG_IMX_I2C=y
|
||||||
|
|
||||||
|
CONFIG_PCIE_PORT=y
|
||||||
CONFIG_XIO3130=y
|
CONFIG_XIO3130=y
|
||||||
CONFIG_IOH3420=y
|
CONFIG_IOH3420=y
|
||||||
CONFIG_I82801B11=y
|
CONFIG_I82801B11=y
|
||||||
|
@@ -15,6 +15,7 @@ CONFIG_IPMI_EXTERN=y
|
|||||||
CONFIG_ISA_IPMI_KCS=y
|
CONFIG_ISA_IPMI_KCS=y
|
||||||
CONFIG_ISA_IPMI_BT=y
|
CONFIG_ISA_IPMI_BT=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_PARALLEL=y
|
CONFIG_PARALLEL=y
|
||||||
CONFIG_I8254=y
|
CONFIG_I8254=y
|
||||||
CONFIG_PCSPK=y
|
CONFIG_PCSPK=y
|
||||||
@@ -51,8 +52,10 @@ CONFIG_PVPANIC=y
|
|||||||
CONFIG_MEM_HOTPLUG=y
|
CONFIG_MEM_HOTPLUG=y
|
||||||
CONFIG_NVDIMM=y
|
CONFIG_NVDIMM=y
|
||||||
CONFIG_ACPI_NVDIMM=y
|
CONFIG_ACPI_NVDIMM=y
|
||||||
|
CONFIG_PCIE_PORT=y
|
||||||
CONFIG_XIO3130=y
|
CONFIG_XIO3130=y
|
||||||
CONFIG_IOH3420=y
|
CONFIG_IOH3420=y
|
||||||
CONFIG_I82801B11=y
|
CONFIG_I82801B11=y
|
||||||
CONFIG_SMBIOS=y
|
CONFIG_SMBIOS=y
|
||||||
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
|
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
|
||||||
|
CONFIG_PXB=y
|
||||||
|
@@ -9,6 +9,7 @@ CONFIG_VGA_ISA_MM=y
|
|||||||
CONFIG_VGA_CIRRUS=y
|
CONFIG_VGA_CIRRUS=y
|
||||||
CONFIG_VMWARE_VGA=y
|
CONFIG_VMWARE_VGA=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_PARALLEL=y
|
CONFIG_PARALLEL=y
|
||||||
CONFIG_I8254=y
|
CONFIG_I8254=y
|
||||||
CONFIG_PCSPK=y
|
CONFIG_PCSPK=y
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
# Default configuration for moxie-softmmu
|
# Default configuration for moxie-softmmu
|
||||||
|
|
||||||
|
CONFIG_ISA_BUS=y
|
||||||
CONFIG_MC146818RTC=y
|
CONFIG_MC146818RTC=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_VGA=y
|
CONFIG_VGA=y
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
CONFIG_PCI=y
|
CONFIG_PCI=y
|
||||||
|
# For now, CONFIG_IDE_CORE requires ISA, so we enable it here
|
||||||
|
CONFIG_ISA_BUS=y
|
||||||
CONFIG_VIRTIO_PCI=y
|
CONFIG_VIRTIO_PCI=y
|
||||||
CONFIG_VIRTIO=y
|
CONFIG_VIRTIO=y
|
||||||
CONFIG_USB_UHCI=y
|
CONFIG_USB_UHCI=y
|
||||||
@@ -27,6 +29,7 @@ CONFIG_AHCI=y
|
|||||||
CONFIG_ESP=y
|
CONFIG_ESP=y
|
||||||
CONFIG_ESP_PCI=y
|
CONFIG_ESP_PCI=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_SERIAL_PCI=y
|
CONFIG_SERIAL_PCI=y
|
||||||
CONFIG_IPACK=y
|
CONFIG_IPACK=y
|
||||||
CONFIG_WDT_IB6300ESB=y
|
CONFIG_WDT_IB6300ESB=y
|
||||||
|
@@ -18,6 +18,7 @@ CONFIG_I82378=y
|
|||||||
CONFIG_PC87312=y
|
CONFIG_PC87312=y
|
||||||
CONFIG_MACIO=y
|
CONFIG_MACIO=y
|
||||||
CONFIG_PCSPK=y
|
CONFIG_PCSPK=y
|
||||||
|
CONFIG_CS4231A=y
|
||||||
CONFIG_CUDA=y
|
CONFIG_CUDA=y
|
||||||
CONFIG_ADB=y
|
CONFIG_ADB=y
|
||||||
CONFIG_MAC_NVRAM=y
|
CONFIG_MAC_NVRAM=y
|
||||||
@@ -45,5 +46,7 @@ CONFIG_PLATFORM_BUS=y
|
|||||||
CONFIG_ETSEC=y
|
CONFIG_ETSEC=y
|
||||||
CONFIG_LIBDECNUMBER=y
|
CONFIG_LIBDECNUMBER=y
|
||||||
# For PReP
|
# For PReP
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_MC146818RTC=y
|
CONFIG_MC146818RTC=y
|
||||||
CONFIG_ISA_TESTDEV=y
|
CONFIG_ISA_TESTDEV=y
|
||||||
|
CONFIG_RS6000_MC=y
|
||||||
|
@@ -52,6 +52,8 @@ CONFIG_XICS=$(CONFIG_PSERIES)
|
|||||||
CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
|
CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
|
||||||
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||||
# For PReP
|
# For PReP
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_MC146818RTC=y
|
CONFIG_MC146818RTC=y
|
||||||
CONFIG_ISA_TESTDEV=y
|
CONFIG_ISA_TESTDEV=y
|
||||||
CONFIG_MEM_HOTPLUG=y
|
CONFIG_MEM_HOTPLUG=y
|
||||||
|
CONFIG_RS6000_MC=y
|
||||||
|
@@ -5,6 +5,7 @@ include sound.mak
|
|||||||
include usb.mak
|
include usb.mak
|
||||||
CONFIG_M48T59=y
|
CONFIG_M48T59=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_OPENPIC=y
|
CONFIG_OPENPIC=y
|
||||||
CONFIG_PFLASH_CFI01=y
|
CONFIG_PFLASH_CFI01=y
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
include pci.mak
|
include pci.mak
|
||||||
include usb.mak
|
include usb.mak
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
CONFIG_PFLASH_CFI02=y
|
CONFIG_PFLASH_CFI02=y
|
||||||
CONFIG_SH4=y
|
CONFIG_SH4=y
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
include pci.mak
|
include pci.mak
|
||||||
include usb.mak
|
include usb.mak
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
CONFIG_PFLASH_CFI02=y
|
CONFIG_PFLASH_CFI02=y
|
||||||
CONFIG_SH4=y
|
CONFIG_SH4=y
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
# Default configuration for sparc-softmmu
|
# Default configuration for sparc-softmmu
|
||||||
|
|
||||||
|
CONFIG_ISA_BUS=y
|
||||||
CONFIG_ECC=y
|
CONFIG_ECC=y
|
||||||
CONFIG_ESP=y
|
CONFIG_ESP=y
|
||||||
CONFIG_ESCC=y
|
CONFIG_ESCC=y
|
||||||
|
@@ -5,6 +5,7 @@ include usb.mak
|
|||||||
CONFIG_M48T59=y
|
CONFIG_M48T59=y
|
||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_PARALLEL=y
|
CONFIG_PARALLEL=y
|
||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
# Default configuration for unicore32-softmmu
|
# Default configuration for unicore32-softmmu
|
||||||
|
CONFIG_ISA_BUS=y
|
||||||
CONFIG_PUV3=y
|
CONFIG_PUV3=y
|
||||||
CONFIG_PTIMER=y
|
CONFIG_PTIMER=y
|
||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
|
@@ -15,6 +15,7 @@ CONFIG_IPMI_EXTERN=y
|
|||||||
CONFIG_ISA_IPMI_KCS=y
|
CONFIG_ISA_IPMI_KCS=y
|
||||||
CONFIG_ISA_IPMI_BT=y
|
CONFIG_ISA_IPMI_BT=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_SERIAL_ISA=y
|
||||||
CONFIG_PARALLEL=y
|
CONFIG_PARALLEL=y
|
||||||
CONFIG_I8254=y
|
CONFIG_I8254=y
|
||||||
CONFIG_PCSPK=y
|
CONFIG_PCSPK=y
|
||||||
@@ -51,8 +52,10 @@ CONFIG_PVPANIC=y
|
|||||||
CONFIG_MEM_HOTPLUG=y
|
CONFIG_MEM_HOTPLUG=y
|
||||||
CONFIG_NVDIMM=y
|
CONFIG_NVDIMM=y
|
||||||
CONFIG_ACPI_NVDIMM=y
|
CONFIG_ACPI_NVDIMM=y
|
||||||
|
CONFIG_PCIE_PORT=y
|
||||||
CONFIG_XIO3130=y
|
CONFIG_XIO3130=y
|
||||||
CONFIG_IOH3420=y
|
CONFIG_IOH3420=y
|
||||||
CONFIG_I82801B11=y
|
CONFIG_I82801B11=y
|
||||||
CONFIG_SMBIOS=y
|
CONFIG_SMBIOS=y
|
||||||
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
|
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
|
||||||
|
CONFIG_PXB=y
|
||||||
|
1
disas.c
1
disas.c
@@ -190,6 +190,7 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
|||||||
|
|
||||||
s.cpu = cpu;
|
s.cpu = cpu;
|
||||||
s.info.read_memory_func = target_read_memory;
|
s.info.read_memory_func = target_read_memory;
|
||||||
|
s.info.read_memory_inner_func = NULL;
|
||||||
s.info.buffer_vma = code;
|
s.info.buffer_vma = code;
|
||||||
s.info.buffer_length = size;
|
s.info.buffer_length = size;
|
||||||
s.info.print_address_func = generic_print_address;
|
s.info.print_address_func = generic_print_address;
|
||||||
|
12
disas/ppc.c
12
disas/ppc.c
@@ -1653,11 +1653,11 @@ extract_tbr (unsigned long insn,
|
|||||||
#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
|
#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
|
||||||
#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK)
|
#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK)
|
||||||
|
|
||||||
/* An Context form instruction. */
|
/* A Context form instruction. */
|
||||||
#define CTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7))
|
#define CTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7))
|
||||||
#define CTX_MASK CTX(0x3f, 0x7)
|
#define CTX_MASK CTX(0x3f, 0x7)
|
||||||
|
|
||||||
/* An User Context form instruction. */
|
/* A User Context form instruction. */
|
||||||
#define UCTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f))
|
#define UCTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f))
|
||||||
#define UCTX_MASK UCTX(0x3f, 0x1f)
|
#define UCTX_MASK UCTX(0x3f, 0x1f)
|
||||||
|
|
||||||
@@ -1710,19 +1710,19 @@ extract_tbr (unsigned long insn,
|
|||||||
#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1))
|
#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1))
|
||||||
#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1)
|
#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1)
|
||||||
|
|
||||||
/* An VX form instruction. */
|
/* A VX form instruction. */
|
||||||
#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff))
|
#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff))
|
||||||
|
|
||||||
/* The mask for an VX form instruction. */
|
/* The mask for an VX form instruction. */
|
||||||
#define VX_MASK VX(0x3f, 0x7ff)
|
#define VX_MASK VX(0x3f, 0x7ff)
|
||||||
|
|
||||||
/* An VA form instruction. */
|
/* A VA form instruction. */
|
||||||
#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f))
|
#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f))
|
||||||
|
|
||||||
/* The mask for an VA form instruction. */
|
/* The mask for a VA form instruction. */
|
||||||
#define VXA_MASK VXA(0x3f, 0x3f)
|
#define VXA_MASK VXA(0x3f, 0x3f)
|
||||||
|
|
||||||
/* An VXR form instruction. */
|
/* A VXR form instruction. */
|
||||||
#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff))
|
#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff))
|
||||||
|
|
||||||
/* The mask for a VXR form instruction. */
|
/* The mask for a VXR form instruction. */
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
#include "sysemu/dma.h"
|
#include "sysemu/dma.h"
|
||||||
#include "trace.h"
|
#include "trace-root.h"
|
||||||
#include "qemu/thread.h"
|
#include "qemu/thread.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
|
|
||||||
|
@@ -27,18 +27,44 @@ for debugging, profiling, and observing execution.
|
|||||||
|
|
||||||
== Trace events ==
|
== Trace events ==
|
||||||
|
|
||||||
|
=== Sub-directory setup ===
|
||||||
|
|
||||||
Each directory in the source tree can declare a set of static trace events
|
Each directory in the source tree can declare a set of static trace events
|
||||||
in a "trace-events" file. Each trace event declaration names the event, its
|
in a local "trace-events" file. All directories which contain "trace-events"
|
||||||
arguments, and the format string which can be used for pretty-printing:
|
files must be listed in the "trace-events-subdirs" make variable in the top
|
||||||
|
level Makefile.objs. During build, the "trace-events" file in each listed
|
||||||
|
subdirectory will be processed by the "tracetool" script to generate code for
|
||||||
|
the trace events.
|
||||||
|
|
||||||
qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p"
|
The individual "trace-events" files are merged into a "trace-events-all" file,
|
||||||
qemu_vfree(void *ptr) "ptr %p"
|
which is also installed into "/usr/share/qemu" with the name "trace-events".
|
||||||
|
This merged file is to be used by the "simpletrace.py" script to later analyse
|
||||||
|
traces in the simpletrace data format.
|
||||||
|
|
||||||
All "trace-events" files must be listed in the "trace-event-y" make variable
|
In the sub-directory the following files will be automatically generated
|
||||||
in the top level Makefile.objs. During build the individual files are combined
|
|
||||||
to create a "trace-events-all" file, which is processed by the "tracetool"
|
- trace.c - the trace event state declarations
|
||||||
script during build to generate code for the trace events. The
|
- trace.h - the trace event enums and probe functions
|
||||||
"trace-events-all" file is also installed into "/usr/share/qemu".
|
- trace-dtrace.h - DTrace event probe specification
|
||||||
|
- trace-dtrace.dtrace - DTrace event probe helper declaration
|
||||||
|
- trace-dtrace.o - binary DTrace provider (generated by dtrace)
|
||||||
|
- trace-ust.h - UST event probe helper declarations
|
||||||
|
|
||||||
|
Source files in the sub-directory should #include the local 'trace.h' file,
|
||||||
|
without any sub-directory path prefix. eg io/channel-buffer.c would do
|
||||||
|
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
To access the 'io/trace.h' file. While it is possible to include a trace.h
|
||||||
|
file from outside a source files' own sub-directory, this is discouraged in
|
||||||
|
general. It is strongly preferred that all events be declared directly in
|
||||||
|
the sub-directory that uses them. The only exception is where there are some
|
||||||
|
shared trace events defined in the top level directory trace-events file.
|
||||||
|
The top level directory generates trace files with a filename prefix of
|
||||||
|
"trace-root" instead of just "trace". This is to avoid ambiguity between
|
||||||
|
a trace.h in the current directory, vs the top level directory.
|
||||||
|
|
||||||
|
=== Using trace events ===
|
||||||
|
|
||||||
Trace events are invoked directly from source code like this:
|
Trace events are invoked directly from source code like this:
|
||||||
|
|
||||||
@@ -83,6 +109,13 @@ Format strings should reflect the types defined in the trace event. Take
|
|||||||
special care to use PRId64 and PRIu64 for int64_t and uint64_t types,
|
special care to use PRId64 and PRIu64 for int64_t and uint64_t types,
|
||||||
respectively. This ensures portability between 32- and 64-bit platforms.
|
respectively. This ensures portability between 32- and 64-bit platforms.
|
||||||
|
|
||||||
|
Each event declaration will start with the event name, then its arguments,
|
||||||
|
finally a format string for pretty-printing. For example:
|
||||||
|
|
||||||
|
qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p"
|
||||||
|
qemu_vfree(void *ptr) "ptr %p"
|
||||||
|
|
||||||
|
|
||||||
=== Hints for adding new trace events ===
|
=== Hints for adding new trace events ===
|
||||||
|
|
||||||
1. Trace state changes in the code. Interesting points in the code usually
|
1. Trace state changes in the code. Interesting points in the code usually
|
||||||
|
3
exec.c
3
exec.c
@@ -44,7 +44,7 @@
|
|||||||
#include "sysemu/dma.h"
|
#include "sysemu/dma.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "sysemu/xen-mapcache.h"
|
#include "sysemu/xen-mapcache.h"
|
||||||
#include "trace.h"
|
#include "trace-root.h"
|
||||||
#endif
|
#endif
|
||||||
#include "exec/cpu-all.h"
|
#include "exec/cpu-all.h"
|
||||||
#include "qemu/rcu_queue.h"
|
#include "qemu/rcu_queue.h"
|
||||||
@@ -2115,6 +2115,7 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
|
vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
|
||||||
|
vaddr = cc->adjust_watchpoint_address(cpu, vaddr, len);
|
||||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||||
if (cpu_watchpoint_address_matches(wp, vaddr, len)
|
if (cpu_watchpoint_address_matches(wp, vaddr, len)
|
||||||
&& (wp->flags & flags)) {
|
&& (wp->flags & flags)) {
|
||||||
|
@@ -185,7 +185,7 @@ float128 float128_default_nan(float_status *status)
|
|||||||
r.high = LIT64(0x7FFF7FFFFFFFFFFF);
|
r.high = LIT64(0x7FFF7FFFFFFFFFFF);
|
||||||
} else {
|
} else {
|
||||||
r.low = LIT64(0x0000000000000000);
|
r.low = LIT64(0x0000000000000000);
|
||||||
#if defined(TARGET_S390X)
|
#if defined(TARGET_S390X) || defined(TARGET_PPC)
|
||||||
r.high = LIT64(0x7FFF800000000000);
|
r.high = LIT64(0x7FFF800000000000);
|
||||||
#else
|
#else
|
||||||
r.high = LIT64(0xFFFF800000000000);
|
r.high = LIT64(0xFFFF800000000000);
|
||||||
|
1
hmp.c
1
hmp.c
@@ -19,6 +19,7 @@
|
|||||||
#include "net/eth.h"
|
#include "net/eth.h"
|
||||||
#include "sysemu/char.h"
|
#include "sysemu/char.h"
|
||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/option.h"
|
#include "qemu/option.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
|
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
|
||||||
#define ASPEED_SOC_SRAM_BASE 0x1E720000
|
#define ASPEED_SOC_SRAM_BASE 0x1E720000
|
||||||
#define ASPEED_SOC_TIMER_BASE 0x1E782000
|
#define ASPEED_SOC_TIMER_BASE 0x1E782000
|
||||||
|
#define ASPEED_SOC_WDT_BASE 0x1E785000
|
||||||
#define ASPEED_SOC_I2C_BASE 0x1E78A000
|
#define ASPEED_SOC_I2C_BASE 0x1E78A000
|
||||||
|
|
||||||
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
||||||
@@ -170,6 +171,10 @@ static void aspeed_soc_init(Object *obj)
|
|||||||
sc->info->silicon_rev);
|
sc->info->silicon_rev);
|
||||||
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
|
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
|
||||||
"ram-size", &error_abort);
|
"ram-size", &error_abort);
|
||||||
|
|
||||||
|
object_initialize(&s->wdt, sizeof(s->wdt), TYPE_ASPEED_WDT);
|
||||||
|
object_property_add_child(obj, "wdt", OBJECT(&s->wdt), NULL);
|
||||||
|
qdev_set_parent_bus(DEVICE(&s->wdt), sysbus_get_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||||
@@ -286,6 +291,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
|
||||||
|
|
||||||
|
/* Watch dog */
|
||||||
|
object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, ASPEED_SOC_WDT_BASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
||||||
|
@@ -53,6 +53,26 @@ static uint8_t integrator_spd[128] = {
|
|||||||
0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
|
0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_integratorcm = {
|
||||||
|
.name = "integratorcm",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(cm_osc, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(cm_ctrl, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(cm_lock, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(cm_auxosc, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(cm_sdram, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(cm_init, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(cm_flags, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(cm_nvflags, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(int_level, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(irq_enabled, IntegratorCMState),
|
||||||
|
VMSTATE_UINT32(fiq_enabled, IntegratorCMState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static uint64_t integratorcm_read(void *opaque, hwaddr offset,
|
static uint64_t integratorcm_read(void *opaque, hwaddr offset,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
@@ -309,6 +329,18 @@ typedef struct icp_pic_state {
|
|||||||
qemu_irq parent_fiq;
|
qemu_irq parent_fiq;
|
||||||
} icp_pic_state;
|
} icp_pic_state;
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_icp_pic = {
|
||||||
|
.name = "icp_pic",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(level, icp_pic_state),
|
||||||
|
VMSTATE_UINT32(irq_enabled, icp_pic_state),
|
||||||
|
VMSTATE_UINT32(fiq_enabled, icp_pic_state),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void icp_pic_update(icp_pic_state *s)
|
static void icp_pic_update(icp_pic_state *s)
|
||||||
{
|
{
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
@@ -438,6 +470,16 @@ typedef struct ICPCtrlRegsState {
|
|||||||
#define ICP_INTREG_WPROT (1 << 0)
|
#define ICP_INTREG_WPROT (1 << 0)
|
||||||
#define ICP_INTREG_CARDIN (1 << 3)
|
#define ICP_INTREG_CARDIN (1 << 3)
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_icp_control = {
|
||||||
|
.name = "icp_control",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(intreg_state, ICPCtrlRegsState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static uint64_t icp_control_read(void *opaque, hwaddr offset,
|
static uint64_t icp_control_read(void *opaque, hwaddr offset,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
@@ -535,27 +577,42 @@ static void integratorcp_init(MachineState *machine)
|
|||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
|
char **cpustr;
|
||||||
ObjectClass *cpu_oc;
|
ObjectClass *cpu_oc;
|
||||||
|
CPUClass *cc;
|
||||||
Object *cpuobj;
|
Object *cpuobj;
|
||||||
ARMCPU *cpu;
|
ARMCPU *cpu;
|
||||||
|
const char *typename;
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
||||||
qemu_irq pic[32];
|
qemu_irq pic[32];
|
||||||
DeviceState *dev, *sic, *icp;
|
DeviceState *dev, *sic, *icp;
|
||||||
int i;
|
int i;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
if (!cpu_model) {
|
if (!cpu_model) {
|
||||||
cpu_model = "arm926";
|
cpu_model = "arm926";
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
cpustr = g_strsplit(cpu_model, ",", 2);
|
||||||
|
|
||||||
|
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
|
||||||
if (!cpu_oc) {
|
if (!cpu_oc) {
|
||||||
fprintf(stderr, "Unable to find CPU definition\n");
|
fprintf(stderr, "Unable to find CPU definition\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
typename = object_class_get_name(cpu_oc);
|
||||||
|
|
||||||
cpuobj = object_new(object_class_get_name(cpu_oc));
|
cc = CPU_CLASS(cpu_oc);
|
||||||
|
cc->parse_features(typename, cpustr[1], &err);
|
||||||
|
g_strfreev(cpustr);
|
||||||
|
if (err) {
|
||||||
|
error_report_err(err);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpuobj = object_new(typename);
|
||||||
|
|
||||||
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
||||||
* currently support EL3 so the CPU EL3 property is disabled before
|
* currently support EL3 so the CPU EL3 property is disabled before
|
||||||
@@ -640,6 +697,21 @@ static void core_class_init(ObjectClass *klass, void *data)
|
|||||||
|
|
||||||
dc->props = core_properties;
|
dc->props = core_properties;
|
||||||
dc->realize = integratorcm_realize;
|
dc->realize = integratorcm_realize;
|
||||||
|
dc->vmsd = &vmstate_integratorcm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void icp_pic_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->vmsd = &vmstate_icp_pic;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void icp_control_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->vmsd = &vmstate_icp_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo core_info = {
|
static const TypeInfo core_info = {
|
||||||
@@ -655,6 +727,7 @@ static const TypeInfo icp_pic_info = {
|
|||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(icp_pic_state),
|
.instance_size = sizeof(icp_pic_state),
|
||||||
.instance_init = icp_pic_init,
|
.instance_init = icp_pic_init,
|
||||||
|
.class_init = icp_pic_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TypeInfo icp_ctrl_regs_info = {
|
static const TypeInfo icp_ctrl_regs_info = {
|
||||||
@@ -662,6 +735,7 @@ static const TypeInfo icp_ctrl_regs_info = {
|
|||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(ICPCtrlRegsState),
|
.instance_size = sizeof(ICPCtrlRegsState),
|
||||||
.instance_init = icp_control_init,
|
.instance_init = icp_control_init,
|
||||||
|
.class_init = icp_control_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void integratorcp_register_types(void)
|
static void integratorcp_register_types(void)
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "hw/char/pl011.h"
|
#include "hw/char/pl011.h"
|
||||||
|
#include "hw/misc/unimp.h"
|
||||||
|
|
||||||
#define GPIO_A 0
|
#define GPIO_A 0
|
||||||
#define GPIO_B 1
|
#define GPIO_B 1
|
||||||
@@ -1220,6 +1221,40 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
|
|||||||
0x40024000, 0x40025000, 0x40026000};
|
0x40024000, 0x40025000, 0x40026000};
|
||||||
static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
|
static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
|
||||||
|
|
||||||
|
/* Memory map of SoC devices, from
|
||||||
|
* Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
|
||||||
|
* http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
|
||||||
|
*
|
||||||
|
* 40000000 wdtimer (unimplemented)
|
||||||
|
* 40002000 i2c (unimplemented)
|
||||||
|
* 40004000 GPIO
|
||||||
|
* 40005000 GPIO
|
||||||
|
* 40006000 GPIO
|
||||||
|
* 40007000 GPIO
|
||||||
|
* 40008000 SSI
|
||||||
|
* 4000c000 UART
|
||||||
|
* 4000d000 UART
|
||||||
|
* 4000e000 UART
|
||||||
|
* 40020000 i2c
|
||||||
|
* 40021000 i2c (unimplemented)
|
||||||
|
* 40024000 GPIO
|
||||||
|
* 40025000 GPIO
|
||||||
|
* 40026000 GPIO
|
||||||
|
* 40028000 PWM (unimplemented)
|
||||||
|
* 4002c000 QEI (unimplemented)
|
||||||
|
* 4002d000 QEI (unimplemented)
|
||||||
|
* 40030000 gptimer
|
||||||
|
* 40031000 gptimer
|
||||||
|
* 40032000 gptimer
|
||||||
|
* 40033000 gptimer
|
||||||
|
* 40038000 ADC
|
||||||
|
* 4003c000 analogue comparator (unimplemented)
|
||||||
|
* 40048000 ethernet
|
||||||
|
* 400fc000 hibernation module (unimplemented)
|
||||||
|
* 400fd000 flash memory control (unimplemented)
|
||||||
|
* 400fe000 system control
|
||||||
|
*/
|
||||||
|
|
||||||
DeviceState *gpio_dev[7], *nvic;
|
DeviceState *gpio_dev[7], *nvic;
|
||||||
qemu_irq gpio_in[7][8];
|
qemu_irq gpio_in[7][8];
|
||||||
qemu_irq gpio_out[7][8];
|
qemu_irq gpio_out[7][8];
|
||||||
@@ -1370,6 +1405,19 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add dummy regions for the devices we don't implement yet,
|
||||||
|
* so guest accesses don't cause unlogged crashes.
|
||||||
|
*/
|
||||||
|
create_unimplemented_device("wdtimer", 0x40000000, 0x1000);
|
||||||
|
create_unimplemented_device("i2c-0", 0x40002000, 0x1000);
|
||||||
|
create_unimplemented_device("i2c-2", 0x40021000, 0x1000);
|
||||||
|
create_unimplemented_device("PWM", 0x40028000, 0x1000);
|
||||||
|
create_unimplemented_device("QEI-0", 0x4002c000, 0x1000);
|
||||||
|
create_unimplemented_device("QEI-1", 0x4002d000, 0x1000);
|
||||||
|
create_unimplemented_device("analogue-comparator", 0x4003c000, 0x1000);
|
||||||
|
create_unimplemented_device("hibernation", 0x400fc000, 0x1000);
|
||||||
|
create_unimplemented_device("flash-control", 0x400fd000, 0x1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Figure out how to generate these from stellaris_boards. */
|
/* FIXME: Figure out how to generate these from stellaris_boards. */
|
||||||
|
5
hw/block/dataplane/trace-events
Normal file
5
hw/block/dataplane/trace-events
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# See docs/tracing.txt for syntax documentation.
|
||||||
|
|
||||||
|
# hw/block/dataplane/virtio-blk.c
|
||||||
|
virtio_blk_data_plane_start(void *s) "dataplane %p"
|
||||||
|
virtio_blk_data_plane_stop(void *s) "dataplane %p"
|
@@ -872,7 +872,7 @@ static int nvme_init(PCIDevice *pci_dev)
|
|||||||
pci_register_bar(&n->parent_obj, 0,
|
pci_register_bar(&n->parent_obj, 0,
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
|
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
|
||||||
&n->iomem);
|
&n->iomem);
|
||||||
msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4);
|
msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4, NULL);
|
||||||
|
|
||||||
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
|
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
|
||||||
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
|
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
|
||||||
|
@@ -7,11 +7,6 @@ virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sec
|
|||||||
virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
|
virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
|
||||||
virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d"
|
virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d"
|
||||||
|
|
||||||
# hw/block/dataplane/virtio-blk.c
|
|
||||||
virtio_blk_data_plane_start(void *s) "dataplane %p"
|
|
||||||
virtio_blk_data_plane_stop(void *s) "dataplane %p"
|
|
||||||
virtio_blk_data_plane_process_request(void *s, unsigned int out_num, unsigned int in_num, unsigned int head) "dataplane %p out_num %u in_num %u head %u"
|
|
||||||
|
|
||||||
# hw/block/hd-geometry.c
|
# hw/block/hd-geometry.c
|
||||||
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
|
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
|
||||||
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
|
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
|
||||||
|
@@ -2,7 +2,8 @@ common-obj-$(CONFIG_IPACK) += ipoctal232.o
|
|||||||
common-obj-$(CONFIG_ESCC) += escc.o
|
common-obj-$(CONFIG_ESCC) += escc.o
|
||||||
common-obj-$(CONFIG_PARALLEL) += parallel.o
|
common-obj-$(CONFIG_PARALLEL) += parallel.o
|
||||||
common-obj-$(CONFIG_PL011) += pl011.o
|
common-obj-$(CONFIG_PL011) += pl011.o
|
||||||
common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o
|
common-obj-$(CONFIG_SERIAL) += serial.o
|
||||||
|
common-obj-$(CONFIG_SERIAL_ISA) += serial-isa.o
|
||||||
common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o
|
common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o
|
||||||
common-obj-$(CONFIG_VIRTIO) += virtio-console.o
|
common-obj-$(CONFIG_VIRTIO) += virtio-console.o
|
||||||
common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
|
common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
|
||||||
|
@@ -933,9 +933,12 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (qdev_get_vmsd(dev)) {
|
if (qdev_get_vmsd(dev)) {
|
||||||
vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
|
if (vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
|
||||||
dev->instance_id_alias,
|
dev->instance_id_alias,
|
||||||
dev->alias_required_for_version);
|
dev->alias_required_for_version,
|
||||||
|
&local_err) < 0) {
|
||||||
|
goto post_realize_fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
|
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
#include "trace.h"
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
@@ -277,10 +278,9 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
|||||||
}
|
}
|
||||||
if (pitch < 0) {
|
if (pitch < 0) {
|
||||||
int64_t min = addr
|
int64_t min = addr
|
||||||
+ ((int64_t)s->cirrus_blt_height-1) * pitch;
|
+ ((int64_t)s->cirrus_blt_height - 1) * pitch
|
||||||
int32_t max = addr
|
- s->cirrus_blt_width;
|
||||||
+ s->cirrus_blt_width;
|
if (min < -1 || addr >= s->vga.vram_size) {
|
||||||
if (min < 0 || max > s->vga.vram_size) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -305,14 +305,14 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
|
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
|
||||||
s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
|
s->cirrus_blt_dstaddr)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (dst_only) {
|
if (dst_only) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
|
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
|
||||||
s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
|
s->cirrus_blt_srcaddr)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,23 +661,54 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
|
|||||||
int off_cur;
|
int off_cur;
|
||||||
int off_cur_end;
|
int off_cur_end;
|
||||||
|
|
||||||
|
if (off_pitch < 0) {
|
||||||
|
off_begin -= bytesperline - 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (y = 0; y < lines; y++) {
|
for (y = 0; y < lines; y++) {
|
||||||
off_cur = off_begin;
|
off_cur = off_begin;
|
||||||
off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
|
off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
|
||||||
|
assert(off_cur_end >= off_cur);
|
||||||
memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
|
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, bool videosrc)
|
||||||
const uint8_t * src)
|
|
||||||
{
|
{
|
||||||
|
uint32_t patternsize;
|
||||||
uint8_t *dst;
|
uint8_t *dst;
|
||||||
|
uint8_t *src;
|
||||||
|
|
||||||
dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
|
dst = s->vga.vram_ptr + s->cirrus_blt_dstaddr;
|
||||||
|
|
||||||
if (blit_is_unsafe(s, false))
|
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;
|
||||||
|
}
|
||||||
|
src = s->vga.vram_ptr + s->cirrus_blt_srcaddr;
|
||||||
|
} else {
|
||||||
|
src = s->cirrus_bltbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blit_is_unsafe(s, true)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
(*s->cirrus_rop) (s, dst, src,
|
(*s->cirrus_rop) (s, dst, src,
|
||||||
s->cirrus_blt_dstpitch, 0,
|
s->cirrus_blt_dstpitch, 0,
|
||||||
@@ -698,7 +729,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
|
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
|
||||||
rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
rop_func(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
|
||||||
s->cirrus_blt_dstpitch,
|
s->cirrus_blt_dstpitch,
|
||||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
||||||
@@ -716,9 +747,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
|||||||
|
|
||||||
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
||||||
{
|
{
|
||||||
return cirrus_bitblt_common_patterncopy(s,
|
return cirrus_bitblt_common_patterncopy(s, true);
|
||||||
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)
|
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||||
@@ -772,10 +801,8 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
|||||||
if (notify)
|
if (notify)
|
||||||
graphic_hw_update(s->vga.con);
|
graphic_hw_update(s->vga.con);
|
||||||
|
|
||||||
(*s->cirrus_rop) (s, s->vga.vram_ptr +
|
(*s->cirrus_rop) (s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
|
||||||
(s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
s->vga.vram_ptr + s->cirrus_blt_srcaddr,
|
||||||
s->vga.vram_ptr +
|
|
||||||
(s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
|
|
||||||
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
|
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
|
||||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||||
|
|
||||||
@@ -819,15 +846,14 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
|
|||||||
|
|
||||||
if (s->cirrus_srccounter > 0) {
|
if (s->cirrus_srccounter > 0) {
|
||||||
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
|
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
|
||||||
cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
|
cirrus_bitblt_common_patterncopy(s, false);
|
||||||
the_end:
|
the_end:
|
||||||
s->cirrus_srccounter = 0;
|
s->cirrus_srccounter = 0;
|
||||||
cirrus_bitblt_reset(s);
|
cirrus_bitblt_reset(s);
|
||||||
} else {
|
} else {
|
||||||
/* at least one scan line */
|
/* at least one scan line */
|
||||||
do {
|
do {
|
||||||
(*s->cirrus_rop)(s, s->vga.vram_ptr +
|
(*s->cirrus_rop)(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
|
||||||
(s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
|
||||||
s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
|
s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
|
||||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
|
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
|
||||||
s->cirrus_blt_width, 1);
|
s->cirrus_blt_width, 1);
|
||||||
@@ -946,6 +972,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
|
|||||||
s->cirrus_blt_modeext = s->vga.gr[0x33];
|
s->cirrus_blt_modeext = s->vga.gr[0x33];
|
||||||
blt_rop = s->vga.gr[0x32];
|
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
|
#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",
|
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,
|
blt_rop,
|
||||||
@@ -1838,12 +1867,14 @@ static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace_vga_cirrus_write_blt(address, value);
|
||||||
return (uint8_t) value;
|
return (uint8_t) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
|
static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
|
||||||
uint8_t value)
|
uint8_t value)
|
||||||
{
|
{
|
||||||
|
trace_vga_cirrus_write_blt(address, value);
|
||||||
switch (address) {
|
switch (address) {
|
||||||
case (CIRRUS_MMIO_BLTBGCOLOR + 0):
|
case (CIRRUS_MMIO_BLTBGCOLOR + 0):
|
||||||
cirrus_vga_write_gr(s, 0x00, value);
|
cirrus_vga_write_gr(s, 0x00, value);
|
||||||
@@ -2593,9 +2624,7 @@ static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(DEBUG_VGA)
|
trace_vga_cirrus_read_io(addr, val);
|
||||||
printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
|
|
||||||
#endif
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2612,9 +2641,7 @@ static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
if (vga_ioport_invalid(s, addr)) {
|
if (vga_ioport_invalid(s, addr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_VGA
|
trace_vga_cirrus_write_io(addr, val);
|
||||||
printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0x3c0:
|
case 0x3c0:
|
||||||
|
@@ -306,12 +306,11 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
|
|||||||
|
|
||||||
static ram_addr_t qxl_rom_size(void)
|
static ram_addr_t qxl_rom_size(void)
|
||||||
{
|
{
|
||||||
uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
|
#define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes))
|
||||||
sizeof(qxl_modes);
|
#define QXL_ROM_SZ 8192
|
||||||
uint32_t rom_size = 8192; /* two pages */
|
|
||||||
|
|
||||||
QEMU_BUILD_BUG_ON(required_rom_size > rom_size);
|
QEMU_BUILD_BUG_ON(QXL_REQUIRED_SZ > QXL_ROM_SZ);
|
||||||
return rom_size;
|
return QXL_ROM_SZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_qxl_rom(PCIQXLDevice *d)
|
static void init_qxl_rom(PCIQXLDevice *d)
|
||||||
|
@@ -34,7 +34,6 @@ vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp"
|
|||||||
# hw/display/virtio-gpu.c
|
# hw/display/virtio-gpu.c
|
||||||
virtio_gpu_features(bool virgl) "virgl %d"
|
virtio_gpu_features(bool virgl) "virgl %d"
|
||||||
virtio_gpu_cmd_get_display_info(void) ""
|
virtio_gpu_cmd_get_display_info(void) ""
|
||||||
virtio_gpu_cmd_get_caps(void) ""
|
|
||||||
virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d"
|
virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d"
|
||||||
virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d"
|
virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d"
|
||||||
virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d"
|
virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d"
|
||||||
@@ -120,3 +119,15 @@ qxl_set_client_capabilities_unsupported_by_revision(int qid, int revision) "%d r
|
|||||||
qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]"
|
qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]"
|
||||||
qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d"
|
qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d"
|
||||||
qxl_render_update_area_done(void *cookie) "%p"
|
qxl_render_update_area_done(void *cookie) "%p"
|
||||||
|
|
||||||
|
# hw/display/vga.c
|
||||||
|
vga_std_read_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
|
||||||
|
vga_std_write_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
|
||||||
|
vga_vbe_read(uint32_t index, uint32_t val) "index 0x%x, val 0x%x"
|
||||||
|
vga_vbe_write(uint32_t index, uint32_t val) "index 0x%x, val 0x%x"
|
||||||
|
|
||||||
|
# hw/display/cirrus_vga.c
|
||||||
|
vga_cirrus_read_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
|
||||||
|
vga_cirrus_write_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
|
||||||
|
vga_cirrus_read_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x"
|
||||||
|
vga_cirrus_write_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x"
|
||||||
|
@@ -34,12 +34,9 @@
|
|||||||
#include "hw/xen/xen.h"
|
#include "hw/xen/xen.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
//#define DEBUG_VGA
|
|
||||||
//#define DEBUG_VGA_MEM
|
//#define DEBUG_VGA_MEM
|
||||||
//#define DEBUG_VGA_REG
|
//#define DEBUG_VGA_REG
|
||||||
|
|
||||||
//#define DEBUG_BOCHS_VBE
|
|
||||||
|
|
||||||
/* 16 state changes per vertical frame @60 Hz */
|
/* 16 state changes per vertical frame @60 Hz */
|
||||||
#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
|
#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
|
||||||
|
|
||||||
@@ -428,9 +425,7 @@ uint32_t vga_ioport_read(void *opaque, uint32_t addr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(DEBUG_VGA)
|
trace_vga_std_read_io(addr, val);
|
||||||
printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
|
|
||||||
#endif
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,9 +438,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
if (vga_ioport_invalid(s, addr)) {
|
if (vga_ioport_invalid(s, addr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_VGA
|
trace_vga_std_write_io(addr, val);
|
||||||
printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case VGA_ATT_W:
|
case VGA_ATT_W:
|
||||||
@@ -733,9 +726,7 @@ uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
|
|||||||
} else {
|
} else {
|
||||||
val = 0;
|
val = 0;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_BOCHS_VBE
|
trace_vga_vbe_read(s->vbe_index, val);
|
||||||
printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
|
|
||||||
#endif
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,9 +741,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
VGACommonState *s = opaque;
|
VGACommonState *s = opaque;
|
||||||
|
|
||||||
if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
|
if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
|
||||||
#ifdef DEBUG_BOCHS_VBE
|
trace_vga_vbe_write(s->vbe_index, val);
|
||||||
printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
|
|
||||||
#endif
|
|
||||||
switch(s->vbe_index) {
|
switch(s->vbe_index) {
|
||||||
case VBE_DISPI_INDEX_ID:
|
case VBE_DISPI_INDEX_ID:
|
||||||
if (val == VBE_DISPI_ID0 ||
|
if (val == VBE_DISPI_ID0 ||
|
||||||
@@ -1543,17 +1532,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|||||||
height, format, s->line_offset,
|
height, format, s->line_offset,
|
||||||
s->vram_ptr + (s->start_addr * 4));
|
s->vram_ptr + (s->start_addr * 4));
|
||||||
dpy_gfx_replace_surface(s->con, surface);
|
dpy_gfx_replace_surface(s->con, surface);
|
||||||
#ifdef DEBUG_VGA
|
|
||||||
printf("VGA: Using shared surface for depth=%d swap=%d\n",
|
|
||||||
depth, byteswap);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
qemu_console_resize(s->con, disp_width, height);
|
qemu_console_resize(s->con, disp_width, height);
|
||||||
surface = qemu_console_surface(s->con);
|
surface = qemu_console_surface(s->con);
|
||||||
#ifdef DEBUG_VGA
|
|
||||||
printf("VGA: Using shadow surface for depth=%d swap=%d\n",
|
|
||||||
depth, byteswap);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
s->last_scr_width = disp_width;
|
s->last_scr_width = disp_width;
|
||||||
s->last_scr_height = height;
|
s->last_scr_height = height;
|
||||||
|
@@ -77,10 +77,18 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g,
|
|||||||
struct virtio_gpu_ctrl_command *cmd)
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
{
|
{
|
||||||
struct virtio_gpu_resource_unref unref;
|
struct virtio_gpu_resource_unref unref;
|
||||||
|
struct iovec *res_iovs = NULL;
|
||||||
|
int num_iovs = 0;
|
||||||
|
|
||||||
VIRTIO_GPU_FILL_CMD(unref);
|
VIRTIO_GPU_FILL_CMD(unref);
|
||||||
trace_virtio_gpu_cmd_res_unref(unref.resource_id);
|
trace_virtio_gpu_cmd_res_unref(unref.resource_id);
|
||||||
|
|
||||||
|
virgl_renderer_resource_detach_iov(unref.resource_id,
|
||||||
|
&res_iovs,
|
||||||
|
&num_iovs);
|
||||||
|
if (res_iovs != NULL && num_iovs != 0) {
|
||||||
|
virtio_gpu_cleanup_mapping_iov(res_iovs, num_iovs);
|
||||||
|
}
|
||||||
virgl_renderer_resource_unref(unref.resource_id);
|
virgl_renderer_resource_unref(unref.resource_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -608,6 +608,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
|||||||
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
pixman_image_unref(rect);
|
||||||
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
|
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -143,8 +143,10 @@ static void mpc8xxx_gpio_write(void *opaque, hwaddr offset,
|
|||||||
mpc8xxx_gpio_update(s);
|
mpc8xxx_gpio_update(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mpc8xxx_gpio_reset(MPC8XXXGPIOState *s)
|
static void mpc8xxx_gpio_reset(DeviceState *dev)
|
||||||
{
|
{
|
||||||
|
MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
|
||||||
|
|
||||||
s->dir = 0;
|
s->dir = 0;
|
||||||
s->odr = 0;
|
s->odr = 0;
|
||||||
s->dat = 0;
|
s->dat = 0;
|
||||||
@@ -180,33 +182,33 @@ static const MemoryRegionOps mpc8xxx_gpio_ops = {
|
|||||||
.endianness = DEVICE_BIG_ENDIAN,
|
.endianness = DEVICE_BIG_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mpc8xxx_gpio_initfn(SysBusDevice *sbd)
|
static void mpc8xxx_gpio_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
DeviceState *dev = DEVICE(sbd);
|
DeviceState *dev = DEVICE(obj);
|
||||||
MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
|
MPC8XXXGPIOState *s = MPC8XXX_GPIO(obj);
|
||||||
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
|
|
||||||
memory_region_init_io(&s->iomem, OBJECT(s), &mpc8xxx_gpio_ops, s, "mpc8xxx_gpio", 0x1000);
|
memory_region_init_io(&s->iomem, obj, &mpc8xxx_gpio_ops,
|
||||||
|
s, "mpc8xxx_gpio", 0x1000);
|
||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
sysbus_init_irq(sbd, &s->irq);
|
sysbus_init_irq(sbd, &s->irq);
|
||||||
qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32);
|
qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32);
|
||||||
qdev_init_gpio_out(dev, s->out, 32);
|
qdev_init_gpio_out(dev, s->out, 32);
|
||||||
mpc8xxx_gpio_reset(s);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
|
static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
|
||||||
|
|
||||||
k->init = mpc8xxx_gpio_initfn;
|
|
||||||
dc->vmsd = &vmstate_mpc8xxx_gpio;
|
dc->vmsd = &vmstate_mpc8xxx_gpio;
|
||||||
|
dc->reset = mpc8xxx_gpio_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo mpc8xxx_gpio_info = {
|
static const TypeInfo mpc8xxx_gpio_info = {
|
||||||
.name = TYPE_MPC8XXX_GPIO,
|
.name = TYPE_MPC8XXX_GPIO,
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(MPC8XXXGPIOState),
|
.instance_size = sizeof(MPC8XXXGPIOState),
|
||||||
|
.instance_init = mpc8xxx_gpio_initfn,
|
||||||
.class_init = mpc8xxx_gpio_class_init,
|
.class_init = mpc8xxx_gpio_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1485,8 +1485,16 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* According to ATS spec table 2.4:
|
||||||
|
* S = 0, bits 15:12 = xxxx range size: 4K
|
||||||
|
* S = 1, bits 15:12 = xxx0 range size: 8K
|
||||||
|
* S = 1, bits 15:12 = xx01 range size: 16K
|
||||||
|
* S = 1, bits 15:12 = x011 range size: 32K
|
||||||
|
* S = 1, bits 15:12 = 0111 range size: 64K
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
if (size) {
|
if (size) {
|
||||||
sz = 1 << (ctz64(~(addr | (VTD_PAGE_MASK_4K - 1))) + 1);
|
sz = (VTD_PAGE_SIZE * 2) << cto64(addr >> VTD_PAGE_SHIFT);
|
||||||
addr &= ~(sz - 1);
|
addr &= ~(sz - 1);
|
||||||
} else {
|
} else {
|
||||||
sz = VTD_PAGE_SIZE;
|
sz = VTD_PAGE_SIZE;
|
||||||
|
@@ -1708,6 +1708,11 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
|
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
|
||||||
|
if (!pcms->acpi_nvdimm_state.is_enabled) {
|
||||||
|
error_setg(&local_err,
|
||||||
|
"nvdimm is not enabled: missing 'nvdimm' in '-M'");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
nvdimm_plug(&pcms->acpi_nvdimm_state);
|
nvdimm_plug(&pcms->acpi_nvdimm_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,12 +1,5 @@
|
|||||||
# See docs/tracing.txt for syntax documentation.
|
# See docs/tracing.txt for syntax documentation.
|
||||||
|
|
||||||
# hw/i386/xen/xen_platform.c
|
|
||||||
xen_platform_log(char *s) "xen platform: %s"
|
|
||||||
|
|
||||||
# hw/i386/xen/xen_pvdevice.c
|
|
||||||
xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")"
|
|
||||||
xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")"
|
|
||||||
|
|
||||||
# hw/i386/x86-iommu.c
|
# hw/i386/x86-iommu.c
|
||||||
x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
|
x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
|
||||||
|
|
||||||
@@ -30,7 +23,6 @@ amdvi_devtab_inval(uint8_t bus, uint8_t slot, uint8_t func) "device table entry
|
|||||||
amdvi_completion_wait(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64
|
amdvi_completion_wait(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64
|
||||||
amdvi_control_status(uint64_t val) "MMIO_STATUS state 0x%"PRIx64
|
amdvi_control_status(uint64_t val) "MMIO_STATUS state 0x%"PRIx64
|
||||||
amdvi_iotlb_reset(void) "IOTLB exceed size limit - reset "
|
amdvi_iotlb_reset(void) "IOTLB exceed size limit - reset "
|
||||||
amdvi_completion_wait_exec(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64
|
|
||||||
amdvi_dte_get_fail(uint64_t addr, uint32_t offset) "error: failed to access Device Entry devtab 0x%"PRIx64" offset 0x%"PRIx32
|
amdvi_dte_get_fail(uint64_t addr, uint32_t offset) "error: failed to access Device Entry devtab 0x%"PRIx64" offset 0x%"PRIx32
|
||||||
amdvi_invalid_dte(uint64_t addr) "PTE entry at 0x%"PRIx64" is invalid "
|
amdvi_invalid_dte(uint64_t addr) "PTE entry at 0x%"PRIx64" is invalid "
|
||||||
amdvi_get_pte_hwerror(uint64_t addr) "hardware error eccessing PTE at addr 0x%"PRIx64
|
amdvi_get_pte_hwerror(uint64_t addr) "hardware error eccessing PTE at addr 0x%"PRIx64
|
||||||
|
6
hw/i386/xen/trace-events
Normal file
6
hw/i386/xen/trace-events
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# hw/i386/xen/xen_platform.c
|
||||||
|
xen_platform_log(char *s) "xen platform: %s"
|
||||||
|
|
||||||
|
# hw/i386/xen/xen_pvdevice.c
|
||||||
|
xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")"
|
||||||
|
xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")"
|
@@ -88,7 +88,7 @@ static void log_writeb(PCIXenPlatformState *s, char val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Xen Platform, Fixed IOPort */
|
/* Xen Platform, Fixed IOPort */
|
||||||
#define UNPLUG_ALL_IDE_DISKS 1
|
#define UNPLUG_ALL_DISKS 1
|
||||||
#define UNPLUG_ALL_NICS 2
|
#define UNPLUG_ALL_NICS 2
|
||||||
#define UNPLUG_AUX_IDE_DISKS 4
|
#define UNPLUG_AUX_IDE_DISKS 4
|
||||||
|
|
||||||
@@ -107,23 +107,37 @@ static void pci_unplug_nics(PCIBus *bus)
|
|||||||
pci_for_each_device(bus, 0, unplug_nic, NULL);
|
pci_for_each_device(bus, 0, unplug_nic, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unplug_disks(PCIBus *b, PCIDevice *d, void *o)
|
static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
|
||||||
{
|
{
|
||||||
|
uint32_t flags = *(uint32_t *)opaque;
|
||||||
|
bool aux = (flags & UNPLUG_AUX_IDE_DISKS) &&
|
||||||
|
!(flags & UNPLUG_ALL_DISKS);
|
||||||
|
|
||||||
/* We have to ignore passthrough devices */
|
/* We have to ignore passthrough devices */
|
||||||
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
|
if (!strcmp(d->name, "xen-pci-passthrough")) {
|
||||||
PCI_CLASS_STORAGE_IDE
|
return;
|
||||||
&& strcmp(d->name, "xen-pci-passthrough") != 0) {
|
}
|
||||||
pci_piix3_xen_ide_unplug(DEVICE(d));
|
|
||||||
} else if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
|
switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) {
|
||||||
PCI_CLASS_STORAGE_SCSI
|
case PCI_CLASS_STORAGE_IDE:
|
||||||
&& strcmp(d->name, "xen-pci-passthrough") != 0) {
|
pci_piix3_xen_ide_unplug(DEVICE(d), aux);
|
||||||
object_unparent(OBJECT(d));
|
break;
|
||||||
|
|
||||||
|
case PCI_CLASS_STORAGE_SCSI:
|
||||||
|
case PCI_CLASS_STORAGE_EXPRESS:
|
||||||
|
if (!aux) {
|
||||||
|
object_unparent(OBJECT(d));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_unplug_disks(PCIBus *bus)
|
static void pci_unplug_disks(PCIBus *bus, uint32_t flags)
|
||||||
{
|
{
|
||||||
pci_for_each_device(bus, 0, unplug_disks, NULL);
|
pci_for_each_device(bus, 0, unplug_disks, &flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||||
@@ -134,19 +148,16 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
|
|||||||
case 0: {
|
case 0: {
|
||||||
PCIDevice *pci_dev = PCI_DEVICE(s);
|
PCIDevice *pci_dev = PCI_DEVICE(s);
|
||||||
/* Unplug devices. Value is a bitmask of which devices to
|
/* Unplug devices. Value is a bitmask of which devices to
|
||||||
unplug, with bit 0 the IDE devices, bit 1 the network
|
unplug, with bit 0 the disk devices, bit 1 the network
|
||||||
devices, and bit 2 the non-primary-master IDE devices. */
|
devices, and bit 2 the non-primary-master IDE devices. */
|
||||||
if (val & UNPLUG_ALL_IDE_DISKS) {
|
if (val & (UNPLUG_ALL_DISKS | UNPLUG_AUX_IDE_DISKS)) {
|
||||||
DPRINTF("unplug disks\n");
|
DPRINTF("unplug disks\n");
|
||||||
pci_unplug_disks(pci_dev->bus);
|
pci_unplug_disks(pci_dev->bus, val);
|
||||||
}
|
}
|
||||||
if (val & UNPLUG_ALL_NICS) {
|
if (val & UNPLUG_ALL_NICS) {
|
||||||
DPRINTF("unplug nics\n");
|
DPRINTF("unplug nics\n");
|
||||||
pci_unplug_nics(pci_dev->bus);
|
pci_unplug_nics(pci_dev->bus);
|
||||||
}
|
}
|
||||||
if (val & UNPLUG_AUX_IDE_DISKS) {
|
|
||||||
DPRINTF("unplug auxiliary disks not supported\n");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
@@ -327,14 +338,14 @@ static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
|
|||||||
* If VMDP was to control both disk and LAN it would use 4.
|
* If VMDP was to control both disk and LAN it would use 4.
|
||||||
* If it controlled just disk or just LAN, it would use 8 below.
|
* If it controlled just disk or just LAN, it would use 8 below.
|
||||||
*/
|
*/
|
||||||
pci_unplug_disks(pci_dev->bus);
|
pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS);
|
||||||
pci_unplug_nics(pci_dev->bus);
|
pci_unplug_nics(pci_dev->bus);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 1:
|
case 1:
|
||||||
pci_unplug_disks(pci_dev->bus);
|
pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
pci_unplug_nics(pci_dev->bus);
|
pci_unplug_nics(pci_dev->bus);
|
||||||
|
@@ -165,7 +165,7 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp)
|
|||||||
pci_piix_init_ports(d);
|
pci_piix_init_ports(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux)
|
||||||
{
|
{
|
||||||
PCIIDEState *pci_ide;
|
PCIIDEState *pci_ide;
|
||||||
DriveInfo *di;
|
DriveInfo *di;
|
||||||
@@ -174,7 +174,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
|||||||
|
|
||||||
pci_ide = PCI_IDE(dev);
|
pci_ide = PCI_IDE(dev);
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = aux ? 1 : 0; i < 4; i++) {
|
||||||
di = drive_get_by_index(IF_IDE, i);
|
di = drive_get_by_index(IF_IDE, i);
|
||||||
if (di != NULL && !di->media_cd) {
|
if (di != NULL && !di->media_cd) {
|
||||||
BlockBackend *blk = blk_by_legacy_dinfo(di);
|
BlockBackend *blk = blk_by_legacy_dinfo(di);
|
||||||
|
@@ -8,8 +8,6 @@ ps2_reset_keyboard(void *s) "%p"
|
|||||||
ps2_write_keyboard(void *opaque, int val) "%p val %d"
|
ps2_write_keyboard(void *opaque, int val) "%p val %d"
|
||||||
ps2_keyboard_set_translation(void *opaque, int mode) "%p mode %d"
|
ps2_keyboard_set_translation(void *opaque, int mode) "%p mode %d"
|
||||||
ps2_mouse_send_packet(void *s, int dx1, int dy1, int dz1, int b) "%p x %d y %d z %d bs %#x"
|
ps2_mouse_send_packet(void *s, int dx1, int dy1, int dz1, int b) "%p x %d y %d z %d bs %#x"
|
||||||
ps2_mouse_event_disabled(void *opaque, int dx, int dy, int dz, int buttons_state, int mouse_dx, int mouse_dy, int mouse_dz) "%p x %d y %d z %d bs %#x mx %d my %d mz %d "
|
|
||||||
ps2_mouse_event(void *opaque, int dx, int dy, int dz, int buttons_state, int mouse_dx, int mouse_dy, int mouse_dz) "%p x %d y %d z %d bs %#x mx %d my %d mz %d "
|
|
||||||
ps2_mouse_fake_event(void *opaque) "%p"
|
ps2_mouse_fake_event(void *opaque) "%p"
|
||||||
ps2_write_mouse(void *opaque, int val) "%p val %d"
|
ps2_write_mouse(void *opaque, int val) "%p val %d"
|
||||||
ps2_kbd_reset(void *opaque) "%p"
|
ps2_kbd_reset(void *opaque) "%p"
|
||||||
|
@@ -329,7 +329,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
|
|||||||
instance_id = -1;
|
instance_id = -1;
|
||||||
}
|
}
|
||||||
vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
|
vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
|
||||||
s, -1, 0);
|
s, -1, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apic_common_unrealize(DeviceState *dev, Error **errp)
|
static void apic_common_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
@@ -67,7 +67,6 @@ xics_alloc(int irq) "irq %d"
|
|||||||
xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d"
|
xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d"
|
||||||
xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
|
xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
|
||||||
xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free"
|
xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free"
|
||||||
xics_icp_post_load(uint32_t server_no, uint32_t xirr, uint64_t addr, uint8_t pend) "server_no %d, xirr %#x, xirr_owner 0x%" PRIx64 ", pending %d"
|
|
||||||
|
|
||||||
# hw/intc/s390_flic_kvm.c
|
# hw/intc/s390_flic_kvm.c
|
||||||
flic_create_device(int err) "flic: create device failed %d"
|
flic_create_device(int err) "flic: create device failed %d"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
common-obj-y += isa-bus.o
|
common-obj-$(CONFIG_ISA_BUS) += isa-bus.o
|
||||||
common-obj-$(CONFIG_APM) += apm.o
|
common-obj-$(CONFIG_APM) += apm.o
|
||||||
common-obj-$(CONFIG_I82378) += i82378.o
|
common-obj-$(CONFIG_I82378) += i82378.o
|
||||||
common-obj-$(CONFIG_PC87312) += pc87312.o
|
common-obj-$(CONFIG_PC87312) += pc87312.o
|
||||||
|
@@ -6,6 +6,8 @@ common-obj-$(CONFIG_SGA) += sga.o
|
|||||||
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
|
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
|
||||||
common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
|
common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
|
||||||
|
|
||||||
|
common-obj-y += unimp.o
|
||||||
|
|
||||||
obj-$(CONFIG_VMPORT) += vmport.o
|
obj-$(CONFIG_VMPORT) += vmport.o
|
||||||
|
|
||||||
# ARM devices
|
# ARM devices
|
||||||
|
@@ -749,13 +749,13 @@ static void ivshmem_reset(DeviceState *d)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ivshmem_setup_interrupts(IVShmemState *s)
|
static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp)
|
||||||
{
|
{
|
||||||
/* allocate QEMU callback data for receiving interrupts */
|
/* allocate QEMU callback data for receiving interrupts */
|
||||||
s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
|
s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
|
||||||
|
|
||||||
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
||||||
if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
|
if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1, errp)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,8 +898,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
|||||||
qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
|
qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
|
||||||
ivshmem_read, NULL, s, NULL, true);
|
ivshmem_read, NULL, s, NULL, true);
|
||||||
|
|
||||||
if (ivshmem_setup_interrupts(s) < 0) {
|
if (ivshmem_setup_interrupts(s, errp) < 0) {
|
||||||
error_setg(errp, "failed to initialize interrupts");
|
error_prepend(errp, "Failed to initialize interrupts: ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
107
hw/misc/unimp.c
Normal file
107
hw/misc/unimp.c
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/* "Unimplemented" device
|
||||||
|
*
|
||||||
|
* This is a dummy device which accepts and logs all accesses.
|
||||||
|
* It's useful for stubbing out regions of an SoC or board
|
||||||
|
* map which correspond to devices that have not yet been
|
||||||
|
* implemented. This is often sufficient to placate initial
|
||||||
|
* guest device driver probing such that the system will
|
||||||
|
* come up.
|
||||||
|
*
|
||||||
|
* Copyright Linaro Limited, 2017
|
||||||
|
* Written by Peter Maydell
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/hw.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "hw/misc/unimp.h"
|
||||||
|
#include "qemu/log.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#define UNIMPLEMENTED_DEVICE(obj) \
|
||||||
|
OBJECT_CHECK(UnimplementedDeviceState, (obj), TYPE_UNIMPLEMENTED_DEVICE)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SysBusDevice parent_obj;
|
||||||
|
MemoryRegion iomem;
|
||||||
|
char *name;
|
||||||
|
uint64_t size;
|
||||||
|
} UnimplementedDeviceState;
|
||||||
|
|
||||||
|
static uint64_t unimp_read(void *opaque, hwaddr offset, unsigned size)
|
||||||
|
{
|
||||||
|
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
|
||||||
|
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
|
||||||
|
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
|
||||||
|
s->name, size, offset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unimp_write(void *opaque, hwaddr offset,
|
||||||
|
uint64_t value, unsigned size)
|
||||||
|
{
|
||||||
|
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
|
||||||
|
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
|
||||||
|
"(size %d, value 0x%" PRIx64
|
||||||
|
", offset 0x%" HWADDR_PRIx ")\n",
|
||||||
|
s->name, size, value, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps unimp_ops = {
|
||||||
|
.read = unimp_read,
|
||||||
|
.write = unimp_write,
|
||||||
|
.impl.min_access_size = 1,
|
||||||
|
.impl.max_access_size = 8,
|
||||||
|
.valid.min_access_size = 1,
|
||||||
|
.valid.max_access_size = 8,
|
||||||
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void unimp_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(dev);
|
||||||
|
|
||||||
|
if (s->size == 0) {
|
||||||
|
error_setg(errp, "property 'size' not specified or zero");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->name == NULL) {
|
||||||
|
error_setg(errp, "property 'name' not specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_init_io(&s->iomem, OBJECT(s), &unimp_ops, s,
|
||||||
|
s->name, s->size);
|
||||||
|
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property unimp_properties[] = {
|
||||||
|
DEFINE_PROP_UINT64("size", UnimplementedDeviceState, size, 0),
|
||||||
|
DEFINE_PROP_STRING("name", UnimplementedDeviceState, name),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void unimp_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->realize = unimp_realize;
|
||||||
|
dc->props = unimp_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo unimp_info = {
|
||||||
|
.name = TYPE_UNIMPLEMENTED_DEVICE,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(UnimplementedDeviceState),
|
||||||
|
.class_init = unimp_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void unimp_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&unimp_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(unimp_register_types)
|
@@ -292,7 +292,7 @@ e1000e_init_msix(E1000EState *s)
|
|||||||
E1000E_MSIX_IDX, E1000E_MSIX_TABLE,
|
E1000E_MSIX_IDX, E1000E_MSIX_TABLE,
|
||||||
&s->msix,
|
&s->msix,
|
||||||
E1000E_MSIX_IDX, E1000E_MSIX_PBA,
|
E1000E_MSIX_IDX, E1000E_MSIX_PBA,
|
||||||
0xA0);
|
0xA0, NULL);
|
||||||
|
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
trace_e1000e_msix_init_fail(res);
|
trace_e1000e_msix_init_fail(res);
|
||||||
|
@@ -29,7 +29,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "trace.h"
|
|
||||||
#include "hw/ptimer.h"
|
#include "hw/ptimer.h"
|
||||||
#include "etsec.h"
|
#include "etsec.h"
|
||||||
#include "registers.h"
|
#include "registers.h"
|
||||||
|
@@ -1256,14 +1256,16 @@ static int rocker_msix_init(Rocker *r)
|
|||||||
{
|
{
|
||||||
PCIDevice *dev = PCI_DEVICE(r);
|
PCIDevice *dev = PCI_DEVICE(r);
|
||||||
int err;
|
int err;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
|
err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
|
||||||
&r->msix_bar,
|
&r->msix_bar,
|
||||||
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
|
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
|
||||||
&r->msix_bar,
|
&r->msix_bar,
|
||||||
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
|
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
|
||||||
0);
|
0, &local_err);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
error_report_err(local_err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,10 +63,6 @@ net_rx_pkt_l4_csum_validate_entry(void) "Starting L4 checksum validation"
|
|||||||
net_rx_pkt_l4_csum_validate_not_xxp(void) "Not a TCP/UDP packet"
|
net_rx_pkt_l4_csum_validate_not_xxp(void) "Not a TCP/UDP packet"
|
||||||
net_rx_pkt_l4_csum_validate_udp_with_no_checksum(void) "UDP packet without checksum"
|
net_rx_pkt_l4_csum_validate_udp_with_no_checksum(void) "UDP packet without checksum"
|
||||||
net_rx_pkt_l4_csum_validate_ip4_fragment(void) "IP4 fragment"
|
net_rx_pkt_l4_csum_validate_ip4_fragment(void) "IP4 fragment"
|
||||||
net_rx_pkt_l4_csum_validate_ip4_udp(void) "IP4/UDP packet"
|
|
||||||
net_rx_pkt_l4_csum_validate_ip4_tcp(void) "IP4/TCP packet"
|
|
||||||
net_rx_pkt_l4_csum_validate_ip6_udp(void) "IP6/UDP packet"
|
|
||||||
net_rx_pkt_l4_csum_validate_ip6_tcp(void) "IP6/TCP packet"
|
|
||||||
net_rx_pkt_l4_csum_validate_csum(bool csum_valid) "Checksum valid: %d"
|
net_rx_pkt_l4_csum_validate_csum(bool csum_valid) "Checksum valid: %d"
|
||||||
|
|
||||||
net_rx_pkt_l4_csum_calc_entry(void) "Starting L4 checksum calculation"
|
net_rx_pkt_l4_csum_calc_entry(void) "Starting L4 checksum calculation"
|
||||||
@@ -117,7 +113,6 @@ e1000e_core_mdic_read(uint8_t page, uint32_t addr, uint32_t data) "MDIC READ: PH
|
|||||||
e1000e_core_mdic_read_unhandled(uint8_t page, uint32_t addr) "MDIC READ: PHY[%u][%u] UNHANDLED"
|
e1000e_core_mdic_read_unhandled(uint8_t page, uint32_t addr) "MDIC READ: PHY[%u][%u] UNHANDLED"
|
||||||
e1000e_core_mdic_write(uint8_t page, uint32_t addr, uint32_t data) "MDIC WRITE: PHY[%u][%u] = 0x%x"
|
e1000e_core_mdic_write(uint8_t page, uint32_t addr, uint32_t data) "MDIC WRITE: PHY[%u][%u] = 0x%x"
|
||||||
e1000e_core_mdic_write_unhandled(uint8_t page, uint32_t addr) "MDIC WRITE: PHY[%u][%u] UNHANDLED"
|
e1000e_core_mdic_write_unhandled(uint8_t page, uint32_t addr) "MDIC WRITE: PHY[%u][%u] UNHANDLED"
|
||||||
e1000e_core_eeeprom_write(uint16_t bit_in, uint16_t bit_out, uint16_t reading) "eeprom bitnum in %d out %d, reading %d"
|
|
||||||
e1000e_core_ctrl_write(uint64_t index, uint32_t val) "Write CTRL register 0x%"PRIx64", value: 0x%X"
|
e1000e_core_ctrl_write(uint64_t index, uint32_t val) "Write CTRL register 0x%"PRIx64", value: 0x%X"
|
||||||
e1000e_core_ctrl_sw_reset(void) "Doing SW reset"
|
e1000e_core_ctrl_sw_reset(void) "Doing SW reset"
|
||||||
e1000e_core_ctrl_phy_reset(void) "Doing PHY reset"
|
e1000e_core_ctrl_phy_reset(void) "Doing PHY reset"
|
||||||
@@ -159,7 +154,6 @@ e1000e_rx_desc_buff_write(uint8_t idx, uint64_t addr, uint16_t offset, const voi
|
|||||||
e1000e_rx_descr(int ridx, uint64_t base, uint8_t len) "Next RX descriptor: ring #%d, PA: 0x%"PRIx64", length: %u"
|
e1000e_rx_descr(int ridx, uint64_t base, uint8_t len) "Next RX descriptor: ring #%d, PA: 0x%"PRIx64", length: %u"
|
||||||
e1000e_rx_set_rctl(uint32_t rctl) "RCTL = 0x%x"
|
e1000e_rx_set_rctl(uint32_t rctl) "RCTL = 0x%x"
|
||||||
e1000e_rx_receive_iov(int iovcnt) "Received vector of %d fragments"
|
e1000e_rx_receive_iov(int iovcnt) "Received vector of %d fragments"
|
||||||
e1000e_rx_packet_size(size_t full, size_t vhdr, size_t data) "Received packet of %zu bytes total, %zu virt header, %zu data"
|
|
||||||
e1000e_rx_flt_dropped(void) "Received packet dropped by RX filter"
|
e1000e_rx_flt_dropped(void) "Received packet dropped by RX filter"
|
||||||
e1000e_rx_written_to_guest(uint32_t causes) "Received packet written to guest (ICR causes %u)"
|
e1000e_rx_written_to_guest(uint32_t causes) "Received packet written to guest (ICR causes %u)"
|
||||||
e1000e_rx_not_written_to_guest(uint32_t causes) "Received packet NOT written to guest (ICR causes %u)"
|
e1000e_rx_not_written_to_guest(uint32_t causes) "Received packet NOT written to guest (ICR causes %u)"
|
||||||
@@ -196,14 +190,12 @@ e1000e_rx_metadata_ipv6_filtering_disabled(void) "IPv6 RX filtering disabled by
|
|||||||
|
|
||||||
e1000e_vlan_vet(uint16_t vet) "Setting VLAN ethernet type 0x%X"
|
e1000e_vlan_vet(uint16_t vet) "Setting VLAN ethernet type 0x%X"
|
||||||
|
|
||||||
e1000e_irq_set_cause(uint32_t cause) "IRQ cause set 0x%x"
|
|
||||||
e1000e_irq_msi_notify(uint32_t cause) "MSI notify 0x%x"
|
e1000e_irq_msi_notify(uint32_t cause) "MSI notify 0x%x"
|
||||||
e1000e_irq_throttling_no_pending_interrupts(void) "No pending interrupts to notify"
|
e1000e_irq_throttling_no_pending_interrupts(void) "No pending interrupts to notify"
|
||||||
e1000e_irq_msi_notify_postponed(void) "Sending MSI postponed by ITR"
|
e1000e_irq_msi_notify_postponed(void) "Sending MSI postponed by ITR"
|
||||||
e1000e_irq_legacy_notify_postponed(void) "Raising legacy IRQ postponed by ITR"
|
e1000e_irq_legacy_notify_postponed(void) "Raising legacy IRQ postponed by ITR"
|
||||||
e1000e_irq_throttling_no_pending_vec(int idx) "No pending interrupts for vector %d"
|
e1000e_irq_throttling_no_pending_vec(int idx) "No pending interrupts for vector %d"
|
||||||
e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%d]"
|
e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%d]"
|
||||||
e1000e_irq_msix_notify(uint32_t cause) "MSI-X notify 0x%x"
|
|
||||||
e1000e_irq_legacy_notify(bool level) "IRQ line state: %d"
|
e1000e_irq_legacy_notify(bool level) "IRQ line state: %d"
|
||||||
e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x"
|
e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x"
|
||||||
e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x"
|
e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x"
|
||||||
|
@@ -2191,7 +2191,7 @@ vmxnet3_init_msix(VMXNET3State *s)
|
|||||||
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
|
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
|
||||||
&s->msix_bar,
|
&s->msix_bar,
|
||||||
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
|
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
|
||||||
VMXNET3_MSIX_OFFSET(s));
|
VMXNET3_MSIX_OFFSET(s), NULL);
|
||||||
|
|
||||||
if (0 > res) {
|
if (0 > res) {
|
||||||
VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
|
VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
common-obj-y += pci_bridge_dev.o
|
common-obj-y += pci_bridge_dev.o
|
||||||
common-obj-y += pci_expander_bridge.o
|
common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o
|
||||||
|
common-obj-$(CONFIG_PXB) += pci_expander_bridge.o
|
||||||
common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o
|
common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o
|
||||||
common-obj-$(CONFIG_IOH3420) += ioh3420.o
|
common-obj-$(CONFIG_IOH3420) += ioh3420.o
|
||||||
common-obj-$(CONFIG_I82801B11) += i82801b11.o
|
common-obj-$(CONFIG_I82801B11) += i82801b11.o
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user