All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/4] Machine config files
@ 2009-06-10 17:38 Paul Brook
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 1/4] Include and build libfdt Paul Brook
                   ` (6 more replies)
  0 siblings, 7 replies; 61+ messages in thread
From: Paul Brook @ 2009-06-10 17:38 UTC (permalink / raw)
  To: qemu-devel

The following series implements machine config files, and adds converts
some of the existing hardcoded machines.

The config files themselves are based on the ppc-linux Flattened Device Trees.
In generaly I've tried to structure things so that the same config file can
be used for both qemu and linux.

There are a still a few things missing, in particular PCI busses are untested,
but both SSI and I2C work.

To handle options like -kernel I've added a "bootstrap" facility. This
allows additional board initialization on top of normal hardware reset.
In the future we may want some more common features (e.g. loading ROM images),
but for now it just provides the functionality in the same way as the old
board init routine.

Also available from git://repo.or.cz/qemu/pbrook.git devtree

---

Paul Brook (4):
      Integrator machine config
      Stellaris machine config
      Add device tree machine
      Include and build libfdt


 .gitignore                       |    1 
 Makefile                         |   39 +
 Makefile.hw                      |    2 
 Makefile.target                  |   19 -
 configure                        |   41 +
 hw/arm-cpu.c                     |   79 +++
 hw/arm_boot.c                    |   22 +
 hw/arm_timer.c                   |    2 
 hw/armv7m.c                      |   61 ++
 hw/boards.h                      |    9 
 hw/dt-machine.c                  |  582 +++++++++++++++++++++
 hw/gpio-buttons.c                |  124 ++++
 hw/i2c.c                         |    8 
 hw/integratorcp.c                |   97 ---
 hw/pci.c                         |    1 
 hw/petalogix_s3adsp1800_mmu.c    |   40 -
 hw/pl011.c                       |    2 
 hw/pl061.c                       |   25 +
 hw/ppc440_bamboo.c               |    2 
 hw/ppce500_mpc8544ds.c           |    4 
 hw/qdev.c                        |  225 ++++++++
 hw/qdev.h                        |   50 +-
 hw/ssi.c                         |    7 
 hw/stellaris.c                   |  272 ++--------
 hw/stellaris_enet.c              |    2 
 hw/stellaris_input.c             |   91 ---
 hw/syborg.c                      |  112 ----
 hw/sysbus.c                      |    5 
 hw/sysbus.h                      |   15 -
 libfdt/Makefile.libfdt           |   14 
 libfdt/TODO                      |    3 
 libfdt/fdt.c                     |  156 ++++++
 libfdt/fdt.h                     |   60 ++
 libfdt/fdt_ro.c                  |  583 +++++++++++++++++++++
 libfdt/fdt_rw.c                  |  471 +++++++++++++++++
 libfdt/fdt_strerror.c            |   96 +++
 libfdt/fdt_sw.c                  |  258 +++++++++
 libfdt/fdt_wip.c                 |  144 +++++
 libfdt/libfdt.h                  | 1070 ++++++++++++++++++++++++++++++++++++++
 libfdt/libfdt_env.h              |   21 +
 libfdt/libfdt_internal.h         |   89 +++
 libfdt/patch.libfdt              |   20 +
 pc-bios/boards/integrator-cp.dts |  110 ++++
 pc-bios/boards/lm3s6965evb.dts   |  212 ++++++++
 pc-bios/boards/lm3s811evb.dts    |  155 ++++++
 pc-bios/boards/syborg.dts        |  134 +++++
 rules.mak                        |    3 
 sysemu.h                         |    3 
 target-ppc/kvm_ppc.c             |    2 
 vl.c                             |   45 +-
 50 files changed, 4973 insertions(+), 615 deletions(-)
 create mode 100644 hw/arm-cpu.c
 create mode 100644 hw/dt-machine.c
 create mode 100644 hw/gpio-buttons.c
 delete mode 100644 hw/stellaris_input.c
 delete mode 100644 hw/syborg.c
 create mode 100644 libfdt/Makefile.libfdt
 create mode 100644 libfdt/TODO
 create mode 100644 libfdt/fdt.c
 create mode 100644 libfdt/fdt.h
 create mode 100644 libfdt/fdt_ro.c
 create mode 100644 libfdt/fdt_rw.c
 create mode 100644 libfdt/fdt_strerror.c
 create mode 100644 libfdt/fdt_sw.c
 create mode 100644 libfdt/fdt_wip.c
 create mode 100644 libfdt/libfdt.h
 create mode 100644 libfdt/libfdt_env.h
 create mode 100644 libfdt/libfdt_internal.h
 create mode 100644 libfdt/patch.libfdt
 create mode 100644 pc-bios/boards/integrator-cp.dts
 create mode 100644 pc-bios/boards/lm3s6965evb.dts
 create mode 100644 pc-bios/boards/lm3s811evb.dts
 create mode 100644 pc-bios/boards/syborg.dts

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

* [Qemu-devel] [PATCH 1/4] Include and build libfdt
  2009-06-10 17:38 [Qemu-devel] [PATCH 0/4] Machine config files Paul Brook
@ 2009-06-10 17:38 ` Paul Brook
  2009-06-10 19:08   ` Glauber Costa
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 2/4] Add device tree machine Paul Brook
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 61+ messages in thread
From: Paul Brook @ 2009-06-10 17:38 UTC (permalink / raw)
  To: qemu-devel

Inlcude libfdt in source tree, and build it if not already available.

Signed-off-by: Paul Brook <paul@codesourcery.com>
---

 Makefile                      |   17 +
 Makefile.target               |   14 -
 configure                     |   24 -
 hw/petalogix_s3adsp1800_mmu.c |   40 --
 hw/ppc440_bamboo.c            |    2 
 hw/ppce500_mpc8544ds.c        |    4 
 libfdt/Makefile.libfdt        |   14 +
 libfdt/TODO                   |    3 
 libfdt/fdt.c                  |  156 ++++++
 libfdt/fdt.h                  |   60 ++
 libfdt/fdt_ro.c               |  583 ++++++++++++++++++++++
 libfdt/fdt_rw.c               |  471 ++++++++++++++++++
 libfdt/fdt_strerror.c         |   96 ++++
 libfdt/fdt_sw.c               |  258 ++++++++++
 libfdt/fdt_wip.c              |  144 ++++++
 libfdt/libfdt.h               | 1070 +++++++++++++++++++++++++++++++++++++++++
 libfdt/libfdt_env.h           |   21 +
 libfdt/libfdt_internal.h      |   89 +++
 libfdt/patch.libfdt           |   20 +
 target-ppc/kvm_ppc.c          |    2 
 20 files changed, 3028 insertions(+), 60 deletions(-)
 create mode 100644 libfdt/Makefile.libfdt
 create mode 100644 libfdt/TODO
 create mode 100644 libfdt/fdt.c
 create mode 100644 libfdt/fdt.h
 create mode 100644 libfdt/fdt_ro.c
 create mode 100644 libfdt/fdt_rw.c
 create mode 100644 libfdt/fdt_strerror.c
 create mode 100644 libfdt/fdt_sw.c
 create mode 100644 libfdt/fdt_wip.c
 create mode 100644 libfdt/libfdt.h
 create mode 100644 libfdt/libfdt_env.h
 create mode 100644 libfdt/libfdt_internal.h
 create mode 100644 libfdt/patch.libfdt

diff --git a/Makefile b/Makefile
index 3177616..6fc234c 100644
--- a/Makefile
+++ b/Makefile
@@ -57,12 +57,23 @@ SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
 subdir-%:
 	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
 
-$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
+$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a $(BUILD_LIBFDT)
 $(filter %-user,$(SUBDIR_RULES)): libqemu_user.a
 
 recurse-all: $(SUBDIR_RULES)
 
 #######################################################################
+# Build libfdt
+ifdef BUILD_LIBFDT
+include $(SRC_PATH)/libfdt/Makefile.libfdt
+FDT_OBJS=$(addprefix libfdt/,$(LIBFDT_OBJS))
+
+$(FDT_OBJS): CFLAGS+=-I$(SRC_PATH)/libfdt
+
+libfdt/libfdt.a: $(FDT_OBJS)
+endif
+
+#######################################################################
 # BLOCK_OBJS is code used by both qemu system emulation and qemu-img
 
 BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
@@ -255,7 +266,9 @@ clean:
 # avoid old build problems by removing potentially incorrect old files
 	rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
 	rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
-	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d
+	for d in slirp audio block libfdt; do \
+	  rm -f $$d/*.o $$d/*.d $$d/*.a ; \
+	done
 	rm -f qemu-img-cmds.h
 	$(MAKE) -C tests clean
 	for d in $(TARGET_DIRS) libhw32 libhw64; do \
diff --git a/Makefile.target b/Makefile.target
index 27de4b9..4e302c0 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -595,10 +595,6 @@ OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 OBJS+= ppc440.o ppc440_bamboo.o
 # PowerPC E500 boards
 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
 endif
@@ -624,10 +620,6 @@ OBJS+= xilinx_uartlite.o
 OBJS+= xilinx_ethlite.o
 
 OBJS+= pflash_cfi02.o
-ifdef FDT_LIBS
-OBJS+= device_tree.o
-LIBS+= $(FDT_LIBS)
-endif
 endif
 ifeq ($(TARGET_BASE_ARCH), cris)
 # Boards
@@ -695,6 +687,12 @@ endif
 ifdef CONFIG_SLIRP
 CPPFLAGS+=-I$(SRC_PATH)/slirp
 endif
+LIBS+=$(FDT_LIBS)
+OBJS+=device_tree.o
+ifdef BUILD_LIBFDT
+$(QEMU_PROG): $(FDT_LIBS)
+CPPFLAGS += -I$(SRC_PATH)/libfdt
+endif
 
 LIBS+=$(PTHREADLIBS)
 LIBS+=$(CLOCKLIBS)
diff --git a/configure b/configure
index 89e7f53..59ba8ef 100755
--- a/configure
+++ b/configure
@@ -194,7 +194,7 @@ kvm="yes"
 kerneldir=""
 aix="no"
 blobs="yes"
-fdt="yes"
+build_fdt="yes"
 sdl="yes"
 sdl_x11="no"
 xen="yes"
@@ -1218,15 +1218,13 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then
 fi
 
 ##########################################
-# fdt probe
-if test "$fdt" = "yes" ; then
-    fdt=no
-    cat > $TMPC << EOF
+# System libfdt probe
+build_fdt=yes
+cat > $TMPC << EOF
 int main(void) { return 0; }
 EOF
-  if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC -lfdt 2> /dev/null > /dev/null ; then
-    fdt=yes
-  fi
+if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC -lfdt 2> /dev/null > /dev/null ; then
+  build_fdt=no
 fi
 
 #
@@ -1380,7 +1378,7 @@ echo "AIO support       $aio"
 echo "IO thread         $io_thread"
 echo "Install blobs     $blobs"
 echo -e "KVM support       $kvm"
-echo "fdt support       $fdt"
+echo "Build libfdt      $build_fdt"
 echo "preadv support    $preadv"
 
 if test $sdl_too_old = "yes"; then
@@ -1712,8 +1710,10 @@ fi
 if test "$preadv" = "yes" ; then
   echo "#define HAVE_PREADV 1" >> $config_h
 fi
-if test "$fdt" = "yes" ; then
-  echo "#define HAVE_FDT 1" >> $config_h
+if test "$build_fdt" = "yes" ; then
+  echo "BUILD_LIBFDT=libfdt/libfdt.a" >> $config_mak
+  echo "FDT_LIBS=../libfdt/libfdt.a" >> $config_mak
+else
   echo "FDT_LIBS=-lfdt" >> $config_mak
 fi
 
@@ -2138,7 +2138,7 @@ done # for target in $targets
 
 # build tree in object directory if source path is different from current one
 if test "$source_path_used" = "yes" ; then
-    DIRS="tests tests/cris slirp audio block"
+    DIRS="tests tests/cris slirp audio block libfdt"
     FILES="Makefile tests/Makefile"
     FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
     FILES="$FILES tests/test-mmap.c"
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index 9ccd12b..25076b7 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -52,47 +52,27 @@ static int petalogix_load_device_tree(target_phys_addr_t addr,
                                       target_phys_addr_t initrd_size,
                                       const char *kernel_cmdline)
 {
-#ifdef HAVE_FDT
     void *fdt;
     int r;
-#endif
     char *path;
     int fdt_size;
 
-#ifdef HAVE_FDT
-    /* Try the local "mb.dtb" override.  */
-    fdt = load_device_tree("mb.dtb", &fdt_size);
+    path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+    if (path) {
+        fdt = load_device_tree(path, &fdt_size);
+        qemu_free(path);
+    } else {
+        fdt = NULL;
+    }
     if (!fdt) {
-        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
-        if (path) {
-            fdt = load_device_tree(path, &fdt_size);
-            qemu_free(path);
-        }
-        if (!fdt)
-            return 0;
+        return 0;
     }
 
     r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
-    if (r < 0)
+    if (r < 0) {
         fprintf(stderr, "couldn't set /chosen/bootargs\n");
-    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
-#else
-    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
-       to the kernel.  */
-    fdt_size = load_image_targphys("mb.dtb", addr, 0x10000);
-    if (fdt_size < 0) {
-        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
-        if (path) {
-            fdt_size = load_image_targphys(path, addr, 0x10000);
-	    qemu_free(path);
-        }
     }
-
-    if (kernel_cmdline) {
-        fprintf(stderr,
-                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
-    }
-#endif
+    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
     return fdt_size;
 }
 
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 00aa2c7..5796570 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -32,7 +32,6 @@ static void *bamboo_load_device_tree(target_phys_addr_t addr,
                                      const char *kernel_cmdline)
 {
     void *fdt = NULL;
-#ifdef HAVE_FDT
     uint32_t mem_reg_property[] = { 0, 0, ramsize };
     char *filename;
     int fdt_size;
@@ -76,7 +75,6 @@ static void *bamboo_load_device_tree(target_phys_addr_t addr,
     cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
 
 out:
-#endif
 
     return fdt;
 }
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index d9ed36c..b1f1458 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -46,7 +46,6 @@
 #define MPC8544_PCI_IO             0xE1000000
 #define MPC8544_PCI_IOLEN          0x10000
 
-#ifdef HAVE_FDT
 static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop)
 {
     uint32_t cell;
@@ -68,7 +67,6 @@ static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop)
 out:
     return ret;
 }
-#endif
 
 static void *mpc8544_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
@@ -77,7 +75,6 @@ static void *mpc8544_load_device_tree(target_phys_addr_t addr,
                                      const char *kernel_cmdline)
 {
     void *fdt = NULL;
-#ifdef HAVE_FDT
     uint32_t mem_reg_property[] = {0, ramsize};
     char *filename;
     int fdt_size;
@@ -144,7 +141,6 @@ static void *mpc8544_load_device_tree(target_phys_addr_t addr,
     cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
 
 out:
-#endif
 
     return fdt;
 }
diff --git a/libfdt/Makefile.libfdt b/libfdt/Makefile.libfdt
new file mode 100644
index 0000000..82f9c6a
--- /dev/null
+++ b/libfdt/Makefile.libfdt
@@ -0,0 +1,14 @@
+# Makefile.libfdt
+#
+# This is not a complete Makefile of itself.  Instead, it is designed to
+# be easily embeddable into other systems of Makefiles.
+#
+LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
+LIBFDT_INCLUDES = fdt.h libfdt.h
+LIBFDT_EXTRA = libfdt_internal.h
+LIBFDT_LIB = libfdt/libfdt.a
+
+LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
+
+$(LIBFDT_objdir)/$(LIBFDT_LIB): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
+
diff --git a/libfdt/TODO b/libfdt/TODO
new file mode 100644
index 0000000..288437e
--- /dev/null
+++ b/libfdt/TODO
@@ -0,0 +1,3 @@
+- Tree traversal functions
+- Graft function
+- Complete libfdt.h documenting comments
diff --git a/libfdt/fdt.c b/libfdt/fdt.c
new file mode 100644
index 0000000..586a361
--- /dev/null
+++ b/libfdt/fdt.c
@@ -0,0 +1,156 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+	if (fdt_magic(fdt) == FDT_MAGIC) {
+		/* Complete tree */
+		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+	} else if (fdt_magic(fdt) == SW_MAGIC) {
+		/* Unfinished sequential-write blob */
+		if (fdt_size_dt_struct(fdt) == 0)
+			return -FDT_ERR_BADSTATE;
+	} else {
+		return -FDT_ERR_BADMAGIC;
+	}
+
+	return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, int len)
+{
+	const void *p;
+
+	if (fdt_version(fdt) >= 0x11)
+		if (((offset + len) < offset)
+		    || ((offset + len) > fdt_size_dt_struct(fdt)))
+			return NULL;
+
+	p = _fdt_offset_ptr(fdt, offset);
+
+	if (p + len < p)
+		return NULL;
+	return p;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
+{
+	const uint32_t *tagp, *lenp;
+	uint32_t tag;
+	const char *p;
+
+	if (offset % FDT_TAGSIZE)
+		return -1;
+
+	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+	if (! tagp)
+		return FDT_END; /* premature end */
+	tag = fdt32_to_cpu(*tagp);
+	offset += FDT_TAGSIZE;
+
+	switch (tag) {
+	case FDT_BEGIN_NODE:
+		/* skip name */
+		do {
+			p = fdt_offset_ptr(fdt, offset++, 1);
+		} while (p && (*p != '\0'));
+		if (! p)
+			return FDT_END;
+		break;
+	case FDT_PROP:
+		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+		if (! lenp)
+			return FDT_END;
+		/* skip name offset, length and value */
+		offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
+		break;
+	}
+
+	if (nextoffset)
+		*nextoffset = ALIGN(offset, FDT_TAGSIZE);
+
+	return tag;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+	int len = strlen(s) + 1;
+	const char *last = strtab + tabsize - len;
+	const char *p;
+
+	for (p = strtab; p <= last; p++)
+		if (memeq(p, s, len))
+			return p;
+	return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+	int err = fdt_check_header(fdt);
+
+	if (err)
+		return err;
+
+	if (fdt_totalsize(fdt) > bufsize)
+		return -FDT_ERR_NOSPACE;
+
+	memmove(buf, fdt, fdt_totalsize(fdt));
+	return 0;
+}
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
new file mode 100644
index 0000000..48ccfd9
--- /dev/null
+++ b/libfdt/fdt.h
@@ -0,0 +1,60 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+	uint32_t magic;			 /* magic word FDT_MAGIC */
+	uint32_t totalsize;		 /* total size of DT block */
+	uint32_t off_dt_struct;		 /* offset to structure */
+	uint32_t off_dt_strings;	 /* offset to strings */
+	uint32_t off_mem_rsvmap;	 /* offset to memory reserve map */
+	uint32_t version;		 /* format version */
+	uint32_t last_comp_version;	 /* last compatible version */
+
+	/* version 2 fields below */
+	uint32_t boot_cpuid_phys;	 /* Which physical CPU id we're
+					    booting on */
+	/* version 3 fields below */
+	uint32_t size_dt_strings;	 /* size of the strings block */
+
+	/* version 17 fields below */
+	uint32_t size_dt_struct;	 /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+	uint64_t address;
+	uint64_t size;
+};
+
+struct fdt_node_header {
+	uint32_t tag;
+	char name[0];
+};
+
+struct fdt_property {
+	uint32_t tag;
+	uint32_t len;
+	uint32_t nameoff;
+	char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
+#define FDT_TAGSIZE	sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE	0x1		/* Start node: full name */
+#define FDT_END_NODE	0x2		/* End node */
+#define FDT_PROP	0x3		/* Property: name off,
+					   size, content */
+#define FDT_NOP		0x4		/* nop */
+#define FDT_END		0x9
+
+#define FDT_V1_SIZE	(7*sizeof(uint32_t))
+#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE	FDT_V3_SIZE
+#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */
diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
new file mode 100644
index 0000000..afb00a2
--- /dev/null
+++ b/libfdt/fdt_ro.c
@@ -0,0 +1,583 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+#define CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = fdt_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+static int nodename_eq(const void *fdt, int offset,
+		       const char *s, int len)
+{
+	const char *p = fdt_offset_ptr(fdt, offset, len+1);
+
+	if (! p)
+		/* short match */
+		return 0;
+
+	if (memcmp(p, s, len) != 0)
+		return 0;
+
+	if (p[len] == '\0')
+		return 1;
+	else if (!memchr(s, '@', len) && (p[len] == '@'))
+		return 1;
+	else
+		return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+	return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+	CHECK_HEADER(fdt);
+	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+	return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+	int i = 0;
+
+	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+		i++;
+	return i;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+			       const char *name, int namelen)
+{
+	int level = 0;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	CHECK_HEADER(fdt);
+
+	tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		return -FDT_ERR_BADOFFSET;
+
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_END:
+			return -FDT_ERR_TRUNCATED;
+
+		case FDT_BEGIN_NODE:
+			level++;
+			if (level != 1)
+				continue;
+			if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen))
+				/* Found it! */
+				return offset;
+			break;
+
+		case FDT_END_NODE:
+			level--;
+			break;
+
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (level >= 0);
+
+	return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+		       const char *name)
+{
+	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+	const char *end = path + strlen(path);
+	const char *p = path;
+	int offset = 0;
+
+	CHECK_HEADER(fdt);
+
+	if (*path != '/')
+		return -FDT_ERR_BADPATH;
+
+	while (*p) {
+		const char *q;
+
+		while (*p == '/')
+			p++;
+		if (! *p)
+			return offset;
+		q = strchr(p, '/');
+		if (! q)
+			q = end;
+
+		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+		if (offset < 0)
+			return offset;
+
+		p = q;
+	}
+
+	return offset;
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+	const struct fdt_node_header *nh;
+	int err;
+
+	if ((err = fdt_check_header(fdt)) != 0)
+		goto fail;
+
+	err = -FDT_ERR_BADOFFSET;
+	nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
+	if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
+		goto fail;
+
+	if (len)
+		*len = strlen(nh->name);
+
+	return nh->name;
+
+ fail:
+	if (len)
+		*len = err;
+	return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+					    int nodeoffset,
+					    const char *name, int *lenp)
+{
+	uint32_t tag;
+	const struct fdt_property *prop;
+	int namestroff;
+	int offset, nextoffset;
+	int err;
+
+	if ((err = fdt_check_header(fdt)) != 0)
+		goto fail;
+
+	err = -FDT_ERR_BADOFFSET;
+	if (nodeoffset % FDT_TAGSIZE)
+		goto fail;
+
+	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		goto fail;
+
+	do {
+		offset = nextoffset;
+
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		switch (tag) {
+		case FDT_END:
+			err = -FDT_ERR_TRUNCATED;
+			goto fail;
+
+		case FDT_BEGIN_NODE:
+		case FDT_END_NODE:
+		case FDT_NOP:
+			break;
+
+		case FDT_PROP:
+			err = -FDT_ERR_BADSTRUCTURE;
+			prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
+			if (! prop)
+				goto fail;
+			namestroff = fdt32_to_cpu(prop->nameoff);
+			if (streq(fdt_string(fdt, namestroff), name)) {
+				/* Found it! */
+				int len = fdt32_to_cpu(prop->len);
+				prop = fdt_offset_ptr(fdt, offset,
+						      sizeof(*prop)+len);
+				if (! prop)
+					goto fail;
+
+				if (lenp)
+					*lenp = len;
+
+				return prop;
+			}
+			break;
+
+		default:
+			err = -FDT_ERR_BADSTRUCTURE;
+			goto fail;
+		}
+	} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
+
+	err = -FDT_ERR_NOTFOUND;
+ fail:
+	if (lenp)
+		*lenp = err;
+	return NULL;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+		  const char *name, int *lenp)
+{
+	const struct fdt_property *prop;
+
+	prop = fdt_get_property(fdt, nodeoffset, name, lenp);
+	if (! prop)
+		return NULL;
+
+	return prop->data;
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+	const uint32_t *php;
+	int len;
+
+	php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+	if (!php || (len != sizeof(*php)))
+		return 0;
+
+	return fdt32_to_cpu(*php);
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+	uint32_t tag;
+	int p = 0, overflow = 0;
+	int offset, nextoffset, namelen;
+	const char *name;
+
+	CHECK_HEADER(fdt);
+
+	tag = fdt_next_tag(fdt, 0, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	if (buflen < 2)
+		return -FDT_ERR_NOSPACE;
+	buf[0] = '/';
+	p = 1;
+
+	while (nextoffset <= nodeoffset) {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		switch (tag) {
+		case FDT_END:
+			return -FDT_ERR_BADOFFSET;
+
+		case FDT_BEGIN_NODE:
+			name = fdt_get_name(fdt, offset, &namelen);
+			if (!name)
+				return namelen;
+			if (overflow || ((p + namelen + 1) > buflen)) {
+				overflow++;
+				break;
+			}
+			memcpy(buf + p, name, namelen);
+			p += namelen;
+			buf[p++] = '/';
+			break;
+
+		case FDT_END_NODE:
+			if (overflow) {
+				overflow--;
+				break;
+			}
+			do {
+				p--;
+			} while  (buf[p-1] != '/');
+			break;
+
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	}
+
+	if (overflow)
+		return -FDT_ERR_NOSPACE;
+
+	if (p > 1) /* special case so that root path is "/", not "" */
+		p--;
+	buf[p] = '\0';
+	return p;
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth)
+{
+	int level = -1;
+	uint32_t tag;
+	int offset, nextoffset = 0;
+	int supernodeoffset = -FDT_ERR_INTERNAL;
+
+	CHECK_HEADER(fdt);
+
+	if (supernodedepth < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		switch (tag) {
+		case FDT_END:
+			return -FDT_ERR_BADOFFSET;
+
+		case FDT_BEGIN_NODE:
+			level++;
+			if (level == supernodedepth)
+				supernodeoffset = offset;
+			break;
+
+		case FDT_END_NODE:
+			level--;
+			break;
+
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (offset < nodeoffset);
+
+	if (nodedepth)
+		*nodedepth = level;
+
+	if (supernodedepth > level)
+		return -FDT_ERR_NOTFOUND;
+	return supernodeoffset;
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+	int nodedepth;
+	int err;
+
+	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+	if (err)
+		return (err < 0) ? err : -FDT_ERR_INTERNAL;
+	return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+	int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+	if (nodedepth < 0)
+		return nodedepth;
+	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+					    nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen)
+{
+	uint32_t tag;
+	int offset, nextoffset;
+	const void *val;
+	int len;
+
+	CHECK_HEADER(fdt);
+
+	if (startoffset >= 0) {
+		tag = fdt_next_tag(fdt, startoffset, &nextoffset);
+		if (tag != FDT_BEGIN_NODE)
+			return -FDT_ERR_BADOFFSET;
+	} else {
+		nextoffset = 0;
+	}
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_getprop(), then if that didn't
+	 * find what we want, we scan over them again making our way
+	 * to the next node.  Still it's the easiest to implement
+	 * approach; performance can come later. */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_BEGIN_NODE:
+			val = fdt_getprop(fdt, offset, propname, &len);
+			if (val
+			    && (len == proplen)
+			    && (memcmp(val, propval, len) == 0))
+				return offset;
+			break;
+
+		case FDT_PROP:
+		case FDT_END:
+		case FDT_END_NODE:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (tag != FDT_END);
+
+	return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+	if ((phandle == 0) || (phandle == -1))
+		return -FDT_ERR_BADPHANDLE;
+	phandle = cpu_to_fdt32(phandle);
+	return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
+					     &phandle, sizeof(phandle));
+}
+
+static int _stringlist_contains(const void *strlist, int listlen, const char *str)
+{
+	int len = strlen(str);
+	const void *p;
+
+	while (listlen >= len) {
+		if (memcmp(str, strlist, len+1) == 0)
+			return 1;
+		p = memchr(strlist, '\0', listlen);
+		if (!p)
+			return 0; /* malformed strlist.. */
+		listlen -= (p-strlist) + 1;
+		strlist = p + 1;
+	}
+	return 0;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible)
+{
+	const void *prop;
+	int len;
+
+	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+	if (!prop)
+		return len;
+	if (_stringlist_contains(prop, len, compatible))
+		return 0;
+	else
+		return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible)
+{
+	uint32_t tag;
+	int offset, nextoffset;
+	int err;
+
+	CHECK_HEADER(fdt);
+
+	if (startoffset >= 0) {
+		tag = fdt_next_tag(fdt, startoffset, &nextoffset);
+		if (tag != FDT_BEGIN_NODE)
+			return -FDT_ERR_BADOFFSET;
+	} else {
+		nextoffset = 0;
+	}
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_node_check_compatible(), then if
+	 * that didn't find what we want, we scan over them again
+	 * making our way to the next node.  Still it's the easiest to
+	 * implement approach; performance can come later. */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_BEGIN_NODE:
+			err = fdt_node_check_compatible(fdt, offset,
+							compatible);
+			if ((err < 0)
+			    && (err != -FDT_ERR_NOTFOUND))
+				return err;
+			else if (err == 0)
+				return offset;
+			break;
+
+		case FDT_PROP:
+		case FDT_END:
+		case FDT_END_NODE:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (tag != FDT_END);
+
+	return -FDT_ERR_NOTFOUND;
+}
diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
new file mode 100644
index 0000000..a1c70ff
--- /dev/null
+++ b/libfdt/fdt_rw.c
@@ -0,0 +1,471 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _blocks_misordered(const void *fdt,
+			      int mem_rsv_size, int struct_size)
+{
+	return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8))
+		|| (fdt_off_dt_struct(fdt) <
+		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+		|| (fdt_off_dt_strings(fdt) <
+		    (fdt_off_dt_struct(fdt) + struct_size))
+		|| (fdt_totalsize(fdt) <
+		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int rw_check_header(void *fdt)
+{
+	int err;
+
+	if ((err = fdt_check_header(fdt)))
+		return err;
+	if (fdt_version(fdt) < 17)
+		return -FDT_ERR_BADVERSION;
+	if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+			       fdt_size_dt_struct(fdt)))
+		return -FDT_ERR_BADLAYOUT;
+	if (fdt_version(fdt) > 17)
+		fdt_set_version(fdt, 17);
+
+	return 0;
+}
+
+#define RW_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = rw_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+static inline int _blob_data_size(void *fdt)
+{
+	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _blob_splice(void *fdt, void *p, int oldlen, int newlen)
+{
+	void *end = fdt + _blob_data_size(fdt);
+
+	if (((p + oldlen) < p) || ((p + oldlen) > end))
+		return -FDT_ERR_BADOFFSET;
+	if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt)))
+		return -FDT_ERR_NOSPACE;
+	memmove(p + newlen, p + oldlen, end - p - oldlen);
+	return 0;
+}
+
+static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+				int oldn, int newn)
+{
+	int delta = (newn - oldn) * sizeof(*p);
+	int err;
+	err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+	if (err)
+		return err;
+	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _blob_splice_struct(void *fdt, void *p,
+			       int oldlen, int newlen)
+{
+	int delta = newlen - oldlen;
+	int err;
+
+	if ((err = _blob_splice(fdt, p, oldlen, newlen)))
+		return err;
+
+	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _blob_splice_string(void *fdt, int newlen)
+{
+	void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+	int err;
+
+	if ((err = _blob_splice(fdt, p, 0, newlen)))
+		return err;
+
+	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+	return 0;
+}
+
+static int _find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+	const char *p;
+	char *new;
+	int len = strlen(s) + 1;
+	int err;
+
+	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+	if (p)
+		/* found it */
+		return (p - strtab);
+
+	new = strtab + fdt_size_dt_strings(fdt);
+	err = _blob_splice_string(fdt, len);
+	if (err)
+		return err;
+
+	memcpy(new, s, len);
+	return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+
+	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+	err = _blob_splice_mem_rsv(fdt, re, 0, 1);
+	if (err)
+		return err;
+
+	re->address = cpu_to_fdt64(address);
+	re->size = cpu_to_fdt64(size);
+	return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+	if (n >= fdt_num_mem_rsv(fdt))
+		return -FDT_ERR_NOTFOUND;
+
+	err = _blob_splice_mem_rsv(fdt, re, 1, 0);
+	if (err)
+		return err;
+	return 0;
+}
+
+static int _resize_property(void *fdt, int nodeoffset, const char *name, int len,
+			    struct fdt_property **prop)
+{
+	int oldlen;
+	int err;
+
+	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+	if (! (*prop))
+		return oldlen;
+
+	if ((err = _blob_splice_struct(fdt, (*prop)->data,
+				       ALIGN(oldlen, FDT_TAGSIZE),
+				       ALIGN(len, FDT_TAGSIZE))))
+		return err;
+
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
+			 struct fdt_property **prop)
+{
+	uint32_t tag;
+	int proplen;
+	int nextoffset;
+	int namestroff;
+	int err;
+
+	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		return -FDT_ERR_BADOFFSET;
+
+	namestroff = _find_add_string(fdt, name);
+	if (namestroff < 0)
+		return namestroff;
+
+	*prop = _fdt_offset_ptr_w(fdt, nextoffset);
+	proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE);
+
+	err = _blob_splice_struct(fdt, *prop, 0, proplen);
+	if (err)
+		return err;
+
+	(*prop)->tag = cpu_to_fdt32(FDT_PROP);
+	(*prop)->nameoff = cpu_to_fdt32(namestroff);
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+	char *namep;
+	int oldlen, newlen;
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+
+	namep = (char *)fdt_get_name(fdt, nodeoffset, &oldlen);
+	if (!namep)
+		return oldlen;
+
+	newlen = strlen(name);
+
+	err = _blob_splice_struct(fdt, namep, ALIGN(oldlen+1, FDT_TAGSIZE),
+				  ALIGN(newlen+1, FDT_TAGSIZE));
+	if (err)
+		return err;
+
+	memcpy(namep, name, newlen+1);
+	return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+
+	err = _resize_property(fdt, nodeoffset, name, len, &prop);
+	if (err == -FDT_ERR_NOTFOUND)
+		err = _add_property(fdt, nodeoffset, name, len, &prop);
+	if (err)
+		return err;
+
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len, proplen;
+
+	RW_CHECK_HEADER(fdt);
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE);
+	return _blob_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen)
+{
+	struct fdt_node_header *nh;
+	int offset, nextoffset;
+	int nodelen;
+	int err;
+	uint32_t tag;
+	uint32_t *endtag;
+
+	RW_CHECK_HEADER(fdt);
+
+	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+	if (offset >= 0)
+		return -FDT_ERR_EXISTS;
+	else if (offset != -FDT_ERR_NOTFOUND)
+		return offset;
+
+	/* Try to place the new node after the parent's properties */
+	fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+	} while (tag == FDT_PROP);
+
+	nh = _fdt_offset_ptr_w(fdt, offset);
+	nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;
+
+	err = _blob_splice_struct(fdt, nh, 0, nodelen);
+	if (err)
+		return err;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE));
+	memcpy(nh->name, name, namelen);
+	endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE);
+	*endtag = cpu_to_fdt32(FDT_END_NODE);
+
+	return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	RW_CHECK_HEADER(fdt);
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+				   endoffset - nodeoffset, 0);
+}
+
+static void _packblocks(const void *fdt, void *buf,
+		       int mem_rsv_size, int struct_size)
+{
+	int mem_rsv_off, struct_off, strings_off;
+
+	mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8);
+	struct_off = mem_rsv_off + mem_rsv_size;
+	strings_off = struct_off + struct_size;
+
+	memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size);
+	fdt_set_off_mem_rsvmap(buf, mem_rsv_off);
+
+	memmove(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size);
+	fdt_set_off_dt_struct(buf, struct_off);
+	fdt_set_size_dt_struct(buf, struct_size);
+
+	memmove(buf + strings_off, fdt + fdt_off_dt_strings(fdt),
+		fdt_size_dt_strings(fdt));
+	fdt_set_off_dt_strings(buf, strings_off);
+	fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+	int err;
+	int mem_rsv_size, struct_size;
+	int newsize;
+	void *tmp;
+
+	err = fdt_check_header(fdt);
+	if (err)
+		return err;
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+
+	if (fdt_version(fdt) >= 17) {
+		struct_size = fdt_size_dt_struct(fdt);
+	} else {
+		struct_size = 0;
+		while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+			;
+	}
+
+	if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+		/* no further work necessary */
+		err = fdt_move(fdt, buf, bufsize);
+		if (err)
+			return err;
+		fdt_set_version(buf, 17);
+		fdt_set_size_dt_struct(buf, struct_size);
+		fdt_set_totalsize(buf, bufsize);
+		return 0;
+	}
+
+	/* Need to reorder */
+	newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+		+ struct_size + fdt_size_dt_strings(fdt);
+
+	if (bufsize < newsize)
+		return -FDT_ERR_NOSPACE;
+
+	if (((buf + newsize) <= fdt)
+	    || (buf >= (fdt + fdt_totalsize(fdt)))) {
+		tmp = buf;
+	} else {
+		tmp = (void *)fdt + fdt_totalsize(fdt);
+		if ((tmp + newsize) > (buf + bufsize))
+			return -FDT_ERR_NOSPACE;
+	}
+
+	_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+	memmove(buf, tmp, newsize);
+
+	fdt_set_magic(buf, FDT_MAGIC);
+	fdt_set_totalsize(buf, bufsize);
+	fdt_set_version(buf, 17);
+	fdt_set_last_comp_version(buf, 16);
+	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+	return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+	int mem_rsv_size;
+	int err;
+
+	err = rw_check_header(fdt);
+	if (err)
+		return err;
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+	_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+	fdt_set_totalsize(fdt, _blob_data_size(fdt));
+
+	return 0;
+}
diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c
new file mode 100644
index 0000000..f9d32ef
--- /dev/null
+++ b/libfdt/fdt_strerror.c
@@ -0,0 +1,96 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct errtabent {
+	const char *str;
+};
+
+#define ERRTABENT(val) \
+	[(val)] = { .str = #val, }
+
+static struct errtabent errtable[] = {
+	ERRTABENT(FDT_ERR_NOTFOUND),
+	ERRTABENT(FDT_ERR_EXISTS),
+	ERRTABENT(FDT_ERR_NOSPACE),
+
+	ERRTABENT(FDT_ERR_BADOFFSET),
+	ERRTABENT(FDT_ERR_BADPATH),
+	ERRTABENT(FDT_ERR_BADSTATE),
+
+	ERRTABENT(FDT_ERR_TRUNCATED),
+	ERRTABENT(FDT_ERR_BADMAGIC),
+	ERRTABENT(FDT_ERR_BADVERSION),
+	ERRTABENT(FDT_ERR_BADSTRUCTURE),
+	ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define ERRTABSIZE	(sizeof(errtable) / sizeof(errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+	if (errval > 0)
+		return "<valid offset/length>";
+	else if (errval == 0)
+		return "<no error>";
+	else if (errval > -ERRTABSIZE) {
+		const char *s = errtable[-errval].str;
+
+		if (s)
+			return s;
+	}
+
+	return "<unknown error>";
+}
diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c
new file mode 100644
index 0000000..dda2de3
--- /dev/null
+++ b/libfdt/fdt_sw.c
@@ -0,0 +1,258 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int check_header_sw(void *fdt)
+{
+	if (fdt_magic(fdt) != SW_MAGIC)
+		return -FDT_ERR_BADMAGIC;
+	return 0;
+}
+
+static void *grab_space(void *fdt, int len)
+{
+	int offset = fdt_size_dt_struct(fdt);
+	int spaceleft;
+
+	spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+		- fdt_size_dt_strings(fdt);
+
+	if ((offset + len < offset) || (offset + len > spaceleft))
+		return NULL;
+
+	fdt_set_size_dt_struct(fdt, offset + len);
+	return fdt_offset_ptr_w(fdt, offset, len);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+	void *fdt = buf;
+
+	if (bufsize < sizeof(struct fdt_header))
+		return -FDT_ERR_NOSPACE;
+
+	memset(buf, 0, bufsize);
+
+	fdt_set_magic(fdt, SW_MAGIC);
+	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+	fdt_set_totalsize(fdt,  bufsize);
+
+	fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header),
+					  sizeof(struct fdt_reserve_entry)));
+	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+	fdt_set_off_dt_strings(fdt, bufsize);
+
+	return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int err = check_header_sw(fdt);
+	int offset;
+
+	if (err)
+		return err;
+	if (fdt_size_dt_struct(fdt))
+		return -FDT_ERR_BADSTATE;
+
+	offset = fdt_off_dt_struct(fdt);
+	if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+		return -FDT_ERR_NOSPACE;
+
+	re = (struct fdt_reserve_entry *)(fdt + offset);
+	re->address = cpu_to_fdt64(addr);
+	re->size = cpu_to_fdt64(size);
+
+	fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+	return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+	return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+	struct fdt_node_header *nh;
+	int err = check_header_sw(fdt);
+	int namelen = strlen(name) + 1;
+
+	if (err)
+		return err;
+
+	nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE));
+	if (! nh)
+		return -FDT_ERR_NOSPACE;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memcpy(nh->name, name, namelen);
+	return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+	uint32_t *en;
+	int err = check_header_sw(fdt);
+
+	if (err)
+		return err;
+
+	en = grab_space(fdt, FDT_TAGSIZE);
+	if (! en)
+		return -FDT_ERR_NOSPACE;
+
+	*en = cpu_to_fdt32(FDT_END_NODE);
+	return 0;
+}
+
+static int find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_totalsize(fdt);
+	const char *p;
+	int strtabsize = fdt_size_dt_strings(fdt);
+	int len = strlen(s) + 1;
+	int struct_top, offset;
+
+	p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+	if (p)
+		return p - strtab;
+
+	/* Add it */
+	offset = -strtabsize - len;
+	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	if (fdt_totalsize(fdt) + offset < struct_top)
+		return 0; /* no more room :( */
+
+	memcpy(strtab + offset, s, len);
+	fdt_set_size_dt_strings(fdt, strtabsize + len);
+	return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err = check_header_sw(fdt);
+	int nameoff;
+
+	if (err)
+		return err;
+
+	nameoff = find_add_string(fdt, name);
+	if (nameoff == 0)
+		return -FDT_ERR_NOSPACE;
+
+	prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE));
+	if (! prop)
+		return -FDT_ERR_NOSPACE;
+
+	prop->tag = cpu_to_fdt32(FDT_PROP);
+	prop->nameoff = cpu_to_fdt32(nameoff);
+	prop->len = cpu_to_fdt32(len);
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+	int err = check_header_sw(fdt);
+	char *p = (char *)fdt;
+	uint32_t *end;
+	int oldstroffset, newstroffset;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	if (err)
+		return err;
+
+	/* Add terminator */
+	end = grab_space(fdt, sizeof(*end));
+	if (! end)
+		return -FDT_ERR_NOSPACE;
+	*end = cpu_to_fdt32(FDT_END);
+
+	/* Relocate the string table */
+	oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+	newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+	fdt_set_off_dt_strings(fdt, newstroffset);
+
+	/* Walk the structure, correcting string offsets */
+	offset = 0;
+	while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+		if (tag == FDT_PROP) {
+			struct fdt_property *prop =
+				fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
+			int nameoff;
+
+			if (! prop)
+				return -FDT_ERR_BADSTRUCTURE;
+
+			nameoff = fdt32_to_cpu(prop->nameoff);
+			nameoff += fdt_size_dt_strings(fdt);
+			prop->nameoff = cpu_to_fdt32(nameoff);
+		}
+		offset = nextoffset;
+	}
+
+	/* Finally, adjust the header */
+	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+	fdt_set_magic(fdt, FDT_MAGIC);
+	return 0;
+}
diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c
new file mode 100644
index 0000000..88e24b8
--- /dev/null
+++ b/libfdt/fdt_wip.c
@@ -0,0 +1,144 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len)
+{
+	void *propval;
+	int proplen;
+
+	propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+	if (! propval)
+		return proplen;
+
+	if (proplen != len)
+		return -FDT_ERR_NOSPACE;
+
+	memcpy(propval, val, len);
+	return 0;
+}
+
+static void nop_region(void *start, int len)
+{
+	uint32_t *p;
+
+	for (p = start; (void *)p < (start + len); p++)
+		*p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len;
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	nop_region(prop, len + sizeof(*prop));
+
+	return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int nodeoffset)
+{
+	int level = 0;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		return -FDT_ERR_BADOFFSET;
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_END:
+			return offset;
+
+		case FDT_BEGIN_NODE:
+			level++;
+			break;
+
+		case FDT_END_NODE:
+			level--;
+			break;
+
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (level >= 0);
+
+	return nextoffset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset);
+	return 0;
+}
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
new file mode 100644
index 0000000..4b98d40
--- /dev/null
+++ b/libfdt/libfdt.h
@@ -0,0 +1,1070 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "libfdt_env.h"
+#include "fdt.h"
+
+#define FDT_FIRST_SUPPORTED_VERSION	0x10
+#define FDT_LAST_SUPPORTED_VERSION	0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND	1
+	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS		2
+	/* FDT_ERR_EXISTS: Attemped to create a node or property which
+	 * already exists */
+#define FDT_ERR_NOSPACE		3
+	/* FDT_ERR_NOSPACE: Operation needed to expand the device
+	 * tree, but its buffer did not have sufficient space to
+	 * contain the expanded tree. Use fdt_open_into() to move the
+	 * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET	4
+	/* FDT_ERR_BADOFFSET: Function was passed a structure block
+	 * offset which is out-of-bounds, or which points to an
+	 * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH		5
+	/* FDT_ERR_BADPATH: Function was passed a badly formatted path
+	 * (e.g. missing a leading / for a function which requires an
+	 * absolute path) */
+#define FDT_ERR_BADPHANDLE	6
+	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+	 * value.  phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE	7
+	/* FDT_ERR_BADSTATE: Function was passed an incomplete device
+	 * tree created by the sequential-write functions, which is
+	 * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED	8
+	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
+	 * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC	9
+	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+	 * device tree at all - it is missing the flattened device
+	 * tree magic number. */
+#define FDT_ERR_BADVERSION	10
+	/* FDT_ERR_BADVERSION: Given device tree has a version which
+	 * can't be handled by the requested operation.  For
+	 * read-write functions, this may mean that fdt_open_into() is
+	 * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE	11
+	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+	 * structure block or other serious error (e.g. misnested
+	 * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT	12
+	/* FDT_ERR_BADLAYOUT: For read-write functions, the given
+	 * device tree has it's sub-blocks in an order that the
+	 * function can't handle (memory reserve map, then structure,
+	 * then strings).  Use fdt_open_into() to reorganize the tree
+	 * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL	13
+	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+	 * Should never be returned, if it is, it indicates a bug in
+	 * libfdt itself. */
+
+#define FDT_ERR_MAX		13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these)                */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+	return (void *)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* General functions                                                  */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt)		(fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+	static inline void fdt_set_##name(void *fdt, uint32_t val) \
+	{ \
+		struct fdt_header *fdth = fdt; \
+		fdth->name = cpu_to_fdt32(val); \
+	}
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ *     0, if the buffer appears to contain a valid device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize.  The buffer may overlap
+ * with the existing device tree blob at fdt.  Therefore,
+ *     fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions                                                */
+/**********************************************************************/
+
+/**
+ * fdt_string - retreive a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retreive the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ *     the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retreive one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name.  This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+			       const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name.  name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ *	structure block offset of the requested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ *	structure block offset of the node with the requested path (>=0), on success
+ *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ *	-FDT_ERR_NOTFOUND, if the requested node does not exist
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retreive the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset.  If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the node's name, on success
+ *		If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset.  If lenp is
+ * non-NULL, the length of the property value also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+					    const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+						      const char *name,
+						      int *lenp)
+{
+	return (struct fdt_property *)fdt_get_property(fdt, nodeoffset,
+						       name, lenp);
+}
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+			const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+				  const char *name, int *lenp)
+{
+	return (void *)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retreive the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ *	the phandle of the node at nodeoffset, on succes (!= 0, != -1)
+ *	0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	0, on success
+ *		buf contains the absolute path of the node at
+ *		nodeoffset, as a NUL-terminated string.
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ *		characters and will not fit in the given buffer.
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth).  So
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node.  If the node at
+ * nodeoffset has depth D, then:
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ *	structure block offset of the node at node offset's ancestor
+ *		of depth supernodedepth (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+*	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node.  The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	depth of the node at nodeoffset (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ *	stucture block offset of the parent of the node at nodeoffset
+ *		(>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ *					       propval, proplen);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *						       propval, proplen);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the node
+ * which has the given phandle value.  If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0), on success
+ *	-FDT_ERR_NOTFOUND, no node with that phandle exists
+ *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ *	0, if the node has a 'compatible' property listing the given string
+ *	1, if the node has a 'compatible' property, but it does not list
+ *		the given string
+ *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * 	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible);
+
+/**********************************************************************/
+/* Write-in-place functions                                           */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: cell (32-bit integer) value to replace the property with
+ *
+ * fdt_setprop_inplace_cell() replaces the value of a given property
+ * with the 32-bit integer cell value in val, converting val to
+ * big-endian if necessary.  This function cannot change the size of a
+ * property, and so will only work if the property already exists and
+ * has length 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 4
+  *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+					   const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions                                         */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_property(fdt, name, &val, sizeof(val));
+}
+#define fdt_property_string(fdt, name, str) \
+	fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions                                               */
+/**********************************************************************/
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @addres, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therfore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new reservation entry
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therfore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *		are less than n+1 reserve map entries)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creeating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len);
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_cell() sets the value of the named property in the
+ * given node to the given cell value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+				   uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *	structure block offset of the created nodeequested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *		the given name
+ *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *		blob to contain the new node
+ *	-FDT_ERR_NOSPACE
+ *	-FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions                                */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/libfdt/libfdt_env.h b/libfdt/libfdt_env.h
new file mode 100644
index 0000000..81bcd7a
--- /dev/null
+++ b/libfdt/libfdt_env.h
@@ -0,0 +1,21 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include "bswap.h"
+
+#ifdef WORDS_BIGENDIAN
+#define fdt32_to_cpu(x)		(x)
+#define cpu_to_fdt32(x)		(x)
+#define fdt64_to_cpu(x)		(x)
+#define cpu_to_fdt64(x)		(x)
+#else
+#define fdt32_to_cpu(x)		(bswap_32((x)))
+#define cpu_to_fdt32(x)		(bswap_32((x)))
+#define fdt64_to_cpu(x)		(bswap_64((x)))
+#define cpu_to_fdt64(x)		(bswap_64((x)))
+#endif
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
new file mode 100644
index 0000000..1e60936
--- /dev/null
+++ b/libfdt/libfdt_internal.h
@@ -0,0 +1,89 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library 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 library 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 library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <fdt.h>
+
+#define ALIGN(x, a)	(((x) + (a) - 1) & ~((a) - 1))
+#define PALIGN(p, a)	((void *)ALIGN((unsigned long)(p), (a)))
+
+#define memeq(p, q, n)	(memcmp((p), (q), (n)) == 0)
+#define streq(p, q)	(strcmp((p), (q)) == 0)
+
+uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+	return fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+	return (void *)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+	const struct fdt_reserve_entry *rsv_table =
+		fdt + fdt_off_mem_rsvmap(fdt);
+
+	return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+	return (void *)_fdt_mem_rsv(fdt, n);
+}
+
+#define SW_MAGIC		(~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/libfdt/patch.libfdt b/libfdt/patch.libfdt
new file mode 100644
index 0000000..c911d10
--- /dev/null
+++ b/libfdt/patch.libfdt
@@ -0,0 +1,20 @@
+Minor changes are required to get libfdt to build as part of qemu.
+The patch below records modifications relative to upstream dtc-v1.2.0.
+
+Index: libfdt_env.h
+===================================================================
+--- libfdt_env.h	(revision 230023)
++++ libfdt_env.h	(working copy)
+@@ -4,10 +4,9 @@
+ #include <stddef.h>
+ #include <stdint.h>
+ #include <string.h>
+-#include <endian.h>
+-#include <byteswap.h>
++#include "bswap.h"
+ 
+-#if __BYTE_ORDER == __BIG_ENDIAN
++#ifdef WORDS_BIGENDIAN
+ #define fdt32_to_cpu(x)		(x)
+ #define cpu_to_fdt32(x)		(x)
+ #define fdt64_to_cpu(x)		(x)
diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
index 10cfdb3..cc639c6 100644
--- a/target-ppc/kvm_ppc.c
+++ b/target-ppc/kvm_ppc.c
@@ -21,7 +21,6 @@
 static QEMUTimer *kvmppc_timer;
 static unsigned int kvmppc_timer_rate;
 
-#ifdef HAVE_FDT
 int kvmppc_read_host_property(const char *node_path, const char *prop,
                                      void *val, size_t len)
 {
@@ -85,7 +84,6 @@ void kvmppc_fdt_update(void *fdt)
     kvmppc_copy_host_cell(fdt, "/cpus/cpu@0", "clock-frequency");
     kvmppc_copy_host_cell(fdt, "/cpus/cpu@0", "timebase-frequency");
 }
-#endif
 
 static void kvmppc_timer_hack(void *opaque)
 {

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

* [Qemu-devel] [PATCH 2/4] Add device tree machine
  2009-06-10 17:38 [Qemu-devel] [PATCH 0/4] Machine config files Paul Brook
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 1/4] Include and build libfdt Paul Brook
@ 2009-06-10 17:38 ` Paul Brook
  2009-06-10 18:30   ` Blue Swirl
                     ` (3 more replies)
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 3/4] Stellaris machine config Paul Brook
                   ` (4 subsequent siblings)
  6 siblings, 4 replies; 61+ messages in thread
From: Paul Brook @ 2009-06-10 17:38 UTC (permalink / raw)
  To: qemu-devel

FDT based machine creation.
When -M foo is specified look for and use foo.fdb.
Build and ship board configs.

Signed-off-by: Paul Brook <paul@codesourcery.com>
---

 .gitignore                |    1 
 Makefile                  |   20 +-
 Makefile.target           |    5 
 configure                 |   17 +
 hw/arm-cpu.c              |   78 ++++++
 hw/arm_boot.c             |   22 ++
 hw/boards.h               |    9 +
 hw/dt-machine.c           |  582 +++++++++++++++++++++++++++++++++++++++++++++
 hw/i2c.c                  |    8 +
 hw/pci.c                  |    1 
 hw/qdev.c                 |  225 +++++++++++++++++
 hw/qdev.h                 |   50 +++-
 hw/ssi.c                  |    7 -
 hw/syborg.c               |  112 ---------
 hw/sysbus.c               |    5 
 hw/sysbus.h               |   15 +
 pc-bios/boards/syborg.dts |  134 ++++++++++
 rules.mak                 |    3 
 sysemu.h                  |    3 
 vl.c                      |   45 +++
 20 files changed, 1179 insertions(+), 163 deletions(-)
 create mode 100644 hw/arm-cpu.c
 create mode 100644 hw/dt-machine.c
 delete mode 100644 hw/syborg.c
 create mode 100644 pc-bios/boards/syborg.dts

diff --git a/.gitignore b/.gitignore
index a8da10e..225f705 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@ qemu-io
 *.vr
 *.d
 *.o
+pc-bios/boards/*.dtb
 .pc
 patches
 pc-bios/bios-pq/status
diff --git a/Makefile b/Makefile
index 6fc234c..6d15c44 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ endif
 .PHONY: all clean cscope distclean dvi html info install install-doc \
 	recurse-all speed tar tarbin test
 
-VPATH=$(SRC_PATH):$(SRC_PATH)/hw
+VPATH=$(SRC_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/pc-bios/boards
 
 
 CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS)
@@ -43,7 +43,16 @@ ifdef CONFIG_WIN32
 LIBS+=-lwinmm -lws2_32 -liphlpapi
 endif
 
-build-all: $(TOOLS) $(DOCS) recurse-all
+#######################################################################
+# Board descriptions
+
+BOARDS = syborg
+
+ifdef DTC
+BOARDS_BIN = $(BOARDS:%=pc-bios/boards/%.dtb)
+endif
+
+build-all: $(TOOLS) $(DOCS) recurse-all $(BOARDS_BIN)
 
 config-host.mak: configure
 ifneq ($(wildcard config-host.mak),)
@@ -266,6 +275,7 @@ clean:
 # avoid old build problems by removing potentially incorrect old files
 	rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
 	rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
+	rm -f $(BOARDS_BIN)
 	for d in slirp audio block libfdt; do \
 	  rm -f $$d/*.o $$d/*.d $$d/*.a ; \
 	done
@@ -316,6 +326,12 @@ ifneq ($(BLOBS),)
 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
 	done
 endif
+ifneq ($(BOARDS_BIN),)
+	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/boards"
+	set -e; for x in $(BOARDS_BIN); do \
+		$(INSTALL_DATA) $(SRC_PATH)/$$x "$(DESTDIR)$(datadir)/boards"; \
+	done
+endif
 ifndef CONFIG_WIN32
 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
 	set -e; for x in $(KEYMAPS); do \
diff --git a/Makefile.target b/Makefile.target
index 4e302c0..4bc4c76 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -494,7 +494,7 @@ endif #CONFIG_BSD_USER
 ifndef CONFIG_USER_ONLY
 
 OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o \
-     gdbstub.o gdbstub-xml.o
+     gdbstub.o gdbstub-xml.o dt-machine.o
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
 OBJS+=virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o
@@ -664,9 +664,10 @@ OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
 OBJS+= mst_fpga.o mainstone.o
 OBJS+= musicpal.o pflash_cfi02.o
 OBJS+= framebuffer.o
-OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
+OBJS+= syborg_fb.o syborg_interrupt.o syborg_keyboard.o
 OBJS+= syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
 OBJS+= syborg_virtio.o
+OBJS+= arm-cpu.o
 CPPFLAGS += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), sh4)
diff --git a/configure b/configure
index 59ba8ef..f20da35 100755
--- a/configure
+++ b/configure
@@ -199,6 +199,7 @@ sdl="yes"
 sdl_x11="no"
 xen="yes"
 pkgversion=""
+dtc=""
 
 # OS specific
 if check_define __linux__ ; then
@@ -503,6 +504,8 @@ for opt do
   ;;
   --with-pkgversion=*) pkgversion=" ($optarg)"
   ;;
+  --with-dtc=*) dtc="$optarg"
+  ;;
   --disable-docs) build_docs="no"
   ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
@@ -1227,6 +1230,13 @@ if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC -lfdt 2> /dev/null > /dev/null ;
   build_fdt=no
 fi
 
+# Check for device tree compiler
+if test -z "$dtc" ; then
+  dtc="`which dtc 2>/dev/null`"
+  if test ! -x "$dtc" ; then
+    dtc=""
+  fi
+fi
 #
 # Check for xxxat() functions when we are building linux-user
 # emulator.  This is done because older glibc versions don't
@@ -1380,6 +1390,7 @@ echo "Install blobs     $blobs"
 echo -e "KVM support       $kvm"
 echo "Build libfdt      $build_fdt"
 echo "preadv support    $preadv"
+echo "dtc               ${dtc:-(Not Found)}"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1708,7 +1719,7 @@ if test "$iovec" = "yes" ; then
   echo "#define HAVE_IOVEC 1" >> $config_h
 fi
 if test "$preadv" = "yes" ; then
-  echo "#define HAVE_PREADV 1" >> $config_h
+  echo "#defne HAVE_PREADV 1" >> $config_h
 fi
 if test "$build_fdt" = "yes" ; then
   echo "BUILD_LIBFDT=libfdt/libfdt.a" >> $config_mak
@@ -1717,6 +1728,10 @@ else
   echo "FDT_LIBS=-lfdt" >> $config_mak
 fi
 
+if [ -n "$dtc" ] ; then
+  echo "DTC=$dtc" >> $config_mak
+fi
+
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
   echo "#define O_LARGEFILE 0" >> $config_h
diff --git a/hw/arm-cpu.c b/hw/arm-cpu.c
new file mode 100644
index 0000000..c15eb12
--- /dev/null
+++ b/hw/arm-cpu.c
@@ -0,0 +1,78 @@
+/*
+ * CPU devices
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GNU GPL v2.
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "boards.h"
+
+/* FIXME: Remove this and make the CPU emulation use the right names.  */
+static const struct {
+    const char *devname;
+    const char *cpuname;
+} cpu_device_name_map[] = {
+    {"ARM,ARM926EJ-S", "arm926"},
+    {"ARM,Cortex-A8", "cortex-a8"}
+};
+
+typedef struct {
+    SysBusDeviceInfo sysbus;
+    const char *cpuname;
+} CPUInfo;
+
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq *cpu_pic;
+} CPUDevice;
+
+static void arm_cpu_dev_set_irq(void *opaque, int n, int level)
+{
+    CPUDevice *s = opaque;
+    assert(n >= 0 && n < 2);
+    qemu_set_irq(s->cpu_pic[n], level);
+}
+
+static DevicePropList cpu_qdev_props[] = {
+    {.name = "nvic", .type = PROP_TYPE_DEV},
+    {.name = ""}
+};
+
+static void arm_cpu_dev_init(SysBusDevice *dev)
+{
+    CPUDevice *s = FROM_SYSBUS(CPUDevice, dev);
+    CPUInfo *info = container_of(dev->info, CPUInfo, sysbus);
+    CPUState *env;
+
+    env = cpu_init(info->cpuname);
+    s->cpu_pic = arm_pic_init_cpu(env);
+    qdev_init_gpio_in(&dev->qdev, arm_cpu_dev_set_irq, 2);
+    if (arm_feature(env, ARM_FEATURE_M)) {
+        env->v7m.nvic = qdev_get_prop_dev(&dev->qdev, "nvic");
+        if (!env->v7m.nvic) {
+            hw_error("CPU requires NVIC");
+        }
+    }
+}
+
+static void arm_cpu_register_devices(void)
+{
+    int i;
+    CPUInfo *info;
+
+    for (i = 0; i < ARRAY_SIZE(cpu_device_name_map); i++) {
+        info = qemu_mallocz(sizeof(*info));
+        info->sysbus.qdev.props = cpu_qdev_props;
+        info->sysbus.init = arm_cpu_dev_init;
+        info->cpuname = cpu_device_name_map[i].cpuname;
+        sysbus_register_withprop(cpu_device_name_map[i].devname,
+                                 sizeof(CPUDevice),
+                                 &info->sysbus);
+    }
+}
+
+device_init(arm_cpu_register_devices)
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index acfa67e..95dd532 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -10,6 +10,7 @@
 #include "hw.h"
 #include "arm-misc.h"
 #include "sysemu.h"
+#include "boards.h"
 
 #define KERNEL_ARGS_ADDR 0x100
 #define KERNEL_LOAD_ADDR 0x00010000
@@ -260,3 +261,24 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
             set_kernel_args(info, initrd_size, info->loader_start);
     }
 }
+
+static struct arm_boot_info arm_linux_binfo;
+static void arm_linux_bootstrap(ram_addr_t ram_size, const char *boot_device,
+    const char *kernel_filename, const char *kernel_cmdline,
+    const char *initrd_filename)
+{
+    arm_linux_binfo.ram_size = ram_size;
+    arm_linux_binfo.kernel_filename = kernel_filename;
+    arm_linux_binfo.kernel_cmdline = kernel_cmdline;
+    arm_linux_binfo.initrd_filename = initrd_filename;
+    arm_linux_binfo.board_id = get_bootstrap_arg_int("board-id", 0);
+    arm_linux_binfo.loader_start = get_bootstrap_arg_int("loader-start", 0);
+    arm_load_kernel(first_cpu, &arm_linux_binfo);
+}
+
+static void arm_boot_register(void)
+{
+    register_machine_bootstrap("arm-linux", arm_linux_bootstrap);
+}
+
+machine_init(arm_boot_register);
diff --git a/hw/boards.h b/hw/boards.h
index f6733b7..1733e8b 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -23,5 +23,14 @@ typedef struct QEMUMachine {
 int qemu_register_machine(QEMUMachine *m);
 
 extern QEMUMachine *current_machine;
+extern QEMUMachine dt_machine;
+
+typedef void (*machine_bootstrapfn)(ram_addr_t ram_size,
+    const char *boot_device,
+    const char *kernel_filename, const char *kernel_cmdline,
+    const char *initrd_filename);
+
+void register_machine_bootstrap(const char *name, machine_bootstrapfn fn);
+uint64_t get_bootstrap_arg_int(const char *name, uint64_t def);
 
 #endif
diff --git a/hw/dt-machine.c b/hw/dt-machine.c
new file mode 100644
index 0000000..b960a6c
--- /dev/null
+++ b/hw/dt-machine.c
@@ -0,0 +1,582 @@
+#include "sysbus.h"
+#include "device_tree.h"
+#include "boards.h"
+
+#include <libfdt.h>
+
+/* FIXME: Remove this.  */
+static void *the_dt;
+static int bootstrap_offset;
+
+static void dt_walk_bus(DeviceState *parent, void *dt, int offset, int folded);
+
+static int fdt_next_node(const void *fdt, int offset)
+{
+    int level = 1;
+    uint32_t tag;
+    int nextoffset;
+
+    tag = fdt_next_tag(fdt, offset, &nextoffset);
+    if (tag != FDT_BEGIN_NODE)
+        return -FDT_ERR_BADOFFSET;
+
+    while (level >= 0) {
+        offset = nextoffset;
+        tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+        switch (tag) {
+        case FDT_END:
+            return -FDT_ERR_TRUNCATED;
+        case FDT_BEGIN_NODE:
+            level++;
+            if (level == 1)
+                return offset;
+            break;
+        case FDT_END_NODE:
+            level--;
+            break;
+        case FDT_PROP:
+        case FDT_NOP:
+            break;
+        default:
+            return -FDT_ERR_BADSTRUCTURE;
+        }
+    }
+
+    return -FDT_ERR_NOTFOUND;
+}
+
+static int fdt_first_subnode(const void *fdt, int offset)
+{
+    uint32_t tag;
+    int nextoffset;
+
+    tag = fdt_next_tag(fdt, offset, &nextoffset);
+    if (tag != FDT_BEGIN_NODE)
+        return -FDT_ERR_BADOFFSET;
+
+    while (tag != FDT_END_NODE) {
+        offset = nextoffset;
+        tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+        switch (tag) {
+        case FDT_END:
+            return -FDT_ERR_TRUNCATED;
+        case FDT_BEGIN_NODE:
+            return offset;
+        case FDT_END_NODE:
+        case FDT_PROP:
+        case FDT_NOP:
+            break;
+        default:
+            return -FDT_ERR_BADSTRUCTURE;
+        }
+    }
+
+    return -FDT_ERR_NOTFOUND;
+}
+
+static void dt_add_props(DeviceState *dev, void *dt, int offset)
+{
+    DevicePropList *prop;
+    const void *p;
+    int prop_len;
+    uint64_t i;
+    const uint32_t *ip;
+
+    prop = qdev_get_proplist(dev);
+    if (!prop) {
+        return;
+    }
+    for (; prop->name; prop++) {
+        p = fdt_getprop(dt, offset, prop->name, &prop_len);
+        if (!p) {
+            continue;
+        }
+        ip = p;
+        switch (prop->type) {
+        case PROP_TYPE_INT:
+            if (prop_len != 4 && prop_len != 8) {
+                hw_error("%s: Bad length for property '%s'\n",
+                         fdt_get_name(dt, offset, NULL), prop->name);
+            }
+            i = fdt32_to_cpu(ip[0]);
+            if (prop_len == 8) {
+                i = (i << 32) | fdt32_to_cpu(ip[1]);
+            }
+            qdev_set_prop_int(dev, prop->name, i);
+            break;
+        case PROP_TYPE_DEV:
+            {
+                uint32_t phandle;
+                DeviceState *other_dev;
+                if (prop_len != 4) {
+                    hw_error("%s: Bad length for property '%s'\n",
+                             fdt_get_name(dt, offset, NULL), prop->name);
+                }
+                phandle = fdt32_to_cpu(ip[0]);
+                other_dev = qdev_from_phandle(phandle);
+                if (!other_dev) {
+                    hw_error("%s: Device (%d) not found\n",
+                             fdt_get_name(dt, offset, NULL), phandle);
+                }
+                qdev_set_prop_dev(dev, prop->name, other_dev);
+            }
+            break;
+        case PROP_TYPE_ARRAY:
+            {
+                uint32_t *data;
+                if (prop_len & 3) {
+                    hw_error("%s: Bad length for property '%s'\n",
+                             fdt_get_name(dt, offset, NULL), prop->name);
+                }
+                data = qemu_malloc(prop_len);
+                for (i = 0; i < prop_len >> 2; i++) {
+                    data[i] = fdt32_to_cpu(ip[i]);
+                }
+                qdev_set_prop_array(dev, prop->name, data, prop_len >> 2);
+                qemu_free(data);
+            }
+            break;
+        default:
+            abort();
+        }
+    }
+}
+
+static void dt_create_device(BusState *bus, void *dt, int offset)
+{
+    char namebuf[128];
+    const char *type;
+    const uint32_t *prop;
+    char *p;
+    DeviceState *dev;
+
+    /* First try the "model" property.  */
+    type = fdt_getprop(dt, offset, "model", NULL);
+    if (type && !qdev_device_exists(type)) {
+        type = NULL;
+    }
+    /* If that does not work then try "compatible".  */
+    if (!type) {
+        type = fdt_getprop(dt, offset, "compatible", NULL);
+        if (type && !qdev_device_exists(type)) {
+            type = NULL;
+        }
+    }
+    /* If all else fails then resort to the device name.  */
+    if (!type) {
+        type = fdt_get_name(dt, offset, NULL);
+        p = namebuf;
+        while (*type && *type != '@') {
+            *(p++) = *(type++);
+        }
+        *p = 0;
+        if (!qdev_device_exists(namebuf)) {
+            hw_error("Unrecognised device '%s'\n",
+                     fdt_get_name(dt, offset, NULL));
+        }
+        type = namebuf;
+    }
+
+    dev = qdev_create(bus, type);
+    dev->fdt_offset = offset;
+    prop = fdt_getprop(dt, offset, "linux,phandle", NULL);
+    if (prop) {
+        dev->phandle = fdt32_to_cpu(*prop);
+    } else {
+        dev->phandle = -1;
+    }
+}
+
+static void dt_init_device(DeviceState *dev, void *opaque)
+{
+    void *dt = opaque;
+    int offset;
+
+    offset = dev->fdt_offset;
+    dt_add_props(dev, dt, offset);
+    qdev_init(dev);
+
+    dt_walk_bus(dev, dt, offset, 0);
+}
+
+static int dt_fold_bus(void *dt, int offset)
+{
+    const char *name = fdt_get_name(dt, offset, NULL);
+
+    if (strcmp(name, "cpus") == 0) {
+        return 1;
+    }
+    if (fdt_getprop(dt, offset, "qemu,fold-bus", NULL)) {
+        return 1;
+    }
+    return 0;
+}
+
+static int dt_ignore_node(void *dt, int offset)
+{
+    const char *name = fdt_get_name(dt, offset, NULL);
+
+    if (strcmp(name, "chosen") == 0) {
+        return 1;
+    }
+    if (strcmp(name, "aliases") == 0) {
+        return 1;
+    }
+    if (fdt_getprop(dt, offset, "qemu,ignore", NULL)) {
+        return 1;
+    }
+    return 0;
+}
+
+static void dt_get_sizes(void *dt, int offset,
+                         int *addr_cells, int *size_cells)
+{
+    const uint32_t *prop;
+    int parent;
+
+    parent = fdt_parent_offset(dt, offset);
+    assert(parent >= 0);
+
+    if (addr_cells) {
+        prop = fdt_getprop(dt, parent, "#address-cells", NULL);
+        if (!prop) {
+            hw_error("%s: Missing #address-cells",
+                     fdt_get_name(dt, offset, NULL));
+        }
+        *addr_cells = fdt32_to_cpu(*prop);
+    }
+
+    if (size_cells) {
+        prop = fdt_getprop(dt, parent, "#size-cells", NULL);
+        if (!prop) {
+            hw_error("%s: Missing #size-cells",
+                     fdt_get_name(dt, offset, NULL));
+        }
+        *size_cells = fdt32_to_cpu(*prop);
+    }
+}
+
+static void dt_create_memory(void *dt, int offset, int flags)
+{
+    const uint32_t *regs;
+    int regs_len;
+    const uint32_t *alias;
+    int alias_len;
+    int addr_cells;
+    int size_cells;
+    uint64_t addr;
+    uint64_t size;
+    ram_addr_t ram_offset;
+
+    dt_get_sizes(dt, offset, &addr_cells, &size_cells);
+    regs = fdt_getprop(dt, offset, "reg", &regs_len);
+    if (!regs || regs_len == 0) {
+        return;
+    }
+    if ((regs_len % ((addr_cells + size_cells) * 4)) != 0) {
+        hw_error("%s: Bad reg size\n", fdt_get_name(dt, offset, NULL));
+    }
+    alias = fdt_getprop(dt, offset, "qemu,alias", &alias_len);
+    while (regs_len > 0) {
+        addr = fdt32_to_cpu(*(regs++));
+        if (addr_cells == 2) {
+            addr = (addr << 32) | fdt32_to_cpu(*(regs++));
+        }
+        size = fdt32_to_cpu(*(regs++));
+        if (size_cells == 2) {
+            size = (size << 32) | fdt32_to_cpu(*(regs++));
+        }
+        regs_len -= (addr_cells + size_cells) * 4;
+        if (size != (ram_addr_t)size) {
+            hw_error("Ram too big\n");
+        }
+        ram_offset = qemu_ram_alloc(size);
+        cpu_register_physical_memory(addr, size, ram_offset | flags);
+        if (alias) {
+            if (regs_len > 0) {
+                hw_error("%s: Aliased memory may only have a single region",
+                         fdt_get_name(dt, offset, NULL));
+            }
+            if ((alias_len % addr_cells) != 0) {
+                hw_error("%s: Bad qemu,alias size\n",
+                         fdt_get_name(dt, offset, NULL));
+            }
+            while (alias_len) {
+                addr = fdt32_to_cpu(*(alias++));
+                if (addr_cells== 2) {
+                    addr = (addr << 32) | fdt32_to_cpu(*(alias++));
+                }
+                cpu_register_physical_memory(addr, size, ram_offset | flags);
+                alias_len -= addr_cells * 4;
+            }
+        }
+    }
+}
+
+static void dt_walk_bus(DeviceState *parent, void *dt, int offset, int folded)
+{
+    int next_offset;
+    const char *type;
+    const char *bus_name;
+    BusState *parent_bus;
+
+    if (parent) {
+        parent_bus = LIST_FIRST(&parent->child_bus);
+    } else {
+        parent_bus = NULL;
+    }
+    next_offset = fdt_first_subnode(dt, offset);
+    while (next_offset > 0) {
+        offset = next_offset;
+        next_offset = fdt_next_node(dt, offset);
+        if (dt_ignore_node(dt, offset)) {
+            continue;
+        }
+        if (dt_fold_bus(dt, offset)) {
+            dt_walk_bus(parent, dt, offset, 1);
+            continue;
+        }
+        bus_name = fdt_getprop(dt, offset, "qemu,parent-bus", NULL);
+        if (bus_name) {
+            if (parent) {
+                parent_bus = qdev_get_child_bus(parent, bus_name);
+            }
+            if (!parent_bus) {
+                hw_error("%s: Unable to find parent bus\n",
+                         fdt_get_name(dt, offset, NULL));
+            }
+        }
+        type = fdt_getprop(dt, offset, "device_type", NULL);
+        /* Special case for memory.  */
+        if (type && strcmp(type, "memory") == 0) {
+            dt_create_memory(dt, offset, IO_MEM_RAM);
+            continue;
+        }
+        if (type && strcmp(type, "rom") == 0) {
+            dt_create_memory(dt, offset, IO_MEM_ROM);
+            continue;
+        }
+        dt_create_device(parent_bus, dt, offset);
+    }
+    if (!folded) {
+        qdev_enumerate_child_devices(parent, dt_init_device, dt);
+    }
+}
+
+void dt_fixup_qdev(DeviceState *dev)
+{
+    void *dt = the_dt;
+    int offset = dev->fdt_offset;
+    int n;
+    int prop_size;
+    const uint32_t *prop;
+
+    if (dev->num_gpio_out) {
+        int parent;
+        int irqn;
+        qemu_irq pin;
+        DeviceState *parent_dev;
+
+        prop = fdt_getprop(dt, offset, "qemu,gpio", &prop_size);
+        if (prop_size != 8 * dev->num_gpio_out) {
+            hw_error("%s: Bad GPIO size\n", fdt_get_name(dt, offset, NULL));
+        }
+        for (n = 0; n < dev->num_gpio_out; n++) {
+            parent = fdt32_to_cpu(*(prop++));
+            if (parent == 0) {
+                /* Assume zero phandle means disconnected.  */
+                prop++;
+                continue;
+            }
+            parent_dev = qdev_from_phandle(parent);
+            if (!parent_dev) {
+                hw_error("%s: GPIO device (%d) not found\n",
+                         fdt_get_name(dt, offset, NULL), parent);
+            }
+            irqn = fdt32_to_cpu(*(prop++));
+            if (irqn >= parent_dev->num_gpio_in) {
+                hw_error("%s: Invalid GPIO %d (%d)\n",
+                         fdt_get_name(dt, offset, NULL), n, irqn);
+            }
+            pin = qdev_get_gpio_in(parent_dev, irqn);
+            qdev_connect_gpio_out(dev, n, pin);
+        }
+    }
+}
+
+void dt_fixup_sysbus_device(DeviceState *dev)
+{
+    SysBusDevice *s = sysbus_from_qdev(dev);
+    void *dt = the_dt;
+    int offset = dev->fdt_offset;
+    const uint32_t *prop;
+    int prop_size;
+    int n;
+
+    if (s->num_mmio) {
+        int addr_cells;
+        int size_cells;
+        uint64_t addr;
+        dt_get_sizes(dt, offset, &addr_cells, &size_cells);
+        if (addr_cells < 1 || addr_cells > 2) {
+            hw_error("%s: unsupported #address-cells (%d)\n",
+                     fdt_get_name(dt, offset, NULL), addr_cells);
+        }
+        prop = fdt_getprop(dt, offset, "reg", &prop_size);
+        if (prop_size != (addr_cells + size_cells) * 4 * s->num_mmio) {
+            hw_error("%s: Bad reg size\n", fdt_get_name(dt, offset, NULL));
+        }
+        for (n = 0; n < s->num_mmio; n++) {
+            addr = fdt32_to_cpu(*(prop++));
+            if (addr_cells == 2) {
+                addr = (addr << 32) | fdt32_to_cpu(*(prop++));
+            }
+            /* The device already told up how big the region is, so ignore
+               what the device tree says.  */
+            prop += size_cells;
+            sysbus_mmio_map(s, n, addr);
+        }
+    }
+
+    if (s->num_irq) {
+        int parent;
+        int irqn;
+        DeviceState *parent_dev;
+
+        prop = fdt_getprop(dt, offset, "interrupt-parent", &prop_size);
+        if (!prop || prop_size != 4) {
+            hw_error("%s: Missing/bad interrupt-parent\n",
+                     fdt_get_name(dt, offset, NULL));
+        }
+        parent = fdt32_to_cpu(*prop);
+        parent_dev = qdev_from_phandle(parent);
+        if (!parent_dev) {
+            hw_error("%s: interrupt-parent device (%d) not found\n",
+                     fdt_get_name(dt, offset, NULL), parent);
+        }
+        prop = fdt_getprop(dt, parent_dev->fdt_offset, "#interrupt-cells",
+                           &prop_size);
+        if (!prop || prop_size != 4) {
+            hw_error("%s: Missing #interrupt-cells\n",
+                     fdt_get_name(dt, parent_dev->fdt_offset, NULL));
+        }
+        if (fdt32_to_cpu(*prop) != 1) {
+            hw_error("%s: unsupported #interrupt-cells\n",
+                     fdt_get_name(dt, parent_dev->fdt_offset, NULL));
+        }
+        prop = fdt_getprop(dt, offset, "interrupts", &prop_size);
+        if (prop_size != 4 * s->num_irq) {
+            hw_error("%s: Bad interrupts size\n",
+                     fdt_get_name(dt, offset, NULL));
+        }
+        for (n = 0; n < s->num_irq; n++) {
+            irqn = fdt32_to_cpu(*(prop++));
+            if (irqn == -1) {
+                continue;
+            }
+            if (irqn >= parent_dev->num_gpio_in) {
+                hw_error("%s: Invalid interrupt %d (%d)\n",
+                         fdt_get_name(dt, offset, NULL), n, irqn);
+            }
+            sysbus_connect_irq(s, n, qdev_get_gpio_in(parent_dev, irqn));
+        }
+    }
+}
+
+typedef struct MachineBootstrap {
+    const char *name;
+    machine_bootstrapfn fn;
+    LIST_ENTRY(MachineBootstrap) next;
+} MachineBootstrap;
+
+LIST_HEAD(, MachineBootstrap) machine_bootstrap_list =
+    LIST_HEAD_INITIALIZER(machine_bootstrap_list);
+
+void register_machine_bootstrap(const char *name, machine_bootstrapfn fn)
+{
+    MachineBootstrap *bootstrap;
+
+    bootstrap = qemu_mallocz(sizeof(*bootstrap));
+    bootstrap->name = qemu_strdup(name);
+    bootstrap->fn = fn;
+    LIST_INSERT_HEAD(&machine_bootstrap_list, bootstrap, next);
+}
+
+uint64_t get_bootstrap_arg_int(const char *name, uint64_t def)
+{
+    void *dt = the_dt;
+    const uint32_t *p;
+    int prop_len;
+    uint64_t val;
+
+    p = fdt_getprop(dt, bootstrap_offset, name, &prop_len);
+    if (!p) {
+        return def;
+    }
+    if (prop_len != 4 && prop_len != 8) {
+        hw_error("Bad length for property '%s'\n", name);
+    }
+    val = fdt32_to_cpu(p[0]);
+    if (prop_len == 8) {
+        val = (val << 32) | fdt32_to_cpu(p[1]);
+    }
+    return val;
+}
+
+static void dt_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    void *dt;
+    int dt_size;
+    const char *filename;
+
+    filename = dt_machine.name;
+    /* FIXME: Allow user to specify filename.  */
+    dt = load_device_tree(filename, &dt_size);
+    if (!dt) {
+        hw_error("Failed to load device tree\n");
+    }
+
+    the_dt = dt;
+
+    dt_walk_bus(NULL, dt, 0, 0);
+
+    qdev_fixup_devices();
+
+    {
+    const char *p;
+    MachineBootstrap *bootstrap;
+
+    bootstrap_offset = fdt_path_offset(dt, "/chosen/qemu");
+    if (bootstrap_offset < 0) {
+        return;
+    }
+    p = fdt_getprop(dt, bootstrap_offset, "bootstrap", NULL);
+    if (!p) {
+        return;
+    }
+
+    LIST_FOREACH(bootstrap, &machine_bootstrap_list, next) {
+        if (strcmp(bootstrap->name, p) == 0) {
+            break;
+        }
+    }
+    if (!bootstrap) {
+        hw_error("Unrecognised machine bootstrap '%s'\n", p);
+    }
+    bootstrap->fn(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename);
+
+    }
+}
+
+/* This is used directly by vl.c, and not registered by normal means.  */
+QEMUMachine dt_machine = {
+    .name = "devtree",
+    .desc = "Device Tree",
+    .init = dt_init,
+};
diff --git a/hw/i2c.c b/hw/i2c.c
index 8a0c4d7..4e53c09 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -68,7 +68,7 @@ int i2c_start_transfer(i2c_bus *bus, int address, int recv)
     DeviceState *qdev;
     i2c_slave *slave = NULL;
 
-    LIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+    TAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
         slave = I2C_SLAVE_FROM_QDEV(qdev);
         if (slave->address == address)
             break;
@@ -152,9 +152,15 @@ static void i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
     info->init(s);
 }
 
+static const DevicePropList i2c_bus_props[] = {
+      {.name = "address", .type = PROP_TYPE_INT},
+      {.name = NULL}
+};
 void i2c_register_slave(const char *name, int size, I2CSlaveInfo *info)
 {
+    assert(!info->qdev.init);
     assert(size >= sizeof(i2c_slave));
+    info->qdev.props = qdev_merge_props(info->qdev.props, i2c_bus_props);
     info->qdev.init = i2c_slave_qdev_init;
     info->qdev.bus_type = BUS_TYPE_I2C;
     qdev_register(name, size, &info->qdev);
diff --git a/hw/pci.c b/hw/pci.c
index 8c904ba..487017d 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -924,6 +924,7 @@ void pci_qdev_register(const char *name, int size, pci_qdev_initfn init)
     PCIDeviceInfo *info;
 
     info = qemu_mallocz(sizeof(*info));
+    assert(!info->qdev.init);
     info->init = init;
     info->qdev.init = pci_qdev_init;
     info->qdev.bus_type = BUS_TYPE_PCI;
diff --git a/hw/qdev.c b/hw/qdev.c
index 636dc78..39e8ce8 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -26,6 +26,25 @@
    inherit from a particular bus (e.g. PCI or I2C) rather than
    this API directly.  */
 
+/* Device instantiation occurs in several stages.
+
+   1) Device objects are created (qdev_create).
+   2) Device properties are set.
+   3) Device init routines are run.
+   4) GPIO and IRQ lines are connected and MMIO regions are mapped.
+   5) Device late init routines are run.
+
+   It can be assumed that all siblings on a bus have been created before
+   any are initialized.  Child devices are created after the parent
+   device is initialized.  Thus PROP_TYPE_DEV may only refer to siblings or
+   siblings of direct ancestors.  No dependency tracking is performed, so
+   a device may be initialized before the devices it references.
+
+   Other than Within each stage, devices are processed in arbitrary order.
+
+   Steps 3, 4 and 5 only occur after preceeding steps have been completed
+   for all devices. */
+
 #include "net.h"
 #include "qdev.h"
 #include "sysemu.h"
@@ -37,6 +56,10 @@ struct DeviceProperty {
     union {
         uint64_t i;
         void *ptr;
+        struct {
+            uint32_t *data;
+            int len;
+        } array;
     } value;
     DeviceProperty *next;
 };
@@ -68,6 +91,23 @@ void qdev_register(const char *name, int size, DeviceInfo *info)
     t->info = info;
 }
 
+static DeviceType *qdev_find_devtype(const char *name)
+{
+    DeviceType *t;
+
+    for (t = device_type_list; t; t = t->next) {
+        if (strcmp(t->name, name) == 0) {
+            return t;;
+        }
+    }
+    return NULL;
+}
+
+int qdev_device_exists(const char *name)
+{
+    return qdev_find_devtype(name) != NULL;
+}
+
 /* Create a new device.  This only initializes the device state structure
    and allows properties to be set.  qdev_init should be called to
    initialize the actual device emulation.  */
@@ -76,11 +116,7 @@ DeviceState *qdev_create(BusState *bus, const char *name)
     DeviceType *t;
     DeviceState *dev;
 
-    for (t = device_type_list; t; t = t->next) {
-        if (strcmp(t->name, name) == 0) {
-            break;
-        }
-    }
+    t = qdev_find_devtype(name);
     if (!t) {
         hw_error("Unknown device '%s'\n", name);
     }
@@ -89,8 +125,8 @@ DeviceState *qdev_create(BusState *bus, const char *name)
     dev->type = t;
 
     if (!bus) {
-        /* ???: This assumes system busses have no additional state.  */
         if (!main_system_bus) {
+            /* ???: This assumes system busses have no additional state.  */
             main_system_bus = qbus_create(BUS_TYPE_SYSTEM, sizeof(BusState),
                                           NULL, "main-system-bus");
         }
@@ -102,7 +138,9 @@ DeviceState *qdev_create(BusState *bus, const char *name)
                  t->info->bus_type, bus->type);
     }
     dev->parent_bus = bus;
-    LIST_INSERT_HEAD(&bus->children, dev, sibling);
+    /* Keep devices in creation order for consistency between creation
+       and initialization passes.  */
+    TAILQ_INSERT_TAIL(&bus->children, dev, sibling);
     return dev;
 }
 
@@ -114,10 +152,32 @@ void qdev_init(DeviceState *dev)
     dev->type->info->init(dev, dev->type->info);
 }
 
+static void qdev_late_init_bus(BusState *bus)
+{
+    DeviceState *dev;
+    BusState *child_bus;
+
+    TAILQ_FOREACH(dev, &bus->children, sibling) {
+        if (dev->type->info->late_init) {
+            dev->type->info->late_init(dev);
+        }
+        LIST_FOREACH(child_bus, &dev->child_bus, sibling) {
+            qdev_late_init_bus(child_bus);
+        }
+    }
+}
+
+void qdev_do_late_init(void)
+{
+    if (main_system_bus) {
+        qdev_late_init_bus(main_system_bus);
+    }
+}
+
 /* Unlink device from bus and free the structure.  */
 void qdev_free(DeviceState *dev)
 {
-    LIST_REMOVE(dev, sibling);
+    TAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
     free(dev);
 }
 
@@ -152,6 +212,17 @@ void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value)
     prop->value.ptr = value;
 }
 
+void qdev_set_prop_array(DeviceState *dev, const char *name, uint32_t *data,
+                         int len)
+{
+    DeviceProperty *prop;
+
+    prop = create_prop(dev, name, PROP_TYPE_ARRAY);
+    prop->value.array.data = qemu_malloc(len * 4);
+    prop->value.array.len = len;
+    memcpy(prop->value.array.data, data, len * 4);
+}
+
 void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
 {
     DeviceProperty *prop;
@@ -231,6 +302,21 @@ DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name)
     return prop->value.ptr;
 }
 
+int qdev_get_prop_array(DeviceState *dev, const char *name,
+                        const uint32_t **p)
+{
+    DeviceProperty *prop;
+
+    prop = find_prop(dev, name, PROP_TYPE_ARRAY);
+    if (!prop) {
+        return -1;
+    }
+    if (p) {
+        *p = prop->value.array.data;
+    }
+    return prop->value.array.len;
+}
+
 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
 {
     assert(dev->num_gpio_in == 0);
@@ -272,6 +358,17 @@ VLANClientState *qdev_get_vlan_client(DeviceState *dev,
 
 void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
 {
+    static int next_netdev;
+    if (!dev->nd) {
+        /* FIXME: This is just plain broken.  */
+        if (next_netdev >= nb_nics) {
+            abort();
+        }
+        dev->nd = &nd_table[next_netdev];
+        next_netdev++;
+
+        qemu_check_nic_model(dev->nd, dev->type->name);
+    }
     memcpy(macaddr, dev->nd->macaddr, 6);
 }
 
@@ -332,13 +429,121 @@ BusState *qbus_create(BusType type, size_t size,
     bus->type = type;
     bus->parent = parent;
     bus->name = qemu_strdup(name);
-    LIST_INIT(&bus->children);
+    TAILQ_INIT(&bus->children);
     if (parent) {
         LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
     }
     return bus;
 }
 
+static DeviceState *qdev_from_phandle1(BusState *bus, uint32_t phandle)
+{
+    DeviceState *dev;
+    BusState *child_bus;
+    DeviceState *child_dev;
+
+    TAILQ_FOREACH(dev, &bus->children, sibling) {
+        if (dev->phandle == phandle) {
+            return dev;
+        }
+        LIST_FOREACH(child_bus, &dev->child_bus, sibling) {
+            child_dev = qdev_from_phandle1(child_bus, phandle);
+            if (child_dev) {
+                return child_dev;
+            }
+        }
+    }
+    return NULL;
+}
+
+DeviceState *qdev_from_phandle(uint32_t phandle)
+{
+    if (!main_system_bus) {
+        return NULL;
+    }
+    return qdev_from_phandle1(main_system_bus, phandle);  
+}
+
+static void qdev_fixup_bus(BusState *bus)
+{
+    DeviceState *dev;
+
+    TAILQ_FOREACH(dev, &bus->children, sibling) {
+        if (!dev->fdt_offset) {
+            continue;
+        }
+        dt_fixup_qdev(dev);
+        switch (bus->type) {
+        case BUS_TYPE_SYSTEM:
+            dt_fixup_sysbus_device(dev);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+void qdev_fixup_devices(void)
+{
+    assert(main_system_bus);
+    qdev_fixup_bus(main_system_bus);
+}
+
+static void enumerate_bus_devices(BusState *bus, enumdevfn cb, void *opaque)
+{
+    DeviceState *dev;
+
+    TAILQ_FOREACH(dev, &bus->children, sibling) {
+        cb(dev, opaque);
+    }
+}
+
+void qdev_enumerate_child_devices(DeviceState *dev, enumdevfn cb, void *opaque)
+{
+    BusState *bus;
+
+    if (!dev) {
+        enumerate_bus_devices(main_system_bus, cb, opaque);
+        return;
+    }
+    LIST_FOREACH(bus, &dev->child_bus, sibling) {
+        enumerate_bus_devices(bus, cb, opaque);
+    }
+}
+
+DevicePropList *qdev_get_proplist(DeviceState *dev)
+{
+    return dev->type->info->props;
+}
+
+DevicePropList *qdev_merge_props(const DevicePropList *a,
+                                 const DevicePropList *b)
+{
+    int n;
+    const DevicePropList *p;
+    DevicePropList *q;
+    DevicePropList *ret;
+
+    n = 0;
+    for (p = a; p && p->name; p++) {
+        n++;
+    }
+    for (p = b; p && p->name; p++) {
+        n++;
+    }
+    n++;
+    ret = qemu_malloc(sizeof(DevicePropList) * n);
+    q = ret;
+    for (p = a; p && p->name; p++) {
+        *(q++) = *p;
+    }
+    for (p = b; p && p->name; p++) {
+        *(q++) = *p;
+    }
+    q->name = NULL;
+    return ret;
+}
+
 static const char *bus_type_names[] = {
     [ BUS_TYPE_SYSTEM ] = "System",
     [ BUS_TYPE_PCI ]    = "PCI",
@@ -399,7 +604,7 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent)
     qdev_printf("bus: %s\n", bus->name);
     indent += 2;
     qdev_printf("type %s\n", bus_type_names[bus->type]);
-    LIST_FOREACH(dev, &bus->children, sibling) {
+    TAILQ_FOREACH(dev, &bus->children, sibling) {
         qdev_print(mon, dev, indent);
     }
 }
diff --git a/hw/qdev.h b/hw/qdev.h
index 7291805..2e2c5f3 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -4,6 +4,18 @@
 #include "hw.h"
 #include "sys-queue.h"
 
+typedef enum {
+    PROP_TYPE_INT,
+    PROP_TYPE_PTR,
+    PROP_TYPE_DEV,
+    PROP_TYPE_ARRAY
+} DevicePropType;
+
+typedef struct {
+    const char *name;
+    DevicePropType type;
+} DevicePropList;
+
 typedef struct DeviceType DeviceType;
 
 typedef struct DeviceProperty DeviceProperty;
@@ -22,7 +34,9 @@ struct DeviceState {
     qemu_irq *gpio_in;
     LIST_HEAD(, BusState) child_bus;
     NICInfo *nd;
-    LIST_ENTRY(DeviceState) sibling;
+    TAILQ_ENTRY(DeviceState) sibling;
+    int fdt_offset;
+    uint32_t phandle;
 };
 
 typedef enum {
@@ -37,7 +51,7 @@ struct BusState {
     DeviceState *parent;
     const char *name;
     BusType type;
-    LIST_HEAD(, DeviceState) children;
+    TAILQ_HEAD(, DeviceState) children;
     LIST_ENTRY(BusState) sibling;
 };
 
@@ -50,6 +64,8 @@ void qdev_free(DeviceState *dev);
 /* Set properties between creation and init.  */
 void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value);
 void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value);
+void qdev_set_prop_array(DeviceState *dev, const char *name, uint32_t *data,
+                         int len);
 void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value);
 void qdev_set_netdev(DeviceState *dev, NICInfo *nd);
 
@@ -58,27 +74,30 @@ void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
 
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
 
-/*** Device API.  ***/
+/*** Internal device tree bits  ***/
 
-typedef enum {
-    PROP_TYPE_INT,
-    PROP_TYPE_PTR,
-    PROP_TYPE_DEV
-} DevicePropType;
+int qdev_device_exists(const char *name);
+DeviceState *qdev_from_phandle(uint32_t phandle);
+void qdev_fixup_devices(void);
+void dt_fixup_qdev(DeviceState *dev);
+void dt_fixup_sysbus_device(DeviceState *dev);
+DevicePropList *qdev_get_proplist(DeviceState *dev);
 
-typedef struct {
-    const char *name;
-    DevicePropType type;
-} DevicePropList;
+typedef void (*enumdevfn)(DeviceState *dev, void *opaque);
+void qdev_enumerate_child_devices(DeviceState *dev, enumdevfn cb, void *opaque);
+
+/*** Device API.  ***/
 
 typedef struct DeviceInfo DeviceInfo;
 
 typedef void (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
+typedef void (*qdev_late_initfn)(DeviceState *dev);
 typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv,
               int unit);
 
 struct DeviceInfo {
     qdev_initfn init;
+    qdev_late_initfn late_init;
     BusType bus_type;
     DevicePropList *props;
 };
@@ -96,10 +115,17 @@ CharDriverState *qdev_init_chardev(DeviceState *dev);
 
 BusState *qdev_get_parent_bus(DeviceState *dev);
 uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def);
+/* Returns the number of elements in the array.  */
+int qdev_get_prop_array(DeviceState *dev, const char *name,
+                        const uint32_t **p);
+/* NOTE: The returned device may not have been initialized yet.  */
 DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name);
 /* FIXME: Remove opaque pointer properties.  */
 void *qdev_get_prop_ptr(DeviceState *dev, const char *name);
 
+DevicePropList *qdev_merge_props(const DevicePropList *a,
+                                 const DevicePropList *b);
+
 /* Convery from a base type to a parent type, with compile time checking.  */
 #ifdef __GNUC__
 #define DO_UPCAST(type, field, dev) ( __extension__ ( { \
diff --git a/hw/ssi.c b/hw/ssi.c
index 52b7b7c..c086f02 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -20,8 +20,8 @@ static void ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
     SSIBus *bus;
 
     bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
-    if (LIST_FIRST(&bus->qbus.children) != dev
-        || LIST_NEXT(dev, sibling) != NULL) {
+    if (TAILQ_FIRST(&bus->qbus.children) != dev
+        || TAILQ_NEXT(dev, sibling) != NULL) {
         hw_error("Too many devices on SSI bus");
     }
 
@@ -32,6 +32,7 @@ static void ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
 void ssi_register_slave(const char *name, int size, SSISlaveInfo *info)
 {
     assert(size >= sizeof(SSISlave));
+    assert(!info->qdev.init);
     info->qdev.init = ssi_slave_init;
     info->qdev.bus_type = BUS_TYPE_SSI;
     qdev_register(name, size, &info->qdev);
@@ -56,7 +57,7 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
 {
     DeviceState *dev;
     SSISlave *slave;
-    dev = LIST_FIRST(&bus->qbus.children);
+    dev = TAILQ_FIRST(&bus->qbus.children);
     if (!dev) {
         return 0;
     }
diff --git a/hw/syborg.c b/hw/syborg.c
deleted file mode 100644
index 5ca9977..0000000
--- a/hw/syborg.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Syborg (Symbian Virtual Platform) reference board
- *
- * Copyright (c) 2009 CodeSourcery
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "sysbus.h"
-#include "boards.h"
-#include "arm-misc.h"
-#include "sysemu.h"
-#include "net.h"
-
-static struct arm_boot_info syborg_binfo;
-
-static void syborg_init(ram_addr_t ram_size,
-                        const char *boot_device,
-                        const char *kernel_filename, const char *kernel_cmdline,
-                        const char *initrd_filename, const char *cpu_model)
-{
-    CPUState *env;
-    qemu_irq *cpu_pic;
-    qemu_irq pic[64];
-    ram_addr_t ram_addr;
-    DeviceState *dev;
-    int i;
-
-    if (!cpu_model)
-        cpu_model = "cortex-a8";
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-
-    /* RAM at address zero. */
-    ram_addr = qemu_ram_alloc(ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_addr | IO_MEM_RAM);
-
-    cpu_pic = arm_pic_init_cpu(env);
-    dev = sysbus_create_simple("syborg,interrupt", 0xC0000000,
-                               cpu_pic[ARM_PIC_CPU_IRQ]);
-    for (i = 0; i < 64; i++) {
-        pic[i] = qdev_get_gpio_in(dev, i);
-    }
-
-    sysbus_create_simple("syborg,rtc", 0xC0001000, NULL);
-
-    dev = qdev_create(NULL, "syborg,timer");
-    qdev_set_prop_int(dev, "frequency", 1000000);
-    qdev_init(dev);
-    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xC0002000);
-    sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[1]);
-
-    sysbus_create_simple("syborg,keyboard", 0xC0003000, pic[2]);
-    sysbus_create_simple("syborg,pointer", 0xC0004000, pic[3]);
-    sysbus_create_simple("syborg,framebuffer", 0xC0005000, pic[4]);
-    sysbus_create_simple("syborg,serial", 0xC0006000, pic[5]);
-    sysbus_create_simple("syborg,serial", 0xC0007000, pic[6]);
-    sysbus_create_simple("syborg,serial", 0xC0008000, pic[7]);
-    sysbus_create_simple("syborg,serial", 0xC0009000, pic[8]);
-
-    if (nd_table[0].vlan) {
-        DeviceState *dev;
-        SysBusDevice *s;
-
-        qemu_check_nic_model(&nd_table[0], "virtio");
-        dev = qdev_create(NULL, "syborg,virtio-net");
-        qdev_set_netdev(dev, &nd_table[0]);
-        qdev_init(dev);
-        s = sysbus_from_qdev(dev);
-        sysbus_mmio_map(s, 0, 0xc000c000);
-        sysbus_connect_irq(s, 0, pic[9]);
-    }
-
-    syborg_binfo.ram_size = ram_size;
-    syborg_binfo.kernel_filename = kernel_filename;
-    syborg_binfo.kernel_cmdline = kernel_cmdline;
-    syborg_binfo.initrd_filename = initrd_filename;
-    syborg_binfo.board_id = 0;
-    arm_load_kernel(env, &syborg_binfo);
-}
-
-static QEMUMachine syborg_machine = {
-    .name = "syborg",
-    .desc = "Syborg (Symbian Virtual Platform)",
-    .init = syborg_init,
-};
-
-static void syborg_machine_init(void)
-{
-    qemu_register_machine(&syborg_machine);
-}
-
-machine_init(syborg_machine_init);
diff --git a/hw/sysbus.c b/hw/sysbus.c
index fbd2ddf..4903747 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -101,13 +101,16 @@ void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
 static void sysbus_device_init(DeviceState *dev, DeviceInfo *base)
 {
     SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
+    SysBusDevice *s = sysbus_from_qdev(dev);
 
-    info->init(sysbus_from_qdev(dev));
+    s->info = info;
+    info->init(s);
 }
 
 void sysbus_register_withprop(const char *name, size_t size,
                               SysBusDeviceInfo *info)
 {
+    assert(!info->qdev.init);
     info->qdev.init = sysbus_device_init;
     info->qdev.bus_type = BUS_TYPE_SYSTEM;
 
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 2973661..11fa8ad 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -11,8 +11,16 @@
 typedef struct SysBusDevice SysBusDevice;
 typedef void (*mmio_mapfunc)(SysBusDevice *dev, target_phys_addr_t addr);
 
+typedef void (*sysbus_initfn)(SysBusDevice *dev);
+
+typedef struct {
+    DeviceInfo qdev;
+    sysbus_initfn init;
+} SysBusDeviceInfo;
+
 struct SysBusDevice {
     DeviceState qdev;
+    SysBusDeviceInfo *info;
     int num_irq;
     qemu_irq irqs[QDEV_MAX_IRQ];
     qemu_irq *irqp[QDEV_MAX_IRQ];
@@ -25,17 +33,10 @@ struct SysBusDevice {
     } mmio[QDEV_MAX_MMIO];
 };
 
-typedef void (*sysbus_initfn)(SysBusDevice *dev);
-
 /* Macros to compensate for lack of type inheritance in C.  */
 #define sysbus_from_qdev(dev) ((SysBusDevice *)(dev))
 #define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
 
-typedef struct {
-    DeviceInfo qdev;
-    sysbus_initfn init;
-} SysBusDeviceInfo;
-
 void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
 void sysbus_register_withprop(const char *name, size_t size,
                               SysBusDeviceInfo *info);
diff --git a/pc-bios/boards/syborg.dts b/pc-bios/boards/syborg.dts
new file mode 100644
index 0000000..39745c7
--- /dev/null
+++ b/pc-bios/boards/syborg.dts
@@ -0,0 +1,134 @@
+/ {
+    #address-cells = <1>;
+    #size-cells  = <1>;
+
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        cpu0: ARM,Cortex-A8@0 {
+            device_type = "cpu";
+            reg = <0>;
+            #interrupt-cells = <1>;
+        };
+    };
+    memory@0 {
+        device_type = "memory";
+        reg = <0 08000000>;
+    };
+    syborg {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        qemu,fold-bus;
+        intc: intc@0 {
+            compatible = "syborg,interrupt";
+            #interrupt-cells = <1>;
+            reg = <c0000000>;
+            interrupt-controller;
+            interrupt-parent = <&cpu0>;
+            interrupts = <0>;
+            num-interrupts = <20>;
+        };
+        rtc@0 {
+            compatible = "syborg,rtc";
+            reg = <c0001000>;
+        };
+        timer@0 {
+            compatible = "syborg,timer";
+            reg = <c0002000>;
+            frequency = <d#1000000>;
+            interrupts = <1>;
+            interrupt-parent = <&intc>;
+        };
+        keyboard@0 {
+            compatible = "syborg,keyboard";
+            reg = <c0003000>;
+            interrupts = <2>;
+            interrupt-parent = <&intc>;
+        };
+        touchscreen@0 {
+            compatible = "syborg,pointer";
+            reg = <c0004000>;
+            interrupts = <3>;
+            interrupt-parent = <&intc>;
+        };
+        framebuffer@0 {
+            compatible = "syborg,framebuffer";
+            reg = <c0005000>;
+            interrupts = <4>;
+            interrupt-parent = <&intc>;
+        };
+        serial@0 {
+            device_type = "serial";
+            compatible = "syborg,serial";
+            chardev = "serial0";
+            reg = <c0006000>;
+            interrupts = <5>;
+            interrupt-parent = <&intc>;
+        };
+        serial@1 {
+            device_type = "serial";
+            compatible = "syborg,serial";
+            chardev = "serial1";
+            reg = <c0007000>;
+            interrupts = <6>;
+            interrupt-parent = <&intc>;
+        };
+        serial@2 {
+            device_type = "serial";
+            compatible = "syborg,serial";
+            chardev = "serial2";
+            reg = <c0008000>;
+            interrupts = <7>;
+            interrupt-parent = <&intc>;
+        };
+        serial@3 {
+            device_type = "serial";
+            compatible = "syborg,serial";
+            chardev = "serial3";
+            reg = <c0009000>;
+            interrupts = <8>;
+            interrupt-parent = <&intc>;
+        };
+/*
+        hostfs@0 {
+            compatible = "syborg,hostfs";
+            reg = <c000a000>;
+            host-path = "\\svphostfs\\";
+            drive-number = <d#19>;
+        };
+        ss@0 {
+            compatible = "syborg,snapshot";
+            reg = <c000b000>;
+        };
+*/
+        net@0 {
+            compatible = "syborg,virtio-net";
+            reg = <c000c000>;
+            interrupts = <9>;
+            interrupt-parent = <&intc>;
+        };
+/*
+        nand@0 {
+            compatible = "syborg,nand";
+            reg = <c000d000>;
+            size = <400>;
+        };
+        audio@0 {
+            compatible = "syborg,virtio-audio";
+            reg = <c000e000>;
+            interrupts = <a>;
+            interrupt-parent = <&intc>;
+        };
+        platform@0 {
+            compatible = "syborg,platform";
+            reg = <c1000000>;
+        };
+*/
+    };
+    chosen {
+        qemu {
+            bootstrap = "arm-linux";
+        };
+    };
+};
+
diff --git a/rules.mak b/rules.mak
index 8d6d96e..d332209 100644
--- a/rules.mak
+++ b/rules.mak
@@ -16,4 +16,7 @@ LINK = $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(1) $(ARLIBS_BEGIN) $(ARLIBS
 %.a:
 	$(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,"  AR    $(TARGET_DIR)$@")
 
+%.dtb: %.dts
+	$(call quiet-command,$(DTC) -O dtb -o $@ $<, "  DTC   $(TARGET_DIR)$@")
+
 quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1))
diff --git a/sysemu.h b/sysemu.h
index 658aeec..ec2961c 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -13,6 +13,7 @@ extern const char *bios_name;
 
 #define QEMU_FILE_TYPE_BIOS   0
 #define QEMU_FILE_TYPE_KEYMAP 1
+#define QEMU_FILE_TYPE_BOARD  2
 char *qemu_find_file(int type, const char *name);
 
 extern int vm_running;
@@ -274,4 +275,6 @@ int check_params(const char * const *params, const char *str);
 
 void register_devices(void);
 
+void qdev_do_late_init(void);
+
 #endif
diff --git a/vl.c b/vl.c
index f08f0f3..b5eb7e1 100644
--- a/vl.c
+++ b/vl.c
@@ -3477,11 +3477,21 @@ int qemu_register_machine(QEMUMachine *m)
 static QEMUMachine *find_machine(const char *name)
 {
     QEMUMachine *m;
+    char *filename;
+    char *buf;
 
     for(m = first_machine; m != NULL; m = m->next) {
         if (!strcmp(m->name, name))
             return m;
     }
+    buf = qemu_mallocz(strlen(name) + 5);
+    sprintf(buf, "%s.dtb", name);
+    filename = qemu_find_file(QEMU_FILE_TYPE_BOARD, buf);
+    qemu_free(buf);
+    if (filename) {
+        dt_machine.name = filename;
+        return &dt_machine;
+    }
     return NULL;
 }
 
@@ -4907,6 +4917,9 @@ char *qemu_find_file(int type, const char *name)
     case QEMU_FILE_TYPE_KEYMAP:
         subdir = "keymaps/";
         break;
+    case QEMU_FILE_TYPE_BOARD:
+        subdir = "boards/";
+        break;
     default:
         abort();
     }
@@ -4950,6 +4963,7 @@ int main(int argc, char **argv, char **envp)
     const char *loadvm = NULL;
     QEMUMachine *machine;
     const char *cpu_model;
+    const char *machine_name;
     const char *usb_devices[MAX_USB_CMDLINE];
     int usb_devices_index;
 #ifndef _WIN32
@@ -5001,7 +5015,7 @@ int main(int argc, char **argv, char **envp)
 #endif
 
     module_call_init(MODULE_INIT_MACHINE);
-    machine = find_default_machine();
+    machine_name = NULL;
     cpu_model = NULL;
     initrd_filename = NULL;
     ram_size = 0;
@@ -5085,17 +5099,7 @@ int main(int argc, char **argv, char **envp)
 
             switch(popt->index) {
             case QEMU_OPTION_M:
-                machine = find_machine(optarg);
-                if (!machine) {
-                    QEMUMachine *m;
-                    printf("Supported machines are:\n");
-                    for(m = first_machine; m != NULL; m = m->next) {
-                        printf("%-10s %s%s\n",
-                               m->name, m->desc,
-                               m->is_default ? " (default)" : "");
-                    }
-                    exit(*optarg != '?');
-                }
+                machine_name = optarg;
                 break;
             case QEMU_OPTION_cpu:
                 /* hw initialization will check this */
@@ -5703,6 +5707,22 @@ int main(int argc, char **argv, char **envp)
     }
 #endif
 
+    if (machine_name) {
+        machine = find_machine(machine_name);
+        if (!machine) {
+            QEMUMachine *m;
+            printf("Supported machines are:\n");
+            for(m = first_machine; m != NULL; m = m->next) {
+                printf("%-10s %s%s\n",
+                       m->name, m->desc,
+                       m->is_default ? " (default)" : "");
+            }
+            exit(*machine_name != '?');
+        }
+    } else {
+        machine = find_default_machine();
+    }
+
     machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
     if (smp_cpus > machine->max_cpus) {
         fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus "
@@ -6045,6 +6065,7 @@ int main(int argc, char **argv, char **envp)
     machine->init(ram_size, boot_devices,
                   kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
 
+    qdev_do_late_init();
 
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
         for (i = 0; i < nb_numa_nodes; i++) {

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

* [Qemu-devel] [PATCH 3/4] Stellaris machine config
  2009-06-10 17:38 [Qemu-devel] [PATCH 0/4] Machine config files Paul Brook
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 1/4] Include and build libfdt Paul Brook
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 2/4] Add device tree machine Paul Brook
@ 2009-06-10 17:38 ` Paul Brook
  2009-06-11  8:21   ` M P
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 4/4] Integrator " Paul Brook
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 61+ messages in thread
From: Paul Brook @ 2009-06-10 17:38 UTC (permalink / raw)
  To: qemu-devel

Replace hardcoded stellaris boards with machine configs

Signed-off-by: Paul Brook <paul@codesourcery.com>
---

 Makefile                       |    4 -
 Makefile.hw                    |    2 
 hw/arm-cpu.c                   |    3 
 hw/armv7m.c                    |   61 +++++++++
 hw/gpio-buttons.c              |  124 ++++++++++++++++++
 hw/pl011.c                     |    2 
 hw/pl061.c                     |   25 +++-
 hw/stellaris.c                 |  272 +++++++++-------------------------------
 hw/stellaris_enet.c            |    2 
 hw/stellaris_input.c           |   91 -------------
 pc-bios/boards/lm3s6965evb.dts |  212 +++++++++++++++++++++++++++++++
 pc-bios/boards/lm3s811evb.dts  |  155 +++++++++++++++++++++++
 12 files changed, 645 insertions(+), 308 deletions(-)
 create mode 100644 hw/gpio-buttons.c
 delete mode 100644 hw/stellaris_input.c
 create mode 100644 pc-bios/boards/lm3s6965evb.dts
 create mode 100644 pc-bios/boards/lm3s811evb.dts

diff --git a/Makefile b/Makefile
index 6d15c44..48a3ec3 100644
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ endif
 #######################################################################
 # Board descriptions
 
-BOARDS = syborg
+BOARDS = syborg lm3s811evb lm3s6965evb
 
 ifdef DTC
 BOARDS_BIN = $(BOARDS:%=pc-bios/boards/%.dtb)
@@ -115,7 +115,7 @@ OBJS+=readline.o console.o
 
 OBJS+=irq.o ptimer.o
 OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
-OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
+OBJS+=ssd0303.o ssd0323.o ads7846.o twl92230.o
 OBJS+=tmp105.o lm832x.o eeprom93xx.o tsc2005.o
 OBJS+=scsi-disk.o cdrom.o
 OBJS+=scsi-generic.o
diff --git a/Makefile.hw b/Makefile.hw
index 6accb3b..1953b85 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -28,6 +28,8 @@ OBJS+= lsi53c895a.o esp.o
 
 OBJS+= dma-helpers.o sysbus.o
 
+OBJS+= gpio-buttons.o
+
 all: $(HWLIB)
 # Dummy command so that make thinks it has done something
 	@true
diff --git a/hw/arm-cpu.c b/hw/arm-cpu.c
index c15eb12..4c128d1 100644
--- a/hw/arm-cpu.c
+++ b/hw/arm-cpu.c
@@ -17,7 +17,8 @@ static const struct {
     const char *cpuname;
 } cpu_device_name_map[] = {
     {"ARM,ARM926EJ-S", "arm926"},
-    {"ARM,Cortex-A8", "cortex-a8"}
+    {"ARM,Cortex-A8", "cortex-a8"},
+    {"ARM,Cortex-M3", "cortex-m3"}
 };
 
 typedef struct {
diff --git a/hw/armv7m.c b/hw/armv7m.c
index c3c5b9e..d74a2fb 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -10,6 +10,7 @@
 #include "sysbus.h"
 #include "arm-misc.h"
 #include "sysemu.h"
+#include "boards.h"
 
 /* Bitbanded IO.  Each word corresponds to a single bit.  */
 
@@ -149,6 +150,47 @@ static void armv7m_bitband_init(void)
 }
 
 /* Board init.  */
+/* Reset initialization and iage loading for ARMv7-M cores.  */
+static void armv7m_bootstrap(ram_addr_t ram_size, const char *boot_device,
+    const char *kernel_filename, const char *kernel_cmdline,
+    const char *initrd_filename)
+{
+    CPUState *env = first_cpu;
+    uint32_t pc;
+    int image_size;
+    uint64_t entry;
+    uint64_t lowaddr;
+
+    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
+    if (image_size < 0) {
+        image_size = load_image_targphys(kernel_filename, 0, ram_size);
+	lowaddr = 0;
+    }
+    if (image_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                kernel_filename);
+        exit(1);
+    }
+
+    /* If the image was loaded at address zero then assume it is a
+       regular ROM image and perform the normal CPU reset sequence.
+       Otherwise jump directly to the entry point.  */
+    if (lowaddr == 0) {
+	env->regs[13] = ldl_phys(0);
+	pc = ldl_phys(4);
+    } else {
+	pc = entry;
+    }
+    env->thumb = pc & 1;
+    env->regs[15] = pc & ~1;
+
+    /* Hack to map an additional page of ram at the top of the address
+       space.  This stops qemu complaining about executing code outside RAM
+       when returning from an exception.  */
+    cpu_register_physical_memory(0xfffff000, 0x1000,
+                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
+}
+
 /* Init CPU and memory for a v7-M based board.
    flash_size and sram_size are in kb.
    Returns the NVIC array.  */
@@ -238,10 +280,25 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
     return pic;
 }
 
+static SysBusDeviceInfo bitband_info = {
+    .init = bitband_init,
+    .qdev.props = (DevicePropList[]) {
+        {.name = "base", .type = PROP_TYPE_INT},
+        {.name = NULL}
+    }
+};
+
 static void armv7m_register_devices(void)
 {
-    sysbus_register_dev("ARM,bitband-memory", sizeof(BitBandState),
-                        bitband_init);
+    sysbus_register_withprop("ARM,bitband-memory", sizeof(BitBandState),
+                             &bitband_info);
 }
 
 device_init(armv7m_register_devices)
+
+static void armv7m_boot_register(void)
+{
+    register_machine_bootstrap("ARMv7-M", armv7m_bootstrap);
+}
+
+machine_init(armv7m_boot_register);
diff --git a/hw/gpio-buttons.c b/hw/gpio-buttons.c
new file mode 100644
index 0000000..0627818
--- /dev/null
+++ b/hw/gpio-buttons.c
@@ -0,0 +1,124 @@
+/*
+ * Buttons connected directly to GPIO pins.
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GNU GPL v2.
+ */
+#include "sysbus.h"
+#include "console.h"
+
+#define KEY_INVERT      0x80000000u
+#define KEY_CODE_MASK   0x0000ffffu
+
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq *irq;
+    const uint32_t *keys;
+    int *pressed;
+    int num_buttons;
+    int extension;
+} GPIOButtonsState;
+
+static void gpio_buttons_put_key(void *opaque, int keycode)
+{
+    GPIOButtonsState *s = (GPIOButtonsState *)opaque;
+    int i;
+    int down;
+
+    if (keycode == 0xe0 && !s->extension) {
+        s->extension = 0x80;
+        return;
+    }
+
+    down = (keycode & 0x80) == 0;
+    keycode = (keycode & 0x7f) | s->extension;
+
+    for (i = 0; i < s->num_buttons; i++) {
+        if ((s->keys[i] & KEY_CODE_MASK) == keycode
+                && s->pressed[i] != down) {
+            s->pressed[i] = down;
+            if (s->keys[i] & KEY_INVERT) {
+                qemu_set_irq(s->irq[i], !down);
+            } else {
+                qemu_set_irq(s->irq[i], down);
+            }
+        }
+    }
+
+    s->extension = 0;
+}
+
+static void gpio_buttons_save(QEMUFile *f, void *opaque)
+{
+    GPIOButtonsState *s = (GPIOButtonsState *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->extension);
+    for (i = 0; i < s->num_buttons; i++)
+        qemu_put_byte(f, s->pressed[i]);
+}
+
+static int gpio_buttons_load(QEMUFile *f, void *opaque, int version_id)
+{
+    GPIOButtonsState *s = (GPIOButtonsState *)opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->extension = qemu_get_be32(f);
+    for (i = 0; i < s->num_buttons; i++)
+        s->pressed[i] = qemu_get_byte(f);
+
+    return 0;
+}
+
+static void gpio_buttons_late_init(DeviceState *dev)
+{
+    GPIOButtonsState *s = FROM_SYSBUS(GPIOButtonsState, sysbus_from_qdev(dev));
+    int i;
+
+    for (i = 0; i < s->num_buttons; i++) {
+        if (s->keys[i] & KEY_INVERT) {
+            qemu_irq_raise(s->irq[i]);
+        }
+    }
+}
+
+static void gpio_buttons_init(SysBusDevice *dev)
+{
+    GPIOButtonsState *s = FROM_SYSBUS(GPIOButtonsState, dev);
+
+    s->num_buttons = qdev_get_prop_array(&dev->qdev, "keys", &s->keys);
+    if (s->num_buttons <= 0) {
+        hw_error("gpio-buttons: Missing keys property");
+    }
+
+    s->irq = qemu_mallocz(sizeof(qemu_irq) * s->num_buttons);
+    qdev_init_gpio_out(&dev->qdev, s->irq, s->num_buttons);
+    s->pressed = qemu_mallocz(sizeof(int) * s->num_buttons);
+    qemu_add_kbd_event_handler(gpio_buttons_put_key, s);
+    register_savevm("gpio-buttons", -1, 1,
+                    gpio_buttons_save, gpio_buttons_load, s);
+}
+
+static SysBusDeviceInfo gpio_buttons_info = {
+    .init = gpio_buttons_init,
+    .qdev.late_init = gpio_buttons_late_init,
+    .qdev.props = (DevicePropList[]) {
+        {.name = "keys", .type = PROP_TYPE_ARRAY},
+        {.name = NULL}
+    }
+};
+
+static void gpio_buttons_register_devices(void)
+{
+    /* ??? This isn't really attached to the system bus, but it's as good
+       a place as any to put it.  */
+    sysbus_register_withprop("qemu,gpio-buttons", sizeof(GPIOButtonsState),
+                             &gpio_buttons_info);
+}
+
+device_init(gpio_buttons_register_devices)
diff --git a/hw/pl011.c b/hw/pl011.c
index 3a1a4cb..f167bec 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -323,7 +323,7 @@ static void pl011_register_devices(void)
 {
     sysbus_register_dev("pl011", sizeof(pl011_state),
                         pl011_init_arm);
-    sysbus_register_dev("pl011_luminary", sizeof(pl011_state),
+    sysbus_register_dev("luminary,pl011", sizeof(pl011_state),
                         pl011_init_luminary);
 }
 
diff --git a/hw/pl061.c b/hw/pl061.c
index aa0a322..8e38bd6 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -291,6 +291,18 @@ static int pl061_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
+static void pl061_late_init(DeviceState *dev)
+{
+    pl061_state *s = FROM_SYSBUS(pl061_state, sysbus_from_qdev(dev));
+    int i;
+
+    for (i = 0; i < 8; i++) {
+        if (s->float_high & (1 << i)) {
+            qemu_irq_raise(s->out[i]);
+        }
+    }
+}
+
 static void pl061_init(SysBusDevice *dev)
 {
     int iomemtype;
@@ -302,14 +314,23 @@ static void pl061_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
     qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8);
     qdev_init_gpio_out(&dev->qdev, s->out, 8);
+    s->float_high = qdev_get_prop_int(&dev->qdev, "float-high", 0);
     pl061_reset(s);
     register_savevm("pl061_gpio", -1, 1, pl061_save, pl061_load, s);
 }
 
+static SysBusDeviceInfo pl061_info = {
+    .init = pl061_init,
+    .qdev.late_init = pl061_late_init,
+    .qdev.props = (DevicePropList[]) {
+        {.name = "float-high", .type = PROP_TYPE_INT},
+        {.name = NULL}
+    }
+};
 static void pl061_register_devices(void)
 {
-    sysbus_register_dev("pl061", sizeof(pl061_state),
-                        pl061_init);
+    sysbus_register_withprop("pl061", sizeof(pl061_state),
+                             &pl061_info);
 }
 
 device_init(pl061_register_devices)
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 38b9830..ba5b11f 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -361,6 +361,7 @@ static void stellaris_gptm_init(SysBusDevice *dev)
 /* System controller.  */
 
 typedef struct {
+    SysBusDevice busdev;
     uint32_t pborctl;
     uint32_t ldopctl;
     uint32_t int_status;
@@ -374,8 +375,12 @@ typedef struct {
     uint32_t ldoarst;
     uint32_t user0;
     uint32_t user1;
+    uint32_t did0;
+    uint32_t did1;
+    uint32_t dc[4];
     qemu_irq irq;
-    stellaris_board_info *board;
+    int got_mac;
+    DeviceState *netdev;
 } ssys_state;
 
 static void ssys_update(ssys_state *s)
@@ -421,25 +426,38 @@ static uint32_t pllcfg_fury[16] = {
     0xb11c /* 8.192 Mhz */
 };
 
+static void ssys_get_mac(ssys_state *s)
+{
+    uint8_t macaddr[6];
+
+    s->got_mac = 1;
+    if (!s->netdev) {
+        return;
+    }
+    qdev_get_macaddr(s->netdev, macaddr);
+    s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
+    s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
+}
+
 static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
 {
     ssys_state *s = (ssys_state *)opaque;
 
     switch (offset) {
     case 0x000: /* DID0 */
-        return s->board->did0;
+        return s->did0;
     case 0x004: /* DID1 */
-        return s->board->did1;
+        return s->did1;
     case 0x008: /* DC0 */
-        return s->board->dc0;
+        return s->dc[0];
     case 0x010: /* DC1 */
-        return s->board->dc1;
+        return s->dc[1];
     case 0x014: /* DC2 */
-        return s->board->dc2;
+        return s->dc[2];
     case 0x018: /* DC3 */
-        return s->board->dc3;
+        return s->dc[3];
     case 0x01c: /* DC4 */
-        return s->board->dc4;
+        return s->dc[4];
     case 0x030: /* PBORCTL */
         return s->pborctl;
     case 0x034: /* LDOPCTL */
@@ -464,7 +482,7 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
         {
             int xtal;
             xtal = (s->rcc >> 6) & 0xf;
-            if (s->board->did0 & (1 << 16)) {
+            if (s->did0 & (1 << 16)) {
                 return pllcfg_fury[xtal];
             } else {
                 return pllcfg_sandstorm[xtal];
@@ -493,8 +511,14 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
     case 0x160: /* LDOARST */
         return s->ldoarst;
     case 0x1e0: /* USER0 */
+        if (!s->got_mac) {
+            ssys_get_mac(s);
+        }
         return s->user0;
     case 0x1e4: /* USER1 */
+        if (!s->got_mac) {
+            ssys_get_mac(s);
+        }
         return s->user1;
     default:
         hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
@@ -654,23 +678,25 @@ static int ssys_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static void stellaris_sys_init(uint32_t base, qemu_irq irq,
-                               stellaris_board_info * board,
-                               uint8_t *macaddr)
+static void stellaris_sysctl_init(SysBusDevice *dev)
 {
     int iomemtype;
-    ssys_state *s;
-
-    s = (ssys_state *)qemu_mallocz(sizeof(ssys_state));
-    s->irq = irq;
-    s->board = board;
-    /* Most devices come preprogrammed with a MAC address in the user data. */
-    s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
-    s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
+    ssys_state *s = FROM_SYSBUS(ssys_state, dev);
 
     iomemtype = cpu_register_io_memory(0, ssys_readfn,
                                        ssys_writefn, s);
-    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
+    s->netdev = qdev_get_prop_dev(&dev->qdev, "enet");
+    s->got_mac = 0;
+    s->did0 = qdev_get_prop_int(&dev->qdev, "did0", 0);
+    s->did1 = qdev_get_prop_int(&dev->qdev, "did1", 0);
+    s->dc[0] = qdev_get_prop_int(&dev->qdev, "dc0", 0);
+    s->dc[1] = qdev_get_prop_int(&dev->qdev, "dc1", 0);
+    s->dc[2] = qdev_get_prop_int(&dev->qdev, "dc2", 0);
+    s->dc[3] = qdev_get_prop_int(&dev->qdev, "dc3", 0);
+    s->dc[4] = qdev_get_prop_int(&dev->qdev, "dc4", 0);
+
     ssys_reset(s);
     register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s);
 }
@@ -1256,200 +1282,30 @@ static void stellaris_ssi_bus_init(SSISlave *dev)
                     stellaris_ssi_bus_save, stellaris_ssi_bus_load, s);
 }
 
-/* Board init.  */
-static stellaris_board_info stellaris_boards[] = {
-  { "LM3S811EVB",
-    0,
-    0x0032000e,
-    0x001f001f, /* dc0 */
-    0x001132bf,
-    0x01071013,
-    0x3f0f01ff,
-    0x0000001f,
-    BP_OLED_I2C
-  },
-  { "LM3S6965EVB",
-    0x10010002,
-    0x1073402e,
-    0x00ff007f, /* dc0 */
-    0x001133ff,
-    0x030f5317,
-    0x0f0f87ff,
-    0x5000007f,
-    BP_OLED_SSI | BP_GAMEPAD
-  }
-};
-
-static void stellaris_init(const char *kernel_filename, const char *cpu_model,
-                           stellaris_board_info *board)
-{
-    static const int uart_irq[] = {5, 6, 33, 34};
-    static const int timer_irq[] = {19, 21, 23, 35};
-    static const uint32_t gpio_addr[7] =
-      { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
-        0x40024000, 0x40025000, 0x40026000};
-    static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
-
-    qemu_irq *pic;
-    DeviceState *gpio_dev[7];
-    qemu_irq gpio_in[7][8];
-    qemu_irq gpio_out[7][8];
-    qemu_irq adc;
-    int sram_size;
-    int flash_size;
-    i2c_bus *i2c;
-    DeviceState *dev;
-    int i;
-    int j;
-
-    flash_size = ((board->dc0 & 0xffff) + 1) << 1;
-    sram_size = (board->dc0 >> 18) + 1;
-    pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
-
-    if (board->dc1 & (1 << 16)) {
-        dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
-                                    pic[14], pic[15], pic[16], pic[17], NULL);
-        adc = qdev_get_gpio_in(dev, 0);
-    } else {
-        adc = NULL;
-    }
-    for (i = 0; i < 4; i++) {
-        if (board->dc2 & (0x10000 << i)) {
-            dev = sysbus_create_simple("stellaris-gptm",
-                                       0x40030000 + i * 0x1000,
-                                       pic[timer_irq[i]]);
-            /* TODO: This is incorrect, but we get away with it because
-               the ADC output is only ever pulsed.  */
-            qdev_connect_gpio_out(dev, 0, adc);
-        }
-    }
-
-    stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
-
-    for (i = 0; i < 7; i++) {
-        if (board->dc4 & (1 << i)) {
-            gpio_dev[i] = sysbus_create_simple("pl061", gpio_addr[i],
-                                               pic[gpio_irq[i]]);
-            for (j = 0; j < 8; j++) {
-                gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
-                gpio_out[i][j] = NULL;
-            }
-        }
-    }
-
-    if (board->dc2 & (1 << 12)) {
-        dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
-        i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
-        if (board->peripherals & BP_OLED_I2C) {
-            i2c_create_slave(i2c, "ssd0303", 0x3d);
-        }
-    }
-
-    for (i = 0; i < 4; i++) {
-        if (board->dc2 & (1 << i)) {
-            sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
-                                 pic[uart_irq[i]]);
-        }
-    }
-    if (board->dc2 & (1 << 4)) {
-        dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
-        if (board->peripherals & BP_OLED_SSI) {
-            DeviceState *mux;
-            void *bus;
-
-            bus = qdev_get_child_bus(dev, "ssi");
-            mux = ssi_create_slave(bus, "evb6965-ssi");
-            gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
-
-            bus = qdev_get_child_bus(mux, "ssi0");
-            dev = ssi_create_slave(bus, "ssi-sd");
-
-            bus = qdev_get_child_bus(mux, "ssi1");
-            dev = ssi_create_slave(bus, "ssd0323");
-            gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
-
-            /* Make sure the select pin is high.  */
-            qemu_irq_raise(gpio_out[GPIO_D][0]);
-        }
-    }
-    if (board->dc4 & (1 << 28)) {
-        DeviceState *enet;
-
-        qemu_check_nic_model(&nd_table[0], "stellaris");
-
-        enet = qdev_create(NULL, "stellaris_enet");
-        qdev_set_netdev(enet, &nd_table[0]);
-        qdev_init(enet);
-        sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
-        sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
-    }
-    if (board->peripherals & BP_GAMEPAD) {
-        qemu_irq gpad_irq[5];
-        static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
-
-        gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
-        gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
-        gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
-        gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
-        gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
-
-        stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
-    }
-    for (i = 0; i < 7; i++) {
-        if (board->dc4 & (1 << i)) {
-            for (j = 0; j < 8; j++) {
-                if (gpio_out[i][j]) {
-                    qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
-                }
-            }
-        }
-    }
-}
-
-/* FIXME: Figure out how to generate these from stellaris_boards.  */
-static void lm3s811evb_init(ram_addr_t ram_size,
-                     const char *boot_device,
-                     const char *kernel_filename, const char *kernel_cmdline,
-                     const char *initrd_filename, const char *cpu_model)
-{
-    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
-}
-
-static void lm3s6965evb_init(ram_addr_t ram_size,
-                     const char *boot_device,
-                     const char *kernel_filename, const char *kernel_cmdline,
-                     const char *initrd_filename, const char *cpu_model)
-{
-    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
-}
-
-static QEMUMachine lm3s811evb_machine = {
-    .name = "lm3s811evb",
-    .desc = "Stellaris LM3S811EVB",
-    .init = lm3s811evb_init,
-};
-
-static QEMUMachine lm3s6965evb_machine = {
-    .name = "lm3s6965evb",
-    .desc = "Stellaris LM3S6965EVB",
-    .init = lm3s6965evb_init,
-};
-
-static void stellaris_machine_init(void)
-{
-    qemu_register_machine(&lm3s811evb_machine);
-    qemu_register_machine(&lm3s6965evb_machine);
-}
-
-machine_init(stellaris_machine_init);
-
 static SSISlaveInfo stellaris_ssi_bus_info = {
     .init = stellaris_ssi_bus_init,
     .transfer = stellaris_ssi_bus_transfer
 };
 
+static SysBusDeviceInfo ssys_info = {
+    .init = stellaris_sysctl_init,
+    .qdev.props = (DevicePropList[]) {
+        {.name = "enet", .type = PROP_TYPE_DEV},
+        {.name = "did0", .type = PROP_TYPE_INT},
+        {.name = "did1", .type = PROP_TYPE_INT},
+        {.name = "dc0", .type = PROP_TYPE_INT},
+        {.name = "dc1", .type = PROP_TYPE_INT},
+        {.name = "dc2", .type = PROP_TYPE_INT},
+        {.name = "dc3", .type = PROP_TYPE_INT},
+        {.name = "dc4", .type = PROP_TYPE_INT},
+        {.name = NULL}
+    }
+};
+
 static void stellaris_register_devices(void)
 {
+    sysbus_register_withprop("stellaris-sysctl", sizeof(ssys_state),
+                             &ssys_info);
     sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
                         stellaris_i2c_init);
     sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 36fabd3..86df231 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -417,7 +417,7 @@ static void stellaris_enet_init(SysBusDevice *dev)
 
 static void stellaris_enet_register_devices(void)
 {
-    sysbus_register_dev("stellaris_enet", sizeof(stellaris_enet_state),
+    sysbus_register_dev("stellaris-enet", sizeof(stellaris_enet_state),
                         stellaris_enet_init);
 }
 
diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c
deleted file mode 100644
index 33395a4..0000000
--- a/hw/stellaris_input.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Gamepad style buttons connected to IRQ/GPIO lines
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GPL.
- */
-#include "hw.h"
-#include "devices.h"
-#include "console.h"
-
-typedef struct {
-    qemu_irq irq;
-    int keycode;
-    int pressed;
-} gamepad_button;
-
-typedef struct {
-    gamepad_button *buttons;
-    int num_buttons;
-    int extension;
-} gamepad_state;
-
-static void stellaris_gamepad_put_key(void * opaque, int keycode)
-{
-    gamepad_state *s = (gamepad_state *)opaque;
-    int i;
-    int down;
-
-    if (keycode == 0xe0 && !s->extension) {
-        s->extension = 0x80;
-        return;
-    }
-
-    down = (keycode & 0x80) == 0;
-    keycode = (keycode & 0x7f) | s->extension;
-
-    for (i = 0; i < s->num_buttons; i++) {
-        if (s->buttons[i].keycode == keycode
-                && s->buttons[i].pressed != down) {
-            s->buttons[i].pressed = down;
-            qemu_set_irq(s->buttons[i].irq, down);
-        }
-    }
-
-    s->extension = 0;
-}
-
-static void stellaris_gamepad_save(QEMUFile *f, void *opaque)
-{
-    gamepad_state *s = (gamepad_state *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->extension);
-    for (i = 0; i < s->num_buttons; i++)
-        qemu_put_byte(f, s->buttons[i].pressed);
-}
-
-static int stellaris_gamepad_load(QEMUFile *f, void *opaque, int version_id)
-{
-    gamepad_state *s = (gamepad_state *)opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->extension = qemu_get_be32(f);
-    for (i = 0; i < s->num_buttons; i++)
-        s->buttons[i].pressed = qemu_get_byte(f);
-
-    return 0;
-}
-
-/* Returns an array 5 ouput slots.  */
-void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
-{
-    gamepad_state *s;
-    int i;
-
-    s = (gamepad_state *)qemu_mallocz(sizeof (gamepad_state));
-    s->buttons = (gamepad_button *)qemu_mallocz(n * sizeof (gamepad_button));
-    for (i = 0; i < n; i++) {
-        s->buttons[i].irq = irq[i];
-        s->buttons[i].keycode = keycode[i];
-    }
-    s->num_buttons = n;
-    qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
-    register_savevm("stellaris_gamepad", -1, 1,
-                    stellaris_gamepad_save, stellaris_gamepad_load, s);
-}
diff --git a/pc-bios/boards/lm3s6965evb.dts b/pc-bios/boards/lm3s6965evb.dts
new file mode 100644
index 0000000..9bc0128
--- /dev/null
+++ b/pc-bios/boards/lm3s6965evb.dts
@@ -0,0 +1,212 @@
+/ {
+    #address-cells = <1>;
+    #size-cells  = <1>;
+
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        cpu0: ARM,Cortex-M3@0 {
+            device_type = "cpu";
+            reg = <0>;
+            #interrupt-cells = <1>;
+            nvic = <&nvic>;
+        };
+    };
+    flash@0 {
+        device_type = "rom";
+        reg = <00000000 00040000>;
+    };
+    memory@0 {
+        device_type = "memory";
+        reg = <20000000 00010000>;
+    };
+    bitband@0 {
+        model = "ARM,bitband-memory";
+        reg = <22000000 02000000>;
+        base = <20000000>;
+    };
+    bitband@1 {
+        model = "ARM,bitband-memory";
+        reg = <42000000 02000000>;
+        base = <40000000>;
+    };
+    nvic: nvic@0 {
+        model = "armv7m_nvic";
+        interrupt-parent = <&cpu0>;
+        interrupts = <0>;
+        interrupt-controller;
+        #interrupt-cells = <1>;
+    };
+    lm3s6965@0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        qemu,fold-bus;
+        // TODO Watchdog at 0x40000000
+        gpioA: gpio@0 {
+            model = "pl061";
+            reg = <40004000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <0>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        gpioB: gpio@1 {
+            model = "pl061";
+            reg = <40005000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <1>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        gpioC: gpio@2 {
+            model = "pl061";
+            reg = <40006000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <2>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 &oled 0>;
+        };
+        gpioD: gpio@3 {
+            model = "pl061";
+            reg = <40007000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <3>;
+            qemu,gpio = <&ssimux 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+            float-high = <01>;
+        };
+        ssi@0 {
+            model = "pl022";
+            reg = <40008000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <7>;
+            ssimux: mux@0 {
+                model = "evb6965-ssi";
+                sd@0 {
+                    model = "ssi-sd";
+                    qemu,parent-bus = "ssi0";
+                };
+                oled: oled@1 {
+                    model = "ssd0323";
+                    qemu,parent-bus = "ssi1";
+                };
+            };
+        };
+        uart@0 {
+            model = "luminary,pl011";
+            reg = <4000c000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <5>;
+        };
+        uart@1 {
+            model = "luminary,pl011";
+            reg = <4000d000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <6>;
+        };
+        uart@2 {
+            model = "luminary,pl011";
+            reg = <4000e000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#33>;
+        };
+        i2c@0 {
+            model = "stellaris-i2c";
+            reg = <40020000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <8>;
+        };
+        i2c@1 {
+            model = "stellaris-i2c";
+            reg = <40021000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#37>;
+        };
+        gpioE: gpio@4 {
+            model = "pl061";
+            reg = <40024000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <4>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        gpioF: gpio@5 {
+            model = "pl061";
+            reg = <40025000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#30>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        gpioG: gpio@6 {
+            model = "pl061";
+            reg = <40026000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#31>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        // TODO PWM at 0x40028000
+        // TODO QEI0 at 0x4002c000
+        // TODO QEI1 at 0x4002d000
+        gptm@0 {
+            model = "stellaris-gptm";
+            reg = <40030000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#19>;
+            qemu,gpio = <&adc0 0>;
+        };
+        gptm@1 {
+            model = "stellaris-gptm";
+            reg = <40031000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#21>;
+            qemu,gpio = <&adc0 0>;
+        };
+        gptm@2 {
+            model = "stellaris-gptm";
+            reg = <40032000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#23>;
+            qemu,gpio = <&adc0 0>;
+        };
+        gptm@3 {
+            model = "stellaris-gptm";
+            reg = <40033000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#35>;
+            qemu,gpio = <&adc0 0>;
+        };
+        adc0: adc@0 {
+            model = "stellaris-adc";
+            reg = <40038000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#14 d#15 d#16 d#17>;
+        };
+        // TODO Comparator at 0x4003c000
+        enet: enet@0 {
+            model = "stellaris-enet";
+            reg = <40048000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#42>;
+        };
+        // TODO Hybernation module at 0x400fc000
+        sysctl@0 {
+            model = "stellaris-sysctl";
+            reg = <400fe000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#28>;
+            did0 = <10010002>;
+            did1 = <1073402e>;
+            dc0 = <00ff007f>;
+            dc1 = <001133ff>;
+            dc2 = <030f5317>;
+            dc3 = <0f0f87ff>;
+            dc4 = <5000007f>;
+            enet = <&enet>;
+        };
+        buttons@0 {
+            model = "qemu,gpio-buttons";
+            keys = <800000c8 800000d0 800000cb 800000cd 8000001d>;
+            qemu,gpio = <&gpioE 0 &gpioE 1 &gpioE 2 &gpioE 3 &gpioF 1>;
+        };
+    };
+    chosen {
+        qemu {
+            bootstrap = "ARMv7-M";
+        };
+    };
+};
diff --git a/pc-bios/boards/lm3s811evb.dts b/pc-bios/boards/lm3s811evb.dts
new file mode 100644
index 0000000..977d080
--- /dev/null
+++ b/pc-bios/boards/lm3s811evb.dts
@@ -0,0 +1,155 @@
+/ {
+    #address-cells = <1>;
+    #size-cells  = <1>;
+
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        cpu0: ARM,Cortex-M3@0 {
+            device_type = "cpu";
+            reg = <0>;
+            #interrupt-cells = <1>;
+            nvic = <&nvic>;
+        };
+    };
+    flash@0 {
+        device_type = "rom";
+        reg = <00000000 00010000>;
+    };
+    memory@0 {
+        device_type = "memory";
+        reg = <20000000 00002000>;
+    };
+    bitband@0 {
+        model = "ARM,bitband-memory";
+        reg = <22000000 02000000>;
+        base = <20000000>;
+    };
+    bitband@1 {
+        model = "ARM,bitband-memory";
+        reg = <42000000 02000000>;
+        base = <40000000>;
+    };
+    nvic: nvic@0 {
+        model = "armv7m_nvic";
+        interrupt-parent = <&cpu0>;
+        interrupts = <0>;
+        interrupt-controller;
+        #interrupt-cells = <1>;
+    };
+    lm3s811@0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        qemu,fold-bus;
+        // TODO Watchdog at 0x40000000
+        gpioA: gpio@0 {
+            model = "pl061";
+            reg = <40004000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <0>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        gpioB: gpio@1 {
+            model = "pl061";
+            reg = <40005000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <1>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        gpioC: gpio@2 {
+            model = "pl061";
+            reg = <40006000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <2>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        gpioD: gpio@3 {
+            model = "pl061";
+            reg = <40007000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <3>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        ssi@0 {
+            model = "pl022";
+            reg = <40008000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <7>;
+        };
+        uart@0 {
+            model = "luminary,pl011";
+            reg = <4000c000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <5>;
+        };
+        uart@1 {
+            model = "luminary,pl011";
+            reg = <4000d000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <6>;
+        };
+        i2c@0 {
+            model = "stellaris-i2c";
+            reg = <40020000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <8>;
+            oled@0 {
+                model = "ssd0303";
+                address = <3d>;
+            };
+        };
+        gpioE: gpio@4 {
+            model = "pl061";
+            reg = <40024000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <4>;
+            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+        };
+        // TODO PWM at 0x40028000
+        gptm@0 {
+            model = "stellaris-gptm";
+            reg = <40030000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#19>;
+            qemu,gpio = <&adc0 0>;
+        };
+        gptm@1 {
+            model = "stellaris-gptm";
+            reg = <40031000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#21>;
+            qemu,gpio = <&adc0 0>;
+        };
+        gptm@2 {
+            model = "stellaris-gptm";
+            reg = <40032000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#23>;
+            qemu,gpio = <&adc0 0>;
+        };
+        adc0: adc@0 {
+            model = "stellaris-adc";
+            reg = <40038000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#14 d#15 d#16 d#17>;
+        };
+        sysctl@0 {
+            model = "stellaris-sysctl";
+            reg = <400fe000>;
+            interrupt-parent = <&nvic>;
+            interrupts = <d#28>;
+            did0 = <00000000>;
+            did1 = <0032000e>;
+            dc0 = <001f001f>;
+            dc1 = <001132bf>;
+            dc2 = <01071013>;
+            dc3 = <3f0f01ff>;
+            dc4 = <0000001f>;
+        };
+    };
+    chosen {
+        qemu {
+            bootstrap = "ARMv7-M";
+        };
+    };
+};

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

* [Qemu-devel] [PATCH 4/4] Integrator machine config
  2009-06-10 17:38 [Qemu-devel] [PATCH 0/4] Machine config files Paul Brook
                   ` (2 preceding siblings ...)
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 3/4] Stellaris machine config Paul Brook
@ 2009-06-10 17:38 ` Paul Brook
  2009-06-11  9:54 ` [Qemu-devel] [PATCH 0/4] Machine config files Gerd Hoffmann
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 61+ messages in thread
From: Paul Brook @ 2009-06-10 17:38 UTC (permalink / raw)
  To: qemu-devel

