qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions
       [not found] <cover.1241106809.git.armbru@redhat.com>
@ 2009-04-30 16:03 ` Markus Armbruster
  2009-05-01 17:27   ` Blue Swirl
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 2/4] Remove global floppy_controller Markus Armbruster
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Markus Armbruster @ 2009-04-30 16:03 UTC (permalink / raw)
  To: qemu-devel

Pass the state as argument to cmos_init() and cmos_init_hd().
cmos_init() still needs to save it in rtc_state for use by
cmos_set_s3_resume().

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 hw/pc.c |   20 +++++++++++---------
 1 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/hw/pc.c b/hw/pc.c
index 07b75f3..0e861ab 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -169,9 +169,9 @@ static int cmos_get_fd_drive_type(int fd0)
     return val;
 }
 
-static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
+static void cmos_init_hd(RTCState *s,
+                         int type_ofs, int info_ofs, BlockDriverState *hd)
 {
-    RTCState *s = rtc_state;
     int cylinders, heads, sectors;
     bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
     rtc_set_memory(s, type_ofs, 47);
@@ -232,10 +232,10 @@ 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,
+static void cmos_init(RTCState *s,
+                      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, };
     int val;
     int fd0, fd1, nb;
@@ -324,9 +324,9 @@ static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
 
     rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
     if (hd_table[0])
-        cmos_init_hd(0x19, 0x1b, hd_table[0]);
+        cmos_init_hd(s, 0x19, 0x1b, hd_table[0]);
     if (hd_table[1])
-        cmos_init_hd(0x1a, 0x24, hd_table[1]);
+        cmos_init_hd(s, 0x1a, 0x24, hd_table[1]);
 
     val = 0;
     for (i = 0; i < 4; i++) {
@@ -353,6 +353,7 @@ static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
         }
     }
     rtc_set_memory(s, 0x39, val);
+    rtc_state = s;              /* for cmos_set_s3_resume() */
 }
 
 void ioport_set_a20(int enable)
@@ -822,6 +823,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
     int bios_size, isa_bios_size, oprom_area_size;
     PCIBus *pci_bus;
     int piix3_devfn = -1;
+    RTCState *rtc;
     CPUState *env;
     qemu_irq *cpu_irq;
     qemu_irq *i8259;
@@ -990,9 +992,9 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
         }
     }
 
-    rtc_state = rtc_init(0x70, i8259[8], 2000);
+    rtc = rtc_init(0x70, i8259[8], 2000);
 
-    qemu_register_boot_set(pc_boot_set, rtc_state);
+    qemu_register_boot_set(pc_boot_set, rtc);
 
     register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
     register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
@@ -1071,7 +1073,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
     }
     floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
 
-    cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd);
+    cmos_init(rtc, below_4g_mem_size, above_4g_mem_size, boot_device, hd);
 
     if (pci_enabled && usb_enabled) {
         usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 2/4] Remove global floppy_controller
       [not found] <cover.1241106809.git.armbru@redhat.com>
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions Markus Armbruster
@ 2009-04-30 16:03 ` Markus Armbruster
  2009-05-01 17:31   ` Blue Swirl
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 3/4] Give parse_macaddr() external linkage Markus Armbruster
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 4/4] Machine description as data Markus Armbruster
  3 siblings, 1 reply; 11+ messages in thread
From: Markus Armbruster @ 2009-04-30 16:03 UTC (permalink / raw)
  To: qemu-devel

Change cmos_init() to take the floppy drive types as arguments instead
of getting them through global floppy_controller.

Change fdctrl_get_drive_type() to take a BlockDriverState argument.
Factor fd_format() out of fd_revalidate() to make that possible.

Use it to compute the new arguments for cmos_init().

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 hw/fdc.c |   76 ++++++++++++++++++++++++++++++++++---------------------------
 hw/fdc.h |    2 +-
 hw/pc.c  |   15 +++++------
 3 files changed, 50 insertions(+), 43 deletions(-)

diff --git a/hw/fdc.c b/hw/fdc.c
index b00a4ec..1e09d52 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -231,12 +231,51 @@ static const fd_format_t fd_formats[] = {
     { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
 };
 
-/* Revalidate a disk drive after a disk change */
-static void fd_revalidate (fdrive_t *drv)
+static const fd_format_t *fd_format(BlockDriverState *bs,
+                                    fdrive_type_t prev_type)
 {
     const fd_format_t *parse;
     uint64_t nb_sectors, size;
     int i, first_match, match;
+
+    bdrv_get_geometry(bs, &nb_sectors);
+    match = -1;
+    first_match = -1;
+    for (i = 0;; i++) {
+        parse = &fd_formats[i];
+        if (parse->drive == FDRIVE_DRV_NONE)
+            break;
+        if (prev_type == parse->drive ||
+            prev_type == FDRIVE_DRV_NONE) {
+            size = (parse->max_head + 1) * parse->max_track *
+                parse->last_sect;
+            if (nb_sectors == size) {
+                match = i;
+                break;
+            }
+            if (first_match == -1)
+                first_match = i;
+        }
+    }
+    if (match == -1) {
+        if (first_match == -1)
+            match = 1;
+        else
+            match = first_match;
+        parse = &fd_formats[match];
+    }
+    return parse;
+}
+
+int fdctrl_get_drive_type(BlockDriverState *bs)
+{
+    return bs ? fd_format(bs, FDRIVE_DRV_NONE)->drive : FDRIVE_DRV_NONE;
+}
+
+/* Revalidate a disk drive after a disk change */
+static void fd_revalidate (fdrive_t *drv)
+{
+    const fd_format_t *parse;
     int nb_heads, max_track, last_sect, ro;
 
     FLOPPY_DPRINTF("revalidate\n");
@@ -247,32 +286,7 @@ static void fd_revalidate (fdrive_t *drv)
             FLOPPY_DPRINTF("User defined disk (%d %d %d)",
                            nb_heads - 1, max_track, last_sect);
         } else {
-            bdrv_get_geometry(drv->bs, &nb_sectors);
-            match = -1;
-            first_match = -1;
-            for (i = 0;; i++) {
-                parse = &fd_formats[i];
-                if (parse->drive == FDRIVE_DRV_NONE)
-                    break;
-                if (drv->drive == parse->drive ||
-                    drv->drive == FDRIVE_DRV_NONE) {
-                    size = (parse->max_head + 1) * parse->max_track *
-                        parse->last_sect;
-                    if (nb_sectors == size) {
-                        match = i;
-                        break;
-                    }
-                    if (first_match == -1)
-                        first_match = i;
-                }
-            }
-            if (match == -1) {
-                if (first_match == -1)
-                    match = 1;
-                else
-                    match = first_match;
-                parse = &fd_formats[match];
-            }
+            parse = fd_format(drv->bs, drv->drive);
             nb_heads = parse->max_head + 1;
             max_track = parse->max_track;
             last_sect = parse->last_sect;
@@ -735,12 +749,6 @@ static void fdctrl_handle_tc(void *opaque, int irq, int level)
     }
 }
 
-/* XXX: may change if moved to bdrv */
-int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
-{
-    return fdctrl->drives[drive_num].drive;
-}
-
 /* Change IRQ state */
 static void fdctrl_reset_irq (fdctrl_t *fdctrl)
 {
diff --git a/hw/fdc.h b/hw/fdc.h
index 7b6a9de..91fad1f 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -8,4 +8,4 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
                        BlockDriverState **fds);
 fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
                              BlockDriverState **fds, qemu_irq *fdc_tc);
-int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);
+int fdctrl_get_drive_type(BlockDriverState *bs);
diff --git a/hw/pc.c b/hw/pc.c
index 0e861ab..a9a39a9 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -56,7 +56,6 @@
 
 #define MAX_IDE_BUS 2
 
-static fdctrl_t *floppy_controller;
 static RTCState *rtc_state;
 static PITState *pit;
 static IOAPICState *ioapic;
