All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] Machine description as data prototype, take 3 (was: [RFC] Machine description as data)
Date: Thu, 19 Feb 2009 11:29:52 +0100	[thread overview]
Message-ID: <871vtuafdr.fsf@pike.pond.sub.org> (raw)
In-Reply-To: <87iqnh6kyv.fsf@pike.pond.sub.org> (Markus Armbruster's message of "Wed\, 11 Feb 2009 16\:40\:08 +0100")

Third iteration of the prototype.

What about an early merge?  If your answer to that is "yes, but", what
exactly do you want changed?

New:

* Rebased to git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6626 c046a42c-6fe2-441c-8c8c-71466251a162

* Code duplication cleaned up.  I chose minimizing the impact on pc.c
  over nice, clean interfaces.  Happy to rework it if that was the wrong
  choice.  I think there are a few opportunities for cleanup that would
  improve pc.c even without taking dt.c into consideration.  I can work
  on patches if you like.

* The "device required" edges moved from struct tree to struct dt_device
  to make the configuration tree more similar to FDTs structurally.

* A bunch of pointless typedefs to hopefully blend in better
  stylistically.  Tabs expanded.  If style issues remain, please point
  them out to me!

Shortcuts:

* I didn't implement all the devices of the "pc" original.  The devices
  I implemented might not support all existing command line options.

* The initial configuration tree is hardcoded.  It should be read from a
  configuration file.

* Optional stuff is inserted into the initial configuration tree in
  hardcoded places.  We should use suitable markers in the configuration
  file instead.

* Linux gripes about ACPI, need to investigate.

Notable qualities:

* Linux still boots & shuts down cleanly (except for the ACPI gripes).

* Machine and host configuration are cleanly separated.  Machine
  configuration enumerates the components of the virtual machine, and
  how they are connected.  It is a tree of devices nodes.  Host
  configuration is about how the host implements virtual devices.
  Currently just a few flat tables.

* Device drivers implement a common abstract interface.

* Device drivers are cleanly separated from each other, and from the
  device-agnostic machine configuration and initialization code.

* Each device driver specifies its configurable properties in a single
  place.  Unknown properties are rejected.

* A device driver gets its configuration from two sources: the device's
  node in the machine configuraton tree, and applicable host
  configuration tables.


 Makefile              |    1 +
 Makefile.target       |    4 +
 hw/dt.c               | 1225 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc.c               |   47 +--
 hw/pcint.h            |   46 ++
 net.c                 |    2 +-
 net.h                 |    1 +
 target-i386/machine.c |    2 +
 tree.c                |  298 ++++++++++++
 tree.h                |   40 ++
 10 files changed, 1638 insertions(+), 28 deletions(-)


diff --git a/Makefile b/Makefile
index 4f7a55a..2198bba 100644
--- a/Makefile
+++ b/Makefile
@@ -85,6 +85,7 @@ OBJS+=sd.o ssi-sd.o
 OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
 OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
 OBJS+=qemu-char.o aio.o net-checksum.o savevm.o cache-utils.o
+OBJS+=tree.o
 
 ifdef CONFIG_BRLAPI
 OBJS+= baum.o
diff --git a/Makefile.target b/Makefile.target
index 9e7a1bb..ad254ad 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -583,8 +583,12 @@ OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
 OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
 OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
+OBJS+= dt.o
 OBJS += device-hotplug.o pci-hotplug.o
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
+ifdef FDT_LIBS
+LIBS+= $(FDT_LIBS)
+endif
 endif
 ifeq ($(TARGET_BASE_ARCH), ppc)
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
diff --git a/hw/dt.c b/hw/dt.c
new file mode 100644
index 0000000..f57668b
--- /dev/null
+++ b/hw/dt.c
@@ -0,0 +1,1225 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * 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.
+ */
+
+/*
+ * Configure and build a machine from configuration data
+ *
+ * The idea is to have generic, device-independent code driven by
+ * device-dependent configuration data, talking to devices through an
+ * abstract device interface.
+ *
+ * For now, this lives in hw/, even though that's not where generic,
+ * device independent code belongs.  This is just so we can minimize
+ * disruption by hiding completely behind the existing QEMUMachine
+ * abstraction.
+ *
+ * The configuration data currently is hardwired to a fairly limited
+ * PC, registered as machine type "pcdt".  The nuts and bolts of PC
+ * emulation remain in pc.c, and that sharing makes the somewhat
+ * clumsy pcint.h necessary.  Having two PC machine types makes no
+ * sense in the long run, of course.  We want to replace pc.c
+ * eventually, and also convert other machine types to this mechanism.
+ */
+
+#include <assert.h>
+#include "hw.h"
+#include "pc.h"
+#include "fdc.h"
+#include "pci.h"
+#include "block.h"
+#include "sysemu.h"
+#include "audio/audio.h"
+#include "net.h"
+#include "smbus.h"
+#include "boards.h"
+#include "console.h"
+#include "fw_cfg.h"
+#include "virtio-blk.h"
+#include "virtio-balloon.h"
+#include "virtio-console.h"
+#include "hpet_emul.h"
+#include "pcint.h"
+#include "tree.h"
+
+#ifdef HAVE_FDT
+#include <libfdt.h>
+#endif
+
+/* Forward declarations */
+typedef struct dt_device dt_device;
+typedef struct dt_tree_list dt_tree_list;
+typedef struct dt_driver dt_driver;
+typedef struct dt_prop_spec dt_prop_spec;
+static void dt_parse_prop(dt_device *dev, tree_prop *prop);
+static BlockDriverState **dt_piix3_hd(tree *piix3);
+
+\f

+/* Host Configuration */
+
+typedef struct dt_host {
+    /* connection NICs <-> VLAN */
+    tree *nic[MAX_NICS];
+    VLANState *nic_vlan[MAX_NICS];
+    /* connection drives <-> controller */
+    tree *drive_ctrl[MAX_DRIVES];
+    BlockDriverState *drive_state[MAX_DRIVES];
+} dt_host;
+
+static void
+dt_attach_nic(dt_host *host, int index,
+              tree *nic, VLANState *vlan)
+{
+    host->nic[index] = nic;
+    host->nic_vlan[index] = vlan;
+}
+
+static VLANState *
+dt_find_vlan(tree *conf, dt_host *host)
+{
+    int i;
+
+    for (i = 0; i < MAX_NICS; i++) {
+        if (host->nic[i] == conf)
+            return host->nic_vlan[i];
+    }
+    return NULL;
+}
+
+static void
+dt_attach_drive(dt_host *host, int index,
+                tree *controller, BlockDriverState *state)
+{
+    host->drive_ctrl[index] = controller;
+    host->drive_state[index] = state;
+}
+
+static void
+dt_drive_config(tree *conf, dt_host *host,
+                BlockDriverState *drive[], int n)
+{
+    int i, j;
+
+    j = 0;
+    for (i = 0; i < MAX_DRIVES; i++) {
+        if (host->drive_ctrl[i] != conf)
+            continue;
+        assert(j < n);
+        drive[j++] = host->drive_state[i];
+    }
+}
+
+static void
+dt_print_host_config(dt_host *host)
+{
+    char buf[1024];
+    int i;
+
+    for (i = 0; i < MAX_NICS; i++) {
+        if (!host->nic[i])
+            continue;
+        tree_path(host->nic[i], buf, sizeof(buf));
+        printf("nic#%d\tvlan %-4d\t%s\n",
+               i, host->nic_vlan[i]->id, buf);
+    }
+
+    for (i = 0; i < MAX_DRIVES; i++) {
+        if (!host->drive_ctrl[i])
+            continue;
+        tree_path(host->drive_ctrl[i], buf, sizeof(buf));
+        printf("drive#%d\t%-15s %s\n",
+               i, bdrv_get_device_name(host->drive_state[i]), buf);
+    }
+}
+
+\f

+/* Device Interface */
+
+/*
+ * Device life cycle:
+ *
+ * 1. Configuration: config() method runs after parent's.  Except kids
+ * are skipped when the parent's config() returns non-zero.  config()
+ * should initialize the device's private data from its configuration
+ * sub-tree.  It may edit the configuration sub-tree, and may declare
+ * initialization ordering constraints with tree_require_named().
+ *
+ * 2. Initialization: init() method runs after parent's and after that
+ * of devices declared required by config().  It should not touch the
+ * configuration tree.
+ *
+ * 3. Start: start() method runs, order is unspecified.
+ *
+ * Error handling in these driver methods: print to stderr and exit
+ * the program unsuccessfully.
+ *
+ * There is no device shutdown protocol yet.
+ */
+
+struct dt_device {
+    tree *conf;                 /* configuration sub-tree */
+    dt_driver *drv;             /* device driver */
+    LIST_HEAD(, dt_tree_list) reqs; /* required devices */
+    int visit;                  /* for dt_visit() */
+    void *priv;                 /* device private data */
+};
+
+struct dt_tree_list {
+    tree *conf;
+    LIST_ENTRY(dt_tree_list) link;
+};
+
+struct dt_driver {
+    const char *name;
+    size_t privsz;              /* size of device private data */
+    dt_prop_spec *prop_spec;    /* recognized conf node properties */
+    int (*config)(dt_device *, dt_host *);
+    void (*init)(dt_device *);
+    void (*start)(dt_device *);
+};
+
+static dt_driver dt_driver_table[];
+
+static dt_driver *
+dt_driver_by_name(const char *name)
+{
+    int i;
+
+    for (i = 0; dt_driver_table[i].name; i++) {
+        if (!strcmp(name, dt_driver_table[i].name))
+            return &dt_driver_table[i];
+    }
+    return NULL;
+}
+
+static dt_device *
+dt_device_of(tree *conf)
+{
+    return tree_get_user(conf);
+}
+
+static dt_device *
+dt_parent_device(dt_device *dev)
+{
+    tree *p = tree_parent(dev->conf);
+
+    return p ? dt_device_of(p) : NULL;
+}
+
+static dt_device *
+dt_new_device(tree *conf, dt_driver *drv)
+{
+    dt_device *dev;
+    tree_prop *prop;
+
+    dev = qemu_malloc(sizeof(*dev));
+    dev->conf = conf;
+    dev->drv = drv;
+    LIST_INIT(&dev->reqs);
+    dev->visit = 0;
+    dev->priv = qemu_malloc(drv->privsz);
+    tree_put_user(conf, dev);
+
+    TREE_FOREACH_PROP(prop, conf)
+        dt_parse_prop(dev, prop);
+
+    return dev;
+}
+
+static void
+dt_config(tree *conf, dt_host *host)
+{
+    dt_driver *drv;
+    dt_device *dev;
+    tree *kid;
+
+    drv = dt_driver_by_name(tree_node_name(conf));
+    if (!drv) {
+        fprintf(stderr, "No driver for device %s\n",
+                tree_node_name(conf));
+        exit(1);
+    }
+    dev = dt_new_device(conf, drv);
+    if (drv->config) {
+        if (drv->config(dev, host))
+            return;
+    }
+
+    TREE_FOREACH_KID(kid, conf)
+        dt_config(kid, host);
+}
+
+static tree *
+dt_require_named(dt_device *dev, const char *reqname)
+{
+    dt_tree_list *l = qemu_malloc(sizeof(*l));
+
+    l->conf = tree_node_by_name(dev->conf, reqname);
+    LIST_INSERT_HEAD(&dev->reqs, l, link);
+    return l->conf;
+}
+
+static void
+dt_do_visit(dt_device *dev,
+            void (*fun)(dt_device *, void *arg),
+            void *arg, int visit)
+{
+    dt_device *parent, *req, *kid;
+    dt_tree_list *l;
+    tree *k;
+
+    assert(dev->visit < visit - 1);
+    dev->visit = visit - 1;
+    parent = dt_parent_device(dev);
+    if (parent && parent->visit < visit)
+        dt_do_visit(parent, fun, arg, visit);
+    LIST_FOREACH(l, &dev->reqs, link) {
+        req = dt_device_of(l->conf);
+        if (req->visit < visit)
+            dt_do_visit(req, fun, arg, visit);
+    }
+    dev->visit = visit;
+    fun(dev, arg);
+    TREE_FOREACH_KID(k, dev->conf) {
+        kid = dt_device_of(k);
+        if (kid->visit < visit - 1)
+            dt_do_visit(kid, fun, arg, visit);
+    }
+}
+
+static void
+dt_visit(tree *node,
+         void (*fun)(dt_device *, void *arg),
+         void *arg)
+{
+    static int visit;
+
+    visit += 2;
+    dt_do_visit(dt_device_of(node), fun, arg, visit);
+}
+
+static void
+dt_init_visitor(dt_device *dev, void *arg)
+{
+    if (dev->drv->init)
+        dev->drv->init(dev);
+}
+
+static void
+dt_init(tree *conf)
+{
+    dt_visit(conf, dt_init_visitor, NULL);
+}
+
+static void
+dt_start(tree *conf)
+{
+    dt_device *dev = dt_device_of(conf);
+    tree *kid;
+
+    if (dev && dev->drv->start)
+        dev->drv->start(dev);
+
+    TREE_FOREACH_KID(kid, conf)
+        dt_start(kid);
+}
+
+\f

+/* Device properties */
+
+/*
+ * This is for parsing configuration tree node properties into device
+ * private data.
+ */
+
+struct dt_prop_spec {
+    const char *name;
+    ptrdiff_t offs;             /* offset in device private data */
+    size_t size;                /* size there, for sanity checking */
+    int (*parse)(void *, const char *, dt_prop_spec *);
+};
+
+#define DT_PROP_SPEC_INIT(name, strty, member, fmt)                     \
+    { name, offsetof(strty, member), sizeof(((strty *)0)->member),      \
+      dt_parse_##fmt }
+
+static dt_prop_spec *
+dt_prop_spec_by_name(dt_driver *drv, const char *name)
+{
+    dt_prop_spec *spec;
+
+    for (spec = drv->prop_spec; spec && spec->name; spec++) {
+        if (!strcmp(spec->name, name))
+            return spec;
+    }
+    return NULL;
+}
+
+static void
+dt_parse_prop(dt_device *dev, tree_prop *prop)
+{
+    const char *name = tree_prop_name(prop);
+    size_t size;
+    const char *val = tree_prop_value(prop, &size);
+    dt_prop_spec *spec = dt_prop_spec_by_name(dev->drv, name);
+
+    if (!spec) {
+        fprintf(stderr, "A %s device has no property %s\n",
+                dev->drv->name, name);
+        exit(1);
+    }
+
+    if (memchr(val, 0, size) != val + size - 1
+        || spec->parse((char *)dev->priv + spec->offs, val, spec) < 0) {
+        fprintf(stderr, "Bad value %.*s for property %s of device %s\n",
+                size, val, name, dev->drv->name);
+        exit(1);
+    }
+}
+
+static int
+dt_parse_string(void *dst, const char *src, dt_prop_spec *spec)
+{
+    assert(spec->size == sizeof(char *));
+    *(const char **)dst = src;
+    return 0;
+}
+
+static int
+dt_parse_int(void *dst, const char *src, dt_prop_spec *spec)
+{
+    char *ep;
+    long val;
+
+    assert(spec->size == sizeof(int));
+    errno = 0;
+    val = strtol(src, &ep, 0);
+    if (*ep || ep == src || errno || (int)val != val)
+        return -1;
+    *(int *)dst = val;
+    return 0;
+}
+
+static int
+dt_parse_ram_addr_t(void *dst, const char *src, dt_prop_spec *spec)
+{
+    char *ep;
+    unsigned long val;
+
+    assert(spec->size == sizeof(ram_addr_t));
+    errno = 0;
+    val = strtoul(src, &ep, 0);
+    if (*ep || ep == src || errno || (ram_addr_t)val != val)
+        return -1;
+    *(ram_addr_t *)dst = val;
+    return 0;
+}
+
+static int
+dt_parse_macaddr(void *dst, const char *src, dt_prop_spec *spec)
+{
+    assert(spec->size == 6);
+    if (parse_macaddr(dst, src) < 0)
+        return -1;
+    return 0;
+}
+
+\f

+/* Interfacing with FDT */
+
+/*
+ * Note: translation to FDT loses the association between
+ * configuration tree nodes and devices.
+ */
+
+#ifdef HAVE_FDT
+
+static int dt_fdt_chk(int res);
+static void dt_subtree_to_fdt(const tree *conf, void *fdt);
+
+static void *
+dt_tree_to_fdt(const tree *conf)
+{
+    int sz = 1024 * 1024;       /* FIXME arbitrary limit */
+    void *fdt = qemu_malloc(sz);
+
+    dt_fdt_chk(fdt_create(fdt, sz));
+    dt_subtree_to_fdt(conf, fdt);
+    dt_fdt_chk(fdt_finish(fdt));
+    return fdt;
+}
+
+static void
+dt_subtree_to_fdt(const tree *conf, void *fdt)
+{
+    tree_prop *prop;
+    tree *kid;
+    const void *pv;
+    size_t sz;
+
+    dt_fdt_chk(fdt_begin_node(fdt, tree_node_name(conf)));
+    TREE_FOREACH_PROP(prop, conf) {
+        pv = tree_prop_value(prop, &sz);
+        dt_fdt_chk(fdt_property(fdt, tree_prop_name(prop), pv, sz));
+    }
+    TREE_FOREACH_KID(kid, conf)
+        dt_subtree_to_fdt(kid, fdt);
+    dt_fdt_chk(fdt_end_node(fdt));
+}
+
+static tree *
+dt_fdt_to_tree(const void *fdt)
+{
+    int offs, next, depth;
+    uint32_t tag;
+    struct fdt_property *prop;
+    tree *stack[32];            /* FIXME arbitrary limit */
+
+    stack[0] = NULL;            /* "parent" of root */
+    next = depth = 0;
+
+    for (;;) {
+        offs = next;
+        tag = fdt_next_tag(fdt, offs, &next);
+        switch (tag) {
+        case FDT_PROP:
+            /*
+             * libfdt apparently doesn't provide a way to get property
+             * by offset, do it by hand
+             */
+            assert(0 < depth && depth < sizeof(stack) / sizeof(*stack));
+            prop = (void *)(const char *)fdt + fdt_off_dt_struct(fdt) + offs;
+            tree_put_prop(stack[depth],
+                          fdt_string(fdt, fdt32_to_cpu(prop->nameoff)),
+                          prop->data,
+                          fdt32_to_cpu(prop->len));
+        case FDT_NOP:
+            break;
+        case FDT_BEGIN_NODE:
+            depth++;
+            assert(0 < depth && depth < sizeof(stack) / sizeof(*stack));
+            stack[depth] = tree_new_kid(stack[depth-1],
+                                        fdt_get_name(fdt, offs, NULL),
+                                        NULL);
+            break;
+        case FDT_END_NODE:
+            depth--;
+            break;
+        case FDT_END:
+            dt_fdt_chk(next);
+            return stack[1];
+        }
+    }
+}
+
+static int
+dt_fdt_chk(int res)
+{
+    if (res < 0) {
+        fprintf(stderr, "%s\n", fdt_strerror(res)); /* FIXME cryptic */
+        exit(1);
+    }
+    return res;
+}
+
+static void
+dt_fdt_test(tree *conf)
+{
+    void *fdt;
+
+    fdt = dt_tree_to_fdt(conf);
+    conf = dt_fdt_to_tree(fdt);
+    tree_print(conf);
+    free(fdt);
+}
+#else
+static void dt_fdt_test(tree *conf) { }
+#endif
+\f

+/* CPUs Driver */
+
+typedef struct dt_device_cpus {
+    const char *model;
+    int num;
+} dt_device_cpus;
+
+static dt_prop_spec dt_cpus_props[] = {
+    DT_PROP_SPEC_INIT("model", dt_device_cpus, model, string),
+    DT_PROP_SPEC_INIT("num", dt_device_cpus, num, int),
+};
+
+static void
+dt_cpus_init(dt_device *dev)
+{
+    dt_device_cpus *priv = dev->priv;
+    int i;
+    CPUState *env;
+
+    for(i = 0; i < priv->num; i++) {
+        env = cpu_init(priv->model);
+        if (!env) {
+            fprintf(stderr, "Unable to find x86 CPU definition\n");
+            exit(1);
+        }
+        if (i != 0)
+            env->halted = 1;
+        qemu_register_reset(main_cpu_reset, env);
+    }
+}
+
+\f

+/* Memory Ranges */
+
+typedef struct dt_device_memrng {
+    target_phys_addr_t phys_addr;
+    ram_addr_t size;
+    ram_addr_t host_offs;
+    ram_addr_t flags;
+} dt_device_memrng;
+
+static void
+dt_memrng(dt_device_memrng *rng,
+          target_phys_addr_t phys_addr, ram_addr_t size,
+          ram_addr_t host_offs, ram_addr_t flags)
+{
+    rng->phys_addr = phys_addr;
+    rng->size = size;
+    rng->host_offs = host_offs;
+    rng->flags = flags;
+}
+
+static void
+dt_memrng_ram(dt_device_memrng *rng,
+              target_phys_addr_t phys_addr, ram_addr_t size)
+{
+    dt_memrng(rng, phys_addr, size, qemu_ram_alloc(size), 0);
+}
+
+static void
+dt_memrng_rom(dt_device_memrng *rng,
+              target_phys_addr_t phys_addr, ram_addr_t maxsz,
+              const char *dir, const char *image, int top)
+{
+    char buf[1024];
+    int size;
+
+    snprintf(buf, sizeof(buf), "%s/%s", dir, image);
+    size = get_image_size(buf);
+    if (size < 0 || size > maxsz)
+        goto error;
+    if (top)
+        phys_addr = phys_addr + maxsz - size;
+    dt_memrng(rng, phys_addr, size, qemu_ram_alloc(size), IO_MEM_ROM);
+    if (load_image(buf, phys_ram_base + rng->host_offs) != size)
+        goto error;
+    return;
+
+error:
+    fprintf(stderr, "qemu: could not load image '%s'\n", buf);
+    exit(1);
+}
+
+static void
+dt_memrng_init(dt_device_memrng *rng, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++)
+        cpu_register_physical_memory(rng[i].phys_addr, rng[i].size,
+                                     rng[i].host_offs | rng[i].flags);
+}
+
+\f

+/* Memory Driver */
+
+typedef struct dt_device_memory {
+    ram_addr_t ram_size;
+    dt_device_memrng *rng;
+    int nrng;
+    /* TODO want a real memory map here */
+    ram_addr_t below_4g, above_4g;
+} dt_device_memory;
+
+static dt_prop_spec dt_memory_props[] = {
+    DT_PROP_SPEC_INIT("ram", dt_device_memory, ram_size, ram_addr_t),
+};
+
+static int
+dt_memory_config(dt_device *dev, dt_host *host)
+{
+    /* TODO memory map hardcoded; get it from dev->conf instead */
+    dt_device_memory *priv = dev->priv;
+    dt_device_memrng *rng = qemu_malloc(sizeof(*rng) * 4);
+
+    if (priv->ram_size >= 0xe0000000 ) {
+        priv->above_4g = priv->ram_size - 0xe0000000;
+        priv->below_4g = 0xe0000000;
+    } else {
+        priv->below_4g = priv->ram_size;
+        priv->above_4g = 0;
+    }
+
+    dt_memrng_ram(&rng[0], 0, 0xa0000);
+    qemu_ram_alloc(0x60000);
+    dt_memrng_ram(&rng[1], 0x100000, priv->below_4g - 0x100000);
+    if (priv->above_4g)
+        abort();                /* TODO */
+    dt_memrng_rom(&rng[2], 0xe0000000, 0x20000000,
+                  bios_dir, BIOS_FILENAME, 1);
+                                /* TODO get name from dev->conf */
+    dt_memrng(&rng[3], 0xe0000, 0x20000,
+              rng[2].host_offs + rng[2].size - 0x20000, IO_MEM_ROM);
+    /* TODO option ROMs */
+
+    priv->rng = rng;
+    priv->nrng = 4;
+    return 0;
+}
+
+static void
+dt_memory_init(dt_device *dev)
+{
+    dt_device_memory *priv = dev->priv;
+
+    dt_memrng_init(priv->rng, priv->nrng);
+    bochs_bios_init();
+}
+
+static ram_addr_t
+dt_memory_below_4g(tree *memory)
+{
+    dt_device *dev = dt_device_of(memory);
+    dt_device_memory *priv = dev->priv;
+    assert(dev->drv->init == dt_memory_init);
+    return priv->below_4g;
+}
+
+static ram_addr_t
+dt_memory_above_4g(tree *memory)
+{
+    dt_device *dev = dt_device_of(memory);
+    dt_device_memory *priv = dev->priv;
+    assert(dev->drv->init == dt_memory_init);
+    return priv->above_4g;
+}
+
+\f

+/* PC Miscellanous Driver */
+
+/*
+ * This is a driver for a whole collection of devices.  Could be
+ * picked apart into separate drivers, I guess.
+ */
+
+typedef struct dt_device_pc_misc {
+    const char *boot_device;
+    int apic;
+    int hpet;
+    qemu_irq *i8259;
+    BlockDriverState *fd[MAX_FD];
+} dt_device_pc_misc;
+
+static dt_prop_spec dt_pc_misc_props[] = {
+    DT_PROP_SPEC_INIT("boot-device", dt_device_pc_misc, boot_device,
+                      string),
+};
+
+static int
+dt_pc_misc_config(dt_device *dev, dt_host *host)
+{
+    dt_device_pc_misc *priv = dev->priv;
+
+    priv->apic = 1;
+    priv->hpet = 1;
+    priv->i8259 = NULL;
+    dt_drive_config(dev->conf, host,
+                    priv->fd, sizeof(priv->fd) / sizeof(*priv->fd));
+    return 1;
+}
+
+static void
+dt_pc_misc_init(dt_device *dev)
+{
+    dt_device_pc_misc *priv = dev->priv;
+    CPUState *env;
+    qemu_irq *cpu_irq;
+    IOAPICState *ioapic;
+    PITState *pit;
+    int i;
+
+    if (priv->apic) {
+        for (env = first_cpu; env; env = env->next_cpu) {
+            env->cpuid_features |= CPUID_APIC;
+            apic_init(env);
+        }
+    }
+
+    vmport_init();
+
+    cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
+    priv->i8259 = i8259_init(cpu_irq[0]);
+    ferr_irq = priv->i8259[13];
+
+    register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
+    register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
+
+    rtc_state = rtc_init(0x70, priv->i8259[8], 2000);
+    qemu_register_boot_set(pc_boot_set, rtc_state);
+
+    register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
+    register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
+
+    if (priv->apic) {
+        ioapic = ioapic_init();
+        pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
+    }
+
+    pit = pit_init(0x40, priv->i8259[0]);
+    pcspk_init(pit);
+    if (priv->hpet)
+        hpet_init(priv->i8259);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_init(serial_io[i], priv->i8259[serial_irq[i]], 115200,
+                        serial_hds[i]);
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        if (parallel_hds[i]) {
+            parallel_init(parallel_io[i], priv->i8259[parallel_irq[i]],
+                          parallel_hds[i]);
+        }
+    }
+
+    i8042_init(priv->i8259[1], priv->i8259[12], 0x60);
+    DMA_init(0);
+
+    floppy_controller = fdctrl_init(priv->i8259[6], 2, 0, 0x3f0, priv->fd);
+}
+
+static void
+dt_pc_misc_start(dt_device *dev)
+{
+    dt_device_pc_misc *priv = dev->priv;
+    tree *memory = tree_node_by_name(dev->conf, "/memory");
+    tree *piix3 = tree_node_by_name(dev->conf, "/pci/piix3");
+
+    cmos_init(dt_memory_below_4g(memory),
+              dt_memory_above_4g(memory),
+              priv->boot_device,
+              dt_piix3_hd(piix3));
+}
+
+static qemu_irq *
+dt_pc_misc_i8259(tree *pc_misc)
+{
+    dt_device *dev = dt_device_of(pc_misc);
+    dt_device_pc_misc *priv = dev->priv;
+    assert(dev->drv->init == dt_pc_misc_init);
+    return priv->i8259;
+}
+
+\f

