[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 2/4] qdev-monitor: Implement three functions used
From: |
Alistair Francis |
Subject: |
[Qemu-devel] [PATCH v2 2/4] qdev-monitor: Implement three functions used to connect devices |
Date: |
Fri, 11 Apr 2014 16:34:51 +1000 |
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 <address@hidden>
---
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);
--
1.7.1
- [Qemu-devel] [PATCH v2 0/4] Allow sysbus devices to be attached via commandline, Alistair Francis, 2014/04/11
- [Qemu-devel] [PATCH v2 1/4] qemu-option.c: Add qemu_opt functions that step over arguments, Alistair Francis, 2014/04/11
- [Qemu-devel] [PATCH v2 2/4] qdev-monitor: Implement three functions used to connect devices,
Alistair Francis <=
- [Qemu-devel] [PATCH v2 3/4] vl.c: Enable adding devices to the system bus, Alistair Francis, 2014/04/11
- [Qemu-devel] [PATCH v2 4/4] qemu-options.hx: Update the command line documentation for -device, Alistair Francis, 2014/04/11
- Re: [Qemu-devel] [PATCH v2 0/4] Allow sysbus devices to be attached via commandline, Alistair Francis, 2014/04/11
- Re: [Qemu-devel] [PATCH v2 0/4] Allow sysbus devices to be attached via commandline, Peter Maydell, 2014/04/11