qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Machine description as data prototype, take 4 (was: [RFC] M


From: Markus Armbruster
Subject: [Qemu-devel] Machine description as data prototype, take 4 (was: [RFC] Machine description as data)
Date: Mon, 23 Feb 2009 19:00:09 +0100
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.3 (gnu/linux)

Fourth iteration of the prototype.  I'm not asking to consider a merge
at this time.

New:

* Split into a generic part (dt.c dt.h) and a device-dependent part
  (hw/pcdt.c).  The latter could be split up further; many of its
  devices aren't PC-specific, or could be made so with a bit of effort.
  Arguably, the drivers are encapsulations of existing device
  implementations, and should live close to what they encapsulate.  I'm
  keeping all drivers in one place for now, just to avoid touching too
  many files.

  hw/pcdt.c also still contains the QEMUMachine init method (everything
  below /* Machine Driver */).  That stuff is temporary; see the
  shortcuts below.

* Some stylistic changes Anthony asked for.

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 configuration tree is simplistic.  I expect it to evolve, and I
  wouldn't exclude the possibility of wholesale replacement.

* The initial configuration tree is hardcoded in hw/pcdt.c.  It should
  be read from a configuration file.

* Optional stuff is inserted into the initial configuration tree in
  hardcoded places, in hw/pcdt.c.  We should use suitable markers in the
  configuration file instead, and do it in device-independent code
  outside hw/.

* I'm hiding completely behind the existing QEMUMachine init method
  interface, in hw/pcdt.c.  I guess we'll want to move that out.

* Linux gripes about ACPI, need to investigate.


 Makefile              |    1 +
 Makefile.target       |    4 +-
 dt.c                  |  445 ++++++++++++++++++++++++++++++++
 dt.h                  |  109 ++++++++
 hw/pc.c               |   47 ++--
 hw/pcdt.c             |  686 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pcint.h            |   46 ++++
 net.c                 |    2 +-
 net.h                 |    1 +
 target-i386/machine.c |    2 +
 tree.c                |  274 ++++++++++++++++++++
 tree.h                |   40 +++
 12 files changed, 1628 insertions(+), 29 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..cabdaf4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -505,6 +505,7 @@ OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o 
machine.o dma-helpers.o
 # need to fix this properly
 OBJS+=virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o
 OBJS+=fw_cfg.o
+OBJS+=dt.o
 ifdef CONFIG_KVM
 OBJS+=kvm.o kvm-all.o
 endif
@@ -536,6 +537,7 @@ endif
 ifdef CONFIG_OSS
 LIBS += $(CONFIG_OSS_LIB)
 endif
+LIBS+= $(FDT_LIBS)
 
 SOUND_HW = sb16.o es1370.o ac97.o
 ifdef CONFIG_ADLIB
@@ -583,6 +585,7 @@ 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+= pcdt.o
 OBJS += device-hotplug.o pci-hotplug.o
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 endif
@@ -604,7 +607,6 @@ OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o 
ppc405_uc.o ppc405_boards.o
 OBJS+= ppc440.o ppc440_bamboo.o
 ifdef FDT_LIBS
 OBJS+= device_tree.o
-LIBS+= $(FDT_LIBS)
 endif
 ifdef CONFIG_KVM
 OBJS+= kvm_ppc.o
diff --git a/dt.c b/dt.c
new file mode 100644
index 0000000..631a81a
--- /dev/null
+++ b/dt.c
@@ -0,0 +1,445 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <address@hidden>
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * Configure and build a machine from configuration data
+ *
+ * This is generic, device-independent code driven by device-dependent
+ * configuration data, talking to devices through an abstract device
+ * interface.
+ *
+ * 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 "block.h"
+#include "cpu.h"
+#include "dt.h"
+#include "net.h"
+#include "tree.h"
+#include "sysemu.h"
+
+#ifdef HAVE_FDT
+#include <libfdt.h>
+#endif
+
+/* Forward declarations */
+static void dt_parse_prop(dt_device *dev, tree_prop *prop);
+static void dt_fdt_test(tree *conf);
+
+
+/* Host Configuration */
+
+void dt_attach_nic(dt_host *host, int index, tree *nic, VLANState *vlan)
+{
+    host->nic[index] = nic;
+    host->nic_vlan[index] = vlan;
+}
+
+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;
+}
+
+void dt_attach_drive(dt_host *host, int index,
+                tree *controller, BlockDriverState *state)
+{
+    host->drive_ctrl[index] = controller;
+    host->drive_state[index] = state;
+}
+
+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);
+    }
+}
+
+
+/* Device Interface */
+
+static dt_driver *dt_driver_by_name(const char *name, dt_driver drvtab[])
+{
+    int i;
+
+    for (i = 0; drvtab[i].name; i++) {
+        if (!strcmp(name, drvtab[i].name))
+            return &drvtab[i];
+    }
+    return NULL;
+}
+
+dt_device *dt_device_of(tree *conf)
+{
+    return tree_get_user(conf);
+}
+
+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 drvtab[])
+{
+    dt_driver *drv;
+    dt_device *dev;
+    tree *kid;
+
+    drv = dt_driver_by_name(tree_node_name(conf), drvtab);
+    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, drvtab);
+}
+
+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);
+}
+
+void dt_create_machine(tree *conf, dt_host *host, dt_driver drvtab[])
+{
+    dt_config(conf, host, drvtab);
+    tree_print(conf);
+    dt_print_host_config(host);
+    dt_fdt_test(conf);
+    dt_init(conf);
+    dt_start(conf);
+}
+
+
+/* Device properties */
+
+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);
+    }
+}
+
+int dt_parse_string(void *dst, const char *src, dt_prop_spec *spec)
+{
+    assert(spec->size == sizeof(char *));
+    *(const char **)dst = src;
+    return 0;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+
+/* 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
diff --git a/dt.h b/dt.h
new file mode 100644
index 0000000..8f7ea8a
--- /dev/null
+++ b/dt.h
@@ -0,0 +1,109 @@
+#ifndef DT_H
+#define DT_H
+
+#include "sysemu.h"
+#include "net.h"
+#include "tree.h"
+
+typedef struct dt_host dt_host;
+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;
+
+
+/* Host Configuration */
+
+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];
+};
+
+void dt_attach_nic(dt_host *host, int index, tree *nic, VLANState *vlan);
+VLANState *dt_find_vlan(tree *conf, dt_host *host);
+void dt_attach_drive(dt_host *host, int index,
+                     tree *controller, BlockDriverState *state);
+void dt_drive_config(tree *conf, dt_host *host,
+                     BlockDriverState *drive[], int n);
+
+
+/* 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 *);
+};
+
+dt_device *dt_device_of(tree *conf);
+dt_device *dt_parent_device(dt_device *dev);
+tree *dt_require_named(dt_device *dev, const char *reqname);
+void dt_create_machine(tree *conf, dt_host *host, dt_driver drvtab[]);
+
+
+/* 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 }
+
+/* Canned property parse methods */
+int dt_parse_string(void *dst, const char *src, dt_prop_spec *spec);
+int dt_parse_int(void *dst, const char *src, dt_prop_spec *spec);
+int dt_parse_ram_addr_t(void *dst, const char *src, dt_prop_spec *spec);
+int dt_parse_macaddr(void *dst, const char *src, dt_prop_spec *spec);
+
+#endif
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/pcdt.c b/hw/pcdt.c
new file mode 100644
index 0000000..95bc698
--- /dev/null
+++ b/hw/pcdt.c
@@ -0,0 +1,686 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <address@hidden>
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * This is a PC configured and built using the new dt_ infrastructure.
+ * 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 infrastructure.
+ *
+ * The configuration data currently is hardwired, and fairly limited.
+ *
+ * The nuts and bolts of PC emulation remain in pc.c for now, and
+ * using the stuff there makes the somewhat clumsy pcint.h necessary.
+ */
+
+#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 "dt.h"
+
+static BlockDriverState **dt_piix3_hd(tree *piix3);
+
+/* 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);
+    }
+}
+
+
+/* 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);
+}
+
+
+/* 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;
+}
+
+
+/* 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;
+}
+
+
+/* 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;
+}
+
+
+/* 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;
+}
+
+
+/* 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);
+}
+
+
+/* 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);
+}
+
+
+/* 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_create_machine(conf, &host, dt_driver_table);
+}
+
+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/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..7f9bcce
--- /dev/null
+++ b/tree.c
@@ -0,0 +1,274 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* 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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]