[PATCH v2 6/6] fdtoverlaymerge: A tool that merges overlays

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



From: Srivatsa Vaddagiri <vatsa@xxxxxxxxxxxxxx>

fdtoverlaymerge is a command-line tool that merges two or more overlay blobs
by making use of fdt_overlay_merge() API

Signed-off-by: Srivatsa Vaddagiri <vatsa@xxxxxxxxxxxxxx>
---
 Makefile             |   3 +
 Makefile.utils       |   6 ++
 fdtoverlaymerge.c    | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++
 libfdt/fdt_overlay.c |   8 +-
 4 files changed, 236 insertions(+), 4 deletions(-)
 create mode 100644 fdtoverlaymerge.c

diff --git a/Makefile b/Makefile
index cb256e8..5db214f 100644
--- a/Makefile
+++ b/Makefile
@@ -147,6 +147,7 @@ BIN += fdtdump
 BIN += fdtget
 BIN += fdtput
 BIN += fdtoverlay
+BIN += fdtoverlaymerge
 
 SCRIPTS = dtdiff
 
@@ -266,6 +267,8 @@ fdtput:	$(FDTPUT_OBJS) $(LIBFDT_lib)
 
 fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_lib)
 
+fdtoverlaymerge: $(FDTOVERLAYMERGE_OBJS) $(LIBFDT_archive)
+
 dist:
 	git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \
 		> ../dtc-$(dtc_version).tar
diff --git a/Makefile.utils b/Makefile.utils
index 9436b34..e24a8ab 100644
--- a/Makefile.utils
+++ b/Makefile.utils
@@ -29,3 +29,9 @@ FDTOVERLAY_SRCS = \
 	util.c
 
 FDTOVERLAY_OBJS = $(FDTOVERLAY_SRCS:%.c=%.o)
