From patchwork Fri Apr 11 06:34:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 338391 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48BE714008F for ; Fri, 11 Apr 2014 16:36:05 +1000 (EST) Received: from localhost ([::1]:56137 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WYV4F-0004fT-4K for incoming@patchwork.ozlabs.org; Fri, 11 Apr 2014 02:36:03 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55230) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WYV3H-0004Mv-DY for qemu-devel@nongnu.org; Fri, 11 Apr 2014 02:35:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WYV3B-0007iQ-9i for qemu-devel@nongnu.org; Fri, 11 Apr 2014 02:35:03 -0400 Received: from mail-pd0-x232.google.com ([2607:f8b0:400e:c02::232]:41366) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WYV3A-0007iC-UB for qemu-devel@nongnu.org; Fri, 11 Apr 2014 02:34:57 -0400 Received: by mail-pd0-f178.google.com with SMTP id x10so4890146pdj.9 for ; Thu, 10 Apr 2014 23:34:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=cbz7pfjWpI95rMFV2CEpZvhsomAX8IwQ7rIUkf2638Y=; b=Efc67HHBx6UdIoUMOp1HBDPCbyjV4PBNoAol6+6THSKgTV9XtJXe6LvczrSCpmVWa7 QFXnzJslEPKBGOOJuSnPnLWk6RDjsn3JbashPa8r9LYdLcnABIPGpoINS+E1gEsTQDOL Y+a4neliq6YenvfPEBGNHQETGg0n+zLvClnGE9dVcC93k2qvMTPyoX8rVYJg0vljvZKq DS5qPC6GDzA2O2h5OTR8OORo8Dj50c38U5Dx6qob8ifOilD1vA8sq7Z+RwNzqlYgBP1d 3VvY2Z555yvms0r3dsig75qutnAr8GnPu4eRqOnYwnY9AkOfRxHd682cCViNZkora/GH eAVA== X-Received: by 10.68.129.34 with SMTP id nt2mr25121969pbb.18.1397198095958; Thu, 10 Apr 2014 23:34:55 -0700 (PDT) Received: from localhost ([203.126.243.116]) by mx.google.com with ESMTPSA id ak1sm13316342pbc.58.2014.04.10.23.34.54 for (version=TLSv1.1 cipher=RC4-SHA bits=128/128); Thu, 10 Apr 2014 23:34:55 -0700 (PDT) From: Alistair Francis To: qemu-devel@nongnu.org Date: Fri, 11 Apr 2014 16:34:51 +1000 Message-Id: <8e3bb3182c535bcdf36bb79bced6d2ab01e03745.1397197001.git.alistair.francis@xilinx.com> X-Mailer: git-send-email 1.9.0 In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400e:c02::232 Cc: edgar.iglesias@xilinx.com, peter.maydell@linaro.org, peter.crosthwaite@xilinx.com, eric.auger@linaro.org, kim.phillips@linaro.org, agraf@suse.de, armbru@redhat.com, edgar.iglesias@gmail.com, alistair.francis@xilinx.com, afaerber@suse.de Subject: [Qemu-devel] [PATCH v2 2/4] qdev-monitor: Implement three functions used to connect devices X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org These functions are used to attach devices that are passed in via the command line using the -device argument. The reason for using three functions is to allow a multi-pass approach. This can then be extended to allow devices to connect to other devices that are being connected via the command line (for example DMA/ethernet AXI-Stream). Signed-off-by: Alistair Francis --- include/hw/boards.h | 2 + include/monitor/qdev.h | 3 + include/qemu/option_int.h | 1 + qdev-monitor.c | 237 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 241 insertions(+), 2 deletions(-) diff --git a/include/hw/boards.h b/include/hw/boards.h index dd2c70d..d06bf86 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -15,6 +15,8 @@ typedef struct QEMUMachineInitArgs { const char *kernel_cmdline; const char *initrd_filename; const char *cpu_model; + DeviceState *intc; + Object *cpu; } QEMUMachineInitArgs; typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args); diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h index 8d16e11..18a5b3d 100644 --- a/include/monitor/qdev.h +++ b/include/monitor/qdev.h @@ -11,5 +11,8 @@ void do_info_qdm(Monitor *mon, const QDict *qdict); int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); int qdev_device_help(QemuOpts *opts); DeviceState *qdev_device_add(QemuOpts *opts); +DeviceState *qdev_device_create(QemuOpts *opts); +DeviceState *qdev_device_init(QemuOpts *opts, DeviceState* intc); +DeviceState *qdev_device_connect(QemuOpts *opts, DeviceState* intc); #endif diff --git a/include/qemu/option_int.h b/include/qemu/option_int.h index 8212fa4..fdab055 100644 --- a/include/qemu/option_int.h +++ b/include/qemu/option_int.h @@ -47,6 +47,7 @@ struct QemuOpts { char *id; QemuOptsList *list; Location loc; + void *opaque; QTAILQ_HEAD(QemuOptHead, QemuOpt) head; QTAILQ_ENTRY(QemuOpts) next; }; diff --git a/qdev-monitor.c b/qdev-monitor.c index 9268c87..5920cb6 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -24,6 +24,8 @@ #include "qmp-commands.h" #include "sysemu/arch_init.h" #include "qemu/config-file.h" +#include "exec/address-spaces.h" +#include "qemu/option_int.h" /* * Aliases were a bad idea from the start. Let's keep them @@ -148,10 +150,27 @@ static int set_property(const char *name, const char *value, void *opaque) Object *obj = opaque; Error *err = NULL; - if (strcmp(name, "driver") == 0) + if (strcmp(name, "driver") == 0) { return 0; - if (strcmp(name, "bus") == 0) + } + if (strcmp(name, "bus") == 0) { + return 0; + } + if (strcmp(name, "addr") == 0) { + return 0; + } + if (strcmp(name, "irq") == 0) { + return 0; + } + if (strcmp(name, "model") == 0) { + return 0; + } + if (strcmp(name, "name") == 0) { return 0; + } + if (strcmp(name, "type") == 0) { + return 0; + } object_property_parse(obj, value, name, &err); if (err != NULL) { @@ -567,6 +586,220 @@ DeviceState *qdev_device_add(QemuOpts *opts) } +DeviceState *qdev_device_create(QemuOpts *opts) +{ + ObjectClass *oc; + DeviceClass *dc; + const char *driver, *path; + DeviceState *dev = NULL; + BusState *bus = NULL; + + hwaddr addr; + MemoryRegion *ram; + MemoryRegion *address_space_mem = get_system_memory();; + uint64_t ram_size; + + Object *cpu; + ObjectClass *cpu_oc; + Error *err = NULL; + + driver = qemu_opt_get(opts, "driver"); + if (!driver) { + qerror_report(QERR_MISSING_PARAMETER, "driver"); + exit(1); + } + + if (!strcmp(driver, "cpu")) { + /* The device being added is a cpu */ + if (qemu_opt_get(opts, "name")) { + cpu = object_new(qemu_opt_get(opts, "name")); + } else { + cpu_oc = cpu_class_by_name(qemu_opt_get(opts, "type"), + qemu_opt_get(opts, "model")); + cpu = object_new(object_class_get_name(cpu_oc)); + } + + /* Set Properties */ + qemu_opt_foreach(opts, set_property, cpu, 1); + + object_property_set_bool(cpu, true, "realized", &err); + if (err) { + error_report("%s", error_get_pretty(err)); + exit(1); + } + + return NULL; + } + + if (!strcmp(driver, "memory")) { + /* The device being added is a memory controller */ + ram = g_new(MemoryRegion, 1); + + sscanf(qemu_opt_get(opts, "size"), "%X", (uint *) &ram_size); + sscanf(qemu_opt_get(opts, "addr"), "%X", (uint *) &addr); + + memory_region_init_ram(ram, NULL, qemu_opt_get(opts, "name"), + (uint) ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space_mem, (uint) addr, ram); + + return NULL; + } + + /* find the driver */ + oc = object_class_by_name(driver); + if (!oc) { + const char *typename = find_typename_by_alias(driver); + + if (typename) { + driver = typename; + oc = object_class_by_name(driver); + } + } + + if (!object_class_dynamic_cast(oc, TYPE_DEVICE)) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "'%s' is not a valid device model name", driver); + exit(1); + } + + if (object_class_is_abstract(oc)) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", + "non-abstract device type"); + exit(1); + } + + dc = DEVICE_CLASS(oc); + if (dc->cannot_instantiate_with_device_add_yet) { + /* Find the Bus */ + path = qemu_opt_get(opts, "bus"); + if (path != NULL) { + bus = qbus_find(path); + if (!bus) { + exit(1); + } + if (!object_dynamic_cast(OBJECT(bus), dc->bus_type)) { + qerror_report(QERR_BAD_BUS_FOR_DEVICE, + driver, object_get_typename(OBJECT(bus))); + exit(1); + } + } else if (dc->bus_type != NULL) { + bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type); + if (!bus) { + qerror_report(QERR_NO_BUS_FOR_DEVICE, + dc->bus_type, driver); + exit(1); + } + } + if (qdev_hotplug && bus && !bus->allow_hotplug) { + qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); + exit(1); + } + + /* create driver */ + dev = DEVICE(object_new(driver)); + + if (bus) { + qdev_set_parent_bus(dev, bus); + } + } else { + /* Init the device later */ + dev = NULL; + } + + opts->opaque = (void *) dev; + return dev; +} + +DeviceState *qdev_device_init(QemuOpts *opts, DeviceState* intc) +{ + DeviceClass *dc; + const char *driver; + DeviceState *dev = NULL; + + driver = qemu_opt_get(opts, "driver"); + if (!driver) { + qerror_report(QERR_MISSING_PARAMETER, "driver"); + exit(1); + } + + dev = (DeviceState *) opts->opaque; + + if (!dev) { + return NULL; + } + + dc = DEVICE_CLASS(object_class_by_name(driver)); + if (!dc->cannot_instantiate_with_device_add_yet) { + return NULL; + } + + /* Set Properties */ + if (qemu_opt_foreach(opts, set_property, dev, 1) != 0) { + object_unparent(OBJECT(dev)); + object_unref(OBJECT(dev)); + exit(1); + } + + qdev_init_nofail(dev); + + return dev; +} + +DeviceState *qdev_device_connect(QemuOpts *opts, DeviceState* intc) +{ + DeviceClass *dc; + const char *driver; + DeviceState *dev = NULL; + int irq, i, n = 0; + hwaddr addr; + + driver = qemu_opt_get(opts, "driver"); + if (!driver) { + qerror_report(QERR_MISSING_PARAMETER, "driver"); + exit(1); + } + + dev = (DeviceState *) opts->opaque; + + if (!dev) { + return NULL; + } + + dc = DEVICE_CLASS(object_class_by_name(driver)); + if (!dc->cannot_instantiate_with_device_add_yet) { + return NULL; + } + + if (qemu_opt_get(opts, "addr")) { + sscanf(qemu_opt_get(opts, "addr"), "%X", (uint *) &addr); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, (uint) addr); + } + + if (qemu_opt_get(opts, "irq") && intc) { + for (i = 0; ; i++) { + if (!qemu_opt_name_step(opts, i)) { + break; + } + if (strcmp(qemu_opt_name_step(opts, i), "irq")) { + continue; + } + + sscanf(qemu_opt_step(opts, i), "%d", &irq); + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, + qdev_get_gpio_in(intc, irq)); + + n++; + } + } else if (first_cpu && dev->num_gpio_in > 0) { + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + qdev_get_gpio_in(DEVICE(first_cpu), 0)); + } + + return dev; +} + #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) static void qbus_print(Monitor *mon, BusState *bus, int indent);