Migrate to libfdt
Replace our custom FDT parser implementation with libfdt while retaining
the original API as a thin wrapper around libfdt. This minimizes the
changes to the rest of our code base and hides differences in coding
styles.
As a byproduct, this fixes an issue with unaligned memory accesses while
parsing as libfdt handles these correctly.
Bug: 150587116
Change-Id: I8d305d7094b1be04608048009d73d7c448a578a0
diff --git a/src/manifest.c b/src/manifest.c
index 7a8474b..f83c0f9 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -31,20 +31,39 @@
} \
} while (0)
-#define VM_NAME_BUF_SIZE (2 + 5 + 1) /* "vm" + number + null terminator */
-static_assert(MAX_VMS <= 99999, "Insufficient VM_NAME_BUF_SIZE");
-static_assert(HF_TEE_VM_ID > MAX_VMS,
+#define VM_ID_MAX (HF_VM_ID_OFFSET + MAX_VMS - 1)
+#define VM_ID_MAX_DIGITS (5)
+#define VM_NAME_EXTRA_CHARS (3) /* "vm" + number + '\0' */
+#define VM_NAME_MAX_SIZE (VM_ID_MAX_DIGITS + VM_NAME_EXTRA_CHARS)
+static_assert(VM_NAME_MAX_SIZE <= STRING_MAX_SIZE,
+ "VM name does not fit into a struct string.");
+static_assert(VM_ID_MAX <= 99999, "Insufficient VM_NAME_BUF_SIZE");
+static_assert(HF_TEE_VM_ID > VM_ID_MAX,
"TrustZone VM ID clashes with normal VM range.");
+static inline size_t count_digits(spci_vm_id_t vm_id)
+{
+ size_t digits = 0;
+
+ do {
+ digits++;
+ vm_id /= 10;
+ } while (vm_id);
+ return digits;
+}
+
/**
* Generates a string with the two letters "vm" followed by an integer.
* Assumes `buf` is of size VM_NAME_BUF_SIZE.
*/
-static const char *generate_vm_node_name(char *buf, spci_vm_id_t vm_id)
+static void generate_vm_node_name(struct string *str, spci_vm_id_t vm_id)
{
static const char *digits = "0123456789";
- char *ptr = buf + VM_NAME_BUF_SIZE;
+ size_t vm_id_digits = count_digits(vm_id);
+ char *base = str->data;
+ char *ptr = base + (VM_NAME_EXTRA_CHARS + vm_id_digits);
+ CHECK(vm_id_digits <= VM_ID_MAX_DIGITS);
*(--ptr) = '\0';
do {
*(--ptr) = digits[vm_id % 10];
@@ -52,8 +71,7 @@
} while (vm_id);
*(--ptr) = 'm';
*(--ptr) = 'v';
-
- return ptr;
+ CHECK(ptr == base);
}
/**
@@ -63,11 +81,10 @@
static enum manifest_return_code read_bool(const struct fdt_node *node,
const char *property, bool *out)
{
- const char *data;
- uint32_t size;
- bool present = fdt_read_property(node, property, &data, &size);
+ struct memiter data;
+ bool present = fdt_read_property(node, property, &data);
- if (present && size != 0) {
+ if (present && memiter_size(&data) != 0) {
return MANIFEST_ERROR_MALFORMED_BOOLEAN;
}
@@ -79,14 +96,13 @@
const char *property,
struct string *out)
{
- const char *data;
- uint32_t size;
+ struct memiter data;
- if (!fdt_read_property(node, property, &data, &size)) {
+ if (!fdt_read_property(node, property, &data)) {
return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
}
- switch (string_init(out, data, size)) {
+ switch (string_init(out, &data)) {
case STRING_SUCCESS:
return MANIFEST_SUCCESS;
case STRING_ERROR_INVALID_INPUT:
@@ -113,14 +129,13 @@
const char *property,
uint64_t *out)
{
- const char *data;
- uint32_t size;
+ struct memiter data;
- if (!fdt_read_property(node, property, &data, &size)) {
+ if (!fdt_read_property(node, property, &data)) {
return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
}
- if (!fdt_parse_number(data, size, out)) {
+ if (!fdt_parse_number(&data, memiter_size(&data), out)) {
return MANIFEST_ERROR_MALFORMED_INTEGER;
}
@@ -165,19 +180,18 @@
const struct fdt_node *node, const char *property,
struct uint32list_iter *out)
{
- const char *data;
- uint32_t size;
+ struct memiter data;
- if (!fdt_read_property(node, property, &data, &size)) {
+ if (!fdt_read_property(node, property, &data)) {
memiter_init(&out->mem_it, NULL, 0);
return MANIFEST_SUCCESS;
}
- if ((size % sizeof(uint32_t)) != 0) {
+ if ((memiter_size(&data) % sizeof(uint32_t)) != 0) {
return MANIFEST_ERROR_MALFORMED_INTEGER_LIST;
}
- memiter_init(&out->mem_it, data, size);
+ out->mem_it = data;
return MANIFEST_SUCCESS;
}
@@ -193,22 +207,27 @@
const char *property,
struct stringlist_iter *out)
{
- const char *data;
- uint32_t size;
+ struct memiter data;
+ const char *str;
+ size_t size;
- if (!fdt_read_property(node, property, &data, &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 (data[size - 1] != '\0') {
+ if ((size < 1) || (str[size - 1] != '\0')) {
return MANIFEST_ERROR_MALFORMED_STRING_LIST;
}
- memiter_init(&out->mem_it, data, size - 1);
+ CHECK(memiter_restrict(&data, 1));
+ out->mem_it = data;
return MANIFEST_SUCCESS;
}
@@ -220,16 +239,13 @@
static enum manifest_return_code uint32list_get_next(
struct uint32list_iter *list, uint32_t *out)
{
- const char *mem_base = memiter_base(&list->mem_it);
uint64_t num;
CHECK(uint32list_has_next(list));
-
- if (!fdt_parse_number(mem_base, sizeof(uint32_t), &num)) {
+ if (!fdt_parse_number(&list->mem_it, sizeof(uint32_t), &num)) {
return MANIFEST_ERROR_MALFORMED_INTEGER;
}
- memiter_advance(&list->mem_it, sizeof(uint32_t));
*out = (uint32_t)num;
return MANIFEST_SUCCESS;
}
@@ -284,7 +300,7 @@
return false;
}
-static enum manifest_return_code parse_vm(struct fdt_node *node,
+static enum manifest_return_code parse_vm(const struct fdt_node *node,
struct manifest_vm *vm,
spci_vm_id_t vm_id)
{
@@ -328,8 +344,8 @@
enum manifest_return_code manifest_init(struct manifest *manifest,
struct memiter *manifest_fdt)
{
- char vm_name_buf[VM_NAME_BUF_SIZE];
- const struct fdt_header *fdt;
+ struct string vm_name;
+ struct fdt fdt;
struct fdt_node hyp_node;
struct stringlist_iter compatible_list;
size_t i = 0;
@@ -337,19 +353,12 @@
memset_s(manifest, sizeof(*manifest), 0, sizeof(*manifest));
- fdt = (const struct fdt_header *)memiter_base(manifest_fdt);
- if (memiter_size(manifest_fdt) != fdt_total_size(fdt)) {
- return MANIFEST_ERROR_FILE_SIZE;
+ if (!fdt_init_from_memiter(&fdt, manifest_fdt)) {
+ return MANIFEST_ERROR_FILE_SIZE; /* TODO */
}
/* Find hypervisor node. */
- if (!fdt_root_node(&hyp_node, fdt)) {
- return MANIFEST_ERROR_NO_ROOT_NODE;
- }
- if (!fdt_find_child(&hyp_node, "")) {
- return MANIFEST_ERROR_NO_ROOT_NODE;
- }
- if (!fdt_find_child(&hyp_node, "hypervisor")) {
+ if (!fdt_find_node(&fdt, "/hypervisor", &hyp_node)) {
return MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE;
}
@@ -363,9 +372,9 @@
for (i = 0; i < HF_VM_ID_OFFSET; i++) {
spci_vm_id_t vm_id = (spci_vm_id_t)i;
struct fdt_node vm_node = hyp_node;
- const char *vm_name = generate_vm_node_name(vm_name_buf, vm_id);
- if (fdt_find_child(&vm_node, vm_name)) {
+ generate_vm_node_name(&vm_name, vm_id);
+ if (fdt_find_child(&vm_node, &vm_name)) {
return MANIFEST_ERROR_RESERVED_VM_ID;
}
}
@@ -374,9 +383,9 @@
for (i = 0; i <= MAX_VMS; ++i) {
spci_vm_id_t vm_id = HF_VM_ID_OFFSET + i;
struct fdt_node vm_node = hyp_node;
- const char *vm_name = generate_vm_node_name(vm_name_buf, vm_id);
- if (!fdt_find_child(&vm_node, vm_name)) {
+ generate_vm_node_name(&vm_name, vm_id);
+ if (!fdt_find_child(&vm_node, &vm_name)) {
break;
}