Replace integrator board with machine config

Signed-off-by: Paul Brook <paul@codesourcery.com>
---

 Makefile                         |    2 -
 hw/arm_timer.c                   |    2 -
 hw/integratorcp.c                |   97 ++++------------------------------
 pc-bios/boards/integrator-cp.dts |  110 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 124 insertions(+), 87 deletions(-)
 create mode 100644 pc-bios/boards/integrator-cp.dts

diff --git a/Makefile b/Makefile
index 48a3ec3..5cc346e 100644
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ endif
 #######################################################################
 # Board descriptions
 
-BOARDS = syborg lm3s811evb lm3s6965evb
+BOARDS = syborg lm3s811evb lm3s6965evb integrator-cp
 
 ifdef DTC
 BOARDS_BIN = $(BOARDS:%=pc-bios/boards/%.dtb)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 226ecc4..6570929 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -347,7 +347,7 @@ static void icp_pit_init(SysBusDevice *dev)
 
 static void arm_timer_register_devices(void)
 {
-    sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
+    sysbus_register_dev("integrator-pit", sizeof(icp_pit_state), icp_pit_init);
     sysbus_register_dev("sp804", sizeof(sp804_state), sp804_init);
 }
 
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index b6fbe15..849f0b4 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -429,104 +429,31 @@ static CPUWriteMemoryFunc *icp_control_writefn[] = {
    icp_control_write
 };
 
