Four changes here. Polling for reconnection of character devices,
the QOMification of accelerators, a fix for -kernel support on x86, and one for a recently-introduced virtio-scsi optimization. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQEcBAABAgAGBQJUNo9yAAoJEBRUblpOawnXQDkH/1M5DxmVwUv+SZtHEdpsT7Eq UGjRzfYXsYP/WkEqxVzYJmN0HJn9z8uJZin/dqwDPQLjCy8gf/xuaNCfoZqMuxHw iNaTgKpi9Uy0G0VWxjlZpRu8f5JjqHbJEP6aTT0hooBHaqQoBSm1fQh/pnCUvnpB qDQeHcOjrzIMkQJ3Ji8z2s+CapHaiIa63hJqRJztS5vbonPjngjj87dA54eIqDtQ RwXy58y+C8YMKqfpOG6lA+RxogESyyCfDBVUA1wwRDad1mOFKUMtEd4jAL39HUgR qINSKybG12V2bx8E+vNbaKB+68+NLdxcyR39JR2aun+a8yw+yDcF5BBiMXlqV0U= =4bqy -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging Four changes here. Polling for reconnection of character devices, the QOMification of accelerators, a fix for -kernel support on x86, and one for a recently-introduced virtio-scsi optimization. # gpg: Signature made Thu 09 Oct 2014 14:36:50 BST using RSA key ID 4E6B09D7 # gpg: Good signature from "Paolo Bonzini <pbonzini@redhat.com>" # gpg: aka "Paolo Bonzini <bonzini@gnu.org>" * remotes/bonzini/tags/for-upstream: (28 commits) qemu-char: Fix reconnect socket error reporting qemu-sockets: Add error to non-blocking connect handler qemu-error: Add error_vreport() virtio-scsi: fix use-after-free of VirtIOSCSIReq linuxboot: compute initrd loading address kvm: Make KVMState be the TYPE_KVM_ACCEL instance struct accel: Create accel object when initializing machine accel: Pass MachineState object to accel init functions accel: Rename 'init' method to 'init_machine' accel: Move accel init/allowed code to separate function accel: Remove tcg_available() function accel: Move qtest accel registration to qtest.c accel: Move Xen registration code to xen-common.c accel: Move KVM accel registration to kvm-all.c accel: Report unknown accelerator as "not found" instead of "does not exist" accel: Make AccelClass.available() optional accel: Use QOM classes for accel types accel: Move accel name lookup to separate function accel: Simplify configure_accelerator() using AccelType *acc variable accel: Create AccelType typedef ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						fcb2cd928f
					
				| @ -62,6 +62,7 @@ common-obj-$(CONFIG_SPICE) += spice-qemu-char.o | ||||
| 
 | ||||
| common-obj-y += audio/ | ||||
| common-obj-y += hw/ | ||||
| common-obj-y += accel.o | ||||
| 
 | ||||
| common-obj-y += ui/ | ||||
| common-obj-y += bt-host.o bt-vhci.o | ||||
|  | ||||
							
								
								
									
										157
									
								
								accel.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								accel.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,157 @@ | ||||
| /*
 | ||||
|  * QEMU System Emulator, accelerator interfaces | ||||
|  * | ||||
|  * Copyright (c) 2003-2008 Fabrice Bellard | ||||
|  * Copyright (c) 2014 Red Hat Inc. | ||||
|  * | ||||
|  * 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 "sysemu/accel.h" | ||||
| #include "hw/boards.h" | ||||
| #include "qemu-common.h" | ||||
| #include "sysemu/arch_init.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "sysemu/kvm.h" | ||||
| #include "sysemu/qtest.h" | ||||
| #include "hw/xen/xen.h" | ||||
| #include "qom/object.h" | ||||
| #include "hw/boards.h" | ||||
| 
 | ||||
| int tcg_tb_size; | ||||
| static bool tcg_allowed = true; | ||||
| 
 | ||||
| static int tcg_init(MachineState *ms) | ||||
| { | ||||
|     tcg_exec_init(tcg_tb_size * 1024 * 1024); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static const TypeInfo accel_type = { | ||||
|     .name = TYPE_ACCEL, | ||||
|     .parent = TYPE_OBJECT, | ||||
|     .class_size = sizeof(AccelClass), | ||||
|     .instance_size = sizeof(AccelState), | ||||
| }; | ||||
| 
 | ||||
| /* Lookup AccelClass from opt_name. Returns NULL if not found */ | ||||
| static AccelClass *accel_find(const char *opt_name) | ||||
| { | ||||
|     char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name); | ||||
|     AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name)); | ||||
|     g_free(class_name); | ||||
|     return ac; | ||||
| } | ||||
| 
 | ||||
