Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
4 *
5 * Author:
6 * Pantelis Antoniou <pantelis.antoniou@konsulko.com>
7 */
8
9#include <assert.h>
10#include <ctype.h>
11#include <getopt.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <inttypes.h>
16
17#include <libfdt.h>
18
19#include "util.h"
20
21#define BUF_INCREMENT 65536
22
23/* Usage related data. */
24static const char usage_synopsis[] =
25 "apply a number of overlays to a base blob\n"
26 " fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]";
27static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
28static struct option const usage_long_opts[] = {
29 {"input", required_argument, NULL, 'i'},
30 {"output", required_argument, NULL, 'o'},
31 {"verbose", no_argument, NULL, 'v'},
32 USAGE_COMMON_LONG_OPTS,
33};
34static const char * const usage_opts_help[] = {
35 "Input base DT blob",
36 "Output DT blob",
37 "Verbose messages",
38 USAGE_COMMON_OPTS_HELP
39};
40
41int verbose = 0;
42
43static void *apply_one(char *base, const char *overlay, size_t *buf_len,
44 const char *name)
45{
46 char *tmp = NULL;
47 char *tmpo;
48 int ret;
49 bool has_symbols;
50
51 /*
52 * We take copies first, because a failed apply can trash
53 * both the base blob and the overlay
54 */
55 tmpo = xmalloc(fdt_totalsize(overlay));
56
57 do {
58 tmp = xrealloc(tmp, *buf_len);
59 ret = fdt_open_into(base, tmp, *buf_len);
60 if (ret) {
61 fprintf(stderr,
62 "\nFailed to make temporary copy: %s\n",
63 fdt_strerror(ret));
64 goto fail;
65 }
66 ret = fdt_path_offset(tmp, "/__symbols__");
67 has_symbols = ret >= 0;
68
69 memcpy(tmpo, overlay, fdt_totalsize(overlay));
70
71 ret = fdt_overlay_apply(tmp, tmpo);
72 if (ret == -FDT_ERR_NOSPACE) {
73 *buf_len += BUF_INCREMENT;
74 }
75 } while (ret == -FDT_ERR_NOSPACE);
76
77 if (ret) {
78 fprintf(stderr, "\nFailed to apply '%s': %s\n",
79 name, fdt_strerror(ret));
80 if (!has_symbols) {
81 fprintf(stderr,
82 "base blob does not have a '/__symbols__' node, "
83 "make sure you have compiled the base blob with '-@' option\n");
84 }
85 goto fail;
86 }
87
88 free(base);
89 free(tmpo);
90 return tmp;
91
92fail:
93 free(tmpo);
94 if (tmp)
95 free(tmp);
96
97 return NULL;
98}
99static int do_fdtoverlay(const char *input_filename,
100 const char *output_filename,
101 int argc, char *argv[])
102{
103 char *blob = NULL;
104 char **ovblob = NULL;
105 size_t buf_len;
106 int i, ret = -1;
107
108 blob = utilfdt_read(input_filename, &buf_len);
109 if (!blob) {
110 fprintf(stderr, "\nFailed to read '%s'\n", input_filename);
111 goto out_err;
112 }
113 if (fdt_totalsize(blob) > buf_len) {
114 fprintf(stderr,
115 "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
116 (unsigned long)buf_len, fdt_totalsize(blob));
117 goto out_err;
118 }
119
120 /* allocate blob pointer array */
121 ovblob = xmalloc(sizeof(*ovblob) * argc);
122 memset(ovblob, 0, sizeof(*ovblob) * argc);
123
124 /* read and keep track of the overlay blobs */
125 for (i = 0; i < argc; i++) {
126 size_t ov_len;
127 ovblob[i] = utilfdt_read(argv[i], &ov_len);
128 if (!ovblob[i]) {
129 fprintf(stderr, "\nFailed to read '%s'\n", argv[i]);
130 goto out_err;
131 }
132 if (fdt_totalsize(ovblob[i]) > ov_len) {
133 fprintf(stderr,
134"\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n",
135 argv[i], (unsigned long)ov_len,
136 fdt_totalsize(ovblob[i]));
137 goto out_err;
138 }
139 }
140
141 buf_len = fdt_totalsize(blob);
142
143 /* apply the overlays in sequence */
144 for (i = 0; i < argc; i++) {
145 blob = apply_one(blob, ovblob[i], &buf_len, argv[i]);
146 if (!blob)
147 goto out_err;
148 }
149
150 fdt_pack(blob);
151 ret = utilfdt_write(output_filename, blob);
152 if (ret)
153 fprintf(stderr, "\nFailed to write '%s'\n",
154 output_filename);
155
156out_err:
157 if (ovblob) {
158 for (i = 0; i < argc; i++) {
159 if (ovblob[i])
160 free(ovblob[i]);
161 }
162 free(ovblob);
163 }
164 free(blob);
165
166 return ret;
167}
168
169int main(int argc, char *argv[])
170{
171 int opt, i;
172 char *input_filename = NULL;
173 char *output_filename = NULL;
174
175 while ((opt = util_getopt_long()) != EOF) {
176 switch (opt) {
177 case_USAGE_COMMON_FLAGS
178
179 case 'i':
180 input_filename = optarg;
181 break;
182 case 'o':
183 output_filename = optarg;
184 break;
185 case 'v':
186 verbose = 1;
187 break;
188 }
189 }
190
191 if (!input_filename)
192 usage("missing input file");
193
194 if (!output_filename)
195 usage("missing output file");
196
197 argv += optind;
198 argc -= optind;
199
200 if (argc <= 0)
201 usage("missing overlay file(s)");
202
203 if (verbose) {
204 printf("input = %s\n", input_filename);
205 printf("output = %s\n", output_filename);
206 for (i = 0; i < argc; i++)
207 printf("overlay[%d] = %s\n", i, argv[i]);
208 }
209
210 if (do_fdtoverlay(input_filename, output_filename, argc, argv))
211 return 1;
212
213 return 0;
214}