@@ -234,11 +233,12 @@ static int pc_boot_set(void *opaque, const char *boot_device)
 /* hd_table must contain 4 block drivers */
 static void cmos_init(RTCState *s,
                       ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
-                      const char *boot_device, BlockDriverState **hd_table)
+                      const char *boot_device, BlockDriverState **hd_table,
+                      int fd0, int fd1)
 {
     int nbds, bds[3] = { 0, };
     int val;
-    int fd0, fd1, nb;
+    int nb;
     int i;
 
     /* various important CMOS locations needed by PC/Bochs bios */
@@ -294,9 +294,6 @@ static void cmos_init(RTCState *s,
 
     /* floppy type */
 
-    fd0 = fdctrl_get_drive_type(floppy_controller, 0);
-    fd1 = fdctrl_get_drive_type(floppy_controller, 1);
-
     val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
     rtc_set_memory(s, 0x10, val);
 
@@ -1071,9 +1068,11 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
 	else
 	    fd[i] = NULL;
     }
-    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
+    fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
 
-    cmos_init(rtc, below_4g_mem_size, above_4g_mem_size, boot_device, hd);
+    cmos_init(rtc, below_4g_mem_size, above_4g_mem_size, boot_device, hd,
+              fdctrl_get_drive_type(fd[0]),
+              fdctrl_get_drive_type(fd[1]));
 
     if (pci_enabled && usb_enabled) {
         usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 3/4] Give parse_macaddr() external linkage
       [not found] <cover.1241106809.git.armbru@redhat.com>
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions Markus Armbruster
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 2/4] Remove global floppy_controller Markus Armbruster
@ 2009-04-30 16:03 ` Markus Armbruster
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 4/4] Machine description as data Markus Armbruster
  3 siblings, 0 replies; 11+ messages in thread
From: Markus Armbruster @ 2009-04-30 16:03 UTC (permalink / raw)
  To: qemu-devel

This is to make it available for the machine description stuff in the
following commit.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 net.c |    2 +-
 net.h |    1 +
 2 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net.c b/net.c
index 7ae1e6d..80d14c2 100644
--- a/net.c
+++ b/net.c
@@ -158,7 +158,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 cdf63a4..fd33165 100644
--- a/net.h
+++ b/net.h
@@ -61,6 +61,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,
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 4/4] Machine description as data
       [not found] <cover.1241106809.git.armbru@redhat.com>
                   ` (2 preceding siblings ...)
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 3/4] Give parse_macaddr() external linkage Markus Armbruster
@ 2009-04-30 16:03 ` Markus Armbruster
  3 siblings, 0 replies; 11+ messages in thread
From: Markus Armbruster @ 2009-04-30 16:03 UTC (permalink / raw)
  To: qemu-devel


Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 Makefile              |    1 +
 Makefile.target       |    7 +-
 dt-fdt.c              |  123 +++++++
 dt-host.c             |  176 +++++++++
 dt.c                  |  600 +++++++++++++++++++++++++++++++
 dt.h                  |  150 ++++++++
 hw/boards.h           |    3 +
 hw/pc.c               |   53 ++--
 hw/pcdt.c             |  941 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pcidt.c            |   67 ++++
 hw/pcint.h            |   47 +++
 target-i386/machine.c |    1 +
 tree.c                |  285 +++++++++++++++
 tree.h                |   41 +++
 14 files changed, 2464 insertions(+), 31 deletions(-)
 create mode 100644 dt-fdt.c
 create mode 100644 dt-host.c
 create mode 100644 dt.c
 create mode 100644 dt.h
 create mode 100644 hw/pcdt.c
 create mode 100644 hw/pcidt.c
 create mode 100644 hw/pcint.h
 create mode 100644 tree.c
 create mode 100644 tree.h

diff --git a/Makefile b/Makefile
index 0f40cda..7c06e12 100644
--- a/Makefile
+++ b/Makefile
@@ -100,6 +100,7 @@ OBJS+=bt-hci-csr.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+=msmouse.o ps2.o
+OBJS+=tree.o
 
 ifdef CONFIG_BRLAPI
 OBJS+= baum.o
diff --git a/Makefile.target b/Makefile.target
index 82ada5a..7b7d77d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -503,6 +503,10 @@ 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 dt-host.o pcidt.o
+ifdef FDT_LIBS
+OBJS+= dt-fdt.o
+endif
 ifdef CONFIG_KVM
 OBJS+=kvm.o kvm-all.o
 endif
@@ -534,6 +538,7 @@ endif
 ifdef CONFIG_OSS
 LIBS += $(CONFIG_OSS_LIB)
 endif
+LIBS+= $(FDT_LIBS)
 
 SOUND_HW = sb16.o es1370.o ac97.o
 ifdef CONFIG_ADLIB
@@ -588,6 +593,7 @@ OBJS+= ide.o pckbd.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 ioapic.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 smbios.o
 CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 endif
@@ -611,7 +617,6 @@ OBJS+= ppc440.o ppc440_bamboo.o
 OBJS+= ppce500_pci.o ppce500_mpc8544ds.o
 ifdef FDT_LIBS
 OBJS+= device_tree.o
-LIBS+= $(FDT_LIBS)
 endif
 ifdef CONFIG_KVM
 OBJS+= kvm_ppc.o
diff --git a/dt-fdt.c b/dt-fdt.c
new file mode 100644
index 0000000..375e50a
--- /dev/null
+++ b/dt-fdt.c
@@ -0,0 +1,123 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ * 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.
+ */
+
+/* Interfacing with FDT */
+
+/*
+ * Note: translation to FDT loses the association between
+ * configuration tree nodes and devices.
+ */
+
+#include <libfdt.h>
+#include "dt.h"
+
+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 *child;
+    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_CHILD(child, conf)
+        dt_subtree_to_fdt(child, 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 < ARRAY_SIZE(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 < ARRAY_SIZE(stack));
+            stack[depth] = tree_new_child(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;
+}
+
+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);
+}
diff --git a/dt-host.c b/dt-host.c
new file mode 100644
index 0000000..eec8dc9
--- /dev/null
+++ b/dt-host.c
@@ -0,0 +1,176 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ * 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.
+ */
+
+/* Host Configuration */
+
+#include <assert.h>
+#include "block.h"
+#include "dt.h"
+
+/* TODO stupid arbitrary limit */
+#define MAX_MEM (MAX_OPTION_ROMS + 4)
+
+typedef struct dt_host_memory {
+    dt_mem_loader loader;
+    target_phys_addr_t addr;
+    ram_addr_t size;
+    const void *arg;
+} dt_host_memory;
+
+struct dt_host {
+    /* driver table */
+    const dt_driver *drvtab;
+    /* connection NIC <-> VLAN */
+    int nics;
+    tree *nic[MAX_NICS];
+    VLANState *nic_vlan[MAX_NICS];
+    /* connection drive <-> block driver state */
+    int drives;
+    tree *drive[MAX_DRIVES];
+    BlockDriverState *drive_state[MAX_DRIVES];
+    /* initial memory contents */
+    int mems;
+    dt_host_memory mem[MAX_MEM];
+    /* the rest isn't configuration, it's derived from other stuff */
+    int virtio_buses;
+};
+
+dt_host *dt_create_host(const dt_driver *drvtab)
+{
+    dt_host *host = qemu_mallocz(sizeof(dt_host));
+    host->drvtab = drvtab;
+    return host;
+}
+
+const dt_driver *dt_driver_by_name(dt_host *host, const char *name)
+{
+    const dt_driver *drvtab = host->drvtab;
+    int i;
+
+    for (i = 0; drvtab[i].name; i++) {
+        if (!strcmp(name, drvtab[i].name))
+            return &drvtab[i];
+    }
+    return NULL;
+}
+
+void dt_attach_nic(dt_host *host, tree *nic, VLANState *vlan)
+{
+    assert(host->nics < MAX_NICS);
+    host->nic[host->nics] = nic;
+    host->nic_vlan[host->nics] = vlan;
+    host->nics++;
+}
+
+VLANState *dt_find_vlan(tree *conf, dt_host *host)
+{
+    int i;
+
+    for (i = 0; i < host->nics; i++) {
+        if (host->nic[i] == conf)
+            return host->nic_vlan[i];
+    }
+    return NULL;
+}
+
+void dt_attach_drive(dt_host *host, tree *node, BlockDriverState *state)
+{
+    assert(host->drives < MAX_DRIVES);
+    host->drive[host->drives] = node;
+    host->drive_state[host->drives] = state;
+    host->drives++;
+}
+
+void dt_find_drives(tree *conf, dt_host *host,
+                    BlockDriverState *drive[], int n)
+{
+    int i, unit;
+
+    memset(drive, 0, n * sizeof(drive[0]));
+
+    for (i = 0; i < host->drives; i++) {
+        if (tree_parent(host->drive[i]) != conf)
+            continue;
+        unit = dt_get_unit(dt_device_of(host->drive[i]));
+        assert(unit < n && !drive[unit]);
+        drive[unit] = host->drive_state[i];
+    }
+}
+
+void dt_config_mem(dt_host *host, dt_mem_loader loader,
+                   target_phys_addr_t addr, ram_addr_t size, const void *arg)
+{
+    assert(host->mems < MAX_MEM);
+    host->mem[host->mems].loader = loader;
+    host->mem[host->mems].addr = addr;
+    host->mem[host->mems].size = size;
+    host->mem[host->mems].arg = arg;
+    host->mems++;
+}
+
+static void dt_init_mem(dt_host *host)
+{
+    dt_host_memory *p;
+
+    for (p = host->mem; p < host->mem + host->mems; p++)
+        p->loader(p->addr, p->size, p->arg);
+}
+
+void dt_image_loader(target_phys_addr_t addr, ram_addr_t size, const void *arg)
+{
+    if (load_image_targphys(arg, addr, size) < 0) {
+        fprintf(stderr, "qemu: could not load image '%s'\n", (char *)arg);
+        exit(1);
+    }
+}
+
+int dt_alloc_virtio_bus(dt_host *host)
+{
+    return host->virtio_buses++;
+}
+
+void dt_host_init(dt_host *host)
+{
+    dt_init_mem(host);
+}
+
+void dt_print_host_config(dt_host *host)
+{
+    char buf[1024];
+    int i;
+
+    for (i = 0; i < host->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 < host->drives; i++) {
+        tree_path(host->drive[i], buf, sizeof(buf));
+        printf("drive#%d\t%-15s %s\n",
+               i, bdrv_get_device_name(host->drive_state[i]), buf);
+    }
+
+    for (i = 0; i < host->mems; i++)
+        printf("image\t" TARGET_FMT_plx " %08lx\n",
+               host->mem[i].addr, (unsigned long)host->mem[i].size);
+}
diff --git a/dt.c b/dt.c
new file mode 100644
index 0000000..1353f5c
--- /dev/null
+++ b/dt.c
@@ -0,0 +1,600 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ * 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.
+ */
+
+#include <assert.h>
+#include "dt.h"
+
+/* Forward declarations */
+static void dt_parse_prop(dt_device *dev, tree_prop *prop);
+
+
+/* Device Interface */
+
+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;
+}
+
+dt_device *dt_root(dt_device *dev)
+{
+    tree *p, *r;
+
+    p = dev->conf;
+    do r = p; while ((p = tree_parent(p)));
+
+    return dt_device_of(r);
+}
+
+static dt_device *dt_do_find_bus(tree *conf, dt_bus_type bus_type, int *skip)
+{
+    dt_device *dev;
+    tree *child;
+
+    dev = dt_device_of(conf);
+    if (dev->drv->bus_type == bus_type && (*skip)-- == 0)
+        return dev;
+
+    TREE_FOREACH_CHILD(child, conf) {
+        dev = dt_do_find_bus(child, bus_type, skip);
+        if (dev)
+            return dev;
+    }
+
+    return NULL;
+}
+
+dt_device *dt_find_bus(tree *conf, dt_bus_type bus_type, int busno)
+{
+    return dt_do_find_bus(conf, bus_type, &busno);
+}
+
+PCIBus *dt_get_pcibus(dt_device *dev)
+{
+    dt_device *bus = dt_parent_device(dev);
+
+    return bus->drv->get_pcibus(bus);
+}
+
+int dt_get_unit(dt_device *dev)
+{
+    return dev->drv->get_unit(dev);
+}
+
+static dt_device *dt_int_parent(dt_device *dev)
+{
+    dt_device *res;
+
+    if (dev->int_parent)
+        return dt_device_of(dev->int_parent);
+
+    res = dt_parent_device(dev);
+    return res && res->drv->get_int ? res : NULL;
+}
+
+qemu_irq *dt_get_int(dt_device *dev, int n)
+{
+    dt_device *int_parent = dt_int_parent(dev);
+    int nirq;
+    qemu_irq *res;
+
+    if (!int_parent)
+        return NULL;
+
+    res = int_parent->drv->get_int(int_parent, &nirq);
+    assert(n <= nirq);
+    return res;
+}
+
+static dt_device *dt_new_device(tree *conf, const dt_driver *drv)
+{
+    dt_device *dev;
+    tree_prop *prop;
+
+    dev = qemu_malloc(sizeof(*dev));
+    dev->conf = conf;
+    dev->drv = drv;
+    dev->int_parent = NULL;
+    TAILQ_INIT(&dev->int_children);
+    dev->priv = qemu_mallocz(drv->privsz);
+    tree_put_user(conf, dev);
+
+    TREE_FOREACH_PROP(prop, conf)
+        dt_parse_prop(dev, prop);
+
+    return dev;
+}
+
+static dt_device *dt_create(tree *conf, dt_host *host)
+{
+    const dt_driver *drv;
+    dt_device *dev;
+    tree *child;
+
+    drv = dt_driver_by_name(host, tree_node_name(conf));
+    if (!drv) {
+        fprintf(stderr, "No driver for device %s\n",
+                tree_node_name(conf));
+        exit(1);
+    }
+
+    assert((drv->bus_type == DT_BUS_PCI) == (drv->get_pcibus != NULL));
+
+    dev = dt_new_device(conf, drv);
+
+    TREE_FOREACH_CHILD(child, conf)
+        dt_create(child, host);
+
+    return dev;
+}
+
+static void dt_config(dt_device *dev, dt_host *host)
+{
+    dt_device *bus = dt_parent_device(dev);
+    dt_device *int_parent = dt_int_parent(dev);
+    dt_device *up;
+    tree *child;
+
+    if (dev->drv->parent_bus_type == DT_BUS_NONE
+        ? bus != NULL
+        : bus == NULL || bus->drv->bus_type != dev->drv->parent_bus_type) {
+        fprintf(stderr, "Device %s is not on a suitable bus\n",
+                dev->drv->name);
+        exit(1);
+    }
+
+    if (dev->int_parent) {
+        if (!int_parent->drv->get_int) {
+            fprintf(stderr, "Device %s has an invalid interrupt-parent\n",
+                    dev->drv->name);
+            exit(1);
+        }
+        for (up = int_parent; up; up = dt_int_parent(up)) {
+            if (up == dev) {
+                fprintf(stderr, "Device %s is its own interrupt ancestor\n",
+                        dev->drv->name);
+                exit(1);
+            }
+        }
+    }
+
+    if (int_parent)
+        TAILQ_INSERT_TAIL(&int_parent->int_children, dev, int_siblings);
+    else if (dev->drv->get_int)
+        TAILQ_INSERT_TAIL(&dt_root(dev)->int_children, dev, int_siblings);
+
+    if (dev->drv->config)
+        dev->drv->config(dev, host);
+
+    TREE_FOREACH_CHILD(child, dev->conf)
+        dt_config(dt_device_of(child), host);
+}
+
+static void dt_int_init(dt_device *dev)
+{
+    dt_device *child;
+
+    if (dev->drv->int_init)
+        dev->drv->int_init(dev);
+
+    TAILQ_FOREACH(child, &dev->int_children, int_siblings)
+        dt_int_init(child);
+}
+
+static void dt_init(dt_device *dev)
+{
+    tree *child;
+
+    if (dev->drv->init)
+        dev->drv->init(dev);
+
+    TREE_FOREACH_CHILD(child, dev->conf)
+        dt_init(dt_device_of(child));
+}
+
+static void dt_start(dt_device *dev)
+{
+    tree *child;
+
+    if (dev->drv->start)
+        dev->drv->start(dev);
+
+    TREE_FOREACH_CHILD(child, dev->conf)
+        dt_start(dt_device_of(child));
+}
+
+void dt_init_machine(dt_device *root, dt_host *host)
+{
+    dt_int_init(root);
+    dt_init(root);
+    dt_host_init(host);
+    dt_start(root);
+}
+
+
+/* Device properties */
+
+static const dt_prop_spec *bus_prop_spec[DT_BUS_NUM] = {
+    [DT_BUS_PCI] = dt_bus_prop_spec_pci,
+};
+
+static const dt_prop_spec *dt_prop_spec_by_name(const dt_prop_spec *prop_spec,
+                                                const char *name)
+{
+    const dt_prop_spec *spec;
+
+    for (spec = 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);
+    const dt_prop_spec *spec;
+
+    spec = dt_prop_spec_by_name(dev->drv->prop_spec, name);
+
+    if (!spec)
+        spec = dt_prop_spec_by_name(bus_prop_spec[dev->drv->parent_bus_type],
+                                    name);
+
+    if (!spec && !strcmp(name, "interrupt-parent")) {
+        dev->int_parent = tree_node_by_name(dev->conf, val);
+        return;
+    }
+
+    if (!spec) {
+        fprintf(stderr, "A %s device has no property %s\n",
+                dev->drv->name, name);
+        exit(1);
+    }
+
+    if (spec->parse) {
+        if (!val) {
+            fprintf(stderr, "Property %s of device %s needs a value\n",
+                    name, dev->drv->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);
+        }
+    } else {
+        if (val) {
+            fprintf(stderr, "Property %s of device %s doesn't take a value\n",
+                    name, dev->drv->name);
+            exit(1);
+        }
+        assert(spec->size == sizeof(int));
+        *(int *)((char *)dev->priv + spec->offs) = 1;
+    }
+}
+
+int dt_parse_string(void *dst, const char *src, const dt_prop_spec *spec)
+{
+    assert(spec->size == sizeof(char *));
+    *(const char **)dst = src;
+    return 0;
+}
+
+int dt_parse_int(void *dst, const char *src, const 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, const 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_target_phys_addr_t(void *dst, const char *src,
+                                const dt_prop_spec *spec)
+{
+    char *ep;
+    unsigned long long val;
+
+    assert(spec->size == sizeof(target_phys_addr_t));
+    errno = 0;
+    val = strtoull(src, &ep, 0);
+    if (*ep || ep == src || errno || (target_phys_addr_t)val != val)
+        return -1;
+    *(target_phys_addr_t *)dst = val;
+    return 0;
+}
+
+int dt_parse_macaddr(void *dst, const char *src, const dt_prop_spec *spec)
+{
+    assert(spec->size == 6);
+    if (parse_macaddr(dst, src) < 0)
+        return -1;
+    return 0;
+}
+
+
+/* Dynamic Devices */
+
+static void dt_add_dyn_dev(tree *conf, dt_host *host, tree *node, int busno)
+{
+    dt_device *dev = dt_create(node, host);
+    dt_device *bus = dt_find_bus(conf, dev->drv->parent_bus_type, busno);
+
+    if (!bus) {
+        fprintf(stderr, "No suitable bus for device %s\n", dev->drv->name);
+        exit(1);
+    }
+
+    tree_insert(bus->conf, node);
+}
+
+static void dt_add_vga(tree *conf, dt_host *host,
+                       const char *model, int vga_ram_size)
+{
+    tree *node = tree_new_child(NULL, "vga", NULL);
+
+    tree_put_propf(node, "model", "%s", model);
+    tree_put_propf(node, "ram", "%#x", vga_ram_size);
+    dt_add_dyn_dev(conf, host, node, 0);
+}
+
+static void dt_add_virtio_console(tree *conf, dt_host *host, int index)
+{
+    tree *node = tree_new_child(NULL, "virtio-console", NULL);
+
+    tree_put_propf(node, "index", "%d", index);
+    dt_add_dyn_dev(conf, host, node, 0);
+}
+
+static void dt_add_nic(tree *conf, dt_host *host, NICInfo *n)
+{
+    tree *node = tree_new_child(NULL, "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_add_dyn_dev(conf, host, node, 0);
+    dt_attach_nic(host, node, n->vlan);
+}
+
+static void dt_add_scsi(tree *conf, dt_host *host, int busno)
+{
+    tree *node = tree_new_child(NULL, "scsi", NULL);
+
+    dt_add_dyn_dev(conf, host, node, 0);
+    assert(dt_find_bus(conf, DT_BUS_SCSI, busno)->conf == node);
+}
+
+static void dt_add_virtio_block(tree *conf, dt_host *host, int busno)
+{
+    tree *node = tree_new_child(NULL, "virtio-block", NULL);
+
+    dt_add_dyn_dev(conf, host, node, 0);
+    assert(dt_find_bus(conf, DT_BUS_VIRTIO, busno)->conf == node);
+}
+
+static const char *block_if_name[] = {
+    [IF_IDE] = "ide",
+    [IF_SCSI] = "scsi",
+    [IF_FLOPPY] = "floppy",
+    [IF_PFLASH] = "pflash",
+    [IF_MTD] = "mtd",
+    [IF_SD] = "sd",
+    [IF_VIRTIO] = "virtio",
+};
+
+static void dt_do_add_drive(tree *conf, dt_host *host,
+                            int bus_type, int busno, int unit,
+                            BlockDriverState *bdrv)
+{
+    char buf[32];
+    tree *node;
+
+    snprintf(buf, sizeof(buf), "%s-drive", block_if_name[bus_type]);
+    node = tree_new_child(NULL, strdup(buf), NULL);
+    tree_put_propf(node, "unit", "%d", unit);
+    dt_add_dyn_dev(conf, host, node, busno);
+    dt_attach_drive(host, node, bdrv);
+}
+
+static void dt_add_drive(tree *conf, dt_host *host, DriveInfo *d)
+{
+    switch (d->type) {
+    case IF_IDE:
+        /* hack to hang all IDE drives off the same node for now */
+        dt_do_add_drive(conf, host,
+                        d->type, 0, d->bus * MAX_IDE_DEVS + d->unit, d->bdrv);
+        break;
+    case IF_SCSI:
+    case IF_FLOPPY:
+        dt_do_add_drive(conf, host,
+                        d->type, d->bus, d->unit, d->bdrv);
+        break;
+    case IF_VIRTIO:
+        /* See comment in on virtio block in dt_add_dyn_devs() */
+        dt_do_add_drive(conf, host,
+                        d->type, dt_alloc_virtio_bus(host), 0, d->bdrv);
+        break;
+    default:
+        /* TODO implement */
+        fprintf(stderr, "Ignoring unimplemented drive %s\n",
+                drives_opt[d->drive_opt_idx].opt);
+        break;
+    }
+}
+
+void dt_add_dyn_devs(tree *conf, dt_host *host, int vga_ram_size)
+{
+    int i, max_bus, busno;
+
+    /* VGA */
+    if (cirrus_vga_enabled || vmsvga_enabled || std_vga_enabled) {
+        dt_add_vga(conf, host,
+                   cirrus_vga_enabled ? "cirrus"
+                   : vmsvga_enabled ? "vms" : "std",
+                   vga_ram_size);
+    }
+
+    /* Virtio consoles */
+    for (i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+        if (virtcon_hds[i])
+            dt_add_virtio_console(conf, host, i);
+    }
+
+    /* NICs */
+    for(i = 0; i < nb_nics; i++)
+        dt_add_nic(conf, host, &nd_table[i]);
+
+    /*
+     * SCSI controllers
+     *
+     * This creates all controllers 0..max_bus, whether they have
+     * drives or not.  Matches pc.c behavior.
+     */
+    max_bus = drive_get_max_bus(IF_SCSI);
+    for (i = 0; i <= max_bus; i++)
+        dt_add_scsi(conf, host, i);
+
+    /*
+     * Virtio block controllers
+     *
+     * Each virtio drive is its own PCI device.  Since the device tree
+     * should reflect that, we give each device on its own virtio
+     * block controller node.
+     *
+     * DriveInfo's bus and unit are a mess.  The user can specify any
+     * bus or unit number.  An unspecified bus number defaults to
+     * zero, and an unspecified unit number defaults to the first
+     * unused one (see drive_init()).  pc.c silently ignores all
+     * virtio drives with non-zero bus number, and all drives on bus
+     * zero after the first unused unit number.  Instead of
+     * replicating that questionable behavior, simply ignore bus and
+     * unit for these drives.
+     */
+    busno = 0;
+    for (i = 0; i < nb_drives; i++) {
+        if (drives_table[i].type == IF_VIRTIO)
+            dt_add_virtio_block(conf, host, busno++);
+    }
+
+    /* Drives */
+    for (i = 0; i < nb_drives; i++)
+        dt_add_drive(conf, host, &drives_table[i]);
+}
+
+void dt_add_memory(tree *conf, dt_host *host,
+                   target_phys_addr_t addr, ram_addr_t sz, int ro)
+{
+    tree *node = tree_new_child(NULL, "memory", NULL);
+
+    tree_put_propf(node, "address", "0x" TARGET_FMT_plx, addr);
+    tree_put_propf(node, "size", "%#lx", (unsigned long)sz);
+    if (ro)
+        tree_put_prop(node, "read-only", NULL, 0);
+    dt_add_dyn_dev(conf, host, node, 0);
+}
+
+
+/* Create a configuration */
+
+#if 0 /* TODO implement */
+tree *dt_read_config(const char *name)
+{
+}
+#endif
+
+static void
+dt_int_tree_print(dt_device *dev, int indent)
+{
+    const char *name = tree_node_name(dev->conf);
+    dt_device *child;
+
+    printf("%*s%s {\n", indent, "", *name ? name : "/");
+    TAILQ_FOREACH(child, &dev->int_children, int_siblings)
+        dt_int_tree_print(child, indent + 4);
+    printf("%*s};\n", indent, "");
+}
+
+dt_device *dt_create_machine(tree *conf, dt_host *host, const char *cpu_model)
+{
+    tree *node;
+
+    tree_print(conf);
+
+    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);
+
+    return dt_create(conf, host);
+}
+
+void dt_config_machine(dt_device *root, dt_host *host)
+{
+    dt_config(root, host);
+
+    dt_print_host_config(host);
+    tree_print(root->conf);
+    dt_int_tree_print(root, 0);
+
+    dt_fdt_test(root->conf);
+}
diff --git a/dt.h b/dt.h
new file mode 100644
index 0000000..003d8d1
--- /dev/null
+++ b/dt.h
@@ -0,0 +1,150 @@
+#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_driver dt_driver;
+typedef struct dt_prop_spec dt_prop_spec;
+typedef struct dt_bus_options dt_bus_options;
+
+
+/* Host Configuration */
+
+typedef void (*dt_mem_loader)(target_phys_addr_t, ram_addr_t, const void *);
+
+dt_host *dt_create_host(const dt_driver *drvtab);
+const dt_driver *dt_driver_by_name(dt_host *host, const char *name);
+void dt_attach_nic(dt_host *host, tree *nic, VLANState *vlan);
+VLANState *dt_find_vlan(tree *conf, dt_host *host);
+void dt_attach_drive(dt_host *host, tree *node, BlockDriverState *state);
+void dt_find_drives(tree *conf, dt_host *host,
+                    BlockDriverState *drive[], int n);
+void dt_config_mem(dt_host *host, dt_mem_loader loader,
+                   target_phys_addr_t addr, ram_addr_t size, const void *);
+void dt_image_loader(target_phys_addr_t addr, ram_addr_t size, const void *);
+int dt_alloc_virtio_bus(dt_host *host);
+void dt_host_init(dt_host *host);
+void dt_print_host_config(dt_host *host);
+
+
+/* Device Interface */
+
+/*
+ * Device life cycle:
+ *
+ * 1. Configuration: config() method runs after parent's.  It should
+ * initialize the device's private data from its configuration
+ * sub-tree.  It may edit the configuration sub-tree.  Private data is
+ * zeroed before config() runs.
+ *
+ * 2. Initialization: int_init() method runs after interrupt parent's.
+ * Then init() method runs after parent's.  Neither should 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 */
+    const dt_driver *drv;       /* device driver */
+    tree *int_parent;           /* interrupt parent if != tree_parent(conf) */
+    TAILQ_HEAD(, dt_device) int_children;
+    TAILQ_ENTRY(dt_device) int_siblings;
+    void *priv;                 /* device private data */
+};
+
+typedef enum dt_bus_type {
+    DT_BUS_NONE, DT_BUS_ROOT, DT_BUS_PCI, DT_BUS_ISA, DT_BUS_IDE,
+    DT_BUS_SCSI, DT_BUS_FLOPPY, DT_BUS_VIRTIO, DT_BUS_NUM
+} dt_bus_type;
+
+struct dt_driver {
+    const char *name;
+    size_t privsz;              /* size of device private data */
+    const dt_prop_spec *prop_spec; /* recognized conf node properties */
+    dt_bus_type bus_type, parent_bus_type;
+    /* live cycle methods */
+    void (*config)(dt_device *, dt_host *);
+    void (*int_init)(dt_device *);
+    void (*init)(dt_device *);
+    void (*start)(dt_device *);
+    /* def'd iff device is a PCI bus, may return NULL until after init() */
+    PCIBus *(*get_pcibus)(dt_device *);
+    /* optional, always available */
+    int (*get_unit)(dt_device *);
+    /* def'd iff is an int. ctrlr., may return NULL until after int_init() */
+    qemu_irq *(*get_int)(dt_device *, int *);
+};
+
+typedef struct dt_pcidevice {
+    int devfn;
+} dt_pcidevice;
+
+dt_device *dt_device_of(tree *conf);
+dt_device *dt_parent_device(dt_device *dev);
+dt_device *dt_root(dt_device *dev);
+dt_device *dt_find_bus(tree *conf, dt_bus_type bus_type, int busno);
+PCIBus *dt_get_pcibus(dt_device *dev);
+int dt_get_unit(dt_device *dev);
+qemu_irq *dt_get_int(dt_device *dev, int n);
+
+tree *dt_read_config(const char *name);
+dt_device *dt_create_machine(tree *conf, dt_host *host, const char *cpu_model);
+void dt_config_machine(dt_device *root, dt_host *host);
+void dt_add_dyn_devs(tree *conf, dt_host *host, int vga_ram_size);
+void dt_add_memory(tree *conf, dt_host *host,
+                   target_phys_addr_t addr, ram_addr_t sz, int ro);
+void dt_init_machine(dt_device *root, dt_host *host);
+
+
+/* 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 *, const dt_prop_spec *);
+};
+
+#define DT_PROP_SPEC_INIT(name, strty, member, fmt)                     \
+    { name, offsetof(strty, member), sizeof(((strty *)0)->member),      \
+      dt_parse_##fmt }
+#define DT_PROP_SPEC_SENTINEL() { NULL, 0, 0, NULL }
+
+/* Canned property parse methods */
+#define dt_parse_void NULL
+int dt_parse_string(void *dst, const char *src, const dt_prop_spec *spec);
+int dt_parse_int(void *dst, const char *src, const dt_prop_spec *spec);
+int dt_parse_ram_addr_t(void *dst, const char *src, const dt_prop_spec *spec);
+int dt_parse_target_phys_addr_t(void *dst, const char *src,
+                                const dt_prop_spec *spec);
+int dt_parse_macaddr(void *dst, const char *src, const dt_prop_spec *spec);
+int dt_parse_pci_unitaddr(void *dst, const char *src, const dt_prop_spec *spec);
+
+/* Bus-specific device properties */
+extern const dt_prop_spec dt_bus_prop_spec_pci[];
+
+
+/* Interfacing with FDT */
+
+#ifdef HAVE_FDT
+void dt_fdt_test(tree *conf);
+#else
+static inline void dt_fdt_test(tree *conf) { }
+#endif
+
+#endif
diff --git a/hw/boards.h b/hw/boards.h
index 5611d2c..8f56b5f 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -32,6 +32,9 @@ extern QEMUMachine axisdev88_machine;
 extern QEMUMachine pc_machine;
 extern QEMUMachine isapc_machine;
 
+/* pcdt.c */
+extern QEMUMachine pcdt_machine;
+
 /* xen_machine.c */
 extern QEMUMachine xenpv_machine;
 
diff --git a/hw/pc.c b/hw/pc.c
index a9a39a9..f591919 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -38,42 +38,35 @@
 #include "virtio-console.h"
 #include "hpet_emul.h"
 #include "smbios.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 FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
 #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
 
-#define MAX_IDE_BUS 2
-
 static 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);
 }
@@ -122,7 +115,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;
 
@@ -204,7 +197,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)
 {
     Monitor *mon = cur_mon;
 #define PC_MAX_BOOT_DEVICES 3
@@ -231,10 +224,10 @@ static int pc_boot_set(void *opaque, const char *boot_device)
 }
 
 /* hd_table must contain 4 block drivers */
-static void cmos_init(RTCState *s,
-                      ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
-                      const char *boot_device, BlockDriverState **hd_table,
-                      int fd0, int fd1)
+void cmos_init(RTCState *s,
+               ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+               const char *boot_device, BlockDriverState **hd_table,
+               int fd0, int fd1)
 {
     int nbds, bds[3] = { 0, };
     int val;
@@ -364,13 +357,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;
 }
@@ -424,7 +417,7 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
 
 extern uint64_t node_cpumask[MAX_NODES];
 
-static void bochs_bios_init(void)
+void bochs_bios_init(void)
 {
     void *fw_cfg;
     uint8_t *smbios_table;
@@ -568,10 +561,10 @@ static long get_file_size(FILE *f)
     return size;
 }
 
-static void load_linux(target_phys_addr_t option_rom,
-                       const char *kernel_filename,
-		       const char *initrd_filename,
-		       const char *kernel_cmdline)
+void load_linux(target_phys_addr_t option_rom,
+                const char *kernel_filename,
+                const char *initrd_filename,
+                const char *kernel_cmdline)
 {
     uint16_t protocol;
     uint32_t gpr[8];
@@ -722,7 +715,7 @@ static void load_linux(target_phys_addr_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);
@@ -737,11 +730,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..a2d0df1
--- /dev/null
+++ b/hw/pcdt.c
@@ -0,0 +1,941 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ * 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.h interface.
+ * 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 interface.
+ *
+ * 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.
+ *
+ * The drivers here generally don't do the actual work, they just
+ * provide a common interface to existing device code.  Arguably, they
+ * should be integrated into that device code, with the goal of
+ * eventually replacing the old, ad hoc interfaces.
+ *
+ * Several drivers here are not PC-specific, e.g. drivers for various
+ * PCI devices.
+ */
+
+#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 "virtio-blk.h"
+#include "virtio-balloon.h"
+#include "virtio-console.h"
+#include "hpet_emul.h"
+#include "pcint.h"
+#include "dt.h"
+
+
+/* CPUs Driver */
+
+typedef struct dt_device_cpus {
+    const char *model;
+    int num;
+} dt_device_cpus;
+
+static const 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),
+    DT_PROP_SPEC_SENTINEL()
+};
+
+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 CPU definition\n");
+            exit(1);
+        }
+        if (i != 0)
+            env->halted = 1;
+        qemu_register_reset(main_cpu_reset, env);
+        if (1 /* TODO priv->apic */) {
+            env->cpuid_features |= CPUID_APIC;
+            apic_init(env);
+        }
+    }
+}
+
+
+/* Memory Driver */
+
+typedef struct dt_device_memory {
+    target_phys_addr_t addr;
+    ram_addr_t size;
+    int read_only;
+} dt_device_memory;
+
+static const dt_prop_spec dt_memory_props[] = {
+    DT_PROP_SPEC_INIT("address", dt_device_memory, addr, target_phys_addr_t),
+    DT_PROP_SPEC_INIT("size", dt_device_memory, size, ram_addr_t),
+    DT_PROP_SPEC_INIT("read-only", dt_device_memory, read_only, void),
+    DT_PROP_SPEC_SENTINEL()
+};
+
+static void dt_memory_init(dt_device *dev)
+{
+    dt_device_memory *priv = dev->priv;
+    ram_addr_t host_offs;
+
+    host_offs = qemu_ram_alloc(priv->size);
+    cpu_register_physical_memory(priv->addr, priv->size,
+                        host_offs | (priv->read_only ? IO_MEM_ROM : 0));
+
+    printf("memory " TARGET_FMT_plx " %8lx %8lx %s\n",
+           priv->addr, (unsigned long)priv->size, (unsigned long)host_offs,
+           priv->read_only ? "ro" : "rw");
+}
+
+
+/* i8254 PIT Driver */
+
+/*
+ * TODO Factor out the parts that are not PC-specific, and move them
+ * out, since there are other architectures that use it.
+ *
+ * TODO HPET should be separate from PIT.
+ */
+
+typedef struct dt_device_i8254 {
+    int hpet;
+} dt_device_i8254;
+
+static void dt_i8254_config(dt_device *dev, dt_host *host)
+{
+    dt_device_i8254 *priv = dev->priv;
+
+    priv->hpet = 1;
+}
+
+static void dt_i8254_init(dt_device *dev)
+{
+    PITState *pit;
+    qemu_irq *gsi;
+    dt_device_i8254 *priv = dev->priv;
+
+    gsi = dt_get_int(dev, 16);
+
+    pit = pit_init(0x40, gsi[0]);
+    pcspk_init(pit);
+    if (priv->hpet)
+        hpet_init(gsi);
+}
+
+
+/* PC APIC Driver */
+
+/*
+ * This driver takes care of I/O APICs and the pair of i8259 PICs.
+ * Bunching them together that way keeps the interrupt graph a tree.
+ * The result is an interrupt controller for GSIs.
+ */
+
+typedef struct dt_device_apic {
+    qemu_irq *gsi;
+} dt_device_apic;
+
+static void dt_apic_int_init(dt_device *dev)
+{
+    dt_device_apic *priv = dev->priv;
+    qemu_irq *cpu_irq;
+    IOAPICState *ioapic;
+
+    cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
+    priv->gsi = i8259_init(cpu_irq[0]);
+    ferr_irq = priv->gsi[13];
+    if (1 /* TODO priv->ioapic */) {
+        ioapic = ioapic_init();
+        pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
+    }
+}
+
+static qemu_irq *dt_apic_get_int(dt_device *dev, int *nirq)
+{
+    dt_device_apic *priv = dev->priv;
+
+    if (nirq)
+        *nirq = 16;
+    return priv->gsi;
+}
+
+
+/* MC146818 RTC Driver */
+
+typedef struct dt_device_MC146818 {
+    const char *boot_device;
+    ram_addr_t ram_below_4g, ram_above_4g;
+    /* TODO store cylinders, heads, sectors, translation instead of bds[] */
+    BlockDriverState *ide_bds[MAX_IDE_BUS * MAX_IDE_DEVS];
+    int fd0, fd1;
+} dt_device_MC146818;
+
+static const dt_prop_spec dt_MC146818_props[] = {
+    DT_PROP_SPEC_INIT("boot-device", dt_device_MC146818, boot_device,
+                      string),
+    DT_PROP_SPEC_INIT("ram-below-4g", dt_device_MC146818, ram_below_4g,
+                      ram_addr_t),
+    DT_PROP_SPEC_INIT("ram-above-4g", dt_device_MC146818, ram_above_4g,
+                      ram_addr_t),
+    DT_PROP_SPEC_SENTINEL()
+};
+
+static void dt_MC146818_config(dt_device *dev, dt_host *host)
+{
+    dt_device_MC146818 *priv = dev->priv;
+    BlockDriverState *fd_bds[MAX_FD];
+
+    dt_find_drives(dt_find_bus(dt_root(dev)->conf, DT_BUS_IDE, 0)->conf,
+                   host, priv->ide_bds, ARRAY_SIZE(priv->ide_bds));
+    dt_find_drives(dt_find_bus(dt_root(dev)->conf, DT_BUS_FLOPPY, 0)->conf,
+                   host, fd_bds, ARRAY_SIZE(fd_bds));
+    priv->fd0 = fdctrl_get_drive_type(fd_bds[0]);
+    priv->fd1 = fdctrl_get_drive_type(fd_bds[1]);
+}
+
+static void dt_MC146818_init(dt_device *dev)
+{
+    dt_device_MC146818 *priv = dev->priv;
+    qemu_irq *gsi = dt_get_int(dev, 16);
+    RTCState *rtc_state;
+
+    rtc_state = rtc_init(0x70, gsi[8], 2000);
+    qemu_register_boot_set(pc_boot_set, rtc_state);
+    cmos_init(rtc_state,
+              priv->ram_below_4g, priv->ram_above_4g, priv->boot_device,
+              priv->ide_bds, priv->fd0, priv->fd1);
+}
+
+
+/* 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 {
+    BlockDriverState *bds[MAX_FD];
+} dt_device_pc_misc;
+
+static void dt_pc_misc_config(dt_device *dev, dt_host *host)
+{
+    dt_device_pc_misc *priv = dev->priv;
+
+    dt_find_drives(dev->conf, host, priv->bds, ARRAY_SIZE(priv->bds));
+}
+
+static void dt_pc_misc_init(dt_device *dev)
+{
+    dt_device_pc_misc *priv = dev->priv;
+    qemu_irq *gsi;
+    int i;
+
+    gsi = dt_get_int(dev, 16);
+
+    vmport_init();
+
+    bochs_bios_init();
+
+    register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
+    register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
+
+    register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
+    register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_init(serial_io[i], gsi[serial_irq[i]], 115200,
+                        serial_hds[i]);
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        if (parallel_hds[i]) {
+            parallel_init(parallel_io[i], gsi[parallel_irq[i]],
+                          parallel_hds[i]);
+        }
+    }
+
+    qemu_system_hot_add_init();
+
+    i8042_init(gsi[1], gsi[12], 0x60);
+    DMA_init(0);
+
+    fdctrl_init(gsi[6], 2, 0, 0x3f0, priv->bds);
+}
+
+
+/* PCI Bus Driver */
+
+typedef struct dt_device_pci {
+    PCIBus *pcibus;
+} dt_device_pci;
+
+static void dt_pci_init(dt_device *dev)
+{
+    dt_device_pci *priv = dev->priv;
+
+    priv->pcibus = i440fx_init(&i440fx_state, dt_get_int(dev, 16));
+}
+
+static void dt_pci_start(dt_device *dev)
+{
+    i440fx_init_memory_mappings(i440fx_state);
+}
+
+static PCIBus *dt_pci_get_pcibus(dt_device *dev)
+{
+    return ((dt_device_pci *)dev->priv)->pcibus;
+}
+
+
+/* PIIX3 IDE Driver */
+
+typedef struct dt_device_piix3_ide {
+    dt_pcidevice pci_dev;
+    BlockDriverState *bds[MAX_IDE_BUS * MAX_IDE_DEVS];
+} dt_device_piix3_ide;
+
+static void dt_piix3_ide_config(dt_device *dev, dt_host *host)
+{
+    dt_device_piix3_ide *priv = dev->priv;
+
+    dt_find_drives(dev->conf, host, priv->bds, ARRAY_SIZE(priv->bds));
+}
+
+static void dt_piix3_ide_init(dt_device *dev)
+{
+    dt_device_piix3_ide *priv = dev->priv;
+    PCIBus *pci_bus = dt_get_pcibus(dev);
+    qemu_irq *gsi = dt_get_int(dev, 16);
+
+    pci_piix3_ide_init(pci_bus, priv->bds, priv->pci_dev.devfn, gsi);
+}
+
+
+/* PIIX3 USB Driver */
+
+typedef struct dt_device_piix3_usb {
+    dt_pcidevice pci_dev;
+} dt_device_piix3_usb;
+
+static void dt_piix3_usb_init(dt_device *dev)
+{
+    dt_device_piix3_usb *priv = dev->priv;
+    PCIBus *pci_bus = dt_get_pcibus(dev);
+
+    usb_uhci_piix3_init(pci_bus, priv->pci_dev.devfn);
+}
+
+
+/* PIIX3 ACPI Driver */
+
+typedef struct dt_device_piix3_acpi {
+    dt_pcidevice pci_dev;
+} dt_device_piix3_acpi;
+
+static void dt_piix3_acpi_init(dt_device *dev)
+{
+    dt_device_piix3_acpi *priv = dev->priv;
+    int i;
+    uint8_t *eeprom_buf;
+    i2c_bus *smbus;
+    PCIBus *pci_bus = dt_get_pcibus(dev);
+    qemu_irq *gsi = dt_get_int(dev, 16);
+
+    eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+
+    /* TODO: Populate SPD eeprom data.  */
+    smbus = piix4_pm_init(pci_bus, priv->pci_dev.devfn, 0xb100, gsi[9]);
+    for (i = 0; i < 8; i++)
+        smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));
+}
+
+
+/* PIIX3 Driver */
+
+typedef struct dt_device_piix3 {
+    dt_pcidevice pci_dev;
+} dt_device_piix3;
+
+static void dt_piix3_init(dt_device *dev)
+{
+    dt_device_piix3 *priv = dev->priv;
+    PCIBus *pci_bus = dt_get_pcibus(dev);
+
+    piix3_init(pci_bus, priv->pci_dev.devfn);
+}
+
+static qemu_irq *dt_piix3_get_int(dt_device *dev, int *nirq)
+{
+    if (nirq)
+        *nirq = 16;
+    return dt_get_int(dev, 16);
+}
+
+
+/* VGA Driver */
+
+typedef struct dt_driver_vga {
+    const char *model;
+    void (*init)(PCIBus *, int);
+} dt_driver_vga;
+
+static void pci_vga_init_(PCIBus *bus, int vga_ram_size)
+{
+    pci_vga_init(bus, vga_ram_size, 0, 0);
+}
+
+static dt_driver_vga dt_driver_vga_table[] = {
+    { "cirrus", pci_cirrus_vga_init },
+    { "vms", pci_vmsvga_init },
+    { "std", pci_vga_init_ },
+    { NULL, NULL }
+};
+
+typedef struct dt_device_vga {
+    dt_pcidevice pci_dev;       /* TODO unused */
+    const char *model;
+    ram_addr_t ram_size;
+    dt_driver_vga *vga_drv;
+} dt_device_vga;
+
+static const 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),
+    DT_PROP_SPEC_SENTINEL()
+};
+
+static void dt_vga_config(dt_device *dev, dt_host *host)
+{
+    dt_device_vga *priv = dev->priv;
+    int i;
+
+    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];
+}
+
+static void dt_vga_init(dt_device *dev)
+{
+    dt_device_vga *priv = dev->priv;
+
+    priv->vga_drv->init(dt_get_pcibus(dev), priv->ram_size);
+}
+
+
+/* NIC Driver */
+
+typedef struct dt_device_nic {
+    dt_pcidevice pci_dev;       /* TODO unused */
+    NICInfo nd;
+} dt_device_nic;
+
+static const 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),
+    DT_PROP_SPEC_SENTINEL()
+};
+
+static void dt_nic_config(dt_device *dev, dt_host *host)
+{
+    dt_device_nic *priv = dev->priv;
+
+    priv->nd.vlan = dt_find_vlan(dev->conf, host);
+}
+
+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);
+}
+
+
+/* SCSI Driver */
+
+typedef struct dt_device_scsi {
+    dt_pcidevice pci_dev;       /* TODO unused */
+    void *opaque;
+    BlockDriverState *bds[LSI_MAX_DEVS];
+} dt_device_scsi;
+
+static void dt_scsi_config(dt_device *dev, dt_host *host)
+{
+    dt_device_scsi *priv = dev->priv;
+
+    dt_find_drives(dev->conf, host, priv->bds, ARRAY_SIZE(priv->bds));
+}
+
+static void dt_scsi_init(dt_device *dev)
+{
+    dt_device_scsi *priv = dev->priv;
+    int i;
+
+    priv->opaque = lsi_scsi_init(dt_get_pcibus(dev), -1);
+
+    for (i = 0; i < ARRAY_SIZE(priv->bds); i++) {
+        if (priv->bds[i])
+            lsi_scsi_attach(priv->opaque, priv->bds[i], i);
+    }
+}
+
+
+/* Virtio Block Driver */
+
+typedef struct dt_device_virtio_block {
+    dt_pcidevice pci_dev;       /* TODO unused */
+    BlockDriverState *bds[1];
+} dt_device_virtio_block;
+
+static void dt_virtio_block_config(dt_device *dev, dt_host *host)
+{
+    dt_device_virtio_block *priv = dev->priv;
+
+    dt_find_drives(dev->conf, host, priv->bds, ARRAY_SIZE(priv->bds));
+}
+
+static void dt_virtio_block_init(dt_device *dev)
+{
+    dt_device_virtio_block *priv = dev->priv;
+
+    virtio_blk_init(dt_get_pcibus(dev), priv->bds[0]);
+}
+
+
+/* Virtio Balloon Driver */
+
+typedef struct dt_device_virtio_balloon {
+    dt_pcidevice pci_dev;       /* TODO unused */
+} dt_device_virtio_balloon;
+
+static void dt_virtio_balloon_init(dt_device *dev)
+{
+    virtio_balloon_init(dt_get_pcibus(dev));
+}
+
+
+/* Virtio Console Driver */
+
+typedef struct dt_device_virtio_console {
+    dt_pcidevice pci_dev;       /* TODO unused */
+    int index;
+    CharDriverState *hds;
+} dt_device_virtio_console;
+
+static const dt_prop_spec dt_virtio_console_props[] = {
+    DT_PROP_SPEC_INIT("index", dt_device_virtio_console, index, int),
+    DT_PROP_SPEC_SENTINEL()
+};
+
+static void dt_virtio_console_config(dt_device *dev, dt_host *host)
+{
+    dt_device_virtio_console *priv = dev->priv;
+
+    priv->hds = virtcon_hds[priv->index];
+}
+
+static void dt_virtio_console_init(dt_device *dev)
+{
+    dt_device_virtio_console *priv = dev->priv;
+
+    virtio_console_init(dt_get_pcibus(dev), priv->hds);
+}
+
+
+/* Drive Driver */
+
+typedef struct dt_device_drive {
+    int unit;
+} dt_device_drive;
+
+static const dt_prop_spec dt_drive_props[] = {
+    DT_PROP_SPEC_INIT("unit", dt_device_drive, unit, int),
+    DT_PROP_SPEC_SENTINEL()
+};
+
+static int dt_drive_get_unit(dt_device *dev)
+{
+    return ((dt_device_drive *)dev->priv)->unit;
+}
+
+
+/* Machine Driver */
+
+static const dt_driver dt_driver_table[] = {
+    { "", 0, NULL, DT_BUS_ROOT, DT_BUS_NONE,
+      NULL, NULL, NULL, NULL,
+      NULL, NULL, NULL },
+    { "cpus", sizeof(dt_device_cpus), dt_cpus_props,
+      DT_BUS_NONE, DT_BUS_ROOT,
+      NULL, NULL, dt_cpus_init, NULL,
+      NULL, NULL, NULL },
+    { "memory", sizeof(dt_device_memory), dt_memory_props,
+      DT_BUS_NONE, DT_BUS_ROOT,
+      NULL, NULL, dt_memory_init, NULL,
+      NULL, NULL, NULL },
+    { "apic", sizeof(dt_device_apic), NULL,
+      DT_BUS_NONE, DT_BUS_ROOT,
+      NULL, dt_apic_int_init, NULL, NULL,
+      NULL, NULL, dt_apic_get_int },
+    { "i8254", sizeof(dt_device_i8254), NULL,
+      DT_BUS_NONE, DT_BUS_ISA,
+      dt_i8254_config, NULL, dt_i8254_init, NULL,
+      NULL, NULL, NULL },
+    { "MC146818", sizeof(dt_device_MC146818), dt_MC146818_props,
+      DT_BUS_NONE, DT_BUS_ISA,
+      dt_MC146818_config, NULL, dt_MC146818_init, NULL,
+      NULL, NULL, NULL },
+    { "pc-misc", sizeof(dt_device_pc_misc), NULL,
+      DT_BUS_FLOPPY, DT_BUS_ROOT,
+      dt_pc_misc_config, NULL, dt_pc_misc_init, NULL,
+      NULL, NULL, NULL },
+    { "pci", sizeof(dt_device_pci), NULL,
+      DT_BUS_PCI, DT_BUS_ROOT,
+      NULL, NULL, dt_pci_init, dt_pci_start,
+      dt_pci_get_pcibus, NULL, NULL },
+    { "piix3-isa-bridge", sizeof(dt_device_piix3), NULL,
+      DT_BUS_ISA, DT_BUS_PCI,
+      NULL, NULL, dt_piix3_init, NULL,
+      NULL, NULL, dt_piix3_get_int },
+    { "piix3-ide", sizeof(dt_device_piix3_ide), NULL,
+      DT_BUS_IDE, DT_BUS_PCI,
+      dt_piix3_ide_config, NULL, dt_piix3_ide_init, NULL,
+      NULL, NULL, NULL },
+    { "piix3-usb", sizeof(dt_device_piix3_usb), NULL,
+      DT_BUS_NONE, DT_BUS_PCI, /* FIXME: DT_BUS_NONE -> BUS_USB ?*/
+      NULL, NULL, dt_piix3_usb_init, NULL,
+      NULL, NULL, NULL },
+    { "piix3-acpi", sizeof(dt_device_piix3_acpi), NULL,
+      DT_BUS_NONE, DT_BUS_PCI,
+      NULL, NULL, dt_piix3_acpi_init, NULL,
+      NULL, NULL, NULL },
+    { "vga", sizeof(dt_device_vga), dt_vga_props,
+      DT_BUS_NONE, DT_BUS_PCI,
+      dt_vga_config, NULL, dt_vga_init, NULL,
+      NULL, NULL, NULL },
+    { "nic", sizeof(dt_device_nic), dt_nic_props,
+      DT_BUS_NONE, DT_BUS_PCI,
+      dt_nic_config, NULL, dt_nic_init, NULL,
+      NULL, NULL, NULL },
+    { "scsi", sizeof(dt_device_scsi), NULL,
+      DT_BUS_SCSI, DT_BUS_PCI,
+      dt_scsi_config, NULL, dt_scsi_init, NULL,
+      NULL, NULL, NULL },
+    { "virtio-block", sizeof(dt_device_virtio_block), NULL,
+      DT_BUS_VIRTIO, DT_BUS_PCI,
+      dt_virtio_block_config, NULL, dt_virtio_block_init, NULL,
+      NULL, NULL, NULL },
+    { "virtio-balloon", sizeof(dt_device_virtio_balloon), NULL,
+      DT_BUS_NONE, DT_BUS_PCI,
+      NULL, NULL, dt_virtio_balloon_init, NULL,
+      NULL, NULL, NULL },
+    { "virtio-console", sizeof(dt_device_virtio_console), dt_virtio_console_props,
+      DT_BUS_NONE, DT_BUS_PCI,
+      dt_virtio_console_config, NULL, dt_virtio_console_init, NULL,
+      NULL, NULL, NULL },
+    { "ide-drive", sizeof(dt_device_drive), dt_drive_props,
+      DT_BUS_NONE, DT_BUS_IDE,
+      NULL, NULL, NULL, NULL,
+      NULL, dt_drive_get_unit, NULL },
+    { "scsi-drive", sizeof(dt_device_drive), dt_drive_props,
+      DT_BUS_NONE, DT_BUS_SCSI,
+      NULL, NULL, NULL, NULL,
+      NULL, dt_drive_get_unit, NULL },
+    { "floppy-drive", sizeof(dt_device_drive), dt_drive_props,
+      DT_BUS_NONE, DT_BUS_FLOPPY,
+      NULL, NULL, NULL, NULL,
+      NULL, dt_drive_get_unit, NULL },
+    { "virtio-drive", sizeof(dt_device_drive), dt_drive_props,
+      DT_BUS_NONE, DT_BUS_VIRTIO,
+      NULL, NULL, NULL, NULL,
+      NULL, dt_drive_get_unit, NULL },
+    { NULL, 0, NULL, DT_BUS_NONE, DT_BUS_NONE,
+      NULL, NULL, NULL, NULL,
+      NULL, NULL, NULL }
+};
+
+static tree *dt_hardcoded_config(const char *name)
+{
+#ifdef TARGET_X86_64
+#define CPU_MODEL_DEFAULT "qemu64"
+#else
+#define CPU_MODEL_DEFAULT "qemu32"
+#endif
+    tree *root, *pci, *isa, *leaf;
+
+    /*
+     * TODO Read from config file.
+     *
+     * TODO Pretty far from a comprehensive machine configuration, but
+     * we need to start somewhere.
+     */
+    if (strcmp(name, "pcdt")) {
+        fprintf(stderr, "qemu: machine %s not implemented", name);
+        exit(1);
+    }
+    root = tree_new_child(NULL, "", NULL);
+
+    leaf = tree_new_child(root, "cpus", NULL);
+    tree_put_propf(leaf, "model", "%s", CPU_MODEL_DEFAULT);
+
+    leaf = tree_new_child(root, "apic", NULL);
+
+    leaf = tree_new_child(root, "pc-misc", NULL);
+    tree_put_propf(leaf, "interrupt-parent", "/apic");
+
+    pci = tree_new_child(root, "pci", NULL);
+    tree_put_propf(pci, "interrupt-parent", "/apic");
+
+    isa = tree_new_child(pci, "piix3-isa-bridge", NULL);
+    tree_put_propf(isa, "interrupt-parent", "/apic");
+    tree_put_propf(isa, "unit-address", "1.0");
+
+    leaf = tree_new_child(isa, "i8254", NULL);
+
+    leaf = tree_new_child(isa, "MC146818", NULL);
+
+    leaf = tree_new_child(pci, "piix3-ide", NULL);
+    tree_put_propf(leaf, "interrupt-parent", "/apic");
+    tree_put_propf(leaf, "unit-address", "1.1");
+
+    if (usb_enabled) {
+        leaf = tree_new_child(pci, "piix3-usb", NULL);
+        tree_put_propf(leaf, "unit-address", "1.2");
+    }
+
+    if (acpi_enabled) {
+        leaf = tree_new_child(pci, "piix3-acpi", NULL);
+        tree_put_propf(leaf, "interrupt-parent", "/apic");
+        tree_put_propf(leaf, "unit-address", "1.3");
+    }
+
+    leaf = tree_new_child(pci, "virtio-balloon", NULL);
+    return root;
+#undef CPU_MODEL_DEFAULT
+}
+
+#define dt_read_config(name) dt_hardcoded_config((name))
+
+static void dt_add_ram(tree *conf, dt_host *host, ram_addr_t ram_size)
+{
+    ram_addr_t left, sz;
+
+    left = ram_size;
+    sz = MIN(left, 0xa0000);
+    dt_add_memory(conf, host, 0, sz, 0);
+    left -= sz;
+
+    sz = MIN(left, 0x60000);
+    left -= sz;
+
+    if (left) {
+        sz = MIN(left, 0xe0000000 - 0x100000);
+        dt_add_memory(conf, host, 0x100000, sz, 0);
+        left -= sz;
+    }
+
+#if TARGET_PHYS_ADDR_BITS > 32
+    if (left)
+        dt_add_memory(conf, host, 0x100000000ull, left, 0);
+#endif
+}
+
+static char *bios_image_fname(const char *image)
+{
+    char *fname = qemu_malloc(strlen(bios_dir) + 1 + strlen(image) + 1);
+    sprintf(fname, "%s/%s", bios_dir, image);
+    return fname;
+}
+
+static void dt_add_bios(tree *conf, dt_host *host)
+{
+    char *fname = bios_image_fname(bios_name ? bios_name : BIOS_FILENAME);
+    int size;
+    target_phys_addr_t addr;
+
+    size = get_image_size(fname);
+    if (size <= 0 || size % 0x10000 != 0 || size > 0x20000) {
+                                /* FIXME implement size > 0x20000 */
+        fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", fname);
+        exit(1);
+    }
+
+    addr = 0xffffffff - (size - 1);
+    dt_add_memory(conf, host, addr, size, 1);
+    dt_config_mem(host, dt_image_loader, addr, size, fname);
+
+    /* TODO map the same memory again */
+    addr = 0x100000 - size;
+    dt_add_memory(conf, host, addr, size, 1);
+    dt_config_mem(host, dt_image_loader, addr, size, fname);
+}
+
+static int dt_config_oprom(dt_host *host, dt_mem_loader loader,
+                           int offs, int size, const void *arg,
+                           const char *what)
+{
+    offs = (offs + 2047) & ~2047;
+
+    if (offs + size > 0x20000) {
+        if (what)
+            fprintf(stderr, "Not enough space for %s\n", what);
+        else
+            fprintf(stderr, "Not enough space for option rom '%s'\n",
+                    (char *)arg);
+        exit(1);
+    }
+
+    dt_config_mem(host, loader, 0xc0000 + offs, size, arg);
+    return offs + size;
+}
+
+static int dt_config_oprom_image(dt_host *host, int offs, const char *fname)
+{
+    int size;
+
+    size = get_image_size(fname);
+    if (size < 0) {
+        fprintf(stderr, "Could not load option rom '%s'\n", fname);
+        exit(1);
+    }
+
+    return dt_config_oprom(host, dt_image_loader, offs, size, fname, fname);
+}
+
+typedef struct dt_linux_loader_arg {
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} dt_linux_loader_arg;
+
+static void dt_linux_loader(target_phys_addr_t addr, ram_addr_t size,
+                             const void *arg)
+{
+    const dt_linux_loader_arg *llarg = arg;
+
+    load_linux(addr, llarg->kernel_filename, llarg->initrd_filename,
+               llarg->kernel_cmdline);
+}
+
+static void dt_add_oprom(tree *conf, dt_host *host,
+                         const char *kernel_filename,
+                         const char *kernel_cmdline,
+                         const char *initrd_filename)
+{
+    int offs, i;
+    dt_linux_loader_arg *llarg;
+
+    offs = 0;
+
+    if (cirrus_vga_enabled || vmsvga_enabled || std_vga_enabled) {
+        offs = dt_config_oprom_image(host, offs, 
+                                     bios_image_fname(cirrus_vga_enabled
+                                                      ? VGABIOS_CIRRUS_FILENAME
+                                                      : VGABIOS_FILENAME));
+        /*
+         * Although video roms can grow larger than 0x8000, the first
+         * 0x8000 bytes are reserved for them.  It means we won't be
+         * looking for any other kind of option rom inside this area.
+         */
+        offs = MAX(offs, 0x8000);
+    }
+
+    if (kernel_filename) {
+        llarg = qemu_malloc(sizeof(*llarg));
+        llarg->kernel_filename = kernel_filename;
+        llarg->kernel_cmdline = kernel_cmdline;
+        llarg->initrd_filename = initrd_filename;
+        offs = dt_config_oprom(host, dt_linux_loader, offs, 2048, llarg,
+                               "kernel loader");
+    }
+
+    for (i = 0; i < nb_option_roms; i++)
+        offs = dt_config_oprom_image(host, offs, option_rom[i]);
+
+    dt_add_memory(conf, host, 0xc0000, offs, 1);
+}
+
+static void pcdt_init(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;
+    tree *node;
+    dt_host *host;
+    dt_device *root;
+
+    conf = dt_read_config(pcdt_machine.name);
+    if (!conf)
+        exit(1);
+
+    node = tree_node_by_name(conf, "/pci/piix3-isa-bridge/MC146818");
+    tree_put_propf(node, "boot-device", "%s", boot_device);
+    assert(ram_size <= 0xe0000000); /* TODO implement */
+    tree_put_propf(node, "ram-below-4g", "%#lx", (unsigned long)ram_size);
+
+    host = dt_create_host(dt_driver_table);
+    root = dt_create_machine(conf, host, cpu_model);
+
+    dt_add_ram(conf, host, ram_size);
+    dt_add_bios(conf, host);
+    dt_add_oprom(conf, host, kernel_filename, kernel_cmdline, initrd_filename);
+    dt_add_dyn_devs(conf, host, vga_ram_size);
+    dt_config_machine(root, host);
+
+    dt_init_machine(root, host);
+}
+
+QEMUMachine pcdt_machine = {
+    .name = "pcdt",
+    .desc = "Standard PC (device tree)",
+    .init = pcdt_init,
+    .max_cpus = 255,
+};
diff --git a/hw/pcidt.c b/hw/pcidt.c
new file mode 100644
index 0000000..db37311
--- /dev/null
+++ b/hw/pcidt.c
@@ -0,0 +1,67 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ * 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.
+ */
+
+/* PCI Bus */
+
+#include <assert.h>
+#include "hw.h"
+#include "pci.h"
+#include "dt.h"
+
+int dt_parse_pci_unitaddr(void *dst, const char *src, const dt_prop_spec *spec)
+{
+    int devfn, slot, func;
+    unsigned long val;
+    const char *p;
+    char *e;
+
+    assert(spec->size == sizeof(int));
+
+    p = src;
+    val = strtoul(p, &e, 16);
+    if (e == p)
+        return -1;
+
+    slot = val;
+
+    if (*e == '.') {
+        p = e + 1;
+        val = strtoul(p, &e, 16);
+        if (e == p)
+            return -1;
+    } else
+        func = 0;
+
+    func = val;
+
+    devfn = PCI_DEVFN(slot, func);
+    *(int *)dst = devfn;
+
+    return 0;
+}
+
+const dt_prop_spec dt_bus_prop_spec_pci[] = {
+    /*
+     * FIXME assumes every PCI device has a dt_pcidevice at offset 0
+     * in dev->priv
+     */
+    DT_PROP_SPEC_INIT("unit-address", dt_pcidevice, devfn, pci_unitaddr),
+    DT_PROP_SPEC_SENTINEL()
+};
diff --git a/hw/pcint.h b/hw/pcint.h
new file mode 100644
index 0000000..acd645b
--- /dev/null
+++ b/hw/pcint.h
@@ -0,0 +1,47 @@
+/*
+ * 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 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 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];
+
+/* 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(RTCState *s,
+               ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+               const char *boot_device, BlockDriverState **hd_table,
+               int fd0, int fd1);
+void load_linux(target_phys_addr_t option_rom,
+                const char *kernel_filename,
+                const char *initrd_filename,
+                const char *kernel_cmdline);
+
+#endif
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 1b0d36d..6465f77 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -7,6 +7,7 @@
 
 void register_machines(void)
 {
+    qemu_register_machine(&pcdt_machine);
     qemu_register_machine(&pc_machine);
     qemu_register_machine(&isapc_machine);
 #ifdef CONFIG_XEN
diff --git a/tree.c b/tree.c
new file mode 100644
index 0000000..da07b76
--- /dev/null
+++ b/tree.c
@@ -0,0 +1,285 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (C) 2009 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ * 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) children;
+    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_child(tree *parent, const char *name, void *user)
+{
+    tree *child = qemu_malloc(sizeof(*child));
+
+    child->name = name;
+    LIST_INIT(&child->props);
+    child->parent = NULL;
+    TAILQ_INIT(&child->children);
+    child->user = user;
+    if (parent)
+        tree_insert(parent, child);
+
+    return child;
+}
+
+void tree_insert(tree *parent, tree *child)
+{
+    assert(!child->parent);
+    child->parent = parent;
+    TAILQ_INSERT_TAIL(&parent->children, child, siblings);
+}
+
+const char *tree_node_name(const tree *node)
+{
+    return node->name;
+}
+
+static tree *tree_child_by_name(const tree *parent, const char *name)
+{
+    const char *slash = strchr(name, '/');
+    size_t len = slash ? slash - name : strlen(name);
+    tree *child;
+
+    TAILQ_FOREACH(child, &parent->children, siblings) {
+        if (!memcmp(child->name, name, len) && child->name[len] == 0)
+            return child;
+    }
+    return NULL;
+}
+
+tree *tree_node_by_name(const tree *node, const char *name)
+{
+    tree *child;
+    size_t len;
+
+    if (name[0] == '/') {
+        for (; node->parent; node = node->parent) ;
+        while (*name == '/') name++;
+    }
+
+    if (name[0] == 0)
+        return (tree *)node;
+
+    child = tree_child_by_name(node, name);
+    if (!child)
+        return NULL;
+
+    len = strlen(child->name);
+    if (name[len] == 0)
+        return child;
+    assert (name[len] == '/');
+
+    while (name[len] == '/') len++;
+    return tree_node_by_name(child, 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_child(const tree *node)
+{
+    return TAILQ_FIRST(&node->children);
+}
+
+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 == 0) {
+        if (++res < bufsz)
+            *--p = '/';
+    }
+
+    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 *child;
+
+    printf("%*s%s {\n", indent, "", node->parent ? 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(child, &node->children, siblings)
+        tree_print_sub(child, 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..3f3b367
--- /dev/null
+++ b/tree.h
@@ -0,0 +1,41 @@
+#ifndef TREE_H
+#define TREE_H
+
+#include <stddef.h>
+
+typedef struct tree tree;
+typedef struct tree_prop tree_prop;
+
+tree *tree_new_child(tree *parent, const char *name, void *user);
+void tree_insert(tree *parent, tree *child);
+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_child(const tree *node);
+tree *tree_sibling(const tree *node);
+#define TREE_FOREACH_CHILD(var, node) \
+    for (var = tree_first_child(node); var; var = tree_sibling(var))
+
+int tree_path(const tree *node, char *buf, size_t bufsz);
+void tree_print(const tree *node);
+
+#endif
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions Markus Armbruster
@ 2009-05-01 17:27   ` Blue Swirl
  2009-05-04 13:54     ` Markus Armbruster
  0 siblings, 1 reply; 11+ messages in thread
From: Blue Swirl @ 2009-05-01 17:27 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

On 4/30/09, Markus Armbruster <armbru@redhat.com> wrote:
> Pass the state as argument to cmos_init() and cmos_init_hd().
>  cmos_init() still needs to save it in rtc_state for use by
>  cmos_set_s3_resume().

pc.c could pass acpi an opaque handle (former rtc_state) at init or
acpi could export a function to set the handle, called by pc.c. Then
cmos_set_s3_resume could take a state parameter.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] Remove global floppy_controller
  2009-04-30 16:03 ` [Qemu-devel] [PATCH 2/4] Remove global floppy_controller Markus Armbruster