+
+FDTOVERLAYMERGE_SRCS = \
+	fdtoverlaymerge.c \
+	util.c
+
+FDTOVERLAYMERGE_OBJS = $(FDTOVERLAYMERGE_SRCS:%.c=%.o)
diff --git a/fdtoverlaymerge.c b/fdtoverlaymerge.c
new file mode 100644
index 0000000..eaf3e97
--- /dev/null
+++ b/fdtoverlaymerge.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <libfdt.h>
+
+#include "util.h"
+
+/* Usage related data. */
+static const char usage_synopsis[] =
+	"merge a number of overlays\n"
+	"	fdtoverlaymerge <options> [<overlay.dtbo> [<overlay.dtbo>]]\n"
+	"\n"
+	USAGE_TYPE_MSG;
+static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+	{"input",            required_argument, NULL, 'i'},
+	{"output",	     required_argument, NULL, 'o'},
+	{"verbose",	           no_argument, NULL, 'v'},
+	USAGE_COMMON_LONG_OPTS,
+};
+static const char * const usage_opts_help[] = {
+	"Input base overlay DT blob",
+	"Output DT blob",
+	"Verbose messages",
+	USAGE_COMMON_OPTS_HELP
+};
+
+int verbose = 0;
+
+static void grow_blob(char **blob, off_t extra_len)
+{
+	int blob_len;
+
+	if (!extra_len)
+		return;
+
+	blob_len = fdt_totalsize(*blob) + extra_len;
+	*blob = xrealloc(*blob, blob_len);
+	fdt_open_into(*blob, *blob, blob_len);
+}
+
+static int reload_blob(char *filename, char **blob, off_t extra_len)
+{
+	size_t len;
+
+	free(*blob);
+	*blob = utilfdt_read(filename, &len);
+	if (!*blob) {
+		fprintf(stderr, "Failed to reload blob %s\n", filename);
+		return -1;
+	}
+
+	grow_blob(blob, extra_len);
+
+	return 0;
+}
+
+static int do_fdtoverlay_merge(const char *input_filename,
+			 const char *output_filename,
+			 int argc, char *argv[])
+{
+	char *blob = NULL;
+	char **ovblob = NULL;
+	size_t ov_len, blob_len, total_len, extra_blob_len = 0;
+	off_t *extra_ov_len;
+	int i, ret = -1;
+
+	/* allocate blob pointer array */
+	ovblob = xmalloc(sizeof(*ovblob) * argc);
+	memset(ovblob, 0, sizeof(*ovblob) * argc);
+
+	extra_ov_len = xmalloc(sizeof(*extra_ov_len) * argc);
+	memset(extra_ov_len, 0, sizeof(*extra_ov_len) * argc);
+
+reload_all_blobs:
+	/* Free existing buffer first */
+	free(blob);
+	blob = utilfdt_read(input_filename, &blob_len);
+	if (!blob) {
+		fprintf(stderr, "\nFailed to read base blob %s\n",
+				input_filename);
+		goto out_err;
+	}
+	if (fdt_totalsize(blob) > blob_len) {
+		fprintf(stderr,
+		 "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
+			(unsigned long)blob_len, fdt_totalsize(blob));
+		goto out_err;
+	}
+	ret = 0;
+
+	/* read and keep track of the overlay blobs */
+	total_len = extra_blob_len;
+	for (i = 0; i < argc; i++) {
+		/* Free existing buffer first */
+		free(ovblob[i]);
+		ovblob[i] = utilfdt_read(argv[i], &ov_len);
+		if (!ovblob[i]) {
+			fprintf(stderr, "\nFailed to read overlay %s\n",
+					argv[i]);
+			goto out_err;
+		}
+		grow_blob(&ovblob[i], extra_ov_len[i]);
+		total_len += ov_len + extra_ov_len[i];
+	}
+
+	/* grow the blob to worst case */
+	grow_blob(&blob, total_len);
+
+	/* apply the overlays in sequence */
+	for (i = 0; i < argc; i++) {
+		do {
+			int fdto_nospace;
+
+			fprintf(stderr, "Merging overlay blob %s\n", argv[i]);
+			ret = fdt_overlay_merge(blob, ovblob[i], &fdto_nospace);
+			if (ret && ret == -FDT_ERR_NOSPACE) {
+				if (fdto_nospace) {
+					extra_ov_len[i] += 512;
+					fprintf(stderr, "Reloading overlay blob %s\n", argv[i]);
+					ret = reload_blob(argv[i], &ovblob[i], extra_ov_len[i]);
+					if (!ret)
+						continue;
+				} else {
+					extra_blob_len += 512;
+					fprintf(stderr, "Reloading all blobs\n");
+					goto reload_all_blobs;
+				}
+			}
+
+			if (!ret)
+				break;
+
+			if (ret) {
+				fprintf(stderr, "\nFailed to merge %s (%d)\n",
+						argv[i], ret);
+				goto out_err;
+			}
+		} while (1);
+	}
+
+	fdt_pack(blob);
+	ret = utilfdt_write(output_filename, blob);
+	if (ret)
+		fprintf(stderr, "\nFailed to write output blob %s\n",
+				output_filename);
+
+out_err:
+	if (ovblob) {
+		for (i = 0; i < argc; i++) {
+			if (ovblob[i])
+				free(ovblob[i]);
+		}
+		free(ovblob);
+	}
+	free(blob);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, i;
+	char *input_filename = NULL;
+	char *output_filename = NULL;
+
+	while ((opt = util_getopt_long()) != EOF) {
+		switch (opt) {
+		case_USAGE_COMMON_FLAGS
+
+		case 'i':
+			input_filename = optarg;
+			break;
+		case 'o':
+			output_filename = optarg;
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		}
+	}
+
+	if (!input_filename)
+		usage("missing input file");
+
+	if (!output_filename)
+		usage("missing output file");
+
+	argv += optind;
+	argc -= optind;
+
+	if (argc <= 0)
+		usage("missing overlay file(s)");
+
+	if (verbose) {
+		printf("input  = %s\n", input_filename);
+		printf("output = %s\n", output_filename);
+		for (i = 0; i < argc; i++)
+			printf("overlay[%d] = %s\n", i, argv[i]);
+	}
+
+	if (do_fdtoverlay_merge(input_filename, output_filename, argc, argv))
+		return 1;
+
+	return 0;
+}
diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c
index d3a567f..bf639c5 100644
--- a/libfdt/fdt_overlay.c
+++ b/libfdt/fdt_overlay.c
@@ -12,7 +12,7 @@
 
 #include "libfdt_internal.h"
 
-#define ULONG_MAX	(~0UL)
+/* #define ULONG_MAX	(~0UL) */
 
 /**
  * overlay_get_target_phandle - retrieves the target phandle of a fragment
@@ -408,7 +408,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto,
 						   sizeof(phandle_prop));
 };
 
-#define PATH_MAX	256
+/* #define PATH_MAX	256 */
 
 static int overlay_add_to_local_fixups(void *fdt, const char *value, int len)
 {
@@ -1510,8 +1510,8 @@ int fdt_overlay_merge(void *fdt, void *fdto, int *fdto_nospace)
 	uint32_t delta = fdt_get_max_phandle(fdt);
 	int ret;
 
-	FDT_CHECK_HEADER(fdt);
-	FDT_CHECK_HEADER(fdto);
+	FDT_RO_PROBE(fdt);
+	FDT_RO_PROBE(fdto);
 
 	*fdto_nospace = 0;
 
-- 
2.7.4




[Index of Archives]     [Device Tree]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux