From patchwork Wed Mar 26 00:47:00 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 333754 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 5A48514007F for ; Wed, 26 Mar 2014 11:47:40 +1100 (EST) Received: from localhost ([::1]:45040 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSc0H-0007Gd-C2 for incoming@patchwork.ozlabs.org; Tue, 25 Mar 2014 20:47:37 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39452) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSbzv-00079C-QV for qemu-devel@nongnu.org; Tue, 25 Mar 2014 20:47:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WSbzm-0002fE-SM for qemu-devel@nongnu.org; Tue, 25 Mar 2014 20:47:15 -0400 Received: from mail-qg0-x22e.google.com ([2607:f8b0:400d:c04::22e]:51130) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSbzm-0002eo-N2 for qemu-devel@nongnu.org; Tue, 25 Mar 2014 20:47:06 -0400 Received: by mail-qg0-f46.google.com with SMTP id e89so3484295qgf.5 for ; Tue, 25 Mar 2014 17:47:06 -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; bh=A6WakRTcF/ZIc37xmsfvSFfEan50/IZuqmAnHZS7Onw=; b=pXG+MDJWnuNHaULJdAtCFNVGdnnlm6FEnFC0b0gCYZD4Lk/0j6qyfvyQ3lSqBUB6cy vidHNFbURhYswkWjTpJN9szw0/FlquAb8gX3RgSs8IOYl2Etk2ypFE5+RJISryfJZw1t 45e3gTNfvYixZ8+egCjuBa4nTaO2IGi6G0vY7H03xk/RnhO48wxJHLIcrpNKXnyWDMak hDVkLZNli+JExJGlJzYXPUm8tVSG6WtoBivKJFgmxQjshuhK9Dc2gmz7aMDkMEH822aZ nEnqR45TdromuhlM7mE8zG0Hw/3EnitDboPThil8i4jqJr1Pxsy43iO5HC+m715cEfI0 SSNQ== X-Received: by 10.140.30.98 with SMTP id c89mr81155263qgc.13.1395794825962; Tue, 25 Mar 2014 17:47:05 -0700 (PDT) Received: from localhost ([203.126.243.116]) by mx.google.com with ESMTPSA id s13sm35589350qag.19.2014.03.25.17.47.04 for (version=TLSv1.1 cipher=RC4-SHA bits=128/128); Tue, 25 Mar 2014 17:47:05 -0700 (PDT) From: Alistair Francis To: qemu-devel@nongnu.org Date: Wed, 26 Mar 2014 10:47:00 +1000 Message-Id: X-Mailer: git-send-email 1.9.0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400d:c04::22e Cc: edgar.iglesias@xilinx.com, peter.crosthwaite@xilinx.com, afaerber@suse.de Subject: [Qemu-devel] [PATCH v1 1/1] vl.c: Allow sysbus devices to be attached via commandline 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 This patch introduces a new command line argument that allows sysbus devices to be attached via the command line. This allows devices to be added after the machine init but before anything is booted The new argument is -sysbusdev A new argument is being used to avoid confusion and user errors that would appear if the same command for hot-plugging was used instead. This could be changed to use -device and specify sysbus by using something like 'bus=sysbus' if that is preferred This patch requires the machine to support this, by passing the interrupt controller back to main() OR the device can be attached without an IRQ line An example usage is adding UART to zynq using these two options: -sysbusdev device=cadence_uart,addr=E0000000,irq=27 -sysbusdev device=cadence_uart,addr=E0001000,irq=50 Signed-off-by: Alistair Francis --- hw/arm/xilinx_zynq.c | 1 + include/hw/boards.h | 1 + include/monitor/qdev.h | 1 + include/sysemu/sysemu.h | 1 + qdev-monitor.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx | 13 +++++++++ vl.c | 27 ++++++++++++++++++- 7 files changed, 108 insertions(+), 1 deletions(-) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 9ee21e7..aae0863 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -172,6 +172,7 @@ static void zynq_init(QEMUMachineInitArgs *args) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000); dev = qdev_create(NULL, "a9mpcore_priv"); + args->intc = dev; qdev_prop_set_uint32(dev, "num-cpu", 1); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); diff --git a/include/hw/boards.h b/include/hw/boards.h index dd2c70d..112ea61 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -15,6 +15,7 @@ typedef struct QEMUMachineInitArgs { const char *kernel_cmdline; const char *initrd_filename; const char *cpu_model; + DeviceState *intc; } QEMUMachineInitArgs; typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args); diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h index 8d16e11..3d3afdc 100644 --- a/include/monitor/qdev.h +++ b/include/monitor/qdev.h @@ -11,5 +11,6 @@ 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_sysbusdev_add(QemuOpts *opts, DeviceState* intc); #endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 3915ce3..1f1a7b6 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -199,6 +199,7 @@ extern QemuOptsList qemu_common_drive_opts; extern QemuOptsList qemu_drive_opts; extern QemuOptsList qemu_chardev_opts; extern QemuOptsList qemu_device_opts; +extern QemuOptsList qemu_sysbusdev_opts; extern QemuOptsList qemu_netdev_opts; extern QemuOptsList qemu_net_opts; extern QemuOptsList qemu_global_opts; diff --git a/qdev-monitor.c b/qdev-monitor.c index 9268c87..ba68f88 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -566,6 +566,57 @@ DeviceState *qdev_device_add(QemuOpts *opts) return dev; } +DeviceState *qdev_sysbusdev_add(QemuOpts *opts, DeviceState* intc) +{ + + ObjectClass *oc; + const char *device; + hwaddr addr; + int irq; + + device = qemu_opt_get(opts, "device"); + if (!device) { + qerror_report(QERR_MISSING_PARAMETER, "device"); + return NULL; + } + + /* find the device */ + oc = object_class_by_name(device); + if (!oc) { + const char *typename = find_typename_by_alias(device); + + if (typename) { + device = typename; + oc = object_class_by_name(device); + } + } + + if (!object_class_dynamic_cast(oc, TYPE_DEVICE)) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "'%s' is not a valid device model name", device); + return NULL; + } + + if (object_class_is_abstract(oc)) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "device", + "non-abstract device type"); + return NULL; + } + + if (qemu_opt_get(opts, "addr") && qemu_opt_get(opts, "irq") && intc) { + sscanf(qemu_opt_get(opts, "addr"), "%X", (uint *) &addr); + sscanf(qemu_opt_get(opts, "irq"), "%d", &irq); + return sysbus_create_varargs(device, addr, + qdev_get_gpio_in(intc, irq), NULL); + } + + if (qemu_opt_get(opts, "addr")) { + sscanf(qemu_opt_get(opts, "addr"), "%X", (uint *) &addr); + return sysbus_create_varargs(device, addr, NULL); + } + + return NULL; +} #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) static void qbus_print(Monitor *mon, BusState *bus, int indent); @@ -712,6 +763,20 @@ QemuOptsList qemu_device_opts = { }, }; +QemuOptsList qemu_sysbusdev_opts = { + .name = "sysbusdev", + .implied_opt_name = "device", + .head = QTAILQ_HEAD_INITIALIZER(qemu_sysbusdev_opts.head), + .desc = { + /* + * no elements => accept any + * sanity checking will happen later + * when setting sysbusdev properties + */ + { /* end of list */ } + }, +}; + QemuOptsList qemu_global_opts = { .name = "global", .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head), diff --git a/qemu-options.hx b/qemu-options.hx index ee5437b..340fb5d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -327,6 +327,19 @@ possible drivers and properties, use @code{-device help} and @code{-device @var{driver},help}. ETEXI +DEF("sysbusdev", HAS_ARG, QEMU_OPTION_sysbusdev, + "-sysbusdev device=sysbusdevice[,prop[=value][,...]]\n" + " add a sysbus device\n" + " prop=value,... sets the sysbus properties\n", + QEMU_ARCH_ALL) +STEXI +@item -sysbusdev @var{device}[,@var{prop}[=@var{value}][,...]] +@findex -sysbusdev +Add sysbusdev @var{device}. @var{prop}=@var{value} sets sysbus +properties. Valid properties are device, addr and irq. Which specifies +the sysbus device name, base address and irq number respectivly. +ETEXI + DEF("name", HAS_ARG, QEMU_OPTION_name, "-name string1[,process=string2][,debug-threads=on|off]\n" " set the name of the guest\n" diff --git a/vl.c b/vl.c index 02bf8ec..c689d2b 100644 --- a/vl.c +++ b/vl.c @@ -2392,6 +2392,18 @@ static int device_init_func(QemuOpts *opts, void *opaque) return 0; } +static int sysbusdev_init_func(QemuOpts *opts, void *opaque) +{ + DeviceState *dev; + + dev = qdev_sysbusdev_add(opts, (DeviceState *) opaque); + if (!dev) { + return -1; + } + object_unref(OBJECT(dev)); + return 0; +} + static int chardev_init_func(QemuOpts *opts, void *opaque) { Error *local_err = NULL; @@ -2987,6 +2999,7 @@ int main(int argc, char **argv, char **envp) qemu_add_drive_opts(&qemu_drive_opts); qemu_add_opts(&qemu_chardev_opts); qemu_add_opts(&qemu_device_opts); + qemu_add_opts(&qemu_sysbusdev_opts); qemu_add_opts(&qemu_netdev_opts); qemu_add_opts(&qemu_net_opts); qemu_add_opts(&qemu_rtc_opts); @@ -3680,6 +3693,11 @@ int main(int argc, char **argv, char **envp) exit(1); } break; + case QEMU_OPTION_sysbusdev: + if (!qemu_opts_parse(qemu_find_opts("sysbusdev"), optarg, 0)) { + exit(1); + } + break; case QEMU_OPTION_smp: if (!qemu_opts_parse(qemu_find_opts("smp-opts"), optarg, 1)) { exit(1); @@ -4384,11 +4402,18 @@ int main(int argc, char **argv, char **envp) .kernel_filename = kernel_filename, .kernel_cmdline = kernel_cmdline, .initrd_filename = initrd_filename, - .cpu_model = cpu_model }; + .cpu_model = cpu_model, + .intc = NULL }; current_machine->init_args = args; machine->init(¤t_machine->init_args); + /* Init sysbus devices */ + if (qemu_opts_foreach(qemu_find_opts("sysbusdev"), sysbusdev_init_func, + current_machine->init_args.intc, 1) != 0) { + exit(1); + } + audio_init(); cpu_synchronize_all_post_init();