@ 2009-05-01 17:31   ` Blue Swirl
  0 siblings, 0 replies; 11+ messages in thread
From: Blue Swirl @ 2009-05-01 17:31 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

On 4/30/09, Markus Armbruster <armbru@redhat.com> wrote:
> Change cmos_init() to take the floppy drive types as arguments instead
>  of getting them through global floppy_controller.
>
>  Change fdctrl_get_drive_type() to take a BlockDriverState argument.
>  Factor fd_format() out of fd_revalidate() to make that possible.
>
>  Use it to compute the new arguments for cmos_init().

Looks OK.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions
  2009-05-01 17:27   ` Blue Swirl
@ 2009-05-04 13:54     ` Markus Armbruster
  2009-05-05 16:22       ` Blue Swirl
  0 siblings, 1 reply; 11+ messages in thread
From: Markus Armbruster @ 2009-05-04 13:54 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

Blue Swirl <blauwirbel@gmail.com> writes:

> On 4/30/09, Markus Armbruster <armbru@redhat.com> wrote:
>> Pass the state as argument to cmos_init() and cmos_init_hd().
>>  cmos_init() still needs to save it in rtc_state for use by
>>  cmos_set_s3_resume().
>
> pc.c could pass acpi an opaque handle (former rtc_state) at init or
> acpi could export a function to set the handle, called by pc.c. Then
> cmos_set_s3_resume could take a state parameter.