+/* PCI Bus Driver */
+
+typedef struct dt_device_pci {
+    PCIBus *bus;
+    tree *pc;
+} dt_device_pci;
+
+static int
+dt_pci_config(dt_device *dev, dt_host *host)
+{
+    dt_device_pci *priv = dev->priv;
+
+    priv->bus = NULL;
+    priv->pc = dt_require_named(dev, "/pc-misc");
+    return 0;
+}
+
+static void
+dt_pci_init(dt_device *dev)
+{
+    dt_device_pci *priv = dev->priv;
+
+    priv->bus = i440fx_init(&i440fx_state, dt_pc_misc_i8259(priv->pc));
+}
+
+static void
+dt_pci_start(dt_device *dev)
+{
+    i440fx_init_memory_mappings(i440fx_state);
+}
+
+static void
+dt_must_be_on_pcibus(dt_device *dev)
+{
+    dt_device *bus = dt_parent_device(dev);
+
+    if (bus->drv->init != dt_pci_init) {
+        fprintf(stderr, "Device %s must be on a PCI bus\n", dev->drv->name);
+        exit(1);
+    }
+}
+
+static PCIBus *
+dt_get_pcibus(dt_device *dev)
+{
+    dt_device *bus = dt_parent_device(dev);
+
+    assert(bus->drv->init == dt_pci_init);
+    return ((dt_device_pci *)bus->priv)->bus;
+}
+
+\f

