Merge "ufdt: provide API to apply multiple overlays" into main am: 89539ce4d2
Original change: https://android-review.googlesource.com/c/platform/system/libufdt/+/3235705
Change-Id: I76166a57ae8e53221200958955d4255010130320
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/include/ufdt_overlay.h b/include/ufdt_overlay.h
index fe8bd54..af3e0c9 100644
--- a/include/ufdt_overlay.h
+++ b/include/ufdt_overlay.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2016-2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,4 +39,22 @@
void *overlay_fdtp,
size_t overlay_size);
+/*
+ * Apply device tree `overlays` to `main_fdt_header` fdt buffer. (API is unstable)
+ *
+ * `main_fdt_header` is getting overrided by result tree, so it must
+ * have enough space (provided by `main_fdt_buffer_size`) to store it.
+ * `main_fdt_header` and all `overlays` must be 8 bytes aligned.
+ *
+ * `dto_malloc` is used for:
+ * - ufdt structures around main fdt and overlays.
+ * - result tree temporary buffer at most `main_fdt_buffer_size` size.
+ *
+ * TODO(b/362830550): expose a more comprehensive error type.
+ * Returns 0 or -1 in case of error.
+ */
+int ufdt_apply_multioverlay(struct fdt_header *main_fdt_header,
+ size_t main_fdt_buffer_size, void *const *overlays,
+ size_t overlays_count);
+
#endif /* UFDT_OVERLAY_H */
diff --git a/ufdt_overlay.c b/ufdt_overlay.c
index 69467a6..4a32291 100644
--- a/ufdt_overlay.c
+++ b/ufdt_overlay.c
@@ -690,3 +690,100 @@
return NULL;
}
+
+/*
+ * Apply device tree `overlays` to `main_fdt_header` fdt buffer. (API is unstable)
+ *
+ * `main_fdt_header` is getting overrided by result tree, so it must
+ * have enough space (provided by `main_fdt_buffer_size`) to store it.
+ * `main_fdt_header` and all `overlays` must be 8 bytes aligned.
+ *
+ * `dto_malloc` is used for:
+ * - ufdt structures around main fdt and overlays.
+ * - result tree temporary buffer at most `main_fdt_buffer_size` size.
+ *
+ * TODO(b/362830550): expose a more comprehensive error type.
+ * Returns 0 or -1 in case of error.
+ */
+int ufdt_apply_multioverlay(struct fdt_header *main_fdt_header,
+ size_t main_fdt_buffer_size, void *const *overlays,
+ size_t overlays_count) {
+ void *temporary_buffer = NULL;
+
+ if (main_fdt_header == NULL || fdt_check_header(main_fdt_header) != 0 ||
+ overlays == NULL) {
+ return -1;
+ }
+ if (overlays_count == 0) {
+ return 0;
+ }
+
+ size_t result_size = fdt_totalsize(main_fdt_header);
+ struct ufdt_node_pool pool;
+ ufdt_node_pool_construct(&pool);
+ struct ufdt *main_tree = ufdt_from_fdt(main_fdt_header, result_size, &pool);
+
+ for (int i = 0; i < overlays_count; i++) {
+ struct fdt_header *current_overlay = overlays[i];
+ if (fdt_check_header(current_overlay) != 0) {
+ dto_error("Failed to parse %dth overlay header\n", i);
+ goto error;
+ }
+
+ size_t overlay_size = fdt_totalsize(current_overlay);
+ result_size += overlay_size;
+
+ // prepare main tree by rebuilding phandle table. don't need to do so
+ // for the first iteration since main_tree hasn't been updated yet
+ if (i != 0) {
+ main_tree->phandle_table = build_phandle_table(main_tree);
+ }
+
+ struct ufdt *overlay_tree =
+ ufdt_from_fdt(current_overlay, overlay_size, &pool);
+ int err = ufdt_overlay_apply(main_tree, overlay_tree, overlay_size, &pool);
+ ufdt_destruct(overlay_tree, &pool);
+ if (err < 0) {
+ dto_error("Failed to apply overlay number: %d\n", i);
+ goto error;
+ }
+ }
+
+ if (result_size > main_fdt_buffer_size) {
+ dto_error(
+ "Not enough space in main_fdt to apply the overlays. Required %d, "
+ "available: %d\n",
+ result_size, main_fdt_buffer_size);
+ goto error;
+ }
+
+ // ufdt tree has references to fdt buffer, so we cannot dump ufdt to
+ // underlying fdt buffer directly. allocate intermediate buffer for that.
+ temporary_buffer = dto_malloc(result_size);
+ if (temporary_buffer == NULL) {
+ dto_error("Failed to allocate memory for temporary buffer: %d\n",
+ result_size);
+ goto error;
+ }
+
+ int err = ufdt_to_fdt(main_tree, temporary_buffer, result_size);
+ if (err < 0) {
+ dto_error(
+ "Failed to dump the result device tree to the temporary buffer\n");
+ goto error;
+ }
+ ufdt_destruct(main_tree, &pool);
+
+ dto_memcpy(main_fdt_header, temporary_buffer, result_size);
+ dto_free(temporary_buffer);
+ ufdt_node_pool_destruct(&pool);
+
+ return 0;
+
+error:
+ dto_free(temporary_buffer);
+ ufdt_destruct(main_tree, &pool);
+ ufdt_node_pool_destruct(&pool);
+
+ return -1;
+}