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