+/* PIIX3 Driver */
+
+typedef struct dt_device_piix3 {
+    int devfn;
+    int acpi;
+    int usb;
+    tree *pc;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+} dt_device_piix3;
+
+static int
+dt_piix3_config(dt_device *dev, dt_host *host)
+{
+    dt_device_piix3 *priv = dev->priv;
+
+    priv->devfn = -1;
+    priv->acpi = 1;
+    priv->usb = 1;
+    priv->pc = dt_require_named(dev, "/pc-misc");
+    dt_drive_config(dev->conf, host,
+                    priv->hd, sizeof(priv->hd) / sizeof(*priv->hd));
+    dt_must_be_on_pcibus(dev);
+    return 1;
+}
+
+static void
+dt_piix3_init(dt_device *dev)
+{
+    dt_device_piix3 *priv = dev->priv;
+    PCIBus *pci_bus = dt_get_pcibus(dev);
+    qemu_irq *i8259 = dt_pc_misc_i8259(priv->pc);
+    int i;
+
+    priv->devfn = piix3_init(pci_bus, priv->devfn);
+
+    pci_piix3_ide_init(pci_bus, priv->hd, priv->devfn + 1, i8259);
+
+    if (priv->usb)
+        usb_uhci_piix3_init(pci_bus, priv->devfn + 2);
+
+    if (priv->acpi) {
+        uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+        i2c_bus *smbus;
+
+        /* TODO: Populate SPD eeprom data.  */
+        smbus = piix4_pm_init(pci_bus, priv->devfn + 3, 0xb100, i8259[9]);
+        for (i = 0; i < 8; i++)
+            smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));
+    }
+}
+
+static BlockDriverState **
+dt_piix3_hd(tree *piix3)
+{
+    dt_device *dev = dt_device_of(piix3);
+    dt_device_piix3 *priv = dev->priv;
+
+    assert(dev->drv->init == dt_piix3_init);
+    return priv->hd;
+}
+
+\f

