Use libfdt for is-compatible checks

Testing the 'compatible' property of manifest FDT requires parsing a
list of strings. As this is currently the only use case, we can remove
a significant amount of code from the manifest parser by using a libfdt
API instead.

Change-Id: Idcfa8d9a85745738a08d4fdaa40f30cc18e3c5c2
diff --git a/inc/hf/fdt.h b/inc/hf/fdt.h
index 08f1741..71753ce 100644
--- a/inc/hf/fdt.h
+++ b/inc/hf/fdt.h
@@ -50,6 +50,7 @@
 
 bool fdt_find_node(const struct fdt *fdt, const char *path,
 		   struct fdt_node *node);
+bool fdt_is_compatible(struct fdt_node *node, const char *compat);
 bool fdt_address_size(const struct fdt_node *node, size_t *addr_size);
 bool fdt_size_size(const struct fdt_node *node, size_t *size);
 
diff --git a/inc/hf/manifest.h b/inc/hf/manifest.h
index 2c736e72..f1aebaf 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -66,7 +66,6 @@
 	MANIFEST_ERROR_PROPERTY_NOT_FOUND,
 	MANIFEST_ERROR_MALFORMED_STRING,
 	MANIFEST_ERROR_STRING_TOO_LONG,
-	MANIFEST_ERROR_MALFORMED_STRING_LIST,
 	MANIFEST_ERROR_MALFORMED_INTEGER,
 	MANIFEST_ERROR_INTEGER_OVERFLOW,
 	MANIFEST_ERROR_MALFORMED_INTEGER_LIST,
diff --git a/src/fdt.c b/src/fdt.c
index 8f57cc8..1983fc6 100644
--- a/src/fdt.c
+++ b/src/fdt.c
@@ -274,3 +274,13 @@
 	/* Not found */
 	return false;
 }
+
+/**
+ * Returns true if `node` has property "compatible" containing a `compat` entry.
+ * Returns false if node not compatible or an error occurred.
+ */
+bool fdt_is_compatible(struct fdt_node *node, const char *compat)
+{
+	return fdt_node_check_compatible(fdt_base(&node->fdt), node->offset,
+					 compat) == 0;
+}
diff --git a/src/manifest.c b/src/manifest.c
index f83c0f9..438b5d0 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -195,42 +195,6 @@
 	return MANIFEST_SUCCESS;
 }
 
-/**
- * Represents the value of property whose type is a list of strings. These are
- * encoded as one contiguous byte buffer with NULL-separated entries.
- */
-struct stringlist_iter {
-	struct memiter mem_it;
-};
-
-static enum manifest_return_code read_stringlist(const struct fdt_node *node,
-						 const char *property,
-						 struct stringlist_iter *out)
-{
-	struct memiter data;
-	const char *str;
-	size_t size;
-
-	if (!fdt_read_property(node, property, &data)) {
-		return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
-	}
-
-	str = memiter_base(&data);
-	size = memiter_size(&data);
-
-	/*
-	 * Require that the value ends with a NULL terminator. Other NULL
-	 * characters separate the string list entries.
-	 */
-	if ((size < 1) || (str[size - 1] != '\0')) {
-		return MANIFEST_ERROR_MALFORMED_STRING_LIST;
-	}
-
-	CHECK(memiter_restrict(&data, 1));
-	out->mem_it = data;
-	return MANIFEST_SUCCESS;
-}
-
 static bool uint32list_has_next(const struct uint32list_iter *list)
 {
 	return memiter_size(&list->mem_it) > 0;
@@ -250,56 +214,6 @@
 	return MANIFEST_SUCCESS;
 }
 
-static bool stringlist_has_next(const struct stringlist_iter *list)
-{
-	return memiter_size(&list->mem_it) > 0;
-}
-
-static void stringlist_get_next(struct stringlist_iter *list,
-				struct memiter *out)
-{
-	const char *mem_base = memiter_base(&list->mem_it);
-	size_t mem_size = memiter_size(&list->mem_it);
-	const char *null_term;
-
-	CHECK(stringlist_has_next(list));
-
-	null_term = memchr(mem_base, '\0', mem_size);
-	if (null_term == NULL) {
-		/*
-		 * NULL terminator not found, this is the last entry.
-		 * Set entry memiter to the entire byte range and advance list
-		 * memiter to the end of the byte range.
-		 */
-		memiter_init(out, mem_base, mem_size);
-		memiter_advance(&list->mem_it, mem_size);
-	} else {
-		/*
-		 * Found NULL terminator. Set entry memiter to byte range
-		 * [base, null) and move list memiter past the terminator.
-		 */
-		size_t entry_size = null_term - mem_base;
-
-		memiter_init(out, mem_base, entry_size);
-		memiter_advance(&list->mem_it, entry_size + 1);
-	}
-}
-
-static bool stringlist_contains(const struct stringlist_iter *list,
-				const char *str)
-{
-	struct stringlist_iter it = *list;
-	struct memiter entry;
-
-	while (stringlist_has_next(&it)) {
-		stringlist_get_next(&it, &entry);
-		if (memiter_iseq(&entry, str)) {
-			return true;
-		}
-	}
-	return false;
-}
-
 static enum manifest_return_code parse_vm(const struct fdt_node *node,
 					  struct manifest_vm *vm,
 					  spci_vm_id_t vm_id)
@@ -347,7 +261,6 @@
 	struct string vm_name;
 	struct fdt fdt;
 	struct fdt_node hyp_node;
-	struct stringlist_iter compatible_list;
 	size_t i = 0;
 	bool found_primary_vm = false;
 
@@ -363,8 +276,7 @@
 	}
 
 	/* Check "compatible" property. */
-	TRY(read_stringlist(&hyp_node, "compatible", &compatible_list));
-	if (!stringlist_contains(&compatible_list, "hafnium,hafnium")) {
+	if (!fdt_is_compatible(&hyp_node, "hafnium,hafnium")) {
 		return MANIFEST_ERROR_NOT_COMPATIBLE;
 	}
 
@@ -435,8 +347,6 @@
 		return "Malformed string property";
 	case MANIFEST_ERROR_STRING_TOO_LONG:
 		return "String too long";
-	case MANIFEST_ERROR_MALFORMED_STRING_LIST:
-		return "Malformed string list property";
 	case MANIFEST_ERROR_MALFORMED_INTEGER:
 		return "Malformed integer property";
 	case MANIFEST_ERROR_INTEGER_OVERFLOW:
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 8273ae4..bed1675 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -304,8 +304,7 @@
 		.Build();
 	/* clang-format on */
 
-	ASSERT_EQ(manifest_from_vec(&m, dtb),
-		  MANIFEST_ERROR_PROPERTY_NOT_FOUND);
+	ASSERT_EQ(manifest_from_vec(&m, dtb), MANIFEST_ERROR_NOT_COMPATIBLE);
 }
 
 TEST(manifest, not_compatible)