-static void icp_control_init(uint32_t base)
+static void icp_control_init(SysBusDevice *dev)
 {
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(0, icp_control_readfn,
                                        icp_control_writefn, NULL);
-    cpu_register_physical_memory(base, 0x00800000, iomemtype);
+    sysbus_init_mmio(dev, 0x00800000, iomemtype);
     /* ??? Save/restore.  */
 }
 
-
-/* Board init.  */
-
-static struct arm_boot_info integrator_binfo = {
-    .loader_start = 0x0,
-    .board_id = 0x113,
-};
-
-static void integratorcp_init(ram_addr_t ram_size,
-                     const char *boot_device,
-                     const char *kernel_filename, const char *kernel_cmdline,
-                     const char *initrd_filename, const char *cpu_model)
-{
-    CPUState *env;
-    ram_addr_t ram_offset;
-    qemu_irq pic[32];
-    qemu_irq *cpu_pic;
-    DeviceState *dev;
-    int i;
-
-    if (!cpu_model)
-        cpu_model = "arm926";
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to find CPU definition\n");
-        exit(1);
-    }
-    ram_offset = qemu_ram_alloc(ram_size);
-    /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
-    /* ??? RAM should repeat to fill physical memory space.  */
-    /* SDRAM at address zero*/
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
-    /* And again at address 0x80000000 */
-    cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM);
-
-    dev = qdev_create(NULL, "integrator_core");
-    qdev_set_prop_int(dev, "memsz", ram_size >> 20);
-    qdev_init(dev);
-    sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
-
-    cpu_pic = arm_pic_init_cpu(env);
-    dev = sysbus_create_varargs("integrator_pic", 0x14000000,
-                                cpu_pic[ARM_PIC_CPU_IRQ],
-                                cpu_pic[ARM_PIC_CPU_FIQ], NULL);
-    for (i = 0; i < 32; i++) {
-        pic[i] = qdev_get_gpio_in(dev, i);
+static SysBusDeviceInfo integratorcm_info = {
+    .init = integratorcm_init,
+    .qdev.props = (DevicePropList[]) {
+        {.name = "memsz", .type = PROP_TYPE_INT},
+        {.name = NULL}
     }
-    sysbus_create_simple("integrator_pic", 0xca000000, pic[26]);
-    sysbus_create_varargs("integrator_pit", 0x13000000,
-                          pic[5], pic[6], pic[7], NULL);
-    sysbus_create_simple("pl031", 0x15000000, pic[8]);
-    sysbus_create_simple("pl011", 0x16000000, pic[1]);
-    sysbus_create_simple("pl011", 0x17000000, pic[2]);
-    icp_control_init(0xcb000000);
-    sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
-    sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
-    sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
-    if (nd_table[0].vlan)
-        smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
-
-    sysbus_create_simple("pl110", 0xc0000000, pic[22]);
-
-    integrator_binfo.ram_size = ram_size;
-    integrator_binfo.kernel_filename = kernel_filename;
-    integrator_binfo.kernel_cmdline = kernel_cmdline;
-    integrator_binfo.initrd_filename = initrd_filename;
-    arm_load_kernel(env, &integrator_binfo);
-}
-
-static QEMUMachine integratorcp_machine = {
-    .name = "integratorcp",
-    .desc = "ARM Integrator/CP (ARM926EJ-S)",
-    .init = integratorcp_init,
-    .is_default = 1,
 };
 
-static void integratorcp_machine_init(void)
-{
-    qemu_register_machine(&integratorcp_machine);
-}
-
-machine_init(integratorcp_machine_init);
-
 static void integratorcp_register_devices(void)
 {
-    sysbus_register_dev("integrator_pic", sizeof(icp_pic_state), icp_pic_init);
-    sysbus_register_dev("integrator_core", sizeof(integratorcm_state),
-                        integratorcm_init);
+    sysbus_register_dev("integrator-pic", sizeof(icp_pic_state), icp_pic_init);
+    sysbus_register_dev("integrator-control", sizeof(SysBusDevice),
+                        icp_control_init);
+    sysbus_register_withprop("integrator-core", sizeof(integratorcm_state),
+                             &integratorcm_info);
 }
 
 device_init(integratorcp_register_devices)
diff --git a/pc-bios/boards/integrator-cp.dts b/pc-bios/boards/integrator-cp.dts
new file mode 100644
index 0000000..6ff27b4
--- /dev/null
+++ b/pc-bios/boards/integrator-cp.dts
@@ -0,0 +1,110 @@
+/ {
+    #address-cells = <1>;
+    #size-cells  = <1>;
+
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        cpu0: ARM,ARM926EJ-S@0 {
+            device_type = "cpu";
+            reg = <0>;
+            #interrupt-cells = <1>;
+        };
+    };
+    memory@0 {
+        device_type = "memory";
+        reg = <0 08000000>;
+        qemu,alias = <80000000>;
+    };
+    integrator-cp@0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        qemu,fold-bus;
+        core-module@0 {
+            model = "integrator-core";
+            memsz = <d#128>;
+            reg = <10000000>;
+        };
+        pic: intc@0 {
+            model = "integrator-pic";
+            #interrupt-cells = <1>;
+            reg = <14000000>;
+            interrupt-controller;
+            interrupt-parent = <&cpu0>;
+            interrupts = <0 1>;
+        };
+        intc@1 {
+            model = "integrator-pic";
+            #interrupt-cells = <1>;
+            reg = <ca000000>;
+            interrupt-controller;
+            interrupt-parent = <&pic>;
+            interrupts = <d#26 ffffffff>;
+        };
+        timer@0 {
+            model = "integrator-pit";
+            reg = <13000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#5 d#6 d#7>;
+        };
+        rtc@0 {
+            model = "pl031";
+            reg = <15000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#8>;
+        };
+        uart@0 {
+            model = "pl011";
+            reg = <16000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#1>;
+        };
+        uart@1 {
+            model = "pl011";
+            reg = <17000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#2>;
+        };
+        keyboard@0 {
+            model = "pl050_keyboard";
+            reg = <18000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#3>;
+        };
+        mouse@0 {
+            model = "pl050_mouse";
+            reg = <19000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#4>;
+        };
+        sd@0 {
+            model = "pl181";
+            reg = <1c000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#23 d#24>;
+        };
+        lcd@0 {
+            model = "pl110";
+            reg = <c0000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#22>;
+        };
+        nic@0 {
+            model = "smc91c111";
+            reg = <c8000000>;
+            interrupt-parent = <&pic>;
+            interrupts = <d#27>;
+        };
+        control@0 {
+            model = "integrator-control";
+            reg = <cb000000>;
+        };
+    };
+    chosen {
+        qemu {
+            bootstrap = "arm-linux";
+            board-id = <113>;
+        };
+    };
+};
+

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

* Re: [Qemu-devel] [PATCH 2/4] Add device tree machine
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 2/4] Add device tree machine Paul Brook
@ 2009-06-10 18:30   ` Blue Swirl
  2009-06-10 19:10     ` Paul Brook
  2009-06-11 13:22   ` Gerd Hoffmann
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 61+ messages in thread
From: Blue Swirl @ 2009-06-10 18:30 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

On 6/10/09, Paul Brook <paul@codesourcery.com> wrote:
> FDT based machine creation.
>  When -M foo is specified look for and use foo.fdb.
>  Build and ship board configs.

Cool.

>   if test "$preadv" = "yes" ; then
>  -  echo "#define HAVE_PREADV 1" >> $config_h
>  +  echo "#defne HAVE_PREADV 1" >> $config_h

#defne?

>  +    buf = qemu_mallocz(strlen(name) + 5);
>  +    sprintf(buf, "%s.dtb", name);

snprintf?

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

* Re: [Qemu-devel] [PATCH 1/4] Include and build libfdt
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 1/4] Include and build libfdt Paul Brook
@ 2009-06-10 19:08   ` Glauber Costa
  2009-06-10 19:23     ` Anthony Liguori
                       ` (2 more replies)
  0 siblings, 3 replies; 61+ messages in thread