+/* VGA Driver */
+
+typedef struct dt_driver_vga {
+    const char *model;
+    const char *bios;
+    void (*init)(PCIBus *, uint8_t *, ram_addr_t, int);
+} dt_driver_vga;
+
+static void
+pci_vmsvga_init_(PCIBus *bus, uint8_t *vga_ram_base,
+                 ram_addr_t vga_ram_offset, int vga_ram_size)
+{
+    pci_vmsvga_init(bus, vga_ram_base, vga_ram_offset, vga_ram_size);
+}
+
+static void
+pci_vga_init_(PCIBus *bus, uint8_t *vga_ram_base,
+              ram_addr_t vga_ram_offset, int vga_ram_size)
+{
+    pci_vga_init(bus, vga_ram_base, vga_ram_offset, vga_ram_size, 0, 0);
+}
+
+static dt_driver_vga dt_driver_vga_table[] = {
+    { "cirrus", VGABIOS_CIRRUS_FILENAME, pci_cirrus_vga_init },
+    { "vms", VGABIOS_FILENAME, pci_vmsvga_init_ },
+    { "std", VGABIOS_FILENAME, pci_vga_init_ },
+    { NULL, NULL, NULL }
+};
+
+typedef struct dt_device_vga {
+    const char *model;
+    ram_addr_t ram_size;
+    dt_device_memrng rng[1];
+    ram_addr_t ram_offs;
+    dt_driver_vga *vga_drv;
+} dt_device_vga;
+
+static dt_prop_spec dt_vga_props[] = {
+    DT_PROP_SPEC_INIT("model", dt_device_vga, model, string),
+    DT_PROP_SPEC_INIT("ram", dt_device_vga, ram_size, ram_addr_t),
+};
+
+static int
+dt_vga_config(dt_device *dev, dt_host *host)
+{
+    dt_device_vga *priv = dev->priv;
+    int i;
+
+    dt_memrng_rom(&priv->rng[0], 0xc0000, 0x10000,
+                  bios_dir, VGABIOS_CIRRUS_FILENAME, 0);
+                                /* TODO get name from dev->conf */
+    priv->ram_offs = qemu_ram_alloc(priv->ram_size);
+
+    for (i = 0; dt_driver_vga_table[i].model; i++) {
+        if (!strcmp(dt_driver_vga_table[i].model, priv->model))
+            break;
+    }
+    if (!dt_driver_vga_table[i].model) {
+        fprintf(stderr, "Unknown VGA model %s\n", priv->model);
+        exit(1);
+    }
+    priv->vga_drv = &dt_driver_vga_table[i];
+    dt_must_be_on_pcibus(dev);
+    return 0;
+}
+
+static void
+dt_vga_init(dt_device *dev)
+{
+    dt_device_vga *priv = dev->priv;
+
+    dt_memrng_init(priv->rng, 1);
+    priv->vga_drv->init(dt_get_pcibus(dev),
+                        phys_ram_base + priv->ram_offs,
+                        priv->ram_offs, priv->ram_size);
+}
+
+\f

+/* NIC Driver */
+
+typedef struct dt_device_nic {
+    NICInfo nd;
+} dt_device_nic;
+
+static dt_prop_spec dt_nic_props[] = {
+    DT_PROP_SPEC_INIT("model", dt_device_nic, nd.model, string),
+    DT_PROP_SPEC_INIT("mac", dt_device_nic, nd.macaddr, macaddr),
+    DT_PROP_SPEC_INIT("name", dt_device_nic, nd.name, string),
+};
+
+static int
+dt_nic_config(dt_device *dev, dt_host *host)
+{
+    dt_device_nic *priv = dev->priv;
+
+    priv->nd.vlan = dt_find_vlan(dev->conf, host);
+    dt_must_be_on_pcibus(dev);
+    return 0;
+}
+
+static void
+dt_nic_init(dt_device *dev)
+{
+    dt_device_nic *priv = dev->priv;
+
+    pci_nic_init(dt_get_pcibus(dev), &priv->nd, -1, NULL);
+}
+
+\f

+/* Machine Driver */
+
+static dt_driver dt_driver_table[] = {
+    { "", 0, NULL, NULL },
+    { "cpus", sizeof(dt_device_cpus), dt_cpus_props,
+      NULL, dt_cpus_init, NULL },
+    { "memory", sizeof(dt_device_memory), dt_memory_props,
+      dt_memory_config, dt_memory_init, NULL },
+    { "pc-misc", sizeof(dt_device_pc_misc), dt_pc_misc_props,
+      dt_pc_misc_config, dt_pc_misc_init, dt_pc_misc_start },
+    { "pci", sizeof(dt_device_pci), NULL,
+      dt_pci_config, dt_pci_init, dt_pci_start },
+    { "piix3", sizeof(dt_device_piix3), NULL,
+      dt_piix3_config, dt_piix3_init, NULL },
+    { "vga", sizeof(dt_device_vga), dt_vga_props,
+      dt_vga_config, dt_vga_init, NULL },
+    { "nic", sizeof(dt_device_nic), dt_nic_props,
+      dt_nic_config, dt_nic_init, NULL },
+    { NULL, 0, NULL, NULL, NULL }
+};
+
+static tree *
+dt_read_config(void)
+{
+    tree *root, *pci, *leaf;
+
+    /*
+     * TODO Read from config file.
+     *
+     * TODO Pretty far from a comprehensive machine configuration, but
+     * we need to start somewhere.
+     */
+    root = tree_new_kid(NULL, "", NULL);
+    leaf = tree_new_kid(root, "cpus", NULL);
+    tree_put_propf(leaf, "model", "%s", "qemu32");
+    leaf = tree_new_kid(root, "memory", NULL);
+    leaf = tree_new_kid(root, "pc-misc", NULL);
+    pci = tree_new_kid(root, "pci", NULL);
+    leaf = tree_new_kid(pci, "piix3", NULL);
+    return root;
+}
+
+/*
+ * Extract configuration from arguments and various global variables
+ * and put it into our machine and host configuration.
+ */
+static void
+dt_customize_config(tree *conf,
+                    dt_host *host,
+                    ram_addr_t ram_size, int vga_ram_size,
+                    const char *boot_device,
+                    const char *kernel_filename,
+                    const char *kernel_cmdline,
+                    const char *initrd_filename,
+                    const char *cpu_model)
+{
+    /*
+     * TODO This is still pretty cheesy: we insert stuff into the tree
+     * at hardcoded places.  Replacing placeholders instead would be
+     * more flexible.  Another idea is to mark certain parts of the
+     * initial tree optional, and remove them here.
+     */
+    tree *pci = tree_node_by_name(conf, "/pci");
+    tree *node;
+    int i, index;
+
+    node = tree_node_by_name(conf, "/cpus");
+    tree_put_propf(node, "num", "%d", smp_cpus);
+    if (cpu_model)
+        tree_put_propf(node, "model", "%s", cpu_model);
+
+    node = tree_node_by_name(conf, "/memory");
+    tree_put_propf(node, "ram", "%#lx", (unsigned long)ram_size);
+
+    node = tree_node_by_name(conf, "/pc-misc");
+    tree_put_propf(node, "boot-device", "%s", boot_device);
+
+    /* Insert VGA node */
+    if (cirrus_vga_enabled || vmsvga_enabled || std_vga_enabled) {
+        node = tree_new_kid(pci, "vga", NULL);
+        tree_put_propf(node, "model", "%s",
+                          cirrus_vga_enabled ? "cirrus" :
+                          vmsvga_enabled ? "vms" : "std");
+        tree_put_propf(node, "ram", "%#x", vga_ram_size);
+    }
+
+    /* Insert NIC nodes, connect to VLANs */
+    for(i = 0; i < nb_nics; i++) {
+        /* TODO non-PCI NICs */
+        NICInfo *n = &nd_table[i];
+
+        node = tree_new_kid(pci, "nic", NULL);
+        tree_put_propf(node, "mac", "%02x:%02x:%02x:%02x:%02x:%02x",
+                       n->macaddr[0], n->macaddr[1], n->macaddr[2],
+                       n->macaddr[3], n->macaddr[4], n->macaddr[5]);
+        tree_put_propf(node, "model", "%s",
+                       n->model ? n->model : "ne2k_pci");
+        if (n->name)
+            tree_put_propf(node, "name", "%s", n->name);
+        dt_attach_nic(host, i, node, n->vlan);
+    }
+
+    /* Connect drives to their controller nodes */
+    /* IDE */
+    node = tree_node_by_name(pci, "piix3");
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+        if (index != -1)
+            dt_attach_drive(host, index, node, drives_table[index].bdrv);
+    }
+    /* Floppy */
+    node = tree_node_by_name(conf, "/pc-misc");
+    for(i = 0; i < MAX_FD; i++) {
+        index = drive_get_index(IF_FLOPPY, 0, i);
+        if (index != -1)
+            dt_attach_drive(host, index, node, drives_table[index].bdrv);
+    }
+
+    /* Unimplemented stuff */
+    if (kernel_filename)
+        abort();                /* TODO */
+}
+
+static void
+pc_init_dt(ram_addr_t ram_size, int vga_ram_size,
+           const char *boot_device,
+           const char *kernel_filename,
+           const char *kernel_cmdline,
+           const char *initrd_filename,
+           const char *cpu_model)
+{
+    tree *conf;
+    dt_host host;
+
+    conf = dt_read_config();
+    if (!conf)
+        exit(1);
+    tree_print(conf);
+    memset(&host, 0, sizeof(host));
+    dt_customize_config(conf, &host, ram_size, vga_ram_size, boot_device,
+                        kernel_filename, kernel_cmdline, initrd_filename,
+                        cpu_model);
+    dt_config(conf, &host);
+    tree_print(conf);
+    dt_print_host_config(&host);
+    dt_fdt_test(conf);
+    dt_init(conf);
+    dt_start(conf);
+}
+
+QEMUMachine pcdt_machine = {
+    .name = "pcdt",
+    .desc = "Standard PC (device tree)",
+    .init = pc_init_dt,
+    .ram_require = VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,
+    .max_cpus = 255,
+};
diff --git a/hw/pc.c b/hw/pc.c
index 57ba803..107afb7 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -37,41 +37,34 @@
 #include "virtio-balloon.h"
 #include "virtio-console.h"
 #include "hpet_emul.h"
+#include "pcint.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
 
-#define BIOS_FILENAME "bios.bin"
-#define VGABIOS_FILENAME "vgabios.bin"
-#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
-
-#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
-
 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
 #define ACPI_DATA_SIZE       0x10000
 #define BIOS_CFG_IOPORT 0x510
 
-#define MAX_IDE_BUS 2
-
-static fdctrl_t *floppy_controller;
-static RTCState *rtc_state;
+fdctrl_t *floppy_controller;
+RTCState *rtc_state;
 static PITState *pit;
 static IOAPICState *ioapic;
-static PCIDevice *i440fx_state;
+PCIDevice *i440fx_state;
 
-static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
+void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
 {
 }
 
 /* MSDOS compatibility mode FPU exception support */
-static qemu_irq ferr_irq;
+qemu_irq ferr_irq;
 /* XXX: add IGNNE support */
 void cpu_set_ferr(CPUX86State *s)
 {
     qemu_irq_raise(ferr_irq);
 }
 
-static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
+void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
 {
     qemu_irq_lower(ferr_irq);
 }
@@ -120,7 +113,7 @@ int cpu_get_pic_interrupt(CPUState *env)
     return intno;
 }
 
-static void pic_irq_request(void *opaque, int irq, int level)
+void pic_irq_request(void *opaque, int irq, int level)
 {
     CPUState *env = first_cpu;
 
@@ -166,7 +159,7 @@ static int cmos_get_fd_drive_type(int fd0)
     return val;
 }
 
