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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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…
	
		Reference in New Issue