From: Glauber Costa @ 2009-06-10 19:08 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

On Wed, Jun 10, 2009 at 06:38:12PM +0100, Paul Brook wrote:
> Inlcude libfdt in source tree, and build it if not already available.
what makes libfdt different than everything else that we link with?
Why do we have to have a in-tree copy of that?

 

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

* Re: [Qemu-devel] [PATCH 2/4] Add device tree machine
  2009-06-10 18:30   ` Blue Swirl
@ 2009-06-10 19:10     ` Paul Brook
  0 siblings, 0 replies; 61+ messages in thread
From: Paul Brook @ 2009-06-10 19:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Blue Swirl

> >   if test "$preadv" = "yes" ; then
> >  -  echo "#define HAVE_PREADV 1" >> $config_h
> >  +  echo "#defne HAVE_PREADV 1" >> $config_h
>
> #defne?

Oops. I've sure I've already fixed that at least twice...

> >  +    buf = qemu_mallocz(strlen(name) + 5);
> >  +    sprintf(buf, "%s.dtb", name);
>
> snprintf?

Bah. Stoopid paranoid OpenBSD. :-)

Paul

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

* Re: [Qemu-devel] [PATCH 1/4] Include and build libfdt
  2009-06-10 19:08   ` Glauber Costa
@ 2009-06-10 19:23     ` Anthony Liguori
  2009-06-10 19:27     ` Paul Brook
  2009-06-10 19:34     ` Blue Swirl
  2 siblings, 0 replies; 61+ messages in thread
From: Anthony Liguori @ 2009-06-10 19:23 UTC (permalink / raw)
  To: Glauber Costa; +Cc: Paul Brook, Hollis Blanchard, qemu-devel

Glauber Costa wrote:
> On Wed, Jun 10, 2009 at 06:38:12PM +0100, Paul Brook wrote:
>   
>> Inlcude libfdt in source tree, and build it if not already available.
>>     
> what makes libfdt different than everything else that we link with?
> Why do we have to have a in-tree copy of that?
>   

Yeah, I had the same comment and withheld it while I considered it.

libfdt isn't widely available as a distro package. Historically, it's 
been part of dtc and not available for independent download/installation.

It's a tough call.

Regards,

Anthony Liguori

>  
>
>
>   

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

* Re: [Qemu-devel] [PATCH 1/4] Include and build libfdt
  2009-06-10 19:08   ` Glauber Costa
  2009-06-10 19:23     ` Anthony Liguori
@ 2009-06-10 19:27     ` Paul Brook
  2009-06-10 19:41       ` Glauber Costa
  2009-06-10 22:32       ` Edgar E. Iglesias
  2009-06-10 19:34     ` Blue Swirl
  2 siblings, 2 replies; 61+ messages in thread
From: Paul Brook @ 2009-06-10 19:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Glauber Costa

On Wednesday 10 June 2009, Glauber Costa wrote:
> On Wed, Jun 10, 2009 at 06:38:12PM +0100, Paul Brook wrote:
> > Inlcude libfdt in source tree, and build it if not already available.
>
> what makes libfdt different than everything else that we link with?
> Why do we have to have a in-tree copy of that?

AFAIK libfdt is still absent from current releases of common mainstream 
distros[1], and qemu is going to become increasingly useless without it.

c.f. dtc where we use the system version.

Paul

[1] We can argue about what constitutes sufficiently wide acceptance, but IMHO 
Fedora, Ubuntu and Debian Sid would be a fairly good start.

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

* Re: [Qemu-devel] [PATCH 1/4] Include and build libfdt
  2009-06-10 19:08   ` Glauber Costa
  2009-06-10 19:23     ` Anthony Liguori
  2009-06-10 19:27     ` Paul Brook
@ 2009-06-10 19:34     ` Blue Swirl
  2 siblings, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-06-10 19:34 UTC (permalink / raw)
  To: Glauber Costa; +Cc: Paul Brook, qemu-devel

On 6/10/09, Glauber Costa <glommer@redhat.com> wrote:
> On Wed, Jun 10, 2009 at 06:38:12PM +0100, Paul Brook wrote:
>  > Inlcude libfdt in source tree, and build it if not already available.
>
> what makes libfdt different than everything else that we link with?
>  Why do we have to have a in-tree copy of that?

Maybe libfdt is already shipping by your distro, but is it available
on Windows, OSX, *Solaris, *BSD, Haiku etc.?

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

* Re: [Qemu-devel] [PATCH 1/4] Include and build libfdt
  2009-06-10 19:27     ` Paul Brook
@ 2009-06-10 19:41       ` Glauber Costa
  2009-06-10 20:38         ` Paul Brook
  2009-06-10 22:32       ` Edgar E. Iglesias
  1 sibling, 1 reply; 61+ messages in thread
From: Glauber Costa @ 2009-06-10 19:41 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

On Wed, Jun 10, 2009 at 08:27:30PM +0100, Paul Brook wrote:
> On Wednesday 10 June 2009, Glauber Costa wrote:
> > On Wed, Jun 10, 2009 at 06:38:12PM +0100, Paul Brook wrote:
> > > Inlcude libfdt in source tree, and build it if not already available.
> >
> > what makes libfdt different than everything else that we link with?
> > Why do we have to have a in-tree copy of that?
> 
> AFAIK libfdt is still absent from current releases of common mainstream 
> distros[1], and qemu is going to become increasingly useless without it.
This is an argument for both including it in our source release,
and pushing it to get shipped as a stand alone package. I believe the later
is a much more sane approach long term

> 
> c.f. dtc where we use the system version.
> 
> Paul
> 
> [1] We can argue about what constitutes sufficiently wide acceptance, but IMHO 
> Fedora, Ubuntu and Debian Sid would be a fairly good start.

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

* Re: [Qemu-devel] [PATCH 1/4] Include and build libfdt
  2009-06-10 19:41       ` Glauber Costa
@ 2009-06-10 20:38         ` Paul Brook
  0 siblings, 0 replies; 61+ messages in thread
From: Paul Brook @ 2009-06-10 20:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Glauber Costa

On Wednesday 10 June 2009, Glauber Costa wrote:
> On Wed, Jun 10, 2009 at 08:27:30PM +0100, Paul Brook wrote:
> > On Wednesday 10 June 2009, Glauber Costa wrote:
> > > On Wed, Jun 10, 2009 at 06:38:12PM +0100, Paul Brook wrote:
> > > > Inlcude libfdt in source tree, and build it if not already available.
> > >
> > > what makes libfdt different than everything else that we link with?
> > > Why do we have to have a in-tree copy of that?
> >
> > AFAIK libfdt is still absent from current releases of common mainstream
> > distros, and qemu is going to become increasingly useless without it.
>
> This is an argument for both including it in our source release,
> and pushing it to get shipped as a stand alone package. I believe the later
> is a much more sane approach long term

Agreed. The configure check will prefer an installed libfdt, so hopefully the 
in-tree copy will go away over timer.

Paul

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

* Re: [Qemu-devel] [PATCH 1/4] Include and build libfdt
  2009-06-10 19:27     ` Paul Brook
  2009-06-10 19:41       ` Glauber Costa
@ 2009-06-10 22:32       ` Edgar E. Iglesias
  1 sibling, 0 replies; 61+ messages in thread
From: Edgar E. Iglesias @ 2009-06-10 22:32 UTC (permalink / raw)
  To: Paul Brook; +Cc: Glauber Costa, qemu-devel

On Wed, Jun 10, 2009 at 08:27:30PM +0100, Paul Brook wrote:
> On Wednesday 10 June 2009, Glauber Costa wrote:
> > On Wed, Jun 10, 2009 at 06:38:12PM +0100, Paul Brook wrote:
> > > Inlcude libfdt in source tree, and build it if not already available.
> >
> > what makes libfdt different than everything else that we link with?
> > Why do we have to have a in-tree copy of that?
> 
> AFAIK libfdt is still absent from current releases of common mainstream 
> distros[1], and qemu is going to become increasingly useless without it.
> 
> c.f. dtc where we use the system version.
> 
> Paul
> 
> [1] We can argue about what constitutes sufficiently wide acceptance, but IMHO 
> Fedora, Ubuntu and Debian Sid would be a fairly good start.

With the microblaze port, one of the main issues I get complaints about
is missing libfdt. We have a dynamic fdt driven board off-tree and
a static board in mainline but both really depend on libfdt to be
useful.

Pretty much everybody has to download dtc and install the libs from
there.

It could be that we have looked for the wrong distro packages but if
not, it's missing on the above mentioned distros + gentoo.

FWIW though, I'd like to see libfdt in qemu as a temporary thing
until libfdt is more widespread.

Cheers

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

* Re: [Qemu-devel] [PATCH 3/4] Stellaris machine config
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 3/4] Stellaris machine config Paul Brook
@ 2009-06-11  8:21   ` M P
  2009-06-11 16:32     ` Jamie Lokier
  0 siblings, 1 reply; 61+ messages in thread
From: M P @ 2009-06-11  8:21 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

I've been following the tree, and the qdev bits in general since I
have my own stack of patches against a few things.

I'm sure it's been discussed to death already, but I just recently
joined so sorry to add another layer on top.

I don't understand how replacing things with a non-source code file
helps anything in this case. The original stellaris code was rather
bad already compared to some other CPUs/SoC:
+ Not a single #define constant, all encoded in good old HEX.
+ No constants for /anything/ in fact, down to the number of GPIO
ports hard coded to 7 in many places.
+ No way to create a derivative board with /just/ the SoC, and add custom IOs.

So now, with qdev, it's all official, /every value, constant, and
bitfield/ is hard coded, in hex, into a different non-code file, with
no way of derivating or overloading from.

I've seen (well I even done a few) projects that tought that using a
super-duper 'meta file' (xml etc) was a fantastic idea, it turns out
it's never really a fantastic idea, and you spend your time looking at
code that is busy recovering properties from deep down an abstract
(and unreadable) runtime tree to do /anything/.

If you look at your diff here and count lines, it's exactly whats
happening, You replaced about 2 page-worth of straightforward readable
code with countless new pages of entirely unrelated non-code. In fact,
the stellaris share /a lot/ between themselves, and there is not a
single shared line between your two stellaris boards definition file.

When I started hacking at qemu to add my own board supports some month
ago, I tought it was the neatest, meanest, "no frill" approach that
made it so cool. You could actualy /follow code thru!/ -- how
refreshing! Now there are a bunch of arcane and ugly /macros/ to
convert blindly struct into others, with no type checking, no
overloading, no methods. It's like even-worse-c++.

Sorry for the rant, I'll go back to idling.

Michel

On Wed, Jun 10, 2009 at 6:38 PM, Paul Brook<paul@codesourcery.com> wrote:
> Replace hardcoded stellaris boards with machine configs
>
> Signed-off-by: Paul Brook <paul@codesourcery.com>
> ---
>
>  Makefile                       |    4 -
>  Makefile.hw                    |    2
>  hw/arm-cpu.c                   |    3
>  hw/armv7m.c                    |   61 +++++++++
>  hw/gpio-buttons.c              |  124 ++++++++++++++++++
>  hw/pl011.c                     |    2
>  hw/pl061.c                     |   25 +++-
>  hw/stellaris.c                 |  272 +++++++++-------------------------------
>  hw/stellaris_enet.c            |    2
>  hw/stellaris_input.c           |   91 -------------
>  pc-bios/boards/lm3s6965evb.dts |  212 +++++++++++++++++++++++++++++++
>  pc-bios/boards/lm3s811evb.dts  |  155 +++++++++++++++++++++++
>  12 files changed, 645 insertions(+), 308 deletions(-)
>  create mode 100644 hw/gpio-buttons.c
>  delete mode 100644 hw/stellaris_input.c
>  create mode 100644 pc-bios/boards/lm3s6965evb.dts
>  create mode 100644 pc-bios/boards/lm3s811evb.dts
>
> diff --git a/Makefile b/Makefile
> index 6d15c44..48a3ec3 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -46,7 +46,7 @@ endif
>  #######################################################################
>  # Board descriptions
>
> -BOARDS = syborg
> +BOARDS = syborg lm3s811evb lm3s6965evb
>
>  ifdef DTC
>  BOARDS_BIN = $(BOARDS:%=pc-bios/boards/%.dtb)
> @@ -115,7 +115,7 @@ OBJS+=readline.o console.o
>
>  OBJS+=irq.o ptimer.o
>  OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
> -OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
> +OBJS+=ssd0303.o ssd0323.o ads7846.o twl92230.o
>  OBJS+=tmp105.o lm832x.o eeprom93xx.o tsc2005.o
>  OBJS+=scsi-disk.o cdrom.o
>  OBJS+=scsi-generic.o
> diff --git a/Makefile.hw b/Makefile.hw
> index 6accb3b..1953b85 100644
> --- a/Makefile.hw
> +++ b/Makefile.hw
> @@ -28,6 +28,8 @@ OBJS+= lsi53c895a.o esp.o
>
>  OBJS+= dma-helpers.o sysbus.o
>
> +OBJS+= gpio-buttons.o
> +
>  all: $(HWLIB)
>  # Dummy command so that make thinks it has done something
>        @true
> diff --git a/hw/arm-cpu.c b/hw/arm-cpu.c
> index c15eb12..4c128d1 100644
> --- a/hw/arm-cpu.c
> +++ b/hw/arm-cpu.c
> @@ -17,7 +17,8 @@ static const struct {
>     const char *cpuname;
>  } cpu_device_name_map[] = {
>     {"ARM,ARM926EJ-S", "arm926"},
> -    {"ARM,Cortex-A8", "cortex-a8"}
> +    {"ARM,Cortex-A8", "cortex-a8"},
> +    {"ARM,Cortex-M3", "cortex-m3"}
>  };
>
>  typedef struct {
> diff --git a/hw/armv7m.c b/hw/armv7m.c
> index c3c5b9e..d74a2fb 100644
> --- a/hw/armv7m.c
> +++ b/hw/armv7m.c
> @@ -10,6 +10,7 @@
>  #include "sysbus.h"
>  #include "arm-misc.h"
>  #include "sysemu.h"
> +#include "boards.h"
>
>  /* Bitbanded IO.  Each word corresponds to a single bit.  */
>
> @@ -149,6 +150,47 @@ static void armv7m_bitband_init(void)
>  }
>
>  /* Board init.  */
> +/* Reset initialization and iage loading for ARMv7-M cores.  */
> +static void armv7m_bootstrap(ram_addr_t ram_size, const char *boot_device,
> +    const char *kernel_filename, const char *kernel_cmdline,
> +    const char *initrd_filename)
> +{
> +    CPUState *env = first_cpu;
> +    uint32_t pc;
> +    int image_size;
> +    uint64_t entry;
> +    uint64_t lowaddr;
> +
> +    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
> +    if (image_size < 0) {
> +        image_size = load_image_targphys(kernel_filename, 0, ram_size);
> +       lowaddr = 0;
> +    }
> +    if (image_size < 0) {
> +        fprintf(stderr, "qemu: could not load kernel '%s'\n",
> +                kernel_filename);
> +        exit(1);
> +    }
> +
> +    /* If the image was loaded at address zero then assume it is a
> +       regular ROM image and perform the normal CPU reset sequence.
> +       Otherwise jump directly to the entry point.  */
> +    if (lowaddr == 0) {
> +       env->regs[13] = ldl_phys(0);
> +       pc = ldl_phys(4);
> +    } else {
> +       pc = entry;
> +    }
> +    env->thumb = pc & 1;
> +    env->regs[15] = pc & ~1;
> +
> +    /* Hack to map an additional page of ram at the top of the address
> +       space.  This stops qemu complaining about executing code outside RAM
> +       when returning from an exception.  */
> +    cpu_register_physical_memory(0xfffff000, 0x1000,
> +                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
> +}
> +
>  /* Init CPU and memory for a v7-M based board.
>    flash_size and sram_size are in kb.
>    Returns the NVIC array.  */
> @@ -238,10 +280,25 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
>     return pic;
>  }
>
> +static SysBusDeviceInfo bitband_info = {
> +    .init = bitband_init,
> +    .qdev.props = (DevicePropList[]) {
> +        {.name = "base", .type = PROP_TYPE_INT},
> +        {.name = NULL}
> +    }
> +};
> +
>  static void armv7m_register_devices(void)
>  {
> -    sysbus_register_dev("ARM,bitband-memory", sizeof(BitBandState),
> -                        bitband_init);
> +    sysbus_register_withprop("ARM,bitband-memory", sizeof(BitBandState),
> +                             &bitband_info);
>  }
>
>  device_init(armv7m_register_devices)
> +
> +static void armv7m_boot_register(void)
> +{
> +    register_machine_bootstrap("ARMv7-M", armv7m_bootstrap);
> +}
> +
> +machine_init(armv7m_boot_register);
> diff --git a/hw/gpio-buttons.c b/hw/gpio-buttons.c
> new file mode 100644
> index 0000000..0627818
> --- /dev/null
> +++ b/hw/gpio-buttons.c
> @@ -0,0 +1,124 @@
> +/*
> + * Buttons connected directly to GPIO pins.
> + *
> + * Copyright (c) 2009 CodeSourcery.
> + * Written by Paul Brook
> + *
> + * This code is licenced under the GNU GPL v2.
> + */
> +#include "sysbus.h"
> +#include "console.h"
> +
> +#define KEY_INVERT      0x80000000u
> +#define KEY_CODE_MASK   0x0000ffffu
> +
> +typedef struct {
> +    SysBusDevice busdev;
> +    qemu_irq *irq;
> +    const uint32_t *keys;
> +    int *pressed;
> +    int num_buttons;
> +    int extension;
> +} GPIOButtonsState;
> +
> +static void gpio_buttons_put_key(void *opaque, int keycode)
> +{
> +    GPIOButtonsState *s = (GPIOButtonsState *)opaque;
> +    int i;
> +    int down;
> +
> +    if (keycode == 0xe0 && !s->extension) {
> +        s->extension = 0x80;
> +        return;
> +    }
> +
> +    down = (keycode & 0x80) == 0;
> +    keycode = (keycode & 0x7f) | s->extension;
> +
> +    for (i = 0; i < s->num_buttons; i++) {
> +        if ((s->keys[i] & KEY_CODE_MASK) == keycode
> +                && s->pressed[i] != down) {
> +            s->pressed[i] = down;
> +            if (s->keys[i] & KEY_INVERT) {
> +                qemu_set_irq(s->irq[i], !down);
> +            } else {
> +                qemu_set_irq(s->irq[i], down);
> +            }
> +        }
> +    }
> +
> +    s->extension = 0;
> +}
> +
> +static void gpio_buttons_save(QEMUFile *f, void *opaque)
> +{
> +    GPIOButtonsState *s = (GPIOButtonsState *)opaque;
> +    int i;
> +
> +    qemu_put_be32(f, s->extension);
> +    for (i = 0; i < s->num_buttons; i++)
> +        qemu_put_byte(f, s->pressed[i]);
> +}
> +
> +static int gpio_buttons_load(QEMUFile *f, void *opaque, int version_id)
> +{
> +    GPIOButtonsState *s = (GPIOButtonsState *)opaque;
> +    int i;
> +
> +    if (version_id != 1)
> +        return -EINVAL;
> +
> +    s->extension = qemu_get_be32(f);
> +    for (i = 0; i < s->num_buttons; i++)
> +        s->pressed[i] = qemu_get_byte(f);
> +
> +    return 0;
> +}
> +
> +static void gpio_buttons_late_init(DeviceState *dev)
> +{
> +    GPIOButtonsState *s = FROM_SYSBUS(GPIOButtonsState, sysbus_from_qdev(dev));
> +    int i;
> +
> +    for (i = 0; i < s->num_buttons; i++) {
> +        if (s->keys[i] & KEY_INVERT) {
> +            qemu_irq_raise(s->irq[i]);
> +        }
> +    }
> +}
> +
> +static void gpio_buttons_init(SysBusDevice *dev)
> +{
> +    GPIOButtonsState *s = FROM_SYSBUS(GPIOButtonsState, dev);
> +
> +    s->num_buttons = qdev_get_prop_array(&dev->qdev, "keys", &s->keys);
> +    if (s->num_buttons <= 0) {
> +        hw_error("gpio-buttons: Missing keys property");
> +    }
> +
> +    s->irq = qemu_mallocz(sizeof(qemu_irq) * s->num_buttons);
> +    qdev_init_gpio_out(&dev->qdev, s->irq, s->num_buttons);
> +    s->pressed = qemu_mallocz(sizeof(int) * s->num_buttons);
> +    qemu_add_kbd_event_handler(gpio_buttons_put_key, s);
> +    register_savevm("gpio-buttons", -1, 1,
> +                    gpio_buttons_save, gpio_buttons_load, s);
> +}
> +
> +static SysBusDeviceInfo gpio_buttons_info = {
> +    .init = gpio_buttons_init,
> +    .qdev.late_init = gpio_buttons_late_init,
> +    .qdev.props = (DevicePropList[]) {
> +        {.name = "keys", .type = PROP_TYPE_ARRAY},
> +        {.name = NULL}
> +    }
> +};
> +
> +static void gpio_buttons_register_devices(void)
> +{
> +    /* ??? This isn't really attached to the system bus, but it's as good
> +       a place as any to put it.  */
> +    sysbus_register_withprop("qemu,gpio-buttons", sizeof(GPIOButtonsState),
> +                             &gpio_buttons_info);
> +}
> +
> +device_init(gpio_buttons_register_devices)
> diff --git a/hw/pl011.c b/hw/pl011.c
> index 3a1a4cb..f167bec 100644
> --- a/hw/pl011.c
> +++ b/hw/pl011.c
> @@ -323,7 +323,7 @@ static void pl011_register_devices(void)
>  {
>     sysbus_register_dev("pl011", sizeof(pl011_state),
>                         pl011_init_arm);
> -    sysbus_register_dev("pl011_luminary", sizeof(pl011_state),
> +    sysbus_register_dev("luminary,pl011", sizeof(pl011_state),
>                         pl011_init_luminary);
>  }
>
> diff --git a/hw/pl061.c b/hw/pl061.c
> index aa0a322..8e38bd6 100644
> --- a/hw/pl061.c
> +++ b/hw/pl061.c
> @@ -291,6 +291,18 @@ static int pl061_load(QEMUFile *f, void *opaque, int version_id)
>     return 0;
>  }
>
> +static void pl061_late_init(DeviceState *dev)
> +{
> +    pl061_state *s = FROM_SYSBUS(pl061_state, sysbus_from_qdev(dev));
> +    int i;
> +
> +    for (i = 0; i < 8; i++) {
> +        if (s->float_high & (1 << i)) {
> +            qemu_irq_raise(s->out[i]);
> +        }
> +    }
> +}
> +
>  static void pl061_init(SysBusDevice *dev)
>  {
>     int iomemtype;
> @@ -302,14 +314,23 @@ static void pl061_init(SysBusDevice *dev)
>     sysbus_init_irq(dev, &s->irq);
>     qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8);
>     qdev_init_gpio_out(&dev->qdev, s->out, 8);
> +    s->float_high = qdev_get_prop_int(&dev->qdev, "float-high", 0);
>     pl061_reset(s);
>     register_savevm("pl061_gpio", -1, 1, pl061_save, pl061_load, s);
>  }
>
> +static SysBusDeviceInfo pl061_info = {
> +    .init = pl061_init,
> +    .qdev.late_init = pl061_late_init,
> +    .qdev.props = (DevicePropList[]) {
> +        {.name = "float-high", .type = PROP_TYPE_INT},
> +        {.name = NULL}
> +    }
> +};
>  static void pl061_register_devices(void)
>  {
> -    sysbus_register_dev("pl061", sizeof(pl061_state),
> -                        pl061_init);
> +    sysbus_register_withprop("pl061", sizeof(pl061_state),
> +                             &pl061_info);
>  }
>
>  device_init(pl061_register_devices)
> diff --git a/hw/stellaris.c b/hw/stellaris.c
> index 38b9830..ba5b11f 100644
> --- a/hw/stellaris.c
> +++ b/hw/stellaris.c
> @@ -361,6 +361,7 @@ static void stellaris_gptm_init(SysBusDevice *dev)
>  /* System controller.  */
>
>  typedef struct {
> +    SysBusDevice busdev;
>     uint32_t pborctl;
>     uint32_t ldopctl;
>     uint32_t int_status;
> @@ -374,8 +375,12 @@ typedef struct {
>     uint32_t ldoarst;
>     uint32_t user0;
>     uint32_t user1;
> +    uint32_t did0;
> +    uint32_t did1;
> +    uint32_t dc[4];
>     qemu_irq irq;
> -    stellaris_board_info *board;
> +    int got_mac;
> +    DeviceState *netdev;
>  } ssys_state;
>
>  static void ssys_update(ssys_state *s)
> @@ -421,25 +426,38 @@ static uint32_t pllcfg_fury[16] = {
>     0xb11c /* 8.192 Mhz */
>  };
>
> +static void ssys_get_mac(ssys_state *s)
> +{
> +    uint8_t macaddr[6];
> +
> +    s->got_mac = 1;
> +    if (!s->netdev) {
> +        return;
> +    }
> +    qdev_get_macaddr(s->netdev, macaddr);
> +    s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
> +    s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
> +}
> +
>  static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
>  {
>     ssys_state *s = (ssys_state *)opaque;
>
>     switch (offset) {
>     case 0x000: /* DID0 */
> -        return s->board->did0;
> +        return s->did0;
>     case 0x004: /* DID1 */
> -        return s->board->did1;
> +        return s->did1;
>     case 0x008: /* DC0 */
> -        return s->board->dc0;
> +        return s->dc[0];
>     case 0x010: /* DC1 */
> -        return s->board->dc1;
> +        return s->dc[1];
>     case 0x014: /* DC2 */
> -        return s->board->dc2;
> +        return s->dc[2];
>     case 0x018: /* DC3 */
> -        return s->board->dc3;
> +        return s->dc[3];
>     case 0x01c: /* DC4 */
> -        return s->board->dc4;
> +        return s->dc[4];
>     case 0x030: /* PBORCTL */
>         return s->pborctl;
>     case 0x034: /* LDOPCTL */
> @@ -464,7 +482,7 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
>         {
>             int xtal;
>             xtal = (s->rcc >> 6) & 0xf;
> -            if (s->board->did0 & (1 << 16)) {
> +            if (s->did0 & (1 << 16)) {
>                 return pllcfg_fury[xtal];
>             } else {
>                 return pllcfg_sandstorm[xtal];
> @@ -493,8 +511,14 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
>     case 0x160: /* LDOARST */
>         return s->ldoarst;
>     case 0x1e0: /* USER0 */
> +        if (!s->got_mac) {
> +            ssys_get_mac(s);
> +        }
>         return s->user0;
>     case 0x1e4: /* USER1 */
> +        if (!s->got_mac) {
> +            ssys_get_mac(s);
> +        }
>         return s->user1;
>     default:
>         hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
> @@ -654,23 +678,25 @@ static int ssys_load(QEMUFile *f, void *opaque, int version_id)
>     return 0;
>  }
>
> -static void stellaris_sys_init(uint32_t base, qemu_irq irq,
> -                               stellaris_board_info * board,
> -                               uint8_t *macaddr)
> +static void stellaris_sysctl_init(SysBusDevice *dev)
>  {
>     int iomemtype;
> -    ssys_state *s;
> -
> -    s = (ssys_state *)qemu_mallocz(sizeof(ssys_state));
> -    s->irq = irq;
> -    s->board = board;
> -    /* Most devices come preprogrammed with a MAC address in the user data. */
> -    s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
> -    s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
> +    ssys_state *s = FROM_SYSBUS(ssys_state, dev);
>
>     iomemtype = cpu_register_io_memory(0, ssys_readfn,
>                                        ssys_writefn, s);
> -    cpu_register_physical_memory(base, 0x00001000, iomemtype);
> +    sysbus_init_mmio(dev, 0x1000, iomemtype);
> +    sysbus_init_irq(dev, &s->irq);
> +    s->netdev = qdev_get_prop_dev(&dev->qdev, "enet");
> +    s->got_mac = 0;
> +    s->did0 = qdev_get_prop_int(&dev->qdev, "did0", 0);
> +    s->did1 = qdev_get_prop_int(&dev->qdev, "did1", 0);
> +    s->dc[0] = qdev_get_prop_int(&dev->qdev, "dc0", 0);
> +    s->dc[1] = qdev_get_prop_int(&dev->qdev, "dc1", 0);
> +    s->dc[2] = qdev_get_prop_int(&dev->qdev, "dc2", 0);
> +    s->dc[3] = qdev_get_prop_int(&dev->qdev, "dc3", 0);
> +    s->dc[4] = qdev_get_prop_int(&dev->qdev, "dc4", 0);
> +
>     ssys_reset(s);
>     register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s);
>  }
> @@ -1256,200 +1282,30 @@ static void stellaris_ssi_bus_init(SSISlave *dev)
>                     stellaris_ssi_bus_save, stellaris_ssi_bus_load, s);
>  }
>
> -/* Board init.  */
> -static stellaris_board_info stellaris_boards[] = {
> -  { "LM3S811EVB",
> -    0,
> -    0x0032000e,
> -    0x001f001f, /* dc0 */
> -    0x001132bf,
> -    0x01071013,
> -    0x3f0f01ff,
> -    0x0000001f,
> -    BP_OLED_I2C
> -  },
> -  { "LM3S6965EVB",
> -    0x10010002,
> -    0x1073402e,
> -    0x00ff007f, /* dc0 */
> -    0x001133ff,
> -    0x030f5317,
> -    0x0f0f87ff,
> -    0x5000007f,
> -    BP_OLED_SSI | BP_GAMEPAD
> -  }
> -};
> -
> -static void stellaris_init(const char *kernel_filename, const char *cpu_model,
> -                           stellaris_board_info *board)
> -{
> -    static const int uart_irq[] = {5, 6, 33, 34};
> -    static const int timer_irq[] = {19, 21, 23, 35};
> -    static const uint32_t gpio_addr[7] =
> -      { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
> -        0x40024000, 0x40025000, 0x40026000};
> -    static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
> -
> -    qemu_irq *pic;
> -    DeviceState *gpio_dev[7];
> -    qemu_irq gpio_in[7][8];
> -    qemu_irq gpio_out[7][8];
> -    qemu_irq adc;
> -    int sram_size;
> -    int flash_size;
> -    i2c_bus *i2c;
> -    DeviceState *dev;
> -    int i;
> -    int j;
> -
> -    flash_size = ((board->dc0 & 0xffff) + 1) << 1;
> -    sram_size = (board->dc0 >> 18) + 1;
> -    pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
> -
> -    if (board->dc1 & (1 << 16)) {
> -        dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
> -                                    pic[14], pic[15], pic[16], pic[17], NULL);
> -        adc = qdev_get_gpio_in(dev, 0);
> -    } else {
> -        adc = NULL;
> -    }
> -    for (i = 0; i < 4; i++) {
> -        if (board->dc2 & (0x10000 << i)) {
> -            dev = sysbus_create_simple("stellaris-gptm",
> -                                       0x40030000 + i * 0x1000,
> -                                       pic[timer_irq[i]]);
> -            /* TODO: This is incorrect, but we get away with it because
> -               the ADC output is only ever pulsed.  */
> -            qdev_connect_gpio_out(dev, 0, adc);
> -        }
> -    }
> -
> -    stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
> -
> -    for (i = 0; i < 7; i++) {
> -        if (board->dc4 & (1 << i)) {
> -            gpio_dev[i] = sysbus_create_simple("pl061", gpio_addr[i],
> -                                               pic[gpio_irq[i]]);
> -            for (j = 0; j < 8; j++) {
> -                gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
> -                gpio_out[i][j] = NULL;
> -            }
> -        }
> -    }
> -
> -    if (board->dc2 & (1 << 12)) {
> -        dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
> -        i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
> -        if (board->peripherals & BP_OLED_I2C) {
> -            i2c_create_slave(i2c, "ssd0303", 0x3d);
> -        }
> -    }
> -
> -    for (i = 0; i < 4; i++) {
> -        if (board->dc2 & (1 << i)) {
> -            sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
> -                                 pic[uart_irq[i]]);
> -        }
> -    }
> -    if (board->dc2 & (1 << 4)) {
> -        dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
> -        if (board->peripherals & BP_OLED_SSI) {
> -            DeviceState *mux;
> -            void *bus;
> -
> -            bus = qdev_get_child_bus(dev, "ssi");
> -            mux = ssi_create_slave(bus, "evb6965-ssi");
> -            gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
> -
> -            bus = qdev_get_child_bus(mux, "ssi0");
> -            dev = ssi_create_slave(bus, "ssi-sd");
> -
> -            bus = qdev_get_child_bus(mux, "ssi1");
> -            dev = ssi_create_slave(bus, "ssd0323");
> -            gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
> -
> -            /* Make sure the select pin is high.  */
> -            qemu_irq_raise(gpio_out[GPIO_D][0]);
> -        }
> -    }
> -    if (board->dc4 & (1 << 28)) {
> -        DeviceState *enet;
> -
> -        qemu_check_nic_model(&nd_table[0], "stellaris");
> -
> -        enet = qdev_create(NULL, "stellaris_enet");
> -        qdev_set_netdev(enet, &nd_table[0]);
> -        qdev_init(enet);
> -        sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
> -        sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
> -    }
> -    if (board->peripherals & BP_GAMEPAD) {
> -        qemu_irq gpad_irq[5];
> -        static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
> -
> -        gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
> -        gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
> -        gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
> -        gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
> -        gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
> -
> -        stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
> -    }
> -    for (i = 0; i < 7; i++) {
> -        if (board->dc4 & (1 << i)) {
> -            for (j = 0; j < 8; j++) {
> -                if (gpio_out[i][j]) {
> -                    qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
> -                }
> -            }
> -        }
> -    }
> -}
> -
> -/* FIXME: Figure out how to generate these from stellaris_boards.  */
> -static void lm3s811evb_init(ram_addr_t ram_size,
> -                     const char *boot_device,
> -                     const char *kernel_filename, const char *kernel_cmdline,
> -                     const char *initrd_filename, const char *cpu_model)
> -{
> -    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
> -}
> -
> -static void lm3s6965evb_init(ram_addr_t ram_size,
> -                     const char *boot_device,
> -                     const char *kernel_filename, const char *kernel_cmdline,
> -                     const char *initrd_filename, const char *cpu_model)
> -{
> -    stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
> -}
> -
> -static QEMUMachine lm3s811evb_machine = {
> -    .name = "lm3s811evb",
> -    .desc = "Stellaris LM3S811EVB",
> -    .init = lm3s811evb_init,
> -};
> -
> -static QEMUMachine lm3s6965evb_machine = {
> -    .name = "lm3s6965evb",
> -    .desc = "Stellaris LM3S6965EVB",
> -    .init = lm3s6965evb_init,
> -};
> -
> -static void stellaris_machine_init(void)
> -{
> -    qemu_register_machine(&lm3s811evb_machine);
> -    qemu_register_machine(&lm3s6965evb_machine);
> -}
> -
> -machine_init(stellaris_machine_init);
> -
>  static SSISlaveInfo stellaris_ssi_bus_info = {
>     .init = stellaris_ssi_bus_init,
>     .transfer = stellaris_ssi_bus_transfer
>  };
>
> +static SysBusDeviceInfo ssys_info = {
> +    .init = stellaris_sysctl_init,
> +    .qdev.props = (DevicePropList[]) {
> +        {.name = "enet", .type = PROP_TYPE_DEV},
> +        {.name = "did0", .type = PROP_TYPE_INT},
> +        {.name = "did1", .type = PROP_TYPE_INT},
> +        {.name = "dc0", .type = PROP_TYPE_INT},
> +        {.name = "dc1", .type = PROP_TYPE_INT},
> +        {.name = "dc2", .type = PROP_TYPE_INT},
> +        {.name = "dc3", .type = PROP_TYPE_INT},
> +        {.name = "dc4", .type = PROP_TYPE_INT},
> +        {.name = NULL}
> +    }
> +};
> +
>  static void stellaris_register_devices(void)
>  {
> +    sysbus_register_withprop("stellaris-sysctl", sizeof(ssys_state),
> +                             &ssys_info);
>     sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
>                         stellaris_i2c_init);
>     sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
> diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
> index 36fabd3..86df231 100644
> --- a/hw/stellaris_enet.c
> +++ b/hw/stellaris_enet.c
> @@ -417,7 +417,7 @@ static void stellaris_enet_init(SysBusDevice *dev)
>
>  static void stellaris_enet_register_devices(void)
>  {
> -    sysbus_register_dev("stellaris_enet", sizeof(stellaris_enet_state),
> +    sysbus_register_dev("stellaris-enet", sizeof(stellaris_enet_state),
>                         stellaris_enet_init);
>  }
>
> diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c
> deleted file mode 100644
> index 33395a4..0000000
> --- a/hw/stellaris_input.c
> +++ /dev/null
> @@ -1,91 +0,0 @@
> -/*
> - * Gamepad style buttons connected to IRQ/GPIO lines
> - *
> - * Copyright (c) 2007 CodeSourcery.
> - * Written by Paul Brook
> - *
> - * This code is licenced under the GPL.
> - */
> -#include "hw.h"
> -#include "devices.h"
> -#include "console.h"
> -
> -typedef struct {
> -    qemu_irq irq;
> -    int keycode;
> -    int pressed;
> -} gamepad_button;
> -
> -typedef struct {
> -    gamepad_button *buttons;
> -    int num_buttons;
> -    int extension;
> -} gamepad_state;
> -
> -static void stellaris_gamepad_put_key(void * opaque, int keycode)
> -{
> -    gamepad_state *s = (gamepad_state *)opaque;
> -    int i;
> -    int down;
> -
> -    if (keycode == 0xe0 && !s->extension) {
> -        s->extension = 0x80;
> -        return;
> -    }
> -
> -    down = (keycode & 0x80) == 0;
> -    keycode = (keycode & 0x7f) | s->extension;
> -
> -    for (i = 0; i < s->num_buttons; i++) {
> -        if (s->buttons[i].keycode == keycode
> -                && s->buttons[i].pressed != down) {
> -            s->buttons[i].pressed = down;
> -            qemu_set_irq(s->buttons[i].irq, down);
> -        }
> -    }
> -
> -    s->extension = 0;
> -}
> -
> -static void stellaris_gamepad_save(QEMUFile *f, void *opaque)
> -{
> -    gamepad_state *s = (gamepad_state *)opaque;
> -    int i;
> -
> -    qemu_put_be32(f, s->extension);
> -    for (i = 0; i < s->num_buttons; i++)
> -        qemu_put_byte(f, s->buttons[i].pressed);
> -}
> -
> -static int stellaris_gamepad_load(QEMUFile *f, void *opaque, int version_id)
> -{
> -    gamepad_state *s = (gamepad_state *)opaque;
> -    int i;
> -
> -    if (version_id != 1)
> -        return -EINVAL;
> -
> -    s->extension = qemu_get_be32(f);
> -    for (i = 0; i < s->num_buttons; i++)
> -        s->buttons[i].pressed = qemu_get_byte(f);
> -
> -    return 0;
> -}
> -
> -/* Returns an array 5 ouput slots.  */
> -void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
> -{
> -    gamepad_state *s;
> -    int i;
> -
> -    s = (gamepad_state *)qemu_mallocz(sizeof (gamepad_state));
> -    s->buttons = (gamepad_button *)qemu_mallocz(n * sizeof (gamepad_button));
> -    for (i = 0; i < n; i++) {
> -        s->buttons[i].irq = irq[i];
> -        s->buttons[i].keycode = keycode[i];
> -    }
> -    s->num_buttons = n;
> -    qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
> -    register_savevm("stellaris_gamepad", -1, 1,
> -                    stellaris_gamepad_save, stellaris_gamepad_load, s);
> -}
> diff --git a/pc-bios/boards/lm3s6965evb.dts b/pc-bios/boards/lm3s6965evb.dts
> new file mode 100644
> index 0000000..9bc0128
> --- /dev/null
> +++ b/pc-bios/boards/lm3s6965evb.dts
> @@ -0,0 +1,212 @@
> +/ {
> +    #address-cells = <1>;
> +    #size-cells  = <1>;
> +
> +    cpus {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        cpu0: ARM,Cortex-M3@0 {
> +            device_type = "cpu";
> +            reg = <0>;
> +            #interrupt-cells = <1>;
> +            nvic = <&nvic>;
> +        };
> +    };
> +    flash@0 {
> +        device_type = "rom";
> +        reg = <00000000 00040000>;
> +    };
> +    memory@0 {
> +        device_type = "memory";
> +        reg = <20000000 00010000>;
> +    };
> +    bitband@0 {
> +        model = "ARM,bitband-memory";
> +        reg = <22000000 02000000>;
> +        base = <20000000>;
> +    };
> +    bitband@1 {
> +        model = "ARM,bitband-memory";
> +        reg = <42000000 02000000>;
> +        base = <40000000>;
> +    };
> +    nvic: nvic@0 {
> +        model = "armv7m_nvic";
> +        interrupt-parent = <&cpu0>;
> +        interrupts = <0>;
> +        interrupt-controller;
> +        #interrupt-cells = <1>;
> +    };
> +    lm3s6965@0 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        qemu,fold-bus;
> +        // TODO Watchdog at 0x40000000
> +        gpioA: gpio@0 {
> +            model = "pl061";
> +            reg = <40004000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <0>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        gpioB: gpio@1 {
> +            model = "pl061";
> +            reg = <40005000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <1>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        gpioC: gpio@2 {
> +            model = "pl061";
> +            reg = <40006000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <2>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 &oled 0>;
> +        };
> +        gpioD: gpio@3 {
> +            model = "pl061";
> +            reg = <40007000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <3>;
> +            qemu,gpio = <&ssimux 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +            float-high = <01>;
> +        };
> +        ssi@0 {
> +            model = "pl022";
> +            reg = <40008000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <7>;
> +            ssimux: mux@0 {
> +                model = "evb6965-ssi";
> +                sd@0 {
> +                    model = "ssi-sd";
> +                    qemu,parent-bus = "ssi0";
> +                };
> +                oled: oled@1 {
> +                    model = "ssd0323";
> +                    qemu,parent-bus = "ssi1";
> +                };
> +            };
> +        };
> +        uart@0 {
> +            model = "luminary,pl011";
> +            reg = <4000c000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <5>;
> +        };
> +        uart@1 {
> +            model = "luminary,pl011";
> +            reg = <4000d000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <6>;
> +        };
> +        uart@2 {
> +            model = "luminary,pl011";
> +            reg = <4000e000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#33>;
> +        };
> +        i2c@0 {
> +            model = "stellaris-i2c";
> +            reg = <40020000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <8>;
> +        };
> +        i2c@1 {
> +            model = "stellaris-i2c";
> +            reg = <40021000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#37>;
> +        };
> +        gpioE: gpio@4 {
> +            model = "pl061";
> +            reg = <40024000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <4>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        gpioF: gpio@5 {
> +            model = "pl061";
> +            reg = <40025000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#30>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        gpioG: gpio@6 {
> +            model = "pl061";
> +            reg = <40026000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#31>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        // TODO PWM at 0x40028000
> +        // TODO QEI0 at 0x4002c000
> +        // TODO QEI1 at 0x4002d000
> +        gptm@0 {
> +            model = "stellaris-gptm";
> +            reg = <40030000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#19>;
> +            qemu,gpio = <&adc0 0>;
> +        };
> +        gptm@1 {
> +            model = "stellaris-gptm";
> +            reg = <40031000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#21>;
> +            qemu,gpio = <&adc0 0>;
> +        };
> +        gptm@2 {
> +            model = "stellaris-gptm";
> +            reg = <40032000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#23>;
> +            qemu,gpio = <&adc0 0>;
> +        };
> +        gptm@3 {
> +            model = "stellaris-gptm";
> +            reg = <40033000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#35>;
> +            qemu,gpio = <&adc0 0>;
> +        };
> +        adc0: adc@0 {
> +            model = "stellaris-adc";
> +            reg = <40038000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#14 d#15 d#16 d#17>;
> +        };
> +        // TODO Comparator at 0x4003c000
> +        enet: enet@0 {
> +            model = "stellaris-enet";
> +            reg = <40048000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#42>;
> +        };
> +        // TODO Hybernation module at 0x400fc000
> +        sysctl@0 {
> +            model = "stellaris-sysctl";
> +            reg = <400fe000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#28>;
> +            did0 = <10010002>;
> +            did1 = <1073402e>;
> +            dc0 = <00ff007f>;
> +            dc1 = <001133ff>;
> +            dc2 = <030f5317>;
> +            dc3 = <0f0f87ff>;
> +            dc4 = <5000007f>;
> +            enet = <&enet>;
> +        };
> +        buttons@0 {
> +            model = "qemu,gpio-buttons";
> +            keys = <800000c8 800000d0 800000cb 800000cd 8000001d>;
> +            qemu,gpio = <&gpioE 0 &gpioE 1 &gpioE 2 &gpioE 3 &gpioF 1>;
> +        };
> +    };
> +    chosen {
> +        qemu {
> +            bootstrap = "ARMv7-M";
> +        };
> +    };
> +};
> diff --git a/pc-bios/boards/lm3s811evb.dts b/pc-bios/boards/lm3s811evb.dts
> new file mode 100644
> index 0000000..977d080
> --- /dev/null
> +++ b/pc-bios/boards/lm3s811evb.dts
> @@ -0,0 +1,155 @@
> +/ {
> +    #address-cells = <1>;
> +    #size-cells  = <1>;
> +
> +    cpus {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        cpu0: ARM,Cortex-M3@0 {
> +            device_type = "cpu";
> +            reg = <0>;
> +            #interrupt-cells = <1>;
> +            nvic = <&nvic>;
> +        };
> +    };
> +    flash@0 {
> +        device_type = "rom";
> +        reg = <00000000 00010000>;
> +    };
> +    memory@0 {
> +        device_type = "memory";
> +        reg = <20000000 00002000>;
> +    };
> +    bitband@0 {
> +        model = "ARM,bitband-memory";
> +        reg = <22000000 02000000>;
> +        base = <20000000>;
> +    };
> +    bitband@1 {
> +        model = "ARM,bitband-memory";
> +        reg = <42000000 02000000>;
> +        base = <40000000>;
> +    };
> +    nvic: nvic@0 {
> +        model = "armv7m_nvic";
> +        interrupt-parent = <&cpu0>;
> +        interrupts = <0>;
> +        interrupt-controller;
> +        #interrupt-cells = <1>;
> +    };
> +    lm3s811@0 {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        qemu,fold-bus;
> +        // TODO Watchdog at 0x40000000
> +        gpioA: gpio@0 {
> +            model = "pl061";
> +            reg = <40004000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <0>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        gpioB: gpio@1 {
> +            model = "pl061";
> +            reg = <40005000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <1>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        gpioC: gpio@2 {
> +            model = "pl061";
> +            reg = <40006000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <2>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        gpioD: gpio@3 {
> +            model = "pl061";
> +            reg = <40007000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <3>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        ssi@0 {
> +            model = "pl022";
> +            reg = <40008000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <7>;
> +        };
> +        uart@0 {
> +            model = "luminary,pl011";
> +            reg = <4000c000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <5>;
> +        };
> +        uart@1 {
> +            model = "luminary,pl011";
> +            reg = <4000d000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <6>;
> +        };
> +        i2c@0 {
> +            model = "stellaris-i2c";
> +            reg = <40020000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <8>;
> +            oled@0 {
> +                model = "ssd0303";
> +                address = <3d>;
> +            };
> +        };
> +        gpioE: gpio@4 {
> +            model = "pl061";
> +            reg = <40024000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <4>;
> +            qemu,gpio = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
> +        };
> +        // TODO PWM at 0x40028000
> +        gptm@0 {
> +            model = "stellaris-gptm";
> +            reg = <40030000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#19>;
> +            qemu,gpio = <&adc0 0>;
> +        };
> +        gptm@1 {
> +            model = "stellaris-gptm";
> +            reg = <40031000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#21>;
> +            qemu,gpio = <&adc0 0>;
> +        };
> +        gptm@2 {
> +            model = "stellaris-gptm";
> +            reg = <40032000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#23>;
> +            qemu,gpio = <&adc0 0>;
> +        };
> +        adc0: adc@0 {
> +            model = "stellaris-adc";
> +            reg = <40038000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#14 d#15 d#16 d#17>;
> +        };
> +        sysctl@0 {
> +            model = "stellaris-sysctl";
> +            reg = <400fe000>;
> +            interrupt-parent = <&nvic>;
> +            interrupts = <d#28>;
> +            did0 = <00000000>;
> +            did1 = <0032000e>;
> +            dc0 = <001f001f>;
> +            dc1 = <001132bf>;
> +            dc2 = <01071013>;
> +            dc3 = <3f0f01ff>;
> +            dc4 = <0000001f>;
> +        };
> +    };
> +    chosen {
> +        qemu {
> +            bootstrap = "ARMv7-M";
> +        };
> +    };
> +};
>
>
>
>

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-10 17:38 [Qemu-devel] [PATCH 0/4] Machine config files Paul Brook
                   ` (3 preceding siblings ...)
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 4/4] Integrator " Paul Brook
@ 2009-06-11  9:54 ` Gerd Hoffmann
  2009-06-11 12:53 ` Gerd Hoffmann
  2009-06-12 13:37 ` Markus Armbruster
  6 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-06-11  9:54 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

> Also available from git://repo.or.cz/qemu/pbrook.git devtree

Doesn't build:

In file included from /home/kraxel/projects/qemu/osdep.c:40,
                  from /home/kraxel/projects/qemu/tool-osdep.c:3:
./config-host.h:25:2: error: invalid preprocessing directive #defne

zweiblum kraxel ~/projects/qemu (devtree)# grep "#defne" configure
   echo "#defne HAVE_PREADV 1" >> $config_h

Huh?  Doesn't look intentional ...

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-10 17:38 [Qemu-devel] [PATCH 0/4] Machine config files Paul Brook
                   ` (4 preceding siblings ...)
  2009-06-11  9:54 ` [Qemu-devel] [PATCH 0/4] Machine config files Gerd Hoffmann
@ 2009-06-11 12:53 ` Gerd Hoffmann
  2009-06-11 13:18   ` Paul Brook
  2009-06-12 13:37 ` Markus Armbruster
  6 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-06-11 12:53 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