-static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
+void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
 {
     RTCState *s = rtc_state;
     int cylinders, heads, sectors;
@@ -202,7 +195,7 @@ static int boot_device2nibble(char boot_device)
 
 /* copy/pasted from cmos_init, should be made a general function
  and used there as well */
-static int pc_boot_set(void *opaque, const char *boot_device)
+int pc_boot_set(void *opaque, const char *boot_device)
 {
 #define PC_MAX_BOOT_DEVICES 3
     RTCState *s = (RTCState *)opaque;
@@ -228,8 +221,8 @@ static int pc_boot_set(void *opaque, const char *boot_device)
 }
 
 /* hd_table must contain 4 block drivers */
-static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
-                      const char *boot_device, BlockDriverState **hd_table)
+void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+               const char *boot_device, BlockDriverState **hd_table)
 {
     RTCState *s = rtc_state;
     int nbds, bds[3] = { 0, };
@@ -362,13 +355,13 @@ int ioport_get_a20(void)
     return ((first_cpu->a20_mask >> 20) & 1);
 }
 
-static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
+void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
 {
     ioport_set_a20((val >> 1) & 1);
     /* XXX: bit 0 is fast reset */
 }
 
-static uint32_t ioport92_read(void *opaque, uint32_t addr)
+uint32_t ioport92_read(void *opaque, uint32_t addr)
 {
     return ioport_get_a20() << 1;
 }
@@ -420,7 +413,7 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-static void bochs_bios_init(void)
+void bochs_bios_init(void)
 {
     void *fw_cfg;
 
@@ -687,7 +680,7 @@ static void load_linux(uint8_t *option_rom,
     generate_bootsect(option_rom, gpr, seg, 0);
 }
 
-static void main_cpu_reset(void *opaque)
+void main_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
     cpu_reset(env);
@@ -702,11 +695,11 @@ static const int ide_irq[2] = { 14, 15 };
 static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
 static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
 
-static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
-static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
+int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
 
-static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
-static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
+int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
+int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
 
 #ifdef HAS_AUDIO
 static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
diff --git a/hw/pcint.h b/hw/pcint.h
new file mode 100644
index 0000000..f18da67
--- /dev/null
+++ b/hw/pcint.h
@@ -0,0 +1,46 @@
+/*
+ * Stuff shared by pc.c and dt.c
+ *
+ * See dt.c for why this should go away eventually.
+ */
+
+#ifndef HW_PC_INT_H
+#define HW_PC_INT_H
+
+#define BIOS_FILENAME "bios.bin"
+#define VGABIOS_FILENAME "vgabios.bin"
+#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
+
+#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
+
+#define MAX_IDE_BUS 2
+
+/* TODO move to ferr stuff in cpu.h? */
+extern qemu_irq ferr_irq;
+void ioportF0_write(void *opaque, uint32_t addr, uint32_t data);
+
+/* TODO eliminate */
+extern RTCState *rtc_state;
+extern PCIDevice *i440fx_state;
+extern int serial_io[MAX_SERIAL_PORTS];
+extern int serial_irq[MAX_SERIAL_PORTS];
+extern int parallel_io[MAX_PARALLEL_PORTS];
+extern int parallel_irq[MAX_PARALLEL_PORTS];
+extern fdctrl_t *floppy_controller;
+
+/* TODO move to pic stuff in pc.h? */
+void pic_irq_request(void *opaque, int irq, int level);
+
+/* TODO move to a20 stuff in pc.h? */
+void ioport92_write(void *opaque, uint32_t addr, uint32_t val);
+uint32_t ioport92_read(void *opaque, uint32_t addr);
+
+void bochs_bios_init(void);
+void main_cpu_reset(void *opaque);
+void ioport80_write(void *opaque, uint32_t addr, uint32_t data);
+int pc_boot_set(void *opaque, const char *boot_device);
+void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd);
+void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+               const char *boot_device, BlockDriverState **hd_table);
+
+#endif
diff --git a/net.c b/net.c
index 29beb28..5ee3ba4 100644
--- a/net.c
+++ b/net.c
@@ -153,7 +153,7 @@ static void hex_dump(FILE *f, const uint8_t *buf, int size)
 }
 #endif
 
-static int parse_macaddr(uint8_t *macaddr, const char *p)
+int parse_macaddr(uint8_t *macaddr, const char *p)
 {
     int i;
     char *last_char;
diff --git a/net.h b/net.h
index 03c7f18..f672915 100644
--- a/net.h
+++ b/net.h
@@ -47,6 +47,7 @@ int qemu_can_send_packet(VLANClientState *vc);
 ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
                           int iovcnt);
 void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+int parse_macaddr(uint8_t *macaddr, const char *p);
 void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]);
 void qemu_check_nic_model(NICInfo *nd, const char *model);
 void qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 1cf49d5..01329d2 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -7,6 +7,8 @@
 
 void register_machines(void)
 {
+    extern QEMUMachine pcdt_machine;
+    qemu_register_machine(&pcdt_machine);
     qemu_register_machine(&pc_machine);
     qemu_register_machine(&isapc_machine);
 }
diff --git a/tree.c b/tree.c
new file mode 100644
index 0000000..a906a6a
--- /dev/null
+++ b/tree.c
@@ -0,0 +1,298 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ * 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.
+ */
+
+/* Ye Olde Decorated Tree */
+
+#include <assert.h>
+#include "tree.h"
+#include "qemu-common.h"
+#include "sys-queue.h"
+
+struct tree {
+    const char *name;
+    LIST_HEAD(, tree_prop) props;
+    tree *parent;
+    TAILQ_HEAD(, tree) kids;
+    TAILQ_ENTRY(tree) siblings;
+    void *user;
+};
+
+struct tree_prop {
+    const char *name;
+    const void *val;
+    int sz;
+    tree *owner;
+    LIST_ENTRY(tree_prop) link;
+};
+
+tree *
+tree_new_kid(tree *parent, const char *name, void *user)
+{
+    tree *kid = qemu_malloc(sizeof(*kid));
+
+    assert(parent || !*name);
+    kid->name = name;
+    LIST_INIT(&kid->props);
+    kid->parent = parent;
+    TAILQ_INIT(&kid->kids);
+    if (parent)
+        TAILQ_INSERT_TAIL(&parent->kids, kid, siblings);
+    kid->user = user;
+
+    return kid;
+}
+
+const char *
+tree_node_name(const tree *node)
+{
+    return node->name;
+}
+
+static tree *
+tree_kid_by_name(const tree *dt, const char *name)
+{
+    const char *slash = strchr(name, '/');
+    size_t len = slash ? slash - name : strlen(name);
+    tree *kid;
+
+    TAILQ_FOREACH(kid, &dt->kids, siblings) {
+        if (!memcmp(kid->name, name, len) && kid->name[len] == 0)
+            return kid;
+    }
+    return NULL;
+}
+
+tree *
+tree_node_by_name(const tree *node, const char *name)
+{
+    tree *kid;
+    size_t len;
+
+    if (name[0] == '/') {
+        for (; node->parent; node = node->parent) ;
+        name++;
+    }
+
+    if (name[0] == 0)
+        return (tree *)node;
+
+    kid = tree_kid_by_name(node, name);
+    if (!kid)
+        return NULL;
+
+    len = strlen(kid->name);
+    if (name[len] == 0)
+        return kid;
+    assert (name[len] == '/');
+
+    while (name[len] == '/') len++;
+    return tree_node_by_name(kid, name + len);
+}
+
+tree_prop *
+tree_first_prop(const tree *node)
+{
+    return LIST_FIRST(&node->props);
+}
+
+tree_prop *
+tree_next_prop(const tree_prop *prop)
+{
+    return LIST_NEXT(prop, link);
+}
+
+tree_prop *
+tree_get_prop(const tree *node, const char *name)
+{
+    tree_prop *prop;
+
+    LIST_FOREACH(prop, &node->props, link) {
+        if (!strcmp(prop->name, name))
+            return prop;
+    }
+    return NULL;
+}
+
+const char *
+tree_get_prop_s(const tree *node, const char *name)
+{
+    tree_prop *prop = tree_get_prop(node, name);
+    if (!prop
+        || memchr(prop->val, 0, prop->sz) != prop->val + prop->sz - 1) {
+        errno = EINVAL;
+        return NULL;
+    }
+    return prop->val;
+}
+
+const char *
+tree_prop_name(const tree_prop *prop)
+{
+    return prop->name;
+}
+
+const void *
+tree_prop_value(const tree_prop *prop, size_t *size)
+{
+    if (size)
+        *size = prop->sz;
+    return prop->val;
+}
+
+void
+tree_put_prop(tree *node, const char *name,
+              const void *val, size_t sz)
+{
+    tree_prop *prop;
+
+    prop = tree_get_prop(node, name);
+    if (!prop) {
+        prop = qemu_malloc(sizeof(*prop));
+        prop->name = name;
+        prop->owner = node;
+        LIST_INSERT_HEAD(&node->props, prop, link);
+    }
+    /* FIXME need a destructor for val */
+    prop->val = val;
+    prop->sz = sz;
+}
+
+void
+tree_put_propf(tree *node, const char *name, const char *fmt, ...)
+{
+    va_list ap;
+    size_t len;
+    char *buf;
+
+    va_start(ap, fmt);
+    len = vsnprintf(NULL, 0, fmt, ap);
+    va_end(ap);
+
+    buf = qemu_malloc(len + 1);
+    va_start(ap, fmt);
+    vsnprintf(buf, len + 1, fmt, ap);
+    va_end(ap);
+
+    tree_put_prop(node, name, buf, len + 1);
+}
+
+void
+tree_put_user(tree *node, void *user)
+{
+    node->user = user;
+}
+
+void *
+tree_get_user(const tree *node)
+{
+    return node->user;
+}
+
+tree *
+tree_parent(const tree *node)
+{
+    return node->parent;
+}
+
+tree *
+tree_first_kid(const tree *node)
+{
+    return TAILQ_FIRST(&node->kids);
+}
+
+tree *
+tree_sibling(const tree *node)
+{
+    return TAILQ_NEXT(node, siblings);
+}
+
+int
+tree_path(const tree *node, char *buf, size_t bufsz)
+{
+    char *p;
+    const tree *np;
+    size_t len, res;
+
+    p = buf + bufsz;
+    res = 0;
+    for (np = node; np->parent; np = np->parent) {
+        len = 1 + strlen(np->name);
+        res += len;
+        if (res >= bufsz)
+            continue;
+        p -= len;
+        memcpy(p + 1, np->name, len - 1);
+        p[0] = '/';
+    }
+
+    if (res < bufsz) {
+        memcpy(buf, p, res);
+        buf[res] = 0;
+    }
+
+    return res;
+}
+
+static void
+tree_print_sub(const tree *node, int indent)
+{
+    int i, use_str, sep;
+    const unsigned char *pv;
+    tree_prop *prop;
+    tree *kid;
+
+    printf("%*s%s {\n", indent, "", node->name[0] ? node->name : "/");
+    LIST_FOREACH(prop, &node->props, link) {
+        printf("%*s%s", indent + 4, "", prop->name);
+        pv = prop->val;
+        if (pv) {
+            printf(" = ");
+            use_str = pv[prop->sz - 1] == 0;
+            for (i = 0; i < prop->sz - 1; i++) {
+                if (!isprint(pv[i]))
+                    use_str = 0;
+            }
+            if (use_str)
+                printf("\"%s\"", (const char *)prop->val);
+            else {
+                sep = '[';
+                for (i = 0; i < prop->sz; i++) {
+                    printf("%c%02x", sep, pv[i]);
+                    sep = ' ';
+                }
+                printf("]");
+            }
+        }
+        printf(";\n");
+    }
+    TAILQ_FOREACH(kid, &node->kids, siblings)
+        tree_print_sub(kid, indent + 4);
+    printf("%*s};\n", indent, "");
+}
+
+void
+tree_print(const tree *node)
+{
+    tree_print_sub(node, 0);
+}
diff --git a/tree.h b/tree.h
new file mode 100644
index 0000000..3e596f8
--- /dev/null
+++ b/tree.h
@@ -0,0 +1,40 @@
+#ifndef TREE_H
+#define TREE_H
+
+#include <stddef.h>
+
+typedef struct tree tree;
+typedef struct tree_prop tree_prop;
+
+tree *tree_new_kid(tree *parent, const char *name, void *user);
+const char *tree_node_name(const tree *node);
+tree *tree_node_by_name(const tree *node,
+                               const char *name);
+
+tree_prop *tree_first_prop(const tree *node);
+tree_prop *tree_next_prop(const tree_prop *prop);
+#define TREE_FOREACH_PROP(var, node) \
+    for (var = tree_first_prop(node); var; var = tree_next_prop(var))
+tree_prop *tree_get_prop(const tree *node, const char *name);
+const char *tree_get_prop_s(const tree *node, const char *name);
+const char *tree_prop_name(const tree_prop *prop);
+const void *tree_prop_value(const tree_prop *prop, size_t *size);
+void tree_put_prop(tree *node, const char *name,
+                   const void *val, size_t sz);
+void tree_put_propf(tree *node, const char *name,
+                    const char *fmt, ...)
+    __attribute__((format(printf,3,4)));
+
+void tree_put_user(tree *node, void *user);
+void *tree_get_user(const tree *node);
+
+tree *tree_parent(const tree *node);
+tree *tree_first_kid(const tree *node);
+tree *tree_sibling(const tree *node);
+#define TREE_FOREACH_KID(var, node)                                     \
+    for (var = tree_first_kid(node); var; var = tree_sibling(var))
+
+int tree_path(const tree *node, char *buf, size_t bufsz);
+void tree_print(const tree *node);
+
+#endif

  parent reply	other threads:[~2009-02-19 10:30 UTC|newest]

Thread overview: 146+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-02-11 15:40 [Qemu-devel] [RFC] Machine description as data Markus Armbruster
2009-02-11 16:31 ` Ian Jackson
2009-02-11 17:43   ` Markus Armbruster
     [not found]   ` <18834.64870.951989.714873-msK/Ju9w1zmnROeE8kUsYhEHtJm+Wo+I@public.gmane.org>
2009-02-11 18:57     ` Hollis Blanchard
2009-02-11 18:57       ` Hollis Blanchard
     [not found]       ` <1234378639.28751.85.camel-EGjIuKC2qUdB0N6nvOmcJFaTQe2KTcn/@public.gmane.org>
2009-02-12  3:50         ` David Gibson
2009-02-12  3:50           ` David Gibson
     [not found] ` <87iqnh6kyv.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-11 18:50   ` Hollis Blanchard
2009-02-11 18:50     ` Hollis Blanchard
2009-02-11 19:34     ` Blue Swirl
2009-02-11 19:34       ` [Qemu-devel] " Blue Swirl
     [not found]     ` <1234378228.28751.79.camel-EGjIuKC2qUdB0N6nvOmcJFaTQe2KTcn/@public.gmane.org>
2009-02-12  4:01       ` David Gibson
2009-02-12  4:01         ` David Gibson
2009-02-12 10:26         ` Markus Armbruster
2009-02-12 10:26           ` [Qemu-devel] " Markus Armbruster
2009-02-12 12:49           ` Carl-Daniel Hailfinger
2009-02-12 12:49             ` [Qemu-devel] " Carl-Daniel Hailfinger
2009-02-12 16:46             ` M. Warner Losh
2009-02-12 16:46               ` [Qemu-devel] " M. Warner Losh
2009-02-12 18:29               ` Markus Armbruster
2009-02-12 18:29                 ` [Qemu-devel] " Markus Armbruster
2009-02-12 23:58                 ` Carl-Daniel Hailfinger
2009-02-12 23:58                   ` [Qemu-devel] " Carl-Daniel Hailfinger
     [not found]                   ` <4994B7B6.80805-hi6Y0CQ0nG0@public.gmane.org>
2009-02-13 11:19                     ` Markus Armbruster
2009-02-13 11:19                       ` Markus Armbruster
     [not found]                 ` <87prhnwltz.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-13  1:05                   ` David Gibson
2009-02-13  1:05                     ` David Gibson
2009-02-12 23:35               ` Carl-Daniel Hailfinger
2009-02-12 23:35                 ` [Qemu-devel] " Carl-Daniel Hailfinger
2009-02-12 23:58                 ` Paul Brook
2009-02-12 23:58                   ` [Qemu-devel] " Paul Brook
     [not found]                   ` <200902122358.25864.paul-qD8j1LwMmJjtCj0u4l0SBw@public.gmane.org>
2009-02-13  0:32                     ` Carl-Daniel Hailfinger
2009-02-13  0:32                       ` Carl-Daniel Hailfinger
2009-02-13  0:47                       ` Jamie Lokier
2009-02-13  0:47                         ` [Qemu-devel] " Jamie Lokier
     [not found]                       ` <4994BF93.2070409-hi6Y0CQ0nG0@public.gmane.org>