We'd just move a global variable from pc.c to acpi.c, wouldn't we?
Could you explain why that's a better place?

Passing rtc_state to piix4_pm_init() doesn't work well for pcdt.c,
because we'd have to pass it from RTC device to PIIX3 ACPI device
somehow, creating one of those ugly "non-tree" device dependencies,
i.e. one that doesn't follow device tree or interrupt tree edges.  Your
other idea (a function to set the handle) allows me to keep the two
devices decoupled, provided I can set the handle even before
piix4_pm_init().

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions
  2009-05-04 13:54     ` Markus Armbruster
@ 2009-05-05 16:22       ` Blue Swirl
  2009-05-19  6:56         ` Markus Armbruster
  0 siblings, 1 reply; 11+ messages in thread
From: Blue Swirl @ 2009-05-05 16:22 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

On 5/4/09, Markus Armbruster <armbru@redhat.com> wrote:
> Blue Swirl <blauwirbel@gmail.com> writes:
>
>  > On 4/30/09, Markus Armbruster <armbru@redhat.com> wrote:
>  >> Pass the state as argument to cmos_init() and cmos_init_hd().
>  >>  cmos_init() still needs to save it in rtc_state for use by
>  >>  cmos_set_s3_resume().
>  >
>  > pc.c could pass acpi an opaque handle (former rtc_state) at init or
>  > acpi could export a function to set the handle, called by pc.c. Then
>  > cmos_set_s3_resume could take a state parameter.
>
>
> We'd just move a global variable from pc.c to acpi.c, wouldn't we?
>  Could you explain why that's a better place?

No, acpi would only have an opaque pointer to the variable stored in
PIIX4PMState, the "owner" would still be pc.c.

>  Passing rtc_state to piix4_pm_init() doesn't work well for pcdt.c,
>  because we'd have to pass it from RTC device to PIIX3 ACPI device
>  somehow, creating one of those ugly "non-tree" device dependencies,
>  i.e. one that doesn't follow device tree or interrupt tree edges.  Your
>  other idea (a function to set the handle) allows me to keep the two
>  devices decoupled, provided I can set the handle even before
>  piix4_pm_init().

Still one idea: a signal (qemu_irq) could be used to convey the s3
resume condition. That may be another tree.

Setting the handle before piix4_pm_init will fail if the handle is
going to be stored in PIIX4PMState, but the setup can be reversed:
piix4_pm_init can call a function to get the handle.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions
  2009-05-05 16:22       ` Blue Swirl
