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/inc/hf/boot_flow.h b/inc/hf/boot_flow.h
index 9bf82c1..0e6a597 100644
--- a/inc/hf/boot_flow.h
+++ b/inc/hf/boot_flow.h
@@ -21,8 +21,7 @@
#include "hf/memiter.h"
#include "hf/mm.h"
-bool boot_flow_get_params(struct boot_params *p,
- const struct fdt_node *fdt_root);
+bool boot_flow_get_params(struct boot_params *p, const struct fdt *fdt);
bool boot_flow_update(struct mm_stage1_locked stage1_locked,
const struct manifest *manifest,
diff --git a/inc/hf/fdt.h b/inc/hf/fdt.h
index 2dbb1d9..08f1741 100644
--- a/inc/hf/fdt.h
+++ b/inc/hf/fdt.h
@@ -16,27 +16,49 @@
#pragma once
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
+#include "hf/memiter.h"
+#include "hf/string.h"
-struct fdt_node {
- const struct fdt_header *hdr;
- const char *begin;
- const char *end;
- const char *strs;
+/**
+ * Wrapper around a pointer to a Flattened Device Tree (FDT) structure located
+ * somewhere in mapped main memory. Sanity checks are performed on initilization
+ * to ensure it is pointing to a valid FDT and most libfdt API calls check for
+ * the presence of the FDT magic.
+ */
+struct fdt {
+ struct memiter buf;
};
-size_t fdt_header_size(void);
-uint32_t fdt_total_size(const struct fdt_header *hdr);
-void fdt_dump(const struct fdt_header *hdr);
-bool fdt_root_node(struct fdt_node *node, const struct fdt_header *hdr);
-bool fdt_find_child(struct fdt_node *node, const char *child);
-bool fdt_first_child(struct fdt_node *node, const char **child_name);
-bool fdt_next_sibling(struct fdt_node *node, const char **sibling_name);
-bool fdt_read_property(const struct fdt_node *node, const char *name,
- const char **buf, uint32_t *size);
-bool fdt_parse_number(const char *data, uint32_t size, uint64_t *value);
+/**
+ * Wrapper around a pointer to a valid Device Tree node inside a FDT structure.
+ */
+struct fdt_node {
+ struct fdt fdt;
+ int offset;
+};
-void fdt_add_mem_reservation(struct fdt_header *hdr, uint64_t addr,
- uint64_t len);
+#define FDT_V17_HEADER_SIZE (10 * sizeof(uint32_t))
+
+bool fdt_size_from_header(const void *ptr, size_t *val);
+
+bool fdt_init_from_ptr(struct fdt *fdt, const void *ptr, size_t len);
+bool fdt_init_from_memiter(struct fdt *fdt, const struct memiter *it);
+void fdt_fini(struct fdt *fdt);
+
+const void *fdt_base(const struct fdt *fdt);
+size_t fdt_size(const struct fdt *fdt);
+
+bool fdt_find_node(const struct fdt *fdt, const char *path,
+ struct fdt_node *node);
+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);
+
+bool fdt_first_child(struct fdt_node *node);
+bool fdt_next_sibling(struct fdt_node *node);
+bool fdt_find_child(struct fdt_node *node, const struct string *name);
+
+bool fdt_read_property(const struct fdt_node *node, const char *name,
+ struct memiter *data);
+bool fdt_read_number(const struct fdt_node *node, const char *name,
+ uint64_t *val);
+bool fdt_parse_number(struct memiter *data, size_t size, uint64_t *val);
diff --git a/inc/hf/fdt_handler.h b/inc/hf/fdt_handler.h
index 4e18afc..8cf3a4a 100644
--- a/inc/hf/fdt_handler.h
+++ b/inc/hf/fdt_handler.h
@@ -22,19 +22,15 @@
#include "hf/mpool.h"
#include "hf/string.h"
-struct fdt_header *fdt_map(struct mm_stage1_locked stage1_locked,
- paddr_t fdt_addr, struct fdt_node *n,
- struct mpool *ppool);
-bool fdt_unmap(struct mm_stage1_locked stage1_locked, struct fdt_header *fdt,
+#define FDT_PROP_INITRD_START "linux,initrd-start"
+#define FDT_PROP_INITRD_END "linux,initrd-end"
+
+bool fdt_map(struct fdt *fdt, struct mm_stage1_locked stage1_locked,
+ paddr_t fdt_addr, struct mpool *ppool);
+bool fdt_unmap(struct fdt *fdt, struct mm_stage1_locked stage1_locked,
struct mpool *ppool);
-bool fdt_find_cpus(const struct fdt_node *root, cpu_id_t *cpu_ids,
- size_t *cpu_count);
-bool fdt_find_memory_ranges(const struct fdt_node *root,
- struct string *device_type,
+bool fdt_find_cpus(const struct fdt *fdt, cpu_id_t *cpu_ids, size_t *cpu_count);
+bool fdt_find_memory_ranges(const struct fdt *fdt, struct string *device_type,
struct mem_range *mem_ranges,
size_t *mem_ranges_count, size_t mem_range_limit);
-bool fdt_find_initrd(const struct fdt_node *root, paddr_t *begin, paddr_t *end);
-
-/** Apply an update to the FDT. */
-bool fdt_patch(struct mm_stage1_locked stage1_locked, paddr_t fdt_addr,
- struct boot_params_update *p, struct mpool *ppool);
+bool fdt_find_initrd(const struct fdt *fdt, paddr_t *begin, paddr_t *end);
diff --git a/inc/hf/fdt_patch.h b/inc/hf/fdt_patch.h
new file mode 100644
index 0000000..5c639fe
--- /dev/null
+++ b/inc/hf/fdt_patch.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2020 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "hf/boot_params.h"
+#include "hf/mm.h"
+#include "hf/mpool.h"
+
+/** Apply an update to the FDT. */
+bool fdt_patch(struct mm_stage1_locked stage1_locked, paddr_t fdt_addr,
+ struct boot_params_update *p, struct mpool *ppool);
diff --git a/inc/hf/memiter.h b/inc/hf/memiter.h
index e3f0db8..d0a830c 100644
--- a/inc/hf/memiter.h
+++ b/inc/hf/memiter.h
@@ -30,6 +30,8 @@
bool memiter_parse_str(struct memiter *it, struct memiter *str);
bool memiter_iseq(const struct memiter *it, const char *str);
bool memiter_advance(struct memiter *it, size_t v);
+bool memiter_restrict(struct memiter *it, size_t v);
+bool memiter_consume(struct memiter *it, size_t v, struct memiter *newit);
const void *memiter_base(const struct memiter *it);
size_t memiter_size(const struct memiter *it);
diff --git a/inc/hf/plat/boot_flow.h b/inc/hf/plat/boot_flow.h
index b5d8145..13409f7 100644
--- a/inc/hf/plat/boot_flow.h
+++ b/inc/hf/plat/boot_flow.h
@@ -25,8 +25,8 @@
paddr_t plat_boot_flow_get_fdt_addr(void);
uintreg_t plat_boot_flow_get_kernel_arg(void);
-bool plat_boot_flow_get_initrd_range(const struct fdt_node *fdt_root,
- paddr_t *begin, paddr_t *end);
+bool plat_boot_flow_get_initrd_range(const struct fdt *fdt, paddr_t *begin,
+ paddr_t *end);
bool plat_boot_flow_update(struct mm_stage1_locked stage1_locked,
const struct manifest *manifest,
struct boot_params_update *p, struct memiter *cpio,
diff --git a/inc/hf/plat/iommu.h b/inc/hf/plat/iommu.h
index 0655232..b9eccf2 100644
--- a/inc/hf/plat/iommu.h
+++ b/inc/hf/plat/iommu.h
@@ -25,7 +25,7 @@
* so that the driver can read from it. This can be used to map IOMMU devices
* into the hypervisor's address space so they are accessible by the driver.
*/
-bool plat_iommu_init(const struct fdt_node *fdt_root,
+bool plat_iommu_init(const struct fdt *fdt,
struct mm_stage1_locked stage1_locked,
struct mpool *ppool);
diff --git a/inc/hf/string.h b/inc/hf/string.h
index 9c64632..6ab6323 100644
--- a/inc/hf/string.h
+++ b/inc/hf/string.h
@@ -19,6 +19,8 @@
#include <stdbool.h>
#include <stddef.h>
+#include "hf/memiter.h"
+
/**
* Maximum length of a string including the NULL terminator.
* This is an arbitrary number and can be adjusted to fit use cases.
@@ -48,8 +50,9 @@
*/
#define STRING_INIT(str) ((struct string){.data = str})
-enum string_return_code string_init(struct string *str, const char *data,
- size_t size);
+enum string_return_code string_init(struct string *str,
+ const struct memiter *data);
void string_init_empty(struct string *str);
bool string_is_empty(const struct string *str);
const char *string_data(const struct string *str);
+bool string_eq(const struct string *str, const struct memiter *data);