2009-02-13  1:46                         ` David Gibson
2009-02-13  1:46                           ` David Gibson
2009-02-13 14:32                       ` Lennart Sorensen
2009-02-13 14:32                         ` [Qemu-devel] " Lennart Sorensen
     [not found]                 ` <4994B22E.6060608-hi6Y0CQ0nG0@public.gmane.org>
2009-02-13  0:05                   ` M. Warner Losh
2009-02-13  0:05                     ` M. Warner Losh
     [not found]           ` <87iqng0x3t.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-12 17:52             ` Hollis Blanchard
2009-02-12 17:52               ` Hollis Blanchard
     [not found]               ` <1234461162.20305.16.camel-EGjIuKC2qUdB0N6nvOmcJFaTQe2KTcn/@public.gmane.org>
2009-02-12 18:53                 ` Markus Armbruster
2009-02-12 18:53                   ` Markus Armbruster
     [not found]                   ` <87fxijwkpn.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-12 19:33                     ` Mitch Bradley
2009-02-12 19:33                       ` Mitch Bradley
     [not found]                       ` <499479A7.5090902-D5eQfiDGL7eakBO8gow8eQ@public.gmane.org>
2009-02-13  0:59                         ` David Gibson
2009-02-13  0:59                           ` David Gibson
2009-02-13  1:00                 ` David Gibson
2009-02-13  1:00                   ` David Gibson
2009-02-13  0:43             ` David Gibson
2009-02-13  0:43               ` David Gibson
     [not found]               ` <20090213004305.GB8104-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2009-02-13  2:11                 ` Carl-Daniel Hailfinger
2009-02-13  2:11                   ` Carl-Daniel Hailfinger
     [not found]                   ` <4994D6C8.5050004-hi6Y0CQ0nG0@public.gmane.org>
2009-02-13  2:17                     ` David Gibson
2009-02-13  2:17                       ` David Gibson
     [not found]                       ` <20090213021704.GA10476-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2009-02-13  2:45                         ` DTS syntax and DTC patches (was: Re: [Qemu-devel] [RFC] Machine description as data) Carl-Daniel Hailfinger
2009-02-13  2:45                           ` Carl-Daniel Hailfinger
     [not found]                           ` <4994DED9.6020803-hi6Y0CQ0nG0@public.gmane.org>
2009-02-13  2:51                             ` David Gibson
2009-02-13  2:51                               ` David Gibson
     [not found]                               ` <20090213025101.GC10476-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2009-02-13 17:07                                 ` [coreboot] " ron minnich
     [not found]                               ` <13426df10902130907m5c3452dpb8f4f2b72f8507b9@mail.gmail.com>
     [not found]                                 ` <13426df10902130907m5c3452dpb8f4f2b72f8507b9-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-02-20  2:29                                   ` David Gibson
     [not found]                                     ` <20090220022918.GA18332-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2009-02-20  3:32                                       ` ron minnich
2009-02-13 20:04                     ` [Qemu-devel] [RFC] Machine description as data Jon Loeliger
2009-02-13 20:04                       ` Jon Loeliger
2009-02-13 20:15                       ` Carl-Daniel Hailfinger
2009-02-13 20:15                         ` Carl-Daniel Hailfinger
     [not found]                         ` <4995D4EE.8030703-hi6Y0CQ0nG0@public.gmane.org>
2009-02-13 20:19                           ` Jon Loeliger
2009-02-13 20:19                             ` Jon Loeliger
2009-02-12 10:26     ` Markus Armbruster
2009-02-12 10:26       ` [Qemu-devel] " Markus Armbruster
2009-02-12 12:36       ` Carl-Daniel Hailfinger
2009-02-12 12:36         ` [Qemu-devel] " Carl-Daniel Hailfinger
2009-02-12 16:07       ` Paul Brook
2009-02-12 17:17         ` Blue Swirl
2009-02-12 18:09         ` Marcelo Tosatti
     [not found]       ` <87k57w0x4r.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-13  0:37         ` David Gibson
2009-02-13  0:37           ` David Gibson
     [not found]           ` <20090213003724.GA8104-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2009-02-13 11:26             ` Markus Armbruster
2009-02-13 11:26               ` Markus Armbruster
     [not found]               ` <87ab8qr317.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-13 12:06                 ` Paul Brook
2009-02-13 12:06                   ` Paul Brook
     [not found]                   ` <200902131206.42427.paul-qD8j1LwMmJjtCj0u4l0SBw@public.gmane.org>
2009-02-13 12:48                     ` Markus Armbruster
2009-02-13 12:48                       ` Markus Armbruster
     [not found]                       ` <87ocx6pkol.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-13 13:33                         ` Paul Brook
2009-02-13 13:33                           ` Paul Brook
     [not found]                           ` <200902131333.47141.paul-qD8j1LwMmJjtCj0u4l0SBw@public.gmane.org>
2009-02-13 14:13                             ` Markus Armbruster
2009-02-13 14:13                               ` Markus Armbruster
     [not found]                               ` <871vu2pgq7.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-13 14:25                                 ` Paul Brook
2009-02-13 14:25                                   ` Paul Brook
     [not found]                                   ` <200902131425.53137.paul-qD8j1LwMmJjtCj0u4l0SBw@public.gmane.org>
2009-02-13 15:47                                     ` Jamie Lokier
2009-02-13 15:47                                       ` Jamie Lokier
2009-02-13 18:36                                 ` Mitch Bradley
2009-02-13 18:36                                   ` Mitch Bradley
     [not found]                                   ` <4995BDC0.3040806-D5eQfiDGL7eakBO8gow8eQ@public.gmane.org>
2009-02-13 19:49                                     ` Markus Armbruster
2009-02-13 19:49                                       ` Markus Armbruster
     [not found]                                       ` <877i3uglqz.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-13 19:51                                         ` Mitch Bradley
2009-02-13 19:51                                           ` Mitch Bradley
2009-02-16  3:42                 ` David Gibson
2009-02-16  3:42                   ` David Gibson
     [not found]                   ` <20090216034214.GB9772-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2009-02-16 16:39                     ` Markus Armbruster
2009-02-16 16:39                       ` Markus Armbruster
     [not found]                       ` <87iqnawd2r.fsf-A7mx1g9ivIOttUaS3K59qNi2O/JbrIOy@public.gmane.org>
2009-02-17  3:29                         ` David Gibson
2009-02-17  3:29                           ` David Gibson
     [not found]                           ` <20090217032909.GA29225-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2009-02-17  7:54                             ` Markus Armbruster
2009-02-17  7:54                               ` Markus Armbruster
2009-02-17 17:44                             ` Paul Brook
2009-02-17 17:44                               ` Paul Brook
     [not found]                               ` <200902171744.34951.paul-qD8j1LwMmJjtCj0u4l0SBw@public.gmane.org>
2009-02-18  8:36                                 ` Markus Armbruster
2009-02-18  8:36                                   ` Markus Armbruster
2009-02-11 19:01 ` Anthony Liguori
2009-02-11 19:36   ` Blue Swirl
2009-02-11 19:56     ` Anthony Liguori
2009-02-12 10:25       ` Markus Armbruster
2009-02-16 16:22 ` [Qemu-devel] Machine description as data prototype, take 2 (was: [RFC] Machine description as data) Markus Armbruster
2009-02-17 17:32   ` Paul Brook
2009-02-18  8:42     ` [Qemu-devel] Machine description as data prototype, take 2 Markus Armbruster
2009-02-19 10:29 ` Markus Armbruster [this message]
2009-02-19 13:53   ` [Qemu-devel] Machine description as data prototype, take 3 (was: [RFC] Machine description as data) Paul Brook
2009-02-19 14:55     ` [Qemu-devel] Machine description as data prototype, take 3 Markus Armbruster
2009-02-19 15:03       ` Paul Brook
2009-02-19 14:36   ` Anthony Liguori
2009-02-19 15:00     ` Markus Armbruster
2009-02-19 14:49   ` Anthony Liguori
2009-02-23 17:38     ` Markus Armbruster
2009-02-23 18:58       ` Anthony Liguori
2009-02-24  9:08         ` Markus Armbruster
2009-02-19 16:40   ` [Qemu-devel] Machine description as data prototype, take 3 (was: [RFC] Machine description as data) Blue Swirl
2009-02-19 18:30     ` [Qemu-devel] Machine description as data prototype, take 3 Markus Armbruster
2009-02-20 18:14       ` Blue Swirl
2009-02-20 18:20         ` Paul Brook
2009-02-23 12:00           ` Markus Armbruster
2009-02-23 12:18         ` Markus Armbruster
2009-02-23 18:00 ` [Qemu-devel] Machine description as data prototype, take 4 (was: [RFC] Machine description as data) Markus Armbruster
2009-02-24 20:06   ` Blue Swirl
2009-02-25 12:13     ` [Qemu-devel] Machine description as data prototype, take 4 Markus Armbruster
2009-02-25 20:11       ` Blue Swirl
2009-03-03 17:46 ` [Qemu-devel] Machine description as data prototype, take 5 (was: [RFC] Machine description as data) Markus Armbruster
2009-03-12 18:43 ` [Qemu-devel] Machine description as data prototype, take 6 " Markus Armbruster
2009-03-17 16:06   ` [Qemu-devel] Machine description as data prototype, take 6 Paul Brook
2009-03-17 17:32     ` Markus Armbruster
2009-03-23 15:50 ` [Qemu-devel] Re: [RFC] Machine description as data Markus Armbruster
2009-03-23 15:53   ` Markus Armbruster
2009-03-31  9:16 ` Markus Armbruster
2009-04-17 16:04 ` Markus Armbruster

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=871vtuafdr.fsf@pike.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.