@ 2009-05-19  6:56         ` Markus Armbruster
  2009-05-19 16:51           ` Blue Swirl
  2009-05-19 16:57           ` Avi Kivity
  0 siblings, 2 replies; 11+ messages in thread
From: Markus Armbruster @ 2009-05-19  6:56 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

Sorry for the sloooow respons, I was on vacation.

Blue Swirl <blauwirbel@gmail.com> writes:

> On 5/4/09, Markus Armbruster <armbru@redhat.com> wrote:
>> Blue Swirl <blauwirbel@gmail.com> writes:
>>
>>  > On 4/30/09, Markus Armbruster <armbru@redhat.com> wrote:
>>  >> Pass the state as argument to cmos_init() and cmos_init_hd().
>>  >>  cmos_init() still needs to save it in rtc_state for use by
>>  >>  cmos_set_s3_resume().
>>  >
>>  > pc.c could pass acpi an opaque handle (former rtc_state) at init or
>>  > acpi could export a function to set the handle, called by pc.c. Then
>>  > cmos_set_s3_resume could take a state parameter.
>>
>>
>> We'd just move a global variable from pc.c to acpi.c, wouldn't we?
>>  Could you explain why that's a better place?
>
> No, acpi would only have an opaque pointer to the variable stored in
> PIIX4PMState, the "owner" would still be pc.c.

Okay, so we'd just move a global variable from pc.c into only instance
of struct PIIX4PMState, referenced from a global variable in acpi.c.
The fact that it becomes opaque in the process isn't much of an
improvement, isn't it?

>>  Passing rtc_state to piix4_pm_init() doesn't work well for pcdt.c,
>>  because we'd have to pass it from RTC device to PIIX3 ACPI device
>>  somehow, creating one of those ugly "non-tree" device dependencies,
>>  i.e. one that doesn't follow device tree or interrupt tree edges.  Your
>>  other idea (a function to set the handle) allows me to keep the two
>>  devices decoupled, provided I can set the handle even before
>>  piix4_pm_init().
>
> Still one idea: a signal (qemu_irq) could be used to convey the s3
> resume condition. That may be another tree.

Hmm.

How does the hardware do it?  Does it update CMOS all by itself?

> Setting the handle before piix4_pm_init will fail if the handle is
> going to be stored in PIIX4PMState,

Correct.

>                                     but the setup can be reversed:
> piix4_pm_init can call a function to get the handle.

Where from?

A global variable in pc.c?  But then we create global state in acpi.c
without reducing it in pc.c.

In the context of pcdt.c: creates the same non-tree device dependency,
only in the opposite direction.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions
  2009-05-19  6:56         ` Markus Armbruster
