dtc.c revision 1.1.1.3 1 1.1.1.2 skrll /* $NetBSD: dtc.c,v 1.1.1.3 2019/12/22 12:34:03 skrll Exp $ */
2 1.1.1.2 skrll
3 1.1.1.3 skrll // SPDX-License-Identifier: GPL-2.0-or-later
4 1.1 macallan /*
5 1.1 macallan * (C) Copyright David Gibson <dwg (at) au1.ibm.com>, IBM Corporation. 2005.
6 1.1 macallan */
7 1.1 macallan
8 1.1 macallan #include <sys/stat.h>
9 1.1 macallan
10 1.1 macallan #include "dtc.h"
11 1.1 macallan #include "srcpos.h"
12 1.1 macallan
13 1.1 macallan /*
14 1.1 macallan * Command line options
15 1.1 macallan */
16 1.1 macallan int quiet; /* Level of quietness */
17 1.1 macallan int reservenum; /* Number of memory reservation slots */
18 1.1 macallan int minsize; /* Minimum blob size */
19 1.1 macallan int padsize; /* Additional padding to blob */
20 1.1.1.2 skrll int alignsize; /* Additional padding to blob accroding to the alignsize */
21 1.1.1.3 skrll int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */
22 1.1.1.2 skrll int generate_symbols; /* enable symbols & fixup support */
23 1.1.1.2 skrll int generate_fixups; /* suppress generation of fixups on symbol support */
24 1.1.1.2 skrll int auto_label_aliases; /* auto generate labels -> aliases */
25 1.1.1.3 skrll int annotate; /* Level of annotation: 1 for input source location
26 1.1.1.3 skrll >1 for full input source location. */
27 1.1.1.2 skrll
28 1.1.1.2 skrll static int is_power_of_2(int x)
29 1.1.1.2 skrll {
30 1.1.1.2 skrll return (x > 0) && ((x & (x - 1)) == 0);
31 1.1.1.2 skrll }
32 1.1 macallan
33 1.1 macallan static void fill_fullpaths(struct node *tree, const char *prefix)
34 1.1 macallan {
35 1.1 macallan struct node *child;
36 1.1 macallan const char *unit;
37 1.1 macallan
38 1.1 macallan tree->fullpath = join_path(prefix, tree->name);
39 1.1 macallan
40 1.1 macallan unit = strchr(tree->name, '@');
41 1.1 macallan if (unit)
42 1.1 macallan tree->basenamelen = unit - tree->name;
43 1.1 macallan else
44 1.1 macallan tree->basenamelen = strlen(tree->name);
45 1.1 macallan
46 1.1 macallan for_each_child(tree, child)
47 1.1 macallan fill_fullpaths(child, tree->fullpath);
48 1.1 macallan }
49 1.1 macallan
50 1.1 macallan /* Usage related data. */
51 1.1 macallan static const char usage_synopsis[] = "dtc [options] <input file>";
52 1.1.1.3 skrll static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv";
53 1.1 macallan static struct option const usage_long_opts[] = {
54 1.1 macallan {"quiet", no_argument, NULL, 'q'},
55 1.1 macallan {"in-format", a_argument, NULL, 'I'},
56 1.1 macallan {"out", a_argument, NULL, 'o'},
57 1.1 macallan {"out-format", a_argument, NULL, 'O'},
58 1.1 macallan {"out-version", a_argument, NULL, 'V'},
59 1.1 macallan {"out-dependency", a_argument, NULL, 'd'},
60 1.1 macallan {"reserve", a_argument, NULL, 'R'},
61 1.1 macallan {"space", a_argument, NULL, 'S'},
62 1.1 macallan {"pad", a_argument, NULL, 'p'},
63 1.1.1.2 skrll {"align", a_argument, NULL, 'a'},
64 1.1 macallan {"boot-cpu", a_argument, NULL, 'b'},
65 1.1 macallan {"force", no_argument, NULL, 'f'},
66 1.1 macallan {"include", a_argument, NULL, 'i'},
67 1.1 macallan {"sort", no_argument, NULL, 's'},
68 1.1 macallan {"phandle", a_argument, NULL, 'H'},
69 1.1 macallan {"warning", a_argument, NULL, 'W'},
70 1.1 macallan {"error", a_argument, NULL, 'E'},
71 1.1.1.2 skrll {"symbols", no_argument, NULL, '@'},
72 1.1.1.2 skrll {"auto-alias", no_argument, NULL, 'A'},
73 1.1.1.3 skrll {"annotate", no_argument, NULL, 'T'},
74 1.1 macallan {"help", no_argument, NULL, 'h'},
75 1.1 macallan {"version", no_argument, NULL, 'v'},
76 1.1 macallan {NULL, no_argument, NULL, 0x0},
77 1.1 macallan };
78 1.1 macallan static const char * const usage_opts_help[] = {
79 1.1 macallan "\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
80 1.1 macallan "\n\tInput formats are:\n"
81 1.1 macallan "\t\tdts - device tree source text\n"
82 1.1 macallan "\t\tdtb - device tree blob\n"
83 1.1 macallan "\t\tfs - /proc/device-tree style directory",
84 1.1 macallan "\n\tOutput file",
85 1.1 macallan "\n\tOutput formats are:\n"
86 1.1 macallan "\t\tdts - device tree source text\n"
87 1.1 macallan "\t\tdtb - device tree blob\n"
88 1.1.1.3 skrll #ifndef NO_YAML
89 1.1.1.3 skrll "\t\tyaml - device tree encoded as YAML\n"
90 1.1.1.3 skrll #endif
91 1.1 macallan "\t\tasm - assembler source",
92 1.1.1.3 skrll "\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
93 1.1 macallan "\n\tOutput dependency file",
94 1.1 macallan "\n\tMake space for <number> reserve map entries (for dtb and asm output)",
95 1.1 macallan "\n\tMake the blob at least <bytes> long (extra space)",
96 1.1 macallan "\n\tAdd padding to the blob of <bytes> long (extra space)",
97 1.1.1.2 skrll "\n\tMake the blob align to the <bytes> (extra space)",
98 1.1 macallan "\n\tSet the physical boot cpu",
99 1.1 macallan "\n\tTry to produce output even if the input tree has errors",
100 1.1 macallan "\n\tAdd a path to search for include files",
101 1.1 macallan "\n\tSort nodes and properties before outputting (useful for comparing trees)",
102 1.1 macallan "\n\tValid phandle formats are:\n"
103 1.1 macallan "\t\tlegacy - \"linux,phandle\" properties only\n"
104 1.1 macallan "\t\tepapr - \"phandle\" properties only\n"
105 1.1 macallan "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
106 1.1 macallan "\n\tEnable/disable warnings (prefix with \"no-\")",
107 1.1 macallan "\n\tEnable/disable errors (prefix with \"no-\")",
108 1.1.1.2 skrll "\n\tEnable generation of symbols",
109 1.1.1.2 skrll "\n\tEnable auto-alias of labels",
110 1.1.1.3 skrll "\n\tAnnotate output .dts with input source file and line (-T -T for more details)",
111 1.1 macallan "\n\tPrint this help and exit",
112 1.1 macallan "\n\tPrint version and exit",
113 1.1 macallan NULL,
114 1.1 macallan };
115 1.1 macallan
116 1.1 macallan static const char *guess_type_by_name(const char *fname, const char *fallback)
117 1.1 macallan {
118 1.1 macallan const char *s;
119 1.1 macallan
120 1.1 macallan s = strrchr(fname, '.');
121 1.1 macallan if (s == NULL)
122 1.1 macallan return fallback;
123 1.1 macallan if (!strcasecmp(s, ".dts"))
124 1.1 macallan return "dts";
125 1.1.1.3 skrll if (!strcasecmp(s, ".yaml"))
126 1.1.1.3 skrll return "yaml";
127 1.1 macallan if (!strcasecmp(s, ".dtb"))
128 1.1 macallan return "dtb";
129 1.1 macallan return fallback;
130 1.1 macallan }
131 1.1 macallan
132 1.1 macallan static const char *guess_input_format(const char *fname, const char *fallback)
133 1.1 macallan {
134 1.1 macallan struct stat statbuf;
135 1.1.1.2 skrll fdt32_t magic;
136 1.1 macallan FILE *f;
137 1.1 macallan
138 1.1 macallan if (stat(fname, &statbuf) != 0)
139 1.1 macallan return fallback;
140 1.1 macallan
141 1.1 macallan if (S_ISDIR(statbuf.st_mode))
142 1.1 macallan return "fs";
143 1.1 macallan
144 1.1 macallan if (!S_ISREG(statbuf.st_mode))
145 1.1 macallan return fallback;
146 1.1 macallan
147 1.1 macallan f = fopen(fname, "r");
148 1.1 macallan if (f == NULL)
149 1.1 macallan return fallback;
150 1.1 macallan if (fread(&magic, 4, 1, f) != 1) {
151 1.1 macallan fclose(f);
152 1.1 macallan return fallback;
153 1.1 macallan }
154 1.1 macallan fclose(f);
155 1.1 macallan
156 1.1.1.2 skrll if (fdt32_to_cpu(magic) == FDT_MAGIC)
157 1.1 macallan return "dtb";
158 1.1 macallan
159 1.1 macallan return guess_type_by_name(fname, fallback);
160 1.1 macallan }
161 1.1 macallan
162 1.1 macallan int main(int argc, char *argv[])
163 1.1 macallan {
164 1.1.1.2 skrll struct dt_info *dti;
165 1.1 macallan const char *inform = NULL;
166 1.1 macallan const char *outform = NULL;
167 1.1 macallan const char *outname = "-";
168 1.1 macallan const char *depname = NULL;
169 1.1 macallan bool force = false, sort = false;
170 1.1 macallan const char *arg;
171 1.1 macallan int opt;
172 1.1 macallan FILE *outf = NULL;
173 1.1 macallan int outversion = DEFAULT_FDT_VERSION;
174 1.1 macallan long long cmdline_boot_cpuid = -1;
175 1.1 macallan
176 1.1 macallan quiet = 0;
177 1.1 macallan reservenum = 0;
178 1.1 macallan minsize = 0;
179 1.1 macallan padsize = 0;
180 1.1.1.2 skrll alignsize = 0;
181 1.1 macallan
182 1.1 macallan while ((opt = util_getopt_long()) != EOF) {
183 1.1 macallan switch (opt) {
184 1.1 macallan case 'I':
185 1.1 macallan inform = optarg;
186 1.1 macallan break;
187 1.1 macallan case 'O':
188 1.1 macallan outform = optarg;
189 1.1 macallan break;
190 1.1 macallan case 'o':
191 1.1 macallan outname = optarg;
192 1.1 macallan break;
193 1.1 macallan case 'V':
194 1.1 macallan outversion = strtol(optarg, NULL, 0);
195 1.1 macallan break;
196 1.1 macallan case 'd':
197 1.1 macallan depname = optarg;
198 1.1 macallan break;
199 1.1 macallan case 'R':
200 1.1 macallan reservenum = strtol(optarg, NULL, 0);
201 1.1 macallan break;
202 1.1 macallan case 'S':
203 1.1 macallan minsize = strtol(optarg, NULL, 0);
204 1.1 macallan break;
205 1.1 macallan case 'p':
206 1.1 macallan padsize = strtol(optarg, NULL, 0);
207 1.1 macallan break;
208 1.1.1.2 skrll case 'a':
209 1.1.1.2 skrll alignsize = strtol(optarg, NULL, 0);
210 1.1.1.2 skrll if (!is_power_of_2(alignsize))
211 1.1.1.2 skrll die("Invalid argument \"%d\" to -a option\n",
212 1.1.1.2 skrll alignsize);
213 1.1.1.2 skrll break;
214 1.1 macallan case 'f':
215 1.1 macallan force = true;
216 1.1 macallan break;
217 1.1 macallan case 'q':
218 1.1 macallan quiet++;
219 1.1 macallan break;
220 1.1 macallan case 'b':
221 1.1 macallan cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
222 1.1 macallan break;
223 1.1 macallan case 'i':
224 1.1 macallan srcfile_add_search_path(optarg);
225 1.1 macallan break;
226 1.1 macallan case 'v':
227 1.1 macallan util_version();
228 1.1 macallan case 'H':
229 1.1 macallan if (streq(optarg, "legacy"))
230 1.1 macallan phandle_format = PHANDLE_LEGACY;
231 1.1 macallan else if (streq(optarg, "epapr"))
232 1.1 macallan phandle_format = PHANDLE_EPAPR;
233 1.1 macallan else if (streq(optarg, "both"))
234 1.1 macallan phandle_format = PHANDLE_BOTH;
235 1.1 macallan else
236 1.1 macallan die("Invalid argument \"%s\" to -H option\n",
237 1.1 macallan optarg);
238 1.1 macallan break;
239 1.1 macallan
240 1.1 macallan case 's':
241 1.1 macallan sort = true;
242 1.1 macallan break;
243 1.1 macallan
244 1.1 macallan case 'W':
245 1.1 macallan parse_checks_option(true, false, optarg);
246 1.1 macallan break;
247 1.1 macallan
248 1.1 macallan case 'E':
249 1.1 macallan parse_checks_option(false, true, optarg);
250 1.1 macallan break;
251 1.1 macallan
252 1.1.1.2 skrll case '@':
253 1.1.1.2 skrll generate_symbols = 1;
254 1.1.1.2 skrll break;
255 1.1.1.2 skrll case 'A':
256 1.1.1.2 skrll auto_label_aliases = 1;
257 1.1.1.2 skrll break;
258 1.1.1.3 skrll case 'T':
259 1.1.1.3 skrll annotate++;
260 1.1.1.3 skrll break;
261 1.1.1.2 skrll
262 1.1 macallan case 'h':
263 1.1 macallan usage(NULL);
264 1.1 macallan default:
265 1.1 macallan usage("unknown option");
266 1.1 macallan }
267 1.1 macallan }
268 1.1 macallan
269 1.1 macallan if (argc > (optind+1))
270 1.1 macallan usage("missing files");
271 1.1 macallan else if (argc < (optind+1))
272 1.1 macallan arg = "-";
273 1.1 macallan else
274 1.1 macallan arg = argv[optind];
275 1.1 macallan
276 1.1 macallan /* minsize and padsize are mutually exclusive */
277 1.1 macallan if (minsize && padsize)
278 1.1 macallan die("Can't set both -p and -S\n");
279 1.1 macallan
280 1.1 macallan if (depname) {
281 1.1 macallan depfile = fopen(depname, "w");
282 1.1 macallan if (!depfile)
283 1.1 macallan die("Couldn't open dependency file %s: %s\n", depname,
284 1.1 macallan strerror(errno));
285 1.1 macallan fprintf(depfile, "%s:", outname);
286 1.1 macallan }
287 1.1 macallan
288 1.1 macallan if (inform == NULL)
289 1.1 macallan inform = guess_input_format(arg, "dts");
290 1.1 macallan if (outform == NULL) {
291 1.1 macallan outform = guess_type_by_name(outname, NULL);
292 1.1 macallan if (outform == NULL) {
293 1.1 macallan if (streq(inform, "dts"))
294 1.1 macallan outform = "dtb";
295 1.1 macallan else
296 1.1 macallan outform = "dts";
297 1.1 macallan }
298 1.1 macallan }
299 1.1.1.3 skrll if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
300 1.1.1.3 skrll die("--annotate requires -I dts -O dts\n");
301 1.1 macallan if (streq(inform, "dts"))
302 1.1.1.2 skrll dti = dt_from_source(arg);
303 1.1 macallan else if (streq(inform, "fs"))
304 1.1.1.2 skrll dti = dt_from_fs(arg);
305 1.1 macallan else if(streq(inform, "dtb"))
306 1.1.1.2 skrll dti = dt_from_blob(arg);
307 1.1 macallan else
308 1.1 macallan die("Unknown input format \"%s\"\n", inform);
309 1.1 macallan
310 1.1.1.2 skrll dti->outname = outname;
311 1.1.1.2 skrll
312 1.1 macallan if (depfile) {
313 1.1 macallan fputc('\n', depfile);
314 1.1 macallan fclose(depfile);
315 1.1 macallan }
316 1.1 macallan
317 1.1 macallan if (cmdline_boot_cpuid != -1)
318 1.1.1.2 skrll dti->boot_cpuid_phys = cmdline_boot_cpuid;
319 1.1.1.2 skrll
320 1.1.1.2 skrll fill_fullpaths(dti->dt, "");
321 1.1.1.2 skrll
322 1.1.1.2 skrll /* on a plugin, generate by default */
323 1.1.1.2 skrll if (dti->dtsflags & DTSF_PLUGIN) {
324 1.1.1.2 skrll generate_fixups = 1;
325 1.1.1.2 skrll }
326 1.1 macallan
327 1.1.1.3 skrll process_checks(force, dti);
328 1.1.1.3 skrll
329 1.1.1.2 skrll if (auto_label_aliases)
330 1.1.1.2 skrll generate_label_tree(dti, "aliases", false);
331 1.1.1.2 skrll
332 1.1.1.2 skrll if (generate_symbols)
333 1.1.1.2 skrll generate_label_tree(dti, "__symbols__", true);
334 1.1.1.2 skrll
335 1.1.1.2 skrll if (generate_fixups) {
336 1.1.1.2 skrll generate_fixups_tree(dti, "__fixups__");
337 1.1.1.2 skrll generate_local_fixups_tree(dti, "__local_fixups__");
338 1.1.1.2 skrll }
339 1.1 macallan
340 1.1 macallan if (sort)
341 1.1.1.2 skrll sort_tree(dti);
342 1.1 macallan
343 1.1 macallan if (streq(outname, "-")) {
344 1.1 macallan outf = stdout;
345 1.1 macallan } else {
346 1.1 macallan outf = fopen(outname, "wb");
347 1.1 macallan if (! outf)
348 1.1 macallan die("Couldn't open output file %s: %s\n",
349 1.1 macallan outname, strerror(errno));
350 1.1 macallan }
351 1.1 macallan
352 1.1 macallan if (streq(outform, "dts")) {
353 1.1.1.2 skrll dt_to_source(outf, dti);
354 1.1.1.3 skrll #ifndef NO_YAML
355 1.1.1.3 skrll } else if (streq(outform, "yaml")) {
356 1.1.1.3 skrll if (!streq(inform, "dts"))
357 1.1.1.3 skrll die("YAML output format requires dts input format\n");
358 1.1.1.3 skrll dt_to_yaml(outf, dti);
359 1.1.1.3 skrll #endif
360 1.1 macallan } else if (streq(outform, "dtb")) {
361 1.1.1.2 skrll dt_to_blob(outf, dti, outversion);
362 1.1 macallan } else if (streq(outform, "asm")) {
363 1.1.1.2 skrll dt_to_asm(outf, dti, outversion);
364 1.1 macallan } else if (streq(outform, "null")) {
365 1.1 macallan /* do nothing */
366 1.1 macallan } else {
367 1.1 macallan die("Unknown output format \"%s\"\n", outform);
368 1.1 macallan }
369 1.1 macallan
370 1.1 macallan exit(0);
371 1.1 macallan }
372