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.status | ||||||
| /config-temp | /config-temp | ||||||
| /trace-events-all | /trace-events-all | ||||||
| /trace/generated-tracers.h |  | ||||||
| /trace/generated-tracers.c |  | ||||||
| /trace/generated-tracers-dtrace.h |  | ||||||
| /trace/generated-tracers.dtrace |  | ||||||
| /trace/generated-events.h | /trace/generated-events.h | ||||||
| /trace/generated-events.c | /trace/generated-events.c | ||||||
| /trace/generated-helpers-wrappers.h | /trace/generated-helpers-wrappers.h | ||||||
| /trace/generated-helpers.h | /trace/generated-helpers.h | ||||||
| /trace/generated-helpers.c | /trace/generated-helpers.c | ||||||
| /trace/generated-tcg-tracers.h | /trace/generated-tcg-tracers.h | ||||||
| /trace/generated-ust-provider.h |  | ||||||
| /trace/generated-ust.c |  | ||||||
| /ui/shader/texture-blit-frag.h | /ui/shader/texture-blit-frag.h | ||||||
| /ui/shader/texture-blit-vert.h | /ui/shader/texture-blit-vert.h | ||||||
| *-timestamp | *-timestamp | ||||||
| @@ -120,3 +114,19 @@ tags | |||||||
| TAGS | TAGS | ||||||
| docker-src.* | docker-src.* | ||||||
| *~ | *~ | ||||||
|  | trace.h | ||||||
|  | trace.c | ||||||
|  | trace-ust.h | ||||||
|  | trace-ust.h | ||||||
|  | trace-dtrace.h | ||||||
|  | trace-dtrace.dtrace | ||||||
|  | trace-root.h | ||||||
|  | trace-root.c | ||||||
|  | trace-ust-root.h | ||||||
|  | trace-ust-root.h | ||||||
|  | trace-ust-all.h | ||||||
|  | trace-ust-all.c | ||||||
|  | trace-dtrace-root.h | ||||||
|  | trace-dtrace-root.dtrace | ||||||
|  | trace-ust-all.h | ||||||
|  | trace-ust-all.c | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								MAINTAINERS
									
									
									
									
									
								
							| @@ -323,7 +323,7 @@ Guest CPU Cores (Xen): | |||||||
| X86 | X86 | ||||||
| M: Stefano Stabellini <sstabellini@kernel.org> | M: Stefano Stabellini <sstabellini@kernel.org> | ||||||
| M: Anthony Perard <anthony.perard@citrix.com> | M: Anthony Perard <anthony.perard@citrix.com> | ||||||
| L: xen-devel@lists.xensource.com | L: xen-devel@lists.xenproject.org | ||||||
| S: Supported | S: Supported | ||||||
| F: xen-* | F: xen-* | ||||||
| F: */xen* | F: */xen* | ||||||
| @@ -671,10 +671,13 @@ F: hw/misc/macio/ | |||||||
| F: hw/intc/heathrow_pic.c | F: hw/intc/heathrow_pic.c | ||||||
|  |  | ||||||
| PReP | PReP | ||||||
|  | M: Hervé Poussineau <hpoussin@reactos.org> | ||||||
| L: qemu-devel@nongnu.org | L: qemu-devel@nongnu.org | ||||||
| L: qemu-ppc@nongnu.org | L: qemu-ppc@nongnu.org | ||||||
| S: Odd Fixes | S: Maintained | ||||||
| F: hw/ppc/prep.c | F: hw/ppc/prep.c | ||||||
|  | F: hw/ppc/prep_systemio.c | ||||||
|  | F: hw/ppc/rs6000_mc.c | ||||||
| F: hw/pci-host/prep.[hc] | F: hw/pci-host/prep.[hc] | ||||||
| F: hw/isa/pc87312.[hc] | F: hw/isa/pc87312.[hc] | ||||||
| F: pc-bios/ppc_rom.bin | F: pc-bios/ppc_rom.bin | ||||||
| @@ -1194,8 +1197,9 @@ T: git git://github.com/jnsnow/qemu.git bitmaps | |||||||
|  |  | ||||||
| Character device backends | Character device backends | ||||||
| M: Paolo Bonzini <pbonzini@redhat.com> | M: Paolo Bonzini <pbonzini@redhat.com> | ||||||
|  | M: Marc-André Lureau <marcandre.lureau@redhat.com> | ||||||
| S: Maintained | S: Maintained | ||||||
| F: qemu-char.c | F: chardev/ | ||||||
| F: backends/msmouse.c | F: backends/msmouse.c | ||||||
| F: backends/testdev.c | F: backends/testdev.c | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										158
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										158
									
								
								Makefile
									
									
									
									
									
								
							| @@ -56,25 +56,136 @@ GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c | |||||||