@ 2009-05-19 16:51           ` Blue Swirl
  2009-05-19 16:57           ` Avi Kivity
  1 sibling, 0 replies; 11+ messages in thread
From: Blue Swirl @ 2009-05-19 16:51 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

On 5/19/09, Markus Armbruster <armbru@redhat.com> wrote:
> Sorry for the sloooow respons, I was on vacation.
>
>
>  Blue Swirl <blauwirbel@gmail.com> writes:
>
>  > On 5/4/09, Markus Armbruster <armbru@redhat.com> wrote:
>  >> Blue Swirl <blauwirbel@gmail.com> writes:
>  >>
>  >>  > On 4/30/09, Markus Armbruster <armbru@redhat.com> wrote:
>  >>  >> Pass the state as argument to cmos_init() and cmos_init_hd().
>  >>  >>  cmos_init() still needs to save it in rtc_state for use by
>  >>  >>  cmos_set_s3_resume().
>  >>  >
>  >>  > pc.c could pass acpi an opaque handle (former rtc_state) at init or
>  >>  > acpi could export a function to set the handle, called by pc.c. Then
>  >>  > cmos_set_s3_resume could take a state parameter.
>  >>
>  >>
>  >> We'd just move a global variable from pc.c to acpi.c, wouldn't we?
>  >>  Could you explain why that's a better place?
>  >
>  > No, acpi would only have an opaque pointer to the variable stored in
>  > PIIX4PMState, the "owner" would still be pc.c.
>
>
> Okay, so we'd just move a global variable from pc.c into only instance
>  of struct PIIX4PMState, referenced from a global variable in acpi.c.
>  The fact that it becomes opaque in the process isn't much of an
>  improvement, isn't it?