| static int accel_init_machine(AccelClass *acc, MachineState *ms) | ||||
| { | ||||
|     ObjectClass *oc = OBJECT_CLASS(acc); | ||||
|     const char *cname = object_class_get_name(oc); | ||||
|     AccelState *accel = ACCEL(object_new(cname)); | ||||
|     int ret; | ||||
|     ms->accelerator = accel; | ||||
|     *(acc->allowed) = true; | ||||
|     ret = acc->init_machine(ms); | ||||
|     if (ret < 0) { | ||||
|         ms->accelerator = NULL; | ||||
|         *(acc->allowed) = false; | ||||
|         object_unref(OBJECT(accel)); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| int configure_accelerator(MachineState *ms) | ||||
| { | ||||
|     const char *p; | ||||
|     char buf[10]; | ||||
|     int ret; | ||||
|     bool accel_initialised = false; | ||||
|     bool init_failed = false; | ||||
|     AccelClass *acc = NULL; | ||||
| 
 | ||||
|     p = qemu_opt_get(qemu_get_machine_opts(), "accel"); | ||||
|     if (p == NULL) { | ||||
|         /* Use the default "accelerator", tcg */ | ||||
|         p = "tcg"; | ||||
|     } | ||||
| 
 | ||||
|     while (!accel_initialised && *p != '\0') { | ||||
|         if (*p == ':') { | ||||
|             p++; | ||||
|         } | ||||
|         p = get_opt_name(buf, sizeof(buf), p, ':'); | ||||
|         acc = accel_find(buf); | ||||
|         if (!acc) { | ||||
|             fprintf(stderr, "\"%s\" accelerator not found.\n", buf); | ||||
|             continue; | ||||
|         } | ||||
|         if (acc->available && !acc->available()) { | ||||
|             printf("%s not supported for this target\n", | ||||
|                    acc->name); | ||||
|             continue; | ||||
|         } | ||||
|         ret = accel_init_machine(acc, ms); | ||||
|         if (ret < 0) { | ||||
|             init_failed = true; | ||||
|             fprintf(stderr, "failed to initialize %s: %s\n", | ||||
|                     acc->name, | ||||
|                     strerror(-ret)); | ||||
|         } else { | ||||
|             accel_initialised = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!accel_initialised) { | ||||
|         if (!init_failed) { | ||||
|             fprintf(stderr, "No accelerator found!\n"); | ||||
|         } | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     if (init_failed) { | ||||
|         fprintf(stderr, "Back to %s accelerator.\n", acc->name); | ||||
|     } | ||||
| 
 | ||||
|     return !accel_initialised; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void tcg_accel_class_init(ObjectClass *oc, void *data) | ||||
| { | ||||
|     AccelClass *ac = ACCEL_CLASS(oc); | ||||
|     ac->name = "tcg"; | ||||
|     ac->init_machine = tcg_init; | ||||
|     ac->allowed = &tcg_allowed; | ||||
| } | ||||
| 
 | ||||
| #define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg") | ||||
| 
 | ||||
| static const TypeInfo tcg_accel_type = { | ||||
|     .name = TYPE_TCG_ACCEL, | ||||
|     .parent = TYPE_ACCEL, | ||||
|     .class_init = tcg_accel_class_init, | ||||
| }; | ||||
| 
 | ||||
| static void register_accel_types(void) | ||||
| { | ||||
|     type_register_static(&accel_type); | ||||
|     type_register_static(&tcg_accel_type); | ||||
| } | ||||
| 
 | ||||
| type_init(register_accel_types); | ||||
| @ -1337,11 +1337,6 @@ void cpudef_init(void) | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| int tcg_available(void) | ||||
| { | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| int kvm_available(void) | ||||
| { | ||||
| #ifdef CONFIG_KVM | ||||
|  | ||||
| @ -545,11 +545,12 @@ bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||||
| 
 | ||||
| void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||||
| { | ||||
|     if (scsi_req_enqueue(req->sreq)) { | ||||
|         scsi_req_continue(req->sreq); | ||||
|     SCSIRequest *sreq = req->sreq; | ||||
|     if (scsi_req_enqueue(sreq)) { | ||||
|         scsi_req_continue(sreq); | ||||
|     } | ||||
|     bdrv_io_unplug(req->sreq->dev->conf.bs); | ||||
|     scsi_req_unref(req->sreq); | ||||
|     bdrv_io_unplug(sreq->dev->conf.bs); | ||||
|     scsi_req_unref(sreq); | ||||
| } | ||||
| 
 | ||||
| static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) | ||||
|  | ||||
| @ -5,12 +5,11 @@ | ||||
| 
 | ||||
| #include "qemu/typedefs.h" | ||||
| #include "sysemu/blockdev.h" | ||||
| #include "sysemu/accel.h" | ||||
| #include "hw/qdev.h" | ||||
| #include "qom/object.h" | ||||
| 
 | ||||
| 
 | ||||
| typedef struct MachineState MachineState; | ||||
| 
 | ||||
| typedef void QEMUMachineInitFunc(MachineState *ms); | ||||
| 
 | ||||
| typedef void QEMUMachineResetFunc(void); | ||||
| @ -135,6 +134,7 @@ struct MachineState { | ||||
|     char *kernel_cmdline; | ||||
|     char *initrd_filename; | ||||
|     const char *cpu_model; | ||||
|     AccelState *accelerator; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -36,7 +36,6 @@ void xen_cmos_set_s3_resume(void *opaque, int irq, int level); | ||||
| 
 | ||||
| qemu_irq *xen_interrupt_controller_init(void); | ||||
| 
 | ||||
| int xen_init(MachineClass *mc); | ||||
| void xenstore_store_pv_console_info(int i, struct CharDriverState *chr); | ||||
| 
 | ||||
| #if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY) | ||||
|  | ||||
| @ -38,6 +38,7 @@ void error_vprintf(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0); | ||||
| void error_printf(const char *fmt, ...) GCC_FMT_ATTR(1, 2); | ||||
| void error_printf_unless_qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2); | ||||
| void error_set_progname(const char *argv0); | ||||
| void error_vreport(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0); | ||||
| void error_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2); | ||||
| const char *error_get_progname(void); | ||||
| extern bool enable_timestamp_msg; | ||||
|  | ||||
| @ -47,7 +47,7 @@ int recv_all(int fd, void *buf, int len1, bool single_read); | ||||
| /* callback function for nonblocking connect
 | ||||
|  * valid fd on success, negative error code on failure | ||||
|  */ | ||||
| typedef void NonBlockingConnectHandler(int fd, void *opaque); | ||||
| typedef void NonBlockingConnectHandler(int fd, Error *errp, void *opaque); | ||||
| 
 | ||||
| InetSocketAddress *inet_parse(const char *str, Error **errp); | ||||
| int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); | ||||
|  | ||||
| @ -32,6 +32,7 @@ typedef struct MemoryMappingList MemoryMappingList; | ||||
| 
 | ||||
| typedef struct QEMUMachine QEMUMachine; | ||||
| typedef struct MachineClass MachineClass; | ||||
| typedef struct MachineState MachineState; | ||||
| typedef struct NICInfo NICInfo; | ||||
| typedef struct HCIInfo HCIInfo; | ||||
| typedef struct AudioState AudioState; | ||||
|  | ||||
							
								
								
									
										62
									
								
								include/sysemu/accel.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								include/sysemu/accel.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | ||||
| /* QEMU accelerator interfaces
 | ||||
|  * | ||||
|  * Copyright (c) 2014 Red Hat Inc | ||||
|  * | ||||
|  * 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 HW_ACCEL_H | ||||
| #define HW_ACCEL_H | ||||
| 
 | ||||
| #include "qemu/typedefs.h" | ||||
| #include "qom/object.h" | ||||
| 
 | ||||
| typedef struct AccelState { | ||||
|     /*< private >*/ | ||||
|     Object parent_obj; | ||||
| } AccelState; | ||||
| 
 | ||||
| typedef struct AccelClass { | ||||
|     /*< private >*/ | ||||
|     ObjectClass parent_class; | ||||
|     /*< public >*/ | ||||
| 
 | ||||
|     const char *opt_name; | ||||
|     const char *name; | ||||
|     int (*available)(void); | ||||
|     int (*init_machine)(MachineState *ms); | ||||
|     bool *allowed; | ||||
| } AccelClass; | ||||
| 
 | ||||
| #define TYPE_ACCEL "accel" | ||||
| 
 | ||||
| #define ACCEL_CLASS_SUFFIX  "-" TYPE_ACCEL | ||||
| #define ACCEL_CLASS_NAME(a) (a ACCEL_CLASS_SUFFIX) | ||||
| 
 | ||||
| #define ACCEL_CLASS(klass) \ | ||||
|     OBJECT_CLASS_CHECK(AccelClass, (klass), TYPE_ACCEL) | ||||
| #define ACCEL(obj) \ | ||||
|     OBJECT_CHECK(AccelState, (obj), TYPE_ACCEL) | ||||
| #define ACCEL_GET_CLASS(obj) \ | ||||
|     OBJECT_GET_CLASS(AccelClass, (obj), TYPE_ACCEL) | ||||
| 
 | ||||
| extern int tcg_tb_size; | ||||
| 
 | ||||
| int configure_accelerator(MachineState *ms); | ||||
| 
 | ||||
| #endif | ||||
| @ -33,7 +33,6 @@ void do_smbios_option(QemuOpts *opts); | ||||
| void ram_mig_init(void); | ||||
| void cpudef_init(void); | ||||
| void audio_init(void); | ||||
| int tcg_available(void); | ||||
| int kvm_available(void); | ||||
| int xen_available(void); | ||||
| 
 | ||||
|  | ||||
| @ -163,8 +163,6 @@ extern KVMState *kvm_state; | ||||
| 
 | ||||
| /* external API */ | ||||
| 
 | ||||
| int kvm_init(MachineClass *mc); | ||||
| 
 | ||||
| int kvm_has_sync_mmu(void); | ||||
| int kvm_has_vcpu_events(void); | ||||
| int kvm_has_robust_singlestep(void); | ||||
|  | ||||
| @ -26,7 +26,6 @@ static inline bool qtest_enabled(void) | ||||
| 
 | ||||
| bool qtest_driver(void); | ||||
| 
 | ||||
| int qtest_init_accel(MachineClass *mc); | ||||
| void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp); | ||||
| 
 | ||||
| static inline int qtest_available(void) | ||||
|  | ||||
							
								
								
									
										40
									
								
								kvm-all.c
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								kvm-all.c
									
									
									
									
									
								
							| @ -25,6 +25,7 @@ | ||||
| #include "qemu/option.h" | ||||
| #include "qemu/config-file.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "sysemu/accel.h" | ||||
| #include "hw/hw.h" | ||||
| #include "hw/pci/msi.h" | ||||
| #include "hw/s390x/adapter.h" | ||||
| @ -70,8 +71,10 @@ typedef struct KVMSlot | ||||
| 
 | ||||
| typedef struct kvm_dirty_log KVMDirtyLog; | ||||
| 
 | ||||
| struct KVMState | ||||
| typedef struct KVMState | ||||
| { | ||||
|     AccelState parent_obj; | ||||
| 
 | ||||
|     KVMSlot *slots; | ||||
|     int nr_slots; | ||||
|     int fd; | ||||
| @ -104,7 +107,12 @@ struct KVMState | ||||
|     QTAILQ_HEAD(msi_hashtab, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE]; | ||||
|     bool direct_msi; | ||||
| #endif | ||||
| }; | ||||
| } KVMState; | ||||
| 
 | ||||
| #define TYPE_KVM_ACCEL ACCEL_CLASS_NAME("kvm") | ||||
| 
 | ||||
| #define KVM_STATE(obj) \ | ||||
|     OBJECT_CHECK(KVMState, (obj), TYPE_KVM_ACCEL) | ||||
| 
 | ||||
| KVMState *kvm_state; | ||||
| bool kvm_kernel_irqchip; | ||||
| @ -1377,8 +1385,9 @@ static int kvm_max_vcpus(KVMState *s) | ||||
|     return (ret) ? ret : kvm_recommended_vcpus(s); | ||||
| } | ||||
| 
 | ||||
| int kvm_init(MachineClass *mc) | ||||
| static int kvm_init(MachineState *ms) | ||||
| { | ||||
|     MachineClass *mc = MACHINE_GET_CLASS(ms); | ||||
|     static const char upgrade_note[] = | ||||
|         "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n" | ||||
|         "(see http://sourceforge.net/projects/kvm).\n"; | ||||
| @ -1397,7 +1406,7 @@ int kvm_init(MachineClass *mc) | ||||
|     int i, type = 0; | ||||
|     const char *kvm_type; | ||||
| 
 | ||||
|     s = g_malloc0(sizeof(KVMState)); | ||||
|     s = KVM_STATE(ms->accelerator); | ||||
| 
 | ||||
|     /*
 | ||||
|      * On systems where the kernel can support different base page | ||||
| @ -1586,7 +1595,6 @@ err: | ||||
|         close(s->fd); | ||||
|     } | ||||
|     g_free(s->slots); | ||||
|     g_free(s); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| @ -2225,3 +2233,25 @@ int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target) | ||||
|     } | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| static void kvm_accel_class_init(ObjectClass *oc, void *data) | ||||
| { | ||||
|     AccelClass *ac = ACCEL_CLASS(oc); | ||||
|     ac->name = "KVM"; | ||||
|     ac->init_machine = kvm_init; | ||||
|     ac->allowed = &kvm_allowed; | ||||
| } | ||||
| 
 | ||||
| static const TypeInfo kvm_accel_type = { | ||||
|     .name = TYPE_KVM_ACCEL, | ||||
|     .parent = TYPE_ACCEL, | ||||
|     .class_init = kvm_accel_class_init, | ||||
|     .instance_size = sizeof(KVMState), | ||||
| }; | ||||
| 
 | ||||
| static void kvm_type_init(void) | ||||
| { | ||||
|     type_register_static(&kvm_accel_type); | ||||
| } | ||||
| 
 | ||||
| type_init(kvm_type_init); | ||||
|  | ||||
| @ -35,11 +35,6 @@ int kvm_init_vcpu(CPUState *cpu) | ||||
|     return -ENOSYS; | ||||
| } | ||||
| 
 | ||||
| int kvm_init(MachineClass *mc) | ||||
| { | ||||
|     return -ENOSYS; | ||||
| } | ||||
| 
 | ||||
| void kvm_flush_coalesced_mmio_buffer(void) | ||||
| { | ||||
| } | ||||
|  | ||||
| @ -33,12 +33,12 @@ | ||||
|     do { } while (0) | ||||
| #endif | ||||
| 
 | ||||
| static void tcp_wait_for_connect(int fd, void *opaque) | ||||
| static void tcp_wait_for_connect(int fd, Error *err, void *opaque) | ||||
| { | ||||
|     MigrationState *s = opaque; | ||||
| 
 | ||||
|     if (fd < 0) { | ||||
|         DPRINTF("migrate connect error\n"); | ||||
|         DPRINTF("migrate connect error: %s\n", error_get_pretty(err)); | ||||
|         s->file = NULL; | ||||
|         migrate_fd_error(s); | ||||
|     } else { | ||||
|  | ||||
| @ -33,12 +33,12 @@ | ||||
|     do { } while (0) | ||||
| #endif | ||||
| 
 | ||||
| static void unix_wait_for_connect(int fd, void *opaque) | ||||
| static void unix_wait_for_connect(int fd, Error *err, void *opaque) | ||||
| { | ||||
|     MigrationState *s = opaque; | ||||
| 
 | ||||
|     if (fd < 0) { | ||||
|         DPRINTF("migrate connect error\n"); | ||||
|         DPRINTF("migrate connect error: %s\n", error_get_pretty(err)); | ||||
|         s->file = NULL; | ||||
|         migrate_fd_error(s); | ||||
|     } else { | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -76,14 +76,45 @@ boot_kernel: | ||||
| 
 | ||||
| 
 | ||||
| copy_kernel: | ||||
| 	/* Compute initrd address */ | ||||
| 	mov		$0xe801, %ax | ||||
| 	xor		%cx, %cx | ||||
| 	xor		%dx, %dx | ||||
| 	int		$0x15 | ||||
| 
 | ||||
| 	/* Output could be in AX/BX or CX/DX */ | ||||
| 	or		%cx, %cx | ||||
| 	jnz		1f | ||||
| 	or		%dx, %dx | ||||
| 	jnz		1f | ||||
| 	mov		%ax, %cx | ||||
| 	mov		%bx, %dx | ||||
| 1: | ||||
| 
 | ||||
| 	or		%dx, %dx | ||||
| 	jnz		2f | ||||
| 	addw		$1024, %cx            /* add 1 MB */ | ||||
| 	movzwl		%cx, %edi | ||||
| 	shll		$10, %edi             /* convert to bytes */ | ||||
| 	jmp		3f | ||||
| 
 | ||||
| 2: | ||||
| 	addw		$16777216 >> 16, %dx  /* add 16 MB */ | ||||
| 	movzwl		%dx, %edi | ||||
| 	shll		$16, %edi             /* convert to bytes */ | ||||
| 
 | ||||
| 3: | ||||
| 	read_fw         FW_CFG_INITRD_SIZE | ||||
| 	subl            %eax, %edi | ||||
| 	andl            $-4096, %edi          /* EDI = start of initrd */ | ||||
| 
 | ||||
| 	/* We need to load the kernel into memory we can't access in 16 bit | ||||
| 	   mode, so let's get into 32 bit mode, write the kernel and jump | ||||
| 	   back again. */ | ||||
| 
 | ||||
| 	/* Reserve space on the stack for our GDT descriptor. */ | ||||
| 	mov		%esp, %ebp | ||||
| 	sub		$16, %esp | ||||
| 	mov             %esp, %ebp | ||||
| 	sub             $16, %esp | ||||
| 
 | ||||
| 	/* Now create the GDT descriptor */ | ||||
| 	movw		$((3 * 8) - 1), -16(%bp) | ||||
| @ -108,10 +139,18 @@ copy_kernel: | ||||
| 	/* We're now running in 16-bit CS, but 32-bit ES! */ | ||||
| 
 | ||||
| 	/* Load kernel and initrd */ | ||||
| 	pushl		%edi | ||||
| 	read_fw_blob_addr32_edi(FW_CFG_INITRD) | ||||
| 	read_fw_blob_addr32(FW_CFG_KERNEL) | ||||
| 	read_fw_blob_addr32(FW_CFG_INITRD) | ||||
| 	read_fw_blob_addr32(FW_CFG_CMDLINE) | ||||
| 	read_fw_blob_addr32(FW_CFG_SETUP) | ||||
| 
 | ||||
| 	read_fw		FW_CFG_SETUP_ADDR | ||||
| 	mov		%eax, %edi | ||||
| 	mov		%eax, %ebx | ||||
| 	read_fw_blob_addr32_edi(FW_CFG_SETUP) | ||||
| 
 | ||||
| 	/* Update the header with the initrd address we chose above */ | ||||
| 	popl		%es:0x218(%ebx) | ||||
| 
 | ||||
| 	/* And now jump into Linux! */ | ||||
| 	mov		$0, %eax | ||||
|  | ||||
| @ -51,8 +51,6 @@ | ||||
| .endm | ||||
| 
 | ||||
| #define read_fw_blob_pre(var)				\ | ||||
| 	read_fw		var ## _ADDR;			\ | ||||
| 	mov		%eax, %edi;			\ | ||||
| 	read_fw		var ## _SIZE;			\ | ||||
| 	mov		%eax, %ecx;			\ | ||||
| 	mov		$var ## _DATA, %ax;		\ | ||||
| @ -68,6 +66,8 @@ | ||||
|  * Clobbers:	%eax, %edx, %es, %ecx, %edi | ||||
|  */ | ||||
| #define read_fw_blob(var)				\ | ||||
| 	read_fw		var ## _ADDR;			\ | ||||
| 	mov		%eax, %edi;			\ | ||||
| 	read_fw_blob_pre(var);				\ | ||||
| 	/* old as(1) doesn't like this insn so emit the bytes instead: \
 | ||||
| 	rep insb	(%dx), %es:(%edi);		\ | ||||
| @ -80,7 +80,22 @@ | ||||
|  * | ||||
|  * Clobbers:	%eax, %edx, %es, %ecx, %edi | ||||
|  */ | ||||
| #define read_fw_blob_addr32(var)				\ | ||||
| #define read_fw_blob_addr32(var)			\ | ||||
| 	read_fw		var ## _ADDR;			\ | ||||
| 	mov		%eax, %edi;			\ | ||||
| 	read_fw_blob_pre(var);				\ | ||||
| 	/* old as(1) doesn't like this insn so emit the bytes instead: \
 | ||||
| 	addr32 rep insb	(%dx), %es:(%edi);		\ | ||||
| 	*/						\ | ||||
| 	.dc.b		0x67,0xf3,0x6c | ||||
| 
 | ||||
| /*
 | ||||
|  * Read a blob from the fw_cfg device in forced addr32 mode, address is in %edi. | ||||
|  * Requires _SIZE and _DATA values for the parameter. | ||||
|  * | ||||
|  * Clobbers:	%eax, %edx, %edi, %es, %ecx | ||||
|  */ | ||||
| #define read_fw_blob_addr32_edi(var)			\ | ||||
| 	read_fw_blob_pre(var);				\ | ||||
| 	/* old as(1) doesn't like this insn so emit the bytes instead: \
 | ||||
| 	addr32 rep insb	(%dx), %es:(%edi);		\ | ||||
|  | ||||
| @ -2651,14 +2651,19 @@ | ||||
| # @nodelay: #optional set TCP_NODELAY socket option (default: false) | ||||
| # @telnet: #optional enable telnet protocol on server | ||||
| #          sockets (default: false) | ||||
| # @reconnect: #optional For a client socket, if a socket is disconnected, | ||||
| #          then attempt a reconnect after the given number of seconds. | ||||
| #          Setting this to zero disables this function. (default: 0) | ||||
| #          (Since: 2.2) | ||||
| # | ||||
| # Since: 1.4 | ||||
| ## | ||||
| { 'type': 'ChardevSocket', 'data': { 'addr'     : 'SocketAddress', | ||||
|                                      '*server'  : 'bool', | ||||
|                                      '*wait'    : 'bool', | ||||
|                                      '*nodelay' : 'bool', | ||||
|                                      '*telnet'  : 'bool' } } | ||||
| { 'type': 'ChardevSocket', 'data': { 'addr'       : 'SocketAddress', | ||||
|                                      '*server'    : 'bool', | ||||
|                                      '*wait'      : 'bool', | ||||
|                                      '*nodelay'   : 'bool', | ||||
|                                      '*telnet'    : 'bool', | ||||
|                                      '*reconnect' : 'int' } } | ||||
| 
 | ||||
| ## | ||||
| # @ChardevUdp: | ||||
|  | ||||
							
								
								
									
										359
									
								
								qemu-char.c
									
									
									
									
									
								
							
							
						
						
									
										359
									
								
								qemu-char.c
									
									
									
									
									
								
							| @ -28,6 +28,9 @@ | ||||
| #include "sysemu/char.h" | ||||
| #include "hw/usb.h" | ||||
| #include "qmp-commands.h" | ||||
| #include "qapi/qmp-input-visitor.h" | ||||
| #include "qapi/qmp-output-visitor.h" | ||||
| #include "qapi-visit.h" | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| @ -84,6 +87,94 @@ | ||||
| 
 | ||||
| #define READ_BUF_LEN 4096 | ||||
| #define READ_RETRIES 10 | ||||
| #define CHR_MAX_FILENAME_SIZE 256 | ||||
| 
 | ||||
| /***********************************************************/ | ||||
| /* Socket address helpers */ | ||||
| static void qapi_copy_SocketAddress(SocketAddress **p_dest, | ||||
|                                     SocketAddress *src) | ||||
| { | ||||
|     QmpOutputVisitor *qov; | ||||
|     QmpInputVisitor *qiv; | ||||
|     Visitor *ov, *iv; | ||||
|     QObject *obj; | ||||
| 
 | ||||
|     *p_dest = NULL; | ||||
| 
 | ||||
|     qov = qmp_output_visitor_new(); | ||||
|     ov = qmp_output_get_visitor(qov); | ||||
|     visit_type_SocketAddress(ov, &src, NULL, &error_abort); | ||||
|     obj = qmp_output_get_qobject(qov); | ||||
|     qmp_output_visitor_cleanup(qov); | ||||
|     if (!obj) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     qiv = qmp_input_visitor_new(obj); | ||||
|     iv = qmp_input_get_visitor(qiv); | ||||
|     visit_type_SocketAddress(iv, p_dest, NULL, &error_abort); | ||||
|     qmp_input_visitor_cleanup(qiv); | ||||
|     qobject_decref(obj); | ||||
| } | ||||
| 
 | ||||
| static int SocketAddress_to_str(char *dest, int max_len, | ||||
|                                 const char *prefix, SocketAddress *addr, | ||||
|                                 bool is_listen, bool is_telnet) | ||||
| { | ||||
|     switch (addr->kind) { | ||||
|     case SOCKET_ADDRESS_KIND_INET: | ||||
|         return snprintf(dest, max_len, "%s%s:%s:%s%s", prefix, | ||||
|                         is_telnet ? "telnet" : "tcp", addr->inet->host, | ||||
|                         addr->inet->port, is_listen ? ",server" : ""); | ||||
|         break; | ||||
|     case SOCKET_ADDRESS_KIND_UNIX: | ||||
|         return snprintf(dest, max_len, "%sunix:%s%s", prefix, | ||||
|                         addr->q_unix->path, is_listen ? ",server" : ""); | ||||
|         break; | ||||
|     case SOCKET_ADDRESS_KIND_FD: | ||||
|         return snprintf(dest, max_len, "%sfd:%s%s", prefix, addr->fd->str, | ||||
|                         is_listen ? ",server" : ""); | ||||
|         break; | ||||
|     default: | ||||
|         abort(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int sockaddr_to_str(char *dest, int max_len, | ||||
|                            struct sockaddr_storage *ss, socklen_t ss_len, | ||||
|                            struct sockaddr_storage *ps, socklen_t ps_len, | ||||
|                            bool is_listen, bool is_telnet) | ||||
| { | ||||
|     char shost[NI_MAXHOST], sserv[NI_MAXSERV]; | ||||
|     char phost[NI_MAXHOST], pserv[NI_MAXSERV]; | ||||
|     const char *left = "", *right = ""; | ||||
| 
 | ||||
|     switch (ss->ss_family) { | ||||
| #ifndef _WIN32 | ||||
|     case AF_UNIX: | ||||
|         return snprintf(dest, max_len, "unix:%s%s", | ||||
|                         ((struct sockaddr_un *)(ss))->sun_path, | ||||
|                         is_listen ? ",server" : ""); | ||||
| #endif | ||||
|     case AF_INET6: | ||||
|         left  = "["; | ||||
|         right = "]"; | ||||
|         /* fall through */ | ||||
|     case AF_INET: | ||||
|         getnameinfo((struct sockaddr *) ss, ss_len, shost, sizeof(shost), | ||||
|                     sserv, sizeof(sserv), NI_NUMERICHOST | NI_NUMERICSERV); | ||||
|         getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost), | ||||
|                     pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV); | ||||
|         return snprintf(dest, max_len, "%s:%s%s%s:%s%s <-> %s%s%s:%s", | ||||
|                         is_telnet ? "telnet" : "tcp", | ||||
|                         left, shost, right, sserv, | ||||
|                         is_listen ? ",server" : "", | ||||
|                         left, phost, right, pserv); | ||||
| 
 | ||||
|     default: | ||||
|         return snprintf(dest, max_len, "unknown"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /***********************************************************/ | ||||
| /* character device */ | ||||
| @ -989,7 +1080,8 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) | ||||
| static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) | ||||
| { | ||||
|     int fd_in, fd_out; | ||||
|     char filename_in[256], filename_out[256]; | ||||
|     char filename_in[CHR_MAX_FILENAME_SIZE]; | ||||
|     char filename_out[CHR_MAX_FILENAME_SIZE]; | ||||
|     const char *filename = opts->device; | ||||
| 
 | ||||
|     if (filename == NULL) { | ||||
| @ -997,8 +1089,8 @@ static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     snprintf(filename_in, 256, "%s.in", filename); | ||||
|     snprintf(filename_out, 256, "%s.out", filename); | ||||
|     snprintf(filename_in, CHR_MAX_FILENAME_SIZE, "%s.in", filename); | ||||
|     snprintf(filename_out, CHR_MAX_FILENAME_SIZE, "%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)); | ||||
|     if (fd_in < 0 || fd_out < 0) { | ||||
| @ -1976,7 +2068,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) | ||||
|     OVERLAPPED ov; | ||||
|     int ret; | ||||
|     DWORD size; | ||||
|     char openname[256]; | ||||
|     char openname[CHR_MAX_FILENAME_SIZE]; | ||||
| 
 | ||||
|     s->fpipe = TRUE; | ||||
| 
 | ||||
| @ -2410,8 +2502,39 @@ typedef struct { | ||||
|     int read_msgfds_num; | ||||
|     int *write_msgfds; | ||||
|     int write_msgfds_num; | ||||
| 
 | ||||
|     SocketAddress *addr; | ||||
|     bool is_listen; | ||||
|     bool is_telnet; | ||||
| 
 | ||||
|     guint reconnect_timer; | ||||
|     int64_t reconnect_time; | ||||
|     bool connect_err_reported; | ||||
| } TCPCharDriver; | ||||
| 
 | ||||
| static gboolean socket_reconnect_timeout(gpointer opaque); | ||||
| 
 | ||||
| static void qemu_chr_socket_restart_timer(CharDriverState *chr) | ||||
| { | ||||
|     TCPCharDriver *s = chr->opaque; | ||||
|     assert(s->connected == 0); | ||||
|     s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time, | ||||
|                                                socket_reconnect_timeout, chr); | ||||
| } | ||||
| 
 | ||||
| static void check_report_connect_error(CharDriverState *chr, | ||||
|                                        Error *err) | ||||
| { | ||||
|     TCPCharDriver *s = chr->opaque; | ||||
| 
 | ||||
|     if (!s->connect_err_reported) { | ||||
|         error_report("Unable to connect character device %s: %s", | ||||
|                      chr->label, error_get_pretty(err)); | ||||
|         s->connect_err_reported = true; | ||||
|     } | ||||
|     qemu_chr_socket_restart_timer(chr); | ||||
| } | ||||
| 
 | ||||
| static gboolean tcp_chr_accept(GIOChannel *chan, GIOCondition cond, void *opaque); | ||||
| 
 | ||||
| #ifndef _WIN32 | ||||
| @ -2690,7 +2813,12 @@ static void tcp_chr_disconnect(CharDriverState *chr) | ||||
|     s->chan = NULL; | ||||
|     closesocket(s->fd); | ||||
|     s->fd = -1; | ||||
|     SocketAddress_to_str(chr->filename, CHR_MAX_FILENAME_SIZE, | ||||
|                          "disconnected:", s->addr, s->is_listen, s->is_telnet); | ||||
|     qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | ||||
|     if (s->reconnect_time) { | ||||
|         qemu_chr_socket_restart_timer(chr); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) | ||||
| @ -2761,6 +2889,21 @@ static void tcp_chr_connect(void *opaque) | ||||
| { | ||||
|     CharDriverState *chr = opaque; | ||||
|     TCPCharDriver *s = chr->opaque; | ||||
|     struct sockaddr_storage ss, ps; | ||||
|     socklen_t ss_len = sizeof(ss), ps_len = sizeof(ps); | ||||
| 
 | ||||
|     memset(&ss, 0, ss_len); | ||||
|     if (getsockname(s->fd, (struct sockaddr *) &ss, &ss_len) != 0) { | ||||
|         snprintf(chr->filename, CHR_MAX_FILENAME_SIZE, | ||||
|                  "Error in getsockname: %s\n", strerror(errno)); | ||||
|     } else if (getpeername(s->fd, (struct sockaddr *) &ps, &ps_len) != 0) { | ||||
|         snprintf(chr->filename, CHR_MAX_FILENAME_SIZE, | ||||
|                  "Error in getpeername: %s\n", strerror(errno)); | ||||
|     } else { | ||||
|         sockaddr_to_str(chr->filename, CHR_MAX_FILENAME_SIZE, | ||||
|                         &ss, ss_len, &ps, ps_len, | ||||
|                         s->is_listen, s->is_telnet); | ||||
|     } | ||||
| 
 | ||||
|     s->connected = 1; | ||||
|     if (s->chan) { | ||||
| @ -2859,6 +3002,12 @@ static void tcp_chr_close(CharDriverState *chr) | ||||
| { | ||||
|     TCPCharDriver *s = chr->opaque; | ||||
|     int i; | ||||
| 
 | ||||
|     if (s->reconnect_timer) { | ||||
|         g_source_remove(s->reconnect_timer); | ||||
|         s->reconnect_timer = 0; | ||||
|     } | ||||
|     qapi_free_SocketAddress(s->addr); | ||||
|     if (s->fd >= 0) { | ||||
|         remove_fd_in_watch(chr); | ||||
|         if (s->chan) { | ||||
| @ -2889,79 +3038,15 @@ static void tcp_chr_close(CharDriverState *chr) | ||||
|     qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | ||||
| } | ||||
| 
 | ||||
| static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, | ||||
|                                                 bool is_listen, bool is_telnet, | ||||
|                                                 bool is_waitconnect, | ||||
|                                                 Error **errp) | ||||
| static void qemu_chr_finish_socket_connection(CharDriverState *chr, int fd) | ||||
| { | ||||
|     CharDriverState *chr = NULL; | ||||
|     TCPCharDriver *s = NULL; | ||||
|     char host[NI_MAXHOST], serv[NI_MAXSERV]; | ||||
|     const char *left = "", *right = ""; | ||||
|     struct sockaddr_storage ss; | ||||
|     socklen_t ss_len = sizeof(ss); | ||||
|     TCPCharDriver *s = chr->opaque; | ||||
| 
 | ||||
|     memset(&ss, 0, ss_len); | ||||
|     if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) != 0) { | ||||
|         error_setg_errno(errp, errno, "getsockname"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     chr = qemu_chr_alloc(); | ||||
|     s = g_malloc0(sizeof(TCPCharDriver)); | ||||
| 
 | ||||
|     s->connected = 0; | ||||
|     s->fd = -1; | ||||
|     s->listen_fd = -1; | ||||
|     s->read_msgfds = 0; | ||||
|     s->read_msgfds_num = 0; | ||||
|     s->write_msgfds = 0; | ||||
|     s->write_msgfds_num = 0; | ||||
| 
 | ||||
|     chr->filename = g_malloc(256); | ||||
|     switch (ss.ss_family) { | ||||
| #ifndef _WIN32 | ||||
|     case AF_UNIX: | ||||
|         s->is_unix = 1; | ||||
|         snprintf(chr->filename, 256, "unix:%s%s", | ||||
|                  ((struct sockaddr_un *)(&ss))->sun_path, | ||||
|                  is_listen ? ",server" : ""); | ||||
|         break; | ||||
| #endif | ||||
|     case AF_INET6: | ||||
|         left  = "["; | ||||
|         right = "]"; | ||||
|         /* fall through */ | ||||
|     case AF_INET: | ||||
|         s->do_nodelay = do_nodelay; | ||||
|         getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host), | ||||
|                     serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); | ||||
|         snprintf(chr->filename, 256, "%s:%s%s%s:%s%s", | ||||
|                  is_telnet ? "telnet" : "tcp", | ||||
|                  left, host, right, serv, | ||||
|                  is_listen ? ",server" : ""); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     chr->opaque = s; | ||||
|     chr->chr_write = tcp_chr_write; | ||||
|     chr->chr_sync_read = tcp_chr_sync_read; | ||||
|     chr->chr_close = tcp_chr_close; | ||||
|     chr->get_msgfds = tcp_get_msgfds; | ||||
|     chr->set_msgfds = tcp_set_msgfds; | ||||
|     chr->chr_add_client = tcp_chr_add_client; | ||||
|     chr->chr_add_watch = tcp_chr_add_watch; | ||||
|     chr->chr_update_read_handler = tcp_chr_update_read_handler; | ||||
|     /* be isn't opened until we get a connection */ | ||||
|     chr->explicit_be_open = true; | ||||
| 
 | ||||
|     if (is_listen) { | ||||
|     if (s->is_listen) { | ||||
|         s->listen_fd = fd; | ||||
|         s->listen_chan = io_channel_from_socket(s->listen_fd); | ||||
|         s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr); | ||||
|         if (is_telnet) { | ||||
|             s->do_telnetopt = 1; | ||||
|         } | ||||
|         s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, | ||||
|                                        tcp_chr_accept, chr); | ||||
|     } else { | ||||
|         s->connected = 1; | ||||
|         s->fd = fd; | ||||
| @ -2969,14 +3054,41 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, | ||||
|         s->chan = io_channel_from_socket(s->fd); | ||||
|         tcp_chr_connect(chr); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|     if (is_listen && is_waitconnect) { | ||||
|         fprintf(stderr, "QEMU waiting for connection on: %s\n", | ||||
|                 chr->filename); | ||||
|         tcp_chr_accept(s->listen_chan, G_IO_IN, chr); | ||||
|         qemu_set_nonblock(s->listen_fd); | ||||
| static void qemu_chr_socket_connected(int fd, Error *err, void *opaque) | ||||
| { | ||||
|     CharDriverState *chr = opaque; | ||||
|     TCPCharDriver *s = chr->opaque; | ||||
| 
 | ||||
|     if (fd < 0) { | ||||
|         check_report_connect_error(chr, err); | ||||
|         return; | ||||
|     } | ||||
|     return chr; | ||||
| 
 | ||||
|     s->connect_err_reported = false; | ||||
|     qemu_chr_finish_socket_connection(chr, fd); | ||||
| } | ||||
| 
 | ||||
| static bool qemu_chr_open_socket_fd(CharDriverState *chr, Error **errp) | ||||
| { | ||||
|     TCPCharDriver *s = chr->opaque; | ||||
|     int fd; | ||||
| 
 | ||||
|     if (s->is_listen) { | ||||
|         fd = socket_listen(s->addr, errp); | ||||
|     } else if (s->reconnect_time) { | ||||
|         fd = socket_connect(s->addr, errp, qemu_chr_socket_connected, chr); | ||||
|         return fd >= 0; | ||||
|     } else { | ||||
|         fd = socket_connect(s->addr, errp, NULL, NULL); | ||||
|     } | ||||
|     if (fd < 0) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     qemu_chr_finish_socket_connection(chr, fd); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /*********************************************************/ | ||||
| @ -3396,6 +3508,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, | ||||
|     bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true); | ||||
|     bool is_telnet      = qemu_opt_get_bool(opts, "telnet", false); | ||||
|     bool do_nodelay     = !qemu_opt_get_bool(opts, "delay", true); | ||||
|     int64_t reconnect   = qemu_opt_get_number(opts, "reconnect", 0); | ||||
|     const char *path = qemu_opt_get(opts, "path"); | ||||
|     const char *host = qemu_opt_get(opts, "host"); | ||||
|     const char *port = qemu_opt_get(opts, "port"); | ||||
| @ -3422,6 +3535,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, | ||||
|     backend->socket->telnet = is_telnet; | ||||
|     backend->socket->has_wait = true; | ||||
|     backend->socket->wait = is_waitconnect; | ||||
|     backend->socket->has_reconnect = true; | ||||
|     backend->socket->reconnect = reconnect; | ||||
| 
 | ||||
|     addr = g_new0(SocketAddress, 1); | ||||
|     if (path) { | ||||
| @ -3820,6 +3935,9 @@ QemuOptsList qemu_chardev_opts = { | ||||
|         },{ | ||||
|             .name = "delay", | ||||
|             .type = QEMU_OPT_BOOL, | ||||
|         },{ | ||||
|             .name = "reconnect", | ||||
|             .type = QEMU_OPT_NUMBER, | ||||
|         },{ | ||||
|             .name = "telnet", | ||||
|             .type = QEMU_OPT_BOOL, | ||||
| @ -3964,26 +4082,95 @@ static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel, | ||||
| 
 | ||||
| #endif /* WIN32 */ | ||||
| 
 | ||||
| static void socket_try_connect(CharDriverState *chr) | ||||
| { | ||||
|     Error *err = NULL; | ||||
| 
 | ||||
|     if (!qemu_chr_open_socket_fd(chr, &err)) { | ||||
|         check_report_connect_error(chr, err); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static gboolean socket_reconnect_timeout(gpointer opaque) | ||||
| { | ||||
|     CharDriverState *chr = opaque; | ||||
|     TCPCharDriver *s = chr->opaque; | ||||
| 
 | ||||
|     s->reconnect_timer = 0; | ||||
| 
 | ||||
|     if (chr->be_open) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     socket_try_connect(chr); | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, | ||||
|                                                 Error **errp) | ||||
| { | ||||
|     CharDriverState *chr; | ||||
|     TCPCharDriver *s; | ||||
|     SocketAddress *addr = sock->addr; | ||||
|     bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false; | ||||
|     bool is_listen      = sock->has_server  ? sock->server  : true; | ||||
|     bool is_telnet      = sock->has_telnet  ? sock->telnet  : false; | ||||
|     bool is_waitconnect = sock->has_wait    ? sock->wait    : false; | ||||
|     int fd; | ||||
|     int64_t reconnect   = sock->has_reconnect ? sock->reconnect : 0; | ||||
| 
 | ||||
|     chr = qemu_chr_alloc(); | ||||
|     s = g_malloc0(sizeof(TCPCharDriver)); | ||||
| 
 | ||||
|     s->fd = -1; | ||||
|     s->listen_fd = -1; | ||||
|     s->is_unix = addr->kind == SOCKET_ADDRESS_KIND_UNIX; | ||||
|     s->is_listen = is_listen; | ||||
|     s->is_telnet = is_telnet; | ||||
|     s->do_nodelay = do_nodelay; | ||||
|     qapi_copy_SocketAddress(&s->addr, sock->addr); | ||||
| 
 | ||||
|     chr->opaque = s; | ||||
|     chr->chr_write = tcp_chr_write; | ||||
|     chr->chr_sync_read = tcp_chr_sync_read; | ||||
|     chr->chr_close = tcp_chr_close; | ||||
|     chr->get_msgfds = tcp_get_msgfds; | ||||
|     chr->set_msgfds = tcp_set_msgfds; | ||||
|     chr->chr_add_client = tcp_chr_add_client; | ||||
|     chr->chr_add_watch = tcp_chr_add_watch; | ||||
|     chr->chr_update_read_handler = tcp_chr_update_read_handler; | ||||
|     /* be isn't opened until we get a connection */ | ||||
|     chr->explicit_be_open = true; | ||||
| 
 | ||||
|     chr->filename = g_malloc(CHR_MAX_FILENAME_SIZE); | ||||
|     SocketAddress_to_str(chr->filename, CHR_MAX_FILENAME_SIZE, "disconnected:", | ||||
|                          addr, is_listen, is_telnet); | ||||
| 
 | ||||
|     if (is_listen) { | ||||
|         fd = socket_listen(addr, errp); | ||||
|     } else { | ||||
|         fd = socket_connect(addr, errp, NULL, NULL); | ||||
|         if (is_telnet) { | ||||
|             s->do_telnetopt = 1; | ||||
|         } | ||||
|     } else if (reconnect > 0) { | ||||
|         s->reconnect_time = reconnect; | ||||
|     } | ||||
|     if (fd < 0) { | ||||
| 
 | ||||
|     if (s->reconnect_time) { | ||||
|         socket_try_connect(chr); | ||||
|     } else if (!qemu_chr_open_socket_fd(chr, errp)) { | ||||
|         g_free(s); | ||||
|         g_free(chr->filename); | ||||
|         g_free(chr); | ||||
|         return NULL; | ||||
|     } | ||||
|     return qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, | ||||
|                                    is_telnet, is_waitconnect, errp); | ||||
| 
 | ||||
|     if (is_listen && is_waitconnect) { | ||||
|         fprintf(stderr, "QEMU waiting for connection on: %s\n", | ||||
|                 chr->filename); | ||||
|         tcp_chr_accept(s->listen_chan, G_IO_IN, chr); | ||||
|         qemu_set_nonblock(s->listen_fd); | ||||
|     } | ||||
| 
 | ||||
|     return chr; | ||||
| } | ||||
| 
 | ||||
| static CharDriverState *qmp_chardev_open_udp(ChardevUdp *udp, | ||||
|  | ||||
| @ -1930,9 +1930,9 @@ ETEXI | ||||
| 
 | ||||
| DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, | ||||
|     "-chardev null,id=id[,mux=on|off]\n" | ||||
|     "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4][,ipv6][,nodelay]\n" | ||||
|     "         [,server][,nowait][,telnet][,mux=on|off] (tcp)\n" | ||||
|     "-chardev socket,id=id,path=path[,server][,nowait][,telnet],[mux=on|off] (unix)\n" | ||||
|     "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4][,ipv6][,nodelay][,reconnect=seconds]\n" | ||||
|     "         [,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off] (tcp)\n" | ||||
|     "-chardev socket,id=id,path=path[,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off] (unix)\n" | ||||
|     "-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n" | ||||
|     "         [,localport=localport][,ipv4][,ipv6][,mux=on|off]\n" | ||||
|     "-chardev msmouse,id=id[,mux=on|off]\n" | ||||
| @ -2004,7 +2004,7 @@ Options to each backend are described below. | ||||
| A void device. This device will not emit any data, and will drop any data it | ||||
| receives. The null backend does not take any options. | ||||
| 
 | ||||
| @item -chardev socket ,id=@var{id} [@var{TCP options} or @var{unix options}] [,server] [,nowait] [,telnet] | ||||
| @item -chardev socket ,id=@var{id} [@var{TCP options} or @var{unix options}] [,server] [,nowait] [,telnet] [,reconnect=@var{seconds}] | ||||
| 
 | ||||
| Create a two-way stream socket, which can be either a TCP or a unix socket. A | ||||
| unix socket will be created if @option{path} is specified. Behaviour is | ||||
| @ -2018,6 +2018,10 @@ connect to a listening socket. | ||||
| @option{telnet} specifies that traffic on the socket should interpret telnet | ||||
| escape sequences. | ||||
| 
 | ||||
| @option{reconnect} sets the timeout for reconnecting on non-server sockets when | ||||
| the remote end goes away.  qemu will delay this many seconds and then attempt | ||||
| to reconnect.  Zero disables reconnecting, and is the default. | ||||
| 
 | ||||
| TCP and unix socket options are given below: | ||||
| 
 | ||||
| @table @option | ||||
| @ -2687,14 +2691,16 @@ telnet on port 5555 to access the QEMU port. | ||||
| localhost 5555 | ||||
| @end table | ||||
| 
 | ||||
| @item tcp:[@var{host}]:@var{port}[,@var{server}][,nowait][,nodelay] | ||||
| @item tcp:[@var{host}]:@var{port}[,@var{server}][,nowait][,nodelay][,reconnect=@var{seconds}] | ||||
| The TCP Net Console has two modes of operation.  It can send the serial | ||||
| I/O to a location or wait for a connection from a location.  By default | ||||
| the TCP Net Console is sent to @var{host} at the @var{port}.  If you use | ||||
| the @var{server} option QEMU will wait for a client socket application | ||||
| to connect to the port before continuing, unless the @code{nowait} | ||||
| option was specified.  The @code{nodelay} option disables the Nagle buffering | ||||
| algorithm.  If @var{host} is omitted, 0.0.0.0 is assumed. Only | ||||
| algorithm.  The @code{reconnect} option only applies if @var{noserver} is | ||||
| set, if the connection goes down it will attempt to reconnect at the | ||||
| given interval.  If @var{host} is omitted, 0.0.0.0 is assumed. Only | ||||
| one TCP connection at a time is accepted. You can use @code{telnet} to | ||||
| connect to the corresponding character device. | ||||
| @table @code | ||||
| @ -2715,7 +2721,7 @@ MAGIC_SYSRQ sequence if you use a telnet that supports sending the break | ||||
| sequence.  Typically in unix telnet you do it with Control-] and then | ||||
| type "send break" followed by pressing the enter key. | ||||
| 
 | ||||
| @item unix:@var{path}[,server][,nowait] | ||||
| @item unix:@var{path}[,server][,nowait][,reconnect=@var{seconds}] | ||||
| A unix domain socket is used instead of a tcp socket.  The option works the | ||||
| same as if you had specified @code{-serial tcp} except the unix domain socket | ||||
| @var{path} is used for connections. | ||||
|  | ||||
							
								
								
									
										27
									
								
								qtest.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								qtest.c
									
									
									
									
									
								
							| @ -17,6 +17,7 @@ | ||||
| #include "exec/ioport.h" | ||||
| #include "exec/memory.h" | ||||
| #include "hw/irq.h" | ||||
| #include "sysemu/accel.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "sysemu/cpus.h" | ||||
| #include "qemu/config-file.h" | ||||
| @ -519,7 +520,7 @@ static void configure_qtest_icount(const char *options) | ||||
|     qemu_opts_del(opts); | ||||
| } | ||||
| 
 | ||||
| int qtest_init_accel(MachineClass *mc) | ||||
| static int qtest_init_accel(MachineState *ms) | ||||
| { | ||||
|     configure_qtest_icount("0"); | ||||
|     return 0; | ||||
| @ -557,3 +558,27 @@ bool qtest_driver(void) | ||||
| { | ||||
|     return qtest_chr; | ||||
| } | ||||
| 
 | ||||
| static void qtest_accel_class_init(ObjectClass *oc, void *data) | ||||
| { | ||||
|     AccelClass *ac = ACCEL_CLASS(oc); | ||||
|     ac->name = "QTest"; | ||||
|     ac->available = qtest_available; | ||||
|     ac->init_machine = qtest_init_accel; | ||||
|     ac->allowed = &qtest_allowed; | ||||
| } | ||||
| 
 | ||||
| #define TYPE_QTEST_ACCEL ACCEL_CLASS_NAME("qtest") | ||||
| 
 | ||||
| static const TypeInfo qtest_accel_type = { | ||||
|     .name = TYPE_QTEST_ACCEL, | ||||
|     .parent = TYPE_ACCEL, | ||||
|     .class_init = qtest_accel_class_init, | ||||
| }; | ||||
| 
 | ||||
| static void qtest_type_init(void) | ||||
| { | ||||
|     type_register_static(&qtest_accel_type); | ||||
| } | ||||
| 
 | ||||
| type_init(qtest_type_init); | ||||
|  | ||||
| @ -199,14 +199,13 @@ static void error_print_loc(void) | ||||
| bool enable_timestamp_msg; | ||||
| /*
 | ||||
|  * Print an error message to current monitor if we have one, else to stderr. | ||||
|  * Format arguments like sprintf().  The result should not contain | ||||
|  * Format arguments like vsprintf().  The result should not contain | ||||
|  * newlines. | ||||
|  * Prepend the current location and append a newline. | ||||
|  * It's wrong to call this in a QMP monitor.  Use qerror_report() there. | ||||
|  */ | ||||
| void error_report(const char *fmt, ...) | ||||
| void error_vreport(const char *fmt, va_list ap) | ||||
| { | ||||
|     va_list ap; | ||||
|     GTimeVal tv; | ||||
|     gchar *timestr; | ||||
| 
 | ||||
| @ -218,8 +217,22 @@ void error_report(const char *fmt, ...) | ||||
|     } | ||||
| 
 | ||||
|     error_print_loc(); | ||||
|     va_start(ap, fmt); | ||||
|     error_vprintf(fmt, ap); | ||||
|     va_end(ap); | ||||
|     error_printf("\n"); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Print an error message to current monitor if we have one, else to stderr. | ||||
|  * Format arguments like sprintf().  The result should not contain | ||||
|  * newlines. | ||||
|  * Prepend the current location and append a newline. | ||||
|  * It's wrong to call this in a QMP monitor.  Use qerror_report() there. | ||||
|  */ | ||||
| void error_report(const char *fmt, ...) | ||||
| { | ||||
|     va_list ap; | ||||
| 
 | ||||
|     va_start(ap, fmt); | ||||
|     error_vreport(fmt, ap); | ||||
|     va_end(ap); | ||||
| } | ||||
|  | ||||
| @ -234,6 +234,7 @@ static void wait_for_connect(void *opaque) | ||||
|     int val = 0, rc = 0; | ||||
|     socklen_t valsize = sizeof(val); | ||||
|     bool in_progress; | ||||
|     Error *err = NULL; | ||||
| 
 | ||||
|     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); | ||||
| 
 | ||||
| @ -244,10 +245,12 @@ static void wait_for_connect(void *opaque) | ||||
|     /* update rc to contain error */ | ||||
|     if (!rc && val) { | ||||
|         rc = -1; | ||||
|         errno = val; | ||||
|     } | ||||
| 
 | ||||
|     /* connect error */ | ||||
|     if (rc < 0) { | ||||
|         error_setg_errno(&err, errno, "Error connecting to socket"); | ||||
|         closesocket(s->fd); | ||||
|         s->fd = rc; | ||||
|     } | ||||
| @ -257,9 +260,14 @@ static void wait_for_connect(void *opaque) | ||||
|         while (s->current_addr->ai_next != NULL && s->fd < 0) { | ||||
|             s->current_addr = s->current_addr->ai_next; | ||||
|             s->fd = inet_connect_addr(s->current_addr, &in_progress, s, NULL); | ||||
|             if (s->fd < 0) { | ||||
|                 error_free(err); | ||||
|                 err = NULL; | ||||
|                 error_setg_errno(&err, errno, "Unable to start socket connect"); | ||||
|             } | ||||
|             /* connect in progress */ | ||||
|             if (in_progress) { | ||||
|                 return; | ||||
|                 goto out; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -267,9 +275,11 @@ static void wait_for_connect(void *opaque) | ||||
|     } | ||||
| 
 | ||||
|     if (s->callback) { | ||||
|         s->callback(s->fd, s->opaque); | ||||
|         s->callback(s->fd, err, s->opaque); | ||||
|     } | ||||
|     g_free(s); | ||||
| out: | ||||
|     error_free(err); | ||||
| } | ||||
| 
 | ||||
| static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, | ||||
| @ -401,7 +411,7 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, | ||||
|         return sock; | ||||
|     } else { | ||||
|         if (callback) { | ||||
|             callback(sock, opaque); | ||||
|             callback(sock, NULL, opaque); | ||||
|         } | ||||
|     } | ||||
|     g_free(connect_state); | ||||
| @ -769,7 +779,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp, | ||||
|     } else if (rc >= 0) { | ||||
|         /* non blocking socket immediate success, call callback */ | ||||
|         if (callback != NULL) { | ||||
|             callback(sock, opaque); | ||||
|             callback(sock, NULL, opaque); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -919,7 +929,7 @@ int socket_connect(SocketAddress *addr, Error **errp, | ||||
|         fd = monitor_get_fd(cur_mon, addr->fd->str, errp); | ||||
|         if (fd >= 0 && callback) { | ||||
|             qemu_set_nonblock(fd); | ||||
|             callback(fd, opaque); | ||||
|             callback(fd, NULL, opaque); | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										83
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								vl.c
									
									
									
									
									
								
							| @ -61,6 +61,7 @@ int main(int argc, char **argv) | ||||
| #include "qemu/sockets.h" | ||||
| #include "hw/hw.h" | ||||
| #include "hw/boards.h" | ||||
| #include "sysemu/accel.h" | ||||
| #include "hw/usb.h" | ||||
| #include "hw/pcmcia.h" | ||||
| #include "hw/i386/pc.h" | ||||
| @ -213,11 +214,9 @@ static NotifierList exit_notifiers = | ||||
| static NotifierList machine_init_done_notifiers = | ||||
|     NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers); | ||||
| 
 | ||||
| static bool tcg_allowed = true; | ||||
| bool xen_allowed; | ||||
| uint32_t xen_domid; | ||||
| enum xen_mode xen_mode = XEN_EMULATE; | ||||
| static int tcg_tb_size; | ||||
| 
 | ||||
| static int has_defaults = 1; | ||||
| static int default_serial = 1; | ||||
| @ -2681,84 +2680,6 @@ static MachineClass *machine_parse(const char *name) | ||||
|     exit(!name || !is_help_option(name)); | ||||
| } | ||||
| 
 | ||||
| static int tcg_init(MachineClass *mc) | ||||
| { | ||||
|     tcg_exec_init(tcg_tb_size * 1024 * 1024); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static struct { | ||||
|     const char *opt_name; | ||||
|     const char *name; | ||||
|     int (*available)(void); | ||||
|     int (*init)(MachineClass *mc); | ||||
|     bool *allowed; | ||||
| } accel_list[] = { | ||||
|     { "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed }, | ||||
|     { "xen", "Xen", xen_available, xen_init, &xen_allowed }, | ||||
|     { "kvm", "KVM", kvm_available, kvm_init, &kvm_allowed }, | ||||
|     { "qtest", "QTest", qtest_available, qtest_init_accel, &qtest_allowed }, | ||||
| }; | ||||
| 
 | ||||
| static int configure_accelerator(MachineClass *mc) | ||||
| { | ||||
|     const char *p; | ||||
|     char buf[10]; | ||||
|     int i, ret; | ||||
|     bool accel_initialised = false; | ||||
|     bool init_failed = false; | ||||
| 
 | ||||
|     p = qemu_opt_get(qemu_get_machine_opts(), "accel"); | ||||
|     if (p == NULL) { | ||||
|         /* Use the default "accelerator", tcg */ | ||||
|         p = "tcg"; | ||||
|     } | ||||
| 
 | ||||
|     while (!accel_initialised && *p != '\0') { | ||||
|         if (*p == ':') { | ||||
|             p++; | ||||
|         } | ||||
|         p = get_opt_name(buf, sizeof (buf), p, ':'); | ||||
|         for (i = 0; i < ARRAY_SIZE(accel_list); i++) { | ||||
|             if (strcmp(accel_list[i].opt_name, buf) == 0) { | ||||
|                 if (!accel_list[i].available()) { | ||||
|                     printf("%s not supported for this target\n", | ||||
|                            accel_list[i].name); | ||||
|                     break; | ||||
|                 } | ||||
|                 *(accel_list[i].allowed) = true; | ||||
|                 ret = accel_list[i].init(mc); | ||||
|                 if (ret < 0) { | ||||
|                     init_failed = true; | ||||
|                     fprintf(stderr, "failed to initialize %s: %s\n", | ||||
|                             accel_list[i].name, | ||||
|                             strerror(-ret)); | ||||
|                     *(accel_list[i].allowed) = false; | ||||
|                 } else { | ||||
|                     accel_initialised = true; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if (i == ARRAY_SIZE(accel_list)) { | ||||
|             fprintf(stderr, "\"%s\" accelerator does not exist.\n", buf); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!accel_initialised) { | ||||
|         if (!init_failed) { | ||||
|             fprintf(stderr, "No accelerator found!\n"); | ||||
|         } | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     if (init_failed) { | ||||
|         fprintf(stderr, "Back to %s accelerator.\n", accel_list[i].name); | ||||
|     } | ||||
| 
 | ||||
|     return !accel_initialised; | ||||
| } | ||||
| 
 | ||||
| void qemu_add_exit_notifier(Notifier *notify) | ||||
| { | ||||
|     notifier_list_add(&exit_notifiers, notify); | ||||
| @ -4264,7 +4185,7 @@ int main(int argc, char **argv, char **envp) | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     configure_accelerator(machine_class); | ||||
|     configure_accelerator(current_machine); | ||||
| 
 | ||||
|     if (qtest_chrdev) { | ||||
|         Error *local_err = NULL; | ||||
|  | ||||
| @ -11,9 +11,3 @@ | ||||
| void xenstore_store_pv_console_info(int i, CharDriverState *chr) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| int xen_init(MachineClass *mc) | ||||
| { | ||||
|     return -ENOSYS; | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										25
									
								
								xen-common.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								xen-common.c
									
									
									
									
									
								
							| @ -11,6 +11,7 @@ | ||||
| #include "hw/xen/xen_backend.h" | ||||
| #include "qmp-commands.h" | ||||
| #include "sysemu/char.h" | ||||
| #include "sysemu/accel.h" | ||||
| 
 | ||||
| //#define DEBUG_XEN
 | ||||
| 
 | ||||
| @ -109,7 +110,7 @@ static void xen_change_state_handler(void *opaque, int running, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int xen_init(MachineClass *mc) | ||||
| static int xen_init(MachineState *ms) | ||||
| { | ||||
|     xen_xc = xen_xc_interface_open(0, 0, 0); | ||||
|     if (xen_xc == XC_HANDLER_INITIAL_VALUE) { | ||||
| @ -121,3 +122,25 @@ int xen_init(MachineClass *mc) | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static void xen_accel_class_init(ObjectClass *oc, void *data) | ||||
| { | ||||
|     AccelClass *ac = ACCEL_CLASS(oc); | ||||
|     ac->name = "Xen"; | ||||
|     ac->init_machine = xen_init; | ||||
|     ac->allowed = &xen_allowed; | ||||
| } | ||||
| 
 | ||||
| #define TYPE_XEN_ACCEL ACCEL_CLASS_NAME("xen") | ||||
| 
 | ||||
| static const TypeInfo xen_accel_type = { | ||||
|     .name = TYPE_XEN_ACCEL, | ||||
|     .parent = TYPE_ACCEL, | ||||
|     .class_init = xen_accel_class_init, | ||||
| }; | ||||
| 
 | ||||
| static void xen_type_init(void) | ||||
| { | ||||
|     type_register_static(&xen_accel_type); | ||||
| } | ||||
| 
 | ||||
| type_init(xen_type_init); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Peter Maydell
						Peter Maydell