On 06/10/09 19:38, Paul Brook wrote:
> The following series implements machine config files, and adds converts
> some of the existing hardcoded machines.

Hmm.  The converted machine types have a pretty static configuration, 
i.e. where you don't need to specify more that just "-M type" on the 
command line.

What is the plan for machines which can be configured in alot of 
different ways such as a typical PC?  Where you can configure lots of 
details such as cpu, memory, nic, disk drives, ... using command line 
options?

What is the plan for linking host and guest devices (i.e. hook up nics 
to vlans, connect disks to blkdrvstates, ...)?  Right now 
qdev_get_macaddr() does it in a hackish way with a bold FIXME ...

> The config files themselves are based on the ppc-linux Flattened Device Trees.
> In generaly I've tried to structure things so that the same config file can
> be used for both qemu and linux.

Is there Documentation (other than source code) for libftd?  Do you have 
a pointer for me?

Guess I have to dive into the libftd to get a more clear picture how all 
this is supposed to work together ...

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-11 12:53 ` Gerd Hoffmann
@ 2009-06-11 13:18   ` Paul Brook
  2009-06-11 14:35     ` Gerd Hoffmann
  2009-06-12  7:51     ` Kevin Wolf
  0 siblings, 2 replies; 61+ messages in thread
From: Paul Brook @ 2009-06-11 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

On Thursday 11 June 2009, Gerd Hoffmann wrote:
> On 06/10/09 19:38, Paul Brook wrote:
> > The following series implements machine config files, and adds converts
> > some of the existing hardcoded machines.
>
> Hmm.  The converted machine types have a pretty static configuration,
> i.e. where you don't need to specify more that just "-M type" on the
> command line.
>
> What is the plan for machines which can be configured in alot of
> different ways such as a typical PC?  Where you can configure lots of
> details such as cpu, memory, nic, disk drives, ... using command line
> options?

I don't believe most of these things should be configured by commandline 
options. It's only done that way because we don't have any alternative (i.e. a 
machine config file). If you really want full control, I expect your VM 
manager will generate the machine config for you.

> What is the plan for linking host and guest devices (i.e. hook up nics
> to vlans, connect disks to blkdrvstates, ...)?  Right now
> qdev_get_macaddr() does it in a hackish way with a bold FIXME ...

Probably identifying things by name.

As I've said before, I think it's good to isolate machine configuration (what 
hardware to emulate) and host configuration (image location, vlans, etc).  The 
details are going to depend how we end up doing the host configuration bits.

> > The config files themselves are based on the ppc-linux Flattened Device
> > Trees. In generaly I've tried to structure things so that the same config
> > file can be used for both qemu and linux.
>
> Is there Documentation (other than source code) for libftd?  Do you have
> a pointer for me?

git://www.jdl.com/software/dtc.git

Paul

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

* Re: [Qemu-devel] [PATCH 2/4] Add device tree machine
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 2/4] Add device tree machine Paul Brook
  2009-06-10 18:30   ` Blue Swirl
@ 2009-06-11 13:22   ` Gerd Hoffmann
  2009-06-11 13:33   ` Gerd Hoffmann
  2009-06-12 16:25   ` Markus Armbruster
  3 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-06-11 13:22 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

> +++ b/hw/arm-cpu.c

> +/* FIXME: Remove this and make the CPU emulation use the right names.  */
> +static const struct {
> +    const char *devname;
> +    const char *cpuname;
> +} cpu_device_name_map[] = {
> +    {"ARM,ARM926EJ-S", "arm926"},
> +    {"ARM,Cortex-A8", "cortex-a8"}
> +};

> +static void arm_cpu_register_devices(void)
> +{
> +    int i;
> +    CPUInfo *info;
> +
> +    for (i = 0; i<  ARRAY_SIZE(cpu_device_name_map); i++) {
> +        info = qemu_mallocz(sizeof(*info));
> +        info->sysbus.qdev.props = cpu_qdev_props;
> +        info->sysbus.init = arm_cpu_dev_init;
> +        info->cpuname = cpu_device_name_map[i].cpuname;
> +        sysbus_register_withprop(cpu_device_name_map[i].devname,
> +                                 sizeof(CPUDevice),
> +&info->sysbus);
> +    }

I would drop cpu_device_name_map[] and have static CPUInfo structs instead.

> +++ b/hw/dt-machine.c

> +void dt_fixup_sysbus_device(DeviceState *dev)
> +{

That doesn't belong here, it should go to sysbus.c.

With the businfo patch 
(http://git.et.redhat.com/?p=qemu-kraxel.git;a=commitdiff;h=c02134e1d986892df7e8cc1cd27cf340fcafec63) 
posted yesterday it is easy, just add a fixup_device() callback to the 
BusInfo struct.  I'd name it configure() instead of fixup() though.

> +    qdev_fixup_devices();

qdev_configure_devices() ?

> +DeviceState *qdev_from_phandle(uint32_t phandle)
> +{
> +    if (!main_system_bus) {
> +        return NULL;
> +    }
> +    return qdev_from_phandle1(main_system_bus, phandle);
> +}

What this is good for?  Seems to be unused in the existing board 
descriptions ...

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 2/4] Add device tree machine
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 2/4] Add device tree machine Paul Brook
  2009-06-10 18:30   ` Blue Swirl
  2009-06-11 13:22   ` Gerd Hoffmann
@ 2009-06-11 13:33   ` Gerd Hoffmann
  2009-06-11 13:39     ` Paul Brook
  2009-06-12 16:25   ` Markus Armbruster
  3 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-06-11 13:33 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

A few more comments ...

> +static void dt_add_props(DeviceState *dev, void *dt, int offset)
> +{

Where do device properties come from?  Only the fdt tree?  If so, do we 
need the property lists in the first place?  We could get them directly 
from the fdt tree instead.

> +static const DevicePropList i2c_bus_props[] = {
> +      {.name = "address", .type = PROP_TYPE_INT},
> +      {.name = NULL}
> +};

That could go into BusInfo as well.

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 2/4] Add device tree machine
  2009-06-11 13:33   ` Gerd Hoffmann
@ 2009-06-11 13:39     ` Paul Brook
  2009-06-11 14:22       ` Gerd Hoffmann
  0 siblings, 1 reply; 61+ messages in thread
From: Paul Brook @ 2009-06-11 13:39 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Thursday 11 June 2009, Gerd Hoffmann wrote:
> A few more comments ...
>
> > +static void dt_add_props(DeviceState *dev, void *dt, int offset)
> > +{
>
> Where do device properties come from?  Only the fdt tree?  If so, do we
> need the property lists in the first place?  We could get them directly
> from the fdt tree instead.

The FDT doesn't contain any type information.  My initial implementation 
omitted DevicePropertyList altogether. That ended up fairly messy. Also, when 
we're using the same tree for both qemu and linux the tree probably has 
additional properties we don't care about.

Paul

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

* Re: [Qemu-devel] [PATCH 2/4] Add device tree machine
  2009-06-11 13:39     ` Paul Brook
@ 2009-06-11 14:22       ` Gerd Hoffmann
  0 siblings, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-06-11 14:22 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

On 06/11/09 15:39, Paul Brook wrote:
> On Thursday 11 June 2009, Gerd Hoffmann wrote:
>> Where do device properties come from?  Only the fdt tree?  If so, do we
>> need the property lists in the first place?  We could get them directly
>> from the fdt tree instead.
>
> The FDT doesn't contain any type information.

Which isn't a issue IMHO.  The driver which needs the value knows the 
type to expect, doesn't it?

To outline in more detail what I mean:

Now we have (picking an example with int type):
   dt_add_props(), calling
     fdt_getprop() + fdt32_to_cpu() + qdev_set_prop_int().
And
   i2c_slave_qdev_init(), calling
     qdev_get_prop_int().

I think instead we can do:
   Have a helper named --say -- qdev_get_fdt_int(), calling
     fdt_getprop() + fdt32_to_cpu(), returning an int.
Then have
   i2c_slave_qdev_init() calling
     qdev_get_fdt_int().

i.e. don't extract and save the properties at all, instead have helper 
functions to get them directly from the fdt tree.

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-11 13:18   ` Paul Brook
@ 2009-06-11 14:35     ` Gerd Hoffmann
  2009-06-12  7:51     ` Kevin Wolf
  1 sibling, 0 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-06-11 14:35 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

On 06/11/09 15:18, Paul Brook wrote:
> On Thursday 11 June 2009, Gerd Hoffmann wrote:
>> What is the plan for machines which can be configured in alot of
>> different ways such as a typical PC?  Where you can configure lots of
>> details such as cpu, memory, nic, disk drives, ... using command line
>> options?
>
> I don't believe most of these things should be configured by commandline
> options. It's only done that way because we don't have any alternative (i.e. a
> machine config file). If you really want full control, I expect your VM
> manager will generate the machine config for you.

Not supporting command line options isn't going to fly.  While VM 
managers probably can and will generate config files, not everybody uses 
management software.  And having to hack the dts and run it through the 
dtc doesn't look like a reasonable solution for users to me.

Also currently qemu lacks an option to specify such dt directly.

>> What is the plan for linking host and guest devices (i.e. hook up nics
>> to vlans, connect disks to blkdrvstates, ...)?  Right now
>> qdev_get_macaddr() does it in a hackish way with a bold FIXME ...
>
> Probably identifying things by name.
>
> As I've said before, I think it's good to isolate machine configuration (what
> hardware to emulate) and host configuration (image location, vlans, etc).

Sure.  You still have to link them.

> The
> details are going to depend how we end up doing the host configuration bits.

Ok, sounds like there isn't (yet) a plan.

> git://www.jdl.com/software/dtc.git

Thanks.

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 3/4] Stellaris machine config
  2009-06-11  8:21   ` M P
@ 2009-06-11 16:32     ` Jamie Lokier
  2009-06-12  8:29       ` Gerd Hoffmann
  2009-06-12 13:53       ` Markus Armbruster
  0 siblings, 2 replies; 61+ messages in thread
From: Jamie Lokier @ 2009-06-11 16:32 UTC (permalink / raw)
  To: M P; +Cc: Paul Brook, qemu-devel

M P wrote:
> So now, with qdev, it's all official, /every value, constant, and
> bitfield/ is hard coded, in hex, into a different non-code file, with
> no way of derivating or overloading from.
[...]
> In fact,
> the stellaris share /a lot/ between themselves, and there is not a
> single shared line between your two stellaris boards definition file.

This is a good point.

I guess FDT is missing a "#include" equivalent, and possibly name
constants.

That isn't surprising given FDT's original use, to pass an entire
machine description to a running kernel.

But for QEMU, some way to give names to, say, a standard SoC or a
basic board, or a PC without peripherals, and then refer to them in
another FDT tree, would be useful.

Whether it's done in QEMU itself or by preprocessing doesn't matter.
Preprocessing would have the advantage that it would output FDTs that
could, maybe, be passed to the guest kernel and just work.  Or maybe
QEMU can have a tree preprocessor built in.

-- Jamie

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-11 13:18   ` Paul Brook
  2009-06-11 14:35     ` Gerd Hoffmann
@ 2009-06-12  7:51     ` Kevin Wolf
  2009-06-12 13:49       ` Markus Armbruster
  1 sibling, 1 reply; 61+ messages in thread
From: Kevin Wolf @ 2009-06-12  7:51 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel, Gerd Hoffmann

Paul Brook schrieb:
> On Thursday 11 June 2009, Gerd Hoffmann wrote:
>> On 06/10/09 19:38, Paul Brook wrote:
>>> The following series implements machine config files, and adds converts
>>> some of the existing hardcoded machines.
>> Hmm.  The converted machine types have a pretty static configuration,
>> i.e. where you don't need to specify more that just "-M type" on the
>> command line.
>>
>> What is the plan for machines which can be configured in alot of
>> different ways such as a typical PC?  Where you can configure lots of
>> details such as cpu, memory, nic, disk drives, ... using command line
>> options?
> 
> I don't believe most of these things should be configured by commandline 
> options. It's only done that way because we don't have any alternative (i.e. a 
> machine config file). If you really want full control, I expect your VM 
> manager will generate the machine config for you.

>From my perspective as a qemu user, I definitely don't want to miss the
command line options. Not having to create configuration files is
exactly what gave me the "just works" feeling when I started using qemu.
And I really don't plan to use management tools in future.

Kevin

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

* Re: [Qemu-devel] [PATCH 3/4] Stellaris machine config
  2009-06-11 16:32     ` Jamie Lokier
@ 2009-06-12  8:29       ` Gerd Hoffmann
  2009-06-12 13:56         ` Markus Armbruster
  2009-06-12 13:53       ` Markus Armbruster
  1 sibling, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-06-12  8:29 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: qemu-devel, M P, Paul Brook

> I guess FDT is missing a "#include" equivalent, and possibly name
> constants.

See: 
http://git.jdl.com/gitweb/?p=dtc.git;a=blob;f=Documentation/manual.txt;h=f8a8a7b482e3a2a1501614c94fa0ea87aeb3a9e7;hb=HEAD

There is:

/include/ "filename"

> But for QEMU, some way to give names to, say, a standard SoC or a
> basic board, or a PC without peripherals, and then refer to them in
> another FDT tree, would be useful.

Yes, that must be solved somehow.  Just punting the issue to the vm 
management software isn't acceptable IMHO.

I'm not sure includes will solve that issue.  What we need is more a 
tree merge, i.e. you could have basic config files for a few pc variants 
without devices (i.e. isapc, pc) and config files snippets for devices 
(ide interface foo, sound card bar, ...).  Then you need some way to 
merge the latter into the former.

Even that solves only a part of the problem.  For some options you 
effectively have to edit the device tree:

-m <mem>
   You have edit memory@0 node.  You even might have to add a node
   depending on the amount of memory (i.e. one for the memory below
   4G one for the memory above ...).

-cpu <cpu>
   You have to edit the cpu node.

-smp <n>
   You have to insert cpu nodes.

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-10 17:38 [Qemu-devel] [PATCH 0/4] Machine config files Paul Brook
                   ` (5 preceding siblings ...)
  2009-06-11 12:53 ` Gerd Hoffmann
@ 2009-06-12 13:37 ` Markus Armbruster
  2009-06-12 14:44   ` Gerd Hoffmann
  6 siblings, 1 reply; 61+ messages in thread
From: Markus Armbruster @ 2009-06-12 13:37 UTC (permalink / raw)
  To: qemu-devel

Paul Brook <paul@codesourcery.com> writes:

> The following series implements machine config files, and adds converts
> some of the existing hardcoded machines.
>
> The config files themselves are based on the ppc-linux Flattened Device Trees.
> In generaly I've tried to structure things so that the same config file can
> be used for both qemu and linux.

This means the configuration file is binary.

It can be compiled from source with dtc, which doesn't seem to be
included in the patch series.  The language accepted by dtc is pretty
low-level: it talks NUL-terminates strings, byte strings and arrays of
"cells" (32 bit integers).

This leaves compiling from configuration concepts like "physical address
range", "interrupt" and so forth to FDT concepts like "array of cell" to
the user.

For instance, to specify an physical address range of 0x7f00000 bytes
starting at 0x100000, you say

    #address-cells = <1>;
    #size-cells  = <1>;
    reg = <0x100000 0x7f00000>

except when you're dealing with 64 bit physical address space, where it
becomes

    #address-cells = <2>;
    #size-cells  = <2>;
    reg = <0 0x100000 0 0x7f00000>

Not sure I got the endianess right.

To specify 8 bytes of ISA I/O space starting at 0x3f8, you say

    #address-cells = <2>;
    #size-cells = <1>;
    reg = <1 0x000002f8 0x00000008>;

The "1" in there means I/O space.  It's defined in the IEEE 1275 binding
document for ISA.

To specify ISA interrupt 4, you do:

    #interrupt-cells = <2>;
    interrupts = <4 3>;

The "3" encodes the interrupt type (level vs. edge; can't be bothered to
look up the number right now).

The various PCI addresses are "fun", too, and covered by their own
binding document.

Is that really what we want for a configuration file?

[...]

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-12  7:51     ` Kevin Wolf
@ 2009-06-12 13:49       ` Markus Armbruster
  2009-06-12 14:22         ` Kevin Wolf
  0 siblings, 1 reply; 61+ messages in thread
From: Markus Armbruster @ 2009-06-12 13:49 UTC (permalink / raw)
  To: qemu-devel

Kevin Wolf <mail@kevin-wolf.de> writes:

> Paul Brook schrieb:
>> On Thursday 11 June 2009, Gerd Hoffmann wrote:
>>> On 06/10/09 19:38, Paul Brook wrote:
>>>> The following series implements machine config files, and adds converts
>>>> some of the existing hardcoded machines.
>>> Hmm.  The converted machine types have a pretty static configuration,
>>> i.e. where you don't need to specify more that just "-M type" on the
>>> command line.
>>>
>>> What is the plan for machines which can be configured in alot of
>>> different ways such as a typical PC?  Where you can configure lots of
>>> details such as cpu, memory, nic, disk drives, ... using command line
>>> options?
>> 
>> I don't believe most of these things should be configured by commandline 
>> options. It's only done that way because we don't have any alternative (i.e. a 
>> machine config file). If you really want full control, I expect your VM 
>> manager will generate the machine config for you.
>
>>From my perspective as a qemu user, I definitely don't want to miss the
> command line options. Not having to create configuration files is
> exactly what gave me the "just works" feeling when I started using qemu.
> And I really don't plan to use management tools in future.
>
> Kevin

I understand where you come from.  For me, configuration files are fine.
What I don't want is having to copy a lengthy configuration file just to
add a device.  Because that leads to zillions of copies with little
differences here and there, and much diffing and merging on upgrade.

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

* Re: [Qemu-devel] [PATCH 3/4] Stellaris machine config
  2009-06-11 16:32     ` Jamie Lokier
  2009-06-12  8:29       ` Gerd Hoffmann
@ 2009-06-12 13:53       ` Markus Armbruster
  2009-06-12 15:25         ` Jamie Lokier
  1 sibling, 1 reply; 61+ messages in thread
From: Markus Armbruster @ 2009-06-12 13:53 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: qemu-devel, M P, Paul Brook

Jamie Lokier <jamie@shareable.org> writes:

> M P wrote:
>> So now, with qdev, it's all official, /every value, constant, and
>> bitfield/ is hard coded, in hex, into a different non-code file, with
>> no way of derivating or overloading from.
> [...]
>> In fact,
>> the stellaris share /a lot/ between themselves, and there is not a
>> single shared line between your two stellaris boards definition file.
>
> This is a good point.
>
> I guess FDT is missing a "#include" equivalent, and possibly name
> constants.
>
> That isn't surprising given FDT's original use, to pass an entire
> machine description to a running kernel.
>
> But for QEMU, some way to give names to, say, a standard SoC or a
> basic board, or a PC without peripherals, and then refer to them in
> another FDT tree, would be useful.
>
> Whether it's done in QEMU itself or by preprocessing doesn't matter.
> Preprocessing would have the advantage that it would output FDTs that
> could, maybe, be passed to the guest kernel and just work.  Or maybe
> QEMU can have a tree preprocessor built in.
>
> -- Jamie

The need for an FDT to pass to the kernel doesn't dictate that we must
use it as configuration file.  FDT could be generated from the internal
machine description.

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

* Re: [Qemu-devel] [PATCH 3/4] Stellaris machine config
  2009-06-12  8:29       ` Gerd Hoffmann
@ 2009-06-12 13:56         ` Markus Armbruster
  0 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2009-06-12 13:56 UTC (permalink / raw)
  To: qemu-devel

Gerd Hoffmann <kraxel@redhat.com> writes:

>> I guess FDT is missing a "#include" equivalent, and possibly name
>> constants.
>
> See:
> http://git.jdl.com/gitweb/?p=dtc.git;a=blob;f=Documentation/manual.txt;h=f8a8a7b482e3a2a1501614c94fa0ea87aeb3a9e7;hb=HEAD
>
> There is:
>
> /include/ "filename"
>
>> But for QEMU, some way to give names to, say, a standard SoC or a
>> basic board, or a PC without peripherals, and then refer to them in
>> another FDT tree, would be useful.
>
> Yes, that must be solved somehow.  Just punting the issue to the vm
> management software isn't acceptable IMHO.
>
> I'm not sure includes will solve that issue.  What we need is more a
> tree merge, i.e. you could have basic config files for a few pc
> variants without devices (i.e. isapc, pc) and config files snippets
> for devices (ide interface foo, sound card bar, ...).  Then you need
> some way to merge the latter into the former.
>
> Even that solves only a part of the problem.  For some options you
> effectively have to edit the device tree:
>
> -m <mem>
>   You have edit memory@0 node.  You even might have to add a node
>   depending on the amount of memory (i.e. one for the memory below
>   4G one for the memory above ...).
>
> -cpu <cpu>
>   You have to edit the cpu node.
>
> -smp <n>
>   You have to insert cpu nodes.
>
> cheers,
>   Gerd

For what it's worth, that's how my prototype worked.  Start with a
minimal, fixed tree for the machine type, then edit it according to
options.

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-12 13:49       ` Markus Armbruster
@ 2009-06-12 14:22         ` Kevin Wolf
  2009-06-12 14:40           ` Markus Armbruster
  2009-06-12 15:02           ` Anthony Liguori
  0 siblings, 2 replies; 61+ messages in thread
From: Kevin Wolf @ 2009-06-12 14:22 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

Markus Armbruster schrieb:
> Kevin Wolf <mail@kevin-wolf.de> writes:
> 
>> Paul Brook schrieb:
>>> On Thursday 11 June 2009, Gerd Hoffmann wrote:
>>>> On 06/10/09 19:38, Paul Brook wrote:
>>>>> The following series implements machine config files, and adds converts
>>>>> some of the existing hardcoded machines.
>>>> Hmm.  The converted machine types have a pretty static configuration,
>>>> i.e. where you don't need to specify more that just "-M type" on the
>>>> command line.
>>>>
>>>> What is the plan for machines which can be configured in alot of
>>>> different ways such as a typical PC?  Where you can configure lots of
>>>> details such as cpu, memory, nic, disk drives, ... using command line
>>>> options?
>>> I don't believe most of these things should be configured by commandline 
>>> options. It's only done that way because we don't have any alternative (i.e. a 
>>> machine config file). If you really want full control, I expect your VM 
>>> manager will generate the machine config for you.
>> >From my perspective as a qemu user, I definitely don't want to miss the
>> command line options. Not having to create configuration files is
>> exactly what gave me the "just works" feeling when I started using qemu.
>> And I really don't plan to use management tools in future.
> 
> I understand where you come from.  For me, configuration files are fine.

Don't get me wrong, I'm not against configuration files. Having them is
great and probably I'd even find some uses for them occasionally. I just
don't want to be _forced_ to use them which I fear is what Paul is
talking about.

> What I don't want is having to copy a lengthy configuration file just to
> add a device.  Because that leads to zillions of copies with little
> differences here and there, and much diffing and merging on upgrade.

Sure, couldn't agree more, but this is a different story. The solution
for my problem is to retain command line options, the solution for your
problem is some mechanism to have a config that adds devices to an
existing base config (or changes options, removes devices, whatever).

Probably my command line switches would use the same mechanism
internally, but I don't really care. I'm just a random qemu user in this
discussion. ;-)

Kevin

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-12 14:22         ` Kevin Wolf
@ 2009-06-12 14:40           ` Markus Armbruster
  2009-06-12 15:02           ` Anthony Liguori
  1 sibling, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2009-06-12 14:40 UTC (permalink / raw)
  To: qemu-devel

Kevin Wolf <mail@kevin-wolf.de> writes:

> Markus Armbruster schrieb:
>> Kevin Wolf <mail@kevin-wolf.de> writes:
>> 
>>> Paul Brook schrieb:
>>>> On Thursday 11 June 2009, Gerd Hoffmann wrote:
>>>>> On 06/10/09 19:38, Paul Brook wrote:
>>>>>> The following series implements machine config files, and adds converts
>>>>>> some of the existing hardcoded machines.
>>>>> Hmm.  The converted machine types have a pretty static configuration,
>>>>> i.e. where you don't need to specify more that just "-M type" on the
>>>>> command line.
>>>>>
>>>>> What is the plan for machines which can be configured in alot of
>>>>> different ways such as a typical PC?  Where you can configure lots of
>>>>> details such as cpu, memory, nic, disk drives, ... using command line
>>>>> options?
>>>> I don't believe most of these things should be configured by commandline 
>>>> options. It's only done that way because we don't have any alternative (i.e. a 
>>>> machine config file). If you really want full control, I expect your VM 
>>>> manager will generate the machine config for you.
>>> >From my perspective as a qemu user, I definitely don't want to miss the
>>> command line options. Not having to create configuration files is
>>> exactly what gave me the "just works" feeling when I started using qemu.
>>> And I really don't plan to use management tools in future.
>> 
>> I understand where you come from.  For me, configuration files are fine.
>
> Don't get me wrong, I'm not against configuration files. Having them is
> great and probably I'd even find some uses for them occasionally. I just
> don't want to be _forced_ to use them which I fear is what Paul is
> talking about.
>
>> What I don't want is having to copy a lengthy configuration file just to
>> add a device.  Because that leads to zillions of copies with little
>> differences here and there, and much diffing and merging on upgrade.
>
> Sure, couldn't agree more, but this is a different story. The solution

It is a different story, and I consider both stories valid.

> for my problem is to retain command line options, the solution for your
> problem is some mechanism to have a config that adds devices to an
> existing base config (or changes options, removes devices, whatever).
>
> Probably my command line switches would use the same mechanism
> internally, but I don't really care. I'm just a random qemu user in this
> discussion. ;-)

Yes, it would be nice if monitor commands, command line options and
configuration file directives to add devices were all frontends to the
same code.

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-12 13:37 ` Markus Armbruster
@ 2009-06-12 14:44   ` Gerd Hoffmann
  2009-06-12 15:58     ` Markus Armbruster
  2009-06-12 16:11     ` [Qemu-devel] " Jan Kiszka
  0 siblings, 2 replies; 61+ messages in thread
From: Gerd Hoffmann @ 2009-06-12 14:44 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

On 06/12/09 15:37, Markus Armbruster wrote:
> It can be compiled from source with dtc, which doesn't seem to be
> included in the patch series.  The language accepted by dtc is pretty
> low-level: it talks NUL-terminates strings, byte strings and arrays of
> "cells" (32 bit integers).

[ a bunch of examples snipped ]

> Is that really what we want for a configuration file?

I do see a point in using fdt as qemu-internal representation.  ppc 
needs it anyway.  It is also a nice way to store the guest configuration 
for save/load and migration, you can just send the blob over the wire. 
And we can hide the details such as cells behind some nifty helper 
functions.

Qemu users should not be required to be fdt experts though.  We need 
another, more user-friendly interface to configure virtual machines.

libfdt has functions to modify the device tree.  I think we will need 
them to keep the fdt in sync with the machine configuration when 
hot-plugging in and out devices (otherwise the fdt is useless for 
migration).  So when we have code to handle the fdt updates triggered by 
the "drive_add ..." monitor command anyway, also handling the -drive 
command line switch (or the same input from a more userfriendly machine 
config file) should be easy.

cheers,
   Gerd

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-12 14:22         ` Kevin Wolf
  2009-06-12 14:40           ` Markus Armbruster
@ 2009-06-12 15:02           ` Anthony Liguori
  2009-06-12 15:29             ` Kevin Wolf
  2009-06-12 16:35             ` Blue Swirl
  1 sibling, 2 replies; 61+ messages in thread
From: Anthony Liguori @ 2009-06-12 15:02 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Markus Armbruster, qemu-devel

Kevin Wolf wrote:
> Markus Armbruster schrieb:
>   
> Don't get me wrong, I'm not against configuration files. Having them is
> great and probably I'd even find some uses for them occasionally. I just
> don't want to be _forced_ to use them which I fear is what Paul is
> talking about.
>   

What we need is a command line option that can be used to manipulate a 
device tree.  All of the existing options could then be implemented in 
terms of the former option.

There will probably be a lot of things in the future that you can only 
do via device tree manipulation.  I don't see any reason why not to add 
convenient syntax though for the most common things.

Regards,

Anthony Liguori

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

* Re: [Qemu-devel] [PATCH 3/4] Stellaris machine config
  2009-06-12 13:53       ` Markus Armbruster
@ 2009-06-12 15:25         ` Jamie Lokier
  0 siblings, 0 replies; 61+ messages in thread
From: Jamie Lokier @ 2009-06-12 15:25 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, M P, Paul Brook

Markus Armbruster wrote:
> The need for an FDT to pass to the kernel doesn't dictate that we must
> use it as configuration file.  FDT could be generated from the internal
> machine description.

I agree and that might be nicer in the end, if FDTs turn out to be an
inconvenient representation of QEMU devices.

I would not be surprised if we start with FDTs, and then gradually
modify the FDT code to get "QEMU FDTs", and eventually evolve to
something everyone likes :-)