| GENERATED_HEADERS += qmp-introspect.h | GENERATED_HEADERS += qmp-introspect.h | ||||||
| GENERATED_SOURCES += qmp-introspect.c | GENERATED_SOURCES += qmp-introspect.c | ||||||
|  |  | ||||||
| GENERATED_HEADERS += trace/generated-tracers.h |  | ||||||
| ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) |  | ||||||
| GENERATED_HEADERS += trace/generated-tracers-dtrace.h |  | ||||||
| endif |  | ||||||
| GENERATED_SOURCES += trace/generated-tracers.c |  | ||||||
|  |  | ||||||
| GENERATED_HEADERS += trace/generated-tcg-tracers.h | GENERATED_HEADERS += trace/generated-tcg-tracers.h | ||||||
|  |  | ||||||
| GENERATED_HEADERS += trace/generated-helpers-wrappers.h | GENERATED_HEADERS += trace/generated-helpers-wrappers.h | ||||||
| GENERATED_HEADERS += trace/generated-helpers.h | GENERATED_HEADERS += trace/generated-helpers.h | ||||||
| GENERATED_SOURCES += trace/generated-helpers.c | GENERATED_SOURCES += trace/generated-helpers.c | ||||||
|  |  | ||||||
| ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) | ifdef CONFIG_TRACE_UST | ||||||
| GENERATED_HEADERS += trace/generated-ust-provider.h | GENERATED_HEADERS += trace-ust-all.h | ||||||
| GENERATED_SOURCES += trace/generated-ust.c | GENERATED_SOURCES += trace-ust-all.c | ||||||
| endif | endif | ||||||
|  |  | ||||||
| GENERATED_HEADERS += module_block.h | GENERATED_HEADERS += module_block.h | ||||||
|  |  | ||||||
|  | TRACE_HEADERS = trace-root.h $(trace-events-subdirs:%=%/trace.h) | ||||||
|  | TRACE_SOURCES = trace-root.c $(trace-events-subdirs:%=%/trace.c) | ||||||
|  | TRACE_DTRACE = | ||||||
|  | ifdef CONFIG_TRACE_DTRACE | ||||||
|  | TRACE_HEADERS += trace-dtrace-root.h $(trace-events-subdirs:%=%/trace-dtrace.h) | ||||||
|  | TRACE_DTRACE += trace-dtrace-root.dtrace $(trace-events-subdirs:%=%/trace-dtrace.dtrace) | ||||||
|  | endif | ||||||
|  | ifdef CONFIG_TRACE_UST | ||||||
|  | TRACE_HEADERS += trace-ust-root.h $(trace-events-subdirs:%=%/trace-ust.h) | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | GENERATED_HEADERS += $(TRACE_HEADERS) | ||||||
|  | GENERATED_SOURCES += $(TRACE_SOURCES) | ||||||
|  |  | ||||||
|  | trace-group-name = $(shell dirname $1 | sed -e 's/[^a-zA-Z0-9]/_/g') | ||||||
|  |  | ||||||
|  | %/trace.h: %/trace.h-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | %/trace.h-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=$(call trace-group-name,$@) \ | ||||||
|  | 		--format=h \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$< > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | %/trace.c: %/trace.c-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | %/trace.c-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=$(call trace-group-name,$@) \ | ||||||
|  | 		--format=c \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$< > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | %/trace-ust.h: %/trace-ust.h-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | %/trace-ust.h-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=$(call trace-group-name,$@) \ | ||||||
|  | 		--format=ust-events-h \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$< > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | %/trace-dtrace.dtrace: %/trace-dtrace.dtrace-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | %/trace-dtrace.dtrace-timestamp: $(SRC_PATH)/%/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=$(call trace-group-name,$@) \ | ||||||
|  | 		--format=d \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$< > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | %/trace-dtrace.h: %/trace-dtrace.dtrace $(tracetool-y) | ||||||
|  | 	$(call quiet-command,dtrace -o $@ -h -s $<, "GEN","$@") | ||||||
|  |  | ||||||
|  | %/trace-dtrace.o: %/trace-dtrace.dtrace $(tracetool-y) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | trace-root.h: trace-root.h-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | trace-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=root \ | ||||||
|  | 		--format=h \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$< > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | trace-root.c: trace-root.c-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | trace-root.c-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=root \ | ||||||
|  | 		--format=c \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$< > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | trace-ust-root.h: trace-ust-root.h-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | trace-ust-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=root \ | ||||||
|  | 		--format=ust-events-h \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$< > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | trace-ust-all.h: trace-ust-all.h-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | trace-ust-all.h-timestamp: $(trace-events-files) $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=all \ | ||||||
|  | 		--format=ust-events-h \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$(trace-events-files) > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | trace-ust-all.c: trace-ust-all.c-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | trace-ust-all.c-timestamp: $(trace-events-files) $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=all \ | ||||||
|  | 		--format=ust-events-c \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$(trace-events-files) > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | trace-dtrace-root.dtrace: trace-dtrace-root.dtrace-timestamp | ||||||
|  | 	@cmp $< $@ >/dev/null 2>&1 || cp $< $@ | ||||||
|  | trace-dtrace-root.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y) | ||||||
|  | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=root \ | ||||||
|  | 		--format=d \ | ||||||
|  | 		--backends=$(TRACE_BACKENDS) \ | ||||||
|  | 		$< > $@,"GEN","$(@:%-timestamp=%)") | ||||||
|  |  | ||||||
|  | trace-dtrace-root.h: trace-dtrace-root.dtrace | ||||||
|  | 	$(call quiet-command,dtrace -o $@ -h -s $<, "GEN","$@") | ||||||
|  |  | ||||||
|  | trace-dtrace-root.o: trace-dtrace-root.dtrace | ||||||
|  |  | ||||||
| # Don't try to regenerate Makefile or configure | # Don't try to regenerate Makefile or configure | ||||||
| # We don't generate any of them | # We don't generate any of them | ||||||
| Makefile: ; | Makefile: ; | ||||||
| @@ -147,6 +258,7 @@ endif | |||||||
|  |  | ||||||
| dummy := $(call unnest-vars,, \ | dummy := $(call unnest-vars,, \ | ||||||
|                 stub-obj-y \ |                 stub-obj-y \ | ||||||
|  |                 chardev-obj-y \ | ||||||
|                 util-obj-y \ |                 util-obj-y \ | ||||||
|                 qga-obj-y \ |                 qga-obj-y \ | ||||||
|                 ivshmem-client-obj-y \ |                 ivshmem-client-obj-y \ | ||||||
| @@ -160,7 +272,8 @@ dummy := $(call unnest-vars,, \ | |||||||
|                 qom-obj-y \ |                 qom-obj-y \ | ||||||
|                 io-obj-y \ |                 io-obj-y \ | ||||||
|                 common-obj-y \ |                 common-obj-y \ | ||||||
|                 common-obj-m) |                 common-obj-m \ | ||||||
|  |                 trace-obj-y) | ||||||
|  |  | ||||||
| ifneq ($(wildcard config-host.mak),) | ifneq ($(wildcard config-host.mak),) | ||||||
| include $(SRC_PATH)/tests/Makefile.include | include $(SRC_PATH)/tests/Makefile.include | ||||||
| @@ -223,7 +336,8 @@ subdir-dtc:dtc/libfdt dtc/tests | |||||||
| dtc/%: | dtc/%: | ||||||
| 	mkdir -p $@ | 	mkdir -p $@ | ||||||
|  |  | ||||||
| $(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY)) | $(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(chardev-obj-y) \ | ||||||
|  | 	$(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY)) $(trace-obj-y) | ||||||
|  |  | ||||||
| ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) | ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) | ||||||
| # Only keep -O and -g cflags | # Only keep -O and -g cflags | ||||||
| @@ -247,15 +361,17 @@ libqemuutil.a: $(util-obj-y) | |||||||
|  |  | ||||||
| ###################################################################### | ###################################################################### | ||||||
|  |  | ||||||
|  | COMMON_LDADDS = $(trace-obj-y) libqemuutil.a libqemustub.a | ||||||
|  |  | ||||||
| qemu-img.o: qemu-img-cmds.h | qemu-img.o: qemu-img-cmds.h | ||||||
|  |  | ||||||
| qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a | qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) | ||||||
| qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a | qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) | ||||||
| qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a | qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) | ||||||
|  |  | ||||||
| qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o libqemuutil.a libqemustub.a | qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS) | ||||||
|  |  | ||||||
| fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o libqemuutil.a libqemustub.a | fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS) | ||||||
| fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap | fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap | ||||||
|  |  | ||||||
| qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool | qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool | ||||||
| @@ -320,7 +436,7 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py) | |||||||
| QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) | QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) | ||||||
| $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) | $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) | ||||||
|  |  | ||||||
| qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a | qemu-ga$(EXESUF): $(qga-obj-y) $(COMMON_LDADDS) | ||||||
| 	$(call LINK, $^) | 	$(call LINK, $^) | ||||||
|  |  | ||||||
| ifdef QEMU_GA_MSI_ENABLED | ifdef QEMU_GA_MSI_ENABLED | ||||||
| @@ -345,9 +461,9 @@ ifneq ($(EXESUF),) | |||||||
| qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI) | qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI) | ||||||
| endif | endif | ||||||
|  |  | ||||||
| ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) libqemuutil.a libqemustub.a | ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) $(COMMON_LDADDS) | ||||||
| 	$(call LINK, $^) | 	$(call LINK, $^) | ||||||
| ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a | ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) $(COMMON_LDADDS) | ||||||
| 	$(call LINK, $^) | 	$(call LINK, $^) | ||||||
|  |  | ||||||
| module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak | module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak | ||||||
| @@ -664,6 +780,10 @@ ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fa | |||||||
| Makefile: $(GENERATED_HEADERS) | Makefile: $(GENERATED_HEADERS) | ||||||
| endif | endif | ||||||
|  |  | ||||||
|  | .SECONDARY: $(TRACE_HEADERS) $(TRACE_HEADERS:%=%-timestamp) \ | ||||||
|  | 	$(TRACE_SOURCES) $(TRACE_SOURCES:%=%-timestamp) \ | ||||||
|  | 	$(TRACE_DTRACE) $(TRACE_DTRACE:%=%-timestamp) | ||||||
|  |  | ||||||
| # Include automatically generated dependency files | # Include automatically generated dependency files | ||||||
| # Dependencies in Makefile.objs files come from our recursive subdir rules | # Dependencies in Makefile.objs files come from our recursive subdir rules | ||||||
| -include $(wildcard *.d tests/*.d) | -include $(wildcard *.d tests/*.d) | ||||||
|   | |||||||
							
								
								
									
										104
									
								
								Makefile.objs
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								Makefile.objs
									
									
									
									
									
								
							| @@ -4,6 +4,8 @@ stub-obj-y = stubs/ crypto/ | |||||||
| util-obj-y = util/ qobject/ qapi/ | util-obj-y = util/ qobject/ qapi/ | ||||||
| util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o | util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o | ||||||
|  |  | ||||||
|  | chardev-obj-y = chardev/ | ||||||
|  |  | ||||||
| ####################################################################### | ####################################################################### | ||||||
| # block-obj-y is code used by both qemu system emulation and qemu-img | # block-obj-y is code used by both qemu system emulation and qemu-img | ||||||
|  |  | ||||||
| @@ -51,8 +53,7 @@ common-obj-$(CONFIG_POSIX) += os-posix.o | |||||||
| common-obj-$(CONFIG_LINUX) += fsdev/ | common-obj-$(CONFIG_LINUX) += fsdev/ | ||||||
|  |  | ||||||
| common-obj-y += migration/ | common-obj-y += migration/ | ||||||
| common-obj-y += qemu-char.o #aio.o | common-obj-y += page_cache.o #aio.o | ||||||
| common-obj-y += page_cache.o |  | ||||||
|  |  | ||||||
| common-obj-$(CONFIG_SPICE) += spice-qemu-char.o | common-obj-$(CONFIG_SPICE) += spice-qemu-char.o | ||||||
|  |  | ||||||
| @@ -118,47 +119,58 @@ ivshmem-server-obj-y = contrib/ivshmem-server/ | |||||||
| libvhost-user-obj-y = contrib/libvhost-user/ | libvhost-user-obj-y = contrib/libvhost-user/ | ||||||
|  |  | ||||||
| ###################################################################### | ###################################################################### | ||||||
| trace-events-y = trace-events | trace-events-subdirs = | ||||||
| trace-events-y += util/trace-events | trace-events-subdirs += util | ||||||
| trace-events-y += crypto/trace-events | trace-events-subdirs += crypto | ||||||
| trace-events-y += io/trace-events | trace-events-subdirs += io | ||||||
| trace-events-y += migration/trace-events | trace-events-subdirs += migration | ||||||
| trace-events-y += block/trace-events | trace-events-subdirs += block | ||||||
| trace-events-y += hw/block/trace-events | trace-events-subdirs += hw/block | ||||||
| trace-events-y += hw/char/trace-events | trace-events-subdirs += hw/block/dataplane | ||||||
| trace-events-y += hw/intc/trace-events | trace-events-subdirs += hw/char | ||||||
| trace-events-y += hw/net/trace-events | trace-events-subdirs += hw/intc | ||||||
| trace-events-y += hw/virtio/trace-events | trace-events-subdirs += hw/net | ||||||
| trace-events-y += hw/audio/trace-events | trace-events-subdirs += hw/virtio | ||||||
| trace-events-y += hw/misc/trace-events | trace-events-subdirs += hw/audio | ||||||
| trace-events-y += hw/usb/trace-events | trace-events-subdirs += hw/misc | ||||||
| trace-events-y += hw/scsi/trace-events | trace-events-subdirs += hw/usb | ||||||
| trace-events-y += hw/nvram/trace-events | trace-events-subdirs += hw/scsi | ||||||
| trace-events-y += hw/display/trace-events | trace-events-subdirs += hw/nvram | ||||||
| trace-events-y += hw/input/trace-events | trace-events-subdirs += hw/display | ||||||
| trace-events-y += hw/timer/trace-events | trace-events-subdirs += hw/input | ||||||
| trace-events-y += hw/dma/trace-events | trace-events-subdirs += hw/timer | ||||||
| trace-events-y += hw/sparc/trace-events | trace-events-subdirs += hw/dma | ||||||
| trace-events-y += hw/sd/trace-events | trace-events-subdirs += hw/sparc | ||||||
| trace-events-y += hw/isa/trace-events | trace-events-subdirs += hw/sd | ||||||
| trace-events-y += hw/mem/trace-events | trace-events-subdirs += hw/isa | ||||||
| trace-events-y += hw/i386/trace-events | trace-events-subdirs += hw/mem | ||||||
| trace-events-y += hw/9pfs/trace-events | trace-events-subdirs += hw/i386 | ||||||
| trace-events-y += hw/ppc/trace-events | trace-events-subdirs += hw/i386/xen | ||||||
| trace-events-y += hw/pci/trace-events | trace-events-subdirs += hw/9pfs | ||||||
| trace-events-y += hw/s390x/trace-events | trace-events-subdirs += hw/ppc | ||||||
| trace-events-y += hw/vfio/trace-events | trace-events-subdirs += hw/pci | ||||||
| trace-events-y += hw/acpi/trace-events | trace-events-subdirs += hw/s390x | ||||||
| trace-events-y += hw/arm/trace-events | trace-events-subdirs += hw/vfio | ||||||
| trace-events-y += hw/alpha/trace-events | trace-events-subdirs += hw/acpi | ||||||
| trace-events-y += ui/trace-events | trace-events-subdirs += hw/arm | ||||||
| trace-events-y += audio/trace-events | trace-events-subdirs += hw/alpha | ||||||
| trace-events-y += net/trace-events | trace-events-subdirs += hw/xen | ||||||
| trace-events-y += target/arm/trace-events | trace-events-subdirs += ui | ||||||
| trace-events-y += target/i386/trace-events | trace-events-subdirs += audio | ||||||
| trace-events-y += target/sparc/trace-events | trace-events-subdirs += net | ||||||
| trace-events-y += target/s390x/trace-events | trace-events-subdirs += target/arm | ||||||
| trace-events-y += target/ppc/trace-events | trace-events-subdirs += target/i386 | ||||||
| trace-events-y += qom/trace-events | trace-events-subdirs += target/sparc | ||||||
| trace-events-y += linux-user/trace-events | trace-events-subdirs += target/s390x | ||||||
| trace-events-y += qapi/trace-events | trace-events-subdirs += target/ppc | ||||||
|  | trace-events-subdirs += qom | ||||||
|  | trace-events-subdirs += linux-user | ||||||
|  | trace-events-subdirs += qapi | ||||||
|  |  | ||||||
|  | trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events) | ||||||
|  |  | ||||||
|  | trace-obj-y = trace-root.o | ||||||
|  | trace-obj-y += $(trace-events-subdirs:%=%/trace.o) | ||||||
|  | trace-obj-$(CONFIG_TRACE_UST) += trace-ust-all.o | ||||||
|  | trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace-root.o | ||||||
|  | trace-obj-$(CONFIG_TRACE_DTRACE) += $(trace-events-subdirs:%=%/trace-dtrace.o) | ||||||
|   | |||||||
| @@ -50,6 +50,7 @@ endif | |||||||
|  |  | ||||||
| $(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all | $(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all | ||||||
| 	$(call quiet-command,$(TRACETOOL) \ | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=all \ | ||||||
| 		--format=stap \ | 		--format=stap \ | ||||||
| 		--backends=$(TRACE_BACKENDS) \ | 		--backends=$(TRACE_BACKENDS) \ | ||||||
| 		--binary=$(bindir)/$(QEMU_PROG) \ | 		--binary=$(bindir)/$(QEMU_PROG) \ | ||||||
| @@ -59,6 +60,7 @@ $(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all | |||||||
|  |  | ||||||
| $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all | $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all | ||||||
| 	$(call quiet-command,$(TRACETOOL) \ | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=all \ | ||||||
| 		--format=stap \ | 		--format=stap \ | ||||||
| 		--backends=$(TRACE_BACKENDS) \ | 		--backends=$(TRACE_BACKENDS) \ | ||||||
| 		--binary=$(realpath .)/$(QEMU_PROG) \ | 		--binary=$(realpath .)/$(QEMU_PROG) \ | ||||||
| @@ -68,6 +70,7 @@ $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all | |||||||
|  |  | ||||||
| $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all | $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all | ||||||
| 	$(call quiet-command,$(TRACETOOL) \ | 	$(call quiet-command,$(TRACETOOL) \ | ||||||
|  | 		--group=all \ | ||||||
| 		--format=simpletrace-stap \ | 		--format=simpletrace-stap \ | ||||||
| 		--backends=$(TRACE_BACKENDS) \ | 		--backends=$(TRACE_BACKENDS) \ | ||||||
| 		--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \ | 		--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \ | ||||||
| @@ -172,31 +175,36 @@ all-obj-y := $(obj-y) | |||||||
| target-obj-y := | target-obj-y := | ||||||
| block-obj-y := | block-obj-y := | ||||||
| common-obj-y := | common-obj-y := | ||||||
|  | chardev-obj-y := | ||||||
| include $(SRC_PATH)/Makefile.objs | include $(SRC_PATH)/Makefile.objs | ||||||
| dummy := $(call unnest-vars,,target-obj-y) | dummy := $(call unnest-vars,,target-obj-y) | ||||||
| target-obj-y-save := $(target-obj-y) | target-obj-y-save := $(target-obj-y) | ||||||
| dummy := $(call unnest-vars,.., \ | dummy := $(call unnest-vars,.., \ | ||||||
|                block-obj-y \ |                block-obj-y \ | ||||||
|                block-obj-m \ |                block-obj-m \ | ||||||
|  |                chardev-obj-y \ | ||||||
|                crypto-obj-y \ |                crypto-obj-y \ | ||||||
|                crypto-aes-obj-y \ |                crypto-aes-obj-y \ | ||||||
|                qom-obj-y \ |                qom-obj-y \ | ||||||
|                io-obj-y \ |                io-obj-y \ | ||||||
|                common-obj-y \ |                common-obj-y \ | ||||||
|                common-obj-m) |                common-obj-m \ | ||||||
|  |                trace-obj-y) | ||||||
| target-obj-y := $(target-obj-y-save) | target-obj-y := $(target-obj-y-save) | ||||||
| all-obj-y += $(common-obj-y) | all-obj-y += $(common-obj-y) | ||||||
| all-obj-y += $(target-obj-y) | all-obj-y += $(target-obj-y) | ||||||
| all-obj-y += $(qom-obj-y) | all-obj-y += $(qom-obj-y) | ||||||
| all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) | all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y) | ||||||
| all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y) | all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y) | ||||||
| all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y) | all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y) | ||||||
| all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y) | all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y) | ||||||
|  |  | ||||||
| $(QEMU_PROG_BUILD): config-devices.mak | $(QEMU_PROG_BUILD): config-devices.mak | ||||||
|  |  | ||||||
|  | COMMON_LDADDS = $(trace-obj-y) ../libqemuutil.a ../libqemustub.a | ||||||
|  |  | ||||||
| # build either PROG or PROGW | # build either PROG or PROGW | ||||||
| $(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a | $(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS) | ||||||
| 	$(call LINK, $(filter-out %.mak, $^)) | 	$(call LINK, $(filter-out %.mak, $^)) | ||||||
| ifdef CONFIG_DARWIN | ifdef CONFIG_DARWIN | ||||||
| 	$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@") | 	$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@") | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ | |||||||
| #include "qemu/rcu_queue.h" | #include "qemu/rcu_queue.h" | ||||||
| #include "qemu/sockets.h" | #include "qemu/sockets.h" | ||||||
| #include "qemu/cutils.h" | #include "qemu/cutils.h" | ||||||
| #include "trace.h" | #include "trace-root.h" | ||||||
| #ifdef CONFIG_EPOLL_CREATE1 | #ifdef CONFIG_EPOLL_CREATE1 | ||||||
| #include <sys/epoll.h> | #include <sys/epoll.h> | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -616,9 +616,9 @@ static void baum_chr_read(void *opaque) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static void baum_chr_free(Chardev *chr) | static void char_braille_finalize(Object *obj) | ||||||
| { | { | ||||||
|     BaumChardev *baum = BAUM_CHARDEV(chr); |     BaumChardev *baum = BAUM_CHARDEV(obj); | ||||||
|  |  | ||||||
|     timer_free(baum->cellCount_timer); |     timer_free(baum->cellCount_timer); | ||||||
|     if (baum->brlapi) { |     if (baum->brlapi) { | ||||||
| @@ -659,23 +659,18 @@ static void char_braille_class_init(ObjectClass *oc, void *data) | |||||||
|     cc->open = baum_chr_open; |     cc->open = baum_chr_open; | ||||||
|     cc->chr_write = baum_chr_write; |     cc->chr_write = baum_chr_write; | ||||||
|     cc->chr_accept_input = baum_chr_accept_input; |     cc->chr_accept_input = baum_chr_accept_input; | ||||||
|     cc->chr_free = baum_chr_free; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static const TypeInfo char_braille_type_info = { | static const TypeInfo char_braille_type_info = { | ||||||
|     .name = TYPE_CHARDEV_BRAILLE, |     .name = TYPE_CHARDEV_BRAILLE, | ||||||
|     .parent = TYPE_CHARDEV, |     .parent = TYPE_CHARDEV, | ||||||
|     .instance_size = sizeof(BaumChardev), |     .instance_size = sizeof(BaumChardev), | ||||||
|  |     .instance_finalize = char_braille_finalize, | ||||||
|     .class_init = char_braille_class_init, |     .class_init = char_braille_class_init, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void register_types(void) | static void register_types(void) | ||||||
| { | { | ||||||
|     static const CharDriver driver = { |  | ||||||
|         .kind = CHARDEV_BACKEND_KIND_BRAILLE, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     register_char_driver(&driver); |  | ||||||
|     type_register_static(&char_braille_type_info); |     type_register_static(&char_braille_type_info); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -139,9 +139,9 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len) | |||||||
|     return len; |     return len; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void msmouse_chr_free(struct Chardev *chr) | static void char_msmouse_finalize(Object *obj) | ||||||
| { | { | ||||||
|     MouseChardev *mouse = MOUSE_CHARDEV(chr); |     MouseChardev *mouse = MOUSE_CHARDEV(obj); | ||||||
|  |  | ||||||
|     qemu_input_handler_unregister(mouse->hs); |     qemu_input_handler_unregister(mouse->hs); | ||||||
| } | } | ||||||
| @@ -172,23 +172,18 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data) | |||||||
|     cc->open = msmouse_chr_open; |     cc->open = msmouse_chr_open; | ||||||
|     cc->chr_write = msmouse_chr_write; |     cc->chr_write = msmouse_chr_write; | ||||||
|     cc->chr_accept_input = msmouse_chr_accept_input; |     cc->chr_accept_input = msmouse_chr_accept_input; | ||||||
|     cc->chr_free = msmouse_chr_free; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static const TypeInfo char_msmouse_type_info = { | static const TypeInfo char_msmouse_type_info = { | ||||||
|     .name = TYPE_CHARDEV_MSMOUSE, |     .name = TYPE_CHARDEV_MSMOUSE, | ||||||
|     .parent = TYPE_CHARDEV, |     .parent = TYPE_CHARDEV, | ||||||
|     .instance_size = sizeof(MouseChardev), |     .instance_size = sizeof(MouseChardev), | ||||||
|  |     .instance_finalize = char_msmouse_finalize, | ||||||
|     .class_init = char_msmouse_class_init, |     .class_init = char_msmouse_class_init, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void register_types(void) | static void register_types(void) | ||||||
| { | { | ||||||
|     static const CharDriver driver = { |  | ||||||
|         .kind = CHARDEV_BACKEND_KIND_MSMOUSE, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     register_char_driver(&driver); |  | ||||||
|     type_register_static(&char_msmouse_type_info); |     type_register_static(&char_msmouse_type_info); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -123,11 +123,6 @@ static const TypeInfo char_testdev_type_info = { | |||||||
|  |  | ||||||
| static void register_types(void) | static void register_types(void) | ||||||
| { | { | ||||||
|     static const CharDriver driver = { |  | ||||||
|         .kind = CHARDEV_BACKEND_KIND_TESTDEV, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     register_char_driver(&driver); |  | ||||||
|     type_register_static(&char_testdev_type_info); |     type_register_static(&char_testdev_type_info); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ | |||||||
| #include "exec/cpu-common.h" | #include "exec/cpu-common.h" | ||||||
| #include "sysemu/kvm.h" | #include "sysemu/kvm.h" | ||||||
| #include "sysemu/balloon.h" | #include "sysemu/balloon.h" | ||||||
| #include "trace.h" | #include "trace-root.h" | ||||||
| #include "qmp-commands.h" | #include "qmp-commands.h" | ||||||
| #include "qapi/qmp/qerror.h" | #include "qapi/qmp/qerror.h" | ||||||
| #include "qapi/qmp/qjson.h" | #include "qapi/qmp/qjson.h" | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								block.c
									
									
									
									
									
								
							| @@ -22,7 +22,7 @@ | |||||||
|  * THE SOFTWARE. |  * THE SOFTWARE. | ||||||
|  */ |  */ | ||||||
| #include "qemu/osdep.h" | #include "qemu/osdep.h" | ||||||
| #include "trace.h" | #include "block/trace.h" | ||||||
| #include "block/block_int.h" | #include "block/block_int.h" | ||||||
| #include "block/blockjob.h" | #include "block/blockjob.h" | ||||||
| #include "block/nbd.h" | #include "block/nbd.h" | ||||||
|   | |||||||
							
								
								
									
										291
									
								
								block/sheepdog.c
									
									
									
									
									
								
							
							
						
						
									
										291
									
								
								block/sheepdog.c
									
									
									
									
									
								
							| @@ -306,6 +306,7 @@ static inline size_t count_data_objs(const struct SheepdogInode *inode) | |||||||
|     } while (0) |     } while (0) | ||||||
|  |  | ||||||
| typedef struct SheepdogAIOCB SheepdogAIOCB; | typedef struct SheepdogAIOCB SheepdogAIOCB; | ||||||
|  | typedef struct BDRVSheepdogState BDRVSheepdogState; | ||||||
|  |  | ||||||
| typedef struct AIOReq { | typedef struct AIOReq { | ||||||
|     SheepdogAIOCB *aiocb; |     SheepdogAIOCB *aiocb; | ||||||
| @@ -334,7 +335,7 @@ enum AIOCBState { | |||||||
|        || y->max_affect_data_idx < x->min_affect_data_idx)) |        || y->max_affect_data_idx < x->min_affect_data_idx)) | ||||||
|  |  | ||||||
| struct SheepdogAIOCB { | struct SheepdogAIOCB { | ||||||
|     BlockAIOCB common; |     BDRVSheepdogState *s; | ||||||
|  |  | ||||||
|     QEMUIOVector *qiov; |     QEMUIOVector *qiov; | ||||||
|  |  | ||||||
| @@ -345,9 +346,6 @@ struct SheepdogAIOCB { | |||||||
|     enum AIOCBState aiocb_type; |     enum AIOCBState aiocb_type; | ||||||
|  |  | ||||||
|     Coroutine *coroutine; |     Coroutine *coroutine; | ||||||
|     void (*aio_done_func)(SheepdogAIOCB *); |  | ||||||
|  |  | ||||||
|     bool cancelable; |  | ||||||
|     int nr_pending; |     int nr_pending; | ||||||
|  |  | ||||||
|     uint32_t min_affect_data_idx; |     uint32_t min_affect_data_idx; | ||||||
| @@ -365,7 +363,7 @@ struct SheepdogAIOCB { | |||||||
|     QLIST_ENTRY(SheepdogAIOCB) aiocb_siblings; |     QLIST_ENTRY(SheepdogAIOCB) aiocb_siblings; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| typedef struct BDRVSheepdogState { | struct BDRVSheepdogState { | ||||||
|     BlockDriverState *bs; |     BlockDriverState *bs; | ||||||
|     AioContext *aio_context; |     AioContext *aio_context; | ||||||
|  |  | ||||||
| @@ -392,7 +390,7 @@ typedef struct BDRVSheepdogState { | |||||||
|  |  | ||||||
|     CoQueue overlapping_queue; |     CoQueue overlapping_queue; | ||||||
|     QLIST_HEAD(inflight_aiocb_head, SheepdogAIOCB) inflight_aiocb_head; |     QLIST_HEAD(inflight_aiocb_head, SheepdogAIOCB) inflight_aiocb_head; | ||||||
| } BDRVSheepdogState; | }; | ||||||
|  |  | ||||||
| typedef struct BDRVSheepdogReopenState { | typedef struct BDRVSheepdogReopenState { | ||||||
|     int fd; |     int fd; | ||||||
| @@ -450,14 +448,13 @@ static const char * sd_strerror(int err) | |||||||
|  * |  * | ||||||
|  * 1. In sd_co_rw_vector, we send the I/O requests to the server and |  * 1. In sd_co_rw_vector, we send the I/O requests to the server and | ||||||
|  *    link the requests to the inflight_list in the |  *    link the requests to the inflight_list in the | ||||||
|  *    BDRVSheepdogState.  The function exits without waiting for |  *    BDRVSheepdogState.  The function yields while waiting for | ||||||
|  *    receiving the response. |  *    receiving the response. | ||||||
|  * |  * | ||||||
|  * 2. We receive the response in aio_read_response, the fd handler to |  * 2. We receive the response in aio_read_response, the fd handler to | ||||||
|  *    the sheepdog connection.  If metadata update is needed, we send |  *    the sheepdog connection.  We switch back to sd_co_readv/sd_writev | ||||||
|  *    the write request to the vdi object in sd_write_done, the write |  *    after all the requests belonging to the AIOCB are finished.  If | ||||||
|  *    completion function.  We switch back to sd_co_readv/writev after |  *    needed, sd_co_writev will send another requests for the vdi object. | ||||||
|  *    all the requests belonging to the AIOCB are finished. |  | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb, | static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb, | ||||||
| @@ -482,94 +479,34 @@ static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb, | |||||||
|     return aio_req; |     return aio_req; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req) | static void wait_for_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *acb) | ||||||
| { | { | ||||||
|     SheepdogAIOCB *acb = aio_req->aiocb; |     SheepdogAIOCB *cb; | ||||||
|  |  | ||||||
|     acb->cancelable = false; | retry: | ||||||
|     QLIST_REMOVE(aio_req, aio_siblings); |     QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) { | ||||||
|     g_free(aio_req); |         if (AIOCBOverlapping(acb, cb)) { | ||||||
|  |             qemu_co_queue_wait(&s->overlapping_queue); | ||||||
|     acb->nr_pending--; |             goto retry; | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb) | static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s, | ||||||
|  |                          QEMUIOVector *qiov, int64_t sector_num, int nb_sectors, | ||||||
|  |                          int type) | ||||||
| { | { | ||||||
|     qemu_coroutine_enter(acb->coroutine); |  | ||||||
|     qemu_aio_unref(acb); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Check whether the specified acb can be canceled |  | ||||||
|  * |  | ||||||
|  * We can cancel aio when any request belonging to the acb is: |  | ||||||
|  *  - Not processed by the sheepdog server. |  | ||||||
|  *  - Not linked to the inflight queue. |  | ||||||
|  */ |  | ||||||
| static bool sd_acb_cancelable(const SheepdogAIOCB *acb) |  | ||||||
| { |  | ||||||
|     BDRVSheepdogState *s = acb->common.bs->opaque; |  | ||||||
|     AIOReq *aioreq; |  | ||||||
|  |  | ||||||
|     if (!acb->cancelable) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     QLIST_FOREACH(aioreq, &s->inflight_aio_head, aio_siblings) { |  | ||||||
|         if (aioreq->aiocb == acb) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void sd_aio_cancel(BlockAIOCB *blockacb) |  | ||||||
| { |  | ||||||
|     SheepdogAIOCB *acb = (SheepdogAIOCB *)blockacb; |  | ||||||
|     BDRVSheepdogState *s = acb->common.bs->opaque; |  | ||||||
|     AIOReq *aioreq, *next; |  | ||||||
|  |  | ||||||
|     if (sd_acb_cancelable(acb)) { |  | ||||||
|         /* Remove outstanding requests from failed queue.  */ |  | ||||||
|         QLIST_FOREACH_SAFE(aioreq, &s->failed_aio_head, aio_siblings, |  | ||||||
|                            next) { |  | ||||||
|             if (aioreq->aiocb == acb) { |  | ||||||
|                 free_aio_req(s, aioreq); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         assert(acb->nr_pending == 0); |  | ||||||
|         if (acb->common.cb) { |  | ||||||
|             acb->common.cb(acb->common.opaque, -ECANCELED); |  | ||||||
|         } |  | ||||||
|         sd_finish_aiocb(acb); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static const AIOCBInfo sd_aiocb_info = { |  | ||||||
|     .aiocb_size     = sizeof(SheepdogAIOCB), |  | ||||||
|     .cancel_async   = sd_aio_cancel, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, |  | ||||||
|                                    int64_t sector_num, int nb_sectors) |  | ||||||
| { |  | ||||||
|     SheepdogAIOCB *acb; |  | ||||||
|     uint32_t object_size; |     uint32_t object_size; | ||||||
|     BDRVSheepdogState *s = bs->opaque; |  | ||||||
|  |  | ||||||
|     object_size = (UINT32_C(1) << s->inode.block_size_shift); |     object_size = (UINT32_C(1) << s->inode.block_size_shift); | ||||||
|  |  | ||||||
|     acb = qemu_aio_get(&sd_aiocb_info, bs, NULL, NULL); |     acb->s = s; | ||||||
|  |  | ||||||
|     acb->qiov = qiov; |     acb->qiov = qiov; | ||||||
|  |  | ||||||
|     acb->sector_num = sector_num; |     acb->sector_num = sector_num; | ||||||
|     acb->nb_sectors = nb_sectors; |     acb->nb_sectors = nb_sectors; | ||||||
|  |  | ||||||
|     acb->aio_done_func = NULL; |  | ||||||
|     acb->cancelable = true; |  | ||||||
|     acb->coroutine = qemu_coroutine_self(); |     acb->coroutine = qemu_coroutine_self(); | ||||||
|     acb->ret = 0; |     acb->ret = 0; | ||||||
|     acb->nr_pending = 0; |     acb->nr_pending = 0; | ||||||
| @@ -580,8 +517,14 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, | |||||||
|  |  | ||||||
|     acb->min_dirty_data_idx = UINT32_MAX; |     acb->min_dirty_data_idx = UINT32_MAX; | ||||||
|     acb->max_dirty_data_idx = 0; |     acb->max_dirty_data_idx = 0; | ||||||
|  |     acb->aiocb_type = type; | ||||||
|  |  | ||||||
|     return acb; |     if (type == AIOCB_FLUSH_CACHE) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     wait_for_overlapping_aiocb(s, acb); | ||||||
|  |     QLIST_INSERT_HEAD(&s->inflight_aiocb_head, acb, aiocb_siblings); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Return -EIO in case of error, file descriptor on success */ | /* Return -EIO in case of error, file descriptor on success */ | ||||||
| @@ -797,7 +740,6 @@ static coroutine_fn void reconnect_to_sdog(void *opaque) | |||||||
|     while (!QLIST_EMPTY(&s->failed_aio_head)) { |     while (!QLIST_EMPTY(&s->failed_aio_head)) { | ||||||
|         aio_req = QLIST_FIRST(&s->failed_aio_head); |         aio_req = QLIST_FIRST(&s->failed_aio_head); | ||||||
|         QLIST_REMOVE(aio_req, aio_siblings); |         QLIST_REMOVE(aio_req, aio_siblings); | ||||||
|         QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); |  | ||||||
|         resend_aioreq(s, aio_req); |         resend_aioreq(s, aio_req); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -840,9 +782,6 @@ static void coroutine_fn aio_read_response(void *opaque) | |||||||
|  |  | ||||||
|     switch (acb->aiocb_type) { |     switch (acb->aiocb_type) { | ||||||
|     case AIOCB_WRITE_UDATA: |     case AIOCB_WRITE_UDATA: | ||||||
|         /* this coroutine context is no longer suitable for co_recv |  | ||||||
|          * because we may send data to update vdi objects */ |  | ||||||
|         s->co_recv = NULL; |  | ||||||
|         if (!is_data_obj(aio_req->oid)) { |         if (!is_data_obj(aio_req->oid)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -890,6 +829,12 @@ static void coroutine_fn aio_read_response(void *opaque) | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /* No more data for this aio_req (reload_inode below uses its own file | ||||||
|  |      * descriptor handler which doesn't use co_recv). | ||||||
|  |     */ | ||||||
|  |     s->co_recv = NULL; | ||||||
|  |  | ||||||
|  |     QLIST_REMOVE(aio_req, aio_siblings); | ||||||
|     switch (rsp.result) { |     switch (rsp.result) { | ||||||
|     case SD_RES_SUCCESS: |     case SD_RES_SUCCESS: | ||||||
|         break; |         break; | ||||||
| @@ -907,26 +852,26 @@ static void coroutine_fn aio_read_response(void *opaque) | |||||||
|             aio_req->oid = vid_to_vdi_oid(s->inode.vdi_id); |             aio_req->oid = vid_to_vdi_oid(s->inode.vdi_id); | ||||||
|         } |         } | ||||||
|         resend_aioreq(s, aio_req); |         resend_aioreq(s, aio_req); | ||||||
|         goto out; |         return; | ||||||
|     default: |     default: | ||||||
|         acb->ret = -EIO; |         acb->ret = -EIO; | ||||||
|         error_report("%s", sd_strerror(rsp.result)); |         error_report("%s", sd_strerror(rsp.result)); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     free_aio_req(s, aio_req); |     g_free(aio_req); | ||||||
|     if (!acb->nr_pending) { |  | ||||||
|  |     if (!--acb->nr_pending) { | ||||||
|         /* |         /* | ||||||
|          * We've finished all requests which belong to the AIOCB, so |          * We've finished all requests which belong to the AIOCB, so | ||||||
|          * we can switch back to sd_co_readv/writev now. |          * we can switch back to sd_co_readv/writev now. | ||||||
|          */ |          */ | ||||||
|         acb->aio_done_func(acb); |         qemu_coroutine_enter(acb->coroutine); | ||||||
|     } |     } | ||||||
| out: |  | ||||||
|     s->co_recv = NULL; |  | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
| err: | err: | ||||||
|     s->co_recv = NULL; |  | ||||||
|     reconnect_to_sdog(opaque); |     reconnect_to_sdog(opaque); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1176,6 +1121,8 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, | |||||||
|     uint64_t old_oid = aio_req->base_oid; |     uint64_t old_oid = aio_req->base_oid; | ||||||
|     bool create = aio_req->create; |     bool create = aio_req->create; | ||||||
|  |  | ||||||
|  |     QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); | ||||||
|  |  | ||||||
|     if (!nr_copies) { |     if (!nr_copies) { | ||||||
|         error_report("bug"); |         error_report("bug"); | ||||||
|     } |     } | ||||||
| @@ -2025,11 +1972,10 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) | |||||||
| /* | /* | ||||||
|  * This function is called after writing data objects.  If we need to |  * This function is called after writing data objects.  If we need to | ||||||
|  * update metadata, this sends a write request to the vdi object. |  * update metadata, this sends a write request to the vdi object. | ||||||
|  * Otherwise, this switches back to sd_co_readv/writev. |  | ||||||
|  */ |  */ | ||||||
| static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) | static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) | ||||||
| { | { | ||||||
|     BDRVSheepdogState *s = acb->common.bs->opaque; |     BDRVSheepdogState *s = acb->s; | ||||||
|     struct iovec iov; |     struct iovec iov; | ||||||
|     AIOReq *aio_req; |     AIOReq *aio_req; | ||||||
|     uint32_t offset, data_len, mn, mx; |     uint32_t offset, data_len, mn, mx; | ||||||
| @@ -2038,6 +1984,7 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) | |||||||
|     mx = acb->max_dirty_data_idx; |     mx = acb->max_dirty_data_idx; | ||||||
|     if (mn <= mx) { |     if (mn <= mx) { | ||||||
|         /* we need to update the vdi object. */ |         /* we need to update the vdi object. */ | ||||||
|  |         ++acb->nr_pending; | ||||||
|         offset = sizeof(s->inode) - sizeof(s->inode.data_vdi_id) + |         offset = sizeof(s->inode) - sizeof(s->inode.data_vdi_id) + | ||||||
|             mn * sizeof(s->inode.data_vdi_id[0]); |             mn * sizeof(s->inode.data_vdi_id[0]); | ||||||
|         data_len = (mx - mn + 1) * sizeof(s->inode.data_vdi_id[0]); |         data_len = (mx - mn + 1) * sizeof(s->inode.data_vdi_id[0]); | ||||||
| @@ -2049,15 +1996,11 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) | |||||||
|         iov.iov_len = sizeof(s->inode); |         iov.iov_len = sizeof(s->inode); | ||||||
|         aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), |         aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), | ||||||
|                                 data_len, offset, 0, false, 0, offset); |                                 data_len, offset, 0, false, 0, offset); | ||||||
|         QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); |  | ||||||
|         add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA); |         add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA); | ||||||
|  |         if (--acb->nr_pending) { | ||||||
|         acb->aio_done_func = sd_finish_aiocb; |             qemu_coroutine_yield(); | ||||||
|         acb->aiocb_type = AIOCB_WRITE_UDATA; |         } | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     sd_finish_aiocb(acb); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Delete current working VDI on the snapshot chain */ | /* Delete current working VDI on the snapshot chain */ | ||||||
| @@ -2169,16 +2112,15 @@ out: | |||||||
|  * Returns 1 when we need to wait a response, 0 when there is no sent |  * Returns 1 when we need to wait a response, 0 when there is no sent | ||||||
|  * request and -errno in error cases. |  * request and -errno in error cases. | ||||||
|  */ |  */ | ||||||
| static int coroutine_fn sd_co_rw_vector(void *p) | static void coroutine_fn sd_co_rw_vector(SheepdogAIOCB *acb) | ||||||
| { | { | ||||||
|     SheepdogAIOCB *acb = p; |  | ||||||
|     int ret = 0; |     int ret = 0; | ||||||
|     unsigned long len, done = 0, total = acb->nb_sectors * BDRV_SECTOR_SIZE; |     unsigned long len, done = 0, total = acb->nb_sectors * BDRV_SECTOR_SIZE; | ||||||
|     unsigned long idx; |     unsigned long idx; | ||||||
|     uint32_t object_size; |     uint32_t object_size; | ||||||
|     uint64_t oid; |     uint64_t oid; | ||||||
|     uint64_t offset; |     uint64_t offset; | ||||||
|     BDRVSheepdogState *s = acb->common.bs->opaque; |     BDRVSheepdogState *s = acb->s; | ||||||
|     SheepdogInode *inode = &s->inode; |     SheepdogInode *inode = &s->inode; | ||||||
|     AIOReq *aio_req; |     AIOReq *aio_req; | ||||||
|  |  | ||||||
| @@ -2190,7 +2132,7 @@ static int coroutine_fn sd_co_rw_vector(void *p) | |||||||
|         ret = sd_create_branch(s); |         ret = sd_create_branch(s); | ||||||
|         if (ret) { |         if (ret) { | ||||||
|             acb->ret = -EIO; |             acb->ret = -EIO; | ||||||
|             goto out; |             return; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -2255,8 +2197,6 @@ static int coroutine_fn sd_co_rw_vector(void *p) | |||||||
|                                 old_oid, |                                 old_oid, | ||||||
|                                 acb->aiocb_type == AIOCB_DISCARD_OBJ ? |                                 acb->aiocb_type == AIOCB_DISCARD_OBJ ? | ||||||
|                                 0 : done); |                                 0 : done); | ||||||
|         QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); |  | ||||||
|  |  | ||||||
|         add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, |         add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, | ||||||
|                         acb->aiocb_type); |                         acb->aiocb_type); | ||||||
|     done: |     done: | ||||||
| @@ -2264,31 +2204,25 @@ static int coroutine_fn sd_co_rw_vector(void *p) | |||||||
|         idx++; |         idx++; | ||||||
|         done += len; |         done += len; | ||||||
|     } |     } | ||||||
| out: |     if (--acb->nr_pending) { | ||||||
|     if (!--acb->nr_pending) { |         qemu_coroutine_yield(); | ||||||
|         return acb->ret; |  | ||||||
|     } |     } | ||||||
|     return 1; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static bool check_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *aiocb) | static void sd_aio_complete(SheepdogAIOCB *acb) | ||||||
| { | { | ||||||
|     SheepdogAIOCB *cb; |     if (acb->aiocb_type == AIOCB_FLUSH_CACHE) { | ||||||
|  |         return; | ||||||
|     QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) { |  | ||||||
|         if (AIOCBOverlapping(aiocb, cb)) { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     QLIST_INSERT_HEAD(&s->inflight_aiocb_head, aiocb, aiocb_siblings); |     QLIST_REMOVE(acb, aiocb_siblings); | ||||||
|     return false; |     qemu_co_queue_restart_all(&acb->s->overlapping_queue); | ||||||
| } | } | ||||||
|  |  | ||||||
| static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, | static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, | ||||||
|                         int nb_sectors, QEMUIOVector *qiov) |                         int nb_sectors, QEMUIOVector *qiov) | ||||||
| { | { | ||||||
|     SheepdogAIOCB *acb; |     SheepdogAIOCB acb; | ||||||
|     int ret; |     int ret; | ||||||
|     int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE; |     int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE; | ||||||
|     BDRVSheepdogState *s = bs->opaque; |     BDRVSheepdogState *s = bs->opaque; | ||||||
| @@ -2300,85 +2234,50 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors); |     sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_WRITE_UDATA); | ||||||
|     acb->aio_done_func = sd_write_done; |     sd_co_rw_vector(&acb); | ||||||
|     acb->aiocb_type = AIOCB_WRITE_UDATA; |     sd_write_done(&acb); | ||||||
|  |     sd_aio_complete(&acb); | ||||||
|  |  | ||||||
| retry: |     return acb.ret; | ||||||
|     if (check_overlapping_aiocb(s, acb)) { |  | ||||||
|         qemu_co_queue_wait(&s->overlapping_queue); |  | ||||||
|         goto retry; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ret = sd_co_rw_vector(acb); |  | ||||||
|     if (ret <= 0) { |  | ||||||
|         QLIST_REMOVE(acb, aiocb_siblings); |  | ||||||
|         qemu_co_queue_restart_all(&s->overlapping_queue); |  | ||||||
|         qemu_aio_unref(acb); |  | ||||||
|         return ret; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     qemu_coroutine_yield(); |  | ||||||
|  |  | ||||||
|     QLIST_REMOVE(acb, aiocb_siblings); |  | ||||||
|     qemu_co_queue_restart_all(&s->overlapping_queue); |  | ||||||
|  |  | ||||||
|     return acb->ret; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num, | static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num, | ||||||
|                        int nb_sectors, QEMUIOVector *qiov) |                        int nb_sectors, QEMUIOVector *qiov) | ||||||
| { | { | ||||||
|     SheepdogAIOCB *acb; |     SheepdogAIOCB acb; | ||||||
|     int ret; |  | ||||||
|     BDRVSheepdogState *s = bs->opaque; |     BDRVSheepdogState *s = bs->opaque; | ||||||
|  |  | ||||||
|     acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors); |     sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_READ_UDATA); | ||||||
|     acb->aiocb_type = AIOCB_READ_UDATA; |     sd_co_rw_vector(&acb); | ||||||
|     acb->aio_done_func = sd_finish_aiocb; |     sd_aio_complete(&acb); | ||||||
|  |  | ||||||
| retry: |     return acb.ret; | ||||||
|     if (check_overlapping_aiocb(s, acb)) { |  | ||||||
|         qemu_co_queue_wait(&s->overlapping_queue); |  | ||||||
|         goto retry; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ret = sd_co_rw_vector(acb); |  | ||||||
|     if (ret <= 0) { |  | ||||||
|         QLIST_REMOVE(acb, aiocb_siblings); |  | ||||||
|         qemu_co_queue_restart_all(&s->overlapping_queue); |  | ||||||
|         qemu_aio_unref(acb); |  | ||||||
|         return ret; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     qemu_coroutine_yield(); |  | ||||||
|  |  | ||||||
|     QLIST_REMOVE(acb, aiocb_siblings); |  | ||||||
|     qemu_co_queue_restart_all(&s->overlapping_queue); |  | ||||||
|     return acb->ret; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) | static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) | ||||||
| { | { | ||||||
|     BDRVSheepdogState *s = bs->opaque; |     BDRVSheepdogState *s = bs->opaque; | ||||||
|     SheepdogAIOCB *acb; |     SheepdogAIOCB acb; | ||||||
|     AIOReq *aio_req; |     AIOReq *aio_req; | ||||||
|  |  | ||||||
|     if (s->cache_flags != SD_FLAG_CMD_CACHE) { |     if (s->cache_flags != SD_FLAG_CMD_CACHE) { | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     acb = sd_aio_setup(bs, NULL, 0, 0); |     sd_aio_setup(&acb, s, NULL, 0, 0, AIOCB_FLUSH_CACHE); | ||||||
|     acb->aiocb_type = AIOCB_FLUSH_CACHE; |  | ||||||
|     acb->aio_done_func = sd_finish_aiocb; |  | ||||||
|  |  | ||||||
|     aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), |     acb.nr_pending++; | ||||||
|  |     aio_req = alloc_aio_req(s, &acb, vid_to_vdi_oid(s->inode.vdi_id), | ||||||
|                             0, 0, 0, false, 0, 0); |                             0, 0, 0, false, 0, 0); | ||||||
|     QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); |     add_aio_request(s, aio_req, NULL, 0, acb.aiocb_type); | ||||||
|     add_aio_request(s, aio_req, NULL, 0, acb->aiocb_type); |  | ||||||
|  |  | ||||||
|  |     if (--acb.nr_pending) { | ||||||
|         qemu_coroutine_yield(); |         qemu_coroutine_yield(); | ||||||
|     return acb->ret; |     } | ||||||
|  |  | ||||||
|  |     sd_aio_complete(&acb); | ||||||
|  |     return acb.ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) | static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) | ||||||
| @@ -2812,9 +2711,8 @@ static int sd_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, | |||||||
| static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset, | static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset, | ||||||
|                                       int count) |                                       int count) | ||||||
| { | { | ||||||
|     SheepdogAIOCB *acb; |     SheepdogAIOCB acb; | ||||||
|     BDRVSheepdogState *s = bs->opaque; |     BDRVSheepdogState *s = bs->opaque; | ||||||
|     int ret; |  | ||||||
|     QEMUIOVector discard_iov; |     QEMUIOVector discard_iov; | ||||||
|     struct iovec iov; |     struct iovec iov; | ||||||
|     uint32_t zero = 0; |     uint32_t zero = 0; | ||||||
| @@ -2832,31 +2730,12 @@ static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset, | |||||||
|     if (!QEMU_IS_ALIGNED(offset | count, BDRV_SECTOR_SIZE)) { |     if (!QEMU_IS_ALIGNED(offset | count, BDRV_SECTOR_SIZE)) { | ||||||
|         return -ENOTSUP; |         return -ENOTSUP; | ||||||
|     } |     } | ||||||
|     acb = sd_aio_setup(bs, &discard_iov, offset >> BDRV_SECTOR_BITS, |     sd_aio_setup(&acb, s, &discard_iov, offset >> BDRV_SECTOR_BITS, | ||||||
|                        count >> BDRV_SECTOR_BITS); |                  count >> BDRV_SECTOR_BITS, AIOCB_DISCARD_OBJ); | ||||||
|     acb->aiocb_type = AIOCB_DISCARD_OBJ; |     sd_co_rw_vector(&acb); | ||||||
|     acb->aio_done_func = sd_finish_aiocb; |     sd_aio_complete(&acb); | ||||||
|  |  | ||||||
| retry: |     return acb.ret; | ||||||
|     if (check_overlapping_aiocb(s, acb)) { |  | ||||||
|         qemu_co_queue_wait(&s->overlapping_queue); |  | ||||||
|         goto retry; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ret = sd_co_rw_vector(acb); |  | ||||||
|     if (ret <= 0) { |  | ||||||
|         QLIST_REMOVE(acb, aiocb_siblings); |  | ||||||
|         qemu_co_queue_restart_all(&s->overlapping_queue); |  | ||||||
|         qemu_aio_unref(acb); |  | ||||||
|         return ret; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     qemu_coroutine_yield(); |  | ||||||
|  |  | ||||||
|     QLIST_REMOVE(acb, aiocb_siblings); |  | ||||||
|     qemu_co_queue_restart_all(&s->overlapping_queue); |  | ||||||
|  |  | ||||||
|     return acb->ret; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static coroutine_fn int64_t | static coroutine_fn int64_t | ||||||
|   | |||||||
| @@ -35,8 +35,6 @@ mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_n | |||||||
| mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d" | mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d" | ||||||
| mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d" | mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d" | ||||||
| mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d" | mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d" | ||||||
| mirror_yield_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d" |  | ||||||
| mirror_break_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d" |  | ||||||
|  |  | ||||||
| # block/backup.c | # block/backup.c | ||||||
| backup_do_cow_enter(void *job, int64_t start, int64_t sector_num, int nb_sectors) "job %p start %"PRId64" sector_num %"PRId64" nb_sectors %d" | backup_do_cow_enter(void *job, int64_t start, int64_t sector_num, int nb_sectors) "job %p start %"PRId64" sector_num %"PRId64" nb_sectors %d" | ||||||
|   | |||||||
| @@ -16,7 +16,6 @@ | |||||||
| #include "qapi/qmp/qerror.h" | #include "qapi/qmp/qerror.h" | ||||||
| #include "sysemu/sysemu.h" | #include "sysemu/sysemu.h" | ||||||
| #include "qmp-commands.h" | #include "qmp-commands.h" | ||||||
| #include "trace.h" |  | ||||||
| #include "block/nbd.h" | #include "block/nbd.h" | ||||||
| #include "io/channel-socket.h" | #include "io/channel-socket.h" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -48,7 +48,7 @@ | |||||||
| #include "sysemu/sysemu.h" | #include "sysemu/sysemu.h" | ||||||
| #include "block/block_int.h" | #include "block/block_int.h" | ||||||
| #include "qmp-commands.h" | #include "qmp-commands.h" | ||||||
| #include "trace.h" | #include "block/trace.h" | ||||||
| #include "sysemu/arch_init.h" | #include "sysemu/arch_init.h" | ||||||
| #include "qemu/cutils.h" | #include "qemu/cutils.h" | ||||||
| #include "qemu/help_option.h" | #include "qemu/help_option.h" | ||||||
|   | |||||||
| @@ -25,7 +25,6 @@ | |||||||
|  |  | ||||||
| #include "qemu/osdep.h" | #include "qemu/osdep.h" | ||||||
| #include "qemu-common.h" | #include "qemu-common.h" | ||||||
| #include "trace.h" |  | ||||||
| #include "block/block.h" | #include "block/block.h" | ||||||
| #include "block/blockjob_int.h" | #include "block/blockjob_int.h" | ||||||
| #include "block/block_int.h" | #include "block/block_int.h" | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								chardev/Makefile.objs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								chardev/Makefile.objs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | chardev-obj-y += char.o | ||||||
|  | chardev-obj-$(CONFIG_WIN32) += char-console.o | ||||||
|  | chardev-obj-$(CONFIG_POSIX) += char-fd.o | ||||||
|  | chardev-obj-y += char-file.o | ||||||
|  | chardev-obj-y += char-io.o | ||||||
|  | chardev-obj-y += char-mux.o | ||||||
|  | chardev-obj-y += char-null.o | ||||||
|  | chardev-obj-$(CONFIG_POSIX) += char-parallel.o | ||||||
|  | chardev-obj-y += char-pipe.o | ||||||
|  | chardev-obj-$(CONFIG_POSIX) += char-pty.o | ||||||
|  | chardev-obj-y += char-ringbuf.o | ||||||
|  | chardev-obj-y += char-serial.o | ||||||
|  | chardev-obj-y += char-socket.o | ||||||
|  | chardev-obj-y += char-stdio.o | ||||||
|  | chardev-obj-y += char-udp.o | ||||||
|  | chardev-obj-$(CONFIG_WIN32) += char-win.o | ||||||
|  | chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o | ||||||
							
								
								
									
										53
									
								
								chardev/char-console.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								chardev/char-console.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "char-win.h" | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_win_con(Chardev *chr, | ||||||
|  |                                   ChardevBackend *backend, | ||||||
|  |                                   bool *be_opened, | ||||||
|  |                                   Error **errp) | ||||||
|  | { | ||||||
|  |     qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_console_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->open = qemu_chr_open_win_con; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_console_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_CONSOLE, | ||||||
|  |     .parent = TYPE_CHARDEV_WIN, | ||||||
|  |     .class_init = char_console_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_console_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										170
									
								
								chardev/char-fd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								chardev/char-fd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qemu/sockets.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  | #include "io/channel-file.h" | ||||||
|  |  | ||||||
|  | #include "char-fd.h" | ||||||
|  | #include "char-io.h" | ||||||
|  |  | ||||||
|  | /* Called with chr_write_lock held.  */ | ||||||
|  | static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len) | ||||||
|  | { | ||||||
|  |     FDChardev *s = FD_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     return io_channel_send(s->ioc_out, buf, len); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     FDChardev *s = FD_CHARDEV(opaque); | ||||||
|  |     int len; | ||||||
|  |     uint8_t buf[CHR_READ_BUF_LEN]; | ||||||
|  |     ssize_t ret; | ||||||
|  |  | ||||||
|  |     len = sizeof(buf); | ||||||
|  |     if (len > s->max_size) { | ||||||
|  |         len = s->max_size; | ||||||
|  |     } | ||||||
|  |     if (len == 0) { | ||||||
|  |         return TRUE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ret = qio_channel_read( | ||||||
|  |         chan, (gchar *)buf, len, NULL); | ||||||
|  |     if (ret == 0) { | ||||||
|  |         remove_fd_in_watch(chr); | ||||||
|  |         qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | ||||||
|  |         return FALSE; | ||||||
|  |     } | ||||||
|  |     if (ret > 0) { | ||||||
|  |         qemu_chr_be_write(chr, buf, ret); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int fd_chr_read_poll(void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     FDChardev *s = FD_CHARDEV(opaque); | ||||||
|  |  | ||||||
|  |     s->max_size = qemu_chr_be_can_write(chr); | ||||||
|  |     return s->max_size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond) | ||||||
|  | { | ||||||
|  |     FDChardev *s = FD_CHARDEV(chr); | ||||||
|  |     return qio_channel_create_watch(s->ioc_out, cond); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void fd_chr_update_read_handler(Chardev *chr, | ||||||
|  |                                        GMainContext *context) | ||||||
|  | { | ||||||
|  |     FDChardev *s = FD_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     remove_fd_in_watch(chr); | ||||||
|  |     if (s->ioc_in) { | ||||||
|  |         chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in, | ||||||
|  |                                            fd_chr_read_poll, | ||||||
|  |                                            fd_chr_read, chr, | ||||||
|  |                                            context); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_fd_finalize(Object *obj) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(obj); | ||||||
|  |     FDChardev *s = FD_CHARDEV(obj); | ||||||
|  |  | ||||||
|  |     remove_fd_in_watch(chr); | ||||||
|  |     if (s->ioc_in) { | ||||||
|  |         object_unref(OBJECT(s->ioc_in)); | ||||||
|  |     } | ||||||
|  |     if (s->ioc_out) { | ||||||
|  |         object_unref(OBJECT(s->ioc_out)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int qmp_chardev_open_file_source(char *src, int flags, Error **errp) | ||||||
|  | { | ||||||
|  |     int fd = -1; | ||||||
|  |  | ||||||
|  |     TFR(fd = qemu_open(src, flags, 0666)); | ||||||
|  |     if (fd == -1) { | ||||||
|  |         error_setg_file_open(errp, errno, src); | ||||||
|  |     } | ||||||
|  |     return fd; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* open a character device to a unix fd */ | ||||||
|  | void qemu_chr_open_fd(Chardev *chr, | ||||||
|  |                       int fd_in, int fd_out) | ||||||
|  | { | ||||||
|  |     FDChardev *s = FD_CHARDEV(chr); | ||||||
|  |     char *name; | ||||||
|  |  | ||||||
|  |     s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in)); | ||||||
|  |     name = g_strdup_printf("chardev-file-in-%s", chr->label); | ||||||
|  |     qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name); | ||||||
|  |     g_free(name); | ||||||
|  |     s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out)); | ||||||
|  |     name = g_strdup_printf("chardev-file-out-%s", chr->label); | ||||||
|  |     qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name); | ||||||
|  |     g_free(name); | ||||||
|  |     qemu_set_nonblock(fd_out); | ||||||
|  |     s->chr = chr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_fd_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->chr_add_watch = fd_chr_add_watch; | ||||||
|  |     cc->chr_write = fd_chr_write; | ||||||
|  |     cc->chr_update_read_handler = fd_chr_update_read_handler; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_fd_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_FD, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .instance_size = sizeof(FDChardev), | ||||||
|  |     .instance_finalize = char_fd_finalize, | ||||||
|  |     .class_init = char_fd_class_init, | ||||||
|  |     .abstract = true, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_fd_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										44
									
								
								chardev/char-fd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								chardev/char-fd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef CHAR_FD_H | ||||||
|  | #define CHAR_FD_H | ||||||
|  |  | ||||||
|  | #include "io/channel.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  |  | ||||||
|  | typedef struct FDChardev { | ||||||
|  |     Chardev parent; | ||||||
|  |     Chardev *chr; | ||||||
|  |     QIOChannel *ioc_in, *ioc_out; | ||||||
|  |     int max_size; | ||||||
|  | } FDChardev; | ||||||
|  |  | ||||||
|  | #define TYPE_CHARDEV_FD "chardev-fd" | ||||||
|  |  | ||||||
|  | #define FD_CHARDEV(obj) OBJECT_CHECK(FDChardev, (obj), TYPE_CHARDEV_FD) | ||||||
|  |  | ||||||
|  | void qemu_chr_open_fd(Chardev *chr, int fd_in, int fd_out); | ||||||
|  | int qmp_chardev_open_file_source(char *src, int flags, Error **errp); | ||||||
|  |  | ||||||
|  | #endif /* CHAR_FD_H */ | ||||||
							
								
								
									
										139
									
								
								chardev/char-file.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								chardev/char-file.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include "char-win.h" | ||||||
|  | #else | ||||||
|  | #include "char-fd.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static void qmp_chardev_open_file(Chardev *chr, | ||||||
|  |                                   ChardevBackend *backend, | ||||||
|  |                                   bool *be_opened, | ||||||
|  |                                   Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevFile *file = backend->u.file.data; | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     HANDLE out; | ||||||
|  |     DWORD accessmode; | ||||||
|  |     DWORD flags; | ||||||
|  |  | ||||||
|  |     if (file->has_in) { | ||||||
|  |         error_setg(errp, "input file not supported"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (file->has_append && file->append) { | ||||||
|  |         /* Append to file if it already exists. */ | ||||||
|  |         accessmode = FILE_GENERIC_WRITE & ~FILE_WRITE_DATA; | ||||||
|  |         flags = OPEN_ALWAYS; | ||||||
|  |     } else { | ||||||
|  |         /* Truncate file if it already exists. */ | ||||||
|  |         accessmode = GENERIC_WRITE; | ||||||
|  |         flags = CREATE_ALWAYS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     out = CreateFile(file->out, accessmode, FILE_SHARE_READ, NULL, flags, | ||||||
|  |                      FILE_ATTRIBUTE_NORMAL, NULL); | ||||||
|  |     if (out == INVALID_HANDLE_VALUE) { | ||||||
|  |         error_setg(errp, "open %s failed", file->out); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     qemu_chr_open_win_file(chr, out); | ||||||
|  | #else | ||||||
|  |     int flags, in = -1, out; | ||||||
|  |  | ||||||
|  |     flags = O_WRONLY | O_CREAT | O_BINARY; | ||||||
|  |     if (file->has_append && file->append) { | ||||||
|  |         flags |= O_APPEND; | ||||||
|  |     } else { | ||||||
|  |         flags |= O_TRUNC; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     out = qmp_chardev_open_file_source(file->out, flags, errp); | ||||||
|  |     if (out < 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (file->has_in) { | ||||||
|  |         flags = O_RDONLY; | ||||||
|  |         in = qmp_chardev_open_file_source(file->in, flags, errp); | ||||||
|  |         if (in < 0) { | ||||||
|  |             qemu_close(out); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     qemu_chr_open_fd(chr, in, out); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend, | ||||||
|  |                                     Error **errp) | ||||||
|  | { | ||||||
|  |     const char *path = qemu_opt_get(opts, "path"); | ||||||
|  |     ChardevFile *file; | ||||||
|  |  | ||||||
|  |     backend->type = CHARDEV_BACKEND_KIND_FILE; | ||||||
|  |     if (path == NULL) { | ||||||
|  |         error_setg(errp, "chardev: file: no filename given"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     file = backend->u.file.data = g_new0(ChardevFile, 1); | ||||||
|  |     qemu_chr_parse_common(opts, qapi_ChardevFile_base(file)); | ||||||
|  |     file->out = g_strdup(path); | ||||||
|  |  | ||||||
|  |     file->has_append = true; | ||||||
|  |     file->append = qemu_opt_get_bool(opts, "append", false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_file_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->parse = qemu_chr_parse_file_out; | ||||||
|  |     cc->open = qmp_chardev_open_file; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_file_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_FILE, | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     .parent = TYPE_CHARDEV_WIN, | ||||||
|  | #else | ||||||
|  |     .parent = TYPE_CHARDEV_FD, | ||||||
|  | #endif | ||||||
|  |     .class_init = char_file_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_file_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										192
									
								
								chardev/char-io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								chardev/char-io.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "char-io.h" | ||||||
|  |  | ||||||
|  | typedef struct IOWatchPoll { | ||||||
|  |     GSource parent; | ||||||
|  |  | ||||||
|  |     QIOChannel *ioc; | ||||||
|  |     GSource *src; | ||||||
|  |  | ||||||
|  |     IOCanReadHandler *fd_can_read; | ||||||
|  |     GSourceFunc fd_read; | ||||||
|  |     void *opaque; | ||||||
|  |     GMainContext *context; | ||||||
|  | } IOWatchPoll; | ||||||
|  |  | ||||||
|  | static IOWatchPoll *io_watch_poll_from_source(GSource *source) | ||||||
|  | { | ||||||
|  |     return container_of(source, IOWatchPoll, parent); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean io_watch_poll_prepare(GSource *source, | ||||||
|  |                                       gint *timeout) | ||||||
|  | { | ||||||
|  |     IOWatchPoll *iwp = io_watch_poll_from_source(source); | ||||||
|  |     bool now_active = iwp->fd_can_read(iwp->opaque) > 0; | ||||||
|  |     bool was_active = iwp->src != NULL; | ||||||
|  |     if (was_active == now_active) { | ||||||
|  |         return FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (now_active) { | ||||||
|  |         iwp->src = qio_channel_create_watch( | ||||||
|  |             iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL); | ||||||
|  |         g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL); | ||||||
|  |         g_source_attach(iwp->src, iwp->context); | ||||||
|  |     } else { | ||||||
|  |         g_source_destroy(iwp->src); | ||||||
|  |         g_source_unref(iwp->src); | ||||||
|  |         iwp->src = NULL; | ||||||
|  |     } | ||||||
|  |     return FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean io_watch_poll_check(GSource *source) | ||||||
|  | { | ||||||
|  |     return FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback, | ||||||
|  |                                        gpointer user_data) | ||||||
|  | { | ||||||
|  |     abort(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void io_watch_poll_finalize(GSource *source) | ||||||
|  | { | ||||||
|  |     /* Due to a glib bug, removing the last reference to a source | ||||||
|  |      * inside a finalize callback causes recursive locking (and a | ||||||
|  |      * deadlock).  This is not a problem inside other callbacks, | ||||||
|  |      * including dispatch callbacks, so we call io_remove_watch_poll | ||||||
|  |      * to remove this source.  At this point, iwp->src must | ||||||
|  |      * be NULL, or we would leak it. | ||||||
|  |      * | ||||||
|  |      * This would be solved much more elegantly by child sources, | ||||||
|  |      * but we support older glib versions that do not have them. | ||||||
|  |      */ | ||||||
|  |     IOWatchPoll *iwp = io_watch_poll_from_source(source); | ||||||
|  |     assert(iwp->src == NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static GSourceFuncs io_watch_poll_funcs = { | ||||||
|  |     .prepare = io_watch_poll_prepare, | ||||||
|  |     .check = io_watch_poll_check, | ||||||
|  |     .dispatch = io_watch_poll_dispatch, | ||||||
|  |     .finalize = io_watch_poll_finalize, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | guint io_add_watch_poll(Chardev *chr, | ||||||
|  |                         QIOChannel *ioc, | ||||||
|  |                         IOCanReadHandler *fd_can_read, | ||||||
|  |                         QIOChannelFunc fd_read, | ||||||
|  |                         gpointer user_data, | ||||||
|  |                         GMainContext *context) | ||||||
|  | { | ||||||
|  |     IOWatchPoll *iwp; | ||||||
|  |     int tag; | ||||||
|  |     char *name; | ||||||
|  |  | ||||||
|  |     iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, | ||||||
|  |                                        sizeof(IOWatchPoll)); | ||||||
|  |     iwp->fd_can_read = fd_can_read; | ||||||
|  |     iwp->opaque = user_data; | ||||||
|  |     iwp->ioc = ioc; | ||||||
|  |     iwp->fd_read = (GSourceFunc) fd_read; | ||||||
|  |     iwp->src = NULL; | ||||||
|  |     iwp->context = context; | ||||||
|  |  | ||||||
|  |     name = g_strdup_printf("chardev-iowatch-%s", chr->label); | ||||||
|  |     g_source_set_name((GSource *)iwp, name); | ||||||
|  |     g_free(name); | ||||||
|  |  | ||||||
|  |     tag = g_source_attach(&iwp->parent, context); | ||||||
|  |     g_source_unref(&iwp->parent); | ||||||
|  |     return tag; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void io_remove_watch_poll(guint tag) | ||||||
|  | { | ||||||
|  |     GSource *source; | ||||||
|  |     IOWatchPoll *iwp; | ||||||
|  |  | ||||||
|  |     g_return_if_fail(tag > 0); | ||||||
|  |  | ||||||
|  |     source = g_main_context_find_source_by_id(NULL, tag); | ||||||
|  |     g_return_if_fail(source != NULL); | ||||||
|  |  | ||||||
|  |     iwp = io_watch_poll_from_source(source); | ||||||
|  |     if (iwp->src) { | ||||||
|  |         g_source_destroy(iwp->src); | ||||||
|  |         g_source_unref(iwp->src); | ||||||
|  |         iwp->src = NULL; | ||||||
|  |     } | ||||||
|  |     g_source_destroy(&iwp->parent); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void remove_fd_in_watch(Chardev *chr) | ||||||
|  | { | ||||||
|  |     if (chr->fd_in_tag) { | ||||||
|  |         io_remove_watch_poll(chr->fd_in_tag); | ||||||
|  |         chr->fd_in_tag = 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int io_channel_send_full(QIOChannel *ioc, | ||||||
|  |                          const void *buf, size_t len, | ||||||
|  |                          int *fds, size_t nfds) | ||||||
|  | { | ||||||
|  |     size_t offset = 0; | ||||||
|  |  | ||||||
|  |     while (offset < len) { | ||||||
|  |         ssize_t ret = 0; | ||||||
|  |         struct iovec iov = { .iov_base = (char *)buf + offset, | ||||||
|  |                              .iov_len = len - offset }; | ||||||
|  |  | ||||||
|  |         ret = qio_channel_writev_full( | ||||||
|  |             ioc, &iov, 1, | ||||||
|  |             fds, nfds, NULL); | ||||||
|  |         if (ret == QIO_CHANNEL_ERR_BLOCK) { | ||||||
|  |             if (offset) { | ||||||
|  |                 return offset; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             errno = EAGAIN; | ||||||
|  |             return -1; | ||||||
|  |         } else if (ret < 0) { | ||||||
|  |             errno = EINVAL; | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         offset += ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return offset; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int io_channel_send(QIOChannel *ioc, const void *buf, size_t len) | ||||||
|  | { | ||||||
|  |     return io_channel_send_full(ioc, buf, len, NULL, 0); | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								chardev/char-io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								chardev/char-io.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef CHAR_IO_H | ||||||
|  | #define CHAR_IO_H | ||||||
|  |  | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "io/channel.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  |  | ||||||
|  | /* Can only be used for read */ | ||||||
|  | guint io_add_watch_poll(Chardev *chr, | ||||||
|  |                         QIOChannel *ioc, | ||||||
|  |                         IOCanReadHandler *fd_can_read, | ||||||
|  |                         QIOChannelFunc fd_read, | ||||||
|  |                         gpointer user_data, | ||||||
|  |                         GMainContext *context); | ||||||
|  |  | ||||||
|  | void remove_fd_in_watch(Chardev *chr); | ||||||
|  |  | ||||||
|  | int io_channel_send(QIOChannel *ioc, const void *buf, size_t len); | ||||||
|  |  | ||||||
|  | int io_channel_send_full(QIOChannel *ioc, const void *buf, size_t len, | ||||||
|  |                          int *fds, size_t nfds); | ||||||
|  |  | ||||||
|  | #endif /* CHAR_IO_H */ | ||||||
							
								
								
									
										358
									
								
								chardev/char-mux.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								chardev/char-mux.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,358 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  | #include "sysemu/block-backend.h" | ||||||
|  | #include "char-mux.h" | ||||||
|  |  | ||||||
|  | /* MUX driver for serial I/O splitting */ | ||||||
|  |  | ||||||
|  | /* Called with chr_write_lock held.  */ | ||||||
|  | static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len) | ||||||
|  | { | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(chr); | ||||||
|  |     int ret; | ||||||
|  |     if (!d->timestamps) { | ||||||
|  |         ret = qemu_chr_fe_write(&d->chr, buf, len); | ||||||
|  |     } else { | ||||||
|  |         int i; | ||||||
|  |  | ||||||
|  |         ret = 0; | ||||||
|  |         for (i = 0; i < len; i++) { | ||||||
|  |             if (d->linestart) { | ||||||
|  |                 char buf1[64]; | ||||||
|  |                 int64_t ti; | ||||||
|  |                 int secs; | ||||||
|  |  | ||||||
|  |                 ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); | ||||||
|  |                 if (d->timestamps_start == -1) { | ||||||
|  |                     d->timestamps_start = ti; | ||||||
|  |                 } | ||||||
|  |                 ti -= d->timestamps_start; | ||||||
|  |                 secs = ti / 1000; | ||||||
|  |                 snprintf(buf1, sizeof(buf1), | ||||||
|  |                          "[%02d:%02d:%02d.%03d] ", | ||||||
|  |                          secs / 3600, | ||||||
|  |                          (secs / 60) % 60, | ||||||
|  |                          secs % 60, | ||||||
|  |                          (int)(ti % 1000)); | ||||||
|  |                 /* XXX this blocks entire thread. Rewrite to use | ||||||
|  |                  * qemu_chr_fe_write and background I/O callbacks */ | ||||||
|  |                 qemu_chr_fe_write_all(&d->chr, | ||||||
|  |                                       (uint8_t *)buf1, strlen(buf1)); | ||||||
|  |                 d->linestart = 0; | ||||||
|  |             } | ||||||
|  |             ret += qemu_chr_fe_write(&d->chr, buf + i, 1); | ||||||
|  |             if (buf[i] == '\n') { | ||||||
|  |                 d->linestart = 1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char * const mux_help[] = { | ||||||
|  |     "% h    print this help\n\r", | ||||||
|  |     "% x    exit emulator\n\r", | ||||||
|  |     "% s    save disk data back to file (if -snapshot)\n\r", | ||||||
|  |     "% t    toggle console timestamps\n\r", | ||||||
|  |     "% b    send break (magic sysrq)\n\r", | ||||||
|  |     "% c    switch between console and monitor\n\r", | ||||||
|  |     "% %  sends %\n\r", | ||||||
|  |     NULL | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int term_escape_char = 0x01; /* ctrl-a is used for escape */ | ||||||
|  | static void mux_print_help(Chardev *chr) | ||||||
|  | { | ||||||
|  |     int i, j; | ||||||
|  |     char ebuf[15] = "Escape-Char"; | ||||||
|  |     char cbuf[50] = "\n\r"; | ||||||
|  |  | ||||||
|  |     if (term_escape_char > 0 && term_escape_char < 26) { | ||||||
|  |         snprintf(cbuf, sizeof(cbuf), "\n\r"); | ||||||
|  |         snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a'); | ||||||
|  |     } else { | ||||||
|  |         snprintf(cbuf, sizeof(cbuf), | ||||||
|  |                  "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", | ||||||
|  |                  term_escape_char); | ||||||
|  |     } | ||||||
|  |     /* XXX this blocks entire thread. Rewrite to use | ||||||
|  |      * qemu_chr_fe_write and background I/O callbacks */ | ||||||
|  |     qemu_chr_write_all(chr, (uint8_t *)cbuf, strlen(cbuf)); | ||||||
|  |     for (i = 0; mux_help[i] != NULL; i++) { | ||||||
|  |         for (j = 0; mux_help[i][j] != '\0'; j++) { | ||||||
|  |             if (mux_help[i][j] == '%') { | ||||||
|  |                 qemu_chr_write_all(chr, (uint8_t *)ebuf, strlen(ebuf)); | ||||||
|  |             } else { | ||||||
|  |                 qemu_chr_write_all(chr, (uint8_t *)&mux_help[i][j], 1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void mux_chr_send_event(MuxChardev *d, int mux_nr, int event) | ||||||
|  | { | ||||||
|  |     CharBackend *be = d->backends[mux_nr]; | ||||||
|  |  | ||||||
|  |     if (be && be->chr_event) { | ||||||
|  |         be->chr_event(be->opaque, event); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch) | ||||||
|  | { | ||||||
|  |     if (d->term_got_escape) { | ||||||
|  |         d->term_got_escape = 0; | ||||||
|  |         if (ch == term_escape_char) { | ||||||
|  |             goto send_char; | ||||||
|  |         } | ||||||
|  |         switch (ch) { | ||||||
|  |         case '?': | ||||||
|  |         case 'h': | ||||||
|  |             mux_print_help(chr); | ||||||
|  |             break; | ||||||
|  |         case 'x': | ||||||
|  |             { | ||||||
|  |                  const char *term =  "QEMU: Terminated\n\r"; | ||||||
|  |                  qemu_chr_write_all(chr, (uint8_t *)term, strlen(term)); | ||||||
|  |                  exit(0); | ||||||
|  |                  break; | ||||||
|  |             } | ||||||
|  |         case 's': | ||||||
|  |             blk_commit_all(); | ||||||
|  |             break; | ||||||
|  |         case 'b': | ||||||
|  |             qemu_chr_be_event(chr, CHR_EVENT_BREAK); | ||||||
|  |             break; | ||||||
|  |         case 'c': | ||||||
|  |             assert(d->mux_cnt > 0); /* handler registered with first fe */ | ||||||
|  |             /* Switch to the next registered device */ | ||||||
|  |             mux_set_focus(chr, (d->focus + 1) % d->mux_cnt); | ||||||
|  |             break; | ||||||
|  |         case 't': | ||||||
|  |             d->timestamps = !d->timestamps; | ||||||
|  |             d->timestamps_start = -1; | ||||||
|  |             d->linestart = 0; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } else if (ch == term_escape_char) { | ||||||
|  |         d->term_got_escape = 1; | ||||||
|  |     } else { | ||||||
|  |     send_char: | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void mux_chr_accept_input(Chardev *chr) | ||||||
|  | { | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(chr); | ||||||
|  |     int m = d->focus; | ||||||
|  |     CharBackend *be = d->backends[m]; | ||||||
|  |  | ||||||
|  |     while (be && d->prod[m] != d->cons[m] && | ||||||
|  |            be->chr_can_read && be->chr_can_read(be->opaque)) { | ||||||
|  |         be->chr_read(be->opaque, | ||||||
|  |                      &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int mux_chr_can_read(void *opaque) | ||||||
|  | { | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(opaque); | ||||||
|  |     int m = d->focus; | ||||||
|  |     CharBackend *be = d->backends[m]; | ||||||
|  |  | ||||||
|  |     if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE) { | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (be && be->chr_can_read) { | ||||||
|  |         return be->chr_can_read(be->opaque); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void mux_chr_read(void *opaque, const uint8_t *buf, int size) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(opaque); | ||||||
|  |     int m = d->focus; | ||||||
|  |     CharBackend *be = d->backends[m]; | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     mux_chr_accept_input(opaque); | ||||||
|  |  | ||||||
|  |     for (i = 0; i < size; i++) | ||||||
|  |         if (mux_proc_byte(chr, d, buf[i])) { | ||||||
|  |             if (d->prod[m] == d->cons[m] && | ||||||
|  |                 be && be->chr_can_read && | ||||||
|  |                 be->chr_can_read(be->opaque)) { | ||||||
|  |                 be->chr_read(be->opaque, &buf[i], 1); | ||||||
|  |             } else { | ||||||
|  |                 d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool muxes_realized; | ||||||
|  |  | ||||||
|  | static void mux_chr_event(void *opaque, int event) | ||||||
|  | { | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(opaque); | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     if (!muxes_realized) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Send the event to all registered listeners */ | ||||||
|  |     for (i = 0; i < d->mux_cnt; i++) { | ||||||
|  |         mux_chr_send_event(d, i, event); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond) | ||||||
|  | { | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(s); | ||||||
|  |     Chardev *chr = qemu_chr_fe_get_driver(&d->chr); | ||||||
|  |     ChardevClass *cc = CHARDEV_GET_CLASS(chr); | ||||||
|  |  | ||||||
|  |     if (!cc->chr_add_watch) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return cc->chr_add_watch(chr, cond); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_mux_finalize(Object *obj) | ||||||
|  | { | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(obj); | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     for (i = 0; i < d->mux_cnt; i++) { | ||||||
|  |         CharBackend *be = d->backends[i]; | ||||||
|  |         if (be) { | ||||||
|  |             be->chr = NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     qemu_chr_fe_deinit(&d->chr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void mux_chr_set_handlers(Chardev *chr, GMainContext *context) | ||||||
|  | { | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     /* Fix up the real driver with mux routines */ | ||||||
|  |     qemu_chr_fe_set_handlers(&d->chr, | ||||||
|  |                              mux_chr_can_read, | ||||||
|  |                              mux_chr_read, | ||||||
|  |                              mux_chr_event, | ||||||
|  |                              chr, | ||||||
|  |                              context, true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void mux_set_focus(Chardev *chr, int focus) | ||||||
|  | { | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     assert(focus >= 0); | ||||||
|  |     assert(focus < d->mux_cnt); | ||||||
|  |  | ||||||
|  |     if (d->focus != -1) { | ||||||
|  |         mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     d->focus = focus; | ||||||
|  |     mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_mux(Chardev *chr, | ||||||
|  |                               ChardevBackend *backend, | ||||||
|  |                               bool *be_opened, | ||||||
|  |                               Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevMux *mux = backend->u.mux.data; | ||||||
|  |     Chardev *drv; | ||||||
|  |     MuxChardev *d = MUX_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     drv = qemu_chr_find(mux->chardev); | ||||||
|  |     if (drv == NULL) { | ||||||
|  |         error_setg(errp, "mux: base chardev %s not found", mux->chardev); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     d->focus = -1; | ||||||
|  |     /* only default to opened state if we've realized the initial | ||||||
|  |      * set of muxes | ||||||
|  |      */ | ||||||
|  |     *be_opened = muxes_realized; | ||||||
|  |     qemu_chr_fe_init(&d->chr, drv, errp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend, | ||||||
|  |                                Error **errp) | ||||||
|  | { | ||||||
|  |     const char *chardev = qemu_opt_get(opts, "chardev"); | ||||||
|  |     ChardevMux *mux; | ||||||
|  |  | ||||||
|  |     if (chardev == NULL) { | ||||||
|  |         error_setg(errp, "chardev: mux: no chardev given"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     backend->type = CHARDEV_BACKEND_KIND_MUX; | ||||||
|  |     mux = backend->u.mux.data = g_new0(ChardevMux, 1); | ||||||
|  |     qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux)); | ||||||
|  |     mux->chardev = g_strdup(chardev); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_mux_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->parse = qemu_chr_parse_mux; | ||||||
|  |     cc->open = qemu_chr_open_mux; | ||||||
|  |     cc->chr_write = mux_chr_write; | ||||||
|  |     cc->chr_accept_input = mux_chr_accept_input; | ||||||
|  |     cc->chr_add_watch = mux_chr_add_watch; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_mux_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_MUX, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .class_init = char_mux_class_init, | ||||||
|  |     .instance_size = sizeof(MuxChardev), | ||||||
|  |     .instance_finalize = char_mux_finalize, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_mux_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										63
									
								
								chardev/char-mux.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								chardev/char-mux.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef CHAR_MUX_H | ||||||
|  | #define CHAR_MUX_H | ||||||
|  |  | ||||||
|  | #include "sysemu/char.h" | ||||||
|  |  | ||||||
|  | extern bool muxes_realized; | ||||||
|  |  | ||||||
|  | #define MAX_MUX 4 | ||||||
|  | #define MUX_BUFFER_SIZE 32 /* Must be a power of 2.  */ | ||||||
|  | #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1) | ||||||
|  | typedef struct MuxChardev { | ||||||
|  |     Chardev parent; | ||||||
|  |     CharBackend *backends[MAX_MUX]; | ||||||
|  |     CharBackend chr; | ||||||
|  |     int focus; | ||||||
|  |     int mux_cnt; | ||||||
|  |     int term_got_escape; | ||||||
|  |     int max_size; | ||||||
|  |     /* Intermediate input buffer catches escape sequences even if the | ||||||
|  |        currently active device is not accepting any input - but only until it | ||||||
|  |        is full as well. */ | ||||||
|  |     unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE]; | ||||||
|  |     int prod[MAX_MUX]; | ||||||
|  |     int cons[MAX_MUX]; | ||||||
|  |     int timestamps; | ||||||
|  |  | ||||||
|  |     /* Protected by the Chardev chr_write_lock.  */ | ||||||
|  |     int linestart; | ||||||
|  |     int64_t timestamps_start; | ||||||
|  | } MuxChardev; | ||||||
|  |  | ||||||
|  | #define MUX_CHARDEV(obj) OBJECT_CHECK(MuxChardev, (obj), TYPE_CHARDEV_MUX) | ||||||
|  | #define CHARDEV_IS_MUX(chr)                             \ | ||||||
|  |     object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX) | ||||||
|  |  | ||||||
|  | void mux_chr_set_handlers(Chardev *chr, GMainContext *context); | ||||||
|  | void mux_set_focus(Chardev *chr, int focus); | ||||||
|  | void mux_chr_send_event(MuxChardev *d, int mux_nr, int event); | ||||||
|  |  | ||||||
|  | #endif /* CHAR_MUX_H */ | ||||||
							
								
								
									
										54
									
								
								chardev/char-null.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								chardev/char-null.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  |  | ||||||
|  | static void null_chr_open(Chardev *chr, | ||||||
|  |                           ChardevBackend *backend, | ||||||
|  |                           bool *be_opened, | ||||||
|  |                           Error **errp) | ||||||
|  | { | ||||||
|  |     *be_opened = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_null_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->open = null_chr_open; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_null_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_NULL, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .instance_size = sizeof(Chardev), | ||||||
|  |     .class_init = char_null_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_null_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										316
									
								
								chardev/char-parallel.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								chardev/char-parallel.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,316 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include <sys/ioctl.h> | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_BSD | ||||||
|  | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | ||||||
|  | #include <dev/ppbus/ppi.h> | ||||||
|  | #include <dev/ppbus/ppbconf.h> | ||||||
|  | #elif defined(__DragonFly__) | ||||||
|  | #include <dev/misc/ppi/ppi.h> | ||||||
|  | #include <bus/ppbus/ppbconf.h> | ||||||
|  | #endif | ||||||
|  | #else | ||||||
|  | #ifdef __linux__ | ||||||
|  | #include <linux/ppdev.h> | ||||||
|  | #include <linux/parport.h> | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "char-fd.h" | ||||||
|  | #include "char-parallel.h" | ||||||
|  |  | ||||||
|  | #if defined(__linux__) | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     Chardev parent; | ||||||
|  |     int fd; | ||||||
|  |     int mode; | ||||||
|  | } ParallelChardev; | ||||||
|  |  | ||||||
|  | #define PARALLEL_CHARDEV(obj) \ | ||||||
|  |     OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL) | ||||||
|  |  | ||||||
|  | static int pp_hw_mode(ParallelChardev *s, uint16_t mode) | ||||||
|  | { | ||||||
|  |     if (s->mode != mode) { | ||||||
|  |         int m = mode; | ||||||
|  |         if (ioctl(s->fd, PPSETMODE, &m) < 0) { | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         s->mode = mode; | ||||||
|  |     } | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int pp_ioctl(Chardev *chr, int cmd, void *arg) | ||||||
|  | { | ||||||
|  |     ParallelChardev *drv = PARALLEL_CHARDEV(chr); | ||||||
|  |     int fd = drv->fd; | ||||||
|  |     uint8_t b; | ||||||
|  |  | ||||||
|  |     switch (cmd) { | ||||||
|  |     case CHR_IOCTL_PP_READ_DATA: | ||||||
|  |         if (ioctl(fd, PPRDATA, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         *(uint8_t *)arg = b; | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_WRITE_DATA: | ||||||
|  |         b = *(uint8_t *)arg; | ||||||
|  |         if (ioctl(fd, PPWDATA, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_READ_CONTROL: | ||||||
|  |         if (ioctl(fd, PPRCONTROL, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         /* Linux gives only the lowest bits, and no way to know data | ||||||
|  |            direction! For better compatibility set the fixed upper | ||||||
|  |            bits. */ | ||||||
|  |         *(uint8_t *)arg = b | 0xc0; | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_WRITE_CONTROL: | ||||||
|  |         b = *(uint8_t *)arg; | ||||||
|  |         if (ioctl(fd, PPWCONTROL, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_READ_STATUS: | ||||||
|  |         if (ioctl(fd, PPRSTATUS, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         *(uint8_t *)arg = b; | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_DATA_DIR: | ||||||
|  |         if (ioctl(fd, PPDATADIR, (int *)arg) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_EPP_READ_ADDR: | ||||||
|  |         if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) { | ||||||
|  |             struct ParallelIOArg *parg = arg; | ||||||
|  |             int n = read(fd, parg->buffer, parg->count); | ||||||
|  |             if (n != parg->count) { | ||||||
|  |                 return -EIO; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_EPP_READ: | ||||||
|  |         if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) { | ||||||
|  |             struct ParallelIOArg *parg = arg; | ||||||
|  |             int n = read(fd, parg->buffer, parg->count); | ||||||
|  |             if (n != parg->count) { | ||||||
|  |                 return -EIO; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_EPP_WRITE_ADDR: | ||||||
|  |         if (pp_hw_mode(drv, IEEE1284_MODE_EPP | IEEE1284_ADDR)) { | ||||||
|  |             struct ParallelIOArg *parg = arg; | ||||||
|  |             int n = write(fd, parg->buffer, parg->count); | ||||||
|  |             if (n != parg->count) { | ||||||
|  |                 return -EIO; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_EPP_WRITE: | ||||||
|  |         if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) { | ||||||
|  |             struct ParallelIOArg *parg = arg; | ||||||
|  |             int n = write(fd, parg->buffer, parg->count); | ||||||
|  |             if (n != parg->count) { | ||||||
|  |                 return -EIO; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         return -ENOTSUP; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_pp_fd(Chardev *chr, | ||||||
|  |                                 int fd, | ||||||
|  |                                 bool *be_opened, | ||||||
|  |                                 Error **errp) | ||||||
|  | { | ||||||
|  |     ParallelChardev *drv = PARALLEL_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     if (ioctl(fd, PPCLAIM) < 0) { | ||||||
|  |         error_setg_errno(errp, errno, "not a parallel port"); | ||||||
|  |         close(fd); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     drv->fd = fd; | ||||||
|  |     drv->mode = IEEE1284_MODE_COMPAT; | ||||||
|  | } | ||||||
|  | #endif /* __linux__ */ | ||||||
|  |  | ||||||
|  | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     Chardev parent; | ||||||
|  |     int fd; | ||||||
|  | } ParallelChardev; | ||||||
|  |  | ||||||
|  | #define PARALLEL_CHARDEV(obj)                                   \ | ||||||
|  |     OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL) | ||||||
|  |  | ||||||
|  | static int pp_ioctl(Chardev *chr, int cmd, void *arg) | ||||||
|  | { | ||||||
|  |     ParallelChardev *drv = PARALLEL_CHARDEV(chr); | ||||||
|  |     uint8_t b; | ||||||
|  |  | ||||||
|  |     switch (cmd) { | ||||||
|  |     case CHR_IOCTL_PP_READ_DATA: | ||||||
|  |         if (ioctl(drv->fd, PPIGDATA, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         *(uint8_t *)arg = b; | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_WRITE_DATA: | ||||||
|  |         b = *(uint8_t *)arg; | ||||||
|  |         if (ioctl(drv->fd, PPISDATA, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_READ_CONTROL: | ||||||
|  |         if (ioctl(drv->fd, PPIGCTRL, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         *(uint8_t *)arg = b; | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_WRITE_CONTROL: | ||||||
|  |         b = *(uint8_t *)arg; | ||||||
|  |         if (ioctl(drv->fd, PPISCTRL, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_PP_READ_STATUS: | ||||||
|  |         if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) { | ||||||
|  |             return -ENOTSUP; | ||||||
|  |         } | ||||||
|  |         *(uint8_t *)arg = b; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         return -ENOTSUP; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_pp_fd(Chardev *chr, | ||||||
|  |                                 int fd, | ||||||
|  |                                 bool *be_opened, | ||||||
|  |                                 Error **errp) | ||||||
|  | { | ||||||
|  |     ParallelChardev *drv = PARALLEL_CHARDEV(chr); | ||||||
|  |     drv->fd = fd; | ||||||
|  |     *be_opened = false; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef HAVE_CHARDEV_PARPORT | ||||||
|  | static void qmp_chardev_open_parallel(Chardev *chr, | ||||||
|  |                                       ChardevBackend *backend, | ||||||
|  |                                       bool *be_opened, | ||||||
|  |                                       Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevHostdev *parallel = backend->u.parallel.data; | ||||||
|  |     int fd; | ||||||
|  |  | ||||||
|  |     fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp); | ||||||
|  |     if (fd < 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     qemu_chr_open_pp_fd(chr, fd, be_opened, errp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, | ||||||
|  |                                     Error **errp) | ||||||
|  | { | ||||||
|  |     const char *device = qemu_opt_get(opts, "path"); | ||||||
|  |     ChardevHostdev *parallel; | ||||||
|  |  | ||||||
|  |     if (device == NULL) { | ||||||
|  |         error_setg(errp, "chardev: parallel: no device path given"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     backend->type = CHARDEV_BACKEND_KIND_PARALLEL; | ||||||
|  |     parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1); | ||||||
|  |     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel)); | ||||||
|  |     parallel->device = g_strdup(device); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_parallel_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->parse = qemu_chr_parse_parallel; | ||||||
|  |     cc->open = qmp_chardev_open_parallel; | ||||||
|  | #if defined(__linux__) | ||||||
|  |     cc->chr_ioctl = pp_ioctl; | ||||||
|  | #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ | ||||||
|  |     defined(__DragonFly__) | ||||||
|  |     cc->chr_ioctl = pp_ioctl; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_parallel_finalize(Object *obj) | ||||||
|  | { | ||||||
|  | #if defined(__linux__) | ||||||
|  |     Chardev *chr = CHARDEV(obj); | ||||||
|  |     ParallelChardev *drv = PARALLEL_CHARDEV(chr); | ||||||
|  |     int fd = drv->fd; | ||||||
|  |  | ||||||
|  |     pp_hw_mode(drv, IEEE1284_MODE_COMPAT); | ||||||
|  |     ioctl(fd, PPRELEASE); | ||||||
|  |     close(fd); | ||||||
|  |     qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | ||||||
|  | #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ | ||||||
|  |     defined(__DragonFly__) | ||||||
|  |     /* FIXME: close fd? */ | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_parallel_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_PARALLEL, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .instance_size = sizeof(ParallelChardev), | ||||||
|  |     .instance_finalize = char_parallel_finalize, | ||||||
|  |     .class_init = char_parallel_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_parallel_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										32
									
								
								chardev/char-parallel.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								chardev/char-parallel.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef CHAR_PARALLEL_H | ||||||
|  | #define CHAR_PARALLEL_H | ||||||
|  |  | ||||||
|  | #if defined(__linux__) || defined(__FreeBSD__) || \ | ||||||
|  |     defined(__FreeBSD_kernel__) || defined(__DragonFly__) | ||||||
|  | #define HAVE_CHARDEV_PARPORT 1 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* CHAR_PARALLEL_H */ | ||||||
							
								
								
									
										191
									
								
								chardev/char-pipe.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								chardev/char-pipe.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include "char-win.h" | ||||||
|  | #else | ||||||
|  | #include "char-fd.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #define MAXCONNECT 1 | ||||||
|  | #define NTIMEOUT 5000 | ||||||
|  |  | ||||||
|  | static int win_chr_pipe_init(Chardev *chr, const char *filename, | ||||||
|  |                              Error **errp) | ||||||
|  | { | ||||||
|  |     WinChardev *s = WIN_CHARDEV(chr); | ||||||
|  |     OVERLAPPED ov; | ||||||
|  |     int ret; | ||||||
|  |     DWORD size; | ||||||
|  |     char *openname; | ||||||
|  |  | ||||||
|  |     s->fpipe = TRUE; | ||||||
|  |  | ||||||
|  |     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); | ||||||
|  |     if (!s->hsend) { | ||||||
|  |         error_setg(errp, "Failed CreateEvent"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); | ||||||
|  |     if (!s->hrecv) { | ||||||
|  |         error_setg(errp, "Failed CreateEvent"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     openname = g_strdup_printf("\\\\.\\pipe\\%s", filename); | ||||||
|  |     s->hcom = CreateNamedPipe(openname, | ||||||
|  |                               PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, | ||||||
|  |                               PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | | ||||||
|  |                               PIPE_WAIT, | ||||||
|  |                               MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL); | ||||||
|  |     g_free(openname); | ||||||
|  |     if (s->hcom == INVALID_HANDLE_VALUE) { | ||||||
|  |         error_setg(errp, "Failed CreateNamedPipe (%lu)", GetLastError()); | ||||||
|  |         s->hcom = NULL; | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ZeroMemory(&ov, sizeof(ov)); | ||||||
|  |     ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | ||||||
|  |     ret = ConnectNamedPipe(s->hcom, &ov); | ||||||
|  |     if (ret) { | ||||||
|  |         error_setg(errp, "Failed ConnectNamedPipe"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE); | ||||||
|  |     if (!ret) { | ||||||
|  |         error_setg(errp, "Failed GetOverlappedResult"); | ||||||
|  |         if (ov.hEvent) { | ||||||
|  |             CloseHandle(ov.hEvent); | ||||||
|  |             ov.hEvent = NULL; | ||||||
|  |         } | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (ov.hEvent) { | ||||||
|  |         CloseHandle(ov.hEvent); | ||||||
|  |         ov.hEvent = NULL; | ||||||
|  |     } | ||||||
|  |     qemu_add_polling_cb(win_chr_pipe_poll, chr); | ||||||
|  |     return 0; | ||||||
|  |  | ||||||
|  |  fail: | ||||||
|  |     return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_pipe(Chardev *chr, | ||||||
|  |                                ChardevBackend *backend, | ||||||
|  |                                bool *be_opened, | ||||||
|  |                                Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevHostdev *opts = backend->u.pipe.data; | ||||||
|  |     const char *filename = opts->device; | ||||||
|  |  | ||||||
|  |     if (win_chr_pipe_init(chr, filename, errp) < 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_pipe(Chardev *chr, | ||||||
|  |                                ChardevBackend *backend, | ||||||
|  |                                bool *be_opened, | ||||||
|  |                                Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevHostdev *opts = backend->u.pipe.data; | ||||||
|  |     int fd_in, fd_out; | ||||||
|  |     char *filename_in; | ||||||
|  |     char *filename_out; | ||||||
|  |     const char *filename = opts->device; | ||||||
|  |  | ||||||
|  |     filename_in = g_strdup_printf("%s.in", filename); | ||||||
|  |     filename_out = g_strdup_printf("%s.out", filename); | ||||||
|  |     TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY)); | ||||||
|  |     TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY)); | ||||||
|  |     g_free(filename_in); | ||||||
|  |     g_free(filename_out); | ||||||
|  |     if (fd_in < 0 || fd_out < 0) { | ||||||
|  |         if (fd_in >= 0) { | ||||||
|  |             close(fd_in); | ||||||
|  |         } | ||||||
|  |         if (fd_out >= 0) { | ||||||
|  |             close(fd_out); | ||||||
|  |         } | ||||||
|  |         TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY)); | ||||||
|  |         if (fd_in < 0) { | ||||||
|  |             error_setg_file_open(errp, errno, filename); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     qemu_chr_open_fd(chr, fd_in, fd_out); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif /* !_WIN32 */ | ||||||
|  |  | ||||||
|  | static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, | ||||||
|  |                                 Error **errp) | ||||||
|  | { | ||||||
|  |     const char *device = qemu_opt_get(opts, "path"); | ||||||
|  |     ChardevHostdev *dev; | ||||||
|  |  | ||||||
|  |     if (device == NULL) { | ||||||
|  |         error_setg(errp, "chardev: pipe: no device path given"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     backend->type = CHARDEV_BACKEND_KIND_PIPE; | ||||||
|  |     dev = backend->u.pipe.data = g_new0(ChardevHostdev, 1); | ||||||
|  |     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev)); | ||||||
|  |     dev->device = g_strdup(device); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_pipe_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->parse = qemu_chr_parse_pipe; | ||||||
|  |     cc->open = qemu_chr_open_pipe; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_pipe_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_PIPE, | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     .parent = TYPE_CHARDEV_WIN, | ||||||
|  | #else | ||||||
|  |     .parent = TYPE_CHARDEV_FD, | ||||||
|  | #endif | ||||||
|  |     .class_init = char_pipe_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_pipe_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										300
									
								
								chardev/char-pty.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								chardev/char-pty.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,300 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  | #include "io/channel-file.h" | ||||||
|  | #include "qemu/sockets.h" | ||||||
|  | #include "qemu/error-report.h" | ||||||
|  |  | ||||||
|  | #include "char-io.h" | ||||||
|  |  | ||||||
|  | #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \ | ||||||
|  |     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ | ||||||
|  |     || defined(__GLIBC__) | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     Chardev parent; | ||||||
|  |     QIOChannel *ioc; | ||||||
|  |     int read_bytes; | ||||||
|  |  | ||||||
|  |     /* Protected by the Chardev chr_write_lock.  */ | ||||||
|  |     int connected; | ||||||
|  |     guint timer_tag; | ||||||
|  |     guint open_tag; | ||||||
|  | } PtyChardev; | ||||||
|  |  | ||||||
|  | #define PTY_CHARDEV(obj) OBJECT_CHECK(PtyChardev, (obj), TYPE_CHARDEV_PTY) | ||||||
|  |  | ||||||
|  | static void pty_chr_update_read_handler_locked(Chardev *chr); | ||||||
|  | static void pty_chr_state(Chardev *chr, int connected); | ||||||
|  |  | ||||||
|  | static gboolean pty_chr_timer(gpointer opaque) | ||||||
|  | { | ||||||
|  |     struct Chardev *chr = CHARDEV(opaque); | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(opaque); | ||||||
|  |  | ||||||
|  |     qemu_mutex_lock(&chr->chr_write_lock); | ||||||
|  |     s->timer_tag = 0; | ||||||
|  |     s->open_tag = 0; | ||||||
|  |     if (!s->connected) { | ||||||
|  |         /* Next poll ... */ | ||||||
|  |         pty_chr_update_read_handler_locked(chr); | ||||||
|  |     } | ||||||
|  |     qemu_mutex_unlock(&chr->chr_write_lock); | ||||||
|  |     return FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Called with chr_write_lock held.  */ | ||||||
|  | static void pty_chr_rearm_timer(Chardev *chr, int ms) | ||||||
|  | { | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(chr); | ||||||
|  |     char *name; | ||||||
|  |  | ||||||
|  |     if (s->timer_tag) { | ||||||
|  |         g_source_remove(s->timer_tag); | ||||||
|  |         s->timer_tag = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (ms == 1000) { | ||||||
|  |         name = g_strdup_printf("pty-timer-secs-%s", chr->label); | ||||||
|  |         s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr); | ||||||
|  |     } else { | ||||||
|  |         name = g_strdup_printf("pty-timer-ms-%s", chr->label); | ||||||
|  |         s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr); | ||||||
|  |     } | ||||||
|  |     g_source_set_name_by_id(s->timer_tag, name); | ||||||
|  |     g_free(name); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Called with chr_write_lock held.  */ | ||||||
|  | static void pty_chr_update_read_handler_locked(Chardev *chr) | ||||||
|  | { | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(chr); | ||||||
|  |     GPollFD pfd; | ||||||
|  |     int rc; | ||||||
|  |     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc); | ||||||
|  |  | ||||||
|  |     pfd.fd = fioc->fd; | ||||||
|  |     pfd.events = G_IO_OUT; | ||||||
|  |     pfd.revents = 0; | ||||||
|  |     do { | ||||||
|  |         rc = g_poll(&pfd, 1, 0); | ||||||
|  |     } while (rc == -1 && errno == EINTR); | ||||||
|  |     assert(rc >= 0); | ||||||
|  |  | ||||||
|  |     if (pfd.revents & G_IO_HUP) { | ||||||
|  |         pty_chr_state(chr, 0); | ||||||
|  |     } else { | ||||||
|  |         pty_chr_state(chr, 1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void pty_chr_update_read_handler(Chardev *chr, | ||||||
|  |                                         GMainContext *context) | ||||||
|  | { | ||||||
|  |     qemu_mutex_lock(&chr->chr_write_lock); | ||||||
|  |     pty_chr_update_read_handler_locked(chr); | ||||||
|  |     qemu_mutex_unlock(&chr->chr_write_lock); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Called with chr_write_lock held.  */ | ||||||
|  | static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len) | ||||||
|  | { | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     if (!s->connected) { | ||||||
|  |         /* guest sends data, check for (re-)connect */ | ||||||
|  |         pty_chr_update_read_handler_locked(chr); | ||||||
|  |         if (!s->connected) { | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return io_channel_send(s->ioc, buf, len); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond) | ||||||
|  | { | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(chr); | ||||||
|  |     if (!s->connected) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     return qio_channel_create_watch(s->ioc, cond); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int pty_chr_read_poll(void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(opaque); | ||||||
|  |  | ||||||
|  |     s->read_bytes = qemu_chr_be_can_write(chr); | ||||||
|  |     return s->read_bytes; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(opaque); | ||||||
|  |     gsize len; | ||||||
|  |     uint8_t buf[CHR_READ_BUF_LEN]; | ||||||
|  |     ssize_t ret; | ||||||
|  |  | ||||||
|  |     len = sizeof(buf); | ||||||
|  |     if (len > s->read_bytes) { | ||||||
|  |         len = s->read_bytes; | ||||||
|  |     } | ||||||
|  |     if (len == 0) { | ||||||
|  |         return TRUE; | ||||||
|  |     } | ||||||
|  |     ret = qio_channel_read(s->ioc, (char *)buf, len, NULL); | ||||||
|  |     if (ret <= 0) { | ||||||
|  |         pty_chr_state(chr, 0); | ||||||
|  |         return FALSE; | ||||||
|  |     } else { | ||||||
|  |         pty_chr_state(chr, 1); | ||||||
|  |         qemu_chr_be_write(chr, buf, ret); | ||||||
|  |     } | ||||||
|  |     return TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean qemu_chr_be_generic_open_func(gpointer opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(opaque); | ||||||
|  |  | ||||||
|  |     s->open_tag = 0; | ||||||
|  |     qemu_chr_be_generic_open(chr); | ||||||
|  |     return FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Called with chr_write_lock held.  */ | ||||||
|  | static void pty_chr_state(Chardev *chr, int connected) | ||||||
|  | { | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     if (!connected) { | ||||||
|  |         if (s->open_tag) { | ||||||
|  |             g_source_remove(s->open_tag); | ||||||
|  |             s->open_tag = 0; | ||||||
|  |         } | ||||||
|  |         remove_fd_in_watch(chr); | ||||||
|  |         s->connected = 0; | ||||||
|  |         /* (re-)connect poll interval for idle guests: once per second. | ||||||
|  |          * We check more frequently in case the guests sends data to | ||||||
|  |          * the virtual device linked to our pty. */ | ||||||
|  |         pty_chr_rearm_timer(chr, 1000); | ||||||
|  |     } else { | ||||||
|  |         if (s->timer_tag) { | ||||||
|  |             g_source_remove(s->timer_tag); | ||||||
|  |             s->timer_tag = 0; | ||||||
|  |         } | ||||||
|  |         if (!s->connected) { | ||||||
|  |             g_assert(s->open_tag == 0); | ||||||
|  |             s->connected = 1; | ||||||
|  |             s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr); | ||||||
|  |         } | ||||||
|  |         if (!chr->fd_in_tag) { | ||||||
|  |             chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, | ||||||
|  |                                                pty_chr_read_poll, | ||||||
|  |                                                pty_chr_read, | ||||||
|  |                                                chr, NULL); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_pty_finalize(Object *obj) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(obj); | ||||||
|  |     PtyChardev *s = PTY_CHARDEV(obj); | ||||||
|  |  | ||||||
|  |     qemu_mutex_lock(&chr->chr_write_lock); | ||||||
|  |     pty_chr_state(chr, 0); | ||||||
|  |     object_unref(OBJECT(s->ioc)); | ||||||
|  |     if (s->timer_tag) { | ||||||
|  |         g_source_remove(s->timer_tag); | ||||||
|  |         s->timer_tag = 0; | ||||||
|  |     } | ||||||
|  |     qemu_mutex_unlock(&chr->chr_write_lock); | ||||||
|  |     qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_pty_open(Chardev *chr, | ||||||
|  |                           ChardevBackend *backend, | ||||||
|  |                           bool *be_opened, | ||||||
|  |                           Error **errp) | ||||||
|  | { | ||||||
|  |     PtyChardev *s; | ||||||
|  |     int master_fd, slave_fd; | ||||||
|  |     char pty_name[PATH_MAX]; | ||||||
|  |     char *name; | ||||||
|  |  | ||||||
|  |     master_fd = qemu_openpty_raw(&slave_fd, pty_name); | ||||||
|  |     if (master_fd < 0) { | ||||||
|  |         error_setg_errno(errp, errno, "Failed to create PTY"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     close(slave_fd); | ||||||
|  |     qemu_set_nonblock(master_fd); | ||||||
|  |  | ||||||
|  |     chr->filename = g_strdup_printf("pty:%s", pty_name); | ||||||
|  |     error_report("char device redirected to %s (label %s)", | ||||||
|  |                  pty_name, chr->label); | ||||||
|  |  | ||||||
|  |     s = PTY_CHARDEV(chr); | ||||||
|  |     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd)); | ||||||
|  |     name = g_strdup_printf("chardev-pty-%s", chr->label); | ||||||
|  |     qio_channel_set_name(QIO_CHANNEL(s->ioc), name); | ||||||
|  |     g_free(name); | ||||||
|  |     s->timer_tag = 0; | ||||||
|  |     *be_opened = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_pty_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->open = char_pty_open; | ||||||
|  |     cc->chr_write = char_pty_chr_write; | ||||||
|  |     cc->chr_update_read_handler = pty_chr_update_read_handler; | ||||||
|  |     cc->chr_add_watch = pty_chr_add_watch; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_pty_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_PTY, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .instance_size = sizeof(PtyChardev), | ||||||
|  |     .instance_finalize = char_pty_finalize, | ||||||
|  |     .class_init = char_pty_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_pty_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										249
									
								
								chardev/char-ringbuf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								chardev/char-ringbuf.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,249 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  | #include "qmp-commands.h" | ||||||
|  | #include "qemu/base64.h" | ||||||
|  |  | ||||||
|  | /* Ring buffer chardev */ | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     Chardev parent; | ||||||
|  |     size_t size; | ||||||
|  |     size_t prod; | ||||||
|  |     size_t cons; | ||||||
|  |     uint8_t *cbuf; | ||||||
|  | } RingBufChardev; | ||||||
|  |  | ||||||
|  | #define RINGBUF_CHARDEV(obj)                                    \ | ||||||
|  |     OBJECT_CHECK(RingBufChardev, (obj), TYPE_CHARDEV_RINGBUF) | ||||||
|  |  | ||||||
|  | static size_t ringbuf_count(const Chardev *chr) | ||||||
|  | { | ||||||
|  |     const RingBufChardev *d = RINGBUF_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     return d->prod - d->cons; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len) | ||||||
|  | { | ||||||
|  |     RingBufChardev *d = RINGBUF_CHARDEV(chr); | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     if (!buf || (len < 0)) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (i = 0; i < len; i++) { | ||||||
|  |         d->cbuf[d->prod++ & (d->size - 1)] = buf[i]; | ||||||
|  |         if (d->prod - d->cons > d->size) { | ||||||
|  |             d->cons = d->prod - d->size; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len) | ||||||
|  | { | ||||||
|  |     RingBufChardev *d = RINGBUF_CHARDEV(chr); | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     qemu_mutex_lock(&chr->chr_write_lock); | ||||||
|  |     for (i = 0; i < len && d->cons != d->prod; i++) { | ||||||
|  |         buf[i] = d->cbuf[d->cons++ & (d->size - 1)]; | ||||||
|  |     } | ||||||
|  |     qemu_mutex_unlock(&chr->chr_write_lock); | ||||||
|  |  | ||||||
|  |     return i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_ringbuf_finalize(Object *obj) | ||||||
|  | { | ||||||
|  |     RingBufChardev *d = RINGBUF_CHARDEV(obj); | ||||||
|  |  | ||||||
|  |     g_free(d->cbuf); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_ringbuf(Chardev *chr, | ||||||
|  |                                   ChardevBackend *backend, | ||||||
|  |                                   bool *be_opened, | ||||||
|  |                                   Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevRingbuf *opts = backend->u.ringbuf.data; | ||||||
|  |     RingBufChardev *d = RINGBUF_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     d->size = opts->has_size ? opts->size : 65536; | ||||||
|  |  | ||||||
|  |     /* The size must be power of 2 */ | ||||||
|  |     if (d->size & (d->size - 1)) { | ||||||
|  |         error_setg(errp, "size of ringbuf chardev must be power of two"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     d->prod = 0; | ||||||
|  |     d->cons = 0; | ||||||
|  |     d->cbuf = g_malloc0(d->size); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void qmp_ringbuf_write(const char *device, const char *data, | ||||||
|  |                        bool has_format, enum DataFormat format, | ||||||
|  |                        Error **errp) | ||||||
|  | { | ||||||
|  |     Chardev *chr; | ||||||
|  |     const uint8_t *write_data; | ||||||
|  |     int ret; | ||||||
|  |     gsize write_count; | ||||||
|  |  | ||||||
|  |     chr = qemu_chr_find(device); | ||||||
|  |     if (!chr) { | ||||||
|  |         error_setg(errp, "Device '%s' not found", device); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!CHARDEV_IS_RINGBUF(chr)) { | ||||||
|  |         error_setg(errp, "%s is not a ringbuf device", device); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (has_format && (format == DATA_FORMAT_BASE64)) { | ||||||
|  |         write_data = qbase64_decode(data, -1, | ||||||
|  |                                     &write_count, | ||||||
|  |                                     errp); | ||||||
|  |         if (!write_data) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         write_data = (uint8_t *)data; | ||||||
|  |         write_count = strlen(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ret = ringbuf_chr_write(chr, write_data, write_count); | ||||||
|  |  | ||||||
|  |     if (write_data != (uint8_t *)data) { | ||||||
|  |         g_free((void *)write_data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (ret < 0) { | ||||||
|  |         error_setg(errp, "Failed to write to device %s", device); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char *qmp_ringbuf_read(const char *device, int64_t size, | ||||||
|  |                        bool has_format, enum DataFormat format, | ||||||
|  |                        Error **errp) | ||||||
|  | { | ||||||
|  |     Chardev *chr; | ||||||
|  |     uint8_t *read_data; | ||||||
|  |     size_t count; | ||||||
|  |     char *data; | ||||||
|  |  | ||||||
|  |     chr = qemu_chr_find(device); | ||||||
|  |     if (!chr) { | ||||||
|  |         error_setg(errp, "Device '%s' not found", device); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!CHARDEV_IS_RINGBUF(chr)) { | ||||||
|  |         error_setg(errp, "%s is not a ringbuf device", device); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (size <= 0) { | ||||||
|  |         error_setg(errp, "size must be greater than zero"); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     count = ringbuf_count(chr); | ||||||
|  |     size = size > count ? count : size; | ||||||
|  |     read_data = g_malloc(size + 1); | ||||||
|  |  | ||||||
|  |     ringbuf_chr_read(chr, read_data, size); | ||||||
|  |  | ||||||
|  |     if (has_format && (format == DATA_FORMAT_BASE64)) { | ||||||
|  |         data = g_base64_encode(read_data, size); | ||||||
|  |         g_free(read_data); | ||||||
|  |     } else { | ||||||
|  |         /* | ||||||
|  |          * FIXME should read only complete, valid UTF-8 characters up | ||||||
|  |          * to @size bytes.  Invalid sequences should be replaced by a | ||||||
|  |          * suitable replacement character.  Except when (and only | ||||||
|  |          * when) ring buffer lost characters since last read, initial | ||||||
|  |          * continuation characters should be dropped. | ||||||
|  |          */ | ||||||
|  |         read_data[size] = 0; | ||||||
|  |         data = (char *)read_data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, | ||||||
|  |                                    Error **errp) | ||||||
|  | { | ||||||
|  |     int val; | ||||||
|  |     ChardevRingbuf *ringbuf; | ||||||
|  |  | ||||||
|  |     backend->type = CHARDEV_BACKEND_KIND_RINGBUF; | ||||||
|  |     ringbuf = backend->u.ringbuf.data = g_new0(ChardevRingbuf, 1); | ||||||
|  |     qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf)); | ||||||
|  |  | ||||||
|  |     val = qemu_opt_get_size(opts, "size", 0); | ||||||
|  |     if (val != 0) { | ||||||
|  |         ringbuf->has_size = true; | ||||||
|  |         ringbuf->size = val; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_ringbuf_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->parse = qemu_chr_parse_ringbuf; | ||||||
|  |     cc->open = qemu_chr_open_ringbuf; | ||||||
|  |     cc->chr_write = ringbuf_chr_write; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_ringbuf_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_RINGBUF, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .class_init = char_ringbuf_class_init, | ||||||
|  |     .instance_size = sizeof(RingBufChardev), | ||||||
|  |     .instance_finalize = char_ringbuf_finalize, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* Bug-compatibility: */ | ||||||
|  | static const TypeInfo char_memory_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_MEMORY, | ||||||
|  |     .parent = TYPE_CHARDEV_RINGBUF, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_ringbuf_type_info); | ||||||
|  |     type_register_static(&char_memory_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										318
									
								
								chardev/char-serial.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								chardev/char-serial.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,318 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qemu/sockets.h" | ||||||
|  | #include "io/channel-file.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include "char-win.h" | ||||||
|  | #else | ||||||
|  | #include <sys/ioctl.h> | ||||||
|  | #include <termios.h> | ||||||
|  | #include "char-fd.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "char-serial.h" | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |  | ||||||
|  | static void qmp_chardev_open_serial(Chardev *chr, | ||||||
|  |                                     ChardevBackend *backend, | ||||||
|  |                                     bool *be_opened, | ||||||
|  |                                     Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevHostdev *serial = backend->u.serial.data; | ||||||
|  |  | ||||||
|  |     win_chr_init(chr, serial->device, errp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \ | ||||||
|  |     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ | ||||||
|  |     || defined(__GLIBC__) | ||||||
|  |  | ||||||
|  | static void tty_serial_init(int fd, int speed, | ||||||
|  |                             int parity, int data_bits, int stop_bits) | ||||||
|  | { | ||||||
|  |     struct termios tty; | ||||||
|  |     speed_t spd; | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  |     printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", | ||||||
|  |            speed, parity, data_bits, stop_bits); | ||||||
|  | #endif | ||||||
|  |     tcgetattr(fd, &tty); | ||||||
|  |  | ||||||
|  | #define check_speed(val) if (speed <= val) { spd = B##val; break; } | ||||||
|  |     speed = speed * 10 / 11; | ||||||
|  |     do { | ||||||
|  |         check_speed(50); | ||||||
|  |         check_speed(75); | ||||||
|  |         check_speed(110); | ||||||
|  |         check_speed(134); | ||||||
|  |         check_speed(150); | ||||||
|  |         check_speed(200); | ||||||
|  |         check_speed(300); | ||||||
|  |         check_speed(600); | ||||||
|  |         check_speed(1200); | ||||||
|  |         check_speed(1800); | ||||||
|  |         check_speed(2400); | ||||||
|  |         check_speed(4800); | ||||||
|  |         check_speed(9600); | ||||||
|  |         check_speed(19200); | ||||||
|  |         check_speed(38400); | ||||||
|  |         /* Non-Posix values follow. They may be unsupported on some systems. */ | ||||||
|  |         check_speed(57600); | ||||||
|  |         check_speed(115200); | ||||||
|  | #ifdef B230400 | ||||||
|  |         check_speed(230400); | ||||||
|  | #endif | ||||||
|  | #ifdef B460800 | ||||||
|  |         check_speed(460800); | ||||||
|  | #endif | ||||||
|  | #ifdef B500000 | ||||||
|  |         check_speed(500000); | ||||||
|  | #endif | ||||||
|  | #ifdef B576000 | ||||||
|  |         check_speed(576000); | ||||||
|  | #endif | ||||||
|  | #ifdef B921600 | ||||||
|  |         check_speed(921600); | ||||||
|  | #endif | ||||||
|  | #ifdef B1000000 | ||||||
|  |         check_speed(1000000); | ||||||
|  | #endif | ||||||
|  | #ifdef B1152000 | ||||||
|  |         check_speed(1152000); | ||||||
|  | #endif | ||||||
|  | #ifdef B1500000 | ||||||
|  |         check_speed(1500000); | ||||||
|  | #endif | ||||||
|  | #ifdef B2000000 | ||||||
|  |         check_speed(2000000); | ||||||
|  | #endif | ||||||
|  | #ifdef B2500000 | ||||||
|  |         check_speed(2500000); | ||||||
|  | #endif | ||||||
|  | #ifdef B3000000 | ||||||
|  |         check_speed(3000000); | ||||||
|  | #endif | ||||||
|  | #ifdef B3500000 | ||||||
|  |         check_speed(3500000); | ||||||
|  | #endif | ||||||
|  | #ifdef B4000000 | ||||||
|  |         check_speed(4000000); | ||||||
|  | #endif | ||||||
|  |         spd = B115200; | ||||||
|  |     } while (0); | ||||||
|  |  | ||||||
|  |     cfsetispeed(&tty, spd); | ||||||
|  |     cfsetospeed(&tty, spd); | ||||||
|  |  | ||||||
|  |     tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | ||||||
|  |                      | INLCR | IGNCR | ICRNL | IXON); | ||||||
|  |     tty.c_oflag |= OPOST; | ||||||
|  |     tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); | ||||||
|  |     tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB); | ||||||
|  |     switch (data_bits) { | ||||||
|  |     default: | ||||||
|  |     case 8: | ||||||
|  |         tty.c_cflag |= CS8; | ||||||
|  |         break; | ||||||
|  |     case 7: | ||||||
|  |         tty.c_cflag |= CS7; | ||||||
|  |         break; | ||||||
|  |     case 6: | ||||||
|  |         tty.c_cflag |= CS6; | ||||||
|  |         break; | ||||||
|  |     case 5: | ||||||
|  |         tty.c_cflag |= CS5; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     switch (parity) { | ||||||
|  |     default: | ||||||
|  |     case 'N': | ||||||
|  |         break; | ||||||
|  |     case 'E': | ||||||
|  |         tty.c_cflag |= PARENB; | ||||||
|  |         break; | ||||||
|  |     case 'O': | ||||||
|  |         tty.c_cflag |= PARENB | PARODD; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     if (stop_bits == 2) { | ||||||
|  |         tty.c_cflag |= CSTOPB; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     tcsetattr(fd, TCSANOW, &tty); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg) | ||||||
|  | { | ||||||
|  |     FDChardev *s = FD_CHARDEV(chr); | ||||||
|  |     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in); | ||||||
|  |  | ||||||
|  |     switch (cmd) { | ||||||
|  |     case CHR_IOCTL_SERIAL_SET_PARAMS: | ||||||
|  |         { | ||||||
|  |             QEMUSerialSetParams *ssp = arg; | ||||||
|  |             tty_serial_init(fioc->fd, | ||||||
|  |                             ssp->speed, ssp->parity, | ||||||
|  |                             ssp->data_bits, ssp->stop_bits); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_SERIAL_SET_BREAK: | ||||||
|  |         { | ||||||
|  |             int enable = *(int *)arg; | ||||||
|  |             if (enable) { | ||||||
|  |                 tcsendbreak(fioc->fd, 1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_SERIAL_GET_TIOCM: | ||||||
|  |         { | ||||||
|  |             int sarg = 0; | ||||||
|  |             int *targ = (int *)arg; | ||||||
|  |             ioctl(fioc->fd, TIOCMGET, &sarg); | ||||||
|  |             *targ = 0; | ||||||
|  |             if (sarg & TIOCM_CTS) { | ||||||
|  |                 *targ |= CHR_TIOCM_CTS; | ||||||
|  |             } | ||||||
|  |             if (sarg & TIOCM_CAR) { | ||||||
|  |                 *targ |= CHR_TIOCM_CAR; | ||||||
|  |             } | ||||||
|  |             if (sarg & TIOCM_DSR) { | ||||||
|  |                 *targ |= CHR_TIOCM_DSR; | ||||||
|  |             } | ||||||
|  |             if (sarg & TIOCM_RI) { | ||||||
|  |                 *targ |= CHR_TIOCM_RI; | ||||||
|  |             } | ||||||
|  |             if (sarg & TIOCM_DTR) { | ||||||
|  |                 *targ |= CHR_TIOCM_DTR; | ||||||
|  |             } | ||||||
|  |             if (sarg & TIOCM_RTS) { | ||||||
|  |                 *targ |= CHR_TIOCM_RTS; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CHR_IOCTL_SERIAL_SET_TIOCM: | ||||||
|  |         { | ||||||
|  |             int sarg = *(int *)arg; | ||||||
|  |             int targ = 0; | ||||||
|  |             ioctl(fioc->fd, TIOCMGET, &targ); | ||||||
|  |             targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR | ||||||
|  |                      | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS); | ||||||
|  |             if (sarg & CHR_TIOCM_CTS) { | ||||||
|  |                 targ |= TIOCM_CTS; | ||||||
|  |             } | ||||||
|  |             if (sarg & CHR_TIOCM_CAR) { | ||||||
|  |                 targ |= TIOCM_CAR; | ||||||
|  |             } | ||||||
|  |             if (sarg & CHR_TIOCM_DSR) { | ||||||
|  |                 targ |= TIOCM_DSR; | ||||||
|  |             } | ||||||
|  |             if (sarg & CHR_TIOCM_RI) { | ||||||
|  |                 targ |= TIOCM_RI; | ||||||
|  |             } | ||||||
|  |             if (sarg & CHR_TIOCM_DTR) { | ||||||
|  |                 targ |= TIOCM_DTR; | ||||||
|  |             } | ||||||
|  |             if (sarg & CHR_TIOCM_RTS) { | ||||||
|  |                 targ |= TIOCM_RTS; | ||||||
|  |             } | ||||||
|  |             ioctl(fioc->fd, TIOCMSET, &targ); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         return -ENOTSUP; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qmp_chardev_open_serial(Chardev *chr, | ||||||
|  |                                     ChardevBackend *backend, | ||||||
|  |                                     bool *be_opened, | ||||||
|  |                                     Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevHostdev *serial = backend->u.serial.data; | ||||||
|  |     int fd; | ||||||
|  |  | ||||||
|  |     fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp); | ||||||
|  |     if (fd < 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     qemu_set_nonblock(fd); | ||||||
|  |     tty_serial_init(fd, 115200, 'N', 8, 1); | ||||||
|  |  | ||||||
|  |     qemu_chr_open_fd(chr, fd, fd); | ||||||
|  | } | ||||||
|  | #endif /* __linux__ || __sun__ */ | ||||||
|  |  | ||||||
|  | #ifdef HAVE_CHARDEV_SERIAL | ||||||
|  | static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, | ||||||
|  |                                   Error **errp) | ||||||
|  | { | ||||||
|  |     const char *device = qemu_opt_get(opts, "path"); | ||||||
|  |     ChardevHostdev *serial; | ||||||
|  |  | ||||||
|  |     if (device == NULL) { | ||||||
|  |         error_setg(errp, "chardev: serial/tty: no device path given"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     backend->type = CHARDEV_BACKEND_KIND_SERIAL; | ||||||
|  |     serial = backend->u.serial.data = g_new0(ChardevHostdev, 1); | ||||||
|  |     qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial)); | ||||||
|  |     serial->device = g_strdup(device); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_serial_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->parse = qemu_chr_parse_serial; | ||||||
|  |     cc->open = qmp_chardev_open_serial; | ||||||
|  | #ifndef _WIN32 | ||||||
|  |     cc->chr_ioctl = tty_serial_ioctl; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static const TypeInfo char_serial_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_SERIAL, | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     .parent = TYPE_CHARDEV_WIN, | ||||||
|  | #else | ||||||
|  |     .parent = TYPE_CHARDEV_FD, | ||||||
|  | #endif | ||||||
|  |     .class_init = char_serial_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_serial_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										35
									
								
								chardev/char-serial.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								chardev/char-serial.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef CHAR_SERIAL_H | ||||||
|  | #define CHAR_SERIAL_H | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #define HAVE_CHARDEV_SERIAL 1 | ||||||
|  | #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)    \ | ||||||
|  |     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ | ||||||
|  |     || defined(__GLIBC__) | ||||||
|  | #define HAVE_CHARDEV_SERIAL 1 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										1017
									
								
								chardev/char-socket.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1017
									
								
								chardev/char-socket.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										164
									
								
								chardev/char-stdio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								chardev/char-stdio.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qemu/sockets.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include "char-win.h" | ||||||
|  | #include "char-win-stdio.h" | ||||||
|  | #else | ||||||
|  | #include <termios.h> | ||||||
|  | #include "char-fd.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef _WIN32 | ||||||
|  | /* init terminal so that we can grab keys */ | ||||||
|  | static struct termios oldtty; | ||||||
|  | static int old_fd0_flags; | ||||||
|  | static bool stdio_in_use; | ||||||
|  | static bool stdio_allow_signal; | ||||||
|  | static bool stdio_echo_state; | ||||||
|  |  | ||||||
|  | static void term_exit(void) | ||||||
|  | { | ||||||
|  |     tcsetattr(0, TCSANOW, &oldtty); | ||||||
|  |     fcntl(0, F_SETFL, old_fd0_flags); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo) | ||||||
|  | { | ||||||
|  |     struct termios tty; | ||||||
|  |  | ||||||
|  |     stdio_echo_state = echo; | ||||||
|  |     tty = oldtty; | ||||||
|  |     if (!echo) { | ||||||
|  |         tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | ||||||
|  |                          | INLCR | IGNCR | ICRNL | IXON); | ||||||
|  |         tty.c_oflag |= OPOST; | ||||||
|  |         tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); | ||||||
|  |         tty.c_cflag &= ~(CSIZE | PARENB); | ||||||
|  |         tty.c_cflag |= CS8; | ||||||
|  |         tty.c_cc[VMIN] = 1; | ||||||
|  |         tty.c_cc[VTIME] = 0; | ||||||
|  |     } | ||||||
|  |     if (!stdio_allow_signal) { | ||||||
|  |         tty.c_lflag &= ~ISIG; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     tcsetattr(0, TCSANOW, &tty); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void term_stdio_handler(int sig) | ||||||
|  | { | ||||||
|  |     /* restore echo after resume from suspend. */ | ||||||
|  |     qemu_chr_set_echo_stdio(NULL, stdio_echo_state); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_stdio(Chardev *chr, | ||||||
|  |                                 ChardevBackend *backend, | ||||||
|  |                                 bool *be_opened, | ||||||
|  |                                 Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevStdio *opts = backend->u.stdio.data; | ||||||
|  |     struct sigaction act; | ||||||
|  |  | ||||||
|  |     if (is_daemonized()) { | ||||||
|  |         error_setg(errp, "cannot use stdio with -daemonize"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (stdio_in_use) { | ||||||
|  |         error_setg(errp, "cannot use stdio by multiple character devices"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     stdio_in_use = true; | ||||||
|  |     old_fd0_flags = fcntl(0, F_GETFL); | ||||||
|  |     tcgetattr(0, &oldtty); | ||||||
|  |     qemu_set_nonblock(0); | ||||||
|  |     atexit(term_exit); | ||||||
|  |  | ||||||
|  |     memset(&act, 0, sizeof(act)); | ||||||
|  |     act.sa_handler = term_stdio_handler; | ||||||
|  |     sigaction(SIGCONT, &act, NULL); | ||||||
|  |  | ||||||
|  |     qemu_chr_open_fd(chr, 0, 1); | ||||||
|  |  | ||||||
|  |     if (opts->has_signal) { | ||||||
|  |         stdio_allow_signal = opts->signal; | ||||||
|  |     } | ||||||
|  |     qemu_chr_set_echo_stdio(chr, false); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, | ||||||
|  |                                  Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevStdio *stdio; | ||||||
|  |  | ||||||
|  |     backend->type = CHARDEV_BACKEND_KIND_STDIO; | ||||||
|  |     stdio = backend->u.stdio.data = g_new0(ChardevStdio, 1); | ||||||
|  |     qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio)); | ||||||
|  |     stdio->has_signal = true; | ||||||
|  |     stdio->signal = qemu_opt_get_bool(opts, "signal", true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_stdio_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->parse = qemu_chr_parse_stdio; | ||||||
|  | #ifndef _WIN32 | ||||||
|  |     cc->open = qemu_chr_open_stdio; | ||||||
|  |     cc->chr_set_echo = qemu_chr_set_echo_stdio; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_stdio_finalize(Object *obj) | ||||||
|  | { | ||||||
|  | #ifndef _WIN32 | ||||||
|  |     term_exit(); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_stdio_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_STDIO, | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     .parent = TYPE_CHARDEV_WIN_STDIO, | ||||||
|  | #else | ||||||
|  |     .parent = TYPE_CHARDEV_FD, | ||||||
|  | #endif | ||||||
|  |     .instance_finalize = char_stdio_finalize, | ||||||
|  |     .class_init = char_stdio_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_stdio_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										233
									
								
								chardev/char-udp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								chardev/char-udp.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,233 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "sysemu/char.h" | ||||||
|  | #include "io/channel-socket.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  |  | ||||||
|  | #include "char-io.h" | ||||||
|  |  | ||||||
|  | /***********************************************************/ | ||||||
|  | /* UDP Net console */ | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     Chardev parent; | ||||||
|  |     QIOChannel *ioc; | ||||||
|  |     uint8_t buf[CHR_READ_BUF_LEN]; | ||||||
|  |     int bufcnt; | ||||||
|  |     int bufptr; | ||||||
|  |     int max_size; | ||||||
|  | } UdpChardev; | ||||||
|  |  | ||||||
|  | #define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP) | ||||||
|  |  | ||||||
|  | /* Called with chr_write_lock held.  */ | ||||||
|  | static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len) | ||||||
|  | { | ||||||
|  |     UdpChardev *s = UDP_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     return qio_channel_write( | ||||||
|  |         s->ioc, (const char *)buf, len, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int udp_chr_read_poll(void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     UdpChardev *s = UDP_CHARDEV(opaque); | ||||||
|  |  | ||||||
|  |     s->max_size = qemu_chr_be_can_write(chr); | ||||||
|  |  | ||||||
|  |     /* If there were any stray characters in the queue process them | ||||||
|  |      * first | ||||||
|  |      */ | ||||||
|  |     while (s->max_size > 0 && s->bufptr < s->bufcnt) { | ||||||
|  |         qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); | ||||||
|  |         s->bufptr++; | ||||||
|  |         s->max_size = qemu_chr_be_can_write(chr); | ||||||
|  |     } | ||||||
|  |     return s->max_size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     UdpChardev *s = UDP_CHARDEV(opaque); | ||||||
|  |     ssize_t ret; | ||||||
|  |  | ||||||
|  |     if (s->max_size == 0) { | ||||||
|  |         return TRUE; | ||||||
|  |     } | ||||||
|  |     ret = qio_channel_read( | ||||||
|  |         s->ioc, (char *)s->buf, sizeof(s->buf), NULL); | ||||||
|  |     if (ret <= 0) { | ||||||
|  |         remove_fd_in_watch(chr); | ||||||
|  |         return FALSE; | ||||||
|  |     } | ||||||
|  |     s->bufcnt = ret; | ||||||
|  |  | ||||||
|  |     s->bufptr = 0; | ||||||
|  |     while (s->max_size > 0 && s->bufptr < s->bufcnt) { | ||||||
|  |         qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); | ||||||
|  |         s->bufptr++; | ||||||
|  |         s->max_size = qemu_chr_be_can_write(chr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void udp_chr_update_read_handler(Chardev *chr, | ||||||
|  |                                         GMainContext *context) | ||||||
|  | { | ||||||
|  |     UdpChardev *s = UDP_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     remove_fd_in_watch(chr); | ||||||
|  |     if (s->ioc) { | ||||||
|  |         chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, | ||||||
|  |                                            udp_chr_read_poll, | ||||||
|  |                                            udp_chr_read, chr, | ||||||
|  |                                            context); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_udp_finalize(Object *obj) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(obj); | ||||||
|  |     UdpChardev *s = UDP_CHARDEV(obj); | ||||||
|  |  | ||||||
|  |     remove_fd_in_watch(chr); | ||||||
|  |     if (s->ioc) { | ||||||
|  |         object_unref(OBJECT(s->ioc)); | ||||||
|  |     } | ||||||
|  |     qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, | ||||||
|  |                                Error **errp) | ||||||
|  | { | ||||||
|  |     const char *host = qemu_opt_get(opts, "host"); | ||||||
|  |     const char *port = qemu_opt_get(opts, "port"); | ||||||
|  |     const char *localaddr = qemu_opt_get(opts, "localaddr"); | ||||||
|  |     const char *localport = qemu_opt_get(opts, "localport"); | ||||||
|  |     bool has_local = false; | ||||||
|  |     SocketAddress *addr; | ||||||
|  |     ChardevUdp *udp; | ||||||
|  |  | ||||||
|  |     backend->type = CHARDEV_BACKEND_KIND_UDP; | ||||||
|  |     if (host == NULL || strlen(host) == 0) { | ||||||
|  |         host = "localhost"; | ||||||
|  |     } | ||||||
|  |     if (port == NULL || strlen(port) == 0) { | ||||||
|  |         error_setg(errp, "chardev: udp: remote port not specified"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if (localport == NULL || strlen(localport) == 0) { | ||||||
|  |         localport = "0"; | ||||||
|  |     } else { | ||||||
|  |         has_local = true; | ||||||
|  |     } | ||||||
|  |     if (localaddr == NULL || strlen(localaddr) == 0) { | ||||||
|  |         localaddr = ""; | ||||||
|  |     } else { | ||||||
|  |         has_local = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     udp = backend->u.udp.data = g_new0(ChardevUdp, 1); | ||||||
|  |     qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); | ||||||
|  |  | ||||||
|  |     addr = g_new0(SocketAddress, 1); | ||||||
|  |     addr->type = SOCKET_ADDRESS_KIND_INET; | ||||||
|  |     addr->u.inet.data = g_new(InetSocketAddress, 1); | ||||||
|  |     *addr->u.inet.data = (InetSocketAddress) { | ||||||
|  |         .host = g_strdup(host), | ||||||
|  |         .port = g_strdup(port), | ||||||
|  |         .has_ipv4 = qemu_opt_get(opts, "ipv4"), | ||||||
|  |         .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), | ||||||
|  |         .has_ipv6 = qemu_opt_get(opts, "ipv6"), | ||||||
|  |         .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), | ||||||
|  |     }; | ||||||
|  |     udp->remote = addr; | ||||||
|  |  | ||||||
|  |     if (has_local) { | ||||||
|  |         udp->has_local = true; | ||||||
|  |         addr = g_new0(SocketAddress, 1); | ||||||
|  |         addr->type = SOCKET_ADDRESS_KIND_INET; | ||||||
|  |         addr->u.inet.data = g_new(InetSocketAddress, 1); | ||||||
|  |         *addr->u.inet.data = (InetSocketAddress) { | ||||||
|  |             .host = g_strdup(localaddr), | ||||||
|  |             .port = g_strdup(localport), | ||||||
|  |         }; | ||||||
|  |         udp->local = addr; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qmp_chardev_open_udp(Chardev *chr, | ||||||
|  |                                  ChardevBackend *backend, | ||||||
|  |                                  bool *be_opened, | ||||||
|  |                                  Error **errp) | ||||||
|  | { | ||||||
|  |     ChardevUdp *udp = backend->u.udp.data; | ||||||
|  |     QIOChannelSocket *sioc = qio_channel_socket_new(); | ||||||
|  |     char *name; | ||||||
|  |     UdpChardev *s = UDP_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     if (qio_channel_socket_dgram_sync(sioc, | ||||||
|  |                                       udp->local, udp->remote, | ||||||
|  |                                       errp) < 0) { | ||||||
|  |         object_unref(OBJECT(sioc)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     name = g_strdup_printf("chardev-udp-%s", chr->label); | ||||||
|  |     qio_channel_set_name(QIO_CHANNEL(sioc), name); | ||||||
|  |     g_free(name); | ||||||
|  |  | ||||||
|  |     s->ioc = QIO_CHANNEL(sioc); | ||||||
|  |     /* be isn't opened until we get a connection */ | ||||||
|  |     *be_opened = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_udp_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->parse = qemu_chr_parse_udp; | ||||||
|  |     cc->open = qmp_chardev_open_udp; | ||||||
|  |     cc->chr_write = udp_chr_write; | ||||||
|  |     cc->chr_update_read_handler = udp_chr_update_read_handler; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_udp_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_UDP, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .instance_size = sizeof(UdpChardev), | ||||||
|  |     .instance_finalize = char_udp_finalize, | ||||||
|  |     .class_init = char_udp_class_init, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_udp_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										266
									
								
								chardev/char-win-stdio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								chardev/char-win-stdio.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,266 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include "char-win.h" | ||||||
|  | #include "char-win-stdio.h" | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     Chardev parent; | ||||||
|  |     HANDLE  hStdIn; | ||||||
|  |     HANDLE  hInputReadyEvent; | ||||||
|  |     HANDLE  hInputDoneEvent; | ||||||
|  |     HANDLE  hInputThread; | ||||||
|  |     uint8_t win_stdio_buf; | ||||||
|  | } WinStdioChardev; | ||||||
|  |  | ||||||
|  | #define WIN_STDIO_CHARDEV(obj)                                          \ | ||||||
|  |     OBJECT_CHECK(WinStdioChardev, (obj), TYPE_CHARDEV_WIN_STDIO) | ||||||
|  |  | ||||||
|  | static void win_stdio_wait_func(void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque); | ||||||
|  |     INPUT_RECORD       buf[4]; | ||||||
|  |     int                ret; | ||||||
|  |     DWORD              dwSize; | ||||||
|  |     int                i; | ||||||
|  |  | ||||||
|  |     ret = ReadConsoleInput(stdio->hStdIn, buf, ARRAY_SIZE(buf), &dwSize); | ||||||
|  |  | ||||||
|  |     if (!ret) { | ||||||
|  |         /* Avoid error storm */ | ||||||
|  |         qemu_del_wait_object(stdio->hStdIn, NULL, NULL); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (i = 0; i < dwSize; i++) { | ||||||
|  |         KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent; | ||||||
|  |  | ||||||
|  |         if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) { | ||||||
|  |             int j; | ||||||
|  |             if (kev->uChar.AsciiChar != 0) { | ||||||
|  |                 for (j = 0; j < kev->wRepeatCount; j++) { | ||||||
|  |                     if (qemu_chr_be_can_write(chr)) { | ||||||
|  |                         uint8_t c = kev->uChar.AsciiChar; | ||||||
|  |                         qemu_chr_be_write(chr, &c, 1); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static DWORD WINAPI win_stdio_thread(LPVOID param) | ||||||
|  | { | ||||||
|  |     WinStdioChardev *stdio = WIN_STDIO_CHARDEV(param); | ||||||
|  |     int                ret; | ||||||
|  |     DWORD              dwSize; | ||||||
|  |  | ||||||
|  |     while (1) { | ||||||
|  |  | ||||||
|  |         /* Wait for one byte */ | ||||||
|  |         ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL); | ||||||
|  |  | ||||||
|  |         /* Exit in case of error, continue if nothing read */ | ||||||
|  |         if (!ret) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if (!dwSize) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* Some terminal emulator returns \r\n for Enter, just pass \n */ | ||||||
|  |         if (stdio->win_stdio_buf == '\r') { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* Signal the main thread and wait until the byte was eaten */ | ||||||
|  |         if (!SetEvent(stdio->hInputReadyEvent)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE) | ||||||
|  |             != WAIT_OBJECT_0) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void win_stdio_thread_wait_func(void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque); | ||||||
|  |  | ||||||
|  |     if (qemu_chr_be_can_write(chr)) { | ||||||
|  |         qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     SetEvent(stdio->hInputDoneEvent); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo) | ||||||
|  | { | ||||||
|  |     WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr); | ||||||
|  |     DWORD              dwMode = 0; | ||||||
|  |  | ||||||
|  |     GetConsoleMode(stdio->hStdIn, &dwMode); | ||||||
|  |  | ||||||
|  |     if (echo) { | ||||||
|  |         SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT); | ||||||
|  |     } else { | ||||||
|  |         SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void qemu_chr_open_stdio(Chardev *chr, | ||||||
|  |                                 ChardevBackend *backend, | ||||||
|  |                                 bool *be_opened, | ||||||
|  |                                 Error **errp) | ||||||
|  | { | ||||||
|  |     WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr); | ||||||
|  |     DWORD              dwMode; | ||||||
|  |     int                is_console = 0; | ||||||
|  |  | ||||||
|  |     stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); | ||||||
|  |     if (stdio->hStdIn == INVALID_HANDLE_VALUE) { | ||||||
|  |         error_setg(errp, "cannot open stdio: invalid handle"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0; | ||||||
|  |  | ||||||
|  |     if (is_console) { | ||||||
|  |         if (qemu_add_wait_object(stdio->hStdIn, | ||||||
|  |                                  win_stdio_wait_func, chr)) { | ||||||
|  |             error_setg(errp, "qemu_add_wait_object: failed"); | ||||||
|  |             goto err1; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         DWORD   dwId; | ||||||
|  |  | ||||||
|  |         stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | ||||||
|  |         stdio->hInputDoneEvent  = CreateEvent(NULL, FALSE, FALSE, NULL); | ||||||
|  |         if (stdio->hInputReadyEvent == INVALID_HANDLE_VALUE | ||||||
|  |             || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { | ||||||
|  |             error_setg(errp, "cannot create event"); | ||||||
|  |             goto err2; | ||||||
|  |         } | ||||||
|  |         if (qemu_add_wait_object(stdio->hInputReadyEvent, | ||||||
|  |                                  win_stdio_thread_wait_func, chr)) { | ||||||
|  |             error_setg(errp, "qemu_add_wait_object: failed"); | ||||||
|  |             goto err2; | ||||||
|  |         } | ||||||
|  |         stdio->hInputThread     = CreateThread(NULL, 0, win_stdio_thread, | ||||||
|  |                                                chr, 0, &dwId); | ||||||
|  |  | ||||||
|  |         if (stdio->hInputThread == INVALID_HANDLE_VALUE) { | ||||||
|  |             error_setg(errp, "cannot create stdio thread"); | ||||||
|  |             goto err3; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     dwMode |= ENABLE_LINE_INPUT; | ||||||
|  |  | ||||||
|  |     if (is_console) { | ||||||
|  |         /* set the terminal in raw mode */ | ||||||
|  |         /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ | ||||||
|  |         dwMode |= ENABLE_PROCESSED_INPUT; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     SetConsoleMode(stdio->hStdIn, dwMode); | ||||||
|  |  | ||||||
|  |     qemu_chr_set_echo_win_stdio(chr, false); | ||||||
|  |  | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  | err3: | ||||||
|  |     qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL); | ||||||
|  | err2: | ||||||
|  |     CloseHandle(stdio->hInputReadyEvent); | ||||||
|  |     CloseHandle(stdio->hInputDoneEvent); | ||||||
|  | err1: | ||||||
|  |     qemu_del_wait_object(stdio->hStdIn, NULL, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_win_stdio_finalize(Object *obj) | ||||||
|  | { | ||||||
|  |     WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj); | ||||||
|  |  | ||||||
|  |     if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) { | ||||||
|  |         CloseHandle(stdio->hInputReadyEvent); | ||||||
|  |     } | ||||||
|  |     if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) { | ||||||
|  |         CloseHandle(stdio->hInputDoneEvent); | ||||||
|  |     } | ||||||
|  |     if (stdio->hInputThread != INVALID_HANDLE_VALUE) { | ||||||
|  |         TerminateThread(stdio->hInputThread, 0); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len) | ||||||
|  | { | ||||||
|  |     HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
|  |     DWORD   dwSize; | ||||||
|  |     int     len1; | ||||||
|  |  | ||||||
|  |     len1 = len; | ||||||
|  |  | ||||||
|  |     while (len1 > 0) { | ||||||
|  |         if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         buf  += dwSize; | ||||||
|  |         len1 -= dwSize; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return len - len1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_win_stdio_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->open = qemu_chr_open_stdio; | ||||||
|  |     cc->chr_write = win_stdio_write; | ||||||
|  |     cc->chr_set_echo = qemu_chr_set_echo_win_stdio; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_win_stdio_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_WIN_STDIO, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .instance_size = sizeof(WinStdioChardev), | ||||||
|  |     .instance_finalize = char_win_stdio_finalize, | ||||||
|  |     .class_init = char_win_stdio_class_init, | ||||||
|  |     .abstract = true, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_win_stdio_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										29
									
								
								chardev/char-win-stdio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								chardev/char-win-stdio.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef CHAR_WIN_STDIO_H | ||||||
|  | #define CHAR_WIN_STDIO_H | ||||||
|  |  | ||||||
|  | #define TYPE_CHARDEV_WIN_STDIO "chardev-win-stdio" | ||||||
|  |  | ||||||
|  | #endif /* CHAR_WIN_STDIO_H */ | ||||||
							
								
								
									
										265
									
								
								chardev/char-win.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								chardev/char-win.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,265 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #include "qemu/osdep.h" | ||||||
|  | #include "qemu-common.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  | #include "char-win.h" | ||||||
|  |  | ||||||
|  | static void win_chr_readfile(Chardev *chr) | ||||||
|  | { | ||||||
|  |     WinChardev *s = WIN_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     int ret, err; | ||||||
|  |     uint8_t buf[CHR_READ_BUF_LEN]; | ||||||
|  |     DWORD size; | ||||||
|  |  | ||||||
|  |     ZeroMemory(&s->orecv, sizeof(s->orecv)); | ||||||
|  |     s->orecv.hEvent = s->hrecv; | ||||||
|  |     ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); | ||||||
|  |     if (!ret) { | ||||||
|  |         err = GetLastError(); | ||||||
|  |         if (err == ERROR_IO_PENDING) { | ||||||
|  |             ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (size > 0) { | ||||||
|  |         qemu_chr_be_write(chr, buf, size); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void win_chr_read(Chardev *chr) | ||||||
|  | { | ||||||
|  |     WinChardev *s = WIN_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     if (s->len > s->max_size) { | ||||||
|  |         s->len = s->max_size; | ||||||
|  |     } | ||||||
|  |     if (s->len == 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     win_chr_readfile(chr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int win_chr_read_poll(Chardev *chr) | ||||||
|  | { | ||||||
|  |     WinChardev *s = WIN_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     s->max_size = qemu_chr_be_can_write(chr); | ||||||
|  |     return s->max_size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int win_chr_poll(void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     WinChardev *s = WIN_CHARDEV(opaque); | ||||||
|  |     COMSTAT status; | ||||||
|  |     DWORD comerr; | ||||||
|  |  | ||||||
|  |     ClearCommError(s->hcom, &comerr, &status); | ||||||
|  |     if (status.cbInQue > 0) { | ||||||
|  |         s->len = status.cbInQue; | ||||||
|  |         win_chr_read_poll(chr); | ||||||
|  |         win_chr_read(chr); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int win_chr_init(Chardev *chr, const char *filename, Error **errp) | ||||||
|  | { | ||||||
|  |     WinChardev *s = WIN_CHARDEV(chr); | ||||||
|  |     COMMCONFIG comcfg; | ||||||
|  |     COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; | ||||||
|  |     COMSTAT comstat; | ||||||
|  |     DWORD size; | ||||||
|  |     DWORD err; | ||||||
|  |  | ||||||
|  |     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); | ||||||
|  |     if (!s->hsend) { | ||||||
|  |         error_setg(errp, "Failed CreateEvent"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); | ||||||
|  |     if (!s->hrecv) { | ||||||
|  |         error_setg(errp, "Failed CreateEvent"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     s->hcom = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, | ||||||
|  |                       OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); | ||||||
|  |     if (s->hcom == INVALID_HANDLE_VALUE) { | ||||||
|  |         error_setg(errp, "Failed CreateFile (%lu)", GetLastError()); | ||||||
|  |         s->hcom = NULL; | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { | ||||||
|  |         error_setg(errp, "Failed SetupComm"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ZeroMemory(&comcfg, sizeof(COMMCONFIG)); | ||||||
|  |     size = sizeof(COMMCONFIG); | ||||||
|  |     GetDefaultCommConfig(filename, &comcfg, &size); | ||||||
|  |     comcfg.dcb.DCBlength = sizeof(DCB); | ||||||
|  |     CommConfigDialog(filename, NULL, &comcfg); | ||||||
|  |  | ||||||
|  |     if (!SetCommState(s->hcom, &comcfg.dcb)) { | ||||||
|  |         error_setg(errp, "Failed SetCommState"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!SetCommMask(s->hcom, EV_ERR)) { | ||||||
|  |         error_setg(errp, "Failed SetCommMask"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     cto.ReadIntervalTimeout = MAXDWORD; | ||||||
|  |     if (!SetCommTimeouts(s->hcom, &cto)) { | ||||||
|  |         error_setg(errp, "Failed SetCommTimeouts"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!ClearCommError(s->hcom, &err, &comstat)) { | ||||||
|  |         error_setg(errp, "Failed ClearCommError"); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  |     qemu_add_polling_cb(win_chr_poll, chr); | ||||||
|  |     return 0; | ||||||
|  |  | ||||||
|  |  fail: | ||||||
|  |     return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int win_chr_pipe_poll(void *opaque) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(opaque); | ||||||
|  |     WinChardev *s = WIN_CHARDEV(opaque); | ||||||
|  |     DWORD size; | ||||||
|  |  | ||||||
|  |     PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); | ||||||
|  |     if (size > 0) { | ||||||
|  |         s->len = size; | ||||||
|  |         win_chr_read_poll(chr); | ||||||
|  |         win_chr_read(chr); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Called with chr_write_lock held.  */ | ||||||
|  | static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1) | ||||||
|  | { | ||||||
|  |     WinChardev *s = WIN_CHARDEV(chr); | ||||||
|  |     DWORD len, ret, size, err; | ||||||
|  |  | ||||||
|  |     len = len1; | ||||||
|  |     ZeroMemory(&s->osend, sizeof(s->osend)); | ||||||
|  |     s->osend.hEvent = s->hsend; | ||||||
|  |     while (len > 0) { | ||||||
|  |         if (s->hsend) { | ||||||
|  |             ret = WriteFile(s->hcom, buf, len, &size, &s->osend); | ||||||
|  |         } else { | ||||||
|  |             ret = WriteFile(s->hcom, buf, len, &size, NULL); | ||||||
|  |         } | ||||||
|  |         if (!ret) { | ||||||
|  |             err = GetLastError(); | ||||||
|  |             if (err == ERROR_IO_PENDING) { | ||||||
|  |                 ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE); | ||||||
|  |                 if (ret) { | ||||||
|  |                     buf += size; | ||||||
|  |                     len -= size; | ||||||
|  |                 } else { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             buf += size; | ||||||
|  |             len -= size; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return len1 - len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_win_finalize(Object *obj) | ||||||
|  | { | ||||||
|  |     Chardev *chr = CHARDEV(obj); | ||||||
|  |     WinChardev *s = WIN_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     if (s->skip_free) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (s->hsend) { | ||||||
|  |         CloseHandle(s->hsend); | ||||||
|  |     } | ||||||
|  |     if (s->hrecv) { | ||||||
|  |         CloseHandle(s->hrecv); | ||||||
|  |     } | ||||||
|  |     if (s->hcom) { | ||||||
|  |         CloseHandle(s->hcom); | ||||||
|  |     } | ||||||
|  |     if (s->fpipe) { | ||||||
|  |         qemu_del_polling_cb(win_chr_pipe_poll, chr); | ||||||
|  |     } else { | ||||||
|  |         qemu_del_polling_cb(win_chr_poll, chr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out) | ||||||
|  | { | ||||||
|  |     WinChardev *s = WIN_CHARDEV(chr); | ||||||
|  |  | ||||||
|  |     s->skip_free = true; | ||||||
|  |     s->hcom = fd_out; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void char_win_class_init(ObjectClass *oc, void *data) | ||||||
|  | { | ||||||
|  |     ChardevClass *cc = CHARDEV_CLASS(oc); | ||||||
|  |  | ||||||
|  |     cc->chr_write = win_chr_write; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const TypeInfo char_win_type_info = { | ||||||
|  |     .name = TYPE_CHARDEV_WIN, | ||||||
|  |     .parent = TYPE_CHARDEV, | ||||||
|  |     .instance_size = sizeof(WinChardev), | ||||||
|  |     .instance_finalize = char_win_finalize, | ||||||
|  |     .class_init = char_win_class_init, | ||||||
|  |     .abstract = true, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void register_types(void) | ||||||
|  | { | ||||||
|  |     type_register_static(&char_win_type_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type_init(register_types); | ||||||
							
								
								
									
										53
									
								
								chardev/char-win.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								chardev/char-win.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | /* | ||||||
|  |  * QEMU System Emulator | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  * THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef CHAR_WIN_H | ||||||
|  | #define CHAR_WIN_H | ||||||
|  |  | ||||||
|  | #include "sysemu/char.h" | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     Chardev parent; | ||||||
|  |     int max_size; | ||||||
|  |     HANDLE hcom, hrecv, hsend; | ||||||
|  |     OVERLAPPED orecv; | ||||||
|  |     BOOL fpipe; | ||||||
|  |     DWORD len; | ||||||
|  |  | ||||||
|  |     /* Protected by the Chardev chr_write_lock.  */ | ||||||
|  |     OVERLAPPED osend; | ||||||
|  |     /* FIXME: file/console do not finalize */ | ||||||
|  |     bool skip_free; | ||||||
|  | } WinChardev; | ||||||
|  |  | ||||||
|  | #define NSENDBUF 2048 | ||||||
|  | #define NRECVBUF 2048 | ||||||
|  |  | ||||||
|  | #define TYPE_CHARDEV_WIN "chardev-win" | ||||||
|  | #define WIN_CHARDEV(obj) OBJECT_CHECK(WinChardev, (obj), TYPE_CHARDEV_WIN) | ||||||
|  |  | ||||||
|  | void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out); | ||||||
|  | int win_chr_init(Chardev *chr, const char *filename, Error **errp); | ||||||
|  | int win_chr_pipe_poll(void *opaque); | ||||||
|  |  | ||||||
|  | #endif /* CHAR_WIN_H */ | ||||||
							
								
								
									
										1334
									
								
								chardev/char.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1334
									
								
								chardev/char.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -1474,7 +1474,7 @@ fi | |||||||
|  |  | ||||||
| gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" | gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" | ||||||
| gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" | gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" | ||||||
| gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" | gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" | ||||||
| gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags" | gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags" | ||||||
| gcc_flags="-Wno-initializer-overrides $gcc_flags" | gcc_flags="-Wno-initializer-overrides $gcc_flags" | ||||||
| gcc_flags="-Wno-string-plus-int $gcc_flags" | gcc_flags="-Wno-string-plus-int $gcc_flags" | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ | |||||||
|  */ |  */ | ||||||
| #include "qemu/osdep.h" | #include "qemu/osdep.h" | ||||||
| #include "cpu.h" | #include "cpu.h" | ||||||
| #include "trace.h" | #include "trace-root.h" | ||||||
| #include "disas/disas.h" | #include "disas/disas.h" | ||||||
| #include "exec/exec-all.h" | #include "exec/exec-all.h" | ||||||
| #include "tcg.h" | #include "tcg.h" | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| include pci.mak | include pci.mak | ||||||
| include usb.mak | include usb.mak | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_I8254=y | CONFIG_I8254=y | ||||||
| CONFIG_PCKBD=y | CONFIG_PCKBD=y | ||||||
| CONFIG_VGA_CIRRUS=y | CONFIG_VGA_CIRRUS=y | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ CONFIG_VGA=y | |||||||
| CONFIG_NAND=y | CONFIG_NAND=y | ||||||
| CONFIG_ECC=y | CONFIG_ECC=y | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_PTIMER=y | CONFIG_PTIMER=y | ||||||
| CONFIG_SD=y | CONFIG_SD=y | ||||||
| CONFIG_MAX7310=y | CONFIG_MAX7310=y | ||||||
| @@ -108,6 +109,7 @@ CONFIG_FSL_IMX25=y | |||||||
|  |  | ||||||
| CONFIG_IMX_I2C=y | CONFIG_IMX_I2C=y | ||||||
|  |  | ||||||
|  | CONFIG_PCIE_PORT=y | ||||||
| CONFIG_XIO3130=y | CONFIG_XIO3130=y | ||||||
| CONFIG_IOH3420=y | CONFIG_IOH3420=y | ||||||
| CONFIG_I82801B11=y | CONFIG_I82801B11=y | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ CONFIG_IPMI_EXTERN=y | |||||||
| CONFIG_ISA_IPMI_KCS=y | CONFIG_ISA_IPMI_KCS=y | ||||||
| CONFIG_ISA_IPMI_BT=y | CONFIG_ISA_IPMI_BT=y | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_PARALLEL=y | CONFIG_PARALLEL=y | ||||||
| CONFIG_I8254=y | CONFIG_I8254=y | ||||||
| CONFIG_PCSPK=y | CONFIG_PCSPK=y | ||||||
| @@ -51,8 +52,10 @@ CONFIG_PVPANIC=y | |||||||
| CONFIG_MEM_HOTPLUG=y | CONFIG_MEM_HOTPLUG=y | ||||||
| CONFIG_NVDIMM=y | CONFIG_NVDIMM=y | ||||||
| CONFIG_ACPI_NVDIMM=y | CONFIG_ACPI_NVDIMM=y | ||||||
|  | CONFIG_PCIE_PORT=y | ||||||
| CONFIG_XIO3130=y | CONFIG_XIO3130=y | ||||||
| CONFIG_IOH3420=y | CONFIG_IOH3420=y | ||||||
| CONFIG_I82801B11=y | CONFIG_I82801B11=y | ||||||
| CONFIG_SMBIOS=y | CONFIG_SMBIOS=y | ||||||
| CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) | CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) | ||||||
|  | CONFIG_PXB=y | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ CONFIG_VGA_ISA_MM=y | |||||||
| CONFIG_VGA_CIRRUS=y | CONFIG_VGA_CIRRUS=y | ||||||
| CONFIG_VMWARE_VGA=y | CONFIG_VMWARE_VGA=y | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_PARALLEL=y | CONFIG_PARALLEL=y | ||||||
| CONFIG_I8254=y | CONFIG_I8254=y | ||||||
| CONFIG_PCSPK=y | CONFIG_PCSPK=y | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| # Default configuration for moxie-softmmu | # Default configuration for moxie-softmmu | ||||||
|  |  | ||||||
|  | CONFIG_ISA_BUS=y | ||||||
| CONFIG_MC146818RTC=y | CONFIG_MC146818RTC=y | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_VGA=y | CONFIG_VGA=y | ||||||
|   | |||||||
| @@ -1,4 +1,6 @@ | |||||||
| CONFIG_PCI=y | CONFIG_PCI=y | ||||||
|  | # For now, CONFIG_IDE_CORE requires ISA, so we enable it here | ||||||
|  | CONFIG_ISA_BUS=y | ||||||
| CONFIG_VIRTIO_PCI=y | CONFIG_VIRTIO_PCI=y | ||||||
| CONFIG_VIRTIO=y | CONFIG_VIRTIO=y | ||||||
| CONFIG_USB_UHCI=y | CONFIG_USB_UHCI=y | ||||||
| @@ -27,6 +29,7 @@ CONFIG_AHCI=y | |||||||
| CONFIG_ESP=y | CONFIG_ESP=y | ||||||
| CONFIG_ESP_PCI=y | CONFIG_ESP_PCI=y | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_SERIAL_PCI=y | CONFIG_SERIAL_PCI=y | ||||||
| CONFIG_IPACK=y | CONFIG_IPACK=y | ||||||
| CONFIG_WDT_IB6300ESB=y | CONFIG_WDT_IB6300ESB=y | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ CONFIG_I82378=y | |||||||
| CONFIG_PC87312=y | CONFIG_PC87312=y | ||||||
| CONFIG_MACIO=y | CONFIG_MACIO=y | ||||||
| CONFIG_PCSPK=y | CONFIG_PCSPK=y | ||||||
|  | CONFIG_CS4231A=y | ||||||
| CONFIG_CUDA=y | CONFIG_CUDA=y | ||||||
| CONFIG_ADB=y | CONFIG_ADB=y | ||||||
| CONFIG_MAC_NVRAM=y | CONFIG_MAC_NVRAM=y | ||||||
| @@ -45,5 +46,7 @@ CONFIG_PLATFORM_BUS=y | |||||||
| CONFIG_ETSEC=y | CONFIG_ETSEC=y | ||||||
| CONFIG_LIBDECNUMBER=y | CONFIG_LIBDECNUMBER=y | ||||||
| # For PReP | # For PReP | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_MC146818RTC=y | CONFIG_MC146818RTC=y | ||||||
| CONFIG_ISA_TESTDEV=y | CONFIG_ISA_TESTDEV=y | ||||||
|  | CONFIG_RS6000_MC=y | ||||||
|   | |||||||
| @@ -52,6 +52,8 @@ CONFIG_XICS=$(CONFIG_PSERIES) | |||||||
| CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) | CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) | ||||||
| CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM)) | CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM)) | ||||||
| # For PReP | # For PReP | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_MC146818RTC=y | CONFIG_MC146818RTC=y | ||||||
| CONFIG_ISA_TESTDEV=y | CONFIG_ISA_TESTDEV=y | ||||||
| CONFIG_MEM_HOTPLUG=y | CONFIG_MEM_HOTPLUG=y | ||||||
|  | CONFIG_RS6000_MC=y | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ include sound.mak | |||||||
| include usb.mak | include usb.mak | ||||||
| CONFIG_M48T59=y | CONFIG_M48T59=y | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_I8257=y | CONFIG_I8257=y | ||||||
| CONFIG_OPENPIC=y | CONFIG_OPENPIC=y | ||||||
| CONFIG_PFLASH_CFI01=y | CONFIG_PFLASH_CFI01=y | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| include pci.mak | include pci.mak | ||||||
| include usb.mak | include usb.mak | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_PTIMER=y | CONFIG_PTIMER=y | ||||||
| CONFIG_PFLASH_CFI02=y | CONFIG_PFLASH_CFI02=y | ||||||
| CONFIG_SH4=y | CONFIG_SH4=y | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| include pci.mak | include pci.mak | ||||||
| include usb.mak | include usb.mak | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_PTIMER=y | CONFIG_PTIMER=y | ||||||
| CONFIG_PFLASH_CFI02=y | CONFIG_PFLASH_CFI02=y | ||||||
| CONFIG_SH4=y | CONFIG_SH4=y | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| # Default configuration for sparc-softmmu | # Default configuration for sparc-softmmu | ||||||
|  |  | ||||||
|  | CONFIG_ISA_BUS=y | ||||||
| CONFIG_ECC=y | CONFIG_ECC=y | ||||||
| CONFIG_ESP=y | CONFIG_ESP=y | ||||||
| CONFIG_ESCC=y | CONFIG_ESCC=y | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ include usb.mak | |||||||
| CONFIG_M48T59=y | CONFIG_M48T59=y | ||||||
| CONFIG_PTIMER=y | CONFIG_PTIMER=y | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_PARALLEL=y | CONFIG_PARALLEL=y | ||||||
| CONFIG_PCKBD=y | CONFIG_PCKBD=y | ||||||
| CONFIG_FDC=y | CONFIG_FDC=y | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| # Default configuration for unicore32-softmmu | # Default configuration for unicore32-softmmu | ||||||
|  | CONFIG_ISA_BUS=y | ||||||
| CONFIG_PUV3=y | CONFIG_PUV3=y | ||||||
| CONFIG_PTIMER=y | CONFIG_PTIMER=y | ||||||
| CONFIG_PCKBD=y | CONFIG_PCKBD=y | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ CONFIG_IPMI_EXTERN=y | |||||||
| CONFIG_ISA_IPMI_KCS=y | CONFIG_ISA_IPMI_KCS=y | ||||||
| CONFIG_ISA_IPMI_BT=y | CONFIG_ISA_IPMI_BT=y | ||||||
| CONFIG_SERIAL=y | CONFIG_SERIAL=y | ||||||
|  | CONFIG_SERIAL_ISA=y | ||||||
| CONFIG_PARALLEL=y | CONFIG_PARALLEL=y | ||||||
| CONFIG_I8254=y | CONFIG_I8254=y | ||||||
| CONFIG_PCSPK=y | CONFIG_PCSPK=y | ||||||
| @@ -51,8 +52,10 @@ CONFIG_PVPANIC=y | |||||||
| CONFIG_MEM_HOTPLUG=y | CONFIG_MEM_HOTPLUG=y | ||||||
| CONFIG_NVDIMM=y | CONFIG_NVDIMM=y | ||||||
| CONFIG_ACPI_NVDIMM=y | CONFIG_ACPI_NVDIMM=y | ||||||
|  | CONFIG_PCIE_PORT=y | ||||||
| CONFIG_XIO3130=y | CONFIG_XIO3130=y | ||||||
| CONFIG_IOH3420=y | CONFIG_IOH3420=y | ||||||
| CONFIG_I82801B11=y | CONFIG_I82801B11=y | ||||||
| CONFIG_SMBIOS=y | CONFIG_SMBIOS=y | ||||||
| CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) | CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) | ||||||
|  | CONFIG_PXB=y | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								disas/ppc.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								disas/ppc.c
									
									
									
									
									
								
							| @@ -1653,11 +1653,11 @@ extract_tbr (unsigned long insn, | |||||||
| #define BBOYBI_MASK (BBOYCB_MASK | BI_MASK) | #define BBOYBI_MASK (BBOYCB_MASK | BI_MASK) | ||||||
| #define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK) | #define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK) | ||||||
|  |  | ||||||
| /* An Context form instruction.  */ | /* A Context form instruction.  */ | ||||||
| #define CTX(op, xop)   (OP (op) | (((unsigned long)(xop)) & 0x7)) | #define CTX(op, xop)   (OP (op) | (((unsigned long)(xop)) & 0x7)) | ||||||
| #define CTX_MASK CTX(0x3f, 0x7) | #define CTX_MASK CTX(0x3f, 0x7) | ||||||
|  |  | ||||||
| /* An User Context form instruction.  */ | /* A User Context form instruction.  */ | ||||||
| #define UCTX(op, xop)  (OP (op) | (((unsigned long)(xop)) & 0x1f)) | #define UCTX(op, xop)  (OP (op) | (((unsigned long)(xop)) & 0x1f)) | ||||||
| #define UCTX_MASK UCTX(0x3f, 0x1f) | #define UCTX_MASK UCTX(0x3f, 0x1f) | ||||||
|  |  | ||||||
| @@ -1710,19 +1710,19 @@ extract_tbr (unsigned long insn, | |||||||
| #define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1)) | #define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1)) | ||||||
| #define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1) | #define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1) | ||||||
|  |  | ||||||
| /* An VX form instruction.  */ | /* A VX form instruction.  */ | ||||||
| #define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff)) | #define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff)) | ||||||
|  |  | ||||||
| /* The mask for an VX form instruction.  */ | /* The mask for an VX form instruction.  */ | ||||||
| #define VX_MASK	VX(0x3f, 0x7ff) | #define VX_MASK	VX(0x3f, 0x7ff) | ||||||
|  |  | ||||||
| /* An VA form instruction.  */ | /* A VA form instruction.  */ | ||||||
| #define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f)) | #define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f)) | ||||||
|  |  | ||||||
| /* The mask for an VA form instruction.  */ | /* The mask for a VA form instruction.  */ | ||||||
| #define VXA_MASK VXA(0x3f, 0x3f) | #define VXA_MASK VXA(0x3f, 0x3f) | ||||||
|  |  | ||||||
| /* An VXR form instruction.  */ | /* A VXR form instruction.  */ | ||||||
| #define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff)) | #define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff)) | ||||||
|  |  | ||||||
| /* The mask for a VXR form instruction.  */ | /* The mask for a VXR form instruction.  */ | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
| #include "qemu/osdep.h" | #include "qemu/osdep.h" | ||||||
| #include "sysemu/block-backend.h" | #include "sysemu/block-backend.h" | ||||||
| #include "sysemu/dma.h" | #include "sysemu/dma.h" | ||||||
| #include "trace.h" | #include "trace-root.h" | ||||||
| #include "qemu/thread.h" | #include "qemu/thread.h" | ||||||
| #include "qemu/main-loop.h" | #include "qemu/main-loop.h" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -27,18 +27,44 @@ for debugging, profiling, and observing execution. | |||||||
|  |  | ||||||
| == Trace events == | == Trace events == | ||||||
|  |  | ||||||
|  | === Sub-directory setup === | ||||||
|  |  | ||||||
| Each directory in the source tree can declare a set of static trace events | Each directory in the source tree can declare a set of static trace events | ||||||
| in a "trace-events" file. Each trace event declaration names the event, its | in a local "trace-events" file. All directories which contain "trace-events" | ||||||
| arguments, and the format string which can be used for pretty-printing: | files must be listed in the "trace-events-subdirs" make variable in the top | ||||||
|  | level Makefile.objs. During build, the "trace-events" file in each listed | ||||||
|  | subdirectory will be processed by the "tracetool" script to generate code for | ||||||
|  | the trace events. | ||||||
|  |  | ||||||
|     qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p" | The individual "trace-events" files are merged into a "trace-events-all" file, | ||||||
|     qemu_vfree(void *ptr) "ptr %p" | which is also installed into "/usr/share/qemu" with the name "trace-events". | ||||||
|  | This merged file is to be used by the "simpletrace.py" script to later analyse | ||||||
|  | traces in the simpletrace data format. | ||||||
|  |  | ||||||
| All "trace-events" files must be listed in the "trace-event-y" make variable | In the sub-directory the following files will be automatically generated | ||||||
| in the top level Makefile.objs. During build the individual files are combined |  | ||||||
| to create a "trace-events-all" file, which is processed by the "tracetool" |  - trace.c - the trace event state declarations | ||||||
| script during build to generate code for the trace events. The |  - trace.h - the trace event enums and probe functions | ||||||
| "trace-events-all" file is also installed into "/usr/share/qemu". |  - trace-dtrace.h - DTrace event probe specification | ||||||
|  |  - trace-dtrace.dtrace - DTrace event probe helper declaration | ||||||
|  |  - trace-dtrace.o - binary DTrace provider (generated by dtrace) | ||||||
|  |  - trace-ust.h - UST event probe helper declarations | ||||||
|  |  | ||||||
|  | Source files in the sub-directory should #include the local 'trace.h' file, | ||||||
|  | without any sub-directory path prefix. eg io/channel-buffer.c would do | ||||||
|  |  | ||||||
|  |   #include "trace.h" | ||||||
|  |  | ||||||
|  | To access the 'io/trace.h' file. While it is possible to include a trace.h | ||||||
|  | file from outside a source files' own sub-directory, this is discouraged in | ||||||
|  | general. It is strongly preferred that all events be declared directly in | ||||||
|  | the sub-directory that uses them. The only exception is where there are some | ||||||
|  | shared trace events defined in the top level directory trace-events file. | ||||||
|  | The top level directory generates trace files with a filename prefix of | ||||||
|  | "trace-root" instead of just "trace". This is to avoid ambiguity between | ||||||
|  | a trace.h in the current directory, vs the top level directory. | ||||||
|  |  | ||||||
|  | === Using trace events === | ||||||
|  |  | ||||||
| Trace events are invoked directly from source code like this: | Trace events are invoked directly from source code like this: | ||||||
|  |  | ||||||
| @@ -83,6 +109,13 @@ Format strings should reflect the types defined in the trace event.  Take | |||||||
| special care to use PRId64 and PRIu64 for int64_t and uint64_t types, | special care to use PRId64 and PRIu64 for int64_t and uint64_t types, | ||||||
| respectively.  This ensures portability between 32- and 64-bit platforms. | respectively.  This ensures portability between 32- and 64-bit platforms. | ||||||
|  |  | ||||||
|  | Each event declaration will start with the event name, then its arguments, | ||||||
|  | finally a format string for pretty-printing. For example: | ||||||
|  |  | ||||||
|  |     qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p" | ||||||
|  |     qemu_vfree(void *ptr) "ptr %p" | ||||||
|  |  | ||||||
|  |  | ||||||
| === Hints for adding new trace events === | === Hints for adding new trace events === | ||||||
|  |  | ||||||
| 1. Trace state changes in the code.  Interesting points in the code usually | 1. Trace state changes in the code.  Interesting points in the code usually | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								exec.c
									
									
									
									
									
								
							| @@ -44,7 +44,7 @@ | |||||||
| #include "sysemu/dma.h" | #include "sysemu/dma.h" | ||||||
| #include "exec/address-spaces.h" | #include "exec/address-spaces.h" | ||||||
| #include "sysemu/xen-mapcache.h" | #include "sysemu/xen-mapcache.h" | ||||||
| #include "trace.h" | #include "trace-root.h" | ||||||
| #endif | #endif | ||||||
| #include "exec/cpu-all.h" | #include "exec/cpu-all.h" | ||||||
| #include "qemu/rcu_queue.h" | #include "qemu/rcu_queue.h" | ||||||
|   | |||||||
| @@ -185,7 +185,7 @@ float128 float128_default_nan(float_status *status) | |||||||
|         r.high = LIT64(0x7FFF7FFFFFFFFFFF); |         r.high = LIT64(0x7FFF7FFFFFFFFFFF); | ||||||
|     } else { |     } else { | ||||||
|         r.low = LIT64(0x0000000000000000); |         r.low = LIT64(0x0000000000000000); | ||||||
| #if defined(TARGET_S390X) | #if defined(TARGET_S390X) || defined(TARGET_PPC) | ||||||
|         r.high = LIT64(0x7FFF800000000000); |         r.high = LIT64(0x7FFF800000000000); | ||||||
| #else | #else | ||||||
|         r.high = LIT64(0xFFFF800000000000); |         r.high = LIT64(0xFFFF800000000000); | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								hmp.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								hmp.c
									
									
									
									
									
								
							| @@ -19,6 +19,7 @@ | |||||||
| #include "net/eth.h" | #include "net/eth.h" | ||||||
| #include "sysemu/char.h" | #include "sysemu/char.h" | ||||||
| #include "sysemu/block-backend.h" | #include "sysemu/block-backend.h" | ||||||
|  | #include "qemu/config-file.h" | ||||||
| #include "qemu/option.h" | #include "qemu/option.h" | ||||||
| #include "qemu/timer.h" | #include "qemu/timer.h" | ||||||
| #include "qmp-commands.h" | #include "qmp-commands.h" | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								hw/block/dataplane/trace-events
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								hw/block/dataplane/trace-events
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | # See docs/tracing.txt for syntax documentation. | ||||||
|  |  | ||||||
|  | # hw/block/dataplane/virtio-blk.c | ||||||
|  | virtio_blk_data_plane_start(void *s) "dataplane %p" | ||||||
|  | virtio_blk_data_plane_stop(void *s) "dataplane %p" | ||||||
| @@ -872,7 +872,7 @@ static int nvme_init(PCIDevice *pci_dev) | |||||||
|     pci_register_bar(&n->parent_obj, 0, |     pci_register_bar(&n->parent_obj, 0, | ||||||
|         PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, |         PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, | ||||||
|         &n->iomem); |         &n->iomem); | ||||||
|     msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4); |     msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4, NULL); | ||||||
|  |  | ||||||
|     id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); |     id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); | ||||||
|     id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); |     id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); | ||||||
|   | |||||||
| @@ -7,11 +7,6 @@ virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sec | |||||||
| virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" | virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" | ||||||
| virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d" | virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d" | ||||||
|  |  | ||||||
| # hw/block/dataplane/virtio-blk.c |  | ||||||
| virtio_blk_data_plane_start(void *s) "dataplane %p" |  | ||||||
| virtio_blk_data_plane_stop(void *s) "dataplane %p" |  | ||||||
| virtio_blk_data_plane_process_request(void *s, unsigned int out_num, unsigned int in_num, unsigned int head) "dataplane %p out_num %u in_num %u head %u" |  | ||||||
|  |  | ||||||
| # hw/block/hd-geometry.c | # hw/block/hd-geometry.c | ||||||
| hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d" | hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d" | ||||||
| hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d" | hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d" | ||||||
|   | |||||||
| @@ -2,7 +2,8 @@ common-obj-$(CONFIG_IPACK) += ipoctal232.o | |||||||
| common-obj-$(CONFIG_ESCC) += escc.o | common-obj-$(CONFIG_ESCC) += escc.o | ||||||
| common-obj-$(CONFIG_PARALLEL) += parallel.o | common-obj-$(CONFIG_PARALLEL) += parallel.o | ||||||
| common-obj-$(CONFIG_PL011) += pl011.o | common-obj-$(CONFIG_PL011) += pl011.o | ||||||
| common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o | common-obj-$(CONFIG_SERIAL) += serial.o | ||||||
|  | common-obj-$(CONFIG_SERIAL_ISA) += serial-isa.o | ||||||
| common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o | common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o | ||||||
| common-obj-$(CONFIG_VIRTIO) += virtio-console.o | common-obj-$(CONFIG_VIRTIO) += virtio-console.o | ||||||
| common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o | common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o | ||||||
|   | |||||||
| @@ -933,9 +933,12 @@ static void device_set_realized(Object *obj, bool value, Error **errp) | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (qdev_get_vmsd(dev)) { |         if (qdev_get_vmsd(dev)) { | ||||||
|             vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev, |             if (vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev, | ||||||
|                                                dev->instance_id_alias, |                                                dev->instance_id_alias, | ||||||
|                                            dev->alias_required_for_version); |                                                dev->alias_required_for_version, | ||||||
|  |                                                &local_err) < 0) { | ||||||
|  |                 goto post_realize_fail; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         QLIST_FOREACH(bus, &dev->child_bus, sibling) { |         QLIST_FOREACH(bus, &dev->child_bus, sibling) { | ||||||
|   | |||||||
| @@ -272,15 +272,11 @@ static void cirrus_update_memory_access(CirrusVGAState *s); | |||||||
| static bool blit_region_is_unsafe(struct CirrusVGAState *s, | static bool blit_region_is_unsafe(struct CirrusVGAState *s, | ||||||
|                                   int32_t pitch, int32_t addr) |                                   int32_t pitch, int32_t addr) | ||||||
| { | { | ||||||
|     if (!pitch) { |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|     if (pitch < 0) { |     if (pitch < 0) { | ||||||
|         int64_t min = addr |         int64_t min = addr | ||||||
|             + ((int64_t)s->cirrus_blt_height-1) * pitch; |             + ((int64_t)s->cirrus_blt_height - 1) * pitch | ||||||
|         int32_t max = addr |             - s->cirrus_blt_width; | ||||||
|             + s->cirrus_blt_width; |         if (min < -1 || addr >= s->vga.vram_size) { | ||||||
|         if (min < 0 || max > s->vga.vram_size) { |  | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
| @@ -294,8 +290,11 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s, | |||||||
|     return false; |     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 */ |     /* should be the case, see cirrus_bitblt_start */ | ||||||
|     assert(s->cirrus_blt_width > 0); |     assert(s->cirrus_blt_width > 0); | ||||||
|     assert(s->cirrus_blt_height > 0); |     assert(s->cirrus_blt_height > 0); | ||||||
| @@ -304,15 +303,25 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only) | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (!s->cirrus_blt_dstpitch) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch, |     if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch, | ||||||
|                               s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) { |                               s->cirrus_blt_dstaddr)) { | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     if (dst_only) { |     if (dst_only) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch, |  | ||||||
|                               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; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -661,9 +670,14 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, | |||||||
|     int off_cur; |     int off_cur; | ||||||
|     int off_cur_end; |     int off_cur_end; | ||||||
|  |  | ||||||
|  |     if (off_pitch < 0) { | ||||||
|  |         off_begin -= bytesperline - 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     for (y = 0; y < lines; y++) { |     for (y = 0; y < lines; y++) { | ||||||
| 	off_cur = off_begin; | 	off_cur = off_begin; | ||||||
| 	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask; | 	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask; | ||||||
|  |         assert(off_cur_end >= off_cur); | ||||||
|         memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur); |         memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur); | ||||||
| 	off_begin += off_pitch; | 	off_begin += off_pitch; | ||||||
|     } |     } | ||||||
| @@ -674,10 +688,11 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, | |||||||
| { | { | ||||||
|     uint8_t *dst; |     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; |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     (*s->cirrus_rop) (s, dst, src, |     (*s->cirrus_rop) (s, dst, src, | ||||||
|                       s->cirrus_blt_dstpitch, 0, |                       s->cirrus_blt_dstpitch, 0, | ||||||
| @@ -694,11 +709,11 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) | |||||||
| { | { | ||||||
|     cirrus_fill_t rop_func; |     cirrus_fill_t rop_func; | ||||||
|  |  | ||||||
|     if (blit_is_unsafe(s, true)) { |     if (blit_is_unsafe(s, true, true)) { | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|     rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; |     rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; | ||||||
|     rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), |     rop_func(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr, | ||||||
|              s->cirrus_blt_dstpitch, |              s->cirrus_blt_dstpitch, | ||||||
|              s->cirrus_blt_width, s->cirrus_blt_height); |              s->cirrus_blt_width, s->cirrus_blt_height); | ||||||
|     cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, |     cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, | ||||||
| @@ -716,9 +731,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) | |||||||
|  |  | ||||||
| static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) | static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) | ||||||
| { | { | ||||||
|     return cirrus_bitblt_common_patterncopy(s, |     return cirrus_bitblt_common_patterncopy(s, s->vga.vram_ptr + | ||||||
| 					    s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) & |                                             (s->cirrus_blt_srcaddr & ~7)); | ||||||
|                                             s->cirrus_addr_mask)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) | static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) | ||||||
| @@ -772,10 +786,8 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) | |||||||
|     if (notify) |     if (notify) | ||||||
|         graphic_hw_update(s->vga.con); |         graphic_hw_update(s->vga.con); | ||||||
|  |  | ||||||
|     (*s->cirrus_rop) (s, s->vga.vram_ptr + |     (*s->cirrus_rop) (s, s->vga.vram_ptr + s->cirrus_blt_dstaddr, | ||||||
| 		      (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), |                       s->vga.vram_ptr + s->cirrus_blt_srcaddr, | ||||||
| 		      s->vga.vram_ptr + |  | ||||||
| 		      (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), |  | ||||||
| 		      s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, | 		      s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, | ||||||
| 		      s->cirrus_blt_width, s->cirrus_blt_height); | 		      s->cirrus_blt_width, s->cirrus_blt_height); | ||||||
|  |  | ||||||
| @@ -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) | static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) | ||||||
| { | { | ||||||
|     if (blit_is_unsafe(s, false)) |     if (blit_is_unsafe(s, false, false)) | ||||||
|         return 0; |         return 0; | ||||||
|  |  | ||||||
|     return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr, |     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 { |         } else { | ||||||
|             /* at least one scan line */ |             /* at least one scan line */ | ||||||
|             do { |             do { | ||||||
|                 (*s->cirrus_rop)(s, s->vga.vram_ptr + |                 (*s->cirrus_rop)(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr, | ||||||
|                                  (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), |  | ||||||
|                                   s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); |                                   s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); | ||||||
|                 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, |                 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, | ||||||
|                                          s->cirrus_blt_width, 1); |                                          s->cirrus_blt_width, 1); | ||||||
| @@ -946,6 +957,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s) | |||||||
|     s->cirrus_blt_modeext = s->vga.gr[0x33]; |     s->cirrus_blt_modeext = s->vga.gr[0x33]; | ||||||
|     blt_rop = s->vga.gr[0x32]; |     blt_rop = s->vga.gr[0x32]; | ||||||
|  |  | ||||||
|  |     s->cirrus_blt_dstaddr &= s->cirrus_addr_mask; | ||||||
|  |     s->cirrus_blt_srcaddr &= s->cirrus_addr_mask; | ||||||
|  |  | ||||||
| #ifdef DEBUG_BITBLT | #ifdef DEBUG_BITBLT | ||||||
|     printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", |     printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", | ||||||
|            blt_rop, |            blt_rop, | ||||||
|   | |||||||
| @@ -306,12 +306,11 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl) | |||||||
|  |  | ||||||
| static ram_addr_t qxl_rom_size(void) | static ram_addr_t qxl_rom_size(void) | ||||||
| { | { | ||||||
|     uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) + | #define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes)) | ||||||
|                                  sizeof(qxl_modes); | #define QXL_ROM_SZ 8192 | ||||||
|     uint32_t rom_size = 8192; /* two pages */ |  | ||||||
|  |  | ||||||
|     QEMU_BUILD_BUG_ON(required_rom_size > rom_size); |     QEMU_BUILD_BUG_ON(QXL_REQUIRED_SZ > QXL_ROM_SZ); | ||||||
|     return rom_size; |     return QXL_ROM_SZ; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void init_qxl_rom(PCIQXLDevice *d) | static void init_qxl_rom(PCIQXLDevice *d) | ||||||
|   | |||||||
| @@ -34,7 +34,6 @@ vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp" | |||||||
| # hw/display/virtio-gpu.c | # hw/display/virtio-gpu.c | ||||||
| virtio_gpu_features(bool virgl) "virgl %d" | virtio_gpu_features(bool virgl) "virgl %d" | ||||||
| virtio_gpu_cmd_get_display_info(void) "" | virtio_gpu_cmd_get_display_info(void) "" | ||||||
| virtio_gpu_cmd_get_caps(void) "" |  | ||||||
| virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d" | virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d" | ||||||
| virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d" | virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d" | ||||||
| virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d" | virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d" | ||||||
|   | |||||||
| @@ -143,8 +143,10 @@ static void mpc8xxx_gpio_write(void *opaque, hwaddr offset, | |||||||
|     mpc8xxx_gpio_update(s); |     mpc8xxx_gpio_update(s); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void mpc8xxx_gpio_reset(MPC8XXXGPIOState *s) | static void mpc8xxx_gpio_reset(DeviceState *dev) | ||||||
| { | { | ||||||
|  |     MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev); | ||||||
|  |  | ||||||
|     s->dir = 0; |     s->dir = 0; | ||||||
|     s->odr = 0; |     s->odr = 0; | ||||||
|     s->dat = 0; |     s->dat = 0; | ||||||
| @@ -180,33 +182,33 @@ static const MemoryRegionOps mpc8xxx_gpio_ops = { | |||||||
|     .endianness = DEVICE_BIG_ENDIAN, |     .endianness = DEVICE_BIG_ENDIAN, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static int mpc8xxx_gpio_initfn(SysBusDevice *sbd) | static void mpc8xxx_gpio_initfn(Object *obj) | ||||||
| { | { | ||||||
|     DeviceState *dev = DEVICE(sbd); |     DeviceState *dev = DEVICE(obj); | ||||||
|     MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev); |     MPC8XXXGPIOState *s = MPC8XXX_GPIO(obj); | ||||||
|  |     SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | ||||||
|  |  | ||||||
|     memory_region_init_io(&s->iomem, OBJECT(s), &mpc8xxx_gpio_ops, s, "mpc8xxx_gpio", 0x1000); |     memory_region_init_io(&s->iomem, obj, &mpc8xxx_gpio_ops, | ||||||
|  |                           s, "mpc8xxx_gpio", 0x1000); | ||||||
|     sysbus_init_mmio(sbd, &s->iomem); |     sysbus_init_mmio(sbd, &s->iomem); | ||||||
|     sysbus_init_irq(sbd, &s->irq); |     sysbus_init_irq(sbd, &s->irq); | ||||||
|     qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32); |     qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32); | ||||||
|     qdev_init_gpio_out(dev, s->out, 32); |     qdev_init_gpio_out(dev, s->out, 32); | ||||||
|     mpc8xxx_gpio_reset(s); |  | ||||||
|     return 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data) | static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data) | ||||||
| { | { | ||||||
|     DeviceClass *dc = DEVICE_CLASS(klass); |     DeviceClass *dc = DEVICE_CLASS(klass); | ||||||
|     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |  | ||||||
|  |  | ||||||
|     k->init = mpc8xxx_gpio_initfn; |  | ||||||
|     dc->vmsd = &vmstate_mpc8xxx_gpio; |     dc->vmsd = &vmstate_mpc8xxx_gpio; | ||||||
|  |     dc->reset = mpc8xxx_gpio_reset; | ||||||
| } | } | ||||||
|  |  | ||||||
| static const TypeInfo mpc8xxx_gpio_info = { | static const TypeInfo mpc8xxx_gpio_info = { | ||||||
|     .name          = TYPE_MPC8XXX_GPIO, |     .name          = TYPE_MPC8XXX_GPIO, | ||||||
|     .parent        = TYPE_SYS_BUS_DEVICE, |     .parent        = TYPE_SYS_BUS_DEVICE, | ||||||
|     .instance_size = sizeof(MPC8XXXGPIOState), |     .instance_size = sizeof(MPC8XXXGPIOState), | ||||||
|  |     .instance_init = mpc8xxx_gpio_initfn, | ||||||
|     .class_init    = mpc8xxx_gpio_class_init, |     .class_init    = mpc8xxx_gpio_class_init, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1485,8 +1485,16 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, | |||||||
|         goto done; |         goto done; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /* According to ATS spec table 2.4: | ||||||
|  |      * S = 0, bits 15:12 = xxxx     range size: 4K | ||||||
|  |      * S = 1, bits 15:12 = xxx0     range size: 8K | ||||||
|  |      * S = 1, bits 15:12 = xx01     range size: 16K | ||||||
|  |      * S = 1, bits 15:12 = x011     range size: 32K | ||||||
|  |      * S = 1, bits 15:12 = 0111     range size: 64K | ||||||
|  |      * ... | ||||||
|  |      */ | ||||||
|     if (size) { |     if (size) { | ||||||
|         sz = 1 << (ctz64(~(addr | (VTD_PAGE_MASK_4K - 1))) + 1); |         sz = (VTD_PAGE_SIZE * 2) << cto64(addr >> VTD_PAGE_SHIFT); | ||||||
|         addr &= ~(sz - 1); |         addr &= ~(sz - 1); | ||||||
|     } else { |     } else { | ||||||
|         sz = VTD_PAGE_SIZE; |         sz = VTD_PAGE_SIZE; | ||||||
|   | |||||||
| @@ -1708,6 +1708,11 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { |     if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { | ||||||
|  |         if (!pcms->acpi_nvdimm_state.is_enabled) { | ||||||
|  |             error_setg(&local_err, | ||||||
|  |                        "nvdimm is not enabled: missing 'nvdimm' in '-M'"); | ||||||
|  |             goto out; | ||||||
|  |         } | ||||||
|         nvdimm_plug(&pcms->acpi_nvdimm_state); |         nvdimm_plug(&pcms->acpi_nvdimm_state); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,12 +1,5 @@ | |||||||
| # See docs/tracing.txt for syntax documentation. | # See docs/tracing.txt for syntax documentation. | ||||||
|  |  | ||||||
| # hw/i386/xen/xen_platform.c |  | ||||||
| xen_platform_log(char *s) "xen platform: %s" |  | ||||||
|  |  | ||||||
| # hw/i386/xen/xen_pvdevice.c |  | ||||||
| xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")" |  | ||||||
| xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")" |  | ||||||
|  |  | ||||||
| # hw/i386/x86-iommu.c | # hw/i386/x86-iommu.c | ||||||
| x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32 | x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32 | ||||||
|  |  | ||||||
| @@ -30,7 +23,6 @@ amdvi_devtab_inval(uint8_t bus, uint8_t slot, uint8_t func) "device table entry | |||||||
| amdvi_completion_wait(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64 | amdvi_completion_wait(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64 | ||||||
| amdvi_control_status(uint64_t val) "MMIO_STATUS state 0x%"PRIx64 | amdvi_control_status(uint64_t val) "MMIO_STATUS state 0x%"PRIx64 | ||||||
| amdvi_iotlb_reset(void) "IOTLB exceed size limit - reset " | amdvi_iotlb_reset(void) "IOTLB exceed size limit - reset " | ||||||
| amdvi_completion_wait_exec(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64 |  | ||||||
| amdvi_dte_get_fail(uint64_t addr, uint32_t offset) "error: failed to access Device Entry devtab 0x%"PRIx64" offset 0x%"PRIx32 | amdvi_dte_get_fail(uint64_t addr, uint32_t offset) "error: failed to access Device Entry devtab 0x%"PRIx64" offset 0x%"PRIx32 | ||||||
| amdvi_invalid_dte(uint64_t addr) "PTE entry at 0x%"PRIx64" is invalid " | amdvi_invalid_dte(uint64_t addr) "PTE entry at 0x%"PRIx64" is invalid " | ||||||
| amdvi_get_pte_hwerror(uint64_t addr) "hardware error eccessing PTE at addr 0x%"PRIx64 | amdvi_get_pte_hwerror(uint64_t addr) "hardware error eccessing PTE at addr 0x%"PRIx64 | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								hw/i386/xen/trace-events
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								hw/i386/xen/trace-events
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | # hw/i386/xen/xen_platform.c | ||||||
|  | xen_platform_log(char *s) "xen platform: %s" | ||||||
|  |  | ||||||
|  | # hw/i386/xen/xen_pvdevice.c | ||||||
|  | xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")" | ||||||
|  | xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")" | ||||||
| @@ -88,7 +88,7 @@ static void log_writeb(PCIXenPlatformState *s, char val) | |||||||
| } | } | ||||||
|  |  | ||||||
| /* Xen Platform, Fixed IOPort */ | /* Xen Platform, Fixed IOPort */ | ||||||
| #define UNPLUG_ALL_IDE_DISKS 1 | #define UNPLUG_ALL_DISKS 1 | ||||||
| #define UNPLUG_ALL_NICS 2 | #define UNPLUG_ALL_NICS 2 | ||||||
| #define UNPLUG_AUX_IDE_DISKS 4 | #define UNPLUG_AUX_IDE_DISKS 4 | ||||||
|  |  | ||||||
| @@ -107,23 +107,37 @@ static void pci_unplug_nics(PCIBus *bus) | |||||||
|     pci_for_each_device(bus, 0, unplug_nic, NULL); |     pci_for_each_device(bus, 0, unplug_nic, NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void unplug_disks(PCIBus *b, PCIDevice *d, void *o) | static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque) | ||||||
| { | { | ||||||
|  |     uint32_t flags = *(uint32_t *)opaque; | ||||||
|  |     bool aux = (flags & UNPLUG_AUX_IDE_DISKS) && | ||||||
|  |         !(flags & UNPLUG_ALL_DISKS); | ||||||
|  |  | ||||||
|     /* We have to ignore passthrough devices */ |     /* We have to ignore passthrough devices */ | ||||||
|     if (pci_get_word(d->config + PCI_CLASS_DEVICE) == |     if (!strcmp(d->name, "xen-pci-passthrough")) { | ||||||
|             PCI_CLASS_STORAGE_IDE |         return; | ||||||
|             && strcmp(d->name, "xen-pci-passthrough") != 0) { |     } | ||||||
|         pci_piix3_xen_ide_unplug(DEVICE(d)); |  | ||||||
|     } else if (pci_get_word(d->config + PCI_CLASS_DEVICE) == |     switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) { | ||||||
|             PCI_CLASS_STORAGE_SCSI |     case PCI_CLASS_STORAGE_IDE: | ||||||
|             && strcmp(d->name, "xen-pci-passthrough") != 0) { |         pci_piix3_xen_ide_unplug(DEVICE(d), aux); | ||||||
|  |         break; | ||||||
|  |  | ||||||
|  |     case PCI_CLASS_STORAGE_SCSI: | ||||||
|  |     case PCI_CLASS_STORAGE_EXPRESS: | ||||||
|  |         if (!aux) { | ||||||
|             object_unparent(OBJECT(d)); |             object_unparent(OBJECT(d)); | ||||||
|         } |         } | ||||||
|  |         break; | ||||||
|  |  | ||||||
|  |     default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static void pci_unplug_disks(PCIBus *bus) | static void pci_unplug_disks(PCIBus *bus, uint32_t flags) | ||||||
| { | { | ||||||
|     pci_for_each_device(bus, 0, unplug_disks, NULL); |     pci_for_each_device(bus, 0, unplug_disks, &flags); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val) | static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val) | ||||||
| @@ -134,19 +148,16 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v | |||||||
|     case 0: { |     case 0: { | ||||||
|         PCIDevice *pci_dev = PCI_DEVICE(s); |         PCIDevice *pci_dev = PCI_DEVICE(s); | ||||||
|         /* Unplug devices.  Value is a bitmask of which devices to |         /* Unplug devices.  Value is a bitmask of which devices to | ||||||
|            unplug, with bit 0 the IDE devices, bit 1 the network |            unplug, with bit 0 the disk devices, bit 1 the network | ||||||
|            devices, and bit 2 the non-primary-master IDE devices. */ |            devices, and bit 2 the non-primary-master IDE devices. */ | ||||||
|         if (val & UNPLUG_ALL_IDE_DISKS) { |         if (val & (UNPLUG_ALL_DISKS | UNPLUG_AUX_IDE_DISKS)) { | ||||||
|             DPRINTF("unplug disks\n"); |             DPRINTF("unplug disks\n"); | ||||||
|             pci_unplug_disks(pci_dev->bus); |             pci_unplug_disks(pci_dev->bus, val); | ||||||
|         } |         } | ||||||
|         if (val & UNPLUG_ALL_NICS) { |         if (val & UNPLUG_ALL_NICS) { | ||||||
|             DPRINTF("unplug nics\n"); |             DPRINTF("unplug nics\n"); | ||||||
|             pci_unplug_nics(pci_dev->bus); |             pci_unplug_nics(pci_dev->bus); | ||||||
|         } |         } | ||||||
|         if (val & UNPLUG_AUX_IDE_DISKS) { |  | ||||||
|             DPRINTF("unplug auxiliary disks not supported\n"); |  | ||||||
|         } |  | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case 2: |     case 2: | ||||||
| @@ -327,14 +338,14 @@ static void xen_platform_ioport_writeb(void *opaque, hwaddr addr, | |||||||
|              * If VMDP was to control both disk and LAN it would use 4. |              * If VMDP was to control both disk and LAN it would use 4. | ||||||
|              * If it controlled just disk or just LAN, it would use 8 below. |              * If it controlled just disk or just LAN, it would use 8 below. | ||||||
|              */ |              */ | ||||||
|             pci_unplug_disks(pci_dev->bus); |             pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS); | ||||||
|             pci_unplug_nics(pci_dev->bus); |             pci_unplug_nics(pci_dev->bus); | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     case 8: |     case 8: | ||||||
|         switch (val) { |         switch (val) { | ||||||
|         case 1: |         case 1: | ||||||
|             pci_unplug_disks(pci_dev->bus); |             pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS); | ||||||
|             break; |             break; | ||||||
|         case 2: |         case 2: | ||||||
|             pci_unplug_nics(pci_dev->bus); |             pci_unplug_nics(pci_dev->bus); | ||||||
|   | |||||||
| @@ -165,7 +165,7 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp) | |||||||
|     pci_piix_init_ports(d); |     pci_piix_init_ports(d); | ||||||
| } | } | ||||||
|  |  | ||||||
| int pci_piix3_xen_ide_unplug(DeviceState *dev) | int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux) | ||||||
| { | { | ||||||
|     PCIIDEState *pci_ide; |     PCIIDEState *pci_ide; | ||||||
|     DriveInfo *di; |     DriveInfo *di; | ||||||
| @@ -174,7 +174,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev) | |||||||
|  |  | ||||||
|     pci_ide = PCI_IDE(dev); |     pci_ide = PCI_IDE(dev); | ||||||
|  |  | ||||||
|     for (i = 0; i < 4; i++) { |     for (i = aux ? 1 : 0; i < 4; i++) { | ||||||
|         di = drive_get_by_index(IF_IDE, i); |         di = drive_get_by_index(IF_IDE, i); | ||||||
|         if (di != NULL && !di->media_cd) { |         if (di != NULL && !di->media_cd) { | ||||||
|             BlockBackend *blk = blk_by_legacy_dinfo(di); |             BlockBackend *blk = blk_by_legacy_dinfo(di); | ||||||
|   | |||||||
| @@ -8,8 +8,6 @@ ps2_reset_keyboard(void *s) "%p" | |||||||
| ps2_write_keyboard(void *opaque, int val) "%p val %d" | ps2_write_keyboard(void *opaque, int val) "%p val %d" | ||||||
| ps2_keyboard_set_translation(void *opaque, int mode) "%p mode %d" | ps2_keyboard_set_translation(void *opaque, int mode) "%p mode %d" | ||||||
| ps2_mouse_send_packet(void *s, int dx1, int dy1, int dz1, int b) "%p x %d y %d z %d bs %#x" | ps2_mouse_send_packet(void *s, int dx1, int dy1, int dz1, int b) "%p x %d y %d z %d bs %#x" | ||||||
| ps2_mouse_event_disabled(void *opaque, int dx, int dy, int dz, int buttons_state, int mouse_dx, int mouse_dy, int mouse_dz) "%p x %d y %d z %d bs %#x mx %d my %d mz %d " |  | ||||||
| ps2_mouse_event(void *opaque, int dx, int dy, int dz, int buttons_state, int mouse_dx, int mouse_dy, int mouse_dz) "%p x %d y %d z %d bs %#x mx %d my %d mz %d " |  | ||||||
| ps2_mouse_fake_event(void *opaque) "%p" | ps2_mouse_fake_event(void *opaque) "%p" | ||||||
| ps2_write_mouse(void *opaque, int val) "%p val %d" | ps2_write_mouse(void *opaque, int val) "%p val %d" | ||||||
| ps2_kbd_reset(void *opaque) "%p" | ps2_kbd_reset(void *opaque) "%p" | ||||||
|   | |||||||
| @@ -329,7 +329,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp) | |||||||
|         instance_id = -1; |         instance_id = -1; | ||||||
|     } |     } | ||||||
|     vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common, |     vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common, | ||||||
|                                    s, -1, 0); |                                    s, -1, 0, NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void apic_common_unrealize(DeviceState *dev, Error **errp) | static void apic_common_unrealize(DeviceState *dev, Error **errp) | ||||||
|   | |||||||
| @@ -67,7 +67,6 @@ xics_alloc(int irq) "irq %d" | |||||||
| xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d" | xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d" | ||||||
| xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" | xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" | ||||||
| xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free" | xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free" | ||||||
| xics_icp_post_load(uint32_t server_no, uint32_t xirr, uint64_t addr, uint8_t pend) "server_no %d, xirr %#x, xirr_owner 0x%" PRIx64 ", pending %d" |  | ||||||
|  |  | ||||||
| # hw/intc/s390_flic_kvm.c | # hw/intc/s390_flic_kvm.c | ||||||
| flic_create_device(int err) "flic: create device failed %d" | flic_create_device(int err) "flic: create device failed %d" | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| common-obj-y += isa-bus.o | common-obj-$(CONFIG_ISA_BUS) += isa-bus.o | ||||||
| common-obj-$(CONFIG_APM) += apm.o | common-obj-$(CONFIG_APM) += apm.o | ||||||
| common-obj-$(CONFIG_I82378) += i82378.o | common-obj-$(CONFIG_I82378) += i82378.o | ||||||
| common-obj-$(CONFIG_PC87312) += pc87312.o | common-obj-$(CONFIG_PC87312) += pc87312.o | ||||||
|   | |||||||
| @@ -749,13 +749,13 @@ static void ivshmem_reset(DeviceState *d) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static int ivshmem_setup_interrupts(IVShmemState *s) | static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp) | ||||||
| { | { | ||||||
|     /* allocate QEMU callback data for receiving interrupts */ |     /* allocate QEMU callback data for receiving interrupts */ | ||||||
|     s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector)); |     s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector)); | ||||||
|  |  | ||||||
|     if (ivshmem_has_feature(s, IVSHMEM_MSI)) { |     if (ivshmem_has_feature(s, IVSHMEM_MSI)) { | ||||||
|         if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) { |         if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1, errp)) { | ||||||
|             return -1; |             return -1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -898,8 +898,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) | |||||||
|         qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive, |         qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive, | ||||||
|                                  ivshmem_read, NULL, s, NULL, true); |                                  ivshmem_read, NULL, s, NULL, true); | ||||||
|  |  | ||||||
|         if (ivshmem_setup_interrupts(s) < 0) { |         if (ivshmem_setup_interrupts(s, errp) < 0) { | ||||||
|             error_setg(errp, "failed to initialize interrupts"); |             error_prepend(errp, "Failed to initialize interrupts: "); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -292,7 +292,7 @@ e1000e_init_msix(E1000EState *s) | |||||||
|                         E1000E_MSIX_IDX, E1000E_MSIX_TABLE, |                         E1000E_MSIX_IDX, E1000E_MSIX_TABLE, | ||||||
|                         &s->msix, |                         &s->msix, | ||||||
|                         E1000E_MSIX_IDX, E1000E_MSIX_PBA, |                         E1000E_MSIX_IDX, E1000E_MSIX_PBA, | ||||||
|                         0xA0); |                         0xA0, NULL); | ||||||
|  |  | ||||||
|     if (res < 0) { |     if (res < 0) { | ||||||
|         trace_e1000e_msix_init_fail(res); |         trace_e1000e_msix_init_fail(res); | ||||||
|   | |||||||
| @@ -29,7 +29,6 @@ | |||||||
| #include "qemu/osdep.h" | #include "qemu/osdep.h" | ||||||
| #include "sysemu/sysemu.h" | #include "sysemu/sysemu.h" | ||||||
| #include "hw/sysbus.h" | #include "hw/sysbus.h" | ||||||
| #include "trace.h" |  | ||||||
| #include "hw/ptimer.h" | #include "hw/ptimer.h" | ||||||
| #include "etsec.h" | #include "etsec.h" | ||||||
| #include "registers.h" | #include "registers.h" | ||||||
|   | |||||||
| @@ -1256,14 +1256,16 @@ static int rocker_msix_init(Rocker *r) | |||||||
| { | { | ||||||
|     PCIDevice *dev = PCI_DEVICE(r); |     PCIDevice *dev = PCI_DEVICE(r); | ||||||
|     int err; |     int err; | ||||||
|  |     Error *local_err = NULL; | ||||||
|  |  | ||||||
|     err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports), |     err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports), | ||||||
|                     &r->msix_bar, |                     &r->msix_bar, | ||||||
|                     ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET, |                     ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET, | ||||||
|                     &r->msix_bar, |                     &r->msix_bar, | ||||||
|                     ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET, |                     ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET, | ||||||
|                     0); |                     0, &local_err); | ||||||
|     if (err) { |     if (err) { | ||||||
|  |         error_report_err(local_err); | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -63,10 +63,6 @@ net_rx_pkt_l4_csum_validate_entry(void) "Starting L4 checksum validation" | |||||||
| net_rx_pkt_l4_csum_validate_not_xxp(void) "Not a TCP/UDP packet" | net_rx_pkt_l4_csum_validate_not_xxp(void) "Not a TCP/UDP packet" | ||||||
| net_rx_pkt_l4_csum_validate_udp_with_no_checksum(void) "UDP packet without checksum" | net_rx_pkt_l4_csum_validate_udp_with_no_checksum(void) "UDP packet without checksum" | ||||||
| net_rx_pkt_l4_csum_validate_ip4_fragment(void) "IP4 fragment" | net_rx_pkt_l4_csum_validate_ip4_fragment(void) "IP4 fragment" | ||||||
| net_rx_pkt_l4_csum_validate_ip4_udp(void) "IP4/UDP packet" |  | ||||||
| net_rx_pkt_l4_csum_validate_ip4_tcp(void) "IP4/TCP packet" |  | ||||||
| net_rx_pkt_l4_csum_validate_ip6_udp(void) "IP6/UDP packet" |  | ||||||
| net_rx_pkt_l4_csum_validate_ip6_tcp(void) "IP6/TCP packet" |  | ||||||
| net_rx_pkt_l4_csum_validate_csum(bool csum_valid) "Checksum valid: %d" | net_rx_pkt_l4_csum_validate_csum(bool csum_valid) "Checksum valid: %d" | ||||||
|  |  | ||||||
| net_rx_pkt_l4_csum_calc_entry(void) "Starting L4 checksum calculation" | net_rx_pkt_l4_csum_calc_entry(void) "Starting L4 checksum calculation" | ||||||
| @@ -117,7 +113,6 @@ e1000e_core_mdic_read(uint8_t page, uint32_t addr, uint32_t data) "MDIC READ: PH | |||||||
| e1000e_core_mdic_read_unhandled(uint8_t page, uint32_t addr) "MDIC READ: PHY[%u][%u] UNHANDLED" | e1000e_core_mdic_read_unhandled(uint8_t page, uint32_t addr) "MDIC READ: PHY[%u][%u] UNHANDLED" | ||||||
| e1000e_core_mdic_write(uint8_t page, uint32_t addr, uint32_t data) "MDIC WRITE: PHY[%u][%u] = 0x%x" | e1000e_core_mdic_write(uint8_t page, uint32_t addr, uint32_t data) "MDIC WRITE: PHY[%u][%u] = 0x%x" | ||||||
| e1000e_core_mdic_write_unhandled(uint8_t page, uint32_t addr) "MDIC WRITE: PHY[%u][%u] UNHANDLED" | e1000e_core_mdic_write_unhandled(uint8_t page, uint32_t addr) "MDIC WRITE: PHY[%u][%u] UNHANDLED" | ||||||
| e1000e_core_eeeprom_write(uint16_t bit_in, uint16_t bit_out, uint16_t reading) "eeprom bitnum in %d out %d, reading %d" |  | ||||||
| e1000e_core_ctrl_write(uint64_t index, uint32_t val) "Write CTRL register 0x%"PRIx64", value: 0x%X" | e1000e_core_ctrl_write(uint64_t index, uint32_t val) "Write CTRL register 0x%"PRIx64", value: 0x%X" | ||||||
| e1000e_core_ctrl_sw_reset(void) "Doing SW reset" | e1000e_core_ctrl_sw_reset(void) "Doing SW reset" | ||||||
| e1000e_core_ctrl_phy_reset(void) "Doing PHY reset" | e1000e_core_ctrl_phy_reset(void) "Doing PHY reset" | ||||||
| @@ -159,7 +154,6 @@ e1000e_rx_desc_buff_write(uint8_t idx, uint64_t addr, uint16_t offset, const voi | |||||||
| e1000e_rx_descr(int ridx, uint64_t base, uint8_t len) "Next RX descriptor: ring #%d, PA: 0x%"PRIx64", length: %u" | e1000e_rx_descr(int ridx, uint64_t base, uint8_t len) "Next RX descriptor: ring #%d, PA: 0x%"PRIx64", length: %u" | ||||||
| e1000e_rx_set_rctl(uint32_t rctl) "RCTL = 0x%x" | e1000e_rx_set_rctl(uint32_t rctl) "RCTL = 0x%x" | ||||||
| e1000e_rx_receive_iov(int iovcnt) "Received vector of %d fragments" | e1000e_rx_receive_iov(int iovcnt) "Received vector of %d fragments" | ||||||
| e1000e_rx_packet_size(size_t full, size_t vhdr, size_t data) "Received packet of %zu bytes total, %zu virt header, %zu data" |  | ||||||
| e1000e_rx_flt_dropped(void) "Received packet dropped by RX filter" | e1000e_rx_flt_dropped(void) "Received packet dropped by RX filter" | ||||||
| e1000e_rx_written_to_guest(uint32_t causes) "Received packet written to guest (ICR causes %u)" | e1000e_rx_written_to_guest(uint32_t causes) "Received packet written to guest (ICR causes %u)" | ||||||
| e1000e_rx_not_written_to_guest(uint32_t causes) "Received packet NOT written to guest (ICR causes %u)" | e1000e_rx_not_written_to_guest(uint32_t causes) "Received packet NOT written to guest (ICR causes %u)" | ||||||
| @@ -196,14 +190,12 @@ e1000e_rx_metadata_ipv6_filtering_disabled(void) "IPv6 RX filtering disabled by | |||||||
|  |  | ||||||
| e1000e_vlan_vet(uint16_t vet) "Setting VLAN ethernet type 0x%X" | e1000e_vlan_vet(uint16_t vet) "Setting VLAN ethernet type 0x%X" | ||||||
|  |  | ||||||
| e1000e_irq_set_cause(uint32_t cause) "IRQ cause set 0x%x" |  | ||||||
| e1000e_irq_msi_notify(uint32_t cause) "MSI notify 0x%x" | e1000e_irq_msi_notify(uint32_t cause) "MSI notify 0x%x" | ||||||
| e1000e_irq_throttling_no_pending_interrupts(void) "No pending interrupts to notify" | e1000e_irq_throttling_no_pending_interrupts(void) "No pending interrupts to notify" | ||||||
| e1000e_irq_msi_notify_postponed(void) "Sending MSI postponed by ITR" | e1000e_irq_msi_notify_postponed(void) "Sending MSI postponed by ITR" | ||||||
| e1000e_irq_legacy_notify_postponed(void) "Raising legacy IRQ postponed by ITR" | e1000e_irq_legacy_notify_postponed(void) "Raising legacy IRQ postponed by ITR" | ||||||
| e1000e_irq_throttling_no_pending_vec(int idx) "No pending interrupts for vector %d" | e1000e_irq_throttling_no_pending_vec(int idx) "No pending interrupts for vector %d" | ||||||
| e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%d]" | e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%d]" | ||||||
| e1000e_irq_msix_notify(uint32_t cause) "MSI-X notify 0x%x" |  | ||||||
| e1000e_irq_legacy_notify(bool level) "IRQ line state: %d" | e1000e_irq_legacy_notify(bool level) "IRQ line state: %d" | ||||||
| e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x" | e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x" | ||||||
| e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x" | e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x" | ||||||
|   | |||||||
| @@ -2191,7 +2191,7 @@ vmxnet3_init_msix(VMXNET3State *s) | |||||||
|                         VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE, |                         VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE, | ||||||
|                         &s->msix_bar, |                         &s->msix_bar, | ||||||
|                         VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s), |                         VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s), | ||||||
|                         VMXNET3_MSIX_OFFSET(s)); |                         VMXNET3_MSIX_OFFSET(s), NULL); | ||||||
|  |  | ||||||
|     if (0 > res) { |     if (0 > res) { | ||||||
|         VMW_WRPRN("Failed to initialize MSI-X, error %d", res); |         VMW_WRPRN("Failed to initialize MSI-X, error %d", res); | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| common-obj-y += pci_bridge_dev.o | common-obj-y += pci_bridge_dev.o | ||||||
| common-obj-y += pci_expander_bridge.o | common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o | ||||||
|  | common-obj-$(CONFIG_PXB) += pci_expander_bridge.o | ||||||
| common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o | common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o | ||||||
| common-obj-$(CONFIG_IOH3420) += ioh3420.o | common-obj-$(CONFIG_IOH3420) += ioh3420.o | ||||||
| common-obj-$(CONFIG_I82801B11) += i82801b11.o | common-obj-$(CONFIG_I82801B11) += i82801b11.o | ||||||
|   | |||||||
							
								
								
									
										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; |     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; |     int rc; | ||||||
|     Error *err = NULL; |     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, IOH_EP_SSVID_OFFSET, |  | ||||||
|                                IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID); |  | ||||||
|     if (rc < 0) { |  | ||||||
|         goto err_bridge; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR, |     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_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) { |     if (rc < 0) { | ||||||
|         assert(rc == -ENOTSUP); |         assert(rc == -ENOTSUP); | ||||||
|         error_report_err(err); |         error_propagate(errp, local_err); | ||||||
|         goto err_bridge; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     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; |     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); |     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 = { | static const VMStateDescription vmstate_ioh3420 = { | ||||||
|     .name = "ioh-3240-express-root-port", |     .name = "ioh-3240-express-root-port", | ||||||
|     .version_id = 1, |     .version_id = 1, | ||||||
| @@ -191,25 +100,25 @@ static void ioh3420_class_init(ObjectClass *klass, void *data) | |||||||
| { | { | ||||||
|     DeviceClass *dc = DEVICE_CLASS(klass); |     DeviceClass *dc = DEVICE_CLASS(klass); | ||||||
|     PCIDeviceClass *k = PCI_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->vendor_id = PCI_VENDOR_ID_INTEL; | ||||||
|     k->device_id = PCI_DEVICE_ID_IOH_EPORT; |     k->device_id = PCI_DEVICE_ID_IOH_EPORT; | ||||||
|     k->revision = PCI_DEVICE_ID_IOH_REV; |     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->desc = "Intel IOH device id 3420 PCIE Root Port"; | ||||||
|     dc->reset = ioh3420_reset; |  | ||||||
|     dc->vmsd = &vmstate_ioh3420; |     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 = { | static const TypeInfo ioh3420_info = { | ||||||
|     .name          = "ioh3420", |     .name          = "ioh3420", | ||||||
|     .parent        = TYPE_PCIE_SLOT, |     .parent        = TYPE_PCIE_ROOT_PORT, | ||||||
|     .class_init    = ioh3420_class_init, |     .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, |     DEFINE_PROP_ON_OFF_AUTO(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, msi, | ||||||
|                             ON_OFF_AUTO_AUTO), |                             ON_OFF_AUTO_AUTO), | ||||||
|     DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags, |     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(), |     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/pci/pci.h" | ||||||
| #include "hw/xen/xen.h" | #include "hw/xen/xen.h" | ||||||
| #include "qemu/range.h" | #include "qemu/range.h" | ||||||
|  | #include "qapi/error.h" | ||||||
|  |  | ||||||
| #define MSIX_CAP_LENGTH 12 | #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, | int msix_init(struct PCIDevice *dev, unsigned short nentries, | ||||||
|               MemoryRegion *table_bar, uint8_t table_bar_nr, |               MemoryRegion *table_bar, uint8_t table_bar_nr, | ||||||
|               unsigned table_offset, MemoryRegion *pba_bar, |               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; |     int cap; | ||||||
|     unsigned table_size, pba_size; |     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 */ |     /* Nothing to do if MSI is not supported by interrupt controller */ | ||||||
|     if (!msi_nonbroken) { |     if (!msi_nonbroken) { | ||||||
|  |         error_setg(errp, "MSI-X is not supported by interrupt controller"); | ||||||
|         return -ENOTSUP; |         return -ENOTSUP; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) { |     if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) { | ||||||
|  |         error_setg(errp, "The number of MSI-X vectors is invalid"); | ||||||
|         return -EINVAL; |         return -EINVAL; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -266,10 +289,13 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, | |||||||
|         table_offset + table_size > memory_region_size(table_bar) || |         table_offset + table_size > memory_region_size(table_bar) || | ||||||
|         pba_offset + pba_size > memory_region_size(pba_bar) || |         pba_offset + pba_size > memory_region_size(pba_bar) || | ||||||
|         (table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) { |         (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; |         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) { |     if (cap < 0) { | ||||||
|         return cap; |         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, | int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, | ||||||
|                             uint8_t bar_nr) |                             uint8_t bar_nr, Error **errp) | ||||||
| { | { | ||||||
|     int ret; |     int ret; | ||||||
|     char *name; |     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, |     ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, | ||||||
|                     0, &dev->msix_exclusive_bar, |                     0, &dev->msix_exclusive_bar, | ||||||
|                     bar_nr, bar_pba_offset, |                     bar_nr, bar_pba_offset, | ||||||
|                     0); |                     0, errp); | ||||||
|     if (ret) { |     if (ret) { | ||||||
|         return ret; |         return ret; | ||||||
|     } |     } | ||||||
| @@ -447,8 +473,10 @@ void msix_notify(PCIDevice *dev, unsigned vector) | |||||||
| { | { | ||||||
|     MSIMessage msg; |     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; |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (msix_is_masked(dev, vector)) { |     if (msix_is_masked(dev, vector)) { | ||||||
|         msix_set_pending(dev, vector); |         msix_set_pending(dev, vector); | ||||||
|         return; |         return; | ||||||
| @@ -483,8 +511,10 @@ void msix_reset(PCIDevice *dev) | |||||||
| /* Mark vector as used. */ | /* Mark vector as used. */ | ||||||
| int msix_vector_use(PCIDevice *dev, unsigned vector) | int msix_vector_use(PCIDevice *dev, unsigned vector) | ||||||
| { | { | ||||||
|     if (vector >= dev->msix_entries_nr) |     if (vector >= dev->msix_entries_nr) { | ||||||
|         return -EINVAL; |         return -EINVAL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     dev->msix_entry_used[vector]++; |     dev->msix_entry_used[vector]++; | ||||||
|     return 0; |     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))); |         snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); | ||||||
|     } |     } | ||||||
|     pdev->has_rom = true; |     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); |     vmstate_register_ram(&pdev->rom, &pdev->qdev); | ||||||
|     ptr = memory_region_get_ram_ptr(&pdev->rom); |     ptr = memory_region_get_ram_ptr(&pdev->rom); | ||||||
|     load_image(path, ptr); |     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 | obj-y += ppc4xx_pci.o | ||||||
| # PReP | # PReP | ||||||
| obj-$(CONFIG_PREP) += prep.o | obj-$(CONFIG_PREP) += prep.o | ||||||
|  | obj-$(CONFIG_PREP) += prep_systemio.o | ||||||
|  | obj-${CONFIG_RS6000_MC} += rs6000_mc.o | ||||||
| # OldWorld PowerMac | # OldWorld PowerMac | ||||||
| obj-$(CONFIG_MAC) += mac_oldworld.o | obj-$(CONFIG_MAC) += mac_oldworld.o | ||||||
| # NewWorld PowerMac | # NewWorld PowerMac | ||||||
|   | |||||||
| @@ -827,6 +827,12 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) | |||||||
|         env = &cpu->env; |         env = &cpu->env; | ||||||
|         cs = CPU(cpu); |         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) { |         if (!firstenv) { | ||||||
|             firstenv = env; |             firstenv = env; | ||||||
|         } |         } | ||||||
| @@ -1049,27 +1055,18 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) | |||||||
|     boot_info->dt_size = dt_size; |     boot_info->dt_size = dt_size; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int e500_ccsr_initfn(SysBusDevice *dev) | static void e500_ccsr_initfn(Object *obj) | ||||||
| { | { | ||||||
|     PPCE500CCSRState *ccsr; |     PPCE500CCSRState *ccsr = CCSR(obj); | ||||||
|  |     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr", | ||||||
|     ccsr = CCSR(dev); |  | ||||||
|     memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr", |  | ||||||
|                        MPC8544_CCSRBAR_SIZE); |                        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 = { | static const TypeInfo e500_ccsr_info = { | ||||||
|     .name          = TYPE_CCSR, |     .name          = TYPE_CCSR, | ||||||
|     .parent        = TYPE_SYS_BUS_DEVICE, |     .parent        = TYPE_SYS_BUS_DEVICE, | ||||||
|     .instance_size = sizeof(PPCE500CCSRState), |     .instance_size = sizeof(PPCE500CCSRState), | ||||||
|     .class_init    = e500_ccsr_class_init, |     .instance_init = e500_ccsr_initfn, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void e500_register_types(void) | 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); |     fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE); | ||||||
|     if (fw_size < 0) { |     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); |         exit(1); | ||||||
|     } |     } | ||||||
|     g_free(fw_filename); |     g_free(fw_filename); | ||||||
| @@ -393,7 +393,7 @@ static void ppc_powernv_init(MachineState *machine) | |||||||
|         kernel_size = load_image_targphys(machine->kernel_filename, |         kernel_size = load_image_targphys(machine->kernel_filename, | ||||||
|                                           KERNEL_LOAD_ADDR, 0x2000000); |                                           KERNEL_LOAD_ADDR, 0x2000000); | ||||||
|         if (kernel_size < 0) { |         if (kernel_size < 0) { | ||||||
|             hw_error("qemu: could not load kernel'%s'\n", |             error_report("qemu: could not load kernel'%s'", | ||||||
|                          machine->kernel_filename); |                          machine->kernel_filename); | ||||||
|             exit(1); |             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); |     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(); |     uint64_t ticks = cpu_get_host_ticks(); | ||||||
|     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); |     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); | ||||||
|  |  | ||||||
| @@ -858,43 +857,30 @@ static void timebase_pre_save(void *opaque) | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /* not used anymore, we keep it for compatibility */ | ||||||
|     tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); |     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 |      * there is no need to update it from KVM here | ||||||
|      */ |      */ | ||||||
|     tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset; |     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; |     CPUState *cpu; | ||||||
|     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); |     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); | ||||||
|     int64_t tb_off_adj, tb_off, ns_diff; |     int64_t tb_off_adj, tb_off; | ||||||
|     int64_t migration_duration_ns, migration_duration_tb, guest_tb, host_ns; |  | ||||||
|     unsigned long freq; |     unsigned long freq; | ||||||
|  |  | ||||||
|     if (!first_ppc_cpu->env.tb_env) { |     if (!first_ppc_cpu->env.tb_env) { | ||||||
|         error_report("No timebase object"); |         error_report("No timebase object"); | ||||||
|         return -1; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     freq = first_ppc_cpu->env.tb_env->tb_freq; |     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; |     tb_off = first_ppc_cpu->env.tb_env->tb_offset; | ||||||
|     trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off, |     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) { |     CPU_FOREACH(cpu) { | ||||||
|         PowerPCCPU *pcpu = POWERPC_CPU(cpu); |         PowerPCCPU *pcpu = POWERPC_CPU(cpu); | ||||||
|         pcpu->env.tb_env->tb_offset = tb_off_adj; |         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 = { | const VMStateDescription vmstate_ppc_timebase = { | ||||||
| @@ -915,7 +936,6 @@ const VMStateDescription vmstate_ppc_timebase = { | |||||||
|     .minimum_version_id = 1, |     .minimum_version_id = 1, | ||||||
|     .minimum_version_id_old = 1, |     .minimum_version_id_old = 1, | ||||||
|     .pre_save = timebase_pre_save, |     .pre_save = timebase_pre_save, | ||||||
|     .post_load = timebase_post_load, |  | ||||||
|     .fields      = (VMStateField []) { |     .fields      = (VMStateField []) { | ||||||
|         VMSTATE_UINT64(guest_timebase, PPCTimebase), |         VMSTATE_UINT64(guest_timebase, PPCTimebase), | ||||||
|         VMSTATE_INT64(time_of_the_day_ns, 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 */ | /* 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) | void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value) | ||||||
| { | { | ||||||
|     _cpu_ppc_store_tbu(env, 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