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);
 