-- Jamie

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-12 15:02           ` Anthony Liguori
@ 2009-06-12 15:29             ` Kevin Wolf
  2009-06-12 16:35             ` Blue Swirl
  1 sibling, 0 replies; 61+ messages in thread
From: Kevin Wolf @ 2009-06-12 15:29 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Markus Armbruster, qemu-devel

Anthony Liguori schrieb:
> Kevin Wolf wrote:
>> Markus Armbruster schrieb:
>>   
>> Don't get me wrong, I'm not against configuration files. Having them is
>> great and probably I'd even find some uses for them occasionally. I just
>> don't want to be _forced_ to use them which I fear is what Paul is
>> talking about.
>>   
> 
> What we need is a command line option that can be used to manipulate a 
> device tree.  All of the existing options could then be implemented in 
> terms of the former option.

I like this idea of a generic device tree manipulation option. Could
come in handy for small ad-hoc modifications to the default config.

> There will probably be a lot of things in the future that you can only 
> do via device tree manipulation.  I don't see any reason why not to add 
> convenient syntax though for the most common things.

Having to use the generic option or a config file for the more obscure
things is absolutely fine with me as long as I can still change the
memory size, network cards and so on using the existing (more or less
obvious) options.

Kevin

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-12 14:44   ` Gerd Hoffmann
@ 2009-06-12 15:58     ` Markus Armbruster
  2009-06-12 16:11     ` [Qemu-devel] " Jan Kiszka
  1 sibling, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2009-06-12 15:58 UTC (permalink / raw)
  To: qemu-devel

Gerd Hoffmann <kraxel@redhat.com> writes:

> On 06/12/09 15:37, Markus Armbruster wrote:
>> It can be compiled from source with dtc, which doesn't seem to be
>> included in the patch series.  The language accepted by dtc is pretty
>> low-level: it talks NUL-terminates strings, byte strings and arrays of
>> "cells" (32 bit integers).
>
> [ a bunch of examples snipped ]
>
>> Is that really what we want for a configuration file?
>
> I do see a point in using fdt as qemu-internal representation.

I was talking about configuration file usability.  Internal
representation is a different matter.

>                                                                 ppc
> needs it anyway.

Could be generated from whatever internal representation we use.

>                   It is also a nice way to store the guest
> configuration for save/load and migration, you can just send the blob
> over the wire. And we can hide the details such as cells behind some
> nifty helper functions.

I agree we need the tree flattened to send it to disk or over the wire.
Keeping it flattened all the time could make certain tree editing jobs
more cumbersome.  We'll see.

> Qemu users should not be required to be fdt experts though.  We need
> another, more user-friendly interface to configure virtual machines.

Yup.

[...]

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

* [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-06-12 14:44   ` Gerd Hoffmann
  2009-06-12 15:58     ` Markus Armbruster
@ 2009-06-12 16:11     ` Jan Kiszka
  2009-07-06 12:49       ` Michael S. Tsirkin
  1 sibling, 1 reply; 61+ messages in thread
From: Jan Kiszka @ 2009-06-12 16:11 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: Markus Armbruster, qemu-devel

Gerd Hoffmann wrote:
> On 06/12/09 15:37, Markus Armbruster wrote:
>> It can be compiled from source with dtc, which doesn't seem to be
>> included in the patch series.  The language accepted by dtc is pretty
>> low-level: it talks NUL-terminates strings, byte strings and arrays of
>> "cells" (32 bit integers).
> 
> [ a bunch of examples snipped ]
> 
>> Is that really what we want for a configuration file?
> 
> I do see a point in using fdt as qemu-internal representation.  ppc
> needs it anyway.  It is also a nice way to store the guest configuration
> for save/load and migration, you can just send the blob over the wire.
> And we can hide the details such as cells behind some nifty helper
> functions.
> 
> Qemu users should not be required to be fdt experts though.  We need
> another, more user-friendly interface to configure virtual machines.
> 
> libfdt has functions to modify the device tree.  I think we will need
> them to keep the fdt in sync with the machine configuration when
> hot-plugging in and out devices (otherwise the fdt is useless for
> migration).  So when we have code to handle the fdt updates triggered by
> the "drive_add ..." monitor command anyway, also handling the -drive
> command line switch (or the same input from a more userfriendly machine
> config file) should be easy.

And if you factor out that code so that a stand-alone tool, say
'qemu-config' could use it too, you would have a way to generate such
files: Simply pass the well-known command line switches to that tool and
let it generate the corresponding config file for you. That file could
then be stuffed into qemu on startup again, maybe temporarily customized
by additional command line switches. Of course, the qemu-config tool
could also read existing configs and modify them according to the
specified wishes.

Not having thought too much about this whole topic, such a path sounds
quite handy for me, specifically as I do not use fancy front-ends for
daily work either.

Jan

-- 
Siemens AG, Corporate Technology, CT SE 2
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [PATCH 2/4] Add device tree machine
  2009-06-10 17:38 ` [Qemu-devel] [PATCH 2/4] Add device tree machine Paul Brook
                     ` (2 preceding siblings ...)
  2009-06-11 13:33   ` Gerd Hoffmann
@ 2009-06-12 16:25   ` Markus Armbruster
  3 siblings, 0 replies; 61+ messages in thread
From: Markus Armbruster @ 2009-06-12 16:25 UTC (permalink / raw)
  To: qemu-devel

Paul Brook <paul@codesourcery.com> writes:

> FDT based machine creation.
> When -M foo is specified look for and use foo.fdb.
> Build and ship board configs.
>
> Signed-off-by: Paul Brook <paul@codesourcery.com>
> ---
>
>  .gitignore                |    1 
>  Makefile                  |   20 +-
>  Makefile.target           |    5 
>  configure                 |   17 +
>  hw/arm-cpu.c              |   78 ++++++
>  hw/arm_boot.c             |   22 ++
>  hw/boards.h               |    9 +
>  hw/dt-machine.c           |  582 +++++++++++++++++++++++++++++++++++++++++++++
>  hw/i2c.c                  |    8 +
>  hw/pci.c                  |    1 
>  hw/qdev.c                 |  225 +++++++++++++++++
>  hw/qdev.h                 |   50 +++-
>  hw/ssi.c                  |    7 -
>  hw/syborg.c               |  112 ---------
>  hw/sysbus.c               |    5 
>  hw/sysbus.h               |   15 +
>  pc-bios/boards/syborg.dts |  134 ++++++++++
>  rules.mak                 |    3 
>  sysemu.h                  |    3 
>  vl.c                      |   45 +++
>  20 files changed, 1179 insertions(+), 163 deletions(-)
>  create mode 100644 hw/arm-cpu.c
>  create mode 100644 hw/dt-machine.c
>  delete mode 100644 hw/syborg.c
>  create mode 100644 pc-bios/boards/syborg.dts
>
[...]
> diff --git a/configure b/configure
> index 59ba8ef..f20da35 100755
> --- a/configure
> +++ b/configure
> @@ -199,6 +199,7 @@ sdl="yes"
>  sdl_x11="no"
>  xen="yes"
>  pkgversion=""
> +dtc=""
>  
>  # OS specific
>  if check_define __linux__ ; then
> @@ -503,6 +504,8 @@ for opt do
>    ;;
>    --with-pkgversion=*) pkgversion=" ($optarg)"
>    ;;
> +  --with-dtc=*) dtc="$optarg"
> +  ;;
>    --disable-docs) build_docs="no"
>    ;;
>    *) echo "ERROR: unknown option $opt"; show_help="yes"
> @@ -1227,6 +1230,13 @@ if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC -lfdt 2> /dev/null > /dev/null ;
>    build_fdt=no
>  fi
>  
> +# Check for device tree compiler
> +if test -z "$dtc" ; then
> +  dtc="`which dtc 2>/dev/null`"
> +  if test ! -x "$dtc" ; then
> +    dtc=""
> +  fi
> +fi

New build dependency.  Fine with me.

>  #
>  # Check for xxxat() functions when we are building linux-user
>  # emulator.  This is done because older glibc versions don't
> @@ -1380,6 +1390,7 @@ echo "Install blobs     $blobs"
>  echo -e "KVM support       $kvm"
>  echo "Build libfdt      $build_fdt"
>  echo "preadv support    $preadv"
> +echo "dtc               ${dtc:-(Not Found)}"
>  
>  if test $sdl_too_old = "yes"; then
>  echo "-> Your SDL version is too old - please upgrade to have SDL support"
> @@ -1708,7 +1719,7 @@ if test "$iovec" = "yes" ; then
>    echo "#define HAVE_IOVEC 1" >> $config_h
>  fi
>  if test "$preadv" = "yes" ; then
> -  echo "#define HAVE_PREADV 1" >> $config_h
> +  echo "#defne HAVE_PREADV 1" >> $config_h
>  fi
>  if test "$build_fdt" = "yes" ; then
>    echo "BUILD_LIBFDT=libfdt/libfdt.a" >> $config_mak
> @@ -1717,6 +1728,10 @@ else
>    echo "FDT_LIBS=-lfdt" >> $config_mak
>  fi
>  
> +if [ -n "$dtc" ] ; then
> +  echo "DTC=$dtc" >> $config_mak
> +fi
> +
>  # XXX: suppress that
>  if [ "$bsd" = "yes" ] ; then
>    echo "#define O_LARGEFILE 0" >> $config_h
[...]
> diff --git a/hw/dt-machine.c b/hw/dt-machine.c
> new file mode 100644
> index 0000000..b960a6c
> --- /dev/null
> +++ b/hw/dt-machine.c
> @@ -0,0 +1,582 @@
> +#include "sysbus.h"
> +#include "device_tree.h"
> +#include "boards.h"
> +
> +#include <libfdt.h>
> +
> +/* FIXME: Remove this.  */
> +static void *the_dt;
> +static int bootstrap_offset;
> +
> +static void dt_walk_bus(DeviceState *parent, void *dt, int offset, int folded);
> +
> +static int fdt_next_node(const void *fdt, int offset)
> +{
> +    int level = 1;
> +    uint32_t tag;
> +    int nextoffset;
> +
> +    tag = fdt_next_tag(fdt, offset, &nextoffset);
> +    if (tag != FDT_BEGIN_NODE)
> +        return -FDT_ERR_BADOFFSET;
> +
> +    while (level >= 0) {
> +        offset = nextoffset;
> +        tag = fdt_next_tag(fdt, offset, &nextoffset);
> +
> +        switch (tag) {
> +        case FDT_END:
> +            return -FDT_ERR_TRUNCATED;
> +        case FDT_BEGIN_NODE:
> +            level++;
> +            if (level == 1)
> +                return offset;
> +            break;
> +        case FDT_END_NODE:
> +            level--;
> +            break;
> +        case FDT_PROP:
> +        case FDT_NOP:
> +            break;
> +        default:
> +            return -FDT_ERR_BADSTRUCTURE;
> +        }
> +    }
> +
> +    return -FDT_ERR_NOTFOUND;
> +}
> +
> +static int fdt_first_subnode(const void *fdt, int offset)
> +{
> +    uint32_t tag;
> +    int nextoffset;
> +
> +    tag = fdt_next_tag(fdt, offset, &nextoffset);
> +    if (tag != FDT_BEGIN_NODE)
> +        return -FDT_ERR_BADOFFSET;
> +
> +    while (tag != FDT_END_NODE) {
> +        offset = nextoffset;
> +        tag = fdt_next_tag(fdt, offset, &nextoffset);
> +
> +        switch (tag) {
> +        case FDT_END:
> +            return -FDT_ERR_TRUNCATED;
> +        case FDT_BEGIN_NODE:
> +            return offset;
> +        case FDT_END_NODE:
> +        case FDT_PROP:
> +        case FDT_NOP:
> +            break;
> +        default:
> +            return -FDT_ERR_BADSTRUCTURE;
> +        }
> +    }
> +
> +    return -FDT_ERR_NOTFOUND;
> +}
> +
> +static void dt_add_props(DeviceState *dev, void *dt, int offset)
> +{
> +    DevicePropList *prop;
> +    const void *p;
> +    int prop_len;
> +    uint64_t i;
> +    const uint32_t *ip;
> +
> +    prop = qdev_get_proplist(dev);
> +    if (!prop) {
> +        return;
> +    }
> +    for (; prop->name; prop++) {
> +        p = fdt_getprop(dt, offset, prop->name, &prop_len);
> +        if (!p) {
> +            continue;
> +        }
> +        ip = p;
> +        switch (prop->type) {
> +        case PROP_TYPE_INT:
> +            if (prop_len != 4 && prop_len != 8) {
> +                hw_error("%s: Bad length for property '%s'\n",
> +                         fdt_get_name(dt, offset, NULL), prop->name);
> +            }
> +            i = fdt32_to_cpu(ip[0]);
> +            if (prop_len == 8) {
> +                i = (i << 32) | fdt32_to_cpu(ip[1]);
> +            }
> +            qdev_set_prop_int(dev, prop->name, i);
> +            break;
> +        case PROP_TYPE_DEV:
> +            {
> +                uint32_t phandle;
> +                DeviceState *other_dev;
> +                if (prop_len != 4) {
> +                    hw_error("%s: Bad length for property '%s'\n",
> +                             fdt_get_name(dt, offset, NULL), prop->name);
> +                }
> +                phandle = fdt32_to_cpu(ip[0]);
> +                other_dev = qdev_from_phandle(phandle);
> +                if (!other_dev) {
> +                    hw_error("%s: Device (%d) not found\n",
> +                             fdt_get_name(dt, offset, NULL), phandle);
> +                }
> +                qdev_set_prop_dev(dev, prop->name, other_dev);
> +            }
> +            break;
> +        case PROP_TYPE_ARRAY:
> +            {
> +                uint32_t *data;
> +                if (prop_len & 3) {
> +                    hw_error("%s: Bad length for property '%s'\n",
> +                             fdt_get_name(dt, offset, NULL), prop->name);
> +                }
> +                data = qemu_malloc(prop_len);
> +                for (i = 0; i < prop_len >> 2; i++) {
> +                    data[i] = fdt32_to_cpu(ip[i]);
> +                }
> +                qdev_set_prop_array(dev, prop->name, data, prop_len >> 2);
> +                qemu_free(data);
> +            }
> +            break;
> +        default:
> +            abort();
> +        }
> +    }
> +}

Here you copy the device's known properties from FDT to the
qdev->props.

Why have a dynamically typed property list in qdev?  Why not make the
properties ordinary members of the device struct, and have the property
descriptor DevicePropList specify where they are (offset from qdev)?
Moves some type checking to compile-time.

Alternatively, why not get the properties straight from FDT, as Gerd
suggested?

> +
> +static void dt_create_device(BusState *bus, void *dt, int offset)
> +{
> +    char namebuf[128];
> +    const char *type;
> +    const uint32_t *prop;
> +    char *p;
> +    DeviceState *dev;
> +
> +    /* First try the "model" property.  */
> +    type = fdt_getprop(dt, offset, "model", NULL);
> +    if (type && !qdev_device_exists(type)) {
> +        type = NULL;
> +    }
> +    /* If that does not work then try "compatible".  */
> +    if (!type) {
> +        type = fdt_getprop(dt, offset, "compatible", NULL);
> +        if (type && !qdev_device_exists(type)) {
> +            type = NULL;
> +        }
> +    }
> +    /* If all else fails then resort to the device name.  */
> +    if (!type) {
> +        type = fdt_get_name(dt, offset, NULL);
> +        p = namebuf;
> +        while (*type && *type != '@') {
> +            *(p++) = *(type++);
> +        }
> +        *p = 0;
> +        if (!qdev_device_exists(namebuf)) {
> +            hw_error("Unrecognised device '%s'\n",
> +                     fdt_get_name(dt, offset, NULL));
> +        }
> +        type = namebuf;
> +    }
> +
> +    dev = qdev_create(bus, type);
> +    dev->fdt_offset = offset;
> +    prop = fdt_getprop(dt, offset, "linux,phandle", NULL);
> +    if (prop) {
> +        dev->phandle = fdt32_to_cpu(*prop);
> +    } else {
> +        dev->phandle = -1;
> +    }
> +}
> +
> +static void dt_init_device(DeviceState *dev, void *opaque)
> +{
> +    void *dt = opaque;
> +    int offset;
> +
> +    offset = dev->fdt_offset;
> +    dt_add_props(dev, dt, offset);
> +    qdev_init(dev);
> +
> +    dt_walk_bus(dev, dt, offset, 0);
> +}
> +
> +static int dt_fold_bus(void *dt, int offset)
> +{
> +    const char *name = fdt_get_name(dt, offset, NULL);
> +
> +    if (strcmp(name, "cpus") == 0) {
> +        return 1;
> +    }
> +    if (fdt_getprop(dt, offset, "qemu,fold-bus", NULL)) {
> +        return 1;
> +    }
> +    return 0;
> +}

Please document all qemu,FOO properties.

> +
> +static int dt_ignore_node(void *dt, int offset)
> +{
> +    const char *name = fdt_get_name(dt, offset, NULL);
> +
> +    if (strcmp(name, "chosen") == 0) {
> +        return 1;
> +    }
> +    if (strcmp(name, "aliases") == 0) {
> +        return 1;
> +    }
> +    if (fdt_getprop(dt, offset, "qemu,ignore", NULL)) {
> +        return 1;
> +    }
> +    return 0;
> +}
> +
> +static void dt_get_sizes(void *dt, int offset,
> +                         int *addr_cells, int *size_cells)
> +{
> +    const uint32_t *prop;
> +    int parent;
> +
> +    parent = fdt_parent_offset(dt, offset);
> +    assert(parent >= 0);
> +
> +    if (addr_cells) {
> +        prop = fdt_getprop(dt, parent, "#address-cells", NULL);
> +        if (!prop) {
> +            hw_error("%s: Missing #address-cells",
> +                     fdt_get_name(dt, offset, NULL));
> +        }
> +        *addr_cells = fdt32_to_cpu(*prop);
> +    }
> +
> +    if (size_cells) {
> +        prop = fdt_getprop(dt, parent, "#size-cells", NULL);
> +        if (!prop) {
> +            hw_error("%s: Missing #size-cells",
> +                     fdt_get_name(dt, offset, NULL));
> +        }
> +        *size_cells = fdt32_to_cpu(*prop);
> +    }
> +}
> +
> +static void dt_create_memory(void *dt, int offset, int flags)
> +{
> +    const uint32_t *regs;
> +    int regs_len;
> +    const uint32_t *alias;
> +    int alias_len;
> +    int addr_cells;
> +    int size_cells;
> +    uint64_t addr;
> +    uint64_t size;
> +    ram_addr_t ram_offset;
> +
> +    dt_get_sizes(dt, offset, &addr_cells, &size_cells);
> +    regs = fdt_getprop(dt, offset, "reg", &regs_len);
> +    if (!regs || regs_len == 0) {
> +        return;
> +    }
> +    if ((regs_len % ((addr_cells + size_cells) * 4)) != 0) {
> +        hw_error("%s: Bad reg size\n", fdt_get_name(dt, offset, NULL));
> +    }
> +    alias = fdt_getprop(dt, offset, "qemu,alias", &alias_len);
> +    while (regs_len > 0) {
> +        addr = fdt32_to_cpu(*(regs++));
> +        if (addr_cells == 2) {
> +            addr = (addr << 32) | fdt32_to_cpu(*(regs++));
> +        }
> +        size = fdt32_to_cpu(*(regs++));
> +        if (size_cells == 2) {
> +            size = (size << 32) | fdt32_to_cpu(*(regs++));
> +        }
> +        regs_len -= (addr_cells + size_cells) * 4;
> +        if (size != (ram_addr_t)size) {
> +            hw_error("Ram too big\n");
> +        }
> +        ram_offset = qemu_ram_alloc(size);
> +        cpu_register_physical_memory(addr, size, ram_offset | flags);
> +        if (alias) {
> +            if (regs_len > 0) {
> +                hw_error("%s: Aliased memory may only have a single region",
> +                         fdt_get_name(dt, offset, NULL));
> +            }
> +            if ((alias_len % addr_cells) != 0) {
> +                hw_error("%s: Bad qemu,alias size\n",
> +                         fdt_get_name(dt, offset, NULL));
> +            }
> +            while (alias_len) {
> +                addr = fdt32_to_cpu(*(alias++));
> +                if (addr_cells== 2) {
> +                    addr = (addr << 32) | fdt32_to_cpu(*(alias++));
> +                }
> +                cpu_register_physical_memory(addr, size, ram_offset | flags);
> +                alias_len -= addr_cells * 4;
> +            }
> +        }
> +    }
> +}
> +
> +static void dt_walk_bus(DeviceState *parent, void *dt, int offset, int folded)

This seems to create the device tree for an FDT.  Not obvious from the
name.