Yes it is, acpi.c does not need to know about rtc_state internals.

>  >>  Passing rtc_state to piix4_pm_init() doesn't work well for pcdt.c,
>  >>  because we'd have to pass it from RTC device to PIIX3 ACPI device
>  >>  somehow, creating one of those ugly "non-tree" device dependencies,
>  >>  i.e. one that doesn't follow device tree or interrupt tree edges.  Your
>  >>  other idea (a function to set the handle) allows me to keep the two
>  >>  devices decoupled, provided I can set the handle even before
>  >>  piix4_pm_init().
>  >
>  > Still one idea: a signal (qemu_irq) could be used to convey the s3
>  > resume condition. That may be another tree.
>
>
> Hmm.
>
>  How does the hardware do it?  Does it update CMOS all by itself?

Just guessing: there could be a signal wire from the power management
chip to CMOS GPIO pin and this would be visible in a CMOS register.

>  > Setting the handle before piix4_pm_init will fail if the handle is
>  > going to be stored in PIIX4PMState,
>
>
> Correct.
>
>
>  >                                     but the setup can be reversed:
>  > piix4_pm_init can call a function to get the handle.
>
>
> Where from?
>
>  A global variable in pc.c?  But then we create global state in acpi.c
>  without reducing it in pc.c.

pc.c is the "owner" of most devices, so that's OK. acpi.c only has a handle.

