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)