> +{
> +    int next_offset;
> +    const char *type;
> +    const char *bus_name;
> +    BusState *parent_bus;
> +
> +    if (parent) {
> +        parent_bus = LIST_FIRST(&parent->child_bus);
> +    } else {
> +        parent_bus = NULL;
> +    }
> +    next_offset = fdt_first_subnode(dt, offset);
> +    while (next_offset > 0) {
> +        offset = next_offset;
> +        next_offset = fdt_next_node(dt, offset);
> +        if (dt_ignore_node(dt, offset)) {
> +            continue;
> +        }
> +        if (dt_fold_bus(dt, offset)) {
> +            dt_walk_bus(parent, dt, offset, 1);
> +            continue;
> +        }
> +        bus_name = fdt_getprop(dt, offset, "qemu,parent-bus", NULL);
> +        if (bus_name) {
> +            if (parent) {
> +                parent_bus = qdev_get_child_bus(parent, bus_name);
> +            }
> +            if (!parent_bus) {
> +                hw_error("%s: Unable to find parent bus\n",
> +                         fdt_get_name(dt, offset, NULL));
> +            }
> +        }
> +        type = fdt_getprop(dt, offset, "device_type", NULL);
> +        /* Special case for memory.  */
> +        if (type && strcmp(type, "memory") == 0) {
> +            dt_create_memory(dt, offset, IO_MEM_RAM);
> +            continue;
> +        }
> +        if (type && strcmp(type, "rom") == 0) {
> +            dt_create_memory(dt, offset, IO_MEM_ROM);
> +            continue;
> +        }
> +        dt_create_device(parent_bus, dt, offset);
> +    }
> +    if (!folded) {
> +        qdev_enumerate_child_devices(parent, dt_init_device, dt);
> +    }
> +}
> +
> +void dt_fixup_qdev(DeviceState *dev)
> +{
> +    void *dt = the_dt;
> +    int offset = dev->fdt_offset;
> +    int n;
> +    int prop_size;
> +    const uint32_t *prop;
> +
> +    if (dev->num_gpio_out) {
> +        int parent;
> +        int irqn;
> +        qemu_irq pin;
> +        DeviceState *parent_dev;
> +
> +        prop = fdt_getprop(dt, offset, "qemu,gpio", &prop_size);
> +        if (prop_size != 8 * dev->num_gpio_out) {
> +            hw_error("%s: Bad GPIO size\n", fdt_get_name(dt, offset, NULL));
> +        }
> +        for (n = 0; n < dev->num_gpio_out; n++) {
> +            parent = fdt32_to_cpu(*(prop++));
> +            if (parent == 0) {
> +                /* Assume zero phandle means disconnected.  */
> +                prop++;
> +                continue;
> +            }
> +            parent_dev = qdev_from_phandle(parent);
> +            if (!parent_dev) {
> +                hw_error("%s: GPIO device (%d) not found\n",
> +                         fdt_get_name(dt, offset, NULL), parent);
> +            }
> +            irqn = fdt32_to_cpu(*(prop++));
> +            if (irqn >= parent_dev->num_gpio_in) {
> +                hw_error("%s: Invalid GPIO %d (%d)\n",
> +                         fdt_get_name(dt, offset, NULL), n, irqn);
> +            }
> +            pin = qdev_get_gpio_in(parent_dev, irqn);
> +            qdev_connect_gpio_out(dev, n, pin);
> +        }
> +    }
> +}
> +
> +void dt_fixup_sysbus_device(DeviceState *dev)
> +{
> +    SysBusDevice *s = sysbus_from_qdev(dev);
> +    void *dt = the_dt;
> +    int offset = dev->fdt_offset;
> +    const uint32_t *prop;
> +    int prop_size;
> +    int n;
> +
> +    if (s->num_mmio) {
> +        int addr_cells;
> +        int size_cells;
> +        uint64_t addr;
> +        dt_get_sizes(dt, offset, &addr_cells, &size_cells);
> +        if (addr_cells < 1 || addr_cells > 2) {
> +            hw_error("%s: unsupported #address-cells (%d)\n",
> +                     fdt_get_name(dt, offset, NULL), addr_cells);
> +        }
> +        prop = fdt_getprop(dt, offset, "reg", &prop_size);
> +        if (prop_size != (addr_cells + size_cells) * 4 * s->num_mmio) {
> +            hw_error("%s: Bad reg size\n", fdt_get_name(dt, offset, NULL));
> +        }
> +        for (n = 0; n < s->num_mmio; n++) {
> +            addr = fdt32_to_cpu(*(prop++));
> +            if (addr_cells == 2) {
> +                addr = (addr << 32) | fdt32_to_cpu(*(prop++));
> +            }
> +            /* The device already told up how big the region is, so ignore
> +               what the device tree says.  */
> +            prop += size_cells;
> +            sysbus_mmio_map(s, n, addr);
> +        }
> +    }
> +
> +    if (s->num_irq) {
> +        int parent;
> +        int irqn;
> +        DeviceState *parent_dev;
> +
> +        prop = fdt_getprop(dt, offset, "interrupt-parent", &prop_size);
> +        if (!prop || prop_size != 4) {
> +            hw_error("%s: Missing/bad interrupt-parent\n",
> +                     fdt_get_name(dt, offset, NULL));
> +        }
> +        parent = fdt32_to_cpu(*prop);
> +        parent_dev = qdev_from_phandle(parent);
> +        if (!parent_dev) {
> +            hw_error("%s: interrupt-parent device (%d) not found\n",
> +                     fdt_get_name(dt, offset, NULL), parent);
> +        }
> +        prop = fdt_getprop(dt, parent_dev->fdt_offset, "#interrupt-cells",
> +                           &prop_size);
> +        if (!prop || prop_size != 4) {
> +            hw_error("%s: Missing #interrupt-cells\n",
> +                     fdt_get_name(dt, parent_dev->fdt_offset, NULL));
> +        }
> +        if (fdt32_to_cpu(*prop) != 1) {
> +            hw_error("%s: unsupported #interrupt-cells\n",
> +                     fdt_get_name(dt, parent_dev->fdt_offset, NULL));
> +        }
> +        prop = fdt_getprop(dt, offset, "interrupts", &prop_size);
> +        if (prop_size != 4 * s->num_irq) {
> +            hw_error("%s: Bad interrupts size\n",
> +                     fdt_get_name(dt, offset, NULL));
> +        }
> +        for (n = 0; n < s->num_irq; n++) {
> +            irqn = fdt32_to_cpu(*(prop++));
> +            if (irqn == -1) {
> +                continue;
> +            }
> +            if (irqn >= parent_dev->num_gpio_in) {
> +                hw_error("%s: Invalid interrupt %d (%d)\n",
> +                         fdt_get_name(dt, offset, NULL), n, irqn);
> +            }
> +            sysbus_connect_irq(s, n, qdev_get_gpio_in(parent_dev, irqn));
> +        }
> +    }
> +}
> +
> +typedef struct MachineBootstrap {
> +    const char *name;
> +    machine_bootstrapfn fn;
> +    LIST_ENTRY(MachineBootstrap) next;
> +} MachineBootstrap;
> +
> +LIST_HEAD(, MachineBootstrap) machine_bootstrap_list =
> +    LIST_HEAD_INITIALIZER(machine_bootstrap_list);
> +
> +void register_machine_bootstrap(const char *name, machine_bootstrapfn fn)
> +{
> +    MachineBootstrap *bootstrap;
> +
> +    bootstrap = qemu_mallocz(sizeof(*bootstrap));
> +    bootstrap->name = qemu_strdup(name);
> +    bootstrap->fn = fn;
> +    LIST_INSERT_HEAD(&machine_bootstrap_list, bootstrap, next);
> +}
> +
> +uint64_t get_bootstrap_arg_int(const char *name, uint64_t def)
> +{
> +    void *dt = the_dt;
> +    const uint32_t *p;
> +    int prop_len;
> +    uint64_t val;
> +
> +    p = fdt_getprop(dt, bootstrap_offset, name, &prop_len);
> +    if (!p) {
> +        return def;
> +    }
> +    if (prop_len != 4 && prop_len != 8) {
> +        hw_error("Bad length for property '%s'\n", name);
> +    }
> +    val = fdt32_to_cpu(p[0]);
> +    if (prop_len == 8) {
> +        val = (val << 32) | fdt32_to_cpu(p[1]);
> +    }
> +    return val;
> +}
> +
> +static void dt_init(ram_addr_t ram_size,
> +                     const char *boot_device,
> +                     const char *kernel_filename, const char *kernel_cmdline,
> +                     const char *initrd_filename, const char *cpu_model)
> +{
> +    void *dt;
> +    int dt_size;
> +    const char *filename;
> +
> +    filename = dt_machine.name;
> +    /* FIXME: Allow user to specify filename.  */
> +    dt = load_device_tree(filename, &dt_size);
> +    if (!dt) {
> +        hw_error("Failed to load device tree\n");
> +    }
> +
> +    the_dt = dt;
> +
> +    dt_walk_bus(NULL, dt, 0, 0);
> +
> +    qdev_fixup_devices();
> +
> +    {
> +    const char *p;
> +    MachineBootstrap *bootstrap;
> +
> +    bootstrap_offset = fdt_path_offset(dt, "/chosen/qemu");
> +    if (bootstrap_offset < 0) {
> +        return;
> +    }
> +    p = fdt_getprop(dt, bootstrap_offset, "bootstrap", NULL);
> +    if (!p) {
> +        return;
> +    }
> +
> +    LIST_FOREACH(bootstrap, &machine_bootstrap_list, next) {
> +        if (strcmp(bootstrap->name, p) == 0) {
> +            break;
> +        }
> +    }
> +    if (!bootstrap) {
> +        hw_error("Unrecognised machine bootstrap '%s'\n", p);
> +    }
> +    bootstrap->fn(ram_size, boot_device, kernel_filename, kernel_cmdline,
> +                  initrd_filename);
> +
> +    }
> +}
> +
> +/* This is used directly by vl.c, and not registered by normal means.  */
> +QEMUMachine dt_machine = {
> +    .name = "devtree",
> +    .desc = "Device Tree",
> +    .init = dt_init,
> +};
[...]
> diff --git a/hw/qdev.c b/hw/qdev.c
> index 636dc78..39e8ce8 100644
> --- a/hw/qdev.c
> +++ b/hw/qdev.c
> @@ -26,6 +26,25 @@
>     inherit from a particular bus (e.g. PCI or I2C) rather than
>     this API directly.  */
>  
> +/* Device instantiation occurs in several stages.
> +
> +   1) Device objects are created (qdev_create).
> +   2) Device properties are set.
> +   3) Device init routines are run.
> +   4) GPIO and IRQ lines are connected and MMIO regions are mapped.
> +   5) Device late init routines are run.

I see you discovered the need for a second initialization callback.
Good.

> +
> +   It can be assumed that all siblings on a bus have been created before
> +   any are initialized.  Child devices are created after the parent
> +   device is initialized.  Thus PROP_TYPE_DEV may only refer to siblings or
> +   siblings of direct ancestors.  No dependency tracking is performed, so
> +   a device may be initialized before the devices it references.
> +
> +   Other than Within each stage, devices are processed in arbitrary order.
> +
> +   Steps 3, 4 and 5 only occur after preceeding steps have been completed
> +   for all devices. */
> +
>  #include "net.h"
>  #include "qdev.h"
>  #include "sysemu.h"
> @@ -37,6 +56,10 @@ struct DeviceProperty {
>      union {
>          uint64_t i;
>          void *ptr;
> +        struct {
> +            uint32_t *data;
> +            int len;
> +        } array;
>      } value;
>      DeviceProperty *next;
>  };
> @@ -68,6 +91,23 @@ void qdev_register(const char *name, int size, DeviceInfo *info)
>      t->info = info;
>  }
>  
> +static DeviceType *qdev_find_devtype(const char *name)
> +{
> +    DeviceType *t;
> +
> +    for (t = device_type_list; t; t = t->next) {
> +        if (strcmp(t->name, name) == 0) {
> +            return t;;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +int qdev_device_exists(const char *name)
> +{
> +    return qdev_find_devtype(name) != NULL;
> +}
> +
>  /* Create a new device.  This only initializes the device state structure
>     and allows properties to be set.  qdev_init should be called to
>     initialize the actual device emulation.  */
> @@ -76,11 +116,7 @@ DeviceState *qdev_create(BusState *bus, const char *name)
>      DeviceType *t;
>      DeviceState *dev;
>  
> -    for (t = device_type_list; t; t = t->next) {
> -        if (strcmp(t->name, name) == 0) {
> -            break;
> -        }
> -    }
> +    t = qdev_find_devtype(name);
>      if (!t) {
>          hw_error("Unknown device '%s'\n", name);
>      }
> @@ -89,8 +125,8 @@ DeviceState *qdev_create(BusState *bus, const char *name)
>      dev->type = t;
>  
>      if (!bus) {
> -        /* ???: This assumes system busses have no additional state.  */
>          if (!main_system_bus) {
> +            /* ???: This assumes system busses have no additional state.  */
>              main_system_bus = qbus_create(BUS_TYPE_SYSTEM, sizeof(BusState),
>                                            NULL, "main-system-bus");
>          }
> @@ -102,7 +138,9 @@ DeviceState *qdev_create(BusState *bus, const char *name)
>                   t->info->bus_type, bus->type);
>      }
>      dev->parent_bus = bus;
> -    LIST_INSERT_HEAD(&bus->children, dev, sibling);
> +    /* Keep devices in creation order for consistency between creation
> +       and initialization passes.  */
> +    TAILQ_INSERT_TAIL(&bus->children, dev, sibling);
>      return dev;
>  }
>  
> @@ -114,10 +152,32 @@ void qdev_init(DeviceState *dev)
>      dev->type->info->init(dev, dev->type->info);
>  }
>  
> +static void qdev_late_init_bus(BusState *bus)
> +{
> +    DeviceState *dev;
> +    BusState *child_bus;
> +
> +    TAILQ_FOREACH(dev, &bus->children, sibling) {
> +        if (dev->type->info->late_init) {
> +            dev->type->info->late_init(dev);
> +        }
> +        LIST_FOREACH(child_bus, &dev->child_bus, sibling) {
> +            qdev_late_init_bus(child_bus);
> +        }
> +    }
> +}
> +
> +void qdev_do_late_init(void)
> +{
> +    if (main_system_bus) {
> +        qdev_late_init_bus(main_system_bus);
> +    }
> +}
> +
>  /* Unlink device from bus and free the structure.  */
>  void qdev_free(DeviceState *dev)
>  {
> -    LIST_REMOVE(dev, sibling);
> +    TAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
>      free(dev);
>  }
>  
> @@ -152,6 +212,17 @@ void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value)
>      prop->value.ptr = value;
>  }
>  
> +void qdev_set_prop_array(DeviceState *dev, const char *name, uint32_t *data,
> +                         int len)
> +{
> +    DeviceProperty *prop;
> +
> +    prop = create_prop(dev, name, PROP_TYPE_ARRAY);
> +    prop->value.array.data = qemu_malloc(len * 4);
> +    prop->value.array.len = len;
> +    memcpy(prop->value.array.data, data, len * 4);
> +}
> +
>  void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
>  {
>      DeviceProperty *prop;
> @@ -231,6 +302,21 @@ DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name)
>      return prop->value.ptr;
>  }
>  
> +int qdev_get_prop_array(DeviceState *dev, const char *name,
> +                        const uint32_t **p)
> +{
> +    DeviceProperty *prop;
> +
> +    prop = find_prop(dev, name, PROP_TYPE_ARRAY);
> +    if (!prop) {
> +        return -1;
> +    }
> +    if (p) {
> +        *p = prop->value.array.data;
> +    }
> +    return prop->value.array.len;
> +}
> +
>  void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
>  {
>      assert(dev->num_gpio_in == 0);
> @@ -272,6 +358,17 @@ VLANClientState *qdev_get_vlan_client(DeviceState *dev,
>  
>  void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
>  {
> +    static int next_netdev;
> +    if (!dev->nd) {
> +        /* FIXME: This is just plain broken.  */
> +        if (next_netdev >= nb_nics) {
> +            abort();
> +        }
> +        dev->nd = &nd_table[next_netdev];
> +        next_netdev++;
> +
> +        qemu_check_nic_model(dev->nd, dev->type->name);
> +    }
>      memcpy(macaddr, dev->nd->macaddr, 6);
>  }
>  
> @@ -332,13 +429,121 @@ BusState *qbus_create(BusType type, size_t size,
>      bus->type = type;
>      bus->parent = parent;
>      bus->name = qemu_strdup(name);
> -    LIST_INIT(&bus->children);
> +    TAILQ_INIT(&bus->children);
>      if (parent) {
>          LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
>      }
>      return bus;
>  }
>  
> +static DeviceState *qdev_from_phandle1(BusState *bus, uint32_t phandle)
> +{
> +    DeviceState *dev;
> +    BusState *child_bus;
> +    DeviceState *child_dev;
> +
> +    TAILQ_FOREACH(dev, &bus->children, sibling) {
> +        if (dev->phandle == phandle) {
> +            return dev;
> +        }
> +        LIST_FOREACH(child_bus, &dev->child_bus, sibling) {
> +            child_dev = qdev_from_phandle1(child_bus, phandle);
> +            if (child_dev) {
> +                return child_dev;
> +            }
> +        }
> +    }
> +    return NULL;
> +}
> +
> +DeviceState *qdev_from_phandle(uint32_t phandle)
> +{
> +    if (!main_system_bus) {
> +        return NULL;
> +    }
> +    return qdev_from_phandle1(main_system_bus, phandle);  
> +}
> +
> +static void qdev_fixup_bus(BusState *bus)
> +{
> +    DeviceState *dev;
> +
> +    TAILQ_FOREACH(dev, &bus->children, sibling) {
> +        if (!dev->fdt_offset) {
> +            continue;
> +        }
> +        dt_fixup_qdev(dev);
> +        switch (bus->type) {
> +        case BUS_TYPE_SYSTEM:
> +            dt_fixup_sysbus_device(dev);
> +            break;
> +        default:
> +            break;
> +        }
> +    }
> +}
> +
> +void qdev_fixup_devices(void)
> +{
> +    assert(main_system_bus);
> +    qdev_fixup_bus(main_system_bus);
> +}
> +
> +static void enumerate_bus_devices(BusState *bus, enumdevfn cb, void *opaque)
> +{
> +    DeviceState *dev;
> +
> +    TAILQ_FOREACH(dev, &bus->children, sibling) {
> +        cb(dev, opaque);
> +    }
> +}
> +
> +void qdev_enumerate_child_devices(DeviceState *dev, enumdevfn cb, void *opaque)
> +{
> +    BusState *bus;
> +
> +    if (!dev) {
> +        enumerate_bus_devices(main_system_bus, cb, opaque);
> +        return;
> +    }
> +    LIST_FOREACH(bus, &dev->child_bus, sibling) {
> +        enumerate_bus_devices(bus, cb, opaque);
> +    }
> +}
> +
> +DevicePropList *qdev_get_proplist(DeviceState *dev)
> +{
> +    return dev->type->info->props;
> +}
> +
> +DevicePropList *qdev_merge_props(const DevicePropList *a,
> +                                 const DevicePropList *b)
> +{
> +    int n;
> +    const DevicePropList *p;
> +    DevicePropList *q;
> +    DevicePropList *ret;
> +
> +    n = 0;
> +    for (p = a; p && p->name; p++) {
> +        n++;
> +    }
> +    for (p = b; p && p->name; p++) {
> +        n++;
> +    }
> +    n++;
> +    ret = qemu_malloc(sizeof(DevicePropList) * n);
> +    q = ret;
> +    for (p = a; p && p->name; p++) {
> +        *(q++) = *p;
> +    }
> +    for (p = b; p && p->name; p++) {
> +        *(q++) = *p;
> +    }
> +    q->name = NULL;
> +    return ret;
> +}
> +
>  static const char *bus_type_names[] = {
>      [ BUS_TYPE_SYSTEM ] = "System",
>      [ BUS_TYPE_PCI ]    = "PCI",
> @@ -399,7 +604,7 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent)
>      qdev_printf("bus: %s\n", bus->name);
>      indent += 2;
>      qdev_printf("type %s\n", bus_type_names[bus->type]);
> -    LIST_FOREACH(dev, &bus->children, sibling) {
> +    TAILQ_FOREACH(dev, &bus->children, sibling) {
>          qdev_print(mon, dev, indent);
>      }
>  }
[...]


There's a fair amount of IEEE-1275 gunk in here, which I believe QEMU
could well do without.  Being able to pass the config straight on to the
PowerPC kernel is nice, but I'm not at all sure that can justify the
gunk.

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

* Re: [Qemu-devel] [PATCH 0/4] Machine config files
  2009-06-12 15:02           ` Anthony Liguori
  2009-06-12 15:29             ` Kevin Wolf
@ 2009-06-12 16:35             ` Blue Swirl
  1 sibling, 0 replies; 61+ messages in thread
From: Blue Swirl @ 2009-06-12 16:35 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Kevin Wolf, Markus Armbruster, qemu-devel

On 6/12/09, Anthony Liguori <anthony@codemonkey.ws> wrote:
> Kevin Wolf wrote:
>
> > Markus Armbruster schrieb:
> >  Don't get me wrong, I'm not against configuration files. Having them is
> > great and probably I'd even find some uses for them occasionally. I just
> > don't want to be _forced_ to use them which I fear is what Paul is
> > talking about.
> >
> >
>
>  What we need is a command line option that can be used to manipulate a
> device tree.  All of the existing options could then be implemented in terms
> of the former option.
>
>  There will probably be a lot of things in the future that you can only do
> via device tree manipulation.  I don't see any reason why not to add
> convenient syntax though for the most common things.

-fdt_change /cpus/cpu@0/clock-frequency 0x20000000
-fdt_delete /plb/obp/serial@ef600400
-fdt_add /plb/obp/serial@ef600500 serial (this is complicated)

But I fear we would be replicating basic awk functionality.

An external tool for manipulating the tree may still be useful.

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-06-12 16:11     ` [Qemu-devel] " Jan Kiszka
@ 2009-07-06 12:49       ` Michael S. Tsirkin
  2009-07-06 13:43         ` Gerd Hoffmann
  0 siblings, 1 reply; 61+ messages in thread
From: Michael S. Tsirkin @ 2009-07-06 12:49 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: qemu-devel, Gerd Hoffmann, Markus Armbruster

On Fri, Jun 12, 2009 at 06:11:24PM +0200, Jan Kiszka wrote:
> Gerd Hoffmann wrote:
> > On 06/12/09 15:37, Markus Armbruster wrote:
> >> It can be compiled from source with dtc, which doesn't seem to be
> >> included in the patch series.  The language accepted by dtc is pretty
> >> low-level: it talks NUL-terminates strings, byte strings and arrays of
> >> "cells" (32 bit integers).
> > 
> > [ a bunch of examples snipped ]
> > 
> >> Is that really what we want for a configuration file?
> > 
> > I do see a point in using fdt as qemu-internal representation.  ppc
> > needs it anyway.  It is also a nice way to store the guest configuration
> > for save/load and migration, you can just send the blob over the wire.
> > And we can hide the details such as cells behind some nifty helper
> > functions.
> > 
> > Qemu users should not be required to be fdt experts though.  We need
> > another, more user-friendly interface to configure virtual machines.
> > 
> > libfdt has functions to modify the device tree.  I think we will need
> > them to keep the fdt in sync with the machine configuration when
> > hot-plugging in and out devices (otherwise the fdt is useless for
> > migration).  So when we have code to handle the fdt updates triggered by
> > the "drive_add ..." monitor command anyway, also handling the -drive
> > command line switch (or the same input from a more userfriendly machine
> > config file) should be easy.
> 
> And if you factor out that code so that a stand-alone tool, say
> 'qemu-config' could use it too, you would have a way to generate such
> files: Simply pass the well-known command line switches to that tool and
> let it generate the corresponding config file for you. That file could
> then be stuffed into qemu on startup again, maybe temporarily customized
> by additional command line switches. Of course, the qemu-config tool
> could also read existing configs and modify them according to the
> specified wishes.
> 
> Not having thought too much about this whole topic, such a path sounds
> quite handy for me, specifically as I do not use fancy front-ends for
> daily work either.
> 
> Jan

Can't we extend loadvm/savevm format to support machine config? It is
already supported by all devices, it seems that we just need to add some
detail such as pci addresses, and qemu flags to save/load this config.
No?

-- 
MST

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 12:49       ` Michael S. Tsirkin
@ 2009-07-06 13:43         ` Gerd Hoffmann
  2009-07-06 13:56           ` Michael S. Tsirkin
  0 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-07-06 13:43 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: Jan Kiszka, Markus Armbruster, qemu-devel

On 07/06/09 14:49, Michael S. Tsirkin wrote:
> On Fri, Jun 12, 2009 at 06:11:24PM +0200, Jan Kiszka wrote:
> Can't we extend loadvm/savevm format to support machine config? It is
> already supported by all devices, it seems that we just need to add some
> detail such as pci addresses, and qemu flags to save/load this config.
> No?

No.  Adding some info to the devices doesn't cut it as you also need to 
know which devices are present in the first place.  Current savevm 
doesn't do that, thats why you have to start the virtual machine with 
the complete set of command line arguments even when resuming / 
migrating.  Once we have a working device tree implementation we can fix 
that too though.  Rough plan is:

   (1) convert drivers to qdev.
   (2) create qdev device tree from config file (probably fdt).

With this in place it is just a little step to also carry this in the 
savevm format:  We just need a to do a qdev->fdt conversion, then we can 
send the device tree as one savevm section and rebuild the vm from that.

cheers,
   Gerd

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 13:43         ` Gerd Hoffmann
@ 2009-07-06 13:56           ` Michael S. Tsirkin
  2009-07-06 14:01             ` Michael S. Tsirkin
  2009-07-06 14:24             ` Gerd Hoffmann
  0 siblings, 2 replies; 61+ messages in thread
From: Michael S. Tsirkin @ 2009-07-06 13:56 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: Jan Kiszka, Markus Armbruster, qemu-devel

On Mon, Jul 06, 2009 at 03:43:23PM +0200, Gerd Hoffmann wrote:
> On 07/06/09 14:49, Michael S. Tsirkin wrote:
>> On Fri, Jun 12, 2009 at 06:11:24PM +0200, Jan Kiszka wrote:
>> Can't we extend loadvm/savevm format to support machine config? It is
>> already supported by all devices, it seems that we just need to add some
>> detail such as pci addresses, and qemu flags to save/load this config.
>> No?
>
> No.  Adding some info to the devices doesn't cut it as you also need to  
> know which devices are present in the first place.

Actually at least for pci devices you have the devid/vendor id
register - from this you can know which devices are present.

>  Current savevm  
> doesn't do that, thats why you have to start the virtual machine with  
> the complete set of command line arguments even when resuming /  
> migrating.  Once we have a working device tree implementation we can fix  
> that too though.  Rough plan is:
>
>   (1) convert drivers to qdev.
>   (2) create qdev device tree from config file (probably fdt).
>
> With this in place it is just a little step to also carry this in the  
> savevm format:  We just need a to do a qdev->fdt conversion, then we can  
> send the device tree as one savevm section and rebuild the vm from that.
>
> cheers,
>   Gerd

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 13:56           ` Michael S. Tsirkin
@ 2009-07-06 14:01             ` Michael S. Tsirkin
  2009-07-06 14:40               ` Gerd Hoffmann
  2009-07-06 14:24             ` Gerd Hoffmann
  1 sibling, 1 reply; 61+ messages in thread
From: Michael S. Tsirkin @ 2009-07-06 14:01 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: Jan Kiszka, Markus Armbruster, qemu-devel

On Mon, Jul 06, 2009 at 04:56:16PM +0300, Michael S. Tsirkin wrote:
> On Mon, Jul 06, 2009 at 03:43:23PM +0200, Gerd Hoffmann wrote:
> > On 07/06/09 14:49, Michael S. Tsirkin wrote:
> >> On Fri, Jun 12, 2009 at 06:11:24PM +0200, Jan Kiszka wrote:
> >> Can't we extend loadvm/savevm format to support machine config? It is
> >> already supported by all devices, it seems that we just need to add some
> >> detail such as pci addresses, and qemu flags to save/load this config.
> >> No?
> >
> > No.  Adding some info to the devices doesn't cut it as you also need to  
> > know which devices are present in the first place.
> 
> Actually at least for pci devices you have the devid/vendor id
> register - from this you can know which devices are present.
> 
> > Current savevm  
> > doesn't do that, thats why you have to start the virtual machine with  
> > the complete set of command line arguments even when resuming /  
> > migrating.

It seems that it'd be trivial to solve this just by adding a fixed size header
telling you which load function to call. No?

> >  Once we have a working device tree implementation we can fix  
> > that too though.  Rough plan is:
> >
> >   (1) convert drivers to qdev.
> >   (2) create qdev device tree from config file (probably fdt).
> >
> > With this in place it is just a little step to also carry this in the  
> > savevm format:  We just need a to do a qdev->fdt conversion, then we can  
> > send the device tree as one savevm section and rebuild the vm from that.
> >
> > cheers,
> >   Gerd

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 13:56           ` Michael S. Tsirkin
  2009-07-06 14:01             ` Michael S. Tsirkin
@ 2009-07-06 14:24             ` Gerd Hoffmann
  2009-07-06 14:31               ` Michael S. Tsirkin
  1 sibling, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-07-06 14:24 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: Jan Kiszka, Markus Armbruster, qemu-devel

On 07/06/09 15:56, Michael S. Tsirkin wrote:
> On Mon, Jul 06, 2009 at 03:43:23PM +0200, Gerd Hoffmann wrote:
>> On 07/06/09 14:49, Michael S. Tsirkin wrote:
>>> On Fri, Jun 12, 2009 at 06:11:24PM +0200, Jan Kiszka wrote:
>>> Can't we extend loadvm/savevm format to support machine config? It is
>>> already supported by all devices, it seems that we just need to add some
>>> detail such as pci addresses, and qemu flags to save/load this config.
>>> No?
>> No.  Adding some info to the devices doesn't cut it as you also need to
>> know which devices are present in the first place.
>
> Actually at least for pci devices you have the devid/vendor id
> register - from this you can know which devices are present.

Doesn't help you.  You can't easily pull out that information from the 
savevm file.  And even it you could you still don't know which backend 
actually drives that piece of hardware.

cheers,
   Gerd

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 14:24             ` Gerd Hoffmann
@ 2009-07-06 14:31               ` Michael S. Tsirkin
  0 siblings, 0 replies; 61+ messages in thread
From: Michael S. Tsirkin @ 2009-07-06 14:31 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: Jan Kiszka, Markus Armbruster, qemu-devel

On Mon, Jul 06, 2009 at 04:24:54PM +0200, Gerd Hoffmann wrote:
> On 07/06/09 15:56, Michael S. Tsirkin wrote:
>> On Mon, Jul 06, 2009 at 03:43:23PM +0200, Gerd Hoffmann wrote:
>>> On 07/06/09 14:49, Michael S. Tsirkin wrote:
>>>> On Fri, Jun 12, 2009 at 06:11:24PM +0200, Jan Kiszka wrote:
>>>> Can't we extend loadvm/savevm format to support machine config? It is
>>>> already supported by all devices, it seems that we just need to add some
>>>> detail such as pci addresses, and qemu flags to save/load this config.
>>>> No?
>>> No.  Adding some info to the devices doesn't cut it as you also need to
>>> know which devices are present in the first place.
>>
>> Actually at least for pci devices you have the devid/vendor id
>> register - from this you can know which devices are present.
>
> Doesn't help you.  You can't easily pull out that information from the  
> savevm file.  And even it you could you still don't know which backend  
> actually drives that piece of hardware.

How hard is it to add a fixed size backend id before each device?

-- 
MST

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 14:01             ` Michael S. Tsirkin
@ 2009-07-06 14:40               ` Gerd Hoffmann
  2009-07-06 16:12                 ` Avi Kivity
  0 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-07-06 14:40 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: Jan Kiszka, Markus Armbruster, qemu-devel

On 07/06/09 16:01, Michael S. Tsirkin wrote:
>>> Current savevm
>>> doesn't do that, thats why you have to start the virtual machine with
>>> the complete set of command line arguments even when resuming /
>>> migrating.
>
> It seems that it'd be trivial to solve this just by adding a fixed size header
> telling you which load function to call. No?

No.  Go read the code.

User adds -somedev params,more=options to the command line.  Qemu asks 
the corresponding driver to creates a device instance.  Every device 
instance registers loadvm/savevm callbacks to load/save state (tagged 
with name + instance id).

When loading vm state qemu will see name + instance id.  There is no way 
to figure the actual driver from that.

Additionall issue: There is no standardized way to create a device 
instance.  This one will be fixed by qdev though.

It might make sense to integrate savevm callbacks into qdev, then you'd 
have actually a chance to figure which driver belongs to your piece of 
savevm state.  I suspect it isn't enougth to make it work though, you 
still need to know the position of the device in the device tree.  To 
answer questions like "is your pci device behind a bridge and if so 
which one?".

cheers,
   Gerd

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 14:40               ` Gerd Hoffmann
@ 2009-07-06 16:12                 ` Avi Kivity
  2009-07-06 16:27                   ` Gerd Hoffmann
  0 siblings, 1 reply; 61+ messages in thread
From: Avi Kivity @ 2009-07-06 16:12 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: qemu-devel, Jan Kiszka, Markus Armbruster, Michael S. Tsirkin

On 07/06/2009 05:40 PM, Gerd Hoffmann wrote:
> It might make sense to integrate savevm callbacks into qdev, then 
> you'd have actually a chance to figure which driver belongs to your 
> piece of savevm state. 

That's my preference.  The very first pass iterates the device tree and 
serializes it.

> I suspect it isn't enougth to make it work though, you still need to 
> know the position of the device in the device tree.  To answer 
> questions like "is your pci device behind a bridge and if so which one?".

Isn't that info provided by qdev?  qdev will walk the pci bus, note 
there's a bridge, walk the bridged pci bus, note there's a usb 
controller, walk the usb bus, note there's a usb-scsi controller, walk 
the scsi bus, ... (ran out of steam).

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

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 16:12                 ` Avi Kivity
@ 2009-07-06 16:27                   ` Gerd Hoffmann
  2009-07-06 16:37                     ` Avi Kivity
  0 siblings, 1 reply; 61+ messages in thread
From: Gerd Hoffmann @ 2009-07-06 16:27 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel, Jan Kiszka, Markus Armbruster, Michael S. Tsirkin

On 07/06/09 18:12, Avi Kivity wrote:
> On 07/06/2009 05:40 PM, Gerd Hoffmann wrote:
>> It might make sense to integrate savevm callbacks into qdev, then
>> you'd have actually a chance to figure which driver belongs to your
>> piece of savevm state.
>
> That's my preference. The very first pass iterates the device tree and
> serializes it.

Sure, needs to happen.

I meant something else though:  Instead of having the drivers call 
register_savevm() in there init functions add section name and 
savevm/loadvm function pointers to qdevs DeviceInfo.  That will add the 
missing link section name -> driver.  That alone will *not* provide the 
position in the device tree though.  And I suspect making the transition 
without breaking backward compatibility could be quite tricky too.  So 
I'm not sure how useful that actually is, although it surely would be 
much cleaner from a design point of view.

>> I suspect it isn't enougth to make it work though, you still need to
>> know the position of the device in the device tree. To answer
>> questions like "is your pci device behind a bridge and if so which one?".
>
> Isn't that info provided by qdev?

Yep, it is.

Serialize qdev tree (into fdt or whatever else), send it over wire 
first, recreate qdev tree on the other side (including save/load 
callback registration), then parse everything else.  That is how I wanna 
have it work some day ...

cheers,
   Gerd

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 16:27                   ` Gerd Hoffmann
@ 2009-07-06 16:37                     ` Avi Kivity
  2009-07-06 16:44                       ` Michael S. Tsirkin
                                         ` (2 more replies)
  0 siblings, 3 replies; 61+ messages in thread
From: Avi Kivity @ 2009-07-06 16:37 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: qemu-devel, Jan Kiszka, Markus Armbruster, Michael S. Tsirkin

On 07/06/2009 07:27 PM, Gerd Hoffmann wrote:
> On 07/06/09 18:12, Avi Kivity wrote:
>> On 07/06/2009 05:40 PM, Gerd Hoffmann wrote:
>>> It might make sense to integrate savevm callbacks into qdev, then
>>> you'd have actually a chance to figure which driver belongs to your
>>> piece of savevm state.
>>
>> That's my preference. The very first pass iterates the device tree and
>> serializes it.
>
> Sure, needs to happen.
>
> I meant something else though:  Instead of having the drivers call 
> register_savevm() in there init functions add section name and 
> savevm/loadvm function pointers to qdevs DeviceInfo. 

Yes, that's how I see it too.  It's just another device method.

> That will add the missing link section name -> driver. 

There's no reason to have a section name.

> That alone will *not* provide the position in the device tree though.  
> And I suspect making the transition without breaking backward 
> compatibility could be quite tricky too.  So I'm not sure how useful 
> that actually is, although it surely would be much cleaner from a 
> design point of view.

I think we need to break the format.  It's semi-broken anyway wrt 
hotplug and the use of ram addresses.  It may be possible to add 
transition code but I don't think it's worth it.

>>> I suspect it isn't enougth to make it work though, you still need to
>>> know the position of the device in the device tree. To answer
>>> questions like "is your pci device behind a bridge and if so which 
>>> one?".
>>
>> Isn't that info provided by qdev?
>
> Yep, it is.
>
> Serialize qdev tree (into fdt or whatever else), send it over wire 
> first, recreate qdev tree on the other side (including save/load 
> callback registration), then parse everything else.  That is how I 
> wanna have it work some day ...

Slight change: instead of serializing into a tree, have a qdev callback 
which generates an add event that can be sent over the wire.  While 
migrating, additional hotplug simply call the same callback and the 
hotplug is migrated in real time.


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

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 16:37                     ` Avi Kivity
@ 2009-07-06 16:44                       ` Michael S. Tsirkin
  2009-07-07  4:47                         ` Avi Kivity
  2009-07-06 16:47                       ` Paul Brook
  2009-07-06 17:28                       ` Anthony Liguori
  2 siblings, 1 reply; 61+ messages in thread
From: Michael S. Tsirkin @ 2009-07-06 16:44 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel, Jan Kiszka, Gerd Hoffmann, Markus Armbruster

On Mon, Jul 06, 2009 at 07:37:32PM +0300, Avi Kivity wrote:
> On 07/06/2009 07:27 PM, Gerd Hoffmann wrote:
>> On 07/06/09 18:12, Avi Kivity wrote:
>>> On 07/06/2009 05:40 PM, Gerd Hoffmann wrote:
>>>> It might make sense to integrate savevm callbacks into qdev, then
>>>> you'd have actually a chance to figure which driver belongs to your
>>>> piece of savevm state.
>>>
>>> That's my preference. The very first pass iterates the device tree and
>>> serializes it.
>>
>> Sure, needs to happen.
>>
>> I meant something else though:  Instead of having the drivers call  
>> register_savevm() in there init functions add section name and  
>> savevm/loadvm function pointers to qdevs DeviceInfo. 
>
> Yes, that's how I see it too.  It's just another device method.
>
>> That will add the missing link section name -> driver. 
>
> There's no reason to have a section name.
>
>> That alone will *not* provide the position in the device tree though.   
>> And I suspect making the transition without breaking backward  
>> compatibility could be quite tricky too.  So I'm not sure how useful  
>> that actually is, although it surely would be much cleaner from a  
>> design point of view.
>
> I think we need to break the format.  It's semi-broken anyway wrt  
> hotplug and the use of ram addresses.  It may be possible to add  
> transition code but I don't think it's worth it.
>
>>>> I suspect it isn't enougth to make it work though, you still need to
>>>> know the position of the device in the device tree. To answer
>>>> questions like "is your pci device behind a bridge and if so which  
>>>> one?".
>>>
>>> Isn't that info provided by qdev?
>>
>> Yep, it is.
>>
>> Serialize qdev tree (into fdt or whatever else), send it over wire  
>> first, recreate qdev tree on the other side (including save/load  
>> callback registration), then parse everything else.  That is how I  
>> wanna have it work some day ...
>
> Slight change: instead of serializing into a tree, have a qdev callback  
> which generates an add event that can be sent over the wire.  While  
> migrating, additional hotplug simply call the same callback and the  
> hotplug is migrated in real time.

IOW, each device just needs to record where it is in the tree.
The tree can be then reconstructed by each driver
finding the parent bus and attaching the device to it.

-- 
MST

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 16:37                     ` Avi Kivity
  2009-07-06 16:44                       ` Michael S. Tsirkin
@ 2009-07-06 16:47                       ` Paul Brook
  2009-07-07  5:01                         ` Avi Kivity
  2009-07-06 17:28                       ` Anthony Liguori
  2 siblings, 1 reply; 61+ messages in thread
From: Paul Brook @ 2009-07-06 16:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Jan Kiszka, Michael S. Tsirkin, Avi Kivity, Markus Armbruster,
	Gerd Hoffmann

> >>> I suspect it isn't enougth to make it work though, you still need to
> >>> know the position of the device in the device tree. To answer
> >>> questions like "is your pci device behind a bridge and if so which
> >>> one?".
> >>
> >> Isn't that info provided by qdev?
> >
> > Yep, it is.
> >
> > Serialize qdev tree (into fdt or whatever else), send it over wire
> > first, recreate qdev tree on the other side (including save/load
> > callback registration), then parse everything else.  That is how I
> > wanna have it work some day ...
>
> Slight change: instead of serializing into a tree, have a qdev callback
> which generates an add event that can be sent over the wire.  While
> migrating, additional hotplug simply call the same callback and the
> hotplug is migrated in real time.

I think this is just going to cause you problems. Way simpler to just disable 
changing the machine configuration while migration is in progress.

Paul

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 16:37                     ` Avi Kivity
  2009-07-06 16:44                       ` Michael S. Tsirkin
  2009-07-06 16:47                       ` Paul Brook
@ 2009-07-06 17:28                       ` Anthony Liguori
  2009-07-06 22:39                         ` Paul Brook
                                           ` (2 more replies)
  2 siblings, 3 replies; 61+ messages in thread
From: Anthony Liguori @ 2009-07-06 17:28 UTC (permalink / raw)
  To: Avi Kivity
  Cc: Jan Kiszka, Michael S. Tsirkin, Gerd Hoffmann, Markus Armbruster,
	qemu-devel

Avi Kivity wrote:
>
>> That alone will *not* provide the position in the device tree 
>> though.  And I suspect making the transition without breaking 
>> backward compatibility could be quite tricky too.  So I'm not sure 
>> how useful that actually is, although it surely would be much cleaner 
>> from a design point of view.
>
> I think we need to break the format.  It's semi-broken anyway wrt 
> hotplug and the use of ram addresses.  It may be possible to add 
> transition code but I don't think it's worth it.

The format is fine.  ram v3 uses ram_addr_t because it's was the only 
sane thing to do at the time.  v4 could easily use target_phys_t.

Most importantly, machine config should not be sent until non-live 
migration kicks in.  At this point, the device tree is stable because 
the guest isn't running.  The device tree should be the first section 
saved for non-live migration.

This means you need to avoid initializing the device model until after 
you get to the second step in migration.  You really just need to 
register any live migration handlers outside of the device model 
creation which pretty much already happens today.

Regards,

Anthony Liguori

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 17:28                       ` Anthony Liguori
@ 2009-07-06 22:39                         ` Paul Brook
  2009-07-06 23:13                           ` Anthony Liguori
  2009-07-07  4:56                         ` Avi Kivity
  2009-07-07  6:19                         ` Michael S. Tsirkin
  2 siblings, 1 reply; 61+ messages in thread
From: Paul Brook @ 2009-07-06 22:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: Michael S. Tsirkin, Jan Kiszka, Markus Armbruster, Gerd Hoffmann,
	Avi Kivity

> Most importantly, machine config should not be sent until non-live
> migration kicks in.  At this point, the device tree is stable because
> the guest isn't running.  The device tree should be the first section
> saved for non-live migration.

RAM is part of the machine config, and can be hotplugged[1], so you need at 
least that before you start transferring anything.

Paul

[1] We don't currently have user accessible knobs for this, but all the code 
is there.

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 22:39                         ` Paul Brook
@ 2009-07-06 23:13                           ` Anthony Liguori
  2009-07-07  5:00                             ` Avi Kivity
  2009-07-07  5:23                             ` Avi Kivity
  0 siblings, 2 replies; 61+ messages in thread
From: Anthony Liguori @ 2009-07-06 23:13 UTC (permalink / raw)
  To: Paul Brook
  Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Markus Armbruster,
	Gerd Hoffmann, Avi Kivity

Paul Brook wrote:
>> Most importantly, machine config should not be sent until non-live
>> migration kicks in.  At this point, the device tree is stable because
>> the guest isn't running.  The device tree should be the first section
>> saved for non-live migration.
>>     
>
> RAM is part of the machine config, and can be hotplugged[1], so you need at 
> least that before you start transferring anything.
>   

You really don't.  The ram_load_live handler should receive RAM as it 
comes in and maintain a growable buffer for all the independently 
transferred regions.  A nice property of live migration is that you'll 
get the whole region at once so something simple based on realloc() will 
work well.

When it comes time to create the virtual machine, you have memory 
buffers ready to be used as the guest's memory.  If it's not sized 
appropriately, you throw an error and migration aborts.

Regards,

Anthony Liguori

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 16:44                       ` Michael S. Tsirkin
@ 2009-07-07  4:47                         ` Avi Kivity
  0 siblings, 0 replies; 61+ messages in thread
From: Avi Kivity @ 2009-07-07  4:47 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: qemu-devel, Jan Kiszka, Gerd Hoffmann, Markus Armbruster

On 07/06/2009 07:44 PM, Michael S. Tsirkin wrote:
>> Slight change: instead of serializing into a tree, have a qdev callback
>> which generates an add event that can be sent over the wire.  While
>> migrating, additional hotplug simply call the same callback and the
>> hotplug is migrated in real time.
>>      
>
> IOW, each device just needs to record where it is in the tree.
>    

There is no easy way to do that.  Instead, each bus records its 
component devices.

> The tree can be then reconstructed by each driver
> finding the parent bus and attaching the device to it.
>    

With a hierarhical save this is much more natural.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 17:28                       ` Anthony Liguori
  2009-07-06 22:39                         ` Paul Brook
@ 2009-07-07  4:56                         ` Avi Kivity
  2009-07-07  6:19                         ` Michael S. Tsirkin
  2 siblings, 0 replies; 61+ messages in thread
From: Avi Kivity @ 2009-07-07  4:56 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: Jan Kiszka, Michael S. Tsirkin, Gerd Hoffmann, Markus Armbruster,
	qemu-devel

On 07/06/2009 08:28 PM, Anthony Liguori wrote:
> Avi Kivity wrote:
>>
>>> That alone will *not* provide the position in the device tree 
>>> though.  And I suspect making the transition without breaking 
>>> backward compatibility could be quite tricky too.  So I'm not sure 
>>> how useful that actually is, although it surely would be much 
>>> cleaner from a design point of view.
>>
>> I think we need to break the format.  It's semi-broken anyway wrt 
>> hotplug and the use of ram addresses.  It may be possible to add 
>> transition code but I don't think it's worth it.
>
> The format is fine.  ram v3 uses ram_addr_t because it's was the only 
> sane thing to do at the time.  v4 could easily use target_phys_t.

IMO the flat format currently used is fragile wrt. hotplug, as is the 
requirement to start qemu with exactly the same parameters.  If we 
serialize the state from the current qdev configuration we don't depend 
on any implementation ordering.

> Most importantly, machine config should not be sent until non-live 
> migration kicks in.  At this point, the device tree is stable because 
> the guest isn't running.  The device tree should be the first section 
> saved for non-live migration.

Memory layout depends on the machine configuration.  RAM, hotplug RAM, 
and framebuffers.  It would get worse if more components migrate live 
(disks?).

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 23:13                           ` Anthony Liguori
@ 2009-07-07  5:00                             ` Avi Kivity
  2009-07-07  5:23                             ` Avi Kivity
  1 sibling, 0 replies; 61+ messages in thread
From: Avi Kivity @ 2009-07-07  5:00 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: Michael S. Tsirkin, Jan Kiszka, Markus Armbruster, qemu-devel,
	Gerd Hoffmann, Paul Brook

On 07/07/2009 02:13 AM, Anthony Liguori wrote:
> Paul Brook wrote:
>>> Most importantly, machine config should not be sent until non-live
>>> migration kicks in.  At this point, the device tree is stable because
>>> the guest isn't running.  The device tree should be the first section
>>> saved for non-live migration.
>>
>> RAM is part of the machine config, and can be hotplugged[1], so you 
>> need at least that before you start transferring anything.
>
> You really don't.  The ram_load_live handler should receive RAM as it 
> comes in and maintain a growable buffer for all the independently 
> transferred regions.  A nice property of live migration is that you'll 
> get the whole region at once so something simple based on realloc() 
> will work well.
>

It's doable but it looks like we're implementing things twice.  If we 
have memory/vga hotplug, then we already support all of this at the 
hotplug level.  All we need to do is send the hotplug command over.

It occured to me that except for RAM we can migrate using the monitor 
protocol.  Start by serializing the qdev tree into an object and create 
the target machine from that.  Additional hotplug commands during the 
migration are simply forwarded to the other side.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 16:47                       ` Paul Brook
@ 2009-07-07  5:01                         ` Avi Kivity
  0 siblings, 0 replies; 61+ messages in thread
From: Avi Kivity @ 2009-07-07  5:01 UTC (permalink / raw)
  To: Paul Brook
  Cc: Jan Kiszka, Michael S. Tsirkin, qemu-devel, Markus Armbruster,
	Gerd Hoffmann

On 07/06/2009 07:47 PM, Paul Brook wrote:
>> Slight change: instead of serializing into a tree, have a qdev callback
>> which generates an add event that can be sent over the wire.  While
>> migrating, additional hotplug simply call the same callback and the
>> hotplug is migrated in real time.
>>      
>
> I think this is just going to cause you problems. Way simpler to just disable
> changing the machine configuration while migration is in progress.
>    

These features are logically orthogonal and initiated by different 
users, so it will be seen as if hotplug randomly has high latency.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 23:13                           ` Anthony Liguori
  2009-07-07  5:00                             ` Avi Kivity
@ 2009-07-07  5:23                             ` Avi Kivity
  1 sibling, 0 replies; 61+ messages in thread
From: Avi Kivity @ 2009-07-07  5:23 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Markus Armbruster,
	Gerd Hoffmann, Paul Brook

On 07/07/2009 02:13 AM, Anthony Liguori wrote:
>>
>> RAM is part of the machine config, and can be hotplugged[1], so you 
>> need at least that before you start transferring anything.
>
>
> You really don't.  The ram_load_live handler should receive RAM as it 
> comes in and maintain a growable buffer for all the independently 
> transferred regions.  A nice property of live migration is that you'll 
> get the whole region at once so something simple based on realloc() 
> will work well.
>

One nasty bit here is large page support.  We need to know memory layout 
in advance so we can migrate to appropriately allocated and aligned 
sections.

realloc()s could work, but they'd be slow (seconds) on large guests, and 
you're not guaranteed to have enough memory.

-- 
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

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

* Re: [Qemu-devel] Re: [PATCH 0/4] Machine config files
  2009-07-06 17:28                       ` Anthony Liguori
  2009-07-06 22:39                         ` Paul Brook
  2009-07-07  4:56                         ` Avi Kivity
@ 2009-07-07  6:19                         ` Michael S. Tsirkin
  2 siblings, 0 replies; 61+ messages in thread
From: Michael S. Tsirkin @ 2009-07-07  6:19 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: qemu-devel, Jan Kiszka, Avi Kivity, Markus Armbruster, Gerd Hoffmann

On Mon, Jul 06, 2009 at 12:28:36PM -0500, Anthony Liguori wrote:
> Most importantly, machine config should not be sent until non-live  
> migration kicks in.  At this point, the device tree is stable because  
> the guest isn't running.  The device tree should be the first section  
> saved for non-live migration.

Why is that? guest by definition can't change the machine config.

-- 
MST

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

end of thread, other threads:[~2009-07-07  6:19 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-10 17:38 [Qemu-devel] [PATCH 0/4] Machine config files Paul Brook
2009-06-10 17:38 ` [Qemu-devel] [PATCH 1/4] Include and build libfdt Paul Brook
2009-06-10 19:08   ` Glauber Costa
2009-06-10 19:23     ` Anthony Liguori
2009-06-10 19:27     ` Paul Brook
2009-06-10 19:41       ` Glauber Costa
2009-06-10 20:38         ` Paul Brook
2009-06-10 22:32       ` Edgar E. Iglesias
2009-06-10 19:34     ` Blue Swirl
2009-06-10 17:38 ` [Qemu-devel] [PATCH 2/4] Add device tree machine Paul Brook
2009-06-10 18:30   ` Blue Swirl
2009-06-10 19:10     ` Paul Brook
2009-06-11 13:22   ` Gerd Hoffmann
2009-06-11 13:33   ` Gerd Hoffmann
2009-06-11 13:39     ` Paul Brook
2009-06-11 14:22       ` Gerd Hoffmann
2009-06-12 16:25   ` Markus Armbruster
2009-06-10 17:38 ` [Qemu-devel] [PATCH 3/4] Stellaris machine config Paul Brook
2009-06-11  8:21   ` M P
2009-06-11 16:32     ` Jamie Lokier
2009-06-12  8:29       ` Gerd Hoffmann
2009-06-12 13:56         ` Markus Armbruster
2009-06-12 13:53       ` Markus Armbruster
2009-06-12 15:25         ` Jamie Lokier
2009-06-10 17:38 ` [Qemu-devel] [PATCH 4/4] Integrator " Paul Brook
2009-06-11  9:54 ` [Qemu-devel] [PATCH 0/4] Machine config files Gerd Hoffmann
2009-06-11 12:53 ` Gerd Hoffmann
2009-06-11 13:18   ` Paul Brook
2009-06-11 14:35     ` Gerd Hoffmann
2009-06-12  7:51     ` Kevin Wolf
2009-06-12 13:49       ` Markus Armbruster
2009-06-12 14:22         ` Kevin Wolf
2009-06-12 14:40           ` Markus Armbruster
2009-06-12 15:02           ` Anthony Liguori
2009-06-12 15:29             ` Kevin Wolf
2009-06-12 16:35             ` Blue Swirl
2009-06-12 13:37 ` Markus Armbruster
2009-06-12 14:44   ` Gerd Hoffmann
2009-06-12 15:58     ` Markus Armbruster
2009-06-12 16:11     ` [Qemu-devel] " Jan Kiszka
2009-07-06 12:49       ` Michael S. Tsirkin
2009-07-06 13:43         ` Gerd Hoffmann
2009-07-06 13:56           ` Michael S. Tsirkin
2009-07-06 14:01             ` Michael S. Tsirkin
2009-07-06 14:40               ` Gerd Hoffmann
2009-07-06 16:12                 ` Avi Kivity
2009-07-06 16:27                   ` Gerd Hoffmann
2009-07-06 16:37                     ` Avi Kivity
2009-07-06 16:44                       ` Michael S. Tsirkin
2009-07-07  4:47                         ` Avi Kivity
2009-07-06 16:47                       ` Paul Brook
2009-07-07  5:01                         ` Avi Kivity
2009-07-06 17:28                       ` Anthony Liguori
2009-07-06 22:39                         ` Paul Brook
2009-07-06 23:13                           ` Anthony Liguori
2009-07-07  5:00                             ` Avi Kivity
2009-07-07  5:23                             ` Avi Kivity
2009-07-07  4:56                         ` Avi Kivity
2009-07-07  6:19                         ` Michael S. Tsirkin
2009-07-06 14:24             ` Gerd Hoffmann
2009-07-06 14:31               ` Michael S. Tsirkin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.