>  In the context of pcdt.c: creates the same non-tree device dependency,
>  only in the opposite direction.

I don't see how you can avoid it. Maybe power management wants a tree
of its own.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions
  2009-05-19  6:56         ` Markus Armbruster
  2009-05-19 16:51           ` Blue Swirl
@ 2009-05-19 16:57           ` Avi Kivity
  1 sibling, 0 replies; 11+ messages in thread
From: Avi Kivity @ 2009-05-19 16:57 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Blue Swirl, qemu-devel

Markus Armbruster wrote:
> How does the hardware do it?  Does it update CMOS all by itself?
>   

I'm guessing the hardware only makes this present in a chipset 
register.  The BIOS reads the registers and writes the CMOS memory 
(which is likely on the same chip, but...).

Would be best to adopt that.

-- 
error compiling committee.c: too many arguments to function

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2009-05-19 16:57 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <cover.1241106809.git.armbru@redhat.com>
2009-04-30 16:03 ` [Qemu-devel] [PATCH 1/4] Confine use of global rtc_state to PC CMOS functions Markus Armbruster
2009-05-01 17:27   ` Blue Swirl
2009-05-04 13:54     ` Markus Armbruster
2009-05-05 16:22       ` Blue Swirl
2009-05-19  6:56         ` Markus Armbruster
2009-05-19 16:51           ` Blue Swirl
2009-05-19 16:57           ` Avi Kivity
2009-04-30 16:03 ` [Qemu-devel] [PATCH 2/4] Remove global floppy_controller Markus Armbruster
2009-05-01 17:31   ` Blue Swirl
2009-04-30 16:03 ` [Qemu-devel] [PATCH 3/4] Give parse_macaddr() external linkage Markus Armbruster
2009-04-30 16:03 ` [Qemu-devel] [PATCH 4/4] Machine description as data Markus Armbruster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).