Compare commits
247 Commits
pull-ui-20
...
pull-ui-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
396f935a9a | ||
|
|
e998e2090f | ||
|
|
57a6d6d538 | ||
|
|
8bd22f477f | ||
|
|
275e0d616b | ||
|
|
4ee74fa708 | ||
|
|
2a7e6857cd | ||
|
|
1b1aeb5828 | ||
|
|
537848ee62 | ||
|
|
c3ff04b60d | ||
|
|
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-temp
|
||||
/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.c
|
||||
/trace/generated-helpers-wrappers.h
|
||||
/trace/generated-helpers.h
|
||||
/trace/generated-helpers.c
|
||||
/trace/generated-tcg-tracers.h
|
||||
/trace/generated-ust-provider.h
|
||||
/trace/generated-ust.c
|
||||
/ui/shader/texture-blit-frag.h
|
||||
/ui/shader/texture-blit-vert.h
|
||||
*-timestamp
|
||||
@@ -120,3 +114,19 @@ tags
|
||||
TAGS
|
||||
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
|
||||
|
||||
10
MAINTAINERS
10
MAINTAINERS
@@ -323,7 +323,7 @@ Guest CPU Cores (Xen):
|
||||
X86
|
||||
M: Stefano Stabellini <sstabellini@kernel.org>
|
||||
M: Anthony Perard <anthony.perard@citrix.com>
|
||||
L: xen-devel@lists.xensource.com
|
||||
L: xen-devel@lists.xenproject.org
|
||||
S: Supported
|
||||
F: xen-*
|
||||
F: */xen*
|
||||
@@ -671,10 +671,13 @@ F: hw/misc/macio/
|
||||
F: hw/intc/heathrow_pic.c
|
||||
|
||||
PReP
|
||||
M: Hervé Poussineau <hpoussin@reactos.org>
|
||||
L: qemu-devel@nongnu.org
|
||||
L: qemu-ppc@nongnu.org
|
||||
S: Odd Fixes
|
||||
S: Maintained
|
||||
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/isa/pc87312.[hc]
|
||||
F: pc-bios/ppc_rom.bin
|
||||
@@ -1194,8 +1197,9 @@ T: git git://github.com/jnsnow/qemu.git bitmaps
|
||||
|
||||
Character device backends
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
S: Maintained
|
||||
F: qemu-char.c
|
||||
F: chardev/
|
||||
F: backends/msmouse.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_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-helpers-wrappers.h
|
||||
GENERATED_HEADERS += trace/generated-helpers.h
|
||||
GENERATED_SOURCES += trace/generated-helpers.c
|
||||
|
||||
ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust)
|
||||
GENERATED_HEADERS += trace/generated-ust-provider.h
|
||||
GENERATED_SOURCES += trace/generated-ust.c
|
||||
ifdef CONFIG_TRACE_UST
|
||||
GENERATED_HEADERS += trace-ust-all.h
|
||||
GENERATED_SOURCES += trace-ust-all.c
|
||||
endif
|
||||
|
||||
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
|
||||
# We don't generate any of them
|
||||
Makefile: ;
|
||||
@@ -147,6 +258,7 @@ endif
|
||||
|
||||
dummy := $(call unnest-vars,, \
|
||||
stub-obj-y \
|
||||
chardev-obj-y \
|
||||
util-obj-y \
|
||||
qga-obj-y \
|
||||
ivshmem-client-obj-y \
|
||||
@@ -160,7 +272,8 @@ dummy := $(call unnest-vars,, \
|
||||
qom-obj-y \
|
||||
io-obj-y \
|
||||
common-obj-y \
|
||||
common-obj-m)
|
||||
common-obj-m \
|
||||
trace-obj-y)
|
||||
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
include $(SRC_PATH)/tests/Makefile.include
|
||||
@@ -223,7 +336,8 @@ subdir-dtc:dtc/libfdt dtc/tests
|
||||
dtc/%:
|
||||
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))
|
||||
# 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$(EXESUF): qemu-img.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) libqemuutil.a libqemustub.a
|
||||
qemu-io$(EXESUF): qemu-io.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) $(COMMON_LDADDS)
|
||||
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
|
||||
|
||||
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)
|
||||
$(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, $^)
|
||||
|
||||
ifdef QEMU_GA_MSI_ENABLED
|
||||
@@ -345,9 +461,9 @@ ifneq ($(EXESUF),)
|
||||
qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
|
||||
endif
|
||||
|
||||
ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) libqemuutil.a libqemustub.a
|
||||
ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a
|
||||
ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
|
||||
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)
|
||||
endif
|
||||
|
||||
.SECONDARY: $(TRACE_HEADERS) $(TRACE_HEADERS:%=%-timestamp) \
|
||||
$(TRACE_SOURCES) $(TRACE_SOURCES:%=%-timestamp) \
|
||||
$(TRACE_DTRACE) $(TRACE_DTRACE:%=%-timestamp)
|
||||
|
||||
# Include automatically generated dependency files
|
||||
# Dependencies in Makefile.objs files come from our recursive subdir rules
|
||||
-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 += 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
|
||||
|
||||
@@ -51,8 +53,7 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
common-obj-$(CONFIG_LINUX) += fsdev/
|
||||
|
||||
common-obj-y += migration/
|
||||
common-obj-y += qemu-char.o #aio.o
|
||||
common-obj-y += page_cache.o
|
||||
common-obj-y += page_cache.o #aio.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/
|
||||
|
||||
######################################################################
|
||||
trace-events-y = trace-events
|
||||
trace-events-y += util/trace-events
|
||||
trace-events-y += crypto/trace-events
|
||||
trace-events-y += io/trace-events
|
||||
trace-events-y += migration/trace-events
|
||||
trace-events-y += block/trace-events
|
||||
trace-events-y += hw/block/trace-events
|
||||
trace-events-y += hw/char/trace-events
|
||||
trace-events-y += hw/intc/trace-events
|
||||
trace-events-y += hw/net/trace-events
|
||||
trace-events-y += hw/virtio/trace-events
|
||||
trace-events-y += hw/audio/trace-events
|
||||
trace-events-y += hw/misc/trace-events
|
||||
trace-events-y += hw/usb/trace-events
|
||||
trace-events-y += hw/scsi/trace-events
|
||||
trace-events-y += hw/nvram/trace-events
|
||||
trace-events-y += hw/display/trace-events
|
||||
trace-events-y += hw/input/trace-events
|
||||
trace-events-y += hw/timer/trace-events
|
||||
trace-events-y += hw/dma/trace-events
|
||||
trace-events-y += hw/sparc/trace-events
|
||||
trace-events-y += hw/sd/trace-events
|
||||
trace-events-y += hw/isa/trace-events
|
||||
trace-events-y += hw/mem/trace-events
|
||||
trace-events-y += hw/i386/trace-events
|
||||
trace-events-y += hw/9pfs/trace-events
|
||||
trace-events-y += hw/ppc/trace-events
|
||||
trace-events-y += hw/pci/trace-events
|
||||
trace-events-y += hw/s390x/trace-events
|
||||
trace-events-y += hw/vfio/trace-events
|
||||
trace-events-y += hw/acpi/trace-events
|
||||
trace-events-y += hw/arm/trace-events
|
||||
trace-events-y += hw/alpha/trace-events
|
||||
trace-events-y += ui/trace-events
|
||||
trace-events-y += audio/trace-events
|
||||
trace-events-y += net/trace-events
|
||||
trace-events-y += target/arm/trace-events
|
||||
trace-events-y += target/i386/trace-events
|
||||
trace-events-y += target/sparc/trace-events
|
||||
trace-events-y += target/s390x/trace-events
|
||||
trace-events-y += target/ppc/trace-events
|
||||
trace-events-y += qom/trace-events
|
||||
trace-events-y += linux-user/trace-events
|
||||
trace-events-y += qapi/trace-events
|
||||
trace-events-subdirs =
|
||||
trace-events-subdirs += util
|
||||
trace-events-subdirs += crypto
|
||||
trace-events-subdirs += io
|
||||
trace-events-subdirs += migration
|
||||
trace-events-subdirs += block
|
||||
trace-events-subdirs += hw/block
|
||||
trace-events-subdirs += hw/block/dataplane
|
||||
trace-events-subdirs += hw/char
|
||||
trace-events-subdirs += hw/intc
|
||||
trace-events-subdirs += hw/net
|
||||
trace-events-subdirs += hw/virtio
|
||||
trace-events-subdirs += hw/audio
|
||||
trace-events-subdirs += hw/misc
|
||||
trace-events-subdirs += hw/usb
|
||||
trace-events-subdirs += hw/scsi
|
||||
trace-events-subdirs += hw/nvram
|
||||
trace-events-subdirs += hw/display
|
||||
trace-events-subdirs += hw/input
|
||||
trace-events-subdirs += hw/timer
|
||||
trace-events-subdirs += hw/dma
|
||||
trace-events-subdirs += hw/sparc
|
||||
trace-events-subdirs += hw/sd
|
||||
trace-events-subdirs += hw/isa
|
||||
trace-events-subdirs += hw/mem
|
||||
trace-events-subdirs += hw/i386
|
||||
trace-events-subdirs += hw/i386/xen
|
||||
trace-events-subdirs += hw/9pfs
|
||||
trace-events-subdirs += hw/ppc
|
||||
trace-events-subdirs += hw/pci
|
||||
trace-events-subdirs += hw/s390x
|
||||
trace-events-subdirs += hw/vfio
|
||||
trace-events-subdirs += hw/acpi
|
||||
trace-events-subdirs += hw/arm
|
||||
trace-events-subdirs += hw/alpha
|
||||
trace-events-subdirs += hw/xen
|
||||
trace-events-subdirs += ui
|
||||
trace-events-subdirs += audio
|
||||
trace-events-subdirs += net
|
||||
trace-events-subdirs += target/arm
|
||||
trace-events-subdirs += target/i386
|
||||
trace-events-subdirs += target/sparc
|
||||
trace-events-subdirs += target/s390x
|
||||
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
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--group=all \
|
||||
--format=stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--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
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--group=all \
|
||||
--format=stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--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
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--group=all \
|
||||
--format=simpletrace-stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \
|
||||
@@ -172,31 +175,36 @@ all-obj-y := $(obj-y)
|
||||
target-obj-y :=
|
||||
block-obj-y :=
|
||||
common-obj-y :=
|
||||
chardev-obj-y :=
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
dummy := $(call unnest-vars,,target-obj-y)
|
||||
target-obj-y-save := $(target-obj-y)
|
||||
dummy := $(call unnest-vars,.., \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
chardev-obj-y \
|
||||
crypto-obj-y \
|
||||
crypto-aes-obj-y \
|
||||
qom-obj-y \
|
||||
io-obj-y \
|
||||
common-obj-y \
|
||||
common-obj-m)
|
||||
common-obj-m \
|
||||
trace-obj-y)
|
||||
target-obj-y := $(target-obj-y-save)
|
||||
all-obj-y += $(common-obj-y)
|
||||
all-obj-y += $(target-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_SOFTMMU) += $(crypto-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
|
||||
|
||||
$(QEMU_PROG_BUILD): config-devices.mak
|
||||
|
||||
COMMON_LDADDS = $(trace-obj-y) ../libqemuutil.a ../libqemustub.a
|
||||
|
||||
# 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, $^))
|
||||
ifdef CONFIG_DARWIN
|
||||
$(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/sockets.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "trace.h"
|
||||
#include "trace-root.h"
|
||||
#ifdef CONFIG_EPOLL_CREATE1
|
||||
#include <sys/epoll.h>
|
||||
#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);
|
||||
if (baum->brlapi) {
|
||||
@@ -659,23 +659,18 @@ static void char_braille_class_init(ObjectClass *oc, void *data)
|
||||
cc->open = baum_chr_open;
|
||||
cc->chr_write = baum_chr_write;
|
||||
cc->chr_accept_input = baum_chr_accept_input;
|
||||
cc->chr_free = baum_chr_free;
|
||||
}
|
||||
|
||||
static const TypeInfo char_braille_type_info = {
|
||||
.name = TYPE_CHARDEV_BRAILLE,
|
||||
.parent = TYPE_CHARDEV,
|
||||
.instance_size = sizeof(BaumChardev),
|
||||
.instance_finalize = char_braille_finalize,
|
||||
.class_init = char_braille_class_init,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,9 +139,9 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int 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);
|
||||
}
|
||||
@@ -172,23 +172,18 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data)
|
||||
cc->open = msmouse_chr_open;
|
||||
cc->chr_write = msmouse_chr_write;
|
||||
cc->chr_accept_input = msmouse_chr_accept_input;
|
||||
cc->chr_free = msmouse_chr_free;
|
||||
}
|
||||
|
||||
static const TypeInfo char_msmouse_type_info = {
|
||||
.name = TYPE_CHARDEV_MSMOUSE,
|
||||
.parent = TYPE_CHARDEV,
|
||||
.instance_size = sizeof(MouseChardev),
|
||||
.instance_finalize = char_msmouse_finalize,
|
||||
.class_init = char_msmouse_class_init,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,11 +123,6 @@ static const TypeInfo char_testdev_type_info = {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "exec/cpu-common.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/balloon.h"
|
||||
#include "trace.h"
|
||||
#include "trace-root.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
2
block.c
2
block.c
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "trace.h"
|
||||
#include "block/trace.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/blockjob.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)
|
||||
|
||||
typedef struct SheepdogAIOCB SheepdogAIOCB;
|
||||
typedef struct BDRVSheepdogState BDRVSheepdogState;
|
||||
|
||||
typedef struct AIOReq {
|
||||
SheepdogAIOCB *aiocb;
|
||||
@@ -334,7 +335,7 @@ enum AIOCBState {
|
||||
|| y->max_affect_data_idx < x->min_affect_data_idx))
|
||||
|
||||
struct SheepdogAIOCB {
|
||||
BlockAIOCB common;
|
||||
BDRVSheepdogState *s;
|
||||
|
||||
QEMUIOVector *qiov;
|
||||
|
||||
@@ -345,9 +346,6 @@ struct SheepdogAIOCB {
|
||||
enum AIOCBState aiocb_type;
|
||||
|
||||
Coroutine *coroutine;
|
||||
void (*aio_done_func)(SheepdogAIOCB *);
|
||||
|
||||
bool cancelable;
|
||||
int nr_pending;
|
||||
|
||||
uint32_t min_affect_data_idx;
|
||||
@@ -365,7 +363,7 @@ struct SheepdogAIOCB {
|
||||
QLIST_ENTRY(SheepdogAIOCB) aiocb_siblings;
|
||||
};
|
||||
|
||||
typedef struct BDRVSheepdogState {
|
||||
struct BDRVSheepdogState {
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
|
||||
@@ -392,7 +390,7 @@ typedef struct BDRVSheepdogState {
|
||||
|
||||
CoQueue overlapping_queue;
|
||||
QLIST_HEAD(inflight_aiocb_head, SheepdogAIOCB) inflight_aiocb_head;
|
||||
} BDRVSheepdogState;
|
||||
};
|
||||
|
||||
typedef struct BDRVSheepdogReopenState {
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* 2. We receive the response in aio_read_response, the fd handler to
|
||||
* the sheepdog connection. If metadata update is needed, we send
|
||||
* the write request to the vdi object in sd_write_done, the write
|
||||
* completion function. We switch back to sd_co_readv/writev after
|
||||
* all the requests belonging to the AIOCB are finished.
|
||||
* the sheepdog connection. We switch back to sd_co_readv/sd_writev
|
||||
* after all the requests belonging to the AIOCB are finished. If
|
||||
* needed, sd_co_writev will send another requests for the vdi object.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
QLIST_REMOVE(aio_req, aio_siblings);
|
||||
g_free(aio_req);
|
||||
|
||||
acb->nr_pending--;
|
||||
}
|
||||
|
||||
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;
|
||||
retry:
|
||||
QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) {
|
||||
if (AIOCBOverlapping(acb, cb)) {
|
||||
qemu_co_queue_wait(&s->overlapping_queue);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
|
||||
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->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
|
||||
acb->aio_done_func = NULL;
|
||||
acb->cancelable = true;
|
||||
acb->coroutine = qemu_coroutine_self();
|
||||
acb->ret = 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->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 */
|
||||
@@ -797,7 +740,6 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
|
||||
while (!QLIST_EMPTY(&s->failed_aio_head)) {
|
||||
aio_req = QLIST_FIRST(&s->failed_aio_head);
|
||||
QLIST_REMOVE(aio_req, aio_siblings);
|
||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||
resend_aioreq(s, aio_req);
|
||||
}
|
||||
}
|
||||
@@ -840,9 +782,6 @@ static void coroutine_fn aio_read_response(void *opaque)
|
||||
|
||||
switch (acb->aiocb_type) {
|
||||
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)) {
|
||||
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) {
|
||||
case SD_RES_SUCCESS:
|
||||
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);
|
||||
}
|
||||
resend_aioreq(s, aio_req);
|
||||
goto out;
|
||||
return;
|
||||
default:
|
||||
acb->ret = -EIO;
|
||||
error_report("%s", sd_strerror(rsp.result));
|
||||
break;
|
||||
}
|
||||
|
||||
free_aio_req(s, aio_req);
|
||||
if (!acb->nr_pending) {
|
||||
g_free(aio_req);
|
||||
|
||||
if (!--acb->nr_pending) {
|
||||
/*
|
||||
* We've finished all requests which belong to the AIOCB, so
|
||||
* 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;
|
||||
|
||||
err:
|
||||
s->co_recv = NULL;
|
||||
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;
|
||||
bool create = aio_req->create;
|
||||
|
||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||
|
||||
if (!nr_copies) {
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
BDRVSheepdogState *s = acb->common.bs->opaque;
|
||||
BDRVSheepdogState *s = acb->s;
|
||||
struct iovec iov;
|
||||
AIOReq *aio_req;
|
||||
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;
|
||||
if (mn <= mx) {
|
||||
/* we need to update the vdi object. */
|
||||
++acb->nr_pending;
|
||||
offset = sizeof(s->inode) - sizeof(s->inode.data_vdi_id) +
|
||||
mn * 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);
|
||||
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
|
||||
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);
|
||||
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
acb->aiocb_type = AIOCB_WRITE_UDATA;
|
||||
return;
|
||||
if (--acb->nr_pending) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
}
|
||||
|
||||
sd_finish_aiocb(acb);
|
||||
}
|
||||
|
||||
/* 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
|
||||
* 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;
|
||||
unsigned long len, done = 0, total = acb->nb_sectors * BDRV_SECTOR_SIZE;
|
||||
unsigned long idx;
|
||||
uint32_t object_size;
|
||||
uint64_t oid;
|
||||
uint64_t offset;
|
||||
BDRVSheepdogState *s = acb->common.bs->opaque;
|
||||
BDRVSheepdogState *s = acb->s;
|
||||
SheepdogInode *inode = &s->inode;
|
||||
AIOReq *aio_req;
|
||||
|
||||
@@ -2190,7 +2132,7 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
||||
ret = sd_create_branch(s);
|
||||
if (ret) {
|
||||
acb->ret = -EIO;
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2255,8 +2197,6 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
||||
old_oid,
|
||||
acb->aiocb_type == AIOCB_DISCARD_OBJ ?
|
||||
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,
|
||||
acb->aiocb_type);
|
||||
done:
|
||||
@@ -2264,31 +2204,25 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
||||
idx++;
|
||||
done += len;
|
||||
}
|
||||
out:
|
||||
if (!--acb->nr_pending) {
|
||||
return acb->ret;
|
||||
if (--acb->nr_pending) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool check_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *aiocb)
|
||||
static void sd_aio_complete(SheepdogAIOCB *acb)
|
||||
{
|
||||
SheepdogAIOCB *cb;
|
||||
|
||||
QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) {
|
||||
if (AIOCBOverlapping(aiocb, cb)) {
|
||||
return true;
|
||||
}
|
||||
if (acb->aiocb_type == AIOCB_FLUSH_CACHE) {
|
||||
return;
|
||||
}
|
||||
|
||||
QLIST_INSERT_HEAD(&s->inflight_aiocb_head, aiocb, aiocb_siblings);
|
||||
return false;
|
||||
QLIST_REMOVE(acb, aiocb_siblings);
|
||||
qemu_co_queue_restart_all(&acb->s->overlapping_queue);
|
||||
}
|
||||
|
||||
static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
SheepdogAIOCB *acb;
|
||||
SheepdogAIOCB acb;
|
||||
int ret;
|
||||
int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE;
|
||||
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);
|
||||
acb->aio_done_func = sd_write_done;
|
||||
acb->aiocb_type = AIOCB_WRITE_UDATA;
|
||||
sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_WRITE_UDATA);
|
||||
sd_co_rw_vector(&acb);
|
||||
sd_write_done(&acb);
|
||||
sd_aio_complete(&acb);
|
||||
|
||||
retry:
|
||||
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;
|
||||
return acb.ret;
|
||||
}
|
||||
|
||||
static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
SheepdogAIOCB *acb;
|
||||
int ret;
|
||||
SheepdogAIOCB acb;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
|
||||
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors);
|
||||
acb->aiocb_type = AIOCB_READ_UDATA;
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_READ_UDATA);
|
||||
sd_co_rw_vector(&acb);
|
||||
sd_aio_complete(&acb);
|
||||
|
||||
retry:
|
||||
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;
|
||||
return acb.ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
|
||||
{
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
SheepdogAIOCB *acb;
|
||||
SheepdogAIOCB acb;
|
||||
AIOReq *aio_req;
|
||||
|
||||
if (s->cache_flags != SD_FLAG_CMD_CACHE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
acb = sd_aio_setup(bs, NULL, 0, 0);
|
||||
acb->aiocb_type = AIOCB_FLUSH_CACHE;
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
sd_aio_setup(&acb, s, NULL, 0, 0, AIOCB_FLUSH_CACHE);
|
||||
|
||||
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);
|
||||
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();
|
||||
return acb->ret;
|
||||
if (--acb.nr_pending) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
sd_aio_complete(&acb);
|
||||
return acb.ret;
|
||||
}
|
||||
|
||||
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,
|
||||
int count)
|
||||
{
|
||||
SheepdogAIOCB *acb;
|
||||
SheepdogAIOCB acb;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
int ret;
|
||||
QEMUIOVector discard_iov;
|
||||
struct iovec iov;
|
||||
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)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
acb = sd_aio_setup(bs, &discard_iov, offset >> BDRV_SECTOR_BITS,
|
||||
count >> BDRV_SECTOR_BITS);
|
||||
acb->aiocb_type = AIOCB_DISCARD_OBJ;
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
sd_aio_setup(&acb, s, &discard_iov, offset >> BDRV_SECTOR_BITS,
|
||||
count >> BDRV_SECTOR_BITS, AIOCB_DISCARD_OBJ);
|
||||
sd_co_rw_vector(&acb);
|
||||
sd_aio_complete(&acb);
|
||||
|
||||
retry:
|
||||
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;
|
||||
return acb.ret;
|
||||
}
|
||||
|
||||
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_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_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
|
||||
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 "sysemu/sysemu.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "trace.h"
|
||||
#include "block/nbd.h"
|
||||
#include "io/channel-socket.h"
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "trace.h"
|
||||
#include "block/trace.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/help_option.h"
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "trace.h"
|
||||
#include "block/block.h"
|
||||
#include "block/blockjob_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="-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="-Wno-initializer-overrides $gcc_flags"
|
||||
gcc_flags="-Wno-string-plus-int $gcc_flags"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "trace.h"
|
||||
#include "trace-root.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg.h"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
|
||||
@@ -6,6 +6,7 @@ CONFIG_VGA=y
|
||||
CONFIG_NAND=y
|
||||
CONFIG_ECC=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_SD=y
|
||||
CONFIG_MAX7310=y
|
||||
@@ -108,6 +109,7 @@ CONFIG_FSL_IMX25=y
|
||||
|
||||
CONFIG_IMX_I2C=y
|
||||
|
||||
CONFIG_PCIE_PORT=y
|
||||
CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
|
||||
@@ -15,6 +15,7 @@ CONFIG_IPMI_EXTERN=y
|
||||
CONFIG_ISA_IPMI_KCS=y
|
||||
CONFIG_ISA_IPMI_BT=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
@@ -51,8 +52,10 @@ CONFIG_PVPANIC=y
|
||||
CONFIG_MEM_HOTPLUG=y
|
||||
CONFIG_NVDIMM=y
|
||||
CONFIG_ACPI_NVDIMM=y
|
||||
CONFIG_PCIE_PORT=y
|
||||
CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
CONFIG_SMBIOS=y
|
||||
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
|
||||
CONFIG_PXB=y
|
||||
|
||||
@@ -9,6 +9,7 @@ CONFIG_VGA_ISA_MM=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Default configuration for moxie-softmmu
|
||||
|
||||
CONFIG_ISA_BUS=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_VGA=y
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
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=y
|
||||
CONFIG_USB_UHCI=y
|
||||
@@ -27,6 +29,7 @@ CONFIG_AHCI=y
|
||||
CONFIG_ESP=y
|
||||
CONFIG_ESP_PCI=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_SERIAL_PCI=y
|
||||
CONFIG_IPACK=y
|
||||
CONFIG_WDT_IB6300ESB=y
|
||||
|
||||
@@ -18,6 +18,7 @@ CONFIG_I82378=y
|
||||
CONFIG_PC87312=y
|
||||
CONFIG_MACIO=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_CS4231A=y
|
||||
CONFIG_CUDA=y
|
||||
CONFIG_ADB=y
|
||||
CONFIG_MAC_NVRAM=y
|
||||
@@ -45,5 +46,7 @@ CONFIG_PLATFORM_BUS=y
|
||||
CONFIG_ETSEC=y
|
||||
CONFIG_LIBDECNUMBER=y
|
||||
# For PReP
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_RS6000_MC=y
|
||||
|
||||
@@ -52,6 +52,8 @@ CONFIG_XICS=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||
# For PReP
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_MEM_HOTPLUG=y
|
||||
CONFIG_RS6000_MC=y
|
||||
|
||||
@@ -5,6 +5,7 @@ include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_OPENPIC=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_SH4=y
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_SH4=y
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Default configuration for sparc-softmmu
|
||||
|
||||
CONFIG_ISA_BUS=y
|
||||
CONFIG_ECC=y
|
||||
CONFIG_ESP=y
|
||||
CONFIG_ESCC=y
|
||||
|
||||
@@ -5,6 +5,7 @@ include usb.mak
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Default configuration for unicore32-softmmu
|
||||
CONFIG_ISA_BUS=y
|
||||
CONFIG_PUV3=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PCKBD=y
|
||||
|
||||
@@ -15,6 +15,7 @@ CONFIG_IPMI_EXTERN=y
|
||||
CONFIG_ISA_IPMI_KCS=y
|
||||
CONFIG_ISA_IPMI_BT=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
@@ -51,8 +52,10 @@ CONFIG_PVPANIC=y
|
||||
CONFIG_MEM_HOTPLUG=y
|
||||
CONFIG_NVDIMM=y
|
||||
CONFIG_ACPI_NVDIMM=y
|
||||
CONFIG_PCIE_PORT=y
|
||||
CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
CONFIG_SMBIOS=y
|
||||
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
|
||||
CONFIG_PXB=y
|
||||
|
||||
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 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_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_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_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))
|
||||
|
||||
/* The mask for an VX form instruction. */
|
||||
#define VX_MASK VX(0x3f, 0x7ff)
|
||||
|
||||
/* An VA form instruction. */
|
||||
/* A VA form instruction. */
|
||||
#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)
|
||||
|
||||
/* An VXR form instruction. */
|
||||
/* A VXR form instruction. */
|
||||
#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff))
|
||||
|
||||
/* The mask for a VXR form instruction. */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "trace.h"
|
||||
#include "trace-root.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
|
||||
@@ -27,18 +27,44 @@ for debugging, profiling, and observing execution.
|
||||
|
||||
== Trace events ==
|
||||
|
||||
=== Sub-directory setup ===
|
||||
|
||||
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
|
||||
arguments, and the format string which can be used for pretty-printing:
|
||||
in a local "trace-events" file. All directories which contain "trace-events"
|
||||
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"
|
||||
qemu_vfree(void *ptr) "ptr %p"
|
||||
The individual "trace-events" files are merged into a "trace-events-all" file,
|
||||
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 top level Makefile.objs. During build the individual files are combined
|
||||
to create a "trace-events-all" file, which is processed by the "tracetool"
|
||||
script during build to generate code for the trace events. The
|
||||
"trace-events-all" file is also installed into "/usr/share/qemu".
|
||||
In the sub-directory the following files will be automatically generated
|
||||
|
||||
- trace.c - the trace event state declarations
|
||||
- trace.h - the trace event enums and probe functions
|
||||
- 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:
|
||||
|
||||
@@ -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,
|
||||
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 ===
|
||||
|
||||
1. Trace state changes in the code. Interesting points in the code usually
|
||||
|
||||
2
exec.c
2
exec.c
@@ -44,7 +44,7 @@
|
||||
#include "sysemu/dma.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/xen-mapcache.h"
|
||||
#include "trace.h"
|
||||
#include "trace-root.h"
|
||||
#endif
|
||||
#include "exec/cpu-all.h"
|
||||
#include "qemu/rcu_queue.h"
|
||||
|
||||
@@ -185,7 +185,7 @@ float128 float128_default_nan(float_status *status)
|
||||
r.high = LIT64(0x7FFF7FFFFFFFFFFF);
|
||||
} else {
|
||||
r.low = LIT64(0x0000000000000000);
|
||||
#if defined(TARGET_S390X)
|
||||
#if defined(TARGET_S390X) || defined(TARGET_PPC)
|
||||
r.high = LIT64(0x7FFF800000000000);
|
||||
#else
|
||||
r.high = LIT64(0xFFFF800000000000);
|
||||
|
||||
1
hmp.c
1
hmp.c
@@ -19,6 +19,7 @@
|
||||
#include "net/eth.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
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_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
|
||||
&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->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_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
|
||||
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"
|
||||
|
||||
@@ -2,7 +2,8 @@ common-obj-$(CONFIG_IPACK) += ipoctal232.o
|
||||
common-obj-$(CONFIG_ESCC) += escc.o
|
||||
common-obj-$(CONFIG_PARALLEL) += parallel.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_VIRTIO) += virtio-console.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)) {
|
||||
vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
|
||||
dev->instance_id_alias,
|
||||
dev->alias_required_for_version);
|
||||
if (vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
|
||||
dev->instance_id_alias,
|
||||
dev->alias_required_for_version,
|
||||
&local_err) < 0) {
|
||||
goto post_realize_fail;
|
||||
}
|
||||
}
|
||||
|
||||
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
|
||||
|
||||
@@ -272,15 +272,11 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
|
||||
static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
int32_t pitch, int32_t addr)
|
||||
{
|
||||
if (!pitch) {
|
||||
return true;
|
||||
}
|
||||
if (pitch < 0) {
|
||||
int64_t min = addr
|
||||
+ ((int64_t)s->cirrus_blt_height-1) * pitch;
|
||||
int32_t max = addr
|
||||
+ s->cirrus_blt_width;
|
||||
if (min < 0 || max > s->vga.vram_size) {
|
||||
+ ((int64_t)s->cirrus_blt_height - 1) * pitch
|
||||
- s->cirrus_blt_width;
|
||||
if (min < -1 || addr >= s->vga.vram_size) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@@ -294,8 +290,11 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
|
||||
static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
|
||||
bool zero_src_pitch_ok)
|
||||
{
|
||||
int32_t check_pitch;
|
||||
|
||||
/* should be the case, see cirrus_bitblt_start */
|
||||
assert(s->cirrus_blt_width > 0);
|
||||
assert(s->cirrus_blt_height > 0);
|
||||
@@ -304,15 +303,25 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!s->cirrus_blt_dstpitch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
|
||||
s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
|
||||
s->cirrus_blt_dstaddr)) {
|
||||
return true;
|
||||
}
|
||||
if (dst_only) {
|
||||
return false;
|
||||
}
|
||||
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
|
||||
s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
|
||||
|
||||
check_pitch = s->cirrus_blt_srcpitch;
|
||||
if (!zero_src_pitch_ok && !check_pitch) {
|
||||
check_pitch = s->cirrus_blt_width;
|
||||
}
|
||||
|
||||
if (blit_region_is_unsafe(s, check_pitch,
|
||||
s->cirrus_blt_srcaddr)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -661,9 +670,14 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
|
||||
int off_cur;
|
||||
int off_cur_end;
|
||||
|
||||
if (off_pitch < 0) {
|
||||
off_begin -= bytesperline - 1;
|
||||
}
|
||||
|
||||
for (y = 0; y < lines; y++) {
|
||||
off_cur = off_begin;
|
||||
off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
|
||||
assert(off_cur_end >= off_cur);
|
||||
memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
|
||||
off_begin += off_pitch;
|
||||
}
|
||||
@@ -674,10 +688,11 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
|
||||
{
|
||||
uint8_t *dst;
|
||||
|
||||
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 (blit_is_unsafe(s, false, true)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*s->cirrus_rop) (s, dst, src,
|
||||
s->cirrus_blt_dstpitch, 0,
|
||||
@@ -694,11 +709,11 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||
{
|
||||
cirrus_fill_t rop_func;
|
||||
|
||||
if (blit_is_unsafe(s, true)) {
|
||||
if (blit_is_unsafe(s, true, true)) {
|
||||
return 0;
|
||||
}
|
||||
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_width, s->cirrus_blt_height);
|
||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
||||
@@ -716,9 +731,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||
|
||||
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
||||
{
|
||||
return cirrus_bitblt_common_patterncopy(s,
|
||||
s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
|
||||
s->cirrus_addr_mask));
|
||||
return cirrus_bitblt_common_patterncopy(s, s->vga.vram_ptr +
|
||||
(s->cirrus_blt_srcaddr & ~7));
|
||||
}
|
||||
|
||||
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
@@ -772,10 +786,8 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
if (notify)
|
||||
graphic_hw_update(s->vga.con);
|
||||
|
||||
(*s->cirrus_rop) (s, s->vga.vram_ptr +
|
||||
(s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
||||
s->vga.vram_ptr +
|
||||
(s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
|
||||
(*s->cirrus_rop) (s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
|
||||
s->vga.vram_ptr + s->cirrus_blt_srcaddr,
|
||||
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
|
||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||
|
||||
@@ -798,7 +810,7 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
|
||||
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||
{
|
||||
if (blit_is_unsafe(s, false))
|
||||
if (blit_is_unsafe(s, false, false))
|
||||
return 0;
|
||||
|
||||
return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
|
||||
@@ -826,8 +838,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
|
||||
} else {
|
||||
/* at least one scan line */
|
||||
do {
|
||||
(*s->cirrus_rop)(s, s->vga.vram_ptr +
|
||||
(s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
||||
(*s->cirrus_rop)(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
|
||||
s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
|
||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
|
||||
s->cirrus_blt_width, 1);
|
||||
@@ -946,6 +957,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
|
||||
s->cirrus_blt_modeext = s->vga.gr[0x33];
|
||||
blt_rop = s->vga.gr[0x32];
|
||||
|
||||
s->cirrus_blt_dstaddr &= s->cirrus_addr_mask;
|
||||
s->cirrus_blt_srcaddr &= s->cirrus_addr_mask;
|
||||
|
||||
#ifdef DEBUG_BITBLT
|
||||
printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
|
||||
blt_rop,
|
||||
|
||||
@@ -306,12 +306,11 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
|
||||
|
||||
static ram_addr_t qxl_rom_size(void)
|
||||
{
|
||||
uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
|
||||
sizeof(qxl_modes);
|
||||
uint32_t rom_size = 8192; /* two pages */
|
||||
#define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes))
|
||||
#define QXL_ROM_SZ 8192
|
||||
|
||||
QEMU_BUILD_BUG_ON(required_rom_size > rom_size);
|
||||
return rom_size;
|
||||
QEMU_BUILD_BUG_ON(QXL_REQUIRED_SZ > QXL_ROM_SZ);
|
||||
return QXL_ROM_SZ;
|
||||
}
|
||||
|
||||
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
|
||||
virtio_gpu_features(bool virgl) "virgl %d"
|
||||
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_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"
|
||||
|
||||
@@ -143,8 +143,10 @@ static void mpc8xxx_gpio_write(void *opaque, hwaddr offset,
|
||||
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->odr = 0;
|
||||
s->dat = 0;
|
||||
@@ -180,33 +182,33 @@ static const MemoryRegionOps mpc8xxx_gpio_ops = {
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static int mpc8xxx_gpio_initfn(SysBusDevice *sbd)
|
||||
static void mpc8xxx_gpio_initfn(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
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_irq(sbd, &s->irq);
|
||||
qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 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)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = mpc8xxx_gpio_initfn;
|
||||
dc->vmsd = &vmstate_mpc8xxx_gpio;
|
||||
dc->reset = mpc8xxx_gpio_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo mpc8xxx_gpio_info = {
|
||||
.name = TYPE_MPC8XXX_GPIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MPC8XXXGPIOState),
|
||||
.instance_init = mpc8xxx_gpio_initfn,
|
||||
.class_init = mpc8xxx_gpio_class_init,
|
||||
};
|
||||
|
||||
|
||||
@@ -1485,8 +1485,16 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
|
||||
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) {
|
||||
sz = 1 << (ctz64(~(addr | (VTD_PAGE_MASK_4K - 1))) + 1);
|
||||
sz = (VTD_PAGE_SIZE * 2) << cto64(addr >> VTD_PAGE_SHIFT);
|
||||
addr &= ~(sz - 1);
|
||||
} else {
|
||||
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 (!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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
# 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
|
||||
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_control_status(uint64_t val) "MMIO_STATUS state 0x%"PRIx64
|
||||
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_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
|
||||
|
||||
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 */
|
||||
#define UNPLUG_ALL_IDE_DISKS 1
|
||||
#define UNPLUG_ALL_DISKS 1
|
||||
#define UNPLUG_ALL_NICS 2
|
||||
#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);
|
||||
}
|
||||
|
||||
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 */
|
||||
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
|
||||
PCI_CLASS_STORAGE_IDE
|
||||
&& strcmp(d->name, "xen-pci-passthrough") != 0) {
|
||||
pci_piix3_xen_ide_unplug(DEVICE(d));
|
||||
} else if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
|
||||
PCI_CLASS_STORAGE_SCSI
|
||||
&& strcmp(d->name, "xen-pci-passthrough") != 0) {
|
||||
object_unparent(OBJECT(d));
|
||||
if (!strcmp(d->name, "xen-pci-passthrough")) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) {
|
||||
case PCI_CLASS_STORAGE_IDE:
|
||||
pci_piix3_xen_ide_unplug(DEVICE(d), aux);
|
||||
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)
|
||||
@@ -134,19 +148,16 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
|
||||
case 0: {
|
||||
PCIDevice *pci_dev = PCI_DEVICE(s);
|
||||
/* 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. */
|
||||
if (val & UNPLUG_ALL_IDE_DISKS) {
|
||||
if (val & (UNPLUG_ALL_DISKS | UNPLUG_AUX_IDE_DISKS)) {
|
||||
DPRINTF("unplug disks\n");
|
||||
pci_unplug_disks(pci_dev->bus);
|
||||
pci_unplug_disks(pci_dev->bus, val);
|
||||
}
|
||||
if (val & UNPLUG_ALL_NICS) {
|
||||
DPRINTF("unplug nics\n");
|
||||
pci_unplug_nics(pci_dev->bus);
|
||||
}
|
||||
if (val & UNPLUG_AUX_IDE_DISKS) {
|
||||
DPRINTF("unplug auxiliary disks not supported\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
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 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);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
switch (val) {
|
||||
case 1:
|
||||
pci_unplug_disks(pci_dev->bus);
|
||||
pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS);
|
||||
break;
|
||||
case 2:
|
||||
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);
|
||||
}
|
||||
|
||||
int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux)
|
||||
{
|
||||
PCIIDEState *pci_ide;
|
||||
DriveInfo *di;
|
||||
@@ -174,7 +174,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *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);
|
||||
if (di != NULL && !di->media_cd) {
|
||||
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_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_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_write_mouse(void *opaque, int val) "%p val %d"
|
||||
ps2_kbd_reset(void *opaque) "%p"
|
||||
|
||||
@@ -329,7 +329,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
|
||||
instance_id = -1;
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -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_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_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
|
||||
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_I82378) += i82378.o
|
||||
common-obj-$(CONFIG_PC87312) += pc87312.o
|
||||
|
||||
@@ -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 */
|
||||
s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -898,8 +898,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||
qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
|
||||
ivshmem_read, NULL, s, NULL, true);
|
||||
|
||||
if (ivshmem_setup_interrupts(s) < 0) {
|
||||
error_setg(errp, "failed to initialize interrupts");
|
||||
if (ivshmem_setup_interrupts(s, errp) < 0) {
|
||||
error_prepend(errp, "Failed to initialize interrupts: ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ e1000e_init_msix(E1000EState *s)
|
||||
E1000E_MSIX_IDX, E1000E_MSIX_TABLE,
|
||||
&s->msix,
|
||||
E1000E_MSIX_IDX, E1000E_MSIX_PBA,
|
||||
0xA0);
|
||||
0xA0, NULL);
|
||||
|
||||
if (res < 0) {
|
||||
trace_e1000e_msix_init_fail(res);
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "etsec.h"
|
||||
#include "registers.h"
|
||||
|
||||
@@ -1256,14 +1256,16 @@ static int rocker_msix_init(Rocker *r)
|
||||
{
|
||||
PCIDevice *dev = PCI_DEVICE(r);
|
||||
int err;
|
||||
Error *local_err = NULL;
|
||||
|
||||
err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
|
||||
&r->msix_bar,
|
||||
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
|
||||
&r->msix_bar,
|
||||
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
|
||||
0);
|
||||
0, &local_err);
|
||||
if (err) {
|
||||
error_report_err(local_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_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_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_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_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_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_sw_reset(void) "Doing SW 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_set_rctl(uint32_t rctl) "RCTL = 0x%x"
|
||||
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_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)"
|
||||
@@ -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_irq_set_cause(uint32_t cause) "IRQ cause set 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_msi_notify_postponed(void) "Sending MSI 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_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_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"
|
||||
|
||||
@@ -2191,7 +2191,7 @@ vmxnet3_init_msix(VMXNET3State *s)
|
||||
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
|
||||
&s->msix_bar,
|
||||
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
|
||||
VMXNET3_MSIX_OFFSET(s));
|
||||
VMXNET3_MSIX_OFFSET(s), NULL);
|
||||
|
||||
if (0 > 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_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_IOH3420) += ioh3420.o
|
||||
common-obj-$(CONFIG_I82801B11) += i82801b11.o
|
||||
|
||||
87
hw/pci-bridge/gen_pcie_root_port.c
Normal file
87
hw/pci-bridge/gen_pcie_root_port.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Generic PCI Express Root Port emulation
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat Inc
|
||||
*
|
||||
* Authors:
|
||||
* Marcel Apfelbaum <marcel@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/pci/msix.h"
|
||||
#include "hw/pci/pcie_port.h"
|
||||
|
||||
#define TYPE_GEN_PCIE_ROOT_PORT "pcie-root-port"
|
||||
|
||||
#define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100
|
||||
#define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1
|
||||
|
||||
static uint8_t gen_rp_aer_vector(const PCIDevice *d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_rp_interrupts_init(PCIDevice *d, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = msix_init_exclusive_bar(d, GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR, 0, errp);
|
||||
|
||||
if (rc < 0) {
|
||||
assert(rc == -ENOTSUP);
|
||||
} else {
|
||||
msix_vector_use(d, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void gen_rp_interrupts_uninit(PCIDevice *d)
|
||||
{
|
||||
msix_uninit_exclusive_bar(d);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_rp_dev = {
|
||||
.name = "pcie-root-port",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = pcie_cap_slot_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
|
||||
VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
|
||||
PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void gen_rp_dev_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
|
||||
|
||||
k->vendor_id = PCI_VENDOR_ID_REDHAT;
|
||||
k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_RP;
|
||||
dc->desc = "PCI Express Root Port";
|
||||
dc->vmsd = &vmstate_rp_dev;
|
||||
rpc->aer_vector = gen_rp_aer_vector;
|
||||
rpc->interrupts_init = gen_rp_interrupts_init;
|
||||
rpc->interrupts_uninit = gen_rp_interrupts_uninit;
|
||||
rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;
|
||||
}
|
||||
|
||||
static const TypeInfo gen_rp_dev_info = {
|
||||
.name = TYPE_GEN_PCIE_ROOT_PORT,
|
||||
.parent = TYPE_PCIE_ROOT_PORT,
|
||||
.class_init = gen_rp_dev_class_init,
|
||||
};
|
||||
|
||||
static void gen_rp_register_types(void)
|
||||
{
|
||||
type_register_static(&gen_rp_dev_info);
|
||||
}
|
||||
type_init(gen_rp_register_types)
|
||||
@@ -61,119 +61,28 @@ static uint8_t ioh3420_aer_vector(const PCIDevice *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ioh3420_aer_vector_update(PCIDevice *d)
|
||||
static int ioh3420_interrupts_init(PCIDevice *d, Error **errp)
|
||||
{
|
||||
pcie_aer_root_set_vector(d, ioh3420_aer_vector(d));
|
||||
}
|
||||
|
||||
static void ioh3420_write_config(PCIDevice *d,
|
||||
uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
uint32_t root_cmd =
|
||||
pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
|
||||
|
||||
pci_bridge_write_config(d, address, val, len);
|
||||
ioh3420_aer_vector_update(d);
|
||||
pcie_cap_slot_write_config(d, address, val, len);
|
||||
pcie_aer_write_config(d, address, val, len);
|
||||
pcie_aer_root_write_config(d, address, val, len, root_cmd);
|
||||
}
|
||||
|
||||
static void ioh3420_reset(DeviceState *qdev)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(qdev);
|
||||
|
||||
ioh3420_aer_vector_update(d);
|
||||
pcie_cap_root_reset(d);
|
||||
pcie_cap_deverr_reset(d);
|
||||
pcie_cap_slot_reset(d);
|
||||
pcie_cap_arifwd_reset(d);
|
||||
pcie_aer_root_reset(d);
|
||||
pci_bridge_reset(qdev);
|
||||
pci_bridge_disable_base_limit(d);
|
||||
}
|
||||
|
||||
static int ioh3420_initfn(PCIDevice *d)
|
||||
{
|
||||
PCIEPort *p = PCIE_PORT(d);
|
||||
PCIESlot *s = PCIE_SLOT(d);
|
||||
int rc;
|
||||
Error *err = NULL;
|
||||
|
||||
pci_config_set_interrupt_pin(d->config, 1);
|
||||
pci_bridge_initfn(d, TYPE_PCIE_BUS);
|
||||
pcie_port_init_reg(d);
|
||||
|
||||
rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
|
||||
IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
|
||||
if (rc < 0) {
|
||||
goto err_bridge;
|
||||
}
|
||||
Error *local_err = NULL;
|
||||
|
||||
rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
|
||||
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
|
||||
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
|
||||
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,
|
||||
&local_err);
|
||||
if (rc < 0) {
|
||||
assert(rc == -ENOTSUP);
|
||||
error_report_err(err);
|
||||
goto err_bridge;
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
|
||||
if (rc < 0) {
|
||||
goto err_msi;
|
||||
}
|
||||
|
||||
pcie_cap_arifwd_init(d);
|
||||
pcie_cap_deverr_init(d);
|
||||
pcie_cap_slot_init(d, s->slot);
|
||||
pcie_cap_root_init(d);
|
||||
|
||||
pcie_chassis_create(s->chassis);
|
||||
rc = pcie_chassis_add_slot(s);
|
||||
if (rc < 0) {
|
||||
goto err_pcie_cap;
|
||||
}
|
||||
|
||||
rc = pcie_aer_init(d, PCI_ERR_VER, IOH_EP_AER_OFFSET,
|
||||
PCI_ERR_SIZEOF, &err);
|
||||
if (rc < 0) {
|
||||
error_report_err(err);
|
||||
goto err;
|
||||
}
|
||||
pcie_aer_root_init(d);
|
||||
ioh3420_aer_vector_update(d);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
pcie_chassis_del_slot(s);
|
||||
err_pcie_cap:
|
||||
pcie_cap_exit(d);
|
||||
err_msi:
|
||||
msi_uninit(d);
|
||||
err_bridge:
|
||||
pci_bridge_exitfn(d);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ioh3420_exitfn(PCIDevice *d)
|
||||
static void ioh3420_interrupts_uninit(PCIDevice *d)
|
||||
{
|
||||
PCIESlot *s = PCIE_SLOT(d);
|
||||
|
||||
pcie_aer_exit(d);
|
||||
pcie_chassis_del_slot(s);
|
||||
pcie_cap_exit(d);
|
||||
msi_uninit(d);
|
||||
pci_bridge_exitfn(d);
|
||||
}
|
||||
|
||||
static Property ioh3420_props[] = {
|
||||
DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
|
||||
QEMU_PCIE_SLTCAP_PCP_BITNR, true),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_ioh3420 = {
|
||||
.name = "ioh-3240-express-root-port",
|
||||
.version_id = 1,
|
||||
@@ -191,25 +100,25 @@ static void ioh3420_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
|
||||
|
||||
k->is_express = 1;
|
||||
k->is_bridge = 1;
|
||||
k->config_write = ioh3420_write_config;
|
||||
k->init = ioh3420_initfn;
|
||||
k->exit = ioh3420_exitfn;
|
||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||
k->device_id = PCI_DEVICE_ID_IOH_EPORT;
|
||||
k->revision = PCI_DEVICE_ID_IOH_REV;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
dc->desc = "Intel IOH device id 3420 PCIE Root Port";
|
||||
dc->reset = ioh3420_reset;
|
||||
dc->vmsd = &vmstate_ioh3420;
|
||||
dc->props = ioh3420_props;
|
||||
rpc->aer_vector = ioh3420_aer_vector;
|
||||
rpc->interrupts_init = ioh3420_interrupts_init;
|
||||
rpc->interrupts_uninit = ioh3420_interrupts_uninit;
|
||||
rpc->exp_offset = IOH_EP_EXP_OFFSET;
|
||||
rpc->aer_offset = IOH_EP_AER_OFFSET;
|
||||
rpc->ssvid_offset = IOH_EP_SSVID_OFFSET;
|
||||
rpc->ssid = IOH_EP_SSVID_SSID;
|
||||
}
|
||||
|
||||
static const TypeInfo ioh3420_info = {
|
||||
.name = "ioh3420",
|
||||
.parent = TYPE_PCIE_SLOT,
|
||||
.parent = TYPE_PCIE_ROOT_PORT,
|
||||
.class_init = ioh3420_class_init,
|
||||
};
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ static Property pci_bridge_dev_properties[] = {
|
||||
DEFINE_PROP_ON_OFF_AUTO(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, msi,
|
||||
ON_OFF_AUTO_AUTO),
|
||||
DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags,
|
||||
PCI_BRIDGE_DEV_F_SHPC_REQ, true),
|
||||
PCI_BRIDGE_DEV_F_SHPC_REQ, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
171
hw/pci-bridge/pcie_root_port.c
Normal file
171
hw/pci-bridge/pcie_root_port.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Base class for PCI Express Root Ports
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat Inc
|
||||
*
|
||||
* Authors:
|
||||
* Marcel Apfelbaum <marcel@redhat.com>
|
||||
*
|
||||
* Most of the code was migrated from hw/pci-bridge/ioh3420.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/pci/pcie_port.h"
|
||||
|
||||
static void rp_aer_vector_update(PCIDevice *d)
|
||||
{
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
|
||||
|
||||
if (rpc->aer_vector) {
|
||||
pcie_aer_root_set_vector(d, rpc->aer_vector(d));
|
||||
}
|
||||
}
|
||||
|
||||
static void rp_write_config(PCIDevice *d, uint32_t address,
|
||||
uint32_t val, int len)
|
||||
{
|
||||
uint32_t root_cmd =
|
||||
pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
|
||||
|
||||
pci_bridge_write_config(d, address, val, len);
|
||||
rp_aer_vector_update(d);
|
||||
pcie_cap_slot_write_config(d, address, val, len);
|
||||
pcie_aer_write_config(d, address, val, len);
|
||||
pcie_aer_root_write_config(d, address, val, len, root_cmd);
|
||||
}
|
||||
|
||||
static void rp_reset(DeviceState *qdev)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(qdev);
|
||||
|
||||
rp_aer_vector_update(d);
|
||||
pcie_cap_root_reset(d);
|
||||
pcie_cap_deverr_reset(d);
|
||||
pcie_cap_slot_reset(d);
|
||||
pcie_cap_arifwd_reset(d);
|
||||
pcie_aer_root_reset(d);
|
||||
pci_bridge_reset(qdev);
|
||||
pci_bridge_disable_base_limit(d);
|
||||
}
|
||||
|
||||
static void rp_realize(PCIDevice *d, Error **errp)
|
||||
{
|
||||
PCIEPort *p = PCIE_PORT(d);
|
||||
PCIESlot *s = PCIE_SLOT(d);
|
||||
PCIDeviceClass *dc = PCI_DEVICE_GET_CLASS(d);
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
|
||||
int rc;
|
||||
Error *local_err = NULL;
|
||||
|
||||
pci_config_set_interrupt_pin(d->config, 1);
|
||||
pci_bridge_initfn(d, TYPE_PCIE_BUS);
|
||||
pcie_port_init_reg(d);
|
||||
|
||||
rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id, rpc->ssid);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "Can't init SSV ID, error %d", rc);
|
||||
goto err_bridge;
|
||||
}
|
||||
|
||||
if (rpc->interrupts_init) {
|
||||
rc = rpc->interrupts_init(d, &local_err);
|
||||
if (rc < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto err_bridge;
|
||||
}
|
||||
}
|
||||
|
||||
rc = pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT, p->port);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "Can't add Root Port capability, error %d", rc);
|
||||
goto err_int;
|
||||
}
|
||||
|
||||
pcie_cap_arifwd_init(d);
|
||||
pcie_cap_deverr_init(d);
|
||||
pcie_cap_slot_init(d, s->slot);
|
||||
pcie_cap_root_init(d);
|
||||
|
||||
pcie_chassis_create(s->chassis);
|
||||
rc = pcie_chassis_add_slot(s);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "Can't add chassis slot, error %d", rc);
|
||||
goto err_pcie_cap;
|
||||
}
|
||||
|
||||
rc = pcie_aer_init(d, PCI_ERR_VER, rpc->aer_offset,
|
||||
PCI_ERR_SIZEOF, &local_err);
|
||||
if (rc < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto err;
|
||||
}
|
||||
pcie_aer_root_init(d);
|
||||
rp_aer_vector_update(d);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
pcie_chassis_del_slot(s);
|
||||
err_pcie_cap:
|
||||
pcie_cap_exit(d);
|
||||
err_int:
|
||||
if (rpc->interrupts_uninit) {
|
||||
rpc->interrupts_uninit(d);
|
||||
}
|
||||
err_bridge:
|
||||
pci_bridge_exitfn(d);
|
||||
}
|
||||
|
||||
static void rp_exit(PCIDevice *d)
|
||||
{
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
|
||||
PCIESlot *s = PCIE_SLOT(d);
|
||||
|
||||
pcie_aer_exit(d);
|
||||
pcie_chassis_del_slot(s);
|
||||
pcie_cap_exit(d);
|
||||
if (rpc->interrupts_uninit) {
|
||||
rpc->interrupts_uninit(d);
|
||||
}
|
||||
pci_bridge_exitfn(d);
|
||||
}
|
||||
|
||||
static Property rp_props[] = {
|
||||
DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
|
||||
QEMU_PCIE_SLTCAP_PCP_BITNR, true),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void rp_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->is_express = 1;
|
||||
k->is_bridge = 1;
|
||||
k->config_write = rp_write_config;
|
||||
k->realize = rp_realize;
|
||||
k->exit = rp_exit;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
dc->reset = rp_reset;
|
||||
dc->props = rp_props;
|
||||
}
|
||||
|
||||
static const TypeInfo rp_info = {
|
||||
.name = TYPE_PCIE_ROOT_PORT,
|
||||
.parent = TYPE_PCIE_SLOT,
|
||||
.class_init = rp_class_init,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(PCIERootPortClass),
|
||||
};
|
||||
|
||||
static void rp_register_types(void)
|
||||
{
|
||||
type_register_static(&rp_info);
|
||||
}
|
||||
|
||||
type_init(rp_register_types)
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define MSIX_CAP_LENGTH 12
|
||||
|
||||
@@ -238,11 +239,31 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the MSI-X structures */
|
||||
/*
|
||||
* Make PCI device @dev MSI-X capable
|
||||
* @nentries is the max number of MSI-X vectors that the device support.
|
||||
* @table_bar is the MemoryRegion that MSI-X table structure resides.
|
||||
* @table_bar_nr is number of base address register corresponding to @table_bar.
|
||||
* @table_offset indicates the offset that the MSI-X table structure starts with
|
||||
* in @table_bar.
|
||||
* @pba_bar is the MemoryRegion that the Pending Bit Array structure resides.
|
||||
* @pba_bar_nr is number of base address register corresponding to @pba_bar.
|
||||
* @pba_offset indicates the offset that the Pending Bit Array structure
|
||||
* starts with in @pba_bar.
|
||||
* Non-zero @cap_pos puts capability MSI-X at that offset in PCI config space.
|
||||
* @errp is for returning errors.
|
||||
*
|
||||
* Return 0 on success; set @errp and return -errno on error:
|
||||
* -ENOTSUP means lacking msi support for a msi-capable platform.
|
||||
* -EINVAL means capability overlap, happens when @cap_pos is non-zero,
|
||||
* also means a programming error, except device assignment, which can check
|
||||
* if a real HW is broken.
|
||||
*/
|
||||
int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
MemoryRegion *table_bar, uint8_t table_bar_nr,
|
||||
unsigned table_offset, MemoryRegion *pba_bar,
|
||||
uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos)
|
||||
uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos,
|
||||
Error **errp)
|
||||
{
|
||||
int cap;
|
||||
unsigned table_size, pba_size;
|
||||
@@ -250,10 +271,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
|
||||
/* Nothing to do if MSI is not supported by interrupt controller */
|
||||
if (!msi_nonbroken) {
|
||||
error_setg(errp, "MSI-X is not supported by interrupt controller");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) {
|
||||
error_setg(errp, "The number of MSI-X vectors is invalid");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -266,10 +289,13 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
table_offset + table_size > memory_region_size(table_bar) ||
|
||||
pba_offset + pba_size > memory_region_size(pba_bar) ||
|
||||
(table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) {
|
||||
error_setg(errp, "table & pba overlap, or they don't fit in BARs,"
|
||||
" or don't align");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH);
|
||||
cap = pci_add_capability2(dev, PCI_CAP_ID_MSIX,
|
||||
cap_pos, MSIX_CAP_LENGTH, errp);
|
||||
if (cap < 0) {
|
||||
return cap;
|
||||
}
|
||||
@@ -306,7 +332,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
}
|
||||
|
||||
int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
|
||||
uint8_t bar_nr)
|
||||
uint8_t bar_nr, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
char *name;
|
||||
@@ -338,7 +364,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
|
||||
ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
|
||||
0, &dev->msix_exclusive_bar,
|
||||
bar_nr, bar_pba_offset,
|
||||
0);
|
||||
0, errp);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@@ -447,8 +473,10 @@ void msix_notify(PCIDevice *dev, unsigned vector)
|
||||
{
|
||||
MSIMessage msg;
|
||||
|
||||
if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
|
||||
if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msix_is_masked(dev, vector)) {
|
||||
msix_set_pending(dev, vector);
|
||||
return;
|
||||
@@ -483,8 +511,10 @@ void msix_reset(PCIDevice *dev)
|
||||
/* Mark vector as used. */
|
||||
int msix_vector_use(PCIDevice *dev, unsigned vector)
|
||||
{
|
||||
if (vector >= dev->msix_entries_nr)
|
||||
if (vector >= dev->msix_entries_nr) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->msix_entry_used[vector]++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2195,7 +2195,7 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
|
||||
snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev)));
|
||||
}
|
||||
pdev->has_rom = true;
|
||||
memory_region_init_ram(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
|
||||
memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
|
||||
vmstate_register_ram(&pdev->rom, &pdev->qdev);
|
||||
ptr = memory_region_get_ram_ptr(&pdev->rom);
|
||||
load_image(path, ptr);
|
||||
|
||||
@@ -16,6 +16,8 @@ obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o
|
||||
obj-y += ppc4xx_pci.o
|
||||
# PReP
|
||||
obj-$(CONFIG_PREP) += prep.o
|
||||
obj-$(CONFIG_PREP) += prep_systemio.o
|
||||
obj-${CONFIG_RS6000_MC} += rs6000_mc.o
|
||||
# OldWorld PowerMac
|
||||
obj-$(CONFIG_MAC) += mac_oldworld.o
|
||||
# NewWorld PowerMac
|
||||
|
||||
@@ -827,6 +827,12 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||
env = &cpu->env;
|
||||
cs = CPU(cpu);
|
||||
|
||||
if (env->mmu_model != POWERPC_MMU_BOOKE206) {
|
||||
fprintf(stderr, "MMU model %i not supported by this machine.\n",
|
||||
env->mmu_model);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!firstenv) {
|
||||
firstenv = env;
|
||||
}
|
||||
@@ -1049,27 +1055,18 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||
boot_info->dt_size = dt_size;
|
||||
}
|
||||
|
||||
static int e500_ccsr_initfn(SysBusDevice *dev)
|
||||
static void e500_ccsr_initfn(Object *obj)
|
||||
{
|
||||
PPCE500CCSRState *ccsr;
|
||||
|
||||
ccsr = CCSR(dev);
|
||||
memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr",
|
||||
PPCE500CCSRState *ccsr = CCSR(obj);
|
||||
memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
|
||||
MPC8544_CCSRBAR_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void e500_ccsr_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
k->init = e500_ccsr_initfn;
|
||||
}
|
||||
|
||||
static const TypeInfo e500_ccsr_info = {
|
||||
.name = TYPE_CCSR,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PPCE500CCSRState),
|
||||
.class_init = e500_ccsr_class_init,
|
||||
.instance_init = e500_ccsr_initfn,
|
||||
};
|
||||
|
||||
static void e500_register_types(void)
|
||||
|
||||
@@ -381,7 +381,7 @@ static void ppc_powernv_init(MachineState *machine)
|
||||
|
||||
fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
|
||||
if (fw_size < 0) {
|
||||
hw_error("qemu: could not load OPAL '%s'\n", fw_filename);
|
||||
error_report("qemu: could not load OPAL '%s'", fw_filename);
|
||||
exit(1);
|
||||
}
|
||||
g_free(fw_filename);
|
||||
@@ -393,8 +393,8 @@ static void ppc_powernv_init(MachineState *machine)
|
||||
kernel_size = load_image_targphys(machine->kernel_filename,
|
||||
KERNEL_LOAD_ADDR, 0x2000000);
|
||||
if (kernel_size < 0) {
|
||||
hw_error("qemu: could not load kernel'%s'\n",
|
||||
machine->kernel_filename);
|
||||
error_report("qemu: could not load kernel'%s'",
|
||||
machine->kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
73
hw/ppc/ppc.c
73
hw/ppc/ppc.c
@@ -847,9 +847,8 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
|
||||
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
|
||||
}
|
||||
|
||||
static void timebase_pre_save(void *opaque)
|
||||
static void timebase_save(PPCTimebase *tb)
|
||||
{
|
||||
PPCTimebase *tb = opaque;
|
||||
uint64_t ticks = cpu_get_host_ticks();
|
||||
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
|
||||
|
||||
@@ -858,43 +857,30 @@ static void timebase_pre_save(void *opaque)
|
||||
return;
|
||||
}
|
||||
|
||||
/* not used anymore, we keep it for compatibility */
|
||||
tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
|
||||
/*
|
||||
* tb_offset is only expected to be changed by migration so
|
||||
* tb_offset is only expected to be changed by QEMU so
|
||||
* there is no need to update it from KVM here
|
||||
*/
|
||||
tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
|
||||
}
|
||||
|
||||
static int timebase_post_load(void *opaque, int version_id)
|
||||
static void timebase_load(PPCTimebase *tb)
|
||||
{
|
||||
PPCTimebase *tb_remote = opaque;
|
||||
CPUState *cpu;
|
||||
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
|
||||
int64_t tb_off_adj, tb_off, ns_diff;
|
||||
int64_t migration_duration_ns, migration_duration_tb, guest_tb, host_ns;
|
||||
int64_t tb_off_adj, tb_off;
|
||||
unsigned long freq;
|
||||
|
||||
if (!first_ppc_cpu->env.tb_env) {
|
||||
error_report("No timebase object");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
freq = first_ppc_cpu->env.tb_env->tb_freq;
|
||||
/*
|
||||
* Calculate timebase on the destination side of migration.
|
||||
* The destination timebase must be not less than the source timebase.
|
||||
* We try to adjust timebase by downtime if host clocks are not
|
||||
* too much out of sync (1 second for now).
|
||||
*/
|
||||
host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
|
||||
ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns);
|
||||
migration_duration_ns = MIN(NANOSECONDS_PER_SECOND, ns_diff);
|
||||
migration_duration_tb = muldiv64(freq, migration_duration_ns,
|
||||
NANOSECONDS_PER_SECOND);
|
||||
guest_tb = tb_remote->guest_timebase + MIN(0, migration_duration_tb);
|
||||
|
||||
tb_off_adj = guest_tb - cpu_get_host_ticks();
|
||||
tb_off_adj = tb->guest_timebase - cpu_get_host_ticks();
|
||||
|
||||
tb_off = first_ppc_cpu->env.tb_env->tb_offset;
|
||||
trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
|
||||
@@ -904,9 +890,44 @@ static int timebase_post_load(void *opaque, int version_id)
|
||||
CPU_FOREACH(cpu) {
|
||||
PowerPCCPU *pcpu = POWERPC_CPU(cpu);
|
||||
pcpu->env.tb_env->tb_offset = tb_off_adj;
|
||||
#if defined(CONFIG_KVM)
|
||||
kvm_set_one_reg(cpu, KVM_REG_PPC_TB_OFFSET,
|
||||
&pcpu->env.tb_env->tb_offset);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
void cpu_ppc_clock_vm_state_change(void *opaque, int running,
|
||||
RunState state)
|
||||
{
|
||||
PPCTimebase *tb = opaque;
|
||||
|
||||
if (running) {
|
||||
timebase_load(tb);
|
||||
} else {
|
||||
timebase_save(tb);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When migrating, read the clock just before migration,
|
||||
* so that the guest clock counts during the events
|
||||
* between:
|
||||
*
|
||||
* * vm_stop()
|
||||
* *
|
||||
* * pre_save()
|
||||
*
|
||||
* This reduces clock difference on migration from 5s
|
||||
* to 0.1s (when max_downtime == 5s), because sending the
|
||||
* final pages of memory (which happens between vm_stop()
|
||||
* and pre_save()) takes max_downtime.
|
||||
*/
|
||||
static void timebase_pre_save(void *opaque)
|
||||
{
|
||||
PPCTimebase *tb = opaque;
|
||||
|
||||
timebase_save(tb);
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_ppc_timebase = {
|
||||
@@ -915,7 +936,6 @@ const VMStateDescription vmstate_ppc_timebase = {
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.pre_save = timebase_pre_save,
|
||||
.post_load = timebase_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT64(guest_timebase, PPCTimebase),
|
||||
VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
|
||||
@@ -950,13 +970,6 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
||||
}
|
||||
|
||||
/* Specific helpers for POWER & PowerPC 601 RTC */
|
||||
#if 0
|
||||
static clk_setup_cb cpu_ppc601_rtc_init (CPUPPCState *env)
|
||||
{
|
||||
return cpu_ppc_tb_init(env, 7812500);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
|
||||
{
|
||||
_cpu_ppc_store_tbu(env, value);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user