Introduce a DT-based manifest

These are first steps towards a new manifest format. A new "device_tree"
build target is introduced to compile DTS files to DTB, and
`generate_initrd.py` now does not produce a "vms.txt" file. Instead
"initrd" targets are expected to provide a path to a DTS manifest in the
format:

    /dts-v1/;

    / {
      hypervisor {
        vm1 {
	  debug_name = "primary";
	};

	vm2 {
	  debug_name = "secondary1";
	  kernel_filename = "filename";
	  vcpu_count = <N>;
          mem_size = <M>;
	};

	...
      };
    };

The information provided in the manifest matches "vms.txt".

Bug: 117551352
Test: manifest_test.cc
Test: used by hftest
Change-Id: I6b70bd44d2b110c4f7a6b971018c834084b6d8c4
diff --git a/src/fdt.c b/src/fdt.c
index 0ba1177..d9cd71d 100644
--- a/src/fdt.c
+++ b/src/fdt.c
@@ -16,8 +16,10 @@
 
 #include "hf/fdt.h"
 
+#include <stdalign.h>
 #include <stdint.h>
 
+#include "hf/check.h"
 #include "hf/dlog.h"
 #include "hf/std.h"
 
@@ -56,6 +58,8 @@
 #define FDT_VERSION 17
 #define FDT_MAGIC 0xd00dfeed
 
+#define FDT_TOKEN_ALIGNMENT sizeof(uint32_t)
+
 static void fdt_tokenizer_init(struct fdt_tokenizer *t, const char *strs,
 			       const char *begin, const char *end)
 {
@@ -66,7 +70,7 @@
 
 static void fdt_tokenizer_align(struct fdt_tokenizer *t)
 {
-	t->cur = (char *)align_up(t->cur, 4);
+	t->cur = (char *)align_up(t->cur, FDT_TOKEN_ALIGNMENT);
 }
 
 static bool fdt_tokenizer_uint32(struct fdt_tokenizer *t, uint32_t *res)
@@ -276,6 +280,43 @@
 	return false;
 }
 
+/**
+ * Helper method for parsing 32/64-bit uints from FDT data.
+ */
+bool fdt_parse_number(const char *data, uint32_t size, uint64_t *value)
+{
+	union {
+		volatile uint64_t v;
+		char a[8];
+	} t;
+
+	/* FDT values should be aligned to 32-bit boundary. */
+	CHECK(is_aligned(data, FDT_TOKEN_ALIGNMENT));
+
+	switch (size) {
+	case sizeof(uint32_t):
+		/*
+		 * Assert that `data` is already sufficiently aligned to
+		 * dereference as uint32_t. We cannot use static_assert()
+		 * because alignof() is not an expression under ISO C11.
+		 */
+		CHECK(alignof(uint32_t) <= FDT_TOKEN_ALIGNMENT);
+		*value = be32toh(*(uint32_t *)data);
+		return true;
+	case sizeof(uint64_t):
+		/*
+		 * ARMv8 requires `data` to be realigned to 64-bit boundary
+		 * to dereference as uint64_t. May not be needed on other
+		 * architectures.
+		 */
+		memcpy_s(t.a, sizeof(t.a), data, sizeof(uint64_t));
+		*value = be64toh(t.v);
+		return true;
+	default:
+		return false;
+	}
+}
+
 bool fdt_first_child(struct fdt_node *node, const char **child_name)
 {
 	struct fdt_tokenizer t;
@@ -333,7 +374,7 @@
 	return false;
 }
 
-void fdt_dump(struct fdt_header *hdr)
+void fdt_dump(const struct fdt_header *hdr)
 {
 	uint32_t token;
 	size_t depth = 0;